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 * NAME 22 * rename09 23 * 24 * DESCRIPTION 25 * check rename() fails with EACCES 26 * 27 * ALGORITHM 28 * Setup: 29 * Setup signal handling. 30 * Create temporary directory. 31 * Pause for SIGUSR1 if option specified. 32 * 33 * Test: 34 * Loop if the proper options are given. 35 * fork the first child 36 * set to be nobody 37 * create old dir with mode 0700 38 * creat a file under it 39 * fork the second child 40 * set to bin 41 * create new dir with mode 0700 42 * create a "new" file under it 43 * try to rename file under old dir to file under new dir 44 * check the return value, if succeeded (return=0) 45 * Issue a FAIL message. 46 * Otherwise, 47 * Log the errno 48 * Verify the errno 49 * if equals to EACCESS, 50 * Issue Pass message. 51 * Otherwise, 52 * Issue Fail message. 53 * Cleanup: 54 * Print errno log and/or timing stats if options given 55 * Delete the temporary directory created. 56 * 57 * USAGE 58 * rename09 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 59 * where, -c n : Run n copies concurrently. 60 * -e : Turn on errno logging. 61 * -i n : Execute test n times. 62 * -I x : Execute test for x seconds. 63 * -P x : Pause for x seconds between iterations. 64 * -t : Turn on syscall timing. 65 * 66 * HISTORY 67 * 07/2001 Ported by Wayne Boyer 68 * 69 * RESTRICTIONS 70 * Must run test as root. 71 * 72 */ 73 #include <errno.h> 74 #include <sys/types.h> 75 #include <sys/stat.h> 76 #include <fcntl.h> 77 #include <pwd.h> 78 #include <sys/wait.h> 79 #include <unistd.h> 80 81 #include "test.h" 82 #include "safe_macros.h" 83 84 void setup(); 85 void cleanup(); 86 87 #define PERMS 0700 88 89 char *TCID = "rename09"; 90 int TST_TOTAL = 1; 91 92 char fdir[255], mdir[255]; 93 char fname[255], mname[255]; 94 uid_t nobody_uid, bin_uid; 95 96 int main(int ac, char **av) 97 { 98 int lc; 99 int rval; 100 pid_t pid, pid1; 101 int status; 102 103 /* 104 * parse standard options 105 */ 106 tst_parse_opts(ac, av, NULL, NULL); 107 108 /* 109 * perform global setup for test 110 */ 111 setup(); 112 113 /* 114 * check looping state if -i option given 115 */ 116 for (lc = 0; TEST_LOOPING(lc); lc++) { 117 118 tst_count = 0; 119 120 if ((pid = FORK_OR_VFORK()) == -1) { 121 tst_brkm(TBROK, cleanup, "fork() #1 failed"); 122 } 123 124 if (pid == 0) { /* first child */ 125 /* set to nobody */ 126 rval = setreuid(nobody_uid, nobody_uid); 127 if (rval < 0) { 128 tst_resm(TWARN, "setreuid failed to " 129 "to set the real uid to %d and " 130 "effective uid to %d", 131 nobody_uid, nobody_uid); 132 perror("setreuid"); 133 exit(1); 134 } 135 136 /* create the a directory with 0700 permits */ 137 if (mkdir(fdir, PERMS) == -1) { 138 tst_resm(TWARN, "mkdir(%s, %#o) Failed", 139 fdir, PERMS); 140 exit(1); 141 } 142 143 /* create "old" file under it */ 144 SAFE_TOUCH(cleanup, fname, 0700, NULL); 145 146 exit(0); 147 } 148 149 /* wait for child to exit */ 150 wait(&status); 151 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 152 tst_brkm(TBROK, cleanup, "First child failed to set " 153 "up conditions for the test"); 154 } 155 156 if ((pid1 = FORK_OR_VFORK()) == -1) { 157 tst_brkm(TBROK, cleanup, "fork() #2 failed"); 158 } 159 160 if (pid1 == 0) { /* second child */ 161 /* set to bin */ 162 if ((rval = seteuid(bin_uid)) == -1) { 163 tst_resm(TWARN, "seteuid() failed"); 164 perror("setreuid"); 165 exit(1); 166 } 167 168 /* create "new" directory */ 169 if (mkdir(mdir, PERMS) == -1) { 170 tst_resm(TWARN, "mkdir(%s, %#o) failed", 171 mdir, PERMS); 172 exit(1); 173 } 174 175 SAFE_TOUCH(cleanup, mname, 0700, NULL); 176 177 /* rename "old" to "new" */ 178 TEST(rename(fname, mname)); 179 if (TEST_RETURN != -1) { 180 tst_resm(TFAIL, "call succeeded unexpectedly"); 181 continue; 182 } 183 184 if (TEST_ERRNO != EACCES) { 185 tst_resm(TFAIL, "Expected EACCES got %d", 186 TEST_ERRNO); 187 } else { 188 tst_resm(TPASS, "rename() returned EACCES"); 189 } 190 191 /* set the process id back to root */ 192 if (seteuid(0) == -1) { 193 tst_resm(TWARN, "seteuid(0) failed"); 194 exit(1); 195 } 196 197 /* clean up things in case we are looping */ 198 SAFE_UNLINK(cleanup, fname); 199 SAFE_UNLINK(cleanup, mname); 200 SAFE_RMDIR(cleanup, fdir); 201 SAFE_RMDIR(cleanup, mdir); 202 } else { 203 /* parent - let the second child carry on */ 204 waitpid(pid1, &status, 0); 205 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 206 exit(WEXITSTATUS(status)); 207 } else { 208 exit(0); 209 } 210 } 211 } 212 213 /* 214 * cleanup and exit 215 */ 216 cleanup(); 217 tst_exit(); 218 219 } 220 221 /* 222 * setup() - performs all ONE TIME setup for this test. 223 */ 224 void setup(void) 225 { 226 struct passwd *pw; 227 228 tst_require_root(); 229 230 pw = SAFE_GETPWNAM(NULL, "nobody"); 231 nobody_uid = pw->pw_uid; 232 pw = SAFE_GETPWNAM(NULL, "bin"); 233 bin_uid = pw->pw_uid; 234 235 tst_sig(FORK, DEF_HANDLER, cleanup); 236 237 TEST_PAUSE; 238 239 /* Create a temporary directory and make it current. */ 240 tst_tmpdir(); 241 242 umask(0); 243 244 sprintf(fdir, "tdir_%d", getpid()); 245 sprintf(mdir, "rndir_%d", getpid()); 246 sprintf(fname, "%s/tfile_%d", fdir, getpid()); 247 sprintf(mname, "%s/rnfile_%d", mdir, getpid()); 248 } 249 250 /* 251 * cleanup() - performs all ONE TIME cleanup for this test at 252 * completion or premature exit. 253 */ 254 void cleanup(void) 255 { 256 257 /* 258 * Remove the temporary directory. 259 */ 260 tst_rmdir(); 261 262 /* 263 * Exit with return code appropriate for results. 264 */ 265 266 } 267