• 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 		group = getgrnam("bin");
118 		if (group == NULL)
119 			tst_brkm(TBROK, cleanup, "bin not in /etc/group");
120 
121 		group2_gid = group->gr_gid;
122 
123 		/*
124 		 * Create a directory with group id the same as this process
125 		 * and with no setgid bit.
126 		 */
127 		if (mkdir(DIR_A, MODE_RWX) < 0) {
128 			tst_resm(TFAIL | TERRNO, "mkdir(%s) failed", DIR_A);
129 			local_flag = FAILED;
130 		}
131 
132 		if (chown(DIR_A, user1_uid, group2_gid) < 0) {
133 			tst_resm(TFAIL | TERRNO, "chown(%s) failed", DIR_A);
134 			local_flag = FAILED;
135 		}
136 
137 		if (stat(DIR_A, &buf) < 0) {
138 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", DIR_A);
139 			local_flag = FAILED;
140 		}
141 
142 		/* Verify modes */
143 		if (buf.st_mode & S_ISGID) {
144 			tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
145 				 DIR_A);
146 			local_flag = FAILED;
147 		}
148 
149 		/* Verify group ID */
150 		if (buf.st_gid != group2_gid) {
151 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
152 				 DIR_A, buf.st_gid, group2_gid);
153 			local_flag = FAILED;
154 		}
155 
156 		/*
157 		 * Create a directory with group id different from that of
158 		 * this process and with the setgid bit set.
159 		 */
160 		if (mkdir(DIR_B, MODE_RWX) < 0) {
161 			tst_resm(TFAIL | TERRNO, "mkdir(%s) failed", DIR_B);
162 			local_flag = FAILED;
163 		}
164 
165 		if (chown(DIR_B, user1_uid, group2_gid) < 0) {
166 			tst_resm(TFAIL | TERRNO, "chown(%s) failed", DIR_B);
167 			local_flag = FAILED;
168 		}
169 
170 		if (chmod(DIR_B, MODE_SGID) < 0) {
171 			tst_resm(TFAIL | TERRNO, "chmod(%s) failed", DIR_B);
172 			local_flag = FAILED;
173 		}
174 
175 		if (stat(DIR_B, &buf) < 0) {
176 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", DIR_B);
177 			local_flag = FAILED;
178 		}
179 
180 		/* Verify modes */
181 		if (!(buf.st_mode & S_ISGID)) {
182 			tst_resm(TFAIL,
183 				 "%s: Incorrect modes, setgid bit not set",
184 				 DIR_B);
185 			local_flag = FAILED;
186 		}
187 
188 		/* Verify group ID */
189 		if (buf.st_gid != group2_gid) {
190 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
191 				 DIR_B, buf.st_gid, group2_gid);
192 			local_flag = FAILED;
193 		}
194 
195 		if (local_flag == PASSED) {
196 			tst_resm(TPASS, "Test passed in block0.");
197 		} else {
198 			tst_resm(TFAIL, "Test failed in block0.");
199 			fail_count++;
200 		}
201 
202 		local_flag = PASSED;
203 
204 		/*
205 		 * Create two files in testdir.A, one with the setgid
206 		 * bit set in the creation modes and the other without.
207 		 * Both should inherit the group ID of the process and
208 		 * maintain the setgid bit as specified in the creation
209 		 * modes.
210 		 */
211 		if (setgid(group1_gid) < 0) {
212 			tst_resm(TINFO,
213 				 "Unable to set process group ID to group1");
214 		}
215 
216 		if (setreuid(-1, user1_uid) < 0)
217 			tst_resm(TINFO, "Unable to set process uid to user1");
218 
219 		mygid = getgid();
220 
221 		/*
222 		 * Create the file with setgid not set
223 		 */
224 		ret = open(nosetgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_RWX);
225 		if (ret < 0) {
226 			tst_resm(TFAIL | TERRNO, "open(%s) failed", nosetgid_A);
227 			local_flag = FAILED;
228 		}
229 		close(ret);
230 
231 		if (stat(nosetgid_A, &buf) < 0) {
232 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", nosetgid_A);
233 			local_flag = FAILED;
234 		}
235 
236 		/* Verify modes */
237 		if (buf.st_mode & S_ISGID) {
238 			tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
239 				 nosetgid_A);
240 			local_flag = FAILED;
241 		}
242 
243 		/* Verify group ID */
244 		if (buf.st_gid != mygid) {
245 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
246 				 nosetgid_A, buf.st_gid, mygid);
247 			local_flag = FAILED;
248 		}
249 
250 		/*
251 		 * Create the file with setgid set
252 		 */
253 		ret = open(setgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
254 		if (ret < 0) {
255 			tst_resm(TFAIL | TERRNO, "open(%s) failed", setgid_A);
256 			local_flag = FAILED;
257 		}
258 		close(ret);
259 
260 		if (stat(setgid_A, &buf) < 0) {
261 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", setgid_A);
262 			local_flag = FAILED;
263 		}
264 
265 		/* Verify modes */
266 		if (!(buf.st_mode & S_ISGID)) {
267 			tst_resm(TFAIL,
268 				 "%s: Incorrect modes, setgid bit not set",
269 				 setgid_A);
270 			local_flag = FAILED;
271 		}
272 
273 		/* Verify group ID */
274 		if (buf.st_gid != mygid) {
275 			tst_resm(TFAIL, "%s: Incorrect group (%d and %d)",
276 				 setgid_A, buf.st_gid, mygid);
277 			local_flag = FAILED;
278 		}
279 
280 		if (local_flag == PASSED) {
281 			tst_resm(TPASS, "Test passed in block1.");
282 		} else {
283 			tst_resm(TFAIL, "Test failed in block1.");
284 			fail_count++;
285 		}
286 
287 		local_flag = PASSED;
288 
289 		/*
290 		 * Create two files in testdir.B, one with the setgid
291 		 * bit set in the creation modes and the other without.
292 		 * Both should inherit the group ID of the parent
293 		 * directory, group2. Either file should have the segid
294 		 * bit set in the modes.
295 		 */
296 		/*
297 		 * Create the file with setgid not set
298 		 */
299 		ret = open(nosetgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_RWX);
300 		if (ret < 0) {
301 			tst_resm(TFAIL | TERRNO, "open(%s) failed", nosetgid_B);
302 			local_flag = FAILED;
303 		}
304 		close(ret);
305 
306 		if (stat(nosetgid_B, &buf) < 0) {
307 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", nosetgid_B);
308 			local_flag = FAILED;
309 		}
310 
311 		/* Verify modes */
312 		if (buf.st_mode & S_ISGID) {
313 			tst_resm(TFAIL,
314 				 "%s: Incorrect modes, setgid bit should be set",
315 				 nosetgid_B);
316 			local_flag = FAILED;
317 		}
318 
319 		/* Verify group ID */
320 		if (buf.st_gid != group2_gid) {
321 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
322 				 nosetgid_B, buf.st_gid, group2_gid);
323 			local_flag = FAILED;
324 		}
325 
326 		/*
327 		 * Create the file with setgid set
328 		 */
329 		ret = open(setgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
330 		if (ret < 0) {
331 			tst_resm(TFAIL | TERRNO, "open(%s) failed", setgid_B);
332 			local_flag = FAILED;
333 		}
334 		close(ret);
335 
336 		if (stat(setgid_B, &buf) < 0) {
337 			tst_resm(TFAIL | TERRNO, "stat(%s) failed", setgid_B);
338 			local_flag = FAILED;
339 		}
340 
341 		/* Verify group ID */
342 		if (buf.st_gid != group2_gid) {
343 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
344 				 setgid_B, buf.st_gid, group2_gid);
345 			local_flag = FAILED;
346 		}
347 
348 		/*
349 		 * Skip S_ISGID check
350 		 * 0fa3ecd87848 ("Fix up non-directory creation in SGID directories")
351 		 * clears S_ISGID for files created by non-group members
352 		 */
353 
354 		if (local_flag == PASSED) {
355 			tst_resm(TPASS, "Test passed in block2.");
356 		} else {
357 			tst_resm(TFAIL, "Test failed in block2.");
358 			fail_count++;
359 		}
360 
361 		local_flag = PASSED;
362 
363 		/*
364 		 * Create a file in testdir.B, with the setgid bit set
365 		 * in the creation modes and do so as root. The file
366 		 * should inherit the group ID of the parent directory,
367 		 * group2 and should have the setgid bit set.
368 		 */
369 
370 		/* Become root again */
371 		if (setreuid(-1, save_myuid) < 0) {
372 			tst_resm(TFAIL | TERRNO,
373 				 "Changing back to root failed");
374 			local_flag = FAILED;
375 		}
376 
377 		/* Create the file with setgid set */
378 		ret = open(root_setgid_B, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
379 		if (ret < 0) {
380 			tst_resm(TFAIL | TERRNO, "open(%s) failed",
381 				 root_setgid_B);
382 			local_flag = FAILED;
383 		}
384 		close(ret);
385 
386 		if (stat(root_setgid_B, &buf) < 0) {
387 			tst_resm(TFAIL | TERRNO, "stat(%s) failed",
388 				 root_setgid_B);
389 			local_flag = FAILED;
390 		}
391 
392 		/* Verify modes */
393 		if (!(buf.st_mode & S_ISGID)) {
394 			tst_resm(TFAIL,
395 				 "%s: Incorrect modes, setgid bit not set",
396 				 root_setgid_B);
397 			local_flag = FAILED;
398 		}
399 
400 		/* Verify group ID */
401 		if (buf.st_gid != group2_gid) {
402 			tst_resm(TFAIL, "%s: Incorrect group (got %d and %d)",
403 				 root_setgid_B, buf.st_gid, group2_gid);
404 			local_flag = FAILED;
405 		}
406 
407 		if (local_flag == PASSED) {
408 			tst_resm(TPASS, "Test passed in block3.");
409 		} else {
410 			tst_resm(TFAIL, "Test failed in block3.");
411 			fail_count++;
412 		}
413 
414 		/*
415 		 * Clean up any files created by test before call to anyfail.
416 		 * Remove the directories.
417 		 */
418 		if (unlink(setgid_A) < 0)
419 			tst_resm(TWARN | TERRNO, "unlink(%s) failed", setgid_A);
420 		if (unlink(nosetgid_A) < 0)
421 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
422 				 nosetgid_A);
423 		if (rmdir(DIR_A) < 0)
424 			tst_resm(TWARN | TERRNO, "rmdir(%s) failed", DIR_A);
425 
426 		if (unlink(setgid_B) < 0)
427 			tst_resm(TWARN | TERRNO, "unlink(%s) failed", setgid_B);
428 		if (unlink(root_setgid_B) < 0)
429 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
430 				 root_setgid_B);
431 		if (unlink(nosetgid_B) < 0)
432 			tst_resm(TWARN | TERRNO, "unlink(%s) failed",
433 				 nosetgid_B);
434 		if (rmdir(DIR_B) < 0)
435 			tst_resm(TWARN | TERRNO, "rmdir(%s) failed", DIR_B);
436 
437 		if (fail_count == 0) {
438 			tst_resm(TPASS, "Test passed.");
439 		} else {
440 			tst_resm(TFAIL,
441 				 "Test failed because of above failures.");
442 		}
443 
444 	}
445 
446 	cleanup();
447 	tst_exit();
448 }
449 
setup(void)450 static void setup(void)
451 {
452 	tst_require_root();
453 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
454 	TEST_PAUSE;
455 	tst_tmpdir();
456 }
457 
cleanup(void)458 static void cleanup(void)
459 {
460 	tst_rmdir();
461 }
462