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