| /* authz_info.c : Information derived from authz settings. |
| * |
| * ==================================================================== |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * ==================================================================== |
| */ |
| |
| #include <apr_hash.h> |
| #include <apr_pools.h> |
| #include <apr_tables.h> |
| |
| #include "svn_hash.h" |
| |
| #include "svn_private_config.h" |
| |
| #include "authz.h" |
| |
| |
| svn_boolean_t |
| svn_authz__acl_applies_to_repo(const authz_acl_t *acl, |
| const char *repos) |
| { |
| /* The repository name must match the one in the rule, iff the rule |
| was defined for a specific repository. */ |
| return (0 == strcmp(acl->rule.repos, AUTHZ_ANY_REPOSITORY)) |
| || (0 == strcmp(repos, acl->rule.repos)); |
| } |
| |
| svn_boolean_t |
| svn_authz__get_acl_access(authz_access_t *access_p, |
| const authz_acl_t *acl, |
| const char *user, const char *repos) |
| { |
| authz_access_t access; |
| svn_boolean_t has_access; |
| int i; |
| |
| /* The repository name must match the one in the rule, iff the rule |
| was defined for a specific repository. */ |
| if (!svn_authz__acl_applies_to_repo(acl, repos)) |
| return FALSE; |
| |
| /* Check anonymous access first. */ |
| if (!user || 0 == strcmp(user, AUTHZ_ANONYMOUS_USER)) |
| { |
| if (!acl->has_anon_access) |
| return FALSE; |
| |
| if (access_p) |
| *access_p = acl->anon_access; |
| return TRUE; |
| } |
| |
| /* Get the access rights for all authenticated users. */ |
| has_access = acl->has_authn_access; |
| access = (has_access ? acl->authn_access : authz_access_none); |
| |
| /* Scan the ACEs in the ACL and merge the access rights. */ |
| for (i = 0; i < acl->user_access->nelts; ++i) |
| { |
| const authz_ace_t *const ace = |
| &APR_ARRAY_IDX(acl->user_access, i, authz_ace_t); |
| const svn_boolean_t match = |
| ((ace->members && svn_hash_gets(ace->members, user)) |
| || (!ace->members && 0 == strcmp(user, ace->name))); |
| |
| if (!match != !ace->inverted) /* match XNOR ace->inverted */ |
| { |
| access |= ace->access; |
| has_access = TRUE; |
| } |
| } |
| |
| if (access_p) |
| *access_p = access; |
| return has_access; |
| } |
| |
| /* Set *RIGHTS_P to the combination of LHS and RHS, i.e. intersect the |
| * minimal rights and join the maximum rights. |
| */ |
| static void |
| combine_rights(authz_rights_t *rights_p, |
| const authz_rights_t *lhs, |
| const authz_rights_t *rhs) |
| { |
| rights_p->min_access = lhs->min_access & rhs->min_access; |
| rights_p->max_access = lhs->max_access | rhs->max_access; |
| } |
| |
| |
| /* Given GLOBAL_RIGHTS and a repository name REPOS, set *RIGHTS_P to |
| * to the actual accumulated rights defined for that repository. |
| * Return TRUE if these rights were defined explicitly. |
| */ |
| static svn_boolean_t |
| resolve_global_rights(authz_rights_t *rights_p, |
| const authz_global_rights_t *global_rights, |
| const char *repos) |
| { |
| if (0 == strcmp(repos, AUTHZ_ANY_REPOSITORY)) |
| { |
| /* Return the accumulated rights that are not repository-specific. */ |
| *rights_p = global_rights->any_repos_rights; |
| return TRUE; |
| } |
| else |
| { |
| /* Check if we have explicit rights for this repository. */ |
| const authz_rights_t *const rights = |
| svn_hash_gets(global_rights->per_repos_rights, repos); |
| |
| if (rights) |
| { |
| combine_rights(rights_p, rights, &global_rights->any_repos_rights); |
| return TRUE; |
| } |
| } |
| |
| /* Fall-through: return the rights defined for "any" repository |
| because this user has no specific rules for this specific REPOS. */ |
| *rights_p = global_rights->any_repos_rights; |
| return FALSE; |
| } |
| |
| |
| svn_boolean_t |
| svn_authz__get_global_rights(authz_rights_t *rights_p, |
| const authz_full_t *authz, |
| const char *user, const char *repos) |
| { |
| if (!user || 0 == strcmp(user, AUTHZ_ANONYMOUS_USER)) |
| { |
| /* Check if we have explicit rights for anonymous access. */ |
| if (authz->has_anon_rights) |
| { |
| return resolve_global_rights(rights_p, &authz->anon_rights, repos); |
| } |
| else |
| { |
| /* Return the implicit rights, i.e., none. */ |
| rights_p->min_access = authz_access_none; |
| rights_p->max_access = authz_access_none; |
| return FALSE; |
| } |
| } |
| else |
| { |
| svn_boolean_t combine_user_rights = FALSE; |
| svn_boolean_t access = FALSE; |
| |
| /* Check if we have explicit rights for this user. */ |
| const authz_global_rights_t *const user_rights = |
| svn_hash_gets(authz->user_rights, user); |
| |
| if (user_rights) |
| { |
| access = resolve_global_rights(rights_p, user_rights, repos); |
| combine_user_rights = TRUE; |
| } |
| else if (authz->has_neg_rights) |
| { |
| /* Check if inverted-rule rights apply */ |
| access = resolve_global_rights(rights_p, &authz->neg_rights, repos); |
| combine_user_rights = TRUE; |
| } |
| |
| /* Rights given to _any_ authenticated user may apply, too. */ |
| if (authz->has_authn_rights) |
| { |
| authz_rights_t authn; |
| access |= resolve_global_rights(&authn, &authz->authn_rights, repos); |
| |
| if (combine_user_rights) |
| combine_rights(rights_p, rights_p, &authn); |
| else |
| *rights_p = authn; |
| } |
| |
| return access; |
| } |
| } |