183736Srwatson/*-
292288Srwatson * Copyright (c) 2001 Networks Associates Technology, Inc.
383736Srwatson * All rights reserved.
483736Srwatson *
583736Srwatson * Redistribution and use in source and binary forms, with or without
683736Srwatson * modification, are permitted provided that the following conditions
783736Srwatson * are met:
883736Srwatson * 1. Redistributions of source code must retain the above copyright
983736Srwatson *    notice, this list of conditions and the following disclaimer.
1083736Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1183736Srwatson *    notice, this list of conditions and the following disclaimer in the
1283736Srwatson *    documentation and/or other materials provided with the distribution.
1383736Srwatson *
1483736Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1583736Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1683736Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1783736Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1883736Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1983736Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2083736Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2183736Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2283736Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2383736Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2483736Srwatson * SUCH DAMAGE.
2583736Srwatson *
2683736Srwatson * Written at NAI Labs at Network Associates by Robert Watson for the
2783736Srwatson * TrustedBSD Project.
2883736Srwatson *
2983736Srwatson * Work sponsored by Defense Advanced Research Projects Agency under the
3083736Srwatson * CHATS research program, CBOSS project.
3183736Srwatson *
3283736Srwatson * $FreeBSD$
3383736Srwatson */
3483736Srwatson
3583736Srwatson#include <sys/types.h>
3683736Srwatson
3783736Srwatson#include <errno.h>
3883736Srwatson#include <fcntl.h>
3983736Srwatson#include <stdio.h>
4083736Srwatson#include <stdlib.h>
4183736Srwatson#include <unistd.h>
4283736Srwatson
4383736Srwatson/*
4483736Srwatson * Regression test to check some basic cases and see if access() and
4583736Srwatson * eaccess() are using the correct portions of the process credential.
4696709Strhodes * This test relies on running with privilege, and on UFS filesystem
4783736Srwatson * semantics.  Running the test in other environments may result
4883736Srwatson * in incorrect failure identification.
4983736Srwatson *
5096709Strhodes * Note that this may also break if filesystem access control is
5183736Srwatson * broken, or if the ability to check and set credentials is broken.
5283736Srwatson *
5383736Srwatson * Note that this test uses two hard-coded non-root UIDs; on multi-user
5483736Srwatson * systems, these UIDs may be in use by an untrusted user, in which
5583736Srwatson * case those users could interfere with the test.
5683736Srwatson */
5783736Srwatson
5883736Srwatson#define	ROOT_UID	(uid_t)0
5983736Srwatson#define	WHEEL_GID	(gid_t)0
6083736Srwatson#define	TEST_UID_ONE	(uid_t)500
6183736Srwatson#define	TEST_GID_ONE	(gid_t)500
6283736Srwatson#define	TEST_UID_TWO	(uid_t)501
6383736Srwatson#define	TEST_GID_TWO	(gid_t)501
6483736Srwatson
6583736Srwatsonstruct file_description {
6683736Srwatson	char	*fd_name;
6783736Srwatson	uid_t	 fd_owner;
6883736Srwatson	gid_t	 fd_group;
6983736Srwatson	mode_t	 fd_mode;
7083736Srwatson};
7183736Srwatson
7283736Srwatsonstatic struct file_description fd_list[] = {
7383736Srwatson{"test1", ROOT_UID, WHEEL_GID, 0400},
7483736Srwatson{"test2", TEST_UID_ONE, WHEEL_GID,0400},
7583736Srwatson{"test3", TEST_UID_TWO, WHEEL_GID, 0400},
7683736Srwatson{"test4", ROOT_UID, WHEEL_GID, 0040},
7783736Srwatson{"test5", ROOT_UID, TEST_GID_ONE, 0040},
7883736Srwatson{"test6", ROOT_UID, TEST_GID_TWO, 0040}};
7983736Srwatson
8083736Srwatsonstatic int fd_list_count = sizeof(fd_list) /
8183736Srwatson    sizeof(struct file_description);
8283736Srwatson
8383736Srwatsonint
8483736Srwatsonsetup(void)
8583736Srwatson{
8683736Srwatson	int i, error;
8783736Srwatson
8883736Srwatson	for (i = 0; i < fd_list_count; i++) {
8983736Srwatson		error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);
9083736Srwatson		if (error == -1) {
9183736Srwatson			perror("open");
9283736Srwatson			return (error);
9383736Srwatson		}
9483736Srwatson		close(error);
9583736Srwatson		error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,
9683736Srwatson		    fd_list[i].fd_group);
9783736Srwatson		if (error) {
9883736Srwatson			perror("chown");
9983736Srwatson			return (error);
10083736Srwatson		}
10183736Srwatson	}
10283736Srwatson	return (0);
10383736Srwatson}
10483736Srwatson
10583736Srwatsonint
10683736Srwatsonrestoreprivilege(void)
10783736Srwatson{
10883736Srwatson	int error;
10983736Srwatson
11083736Srwatson	error = setreuid(ROOT_UID, ROOT_UID);
11183736Srwatson	if (error)
11283736Srwatson		return (error);
11383736Srwatson
11483736Srwatson	error = setregid(WHEEL_GID, WHEEL_GID);
11583736Srwatson	if (error)
11683736Srwatson		return (error);
11783736Srwatson
11883736Srwatson	return (0);
11983736Srwatson}
12083736Srwatson
12183736Srwatsonint
12283736Srwatsonreportprivilege(char *message)
12383736Srwatson{
12483736Srwatson	uid_t euid, ruid, suid;
12583736Srwatson	gid_t egid, rgid, sgid;
12683736Srwatson	int error;
12783736Srwatson
12883736Srwatson	error = getresuid(&ruid, &euid, &suid);
12983736Srwatson	if (error) {
13083736Srwatson		perror("getresuid");
13183736Srwatson		return (error);
13283736Srwatson	}
13383736Srwatson
13483736Srwatson	error = getresgid(&rgid, &egid, &sgid);
13583736Srwatson	if (error) {
13683736Srwatson		perror("getresgid");
13783736Srwatson		return (error);
13883736Srwatson	}
13983736Srwatson
14083736Srwatson	if (message)
14183736Srwatson		printf("%s: ", message);
14283736Srwatson	printf("ruid: %d, euid: %d, suid: %d,     ", ruid, euid, suid);
14383736Srwatson	printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);
14483736Srwatson
14583736Srwatson	return (0);
14683736Srwatson}
14783736Srwatson
14883736Srwatsonint
14983736Srwatsoncleanup(void)
15083736Srwatson{
15183736Srwatson	int i, error;
15283736Srwatson
15383736Srwatson	error = restoreprivilege();
15483736Srwatson	if (error) {
15583736Srwatson		perror("restoreprivilege");
15683736Srwatson		return (error);
15783736Srwatson	}
15883736Srwatson
15983736Srwatson	for (i = 0; i < fd_list_count; i++) {
16083736Srwatson		error = unlink(fd_list[i].fd_name);
16183736Srwatson		if (error)
16283736Srwatson			return (error);
16383736Srwatson	}
16483736Srwatson
16583736Srwatson	return (0);
16683736Srwatson}
16783736Srwatson
16883736Srwatsonint
16983736Srwatsonmain(int argc, char *argv[])
17083736Srwatson{
17183736Srwatson	int error, errorseen;
17283736Srwatson
17383736Srwatson	if (geteuid() != 0) {
17483736Srwatson		fprintf(stderr, "testaccess must run as root.\n");
17583736Srwatson		exit (EXIT_FAILURE);
17683736Srwatson	}
17783736Srwatson
17883736Srwatson	error = setup();
17983736Srwatson	if (error) {
18083736Srwatson		cleanup();
18183736Srwatson		exit (EXIT_FAILURE);
18283736Srwatson	}
18383736Srwatson
18483736Srwatson	/* Make sure saved uid is set appropriately. */
18583736Srwatson	error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);
18683736Srwatson	if (error) {
18783736Srwatson		perror("setresuid");
18883736Srwatson		cleanup();
18983736Srwatson	}
19083736Srwatson
19183736Srwatson	/* Clear out additional groups. */
19283736Srwatson	error = setgroups(0, NULL);
19383736Srwatson	if (error) {
19483736Srwatson		perror("setgroups");
19583736Srwatson		cleanup();
19683736Srwatson	}
19783736Srwatson
19883736Srwatson	/* Make sure saved gid is set appropriately. */
19983736Srwatson	error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);
20083736Srwatson	if (error) {
20183736Srwatson		perror("setresgid");
20283736Srwatson		cleanup();
20383736Srwatson	}
20483736Srwatson
20583736Srwatson	/*
20683736Srwatson	 * UID-only tests.
20783736Srwatson	 */
20883736Srwatson
20983736Srwatson	/* Check that saved uid is not used */
21083736Srwatson	error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
21183736Srwatson	if (error) {
21283736Srwatson		perror("setresuid.1");
21383736Srwatson		cleanup();
21483736Srwatson		exit (EXIT_FAILURE);
21583736Srwatson	}
21683736Srwatson
21783736Srwatson	errorseen = 0;
21883736Srwatson
21983736Srwatson	error = access("test1", R_OK);
22083736Srwatson	if (!error) {
22183736Srwatson		fprintf(stderr, "saved uid used instead of real uid\n");
22283736Srwatson		errorseen++;
22383736Srwatson	}
22483736Srwatson
22583736Srwatson#ifdef EACCESS_AVAILABLE
22683794Srwatson	error = eaccess("test1", R_OK);
22783736Srwatson	if (!error) {
22883736Srwatson		fprintf(stderr, "saved uid used instead of effective uid\n");
22983736Srwatson		errorseen++;
23083736Srwatson	}
23183736Srwatson#endif
23283736Srwatson
23383736Srwatson	error = restoreprivilege();
23483736Srwatson	if (error) {
23583736Srwatson		perror("restoreprivilege");
23683736Srwatson		cleanup();
23783736Srwatson		exit (EXIT_FAILURE);
23883736Srwatson	}
23983736Srwatson
24083736Srwatson	error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);
24183736Srwatson	if (error) {
24283736Srwatson		perror("setresid.2");
24383736Srwatson		cleanup();
24483736Srwatson		exit (EXIT_FAILURE);
24583736Srwatson	}
24683736Srwatson
24783736Srwatson	/* Check that the real uid is used, not the effective uid */
24883736Srwatson	error = access("test2", R_OK);
24983736Srwatson	if (error) {
25083736Srwatson		fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
25183736Srwatson		errorseen++;
25283736Srwatson	}
25383736Srwatson
25483736Srwatson#ifdef EACCESS_AVAILABLE
25583736Srwatson	/* Check that the effective uid is used, not the real uid */
25683736Srwatson	error = eaccess("test3", R_OK);
25783736Srwatson	if (error) {
25883736Srwatson		fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
25983736Srwatson		errorseen++;
26083736Srwatson	}
26183736Srwatson#endif
26283736Srwatson
26383736Srwatson	/* Check that the real uid is used, not the effective uid */
26483736Srwatson	error = access("test3", R_OK);
26583736Srwatson	if (!error) {
26683736Srwatson		fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
26783736Srwatson		errorseen++;
26883736Srwatson	}
26983736Srwatson
27083736Srwatson#ifdef EACCESS_AVAILABLE
27183736Srwatson	/* Check that the effective uid is used, not the real uid */
27283736Srwatson	error = eaccess("test2", R_OK);
27383794Srwatson	if (!error) {
27483736Srwatson		fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
27583736Srwatson		errorseen++;
27683736Srwatson	}
27783736Srwatson#endif
27883736Srwatson
27983736Srwatson	error = restoreprivilege();
28083736Srwatson	if (error) {
28183736Srwatson		perror("restoreprivilege");
28283736Srwatson		cleanup();
28383736Srwatson		exit (EXIT_FAILURE);
28483736Srwatson	}
28583736Srwatson
28683736Srwatson	error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);
28783736Srwatson	if (error) {
28883736Srwatson		perror("setresgid.1");
28983736Srwatson		cleanup();
29083736Srwatson		exit (EXIT_FAILURE);
29183736Srwatson	}
29283736Srwatson
29383736Srwatson	/* Set non-root effective uid to avoid excess privilege. */
29483736Srwatson	error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);
29583736Srwatson	if (error) {
29683736Srwatson		perror("setresuid.3");
29783736Srwatson		cleanup();
29883736Srwatson		exit (EXIT_FAILURE);
29983736Srwatson	}
30083736Srwatson
30183736Srwatson	/* Check that the saved gid is not used */
30283736Srwatson	error = access("test4", R_OK);
30383736Srwatson	if (!error) {
30483736Srwatson		fprintf(stderr, "saved gid used instead of real gid\n");
30583736Srwatson	}
30683736Srwatson
30783736Srwatson#ifdef EACCESS_AVAILABLE
30883736Srwatson	error = eaccess("test4", R_OK);
30983736Srwatson	if (!error) {
31083736Srwatson		fprintf(stderr, "saved gid used instead of effective gid\n");
31183736Srwatson		errorseen++;
31283736Srwatson	}
31383736Srwatson#endif
31483736Srwatson
31583736Srwatson	/* Check that the real gid is used, not the effective gid */
31683736Srwatson	error = access("test5", R_OK);
31783736Srwatson	if (error) {
31883736Srwatson		fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
31983736Srwatson		errorseen++;
32083736Srwatson	}
32183736Srwatson
32283736Srwatson#ifdef EACCESS_AVAILABLE
32383736Srwatson	/* Check that the effective gid is used, not the real gid */
32483736Srwatson	error = eaccess("test6", R_OK);
32583736Srwatson	if (error) {
32683736Srwatson		fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
32783736Srwatson		errorseen++;
32883736Srwatson	}
32983736Srwatson#endif
33083736Srwatson
33183736Srwatson	/* Check that the real gid is used, not the effective gid */
33283736Srwatson	error = access("test6", R_OK);
33383736Srwatson	if (!error) {
33483736Srwatson		fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
33583736Srwatson		errorseen++;
33683736Srwatson	}
33783736Srwatson
33883736Srwatson#ifdef EACCESS_AVAILABLE
33983736Srwatson	/* Check that the effective gid is used, not the real gid */
34083736Srwatson	error = eaccess("test5", R_OK);
34183736Srwatson	if (!error) {
34283736Srwatson		fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
34383736Srwatson		errorseen++;
34483736Srwatson	}
34583736Srwatson#endif
34683736Srwatson
34783736Srwatson	fprintf(stderr, "%d errors seen.\n", errorseen);
34883736Srwatson
34983736Srwatson	/*
35083736Srwatson	 * All tests done, restore and clean up
35183736Srwatson	 */
35283736Srwatson
35383736Srwatson	error = cleanup();
35483736Srwatson	if (error) {
35583736Srwatson		perror("cleanup");
35683736Srwatson		exit (EXIT_FAILURE);
35783736Srwatson	}
35883736Srwatson
35983736Srwatson	exit (EXIT_SUCCESS);
36083736Srwatson}
361