mknod08.c revision 2c28215423293e443469a07ae7011135d058b671
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"; /* Test program identifier. */ 94int TST_TOTAL = 1; /* Total number of test cases. */ 95char node_name[PATH_MAX]; /* buffer to hold node name created */ 96extern int Tst_count; /* Test Case counter for tst_* routines */ 97 98gid_t group1_gid, group2_gid, mygid; /* user and process group id's */ 99uid_t save_myuid, user1_uid; /* user and process user id's */ 100pid_t mypid; /* process id */ 101 102void setup(); /* setup function for the test */ 103void cleanup(); /* cleanup function for the test */ 104 105int main(int ac, char **av) 106{ 107 int lc; /* loop counter */ 108 int fflag; /* functionality flag variable */ 109 char *msg; /* message returned from parse_opts */ 110 111 /* Parse standard options given to run the test. */ 112<<<<<<< HEAD 113 msg = parse_opts(ac, av, NULL, NULL); 114======= 115 msg = parse_opts(ac, av, (option_t *) NULL, NULL); 116>>>>>>> master 117 if (msg != NULL) { 118 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 119 120 } 121 122 setup(); 123 124 for (lc = 0; TEST_LOOPING(lc); lc++) { 125 126 Tst_count = 0; 127 128 /* 129 * Call mknod() to creat a node on a directory without 130 * set group-ID (sgid) bit set. 131 */ 132 TEST(mknod(node_name, MODE_RWX, 0)); 133 134 /* Check return code from mknod(2) */ 135 if (TEST_RETURN == -1) { 136 tst_resm(TFAIL, 137 "mknod(%s, %#o, 0) failed, errno=%d : %s", 138 node_name, MODE_RWX, TEST_ERRNO, 139 strerror(TEST_ERRNO)); 140 continue; 141 } 142 /* 143 * Perform functional verification if test executed 144 * without (-f) option. 145 */ 146 if (STD_FUNCTIONAL_TEST) { 147 /* Set the functionality flag */ 148 fflag = 1; 149 150 /* Check for node's creation */ 151 if (stat(node_name, &buf) < 0) { 152 tst_resm(TFAIL, 153 "stat() of %s failed, errno:%d", 154 node_name, TEST_ERRNO); 155 /* unset flag as functionality fails */ 156 fflag = 0; 157 } 158 159 /* Verify mode permissions of node */ 160 if (buf.st_mode & S_ISGID) { 161 tst_resm(TFAIL, "%s: Incorrect modes, setgid " 162 "bit set", node_name); 163 /* unset flag as functionality fails */ 164 fflag = 0; 165 } 166 167 /* Verify group ID */ 168 if (buf.st_gid != mygid) { 169 tst_resm(TFAIL, "%s: Incorrect group", 170 node_name); 171 /* unset flag as functionality fails */ 172 fflag = 0; 173 } 174 if (fflag) { 175 tst_resm(TPASS, "Functionality of mknod(%s, " 176 "%#o, 0) successful", 177 node_name, MODE_RWX); 178 } 179 } else { 180 tst_resm(TPASS, "call succeeded"); 181 } 182 183 /* Remove the node for the next go `round */ 184 if (unlink(node_name) == -1) { 185 tst_resm(TWARN, 186 "unlink(%s) failed, errno:%d %s", 187 node_name, errno, strerror(errno)); 188 } 189 } 190 191 /* Change the directory back to temporary directory */ 192 chdir(".."); 193 194 /* 195 * Invoke cleanup() to delete the test directories created 196 * in the setup() and exit main(). 197 */ 198 cleanup(); 199 200 return 0; 201} 202 203/* 204 * setup(void) - performs all ONE TIME setup for this test. 205 * Exit the test program on receipt of unexpected signals. 206 * Create a temporary directory used to hold test directories created 207 * and change the directory to it. 208 * Verify that pid of process executing the test is root. 209 * Create a test directory on temporary directory and set the ownership 210 * of test directory to nobody user. 211 * Set the effective uid/gid of the process to that of nobody user. 212 */ 213void setup() 214{ 215 216 /* Capture unexpected signals */ 217 tst_sig(NOFORK, DEF_HANDLER, cleanup); 218 219 /* Check that the test process id is super/root */ 220 if (geteuid() != 0) { 221 tst_brkm(TBROK, NULL, "Must be super/root for this test!"); 222 tst_exit(); 223 } 224 225 TEST_PAUSE; 226 227 /* Make a temp dir and cd to it */ 228 tst_tmpdir(); 229 230 /* fix permissions on the tmpdir */ 231 if (chmod(".", 0711) != 0) { 232 tst_brkm(TBROK, cleanup, "chmod() failed"); 233 } 234 235 /* Save the real user id of the test process */ 236 save_myuid = getuid(); 237 238 /* Save the process id of the test process */ 239 mypid = getpid(); 240 241 /* Get the node name to be created in the test */ 242 sprintf(node_name, TNODE, mypid); 243 244 /* Get the uid/gid of guest user - nobody */ 245 if ((user1 = getpwnam(LTPUSER)) == NULL) { 246 tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER); 247 } 248 user1_uid = user1->pw_uid; 249 group1_gid = user1->pw_gid; 250 251 /* Get effective group id of the test process */ 252 group2_gid = getegid(); 253 254 /* 255 * Create a test directory under temporary directory with the 256 * specified mode permissions, with uid/gid set to that of guest 257 * user and the test process. 258 */ 259 if (mkdir(DIR_TEMP, MODE_RWX) < 0) { 260 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP); 261 } 262 if (chown(DIR_TEMP, user1_uid, group2_gid) < 0) { 263 tst_brkm(TBROK, cleanup, "chown(2) of %s failed", DIR_TEMP); 264 } 265 266 /* 267 * Verify that test directory created with expected permission modes 268 * and ownerships. 269 */ 270 if (stat(DIR_TEMP, &buf) < 0) { 271 tst_brkm(TBROK, cleanup, "stat(2) of %s failed", DIR_TEMP); 272 } 273 274 /* Verify modes of test directory */ 275 if (buf.st_mode & S_ISGID) { 276 tst_brkm(TBROK, cleanup, 277 "%s: Incorrect modes, setgid bit set", DIR_TEMP); 278 } 279 280 /* Verify group ID */ 281 if (buf.st_gid != group2_gid) { 282 tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); 283 } 284 285 /* 286 * Set the effective group id and user id of the test process 287 * to that of guest user. 288 */ 289 if (setgid(group1_gid) < 0) { 290 tst_brkm(TBROK, cleanup, 291 "Unable to set process gid to that of ltp user"); 292 } 293 if (setreuid(-1, user1_uid) < 0) { 294 tst_brkm(TBROK, cleanup, 295 "Unable to set process uid to that of ltp user"); 296 } 297 298 /* Save the real group ID of the current process */ 299 mygid = getgid(); 300 301 /* Change directory to DIR_TEMP */ 302 if (chdir(DIR_TEMP) < 0) { 303 tst_brkm(TBROK, cleanup, 304 "Unable to change to %s directory", DIR_TEMP); 305 } 306} 307 308/* 309 * cleanup() - Performs all ONE TIME cleanup for this test at 310 * completion or premature exit. 311 * Print test timing stats and errno log if test executed with options. 312 * Restore the real/effective user id of the process changed during 313 * setup(). 314 * Remove temporary directory and sub-directories/files under it 315 * created during setup(). 316 * Exit the test program with normal exit code. 317 */ 318void cleanup() 319{ 320 /* 321 * print timing stats if that option was specified. 322 * print errno log if that option was specified. 323 */ 324 TEST_CLEANUP; 325 326 /* 327 * Restore the effective uid of the process changed in the 328 * setup(). 329 */ 330 if (setreuid(-1, save_myuid) < 0) { 331 tst_brkm(TBROK, NULL, 332 "resetting process real/effective uid failed"); 333 } 334 335 tst_rmdir(); 336 337}