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