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 * chdir03 23 * 24 * DESCRIPTION 25 * Testcase for testing that chdir(2) sets EACCES errno 26 * 27 * ALGORITHM 28 * 1. create a child process, sets its uid to ltpuser1 29 * 2. this child creates a directory with perm 700, and exits 30 * 3. create another child process, sets its uid to ltpuser2 31 * 4. this child attempts to chdir(2) to the directory created in 2. 32 * and expects to get an EACCES. 33 * 34 * USAGE: <for command-line> 35 * chdir03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 36 * where, -c n : Run n copies concurrently. 37 * -e : Turn on errno logging. 38 * -i n : Execute test n times. 39 * -I x : Execute test for x seconds. 40 * -P x : Pause for x seconds between iterations. 41 * -t : Turn on syscall timing. 42 * 43 * HISTORY 44 * 07/2001 Ported by Wayne Boyer 45 * 46 * RESTRICTIONS 47 * This test must be run as root. 48 */ 49 50 #include <stdio.h> 51 #include <sys/types.h> 52 #include <unistd.h> 53 #include <pwd.h> 54 #include <errno.h> 55 #include <sys/wait.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <sys/stat.h> 59 #include <sys/types.h> 60 61 #include "test.h" 62 #include "safe_macros.h" 63 64 char *TCID = "chdir03"; 65 int TST_TOTAL = 1; 66 67 void setup(void); 68 void cleanup(void); 69 70 char good_dir[100]; 71 72 static uid_t nobody_uid, bin_uid; 73 74 int main(int ac, char **av) 75 { 76 int lc; 77 78 pid_t pid, pid1; 79 int status; 80 81 tst_parse_opts(ac, av, NULL, NULL); 82 83 setup(); 84 85 for (lc = 0; TEST_LOOPING(lc); lc++) { 86 tst_count = 0; 87 88 if ((pid = FORK_OR_VFORK()) < 0) { 89 tst_brkm(TBROK, cleanup, "first fork failed"); 90 } 91 92 if (pid == 0) { 93 if (setreuid(nobody_uid, nobody_uid) != 0) { 94 perror("setreuid failed in child #1"); 95 exit(1); 96 } 97 if (mkdir(good_dir, 00700) != 0) { 98 perror("mkdir failed in child #1"); 99 exit(1); 100 } 101 exit(0); 102 } 103 wait(&status); 104 105 if ((pid1 = FORK_OR_VFORK()) < 0) 106 tst_brkm(TBROK, cleanup, "second fork failed"); 107 108 if (pid1 == 0) { /* second child */ 109 110 int rval; 111 112 /* 113 * set the child's ID to ltpuser2 using seteuid() 114 * so that the ID can be changed back after the 115 * TEST call is made. 116 */ 117 if (seteuid(bin_uid) != 0) { 118 perror("setreuid failed in child #2"); 119 exit(1); 120 } 121 122 TEST(chdir(good_dir)); 123 124 if (TEST_RETURN != -1) { 125 printf("call succeeded unexpectedly\n"); 126 rval = 1; 127 } else if (TEST_ERRNO != EACCES) { 128 printf("didn't get EACCES as expected; got "); 129 rval = 1; 130 } else { 131 printf("got EACCES as expected\n"); 132 rval = 0; 133 } 134 /* Only really required with vfork. */ 135 if (seteuid(0) != 0) { 136 perror("seteuid(0) failed"); 137 rval = 1; 138 } 139 140 exit(rval); 141 142 } else { 143 if (wait(&status) == -1) 144 tst_brkm(TBROK | TERRNO, cleanup, 145 "wait failed"); 146 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 147 tst_brkm(TBROK, cleanup, 148 "child exited abnormally"); 149 tst_resm(TPASS, "child reported success"); 150 } 151 if (rmdir(good_dir) == -1) { 152 tst_brkm(TBROK | TERRNO, cleanup, 153 "rmdir(%s) failed", good_dir); 154 } 155 } 156 157 cleanup(); 158 tst_exit(); 159 } 160 161 void setup(void) 162 { 163 struct passwd *pw; 164 char *cur_dir = NULL; 165 166 tst_require_root(); 167 168 pw = SAFE_GETPWNAM(NULL, "nobody"); 169 nobody_uid = pw->pw_uid; 170 #ifndef ANDROID 171 pw = SAFE_GETPWNAM(NULL, "bin"); 172 #else 173 // user "bin" does not exist in Android kernel 174 pw = SAFE_GETPWNAM(NULL, "everybody"); 175 #endif 176 bin_uid = pw->pw_uid; 177 178 tst_sig(FORK, DEF_HANDLER, cleanup); 179 180 TEST_PAUSE; 181 182 tst_tmpdir(); 183 184 if ((cur_dir = getcwd(cur_dir, 0)) == NULL) 185 tst_brkm(TBROK | TERRNO, cleanup, "getcwd failed"); 186 187 sprintf(good_dir, "%s/%d", cur_dir, getpid()); 188 } 189 190 void cleanup(void) 191 { 192 tst_rmdir(); 193 194 } 195