1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
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 * mkdir02
23 *
24 * DESCRIPTION
25 * This test will verify that new directory created
26 * by mkdir(2) inherites the group ID from the parent
27 * directory and S_ISGID bit, if the S_ISGID bit is set
28 * in the parent directory.
29 *
30 * ALGORITHM
31 * Setup:
32 * Setup signal handling.
33 * Pause for SIGUSR1 if option specified.
34 * Create temporary directory.
35 * Give write permission on temporary directory for all users.
36 * set up umask
37 *
38 * Test:
39 * Loop if the proper options are given.
40 * fork the first child as ltpuser1
41 * create a directory tstdir1 with S_ISGID set
42 * fork the second child as ltpuser2
43 * create a directtory tstdir2 user tstdir1
44 * check tstdir2's group ID and the S_ISGID bit
45 * if they are the same as tstdir1's
46 * PASS
47 * else FAIL
48 * Cleanup:
49 * Print errno log and/or timing stats if options given
50 * Delete the temporary directory created.*
51 * USAGE
52 * mkdir02 [-c n] [-e] [-f] [-i n] [-I x] [-P x] [-t]
53 * where, -c n : Run n copies concurrently.
54 * -e : Turn on errno logging.
55 * -f : Turn off functionality Testing.
56 * -i n : Execute test n times.
57 * -I x : Execute test for x seconds.
58 * -P x : Pause for x seconds between iterations.
59 * -t : Turn on syscall timing.
60 *
61 * HISTORY
62 * 07/2001 Ported by Wayne Boyer
63 *
64 * RESTRICTIONS
65 * None.
66 */
67
68 #include <errno.h>
69 #include <string.h>
70 #include <signal.h>
71 #include <sys/stat.h>
72 #include <sys/types.h>
73 #include <fcntl.h>
74 #include <pwd.h>
75 #include <sys/wait.h>
76 #include <unistd.h>
77
78 #include "test.h"
79 #include "safe_macros.h"
80
81 void setup();
82 void cleanup();
83
84 #define PERMS 0777
85
86 static uid_t nobody_uid, bin_uid;
87 static gid_t nobody_gid, bin_gid;
88
89 char *TCID = "mkdir02";
90 int TST_TOTAL = 1;
91
92 char tstdir1[100];
93 char tstdir2[100];
94
main(int ac,char ** av)95 int main(int ac, char **av)
96 {
97 int lc;
98 struct stat buf, buf1;
99 pid_t pid, pid1;
100 int rval, status;
101
102 /*
103 * parse standard options
104 */
105 tst_parse_opts(ac, av, NULL, NULL);
106
107 /*
108 * perform global setup for test
109 */
110 setup();
111
112 /*
113 * check looping state if -i option given
114 */
115 for (lc = 0; TEST_LOOPING(lc); lc++) {
116
117 tst_count = 0;
118
119 /* check the inherited group ID */
120
121 /*
122 * first, fork the first child, set to ltpuser1's uid and gid,
123 * create a directory, with S_ISGID bit set
124 */
125
126 sprintf(tstdir1, "tstdir1.%d", getpid());
127
128 if ((pid = FORK_OR_VFORK()) < 0) {
129 tst_brkm(TFAIL, cleanup, "fork() failed");
130
131 }
132
133 if (pid == 0) { /* first child */
134 rval = setregid(nobody_gid, nobody_gid);
135 if (rval < 0) {
136 perror("setregid");
137 tst_resm(TFAIL, "setregid failed to "
138 "to set the real gid to %d and "
139 "effective gid to %d",
140 nobody_gid, nobody_gid);
141 exit(1);
142
143 }
144 /* being ltupuser1 */
145 rval = setreuid(nobody_uid, nobody_uid);
146 if (rval < 0) {
147 perror("setreuid");
148 tst_resm(TFAIL, "setreuid failed to "
149 "to set the real uid to %d and "
150 "effective uid to %d",
151 nobody_uid, nobody_uid);
152 exit(1);
153
154 }
155
156 /*
157 * create a direcoty with S_ISGID bit set
158 * and the group ID is ltpuser1
159 */
160 if (mkdir(tstdir1, PERMS) != 0) {
161 perror("mkdir");
162 tst_resm(TFAIL, "mkdir() failed to create"
163 " a directory with Set "
164 " group ID turn on ");
165 exit(1);
166
167 }
168 if (stat(tstdir1, &buf1) == -1) {
169 perror("stat");
170 tst_resm(TFAIL,
171 "failed to stat the new directory"
172 "in mkdir()");
173 exit(1);
174
175 }
176 if (chmod(tstdir1, buf1.st_mode | S_ISGID) != 0) {
177 perror("chmod");
178 tst_resm(TFAIL, "failed to set S_ISGID bit");
179 exit(1);
180
181 }
182
183 /* Successfully create the parent directory */
184 exit(0);
185
186 }
187 wait(&status);
188 if (WEXITSTATUS(status) != 0) {
189 tst_brkm(TFAIL, cleanup,
190 "Test to attempt to make a directory"
191 " inherits group ID FAILED ");
192 }
193 /*
194 * fork the second child process, set to ltpuser2's uid and gid
195 * create a sub directory under the directory
196 * just created by child process 1
197 * check the group ID of the sub directory
198 * should inherit from parent directory
199 */
200
201 sprintf(tstdir2, "%s/tstdir2.%d", tstdir1, getpid());
202 if ((pid1 = FORK_OR_VFORK()) < 0) {
203 perror("fork failed");
204 tst_brkm(TFAIL, cleanup, "fork() failed");
205
206 } else if (pid1 == 0) { /* second child */
207
208 /* being user ltpuser2 */
209 rval = setregid(bin_gid, bin_gid);
210 if (rval < 0) {
211 tst_resm(TFAIL, "setregid failed to "
212 "to set the real gid to %d and "
213 "effective gid to %d",
214 bin_gid, bin_gid);
215 perror("setregid");
216 exit(1);
217
218 }
219 rval = setreuid(bin_uid, bin_uid);
220 if (rval < 0) {
221 tst_resm(TFAIL, "setreuid failed to "
222 "to set the real uid to %d and "
223 "effective uid to %d",
224 bin_uid, bin_uid);
225 perror("setreuid");
226 exit(1);
227
228 }
229
230 /*
231 * create a sub direcoty
232 * under the directory just created
233 * by ltpuser1
234 */
235 if (mkdir(tstdir2, PERMS) != 0) {
236 tst_resm(TFAIL, "mkdir() failed to create"
237 " a directory %s under %s ", tstdir2,
238 tstdir1);
239 exit(1);
240
241 }
242 /*
243 * check the group ID
244 * should not be the same as the current processs's
245 * since parent directory is set with S_ISGID bit
246 */
247 if (stat(tstdir2, &buf) == -1) {
248 tst_resm(TFAIL,
249 "failed to stat the new directory"
250 "in mkdir()");
251 exit(1);
252
253 }
254 if (stat(tstdir1, &buf1) == -1) {
255 tst_resm(TFAIL,
256 "failed to stat the new directory"
257 "in mkdir()");
258 exit(1);
259
260 }
261 if (buf.st_gid != buf1.st_gid) {
262 tst_resm(TFAIL, "mkdir() FAILED to inherit "
263 " the group ID %d from parent "
264 " directory %d",
265 buf.st_gid, buf1.st_gid);
266 exit(1);
267
268 }
269
270 /* check the S_ISGID bit */
271 if (!(buf.st_mode & S_ISGID)) {
272 tst_resm(TFAIL, "mkdir() FAILED to inherit "
273 " the S_ISGID bit from parent "
274 " directory");
275 exit(1);
276
277 }
278 /* PASS */
279 exit(0);
280
281 }
282
283 waitpid(pid1, &status, 0);
284 if (WEXITSTATUS(status) == 0) {
285 tst_resm(TPASS, "Test to attempt to make a directory"
286 " inherits group ID SUCCEEDED ");
287 } else {
288 tst_resm(TFAIL, "Test to attempt to make a directory"
289 " inherits group ID FAILED");
290 cleanup();
291 }
292
293 }
294
295 /*
296 * cleanup and exit
297 */
298 cleanup();
299
300 tst_exit();
301 }
302
303 /*
304 * setup() - performs all ONE TIME setup for this test.
305 */
setup(void)306 void setup(void)
307 {
308 struct passwd *pw;
309
310 tst_require_root();
311
312 pw = SAFE_GETPWNAM(NULL, "nobody");
313 nobody_uid = pw->pw_uid;
314 nobody_gid = pw->pw_gid;
315 pw = SAFE_GETPWNAM(NULL, "bin");
316 bin_uid = pw->pw_uid;
317 bin_gid = pw->pw_gid;
318
319 tst_sig(FORK, DEF_HANDLER, cleanup);
320
321 TEST_PAUSE;
322
323 /* Create a temporary directory and make it current. */
324 tst_tmpdir();
325
326 umask(0);
327 }
328
329 /*
330 * cleanup() - performs all ONE TIME cleanup for this test at
331 * completion or premature exit.
332 */
cleanup(void)333 void cleanup(void)
334 {
335
336 /*
337 * Remove the temporary directory.
338 */
339 tst_rmdir();
340
341 /*
342 * Exit with return code appropriate for results.
343 */
344
345 }
346