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