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 
34 svn_boolean_t
svn_authz__acl_applies_to_repo(const authz_acl_t * acl,const char * repos)35 svn_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 
44 svn_boolean_t
svn_authz__get_acl_access(authz_access_t * access_p,const authz_acl_t * acl,const char * user,const char * repos)45 svn_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  */
97 static void
combine_rights(authz_rights_t * rights_p,const authz_rights_t * lhs,const authz_rights_t * rhs)98 combine_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  */
111 static svn_boolean_t
resolve_global_rights(authz_rights_t * rights_p,const authz_global_rights_t * global_rights,const char * repos)112 resolve_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 
142 svn_boolean_t
svn_authz__get_global_rights(authz_rights_t * rights_p,const authz_full_t * authz,const char * user,const char * repos)143 svn_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