]> gitweb.michael.orlitzky.com - apply-default-acl.git/blob - src/libadacl.c
53bd380a06013c5475d37c15b19ec59ad2a9c393
[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, int fd, bool recursive) {
684 int result = ACL_SUCCESS;
685
686 /* The new ACL for this path */
687 acl_t new_acl = (acl_t)NULL;
688
689 /* A copy of new_acl, to be made before we begin mangling new_acl in
690 order to mask the execute bit. */
691 acl_t new_acl_unmasked = (acl_t)NULL;
692
693 /* Refuse to operate on hard links, which can be abused by an
694 * attacker to trick us into changing the ACL on a file we didn't
695 * intend to; namely the "target" of the hard link. There is TOCTOU
696 * race condition here, but the window is as small as possible
697 * between when we open the file descriptor (look above) and when we
698 * fstat it.
699 */
700 struct stat s;
701 if (fstat(fd, &s) == STAT_ERROR) {
702 perror("apply_default_acl_fds (fstat)");
703 /* We can't recurse without the stat struct for fd */
704 goto cleanup;
705 }
706
707
708 /* Check to make sure the parent descriptor actually has a default
709 ACL. If it doesn't, then we can "succeed" immediately, saving a
710 little work, particularly in any_can_execute(). Note that we
711 can't skip the fstat() above, because we need it in case we
712 recurse. */
713 if (has_default_acl_fd(parent_fd) == ACL_FAILURE) {
714 result = ACL_SUCCESS;
715 /* Just because this target can't inherit anything doesn't mean
716 that one of it's children can't. For example, if there's a
717 default on "c" in "a/b/c/d", then we don't want to skip all
718 children of "a"! */
719 goto recurse;
720 }
721
722
723 if (!S_ISDIR(s.st_mode)) {
724 /* If it's not a directory, make sure it's a regular,
725 non-hard-linked file. */
726 if (!S_ISREG(s.st_mode) || s.st_nlink != 1) {
727 result = ACL_FAILURE;
728 goto cleanup; /* It's not a directory, so we can skip the recursion. */
729 }
730 }
731
732
733 /* Next We try to guess whether or not to strip the execute bits.
734 * This behavior is modeled after the capital 'X' perms of setfacl.
735 */
736 int ace_result = any_can_execute(fd, &s);
737
738 if (ace_result == ACL_ERROR) {
739 perror("apply_default_acl_fds (any_can_execute)");
740 result = ACL_ERROR;
741 goto cleanup;
742 }
743
744 /* Never mask the execute bit on directories. */
745 bool allow_exec = (bool)ace_result || S_ISDIR(s.st_mode);
746
747
748 /* If it's a directory, inherit the parent's default. */
749 if (S_ISDIR(s.st_mode)) {
750 if (acl_copy_xattr(parent_fd,
751 ACL_TYPE_DEFAULT,
752 fd,
753 ACL_TYPE_DEFAULT) == ACL_ERROR) {
754 perror("apply_default_acl_fds (acl_copy_xattr default)");
755 result = ACL_ERROR;
756 goto cleanup;
757 }
758 }
759
760 /* If it's anything, _apply_ the parent's default. */
761 if (acl_copy_xattr(parent_fd,
762 ACL_TYPE_DEFAULT,
763 fd,
764 ACL_TYPE_ACCESS) == ACL_ERROR) {
765 perror("apply_default_acl_fds (acl_copy_xattr access)");
766 result = ACL_ERROR;
767 goto cleanup;
768 }
769
770 /* There's a good reason why we saved the ACL above, even though
771 * we're about to read it back into memory and mess with it on the
772 * next line. The acl_copy_xattr() function is already a hack to let
773 * us copy default ACLs without resorting to path names; we simply
774 * have no way to read the parent's default ACL into memory using
775 * parent_fd. We can, however, copy the parent's ACL to a file (with
776 * acl_copy_xattr), and then read the ACL from a file using
777 * "fd". It's quite the circus, but it works and should be safe from
778 * sym/hardlink attacks.
779 */
780
781 /* Now we potentially need to mask the execute permissions in the
782 ACL on fd; or maybe not. */
783 if (allow_exec) {
784 /* Skip the mask code for this target, but don't skip its children! */
785 goto recurse;
786 }
787
788 /* OK, we need to mask some execute permissions. First obtain the
789 current ACL... */
790 new_acl = acl_get_fd(fd);
791 if (new_acl == (acl_t)NULL) {
792 perror("apply_default_acl_fds (acl_get_fd)");
793 result = ACL_ERROR;
794 goto cleanup;
795 }
796
797 /* ...and now make a copy of it, because otherwise when we loop
798 below, some shit gets stuck (modifying the structure while
799 looping over it no worky). */
800 new_acl_unmasked = acl_dup(new_acl);
801 if (new_acl_unmasked == (acl_t)NULL) {
802 perror("apply_default_acl_fds (acl_dup)");
803 result = ACL_ERROR;
804 goto cleanup;
805 }
806
807 acl_entry_t entry;
808 int ge_result = acl_get_entry(new_acl_unmasked, ACL_FIRST_ENTRY, &entry);
809
810 while (ge_result == ACL_SUCCESS) {
811 acl_tag_t tag = ACL_UNDEFINED_TAG;
812
813 if (acl_get_tag_type(entry, &tag) == ACL_ERROR) {
814 perror("apply_default_acl_fds (acl_get_tag_type)");
815 result = ACL_ERROR;
816 goto cleanup;
817 }
818
819
820 /* We've got an entry/tag from the default ACL. Get its permset. */
821 acl_permset_t permset;
822 if (acl_get_permset(entry, &permset) == ACL_ERROR) {
823 perror("apply_default_acl_fds (acl_get_permset)");
824 result = ACL_ERROR;
825 goto cleanup;
826 }
827
828 /* To mimic what the kernel does, I think we could drop
829 ACL_GROUP_OBJ from the list below? */
830 if (tag == ACL_MASK ||
831 tag == ACL_USER_OBJ ||
832 tag == ACL_GROUP_OBJ ||
833 tag == ACL_OTHER) {
834
835 /* The mask doesn't affect acl_user_obj, acl_group_obj (in
836 minimal ACLs) or acl_other entries, so if execute should be
837 masked, we have to do it manually. */
838 if (acl_delete_perm(permset, ACL_EXECUTE) == ACL_ERROR) {
839 perror("apply_default_acl_fds (acl_delete_perm)");
840 result = ACL_ERROR;
841 goto cleanup;
842 }
843
844 if (acl_set_permset(entry, permset) == ACL_ERROR) {
845 perror("apply_default_acl_fds (acl_set_permset)");
846 result = ACL_ERROR;
847 goto cleanup;
848 }
849 }
850
851 if (acl_update_entry(new_acl, entry) == ACL_ERROR) {
852 perror("apply_default_acl_fds (acl_update_entry)");
853 result = ACL_ERROR;
854 goto cleanup;
855 }
856
857 ge_result = acl_get_entry(new_acl_unmasked, ACL_NEXT_ENTRY, &entry);
858 }
859
860 /* Catches the first acl_get_entry as well as the ones at the end of
861 the loop. */
862 if (ge_result == ACL_ERROR) {
863 perror("apply_default_acl_fds (acl_get_entry)");
864 result = ACL_ERROR;
865 goto cleanup;
866 }
867
868 if (acl_set_fd(fd, new_acl) == ACL_ERROR) {
869 perror("apply_default_acl_fds (acl_set_fd)");
870 result = ACL_ERROR;
871 goto cleanup;
872 }
873
874 recurse:
875 if (recursive && S_ISDIR(s.st_mode)) {
876 /* Recurse into subdirectories. Don't call closedir() on d! It
877 closes the open file descriptor as well, and subsequent calls
878 to close() then throw errors. */
879 DIR* d = fdopendir(fd);
880 if (d == NULL) {
881 perror("apply_default_acl_fds (fdopendir)");
882 result = ACL_ERROR;
883 goto cleanup;
884 }
885
886 struct dirent* de;
887 int new_fd = 0;
888 while ((de = readdir(d)) != NULL) {
889 if (de->d_type != DT_DIR && de->d_type != DT_REG) {
890 /* Hit a symlink or whatever. */
891 result = ACL_FAILURE;
892 continue;
893 }
894 if (strcmp(de->d_name, ".") == 0) { continue; }
895 if (strcmp(de->d_name, "..") == 0) { continue; }
896
897 /* Be careful not to "return" out of this loop and leave the
898 new_fd open! */
899 new_fd = openat(fd, de->d_name, O_NOFOLLOW);
900 if (new_fd == OPEN_ERROR) {
901 if (errno == ELOOP || errno == ENOTDIR) {
902 /* We hit a symlink, either in the last path component (ELOOP)
903 or higher up (ENOTDIR). */
904 if (result == ACL_SUCCESS) {
905 /* Don't overwrite an error result with success/failure. */
906 result = ACL_FAILURE;
907 }
908 continue;
909 }
910 else {
911 perror("apply_default_acl_fds (openat)");
912 result = ACL_ERROR;
913 continue;
914 }
915 }
916 switch (apply_default_acl_fds(fd, new_fd, recursive)) {
917 /* Don't overwrite an error result with success/failure. */
918 case ACL_FAILURE:
919 if (result == ACL_SUCCESS) {
920 result = ACL_FAILURE;
921 }
922 break;
923 case ACL_ERROR:
924 result = ACL_ERROR;
925 default:
926 if (close(new_fd) == CLOSE_ERROR) {
927 perror("apply_default_acl_fds (close)");
928 result = ACL_ERROR;
929 }
930 }
931 }
932 }
933
934 cleanup:
935 acl_free(new_acl);
936 acl_free(new_acl_unmasked);
937 return result;
938 }
939
940
941 /**
942 * @brief Apply parent default ACL to a path and optionally its children.
943 *
944 * This overwrites any existing ACLs on the target, and, if @c
945 * recursive is @c true, its children. When @c recursive is @c true,
946 * the "worst" result encountered is returned as the overall result.
947 *
948 * @param path
949 * The path whose ACL we would like to reset to its default.
950 *
951 * @param recursive
952 * Should we recurse into subdirectories?
953 *
954 * @return
955 * - @c ACL_SUCCESS - The parent default ACLs were inherited successfully.
956 * - @c ACL_FAILURE - If symlinks or hard links are encountered.
957 * - @c ACL_ERROR - Unexpected library error.
958 */
959 int apply_default_acl(const char* path, bool recursive) {
960
961 if (path == NULL) {
962 errno = EINVAL;
963 perror("apply_default_acl (args)");
964 return ACL_ERROR;
965 }
966
967 /* Define these next three variables here because we may have to
968 * jump to the cleanup routine which expects them to exist.
969 */
970
971 /* Our return value. */
972 int result = ACL_SUCCESS;
973
974 /* The file descriptor corresponding to "path" */
975 int fd = 0;
976
977 /* The file descriptor for the directory containing "path" */
978 int parent_fd = 0;
979
980 /* dirname() and basename() mangle their arguments, so we need
981 to make copies of "path" before using them. */
982 char* dirname_path_copy = NULL;
983 char* basename_path_copy = NULL;
984
985 /* Get the parent directory of "path" with dirname(), which happens
986 * to murder its argument and necessitates a path_copy. */
987 dirname_path_copy = strdup(path);
988 if (dirname_path_copy == NULL) {
989 perror("apply_default_acl (strdup)");
990 return ACL_ERROR;
991 }
992 char* parent = dirname(dirname_path_copy);
993 parent_fd = safe_open(parent, O_DIRECTORY | O_NOFOLLOW);
994 if (parent_fd == OPEN_ERROR) {
995 if (errno == ELOOP || errno == ENOTDIR) {
996 /* We hit a symlink, either in the last path component (ELOOP)
997 or higher up (ENOTDIR). */
998 result = ACL_FAILURE;
999 goto cleanup;
1000 }
1001 else {
1002 perror("apply_default_acl (open parent fd)");
1003 result = ACL_ERROR;
1004 goto cleanup;
1005 }
1006 }
1007
1008 /* We already obtained the parent fd safely, so if we use the
1009 basename of path here instead of the full thing, then we can get
1010 away with using openat() and spare ourselves the slowness of
1011 another safe_open(). */
1012 basename_path_copy = strdup(path);
1013 if (basename_path_copy == NULL) {
1014 perror("apply_default_acl (strdup)");
1015 return ACL_ERROR;
1016 }
1017 fd = openat(parent_fd, basename(basename_path_copy), O_NOFOLLOW);
1018 if (fd == OPEN_ERROR) {
1019 if (errno == ELOOP || errno == ENOTDIR) {
1020 /* We hit a symlink, either in the last path component (ELOOP)
1021 or higher up (ENOTDIR). */
1022 result = ACL_FAILURE;
1023 goto cleanup;
1024 }
1025 else {
1026 perror("apply_default_acl (open fd)");
1027 result = ACL_ERROR;
1028 goto cleanup;
1029 }
1030 }
1031
1032 result = apply_default_acl_fds(parent_fd, fd, recursive);
1033
1034 cleanup:
1035 free(dirname_path_copy);
1036 free(basename_path_copy);
1037
1038 if (parent_fd > 0 && close(parent_fd) == CLOSE_ERROR) {
1039 perror("apply_default_acl (close parent_fd)");
1040 result = ACL_ERROR;
1041 }
1042 if (fd > 0 && close(fd) == CLOSE_ERROR) {
1043 perror("apply_default_acl (close fd)");
1044 result = ACL_ERROR;
1045 }
1046 return result;
1047 }