Thu, 09 May 2013 19:41:11 +0200
added keyfile based authentication
51 | 1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
3 | * | |
4 | * Copyright 2013 Olaf Wintermann. All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | |
28 | ||
29 | #include <stdio.h> | |
30 | #include <stdlib.h> | |
31 | ||
32 | #include "../util/pool.h" | |
33 | #include "../safs/auth.h" | |
34 | #include "acl.h" | |
35 | ||
36 | void acllist_createhandle(Session *sn, Request *rq) { | |
37 | ACLListHandle *handle = pool_malloc(sn->pool, sizeof(ACLListHandle)); | |
38 | handle->defaultauthdb = NULL; | |
39 | handle->listhead = NULL; | |
40 | handle->listtail = NULL; | |
41 | rq->acllist = handle; | |
42 | } | |
43 | ||
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
44 | /* |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
45 | * append or prepend an ACL |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
46 | */ |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
47 | void acllist_add(Session *sn, Request *rq, ACLList *acl, int append) { |
51 | 48 | if(!rq->acllist) { |
49 | acllist_createhandle(sn, rq); | |
50 | } | |
51 | ACLListHandle *list = rq->acllist; | |
52 | ||
53 | if(!list->defaultauthdb && acl->authdb) { | |
54 | list->defaultauthdb = acl->authdb; | |
55 | } | |
56 | ||
57 | ACLListElm *elm = pool_malloc(sn->pool, sizeof(ACLListElm)); | |
58 | elm->acl = acl; | |
59 | elm->next = NULL; | |
60 | if(list->listhead == NULL) { | |
61 | list->listhead = elm; | |
62 | list->listtail = elm; | |
63 | } else { | |
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
64 | if(append) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
65 | list->listtail->next = elm; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
66 | list->listtail = elm; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
67 | } else { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
68 | elm->next = list->listhead; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
69 | list->listhead = elm; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
70 | } |
51 | 71 | } |
72 | } | |
73 | ||
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
74 | void acllist_append(Session *sn, Request *rq, ACLList *acl) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
75 | acllist_add(sn, rq, acl, 1); |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
76 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
77 | |
51 | 78 | void acllist_prepend(Session *sn, Request *rq, ACLList *acl) { |
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
79 | acllist_add(sn, rq, acl, 0); |
51 | 80 | } |
81 | ||
54 | 82 | uint32_t acl_oflag2mask(int oflags) { |
83 | /* TODO: | |
84 | * maybe there is a plattform where O_RDWR is not O_RDONLY | O_WRONLY | |
85 | */ | |
86 | uint32_t access_mask = 0; | |
87 | if((oflags & O_RDONLY) == O_RDONLY) { | |
88 | access_mask |= ACL_READ_DATA; | |
89 | } | |
90 | if((oflags & O_WRONLY) == O_WRONLY) { | |
91 | access_mask |= ACL_WRITE_DATA; | |
92 | } | |
93 | return access_mask; | |
94 | } | |
51 | 95 | |
54 | 96 | User* acllist_getuser(Session *sn, Request *rq, ACLListHandle *list) { |
97 | if(!sn || !rq || !list) { | |
98 | return NULL; | |
51 | 99 | } |
100 | ||
101 | // get user | |
102 | User *user = NULL; | |
103 | if(list->defaultauthdb) { | |
104 | char *usr; | |
105 | char *pw; | |
106 | if(!basicauth_getuser(sn, rq, &usr, &pw)) { | |
107 | user = list->defaultauthdb->get_user(list->defaultauthdb, usr); | |
108 | if(!user) { | |
109 | // wrong user name | |
54 | 110 | return NULL; |
51 | 111 | } |
112 | if(!user->verify_password(user, pw)) { | |
113 | // wrong password | |
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
114 | user->free(user); |
54 | 115 | return NULL; |
51 | 116 | } |
117 | // ok - user is authenticated | |
118 | } | |
54 | 119 | } |
120 | ||
121 | return user; | |
122 | } | |
123 | ||
124 | void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user) { | |
125 | if(!user) { | |
126 | char *value = NULL; | |
127 | if(acl->authprompt) { | |
128 | size_t realmlen = strlen(acl->authprompt); | |
129 | size_t len = realmlen + 16; | |
130 | value = pool_malloc(sn->pool, len); | |
131 | if(value) { | |
132 | snprintf( | |
133 | value, | |
134 | len, | |
135 | "Basic realm=\"%s\"", | |
136 | acl->authprompt); | |
137 | } | |
138 | } | |
139 | if(!value) { | |
140 | value = "Basic realm=\"login\""; | |
141 | } | |
142 | pblock_nvinsert("www-authenticate", value, rq->srvhdrs); | |
143 | protocol_status(sn, rq, PROTOCOL_UNAUTHORIZED, NULL); | |
51 | 144 | } else { |
54 | 145 | protocol_status(sn, rq, PROTOCOL_FORBIDDEN, NULL); |
146 | } | |
147 | } | |
148 | ||
149 | int acl_evaluate(Session *sn, Request *rq, int access_mask) { | |
150 | ACLListHandle *list = rq->acllist; | |
151 | if(!list) { | |
152 | return REQ_PROCEED; | |
153 | } | |
154 | ||
155 | // we combine access_mask with the required access rights | |
156 | access_mask |= rq->aclreqaccess; | |
157 | ||
158 | // get user | |
159 | User *user = acllist_getuser(sn, rq, list); | |
160 | ||
161 | // evalutate all ACLs | |
162 | ACLList *acl = acl_evallist(list, user, access_mask); | |
163 | if(acl) { | |
164 | acl_set_error_status(sn, rq, acl, user); | |
165 | // TODO: don't free the user here | |
166 | if(user) { | |
167 | user->free(user); | |
168 | } | |
51 | 169 | return REQ_ABORTED; |
170 | } | |
171 | ||
54 | 172 | // access allowed, we can free the user |
173 | if(user) { | |
174 | user->free(user); | |
175 | } | |
176 | ||
177 | return REQ_PROCEED; | |
178 | } | |
179 | ||
180 | ACLList* acl_evallist(ACLListHandle *list, User *user, int access_mask) { | |
181 | if(!list) { | |
182 | return NULL; | |
183 | } | |
184 | ||
51 | 185 | // evaluate each acl until one denies access |
186 | ACLListElm *elm = list->listhead; | |
187 | while(elm) { | |
188 | ACLList *acl = elm->acl; | |
54 | 189 | if(!acl->check(acl, user, access_mask)) { |
51 | 190 | // the acl denies access |
54 | 191 | return acl; |
51 | 192 | } |
193 | elm = elm->next; | |
194 | } | |
195 | ||
196 | // ok - all acls allowed access | |
54 | 197 | |
198 | return NULL; | |
51 | 199 | } |
200 | ||
54 | 201 | int wsacl_affects_user(WSAce *ace, User *user) { |
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
202 | int check_access = 0; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
203 | |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
204 | /* |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
205 | * an ace can affect |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
206 | * a named user or group (ace->who is set) |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
207 | * the owner of the resource (ACL_OWNER is set) |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
208 | * the owning group of the resource (ACL_GROUP is set) |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
209 | * everyone (ACL_EVERYONE is set) |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
210 | * |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
211 | * Only one of this conditions should be true. The behavior on |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
212 | * illegal flag combination is undefined. We assume that the acls |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
213 | * are created correctly by the configuration loader. |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
214 | */ |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
215 | |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
216 | if(ace->who && user) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
217 | // this ace is defined for a named user or group |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
218 | if((ace->flags & ACL_IDENTIFIER_GROUP) == ACL_IDENTIFIER_GROUP) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
219 | if(user->check_group(user, ace->who)) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
220 | // the user is in the group |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
221 | check_access = 1; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
222 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
223 | } else { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
224 | if(!strcmp(user->name, ace->who)) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
225 | check_access = 1; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
226 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
227 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
228 | } else if((ace->flags & ACL_OWNER) == ACL_OWNER) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
229 | // TODO |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
230 | } else if((ace->flags & ACL_GROUP) == ACL_GROUP) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
231 | // TODO |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
232 | } else if((ace->flags & ACL_EVERYONE) == ACL_EVERYONE) { |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
233 | check_access = 1; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
234 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
235 | |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
236 | return check_access; |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
237 | } |
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
238 | |
54 | 239 | int wsacl_check(WSAcl *acl, User *user, int access_mask) { |
51 | 240 | int allow = 0; |
241 | uint32_t allowed_access = 0; | |
242 | // check each access control entry | |
243 | for(int i=0;i<acl->acenum;i++) { | |
54 | 244 | WSAce *ace = acl->ace[i]; |
52
aced2245fb1c
new pathcheck saf and code cleanup
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
51
diff
changeset
|
245 | if(wsacl_affects_user(ace, user)) { |
51 | 246 | if(ace->type == ACL_TYPE_ALLOWED) { |
247 | // add all new access rights | |
54 | 248 | allowed_access |= (access_mask & ace->access_mask); |
51 | 249 | // check if we have all requested rights |
250 | if((allowed_access & access_mask) == access_mask) { | |
251 | allow = 1; | |
252 | break; | |
253 | } | |
254 | } else { | |
255 | // ACL_TYPE_DENIED | |
256 | ||
257 | if((ace->access_mask & access_mask) != 0) { | |
258 | // access denied | |
259 | break; | |
260 | } | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | // TODO: events | |
266 | ||
54 | 267 | return allow; // allow is 0, if no ace set it to 1 |
51 | 268 | } |