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