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
main(int ac,char ** av)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 */
setup(void)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 */
cleanup(void)215 void cleanup(void)
216 {
217
218 /*
219 * Remove the temporary directory.
220 */
221 tst_rmdir();
222 }
223