Path: blob/main/tools/regression/security/access/testaccess.c
48266 views
/*-1* Copyright (c) 2001 Networks Associates Technology, Inc.2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*25* Written at NAI Labs at Network Associates by Robert Watson for the26* TrustedBSD Project.27*28* Work sponsored by Defense Advanced Research Projects Agency under the29* CHATS research program, CBOSS project.30*/3132#include <sys/types.h>3334#include <errno.h>35#include <fcntl.h>36#include <stdio.h>37#include <stdlib.h>38#include <unistd.h>3940/*41* Regression test to check some basic cases and see if access() and42* eaccess() are using the correct portions of the process credential.43* This test relies on running with privilege, and on UFS filesystem44* semantics. Running the test in other environments may result45* in incorrect failure identification.46*47* Note that this may also break if filesystem access control is48* broken, or if the ability to check and set credentials is broken.49*50* Note that this test uses two hard-coded non-root UIDs; on multi-user51* systems, these UIDs may be in use by an untrusted user, in which52* case those users could interfere with the test.53*/5455#define ROOT_UID (uid_t)056#define WHEEL_GID (gid_t)057#define TEST_UID_ONE (uid_t)50058#define TEST_GID_ONE (gid_t)50059#define TEST_UID_TWO (uid_t)50160#define TEST_GID_TWO (gid_t)5016162struct file_description {63char *fd_name;64uid_t fd_owner;65gid_t fd_group;66mode_t fd_mode;67};6869static struct file_description fd_list[] = {70{"test1", ROOT_UID, WHEEL_GID, 0400},71{"test2", TEST_UID_ONE, WHEEL_GID,0400},72{"test3", TEST_UID_TWO, WHEEL_GID, 0400},73{"test4", ROOT_UID, WHEEL_GID, 0040},74{"test5", ROOT_UID, TEST_GID_ONE, 0040},75{"test6", ROOT_UID, TEST_GID_TWO, 0040}};7677static int fd_list_count = sizeof(fd_list) /78sizeof(struct file_description);7980int81setup(void)82{83int i, error;8485for (i = 0; i < fd_list_count; i++) {86error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode);87if (error == -1) {88perror("open");89return (error);90}91close(error);92error = chown(fd_list[i].fd_name, fd_list[i].fd_owner,93fd_list[i].fd_group);94if (error) {95perror("chown");96return (error);97}98}99return (0);100}101102int103restoreprivilege(void)104{105int error;106107error = setreuid(ROOT_UID, ROOT_UID);108if (error)109return (error);110111error = setregid(WHEEL_GID, WHEEL_GID);112if (error)113return (error);114115return (0);116}117118int119reportprivilege(char *message)120{121uid_t euid, ruid, suid;122gid_t egid, rgid, sgid;123int error;124125error = getresuid(&ruid, &euid, &suid);126if (error) {127perror("getresuid");128return (error);129}130131error = getresgid(&rgid, &egid, &sgid);132if (error) {133perror("getresgid");134return (error);135}136137if (message)138printf("%s: ", message);139printf("ruid: %d, euid: %d, suid: %d, ", ruid, euid, suid);140printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid);141142return (0);143}144145int146cleanup(void)147{148int i, error;149150error = restoreprivilege();151if (error) {152perror("restoreprivilege");153return (error);154}155156for (i = 0; i < fd_list_count; i++) {157error = unlink(fd_list[i].fd_name);158if (error)159return (error);160}161162return (0);163}164165int166main(int argc, char *argv[])167{168int error, errorseen;169170if (geteuid() != 0) {171fprintf(stderr, "testaccess must run as root.\n");172exit (EXIT_FAILURE);173}174175error = setup();176if (error) {177cleanup();178exit (EXIT_FAILURE);179}180181/* Make sure saved uid is set appropriately. */182error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID);183if (error) {184perror("setresuid");185cleanup();186}187188/* Clear out additional groups. */189error = setgroups(0, NULL);190if (error) {191perror("setgroups");192cleanup();193}194195/* Make sure saved gid is set appropriately. */196error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID);197if (error) {198perror("setresgid");199cleanup();200}201202/*203* UID-only tests.204*/205206/* Check that saved uid is not used */207error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);208if (error) {209perror("setresuid.1");210cleanup();211exit (EXIT_FAILURE);212}213214errorseen = 0;215216error = access("test1", R_OK);217if (!error) {218fprintf(stderr, "saved uid used instead of real uid\n");219errorseen++;220}221222#ifdef EACCESS_AVAILABLE223error = eaccess("test1", R_OK);224if (!error) {225fprintf(stderr, "saved uid used instead of effective uid\n");226errorseen++;227}228#endif229230error = restoreprivilege();231if (error) {232perror("restoreprivilege");233cleanup();234exit (EXIT_FAILURE);235}236237error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID);238if (error) {239perror("setresid.2");240cleanup();241exit (EXIT_FAILURE);242}243244/* Check that the real uid is used, not the effective uid */245error = access("test2", R_OK);246if (error) {247fprintf(stderr, "Effective uid was used instead of real uid in access().\n");248errorseen++;249}250251#ifdef EACCESS_AVAILABLE252/* Check that the effective uid is used, not the real uid */253error = eaccess("test3", R_OK);254if (error) {255fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");256errorseen++;257}258#endif259260/* Check that the real uid is used, not the effective uid */261error = access("test3", R_OK);262if (!error) {263fprintf(stderr, "Effective uid was used instead of real uid in access().\n");264errorseen++;265}266267#ifdef EACCESS_AVAILABLE268/* Check that the effective uid is used, not the real uid */269error = eaccess("test2", R_OK);270if (!error) {271fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");272errorseen++;273}274#endif275276error = restoreprivilege();277if (error) {278perror("restoreprivilege");279cleanup();280exit (EXIT_FAILURE);281}282283error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID);284if (error) {285perror("setresgid.1");286cleanup();287exit (EXIT_FAILURE);288}289290/* Set non-root effective uid to avoid excess privilege. */291error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID);292if (error) {293perror("setresuid.3");294cleanup();295exit (EXIT_FAILURE);296}297298/* Check that the saved gid is not used */299error = access("test4", R_OK);300if (!error) {301fprintf(stderr, "saved gid used instead of real gid\n");302}303304#ifdef EACCESS_AVAILABLE305error = eaccess("test4", R_OK);306if (!error) {307fprintf(stderr, "saved gid used instead of effective gid\n");308errorseen++;309}310#endif311312/* Check that the real gid is used, not the effective gid */313error = access("test5", R_OK);314if (error) {315fprintf(stderr, "Effective gid was used instead of real gid in access().\n");316errorseen++;317}318319#ifdef EACCESS_AVAILABLE320/* Check that the effective gid is used, not the real gid */321error = eaccess("test6", R_OK);322if (error) {323fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");324errorseen++;325}326#endif327328/* Check that the real gid is used, not the effective gid */329error = access("test6", R_OK);330if (!error) {331fprintf(stderr, "Effective gid was used instead of real gid in access().\n");332errorseen++;333}334335#ifdef EACCESS_AVAILABLE336/* Check that the effective gid is used, not the real gid */337error = eaccess("test5", R_OK);338if (!error) {339fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");340errorseen++;341}342#endif343344fprintf(stderr, "%d errors seen.\n", errorseen);345346/*347* All tests done, restore and clean up348*/349350error = cleanup();351if (error) {352perror("cleanup");353exit (EXIT_FAILURE);354}355356exit (EXIT_SUCCESS);357}358359360