1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 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 * NAME 22 * creat08.c - Verifies that the group ID and setgid bit are 23 * set correctly when a new file is created. 24 * (ported from SPIE, section2/iosuite/creat5.c, 25 * by Airong Zhang <zhanga (at) us.ibm.com>) 26 * CALLS 27 * creat 28 * 29 * ALGORITHM 30 * Create two directories, one with the group ID of this process 31 * and the setgid bit not set, and the other with a group ID 32 * other than that of this process and with the setgid bit set. 33 * In each directory, create a file with and without the setgid 34 * bit set in the creation modes. Verify that the modes and group 35 * ID are correct on each of the 4 files. 36 * As root, create a file with the setgid bit on in the 37 * directory with the setgid bit. 38 * This tests the SVID3 create group semantics. 39 * 40 * USAGE 41 * creat08 42 * 43 * RESTRICTIONS 44 * 45 */ 46 47 #include <stdio.h> /* needed by testhead.h */ 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <fcntl.h> 51 #include <errno.h> 52 #include <grp.h> 53 #include <pwd.h> 54 #include "test.h" 55 #include "safe_macros.h" 56 57 char *TCID = "creat08"; 58 int TST_TOTAL = 1; 59 int local_flag; 60 61 #define PASSED 1 62 #define FAILED 0 63 64 #define MODE_RWX (S_IRWXU|S_IRWXG|S_IRWXO) 65 #define MODE_SGID (S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 66 #define DIR_A_TEMP "testdir.A.%d" 67 #define DIR_B_TEMP "testdir.B.%d" 68 #define SETGID "setgid" 69 #define NOSETGID "nosetgid" 70 #define ROOT_SETGID "root_setgid" 71 #define MSGSIZE 150 72 73 static void tst_cleanup(void); 74 static void cleanup(void); 75 static void setup(void); 76 77 static char DIR_A[MSGSIZE], DIR_B[MSGSIZE]; 78 static char setgid_A[MSGSIZE], nosetgid_A[MSGSIZE]; 79 static char setgid_B[MSGSIZE], nosetgid_B[MSGSIZE], root_setgid_B[MSGSIZE]; 80 81 int main(int ac, char **av) 82 { 83 struct stat buf; 84 struct group *group; 85 struct passwd *user1; 86 gid_t group1_gid, group2_gid, mygid; 87 uid_t save_myuid, user1_uid; 88 pid_t mypid; 89 90 int fd; 91 int lc; 92 93 tst_parse_opts(ac, av, NULL, NULL); 94 95 setup(); 96 97 for (lc = 0; TEST_LOOPING(lc); lc++) { 98 99 local_flag = PASSED; 100 101 save_myuid = getuid(); 102 mypid = getpid(); 103 sprintf(DIR_A, DIR_A_TEMP, mypid); 104 sprintf(DIR_B, DIR_B_TEMP, mypid); 105 sprintf(setgid_A, "%s/%s", DIR_A, SETGID); 106 sprintf(nosetgid_A, "%s/%s", DIR_A, NOSETGID); 107 sprintf(setgid_B, "%s/%s", DIR_B, SETGID); 108 sprintf(nosetgid_B, "%s/%s", DIR_B, NOSETGID); 109 sprintf(root_setgid_B, "%s/%s", DIR_B, ROOT_SETGID); 110 111 /* Get the uid of user1 */ 112 if ((user1 = getpwnam("nobody")) == NULL) { 113 tst_brkm(TBROK | TERRNO, NULL, 114 "getpwnam(\"nobody\") failed"); 115 } 116 117 user1_uid = user1->pw_uid; 118 119 /* 120 * Get the group IDs of group1 and group2. 121 */ 122 if ((group = getgrnam("nobody")) == NULL) { 123 if ((group = getgrnam("nogroup")) == NULL) { 124 tst_brkm(TBROK | TERRNO, cleanup, 125 "getgrnam(\"nobody\") and " 126 "getgrnam(\"nogroup\") failed"); 127 } 128 } 129 group1_gid = group->gr_gid; 130 if ((group = getgrnam("bin")) == NULL) { 131 tst_brkm(TBROK | TERRNO, cleanup, 132 "getgrnam(\"bin\") failed"); 133 } 134 group2_gid = group->gr_gid; 135 136 /*--------------------------------------------------------------*/ 137 /* Block0: Set up the parent directories */ 138 /*--------------------------------------------------------------*/ 139 /* 140 * Create a directory with group id the same as this process 141 * and with no setgid bit. 142 */ 143 if (mkdir(DIR_A, MODE_RWX) == -1) { 144 tst_resm(TFAIL, "Creation of %s failed", DIR_A); 145 local_flag = FAILED; 146 } 147 148 if (chown(DIR_A, user1_uid, group2_gid) == -1) { 149 tst_resm(TFAIL, "Chown of %s failed", DIR_A); 150 local_flag = FAILED; 151 } 152 153 if (stat(DIR_A, &buf) == -1) { 154 tst_resm(TFAIL, "Stat of %s failed", DIR_A); 155 local_flag = FAILED; 156 } 157 158 /* Verify modes */ 159 if (buf.st_mode & S_ISGID) { 160 tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set", 161 DIR_A); 162 local_flag = FAILED; 163 } 164 165 /* Verify group ID */ 166 if (buf.st_gid != group2_gid) { 167 tst_resm(TFAIL, "%s: Incorrect group", DIR_A); 168 tst_resm(TINFO, "got %u and %u", buf.st_gid, 169 group2_gid); 170 local_flag = FAILED; 171 } 172 173 /* 174 * Create a directory with group id different from that of 175 * this process and with the setgid bit set. 176 */ 177 if (mkdir(DIR_B, MODE_RWX) == -1) { 178 tst_resm(TFAIL, "Creation of %s failed", DIR_B); 179 local_flag = FAILED; 180 } 181 182 if (chown(DIR_B, user1_uid, group2_gid) == -1) { 183 tst_resm(TFAIL, "Chown of %s failed", DIR_B); 184 local_flag = FAILED; 185 } 186 187 if (chmod(DIR_B, MODE_SGID) == -1) { 188 tst_resm(TFAIL, "Chmod of %s failed", DIR_B); 189 local_flag = FAILED; 190 } 191 192 if (stat(DIR_B, &buf) == -1) { 193 tst_resm(TFAIL, "Stat of %s failed", DIR_B); 194 local_flag = FAILED; 195 } 196 197 /* Verify modes */ 198 if (!(buf.st_mode & S_ISGID)) { 199 tst_resm(TFAIL, 200 "%s: Incorrect modes, setgid bit not set", 201 DIR_B); 202 local_flag = FAILED; 203 } 204 205 /* Verify group ID */ 206 if (buf.st_gid != group2_gid) { 207 tst_resm(TFAIL, "%s: Incorrect group", DIR_B); 208 tst_resm(TINFO, "got %u and %u", buf.st_gid, 209 group2_gid); 210 local_flag = FAILED; 211 } 212 213 if (local_flag == PASSED) { 214 tst_resm(TPASS, "Test passed in block0."); 215 } else { 216 tst_resm(TFAIL, "Test failed in block0."); 217 } 218 219 local_flag = PASSED; 220 221 /*--------------------------------------------------------------*/ 222 /* Block1: Create two files in testdir.A, one with the setgid */ 223 /* bit set in the creation modes and the other without. */ 224 /* Both should inherit the group ID of the process and */ 225 /* maintain the setgid bit as specified in the creation */ 226 /* modes. */ 227 /*--------------------------------------------------------------*/ 228 /* 229 * Now become user1, group1 230 */ 231 if (setgid(group1_gid) == -1) { 232 tst_resm(TINFO, 233 "Unable to set process group ID to group1"); 234 } 235 236 if (setreuid(-1, user1_uid) == -1) { 237 tst_resm(TINFO, "Unable to set process uid to user1"); 238 } 239 mygid = getgid(); 240 241 /* 242 * Create the file with setgid not set 243 */ 244 fd = open(nosetgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_RWX); 245 if (fd == -1) { 246 tst_resm(TFAIL, "Creation of %s failed", nosetgid_A); 247 local_flag = FAILED; 248 } 249 250 if (stat(nosetgid_A, &buf) == -1) { 251 tst_resm(TFAIL, "Stat of %s failed", nosetgid_A); 252 local_flag = FAILED; 253 } 254 255 /* Verify modes */ 256 if (buf.st_mode & S_ISGID) { 257 tst_resm(TFAIL, "%s: Incorrect modes, setgid bit set", 258 nosetgid_A); 259 local_flag = FAILED; 260 } 261 262 /* Verify group ID */ 263 if (buf.st_gid != mygid) { 264 tst_resm(TFAIL, "%s: Incorrect group", nosetgid_A); 265 local_flag = FAILED; 266 } 267 close(fd); 268 269 /* 270 * Create the file with setgid set 271 */ 272 fd = open(setgid_A, O_CREAT | O_EXCL | O_RDWR, MODE_SGID); 273 if (fd == -1) { 274 tst_resm(TFAIL, "Creation of %s failed", setgid_A); 275 local_flag = FAILED; 276 } 277 278 if (stat(setgid_A, &buf) == -1) { 279 tst_resm(TFAIL, "Stat of %s failed", setgid_A); 280 local_flag = FAILED; 281 } 282 283 /* Verify modes */ 284 if (!(buf.st_mode & S_ISGID)) { 285 tst_resm(TFAIL, 286 "%s: Incorrect modes, setgid bit not set", 287 setgid_A); 288 local_flag = FAILED; 289 } 290 291 /* Verify group ID */ 292 if (buf.st_gid != mygid) { 293 tst_resm(TFAIL, "%s: Incorrect group", setgid_A); 294 tst_resm(TINFO, "got %u and %u", buf.st_gid, mygid); 295 local_flag = FAILED; 296 } 297 close(fd); 298 299 if (local_flag == PASSED) { 300 tst_resm(TPASS, "Test passed in block1."); 301 } else { 302 tst_resm(TFAIL, "Test failed in block1."); 303 } 304 305 local_flag = PASSED; 306 307 /*--------------------------------------------------------------*/ 308 /* Block2: Create two files in testdir.B, one with the setgid */ 309 /* bit set in the creation modes and the other without. */ 310 /* Both should inherit the group ID of the parent */ 311 /* directory, group2. */ 312 /*--------------------------------------------------------------*/ 313 /* 314 * Create the file with setgid not set 315 */ 316 fd = creat(nosetgid_B, MODE_RWX); 317 if (fd == -1) { 318 tst_resm(TFAIL, "Creation of %s failed", nosetgid_B); 319 local_flag = FAILED; 320 } 321 322 if (stat(nosetgid_B, &buf) == -1) { 323 tst_resm(TFAIL, "Stat of %s failed", nosetgid_B); 324 local_flag = FAILED; 325 } 326 327 /* Verify modes */ 328 if (buf.st_mode & S_ISGID) { 329 tst_resm(TFAIL, 330 "%s: Incorrect modes, setgid bit should not be set", 331 nosetgid_B); 332 local_flag = FAILED; 333 } 334 335 /* Verify group ID */ 336 if (buf.st_gid != group2_gid) { 337 tst_resm(TFAIL, "%s: Incorrect group", nosetgid_B); 338 local_flag = FAILED; 339 } 340 close(fd); 341 342 /* 343 * Create the file with setgid set 344 */ 345 fd = creat(setgid_B, MODE_SGID); 346 if (fd == -1) { 347 tst_resm(TFAIL, "Creation of %s failed", setgid_B); 348 local_flag = FAILED; 349 } 350 351 if (stat(setgid_B, &buf) == -1) { 352 tst_resm(TFAIL, "Stat of %s failed", setgid_B); 353 local_flag = FAILED; 354 } 355 356 /* Verify group ID */ 357 if (buf.st_gid != group2_gid) { 358 tst_resm(TFAIL, "%s: Incorrect group", setgid_B); 359 tst_resm(TFAIL, "got %u and %u", buf.st_gid, 360 group2_gid); 361 local_flag = FAILED; 362 } 363 364 /* 365 * Skip S_ISGID check 366 * 0fa3ecd87848 ("Fix up non-directory creation in SGID directories") 367 * clears S_ISGID for files created by non-group members 368 */ 369 370 close(fd); 371 372 if (local_flag == PASSED) { 373 tst_resm(TPASS, "Test passed in block2."); 374 } else { 375 tst_resm(TFAIL, "Test failed in block2."); 376 } 377 378 local_flag = PASSED; 379 /*--------------------------------------------------------------*/ 380 /* Block3: Create a file in testdir.B, with the setgid bit set */ 381 /* in the creation modes and do so as root. The file */ 382 /* should inherit the group ID of the parent directory, */ 383 /* group2 and should have the setgid bit set. */ 384 /*--------------------------------------------------------------*/ 385 /* Become root again */ 386 if (setreuid(-1, save_myuid) == -1) { 387 tst_resm(TFAIL | TERRNO, 388 "Changing back to root failed"); 389 local_flag = FAILED; 390 } 391 392 /* Create the file with setgid set */ 393 fd = creat(root_setgid_B, MODE_SGID); 394 if (fd == -1) { 395 tst_resm(TFAIL, "Creation of %s failed", root_setgid_B); 396 local_flag = FAILED; 397 } 398 399 if (stat(root_setgid_B, &buf) == -1) { 400 tst_resm(TFAIL, "Stat of %s failed", root_setgid_B); 401 local_flag = FAILED; 402 } 403 404 /* Verify modes */ 405 if (!(buf.st_mode & S_ISGID)) { 406 tst_resm(TFAIL, 407 "%s: Incorrect modes, setgid bit not set", 408 root_setgid_B); 409 local_flag = FAILED; 410 } 411 412 /* Verify group ID */ 413 if (buf.st_gid != group2_gid) { 414 tst_resm(TFAIL, "%s: Incorrect group", root_setgid_B); 415 tst_resm(TINFO, "got %u and %u", buf.st_gid, 416 group2_gid); 417 local_flag = FAILED; 418 } 419 close(fd); 420 421 if (local_flag == PASSED) { 422 tst_resm(TPASS, "Test passed in block3"); 423 } else { 424 tst_resm(TFAIL, "Test failed in block3"); 425 } 426 tst_cleanup(); 427 } 428 cleanup(); 429 tst_exit(); 430 } 431 432 static void setup(void) 433 { 434 tst_require_root(); 435 tst_tmpdir(); 436 } 437 438 static void tst_cleanup(void) 439 { 440 if (unlink(setgid_A) == -1) { 441 tst_resm(TBROK, "%s failed", setgid_A); 442 } 443 if (unlink(nosetgid_A) == -1) { 444 tst_resm(TBROK, "unlink %s failed", nosetgid_A); 445 } 446 SAFE_RMDIR(NULL, DIR_A); 447 SAFE_UNLINK(NULL, setgid_B); 448 SAFE_UNLINK(NULL, root_setgid_B); 449 SAFE_UNLINK(NULL, nosetgid_B); 450 SAFE_RMDIR(NULL, DIR_B); 451 } 452 453 static void cleanup(void) 454 { 455 tst_rmdir(); 456 } 457