1 /*
2  *
3  * Copyright (C) Bull S.A. 2001
4  * Copyright (c) International Business Machines  Corp., 2001
5  *
6  *   This program is free software;  you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14  *   the GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program;  if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * NAME
23  *	fchdir03
24  *
25  * DESCRIPTION
26  *	Testcase for testing that fchdir(2) sets EACCES errno
27  *
28  * ALGORITHM
29  *	1.	create a child process, sets its uid to ltpuser1
30  *	2.	this child creates a directory with perm 400,
31  *	3.	this child opens the directory and gets a file descriptor
32  *	4.	this child attempts to fchdir(2) to the directory created in 2.
33  *		and expects to get an EACCES.
34  *	5.	finally this child checks the return code,
35  *		resets the process ID to root and calls cleanup.
36  *
37  * USAGE:  <for command-line>
38  *  fchdir03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
39  *     where,  -c n : Run n copies concurrently.
40  *             -e   : Turn on errno logging.
41  *             -i n : Execute test n times.
42  *             -I x : Execute test for x seconds.
43  *             -P x : Pause for x seconds between iterations.
44  *             -t   : Turn on syscall timing.
45  *
46  * HISTORY
47  *	04/2002 Ported by Jacky Malcles
48  *
49  * RESTRICTIONS
50  *	This test must be run as root.
51  */
52 
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <sys/wait.h>
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <pwd.h>
59 #include <stdio.h>
60 #include <string.h>
61 #include <unistd.h>
62 
63 #include "test.h"
64 #include "safe_macros.h"
65 
66 char *TCID = "fchdir03";
67 int TST_TOTAL = 1;
68 
69 void setup(void);
70 void cleanup(void);
71 
72 char good_dir[100];
73 int fd;
74 
75 static uid_t nobody_uid;
76 
main(int ac,char ** av)77 int main(int ac, char **av)
78 {
79 	int lc;
80 
81 	pid_t pid;
82 	int status;
83 
84 	tst_parse_opts(ac, av, NULL, NULL);
85 
86 	setup();
87 
88 	for (lc = 0; TEST_LOOPING(lc); lc++) {
89 		tst_count = 0;
90 
91 		if ((pid = FORK_OR_VFORK()) == -1)
92 			tst_brkm(TBROK, cleanup, "fork failed");
93 
94 		if (pid == 0) {
95 			/*
96 			 * set the child's ID to ltpuser1 using seteuid()
97 			 * so that the ID can be changed back after the
98 			 * TEST call is made.
99 			 */
100 			if (seteuid(nobody_uid) != 0) {
101 				perror("setreuid failed in child #1");
102 				exit(1);
103 			}
104 			if (mkdir(good_dir, 00400) != 0) {
105 				perror("mkdir failed in child #1");
106 				exit(1);
107 			}
108 			if ((fd = open(good_dir, O_RDONLY)) == -1) {
109 				perror("opening directory failed");
110 			}
111 
112 			TEST(fchdir(fd));
113 
114 			if (TEST_RETURN != -1) {
115 				printf("Call succeeded unexpectedly\n");
116 				exit(1);
117 			} else if (TEST_ERRNO != EACCES) {
118 				printf("Expected %d - got %d\n",
119 				       EACCES, TEST_ERRNO);
120 				exit(1);
121 			} else
122 				printf("Got EACCES as expected\n");
123 
124 			/* reset the UID to root */
125 			if (setuid(0) == -1)
126 				perror("setuid(0) failed");
127 
128 		} else {
129 			if (wait(&status) == -1)
130 				tst_brkm(TBROK | TERRNO, cleanup,
131 					 "wait failed");
132 			else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
133 				tst_brkm(TBROK, cleanup,
134 					 "child exited abnormally (wait status = "
135 					 "%d", status);
136 			else {
137 				/* let the child carry on */
138 				exit(0);
139 			}
140 		}
141 
142 		if (rmdir(good_dir) == -1)
143 			tst_brkm(TBROK, cleanup, "rmdir failed");
144 
145 	}
146 	cleanup();
147 
148 	tst_exit();
149 }
150 
setup(void)151 void setup(void)
152 {
153 	struct passwd *pw;
154 
155 	char *cur_dir = NULL;
156 
157 	tst_require_root();
158 
159 	pw = SAFE_GETPWNAM(NULL, "nobody");
160 	nobody_uid = pw->pw_uid;
161 
162 	tst_sig(FORK, DEF_HANDLER, cleanup);
163 
164 	TEST_PAUSE;
165 
166 	tst_tmpdir();
167 
168 	if ((cur_dir = getcwd(cur_dir, 0)) == NULL)
169 		tst_brkm(TBROK | TERRNO, cleanup, "getcwd failed");
170 
171 	sprintf(good_dir, "%s.%d", cur_dir, getpid());
172 }
173 
cleanup(void)174 void cleanup(void)
175 {
176 	tst_rmdir();
177 }
178