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