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