]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/libadacl.c
libadacl.c: remove unused acl_get_permset() call in acl_set_entry().
[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 and the O_PATH flag. */
9 #define _GNU_SOURCE
10
11 #include <errno.h> /* EINVAL, ELOOP, ENOTDIR, 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) {
57 errno = EINVAL;
58 perror("safe_open_ex (args)");
59 return OPEN_ERROR;
60 }
61
62 char* firstslash = strchr(pathname, '/');
63 if (firstslash == NULL) {
64 /* No more slashes, this is the base case. */
65 return openat(at_fd, pathname, flags);
66 }
67 else if (firstslash[1] == '\0') {
68 /* The first slash is the last character; ensure that we open
69 a directory. */
70 firstslash[0] = '\0';
71 return openat(at_fd, pathname, flags | O_DIRECTORY);
72 }
73
74 /* The first slash exists and isn't the last character in the path,
75 so we can split the path wherever that first slash lies and
76 recurse. */
77 *firstslash = '\0';
78 int fd = openat(at_fd, pathname, flags | O_DIRECTORY | O_PATH);
79 if (fd == OPEN_ERROR) {
80 if (errno != ENOTDIR) {
81 /* Don't output anything if we ignore a symlink */
82 perror("safe_open_ex (safe_open_ex)");
83 }
84 return OPEN_ERROR;
85 }
86
87 /* The +1 is safe because there needs to be at least one character
88 after the first slash (we checked this above). */
89 int result = safe_open_ex(fd, firstslash+1, flags);
90 if (close(fd) == CLOSE_ERROR) {
91 perror("safe_open_ex (close)");
92 return OPEN_ERROR;
93 }
94 return result;
95 }
96
97
98 /**
99 * @brief A version of @c open that is completely symlink-safe when
100 * used with the @c O_NOFOLLOW flag.
101 *
102 * The @c openat function exists to ensure that you can anchor one
103 * path to a particular directory while opening it; however, if you
104 * open "b/c/d" relative to "/a", then even the @c openat function will
105 * still follow symlinks in the "b" component. This can be exploited
106 * by an attacker to make you open the wrong path.
107 *
108 * To avoid that problem, this function uses a recursive
109 * implementation that opens every path from the root, one level at a
110 * time. So "a" is opened relative to "/", and then "b" is opened
111 * relative to "/a", and then "c" is opened relative to "/a/b",
112 * etc. When the @c O_NOFOLLOW flag is used, this approach ensures
113 * that no symlinks in any component are followed.
114 *
115 * @param pathname
116 * The path to the file/directory/whatever whose descriptor you want.
117 *
118 * @param flags
119 * File status flags to be passed to @c openat.
120 *
121 * @return a file descriptor for @c pathname if everything goes well,
122 * and @c OPEN_ERROR if not.
123 */
124 int safe_open(const char* pathname, int flags) {
125 if (pathname == NULL || strlen(pathname) == 0 || pathname[0] == '\0') {
126 errno = EINVAL;
127 perror("safe_open (args)");
128 return OPEN_ERROR;
129 }
130
131 char abspath[PATH_MAX];
132 int snprintf_result = 0;
133 if (strchr(pathname, '/') == pathname) {
134 /* pathname is already absolute; just copy it. */
135 snprintf_result = snprintf(abspath, PATH_MAX, "%s", pathname);
136 }
137 else {
138 /* Concatenate the current working directory and pathname into an
139 * absolute path. We use realpath() ONLY on the cwd part, and not
140 * on the pathname part, because realpath() resolves symlinks. And
141 * the whole point of all this crap is to avoid following symlinks
142 * in the pathname.
143 *
144 * Using realpath() on the cwd lets us operate on relative paths
145 * while we're sitting in a directory that happens to have a
146 * symlink in it; for example: cd /var/run && apply-default-acl foo.
147 */
148 char* cwd = get_current_dir_name();
149 if (cwd == NULL) {
150 perror("safe_open (get_current_dir_name)");
151 return OPEN_ERROR;
152 }
153
154 char abs_cwd[PATH_MAX];
155 if (realpath(cwd, abs_cwd) == NULL) {
156 perror("safe_open (realpath)");
157 free(cwd);
158 return OPEN_ERROR;
159 }
160 snprintf_result = snprintf(abspath, PATH_MAX, "%s/%s", abs_cwd, pathname);
161 free(cwd);
162 }
163 if (snprintf_result == SNPRINTF_ERROR || snprintf_result > PATH_MAX) {
164 perror("safe_open (snprintf)");
165 return OPEN_ERROR;
166 }
167
168 int fd = 0;
169 if (strcmp(abspath, "/") == 0) {
170 fd = open("/", flags | O_DIRECTORY);
171 }
172 else {
173 /* Use O_PATH for some added safety if "/" is not our target */
174 fd = open("/", flags | O_DIRECTORY | O_PATH);
175 }
176 if (fd == OPEN_ERROR) {
177 perror("safe_open (open)");
178 return OPEN_ERROR;
179 }
180
181 if (strcmp(abspath, "/") == 0) {
182 return fd;
183 }
184
185 int result = safe_open_ex(fd, abspath+1, flags);
186 if (close(fd) == CLOSE_ERROR) {
187 perror("safe_open (close)");
188 return OPEN_ERROR;
189 }
190 return result;
191 }
192
193
194
195
196 /**
197 * @brief Update (or create) an entry in an @b minimal ACL.
198 *
199 * This function will not work if @c aclp contains extended
200 * entries. This is fine for our purposes, since we call @c wipe_acls
201 * on each path before applying the default to it.
202 *
203 * The assumption that there are no extended entries makes things much
204 * simpler. For example, we only have to update the @c ACL_USER_OBJ,
205 * @c ACL_GROUP_OBJ, and @c ACL_OTHER entries -- all others can simply
206 * be created anew. This means we don't have to fool around comparing
207 * named-user/group entries.
208 *
209 * @param aclp
210 * A pointer to the acl_t structure whose entry we want to modify.
211 *
212 * @param entry
213 * The new entry. If @c entry contains a user/group/other entry, we
214 * update the existing one. Otherwise we create a new entry.
215 *
216 * @return If there is an unexpected library error, @c ACL_ERROR is
217 * returned. Otherwise, @c ACL_SUCCESS.
218 *
219 */
220 int acl_set_entry(acl_t* aclp, acl_entry_t entry) {
221 if (aclp == NULL || entry == NULL) {
222 errno = EINVAL;
223 perror("acl_set_entry (args)");
224 return ACL_ERROR;
225 }
226
227 acl_tag_t entry_tag;
228 if (acl_get_tag_type(entry, &entry_tag) == ACL_ERROR) {
229 perror("acl_set_entry (acl_get_tag_type)");
230 return ACL_ERROR;
231 }
232
233 acl_permset_t entry_permset;
234 if (acl_get_permset(entry, &entry_permset) == ACL_ERROR) {
235 perror("acl_set_entry (acl_get_permset)");
236 return ACL_ERROR;
237 }
238
239 acl_entry_t existing_entry;
240 /* Loop through the given ACL looking for matching entries. */
241 int result = acl_get_entry(*aclp, ACL_FIRST_ENTRY, &existing_entry);
242
243 while (result == ACL_SUCCESS) {
244 acl_tag_t existing_tag = ACL_UNDEFINED_TAG;
245
246 if (acl_get_tag_type(existing_entry, &existing_tag) == ACL_ERROR) {
247 perror("set_acl_tag_permset (acl_get_tag_type)");
248 return ACL_ERROR;
249 }
250
251 if (existing_tag == entry_tag) {
252 if (entry_tag == ACL_USER_OBJ ||
253 entry_tag == ACL_GROUP_OBJ ||
254 entry_tag == ACL_OTHER) {
255 /* Only update for these three since all other tags will have
256 been wiped. These three are guaranteed to exist, so if we
257 match one of them, we're allowed to return ACL_SUCCESS
258 below and bypass the rest of the function. */
259 if (acl_set_permset(existing_entry, entry_permset) == ACL_ERROR) {
260 perror("acl_set_entry (acl_set_permset)");
261 return ACL_ERROR;
262 }
263
264 return ACL_SUCCESS;
265 }
266
267 }
268
269 result = acl_get_entry(*aclp, ACL_NEXT_ENTRY, &existing_entry);
270 }
271
272 /* This catches both the initial acl_get_entry and the ones at the
273 end of the loop. */
274 if (result == ACL_ERROR) {
275 perror("acl_set_entry (acl_get_entry)");
276 return ACL_ERROR;
277 }
278
279 /* If we've made it this far, we need to add a new entry to the
280 ACL. */
281 acl_entry_t new_entry;
282
283 /* The acl_create_entry() function can allocate new memory and/or
284 * change the location of the ACL structure entirely. When that
285 * happens, the value pointed to by aclp is updated, which means
286 * that a new acl_t gets "passed out" to our caller, eventually to
287 * be fed to acl_free(). In other words, we should still be freeing
288 * the right thing, even if the value pointed to by aclp changes.
289 */
290 if (acl_create_entry(aclp, &new_entry) == ACL_ERROR) {
291 perror("acl_set_entry (acl_create_entry)");
292 return ACL_ERROR;
293 }
294
295 if (acl_set_tag_type(new_entry, entry_tag) == ACL_ERROR) {
296 perror("acl_set_entry (acl_set_tag_type)");
297 return ACL_ERROR;
298 }
299
300 if (acl_set_permset(new_entry, entry_permset) == ACL_ERROR) {
301 perror("acl_set_entry (acl_set_permset)");
302 return ACL_ERROR;
303 }
304
305 if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) {
306 /* We need to set the qualifier too. */
307 void* entry_qual = acl_get_qualifier(entry);
308 if (entry_qual == (void*)NULL) {
309 perror("acl_set_entry (acl_get_qualifier)");
310 return ACL_ERROR;
311 }
312
313 if (acl_set_qualifier(new_entry, entry_qual) == ACL_ERROR) {
314 perror("acl_set_entry (acl_set_qualifier)");
315 return ACL_ERROR;
316 }
317 }
318
319 return ACL_SUCCESS;
320 }
321
322
323
324 /**
325 * @brief Determine the number of entries in the given ACL.
326 *
327 * @param acl
328 * The ACL to inspect.
329 *
330 * @return Either the non-negative number of entries in @c acl, or
331 * @c ACL_ERROR on error.
332 */
333 int acl_entry_count(acl_t acl) {
334
335 acl_entry_t entry;
336 int entry_count = 0;
337 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
338
339 while (result == ACL_SUCCESS) {
340 entry_count++;
341 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
342 }
343
344 if (result == ACL_ERROR) {
345 perror("acl_entry_count (acl_get_entry)");
346 return ACL_ERROR;
347 }
348
349 return entry_count;
350 }
351
352
353
354 /**
355 * @brief Determine whether or not the given ACL is minimal.
356 *
357 * An ACL is minimal if it has fewer than four entries.
358 *
359 * @param acl
360 * The ACL whose minimality is in question.
361 *
362 * @return
363 * - @c ACL_SUCCESS - @c acl is minimal
364 * - @c ACL_FAILURE - @c acl is not minimal
365 * - @c ACL_ERROR - Unexpected library error
366 */
367 int acl_is_minimal(acl_t acl) {
368 if (acl == NULL) {
369 errno = EINVAL;
370 perror("acl_is_minimal (args)");
371 return ACL_ERROR;
372 }
373
374 int ec = acl_entry_count(acl);
375
376 if (ec == ACL_ERROR) {
377 perror("acl_is_minimal (acl_entry_count)");
378 return ACL_ERROR;
379 }
380
381 if (ec < 4) {
382 return ACL_SUCCESS;
383 }
384 else {
385 return ACL_FAILURE;
386 }
387 }
388
389
390
391 /**
392 * @brief Determine whether the given ACL's mask denies execute.
393 *
394 * @param acl
395 * The ACL whose mask we want to check.
396 *
397 * @return
398 * - @c ACL_SUCCESS - The @c acl has a mask which denies execute.
399 * - @c ACL_FAILURE - The @c acl has a mask which does not deny execute.
400 * - @c ACL_ERROR - Unexpected library error.
401 */
402 int acl_execute_masked(acl_t acl) {
403 if (acl == NULL) {
404 errno = EINVAL;
405 perror("acl_execute_masked (args)");
406 return ACL_ERROR;
407 }
408
409 acl_entry_t entry;
410 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
411
412 while (ge_result == ACL_SUCCESS) {
413 acl_tag_t tag = ACL_UNDEFINED_TAG;
414
415 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
416 perror("acl_execute_masked (acl_get_tag_type)");
417 return ACL_ERROR;
418 }
419
420 if (tag == ACL_MASK) {
421 /* This is the mask entry, get its permissions, and see if
422 execute is specified. */
423 acl_permset_t permset;
424
425 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
426 perror("acl_execute_masked (acl_get_permset)");
427 return ACL_ERROR;
428 }
429
430 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
431 if (gp_result == ACL_ERROR) {
432 perror("acl_execute_masked (acl_get_perm)");
433 return ACL_ERROR;
434 }
435
436 if (gp_result == ACL_FAILURE) {
437 /* No execute bit set in the mask; execute not allowed. */
438 return ACL_SUCCESS;
439 }
440 }
441
442 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
443 }
444
445 return ACL_FAILURE;
446 }
447
448
449
450 /**
451 * @brief Determine whether @c fd is executable by anyone.
452 *
453 *
454 * This is used as part of the heuristic to determine whether or not
455 * we should mask the execute bit when inheriting an ACL. If @c fd
456 * describes a file, we check the @a effective permissions, contrary
457 * to what setfacl does.
458 *
459 * @param fd
460 * The file descriptor to check.
461 *
462 * @param sp
463 * A pointer to a stat structure for @c fd.
464 *
465 * @return
466 * - @c ACL_SUCCESS - Someone has effective execute permissions on @c fd.
467 * - @c ACL_FAILURE - Nobody can execute @c fd.
468 * - @c ACL_ERROR - Unexpected library error.
469 */
470 int any_can_execute(int fd, const struct stat* sp) {
471 if (sp == NULL) {
472 errno = EINVAL;
473 perror("any_can_execute (args)");
474 return ACL_ERROR;
475 }
476
477 acl_t acl = acl_get_fd(fd);
478
479 if (acl == (acl_t)NULL) {
480 perror("any_can_execute (acl_get_file)");
481 return ACL_ERROR;
482 }
483
484 /* Our return value. */
485 int result = ACL_FAILURE;
486
487 if (acl_is_minimal(acl)) {
488 if (sp->st_mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
489 result = ACL_SUCCESS;
490 goto cleanup;
491 }
492 else {
493 result = ACL_FAILURE;
494 goto cleanup;
495 }
496 }
497
498 acl_entry_t entry;
499 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
500
501 while (ge_result == ACL_SUCCESS) {
502 /* The first thing we do is check to see if this is a mask
503 entry. If it is, we skip it entirely. */
504 acl_tag_t tag = ACL_UNDEFINED_TAG;
505
506 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
507 perror("any_can_execute_or (acl_get_tag_type)");
508 result = ACL_ERROR;
509 goto cleanup;
510 }
511
512 if (tag == ACL_MASK) {
513 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
514 continue;
515 }
516
517 /* Ok, so it's not a mask entry. Check the execute perms. */
518 acl_permset_t permset;
519
520 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
521 perror("any_can_execute_or (acl_get_permset)");
522 result = ACL_ERROR;
523 goto cleanup;
524 }
525
526 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
527 if (gp_result == ACL_ERROR) {
528 perror("any_can_execute (acl_get_perm)");
529 result = ACL_ERROR;
530 goto cleanup;
531 }
532
533 if (gp_result == ACL_SUCCESS) {
534 /* Only return ACL_SUCCESS if this execute bit is not masked. */
535 if (acl_execute_masked(acl) != ACL_SUCCESS) {
536 result = ACL_SUCCESS;
537 goto cleanup;
538 }
539 }
540
541 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
542 }
543
544 if (ge_result == ACL_ERROR) {
545 perror("any_can_execute (acl_get_entry)");
546 result = ACL_ERROR;
547 goto cleanup;
548 }
549
550 cleanup:
551 acl_free(acl);
552 return result;
553 }
554
555
556
557 /**
558 * @brief Set @c acl as the default ACL on @c path.
559 *
560 * This overwrites any existing default ACL on @c path. If @c path is
561 * not a directory, we return ACL_ERROR and @c errno is set.
562 *
563 * @param path
564 * The target directory whose ACL we wish to replace or create.
565 *
566 * @param acl
567 * The ACL to set as default on @c path.
568 *
569 * @return
570 * - @c ACL_SUCCESS - The default ACL was assigned successfully.
571 * - @c ACL_ERROR - Unexpected library error.
572 */
573 int assign_default_acl(const char* path, acl_t acl) {
574 if (path == NULL || acl == NULL) {
575 errno = EINVAL;
576 perror("assign_default_acl (args)");
577 return ACL_ERROR;
578 }
579
580 /* Our return value; success unless something bad happens. */
581 int result = ACL_SUCCESS;
582 acl_t path_acl = acl_dup(acl);
583
584 if (path_acl == (acl_t)NULL) {
585 perror("assign_default_acl (acl_dup)");
586 return ACL_ERROR; /* Nothing to clean up in this case. */
587 }
588
589 if (acl_set_file(path, ACL_TYPE_DEFAULT, path_acl) == ACL_ERROR) {
590 perror("assign_default_acl (acl_set_file)");
591 result = ACL_ERROR;
592 }
593
594 acl_free(path_acl);
595 return result;
596 }
597
598
599
600 /**
601 * @brief Remove all @c ACL_TYPE_ACCESS entries from the given file
602 * descriptor, leaving the UNIX permission bits.
603 *
604 * @param fd
605 * The file descriptor whose ACLs we want to wipe.
606 *
607 * @return
608 * - @c ACL_SUCCESS - The ACLs were wiped successfully, or none
609 * existed in the first place.
610 * - @c ACL_ERROR - Unexpected library error.
611 */
612 int wipe_acls(int fd) {
613 /* Initialize an empty ACL, and then overwrite the one on "fd" with it. */
614 acl_t empty_acl = acl_init(0);
615
616 if (empty_acl == (acl_t)NULL) {
617 perror("wipe_acls (acl_init)");
618 return ACL_ERROR;
619 }
620
621 if (acl_set_fd(fd, empty_acl) == ACL_ERROR) {
622 perror("wipe_acls (acl_set_fd)");
623 acl_free(empty_acl);
624 return ACL_ERROR;
625 }
626
627 acl_free(empty_acl);
628 return ACL_SUCCESS;
629 }
630
631
632
633 /**
634 * @brief Apply parent default ACL to a path.
635 *
636 * This overwrites any existing ACLs on @c path.
637 *
638 * @param path
639 * The path whose ACL we would like to reset to its default.
640 *
641 * @param sp
642 * A pointer to a stat structure for @c path, or @c NULL if you don't
643 * have one handy.
644 *
645 * @param no_exec_mask
646 * The value (either true or false) of the --no-exec-mask flag.
647 *
648 * @return
649 * - @c ACL_SUCCESS - The parent default ACL was inherited successfully.
650 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
651 * - @c ACL_ERROR - Unexpected library error.
652 */
653 int apply_default_acl_ex(const char* path,
654 const struct stat* sp,
655 bool no_exec_mask) {
656
657 if (path == NULL) {
658 errno = EINVAL;
659 perror("apply_default_acl_ex (args)");
660 return ACL_ERROR;
661 }
662
663 /* Define these next three variables here because we may have to
664 * jump to the cleanup routine which expects them to exist.
665 */
666
667 /* Our return value. */
668 int result = ACL_SUCCESS;
669
670 /* The default ACL on path's parent directory */
671 acl_t defacl = (acl_t)NULL;
672
673 /* The file descriptor corresponding to "path" */
674 int fd = 0;
675
676 /* Get the parent directory of "path" with dirname(), which happens
677 * to murder its argument and necessitates a path_copy.
678 */
679 char* path_copy = strdup(path);
680 if (path_copy == NULL) {
681 perror("apply_default_acl_ex (strdup)");
682 return ACL_ERROR;
683 }
684 char* parent = dirname(path_copy);
685
686 fd = safe_open(path, O_NOFOLLOW);
687 if (fd == OPEN_ERROR) {
688 if (errno == ELOOP || errno == ENOTDIR) {
689 /* We hit a symlink, either in the last path component (ELOOP)
690 or higher up (ENOTDIR). */
691 result = ACL_FAILURE;
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 }