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