1/* authz_info.c : Information derived from authz settings. 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 */ 22 23#include <apr_hash.h> 24#include <apr_pools.h> 25#include <apr_tables.h> 26 27#include "svn_hash.h" 28 29#include "svn_private_config.h" 30 31#include "authz.h" 32 33 34svn_boolean_t 35svn_authz__acl_applies_to_repo(const authz_acl_t *acl, 36 const char *repos) 37{ 38 /* The repository name must match the one in the rule, iff the rule 39 was defined for a specific repository. */ 40 return (0 == strcmp(acl->rule.repos, AUTHZ_ANY_REPOSITORY)) 41 || (0 == strcmp(repos, acl->rule.repos)); 42} 43 44svn_boolean_t 45svn_authz__get_acl_access(authz_access_t *access_p, 46 const authz_acl_t *acl, 47 const char *user, const char *repos) 48{ 49 authz_access_t access; 50 svn_boolean_t has_access; 51 int i; 52 53 /* The repository name must match the one in the rule, iff the rule 54 was defined for a specific repository. */ 55 if (!svn_authz__acl_applies_to_repo(acl, repos)) 56 return FALSE; 57 58 /* Check anonymous access first. */ 59 if (!user || 0 == strcmp(user, AUTHZ_ANONYMOUS_USER)) 60 { 61 if (!acl->has_anon_access) 62 return FALSE; 63 64 if (access_p) 65 *access_p = acl->anon_access; 66 return TRUE; 67 } 68 69 /* Get the access rights for all authenticated users. */ 70 has_access = acl->has_authn_access; 71 access = (has_access ? acl->authn_access : authz_access_none); 72 73 /* Scan the ACEs in the ACL and merge the access rights. */ 74 for (i = 0; i < acl->user_access->nelts; ++i) 75 { 76 const authz_ace_t *const ace = 77 &APR_ARRAY_IDX(acl->user_access, i, authz_ace_t); 78 const svn_boolean_t match = 79 ((ace->members && svn_hash_gets(ace->members, user)) 80 || (!ace->members && 0 == strcmp(user, ace->name))); 81 82 if (!match != !ace->inverted) /* match XNOR ace->inverted */ 83 { 84 access |= ace->access; 85 has_access = TRUE; 86 } 87 } 88 89 if (access_p) 90 *access_p = access; 91 return has_access; 92} 93 94/* Set *RIGHTS_P to the combination of LHS and RHS, i.e. intersect the 95 * minimal rights and join the maximum rights. 96 */ 97static void 98combine_rights(authz_rights_t *rights_p, 99 const authz_rights_t *lhs, 100 const authz_rights_t *rhs) 101{ 102 rights_p->min_access = lhs->min_access & rhs->min_access; 103 rights_p->max_access = lhs->max_access | rhs->max_access; 104} 105 106 107/* Given GLOBAL_RIGHTS and a repository name REPOS, set *RIGHTS_P to 108 * to the actual accumulated rights defined for that repository. 109 * Return TRUE if these rights were defined explicitly. 110 */ 111static svn_boolean_t 112resolve_global_rights(authz_rights_t *rights_p, 113 const authz_global_rights_t *global_rights, 114 const char *repos) 115{ 116 if (0 == strcmp(repos, AUTHZ_ANY_REPOSITORY)) 117 { 118 /* Return the accumulated rights that are not repository-specific. */ 119 *rights_p = global_rights->any_repos_rights; 120 return TRUE; 121 } 122 else 123 { 124 /* Check if we have explicit rights for this repository. */ 125 const authz_rights_t *const rights = 126 svn_hash_gets(global_rights->per_repos_rights, repos); 127 128 if (rights) 129 { 130 combine_rights(rights_p, rights, &global_rights->any_repos_rights); 131 return TRUE; 132 } 133 } 134 135 /* Fall-through: return the rights defined for "any" repository 136 because this user has no specific rules for this specific REPOS. */ 137 *rights_p = global_rights->any_repos_rights; 138 return FALSE; 139} 140 141 142svn_boolean_t 143svn_authz__get_global_rights(authz_rights_t *rights_p, 144 const authz_full_t *authz, 145 const char *user, const char *repos) 146{ 147 if (!user || 0 == strcmp(user, AUTHZ_ANONYMOUS_USER)) 148 { 149 /* Check if we have explicit rights for anonymous access. */ 150 if (authz->has_anon_rights) 151 { 152 return resolve_global_rights(rights_p, &authz->anon_rights, repos); 153 } 154 else 155 { 156 /* Return the implicit rights, i.e., none. */ 157 rights_p->min_access = authz_access_none; 158 rights_p->max_access = authz_access_none; 159 return FALSE; 160 } 161 } 162 else 163 { 164 svn_boolean_t combine_user_rights = FALSE; 165 svn_boolean_t access = FALSE; 166 167 /* Check if we have explicit rights for this user. */ 168 const authz_global_rights_t *const user_rights = 169 svn_hash_gets(authz->user_rights, user); 170 171 if (user_rights) 172 { 173 access = resolve_global_rights(rights_p, user_rights, repos); 174 combine_user_rights = TRUE; 175 } 176 else if (authz->has_neg_rights) 177 { 178 /* Check if inverted-rule rights apply */ 179 access = resolve_global_rights(rights_p, &authz->neg_rights, repos); 180 combine_user_rights = TRUE; 181 } 182 183 /* Rights given to _any_ authenticated user may apply, too. */ 184 if (authz->has_authn_rights) 185 { 186 authz_rights_t authn; 187 access |= resolve_global_rights(&authn, &authz->authn_rights, repos); 188 189 if (combine_user_rights) 190 combine_rights(rights_p, rights_p, &authn); 191 else 192 *rights_p = authn; 193 } 194 195 return access; 196 } 197} 198