]>
Commit | Line | Data |
---|---|---|
cb9e44db LP |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
3 | #include <sys/xattr.h> | |
4 | ||
5 | #include "alloc-util.h" | |
6 | #include "chown-recursive.h" | |
cb9e44db LP |
7 | #include "log.h" |
8 | #include "rm-rf.h" | |
9 | #include "string-util.h" | |
10 | #include "tests.h" | |
e4de7287 | 11 | #include "tmpfile-util.h" |
cb9e44db LP |
12 | |
13 | static const uint8_t acl[] = { | |
14 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, | |
15 | 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x07, 0x00, | |
16 | 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, | |
17 | 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x07, 0x00, | |
18 | 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00, | |
19 | 0xff, 0xff, 0xff, 0xff, | |
20 | }; | |
21 | ||
22 | static const uint8_t default_acl[] = { | |
23 | 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, | |
24 | 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x07, 0x00, | |
25 | 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x07, 0x00, | |
26 | 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, | |
27 | 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x05, 0x00, | |
28 | 0xff, 0xff, 0xff, 0xff, | |
29 | }; | |
30 | ||
31 | static bool has_xattr(const char *p) { | |
32 | char buffer[sizeof(acl) * 4]; | |
33 | ||
34 | if (lgetxattr(p, "system.posix_acl_access", buffer, sizeof(buffer)) < 0) { | |
35 | if (IN_SET(errno, EOPNOTSUPP, ENOTTY, ENODATA, ENOSYS)) | |
36 | return false; | |
37 | } | |
38 | ||
39 | return true; | |
40 | } | |
41 | ||
42 | static void test_chown_recursive(void) { | |
43 | _cleanup_(rm_rf_physical_and_freep) char *t = NULL; | |
44 | struct stat st; | |
45 | const char *p; | |
46 | ||
47 | umask(022); | |
48 | assert_se(mkdtemp_malloc(NULL, &t) >= 0); | |
49 | ||
50 | p = strjoina(t, "/dir"); | |
51 | assert_se(mkdir(p, 0777) >= 0); | |
52 | assert_se(lstat(p, &st) >= 0); | |
53 | assert_se(S_ISDIR(st.st_mode)); | |
54 | assert_se((st.st_mode & 07777) == 0755); | |
55 | assert_se(st.st_uid == 0); | |
56 | assert_se(st.st_gid == 0); | |
57 | assert_se(!has_xattr(p)); | |
58 | ||
59 | p = strjoina(t, "/dir/symlink"); | |
60 | assert_se(symlink("../../", p) >= 0); | |
61 | assert_se(lstat(p, &st) >= 0); | |
62 | assert_se(S_ISLNK(st.st_mode)); | |
63 | assert_se((st.st_mode & 07777) == 0777); | |
64 | assert_se(st.st_uid == 0); | |
65 | assert_se(st.st_gid == 0); | |
66 | assert_se(!has_xattr(p)); | |
67 | ||
68 | p = strjoina(t, "/dir/reg"); | |
69 | assert_se(mknod(p, S_IFREG|0777, 0) >= 0); | |
70 | assert_se(lstat(p, &st) >= 0); | |
71 | assert_se(S_ISREG(st.st_mode)); | |
72 | assert_se((st.st_mode & 07777) == 0755); | |
73 | assert_se(st.st_uid == 0); | |
74 | assert_se(st.st_gid == 0); | |
75 | assert_se(!has_xattr(p)); | |
76 | ||
77 | p = strjoina(t, "/dir/sock"); | |
78 | assert_se(mknod(p, S_IFSOCK|0777, 0) >= 0); | |
79 | assert_se(lstat(p, &st) >= 0); | |
80 | assert_se(S_ISSOCK(st.st_mode)); | |
81 | assert_se((st.st_mode & 07777) == 0755); | |
82 | assert_se(st.st_uid == 0); | |
83 | assert_se(st.st_gid == 0); | |
84 | assert_se(!has_xattr(p)); | |
85 | ||
86 | p = strjoina(t, "/dir/fifo"); | |
87 | assert_se(mknod(p, S_IFIFO|0777, 0) >= 0); | |
88 | assert_se(lstat(p, &st) >= 0); | |
89 | assert_se(S_ISFIFO(st.st_mode)); | |
90 | assert_se((st.st_mode & 07777) == 0755); | |
91 | assert_se(st.st_uid == 0); | |
92 | assert_se(st.st_gid == 0); | |
93 | assert_se(!has_xattr(p)); | |
94 | ||
95 | /* We now apply an xattr to the dir, and check it again */ | |
96 | p = strjoina(t, "/dir"); | |
97 | assert_se(setxattr(p, "system.posix_acl_access", acl, sizeof(acl), 0) >= 0); | |
98 | assert_se(setxattr(p, "system.posix_acl_default", default_acl, sizeof(default_acl), 0) >= 0); | |
99 | assert_se(lstat(p, &st) >= 0); | |
100 | assert_se(S_ISDIR(st.st_mode)); | |
101 | assert_se((st.st_mode & 07777) == 0775); /* acl change changed the mode too */ | |
102 | assert_se(st.st_uid == 0); | |
103 | assert_se(st.st_gid == 0); | |
104 | assert_se(has_xattr(p)); | |
105 | ||
106 | assert_se(path_chown_recursive(t, 1, 2) >= 0); | |
107 | ||
108 | p = strjoina(t, "/dir"); | |
109 | assert_se(lstat(p, &st) >= 0); | |
110 | assert_se(S_ISDIR(st.st_mode)); | |
111 | assert_se((st.st_mode & 07777) == 0775); | |
112 | assert_se(st.st_uid == 1); | |
113 | assert_se(st.st_gid == 2); | |
114 | assert_se(!has_xattr(p)); | |
115 | ||
116 | p = strjoina(t, "/dir/symlink"); | |
117 | assert_se(lstat(p, &st) >= 0); | |
118 | assert_se(S_ISLNK(st.st_mode)); | |
119 | assert_se((st.st_mode & 07777) == 0777); | |
120 | assert_se(st.st_uid == 1); | |
121 | assert_se(st.st_gid == 2); | |
122 | assert_se(!has_xattr(p)); | |
123 | ||
124 | p = strjoina(t, "/dir/reg"); | |
125 | assert_se(lstat(p, &st) >= 0); | |
126 | assert_se(S_ISREG(st.st_mode)); | |
127 | assert_se((st.st_mode & 07777) == 0755); | |
128 | assert_se(st.st_uid == 1); | |
129 | assert_se(st.st_gid == 2); | |
130 | assert_se(!has_xattr(p)); | |
131 | ||
132 | p = strjoina(t, "/dir/sock"); | |
133 | assert_se(lstat(p, &st) >= 0); | |
134 | assert_se(S_ISSOCK(st.st_mode)); | |
135 | assert_se((st.st_mode & 07777) == 0755); | |
136 | assert_se(st.st_uid == 1); | |
137 | assert_se(st.st_gid == 2); | |
138 | assert_se(!has_xattr(p)); | |
139 | ||
140 | p = strjoina(t, "/dir/fifo"); | |
141 | assert_se(lstat(p, &st) >= 0); | |
142 | assert_se(S_ISFIFO(st.st_mode)); | |
143 | assert_se((st.st_mode & 07777) == 0755); | |
144 | assert_se(st.st_uid == 1); | |
145 | assert_se(st.st_gid == 2); | |
146 | assert_se(!has_xattr(p)); | |
147 | } | |
148 | ||
149 | int main(int argc, char *argv[]) { | |
2b686260 | 150 | test_setup_logging(LOG_DEBUG); |
cb9e44db LP |
151 | |
152 | if (geteuid() != 0) | |
153 | return log_tests_skipped("not running as root"); | |
154 | ||
155 | test_chown_recursive(); | |
156 | ||
157 | return EXIT_SUCCESS; | |
158 | } |