/* retrieve ssl server CA failure overrides (if any) from servers config */ static svn_error_t * ssl_server_trust_file_first_credentials(void **credentials, void **iter_baton, void *provider_baton, apr_hash_t *parameters, const char *realmstring, apr_pool_t *pool) { apr_uint32_t *failures = svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_FAILURES); const svn_auth_ssl_server_cert_info_t *cert_info = svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO); apr_hash_t *creds_hash = NULL; const char *config_dir; svn_error_t *error = SVN_NO_ERROR; *credentials = NULL; *iter_baton = NULL; /* Check if this is a permanently accepted certificate */ config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR); error = svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SSL_SERVER_TRUST, realmstring, config_dir, pool); svn_error_clear(error); if (! error && creds_hash) { svn_string_t *trusted_cert, *this_cert, *failstr; apr_uint32_t last_failures = 0; trusted_cert = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_ASCII_CERT_KEY); this_cert = svn_string_create(cert_info->ascii_cert, pool); failstr = svn_hash_gets(creds_hash, SVN_CONFIG_AUTHN_FAILURES_KEY); if (failstr) SVN_ERR(svn_cstring_atoui(&last_failures, failstr->data)); /* If the cert is trusted and there are no new failures, we * accept it by clearing all failures. */ if (trusted_cert && svn_string_compare(this_cert, trusted_cert) && (*failures & ~last_failures) == 0) { *failures = 0; } } /* If all failures are cleared now, we return the creds */ if (! *failures) { svn_auth_cred_ssl_server_trust_t *creds = apr_pcalloc(pool, sizeof(*creds)); creds->may_save = FALSE; /* No need to save it again... */ *credentials = creds; } return SVN_NO_ERROR; }
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, *val; 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 = sasl_server_new(SVN_RA_SVN_SASL_NAME, hostname, b->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, 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 || get_access(b, UNAUTHENTICATED) < required; if (no_anonymous) secprops.security_flags |= SASL_SEC_NOANONYMOUS; svn_config_get(b->cfg, &val, SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_MIN_SSF, "0"); SVN_ERR(svn_cstring_atoui(&secprops.min_ssf, val)); svn_config_get(b->cfg, &val, SVN_CONFIG_SECTION_SASL, SVN_CONFIG_OPTION_MAX_SSF, "256"); SVN_ERR(svn_cstring_atoui(&secprops.max_ssf, val)); /* Set security properties. */ result = 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->tunnel_user) result = sasl_setprop(sasl_ctx, SASL_AUTH_EXTERNAL, b->tunnel_user); if (result != SASL_OK) return fail_cmd(conn, pool, sasl_ctx); /* Get the list of mechanisms. */ result = 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->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 = 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->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; }