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