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