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 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 */
setup(void)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 */
cleanup(void)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