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