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 |