1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32
33 #include "../util/util.h"
34 #include "../util/pool.h"
35 #include "../util/pblock.h"
36 #include "../safs/auth.h"
37 #include "log.h"
38 #include "acl.h"
39
40 #define AUTH_TYPE_BASIC "basic"
41
42 void acllist_createhandle(Session *sn, Request *rq) {
43 ACLListHandle *handle = pool_malloc(sn->pool,
sizeof(ACLListHandle));
44 handle->defaultauthdb =
NULL;
45 handle->listhead =
NULL;
46 handle->listtail =
NULL;
47 rq->acllist = handle;
48 }
49
50
51
52
53 void acllist_add(Session *sn, Request *rq, ACLList *acl,
int append) {
54 if(!rq->acllist) {
55 acllist_createhandle(sn, rq);
56 }
57 ACLListHandle *list = rq->acllist;
58
59 if(!list->defaultauthdb && acl->authdb) {
60 list->defaultauthdb = acl->authdb;
61 }
62
63 ACLListElm *elm = pool_malloc(sn->pool,
sizeof(ACLListElm));
64 elm->acl = acl;
65 elm->next =
NULL;
66 if(list->listhead ==
NULL) {
67 list->listhead = elm;
68 list->listtail = elm;
69 }
else {
70 if(append) {
71 list->listtail->next = elm;
72 list->listtail = elm;
73 }
else {
74 elm->next = list->listhead;
75 list->listhead = elm;
76 }
77 }
78 }
79
80 void acllist_append(Session *sn, Request *rq, ACLList *acl) {
81 acllist_add(sn, rq, acl,
1);
82 }
83
84 void acllist_prepend(Session *sn, Request *rq, ACLList *acl) {
85 acllist_add(sn, rq, acl,
0);
86 }
87
88 uint32_t acl_oflag2mask(
int oflags) {
89
90
91
92 uint32_t access_mask =
0;
93 if((oflags &
O_RDONLY) ==
O_RDONLY) {
94 access_mask |=
ACL_READ_DATA;
95 }
96 if((oflags &
O_WRONLY) ==
O_WRONLY) {
97 access_mask |=
ACL_WRITE_DATA;
98 }
99 return access_mask;
100 }
101
102 User* acllist_getuser(Session *sn, Request *rq, ACLListHandle *list) {
103 if(!sn || !rq || !list) {
104 return NULL;
105 }
106
107
108 User *user =
NULL;
109 if(list->defaultauthdb) {
110 char *usr;
111 char *pw;
112 if(!basicauth_getuser(sn, rq, &usr, &pw)) {
113 int pwok;
114 user = authdb_get_and_verify(list->defaultauthdb, usr, pw, &pwok);
115 if(!user) {
116
117 return NULL;
118 }
119
120 pblock_kvinsert(
121 pb_key_auth_user,
122 user->name,
123 strlen(user->name),
124 rq->vars);
125 pblock_kvinsert(
126 pb_key_auth_type,
127 AUTH_TYPE_BASIC,
128 sizeof(
AUTH_TYPE_BASIC)-
1,
129 rq->vars);
130 }
131 }
132
133 return user;
134 }
135
136 void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user) {
137 if(sn ==
NULL || rq ==
NULL) {
138 return;
139 }
140
141 if(!user) {
142 char *value =
NULL;
143 if(acl->authprompt) {
144 size_t realmlen = strlen(acl->authprompt);
145 size_t len = realmlen +
16;
146 value = pool_malloc(sn->pool, len);
147 if(value) {
148 snprintf(
149 value,
150 len,
151 "Basic realm=\"%s\"",
152 acl->authprompt);
153 }
154 }
155 if(!value) {
156 value =
"Basic realm=\"login\"";
157 }
158 pblock_nvinsert(
"www-authenticate", value, rq->srvhdrs);
159 protocol_status(sn, rq,
PROTOCOL_UNAUTHORIZED,
NULL);
160 }
else {
161 protocol_status(sn, rq,
PROTOCOL_FORBIDDEN,
NULL);
162 }
163 }
164
165 int acl_evaluate(Session *sn, Request *rq,
int access_mask) {
166 ACLListHandle *list = rq->acllist;
167 if(!list) {
168 return REQ_PROCEED;
169 }
170
171
172 access_mask |= rq->aclreqaccess;
173
174
175 User *user = acllist_getuser(sn, rq, list);
176
177
178 ACLList *acl = acl_evallist(list, user, access_mask,
NULL);
179 if(acl) {
180 acl_set_error_status(sn, rq, acl, user);
181
182 if(user) {
183 user->free(user);
184 }
185 return REQ_ABORTED;
186 }
187
188
189 if(user) {
190 user->free(user);
191 }
192
193 return REQ_PROCEED;
194 }
195
196 ACLList* acl_evallist(
197 ACLListHandle *list,
198 User *user,
199 int access_mask,
200 ACLList **externacl)
201 {
202 if(!list) {
203 return NULL;
204 }
205 if(externacl) {
206 *externacl =
NULL;
207 }
208
209
210 ACLListElm *elm = list->listhead;
211 while(elm) {
212 ACLList *acl = elm->acl;
213 if(acl->isextern) {
214
215 if(externacl && *externacl ==
NULL) {
216 *externacl = acl;
217 }
218 }
else if(!acl->check(acl, user, access_mask)) {
219
220 return acl;
221 }
222 elm = elm->next;
223 }
224
225
226
227 return NULL;
228 }
229
230 int wsacl_affects_user(WSAce *ace, User *user) {
231 int check_access =
0;
232
233
234
235
236
237
238
239
240
241
242
243
244
245 if(ace->who && user) {
246
247 if((ace->flags &
ACL_IDENTIFIER_GROUP) ==
ACL_IDENTIFIER_GROUP) {
248 if(user->check_group(user, ace->who)) {
249
250 check_access =
1;
251 }
252 }
else {
253 if(!strcmp(user->name, ace->who)) {
254 check_access =
1;
255 }
256 }
257 }
else if((ace->flags &
ACL_OWNER) ==
ACL_OWNER) {
258
259 }
else if((ace->flags &
ACL_GROUP) ==
ACL_GROUP) {
260
261 }
else if((ace->flags &
ACL_EVERYONE) ==
ACL_EVERYONE) {
262 check_access =
1;
263 }
264
265 return check_access;
266 }
267
268 int wsacl_check(WSAcl *acl, User *user,
int access_mask) {
269 int allow =
0;
270 uint32_t allowed_access =
0;
271
272 for(
int i=
0;i<acl->acenum;i++) {
273 WSAce *ace = acl->ace[i];
274 if(wsacl_affects_user(ace, user)) {
275 if(ace->type ==
ACL_TYPE_ALLOWED) {
276
277 allowed_access |= (access_mask & ace->access_mask);
278
279 if((allowed_access & access_mask) == access_mask) {
280 allow =
1;
281 break;
282 }
283 }
else {
284
285
286 if((ace->access_mask & access_mask) !=
0) {
287
288 break;
289 }
290 }
291 }
292 }
293
294
295
296 return allow;
297 }
298
299
300
301
302 #if defined (
__SVR4) && defined (__sun)
303
304 #include <sys/acl.h>
305
306 int solaris_acl_check(
307 char *path,
308 struct stat *s,
309 uint32_t mask,
310 uid_t uid,
311 gid_t gid);
312 int solaris_acl_affects_user(
313 ace_t *ace,
314 uid_t uid,
315 gid_t gid,
316 uid_t owner,
317 gid_t owninggroup);
318
319 int fs_acl_check(SysACL *acl, User *user,
char *path,
uint32_t access_mask) {
320 sstr_t p;
321 if(path[
0] !=
'/') {
322 size_t n =
128;
323 char *cwd = malloc(n);
324 while(!getcwd(cwd, n)) {
325 if(errno ==
ERANGE) {
326 n *=
2;
327 cwd = realloc(cwd, n);
328 }
else {
329 free(cwd);
330 return 0;
331 }
332 }
333 sstr_t wd = sstr(cwd);
334 sstr_t pp = sstr(path);
335
336 p = sstrcat(
3, wd, sstrn(
"/",
1), pp);
337 }
else {
338 p = sstrdup(sstr(path));
339 }
340 if(p.ptr[p.length-
1] ==
'/') {
341 p.ptr[p.length-
1] =
0;
342 p.length--;
343 }
344
345
346 struct passwd pw;
347 if(user) {
348 char *pwbuf = malloc(
DEF_PWBUF);
349 if(pwbuf ==
NULL) {
350 free(p.ptr);
351 return 0;
352 }
353 if(!util_getpwnam(user->name, &pw, pwbuf,
DEF_PWBUF)) {
354 free(pwbuf);
355 free(p.ptr);
356 return 0;
357 }
358 free(pwbuf);
359 acl->user_uid = pw.pw_uid;
360 acl->user_gid = pw.pw_gid;
361 }
else {
362 acl->user_uid = -
1;
363 acl->user_gid = -
1;
364 }
365
366
367 uint32_t mask =
0;
368 if((access_mask &
ACL_READ_DATA) ==
ACL_READ_DATA) {
369 mask |=
ACE_READ_DATA;
370 }
371 if((access_mask &
ACL_WRITE_DATA) ==
ACL_WRITE_DATA) {
372 mask |=
ACE_WRITE_DATA;
373 }
374 if((access_mask &
ACL_ADD_FILE) ==
ACL_ADD_FILE) {
375 mask |=
ACE_ADD_FILE;
376 }
377 if((access_mask &
ACL_READ_XATTR) ==
ACL_READ_XATTR) {
378 mask |=
ACE_READ_NAMED_ATTRS;
379 }
380 if((access_mask &
ACL_WRITE_XATTR) ==
ACL_WRITE_XATTR) {
381 mask |=
ACE_WRITE_NAMED_ATTRS;
382 }
383 if((access_mask &
ACL_EXECUTE) ==
ACL_EXECUTE) {
384 mask |=
ACE_EXECUTE;
385 }
386 if((access_mask &
ACL_DELETE) ==
ACL_DELETE) {
387 mask |=
ACE_DELETE_CHILD;
388 }
389 if((access_mask &
ACL_READ_ATTRIBUTES) ==
ACL_READ_ATTRIBUTES) {
390 mask |=
ACE_READ_ATTRIBUTES;
391 }
392 if((access_mask &
ACL_WRITE_ATTRIBUTES) ==
ACL_WRITE_ATTRIBUTES) {
393 mask |=
ACE_WRITE_ATTRIBUTES;
394 }
395 if((access_mask &
ACL_LIST) ==
ACL_LIST) {
396 mask |=
ACE_LIST_DIRECTORY;
397 }
398 if((access_mask &
ACL_READ_ACL) ==
ACL_READ_ACL) {
399 mask |=
ACE_READ_ACL;
400 }
401 if((access_mask &
ACL_WRITE_ACL) ==
ACL_WRITE_ACL) {
402 mask |=
ACE_WRITE_ACL;
403 }
404 if((access_mask &
ACL_WRITE_OWNER) ==
ACL_WRITE_OWNER) {
405 mask |=
ACE_WRITE_OWNER;
406 }
407 if((access_mask &
ACL_SYNCHRONIZE) ==
ACL_SYNCHRONIZE) {
408 mask |=
ACE_SYNCHRONIZE;
409 }
410
411
412
413
414
415
416 struct stat s;
417 if(stat(p.ptr, &s)) {
418 if(errno !=
ENOENT) {
419 perror(
"fs_acl_check: stat");
420 free(p.ptr);
421 return 0;
422 }
else {
423 mask =
ACE_ADD_FILE;
424 p = util_path_remove_last(p);
425 if(stat(p.ptr, &s)) {
426 free(p.ptr);
427 return 0;
428 }
429 }
430 }
431
432
433
434
435
436
437
438
439 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) {
440 free(p.ptr);
441 return 0;
442 }
443
444 p = util_path_remove_last(p);
445 mask =
ACE_LIST_DIRECTORY;
446 while(p.length >
1) {
447 if(stat(p.ptr, &s)) {
448 free(p.ptr);
449 return 0;
450 }
451 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) {
452 free(p.ptr);
453 return 0;
454 }
455
456
457 p = util_path_remove_last(p);
458 }
459
460
461 return 1;
462 }
463
464 int solaris_acl_check(
465 char *path,
466 struct stat *s,
467 uint32_t mask,
468 uid_t uid,
469 gid_t gid)
470 {
471
472
473 int nace = acl(path,
ACE_GETACLCNT,
0,
NULL);
474 if(nace == -
1) {
475 perror(
"acl: ACE_GETACLCNT");
476
477 return 0;
478 }
479 ace_t *aces = calloc(nace,
sizeof(
ace_t));
480 if(acl(path,
ACE_GETACL, nace, aces) ==
1) {
481 perror(
"acl: ACE_GETACL");
482
483 free(aces);
484 return 0;
485 }
486
487 int allow =
0;
488 uint32_t allowed_access =
0;
489 for(
int i=
0;i<nace;i++) {
490 ace_t ace = aces[i];
491 if(solaris_acl_affects_user(&ace, uid, gid, s->st_uid, s->st_gid)) {
492 if(ace.a_type ==
ACE_ACCESS_ALLOWED_ACE_TYPE) {
493
494 allowed_access |= (mask & ace.a_access_mask);
495
496 if((allowed_access & mask) == mask) {
497 allow =
1;
498 break;
499 }
500 }
else if(ace.a_type ==
ACE_ACCESS_DENIED_ACE_TYPE) {
501
502
503 if((ace.a_access_mask & mask) !=
0) {
504
505 break;
506 }
507 }
508 }
509 }
510
511 free(aces);
512
513
514 return allow;
515 }
516
517 int solaris_acl_affects_user(
518 ace_t *ace,
519 uid_t uid,
520 gid_t gid,
521 uid_t owner,
522 gid_t owninggroup)
523 {
524
525
526
527
528 int check_access =
0;
529
530 if((ace->a_flags &
ACE_OWNER) ==
ACE_OWNER) {
531 if(uid == owner) {
532 check_access =
1;
533 }
534 }
else if((ace->a_flags &
ACE_GROUP) ==
ACE_GROUP) {
535 if(gid == owninggroup) {
536 check_access =
1;
537 }
538 }
else if((ace->a_flags &
ACE_EVERYONE) ==
ACE_EVERYONE) {
539 check_access =
1;
540 }
else if(ace->a_who != -
1 && uid !=
0) {
541
542 if((ace->a_flags &
ACE_IDENTIFIER_GROUP) ==
ACE_IDENTIFIER_GROUP) {
543
544 if(ace->a_who == gid) {
545
546 check_access =
1;
547 }
548 }
else {
549 if(ace->a_who == uid) {
550 check_access =
1;
551 }
552 }
553 }
554
555 return check_access;
556 }
557
558 void fs_acl_finish() {
559
560 }
561
562 #endif
563
564
565
566
567
568 #ifdef OSX
569
570 int fs_acl_check(SysACL *acl, User *user,
char *path,
uint32_t access_mask) {
571 return 1;
572 }
573
574 void fs_acl_finish() {
575
576 }
577
578 #endif
579
580 #ifdef BSD
581
582 int fs_acl_check(SysACL *acl, User *user,
char *path,
uint32_t access_mask) {
583 return 1;
584 }
585
586 void fs_acl_finish() {
587
588 }
589
590 #endif
591
592
593 #ifdef LINUX
594
595 #include <sys/fsuid.h>
596
597 int fs_acl_check(SysACL *acl, User *user,
char *path,
uint32_t access_mask) {
598 struct passwd *ws_pw = conf_getglobals()->Vuserpw;
599 if(!ws_pw) {
600 log_ereport(
LOG_FAILURE,
"fs_acl_check: unknown webserver uid/gid");
601 return 1;
602 }
603
604
605 struct passwd pw;
606 if(user) {
607 char *pwbuf = malloc(
DEF_PWBUF);
608 if(pwbuf ==
NULL) {
609 return 0;
610 }
611 if(!util_getpwnam(user->name, &pw, pwbuf,
DEF_PWBUF)) {
612 free(pwbuf);
613 return 0;
614 }
615 free(pwbuf);
616 acl->user_uid = pw.pw_uid;
617 acl->user_gid = pw.pw_gid;
618 }
else {
619 acl->user_uid =
0;
620 acl->user_gid =
0;
621 }
622
623
624 if(acl->user_uid !=
0) {
625 if(setfsuid(pw.pw_uid)) {
626 log_ereport(
627 LOG_FAILURE,
628 "Cannot set fsuid to uid: %u", pw.pw_uid);
629 }
630 if(setfsgid(pw.pw_gid)) {
631 log_ereport(
632 LOG_FAILURE,
633 "Cannot set fsgid to gid: %u", pw.pw_gid);
634 }
635 }
636
637
638 return 1;
639 }
640
641 void fs_acl_finish() {
642 struct passwd *pw = conf_getglobals()->Vuserpw;
643 if(!pw) {
644 log_ereport(
645 LOG_FAILURE,
646 "global configuration broken (Vuserpw is null)");
647 return;
648 }
649 if(setfsuid(pw->pw_uid)) {
650 log_ereport(
651 LOG_FAILURE,
652 "Cannot set fsuid back to server uid: %u", pw->pw_uid);
653 }
654 if(setfsgid(pw->pw_gid)) {
655 log_ereport(
656 LOG_FAILURE,
657 "Cannot set fsgid back to server gid: %u", pw->pw_gid);
658 }
659 }
660
661 #endif
662