Пример #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);
}
Пример #2
0
svn_error_t *svn_ra_svn_cram_server(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                    svn_config_t *pwdb, const char **user,
                                    svn_boolean_t *success)
{
  apr_status_t status;
  apr_uint64_t nonce;
  char hostbuf[APRMAXHOSTLEN + 1];
  unsigned char cdigest[APR_MD5_DIGESTSIZE], sdigest[APR_MD5_DIGESTSIZE];
  const char *challenge, *sep, *password;
  svn_ra_svn_item_t *item;
  svn_string_t *resp;

  *success = FALSE;

  /* Send a challenge. */
  status = make_nonce(&nonce);
  if (!status)
    status = apr_gethostname(hostbuf, sizeof(hostbuf), pool);
  if (status)
    return fail(conn, pool, "Internal server error in authentication");
  challenge = apr_psprintf(pool,
                           "<%" APR_UINT64_T_FMT ".%" APR_TIME_T_FMT "@%s>",
                           nonce, apr_time_now(), hostbuf);
  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(c)", "step", challenge));

  /* Read the client's response and decode it into *user and cdigest. */
  SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
  if (item->kind != SVN_RA_SVN_STRING)  /* Very wrong; don't report failure */
    return SVN_NO_ERROR;
  resp = item->u.string;
  sep = strrchr(resp->data, ' ');
  if (!sep || resp->len - (sep + 1 - resp->data) != APR_MD5_DIGESTSIZE * 2
      || !hex_decode(cdigest, sep + 1))
    return fail(conn, pool, "Malformed client response in authentication");
  *user = apr_pstrmemdup(pool, resp->data, sep - resp->data);

  /* Verify the digest against the password in pwfile. */
  svn_config_get(pwdb, &password, SVN_CONFIG_SECTION_USERS, *user, NULL);
  if (!password)
    return fail(conn, pool, "Username not found");
  compute_digest(sdigest, challenge, password);
  if (memcmp(cdigest, sdigest, sizeof(sdigest)) != 0)
    return fail(conn, pool, "Password incorrect");

  *success = TRUE;
  return svn_ra_svn__write_tuple(conn, pool, "w()", "success");
}
Пример #3
0
static svn_error_t *try_auth(svn_ra_svn_conn_t *conn,
                             sasl_conn_t *sasl_ctx,
                             apr_pool_t *pool,
                             server_baton_t *b,
                             svn_boolean_t *success)
{
  const char *out, *mech;
  const svn_string_t *arg = NULL, *in;
  unsigned int outlen;
  int result;
  svn_boolean_t use_base64;

  *success = FALSE;

  /* Read the client's chosen mech and the initial token. */
  SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "w(?s)", &mech, &in));

  if (strcmp(mech, "EXTERNAL") == 0 && !in)
    in = svn_string_create(b->client_info->tunnel_user, pool);
  else if (in)
    in = svn_base64_decode_string(in, pool);

  /* For CRAM-MD5, we don't base64-encode stuff. */
  use_base64 = (strcmp(mech, "CRAM-MD5") != 0);

  /* sasl uses unsigned int for the length of strings, we use apr_size_t
   * which may not be the same size.  Deal with potential integer overflow */
  if (in && in->len > UINT_MAX)
    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                             _("Initial token is too long"));

  result = svn_sasl__server_start(sasl_ctx, mech,
                                  in ? in->data : NULL,
                                  in ? (unsigned int) in->len : 0,
                                  &out, &outlen);

  if (result != SASL_OK && result != SASL_CONTINUE)
    return fail_auth(conn, pool, sasl_ctx);

  while (result == SASL_CONTINUE)
    {
      svn_ra_svn__item_t *item;

      arg = svn_string_ncreate(out, outlen, pool);
      /* Encode what we send to the client. */
      if (use_base64)
        arg = svn_base64_encode_string2(arg, TRUE, pool);

      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(s)", "step", arg));

      /* Read and decode the client response. */
      SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
      if (item->kind != SVN_RA_SVN_STRING)
        return SVN_NO_ERROR;

      in = &item->u.string;
      if (use_base64)
        in = svn_base64_decode_string(in, pool);

      if (in->len > UINT_MAX)
        return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                 _("Step response is too long"));

      result = svn_sasl__server_step(sasl_ctx, in->data,
                                     (unsigned int) in->len,
                                     &out, &outlen);
    }

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

  /* Send our last response, if necessary. */
  if (outlen)
    arg = svn_base64_encode_string2(svn_string_ncreate(out, outlen, pool), TRUE,
                                    pool);
  else
    arg = NULL;

  *success = TRUE;
  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(?s)", "success", arg));

  return SVN_NO_ERROR;
}
Пример #4
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));
}