blob: 6b7be99933611790512e10963bbab67f35b23363 [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name: mknod03
22 *
23 * Test Description:
24 * Verify that mknod(2) succeeds when used to create a filesystem
25 * node with set group-ID bit set on a directory with set group-ID bit set.
26 * The node created should have set group-ID bit set and its gid should be
27 * equal to the effective gid of the process.
28 *
29 * Expected Result:
30 * mknod() should return value 0 on success and node created should have
31 * set group-ID bit set, its gid should be equal to the effective gid of
32 * the process.
33 *
34 * Algorithm:
35 * Setup:
36 * Setup signal handling.
37 * Create temporary directory.
38 * Pause for SIGUSR1 if option specified.
39 *
40 * Test:
41 * Loop if the proper options are given.
42 * Execute system call
43 * Check return code, if system call failed (return=-1)
44 * Log the errno and Issue a FAIL message.
45 * Otherwise,
46 * Verify the Functionality of system call
47 * if successful,
48 * Issue Functionality-Pass message.
49 * Otherwise,
50 * Issue Functionality-Fail message.
51 * Cleanup:
52 * Print errno log and/or timing stats if options given
53 * Delete the temporary directory created.
54 *
55 * Usage: <for command-line>
56 * mknod03 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
57 * where, -c n : Run n copies concurrently.
58 * -f : Turn off functionality Testing.
59 * -i n : Execute test n times.
60 * -I x : Execute test for x seconds.
61 * -P x : Pause for x seconds between iterations.
62 * -t : Turn on syscall timing.
63 *
64 * HISTORY
65 * 07/2001 Ported by Wayne Boyer
66 *
67 * RESTRICTIONS:
68 * This test should be run by 'super-user' (root) only.
69 *
70 */
71
72#include <stdio.h>
73#include <stdlib.h>
74#include <unistd.h>
75#include <errno.h>
76#include <string.h>
77#include <signal.h>
78#include <pwd.h>
79#include <sys/types.h>
80#include <sys/stat.h>
81
82#include "test.h"
83#include "usctest.h"
84
85#define LTPUSER "nobody"
86#define MODE_RWX S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO
87#define MODE_SGID S_IFIFO | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO
88#define DIR_TEMP "testdir_3"
89#define TNODE "tnode_%d"
90
91struct stat buf; /* struct. to hold stat(2) o/p contents */
92struct passwd *user1; /* struct. to hold getpwnam(3) o/p contents */
93
94char *TCID="mknod03"; /* Test program identifier. */
95int TST_TOTAL = 1; /* Total number of test cases. */
96char node_name[PATH_MAX]; /* buffer to hold node name created */
97extern int Tst_count; /* Test Case counter for tst_* routines */
98
99gid_t group1_gid, group2_gid, mygid; /* user and process group id's */
100uid_t save_myuid, user1_uid; /* user and process user id's */
101pid_t mypid; /* process id */
102
103void setup(); /* setup function for the test */
104void cleanup(); /* cleanup function for the test */
105
106int
107main(int ac, char **av)
108{
109 int lc; /* loop counter */
110 int fflag; /* functionality flag variable */
111 char *msg; /* message returned from parse_opts */
112
113 /* Parse standard options given to run the test. */
114 msg = parse_opts(ac, av, (option_t *) NULL, NULL);
115 if (msg != (char *) NULL) {
116 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
117 tst_exit();
118 }
119
120 /* Perform global setup for test */
121 setup();
122
123 /* Check looping state if -i option given */
124 for (lc = 0; TEST_LOOPING(lc); lc++) {
125 /* Reset Tst_count in case we are looping. */
126 Tst_count=0;
127
128 /*
129 * Attempt to create a filesystem node with group id (sgid)
130 * bit set on a directory with group id (sgid) bit set
131 * such that, the node created by mknod(2) should have
132 * group id (sgid) bit set and node's gid should be equal
133 * to that of effective gid of the process.
134 */
135 TEST(mknod(node_name, MODE_SGID, 0));
136
137 /* Check return code from mknod(2) */
138 if (TEST_RETURN == -1) {
139 tst_resm(TFAIL, "mknod(%s, %#o, 0) failed, errno=%d : "
140 "%s", node_name, MODE_SGID, TEST_ERRNO,
141 strerror(TEST_ERRNO));
142 continue;
143 }
144 /*
145 * Perform functional verification if test executed
146 * without (-f) option.
147 */
148 if (STD_FUNCTIONAL_TEST) {
149 /* Set the functionality flag */
150 fflag = 1;
151
152 /* Check for node's creation */
153 if (stat(node_name, &buf) < 0) {
154 tst_resm(TFAIL, "stat() of %s failed, errno:%d",
155 node_name, TEST_ERRNO);
156 /* unset functionality flag */
157 fflag = 0;
158 }
159
160 /* Verify mode permissions of node */
161 if (!(buf.st_mode & S_ISGID)) {
162 tst_resm(TFAIL,
163 "%s: Incorrect modes, setgid bit not "
164 "set", node_name);
165 /* unset flag as functionality fails */
166 fflag = 0;
167 }
168
169 /* Verify group ID */
170 if (buf.st_gid != group2_gid) {
171 tst_resm(TFAIL, "%s: Incorrect group",
172 node_name);
173 /* unset flag as functionality fails */
174 fflag = 0;
175 }
176 if (fflag) {
177 tst_resm(TPASS, "Functionality of mknod(%s, "
178 "%#o, 0) successful",
179 node_name, MODE_SGID);
180 }
181 } else {
182 tst_resm(TPASS, "call succeeded");
183 }
184
185 /* Remove the node for the next go `round */
186 if (unlink(node_name) == -1) {
187 tst_resm(TWARN, "unlink(%s) failed, errno:%d %s",
188 node_name, errno, strerror(errno));
189 }
190 }
191
192 /* Change the directory back to temporary directory */
193 chdir("..");
194
195 /*
196 * Invoke cleanup() to delete the test directories created
197 * in the setup() and exit main().
198 */
199 cleanup();
200
201 /*NOTREACHED*/
202} /* End main */
203
204/*
205 * setup(void) - performs all ONE TIME setup for this test.
206 * Exit the test program on receipt of unexpected signals.
207 * Create a temporary directory used to hold test directories created
208 * and change the directory to it.
209 * Verify that pid of process executing the test is root.
210 * Create a test directory on temporary directory and set the ownership
211 * of test directory to guest user and process, change mode permissions
212 * to set group id bit on it.
213 * Set the effective uid/gid of the process to that of guest user.
214 */
215void
216setup()
217{
218 char DIR_A[PATH_MAX];
219
220 /* Capture unexpected signals */
221 tst_sig(NOFORK, DEF_HANDLER, cleanup);
222
223 /* Check that the test process id is super/root */
224 if (geteuid() != 0) {
225 tst_brkm(TBROK, NULL, "Must be super/root for this test!");
226 tst_exit();
227 }
228
229 /* Pause if that option was specified */
230 TEST_PAUSE;
231
232 /* Make a temp dir and cd to it */
233 tst_tmpdir();
234
plars05a3b8b2001-09-05 15:37:06 +0000235 /* fix permissions on the tmpdir */
236 if (chmod(".", 0711) != 0) {
237 tst_brkm(TBROK, cleanup, "chmod() failed");
238 }
239
plars865695b2001-08-27 22:15:12 +0000240 /* Save the real user id of the current test process */
241 save_myuid = getuid();
242 /* Save the process id of the current test process */
243 mypid = getpid();
244
245 /* Get the node name to be created in the test */
246 sprintf(node_name, TNODE, mypid);
247
248 /* Get the uid/gid of ltpuser user */
249 if ((user1 = getpwnam(LTPUSER)) == NULL) {
250 tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER);
251 }
252 user1_uid = user1->pw_uid;
253 group1_gid = user1->pw_gid;
254
255 /* Get the effective group id of the test process */
256 group2_gid = getegid();
257
258 /*
259 * Create a test directory under temporary directory with the
260 * specified mode permissions, with uid/gid set to that of guest
261 * user and the test process.
262 */
263 if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
264 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
265 }
266 if (chown(DIR_TEMP, user1_uid, group2_gid) < 0) {
267 tst_brkm(TBROK, cleanup, "chown(2) of %s failed", DIR_TEMP);
268 }
269 if (chmod(DIR_TEMP, MODE_SGID) < 0) {
270 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP);
271 }
272
273 /*
274 * Verify that test directory created with expected permission modes
275 * and ownerships.
276 */
277 if (stat(DIR_TEMP, &buf) < 0) {
278 tst_brkm(TBROK, cleanup, "stat(2) of %s failed", DIR_TEMP);
279 }
280
281 /* Verify modes of test directory */
282 if (!(buf.st_mode & S_ISGID)) {
283 tst_brkm(TBROK, cleanup,
284 "%s: Incorrect modes, setgid bit not set", DIR_TEMP);
285 }
286
287 /* Verify group ID of test directory */
288 if (buf.st_gid != group2_gid) {
289 tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP);
290 }
291
292 /*
293 * Set the effective group id and user id of the test process
294 * to that of guest user (nobody)
295 */
296 if (setgid(group1_gid) < 0) {
297 tst_brkm(TBROK, cleanup,
298 "Unable to set process gid to that of ltp user");
299 }
300 if (setreuid(-1, user1_uid) < 0) {
301 tst_brkm(TBROK, cleanup,
302 "Unable to set process uid to that of ltp user");
303 }
304
305 /* Save the real group ID of the current process */
306 mygid = getgid();
307
308 /* Change directory to DIR_TEMP */
309 if (chdir(DIR_TEMP) < 0) {
310 tst_brkm(TBROK, cleanup,
311 "Unable to change to %s directory", DIR_TEMP);
312 }
313}
314
315/*
316 * cleanup() - Performs all ONE TIME cleanup for this test at
317 * completion or premature exit.
318 * Print test timing stats and errno log if test executed with options.
319 * Restore the real/effective user id of the process changed during
320 * setup().
321 * Remove temporary directory and sub-directories/files under it
322 * created during setup().
323 * Exit the test program with normal exit code.
324 */
325void
326cleanup()
327{
328 /*
329 * print timing stats if that option was specified.
330 * print errno log if that option was specified.
331 */
332 TEST_CLEANUP;
333
334 /*
335 * Restore the effective uid of the process changed in the
336 * setup().
337 */
338 if (setreuid(-1, save_myuid) < 0) {
339 tst_brkm(TBROK, NULL,
340 "resetting process real/effective uid failed");
341 }
342
343 /* Remove files and temporary directory created */
344 tst_rmdir();
345
346 /* exit with return code appropriate for results */
347 tst_exit();
348}