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