xref: /freebsd/tools/regression/security/access/testaccess.c (revision cd7aba4057fb3d5cd3d4d4397112c120270d8d06)
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  * $FreeBSD$
33884748cfSRobert Watson  */
34884748cfSRobert Watson 
35884748cfSRobert Watson #include <sys/types.h>
36884748cfSRobert Watson 
37884748cfSRobert Watson #include <errno.h>
38884748cfSRobert Watson #include <fcntl.h>
39884748cfSRobert Watson #include <stdio.h>
40884748cfSRobert Watson #include <stdlib.h>
41884748cfSRobert Watson #include <unistd.h>
42884748cfSRobert Watson 
43884748cfSRobert Watson /*
44884748cfSRobert Watson  * Regression test to check some basic cases and see if access() and
45884748cfSRobert Watson  * eaccess() are using the correct portions of the process credential.
46884748cfSRobert Watson  * This test relies on running with privilege, and on UFS file system
47884748cfSRobert Watson  * semantics.  Running the test in other environments may result
48884748cfSRobert Watson  * in incorrect failure identification.
49884748cfSRobert Watson  *
50884748cfSRobert Watson  * Note that this may also break if file system access control is
51884748cfSRobert Watson  * broken, or if the ability to check and set credentials is broken.
52884748cfSRobert Watson  *
53884748cfSRobert Watson  * Note that this test uses two hard-coded non-root UIDs; on multi-user
54884748cfSRobert Watson  * systems, these UIDs may be in use by an untrusted user, in which
55884748cfSRobert Watson  * case those users could interfere with the test.
56884748cfSRobert Watson  */
57884748cfSRobert Watson 
58884748cfSRobert Watson #define	ROOT_UID	(uid_t)0
59884748cfSRobert Watson #define	WHEEL_GID	(gid_t)0
60884748cfSRobert Watson #define	TEST_UID_ONE	(uid_t)500
61884748cfSRobert Watson #define	TEST_GID_ONE	(gid_t)500
62884748cfSRobert Watson #define	TEST_UID_TWO	(uid_t)501
63884748cfSRobert Watson #define	TEST_GID_TWO	(gid_t)501
64884748cfSRobert Watson 
65884748cfSRobert Watson struct file_description {
66884748cfSRobert Watson 	char	*fd_name;
67884748cfSRobert Watson 	uid_t	 fd_owner;
68884748cfSRobert Watson 	gid_t	 fd_group;
69884748cfSRobert Watson 	mode_t	 fd_mode;
70884748cfSRobert Watson };
71884748cfSRobert Watson 
72884748cfSRobert Watson static struct file_description fd_list[] = {
73884748cfSRobert Watson {"test1", ROOT_UID, WHEEL_GID, 0400},
74884748cfSRobert Watson {"test2", TEST_UID_ONE, WHEEL_GID,0400},
75884748cfSRobert Watson {"test3", TEST_UID_TWO, WHEEL_GID, 0400},
76884748cfSRobert Watson {"test4", ROOT_UID, WHEEL_GID, 0040},
77884748cfSRobert Watson {"test5", ROOT_UID, TEST_GID_ONE, 0040},
78884748cfSRobert Watson {"test6", ROOT_UID, TEST_GID_TWO, 0040}};
79884748cfSRobert Watson 
80884748cfSRobert Watson static int fd_list_count = sizeof(fd_list) /
81884748cfSRobert Watson     sizeof(struct file_description);
82884748cfSRobert Watson 
83884748cfSRobert Watson int
84884748cfSRobert Watson setup(void)
85884748cfSRobert Watson {
86884748cfSRobert Watson 	int i, error;
87884748cfSRobert Watson 
88884748cfSRobert Watson 	for (i = 0; i < fd_list_count; i++) {
89884748cfSRobert Watson 		error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
90884748cfSRobert Watson 		if (error == -1) {
91884748cfSRobert Watson 			perror("open");
92884748cfSRobert Watson 			return (error);
93884748cfSRobert Watson 		}
94884748cfSRobert Watson 		close(error);
95884748cfSRobert Watson 		error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
96884748cfSRobert Watson 		    fd_list[i].fd_group);
97884748cfSRobert Watson 		if (error) {
98884748cfSRobert Watson 			perror("chown");
99884748cfSRobert Watson 			return (error);
100884748cfSRobert Watson 		}
101884748cfSRobert Watson 	}
102884748cfSRobert Watson 	return (0);
103884748cfSRobert Watson }
104884748cfSRobert Watson 
105884748cfSRobert Watson int
106884748cfSRobert Watson restoreprivilege(void)
107884748cfSRobert Watson {
108884748cfSRobert Watson 	int error;
109884748cfSRobert Watson 
110884748cfSRobert Watson 	error = setreuid(ROOT_UID, ROOT_UID);
111884748cfSRobert Watson 	if (error)
112884748cfSRobert Watson 		return (error);
113884748cfSRobert Watson 
114884748cfSRobert Watson 	error = setregid(WHEEL_GID, WHEEL_GID);
115884748cfSRobert Watson 	if (error)
116884748cfSRobert Watson 		return (error);
117884748cfSRobert Watson 
118884748cfSRobert Watson 	return (0);
119884748cfSRobert Watson }
120884748cfSRobert Watson 
121884748cfSRobert Watson int
122884748cfSRobert Watson reportprivilege(char *message)
123884748cfSRobert Watson {
124884748cfSRobert Watson 	uid_t euid, ruid, suid;
125884748cfSRobert Watson 	gid_t egid, rgid, sgid;
126884748cfSRobert Watson 	int error;
127884748cfSRobert Watson 
128884748cfSRobert Watson 	error = getresuid(&ruid, &euid, &suid);
129884748cfSRobert Watson 	if (error) {
130884748cfSRobert Watson 		perror("getresuid");
131884748cfSRobert Watson 		return (error);
132884748cfSRobert Watson 	}
133884748cfSRobert Watson 
134884748cfSRobert Watson 	error = getresgid(&rgid, &egid, &sgid);
135884748cfSRobert Watson 	if (error) {
136884748cfSRobert Watson 		perror("getresgid");
137884748cfSRobert Watson 		return (error);
138884748cfSRobert Watson 	}
139884748cfSRobert Watson 
140884748cfSRobert Watson 	if (message)
141884748cfSRobert Watson 		printf("%s: ", message);
142884748cfSRobert Watson 	printf("ruid: %d, euid: %d, suid: %d,     ", ruid, euid, suid);
143884748cfSRobert Watson 	printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
144884748cfSRobert Watson 
145884748cfSRobert Watson 	return (0);
146884748cfSRobert Watson }
147884748cfSRobert Watson 
148884748cfSRobert Watson int
149884748cfSRobert Watson cleanup(void)
150884748cfSRobert Watson {
151884748cfSRobert Watson 	int i, error;
152884748cfSRobert Watson 
153884748cfSRobert Watson 	error = restoreprivilege();
154884748cfSRobert Watson 	if (error) {
155884748cfSRobert Watson 		perror("restoreprivilege");
156884748cfSRobert Watson 		return (error);
157884748cfSRobert Watson 	}
158884748cfSRobert Watson 
159884748cfSRobert Watson 	for (i = 0; i < fd_list_count; i++) {
160884748cfSRobert Watson 		error = unlink(fd_list[i].fd_name);
161884748cfSRobert Watson 		if (error)
162884748cfSRobert Watson 			return (error);
163884748cfSRobert Watson 	}
164884748cfSRobert Watson 
165884748cfSRobert Watson 	return (0);
166884748cfSRobert Watson }
167884748cfSRobert Watson 
168884748cfSRobert Watson int
169884748cfSRobert Watson main(int argc, char *argv[])
170884748cfSRobert Watson {
171884748cfSRobert Watson 	int error, errorseen;
172884748cfSRobert Watson 
173884748cfSRobert Watson 	if (geteuid() != 0) {
174884748cfSRobert Watson 		fprintf(stderr, "testaccess must run as root.\n");
175884748cfSRobert Watson 		exit (EXIT_FAILURE);
176884748cfSRobert Watson 	}
177884748cfSRobert Watson 
178884748cfSRobert Watson 	error = setup();
179884748cfSRobert Watson 	if (error) {
180884748cfSRobert Watson 		cleanup();
181884748cfSRobert Watson 		exit (EXIT_FAILURE);
182884748cfSRobert Watson 	}
183884748cfSRobert Watson 
184884748cfSRobert Watson 	/* Make sure saved uid is set appropriately. */
185884748cfSRobert Watson 	error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
186884748cfSRobert Watson 	if (error) {
187884748cfSRobert Watson 		perror("setresuid");
188884748cfSRobert Watson 		cleanup();
189884748cfSRobert Watson 	}
190884748cfSRobert Watson 
191884748cfSRobert Watson 	/* Clear out additional groups. */
192884748cfSRobert Watson 	error = setgroups(0, NULL);
193884748cfSRobert Watson 	if (error) {
194884748cfSRobert Watson 		perror("setgroups");
195884748cfSRobert Watson 		cleanup();
196884748cfSRobert Watson 	}
197884748cfSRobert Watson 
198884748cfSRobert Watson 	/* Make sure saved gid is set appropriately. */
199884748cfSRobert Watson 	error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
200884748cfSRobert Watson 	if (error) {
201884748cfSRobert Watson 		perror("setresgid");
202884748cfSRobert Watson 		cleanup();
203884748cfSRobert Watson 	}
204884748cfSRobert Watson 
205884748cfSRobert Watson 	/*
206884748cfSRobert Watson 	 * UID-only tests.
207884748cfSRobert Watson 	 */
208884748cfSRobert Watson 
209884748cfSRobert Watson 	/* Check that saved uid is not used */
210884748cfSRobert Watson 	error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
211884748cfSRobert Watson 	if (error) {
212884748cfSRobert Watson 		perror("setresuid.1");
213884748cfSRobert Watson 		cleanup();
214884748cfSRobert Watson 		exit (EXIT_FAILURE);
215884748cfSRobert Watson 	}
216884748cfSRobert Watson 
217884748cfSRobert Watson 	errorseen = 0;
218884748cfSRobert Watson 
219884748cfSRobert Watson 	error = access("test1", R_OK);
220884748cfSRobert Watson 	if (!error) {
221884748cfSRobert Watson 		fprintf(stderr, "saved uid used instead of real uid\n");
222884748cfSRobert Watson 		errorseen++;
223884748cfSRobert Watson 	}
224884748cfSRobert Watson 
225884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
226abc9a360SRobert Watson 	error = eaccess("test1", R_OK);
227884748cfSRobert Watson 	if (!error) {
228884748cfSRobert Watson 		fprintf(stderr, "saved uid used instead of effective uid\n");
229884748cfSRobert Watson 		errorseen++;
230884748cfSRobert Watson 	}
231884748cfSRobert Watson #endif
232884748cfSRobert Watson 
233884748cfSRobert Watson 	error = restoreprivilege();
234884748cfSRobert Watson 	if (error) {
235884748cfSRobert Watson 		perror("restoreprivilege");
236884748cfSRobert Watson 		cleanup();
237884748cfSRobert Watson 		exit (EXIT_FAILURE);
238884748cfSRobert Watson 	}
239884748cfSRobert Watson 
240884748cfSRobert Watson 	error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
241884748cfSRobert Watson 	if (error) {
242884748cfSRobert Watson 		perror("setresid.2");
243884748cfSRobert Watson 		cleanup();
244884748cfSRobert Watson 		exit (EXIT_FAILURE);
245884748cfSRobert Watson 	}
246884748cfSRobert Watson 
247884748cfSRobert Watson 	/* Check that the real uid is used, not the effective uid */
248884748cfSRobert Watson 	error = access("test2", R_OK);
249884748cfSRobert Watson 	if (error) {
250884748cfSRobert Watson 		fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
251884748cfSRobert Watson 		errorseen++;
252884748cfSRobert Watson 	}
253884748cfSRobert Watson 
254884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
255884748cfSRobert Watson 	/* Check that the effective uid is used, not the real uid */
256884748cfSRobert Watson 	error = eaccess("test3", R_OK);
257884748cfSRobert Watson 	if (error) {
258884748cfSRobert Watson 		fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
259884748cfSRobert Watson 		errorseen++;
260884748cfSRobert Watson 	}
261884748cfSRobert Watson #endif
262884748cfSRobert Watson 
263884748cfSRobert Watson 	/* Check that the real uid is used, not the effective uid */
264884748cfSRobert Watson 	error = access("test3", R_OK);
265884748cfSRobert Watson 	if (!error) {
266884748cfSRobert Watson 		fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
267884748cfSRobert Watson 		errorseen++;
268884748cfSRobert Watson 	}
269884748cfSRobert Watson 
270884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
271884748cfSRobert Watson 	/* Check that the effective uid is used, not the real uid */
272884748cfSRobert Watson 	error = eaccess("test2", R_OK);
273abc9a360SRobert Watson 	if (!error) {
274884748cfSRobert Watson 		fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
275884748cfSRobert Watson 		errorseen++;
276884748cfSRobert Watson 	}
277884748cfSRobert Watson #endif
278884748cfSRobert Watson 
279884748cfSRobert Watson 	error = restoreprivilege();
280884748cfSRobert Watson 	if (error) {
281884748cfSRobert Watson 		perror("restoreprivilege");
282884748cfSRobert Watson 		cleanup();
283884748cfSRobert Watson 		exit (EXIT_FAILURE);
284884748cfSRobert Watson 	}
285884748cfSRobert Watson 
286884748cfSRobert Watson 	error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
287884748cfSRobert Watson 	if (error) {
288884748cfSRobert Watson 		perror("setresgid.1");
289884748cfSRobert Watson 		cleanup();
290884748cfSRobert Watson 		exit (EXIT_FAILURE);
291884748cfSRobert Watson 	}
292884748cfSRobert Watson 
293884748cfSRobert Watson 	/* Set non-root effective uid to avoid excess privilege. */
294884748cfSRobert Watson 	error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
295884748cfSRobert Watson 	if (error) {
296884748cfSRobert Watson 		perror("setresuid.3");
297884748cfSRobert Watson 		cleanup();
298884748cfSRobert Watson 		exit (EXIT_FAILURE);
299884748cfSRobert Watson 	}
300884748cfSRobert Watson 
301884748cfSRobert Watson 	/* Check that the saved gid is not used */
302884748cfSRobert Watson 	error = access("test4", R_OK);
303884748cfSRobert Watson 	if (!error) {
304884748cfSRobert Watson 		fprintf(stderr, "saved gid used instead of real gid\n");
305884748cfSRobert Watson 	}
306884748cfSRobert Watson 
307884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
308884748cfSRobert Watson 	error = eaccess("test4", R_OK);
309884748cfSRobert Watson 	if (!error) {
310884748cfSRobert Watson 		fprintf(stderr, "saved gid used instead of effective gid\n");
311884748cfSRobert Watson 		errorseen++;
312884748cfSRobert Watson 	}
313884748cfSRobert Watson #endif
314884748cfSRobert Watson 
315884748cfSRobert Watson 	/* Check that the real gid is used, not the effective gid */
316884748cfSRobert Watson 	error = access("test5", R_OK);
317884748cfSRobert Watson 	if (error) {
318884748cfSRobert Watson 		fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
319884748cfSRobert Watson 		errorseen++;
320884748cfSRobert Watson 	}
321884748cfSRobert Watson 
322884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
323884748cfSRobert Watson 	/* Check that the effective gid is used, not the real gid */
324884748cfSRobert Watson 	error = eaccess("test6", R_OK);
325884748cfSRobert Watson 	if (error) {
326884748cfSRobert Watson 		fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
327884748cfSRobert Watson 		errorseen++;
328884748cfSRobert Watson 	}
329884748cfSRobert Watson #endif
330884748cfSRobert Watson 
331884748cfSRobert Watson 	/* Check that the real gid is used, not the effective gid */
332884748cfSRobert Watson 	error = access("test6", R_OK);
333884748cfSRobert Watson 	if (!error) {
334884748cfSRobert Watson 		fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
335884748cfSRobert Watson 		errorseen++;
336884748cfSRobert Watson 	}
337884748cfSRobert Watson 
338884748cfSRobert Watson #ifdef EACCESS_AVAILABLE
339884748cfSRobert Watson 	/* Check that the effective gid is used, not the real gid */
340884748cfSRobert Watson 	error = eaccess("test5", R_OK);
341884748cfSRobert Watson 	if (!error) {
342884748cfSRobert Watson 		fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
343884748cfSRobert Watson 		errorseen++;
344884748cfSRobert Watson 	}
345884748cfSRobert Watson #endif
346884748cfSRobert Watson 
347884748cfSRobert Watson 	fprintf(stderr, "%d errors seen.\n", errorseen);
348884748cfSRobert Watson 
349884748cfSRobert Watson 	/*
350884748cfSRobert Watson 	 * All tests done, restore and clean up
351884748cfSRobert Watson 	 */
352884748cfSRobert Watson 
353884748cfSRobert Watson 	error = cleanup();
354884748cfSRobert Watson 	if (error) {
355884748cfSRobert Watson 		perror("cleanup");
356884748cfSRobert Watson 		exit (EXIT_FAILURE);
357884748cfSRobert Watson 	}
358884748cfSRobert Watson 
359884748cfSRobert Watson 	exit (EXIT_SUCCESS);
360884748cfSRobert Watson }
361