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 if (mkdir(tstdir1, PERMS) == -1) {
136 tst_brkm(TBROK, cleanup,
137 "Couldnot create directory %s", tstdir1);
138 }
139 if (stat(tstdir1, &buf1) == -1) {
140 perror("stat");
141 tst_brkm(TBROK, cleanup, "failed to stat directory %s "
142 "in rmdir()", tstdir1);
143
144 }
145 /* set the sticky bit */
146 if (chmod(tstdir1, buf1.st_mode | S_ISVTX) != 0) {
147 perror("chmod");
148 tst_brkm(TBROK, cleanup,
149 "failed to set the S_ISVTX bit");
150
151 }
152 /* create a sub directory under tstdir1 */
153 if (mkdir(tstdir2, PERMS) == -1) {
154 tst_brkm(TBROK, cleanup,
155 "Could not create directory %s", tstdir2);
156 }
157
158 if ((pid = FORK_OR_VFORK()) == -1) {
159 tst_brkm(TBROK, cleanup, "fork() failed");
160 }
161
162 if (pid == 0) { /* first child */
163 #ifdef UCLINUX
164 if (self_exec(av[0], "ns", 1, tstdir2) < 0) {
165 tst_brkm(TBROK, cleanup, "self_exec failed");
166 }
167 #else
168 dochild1();
169 #endif
170 }
171 /* Parent */
172
173 //test2: $
174 /* create the a directory with 0700 permits */
175 if (mkdir(tstdir3, 0700) == -1) {
176 tst_brkm(TBROK, cleanup, "mkdir(%s, %#o) Failed",
177 tstdir3, PERMS);
178 }
179 /* create the a directory with 0700 permits */
180 if (mkdir(tstdir4, 0777) == -1) {
181 tst_brkm(TBROK, cleanup, "mkdir(%s, %#o) Failed",
182 tstdir4, PERMS);
183 }
184
185 if ((pid = FORK_OR_VFORK()) == -1) {
186 tst_brkm(TBROK, cleanup, "fork() failed");
187 }
188
189 if (pid == 0) { /* child */
190 #ifdef UCLINUX
191 if (self_exec(av[0], "ns", 2, tstdir4) < 0) {
192 tst_brkm(TBROK, cleanup, "self_exec failed");
193 }
194 #else
195 dochild2();
196 #endif
197 } else { /* parent */
198 /* wait for the child to finish */
199 wait(&status);
200 wait(&status2);
201 /* make sure the child returned a good exit status */
202 e_code = status >> 8;
203 if (e_code != 0) {
204 tst_resm(TFAIL, "Failures reported above");
205 } else {
206 /* No error in the 1st one, check the 2nd */
207 e_code = status2 >> 8;
208 if (e_code != 0) {
209 tst_resm(TFAIL,
210 "Failures reported above");
211 }
212 }
213 }
214
215 /* clean up things in case we are looping */
216
217 (void)rmdir(tstdir2);
218 (void)rmdir(tstdir1);
219 (void)rmdir(tstdir4);
220 (void)rmdir(tstdir3);
221
222 }
223
224 /*
225 * cleanup and exit
226 */
227 cleanup();
228 tst_exit();
229
230 }
231
232 /*
233 * dochild1()
234 */
dochild1(void)235 void dochild1(void)
236 {
237 int retval = 0;
238
239 /* set to nobody */
240 if (seteuid(nobody_uid) == -1) {
241 retval = 1;
242 tst_brkm(TBROK, cleanup, "setreuid failed to "
243 "set effective uid to %d", nobody_uid);
244 }
245
246 /* rmdir tstdir2 */
247 TEST(rmdir(tstdir2));
248
249 if (TEST_ERRNO) {
250 }
251
252 if (TEST_RETURN != -1) {
253 retval = 1;
254 tst_resm(TFAIL, "call succeeded unexpectedly");
255 } else if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) {
256 retval = 1;
257 tst_resm(TFAIL, "Expected EPERM or EACCES, got %d", TEST_ERRNO);
258 } else {
259 tst_resm(TPASS, "rmdir() produced EPERM or EACCES");
260 }
261
262 if (seteuid(0) == -1) {
263 retval = 1;
264 tst_brkm(TBROK, cleanup, "seteuid(0) failed");
265 }
266 exit(retval);
267 /* END of child 1 (test1) */
268 }
269
270 /*
271 * dochild1()
272 */
dochild2(void)273 void dochild2(void)
274 {
275 int retval = 0;
276
277 /* set to nobody */
278 if (seteuid(nobody_uid) == -1) {
279 retval = 1;
280 tst_brkm(TBROK, cleanup, "setreuid failed to "
281 "set effective uid to %d", nobody_uid);
282 }
283
284 /* rmdir tstdir4 */
285 TEST(rmdir(tstdir4));
286
287 if (TEST_ERRNO) {
288 }
289
290 if (TEST_RETURN != -1) {
291 retval = 1;
292 tst_resm(TFAIL, "call succeeded unexpectedly");
293 } else if (TEST_ERRNO != EACCES) {
294 retval = 1;
295 tst_resm(TFAIL, "Expected EACCES got %d", TEST_ERRNO);
296 } else {
297 tst_resm(TPASS, "rmdir() produced EACCES");
298 }
299
300 if (seteuid(0) == -1) {
301 retval = 1;
302 tst_brkm(TBROK, cleanup, "seteuid(0) failed");
303 }
304 exit(retval);
305 }
306
307 /*
308 * setup() - performs all ONE TIME setup for this test.
309 */
setup(void)310 void setup(void)
311 {
312 struct passwd *pw;
313
314 tst_require_root();
315
316 pw = SAFE_GETPWNAM(NULL, "nobody");
317 nobody_uid = pw->pw_uid;
318
319 tst_sig(FORK, DEF_HANDLER, cleanup);
320
321 TEST_PAUSE;
322
323 /* Create a temporary directory and make it current. */
324 tst_tmpdir();
325
326 umask(0);
327
328 sprintf(tstdir1, "./tstdir1_%d", getpid());
329 sprintf(tstdir2, "%s/tstdir2_%d", tstdir1, getpid());
330 sprintf(tstdir3, "./tstdir3_%d", getpid());
331 sprintf(tstdir4, "%s/tstdir3_%d", tstdir3, getpid());
332 }
333
334 /*
335 * cleanup() - performs all ONE TIME cleanup for this test at
336 * completion or premature exit.
337 */
cleanup(void)338 void cleanup(void)
339 {
340
341 /*
342 * Remove the temporary directory.
343 */
344 tst_rmdir();
345
346 /*
347 * Exit with return code appropriate for results.
348 */
349
350 }
351