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 * rename12 23 * 24 * DESCRIPTION 25 * check rename() fails with EPERM or 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 * create a directory fdir and set the sticky bit 36 * create file fname under fdir 37 * fork a child 38 * set to nobody 39 * try to rename fname to mname 40 * check the return value, if succeeded (return=0) 41 * Log the errno and Issue a FAIL message. 42 * Otherwise, 43 * Verify the errno 44 * if equals to EPERMS or EACCES, 45 * Issue Pass message. 46 * Otherwise, 47 * Issue Fail message. 48 * Cleanup: 49 * Print errno log and/or timing stats if options given 50 * Delete the temporary directory created. 51 * USAGE 52 * rename12 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 53 * where, -c n : Run n copies concurrently. 54 * -e : Turn on errno logging. 55 * -i n : Execute test n times. 56 * -I x : Execute test for x seconds. 57 * -P x : Pause for x seconds between iterations. 58 * -t : Turn on syscall timing. 59 * 60 * HISTORY 61 * 07/2001 Ported by Wayne Boyer 62 * 63 * RESTRICTIONS 64 * Must run test as root. 65 * 66 */ 67 #include <errno.h> 68 #include <sys/stat.h> 69 #include <sys/types.h> 70 #include <sys/wait.h> 71 #include <fcntl.h> 72 #include <pwd.h> 73 #include <unistd.h> 74 75 #include "test.h" 76 #include "safe_macros.h" 77 78 void setup(); 79 void cleanup(); 80 81 #define PERMS 0777 82 83 char *TCID = "rename12"; 84 int TST_TOTAL = 1; 85 86 int fd; 87 char fdir[255]; 88 char fname[255], mname[255]; 89 uid_t nobody_uid; 90 struct stat buf1; 91 92 int main(int ac, char **av) 93 { 94 int lc; 95 pid_t pid; 96 int status; 97 98 /* 99 * parse standard options 100 */ 101 tst_parse_opts(ac, av, NULL, NULL); 102 103 /* 104 * perform global setup for test 105 */ 106 setup(); 107 108 /* 109 * check looping state if -i option given 110 */ 111 for (lc = 0; TEST_LOOPING(lc); lc++) { 112 113 tst_count = 0; 114 115 /* 116 * rename a file whose parent directory has 117 * the sticky bit set without root permission 118 * or effective uid 119 */ 120 121 if ((pid = FORK_OR_VFORK()) == -1) { 122 tst_brkm(TBROK, cleanup, "fork() failed"); 123 } 124 125 if (pid == 0) { /* child */ 126 /* set to nobody */ 127 if (seteuid(nobody_uid) == -1) { 128 tst_resm(TWARN, "setreuid failed"); 129 perror("setreuid"); 130 exit(1); 131 } 132 133 /* rename "old" to "new" */ 134 TEST(rename(fname, mname)); 135 136 if (TEST_RETURN != -1) { 137 tst_resm(TFAIL, "call succeeded unexpectedly"); 138 exit(1); 139 } 140 141 if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) { 142 tst_resm(TFAIL, 143 "Expected EPERM or EACCES, got %d", 144 TEST_ERRNO); 145 exit(1); 146 } else { 147 tst_resm(TPASS, 148 "rename returned EPERM or EACCES"); 149 } 150 151 /* set the id back to root */ 152 if (seteuid(0) == -1) { 153 tst_resm(TWARN, "seteuid(0) failed"); 154 } 155 } else { /* parent */ 156 wait(&status); 157 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { 158 exit(WEXITSTATUS(status)); 159 } else { 160 exit(0); 161 } 162 163 } 164 } 165 166 cleanup(); 167 tst_exit(); 168 169 } 170 171 /* 172 * setup() - performs all ONE TIME setup for this test. 173 */ 174 void setup(void) 175 { 176 struct passwd *pw; 177 178 tst_require_root(); 179 180 tst_sig(FORK, DEF_HANDLER, cleanup); 181 182 pw = SAFE_GETPWNAM(NULL, "nobody"); 183 nobody_uid = pw->pw_uid; 184 185 TEST_PAUSE; 186 187 /* Create a temporary directory and make it current. */ 188 tst_tmpdir(); 189 190 umask(0); 191 192 sprintf(fdir, "./tdir_%d", getpid()); 193 sprintf(fname, "%s/tfile_%d", fdir, getpid()); 194 sprintf(mname, "%s/rnfile_%d", fdir, getpid()); 195 196 /* create a directory */ 197 SAFE_MKDIR(cleanup, fdir, PERMS); 198 199 SAFE_STAT(cleanup, fdir, &buf1); 200 201 /* set the sticky bit */ 202 if (chmod(fdir, buf1.st_mode | S_ISVTX) != 0) { 203 tst_brkm(TBROK, cleanup, "failed to set the S_ISVTX bit"); 204 205 } 206 207 /* create a file under fdir */ 208 SAFE_TOUCH(cleanup, fname, 0700, NULL); 209 } 210 211 /* 212 * cleanup() - performs all ONE TIME cleanup for this test at 213 * completion or premature exit. 214 */ 215 void cleanup(void) 216 { 217 218 /* 219 * Remove the temporary directory. 220 */ 221 tst_rmdir(); 222 } 223