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