mknod08.c revision 53740500924f6439623a8ac256b5be2d6c59ed1f
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 tst_exit(); 120 } 121 122 /* Perform global setup for test */ 123 setup(); 124 125 /* Check looping state if -i option given */ 126 for (lc = 0; TEST_LOOPING(lc); lc++) { 127 /* Reset Tst_count in case we are looping. */ 128 Tst_count = 0; 129 130 /* 131 * Call mknod() to creat a node on a directory without 132 * set group-ID (sgid) bit set. 133 */ 134 TEST(mknod(node_name, MODE_RWX, 0)); 135 136 /* Check return code from mknod(2) */ 137 if (TEST_RETURN == -1) { 138 tst_resm(TFAIL, 139 "mknod(%s, %#o, 0) failed, errno=%d : %s", 140 node_name, MODE_RWX, 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, 155 "stat() of %s failed, errno:%d", 156 node_name, TEST_ERRNO); 157 /* unset flag as functionality fails */ 158 fflag = 0; 159 } 160 161 /* Verify mode permissions of node */ 162 if (buf.st_mode & S_ISGID) { 163 tst_resm(TFAIL, "%s: Incorrect modes, setgid " 164 "bit set", node_name); 165 /* unset flag as functionality fails */ 166 fflag = 0; 167 } 168 169 /* Verify group ID */ 170 if (buf.st_gid != mygid) { 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_RWX); 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, 188 "unlink(%s) failed, errno:%d %s", 189 node_name, errno, strerror(errno)); 190 } 191 } 192 193 /* Change the directory back to temporary directory */ 194 chdir(".."); 195 196 /* 197 * Invoke cleanup() to delete the test directories created 198 * in the setup() and exit main(). 199 */ 200 cleanup(); 201 202 return 0; 203} /* End main */ 204 205/* 206 * setup(void) - performs all ONE TIME setup for this test. 207 * Exit the test program on receipt of unexpected signals. 208 * Create a temporary directory used to hold test directories created 209 * and change the directory to it. 210 * Verify that pid of process executing the test is root. 211 * Create a test directory on temporary directory and set the ownership 212 * of test directory to nobody user. 213 * Set the effective uid/gid of the process to that of nobody user. 214 */ 215void setup() 216{ 217 218 /* Capture unexpected signals */ 219 tst_sig(NOFORK, DEF_HANDLER, cleanup); 220 221 /* Check that the test process id is super/root */ 222 if (geteuid() != 0) { 223 tst_brkm(TBROK, NULL, "Must be super/root for this test!"); 224 tst_exit(); 225 } 226 227 /* Pause if that option was specified */ 228 TEST_PAUSE; 229 230 /* Make a temp dir and cd to it */ 231 tst_tmpdir(); 232 233 /* fix permissions on the tmpdir */ 234 if (chmod(".", 0711) != 0) { 235 tst_brkm(TBROK, cleanup, "chmod() failed"); 236 } 237 238 /* Save the real user id of the test process */ 239 save_myuid = getuid(); 240 241 /* Save the process id of the test process */ 242 mypid = getpid(); 243 244 /* Get the node name to be created in the test */ 245 sprintf(node_name, TNODE, mypid); 246 247 /* Get the uid/gid of guest user - nobody */ 248 if ((user1 = getpwnam(LTPUSER)) == NULL) { 249 tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER); 250 } 251 user1_uid = user1->pw_uid; 252 group1_gid = user1->pw_gid; 253 254 /* Get effective group id of the test process */ 255 group2_gid = getegid(); 256 257 /* 258 * Create a test directory under temporary directory with the 259 * specified mode permissions, with uid/gid set to that of guest 260 * user and the test process. 261 */ 262 if (mkdir(DIR_TEMP, MODE_RWX) < 0) { 263 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP); 264 } 265 if (chown(DIR_TEMP, user1_uid, group2_gid) < 0) { 266 tst_brkm(TBROK, cleanup, "chown(2) of %s failed", DIR_TEMP); 267 } 268 269 /* 270 * Verify that test directory created with expected permission modes 271 * and ownerships. 272 */ 273 if (stat(DIR_TEMP, &buf) < 0) { 274 tst_brkm(TBROK, cleanup, "stat(2) of %s failed", DIR_TEMP); 275 } 276 277 /* Verify modes of test directory */ 278 if (buf.st_mode & S_ISGID) { 279 tst_brkm(TBROK, cleanup, 280 "%s: Incorrect modes, setgid bit set", DIR_TEMP); 281 } 282 283 /* Verify group ID */ 284 if (buf.st_gid != group2_gid) { 285 tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); 286 } 287 288 /* 289 * Set the effective group id and user id of the test process 290 * to that of guest user. 291 */ 292 if (setgid(group1_gid) < 0) { 293 tst_brkm(TBROK, cleanup, 294 "Unable to set process gid to that of ltp user"); 295 } 296 if (setreuid(-1, user1_uid) < 0) { 297 tst_brkm(TBROK, cleanup, 298 "Unable to set process uid to that of ltp user"); 299 } 300 301 /* Save the real group ID of the current process */ 302 mygid = getgid(); 303 304 /* Change directory to DIR_TEMP */ 305 if (chdir(DIR_TEMP) < 0) { 306 tst_brkm(TBROK, cleanup, 307 "Unable to change to %s directory", DIR_TEMP); 308 } 309} 310 311/* 312 * cleanup() - Performs all ONE TIME cleanup for this test at 313 * completion or premature exit. 314 * Print test timing stats and errno log if test executed with options. 315 * Restore the real/effective user id of the process changed during 316 * setup(). 317 * Remove temporary directory and sub-directories/files under it 318 * created during setup(). 319 * Exit the test program with normal exit code. 320 */ 321void cleanup() 322{ 323 /* 324 * print timing stats if that option was specified. 325 * print errno log if that option was specified. 326 */ 327 TEST_CLEANUP; 328 329 /* 330 * Restore the effective uid of the process changed in the 331 * setup(). 332 */ 333 if (setreuid(-1, save_myuid) < 0) { 334 tst_brkm(TBROK, NULL, 335 "resetting process real/effective uid failed"); 336 } 337 338 /* Remove files and temporary directory created */ 339 tst_rmdir(); 340 341 /* exit with return code appropriate for results */ 342 tst_exit(); 343} 344