xref: /freebsd/tools/regression/security/access/testaccess.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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