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