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