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: chown02 22 * 23 * Test Description: 24 * Verify that, when chown(2) invoked by super-user to change the owner and 25 * group of a file specified by path to any numeric owner(uid)/group(gid) 26 * values, 27 * - clears setuid and setgid bits set on an executable file. 28 * - preserves setgid bit set on a non-group-executable file. 29 * 30 * Expected Result: 31 * chown(2) should return 0 and the ownership set on the file should match 32 * the numeric values contained in owner and group respectively. 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 * chown02 [-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 <sys/types.h> 74 #include <sys/stat.h> 75 #include <sys/fcntl.h> 76 #include <errno.h> 77 #include <string.h> 78 #include <signal.h> 79 80 #include "test.h" 81 #include "compat_16.h" 82 83 #define FILE_MODE (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 84 #define NEW_PERMS1 (S_IFREG|S_IRWXU|S_IRWXG|S_ISUID|S_ISGID) 85 #define NEW_PERMS2 (S_IFREG|S_IRWXU|S_ISGID) 86 #define EXP_PERMS (S_IFREG|S_IRWXU|S_IRWXG) 87 #define TESTFILE1 "testfile1" 88 #define TESTFILE2 "testfile2" 89 90 TCID_DEFINE(chown02); 91 92 int setup1(); /* Test specific setup functions */ 93 int setup2(); 94 95 struct test_case_t { 96 char *pathname; 97 uid_t user_id; 98 gid_t group_id; 99 int test_flag; 100 int (*setupfunc) (); 101 } test_cases[] = { 102 /* setuid/setgid bits cleared */ 103 { 104 TESTFILE1, 700, 701, 1, setup1}, 105 /* setgid bit not cleared */ 106 { 107 TESTFILE2, 700, 701, 2, setup2},}; 108 109 int TST_TOTAL = ARRAY_SIZE(test_cases); 110 111 void setup(); /* setup function for the test */ 112 void cleanup(); /* cleanup function for the test */ 113 114 int main(int ac, char **av) 115 { 116 struct stat stat_buf; /* stat(2) struct contents */ 117 int lc; 118 int i; 119 uid_t user_id; /* user id of the user set for testfile */ 120 gid_t group_id; /* group id of the user set for testfile */ 121 int test_flag; /* test condition specific flag variable */ 122 char *file_name; /* ptr. for test file name */ 123 124 tst_parse_opts(ac, av, NULL, NULL); 125 126 setup(); 127 128 for (lc = 0; TEST_LOOPING(lc); lc++) { 129 130 tst_count = 0; 131 132 for (i = 0; i < TST_TOTAL; i++) { 133 134 file_name = test_cases[i].pathname; 135 user_id = test_cases[i].user_id; 136 group_id = test_cases[i].group_id; 137 test_flag = test_cases[i].test_flag; 138 139 /* 140 * Call chown(2) with different user id and 141 * group id (numeric values) to set it on testfile. 142 */ 143 TEST(CHOWN(cleanup, file_name, user_id, group_id)); 144 145 if (TEST_RETURN == -1) { 146 tst_resm(TFAIL | TTERRNO, 147 "chown(%s, ..) failed", file_name); 148 continue; 149 } 150 151 /* 152 * Get the testfile information using stat(2). 153 */ 154 if (stat(file_name, &stat_buf) < 0) { 155 tst_brkm(TFAIL, cleanup, "stat(2) of " 156 "%s failed, errno:%d", 157 file_name, TEST_ERRNO); 158 } 159 160 /* 161 * Check for expected Ownership ids 162 * set on testfile. 163 */ 164 if (stat_buf.st_uid != user_id || 165 stat_buf.st_gid != group_id) { 166 tst_brkm(TFAIL, cleanup, "%s: incorrect" 167 " ownership set, Expected %d " 168 "%d", file_name, 169 user_id, group_id); 170 } 171 172 /* 173 * Verify that S_ISUID/S_ISGID bits set on the 174 * testfile(s) in setup()s are cleared by 175 * chown(). 176 */ 177 if (test_flag == 1 && 178 (stat_buf.st_mode & (S_ISUID | S_ISGID)) != 0) { 179 tst_resm(TFAIL, 180 "%s: incorrect mode " 181 "permissions %#o, Expected " 182 "%#o", file_name, NEW_PERMS1, 183 EXP_PERMS); 184 } else if (test_flag == 2 185 && (stat_buf.st_mode & S_ISGID) == 0) { 186 tst_resm(TFAIL, 187 "%s: Incorrect mode " 188 "permissions %#o, Expected " 189 "%#o", file_name, 190 stat_buf.st_mode, NEW_PERMS2); 191 } else { 192 tst_resm(TPASS, 193 "chown(%s, ..) succeeded", 194 file_name); 195 } 196 } 197 } 198 199 cleanup(); 200 tst_exit(); 201 } 202 203 /* 204 * void 205 * setup() - performs all ONE TIME setup for this test. 206 * Create a temporary directory and change directory to it. 207 * Create a test file under temporary directory and close it 208 */ 209 void setup(void) 210 { 211 int i; 212 213 tst_sig(NOFORK, DEF_HANDLER, cleanup); 214 215 tst_require_root(); 216 217 TEST_PAUSE; 218 219 tst_tmpdir(); 220 221 /* call iividual setup functions */ 222 for (i = 0; i < TST_TOTAL; i++) 223 test_cases[i].setupfunc(); 224 } 225 226 /* 227 * int 228 * setup1() - Setup function for chown(2) to verify setuid/setgid bits 229 * set on an executable file will not be cleared. 230 * Creat a testfile and set setuid/setgid bits on the mode of file.$ 231 */ 232 int setup1(void) 233 { 234 int fd; /* File descriptor for testfile1 */ 235 236 /* Creat a testfile and close it */ 237 if ((fd = open(TESTFILE1, O_RDWR | O_CREAT, FILE_MODE)) == -1) 238 tst_brkm(TBROK | TERRNO, cleanup, 239 "open(%s, O_RDWR|O_CREAT, %o) failed", 240 TESTFILE1, FILE_MODE); 241 if (close(fd) == -1) 242 tst_brkm(TBROK | TERRNO, cleanup, "close(%s) failed", 243 TESTFILE1); 244 245 /* Set setuid/setgid bits on the test file created */ 246 if (chmod(TESTFILE1, NEW_PERMS1) == -1) 247 tst_brkm(TBROK | TERRNO, cleanup, "chmod(%s, ..) failed", 248 TESTFILE1); 249 return 0; 250 } 251 252 /* 253 * int 254 * setup2() - Setup function for chown(2) to verify setgid bit set 255 * set on non-group executable file will not be cleared. 256 * Creat a testfile and set setgid bit on the mode of file. 257 */ 258 int setup2(void) 259 { 260 int fd; /* File descriptor for testfile2 */ 261 262 /* Creat a testfile and close it */ 263 if ((fd = open(TESTFILE2, O_RDWR | O_CREAT, FILE_MODE)) == -1) { 264 tst_brkm(TBROK | TERRNO, cleanup, 265 "open(%s, O_RDWR|O_CREAT, %o) failed", 266 TESTFILE2, FILE_MODE); 267 } 268 /* Set setgid bit on the test file created */ 269 if (fchmod(fd, NEW_PERMS2) != 0) 270 tst_brkm(TBROK | TERRNO, cleanup, "fchmod failed"); 271 if (close(fd) == -1) 272 tst_brkm(TBROK | TERRNO, cleanup, "close(%s) failed", 273 TESTFILE2); 274 return 0; 275 } 276 277 /* 278 * void 279 * cleanup() - performs all ONE TIME cleanup for this test at 280 * completion or premature exit. 281 * Remove the test directory and testfile created in the setup. 282 */ 283 void cleanup(void) 284 { 285 286 tst_rmdir(); 287 288 } 289