]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/libadacl.c
src: add prototypes for all functions.
[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, the O_PATH flag, and
9 * the asprintf() function.
10 */
11 #define _GNU_SOURCE
12
13 #include <dirent.h> /* readdir(), etc. */
14 #include <errno.h> /* EINVAL, ELOOP, ENOTDIR, etc. */
15 #include <fcntl.h> /* openat() */
16 #include <libgen.h> /* basename(), dirname() */
17 #include <stdbool.h> /* the "bool" type */
18 #include <stdio.h> /* perror(), asprintf() */
19 #include <stdlib.h> /* free() */
20 #include <string.h> /* strdup() */
21 #include <sys/stat.h> /* fstat() */
22 #include <sys/xattr.h> /* fgetxattr(), fsetxattr() */
23 #include <unistd.h> /* get_current_dir_name() */
24
25 /* ACLs */
26 #include <acl/libacl.h> /* acl_get_perm, not portable */
27 #include <sys/acl.h> /* all other acl_foo functions */
28
29 /* XATTR_NAME_POSIX_ACL_ACCESS and XATTR_NAME_POSIX_ACL_DEFAULT */
30 #include <linux/xattr.h>
31
32 #include "libadacl.h"
33
34
35 /* Even though most other library functions reliably return -1 for
36 * error, it feels a little wrong to re-use the ACL_ERROR constant.
37 */
38 #define CLOSE_ERROR -1
39 #define OPEN_ERROR -1
40 #define ASPRINTF_ERROR -1
41 #define STAT_ERROR -1
42 #define XATTR_ERROR -1
43
44
45 /* Prototypes */
46 int safe_open_ex(int at_fd, char* pathname, int flags);
47 int safe_open(const char* pathname, int flags);
48 int acl_update_entry(acl_t aclp, acl_entry_t entry);
49 int acl_entry_count(acl_t acl);
50 int acl_is_minimal(acl_t acl);
51 int acl_execute_masked(acl_t acl);
52 int any_can_execute(int fd, const struct stat* sp);
53 int acl_copy_xattr(int src_fd,
54 acl_type_t src_type,
55 int dst_fd,
56 acl_type_t dst_type);
57 int has_default_acl_fd(int fd);
58 int apply_default_acl_fds(int parent_fd, int fd, bool recursive);
59 int apply_default_acl(const char* path, bool recursive);
60
61
62
63 /**
64 * @brief The recursive portion of the @c safe_open function, used to
65 * open a file descriptor in a symlink-safe way when combined with
66 * the @c O_NOFOLLOW flag.
67 *
68 * @param at_fd
69 * A file descriptor relative to which @c pathname will be opened.
70 *
71 * @param pathname
72 * The path to the file/directory/whatever whose descriptor you want.
73 *
74 * @param flags
75 * File status flags to be passed to @c openat.
76 *
77 * @return a file descriptor for @c pathname if everything goes well,
78 * and @c OPEN_ERROR if not.
79 */
80 int safe_open_ex(int at_fd, char* pathname, int flags) {
81 if (pathname == NULL) {
82 errno = EINVAL;
83 perror("safe_open_ex (args)");
84 return OPEN_ERROR;
85 }
86
87 char* firstslash = strchr(pathname, '/');
88 if (firstslash == NULL) {
89 /* No more slashes, this is the base case. */
90 return openat(at_fd, pathname, flags);
91 }
92 if (firstslash[1] == '\0') {
93 /* The first slash is the last character; ensure that we open
94 a directory. */
95 firstslash[0] = '\0';
96 return openat(at_fd, pathname, flags | O_DIRECTORY);
97 }
98
99 /* The first slash exists and isn't the last character in the path,
100 so we can split the path wherever that first slash lies and
101 recurse. */
102 *firstslash = '\0';
103 int fd = openat(at_fd, pathname, flags | O_DIRECTORY | O_PATH);
104 if (fd == OPEN_ERROR) {
105 if (errno != ENOTDIR) {
106 /* Don't output anything if we ignore a symlink */
107 perror("safe_open_ex (safe_open_ex)");
108 }
109 return OPEN_ERROR;
110 }
111
112 /* The +1 is safe because there needs to be at least one character
113 after the first slash (we checked this above). */
114 int result = safe_open_ex(fd, firstslash+1, flags);
115 if (close(fd) == CLOSE_ERROR) {
116 perror("safe_open_ex (close)");
117 return OPEN_ERROR;
118 }
119 return result;
120 }
121
122
123 /**
124 * @brief A version of @c open that is completely symlink-safe when
125 * used with the @c O_NOFOLLOW flag.
126 *
127 * The @c openat function exists to ensure that you can anchor one
128 * path to a particular directory while opening it; however, if you
129 * open "b/c/d" relative to "/a", then even the @c openat function will
130 * still follow symlinks in the "b" component. This can be exploited
131 * by an attacker to make you open the wrong path.
132 *
133 * To avoid that problem, this function uses a recursive
134 * implementation that opens every path from the root, one level at a
135 * time. So "a" is opened relative to "/", and then "b" is opened
136 * relative to "/a", and then "c" is opened relative to "/a/b",
137 * etc. When the @c O_NOFOLLOW flag is used, this approach ensures
138 * that no symlinks in any component are followed.
139 *
140 * @param pathname
141 * The path to the file/directory/whatever whose descriptor you want.
142 *
143 * @param flags
144 * File status flags to be passed to @c openat.
145 *
146 * @return a file descriptor for @c pathname if everything goes well,
147 * and @c OPEN_ERROR if not.
148 */
149 int safe_open(const char* pathname, int flags) {
150 if (pathname == NULL) {
151 errno = EINVAL;
152 perror("safe_open (args)");
153 return OPEN_ERROR;
154 }
155
156 char* abspath = NULL;
157 int asprintf_result = 0;
158 if (strchr(pathname, '/') == pathname) {
159 /* pathname is already absolute; just copy it. */
160 asprintf_result = asprintf(&abspath, "%s", pathname);
161 }
162 else {
163 /* Concatenate the current working directory and pathname into an
164 * absolute path. We use realpath() ONLY on the cwd part, and not
165 * on the pathname part, because realpath() resolves symlinks. And
166 * the whole point of all this crap is to avoid following symlinks
167 * in the pathname.
168 *
169 * Using realpath() on the cwd lets us operate on relative paths
170 * while we're sitting in a directory that happens to have a
171 * symlink in it; for example: cd /var/run && apply-default-acl foo.
172 */
173 char* cwd = get_current_dir_name();
174 if (cwd == NULL) {
175 perror("safe_open (get_current_dir_name)");
176 return OPEN_ERROR;
177 }
178
179 char abs_cwd[PATH_MAX];
180 if (realpath(cwd, abs_cwd) == NULL) {
181 perror("safe_open (realpath)");
182 free(cwd);
183 return OPEN_ERROR;
184 }
185 asprintf_result = asprintf(&abspath, "%s/%s", abs_cwd, pathname);
186 free(cwd);
187 }
188 if (asprintf_result == ASPRINTF_ERROR) {
189 perror("safe_open (asprintf)");
190 return OPEN_ERROR;
191 }
192
193 /* Beyond here, asprintf() worked, and we need to free abspath. */
194 int result = OPEN_ERROR;
195
196 bool abspath_is_root = (strcmp(abspath, "/") == 0);
197 int rootflags = flags | O_DIRECTORY;
198 if (!abspath_is_root) {
199 /* Use O_PATH for some added safety if "/" is not our target */
200 rootflags |= O_PATH;
201 }
202 int rootfd = open("/", rootflags);
203 if (rootfd == OPEN_ERROR) {
204 perror("safe_open (open)");
205 result = OPEN_ERROR;
206 goto cleanup;
207 }
208
209 if (abspath_is_root) {
210 result = rootfd;
211 goto cleanup;
212 }
213
214 result = safe_open_ex(rootfd, abspath+1, flags);
215 if (close(rootfd) == CLOSE_ERROR) {
216 perror("safe_open (close)");
217 result = OPEN_ERROR;
218 goto cleanup;
219 }
220
221 cleanup:
222 free(abspath);
223 return result;
224 }
225
226
227
228
229 /**
230 * @brief Update an entry in an @b minimal ACL.
231 *
232 * @param aclp
233 * A pointer to the acl_t structure whose entry we want to update.
234 *
235 * @param entry
236 * The new entry.
237 *
238 * @return
239 * - @c ACL_SUCCESS - If we update an existing entry.
240 * - @c ACL_FAILURE - If we don't find an entry to update.
241 * - @c ACL_ERROR - Unexpected library error.
242 */
243 int acl_update_entry(acl_t aclp, acl_entry_t entry) {
244 if (aclp == NULL || entry == NULL) {
245 errno = EINVAL;
246 perror("acl_update_entry (args)");
247 return ACL_ERROR;
248 }
249
250 acl_tag_t entry_tag;
251 if (acl_get_tag_type(entry, &entry_tag) == ACL_ERROR) {
252 perror("acl_update_entry (acl_get_tag_type)");
253 return ACL_ERROR;
254 }
255
256 acl_permset_t entry_permset;
257 if (acl_get_permset(entry, &entry_permset) == ACL_ERROR) {
258 perror("acl_update_entry (acl_get_permset)");
259 return ACL_ERROR;
260 }
261
262 acl_entry_t existing_entry;
263 /* Loop through the given ACL looking for matching entries. */
264 int result = acl_get_entry(aclp, ACL_FIRST_ENTRY, &existing_entry);
265
266 while (result == ACL_SUCCESS) {
267 acl_tag_t existing_tag = ACL_UNDEFINED_TAG;
268
269 if (acl_get_tag_type(existing_entry, &existing_tag) == ACL_ERROR) {
270 perror("set_acl_tag_permset (acl_get_tag_type)");
271 return ACL_ERROR;
272 }
273
274 if (existing_tag == entry_tag) {
275 /* If we update something, we're done and return ACL_SUCCESS */
276 if (acl_set_permset(existing_entry, entry_permset) == ACL_ERROR) {
277 perror("acl_update_entry (acl_set_permset)");
278 return ACL_ERROR;
279 }
280
281 return ACL_SUCCESS;
282 }
283
284 result = acl_get_entry(aclp, ACL_NEXT_ENTRY, &existing_entry);
285 }
286
287 /* This catches both the initial acl_get_entry and the ones at the
288 end of the loop. */
289 if (result == ACL_ERROR) {
290 perror("acl_update_entry (acl_get_entry)");
291 return ACL_ERROR;
292 }
293
294 return ACL_FAILURE;
295 }
296
297
298
299 /**
300 * @brief Determine the number of entries in the given ACL.
301 *
302 * @param acl
303 * The ACL to inspect.
304 *
305 * @return Either the non-negative number of entries in @c acl, or
306 * @c ACL_ERROR on error.
307 */
308 int acl_entry_count(acl_t acl) {
309
310 acl_entry_t entry;
311 int entry_count = 0;
312 int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
313
314 while (result == ACL_SUCCESS) {
315 entry_count++;
316 result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
317 }
318
319 if (result == ACL_ERROR) {
320 perror("acl_entry_count (acl_get_entry)");
321 return ACL_ERROR;
322 }
323
324 return entry_count;
325 }
326
327
328
329 /**
330 * @brief Determine whether or not the given ACL is minimal.
331 *
332 * An ACL is minimal if it has fewer than four entries.
333 *
334 * @param acl
335 * The ACL whose minimality is in question.
336 *
337 * @return
338 * - @c ACL_SUCCESS - @c acl is minimal
339 * - @c ACL_FAILURE - @c acl is not minimal
340 * - @c ACL_ERROR - Unexpected library error
341 */
342 int acl_is_minimal(acl_t acl) {
343 if (acl == NULL) {
344 errno = EINVAL;
345 perror("acl_is_minimal (args)");
346 return ACL_ERROR;
347 }
348
349 int ec = acl_entry_count(acl);
350
351 if (ec == ACL_ERROR) {
352 perror("acl_is_minimal (acl_entry_count)");
353 return ACL_ERROR;
354 }
355
356 if (ec < 4) {
357 return ACL_SUCCESS;
358 }
359 else {
360 return ACL_FAILURE;
361 }
362 }
363
364
365
366 /**
367 * @brief Determine whether the given ACL's mask denies execute.
368 *
369 * @param acl
370 * The ACL whose mask we want to check.
371 *
372 * @return
373 * - @c ACL_SUCCESS - The @c acl has a mask which denies execute.
374 * - @c ACL_FAILURE - The @c acl has a mask which does not deny execute.
375 * - @c ACL_ERROR - Unexpected library error.
376 */
377 int acl_execute_masked(acl_t acl) {
378 if (acl == NULL) {
379 errno = EINVAL;
380 perror("acl_execute_masked (args)");
381 return ACL_ERROR;
382 }
383
384 acl_entry_t entry;
385 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
386
387 while (ge_result == ACL_SUCCESS) {
388 acl_tag_t tag = ACL_UNDEFINED_TAG;
389
390 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
391 perror("acl_execute_masked (acl_get_tag_type)");
392 return ACL_ERROR;
393 }
394
395 if (tag == ACL_MASK) {
396 /* This is the mask entry, get its permissions, and see if
397 execute is specified. */
398 acl_permset_t permset;
399
400 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
401 perror("acl_execute_masked (acl_get_permset)");
402 return ACL_ERROR;
403 }
404
405 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
406 if (gp_result == ACL_ERROR) {
407 perror("acl_execute_masked (acl_get_perm)");
408 return ACL_ERROR;
409 }
410
411 if (gp_result == ACL_FAILURE) {
412 /* No execute bit set in the mask; execute not allowed. */
413 return ACL_SUCCESS;
414 }
415 }
416
417 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
418 }
419
420 return ACL_FAILURE;
421 }
422
423
424
425 /**
426 * @brief Determine whether @c fd is executable by anyone.
427 *
428 *
429 * This is used as part of the heuristic to determine whether or not
430 * we should mask the execute bit when inheriting an ACL. If @c fd
431 * describes a file, we check the @a effective permissions, contrary
432 * to what setfacl does.
433 *
434 * @param fd
435 * The file descriptor to check.
436 *
437 * @param sp
438 * A pointer to a stat structure for @c fd.
439 *
440 * @return
441 * - @c ACL_SUCCESS - Someone has effective execute permissions on @c fd.
442 * - @c ACL_FAILURE - Nobody can execute @c fd.
443 * - @c ACL_ERROR - Unexpected library error.
444 */
445 int any_can_execute(int fd, const struct stat* sp) {
446 if (sp == NULL) {
447 errno = EINVAL;
448 perror("any_can_execute (args)");
449 return ACL_ERROR;
450 }
451
452 acl_t acl = acl_get_fd(fd);
453
454 if (acl == (acl_t)NULL) {
455 perror("any_can_execute (acl_get_fd)");
456 return ACL_ERROR;
457 }
458
459 /* Our return value. */
460 int result = ACL_FAILURE;
461
462 if (acl_is_minimal(acl)) {
463 if (sp->st_mode & (S_IXUSR | S_IXOTH | S_IXGRP)) {
464 result = ACL_SUCCESS;
465 goto cleanup;
466 }
467 else {
468 result = ACL_FAILURE;
469 goto cleanup;
470 }
471 }
472
473 acl_entry_t entry;
474 int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
475
476 while (ge_result == ACL_SUCCESS) {
477 /* The first thing we do is check to see if this is a mask
478 entry. If it is, we skip it entirely. */
479 acl_tag_t tag = ACL_UNDEFINED_TAG;
480
481 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
482 perror("any_can_execute_or (acl_get_tag_type)");
483 result = ACL_ERROR;
484 goto cleanup;
485 }
486
487 if (tag == ACL_MASK) {
488 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
489 continue;
490 }
491
492 /* Ok, so it's not a mask entry. Check the execute perms. */
493 acl_permset_t permset;
494
495 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
496 perror("any_can_execute_or (acl_get_permset)");
497 result = ACL_ERROR;
498 goto cleanup;
499 }
500
501 int gp_result = acl_get_perm(permset, ACL_EXECUTE);
502 if (gp_result == ACL_ERROR) {
503 perror("any_can_execute (acl_get_perm)");
504 result = ACL_ERROR;
505 goto cleanup;
506 }
507
508 if (gp_result == ACL_SUCCESS) {
509 /* Only return ACL_SUCCESS if this execute bit is not masked. */
510 if (acl_execute_masked(acl) != ACL_SUCCESS) {
511 result = ACL_SUCCESS;
512 goto cleanup;
513 }
514 }
515
516 ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
517 }
518
519 if (ge_result == ACL_ERROR) {
520 perror("any_can_execute (acl_get_entry)");
521 result = ACL_ERROR;
522 goto cleanup;
523 }
524
525 cleanup:
526 acl_free(acl);
527 return result;
528 }
529
530
531
532 /**
533 * @brief Copy ACLs between file descriptors as xattrs, verbatim.
534 *
535 * There is a small deficiency in libacl, namely that there is no way
536 * to get or set default ACLs through file descriptors. The @c
537 * acl_get_file and @c acl_set_file functions can do it, but they use
538 * paths, and are vulnerable to symlink attacks.
539 *
540 * Fortunately, when inheriting an ACL, we don't really need to look
541 * at what it contains. That means that we can copy the on-disk xattrs
542 * from the source directory to the destination file/directory without
543 * passing through libacl, and this can be done with file descriptors
544 * through @c fgetxattr and @c fsetxattr. That's what this function
545 * does.
546 *
547 * @param src_fd
548 * The file descriptor from which the ACL will be copied.
549 *
550 * @param src_type
551 * The type of ACL (either @c ACL_TYPE_ACCESS or @c ACL_TYPE_DEFAULT)
552 * to copy from @c src_fd.
553 *
554 * @param dst_fd
555 * The file descriptor whose ACL will be overwritten with the one
556 * from @c src_fd.
557 *
558 * @param dst_type
559 * The type of ACL (either @c ACL_TYPE_ACCESS or @c ACL_TYPE_DEFAULT)
560 * to replace on @c dst_fd.
561 *
562 * @return
563 * - @c ACL_SUCCESS - The ACL was copied successfully.
564 * - @c ACL_FAILURE - There was no ACL on @c src_fd.
565 * - @c ACL_ERROR - Unexpected library error.
566 */
567 int acl_copy_xattr(int src_fd,
568 acl_type_t src_type,
569 int dst_fd,
570 acl_type_t dst_type) {
571
572 const char* src_name;
573 if (src_type == ACL_TYPE_ACCESS) {
574 src_name = XATTR_NAME_POSIX_ACL_ACCESS;
575 }
576 else if (src_type == ACL_TYPE_DEFAULT) {
577 src_name = XATTR_NAME_POSIX_ACL_DEFAULT;
578 }
579 else {
580 errno = EINVAL;
581 perror("acl_copy_xattr (src type)");
582 return ACL_ERROR;
583 }
584
585 const char* dst_name;
586 if (dst_type == ACL_TYPE_ACCESS) {
587 dst_name = XATTR_NAME_POSIX_ACL_ACCESS;
588 }
589 else if (dst_type == ACL_TYPE_DEFAULT) {
590 dst_name = XATTR_NAME_POSIX_ACL_DEFAULT;
591 }
592 else {
593 errno = EINVAL;
594 perror("acl_copy_xattr (dst type)");
595 return ACL_ERROR;
596 }
597
598 ssize_t src_size_guess = fgetxattr(src_fd, src_name, NULL, 0);
599 if (src_size_guess == XATTR_ERROR) {
600 if (errno == ENODATA) {
601 /* A missing ACL isn't really an error. ENOATTR and ENODATA are
602 synonyms, but using ENODATA here lets us avoid another
603 "include" directive. */
604 return ACL_FAILURE;
605 }
606 perror("acl_copy_xattr (fgetxattr size guess)");
607 return ACL_ERROR;
608 }
609 char* src_acl_p = alloca(src_size_guess);
610 /* The actual size may be smaller than our guess? I don't know. */
611 ssize_t src_size = fgetxattr(src_fd, src_name, src_acl_p, src_size_guess);
612 if (src_size == XATTR_ERROR) {
613 if (errno == ENODATA) {
614 /* A missing ACL isn't an error. */
615 return ACL_FAILURE;
616 }
617 perror("acl_copy_xattr (fgetxattr)");
618 return ACL_ERROR;
619 }
620
621 if (fsetxattr(dst_fd, dst_name, src_acl_p, src_size, 0) == XATTR_ERROR) {
622 perror("acl_copy_xattr (fsetxattr)");
623 return ACL_ERROR;
624 }
625
626 return ACL_SUCCESS;
627 }
628
629
630 /**
631 * @brief Determine if a file descriptor has a default ACL.
632 *
633 * @param fd
634 * The file descriptor whose default ACL is in question.
635 *
636 * @return
637 * - @c ACL_SUCCESS - If @c fd has a default ACL.
638 * - @c ACL_FAILURE - If @c fd does not have a default ACL.
639 * - @c ACL_ERROR - Unexpected library error.
640 */
641 int has_default_acl_fd(int fd) {
642 if (fgetxattr(fd, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0) == XATTR_ERROR) {
643 if (errno == ENODATA) {
644 return ACL_FAILURE;
645 }
646 perror("has_default_acl_fd (fgetxattr)");
647 return ACL_ERROR;
648 }
649
650 return ACL_SUCCESS;
651 }
652
653
654
655 /**
656 * @brief The recursive portion of @c apply_default_acl.
657 *
658 * The @c apply_default_acl function takes a path, but then opens file
659 * descriptors for the path and its parent. Afterwards, everything is
660 * done using file descriptors, including the recursive application on
661 * the path's children. This function encapsulates the portion of @c
662 * apply_default_acl that uses only file descriptors; for the
663 * recursion, this function ultimately calls itself.
664 *
665 * This overwrites any existing ACLs on @c fd and, if @c recursive is
666 * @c true, its children. When @c recursive is @c true, the "worst"
667 * result encountered is returned as the overall result.
668 *
669 * @param parent_fd
670 * A file descriptor for the parent directory of @c fd.
671 *
672 * @param fd
673 * The file descriptor that should inherit its parent's default ACL.
674 *
675 * @param recursive
676 * Should we recurse into subdirectories?
677 *
678 * @return
679 * - @c ACL_SUCCESS - The parent default ACLs were inherited successfully.
680 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
681 * - @c ACL_ERROR - Unexpected library error.
682 */
683 int apply_default_acl_fds(int parent_fd,
684 int fd,
685 bool recursive) {
686 int result = ACL_SUCCESS;
687
688 /* The new ACL for this path */
689 acl_t new_acl = (acl_t)NULL;
690
691 /* A copy of new_acl, to be made before we begin mangling new_acl in
692 order to mask the execute bit. */
693 acl_t new_acl_unmasked = (acl_t)NULL;
694
695 /* Refuse to operate on hard links, which can be abused by an
696 * attacker to trick us into changing the ACL on a file we didn't
697 * intend to; namely the "target" of the hard link. There is TOCTOU
698 * race condition here, but the window is as small as possible
699 * between when we open the file descriptor (look above) and when we
700 * fstat it.
701 */
702 struct stat s;
703 if (fstat(fd, &s) == STAT_ERROR) {
704 perror("apply_default_acl_fds (fstat)");
705 /* We can't recurse without the stat struct for fd */
706 goto cleanup;
707 }
708
709
710 /* Check to make sure the parent descriptor actually has a default
711 ACL. If it doesn't, then we can "succeed" immediately, saving a
712 little work, particularly in any_can_execute(). Note that we
713 can't skip the fstat() above, because we need it in case we
714 recurse. */
715 if (has_default_acl_fd(parent_fd) == ACL_FAILURE) {
716 result = ACL_SUCCESS;
717 /* Just because this target can't inherit anything doesn't mean
718 that one of it's children can't. For example, if there's a
719 default on "c" in "a/b/c/d", then we don't want to skip all
720 children of "a"! */
721 goto recurse;
722 }
723
724
725 if (!S_ISDIR(s.st_mode)) {
726 /* If it's not a directory, make sure it's a regular,
727 non-hard-linked file. */
728 if (!S_ISREG(s.st_mode) || s.st_nlink != 1) {
729 result = ACL_FAILURE;
730 goto cleanup; /* It's not a directory, so we can skip the recursion. */
731 }
732 }
733
734
735 /* Next We try to guess whether or not to strip the execute bits.
736 * This behavior is modeled after the capital 'X' perms of setfacl.
737 */
738 int ace_result = any_can_execute(fd, &s);
739
740 if (ace_result == ACL_ERROR) {
741 perror("apply_default_acl_fds (any_can_execute)");
742 result = ACL_ERROR;
743 goto cleanup;
744 }
745
746 /* Never mask the execute bit on directories. */
747 bool allow_exec = (bool)ace_result || S_ISDIR(s.st_mode);
748
749
750 /* If it's a directory, inherit the parent's default. */
751 if (S_ISDIR(s.st_mode)) {
752 if (acl_copy_xattr(parent_fd,
753 ACL_TYPE_DEFAULT,
754 fd,
755 ACL_TYPE_DEFAULT) == ACL_ERROR) {
756 perror("apply_default_acl_fds (acl_copy_xattr default)");
757 result = ACL_ERROR;
758 goto cleanup;
759 }
760 }
761
762 /* If it's anything, _apply_ the parent's default. */
763 if (acl_copy_xattr(parent_fd,
764 ACL_TYPE_DEFAULT,
765 fd,
766 ACL_TYPE_ACCESS) == ACL_ERROR) {
767 perror("apply_default_acl_fds (acl_copy_xattr access)");
768 result = ACL_ERROR;
769 goto cleanup;
770 }
771
772 /* There's a good reason why we saved the ACL above, even though
773 * we're about to read it back into memory and mess with it on the
774 * next line. The acl_copy_xattr() function is already a hack to let
775 * us copy default ACLs without resorting to path names; we simply
776 * have no way to read the parent's default ACL into memory using
777 * parent_fd. We can, however, copy the parent's ACL to a file (with
778 * acl_copy_xattr), and then read the ACL from a file using
779 * "fd". It's quite the circus, but it works and should be safe from
780 * sym/hardlink attacks.
781 */
782
783 /* Now we potentially need to mask the execute permissions in the
784 ACL on fd; or maybe not. */
785 if (allow_exec) {
786 /* Skip the mask code for this target, but don't skip its children! */
787 goto recurse;
788 }
789
790 /* OK, we need to mask some execute permissions. First obtain the
791 current ACL... */
792 new_acl = acl_get_fd(fd);
793 if (new_acl == (acl_t)NULL) {
794 perror("apply_default_acl_fds (acl_get_fd)");
795 result = ACL_ERROR;
796 goto cleanup;
797 }
798
799 /* ...and now make a copy of it, because otherwise when we loop
800 below, some shit gets stuck (modifying the structure while
801 looping over it no worky). */
802 new_acl_unmasked = acl_dup(new_acl);
803 if (new_acl_unmasked == (acl_t)NULL) {
804 perror("apply_default_acl_fds (acl_dup)");
805 result = ACL_ERROR;
806 goto cleanup;
807 }
808
809 acl_entry_t entry;
810 int ge_result = acl_get_entry(new_acl_unmasked, ACL_FIRST_ENTRY, &entry);
811
812 while (ge_result == ACL_SUCCESS) {
813 acl_tag_t tag = ACL_UNDEFINED_TAG;
814
815 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
816 perror("apply_default_acl_fds (acl_get_tag_type)");
817 result = ACL_ERROR;
818 goto cleanup;
819 }
820
821
822 /* We've got an entry/tag from the default ACL. Get its permset. */
823 acl_permset_t permset;
824 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
825 perror("apply_default_acl_fds (acl_get_permset)");
826 result = ACL_ERROR;
827 goto cleanup;
828 }
829
830 /* To mimic what the kernel does, I think we could drop
831 ACL_GROUP_OBJ from the list below? */
832 if (tag == ACL_MASK ||
833 tag == ACL_USER_OBJ ||
834 tag == ACL_GROUP_OBJ ||
835 tag == ACL_OTHER) {
836
837 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
838 minimal ACLs) or acl_other entries, so if execute should be
839 masked, we have to do it manually. */
840 if (acl_delete_perm(permset, ACL_EXECUTE) == ACL_ERROR) {
841 perror("apply_default_acl_fds (acl_delete_perm)");
842 result = ACL_ERROR;
843 goto cleanup;
844 }
845
846 if (acl_set_permset(entry, permset) == ACL_ERROR) {
847 perror("apply_default_acl_fds (acl_set_permset)");
848 result = ACL_ERROR;
849 goto cleanup;
850 }
851 }
852
853 if (acl_update_entry(new_acl, entry) == ACL_ERROR) {
854 perror("apply_default_acl_fds (acl_update_entry)");
855 result = ACL_ERROR;
856 goto cleanup;
857 }
858
859 ge_result = acl_get_entry(new_acl_unmasked, ACL_NEXT_ENTRY, &entry);
860 }
861
862 /* Catches the first acl_get_entry as well as the ones at the end of
863 the loop. */
864 if (ge_result == ACL_ERROR) {
865 perror("apply_default_acl_fds (acl_get_entry)");
866 result = ACL_ERROR;
867 goto cleanup;
868 }
869
870 if (acl_set_fd(fd, new_acl) == ACL_ERROR) {
871 perror("apply_default_acl_fds (acl_set_fd)");
872 result = ACL_ERROR;
873 goto cleanup;
874 }
875
876 recurse:
877 if (recursive && S_ISDIR(s.st_mode)) {
878 /* Recurse into subdirectories. Don't call closedir() on d! It
879 closes the open file descriptor as well, and subsequent calls
880 to close() then throw errors. */
881 DIR* d = fdopendir(fd);
882 if (d == NULL) {
883 perror("apply_default_acl_fds (fdopendir)");
884 result = ACL_ERROR;
885 goto cleanup;
886 }
887
888 struct dirent* de;
889 int new_fd = 0;
890 while ((de = readdir(d)) != NULL) {
891 if (de->d_type != DT_DIR && de->d_type != DT_REG) {
892 /* Hit a symlink or whatever. */
893 result = ACL_FAILURE;
894 continue;
895 }
896 if (strcmp(de->d_name, ".") == 0) { continue; }
897 if (strcmp(de->d_name, "..") == 0) { continue; }
898
899 /* Be careful not to "return" out of this loop and leave the
900 new_fd open! */
901 new_fd = openat(fd, de->d_name, O_NOFOLLOW);
902 if (new_fd == OPEN_ERROR) {
903 if (errno == ELOOP || errno == ENOTDIR) {
904 /* We hit a symlink, either in the last path component (ELOOP)
905 or higher up (ENOTDIR). */
906 if (result == ACL_SUCCESS) {
907 /* Don't overwrite an error result with success/failure. */
908 result = ACL_FAILURE;
909 }
910 continue;
911 }
912 else {
913 perror("apply_default_acl_fds (openat)");
914 result = ACL_ERROR;
915 continue;
916 }
917 }
918 switch (apply_default_acl_fds(fd, new_fd, recursive)) {
919 /* Don't overwrite an error result with success/failure. */
920 case ACL_FAILURE:
921 if (result == ACL_SUCCESS) {
922 result = ACL_FAILURE;
923 }
924 break;
925 case ACL_ERROR:
926 result = ACL_ERROR;
927 default:
928 if (close(new_fd) == CLOSE_ERROR) {
929 perror("apply_default_acl_fds (close)");
930 result = ACL_ERROR;
931 }
932 }
933 }
934 }
935
936 cleanup:
937 acl_free(new_acl);
938 acl_free(new_acl_unmasked);
939 return result;
940 }
941
942
943 /**
944 * @brief Apply parent default ACL to a path and optionally its children.
945 *
946 * This overwrites any existing ACLs on the target, and, if @c
947 * recursive is @c true, its children. When @c recursive is @c true,
948 * the "worst" result encountered is returned as the overall result.
949 *
950 * @param path
951 * The path whose ACL we would like to reset to its default.
952 *
953 * @param recursive
954 * Should we recurse into subdirectories?
955 *
956 * @return
957 * - @c ACL_SUCCESS - The parent default ACLs were inherited successfully.
958 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
959 * - @c ACL_ERROR - Unexpected library error.
960 */
961 int apply_default_acl(const char* path, bool recursive) {
962
963 if (path == NULL) {
964 errno = EINVAL;
965 perror("apply_default_acl (args)");
966 return ACL_ERROR;
967 }
968
969 /* Define these next three variables here because we may have to
970 * jump to the cleanup routine which expects them to exist.
971 */
972
973 /* Our return value. */
974 int result = ACL_SUCCESS;
975
976 /* The file descriptor corresponding to "path" */
977 int fd = 0;
978
979 /* The file descriptor for the directory containing "path" */
980 int parent_fd = 0;
981
982 /* dirname() and basename() mangle their arguments, so we need
983 to make copies of "path" before using them. */
984 char* dirname_path_copy = NULL;
985 char* basename_path_copy = NULL;
986
987 /* Get the parent directory of "path" with dirname(), which happens
988 * to murder its argument and necessitates a path_copy. */
989 dirname_path_copy = strdup(path);
990 if (dirname_path_copy == NULL) {
991 perror("apply_default_acl (strdup)");
992 return ACL_ERROR;
993 }
994 char* parent = dirname(dirname_path_copy);
995 parent_fd = safe_open(parent, O_DIRECTORY | O_NOFOLLOW);
996 if (parent_fd == OPEN_ERROR) {
997 if (errno == ELOOP || errno == ENOTDIR) {
998 /* We hit a symlink, either in the last path component (ELOOP)
999 or higher up (ENOTDIR). */
1000 result = ACL_FAILURE;
1001 goto cleanup;
1002 }
1003 else {
1004 perror("apply_default_acl (open parent fd)");
1005 result = ACL_ERROR;
1006 goto cleanup;
1007 }
1008 }
1009
1010 /* We already obtained the parent fd safely, so if we use the
1011 basename of path here instead of the full thing, then we can get
1012 away with using openat() and spare ourselves the slowness of
1013 another safe_open(). */
1014 basename_path_copy = strdup(path);
1015 if (basename_path_copy == NULL) {
1016 perror("apply_default_acl (strdup)");
1017 return ACL_ERROR;
1018 }
1019 fd = openat(parent_fd, basename(basename_path_copy), O_NOFOLLOW);
1020 if (fd == OPEN_ERROR) {
1021 if (errno == ELOOP || errno == ENOTDIR) {
1022 /* We hit a symlink, either in the last path component (ELOOP)
1023 or higher up (ENOTDIR). */
1024 result = ACL_FAILURE;
1025 goto cleanup;
1026 }
1027 else {
1028 perror("apply_default_acl (open fd)");
1029 result = ACL_ERROR;
1030 goto cleanup;
1031 }
1032 }
1033
1034 result = apply_default_acl_fds(parent_fd, fd, recursive);
1035
1036 cleanup:
1037 free(dirname_path_copy);
1038 free(basename_path_copy);
1039
1040 if (parent_fd > 0 && close(parent_fd) == CLOSE_ERROR) {
1041 perror("apply_default_acl (close parent_fd)");
1042 result = ACL_ERROR;
1043 }
1044 if (fd > 0 && close(fd) == CLOSE_ERROR) {
1045 perror("apply_default_acl (close fd)");
1046 result = ACL_ERROR;
1047 }
1048 return result;
1049 }