Home | History | Annotate | Download | only in mknod
      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: mknod05
     22  *
     23  * Test Description:
     24  *  Verify that mknod(2) succeeds when used by root 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 that of its parent directory.
     28  *
     29  * Expected Result:
     30  *  mknod() should return value 0 on success and node created should have
     31  *  set group-ID bit set and its gid should be equal to that of its parent
     32  *  directory.
     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  *  mknod05 [-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 "safe_macros.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_5"
     89 #define TNODE		"tnode_%d"
     90 
     91 struct stat buf;		/* struct. to hold stat(2) o/p contents */
     92 struct passwd *user1;		/* struct. to hold getpwnam(3) o/p contents */
     93 
     94 char *TCID = "mknod05";
     95 int TST_TOTAL = 1;
     96 char node_name[PATH_MAX];	/* buffer to hold node name created */
     97 
     98 gid_t group1_gid, group2_gid, mygid;	/* user and process group id's */
     99 uid_t save_myuid, user1_uid;	/* user and process user id's */
    100 pid_t mypid;			/* process id */
    101 
    102 void setup();			/* setup function for the test */
    103 void cleanup();			/* cleanup function for the test */
    104 
    105 int main(int ac, char **av)
    106 {
    107 	int lc;
    108 	int fflag;
    109 
    110 	tst_parse_opts(ac, av, NULL, NULL);
    111 
    112 	setup();
    113 
    114 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    115 
    116 		tst_count = 0;
    117 
    118 		/*
    119 		 *  Attempt to create a filesystem node with group id (sgid)
    120 		 *  bit set on a directory with group id (sgid) bit set
    121 		 *  such that, the node created by mknod(2) should have
    122 		 *  group id (sgid) bit set and node's gid should be equal
    123 		 *  to that of effective gid of the process.
    124 		 */
    125 		TEST(mknod(node_name, MODE_SGID, 0));
    126 
    127 		/* Check return code from mknod(2) */
    128 		if (TEST_RETURN == -1) {
    129 			tst_resm(TFAIL, "mknod(%s, %#o, 0)  failed, errno=%d : "
    130 				 "%s", node_name, MODE_SGID, TEST_ERRNO,
    131 				 strerror(TEST_ERRNO));
    132 			continue;
    133 		}
    134 		/* Set the functionality flag */
    135 		fflag = 1;
    136 
    137 		/* Check for node's creation */
    138 		if (stat(node_name, &buf) < 0) {
    139 			tst_resm(TFAIL, "stat() of %s failed, errno:%d",
    140 				 node_name, TEST_ERRNO);
    141 			/* unset functionality flag */
    142 			fflag = 0;
    143 		}
    144 
    145 		/* Verify mode permissions of node */
    146 		if (!(buf.st_mode & S_ISGID)) {
    147 			tst_resm(TFAIL, "%s: Incorrect modes, "
    148 				 "setgid bit not set", node_name);
    149 			/* unset flag as functionality fails */
    150 			fflag = 0;
    151 		}
    152 
    153 		/* Verify group ID */
    154 		if (buf.st_gid != group2_gid) {
    155 			tst_resm(TFAIL, "%s: Incorrect group",
    156 				 node_name);
    157 			/* unset flag as functionality fails */
    158 			fflag = 0;
    159 		}
    160 		if (fflag) {
    161 			tst_resm(TPASS, "Functionality of mknod(%s, "
    162 				 "%#o, 0) successful",
    163 				 node_name, MODE_SGID);
    164 		}
    165 
    166 		/* Remove the node for the next go `round */
    167 		if (unlink(node_name) == -1) {
    168 			tst_resm(TWARN, "unlink(%s) failed, errno:%d %s",
    169 				 node_name, errno, strerror(errno));
    170 		}
    171 	}
    172 
    173 	/* change the directory back to temporary directory */
    174 	SAFE_CHDIR(cleanup, "..");
    175 
    176 	/*
    177 	 * Invoke cleanup() to delete the test directories created
    178 	 * in the setup() and exit main().
    179 	 */
    180 	cleanup();
    181 
    182 	tst_exit();
    183 }
    184 
    185 /*
    186  * setup(void) - performs all ONE TIME setup for this test.
    187  * 	Exit the test program on receipt of unexpected signals.
    188  *	Create a temporary directory used to hold test directories created
    189  *	and change the directory to it.
    190  *	Verify that pid of process executing the test is root.
    191  *	Create a test directory on temporary directory and set the ownership
    192  *	of test directory to guest user and process, change mode permissions
    193  *	to set group id bit on it.
    194  */
    195 void setup(void)
    196 {
    197 	tst_require_root();
    198 
    199 	/* Capture unexpected signals */
    200 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    201 
    202 	TEST_PAUSE;
    203 
    204 	/* Make a temp dir and cd to it */
    205 	tst_tmpdir();
    206 
    207 	/* Save the real user id of the current test process */
    208 	save_myuid = getuid();
    209 
    210 	/* Save the process id of the current test process */
    211 	mypid = getpid();
    212 
    213 	/* Get the node name to be created in the test */
    214 	sprintf(node_name, TNODE, mypid);
    215 
    216 	/* Get the uid/gid of ltp user */
    217 	if ((user1 = getpwnam(LTPUSER)) == NULL) {
    218 		tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER);
    219 	}
    220 	user1_uid = user1->pw_uid;
    221 	group1_gid = user1->pw_gid;
    222 
    223 	/* Get the effective group id of the test process */
    224 	group2_gid = getegid();
    225 
    226 	/*
    227 	 * Create a test directory under temporary directory with the
    228 	 * specified mode permissions, with uid/gid set to that of guest
    229 	 * user and the test process.
    230 	 */
    231 	SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX);
    232 	SAFE_CHOWN(cleanup, DIR_TEMP, user1_uid, group2_gid);
    233 	SAFE_CHMOD(cleanup, DIR_TEMP, MODE_SGID);
    234 
    235 	/*
    236 	 * Verify that test directory created with expected permission modes
    237 	 * and ownerships.
    238 	 */
    239 	SAFE_STAT(cleanup, DIR_TEMP, &buf);
    240 	/* Verify modes of test directory */
    241 	if (!(buf.st_mode & S_ISGID)) {
    242 		tst_brkm(TBROK, cleanup,
    243 			 "%s: Incorrect modes, setgid bit not set", DIR_TEMP);
    244 	}
    245 
    246 	/* Verify group ID of test directory */
    247 	if (buf.st_gid != group2_gid) {
    248 		tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP);
    249 	}
    250 
    251 	/* Change directory to DIR_TEMP */
    252 	SAFE_CHDIR(cleanup, DIR_TEMP);
    253 }
    254 
    255 /*
    256  * cleanup() - Performs all ONE TIME cleanup for this test at
    257  *             completion or premature exit.
    258  *	Print test timing stats and errno log if test executed with options.
    259  *	Remove temporary directory and sub-directories/files under it
    260  *	created during setup().
    261  *	Exit the test program with normal exit code.
    262  */
    263 void cleanup(void)
    264 {
    265 
    266 	tst_rmdir();
    267 
    268 }
    269