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 tst_cleanup(void);
74 static void cleanup(void);
75 static void setup(void);
76
77 static char DIR_A[MSGSIZE], DIR_B[MSGSIZE];
78 static char setgid_A[MSGSIZE], nosetgid_A[MSGSIZE];
79 static char setgid_B[MSGSIZE], nosetgid_B[MSGSIZE], root_setgid_B[MSGSIZE];
80
main(int ac,char ** av)81 int main(int ac, char **av)
82 {
83 struct stat buf;
84 struct group *group;
85 struct passwd *user1;
86 gid_t group1_gid, group2_gid, mygid;
87 uid_t save_myuid, user1_uid;
88 pid_t mypid;
89
90 int fd;
91 int lc;
92
93 tst_parse_opts(ac, av, NULL, NULL);
94
95 setup();
96
97 for (lc = 0; TEST_LOOPING(lc); lc++) {
98
99 local_flag = PASSED;
100
101 save_myuid = getuid();
102 mypid = getpid();
103 sprintf(DIR_A, DIR_A_TEMP, mypid);
104 sprintf(DIR_B, DIR_B_TEMP, mypid);
105 sprintf(setgid_A, "%s/%s", DIR_A, SETGID);
106 sprintf(nosetgid_A, "%s/%s", DIR_A, NOSETGID);
107 sprintf(setgid_B, "%s/%s", DIR_B, SETGID);
108 sprintf(nosetgid_B, "%s/%s", DIR_B, NOSETGID);
109 sprintf(root_setgid_B, "%s/%s", DIR_B, ROOT_SETGID);
110
111 /* Get the uid of user1 */
112 if ((user1 = getpwnam("nobody")) == NULL) {
113 tst_brkm(TBROK | TERRNO, NULL,
114 "getpwnam(\"nobody\") failed");
115 }
116
117 user1_uid = user1->pw_uid;
118
119 /*
120 * Get the group IDs of group1 and group2.
121 */
122 if ((group = getgrnam("nobody")) == NULL) {
123 if ((group = getgrnam("nogroup")) == NULL) {
124 tst_brkm(TBROK | TERRNO, cleanup,
125 "getgrnam(\"nobody\") and "
126 "getgrnam(\"nogroup\") failed");
127 }
128 }
129 group1_gid = group->gr_gid;
130 if ((group = getgrnam("bin")) == NULL) {
131 tst_brkm(TBROK | TERRNO, cleanup,
132 "getgrnam(\"bin\") failed");
133 }
134 group2_gid = group->gr_gid;
135
136 /*--------------------------------------------------------------*/
137 /* Block0: Set up the parent directories */
138 /*--------------------------------------------------------------*/
139 /*
140 * Create a directory with group id the same as this process
141 * and with no setgid bit.
142 */
143 if (mkdir(DIR_A, MODE_RWX) == -1) {
144 tst_resm(TFAIL, "Creation of %s failed", DIR_A);
145 local_flag = FAILED;
146 }
147
148 if (chown(DIR_A, user1_uid, group2_gid) == -1) {
149 tst_resm(TFAIL, "Chown of %s failed", DIR_A);
150 local_flag = FAILED;
151 }
152
153 if (stat(DIR_A, &buf) == -1) {
154 tst_resm(TFAIL, "Stat of %s failed", DIR_A);
155 local_flag = FAILED;
156 }
157
158 /* Verify modes */
159 if (buf.st_mode & S_ISGID) {
160 tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
161 DIR_A);
162 local_flag = FAILED;
163 }
164
165 /* Verify group ID */
166 if (buf.st_gid != group2_gid) {
167 tst_resm(TFAIL, "%s: Incorrect group", DIR_A);
168 tst_resm(TINFO, "got %u and %u", buf.st_gid,
169 group2_gid);
170 local_flag = FAILED;
171 }
172
173 /*
174 * Create a directory with group id different from that of
175 * this process and with the setgid bit set.
176 */
177 if (mkdir(DIR_B, MODE_RWX) == -1) {
178 tst_resm(TFAIL, "Creation of %s failed", DIR_B);
179 local_flag = FAILED;
180 }
181
182 if (chown(DIR_B, user1_uid, group2_gid) == -1) {
183 tst_resm(TFAIL, "Chown of %s failed", DIR_B);
184 local_flag = FAILED;
185 }
186
187 if (chmod(DIR_B, MODE_SGID) == -1) {
188 tst_resm(TFAIL, "Chmod of %s failed", DIR_B);
189 local_flag = FAILED;
190 }
191
192 if (stat(DIR_B, &buf) == -1) {
193 tst_resm(TFAIL, "Stat of %s failed", DIR_B);
194 local_flag = FAILED;
195 }
196
197 /* Verify modes */
198 if (!(buf.st_mode & S_ISGID)) {
199 tst_resm(TFAIL,
200 "%s: Incorrect modes, setgid bit not set",
201 DIR_B);
202 local_flag = FAILED;
203 }
204
205 /* Verify group ID */
206 if (buf.st_gid != group2_gid) {
207 tst_resm(TFAIL, "%s: Incorrect group", DIR_B);
208 tst_resm(TINFO, "got %u and %u", buf.st_gid,
209 group2_gid);
210 local_flag = FAILED;
211 }
212
213 if (local_flag == PASSED) {
214 tst_resm(TPASS, "Test passed in block0.");
215 } else {
216 tst_resm(TFAIL, "Test failed in block0.");
217 }
218
219 local_flag = PASSED;
220
221 /*--------------------------------------------------------------*/
222 /* Block1: Create two files in testdir.A, one with the setgid */
223 /* bit set in the creation modes and the other without. */
224 /* Both should inherit the group ID of the process and */
225 /* maintain the setgid bit as specified in the creation */
226 /* modes. */
227 /*--------------------------------------------------------------*/
228 /*
229 * Now become user1, group1
230 */
231 if (setgid(group1_gid) == -1) {
232 tst_resm(TINFO,
233 "Unable to set process group ID to group1");
234 }
235
236 if (setreuid(-1, user1_uid) == -1) {
237 tst_resm(TINFO, "Unable to set process uid to user1");
238 }
239 mygid = getgid();
240
241 /*
242 * Create the file with setgid not set
243 */
244 fd = open(nosetgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_RWX);
245 if (fd == -1) {
246 tst_resm(TFAIL, "Creation of %s failed", nosetgid_A);
247 local_flag = FAILED;
248 }
249
250 if (stat(nosetgid_A, &buf) == -1) {
251 tst_resm(TFAIL, "Stat of %s failed", nosetgid_A);
252 local_flag = FAILED;
253 }
254
255 /* Verify modes */
256 if (buf.st_mode & S_ISGID) {
257 tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set",
258 nosetgid_A);
259 local_flag = FAILED;
260 }
261
262 /* Verify group ID */
263 if (buf.st_gid != mygid) {
264 tst_resm(TFAIL, "%s: Incorrect group", nosetgid_A);
265 local_flag = FAILED;
266 }
267 close(fd);
268
269 /*
270 * Create the file with setgid set
271 */
272 fd = open(setgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_SGID);
273 if (fd == -1) {
274 tst_resm(TFAIL, "Creation of %s failed", setgid_A);
275 local_flag = FAILED;
276 }
277
278 if (stat(setgid_A, &buf) == -1) {
279 tst_resm(TFAIL, "Stat of %s failed", setgid_A);
280 local_flag = FAILED;
281 }
282
283 /* Verify modes */
284 if (!(buf.st_mode & S_ISGID)) {
285 tst_resm(TFAIL,
286 "%s: Incorrect modes, setgid bit not set",
287 setgid_A);
288 local_flag = FAILED;
289 }
290
291 /* Verify group ID */
292 if (buf.st_gid != mygid) {
293 tst_resm(TFAIL, "%s: Incorrect group", setgid_A);
294 tst_resm(TINFO, "got %u and %u", buf.st_gid, mygid);
295 local_flag = FAILED;
296 }
297 close(fd);
298
299 if (local_flag == PASSED) {
300 tst_resm(TPASS, "Test passed in block1.");
301 } else {
302 tst_resm(TFAIL, "Test failed in block1.");
303 }
304
305 local_flag = PASSED;
306
307 /*--------------------------------------------------------------*/
308 /* Block2: Create two files in testdir.B, one with the setgid */
309 /* bit set in the creation modes and the other without. */
310 /* Both should inherit the group ID of the parent */
311 /* directory, group2. */
312 /*--------------------------------------------------------------*/
313 /*
314 * Create the file with setgid not set
315 */
316 fd = creat(nosetgid_B, MODE_RWX);
317 if (fd == -1) {
318 tst_resm(TFAIL, "Creation of %s failed", nosetgid_B);
319 local_flag = FAILED;
320 }
321
322 if (stat(nosetgid_B, &buf) == -1) {
323 tst_resm(TFAIL, "Stat of %s failed", nosetgid_B);
324 local_flag = FAILED;
325 }
326
327 /* Verify modes */
328 if (buf.st_mode & S_ISGID) {
329 tst_resm(TFAIL,
330 "%s: Incorrect modes, setgid bit should not be set",
331 nosetgid_B);
332 local_flag = FAILED;
333 }
334
335 /* Verify group ID */
336 if (buf.st_gid != group2_gid) {
337 tst_resm(TFAIL, "%s: Incorrect group", nosetgid_B);
338 local_flag = FAILED;
339 }
340 close(fd);
341
342 /*
343 * Create the file with setgid set
344 */
345 fd = creat(setgid_B, MODE_SGID);
346 if (fd == -1) {
347 tst_resm(TFAIL, "Creation of %s failed", setgid_B);
348 local_flag = FAILED;
349 }
350
351 if (stat(setgid_B, &buf) == -1) {
352 tst_resm(TFAIL, "Stat of %s failed", setgid_B);
353 local_flag = FAILED;
354 }
355
356 /* Verify group ID */
357 if (buf.st_gid != group2_gid) {
358 tst_resm(TFAIL, "%s: Incorrect group", setgid_B);
359 tst_resm(TFAIL, "got %u and %u", buf.st_gid,
360 group2_gid);
361 local_flag = FAILED;
362 }
363
364 /*
365 * Skip S_ISGID check
366 * 0fa3ecd87848 ("Fix up non-directory creation in SGID directories")
367 * clears S_ISGID for files created by non-group members
368 */
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 tst_cleanup();
427 }
428 cleanup();
429 tst_exit();
430 }
431
setup(void)432 static void setup(void)
433 {
434 tst_require_root();
435 tst_tmpdir();
436 }
437
tst_cleanup(void)438 static void tst_cleanup(void)
439 {
440 if (unlink(setgid_A) == -1) {
441 tst_resm(TBROK, "%s failed", setgid_A);
442 }
443 if (unlink(nosetgid_A) == -1) {
444 tst_resm(TBROK, "unlink %s failed", nosetgid_A);
445 }
446 SAFE_RMDIR(NULL, DIR_A);
447 SAFE_UNLINK(NULL, setgid_B);
448 SAFE_UNLINK(NULL, root_setgid_B);
449 SAFE_UNLINK(NULL, nosetgid_B);
450 SAFE_RMDIR(NULL, DIR_B);
451 }
452
cleanup(void)453 static void cleanup(void)
454 {
455 tst_rmdir();
456 }
457