]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/aclq.c
Complicate the shit out of everything to pass the new tests.
[apply-default-acl.git] / src / aclq.c
1 #include <errno.h>
2 #include <libgen.h> /* dirname() */
3 #include <limits.h> /* PATH_MAX */
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10
11 /* ACLs */
12 #include <acl/libacl.h> /* acl_get_perm, not portable */
13 #include <sys/types.h>
14 #include <sys/acl.h>
15
16
17 mode_t get_mode(const char* path) {
18 if (path == NULL) {
19 errno = ENOENT;
20 return -1;
21 }
22
23 struct stat s;
24 int result = stat(path, &s);
25
26 if (result == 0) {
27 return s.st_mode;
28 }
29 else {
30 /* errno will be set already by stat() */
31 return result;
32 }
33 }
34
35 bool mode_has_perm(mode_t mode, int perm) {
36 if (mode & perm) {
37 return true;
38 }
39 else {
40 return false;
41 }
42 }
43
44
45 bool is_regular_file(const char* path) {
46 if (path == NULL) {
47 return false;
48 }
49
50 struct stat s;
51 int result = stat(path, &s);
52 if (result == 0) {
53 return S_ISREG(s.st_mode);
54 }
55 else {
56 return false;
57 }
58 }
59
60 bool is_directory(const char* path) {
61 if (path == NULL) {
62 return false;
63 }
64
65 struct stat s;
66 int result = stat(path, &s);
67 if (result == 0) {
68 return S_ISDIR(s.st_mode);
69 }
70 else {
71 return false;
72 }
73 }
74
75
76 int has_type_tag_acl(const char* path,
77 acl_type_t type,
78 acl_tag_t desired_tag) {
79 /* Returns one if the given path has a default ACL for the supplied
80 tag, zero if it doesn't, and -1 on error. */
81 acl_t defacl = acl_get_file(path, type);
82
83 if (defacl == (acl_t)NULL) {
84 return 0;
85 }
86
87 acl_entry_t entry;
88 int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry);
89
90 while (result == 1) {
91 acl_tag_t tag = ACL_UNDEFINED_TAG;
92 int tag_result = acl_get_tag_type(entry, &tag);
93
94 if (tag_result == -1) {
95 perror("has_default_tag_acl (acl_get_tag_type)");
96 return -1;
97 }
98 else {
99 if (tag == desired_tag) {
100 return 1;
101 }
102 }
103
104 result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
105 }
106
107 if (result == -1) {
108 perror("has_default_tag_acl (acl_get_entry)");
109 return -1;
110 }
111
112 return 0;
113 }
114
115 int has_default_tag_acl(const char* path, acl_tag_t desired_tag) {
116 return has_type_tag_acl(path, ACL_TYPE_DEFAULT, desired_tag);
117 }
118
119 int has_access_tag_acl(const char* path, acl_tag_t desired_tag) {
120 return has_type_tag_acl(path, ACL_TYPE_ACCESS, desired_tag);
121 }
122
123 int has_default_user_obj_acl(const char* path) {
124 return has_default_tag_acl(path, ACL_USER_OBJ);
125 }
126
127 int has_default_group_obj_acl(const char* path) {
128 return has_default_tag_acl(path, ACL_GROUP_OBJ);
129 }
130
131 int has_default_other_acl(const char* path) {
132 return has_default_tag_acl(path, ACL_OTHER);
133 }
134
135 int has_default_mask_acl(const char* path) {
136 return has_default_tag_acl(path, ACL_MASK);
137 }
138
139
140 int get_type_tag_entry(const char* path,
141 acl_type_t type,
142 acl_tag_t desired_tag,
143 acl_entry_t* entry) {
144 /* Returns one if successful, zero when the ACL doesn't exist, and
145 -1 on unexpected errors. */
146 acl_t acl = acl_get_file(path, type);
147
148 if (acl == (acl_t)NULL) {
149 /* Follow the acl_foo convention of -1 == error. */
150 return 0;
151 }
152
153 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, entry);
154
155 while (result == 1) {
156 acl_tag_t tag = ACL_UNDEFINED_TAG;
157 int tag_result = acl_get_tag_type(*entry, &tag);
158
159 if (tag_result == -1) {
160 perror("get_type_tag_entry (acl_get_tag_type)");
161 return -1;
162 }
163
164 if (tag == desired_tag) {
165 /* We found the right tag, so return successfully. */
166 return 1;
167 }
168
169 result = acl_get_entry(acl, ACL_NEXT_ENTRY, entry);
170 }
171
172 /* This catches both the initial acl_get_entry and the ones at the
173 end of the loop. */
174 if (result == -1) {
175 perror("get_type_tag_entry (acl_get_entry)");
176 return -1;
177 }
178
179 return 0;
180 }
181
182 int get_default_tag_entry(const char* path,
183 acl_tag_t desired_tag,
184 acl_entry_t* entry) {
185 return get_type_tag_entry(path, ACL_TYPE_DEFAULT, desired_tag, entry);
186 }
187
188 int get_access_tag_entry(const char* path,
189 acl_tag_t desired_tag,
190 acl_entry_t* entry) {
191 return get_type_tag_entry(path, ACL_TYPE_ACCESS, desired_tag, entry);
192 }
193
194
195
196 int get_type_tag_permset(const char* path,
197 acl_type_t type,
198 acl_tag_t desired_tag,
199 acl_permset_t* output_perms) {
200 /* Returns one if successful, zero when the ACL doesn't exist, and
201 -1 on unexpected errors. */
202 acl_t defacl = acl_get_file(path, type);
203
204 if (defacl == (acl_t)NULL) {
205 /* Follow the acl_foo convention of -1 == error. */
206 return 0;
207 }
208
209 acl_entry_t entry;
210 int result = get_type_tag_entry(path, type, desired_tag, &entry);
211
212 if (result == 1) {
213 /* We found the right tag, now get the permset. */
214 int ps_result = acl_get_permset(entry, output_perms);
215 if (ps_result == -1) {
216 perror("get_type_tag_permset (acl_get_permset)");
217 return -1;
218 }
219
220 if (ps_result == 0) {
221 return 1;
222 }
223 else {
224 return 0;
225 }
226 }
227 else {
228 return result;
229 }
230 }
231
232 int get_default_tag_permset(const char* path,
233 acl_tag_t desired_tag,
234 acl_permset_t* output_perms) {
235 return get_type_tag_permset(path,
236 ACL_TYPE_DEFAULT,
237 desired_tag,
238 output_perms);
239 }
240
241 int get_access_tag_permset(const char* path,
242 acl_tag_t desired_tag,
243 acl_permset_t* output_perms) {
244 return get_type_tag_permset(path, ACL_TYPE_ACCESS, desired_tag, output_perms);
245 }
246
247 int has_default_tag_perm(const char* path,
248 acl_tag_t tag,
249 acl_perm_t perm) {
250 /* Check path to see if tag has the given perm. Returns one if it
251 does, zero if it doesn't (or there's no ACL), and -1 on unexpected
252 errors. */
253
254 if (!has_default_tag_acl(path, tag)) {
255 return 0;
256 }
257
258 acl_permset_t permset;
259 bool ps_result = get_default_tag_permset(path, tag, &permset);
260
261 if (ps_result != 1) {
262 /* Failure or error. */
263 return ps_result;
264 }
265
266 int p_result = acl_get_perm(permset, perm);
267 if (p_result == -1) {
268 perror("has_default_tag_perm (acl_get_perm)");
269 }
270
271 return p_result;
272 }
273
274 int remove_access_tag_perm(const char* path,
275 acl_tag_t desired_tag,
276 acl_perm_t perm) {
277 /* Attempt to remove perm from tag. Returns one if successful, zero
278 if there was nothing to do, and -1 on errors. */
279 acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
280 if (acl == (acl_t)NULL) {
281 /* Error. */
282 return -1;
283 }
284
285 acl_permset_t permset;
286 bool ps_result = get_access_tag_permset(path, desired_tag, &permset);
287
288 if (ps_result != 1) {
289 /* Failure or error. */
290 return ps_result;
291 }
292
293 int d_result = acl_delete_perm(permset, perm);
294 if (d_result == -1) {
295 perror("remove_access_tag_perm (acl_delete_perm)");
296 return -1;
297 }
298
299 /* We've only removed perm from the permset; now we have to replace
300 the permset. */
301 acl_entry_t entry;
302 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
303
304 while (result == 1) {
305 acl_tag_t tag = ACL_UNDEFINED_TAG;
306 int tag_result = acl_get_tag_type(entry, &tag);
307
308 if (tag_result == -1) {
309 perror("remove_access_tag_perm (acl_get_tag_type)");
310 return -1;
311 }
312
313 if (tag == desired_tag) {
314 /* We found the right tag. Update the permset. */
315 int s_result = acl_set_permset(entry, permset);
316 if (s_result == -1) {
317 perror("remove_access_tag_perm (acl_set_permset)");
318 return -1;
319 }
320
321 int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl);
322 if (sf_result == -1) {
323 perror("remove_access_tag_perm (acl_set_file)");
324 return -1;
325 }
326
327 return 1;
328 }
329
330 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
331 }
332
333 /* This catches both the initial acl_get_entry and the ones at the
334 end of the loop. */
335 if (result == -1) {
336 perror("remove_access_tag_perm (acl_get_entry)");
337 return -1;
338 }
339
340 return 0;
341 }
342
343 int remove_access_group_obj_execute(const char* path) {
344 return remove_access_tag_perm(path, ACL_GROUP_OBJ, ACL_EXECUTE);
345 }
346
347
348 int has_default_user_obj_read(const char* path) {
349 return has_default_tag_perm(path, ACL_USER_OBJ, ACL_READ);
350 }
351
352 int has_default_user_obj_write(const char* path) {
353 return has_default_tag_perm(path, ACL_USER_OBJ, ACL_WRITE);
354 }
355
356 int has_default_user_obj_execute(const char* path) {
357 return has_default_tag_perm(path, ACL_USER_OBJ, ACL_EXECUTE);
358 }
359
360 int has_default_group_obj_read(const char* path) {
361 return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_READ);
362 }
363
364 int has_default_group_obj_write(const char* path) {
365 return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_WRITE);
366 }
367
368 int has_default_group_obj_execute(const char* path) {
369 return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_EXECUTE);
370 }
371
372 int has_default_other_read(const char* path) {
373 return has_default_tag_perm(path, ACL_OTHER, ACL_READ);
374 }
375
376 int has_default_other_write(const char* path) {
377 return has_default_tag_perm(path, ACL_OTHER, ACL_WRITE);
378 }
379
380 int has_default_other_execute(const char* path) {
381 return has_default_tag_perm(path, ACL_OTHER, ACL_EXECUTE);
382 }
383
384 int has_default_mask_read(const char* path) {
385 return has_default_tag_perm(path, ACL_MASK, ACL_READ);
386 }
387
388 int has_default_mask_write(const char* path) {
389 return has_default_tag_perm(path, ACL_MASK, ACL_WRITE);
390 }
391
392 int has_default_mask_execute(const char* path) {
393 return has_default_tag_perm(path, ACL_MASK, ACL_EXECUTE);
394 }
395
396
397 int reapply_default_acl(const char* path) {
398 /* If this is a normal file or directory (i.e. that has just been
399 created), we proceed to find its parent directory which will have
400 a default ACL.
401
402 Returns one for success, zero for failure (i.e. no ACL), and -1
403 on unexpected errors. */
404 if (path == NULL) {
405 return 0;
406 }
407
408 if (!is_regular_file(path) && !is_directory(path)) {
409 return 0;
410 }
411
412 /* dirname mangles its argument */
413 char path_copy[PATH_MAX];
414 strncpy(path_copy, path, PATH_MAX-1);
415 path_copy[PATH_MAX-1] = 0;
416
417 char* parent = dirname(path_copy);
418 if (!is_directory(parent)) {
419 /* Make sure dirname() did what we think it did. */
420 return 0;
421 }
422
423 /* This is the original mode of path. We will simply add permissions
424 to it, and then later reapply the result via chmod. */
425 mode_t path_mode = get_mode(path);
426
427 if (has_default_mask_acl(parent)) {
428 /* The parent has an extended ACL. Extended ACLs use the mask
429 entry. */
430
431 /* For the group bits, we'll use the ACL's mask instead of the group
432 object bits. If the default ACL had a group entry, it should
433 already have propagated (but might be masked). */
434 if (has_default_mask_read(parent)) {
435 path_mode |= S_IRGRP;
436 }
437 else {
438 path_mode &= ~S_IRGRP;
439 }
440
441 if (has_default_mask_write(parent)) {
442 path_mode |= S_IWGRP;
443 }
444 else {
445 path_mode &= ~S_IWGRP;
446 }
447
448 if (!mode_has_perm(path_mode, S_IXGRP)) {
449 /* The group ACL entry should already have been inherited from the
450 default ACL. If the source was not group executable, we want to
451 modify the destination so that it is not group executable
452 either. In the presence of ACLs, the group permissions come not
453 from the mode bits, but from the group:: ACL entry. So, to do
454 this, we remove the group::x entry. */
455 remove_access_group_obj_execute(path);
456 }
457
458 /* We need to determine whether or not to mask the execute
459 bit. This applies not only to the user/group/other entries, but
460 also to all other named entries. If the original file wasn't
461 executable, then the result probably should not be. To
462 determine whether or not "it was executable", we rely on the
463 user execute bits. Obviously this should be done before we
464 twiddle that bit. */
465 if (has_default_mask_execute(parent)) {
466 if (mode_has_perm(path_mode, S_IXUSR)) {
467 /* This just adds the group execute bit, and doesn't actually
468 grant group execute permissions. */
469 path_mode |= S_IXGRP;
470 }
471 }
472 else {
473 path_mode &= ~S_IXGRP;
474 }
475
476 }
477 else {
478 /* It's a minimal ACL. We'll repeat for the group bits what we
479 already did for the owner/other bits. */
480 if (has_default_group_obj_acl(parent)) {
481 if (has_default_group_obj_read(parent)) {
482 path_mode |= S_IRGRP;
483 }
484 else {
485 path_mode &= ~S_IRGRP;
486 }
487
488
489 if (has_default_group_obj_write(parent)) {
490 path_mode |= S_IWGRP;
491 }
492 else {
493 path_mode &= ~S_IWGRP;
494 }
495
496 /* We don't want to set the execute bit on via the ACL unless it
497 was on originally. */
498 if (!has_default_group_obj_execute(parent)) {
499 path_mode &= ~S_IXGRP;
500 }
501 }
502 }
503
504
505 /* If parent has a default user ACL, apply it. */
506 if (has_default_user_obj_acl(parent)) {
507
508 if (has_default_user_obj_read(parent)) {
509 /* Add user read. */
510 path_mode |= S_IRUSR;
511 }
512 else {
513 /* Remove user read. */
514 path_mode &= ~S_IRUSR;
515 }
516
517
518 if (has_default_user_obj_write(parent)) {
519 /* Add user write. */
520 path_mode |= S_IWUSR;
521 }
522 else {
523 /* Remove user write. */
524 path_mode &= ~S_IWUSR;
525 }
526
527
528 /* We don't want to set the execute bit on via the ACL unless it
529 was on originally. */
530 if (!has_default_user_obj_execute(parent)) {
531 /* Remove user execute. */
532 path_mode &= ~S_IXUSR;
533 }
534 }
535
536
537 /* Do the same thing with the other perms/ACL. */
538 if (has_default_other_acl(parent)) {
539
540 if (has_default_other_read(parent)) {
541 path_mode |= S_IROTH;
542 }
543 else {
544 path_mode &= ~S_IROTH;
545 }
546
547
548 if (has_default_other_write(parent)) {
549 path_mode |= S_IWOTH;
550 }
551 else {
552 path_mode &= ~S_IWOTH;
553 }
554
555
556 /* We don't want to set the execute bit on via the ACL unless it
557 was on originally. */
558 if (!has_default_other_execute(parent)) {
559 path_mode &= ~S_IXOTH;
560 }
561 }
562
563 int chmod_result = chmod(path, path_mode);
564 if (chmod_result == 0) {
565 return 1;
566 }
567 else {
568 return 0;
569 }
570 }
571
572
573
574
575
576 int set_acl_entry(acl_t* aclp,
577 acl_entry_t entry) {
578 /* Update or create the given entry. */
579
580 acl_tag_t entry_tag;
581 int gt_result = acl_get_tag_type(entry, &entry_tag);
582 if (gt_result == -1) {
583 perror("set_acl_entry (acl_get_tag_type)");
584 return -1;
585 }
586
587 acl_permset_t entry_permset;
588 int ps_result = acl_get_permset(entry, &entry_permset);
589 if (ps_result == -1) {
590 perror("set_acl_entry (acl_get_permset)");
591 return -1;
592 }
593
594 acl_entry_t existing_entry;
595 /* Loop through the given ACL looking for matching entries. */
596 int result = acl_get_entry(*aclp, ACL_FIRST_ENTRY, &existing_entry);
597
598 while (result == 1) {
599 acl_tag_t existing_tag = ACL_UNDEFINED_TAG;
600 int tag_result = acl_get_tag_type(existing_entry, &existing_tag);
601
602 if (tag_result == -1) {
603 perror("set_acl_tag_permset (acl_get_tag_type)");
604 return -1;
605 }
606
607 if (existing_tag == entry_tag) {
608 bool update_it = true;
609
610 if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) {
611 void* entry_qual = acl_get_qualifier(entry);
612 if (entry_qual == (void*)NULL) {
613 perror("set_acl_entry (acl_get_qualifier - entry_qual)");
614 return -1;
615 }
616
617 void* existing_qual = acl_get_qualifier(existing_entry);
618 if (existing_qual == (void*)NULL) {
619 perror("set_acl_entry (acl_get_qualifier - existing_qual)");
620 return -1;
621 }
622
623 if (entry_tag == ACL_USER) {
624 uid_t* u1p = (uid_t *)entry_qual;
625 uid_t* u2p = (uid_t *)existing_qual;
626 if (*u1p != *u2p) {
627 update_it = false;
628 }
629 }
630 else {
631 gid_t* g1p = (gid_t *)entry_qual;
632 gid_t* g2p = (gid_t *)existing_qual;
633 if (*g1p != *g2p) {
634 update_it = false;
635 }
636 }
637
638 acl_free(entry_qual);
639 acl_free(existing_qual);
640 }
641
642 if (update_it) {
643 acl_permset_t existing_permset;
644 int gep_result = acl_get_permset(existing_entry, &existing_permset);
645 if (gep_result == -1) {
646 perror("set_acl_entry (acl_get_permset)");
647 return -1;
648 }
649
650 /* If an existing entry doesn't have its execute bits set, we
651 don't want to set them from a default ACL. Unless it's the
652 mask entry! */
653 int gp_result = acl_get_perm(existing_permset, ACL_EXECUTE);
654 if (gp_result == -1) {
655 perror("set_acl_entry (acl_get_perm)");
656 return -1;
657 }
658
659 if (gp_result == 0 && existing_tag != ACL_MASK) {
660 /* It doesn't already have execute perms */
661 int d_result = acl_delete_perm(entry_permset, ACL_EXECUTE);
662 if (d_result == -1) {
663 perror("set_acl_entry (acl_delete_perm)");
664 return -1;
665 }
666 }
667
668 int s_result = acl_set_permset(existing_entry, entry_permset);
669 if (s_result == -1) {
670 perror("set_acl_entry (acl_set_permset)");
671 return -1;
672 }
673
674 return 1;
675 }
676
677 }
678
679 result = acl_get_entry(*aclp, ACL_NEXT_ENTRY, &existing_entry);
680 }
681
682 /* This catches both the initial acl_get_entry and the ones at the
683 end of the loop. */
684 if (result == -1) {
685 perror("set_acl_entry (acl_get_entry)");
686 return -1;
687 }
688
689 /* If we've made it this far, we need to add a new entry to the
690 ACL. */
691 acl_entry_t new_entry;
692 int c_result = acl_create_entry(aclp, &new_entry);
693 if (c_result == -1) {
694 perror("set_acl_entry (acl_create_entry)");
695 return -1;
696 }
697
698 int st_result = acl_set_tag_type(new_entry, entry_tag);
699 if (st_result == -1) {
700 perror("set_acl_entry (acl_set_tag_type)");
701 return -1;
702 }
703
704 int s_result = acl_set_permset(new_entry, entry_permset);
705 if (s_result == -1) {
706 perror("set_acl_entry (acl_set_permset)");
707 return -1;
708 }
709
710 if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) {
711 /* We need to set the qualifier too. */
712 void* entry_qual = acl_get_qualifier(entry);
713 if (entry_qual == (void*)NULL) {
714 perror("set_acl_entry (acl_get_qualifier)");
715 return -1;
716 }
717
718 int sq_result = acl_set_qualifier(new_entry, entry_qual);
719 if (sq_result == -1) {
720 perror("set_acl_entry (acl_set_qualifier)");
721 return -1;
722 }
723 }
724
725 return 1;
726 }
727
728
729
730 int acl_is_minimal(acl_t* acl) {
731 /* An ACL is minimal if it has fewer than four entries. */
732 acl_entry_t entry;
733 int entry_count = 0;
734 int result = acl_get_entry(*acl, ACL_FIRST_ENTRY, &entry);
735
736 while (result == 1) {
737 entry_count++;
738 result = acl_get_entry(*acl, ACL_NEXT_ENTRY, &entry);
739 }
740
741 if (result == -1) {
742 perror("acl_is_minimal (acl_get_entry)");
743 return -1;
744 }
745
746 if (entry_count > 3) {
747 return 1;
748 }
749 else {
750 return 0;
751 }
752 }
753
754 int any_can_execute(const char* path) {
755 acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
756
757 if (acl_is_minimal(&acl)) {
758 mode_t mode = get_mode(path);
759 if (mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
760 return 1;
761 }
762 else {
763 return 0;
764 }
765 }
766
767 if (acl == (acl_t)NULL) {
768 return 0;
769 }
770
771 acl_entry_t entry;
772 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
773
774 while (result == 1) {
775 acl_permset_t permset;
776
777 int ps_result = acl_get_permset(entry, &permset);
778 if (ps_result == -1) {
779 perror("any_can_execute (acl_get_permset)");
780 return -1;
781 }
782
783 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
784 if (gp_result == -1) {
785 perror("any_can_execute (acl_get_perm)");
786 return -1;
787 }
788
789 if (gp_result == 1) {
790 return 1;
791 }
792
793 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
794 }
795
796 if (result == -1) {
797 perror("any_can_execute (acl_get_entry)");
798 return -1;
799 }
800
801 return 0;
802 }
803
804
805 int reapply_default_acl_ng(const char* path) {
806 /* Really reapply the default ACL by looping through it. Returns one
807 for success, zero for failure (i.e. no ACL), and -1 on unexpected
808 errors. */
809 if (path == NULL) {
810 return 0;
811 }
812
813 if (!is_regular_file(path) && !is_directory(path)) {
814 return 0;
815 }
816
817 /* dirname mangles its argument */
818 char path_copy[PATH_MAX];
819 strncpy(path_copy, path, PATH_MAX-1);
820 path_copy[PATH_MAX-1] = 0;
821
822 char* parent = dirname(path_copy);
823 if (!is_directory(parent)) {
824 /* Make sure dirname() did what we think it did. */
825 return 0;
826 }
827
828 int ace_result = any_can_execute(path);
829 if (ace_result == -1) {
830 perror("reapply_default_acl_ng (any_can_execute)");
831 return -1;
832 }
833
834 bool allow_exec = (bool)ace_result;
835
836 acl_t defacl = acl_get_file(parent, ACL_TYPE_DEFAULT);
837 acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS);
838
839 if (defacl == (acl_t)NULL || acl == (acl_t)NULL) {
840 return 0;
841 }
842
843 acl_entry_t entry;
844 int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry);
845
846 while (result == 1) {
847 acl_tag_t tag = ACL_UNDEFINED_TAG;
848 int tag_result = acl_get_tag_type(entry, &tag);
849
850 if (tag_result == -1) {
851 perror("has_default_tag_acl (acl_get_tag_type)");
852 return -1;
853 }
854
855
856 /* We've got an entry/tag from the default ACL. Get its permset. */
857 acl_permset_t permset;
858 int ps_result = acl_get_permset(entry, &permset);
859 if (ps_result == -1) {
860 perror("reapply_default_acl_ng (acl_get_permset)");
861 return -1;
862 }
863
864 /* If this is a default mask, fix it up. */
865 if (tag == ACL_MASK ||
866 tag == ACL_USER_OBJ ||
867 tag == ACL_GROUP_OBJ ||
868 tag == ACL_OTHER) {
869 if (!allow_exec) {
870 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
871 minimal ACLs) or acl_other entries, so if execute should be
872 masked, we have to do it manually. */
873 int d_result = acl_delete_perm(permset, ACL_EXECUTE);
874 if (d_result == -1) {
875 perror("reapply_default_acl_ng (acl_delete_perm)");
876 return -1;
877 }
878
879 int sp_result = acl_set_permset(entry, permset);
880 if (sp_result == -1) {
881 perror("reapply_default_acl_ng (acl_set_permset)");
882 return -1;
883 }
884 }
885 }
886
887 /* Finally, add the permset to the access ACL. */
888 int set_result = set_acl_entry(&acl, entry);
889 if (set_result == -1) {
890 perror("reapply_default_acl_ng (set_acl_entry)");
891 return -1;
892 }
893
894 result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
895 }
896
897 /* Catches the first acl_get_entry as well as the ones at the end of
898 the loop. */
899 if (result == -1) {
900 perror("reapply_default_acl_ng (acl_get_entry)");
901 return -1;
902 }
903
904 int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl);
905 if (sf_result == -1) {
906 perror("reapply_default_acl_ng (acl_set_file)");
907 return -1;
908 }
909
910 return 1;
911 }
912
913
914
915 int main(int argc, char* argv[]) {
916 const char* target = argv[1];
917
918 bool result = reapply_default_acl_ng(target);
919
920 if (result) {
921 return EXIT_SUCCESS;
922 }
923 else {
924 return EXIT_FAILURE;
925 }
926 }