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