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