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