1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  *   AUTHOR		: William Roske
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * Further, this software is distributed without any warranty that it is
14  * free of the rightful claim of any third person regarding infringement
15  * or the like.  Any license provided herein, whether implied or
16  * otherwise, applies only to this software file.  Patent licenses, if
17  * any, provided herein do not apply to combinations of this program with
18  * other software, or any other product whatsoever.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  */
25 /*
26  * Basic test for access(2) using F_OK, R_OK, W_OK and X_OK
27  */
28 #include <errno.h>
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include <pwd.h>
32 #include "tst_test.h"
33 
34 #define FNAME_RWX "accessfile_rwx"
35 #define FNAME_R   "accesfile_r"
36 #define FNAME_W   "accesfile_w"
37 #define FNAME_X   "accesfile_x"
38 
39 static uid_t uid;
40 
41 static struct tcase {
42 	const char *fname;
43 	int mode;
44 	char *name;
45 	int exp_errno;
46 	/* 1: nobody expected  2: root expected 3: both */
47 	int exp_user;
48 } tcases[] = {
49 	{FNAME_RWX, F_OK, "F_OK", 0, 3},
50 	{FNAME_RWX, X_OK, "X_OK", 0, 3},
51 	{FNAME_RWX, W_OK, "W_OK", 0, 3},
52 	{FNAME_RWX, R_OK, "R_OK", 0, 3},
53 
54 	{FNAME_RWX, R_OK|W_OK, "R_OK|W_OK", 0, 3},
55 	{FNAME_RWX, R_OK|X_OK, "R_OK|X_OK", 0, 3},
56 	{FNAME_RWX, W_OK|X_OK, "W_OK|X_OK", 0, 3},
57 	{FNAME_RWX, R_OK|W_OK|X_OK, "R_OK|W_OK|X_OK", 0, 3},
58 
59 	{FNAME_X, X_OK, "X_OK", 0, 3},
60 	{FNAME_W, W_OK, "W_OK", 0, 3},
61 	{FNAME_R, R_OK, "R_OK", 0, 3},
62 
63 	{FNAME_R, X_OK, "X_OK", EACCES, 3},
64 	{FNAME_R, W_OK, "W_OK", EACCES, 1},
65 	{FNAME_W, R_OK, "R_OK", EACCES, 1},
66 	{FNAME_W, X_OK, "X_OK", EACCES, 3},
67 	{FNAME_X, R_OK, "R_OK", EACCES, 1},
68 	{FNAME_X, W_OK, "W_OK", EACCES, 1},
69 
70 	{FNAME_R, W_OK|X_OK, "W_OK|X_OK", EACCES, 3},
71 	{FNAME_R, R_OK|X_OK, "R_OK|X_OK", EACCES, 3},
72 	{FNAME_R, R_OK|W_OK, "R_OK|W_OK", EACCES, 1},
73 	{FNAME_R, R_OK|W_OK|X_OK, "R_OK|W_OK|X_OK", EACCES, 3},
74 
75 	{FNAME_W, W_OK|X_OK, "W_OK|X_OK", EACCES, 3},
76 	{FNAME_W, R_OK|X_OK, "R_OK|X_OK", EACCES, 3},
77 	{FNAME_W, R_OK|W_OK, "R_OK|W_OK", EACCES, 1},
78 	{FNAME_W, R_OK|W_OK|X_OK, "R_OK|W_OK|X_OK", EACCES, 3},
79 
80 	{FNAME_X, W_OK|X_OK, "W_OK|X_OK", EACCES, 1},
81 	{FNAME_X, R_OK|X_OK, "R_OK|X_OK", EACCES, 1},
82 	{FNAME_X, R_OK|W_OK, "R_OK|W_OK", EACCES, 1},
83 	{FNAME_X, R_OK|W_OK|X_OK, "R_OK|W_OK|X_OK", EACCES, 1},
84 
85 	{FNAME_R, W_OK, "W_OK", 0, 2},
86 	{FNAME_R, R_OK|W_OK, "R_OK|W_OK", 0, 2},
87 
88 	{FNAME_W, R_OK, "R_OK", 0, 2},
89 	{FNAME_W, R_OK|W_OK, "R_OK|W_OK", 0, 2},
90 
91 	{FNAME_X, R_OK, "R_OK", 0, 2},
92 	{FNAME_X, W_OK, "W_OK", 0, 2},
93 	{FNAME_X, R_OK|W_OK, "R_OK|W_OK", 0, 2}
94 };
95 
verify_success(struct tcase * tc,const char * user)96 static void verify_success(struct tcase *tc, const char *user)
97 {
98 	if (TEST_RETURN == -1) {
99 		tst_res(TFAIL | TTERRNO,
100 		        "access(%s, %s) as %s failed unexpectedly",
101 		        tc->fname, tc->name, user);
102 		return;
103 	}
104 
105 	tst_res(TPASS, "access(%s, %s) as %s", tc->fname, tc->name, user);
106 }
107 
verify_failure(struct tcase * tc,const char * user)108 static void verify_failure(struct tcase *tc, const char *user)
109 {
110 	if (TEST_RETURN != -1) {
111 		tst_res(TFAIL, "access(%s, %s) as %s succeded unexpectedly",
112 		        tc->fname, tc->name, user);
113 		return;
114 	}
115 
116 	if (TEST_ERRNO != tc->exp_errno) {
117 		tst_res(TFAIL | TTERRNO,
118 		        "access(%s, %s) as %s should fail with %s",
119 		        tc->fname, tc->name, user,
120 		        tst_strerrno(tc->exp_errno));
121 		return;
122 	}
123 
124 	tst_res(TPASS | TTERRNO, "access(%s, %s) as %s",
125 	        tc->fname, tc->name, user);
126 }
127 
access_test(struct tcase * tc,const char * user)128 static void access_test(struct tcase *tc, const char *user)
129 {
130 	TEST(access(tc->fname, tc->mode));
131 
132 	if (tc->exp_errno)
133 		verify_failure(tc, user);
134 	else
135 		verify_success(tc, user);
136 }
137 
verify_access(unsigned int n)138 static void verify_access(unsigned int n)
139 {
140 	struct tcase *tc = tcases + n;
141 	pid_t pid;
142 
143 	if (tc->exp_user & 0x02)
144 		access_test(tc, "root");
145 
146 	if (tc->exp_user & 0x01) {
147 		pid = SAFE_FORK();
148 		if (pid) {
149 			SAFE_WAITPID(pid, NULL, 0);
150 		} else {
151 			SAFE_SETUID(uid);
152 			access_test(tc, "nobody");
153 		}
154 	}
155 }
156 
setup(void)157 static void setup(void)
158 {
159 	struct passwd *pw;
160 
161 	pw = SAFE_GETPWNAM("nobody");
162 
163 	uid = pw->pw_uid;
164 
165 	SAFE_TOUCH(FNAME_RWX, 0777, NULL);
166 	SAFE_TOUCH(FNAME_R, 0444, NULL);
167 	SAFE_TOUCH(FNAME_W, 0222, NULL);
168 	SAFE_TOUCH(FNAME_X, 0111, NULL);
169 }
170 
171 static struct tst_test test = {
172 	.tid = "access01",
173 	.needs_tmpdir = 1,
174 	.needs_root = 1,
175 	.forks_child = 1,
176 	.setup = setup,
177 	.test = verify_access,
178 	.tcnt = ARRAY_SIZE(tcases),
179 };
180