📄 session.c
字号:
/* * session.c : routines for maintaining sessions state (to the DAV server) * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <assert.h>#include <ctype.h>#define APR_WANT_STRFUNC#include <apr_want.h>#include <apr_general.h>#include <apr_xml.h>#include <ne_socket.h>#include <ne_request.h>#include <ne_uri.h>#include <ne_auth.h>#include <ne_locks.h>#include <ne_alloc.h>#include <ne_utils.h>#include "svn_error.h"#include "svn_pools.h"#include "svn_ra.h"#include "../libsvn_ra/ra_loader.h"#include "svn_config.h"#include "svn_delta.h"#include "svn_version.h"#include "svn_path.h"#include "svn_time.h"#include "svn_xml.h"#include "svn_private_config.h"#include "ra_dav.h"#define DEFAULT_HTTP_TIMEOUT 3600/* a cleanup routine attached to the pool that contains the RA session baton. */static apr_status_t cleanup_session(void *sess){ ne_session_destroy(sess); return APR_SUCCESS;}/* a cleanup routine attached to the pool that contains the RA session root URI. */static apr_status_t cleanup_uri(void *uri){ ne_uri_free(uri); return APR_SUCCESS;}/* A neon-session callback to 'pull' authentication data when challenged. In turn, this routine 'pulls' the data from the client callbacks if needed. */static int request_auth(void *userdata, const char *realm, int attempt, char *username, char *password){ svn_error_t *err; svn_ra_dav__session_t *ras = userdata; void *creds; svn_auth_cred_simple_t *simple_creds; /* Start by clearing the cache of any previously-fetched username. */ ras->auth_username = NULL; /* No auth_baton? Give up. */ if (! ras->callbacks->auth_baton) return -1; /* Neon automatically tries some auth protocols and bumps the attempt count without using Subversion's callbacks, so we can't depend on attempt == 0 the first time we are called -- we need to check if the auth state has been initted as well. */ if (attempt == 0 || ras->auth_iterstate == NULL) { const char *realmstring; /* <https://svn.collab.net:80> Subversion repository */ realmstring = apr_psprintf(ras->pool, "<%s://%s:%d> %s", ras->root.scheme, ras->root.host, ras->root.port, realm); err = svn_auth_first_credentials(&creds, &(ras->auth_iterstate), SVN_AUTH_CRED_SIMPLE, realmstring, ras->callbacks->auth_baton, ras->pool); } else /* attempt > 0 */ /* ### TODO: if the http realm changed this time around, we should be calling first_creds(), not next_creds(). */ err = svn_auth_next_credentials(&creds, ras->auth_iterstate, ras->pool); if (err || ! creds) { svn_error_clear(err); return -1; } simple_creds = creds; /* ### silently truncates username/password to 256 chars. */ apr_cpystrn(username, simple_creds->username, NE_ABUFSIZ); apr_cpystrn(password, simple_creds->password, NE_ABUFSIZ); /* Cache the fetched username in ra_session. */ ras->auth_username = apr_pstrdup(ras->pool, simple_creds->username); return 0;}static const apr_uint32_t neon_failure_map[][2] ={ { NE_SSL_NOTYETVALID, SVN_AUTH_SSL_NOTYETVALID }, { NE_SSL_EXPIRED, SVN_AUTH_SSL_EXPIRED }, { NE_SSL_IDMISMATCH, SVN_AUTH_SSL_CNMISMATCH }, { NE_SSL_UNTRUSTED, SVN_AUTH_SSL_UNKNOWNCA }};/* Convert neon's SSL failure mask to our own failure mask. */static apr_uint32_tconvert_neon_failures(int neon_failures){ apr_uint32_t svn_failures = 0; apr_size_t i; for (i = 0; i < sizeof(neon_failure_map) / (2 * sizeof(int)); ++i) { if (neon_failures & neon_failure_map[i][0]) { svn_failures |= neon_failure_map[i][1]; neon_failures &= ~neon_failure_map[i][0]; } } /* Map any remaining neon failure bits to our OTHER bit. */ if (neon_failures) { svn_failures |= SVN_AUTH_SSL_OTHER; } return svn_failures;}/* A neon-session callback to validate the SSL certificate when the CA is unknown (e.g. a self-signed cert), or there are other SSL certificate problems. */static intserver_ssl_callback(void *userdata, int failures, const ne_ssl_certificate *cert){ svn_ra_dav__session_t *ras = userdata; svn_auth_cred_ssl_server_trust_t *server_creds = NULL; void *creds; svn_auth_iterstate_t *state; apr_pool_t *pool; svn_error_t *error; char *ascii_cert = ne_ssl_cert_export(cert); char *issuer_dname = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert)); svn_auth_ssl_server_cert_info_t cert_info; char fingerprint[NE_SSL_DIGESTLEN]; char valid_from[NE_SSL_VDATELEN], valid_until[NE_SSL_VDATELEN]; const char *realmstring; apr_uint32_t *svn_failures = apr_palloc(ras->pool, sizeof(*svn_failures)); /* Construct the realmstring, e.g. https://svn.collab.net:80 */ realmstring = apr_psprintf(ras->pool, "%s://%s:%d", ras->root.scheme, ras->root.host, ras->root.port); *svn_failures = convert_neon_failures(failures); svn_auth_set_parameter(ras->callbacks->auth_baton, SVN_AUTH_PARAM_SSL_SERVER_FAILURES, svn_failures); /* Extract the info from the certificate */ cert_info.hostname = ne_ssl_cert_identity(cert); if (ne_ssl_cert_digest(cert, fingerprint) != 0) { strcpy(fingerprint, "<unknown>"); } cert_info.fingerprint = fingerprint; ne_ssl_cert_validity(cert, valid_from, valid_until); cert_info.valid_from = valid_from; cert_info.valid_until = valid_until; cert_info.issuer_dname = issuer_dname; cert_info.ascii_cert = ascii_cert; svn_auth_set_parameter(ras->callbacks->auth_baton, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, &cert_info); apr_pool_create(&pool, ras->pool); error = svn_auth_first_credentials(&creds, &state, SVN_AUTH_CRED_SSL_SERVER_TRUST, realmstring, ras->callbacks->auth_baton, pool); if (error || ! creds) { svn_error_clear(error); } else { server_creds = creds; error = svn_auth_save_credentials(state, pool); if (error) { /* It would be nice to show the error to the user somehow... */ svn_error_clear(error); } } free(issuer_dname); free(ascii_cert); svn_auth_set_parameter(ras->callbacks->auth_baton, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL); apr_pool_destroy(pool); return ! server_creds;}static svn_boolean_tclient_ssl_decrypt_cert(svn_ra_dav__session_t *ras, const char *cert_file, ne_ssl_client_cert *clicert){ svn_auth_iterstate_t *state; svn_error_t *error; apr_pool_t *pool; svn_boolean_t ok = FALSE; void *creds; int try; apr_pool_create(&pool, ras->pool); for (try = 0; TRUE; ++try) { if (try == 0) { error = svn_auth_first_credentials(&creds, &state, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, cert_file, ras->callbacks->auth_baton, pool); } else { error = svn_auth_next_credentials(&creds, state, pool); } if (error || ! creds) { /* Failure or too many attempts */ svn_error_clear(error); break; } else { svn_auth_cred_ssl_client_cert_pw_t *pw_creds = creds; if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0) { /* Success */ ok = TRUE; break; } } } apr_pool_destroy(pool); return ok;}static voidclient_ssl_callback(void *userdata, ne_session *sess, const ne_ssl_dname *const *dnames, int dncount){ svn_ra_dav__session_t *ras = userdata; ne_ssl_client_cert *clicert = NULL; void *creds; svn_auth_iterstate_t *state; const char *realmstring; apr_pool_t *pool; svn_error_t *error; int try; apr_pool_create(&pool, ras->pool); realmstring = apr_psprintf(pool, "%s://%s:%d", ras->root.scheme, ras->root.host, ras->root.port); for (try = 0; TRUE; ++try) { if (try == 0) { error = svn_auth_first_credentials(&creds, &state, SVN_AUTH_CRED_SSL_CLIENT_CERT, realmstring, ras->callbacks->auth_baton, pool); } else { error = svn_auth_next_credentials(&creds, state, pool); } if (error || ! creds) { /* Failure or too many attempts */ svn_error_clear(error); break; } else { svn_auth_cred_ssl_client_cert_t *client_creds = creds; clicert = ne_ssl_clicert_read(client_creds->cert_file); if (clicert) { if (! ne_ssl_clicert_encrypted(clicert) || client_ssl_decrypt_cert(ras, client_creds->cert_file, clicert)) { ne_ssl_set_clicert(sess, clicert); } break; } } } apr_pool_destroy(pool);}/* Set *PROXY_HOST, *PROXY_PORT, *PROXY_USERNAME, *PROXY_PASSWORD, * *TIMEOUT_SECONDS and *NEON_DEBUG to the information for REQUESTED_HOST, * allocated in POOL, if there is any applicable information. If there is * no applicable information or if there is an error, then set *PROXY_PORT * to (unsigned int) -1, *TIMEOUT_SECONDS and *NEON_DEBUG to zero, and the * rest to NULL. This function can return an error, so before checking any * values, check the error return value. */static svn_error_t *get_server_settings(const char **proxy_host, unsigned int *proxy_port, const char **proxy_username, const char **proxy_password, int *timeout_seconds, int *neon_debug, svn_boolean_t *compression, svn_config_t *cfg, const char *requested_host, apr_pool_t *pool){ const char *exceptions, *port_str, *timeout_str, *server_group; const char *debug_str; svn_boolean_t is_exception = FALSE; /* If we find nothing, default to nulls. */ *proxy_host = NULL; *proxy_port = (unsigned int) -1; *proxy_username = NULL; *proxy_password = NULL; port_str = NULL; timeout_str = NULL; debug_str = NULL; /* If there are defaults, use them, but only if the requested host is not one of the exceptions to the defaults. */ svn_config_get(cfg, &exceptions, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, NULL); if (exceptions) { apr_array_header_t *l = svn_cstring_split(exceptions, ",", TRUE, pool); is_exception = svn_cstring_match_glob_list(requested_host, l); } if (! is_exception) { svn_config_get(cfg, proxy_host, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL); svn_config_get(cfg, &port_str, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL); svn_config_get(cfg, proxy_username, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL); svn_config_get(cfg, proxy_password, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL); svn_config_get(cfg, &timeout_str, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_TIMEOUT, NULL); SVN_ERR(svn_config_get_bool(cfg, compression, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_HTTP_COMPRESSION, TRUE)); svn_config_get(cfg, &debug_str, SVN_CONFIG_SECTION_GLOBAL, SVN_CONFIG_OPTION_NEON_DEBUG_MASK, NULL); } if (cfg) server_group = svn_config_find_group(cfg, requested_host, SVN_CONFIG_SECTION_GROUPS, pool);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -