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 (TST_RET == -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 (TST_RET == -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 (TST_RET == -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(TST_RET);
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 (TST_RET == -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(TST_RET);
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 (TST_RET != 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