1884748cfSRobert Watson /*-
2cd7aba40SRobert Watson * Copyright (c) 2001 Networks Associates Technology, Inc.
3884748cfSRobert Watson * All rights reserved.
4884748cfSRobert Watson *
5884748cfSRobert Watson * Redistribution and use in source and binary forms, with or without
6884748cfSRobert Watson * modification, are permitted provided that the following conditions
7884748cfSRobert Watson * are met:
8884748cfSRobert Watson * 1. Redistributions of source code must retain the above copyright
9884748cfSRobert Watson * notice, this list of conditions and the following disclaimer.
10884748cfSRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
11884748cfSRobert Watson * notice, this list of conditions and the following disclaimer in the
12884748cfSRobert Watson * documentation and/or other materials provided with the distribution.
13884748cfSRobert Watson *
14884748cfSRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15884748cfSRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16884748cfSRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17884748cfSRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18884748cfSRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19884748cfSRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20884748cfSRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21884748cfSRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22884748cfSRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23884748cfSRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24884748cfSRobert Watson * SUCH DAMAGE.
25884748cfSRobert Watson *
26884748cfSRobert Watson * Written at NAI Labs at Network Associates by Robert Watson for the
27884748cfSRobert Watson * TrustedBSD Project.
28884748cfSRobert Watson *
29884748cfSRobert Watson * Work sponsored by Defense Advanced Research Projects Agency under the
30884748cfSRobert Watson * CHATS research program, CBOSS project.
31884748cfSRobert Watson */
32884748cfSRobert Watson
33884748cfSRobert Watson #include <sys/types.h>
34884748cfSRobert Watson
35884748cfSRobert Watson #include <errno.h>
36884748cfSRobert Watson #include <fcntl.h>
37884748cfSRobert Watson #include <stdio.h>
38884748cfSRobert Watson #include <stdlib.h>
39884748cfSRobert Watson #include <unistd.h>
40884748cfSRobert Watson
41884748cfSRobert Watson /*
42884748cfSRobert Watson * Regression test to check some basic cases and see if access() and
43884748cfSRobert Watson * eaccess() are using the correct portions of the process credential.
44884748cfSRobert Watson * This test relies on running with privilege, and on UFS filesystem
45884748cfSRobert Watson * semantics. Running the test in other environments may result
46884748cfSRobert Watson * in incorrect failure identification.
47884748cfSRobert Watson *
48884748cfSRobert Watson * Note that this may also break if filesystem access control is
49884748cfSRobert Watson * broken, or if the ability to check and set credentials is broken.
50884748cfSRobert Watson *
51884748cfSRobert Watson * Note that this test uses two hard-coded non-root UIDs; on multi-user
52884748cfSRobert Watson * systems, these UIDs may be in use by an untrusted user, in which
53884748cfSRobert Watson * case those users could interfere with the test.
54884748cfSRobert Watson */
55884748cfSRobert Watson
56884748cfSRobert Watson #define ROOT_UID (uid_t)0
57884748cfSRobert Watson #define WHEEL_GID (gid_t)0
58884748cfSRobert Watson #define TEST_UID_ONE (uid_t)500
59884748cfSRobert Watson #define TEST_GID_ONE (gid_t)500
60884748cfSRobert Watson #define TEST_UID_TWO (uid_t)501
61884748cfSRobert Watson #define TEST_GID_TWO (gid_t)501
62884748cfSRobert Watson
63884748cfSRobert Watson struct file_description {
64884748cfSRobert Watson char *fd_name;
65884748cfSRobert Watson uid_t fd_owner;
66884748cfSRobert Watson gid_t fd_group;
67884748cfSRobert Watson mode_t fd_mode;
68884748cfSRobert Watson };
69884748cfSRobert Watson
70884748cfSRobert Watson static struct file_description fd_list[] = {
71884748cfSRobert Watson {"test1", ROOT_UID, WHEEL_GID, 0400},
72884748cfSRobert Watson {"test2", TEST_UID_ONE, WHEEL_GID,0400},
73884748cfSRobert Watson {"test3", TEST_UID_TWO, WHEEL_GID, 0400},
74884748cfSRobert Watson {"test4", ROOT_UID, WHEEL_GID, 0040},
75884748cfSRobert Watson {"test5", ROOT_UID, TEST_GID_ONE, 0040},
76884748cfSRobert Watson {"test6", ROOT_UID, TEST_GID_TWO, 0040}};
77884748cfSRobert Watson
78884748cfSRobert Watson static int fd_list_count = sizeof(fd_list) /
79884748cfSRobert Watson sizeof(struct file_description);
80884748cfSRobert Watson
81884748cfSRobert Watson int
setup(void)82884748cfSRobert Watson setup(void)
83884748cfSRobert Watson {
84884748cfSRobert Watson int i, error;
85884748cfSRobert Watson
86884748cfSRobert Watson for (i = 0; i < fd_list_count; i++) {
87884748cfSRobert Watson error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
88884748cfSRobert Watson if (error == -1) {
89884748cfSRobert Watson perror("open");
90884748cfSRobert Watson return (error);
91884748cfSRobert Watson }
92884748cfSRobert Watson close(error);
93884748cfSRobert Watson error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
94884748cfSRobert Watson fd_list[i].fd_group);
95884748cfSRobert Watson if (error) {
96884748cfSRobert Watson perror("chown");
97884748cfSRobert Watson return (error);
98884748cfSRobert Watson }
99884748cfSRobert Watson }
100884748cfSRobert Watson return (0);
101884748cfSRobert Watson }
102884748cfSRobert Watson
103884748cfSRobert Watson int
restoreprivilege(void)104884748cfSRobert Watson restoreprivilege(void)
105884748cfSRobert Watson {
106884748cfSRobert Watson int error;
107884748cfSRobert Watson
108884748cfSRobert Watson error = setreuid(ROOT_UID, ROOT_UID);
109884748cfSRobert Watson if (error)
110884748cfSRobert Watson return (error);
111884748cfSRobert Watson
112884748cfSRobert Watson error = setregid(WHEEL_GID, WHEEL_GID);
113884748cfSRobert Watson if (error)
114884748cfSRobert Watson return (error);
115884748cfSRobert Watson
116884748cfSRobert Watson return (0);
117884748cfSRobert Watson }
118884748cfSRobert Watson
119884748cfSRobert Watson int
reportprivilege(char * message)120884748cfSRobert Watson reportprivilege(char *message)
121884748cfSRobert Watson {
122884748cfSRobert Watson uid_t euid, ruid, suid;
123884748cfSRobert Watson gid_t egid, rgid, sgid;
124884748cfSRobert Watson int error;
125884748cfSRobert Watson
126884748cfSRobert Watson error = getresuid(&ruid, &euid, &suid);
127884748cfSRobert Watson if (error) {
128884748cfSRobert Watson perror("getresuid");
129884748cfSRobert Watson return (error);
130884748cfSRobert Watson }
131884748cfSRobert Watson
132884748cfSRobert Watson error = getresgid(&rgid, &egid, &sgid);
133884748cfSRobert Watson if (error) {
134884748cfSRobert Watson perror("getresgid");
135884748cfSRobert Watson return (error);
136884748cfSRobert Watson }
137884748cfSRobert Watson
138884748cfSRobert Watson if (message)
139884748cfSRobert Watson printf("%s: ", message);
140884748cfSRobert Watson printf("ruid: %d, euid: %d, suid: %d, ", ruid, euid, suid);
141884748cfSRobert Watson printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
142884748cfSRobert Watson
143884748cfSRobert Watson return (0);
144884748cfSRobert Watson }
145884748cfSRobert Watson
146884748cfSRobert Watson int
cleanup(void)147884748cfSRobert Watson cleanup(void)
148884748cfSRobert Watson {
149884748cfSRobert Watson int i, error;
150884748cfSRobert Watson
151884748cfSRobert Watson error = restoreprivilege();
152884748cfSRobert Watson if (error) {
153884748cfSRobert Watson perror("restoreprivilege");
154884748cfSRobert Watson return (error);
155884748cfSRobert Watson }
156884748cfSRobert Watson
157884748cfSRobert Watson for (i = 0; i < fd_list_count; i++) {
158884748cfSRobert Watson error = unlink(fd_list[i].fd_name);
159884748cfSRobert Watson if (error)
160884748cfSRobert Watson return (error);
161884748cfSRobert Watson }
162884748cfSRobert Watson
163884748cfSRobert Watson return (0);
164884748cfSRobert Watson }
165884748cfSRobert Watson
166884748cfSRobert Watson int
main(int argc,char * argv[])167884748cfSRobert Watson main(int argc, char *argv[])
168884748cfSRobert Watson {
169884748cfSRobert Watson int error, errorseen;
170884748cfSRobert Watson
171884748cfSRobert Watson if (geteuid() != 0) {
172884748cfSRobert Watson fprintf(stderr, "testaccess must run as root.\n");
173884748cfSRobert Watson exit (EXIT_FAILURE);
174884748cfSRobert Watson }
175884748cfSRobert Watson
176884748cfSRobert Watson error = setup();
177884748cfSRobert Watson if (error) {
178884748cfSRobert Watson cleanup();
179884748cfSRobert Watson exit (EXIT_FAILURE);
180884748cfSRobert Watson }
181884748cfSRobert Watson
182884748cfSRobert Watson /* Make sure saved uid is set appropriately. */
183884748cfSRobert Watson error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
184884748cfSRobert Watson if (error) {
185884748cfSRobert Watson perror("setresuid");
186884748cfSRobert Watson cleanup();
187884748cfSRobert Watson }
188884748cfSRobert Watson
189884748cfSRobert Watson /* Clear out additional groups. */
190884748cfSRobert Watson error = setgroups(0, NULL);
191884748cfSRobert Watson if (error) {
192884748cfSRobert Watson perror("setgroups");
193884748cfSRobert Watson cleanup();
194884748cfSRobert Watson }
195884748cfSRobert Watson
196884748cfSRobert Watson /* Make sure saved gid is set appropriately. */
197884748cfSRobert Watson error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
198884748cfSRobert Watson if (error) {
199884748cfSRobert Watson perror("setresgid");
200884748cfSRobert Watson cleanup();
201884748cfSRobert Watson }
202884748cfSRobert Watson
203884748cfSRobert Watson /*
204884748cfSRobert Watson * UID-only tests.
205884748cfSRobert Watson */
206884748cfSRobert Watson
207884748cfSRobert Watson /* Check that saved uid is not used */
208884748cfSRobert Watson error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
209884748cfSRobert Watson if (error) {
210884748cfSRobert Watson perror("setresuid.1");
211884748cfSRobert Watson cleanup();
212884748cfSRobert Watson exit (EXIT_FAILURE);
213884748cfSRobert Watson }
214884748cfSRobert Watson
215884748cfSRobert Watson errorseen = 0;
216884748cfSRobert Watson
217884748cfSRobert Watson error = access("test1", R_OK);
218884748cfSRobert Watson if (!error) {
219884748cfSRobert Watson fprintf(stderr, "saved uid used instead of real uid\n");
220884748cfSRobert Watson errorseen++;
221884748cfSRobert Watson }
222884748cfSRobert Watson
223884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
224abc9a360SRobert Watson error = eaccess("test1", R_OK);
225884748cfSRobert Watson if (!error) {
226884748cfSRobert Watson fprintf(stderr, "saved uid used instead of effective uid\n");
227884748cfSRobert Watson errorseen++;
228884748cfSRobert Watson }
229884748cfSRobert Watson #endif
230884748cfSRobert Watson
231884748cfSRobert Watson error = restoreprivilege();
232884748cfSRobert Watson if (error) {
233884748cfSRobert Watson perror("restoreprivilege");
234884748cfSRobert Watson cleanup();
235884748cfSRobert Watson exit (EXIT_FAILURE);
236884748cfSRobert Watson }
237884748cfSRobert Watson
238884748cfSRobert Watson error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
239884748cfSRobert Watson if (error) {
240884748cfSRobert Watson perror("setresid.2");
241884748cfSRobert Watson cleanup();
242884748cfSRobert Watson exit (EXIT_FAILURE);
243884748cfSRobert Watson }
244884748cfSRobert Watson
245884748cfSRobert Watson /* Check that the real uid is used, not the effective uid */
246884748cfSRobert Watson error = access("test2", R_OK);
247884748cfSRobert Watson if (error) {
248884748cfSRobert Watson fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
249884748cfSRobert Watson errorseen++;
250884748cfSRobert Watson }
251884748cfSRobert Watson
252884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
253884748cfSRobert Watson /* Check that the effective uid is used, not the real uid */
254884748cfSRobert Watson error = eaccess("test3", R_OK);
255884748cfSRobert Watson if (error) {
256884748cfSRobert Watson fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
257884748cfSRobert Watson errorseen++;
258884748cfSRobert Watson }
259884748cfSRobert Watson #endif
260884748cfSRobert Watson
261884748cfSRobert Watson /* Check that the real uid is used, not the effective uid */
262884748cfSRobert Watson error = access("test3", R_OK);
263884748cfSRobert Watson if (!error) {
264884748cfSRobert Watson fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
265884748cfSRobert Watson errorseen++;
266884748cfSRobert Watson }
267884748cfSRobert Watson
268884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
269884748cfSRobert Watson /* Check that the effective uid is used, not the real uid */
270884748cfSRobert Watson error = eaccess("test2", R_OK);
271abc9a360SRobert Watson if (!error) {
272884748cfSRobert Watson fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
273884748cfSRobert Watson errorseen++;
274884748cfSRobert Watson }
275884748cfSRobert Watson #endif
276884748cfSRobert Watson
277884748cfSRobert Watson error = restoreprivilege();
278884748cfSRobert Watson if (error) {
279884748cfSRobert Watson perror("restoreprivilege");
280884748cfSRobert Watson cleanup();
281884748cfSRobert Watson exit (EXIT_FAILURE);
282884748cfSRobert Watson }
283884748cfSRobert Watson
284884748cfSRobert Watson error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
285884748cfSRobert Watson if (error) {
286884748cfSRobert Watson perror("setresgid.1");
287884748cfSRobert Watson cleanup();
288884748cfSRobert Watson exit (EXIT_FAILURE);
289884748cfSRobert Watson }
290884748cfSRobert Watson
291884748cfSRobert Watson /* Set non-root effective uid to avoid excess privilege. */
292884748cfSRobert Watson error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
293884748cfSRobert Watson if (error) {
294884748cfSRobert Watson perror("setresuid.3");
295884748cfSRobert Watson cleanup();
296884748cfSRobert Watson exit (EXIT_FAILURE);
297884748cfSRobert Watson }
298884748cfSRobert Watson
299884748cfSRobert Watson /* Check that the saved gid is not used */
300884748cfSRobert Watson error = access("test4", R_OK);
301884748cfSRobert Watson if (!error) {
302884748cfSRobert Watson fprintf(stderr, "saved gid used instead of real gid\n");
303884748cfSRobert Watson }
304884748cfSRobert Watson
305884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
306884748cfSRobert Watson error = eaccess("test4", R_OK);
307884748cfSRobert Watson if (!error) {
308884748cfSRobert Watson fprintf(stderr, "saved gid used instead of effective gid\n");
309884748cfSRobert Watson errorseen++;
310884748cfSRobert Watson }
311884748cfSRobert Watson #endif
312884748cfSRobert Watson
313884748cfSRobert Watson /* Check that the real gid is used, not the effective gid */
314884748cfSRobert Watson error = access("test5", R_OK);
315884748cfSRobert Watson if (error) {
316884748cfSRobert Watson fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
317884748cfSRobert Watson errorseen++;
318884748cfSRobert Watson }
319884748cfSRobert Watson
320884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
321884748cfSRobert Watson /* Check that the effective gid is used, not the real gid */
322884748cfSRobert Watson error = eaccess("test6", R_OK);
323884748cfSRobert Watson if (error) {
324884748cfSRobert Watson fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
325884748cfSRobert Watson errorseen++;
326884748cfSRobert Watson }
327884748cfSRobert Watson #endif
328884748cfSRobert Watson
329884748cfSRobert Watson /* Check that the real gid is used, not the effective gid */
330884748cfSRobert Watson error = access("test6", R_OK);
331884748cfSRobert Watson if (!error) {
332884748cfSRobert Watson fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
333884748cfSRobert Watson errorseen++;
334884748cfSRobert Watson }
335884748cfSRobert Watson
336884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
337884748cfSRobert Watson /* Check that the effective gid is used, not the real gid */
338884748cfSRobert Watson error = eaccess("test5", R_OK);
339884748cfSRobert Watson if (!error) {
340884748cfSRobert Watson fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
341884748cfSRobert Watson errorseen++;
342884748cfSRobert Watson }
343884748cfSRobert Watson #endif
344884748cfSRobert Watson
345884748cfSRobert Watson fprintf(stderr, "%d errors seen.\n", errorseen);
346884748cfSRobert Watson
347884748cfSRobert Watson /*
348884748cfSRobert Watson * All tests done, restore and clean up
349884748cfSRobert Watson */
350884748cfSRobert Watson
351884748cfSRobert Watson error = cleanup();
352884748cfSRobert Watson if (error) {
353884748cfSRobert Watson perror("cleanup");
354884748cfSRobert Watson exit (EXIT_FAILURE);
355884748cfSRobert Watson }
356884748cfSRobert Watson
357884748cfSRobert Watson exit (EXIT_SUCCESS);
358884748cfSRobert Watson }
359