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