Example #1
0
/* Tell the client the authentication failed. This is only used during
   the authentication exchange (i.e. inside try_auth()). */
static svn_error_t *
fail_auth(svn_ra_svn_conn_t *conn, apr_pool_t *pool, sasl_conn_t *sasl_ctx)
{
  const char *msg = svn_sasl__errdetail(sasl_ctx);
  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure", msg));
  return svn_ra_svn__flush(conn, pool);
}
Example #2
0
/* Used if we run into a SASL error outside try_auth(). */
static svn_error_t *
fail_cmd(svn_ra_svn_conn_t *conn, apr_pool_t *pool, sasl_conn_t *sasl_ctx)
{
  svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                      svn_sasl__errdetail(sasl_ctx));
  SVN_ERR(write_failure(conn, pool, &err));
  return svn_ra_svn__flush(conn, pool);
}
Example #3
0
svn_error_t *svn_ra_svn_drive_editor2(svn_ra_svn_conn_t *conn,
                                      apr_pool_t *pool,
                                      const svn_delta_editor_t *editor,
                                      void *edit_baton,
                                      svn_boolean_t *aborted,
                                      svn_boolean_t for_replay)
{
  ra_svn_driver_state_t state;
  apr_pool_t *subpool = svn_pool_create(pool);
  const char *cmd;
  int i;
  svn_error_t *err, *write_err;
  apr_array_header_t *params;

  state.editor = editor;
  state.edit_baton = edit_baton;
  state.tokens = apr_hash_make(pool);
  state.aborted = aborted;
  state.done = FALSE;
  state.pool = pool;
  state.file_pool = svn_pool_create(pool);
  state.file_refs = 0;
  state.for_replay = for_replay;

  while (!state.done)
    {
      svn_pool_clear(subpool);
      if (editor)
        {
          SVN_ERR(svn_ra_svn__read_tuple(conn, subpool, "wl", &cmd, &params));
          for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
              if (strcmp(cmd, ra_svn_edit_cmds[i].cmd) == 0)
                break;

          if (ra_svn_edit_cmds[i].cmd)
            err = (*ra_svn_edit_cmds[i].handler)(conn, subpool, params, &state);
          else if (strcmp(cmd, "failure") == 0)
            {
              /* While not really an editor command this can occur when
                reporter->finish_report() fails before the first editor
                command */
              if (aborted)
                *aborted = TRUE;
              err = svn_ra_svn__handle_failure_status(params, pool);
              return svn_error_compose_create(
                                err,
                                editor->abort_edit(edit_baton, subpool));
            }
          else
            {
              err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
                                      _("Unknown editor command '%s'"), cmd);
              err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
            }
        }
      else
        {
          const char* command = NULL;
          SVN_ERR(svn_ra_svn__read_command_only(conn, subpool, &command));
          if (strcmp(command, "close-edit") == 0)
            {
              state.done = TRUE;
              if (aborted)
                *aborted = FALSE;
              err = svn_ra_svn__write_cmd_response(conn, pool, "");
            }
          else
            err = NULL;
        }

      if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
        {
          if (aborted)
            *aborted = TRUE;
          if (!state.done)
            {
              /* Abort the edit and use non-blocking I/O to write the error. */
              if (editor)
                svn_error_clear(editor->abort_edit(edit_baton, subpool));
              svn_ra_svn__set_block_handler(conn, blocked_write, &state);
            }
          write_err = svn_ra_svn__write_cmd_failure(
                          conn, subpool,
                          svn_ra_svn__locate_real_error_child(err));
          if (!write_err)
            write_err = svn_ra_svn__flush(conn, subpool);
          svn_ra_svn__set_block_handler(conn, NULL, NULL);
          svn_error_clear(err);
          SVN_ERR(write_err);
          break;
        }
      SVN_ERR(err);
    }

  /* Read and discard editing commands until the edit is complete.
     Hopefully, the other side will call another editor command, run
     check_for_error, notice the error, write "abort-edit" at us, and
     throw the error up a few levels on its side (possibly even
     tossing it right back at us, which is why we can return
     SVN_NO_ERROR below).

     However, if the other side is way ahead of us, it might
     completely finish the edit (or sequence of edit/revprops, for
     "replay-range") before we send over our "failure".  So we should
     also stop if we see "success".  (Then the other side will try to
     interpret our "failure" as a command, which will itself fail...
     The net effect is that whatever error we wrote to the other side
     will be replaced with SVN_ERR_RA_SVN_UNKNOWN_CMD.)
   */
  while (!state.done)
    {
      svn_pool_clear(subpool);
      err = svn_ra_svn__read_tuple(conn, subpool, "wl", &cmd, &params);
      if (err && err->apr_err == SVN_ERR_RA_SVN_CONNECTION_CLOSED)
        {
          /* Other side disconnected; that's no error. */
          svn_error_clear(err);
          svn_pool_destroy(subpool);
          return SVN_NO_ERROR;
        }
      svn_error_clear(err);
      if (strcmp(cmd, "abort-edit") == 0
          || strcmp(cmd, "success") == 0)
        state.done = TRUE;
    }

  svn_pool_destroy(subpool);
  return SVN_NO_ERROR;
}
Example #4
0
svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                server_baton_t *b,
                                enum access_type required,
                                svn_boolean_t needs_username)
{
  sasl_conn_t *sasl_ctx;
  apr_pool_t *subpool;
  apr_status_t apr_err;
  const char *localaddrport = NULL, *remoteaddrport = NULL;
  const char *mechlist;
  char hostname[APRMAXHOSTLEN + 1];
  sasl_security_properties_t secprops;
  svn_boolean_t success, no_anonymous;
  int mech_count, result = SASL_OK;

  SVN_ERR(svn_ra_svn__get_addresses(&localaddrport, &remoteaddrport,
                                        conn, pool));
  apr_err = apr_gethostname(hostname, sizeof(hostname), pool);
  if (apr_err)
    {
      svn_error_t *err = svn_error_wrap_apr(apr_err, _("Can't get hostname"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol
     supports sending data along with the final "success" message. */
  result = svn_sasl__server_new(SVN_RA_SVN_SASL_NAME,
                                hostname, b->repository->realm,
                                localaddrport, remoteaddrport,
                                NULL, SASL_SUCCESS_DATA,
                                &sasl_ctx);
  if (result != SASL_OK)
    {
      svn_error_t *err = svn_error_create(
          SVN_ERR_RA_NOT_AUTHORIZED, NULL,
          svn_sasl__errstring(result, NULL, NULL));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Make sure the context is always destroyed. */
  apr_pool_cleanup_register(b->pool, sasl_ctx, sasl_dispose_cb,
                            apr_pool_cleanup_null);

  /* Initialize security properties. */
  svn_ra_svn__default_secprops(&secprops);

  /* Don't allow ANONYMOUS if a username is required. */
  no_anonymous = needs_username || b->repository->anon_access < required;
  if (no_anonymous)
    secprops.security_flags |= SASL_SEC_NOANONYMOUS;

  secprops.min_ssf = b->repository->min_ssf;
  secprops.max_ssf = b->repository->max_ssf;

  /* Set security properties. */
  result = svn_sasl__setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* SASL needs to know if we are externally authenticated. */
  if (b->client_info->tunnel_user)
    result = svn_sasl__setprop(sasl_ctx, SASL_AUTH_EXTERNAL,
                               b->client_info->tunnel_user);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* Get the list of mechanisms. */
  result = svn_sasl__listmech(sasl_ctx, NULL, NULL, " ", NULL,
                              &mechlist, NULL, &mech_count);

  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  if (mech_count == 0)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          _("Could not obtain the list"
                                          " of SASL mechanisms"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Send the list of mechanisms and the realm to the client. */
  SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "(w)c",
                                         mechlist, b->repository->realm));

  /* The main authentication loop. */
  subpool = svn_pool_create(pool);
  do
    {
      svn_pool_clear(subpool);
      SVN_ERR(try_auth(conn, sasl_ctx, subpool, b, &success));
    }
  while (!success);
  svn_pool_destroy(subpool);

  SVN_ERR(svn_ra_svn__enable_sasl_encryption(conn, sasl_ctx, pool));

  if (no_anonymous)
    {
      char *p;
      const void *user;

      /* Get the authenticated username. */
      result = svn_sasl__getprop(sasl_ctx, SASL_USERNAME, &user);

      if (result != SASL_OK)
        return fail_cmd(conn, pool, sasl_ctx);

      if ((p = strchr(user, '@')) != NULL)
        {
          /* Drop the realm part. */
          b->client_info->user = apr_pstrndup(b->pool, user,
                                              p - (const char *)user);
        }
      else
        {
          svn_error_t *err;
          err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                 _("Couldn't obtain the authenticated"
                                 " username"));
          SVN_ERR(write_failure(conn, pool, &err));
          return svn_ra_svn__flush(conn, pool);
        }
    }

  return SVN_NO_ERROR;
}
Example #5
0
/* Fail the authentication, from the server's perspective. */
static svn_error_t *fail(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                         const char *msg)
{
  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c)", "failure", msg));
  return svn_error_trace(svn_ra_svn__flush(conn, pool));
}