1 /*- 2 * Copyright (c) 2001 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Written at NAI Labs at Network Associates by Robert Watson for the 27 * TrustedBSD Project. 28 * 29 * Work sponsored by Defense Advanced Research Projects Agency under the 30 * CHATS research program, CBOSS project. 31 * 32 * $FreeBSD$ 33 */ 34 35 #include <sys/types.h> 36 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 43 /* 44 * Regression test to check some basic cases and see if access() and 45 * eaccess() are using the correct portions of the process credential. 46 * This test relies on running with privilege, and on UFS filesystem 47 * semantics. Running the test in other environments may result 48 * in incorrect failure identification. 49 * 50 * Note that this may also break if filesystem access control is 51 * broken, or if the ability to check and set credentials is broken. 52 * 53 * Note that this test uses two hard-coded non-root UIDs; on multi-user 54 * systems, these UIDs may be in use by an untrusted user, in which 55 * case those users could interfere with the test. 56 */ 57 58 #define ROOT_UID (uid_t)0 59 #define WHEEL_GID (gid_t)0 60 #define TEST_UID_ONE (uid_t)500 61 #define TEST_GID_ONE (gid_t)500 62 #define TEST_UID_TWO (uid_t)501 63 #define TEST_GID_TWO (gid_t)501 64 65 struct file_description { 66 char *fd_name; 67 uid_t fd_owner; 68 gid_t fd_group; 69 mode_t fd_mode; 70 }; 71 72 static struct file_description fd_list[] = { 73 {"test1", ROOT_UID, WHEEL_GID, 0400}, 74 {"test2", TEST_UID_ONE, WHEEL_GID,0400}, 75 {"test3", TEST_UID_TWO, WHEEL_GID, 0400}, 76 {"test4", ROOT_UID, WHEEL_GID, 0040}, 77 {"test5", ROOT_UID, TEST_GID_ONE, 0040}, 78 {"test6", ROOT_UID, TEST_GID_TWO, 0040}}; 79 80 static int fd_list_count = sizeof(fd_list) / 81 sizeof(struct file_description); 82 83 int 84 setup(void) 85 { 86 int i, error; 87 88 for (i = 0; i < fd_list_count; i++) { 89 error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode); 90 if (error == -1) { 91 perror("open"); 92 return (error); 93 } 94 close(error); 95 error = chown(fd_list[i].fd_name, fd_list[i].fd_owner, 96 fd_list[i].fd_group); 97 if (error) { 98 perror("chown"); 99 return (error); 100 } 101 } 102 return (0); 103 } 104 105 int 106 restoreprivilege(void) 107 { 108 int error; 109 110 error = setreuid(ROOT_UID, ROOT_UID); 111 if (error) 112 return (error); 113 114 error = setregid(WHEEL_GID, WHEEL_GID); 115 if (error) 116 return (error); 117 118 return (0); 119 } 120 121 int 122 reportprivilege(char *message) 123 { 124 uid_t euid, ruid, suid; 125 gid_t egid, rgid, sgid; 126 int error; 127 128 error = getresuid(&ruid, &euid, &suid); 129 if (error) { 130 perror("getresuid"); 131 return (error); 132 } 133 134 error = getresgid(&rgid, &egid, &sgid); 135 if (error) { 136 perror("getresgid"); 137 return (error); 138 } 139 140 if (message) 141 printf("%s: ", message); 142 printf("ruid: %d, euid: %d, suid: %d, ", ruid, euid, suid); 143 printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid); 144 145 return (0); 146 } 147 148 int 149 cleanup(void) 150 { 151 int i, error; 152 153 error = restoreprivilege(); 154 if (error) { 155 perror("restoreprivilege"); 156 return (error); 157 } 158 159 for (i = 0; i < fd_list_count; i++) { 160 error = unlink(fd_list[i].fd_name); 161 if (error) 162 return (error); 163 } 164 165 return (0); 166 } 167 168 int 169 main(int argc, char *argv[]) 170 { 171 int error, errorseen; 172 173 if (geteuid() != 0) { 174 fprintf(stderr, "testaccess must run as root.\n"); 175 exit (EXIT_FAILURE); 176 } 177 178 error = setup(); 179 if (error) { 180 cleanup(); 181 exit (EXIT_FAILURE); 182 } 183 184 /* Make sure saved uid is set appropriately. */ 185 error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID); 186 if (error) { 187 perror("setresuid"); 188 cleanup(); 189 } 190 191 /* Clear out additional groups. */ 192 error = setgroups(0, NULL); 193 if (error) { 194 perror("setgroups"); 195 cleanup(); 196 } 197 198 /* Make sure saved gid is set appropriately. */ 199 error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID); 200 if (error) { 201 perror("setresgid"); 202 cleanup(); 203 } 204 205 /* 206 * UID-only tests. 207 */ 208 209 /* Check that saved uid is not used */ 210 error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID); 211 if (error) { 212 perror("setresuid.1"); 213 cleanup(); 214 exit (EXIT_FAILURE); 215 } 216 217 errorseen = 0; 218 219 error = access("test1", R_OK); 220 if (!error) { 221 fprintf(stderr, "saved uid used instead of real uid\n"); 222 errorseen++; 223 } 224 225 #ifdef EACCESS_AVAILABLE 226 error = eaccess("test1", R_OK); 227 if (!error) { 228 fprintf(stderr, "saved uid used instead of effective uid\n"); 229 errorseen++; 230 } 231 #endif 232 233 error = restoreprivilege(); 234 if (error) { 235 perror("restoreprivilege"); 236 cleanup(); 237 exit (EXIT_FAILURE); 238 } 239 240 error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID); 241 if (error) { 242 perror("setresid.2"); 243 cleanup(); 244 exit (EXIT_FAILURE); 245 } 246 247 /* Check that the real uid is used, not the effective uid */ 248 error = access("test2", R_OK); 249 if (error) { 250 fprintf(stderr, "Effective uid was used instead of real uid in access().\n"); 251 errorseen++; 252 } 253 254 #ifdef EACCESS_AVAILABLE 255 /* Check that the effective uid is used, not the real uid */ 256 error = eaccess("test3", R_OK); 257 if (error) { 258 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n"); 259 errorseen++; 260 } 261 #endif 262 263 /* Check that the real uid is used, not the effective uid */ 264 error = access("test3", R_OK); 265 if (!error) { 266 fprintf(stderr, "Effective uid was used instead of real uid in access().\n"); 267 errorseen++; 268 } 269 270 #ifdef EACCESS_AVAILABLE 271 /* Check that the effective uid is used, not the real uid */ 272 error = eaccess("test2", R_OK); 273 if (!error) { 274 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n"); 275 errorseen++; 276 } 277 #endif 278 279 error = restoreprivilege(); 280 if (error) { 281 perror("restoreprivilege"); 282 cleanup(); 283 exit (EXIT_FAILURE); 284 } 285 286 error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID); 287 if (error) { 288 perror("setresgid.1"); 289 cleanup(); 290 exit (EXIT_FAILURE); 291 } 292 293 /* Set non-root effective uid to avoid excess privilege. */ 294 error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID); 295 if (error) { 296 perror("setresuid.3"); 297 cleanup(); 298 exit (EXIT_FAILURE); 299 } 300 301 /* Check that the saved gid is not used */ 302 error = access("test4", R_OK); 303 if (!error) { 304 fprintf(stderr, "saved gid used instead of real gid\n"); 305 } 306 307 #ifdef EACCESS_AVAILABLE 308 error = eaccess("test4", R_OK); 309 if (!error) { 310 fprintf(stderr, "saved gid used instead of effective gid\n"); 311 errorseen++; 312 } 313 #endif 314 315 /* Check that the real gid is used, not the effective gid */ 316 error = access("test5", R_OK); 317 if (error) { 318 fprintf(stderr, "Effective gid was used instead of real gid in access().\n"); 319 errorseen++; 320 } 321 322 #ifdef EACCESS_AVAILABLE 323 /* Check that the effective gid is used, not the real gid */ 324 error = eaccess("test6", R_OK); 325 if (error) { 326 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n"); 327 errorseen++; 328 } 329 #endif 330 331 /* Check that the real gid is used, not the effective gid */ 332 error = access("test6", R_OK); 333 if (!error) { 334 fprintf(stderr, "Effective gid was used instead of real gid in access().\n"); 335 errorseen++; 336 } 337 338 #ifdef EACCESS_AVAILABLE 339 /* Check that the effective gid is used, not the real gid */ 340 error = eaccess("test5", R_OK); 341 if (!error) { 342 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n"); 343 errorseen++; 344 } 345 #endif 346 347 fprintf(stderr, "%d errors seen.\n", errorseen); 348 349 /* 350 * All tests done, restore and clean up 351 */ 352 353 error = cleanup(); 354 if (error) { 355 perror("cleanup"); 356 exit (EXIT_FAILURE); 357 } 358 359 exit (EXIT_SUCCESS); 360 } 361