• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *	mkdir02
23  *
24  * DESCRIPTION
25  *	This test will verify that new directory created
26  *	by mkdir(2) inherites the group ID from the parent
27  *      directory and S_ISGID bit, if the S_ISGID bit is set
28  *	in the parent directory.
29  *
30  * ALGORITHM
31  *	Setup:
32  *		Setup signal handling.
33  *		Pause for SIGUSR1 if option specified.
34  *		Create temporary directory.
35  *              Give write permission on temporary directory for all users.
36  *              set up umask
37  *
38  *	Test:
39  *		Loop if the proper options are given.
40  *              fork the first child as ltpuser1
41  *                  create a directory tstdir1 with S_ISGID set
42  *              fork the second child as ltpuser2
43  *                  create a directtory tstdir2 user tstdir1
44  *                  check tstdir2's group ID and the S_ISGID bit
45  *                  if they are the same as tstdir1's
46  *                       PASS
47  *                  else FAIL
48  *	Cleanup:
49  *		Print errno log and/or timing stats if options given
50  *		Delete the temporary directory created.*
51  * USAGE
52  *	mkdir02 [-c n] [-e] [-f] [-i n] [-I x] [-P x] [-t]
53  *	where,  -c n : Run n copies concurrently.
54  *		-e   : Turn on errno logging.
55  *		-f   : Turn off functionality Testing.
56  *		-i n : Execute test n times.
57  *		-I x : Execute test for x seconds.
58  *		-P x : Pause for x seconds between iterations.
59  *		-t   : Turn on syscall timing.
60  *
61  * HISTORY
62  *	07/2001 Ported by Wayne Boyer
63  *
64  * RESTRICTIONS
65  *	None.
66  */
67 
68 #include <errno.h>
69 #include <string.h>
70 #include <signal.h>
71 #include <sys/stat.h>
72 #include <sys/types.h>
73 #include <fcntl.h>
74 #include <pwd.h>
75 #include <sys/wait.h>
76 #include <unistd.h>
77 
78 #include "test.h"
79 #include "safe_macros.h"
80 
81 void setup();
82 void cleanup();
83 
84 #define PERMS		0777
85 
86 static uid_t nobody_uid, bin_uid;
87 static gid_t nobody_gid, bin_gid;
88 
89 char *TCID = "mkdir02";
90 int TST_TOTAL = 1;
91 
92 char tstdir1[100];
93 char tstdir2[100];
94 
main(int ac,char ** av)95 int main(int ac, char **av)
96 {
97 	int lc;
98 	struct stat buf, buf1;
99 	pid_t pid, pid1;
100 	int rval, status;
101 
102 	/*
103 	 * parse standard options
104 	 */
105 	tst_parse_opts(ac, av, NULL, NULL);
106 
107 	/*
108 	 * perform global setup for test
109 	 */
110 	setup();
111 
112 	/*
113 	 * check looping state if -i option given
114 	 */
115 	for (lc = 0; TEST_LOOPING(lc); lc++) {
116 
117 		tst_count = 0;
118 
119 		/* check the inherited group ID */
120 
121 		/*
122 		 * first, fork the first child, set to ltpuser1's uid and gid,
123 		 * create a directory, with S_ISGID bit set
124 		 */
125 
126 		sprintf(tstdir1, "tstdir1.%d", getpid());
127 
128 		if ((pid = FORK_OR_VFORK()) < 0) {
129 			tst_brkm(TFAIL, cleanup, "fork() failed");
130 
131 		}
132 
133 		if (pid == 0) {	/* first child */
134 			rval = setregid(nobody_gid, nobody_gid);
135 			if (rval < 0) {
136 				perror("setregid");
137 				tst_resm(TFAIL, "setregid failed to "
138 					 "to set the real gid to %d and "
139 					 "effective gid to %d",
140 					 nobody_gid, nobody_gid);
141 				exit(1);
142 
143 			}
144 			/* being ltupuser1 */
145 			rval = setreuid(nobody_uid, nobody_uid);
146 			if (rval < 0) {
147 				perror("setreuid");
148 				tst_resm(TFAIL, "setreuid failed to "
149 					 "to set the real uid to %d and "
150 					 "effective uid to %d",
151 					 nobody_uid, nobody_uid);
152 				exit(1);
153 
154 			}
155 
156 			/*
157 			 * create a direcoty with S_ISGID bit set
158 			 * and the group ID is ltpuser1
159 			 */
160 			if (mkdir(tstdir1, PERMS) != 0) {
161 				perror("mkdir");
162 				tst_resm(TFAIL, "mkdir() failed to create"
163 					 " a directory with Set "
164 					 " group ID turn on ");
165 				exit(1);
166 
167 			}
168 			if (stat(tstdir1, &buf1) == -1) {
169 				perror("stat");
170 				tst_resm(TFAIL,
171 					 "failed to stat the new directory"
172 					 "in mkdir()");
173 				exit(1);
174 
175 			}
176 			if (chmod(tstdir1, buf1.st_mode | S_ISGID) != 0) {
177 				perror("chmod");
178 				tst_resm(TFAIL, "failed to set S_ISGID bit");
179 				exit(1);
180 
181 			}
182 
183 			/* Successfully create the parent directory */
184 			exit(0);
185 
186 		}
187 		wait(&status);
188 		if (WEXITSTATUS(status) != 0) {
189 			tst_brkm(TFAIL, cleanup,
190 				 "Test to attempt to make a directory"
191 				 " inherits group ID FAILED ");
192 		}
193 		/*
194 		 * fork the second child process, set to ltpuser2's uid and gid
195 		 * create a sub directory under the directory
196 		 * just created by child process 1
197 		 * check the group ID of the sub directory
198 		 * should inherit from parent directory
199 		 */
200 
201 		sprintf(tstdir2, "%s/tstdir2.%d", tstdir1, getpid());
202 		if ((pid1 = FORK_OR_VFORK()) < 0) {
203 			perror("fork failed");
204 			tst_brkm(TFAIL, cleanup, "fork() failed");
205 
206 		} else if (pid1 == 0) {	/* second child */
207 
208 			/* being user ltpuser2 */
209 			rval = setregid(bin_gid, bin_gid);
210 			if (rval < 0) {
211 				tst_resm(TFAIL, "setregid failed to "
212 					 "to set the real gid to %d and "
213 					 "effective gid to %d",
214 					 bin_gid, bin_gid);
215 				perror("setregid");
216 				exit(1);
217 
218 			}
219 			rval = setreuid(bin_uid, bin_uid);
220 			if (rval < 0) {
221 				tst_resm(TFAIL, "setreuid failed to "
222 					 "to set the real uid to %d and "
223 					 "effective uid to %d",
224 					 bin_uid, bin_uid);
225 				perror("setreuid");
226 				exit(1);
227 
228 			}
229 
230 			/*
231 			 * create a sub direcoty
232 			 * under the directory just created
233 			 * by ltpuser1
234 			 */
235 			if (mkdir(tstdir2, PERMS) != 0) {
236 				tst_resm(TFAIL, "mkdir() failed to create"
237 					 " a directory %s under %s ", tstdir2,
238 					 tstdir1);
239 				exit(1);
240 
241 			}
242 			/*
243 			 * check the group ID
244 			 * should not be the same as the current processs's
245 			 * since parent directory is set with S_ISGID bit
246 			 */
247 			if (stat(tstdir2, &buf) == -1) {
248 				tst_resm(TFAIL,
249 					 "failed to stat the new directory"
250 					 "in mkdir()");
251 				exit(1);
252 
253 			}
254 			if (stat(tstdir1, &buf1) == -1) {
255 				tst_resm(TFAIL,
256 					 "failed to stat the new directory"
257 					 "in mkdir()");
258 				exit(1);
259 
260 			}
261 			if (buf.st_gid != buf1.st_gid) {
262 				tst_resm(TFAIL, "mkdir() FAILED to inherit "
263 					 " the group ID %d from parent "
264 					 " directory %d",
265 					 buf.st_gid, buf1.st_gid);
266 				exit(1);
267 
268 			}
269 
270 			/* check the S_ISGID  bit */
271 			if (!(buf.st_mode & S_ISGID)) {
272 				tst_resm(TFAIL, "mkdir() FAILED to inherit "
273 					 " the S_ISGID bit from parent "
274 					 " directory");
275 				exit(1);
276 
277 			}
278 			/* PASS */
279 			exit(0);
280 
281 		}
282 
283 		waitpid(pid1, &status, 0);
284 		if (WEXITSTATUS(status) == 0) {
285 			tst_resm(TPASS, "Test to attempt to make a directory"
286 				 " inherits group ID SUCCEEDED ");
287 		} else {
288 			tst_resm(TFAIL, "Test to attempt to make a directory"
289 				 " inherits group ID FAILED");
290 			cleanup();
291 		}
292 
293 	}
294 
295 	/*
296 	 * cleanup and exit
297 	 */
298 	cleanup();
299 
300 	tst_exit();
301 }
302 
303 /*
304  * setup() - performs all ONE TIME setup for this test.
305  */
setup(void)306 void setup(void)
307 {
308 	struct passwd *pw;
309 
310 	tst_require_root();
311 
312 	pw = SAFE_GETPWNAM(NULL, "nobody");
313 	nobody_uid = pw->pw_uid;
314 	nobody_gid = pw->pw_gid;
315 	pw = SAFE_GETPWNAM(NULL, "bin");
316 	bin_uid = pw->pw_uid;
317 	bin_gid = pw->pw_gid;
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 
329 /*
330  * cleanup() - performs all ONE TIME cleanup for this test at
331  *             completion or premature exit.
332  */
cleanup(void)333 void cleanup(void)
334 {
335 
336 	/*
337 	 * Remove the temporary directory.
338 	 */
339 	tst_rmdir();
340 
341 	/*
342 	 * Exit with return code appropriate for results.
343 	 */
344 
345 }
346