]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/libadacl.c
Move a few constants out of the libadacl.h header to where they are used.
[apply-default-acl.git] / src / libadacl.c
1 /**
2 * @file libadacl.c
3 *
4 * @brief The adacl (apply default acl) shared library.
5 *
6 */
7
8 /* Enables get_current_dir_name() in unistd.h */
9 #define _GNU_SOURCE
10
11 #include <errno.h> /* ELOOP, EINVAL, etc. */
12 #include <fcntl.h> /* openat() */
13 #include <libgen.h> /* basename(), dirname() */
14 #include <limits.h> /* PATH_MAX */
15 #include <stdbool.h> /* the "bool" type */
16 #include <stdio.h> /* perror(), snprintf() */
17 #include <stdlib.h> /* free() */
18 #include <string.h> /* strdup() */
19 #include <sys/stat.h> /* fstat() */
20 #include <unistd.h> /* get_current_dir_name() */
21
22 /* ACLs */
23 #include <acl/libacl.h> /* acl_get_perm, not portable */
24 #include <sys/acl.h> /* all other acl_foo functions */
25
26 #include "libadacl.h"
27
28
29 /* Even though most other library functions reliably return -1 for
30 * error, it feels a little wrong to re-use the ACL_ERROR constant.
31 */
32 #define CLOSE_ERROR -1
33 #define OPEN_ERROR -1
34 #define SNPRINTF_ERROR -1
35 #define STAT_ERROR -1
36
37
38 /**
39 * @brief The recursive portion of the @c safe_open function, used to
40 * open a file descriptor in a symlink-safe way when combined with
41 * the @c O_NOFOLLOW flag.
42 *
43 * @param at_fd
44 * A file descriptor relative to which @c pathname will be opened.
45 *
46 * @param pathname
47 * The path to the file/directory/whatever whose descriptor you want.
48 *
49 * @return a file descriptor for @c pathname if everything goes well,
50 * and @c OPEN_ERROR if not.
51 */
52 int safe_open_ex(int at_fd, char* pathname, int flags) {
53 if (pathname != NULL && strlen(pathname) == 0) {
54 /* Oops, went one level to deep with nothing to do. */
55 return at_fd;
56 }
57
58 char* firstslash = strchr(pathname, '/');
59 if (firstslash == NULL) {
60 /* No more slashes, this is the base case. */
61 int r = openat(at_fd, pathname, flags);
62 return r;
63 }
64
65 /* Temporarily disable the slash, so that the subsequent call to
66 openat() opens only the next directory (and doesn't recurse). */
67 *firstslash = '\0';
68 int fd = safe_open_ex(at_fd, pathname, flags);
69 if (fd == OPEN_ERROR) {
70 if (errno != ELOOP) {
71 /* Don't output anything if we ignore a symlink */
72 perror("safe_open_ex (safe_open_ex)");
73 }
74 return OPEN_ERROR;
75 }
76
77 /* The ++ is safe because there needs to be at least a null byte
78 after the first slash, even if it's the last real character in
79 the string. */
80 int result = safe_open_ex(fd, firstslash+1, flags);
81 if (close(fd) == CLOSE_ERROR) {
82 perror("safe_open_ex (close)");
83 return OPEN_ERROR;
84 }
85 return result;
86 }
87
88
89 /**
90 * @brief A version of @c open that is completely symlink-safe when
91 * used with the @c O_NOFOLLOW flag.
92 *
93 * The @c openat function exists to ensure that you can anchor one
94 * path to a particular directory while opening it; however, if you
95 * open "b/c/d" relative to "/a", then even the @c openat function will
96 * still follow symlinks in the "b" component. This can be exploited
97 * by an attacker to make you open the wrong path.
98 *
99 * To avoid that problem, this function uses a recursive
100 * implementation that opens every path from the root, one level at a
101 * time. So "a" is opened relative to "/", and then "b" is opened
102 * relative to "/a", and then "c" is opened relative to "/a/b",
103 * etc. When the @c O_NOFOLLOW flag is used, this approach ensures
104 * that no symlinks in any component are followed.
105 *
106 * @param pathname
107 * The path to the file/directory/whatever whose descriptor you want.
108 *
109 * @return a file descriptor for @c pathname if everything goes well,
110 * and @c OPEN_ERROR if not.
111 */
112 int safe_open(const char* pathname, int flags) {
113 if (pathname == NULL || strlen(pathname) == 0 || pathname[0] == '\0') {
114 errno = EINVAL;
115 perror("safe_open (args)");
116 return OPEN_ERROR;
117 }
118
119 char abspath[PATH_MAX];
120 int snprintf_result = 0;
121 if (strchr(pathname, '/') == pathname) {
122 /* pathname is already absolute; just copy it. */
123 snprintf_result = snprintf(abspath, PATH_MAX, "%s", pathname);
124 }
125 else {
126 /* Concatenate the current working directory and pathname into an
127 * absolute path. We use realpath() ONLY on the cwd part, and not
128 * on the pathname part, because realpath() resolves symlinks. And
129 * the whole point of all this crap is to avoid following symlinks
130 * in the pathname.
131 *
132 * Using realpath() on the cwd lets us operate on relative paths
133 * while we're sitting in a directory that happens to have a
134 * symlink in it; for example: cd /var/run && apply-default-acl foo.
135 */
136 char* cwd = get_current_dir_name();
137 if (cwd == NULL) {
138 perror("safe_open (get_current_dir_name)");
139 return OPEN_ERROR;
140 }
141
142 char abs_cwd[PATH_MAX];
143 if (realpath(cwd, abs_cwd) == NULL) {
144 perror("safe_open (realpath)");
145 free(cwd);
146 return OPEN_ERROR;
147 }
148 snprintf_result = snprintf(abspath, PATH_MAX, "%s/%s", abs_cwd, pathname);
149 free(cwd);
150 }
151 if (snprintf_result == SNPRINTF_ERROR || snprintf_result > PATH_MAX) {
152 perror("safe_open (snprintf)");
153 return OPEN_ERROR;
154 }
155
156 int fd = open("/", flags);
157 if (strcmp(abspath, "/") == 0) {
158 return fd;
159 }
160
161 int result = safe_open_ex(fd, abspath+1, flags);
162 if (close(fd) == CLOSE_ERROR) {
163 perror("safe_open (close)");
164 return OPEN_ERROR;
165 }
166 return result;
167 }
168
169
170
171
172 /**
173 * @brief Update (or create) an entry in an @b minimal ACL.
174 *
175 * This function will not work if @c aclp contains extended
176 * entries. This is fine for our purposes, since we call @c wipe_acls
177 * on each path before applying the default to it.
178 *
179 * The assumption that there are no extended entries makes things much
180 * simpler. For example, we only have to update the @c ACL_USER_OBJ,
181 * @c ACL_GROUP_OBJ, and @c ACL_OTHER entries -- all others can simply
182 * be created anew. This means we don't have to fool around comparing
183 * named-user/group entries.
184 *
185 * @param aclp
186 * A pointer to the acl_t structure whose entry we want to modify.
187 *
188 * @param entry
189 * The new entry. If @c entry contains a user/group/other entry, we
190 * update the existing one. Otherwise we create a new entry.
191 *
192 * @return If there is an unexpected library error, @c ACL_ERROR is
193 * returned. Otherwise, @c ACL_SUCCESS.
194 *
195 */
196 int acl_set_entry(acl_t* aclp, acl_entry_t entry) {
197
198 acl_tag_t entry_tag;
199 if (acl_get_tag_type(entry, &entry_tag) == ACL_ERROR) {
200 perror("acl_set_entry (acl_get_tag_type)");
201 return ACL_ERROR;
202 }
203
204 acl_permset_t entry_permset;
205 if (acl_get_permset(entry, &entry_permset) == ACL_ERROR) {
206 perror("acl_set_entry (acl_get_permset)");
207 return ACL_ERROR;
208 }
209
210 acl_entry_t existing_entry;
211 /* Loop through the given ACL looking for matching entries. */
212 int result = acl_get_entry(*aclp, ACL_FIRST_ENTRY, &existing_entry);
213
214 while (result == ACL_SUCCESS) {
215 acl_tag_t existing_tag = ACL_UNDEFINED_TAG;
216
217 if (acl_get_tag_type(existing_entry, &existing_tag) == ACL_ERROR) {
218 perror("set_acl_tag_permset (acl_get_tag_type)");
219 return ACL_ERROR;
220 }
221
222 if (existing_tag == entry_tag) {
223 if (entry_tag == ACL_USER_OBJ ||
224 entry_tag == ACL_GROUP_OBJ ||
225 entry_tag == ACL_OTHER) {
226 /* Only update for these three since all other tags will have
227 been wiped. These three are guaranteed to exist, so if we
228 match one of them, we're allowed to return ACL_SUCCESS
229 below and bypass the rest of the function. */
230 acl_permset_t existing_permset;
231 if (acl_get_permset(existing_entry, &existing_permset) == ACL_ERROR) {
232 perror("acl_set_entry (acl_get_permset)");
233 return ACL_ERROR;
234 }
235
236 if (acl_set_permset(existing_entry, entry_permset) == ACL_ERROR) {
237 perror("acl_set_entry (acl_set_permset)");
238 return ACL_ERROR;
239 }
240
241 return ACL_SUCCESS;
242 }
243
244 }
245
246 result = acl_get_entry(*aclp, ACL_NEXT_ENTRY, &existing_entry);
247 }
248
249 /* This catches both the initial acl_get_entry and the ones at the
250 end of the loop. */
251 if (result == ACL_ERROR) {
252 perror("acl_set_entry (acl_get_entry)");
253 return ACL_ERROR;
254 }
255
256 /* If we've made it this far, we need to add a new entry to the
257 ACL. */
258 acl_entry_t new_entry;
259
260 /* The acl_create_entry() function can allocate new memory and/or
261 * change the location of the ACL structure entirely. When that
262 * happens, the value pointed to by aclp is updated, which means
263 * that a new acl_t gets "passed out" to our caller, eventually to
264 * be fed to acl_free(). In other words, we should still be freeing
265 * the right thing, even if the value pointed to by aclp changes.
266 */
267 if (acl_create_entry(aclp, &new_entry) == ACL_ERROR) {
268 perror("acl_set_entry (acl_create_entry)");
269 return ACL_ERROR;
270 }
271
272 if (acl_set_tag_type(new_entry, entry_tag) == ACL_ERROR) {
273 perror("acl_set_entry (acl_set_tag_type)");
274 return ACL_ERROR;
275 }
276
277 if (acl_set_permset(new_entry, entry_permset) == ACL_ERROR) {
278 perror("acl_set_entry (acl_set_permset)");
279 return ACL_ERROR;
280 }
281
282 if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) {
283 /* We need to set the qualifier too. */
284 void* entry_qual = acl_get_qualifier(entry);
285 if (entry_qual == (void*)NULL) {
286 perror("acl_set_entry (acl_get_qualifier)");
287 return ACL_ERROR;
288 }
289
290 if (acl_set_qualifier(new_entry, entry_qual) == ACL_ERROR) {
291 perror("acl_set_entry (acl_set_qualifier)");
292 return ACL_ERROR;
293 }
294 }
295
296 return ACL_SUCCESS;
297 }
298
299
300
301 /**
302 * @brief Determine the number of entries in the given ACL.
303 *
304 * @param acl
305 * The ACL to inspect.
306 *
307 * @return Either the non-negative number of entries in @c acl, or
308 * @c ACL_ERROR on error.
309 */
310 int acl_entry_count(acl_t acl) {
311
312 acl_entry_t entry;
313 int entry_count = 0;
314 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
315
316 while (result == ACL_SUCCESS) {
317 entry_count++;
318 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
319 }
320
321 if (result == ACL_ERROR) {
322 perror("acl_entry_count (acl_get_entry)");
323 return ACL_ERROR;
324 }
325
326 return entry_count;
327 }
328
329
330
331 /**
332 * @brief Determine whether or not the given ACL is minimal.
333 *
334 * An ACL is minimal if it has fewer than four entries.
335 *
336 * @param acl
337 * The ACL whose minimality is in question.
338 *
339 * @return
340 * - @c ACL_SUCCESS - @c acl is minimal
341 * - @c ACL_FAILURE - @c acl is not minimal
342 * - @c ACL_ERROR - Unexpected library error
343 */
344 int acl_is_minimal(acl_t acl) {
345
346 int ec = acl_entry_count(acl);
347
348 if (ec == ACL_ERROR) {
349 perror("acl_is_minimal (acl_entry_count)");
350 return ACL_ERROR;
351 }
352
353 if (ec < 4) {
354 return ACL_SUCCESS;
355 }
356 else {
357 return ACL_FAILURE;
358 }
359 }
360
361
362
363 /**
364 * @brief Determine whether the given ACL's mask denies execute.
365 *
366 * @param acl
367 * The ACL whose mask we want to check.
368 *
369 * @return
370 * - @c ACL_SUCCESS - The @c acl has a mask which denies execute.
371 * - @c ACL_FAILURE - The @c acl has a mask which does not deny execute.
372 * - @c ACL_ERROR - Unexpected library error.
373 */
374 int acl_execute_masked(acl_t acl) {
375
376 acl_entry_t entry;
377 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
378
379 while (ge_result == ACL_SUCCESS) {
380 acl_tag_t tag = ACL_UNDEFINED_TAG;
381
382 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
383 perror("acl_execute_masked (acl_get_tag_type)");
384 return ACL_ERROR;
385 }
386
387 if (tag == ACL_MASK) {
388 /* This is the mask entry, get its permissions, and see if
389 execute is specified. */
390 acl_permset_t permset;
391
392 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
393 perror("acl_execute_masked (acl_get_permset)");
394 return ACL_ERROR;
395 }
396
397 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
398 if (gp_result == ACL_ERROR) {
399 perror("acl_execute_masked (acl_get_perm)");
400 return ACL_ERROR;
401 }
402
403 if (gp_result == ACL_FAILURE) {
404 /* No execute bit set in the mask; execute not allowed. */
405 return ACL_SUCCESS;
406 }
407 }
408
409 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
410 }
411
412 return ACL_FAILURE;
413 }
414
415
416
417 /**
418 * @brief Determine whether @c fd is executable by anyone.
419 *
420 *
421 * This is used as part of the heuristic to determine whether or not
422 * we should mask the execute bit when inheriting an ACL. If @c fd
423 * describes a file, we check the @a effective permissions, contrary
424 * to what setfacl does.
425 *
426 * @param fd
427 * The file descriptor to check.
428 *
429 * @param sp
430 * A pointer to a stat structure for @c fd.
431 *
432 * @return
433 * - @c ACL_SUCCESS - Someone has effective execute permissions on @c fd.
434 * - @c ACL_FAILURE - Nobody can execute @c fd.
435 * - @c ACL_ERROR - Unexpected library error.
436 */
437 int any_can_execute(int fd, const struct stat* sp) {
438 acl_t acl = acl_get_fd(fd);
439
440 if (acl == (acl_t)NULL) {
441 perror("any_can_execute (acl_get_file)");
442 return ACL_ERROR;
443 }
444
445 /* Our return value. */
446 int result = ACL_FAILURE;
447
448 if (acl_is_minimal(acl)) {
449 if (sp->st_mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
450 result = ACL_SUCCESS;
451 goto cleanup;
452 }
453 else {
454 result = ACL_FAILURE;
455 goto cleanup;
456 }
457 }
458
459 acl_entry_t entry;
460 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
461
462 while (ge_result == ACL_SUCCESS) {
463 /* The first thing we do is check to see if this is a mask
464 entry. If it is, we skip it entirely. */
465 acl_tag_t tag = ACL_UNDEFINED_TAG;
466
467 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
468 perror("any_can_execute_or (acl_get_tag_type)");
469 result = ACL_ERROR;
470 goto cleanup;
471 }
472
473 if (tag == ACL_MASK) {
474 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
475 continue;
476 }
477
478 /* Ok, so it's not a mask entry. Check the execute perms. */
479 acl_permset_t permset;
480
481 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
482 perror("any_can_execute_or (acl_get_permset)");
483 result = ACL_ERROR;
484 goto cleanup;
485 }
486
487 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
488 if (gp_result == ACL_ERROR) {
489 perror("any_can_execute (acl_get_perm)");
490 result = ACL_ERROR;
491 goto cleanup;
492 }
493
494 if (gp_result == ACL_SUCCESS) {
495 /* Only return ACL_SUCCESS if this execute bit is not masked. */
496 if (acl_execute_masked(acl) != ACL_SUCCESS) {
497 result = ACL_SUCCESS;
498 goto cleanup;
499 }
500 }
501
502 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
503 }
504
505 if (ge_result == ACL_ERROR) {
506 perror("any_can_execute (acl_get_entry)");
507 result = ACL_ERROR;
508 goto cleanup;
509 }
510
511 cleanup:
512 acl_free(acl);
513 return result;
514 }
515
516
517
518 /**
519 * @brief Set @c acl as the default ACL on @c path.
520 *
521 * This overwrites any existing default ACL on @c path. If @c path is
522 * not a directory, we return ACL_ERROR and @c errno is set.
523 *
524 * @param path
525 * The target directory whose ACL we wish to replace or create.
526 *
527 * @param acl
528 * The ACL to set as default on @c path.
529 *
530 * @return
531 * - @c ACL_SUCCESS - The default ACL was assigned successfully.
532 * - @c ACL_ERROR - Unexpected library error.
533 */
534 int assign_default_acl(const char* path, acl_t acl) {
535
536 if (path == NULL) {
537 errno = EINVAL;
538 perror("assign_default_acl (args)");
539 return ACL_ERROR;
540 }
541
542 /* Our return value; success unless something bad happens. */
543 int result = ACL_SUCCESS;
544 acl_t path_acl = acl_dup(acl);
545
546 if (path_acl == (acl_t)NULL) {
547 perror("assign_default_acl (acl_dup)");
548 return ACL_ERROR; /* Nothing to clean up in this case. */
549 }
550
551 if (acl_set_file(path, ACL_TYPE_DEFAULT, path_acl) == ACL_ERROR) {
552 perror("assign_default_acl (acl_set_file)");
553 result = ACL_ERROR;
554 }
555
556 acl_free(path_acl);
557 return result;
558 }
559
560
561
562 /**
563 * @brief Remove all @c ACL_TYPE_ACCESS entries from the given file
564 * descriptor, leaving the UNIX permission bits.
565 *
566 * @param fd
567 * The file descriptor whose ACLs we want to wipe.
568 *
569 * @return
570 * - @c ACL_SUCCESS - The ACLs were wiped successfully, or none
571 * existed in the first place.
572 * - @c ACL_ERROR - Unexpected library error.
573 */
574 int wipe_acls(int fd) {
575 /* Initialize an empty ACL, and then overwrite the one on "fd" with it. */
576 acl_t empty_acl = acl_init(0);
577
578 if (empty_acl == (acl_t)NULL) {
579 perror("wipe_acls (acl_init)");
580 return ACL_ERROR;
581 }
582
583 if (acl_set_fd(fd, empty_acl) == ACL_ERROR) {
584 perror("wipe_acls (acl_set_fd)");
585 acl_free(empty_acl);
586 return ACL_ERROR;
587 }
588
589 acl_free(empty_acl);
590 return ACL_SUCCESS;
591 }
592
593
594
595 /**
596 * @brief Apply parent default ACL to a path.
597 *
598 * This overwrites any existing ACLs on @c path.
599 *
600 * @param path
601 * The path whose ACL we would like to reset to its default.
602 *
603 * @param sp
604 * A pointer to a stat structure for @c path, or @c NULL if you don't
605 * have one handy.
606 *
607 * @param no_exec_mask
608 * The value (either true or false) of the --no-exec-mask flag.
609 *
610 * @return
611 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
612 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
613 * - @c ACL_ERROR - Unexpected library error.
614 */
615 int apply_default_acl_ex(const char* path,
616 const struct stat* sp,
617 bool no_exec_mask) {
618
619 if (path == NULL) {
620 errno = EINVAL;
621 perror("apply_default_acl_ex (args)");
622 return ACL_ERROR;
623 }
624
625 /* Define these next three variables here because we may have to
626 * jump to the cleanup routine which expects them to exist.
627 */
628
629 /* Our return value. */
630 int result = ACL_SUCCESS;
631
632 /* The default ACL on path's parent directory */
633 acl_t defacl = (acl_t)NULL;
634
635 /* The file descriptor corresponding to "path" */
636 int fd = 0;
637
638 /* Get the parent directory of "path" with dirname(), which happens
639 * to murder its argument and necessitates a path_copy.
640 */
641 char* path_copy = strdup(path);
642 if (path_copy == NULL) {
643 perror("apply_default_acl_ex (strdup)");
644 return ACL_ERROR;
645 }
646 char* parent = dirname(path_copy);
647
648 fd = safe_open(path, O_NOFOLLOW);
649 if (fd == OPEN_ERROR) {
650 if (errno == ELOOP) {
651 result = ACL_FAILURE; /* hit a symlink */
652 goto cleanup;
653 }
654 else {
655 perror("apply_default_acl_ex (open fd)");
656 result = ACL_ERROR;
657 goto cleanup;
658 }
659 }
660
661
662 /* Refuse to operate on hard links, which can be abused by an
663 * attacker to trick us into changing the ACL on a file we didn't
664 * intend to; namely the "target" of the hard link. There is TOCTOU
665 * race condition here, but the window is as small as possible
666 * between when we open the file descriptor (look above) and when we
667 * fstat it.
668 *
669 * Note: we only need to call fstat ourselves if we weren't passed a
670 * valid pointer to a stat structure (nftw does that).
671 */
672 if (sp == NULL) {
673 struct stat s;
674 if (fstat(fd, &s) == STAT_ERROR) {
675 perror("apply_default_acl_ex (fstat)");
676 goto cleanup;
677 }
678
679 sp = &s;
680 }
681
682 if (!S_ISDIR(sp->st_mode)) {
683 /* If it's not a directory, make sure it's a regular,
684 non-hard-linked file. */
685 if (!S_ISREG(sp->st_mode) || sp->st_nlink != 1) {
686 result = ACL_FAILURE;
687 goto cleanup;
688 }
689 }
690
691
692 /* Default to not masking the exec bit; i.e. applying the default
693 ACL literally. If --no-exec-mask was not specified, then we try
694 to "guess" whether or not to mask the exec bit. This behavior
695 is modeled after the capital 'X' perms of setfacl. */
696 bool allow_exec = true;
697
698 if (!no_exec_mask) {
699 /* Never mask the execute bit on directories. */
700 int ace_result = any_can_execute(fd,sp) || S_ISDIR(sp->st_mode);
701
702 if (ace_result == ACL_ERROR) {
703 perror("apply_default_acl_ex (any_can_execute)");
704 result = ACL_ERROR;
705 goto cleanup;
706 }
707
708 allow_exec = (bool)ace_result;
709 }
710
711 defacl = acl_get_file(parent, ACL_TYPE_DEFAULT);
712
713 if (defacl == (acl_t)NULL) {
714 perror("apply_default_acl_ex (acl_get_file)");
715 result = ACL_ERROR;
716 goto cleanup;
717 }
718
719 if (wipe_acls(fd) == ACL_ERROR) {
720 perror("apply_default_acl_ex (wipe_acls)");
721 result = ACL_ERROR;
722 goto cleanup;
723 }
724
725 /* Do this after wipe_acls(), otherwise we'll overwrite the wiped
726 ACL with this one. */
727 acl_t acl = acl_get_fd(fd);
728 if (acl == (acl_t)NULL) {
729 perror("apply_default_acl_ex (acl_get_fd)");
730 result = ACL_ERROR;
731 goto cleanup;
732 }
733
734 /* If it's a directory, inherit the parent's default. We sure hope
735 * that "path" still points to the same thing that "fd" and this
736 * "sp" describe. If not, we may wind up trying to set a default ACL
737 * on a file, and this will throw an error. I guess that's what we
738 * want to do?
739 */
740 if (S_ISDIR(sp->st_mode) && assign_default_acl(path, defacl) == ACL_ERROR) {
741 perror("apply_default_acl_ex (assign_default_acl)");
742 result = ACL_ERROR;
743 goto cleanup;
744 }
745
746 acl_entry_t entry;
747 int ge_result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry);
748
749 while (ge_result == ACL_SUCCESS) {
750 acl_tag_t tag = ACL_UNDEFINED_TAG;
751
752 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
753 perror("apply_default_acl_ex (acl_get_tag_type)");
754 result = ACL_ERROR;
755 goto cleanup;
756 }
757
758
759 /* We've got an entry/tag from the default ACL. Get its permset. */
760 acl_permset_t permset;
761 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
762 perror("apply_default_acl_ex (acl_get_permset)");
763 result = ACL_ERROR;
764 goto cleanup;
765 }
766
767 /* If this is a default mask, fix it up. */
768 if (tag == ACL_MASK ||
769 tag == ACL_USER_OBJ ||
770 tag == ACL_GROUP_OBJ ||
771 tag == ACL_OTHER) {
772
773 if (!allow_exec) {
774 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
775 minimal ACLs) or acl_other entries, so if execute should be
776 masked, we have to do it manually. */
777 if (acl_delete_perm(permset, ACL_EXECUTE) == ACL_ERROR) {
778 perror("apply_default_acl_ex (acl_delete_perm)");
779 result = ACL_ERROR;
780 goto cleanup;
781 }
782
783 if (acl_set_permset(entry, permset) == ACL_ERROR) {
784 perror("apply_default_acl_ex (acl_set_permset)");
785 result = ACL_ERROR;
786 goto cleanup;
787 }
788 }
789 }
790
791 /* Finally, add the permset to the access ACL. It's actually
792 * important that we pass in the address of "acl" here, and not
793 * "acl" itself. Why? The call to acl_create_entry() within
794 * acl_set_entry() can allocate new memory for the entry.
795 * Sometimes that can be done in-place, in which case everything
796 * is cool and the new memory gets released when we call
797 * acl_free(acl).
798 *
799 * But occasionally, the whole ACL structure will have to be moved
800 * in order to allocate the extra space. When that happens,
801 * acl_create_entry() modifies the pointer it was passed (in this
802 * case, &acl) to point to the new location. We want to call
803 * acl_free() on the new location, and since acl_free() gets
804 * called right here, we need acl_create_entry() to update the
805 * value of "acl". To do that, it needs the address of "acl".
806 */
807 if (acl_set_entry(&acl, entry) == ACL_ERROR) {
808 perror("apply_default_acl_ex (acl_set_entry)");
809 result = ACL_ERROR;
810 goto cleanup;
811 }
812
813 ge_result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry);
814 }
815
816 /* Catches the first acl_get_entry as well as the ones at the end of
817 the loop. */
818 if (ge_result == ACL_ERROR) {
819 perror("apply_default_acl_ex (acl_get_entry)");
820 result = ACL_ERROR;
821 goto cleanup;
822 }
823
824 if (acl_set_fd(fd, acl) == ACL_ERROR) {
825 perror("apply_default_acl_ex (acl_set_fd)");
826 result = ACL_ERROR;
827 goto cleanup;
828 }
829
830 cleanup:
831 free(path_copy);
832 if (defacl != (acl_t)NULL) {
833 acl_free(defacl);
834 }
835 if (fd >= 0 && close(fd) == CLOSE_ERROR) {
836 perror("apply_default_acl_ex (close)");
837 result = ACL_ERROR;
838 }
839 return result;
840 }
841
842
843
844 /**
845 * @brief The friendly interface to @c apply_default_acl_ex.
846 *
847 * The @c apply_default_acl_ex function holds the real implementation
848 * of this function, but it takes a weird second argument that most
849 * people won't care about (a stat structure). But, we use that
850 * argument for the recursive mode of the CLI, so it's there.
851 *
852 * If you don't have a stat structure for your @c path, use this instead.
853 *
854 * @param path
855 * The path whose ACL we would like to reset to its default.
856 *
857 * @param no_exec_mask
858 * The value (either true or false) of the --no-exec-mask flag.
859 *
860 * @return
861 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
862 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
863 * or the parent of @c path is not a directory.
864 * - @c ACL_ERROR - Unexpected library error.
865 */
866 int apply_default_acl(const char* path, bool no_exec_mask) {
867 return apply_default_acl_ex(path, NULL, no_exec_mask);
868 }