• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2002
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  * Description:
22  *	Verifies that the group ID and setgid bit are
23  *	set correctly when a new file is created using open.
24  *
25  * ALGORITHM
26  *	Create two directories, one with the group ID of this process
27  *	and the setgid bit not set, and the other with a group ID
28  *	other than that of this process and with the setgid bit set.
29  *	In each directory, create a file with and without the setgid
30  *	bit set in the creation modes. Verify that the modes and group
31  *	ID are correct on each of the 4 files.
32  *	As root, create a file with the setgid bit on in the
33  *	directory with the setgid bit.
34  *	This tests the SVID3 create group semantics.
35  */
36 
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <grp.h>
43 #include <pwd.h>
44 #include "test.h"
45 
46 char *TCID = "open10";
47 int TST_TOTAL = 1;
48 static int local_flag;
49 
50 #define PASSED 1
51 #define FAILED 0
52 
53 #define MODE_RWX        (S_IRWXU | S_IRWXG | S_IRWXO)
54 #define MODE_SGID       (S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO)
55 #define DIR_A_TEMP	"open10.testdir.A.%d"
56 #define DIR_B_TEMP	"open10.testdir.B.%d"
57 #define SETGID		"setgid"
58 #define NOSETGID	"nosetgid"
59 #define ROOT_SETGID	"root_setgid"
60 #define	MSGSIZE		150
61 
62 static void setup(void);
63 static void cleanup(void);
64 
main(int ac,char * av[])65 int main(int ac, char *av[])
66 {
67 	int ret;
68 	struct stat buf;
69 	struct group *group;
70 	struct passwd *user1;
71 	char DIR_A[MSGSIZE], DIR_B[MSGSIZE];
72 	char setgid_A[MSGSIZE], nosetgid_A[MSGSIZE];
73 	char setgid_B[MSGSIZE], nosetgid_B[MSGSIZE], root_setgid_B[MSGSIZE];
74 	gid_t group1_gid, group2_gid, mygid;
75 	uid_t save_myuid, user1_uid;
76 	pid_t mypid;
77 
78 	int lc;
79 	int fail_count = 0;
80 
81 	tst_parse_opts(ac, av, NULL, NULL);
82 
83 	setup();
84 
85 	for (lc = 0; TEST_LOOPING(lc); lc++) {
86 		local_flag = PASSED;
87 
88 		save_myuid = getuid();
89 		mypid = getpid();
90 		sprintf(DIR_A, DIR_A_TEMP, mypid);
91 		sprintf(DIR_B, DIR_B_TEMP, mypid);
92 		sprintf(setgid_A, "%s/%s", DIR_A, SETGID);
93 		sprintf(nosetgid_A, "%s/%s", DIR_A, NOSETGID);
94 		sprintf(setgid_B, "%s/%s", DIR_B, SETGID);
95 		sprintf(nosetgid_B, "%s/%s", DIR_B, NOSETGID);
96 		sprintf(root_setgid_B, "%s/%s", DIR_B, ROOT_SETGID);
97 
98 		/* Get the uid of user1 */
99 		user1 = getpwnam("nobody");
100 		if (user1 == NULL)
101 			tst_brkm(TBROK, cleanup, "nobody not in /etc/passwd");
102 
103 		user1_uid = user1->pw_uid;
104 
105 		/*
106 		 * Get the group IDs of group1 and group2.
107 		 */
108 		group = getgrnam("nobody");
109 		if (group == NULL) {
110 			group = getgrnam("nogroup");
111 			if (group == NULL) {
112 				tst_brkm(TBROK, cleanup,
113 					 "nobody/nogroup not in /etc/group");
114 			}
115 		}
116 		group1_gid = group->gr_gid;
117 #ifdef ANDROID
118 		group = getgrnam("everybody");
119 		if (group == NULL)
120 			tst_brkm(TBROK, cleanup, "everybody not in /etc/group");
121 #else
122 		group = getgrnam("bin");
123 		if (group == NULL)
124 			tst_brkm(TBROK, cleanup, "bin not in /etc/group");
125 #endif
126 
127 		group2_gid = group->gr_gid;
128 
129 		/*
130 		 * Create a directory with group id the same as this process
131 		 * and with no setgid bit.
132 		 */
133 		if (mkdir(DIR_A, MODE_RWX) < 0) {
134 			tst_resm(TFAIL | TERRNO, "mkdir(%s) failed", DIR_A);
135 			local_flag = FAILED;
136 		}
137 
138 		if (chown(DIR_A, user1_uid, group2_gid) < 0) {
139 			tst_resm(TFAIL | TERRNO, "chown(%s) failed", DIR_A);
140 			local_flag = FAILED;
141 		}
142 
143 		if (stat(DIR_A, &buf) < 0) {
144 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", DIR_A);
145 			local_flag = FAILED;
146 		}
147 
148 		/* Verify modes */
149 		if (buf.st_mode & S_ISGID) {
150 			tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
151 				 DIR_A);
152 			local_flag = FAILED;
153 		}
154 
155 		/* Verify group ID */
156 		if (buf.st_gid != group2_gid) {
157 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
158 				 DIR_A, buf.st_gid, group2_gid);
159 			local_flag = FAILED;
160 		}
161 
162 		/*
163 		 * Create a directory with group id different from that of
164 		 * this process and with the setgid bit set.
165 		 */
166 		if (mkdir(DIR_B, MODE_RWX) < 0) {
167 			tst_resm(TFAIL | TERRNO, "mkdir(%s) failed", DIR_B);
168 			local_flag = FAILED;
169 		}
170 
171 		if (chown(DIR_B, user1_uid, group2_gid) < 0) {
172 			tst_resm(TFAIL | TERRNO, "chown(%s) failed", DIR_B);
173 			local_flag = FAILED;
174 		}
175 
176 		if (chmod(DIR_B, MODE_SGID) < 0) {
177 			tst_resm(TFAIL | TERRNO, "chmod(%s) failed", DIR_B);
178 			local_flag = FAILED;
179 		}
180 
181 		if (stat(DIR_B, &buf) < 0) {
182 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", DIR_B);
183 			local_flag = FAILED;
184 		}
185 
186 		/* Verify modes */
187 		if (!(buf.st_mode & S_ISGID)) {
188 			tst_resm(TFAIL,
189 				 "%s: Incorrect modes, setgid bit not set",
190 				 DIR_B);
191 			local_flag = FAILED;
192 		}
193 
194 		/* Verify group ID */
195 		if (buf.st_gid != group2_gid) {
196 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
197 				 DIR_B, buf.st_gid, group2_gid);
198 			local_flag = FAILED;
199 		}
200 
201 		if (local_flag == PASSED) {
202 			tst_resm(TPASS, "Test passed in block0.");
203 		} else {
204 			tst_resm(TFAIL, "Test failed in block0.");
205 			fail_count++;
206 		}
207 
208 		local_flag = PASSED;
209 
210 		/*
211 		 * Create two files in testdir.A, one with the setgid
212 		 * bit set in the creation modes and the other without.
213 		 * Both should inherit the group ID of the process and
214 		 * maintain the setgid bit as specified in the creation
215 		 * modes.
216 		 */
217 		if (setgid(group1_gid) < 0) {
218 			tst_resm(TINFO,
219 				 "Unable to set process group ID to group1");
220 		}
221 
222 		if (setreuid(-1, user1_uid) < 0)
223 			tst_resm(TINFO, "Unable to set process uid to user1");
224 
225 		mygid = getgid();
226 
227 		/*
228 		 * Create the file with setgid not set
229 		 */
230 		ret = open(nosetgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_RWX);
231 		if (ret < 0) {
232 			tst_resm(TFAIL | TERRNO, "open(%s) failed", nosetgid_A);
233 			local_flag = FAILED;
234 		}
235 		close(ret);
236 
237 		if (stat(nosetgid_A, &buf) < 0) {
238 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", nosetgid_A);
239 			local_flag = FAILED;
240 		}
241 
242 		/* Verify modes */
243 		if (buf.st_mode & S_ISGID) {
244 			tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
245 				 nosetgid_A);
246 			local_flag = FAILED;
247 		}
248 
249 		/* Verify group ID */
250 		if (buf.st_gid != mygid) {
251 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
252 				 nosetgid_A, buf.st_gid, mygid);
253 			local_flag = FAILED;
254 		}
255 
256 		/*
257 		 * Create the file with setgid set
258 		 */
259 		ret = open(setgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
260 		if (ret < 0) {
261 			tst_resm(TFAIL | TERRNO, "open(%s) failed", setgid_A);
262 			local_flag = FAILED;
263 		}
264 		close(ret);
265 
266 		if (stat(setgid_A, &buf) < 0) {
267 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", setgid_A);
268 			local_flag = FAILED;
269 		}
270 
271 		/* Verify modes */
272 		if (!(buf.st_mode & S_ISGID)) {
273 			tst_resm(TFAIL,
274 				 "%s: Incorrect modes, setgid bit not set",
275 				 setgid_A);
276 			local_flag = FAILED;
277 		}
278 
279 		/* Verify group ID */
280 		if (buf.st_gid != mygid) {
281 			tst_resm(TFAIL, "%s: Incorrect group (%d and %d)",
282 				 setgid_A, buf.st_gid, mygid);
283 			local_flag = FAILED;
284 		}
285 
286 		if (local_flag == PASSED) {
287 			tst_resm(TPASS, "Test passed in block1.");
288 		} else {
289 			tst_resm(TFAIL, "Test failed in block1.");
290 			fail_count++;
291 		}
292 
293 		local_flag = PASSED;
294 
295 		/*
296 		 * Create two files in testdir.B, one with the setgid
297 		 * bit set in the creation modes and the other without.
298 		 * Both should inherit the group ID of the parent
299 		 * directory, group2. Either file should have the segid
300 		 * bit set in the modes.
301 		 */
302 		/*
303 		 * Create the file with setgid not set
304 		 */
305 		ret = open(nosetgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_RWX);
306 		if (ret < 0) {
307 			tst_resm(TFAIL | TERRNO, "open(%s) failed", nosetgid_B);
308 			local_flag = FAILED;
309 		}
310 		close(ret);
311 
312 		if (stat(nosetgid_B, &buf) < 0) {
313 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", nosetgid_B);
314 			local_flag = FAILED;
315 		}
316 
317 		/* Verify modes */
318 		if (buf.st_mode & S_ISGID) {
319 			tst_resm(TFAIL,
320 				 "%s: Incorrect modes, setgid bit should be set",
321 				 nosetgid_B);
322 			local_flag = FAILED;
323 		}
324 
325 		/* Verify group ID */
326 		if (buf.st_gid != group2_gid) {
327 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
328 				 nosetgid_B, buf.st_gid, group2_gid);
329 			local_flag = FAILED;
330 		}
331 
332 		/*
333 		 * Create the file with setgid set
334 		 */
335 		ret = open(setgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
336 		if (ret < 0) {
337 			tst_resm(TFAIL | TERRNO, "open(%s) failed", setgid_B);
338 			local_flag = FAILED;
339 		}
340 		close(ret);
341 
342 		if (stat(setgid_B, &buf) < 0) {
343 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", setgid_B);
344 			local_flag = FAILED;
345 		}
346 
347 		/* Verify group ID */
348 		if (buf.st_gid != group2_gid) {
349 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
350 				 setgid_B, buf.st_gid, group2_gid);
351 			local_flag = FAILED;
352 		}
353 
354 		/* Verify modes */
355 		if (!(buf.st_mode & S_ISGID)) {
356 			tst_resm(TFAIL,
357 				 "%s: Incorrect modes, setgid bit not set",
358 				 setgid_B);
359 			local_flag = FAILED;
360 		}
361 
362 		if (local_flag == PASSED) {
363 			tst_resm(TPASS, "Test passed in block2.");
364 		} else {
365 			tst_resm(TFAIL, "Test failed in block2.");
366 			fail_count++;
367 		}
368 
369 		local_flag = PASSED;
370 
371 		/*
372 		 * Create a file in testdir.B, with the setgid bit set
373 		 * in the creation modes and do so as root. The file
374 		 * should inherit the group ID of the parent directory,
375 		 * group2 and should have the setgid bit set.
376 		 */
377 
378 		/* Become root again */
379 		if (setreuid(-1, save_myuid) < 0) {
380 			tst_resm(TFAIL | TERRNO,
381 				 "Changing back to root failed");
382 			local_flag = FAILED;
383 		}
384 
385 		/* Create the file with setgid set */
386 		ret = open(root_setgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
387 		if (ret < 0) {
388 			tst_resm(TFAIL | TERRNO, "open(%s) failed",
389 				 root_setgid_B);
390 			local_flag = FAILED;
391 		}
392 		close(ret);
393 
394 		if (stat(root_setgid_B, &buf) < 0) {
395 			tst_resm(TFAIL | TERRNO, "stat(%s) failed",
396 				 root_setgid_B);
397 			local_flag = FAILED;
398 		}
399 
400 		/* Verify modes */
401 		if (!(buf.st_mode & S_ISGID)) {
402 			tst_resm(TFAIL,
403 				 "%s: Incorrect modes, setgid bit not set",
404 				 root_setgid_B);
405 			local_flag = FAILED;
406 		}
407 
408 		/* Verify group ID */
409 		if (buf.st_gid != group2_gid) {
410 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
411 				 root_setgid_B, buf.st_gid, group2_gid);
412 			local_flag = FAILED;
413 		}
414 
415 		if (local_flag == PASSED) {
416 			tst_resm(TPASS, "Test passed in block3.");
417 		} else {
418 			tst_resm(TFAIL, "Test failed in block3.");
419 			fail_count++;
420 		}
421 
422 		/*
423 		 * Clean up any files created by test before call to anyfail.
424 		 * Remove the directories.
425 		 */
426 		if (unlink(setgid_A) < 0)
427 			tst_resm(TWARN | TERRNO, "unlink(%s) failed", setgid_A);
428 		if (unlink(nosetgid_A) < 0)
429 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
430 				 nosetgid_A);
431 		if (rmdir(DIR_A) < 0)
432 			tst_resm(TWARN | TERRNO, "rmdir(%s) failed", DIR_A);
433 
434 		if (unlink(setgid_B) < 0)
435 			tst_resm(TWARN | TERRNO, "unlink(%s) failed", setgid_B);
436 		if (unlink(root_setgid_B) < 0)
437 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
438 				 root_setgid_B);
439 		if (unlink(nosetgid_B) < 0)
440 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
441 				 nosetgid_B);
442 		if (rmdir(DIR_B) < 0)
443 			tst_resm(TWARN | TERRNO, "rmdir(%s) failed", DIR_B);
444 
445 		if (fail_count == 0) {
446 			tst_resm(TPASS, "Test passed.");
447 		} else {
448 			tst_resm(TFAIL,
449 				 "Test failed because of above failures.");
450 		}
451 
452 	}
453 
454 	cleanup();
455 	tst_exit();
456 }
457 
setup(void)458 static void setup(void)
459 {
460 	tst_require_root();
461 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
462 	TEST_PAUSE;
463 	tst_tmpdir();
464 }
465 
cleanup(void)466 static void cleanup(void)
467 {
468 	tst_rmdir();
469 }
470