📄 mod_authz_svn.c
字号:
/* * mod_authz_svn.c: an Apache mod_dav_svn sub-module to provide path * based authorization for a Subversion repository. * * ==================================================================== * Copyright (c) 2003-2005 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 <httpd.h>#include <http_config.h>#include <http_core.h>#include <http_request.h>#include <http_protocol.h>#include <http_log.h>#include <ap_config.h>#include <apr_uri.h>#include <mod_dav.h>#if AP_MODULE_MAGIC_AT_LEAST(20060110,0)#include <mod_auth.h>extern APR_OPTIONAL_FN_TYPE(ap_satisfies) *ap_satisfies;#endif#include "mod_dav_svn.h"#include "svn_path.h"#include "svn_config.h"#include "svn_string.h"#include "svn_repos.h"extern module AP_MODULE_DECLARE_DATA authz_svn_module;typedef struct { int authoritative; int anonymous; int no_auth_when_anon_ok; const char *base_path; const char *access_file;} authz_svn_config_rec;/* * Configuration */static void *create_authz_svn_dir_config(apr_pool_t *p, char *d){ authz_svn_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); conf->base_path = d; /* By default keep the fortress secure */ conf->authoritative = 1; conf->anonymous = 1; return conf;}static const command_rec authz_svn_cmds[] ={ AP_INIT_FLAG("AuthzSVNAuthoritative", ap_set_flag_slot, (void *)APR_OFFSETOF(authz_svn_config_rec, authoritative), OR_AUTHCFG, "Set to 'Off' to allow access control to be passed along to " "lower modules. (default is On.)"), AP_INIT_TAKE1("AuthzSVNAccessFile", ap_set_file_slot, (void *)APR_OFFSETOF(authz_svn_config_rec, access_file), OR_AUTHCFG, "Text file containing permissions of repository paths."), AP_INIT_FLAG("AuthzSVNAnonymous", ap_set_flag_slot, (void *)APR_OFFSETOF(authz_svn_config_rec, anonymous), OR_AUTHCFG, "Set to 'Off' to disable two special-case behaviours of " "this module: (1) interaction with the 'Satisfy Any' " "directive, and (2) enforcement of the authorization " "policy even when no 'Require' directives are present. " "(default is On.)"), AP_INIT_FLAG("AuthzSVNNoAuthWhenAnonymousAllowed", ap_set_flag_slot, (void *)APR_OFFSETOF(authz_svn_config_rec, no_auth_when_anon_ok), OR_AUTHCFG, "Set to 'On' to suppress authentication and authorization " "for requests which anonymous users are allowed to perform. " "(default is Off.)"), { NULL }};/* Check if the current request R is allowed. Upon exit *REPOS_PATH_REF * will contain the path and repository name that an operation was requested * on in the form 'name:path'. *DEST_REPOS_PATH_REF will contain the * destination path if the requested operation was a MOVE or a COPY. * Returns OK when access is allowed, DECLINED when it isn't, or an HTTP_ * error code when an error occurred. */static int req_check_access(request_rec *r, authz_svn_config_rec *conf, const char **repos_path_ref, const char **dest_repos_path_ref){ const char *dest_uri; apr_uri_t parsed_dest_uri; const char *cleaned_uri; int trailing_slash; const char *repos_name; const char *dest_repos_name; const char *relative_path; const char *repos_path; const char *dest_repos_path = NULL; dav_error *dav_err; svn_repos_authz_access_t authz_svn_type = svn_authz_none; svn_boolean_t authz_access_granted = FALSE; svn_authz_t *access_conf = NULL; svn_error_t *svn_err; const char *cache_key; void *user_data; char errbuf[256]; switch (r->method_number) { /* All methods requiring read access to all subtrees of r->uri */ case M_COPY: authz_svn_type |= svn_authz_recursive; /* All methods requiring read access to r->uri */ case M_OPTIONS: case M_GET: case M_PROPFIND: case M_REPORT: authz_svn_type |= svn_authz_read; break; /* All methods requiring write access to all subtrees of r->uri */ case M_MOVE: case M_DELETE: authz_svn_type |= svn_authz_recursive; /* All methods requiring write access to r->uri */ case M_MKCOL: case M_PUT: case M_PROPPATCH: case M_CHECKOUT: case M_MERGE: case M_MKACTIVITY: case M_LOCK: case M_UNLOCK: authz_svn_type |= svn_authz_write; break; default: /* Require most strict access for unknown methods */ authz_svn_type |= svn_authz_write | svn_authz_recursive; break; } dav_err = dav_svn_split_uri(r, r->uri, conf->base_path, &cleaned_uri, &trailing_slash, &repos_name, &relative_path, &repos_path); if (dav_err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s [%d, #%d]", dav_err->desc, dav_err->status, dav_err->error_id); /* Ensure that we never allow access by dav_err->status */ return (dav_err->status != OK && dav_err->status != DECLINED) ? dav_err->status : HTTP_INTERNAL_SERVER_ERROR; } /* Ignore the URI passed to MERGE, like mod_dav_svn does. * See issue #1821. * XXX: When we start accepting a broader range of DeltaV MERGE * XXX: requests, this should be revisited. */ if (r->method_number == M_MERGE) { repos_path = NULL; } if (repos_path) repos_path = svn_path_join("/", repos_path, r->pool); *repos_path_ref = apr_pstrcat(r->pool, repos_name, ":", repos_path, NULL); if (r->method_number == M_MOVE || r->method_number == M_COPY) { dest_uri = apr_table_get(r->headers_in, "Destination"); /* Decline MOVE or COPY when there is no Destination uri, this will * cause failure. */ if (!dest_uri) return DECLINED; apr_uri_parse(r->pool, dest_uri, &parsed_dest_uri); ap_unescape_url(parsed_dest_uri.path); dest_uri = parsed_dest_uri.path; if (strncmp(dest_uri, conf->base_path, strlen(conf->base_path))) { /* If it is not the same location, then we don't allow it. * XXX: Instead we could compare repository uuids, but that * XXX: seems a bit over the top. */ return HTTP_BAD_REQUEST; } dav_err = dav_svn_split_uri(r, dest_uri, conf->base_path, &cleaned_uri, &trailing_slash, &dest_repos_name, &relative_path, &dest_repos_path); if (dav_err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s [%d, #%d]", dav_err->desc, dav_err->status, dav_err->error_id); /* Ensure that we never allow access by dav_err->status */ return (dav_err->status != OK && dav_err->status != DECLINED) ? dav_err->status : HTTP_INTERNAL_SERVER_ERROR; } if (dest_repos_path) dest_repos_path = svn_path_join("/", dest_repos_path, r->pool); *dest_repos_path_ref = apr_pstrcat(r->pool, dest_repos_name, ":", dest_repos_path, NULL); } /* Retrieve/cache authorization file */ cache_key = apr_pstrcat(r->pool, "mod_authz_svn:", conf->access_file, NULL); apr_pool_userdata_get(&user_data, cache_key, r->connection->pool); access_conf = user_data; if (access_conf == NULL) { svn_err = svn_repos_authz_read(&access_conf, conf->access_file, TRUE, r->connection->pool); if (svn_err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, /* If it is an error code that APR can make sense of, then show it, otherwise, pass zero to avoid putting "APR does not understand this error code" in the error log. */ ((svn_err->apr_err >= APR_OS_START_USERERR && svn_err->apr_err < APR_OS_START_CANONERR) ? 0 : svn_err->apr_err), r, "Failed to load the AuthzSVNAccessFile: %s", svn_err_best_message(svn_err, errbuf, sizeof(errbuf))); svn_error_clear(svn_err); return DECLINED; } /* Cache the open repos for the next request on this connection */ apr_pool_userdata_set(access_conf, cache_key, NULL, r->connection->pool); } /* Perform authz access control. * * First test the special case where repos_path == NULL, and skip * calling the authz routines in that case. This is an oddity of * the DAV RA method: some requests have no repos_path, but apache * still triggers an authz lookup for the URI. * * However, if repos_path == NULL and the request requires write * access, then perform a global authz lookup. The request is * denied if the user commiting isn't granted any access anywhere
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -