📄 mod_authz_svn.c
字号:
svn_error_t *svn_err;
const char *cache_key;
void *user_data;
switch (r->method_number) {
/* All methods requiring read access to all subtrees of r->uri */
case M_COPY:
authz_svn_type |= AUTHZ_SVN_RECURSIVE;
/* All methods requiring read access to r->uri */
case M_OPTIONS:
case M_GET:
case M_PROPFIND:
case M_REPORT:
authz_svn_type |= AUTHZ_SVN_READ;
break;
/* All methods requiring write access to all subtrees of r->uri */
case M_MOVE:
case M_DELETE:
authz_svn_type |= AUTHZ_SVN_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:
authz_svn_type |= AUTHZ_SVN_WRITE;
break;
default:
/* Require most strict access for unknown methods */
authz_svn_type |= AUTHZ_SVN_WRITE|AUTHZ_SVN_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);
dest_uri = parsed_dest_uri.path;
ap_unescape_url((char *)dest_uri);
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_config_read(&access_conf, conf->access_file, FALSE,
r->connection->pool);
if (svn_err) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, svn_err->apr_err, r,
"%s", svn_err->message);
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);
}
if (!check_access(access_conf,
repos_name, repos_path,
r->user, authz_svn_type,
r->pool)) {
return DECLINED;
}
/* XXX: MKCOL, MOVE, DELETE
* XXX: Require write access to the parent dir of repos_path.
*/
/* XXX: PUT
* XXX: If the path doesn't exist, require write access to the
* XXX: parent dir of repos_path.
*/
/* Only MOVE and COPY have a second uri we have to check access to. */
if (r->method_number != M_MOVE
&& r->method_number != M_COPY) {
return OK;
}
/* Check access on the first repos_path */
if (!check_access(access_conf,
dest_repos_name, dest_repos_path,
r->user, AUTHZ_SVN_WRITE|AUTHZ_SVN_RECURSIVE,
r->pool)) {
return DECLINED;
}
/* XXX: MOVE and COPY, if the path doesn't exist yet, also
* XXX: require write access to the parent dir of dest_repos_path.
*/
return OK;
}
/*
* Hooks
*/
static int access_checker(request_rec *r)
{
authz_svn_config_rec *conf = ap_get_module_config(r->per_dir_config,
&authz_svn_module);
const char *repos_path;
const char *dest_repos_path = NULL;
int status;
/* We are not configured to run */
if (!conf->anonymous || !conf->access_file)
return DECLINED;
if (ap_some_auth_required(r)) {
/* It makes no sense to check if a location is both accessible
* anonymous and by an authenticated user (in the same request!).
*/
if (ap_satisfies(r) != SATISFY_ANY)
return DECLINED;
/* If the user is trying to authenticate, let him. If anonymous
* access is allowed, so is authenticated access, by definition
* of the meaning of '*' in the access file.
*/
if (apr_table_get(r->headers_in,
(PROXYREQ_PROXY == r->proxyreq)
? "Proxy-Authorization" : "Authorization")) {
/* Given Satisfy Any is in effect, we have to forbid access
* to let the auth_checker hook have a go at it.
*/
return HTTP_FORBIDDEN;
}
}
/* If anon access is allowed, return OK */
status = req_check_access(r, conf, &repos_path, &dest_repos_path);
if (status == DECLINED) {
if (!conf->authoritative)
return DECLINED;
if (!ap_some_auth_required(r)) {
if (dest_repos_path) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Access denied: - %s %s %s",
r->method, repos_path, dest_repos_path);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Access denied: - %s %s",
r->method, repos_path);
}
}
return HTTP_FORBIDDEN;
}
if (status != OK)
return status;
if (dest_repos_path) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"Access granted: - %s %s %s",
r->method, repos_path, dest_repos_path);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"Access granted: - %s %s",
r->method, repos_path);
}
return OK;
}
static int auth_checker(request_rec *r)
{
authz_svn_config_rec *conf = ap_get_module_config(r->per_dir_config,
&authz_svn_module);
const char *repos_path;
const char *dest_repos_path = NULL;
int status;
/* We are not configured to run */
if (!conf->access_file)
return DECLINED;
status = req_check_access(r, conf, &repos_path, &dest_repos_path);
if (status == DECLINED) {
if (conf->authoritative) {
if (dest_repos_path) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Access denied: '%s' %s %s %s",
r->user, r->method, repos_path, dest_repos_path);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Access denied: '%s' %s %s",
r->user, r->method, repos_path);
}
ap_note_auth_failure(r);
return HTTP_UNAUTHORIZED;
}
return DECLINED;
}
if (status != OK)
return status;
if (dest_repos_path) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"Access granted: '%s' %s %s %s",
r->user, r->method, repos_path, dest_repos_path);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"Access granted: '%s' %s %s",
r->user, r->method, repos_path);
}
return OK;
}
/*
* Module flesh
*/
static void register_hooks(apr_pool_t *p)
{
ap_hook_access_checker(access_checker, NULL, NULL, APR_HOOK_LAST);
ap_hook_auth_checker(auth_checker, NULL, NULL, APR_HOOK_FIRST);
}
module AP_MODULE_DECLARE_DATA authz_svn_module =
{
STANDARD20_MODULE_STUFF,
create_authz_svn_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
authz_svn_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -