mknod08.c revision fdce7d5e2a219d201a2b0e3bab6b61b01ec1d716
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 * Test Name: mknod08
22 *
23 * Test Description:
24 *  Verify that mknod(2) succeeds when used to create a filesystem
25 *  node on a directory without set group-ID bit set. The node created
26 *  should not have set group-ID bit set and its gid should be equal to that
27 *  of its parent directory.
28 *
29 * Expected Result:
30 *  mknod() should return value 0 on success and node created should not
31 *  have set group-ID bit set.
32 *
33 * Algorithm:
34 *  Setup:
35 *   Setup signal handling.
36 *   Create temporary directory.
37 *   Pause for SIGUSR1 if option specified.
38 *
39 *  Test:
40 *   Loop if the proper options are given.
41 *   Execute system call
42 *   Check return code, if system call failed (return=-1)
43 *	Log the errno and Issue a FAIL message.
44 *   Otherwise,
45 *	Verify the Functionality of system call
46 *      if successful,
47 *		Issue Functionality-Pass message.
48 *      Otherwise,
49 *		Issue Functionality-Fail message.
50 *  Cleanup:
51 *   Print errno log and/or timing stats if options given
52 *   Delete the temporary directory created.
53 *
54 * Usage:  <for command-line>
55 *  mknod08 [-c n] [-e] [-f] [-i n] [-I x] [-P x] [-t]
56 *     where,  -c n : Run n copies concurrently.
57 *             -e   : Turn on errno logging.
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 DIR_TEMP	"testdir_1"
88#define TNODE		"tnode_%d"
89
90struct stat buf;		/* struct. to hold stat(2) o/p contents */
91struct passwd *user1;		/* struct. to hold getpwnam(3) o/p contents */
92
93char *TCID = "mknod08";
94int TST_TOTAL = 1;
95char node_name[PATH_MAX];	/* buffer to hold node name created */
96
97gid_t group1_gid, group2_gid, mygid;	/* user and process group id's */
98uid_t save_myuid, user1_uid;	/* user and process user id's */
99pid_t mypid;			/* process id */
100
101void setup();			/* setup function for the test */
102void cleanup();			/* cleanup function for the test */
103
104int main(int ac, char **av)
105{
106	int lc;
107	int fflag;		/* functionality flag variable */
108	char *msg;
109
110	msg = parse_opts(ac, av, NULL, NULL);
111	if (msg != NULL) {
112		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
113
114	}
115
116	setup();
117
118	for (lc = 0; TEST_LOOPING(lc); lc++) {
119
120		tst_count = 0;
121
122		/*
123		 * Call mknod() to creat a node on a directory without
124		 * set group-ID (sgid) bit set.
125		 */
126		TEST(mknod(node_name, MODE_RWX, 0));
127
128		/* Check return code from mknod(2) */
129		if (TEST_RETURN == -1) {
130			tst_resm(TFAIL,
131				 "mknod(%s, %#o, 0)  failed, errno=%d : %s",
132				 node_name, MODE_RWX, TEST_ERRNO,
133				 strerror(TEST_ERRNO));
134			continue;
135		}
136		/*
137		 * Perform functional verification if test executed
138		 * without (-f) option.
139		 */
140		if (STD_FUNCTIONAL_TEST) {
141			/* Set the functionality flag */
142			fflag = 1;
143
144			/* Check for node's creation */
145			if (stat(node_name, &buf) < 0) {
146				tst_resm(TFAIL,
147					 "stat() of %s failed, errno:%d",
148					 node_name, TEST_ERRNO);
149				/* unset flag as functionality fails */
150				fflag = 0;
151			}
152
153			/* Verify mode permissions of node */
154			if (buf.st_mode & S_ISGID) {
155				tst_resm(TFAIL, "%s: Incorrect modes, setgid "
156					 "bit set", node_name);
157				/* unset flag as functionality fails */
158				fflag = 0;
159			}
160
161			/* Verify group ID */
162			if (buf.st_gid != mygid) {
163				tst_resm(TFAIL, "%s: Incorrect group",
164					 node_name);
165				/* unset flag as functionality fails */
166				fflag = 0;
167			}
168			if (fflag) {
169				tst_resm(TPASS, "Functionality of mknod(%s, "
170					 "%#o, 0) successful",
171					 node_name, MODE_RWX);
172			}
173		} else {
174			tst_resm(TPASS, "call succeeded");
175		}
176
177		/* Remove the node for the next go `round */
178		if (unlink(node_name) == -1) {
179			tst_resm(TWARN,
180				 "unlink(%s) failed, errno:%d %s",
181				 node_name, errno, strerror(errno));
182		}
183	}
184
185	/* Change the directory back to temporary directory */
186	chdir("..");
187
188	/*
189	 * Invoke cleanup() to delete the test directories created
190	 * in the setup() and exit main().
191	 */
192	cleanup();
193
194	tst_exit();
195}
196
197/*
198 * setup(void) - performs all ONE TIME setup for this test.
199 *	Exit the test program on receipt of unexpected signals.
200 *	Create a temporary directory used to hold test directories created
201 *	and change the directory to it.
202 *	Verify that pid of process executing the test is root.
203 *	Create a test directory on temporary directory and set the ownership
204 *	of test directory to nobody user.
205 *	Set the effective uid/gid of the process to that of nobody user.
206 */
207void setup()
208{
209
210	/* Capture unexpected signals */
211	tst_sig(NOFORK, DEF_HANDLER, cleanup);
212
213	/* Check that the test process id is super/root  */
214	if (geteuid() != 0) {
215		tst_brkm(TBROK, NULL, "Must be super/root for this test!");
216		tst_exit();
217	}
218
219	TEST_PAUSE;
220
221	/* Make a temp dir and cd to it */
222	tst_tmpdir();
223
224	/* fix permissions on the tmpdir */
225	if (chmod(".", 0711) != 0) {
226		tst_brkm(TBROK, cleanup, "chmod() failed");
227	}
228
229	/* Save the real user id of the test process */
230	save_myuid = getuid();
231
232	/* Save the process id of the test process */
233	mypid = getpid();
234
235	/* Get the node name to be created in the test */
236	sprintf(node_name, TNODE, mypid);
237
238	/* Get the uid/gid of guest user - nobody */
239	if ((user1 = getpwnam(LTPUSER)) == NULL) {
240		tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER);
241	}
242	user1_uid = user1->pw_uid;
243	group1_gid = user1->pw_gid;
244
245	/* Get effective group id of the test process */
246	group2_gid = getegid();
247
248	/*
249	 * Create a test directory under temporary directory with the
250	 * specified mode permissions, with uid/gid set to that of guest
251	 * user and the test process.
252	 */
253	if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
254		tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
255	}
256	if (chown(DIR_TEMP, user1_uid, group2_gid) < 0) {
257		tst_brkm(TBROK, cleanup, "chown(2) of %s failed", DIR_TEMP);
258	}
259
260	/*
261	 * Verify that test directory created with expected permission modes
262	 * and ownerships.
263	 */
264	if (stat(DIR_TEMP, &buf) < 0) {
265		tst_brkm(TBROK, cleanup, "stat(2) of %s failed", DIR_TEMP);
266	}
267
268	/* Verify modes of test directory */
269	if (buf.st_mode & S_ISGID) {
270		tst_brkm(TBROK, cleanup,
271			 "%s: Incorrect modes, setgid bit set", DIR_TEMP);
272	}
273
274	/* Verify group ID */
275	if (buf.st_gid != group2_gid) {
276		tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP);
277	}
278
279	/*
280	 * Set the effective group id and user id of the test process
281	 * to that of guest user.
282	 */
283	if (setgid(group1_gid) < 0) {
284		tst_brkm(TBROK, cleanup,
285			 "Unable to set process gid to that of ltp user");
286	}
287	if (setreuid(-1, user1_uid) < 0) {
288		tst_brkm(TBROK, cleanup,
289			 "Unable to set process uid to that of ltp user");
290	}
291
292	/* Save the real group ID of the current process */
293	mygid = getgid();
294
295	/* Change directory to DIR_TEMP */
296	if (chdir(DIR_TEMP) < 0) {
297		tst_brkm(TBROK, cleanup,
298			 "Unable to change to %s directory", DIR_TEMP);
299	}
300}
301
302/*
303 * cleanup() - Performs all ONE TIME cleanup for this test at
304 *             completion or premature exit.
305 *	Print test timing stats and errno log if test executed with options.
306 *	Restore the real/effective user id of the process changed during
307 *	setup().
308 *	Remove temporary directory and sub-directories/files under it
309 *	created during setup().
310 *	Exit the test program with normal exit code.
311 */
312void cleanup()
313{
314	/*
315	 * print timing stats if that option was specified.
316	 * print errno log if that option was specified.
317	 */
318	TEST_CLEANUP;
319
320	/*
321	 * Restore the effective uid of the process changed in the
322	 * setup().
323	 */
324	if (setreuid(-1, save_myuid) < 0) {
325		tst_brkm(TBROK, NULL,
326			 "resetting process real/effective uid failed");
327	}
328
329	tst_rmdir();
330
331}
332