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