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: chown03 22 * 23 * Test Description: 24 * Verify that, chown(2) succeeds to change the group of a file specified 25 * by path when called by non-root user with the following constraints, 26 * - euid of the process is equal to the owner of the file. 27 * - the intended gid is either egid, or one of the supplementary gids 28 * of the process. 29 * Also, verify that chown() clears the setuid/setgid bits set on the file. 30 * 31 * Expected Result: 32 * chown(2) should return 0 and the ownership set on the file should match 33 * the numeric values contained in owner and group respectively. 34 * 35 * Algorithm: 36 * Setup: 37 * Setup signal handling. 38 * Create temporary directory. 39 * Pause for SIGUSR1 if option specified. 40 * 41 * Test: 42 * Loop if the proper options are given. 43 * Execute system call 44 * Check return code, if system call failed (return=-1) 45 * Log the errno and Issue a FAIL message. 46 * Otherwise, 47 * Verify the Functionality of system call 48 * if successful, 49 * Issue Functionality-Pass message. 50 * Otherwise, 51 * Issue Functionality-Fail message. 52 * Cleanup: 53 * Print errno log and/or timing stats if options given 54 * Delete the temporary directory created. 55 * 56 * Usage: <for command-line> 57 * chown03 [-c n] [-f] [-i n] [-I x] [-P x] [-t] 58 * where, -c n : Run n copies concurrently. 59 * -f : Turn off functionality Testing. 60 * -i n : Execute test n times. 61 * -I x : Execute test for x seconds. 62 * -P x : Pause for x seconds between iterations. 63 * -t : Turn on syscall timing. 64 * 65 * HISTORY 66 * 07/2001 Ported by Wayne Boyer 67 * 68 * RESTRICTIONS: 69 * 70 */ 71 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <sys/types.h> 75 #include <sys/stat.h> 76 #include <sys/fcntl.h> 77 #include <errno.h> 78 #include <string.h> 79 #include <signal.h> 80 #include <grp.h> 81 #include <pwd.h> 82 83 #include "test.h" 84 #include "compat_16.h" 85 86 #define FILE_MODE (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 87 #define NEW_PERMS (S_IFREG|S_IRWXU|S_IRWXG|S_ISUID|S_ISGID) 88 #define TESTFILE "testfile" 89 90 TCID_DEFINE(chown03); 91 int TST_TOTAL = 1; /* Total number of test conditions */ 92 char nobody_uid[] = "nobody"; 93 struct passwd *ltpuser; 94 95 void setup(); /* setup function for the test */ 96 void cleanup(); /* cleanup function for the test */ 97 98 int main(int ac, char **av) 99 { 100 struct stat stat_buf; /* stat(2) struct contents */ 101 int lc; 102 uid_t user_id; /* Owner id of the test file. */ 103 gid_t group_id; /* Group id of the test file. */ 104 105 tst_parse_opts(ac, av, NULL, NULL); 106 107 setup(); 108 109 for (lc = 0; TEST_LOOPING(lc); lc++) { 110 111 tst_count = 0; 112 113 UID16_CHECK((user_id = geteuid()), "chown", cleanup) 114 GID16_CHECK((group_id = getegid()), "chown", cleanup) 115 116 TEST(CHOWN(cleanup, TESTFILE, -1, group_id)); 117 118 if (TEST_RETURN == -1) { 119 tst_resm(TFAIL | TTERRNO, "chown(%s, ..) failed", 120 TESTFILE); 121 continue; 122 } 123 124 if (stat(TESTFILE, &stat_buf) == -1) 125 tst_brkm(TFAIL | TERRNO, cleanup, 126 "stat failed"); 127 128 if (stat_buf.st_uid != user_id || 129 stat_buf.st_gid != group_id) 130 tst_resm(TFAIL, "%s: Incorrect ownership" 131 "set to %d %d, Expected %d %d", 132 TESTFILE, stat_buf.st_uid, 133 stat_buf.st_gid, user_id, group_id); 134 135 if (stat_buf.st_mode != 136 (NEW_PERMS & ~(S_ISUID | S_ISGID))) 137 tst_resm(TFAIL, "%s: incorrect mode permissions" 138 " %#o, Expected %#o", TESTFILE, 139 stat_buf.st_mode, 140 NEW_PERMS & ~(S_ISUID | S_ISGID)); 141 else 142 tst_resm(TPASS, "chown(%s, ..) was successful", 143 TESTFILE); 144 } 145 146 cleanup(); 147 tst_exit(); 148 } 149 150 /* 151 * void 152 * setup() - performs all ONE TIME setup for this test. 153 * Create a temporary directory and change directory to it. 154 * Create a test file under temporary directory and close it 155 * Change the group ownership on testfile. 156 */ 157 void setup(void) 158 { 159 int fd; /* file handler for testfile */ 160 161 TEST_PAUSE; 162 163 tst_require_root(); 164 165 tst_sig(FORK, DEF_HANDLER, cleanup); 166 167 tst_tmpdir(); 168 169 ltpuser = getpwnam(nobody_uid); 170 if (ltpuser == NULL) 171 tst_brkm(TBROK | TERRNO, NULL, "getpwnam(\"nobody\") failed"); 172 if (setegid(ltpuser->pw_gid) == -1) 173 tst_brkm(TBROK | TERRNO, NULL, "setegid(%d) failed", 174 ltpuser->pw_gid); 175 if (seteuid(ltpuser->pw_uid) == -1) 176 tst_brkm(TBROK | TERRNO, NULL, "seteuid(%d) failed", 177 ltpuser->pw_uid); 178 179 /* Create a test file under temporary directory */ 180 if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) 181 tst_brkm(TBROK | TERRNO, cleanup, 182 "open(%s, O_RDWR|O_CREAT, %o) failed", TESTFILE, 183 FILE_MODE); 184 185 if (seteuid(0) == -1) 186 tst_brkm(TBROK | TERRNO, cleanup, "seteuid(0) failed"); 187 188 if (fchown(fd, -1, 0) < 0) 189 tst_brkm(TBROK | TERRNO, cleanup, "fchown failed"); 190 191 if (fchmod(fd, NEW_PERMS) < 0) 192 tst_brkm(TBROK | TERRNO, cleanup, "fchmod failed"); 193 194 if (seteuid(ltpuser->pw_uid) == -1) 195 tst_brkm(TBROK | TERRNO, cleanup, "seteuid to nobody failed"); 196 197 if (close(fd) == -1) 198 tst_brkm(TBROK | TERRNO, cleanup, "closing %s failed", 199 TESTFILE); 200 } 201 202 void cleanup(void) 203 { 204 if (setegid(0) == -1) 205 tst_resm(TWARN | TERRNO, "setegid(0) failed"); 206 if (seteuid(0) == -1) 207 tst_resm(TWARN | TERRNO, "seteuid(0) failed"); 208 209 tst_rmdir(); 210 211 } 212