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
main(int ac,char ** av)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 if (unlink(fname) == -1) {
199 tst_brkm(TBROK, cleanup, "unlink() #1 failed");
200 }
201 if (unlink(mname) == -1) {
202 tst_brkm(TBROK, cleanup, "unlink() #2 failed");
203 }
204 if (rmdir(fdir) == -1) {
205 tst_brkm(TBROK, cleanup, "rmdir() #1 failed");
206 }
207 if (rmdir(mdir) == -1) {
208 tst_brkm(TBROK, cleanup, "rmdir() #2 failed");
209 }
210 } else {
211 /* parent - let the second child carry on */
212 waitpid(pid1, &status, 0);
213 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
214 exit(WEXITSTATUS(status));
215 } else {
216 exit(0);
217 }
218 }
219 }
220
221 /*
222 * cleanup and exit
223 */
224 cleanup();
225 tst_exit();
226
227 }
228
229 /*
230 * setup() - performs all ONE TIME setup for this test.
231 */
setup(void)232 void setup(void)
233 {
234 struct passwd *pw;
235
236 tst_require_root();
237
238 pw = SAFE_GETPWNAM(NULL, "nobody");
239 nobody_uid = pw->pw_uid;
240 #ifndef ANDROID
241 pw = SAFE_GETPWNAM(NULL, "bin");
242 #else
243 // user "bin" does not exist in Android kernel
244 pw = SAFE_GETPWNAM(NULL, "everybody");
245 #endif
246 bin_uid = pw->pw_uid;
247
248 tst_sig(FORK, DEF_HANDLER, cleanup);
249
250 TEST_PAUSE;
251
252 /* Create a temporary directory and make it current. */
253 tst_tmpdir();
254
255 umask(0);
256
257 sprintf(fdir, "tdir_%d", getpid());
258 sprintf(mdir, "rndir_%d", getpid());
259 sprintf(fname, "%s/tfile_%d", fdir, getpid());
260 sprintf(mname, "%s/rnfile_%d", mdir, getpid());
261 }
262
263 /*
264 * cleanup() - performs all ONE TIME cleanup for this test at
265 * completion or premature exit.
266 */
cleanup(void)267 void cleanup(void)
268 {
269
270 /*
271 * Remove the temporary directory.
272 */
273 tst_rmdir();
274
275 /*
276 * Exit with return code appropriate for results.
277 */
278
279 }
280