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  * Test Description:
22  *  Verify that access() succeeds to check the existence or read/write/execute
23  *  permissions on a file if the mode argument passed was F_OK/R_OK/W_OK/X_OK.
24  *
25  *  Also verify that, access() succeeds to test the accessibility of the file
26  *  referred to by symbolic link if the pathname points to a symbolic link.
27  *
28  *  As well as verify that, these test files can be
29  *  stat/read/written/executed indeed as root and nobody respectively.
30  *
31  *	07/2001 Ported by Wayne Boyera
32  *	06/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
33  */
34 
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <pwd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <paths.h>
42 #include "tst_test.h"
43 
44 #define FNAME_F	"file_f"
45 #define FNAME_R	"file_r"
46 #define FNAME_W	"file_w"
47 #define FNAME_X	"file_x"
48 #define SNAME_F	"symlink_f"
49 #define SNAME_R	"symlink_r"
50 #define SNAME_W	"symlink_w"
51 #define SNAME_X	"symlink_x"
52 
53 static uid_t uid;
54 
55 static struct tcase {
56 	const char *pathname;
57 	int mode;
58 	char *name;
59 	const char *targetname;
60 } tcases[] = {
61 	{FNAME_F, F_OK, "F_OK", FNAME_F},
62 	{FNAME_R, R_OK, "R_OK", FNAME_R},
63 	{FNAME_W, W_OK, "W_OK", FNAME_W},
64 	{FNAME_X, X_OK, "X_OK", FNAME_X},
65 	{SNAME_F, F_OK, "F_OK", FNAME_F},
66 	{SNAME_R, R_OK, "R_OK", FNAME_R},
67 	{SNAME_W, W_OK, "W_OK", FNAME_W},
68 	{SNAME_X, X_OK, "X_OK", FNAME_X}
69 };
70 
access_test(struct tcase * tc,const char * user)71 static void access_test(struct tcase *tc, const char *user)
72 {
73 	struct stat stat_buf;
74 	char command[64];
75 
76 	TEST(access(tc->pathname, tc->mode));
77 
78 	if (TEST_RETURN == -1) {
79 		tst_res(TFAIL | TTERRNO, "access(%s, %s) as %s failed",
80 			tc->pathname, tc->name, user);
81 		return;
82 	}
83 
84 	switch (tc->mode) {
85 	case F_OK:
86 		/*
87 		 * The specified file(or pointed to by symbolic link)
88 		 * exists, attempt to get its status, if successful,
89 		 * access() behaviour is correct.
90 		 */
91 		TEST(stat(tc->targetname, &stat_buf));
92 
93 		if (TEST_RETURN == -1) {
94 			tst_res(TFAIL | TTERRNO, "stat(%s) as %s failed",
95 				tc->targetname, user);
96 			return;
97 		}
98 
99 		break;
100 	case R_OK:
101 		/*
102 		 * The specified file(or pointed to by symbolic link)
103 		 * has read access, attempt to open the file with O_RDONLY,
104 		 * if we get a valid fd, access() behaviour is correct.
105 		 */
106 		TEST(open(tc->targetname, O_RDONLY));
107 
108 		if (TEST_RETURN == -1) {
109 			tst_res(TFAIL | TTERRNO,
110 				"open %s with O_RDONLY as %s failed",
111 				tc->targetname, user);
112 			return;
113 		}
114 
115 		SAFE_CLOSE(TEST_RETURN);
116 
117 		break;
118 	case W_OK:
119 		/*
120 		 * The specified file(or pointed to by symbolic link)
121 		 * has write access, attempt to open the file with O_WRONLY,
122 		 * if we get a valid fd, access() behaviour is correct.
123 		 */
124 		TEST(open(tc->targetname, O_WRONLY));
125 
126 		if (TEST_RETURN == -1) {
127 			tst_res(TFAIL | TTERRNO,
128 				"open %s with O_WRONLY as %s failed",
129 				tc->targetname, user);
130 			return;
131 		}
132 
133 		SAFE_CLOSE(TEST_RETURN);
134 
135 		break;
136 	case X_OK:
137 		/*
138 		 * The specified file(or pointed to by symbolic link)
139 		 * has execute access, attempt to execute the executable
140 		 * file, if successful, access() behaviour is correct.
141 		 */
142 		sprintf(command, "./%s", tc->targetname);
143 
144 		TEST(system(command));
145 
146 		if (TEST_RETURN != 0) {
147 			tst_res(TFAIL | TTERRNO, "execute %s as %s failed",
148 				tc->targetname, user);
149 			return;
150 		}
151 
152 		break;
153 	default:
154 		break;
155 	}
156 
157 	tst_res(TPASS, "access(%s, %s) as %s behaviour is correct.",
158 		tc->pathname, tc->name, user);
159 }
160 
verify_access(unsigned int n)161 static void verify_access(unsigned int n)
162 {
163 	struct tcase *tc = &tcases[n];
164 	pid_t pid;
165 
166 	/* test as root */
167 	access_test(tc, "root");
168 
169 	/* test as nobody */
170 	pid = SAFE_FORK();
171 	if (pid) {
172 		SAFE_WAITPID(pid, NULL, 0);
173 	} else {
174 		SAFE_SETUID(uid);
175 		access_test(tc, "nobody");
176 	}
177 }
178 
setup(void)179 static void setup(void)
180 {
181 	struct passwd *pw;
182 
183 	pw = SAFE_GETPWNAM("nobody");
184 
185 	uid = pw->pw_uid;
186 
187 	SAFE_TOUCH(FNAME_F, 0000, NULL);
188 	SAFE_TOUCH(FNAME_R, 0444, NULL);
189 	SAFE_TOUCH(FNAME_W, 0222, NULL);
190 	SAFE_TOUCH(FNAME_X, 0555, NULL);
191 	SAFE_FILE_PRINTF(FNAME_X, "#!%s\n", _PATH_BSHELL);
192 
193 	SAFE_SYMLINK(FNAME_F, SNAME_F);
194 	SAFE_SYMLINK(FNAME_R, SNAME_R);
195 	SAFE_SYMLINK(FNAME_W, SNAME_W);
196 	SAFE_SYMLINK(FNAME_X, SNAME_X);
197 }
198 
199 static struct tst_test test = {
200 	.tcnt = ARRAY_SIZE(tcases),
201 	.needs_tmpdir = 1,
202 	.needs_root = 1,
203 	.forks_child = 1,
204 	.setup = setup,
205 	.test = verify_access,
206 };
207