1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * NAME
22 * rmdir03
23 *
24 * DESCRIPTION
25 * check rmdir() fails with EPERM or EACCES
26 *
27 * ALGORITHM
28 * Setup:
29 * Setup signal handling.
30 * Pause for SIGUSR1 if option specified.
31 * Create temporary directory.
32 *
33 * Test:
34 * Loop if the proper options are given.
35 * 1. create a directory tstdir1 and set the sticky bit, then
36 * create directory tstdir2 under tstdir1. Fork a
37 * child , set to be user nobody. Pass tstdir2 to rmdir(2).
38 * Verify the return value is not 0 and the errno is EPERM
39 * or EACCES.
40 * 2. Fork a child, set to be user nobody. Create a directory
41 * tstdir1 and only give write permission to nobody.
42 * Create directory tstdir2 under tstdir1. Fork the second
43 * child , set to be user nobody. Pass tstdir2 to rmdir(2).
44 * Verify the return value is not 0 and the errno is EACCES.
45 *
46 * Cleanup:
47 * Print errno log and/or timing stats if options given
48 * Delete the temporary directory created.
49 *
50 * USAGE
51 * rmdir03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
52 * where, -c n : Run n copies concurrently.
53 * -e : Turn on errno logging.
54 * -i n : Execute test n times.
55 * -I x : Execute test for x seconds.
56 * -P x : Pause for x seconds between iterations.
57 * -t : Turn on syscall timing.
58 *
59 * HISTORY
60 * 07/2001 Ported by Wayne Boyer
61 *
62 * RESTRICTIONS
63 * Test must be run as root.
64 *
65 */
66 #include <errno.h>
67 #include <string.h>
68 #include <sys/stat.h>
69 #include <sys/types.h>
70 #include <sys/wait.h>
71 #include <fcntl.h>
72 #include <pwd.h>
73 #include <unistd.h>
74
75 #include "test.h"
76 #include "safe_macros.h"
77
78 void dochild1();
79 void dochild2();
80 void setup();
81 void cleanup();
82
83 #define PERMS 0777
84
85 static uid_t nobody_uid;
86
87 char *TCID = "rmdir03";
88 int TST_TOTAL = 1;
89
90 char tstdir1[255];
91 char tstdir2[255];
92 char tstdir3[255];
93 char tstdir4[255];
94
main(int ac,char ** av)95 int main(int ac, char **av)
96 {
97 int lc;
98 pid_t pid;
99 struct stat buf1;
100 int e_code, status, status2;
101
102 /*
103 * parse standard options
104 */
105 tst_parse_opts(ac, av, NULL, NULL);
106 #ifdef UCLINUX
107 maybe_run_child(&dochild1, "ns", 1, tstdir2);
108 maybe_run_child(&dochild2, "ns", 2, tstdir4);
109 #endif
110
111 /*
112 * perform global setup for test
113 */
114 setup();
115
116 /*
117 * check looping state if -i option given
118 */
119 for (lc = 0; TEST_LOOPING(lc); lc++) {
120
121 tst_count = 0;
122
123 //test1: $
124 /*
125 * attempt to rmdir a file whose parent directory has
126 * the sticky bit set without the root right
127 * or effective uid
128 */
129
130 if (stat(tstdir1, &buf1) != -1) {
131 tst_brkm(TBROK, cleanup,
132 "tmp directory %s found!", tstdir1);
133 }
134 /* create a directory */
135 SAFE_MKDIR(cleanup, tstdir1, PERMS);
136 if (stat(tstdir1, &buf1) == -1) {
137 perror("stat");
138 tst_brkm(TBROK, cleanup, "failed to stat directory %s "
139 "in rmdir()", tstdir1);
140
141 }
142 /* set the sticky bit */
143 if (chmod(tstdir1, buf1.st_mode | S_ISVTX) != 0) {
144 perror("chmod");
145 tst_brkm(TBROK, cleanup,
146 "failed to set the S_ISVTX bit");
147
148 }
149 /* create a sub directory under tstdir1 */
150 SAFE_MKDIR(cleanup, tstdir2, PERMS);
151
152 if ((pid = FORK_OR_VFORK()) == -1) {
153 tst_brkm(TBROK, cleanup, "fork() failed");
154 }
155
156 if (pid == 0) { /* first child */
157 #ifdef UCLINUX
158 if (self_exec(av[0], "ns", 1, tstdir2) < 0) {
159 tst_brkm(TBROK, cleanup, "self_exec failed");
160 }
161 #else
162 dochild1();
163 #endif
164 }
165 /* Parent */
166
167 //test2: $
168 /* create the a directory with 0700 permits */
169 SAFE_MKDIR(cleanup, tstdir3, 0700);
170 /* create the a directory with 0700 permits */
171 SAFE_MKDIR(cleanup, tstdir4, 0777);
172
173 if ((pid = FORK_OR_VFORK()) == -1) {
174 tst_brkm(TBROK, cleanup, "fork() failed");
175 }
176
177 if (pid == 0) { /* child */
178 #ifdef UCLINUX
179 if (self_exec(av[0], "ns", 2, tstdir4) < 0) {
180 tst_brkm(TBROK, cleanup, "self_exec failed");
181 }
182 #else
183 dochild2();
184 #endif
185 } else { /* parent */
186 /* wait for the child to finish */
187 wait(&status);
188 wait(&status2);
189 /* make sure the child returned a good exit status */
190 e_code = status >> 8;
191 if (e_code != 0) {
192 tst_resm(TFAIL, "Failures reported above");
193 } else {
194 /* No error in the 1st one, check the 2nd */
195 e_code = status2 >> 8;
196 if (e_code != 0) {
197 tst_resm(TFAIL,
198 "Failures reported above");
199 }
200 }
201 }
202
203 /* clean up things in case we are looping */
204
205 (void)rmdir(tstdir2);
206 (void)rmdir(tstdir1);
207 (void)rmdir(tstdir4);
208 (void)rmdir(tstdir3);
209
210 }
211
212 /*
213 * cleanup and exit
214 */
215 cleanup();
216 tst_exit();
217
218 }
219
220 /*
221 * dochild1()
222 */
dochild1(void)223 void dochild1(void)
224 {
225 int retval = 0;
226
227 /* set to nobody */
228 if (seteuid(nobody_uid) == -1) {
229 retval = 1;
230 tst_brkm(TBROK, cleanup, "setreuid failed to "
231 "set effective uid to %d", nobody_uid);
232 }
233
234 /* rmdir tstdir2 */
235 TEST(rmdir(tstdir2));
236
237 if (TEST_ERRNO) {
238 }
239
240 if (TEST_RETURN != -1) {
241 retval = 1;
242 tst_resm(TFAIL, "call succeeded unexpectedly");
243 } else if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) {
244 retval = 1;
245 tst_resm(TFAIL, "Expected EPERM or EACCES, got %d", TEST_ERRNO);
246 } else {
247 tst_resm(TPASS, "rmdir() produced EPERM or EACCES");
248 }
249
250 if (seteuid(0) == -1) {
251 retval = 1;
252 tst_brkm(TBROK, cleanup, "seteuid(0) failed");
253 }
254 exit(retval);
255 /* END of child 1 (test1) */
256 }
257
258 /*
259 * dochild1()
260 */
dochild2(void)261 void dochild2(void)
262 {
263 int retval = 0;
264
265 /* set to nobody */
266 if (seteuid(nobody_uid) == -1) {
267 retval = 1;
268 tst_brkm(TBROK, cleanup, "setreuid failed to "
269 "set effective uid to %d", nobody_uid);
270 }
271
272 /* rmdir tstdir4 */
273 TEST(rmdir(tstdir4));
274
275 if (TEST_ERRNO) {
276 }
277
278 if (TEST_RETURN != -1) {
279 retval = 1;
280 tst_resm(TFAIL, "call succeeded unexpectedly");
281 } else if (TEST_ERRNO != EACCES) {
282 retval = 1;
283 tst_resm(TFAIL, "Expected EACCES got %d", TEST_ERRNO);
284 } else {
285 tst_resm(TPASS, "rmdir() produced EACCES");
286 }
287
288 if (seteuid(0) == -1) {
289 retval = 1;
290 tst_brkm(TBROK, cleanup, "seteuid(0) failed");
291 }
292 exit(retval);
293 }
294
295 /*
296 * setup() - performs all ONE TIME setup for this test.
297 */
setup(void)298 void setup(void)
299 {
300 struct passwd *pw;
301
302 tst_require_root();
303
304 pw = SAFE_GETPWNAM(NULL, "nobody");
305 nobody_uid = pw->pw_uid;
306
307 tst_sig(FORK, DEF_HANDLER, cleanup);
308
309 TEST_PAUSE;
310
311 /* Create a temporary directory and make it current. */
312 tst_tmpdir();
313
314 umask(0);
315
316 sprintf(tstdir1, "./tstdir1_%d", getpid());
317 sprintf(tstdir2, "%s/tstdir2_%d", tstdir1, getpid());
318 sprintf(tstdir3, "./tstdir3_%d", getpid());
319 sprintf(tstdir4, "%s/tstdir3_%d", tstdir3, getpid());
320 }
321
322 /*
323 * cleanup() - performs all ONE TIME cleanup for this test at
324 * completion or premature exit.
325 */
cleanup(void)326 void cleanup(void)
327 {
328
329 /*
330 * Remove the temporary directory.
331 */
332 tst_rmdir();
333
334 /*
335 * Exit with return code appropriate for results.
336 */
337
338 }
339