src/server/daemon/acl.c

changeset 63
66442f81f823
parent 54
3a1d5a52adfc
child 66
74babc0082b7
equal deleted inserted replaced
62:c47e081b6c0f 63:66442f81f823
27 */ 27 */
28 28
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 31
32 #include "../util/util.h"
32 #include "../util/pool.h" 33 #include "../util/pool.h"
33 #include "../safs/auth.h" 34 #include "../safs/auth.h"
34 #include "acl.h" 35 #include "acl.h"
35 36
36 void acllist_createhandle(Session *sn, Request *rq) { 37 void acllist_createhandle(Session *sn, Request *rq) {
120 121
121 return user; 122 return user;
122 } 123 }
123 124
124 void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user) { 125 void acl_set_error_status(Session *sn, Request *rq, ACLList *acl, User *user) {
126 if(sn == NULL || rq == NULL) {
127 return;
128 }
129
125 if(!user) { 130 if(!user) {
126 char *value = NULL; 131 char *value = NULL;
127 if(acl->authprompt) { 132 if(acl->authprompt) {
128 size_t realmlen = strlen(acl->authprompt); 133 size_t realmlen = strlen(acl->authprompt);
129 size_t len = realmlen + 16; 134 size_t len = realmlen + 16;
157 162
158 // get user 163 // get user
159 User *user = acllist_getuser(sn, rq, list); 164 User *user = acllist_getuser(sn, rq, list);
160 165
161 // evalutate all ACLs 166 // evalutate all ACLs
162 ACLList *acl = acl_evallist(list, user, access_mask); 167 ACLList *acl = acl_evallist(list, user, access_mask, NULL);
163 if(acl) { 168 if(acl) {
164 acl_set_error_status(sn, rq, acl, user); 169 acl_set_error_status(sn, rq, acl, user);
165 // TODO: don't free the user here 170 // TODO: don't free the user here
166 if(user) { 171 if(user) {
167 user->free(user); 172 user->free(user);
175 } 180 }
176 181
177 return REQ_PROCEED; 182 return REQ_PROCEED;
178 } 183 }
179 184
180 ACLList* acl_evallist(ACLListHandle *list, User *user, int access_mask) { 185 ACLList* acl_evallist(
186 ACLListHandle *list,
187 User *user,
188 int access_mask,
189 ACLList **externacl)
190 {
181 if(!list) { 191 if(!list) {
182 return NULL; 192 return NULL;
193 }
194 if(externacl) {
195 *externacl = NULL;
183 } 196 }
184 197
185 // evaluate each acl until one denies access 198 // evaluate each acl until one denies access
186 ACLListElm *elm = list->listhead; 199 ACLListElm *elm = list->listhead;
187 while(elm) { 200 while(elm) {
188 ACLList *acl = elm->acl; 201 ACLList *acl = elm->acl;
189 if(!acl->check(acl, user, access_mask)) { 202 if(acl->isextern) {
203 // set externacl to the first external acl
204 if(externacl && *externacl == NULL) {
205 *externacl = acl;
206 }
207 } else if(!acl->check(acl, user, access_mask)) {
190 // the acl denies access 208 // the acl denies access
191 return acl; 209 return acl;
192 } 210 }
193 elm = elm->next; 211 elm = elm->next;
194 } 212 }
264 282
265 // TODO: events 283 // TODO: events
266 284
267 return allow; // allow is 0, if no ace set it to 1 285 return allow; // allow is 0, if no ace set it to 1
268 } 286 }
287
288
289 /* filesystem acl functions */
290
291 #if defined (__SVR4) && defined (__sun)
292
293 #include <sys/acl.h>
294
295 int solaris_acl_check(
296 char *path,
297 struct stat *s,
298 uint32_t mask,
299 uid_t uid,
300 gid_t gid);
301 int solaris_acl_affects_user(
302 ace_t *ace,
303 uid_t uid,
304 gid_t gid,
305 uid_t owner,
306 gid_t owninggroup);
307
308 int fs_acl_check(SysACL *acl, User *user, char *path, uint32_t access_mask) {
309 sstr_t p;
310 if(path[0] != '/') {
311 size_t n = 128;
312 char *cwd = malloc(n);
313 while(!getcwd(cwd, n)) {
314 if(errno == ERANGE) {
315 n *= 2;
316 cwd = realloc(cwd, n);
317 } else {
318 free(cwd);
319 return 0;
320 }
321 }
322 sstr_t wd = sstr(cwd);
323 sstr_t pp = sstr(path);
324 p.length = wd.length + pp.length + 1;
325 p.ptr = malloc(p.length + 1);
326 p = sstrncat(3, p, wd, sstrn("/", 1), pp);
327 p.ptr[p.length] = '\0';
328 } else {
329 p = sstrdup(sstr(path));
330 }
331 if(p.ptr[p.length-1] == '/') {
332 p.ptr[p.length-1] = 0;
333 p.length--;
334 }
335
336 // get uid/gid
337 struct passwd pw;
338 if(user) {
339 char *pwbuf = malloc(DEF_PWBUF);
340 if(pwbuf == NULL) {
341 free(p.ptr);
342 return 0;
343 }
344 if(!util_getpwnam(user->name, &pw, pwbuf, DEF_PWBUF)) {
345 free(pwbuf);
346 free(p.ptr);
347 return 0;
348 }
349 free(pwbuf);
350 acl->user_uid = pw.pw_uid;
351 acl->user_gid = pw.pw_gid;
352 } else {
353 acl->user_uid = -1;
354 acl->user_gid = -1;
355 }
356
357 // translate access_mask
358 uint32_t mask = 0;
359 if((access_mask & ACL_READ_DATA) == ACL_READ_DATA) {
360 mask |= ACE_READ_DATA;
361 }
362 if((access_mask & ACL_WRITE_DATA) == ACL_WRITE_DATA) {
363 mask |= ACE_WRITE_DATA;
364 }
365 if((access_mask & ACL_ADD_FILE) == ACL_ADD_FILE) {
366 mask |= ACE_ADD_FILE;
367 }
368 if((access_mask & ACL_READ_XATTR) == ACL_READ_XATTR) {
369 mask |= ACE_READ_NAMED_ATTRS;
370 }
371 if((access_mask & ACL_WRITE_XATTR) == ACL_WRITE_XATTR) {
372 mask |= ACE_WRITE_NAMED_ATTRS;
373 }
374 if((access_mask & ACL_EXECUTE) == ACL_EXECUTE) {
375 mask |= ACE_EXECUTE;
376 }
377 if((access_mask & ACL_DELETE) == ACL_DELETE) {
378 mask |= ACE_DELETE_CHILD;
379 }
380 if((access_mask & ACL_READ_ATTRIBUTES) == ACL_READ_ATTRIBUTES) {
381 mask |= ACE_READ_ATTRIBUTES;
382 }
383 if((access_mask & ACL_WRITE_ATTRIBUTES) == ACL_WRITE_ATTRIBUTES) {
384 mask |= ACE_WRITE_ATTRIBUTES;
385 }
386 if((access_mask & ACL_LIST) == ACL_LIST) {
387 mask |= ACE_LIST_DIRECTORY;
388 }
389 if((access_mask & ACL_READ_ACL) == ACL_READ_ACL) {
390 mask |= ACE_READ_ACL;
391 }
392 if((access_mask & ACL_WRITE_ACL) == ACL_WRITE_ACL) {
393 mask |= ACE_WRITE_ACL;
394 }
395 if((access_mask & ACL_WRITE_OWNER) == ACL_WRITE_OWNER) {
396 mask |= ACE_WRITE_OWNER;
397 }
398 if((access_mask & ACL_SYNCHRONIZE) == ACL_SYNCHRONIZE) {
399 mask |= ACE_SYNCHRONIZE;
400 }
401
402 /*
403 * If the vfs wants to create new files, path does not name an existing
404 * file. In this case, we check if the user has the ACE_ADD_FILE
405 * permission for the parent directory
406 */
407 struct stat s;
408 if(stat(p.ptr, &s)) {
409 if(errno != ENOENT) {
410 perror("fs_acl_check: stat");
411 free(p.ptr);
412 return 0;
413 } else {
414 mask = ACE_ADD_FILE;
415 p = util_path_remove_last(p);
416 if(stat(p.ptr, &s)) {
417 free(p.ptr);
418 return 0;
419 }
420 }
421 }
422
423 /*
424 * perform a acl check for the path and each parent directory
425 * we don't check the file system root
426 *
427 * after the first check, we check only search permission for the
428 * directories
429 */
430 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) {
431 free(p.ptr);
432 return 0;
433 }
434
435 p = util_path_remove_last(p);
436 mask = ACE_LIST_DIRECTORY;
437 while(p.length > 1) {
438 if(stat(p.ptr, &s)) {
439 free(p.ptr);
440 return 0;
441 }
442 if(!solaris_acl_check(p.ptr, &s, mask, pw.pw_uid, pw.pw_gid)) {
443 free(p.ptr);
444 return 0;
445 }
446
447 // cut the last file name from the path
448 p = util_path_remove_last(p);
449 }
450
451
452 return 1;
453 }
454
455 int solaris_acl_check(
456 char *path,
457 struct stat *s,
458 uint32_t mask,
459 uid_t uid,
460 gid_t gid)
461 {
462 //printf("solaris_acl_check %s\n", path);
463
464 int nace = acl(path, ACE_GETACLCNT, 0, NULL);
465 if(nace == -1) {
466 perror("acl: ACE_GETACLCNT");
467 // TODO: log error
468 return 0;
469 }
470 ace_t *aces = calloc(nace, sizeof(ace_t));
471 if(acl(path, ACE_GETACL, nace, aces) == 1) {
472 perror("acl: ACE_GETACL");
473 // TODO: log error
474 free(aces);
475 return 0;
476 }
477
478 int allow = 0;
479 uint32_t allowed_access = 0;
480 for(int i=0;i<nace;i++) {
481 ace_t ace = aces[i];
482 if(solaris_acl_affects_user(&ace, uid, gid, s->st_uid, s->st_gid)) {
483 if(ace.a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
484 // add all new access rights
485 allowed_access |= (mask & ace.a_access_mask);
486 // check if we have all requested rights
487 if((allowed_access & mask) == mask) {
488 allow = 1;
489 break;
490 }
491 } else if(ace.a_type == ACE_ACCESS_DENIED_ACE_TYPE) {
492 // ACL_TYPE_DENIED
493
494 if((ace.a_access_mask & mask) != 0) {
495 // access denied
496 break;
497 }
498 }
499 }
500 }
501
502 free(aces);
503
504 //printf("return %d\n", allow);
505 return allow;
506 }
507
508 int solaris_acl_affects_user(
509 ace_t *ace,
510 uid_t uid,
511 gid_t gid,
512 uid_t owner,
513 gid_t owninggroup)
514 {
515 /*
516 * mostly the same as wsacl_affects_user
517 */
518
519 int check_access = 0;
520
521 if((ace->a_flags & ACE_OWNER) == ACE_OWNER) {
522 if(uid == owner) {
523 check_access = 1;
524 }
525 } else if((ace->a_flags & ACE_GROUP) == ACE_GROUP) {
526 if(gid == owninggroup) {
527 check_access = 1;
528 }
529 } else if((ace->a_flags & ACE_EVERYONE) == ACE_EVERYONE) {
530 check_access = 1;
531 } else if(ace->a_who != -1 && uid != 0) {
532 // this ace is defined for a named user or group
533 if((ace->a_flags & ACE_IDENTIFIER_GROUP) == ACE_IDENTIFIER_GROUP) {
534 // TODO: check all groups
535 if(ace->a_who == gid) {
536 // the user is in the group
537 check_access = 1;
538 }
539 } else {
540 if(ace->a_who == uid) {
541 check_access = 1;
542 }
543 }
544 }
545
546 return check_access;
547 }
548
549
550
551 #endif
552

mercurial