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