1274f7445SRobert Watson /*- 2274f7445SRobert Watson * Copyright (c) 2001 Robert N. M. Watson 3274f7445SRobert Watson * All rights reserved. 4274f7445SRobert Watson * 5274f7445SRobert Watson * Redistribution and use in source and binary forms, with or without 6274f7445SRobert Watson * modification, are permitted provided that the following conditions 7274f7445SRobert Watson * are met: 8274f7445SRobert Watson * 1. Redistributions of source code must retain the above copyright 9274f7445SRobert Watson * notice, this list of conditions and the following disclaimer. 10274f7445SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 11274f7445SRobert Watson * notice, this list of conditions and the following disclaimer in the 12274f7445SRobert Watson * documentation and/or other materials provided with the distribution. 13274f7445SRobert Watson * 14274f7445SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15274f7445SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16274f7445SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17274f7445SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18274f7445SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19274f7445SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20274f7445SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21274f7445SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22274f7445SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23274f7445SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24274f7445SRobert Watson * SUCH DAMAGE. 25274f7445SRobert Watson * 26274f7445SRobert Watson * $FreeBSD$ 27274f7445SRobert Watson */ 28274f7445SRobert Watson 29274f7445SRobert Watson #include <sys/types.h> 30274f7445SRobert Watson #include <sys/ptrace.h> 31274f7445SRobert Watson #include <sys/time.h> 32274f7445SRobert Watson #include <sys/resource.h> 33274f7445SRobert Watson #include <sys/syscall.h> 34274f7445SRobert Watson #include <sys/wait.h> 35274f7445SRobert Watson 36274f7445SRobert Watson #include <assert.h> 37274f7445SRobert Watson #include <errno.h> 38274f7445SRobert Watson #include <signal.h> 39274f7445SRobert Watson #include <stdio.h> 40274f7445SRobert Watson #include <string.h> 41274f7445SRobert Watson #include <unistd.h> 42274f7445SRobert Watson 43274f7445SRobert Watson /* 44274f7445SRobert Watson * Relevant parts of a process credential. 45274f7445SRobert Watson */ 46274f7445SRobert Watson struct cred { 47274f7445SRobert Watson uid_t cr_euid, cr_ruid, cr_svuid; 48274f7445SRobert Watson int cr_issetugid; 49274f7445SRobert Watson }; 50274f7445SRobert Watson 51274f7445SRobert Watson /* 52274f7445SRobert Watson * Description of a scenario. 53274f7445SRobert Watson */ 54274f7445SRobert Watson struct scenario { 55274f7445SRobert Watson struct cred *sc_cred1, *sc_cred2; /* credentials of p1 and p2 */ 56274f7445SRobert Watson int sc_candebug_errno; /* desired ptrace failure */ 57bacff58cSRobert Watson int sc_cansighup_errno; /* desired SIGHUP failure */ 58bacff58cSRobert Watson int sc_cansigsegv_errno; /* desired SIGSEGV failure */ 59274f7445SRobert Watson int sc_cansee_errno; /* desired getprio failure */ 60274f7445SRobert Watson int sc_cansched_errno; /* desired setprio failure */ 61274f7445SRobert Watson char *sc_name; /* test name */ 62274f7445SRobert Watson }; 63274f7445SRobert Watson 64274f7445SRobert Watson /* 65274f7445SRobert Watson * Table of relevant credential combinations. 66274f7445SRobert Watson */ 67274f7445SRobert Watson static struct cred creds[] = { 68274f7445SRobert Watson /* euid ruid svuid issetugid */ 69274f7445SRobert Watson /* 0 */ { 0, 0, 0, 0 }, /* privileged */ 70274f7445SRobert Watson /* 1 */ { 0, 0, 0, 1 }, /* privileged + issetugid */ 71274f7445SRobert Watson /* 2 */ { 1000, 1000, 1000, 0 }, /* unprivileged1 */ 72274f7445SRobert Watson /* 3 */ { 1000, 1000, 1000, 1 }, /* unprivileged1 + issetugid */ 73274f7445SRobert Watson /* 4 */ { 1001, 1001, 1001, 0 }, /* unprivileged2 */ 74274f7445SRobert Watson /* 5 */ { 1001, 1001, 1001, 1 }, /* unprivileged2 + issetugid */ 75274f7445SRobert Watson /* 6 */ { 1000, 0, 0, 0 }, /* daemon1 */ 76274f7445SRobert Watson /* 7 */ { 1000, 0, 0, 1 }, /* daemon1 + issetugid */ 77274f7445SRobert Watson /* 8 */ { 1001, 0, 0, 0 }, /* daemon2 */ 78274f7445SRobert Watson /* 9 */ { 1001, 0, 0, 1 }, /* daemon2 + issetugid */ 79274f7445SRobert Watson /* 10 */{ 0, 1000, 1000, 0 }, /* setuid1 */ 80274f7445SRobert Watson /* 11 */{ 0, 1000, 1000, 1 }, /* setuid1 + issetugid */ 81274f7445SRobert Watson /* 12 */{ 0, 1001, 1001, 0 }, /* setuid2 */ 82274f7445SRobert Watson /* 13 */{ 0, 1001, 1001, 1 }, /* setuid2 + issetugid */ 83274f7445SRobert Watson }; 84274f7445SRobert Watson 85274f7445SRobert Watson /* 86274f7445SRobert Watson * Table of scenarios. 87274f7445SRobert Watson */ 88274f7445SRobert Watson static const struct scenario scenarios[] = { 89bacff58cSRobert Watson /* cred1 cred2 debug sighup sigsegv see sched name */ 90bacff58cSRobert Watson { &creds[0], &creds[0], 0, 0, 0, 0, 0, "0. priv on priv"}, 91bacff58cSRobert Watson { &creds[0], &creds[1], 0, 0, 0, 0, 0, "1. priv on priv"}, 92bacff58cSRobert Watson { &creds[1], &creds[0], 0, 0, 0, 0, 0, "2. priv on priv"}, 93bacff58cSRobert Watson { &creds[1], &creds[1], 0, 0, 0, 0, 0, "3. priv on priv"}, 94274f7445SRobert Watson /* privileged on unprivileged */ 95bacff58cSRobert Watson { &creds[0], &creds[2], 0, 0, 0, 0, 0, "4. priv on unpriv1"}, 96bacff58cSRobert Watson { &creds[0], &creds[3], 0, 0, 0, 0, 0, "5. priv on unpriv1"}, 97bacff58cSRobert Watson { &creds[1], &creds[2], 0, 0, 0, 0, 0, "6. priv on unpriv1"}, 98bacff58cSRobert Watson { &creds[1], &creds[3], 0, 0, 0, 0, 0, "7. priv on unpriv1"}, 99274f7445SRobert Watson /* unprivileged on privileged */ 100bacff58cSRobert Watson { &creds[2], &creds[0], EPERM, EPERM, EPERM, 0, EPERM, "8. unpriv1 on priv"}, 101bacff58cSRobert Watson { &creds[2], &creds[1], EPERM, EPERM, EPERM, 0, EPERM, "9. unpriv1 on priv"}, 102bacff58cSRobert Watson { &creds[3], &creds[0], EPERM, EPERM, EPERM, 0, EPERM, "10. unpriv1 on priv"}, 103bacff58cSRobert Watson { &creds[3], &creds[1], EPERM, EPERM, EPERM, 0, EPERM, "11. unpriv1 on priv"}, 104274f7445SRobert Watson /* unprivileged on same unprivileged */ 105bacff58cSRobert Watson { &creds[2], &creds[2], 0, 0, 0, 0, 0, "12. unpriv1 on unpriv1"}, 106bacff58cSRobert Watson { &creds[2], &creds[3], EPERM, 0, EPERM, 0, 0, "13. unpriv1 on unpriv1"}, 107bacff58cSRobert Watson { &creds[3], &creds[2], 0, 0, 0, 0, 0, "14. unpriv1 on unpriv1"}, 108bacff58cSRobert Watson { &creds[3], &creds[3], EPERM, 0, EPERM, 0, 0, "15. unpriv1 on unpriv1"}, 109274f7445SRobert Watson /* unprivileged on different unprivileged */ 110bacff58cSRobert Watson { &creds[2], &creds[4], EPERM, EPERM, EPERM, 0, EPERM, "16. unpriv1 on unpriv2"}, 111bacff58cSRobert Watson { &creds[2], &creds[5], EPERM, EPERM, EPERM, 0, EPERM, "17. unpriv1 on unpriv2"}, 112bacff58cSRobert Watson { &creds[3], &creds[4], EPERM, EPERM, EPERM, 0, EPERM, "18. unpriv1 on unpriv2"}, 113bacff58cSRobert Watson { &creds[3], &creds[5], EPERM, EPERM, EPERM, 0, EPERM, "19. unpriv1 on unpriv2"}, 114274f7445SRobert Watson /* unprivileged on daemon, same */ 115bacff58cSRobert Watson { &creds[2], &creds[6], EPERM, EPERM, EPERM, 0, EPERM, "20. unpriv1 on daemon1"}, 116bacff58cSRobert Watson { &creds[2], &creds[7], EPERM, EPERM, EPERM, 0, EPERM, "21. unpriv1 on daemon1"}, 117bacff58cSRobert Watson { &creds[3], &creds[6], EPERM, EPERM, EPERM, 0, EPERM, "22. unpriv1 on daemon1"}, 118bacff58cSRobert Watson { &creds[3], &creds[7], EPERM, EPERM, EPERM, 0, EPERM, "23. unpriv1 on daemon1"}, 119274f7445SRobert Watson /* unprivileged on daemon, different */ 120bacff58cSRobert Watson { &creds[2], &creds[8], EPERM, EPERM, EPERM, 0, EPERM, "24. unpriv1 on daemon2"}, 121bacff58cSRobert Watson { &creds[2], &creds[9], EPERM, EPERM, EPERM, 0, EPERM, "25. unpriv1 on daemon2"}, 122bacff58cSRobert Watson { &creds[3], &creds[8], EPERM, EPERM, EPERM, 0, EPERM, "26. unpriv1 on daemon2"}, 123bacff58cSRobert Watson { &creds[3], &creds[9], EPERM, EPERM, EPERM, 0, EPERM, "27. unpriv1 on daemon2"}, 124274f7445SRobert Watson /* unprivileged on setuid, same */ 125bacff58cSRobert Watson { &creds[2], &creds[10], EPERM, 0, 0, 0, 0, "28. unpriv1 on setuid1"}, 126bacff58cSRobert Watson { &creds[2], &creds[11], EPERM, 0, EPERM, 0, 0, "29. unpriv1 on setuid1"}, 127bacff58cSRobert Watson { &creds[3], &creds[10], EPERM, 0, 0, 0, 0, "30. unpriv1 on setuid1"}, 128bacff58cSRobert Watson { &creds[3], &creds[11], EPERM, 0, EPERM, 0, 0, "31. unpriv1 on setuid1"}, 129274f7445SRobert Watson /* unprivileged on setuid, different */ 130bacff58cSRobert Watson { &creds[2], &creds[12], EPERM, EPERM, EPERM, 0, EPERM, "32. unpriv1 on setuid2"}, 131bacff58cSRobert Watson { &creds[2], &creds[13], EPERM, EPERM, EPERM, 0, EPERM, "33. unpriv1 on setuid2"}, 132bacff58cSRobert Watson { &creds[3], &creds[12], EPERM, EPERM, EPERM, 0, EPERM, "34. unpriv1 on setuid2"}, 133bacff58cSRobert Watson { &creds[3], &creds[13], EPERM, EPERM, EPERM, 0, EPERM, "35. unpriv1 on setuid2"}, 134274f7445SRobert Watson }; 135274f7445SRobert Watson int scenarios_count = sizeof(scenarios) / sizeof(struct scenario); 136274f7445SRobert Watson 137274f7445SRobert Watson /* 138274f7445SRobert Watson * Convert an error number to a compact string representation. For now, 139274f7445SRobert Watson * implement only the error numbers we are likely to see. 140274f7445SRobert Watson */ 141274f7445SRobert Watson static char * 142274f7445SRobert Watson errno_to_string(int error) 143274f7445SRobert Watson { 144274f7445SRobert Watson 145274f7445SRobert Watson switch (error) { 146274f7445SRobert Watson case EPERM: 147274f7445SRobert Watson return ("EPERM"); 148274f7445SRobert Watson case EACCES: 149274f7445SRobert Watson return ("EACCES"); 150274f7445SRobert Watson case EINVAL: 151274f7445SRobert Watson return ("EINVAL"); 152274f7445SRobert Watson case ENOSYS: 153274f7445SRobert Watson return ("ENOSYS"); 154274f7445SRobert Watson case ESRCH: 155274f7445SRobert Watson return ("ESRCH"); 156bacff58cSRobert Watson case EOPNOTSUPP: 157bacff58cSRobert Watson return ("EOPNOTSUPP"); 158274f7445SRobert Watson case 0: 159274f7445SRobert Watson return ("0"); 160274f7445SRobert Watson default: 161274f7445SRobert Watson return ("unknown"); 162274f7445SRobert Watson } 163274f7445SRobert Watson } 164274f7445SRobert Watson 165274f7445SRobert Watson /* 166274f7445SRobert Watson * Return a process credential describing the current process. 167274f7445SRobert Watson */ 168274f7445SRobert Watson static int 169274f7445SRobert Watson cred_get(struct cred *cred) 170274f7445SRobert Watson { 171274f7445SRobert Watson int error; 172274f7445SRobert Watson 173274f7445SRobert Watson error = getresuid(&cred->cr_ruid, &cred->cr_euid, &cred->cr_svuid); 174274f7445SRobert Watson if (error) 175274f7445SRobert Watson return (error); 176274f7445SRobert Watson 177274f7445SRobert Watson cred->cr_issetugid = issetugid(); 178274f7445SRobert Watson 179274f7445SRobert Watson return (0); 180274f7445SRobert Watson } 181274f7445SRobert Watson 182274f7445SRobert Watson /* 183274f7445SRobert Watson * Userland stub for __setsugid() to take into account possible presence 184274f7445SRobert Watson * in C library, kernel, et al. 185274f7445SRobert Watson */ 186274f7445SRobert Watson int 187274f7445SRobert Watson setugid(int flag) 188274f7445SRobert Watson { 189274f7445SRobert Watson 190274f7445SRobert Watson #ifdef SETSUGID_SUPPORTED 191274f7445SRobert Watson return (__setugid(flag)); 192274f7445SRobert Watson #else 193274f7445SRobert Watson #ifdef SETSUGID_SUPPORTED_BUT_NO_LIBC_STUB 194274f7445SRobert Watson return (syscall(374, flag)); 195274f7445SRobert Watson #else 196274f7445SRobert Watson return (ENOSYS); 197274f7445SRobert Watson #endif 198274f7445SRobert Watson #endif 199274f7445SRobert Watson } 200274f7445SRobert Watson 201274f7445SRobert Watson /* 202274f7445SRobert Watson * Set the current process's credentials to match the passed credential. 203274f7445SRobert Watson */ 204274f7445SRobert Watson static int 205274f7445SRobert Watson cred_set(struct cred *cred) 206274f7445SRobert Watson { 207274f7445SRobert Watson int error; 208274f7445SRobert Watson 209274f7445SRobert Watson error = setresuid(cred->cr_ruid, cred->cr_euid, cred->cr_svuid); 210274f7445SRobert Watson if (error) 211274f7445SRobert Watson return (error); 212274f7445SRobert Watson 213274f7445SRobert Watson error = setugid(cred->cr_issetugid); 214274f7445SRobert Watson if (error) { 215274f7445SRobert Watson perror("__setugid"); 216274f7445SRobert Watson return (error); 217274f7445SRobert Watson } 218274f7445SRobert Watson 219274f7445SRobert Watson #ifdef CHECK_CRED_SET 220274f7445SRobert Watson { 221274f7445SRobert Watson uid_t ruid, euid, svuid; 222274f7445SRobert Watson error = getresuid(&ruid, &euid, &svuid); 223274f7445SRobert Watson if (error) { 224274f7445SRobert Watson perror("getresuid"); 225274f7445SRobert Watson return (-1); 226274f7445SRobert Watson } 227274f7445SRobert Watson assert(ruid == cred->cr_ruid); 228274f7445SRobert Watson assert(euid == cred->cr_euid); 229274f7445SRobert Watson assert(svuid == cred->cr_svuid); 230274f7445SRobert Watson assert(cred->cr_issetugid == issetugid()); 231274f7445SRobert Watson } 232274f7445SRobert Watson #endif /* !CHECK_CRED_SET */ 233274f7445SRobert Watson 234274f7445SRobert Watson return (0); 235274f7445SRobert Watson } 236274f7445SRobert Watson 237274f7445SRobert Watson /* 238274f7445SRobert Watson * Print the passed process credential to the passed I/O stream. 239274f7445SRobert Watson */ 240274f7445SRobert Watson static void 241274f7445SRobert Watson cred_print(FILE *output, struct cred *cred) 242274f7445SRobert Watson { 243274f7445SRobert Watson 244274f7445SRobert Watson fprintf(output, "(e:%d r:%d s:%d P_SUGID:%d)", cred->cr_euid, 245274f7445SRobert Watson cred->cr_ruid, cred->cr_svuid, cred->cr_issetugid); 246274f7445SRobert Watson } 247274f7445SRobert Watson 248274f7445SRobert Watson #define LOOP_PTRACE 0 249bacff58cSRobert Watson #define LOOP_SIGHUP 1 250bacff58cSRobert Watson #define LOOP_SIGSEGV 2 251bacff58cSRobert Watson #define LOOP_SEE 3 252bacff58cSRobert Watson #define LOOP_SCHED 4 253274f7445SRobert Watson #define LOOP_MAX LOOP_SCHED 254274f7445SRobert Watson 255274f7445SRobert Watson /* 256274f7445SRobert Watson * Enact a scenario by looping through the four test cases for the scenario, 257274f7445SRobert Watson * spawning off pairs of processes with the desired credentials, and 258274f7445SRobert Watson * reporting results to stdout. 259274f7445SRobert Watson */ 260274f7445SRobert Watson static int 261274f7445SRobert Watson enact_scenario(int scenario) 262274f7445SRobert Watson { 263274f7445SRobert Watson pid_t pid1, pid2; 264274f7445SRobert Watson char *name; 265274f7445SRobert Watson int error, desirederror, loop; 266274f7445SRobert Watson 267274f7445SRobert Watson for (loop = 0; loop < LOOP_MAX+1; loop++) { 268274f7445SRobert Watson /* 269274f7445SRobert Watson * Spawn the first child, target of the operation. 270274f7445SRobert Watson */ 271274f7445SRobert Watson pid1 = fork(); 272274f7445SRobert Watson switch (pid1) { 273274f7445SRobert Watson case -1: 274274f7445SRobert Watson return (-1); 275274f7445SRobert Watson case 0: 276274f7445SRobert Watson /* child */ 277274f7445SRobert Watson error = cred_set(scenarios[scenario].sc_cred2); 278274f7445SRobert Watson if (error) { 279274f7445SRobert Watson perror("cred_set"); 280274f7445SRobert Watson return (error); 281274f7445SRobert Watson } 282274f7445SRobert Watson /* 200 seconds should be plenty of time. */ 283274f7445SRobert Watson sleep(200); 284274f7445SRobert Watson exit(0); 285274f7445SRobert Watson default: 286274f7445SRobert Watson /* parent */ 287274f7445SRobert Watson } 288274f7445SRobert Watson 289274f7445SRobert Watson /* 290274f7445SRobert Watson * XXX 291274f7445SRobert Watson * This really isn't ideal -- give proc 1 a chance to set 292274f7445SRobert Watson * its credentials, or we may get spurious errors. Really, 293274f7445SRobert Watson * some for of IPC should be used to allow the parent to 294274f7445SRobert Watson * wait for the first child to be ready before spawning 295274f7445SRobert Watson * the second child. 296274f7445SRobert Watson */ 297274f7445SRobert Watson sleep(1); 298274f7445SRobert Watson 299274f7445SRobert Watson /* 300274f7445SRobert Watson * Spawn the second child, source of the operation. 301274f7445SRobert Watson */ 302274f7445SRobert Watson pid2 = fork(); 303274f7445SRobert Watson switch (pid2) { 304274f7445SRobert Watson case -1: 305274f7445SRobert Watson return (-1); 306274f7445SRobert Watson 307274f7445SRobert Watson case 0: 308274f7445SRobert Watson /* child */ 309274f7445SRobert Watson error = cred_set(scenarios[scenario].sc_cred1); 310274f7445SRobert Watson if (error) { 311274f7445SRobert Watson perror("cred_set"); 312274f7445SRobert Watson return (error); 313274f7445SRobert Watson } 314274f7445SRobert Watson 315274f7445SRobert Watson /* 316274f7445SRobert Watson * Initialize errno to zero so as to catch any 317274f7445SRobert Watson * generated errors. In each case, perform the 318274f7445SRobert Watson * operation. Preserve the error number for later 319274f7445SRobert Watson * use so it doesn't get stomped on by any I/O. 320274f7445SRobert Watson * Determine the desired error for the given case 321274f7445SRobert Watson * by extracting it from the scenario table. 322274f7445SRobert Watson * Initialize a function name string for output 323274f7445SRobert Watson * prettiness. 324274f7445SRobert Watson */ 325274f7445SRobert Watson errno = 0; 326274f7445SRobert Watson switch (loop) { 327274f7445SRobert Watson case LOOP_PTRACE: 328274f7445SRobert Watson error = ptrace(PT_ATTACH, pid1, NULL, 0); 329274f7445SRobert Watson error = errno; 330274f7445SRobert Watson name = "ptrace"; 331274f7445SRobert Watson desirederror = 332274f7445SRobert Watson scenarios[scenario].sc_candebug_errno; 333274f7445SRobert Watson break; 334bacff58cSRobert Watson case LOOP_SIGHUP: 335274f7445SRobert Watson error = kill(pid1, SIGHUP); 336274f7445SRobert Watson error = errno; 337bacff58cSRobert Watson name = "sighup"; 338274f7445SRobert Watson desirederror = 339bacff58cSRobert Watson scenarios[scenario].sc_cansighup_errno; 340bacff58cSRobert Watson break; 341bacff58cSRobert Watson case LOOP_SIGSEGV: 342bacff58cSRobert Watson error = kill(pid1, SIGSEGV); 343bacff58cSRobert Watson error = errno; 344bacff58cSRobert Watson name = "sigsegv"; 345bacff58cSRobert Watson desirederror = 346bacff58cSRobert Watson scenarios[scenario].sc_cansigsegv_errno; 347274f7445SRobert Watson break; 348274f7445SRobert Watson case LOOP_SEE: 349274f7445SRobert Watson getpriority(PRIO_PROCESS, pid1); 350274f7445SRobert Watson error = errno; 351274f7445SRobert Watson name = "see"; 352274f7445SRobert Watson desirederror = 353274f7445SRobert Watson scenarios[scenario].sc_cansee_errno; 354274f7445SRobert Watson break; 355274f7445SRobert Watson case LOOP_SCHED: 356274f7445SRobert Watson error = setpriority(PRIO_PROCESS, pid1, 357274f7445SRobert Watson 0); 358274f7445SRobert Watson error = errno; 359274f7445SRobert Watson name = "sched"; 360274f7445SRobert Watson desirederror = 361274f7445SRobert Watson scenarios[scenario].sc_cansched_errno; 362274f7445SRobert Watson break; 363274f7445SRobert Watson default: 364274f7445SRobert Watson name = "broken"; 365274f7445SRobert Watson } 366274f7445SRobert Watson 367274f7445SRobert Watson if (error != desirederror) { 368274f7445SRobert Watson fprintf(stdout, 369274f7445SRobert Watson "[%s].%s: expected %s, got %s\n ", 370274f7445SRobert Watson scenarios[scenario].sc_name, name, 371274f7445SRobert Watson errno_to_string(desirederror), 372274f7445SRobert Watson errno_to_string(error)); 373274f7445SRobert Watson cred_print(stdout, 374274f7445SRobert Watson scenarios[scenario].sc_cred1); 375274f7445SRobert Watson cred_print(stdout, 376274f7445SRobert Watson scenarios[scenario].sc_cred2); 377274f7445SRobert Watson fprintf(stdout, "\n"); 378274f7445SRobert Watson } 379274f7445SRobert Watson 380274f7445SRobert Watson exit(0); 381274f7445SRobert Watson 382274f7445SRobert Watson default: 383274f7445SRobert Watson /* parent */ 384274f7445SRobert Watson } 385274f7445SRobert Watson 386274f7445SRobert Watson error = waitpid(pid2, NULL, 0); 387274f7445SRobert Watson /* 388274f7445SRobert Watson * Once pid2 has died, it's safe to kill pid1, if it's still 389274f7445SRobert Watson * alive. Mask signal failure in case the test actually 390274f7445SRobert Watson * killed pid1 (not unlikely: can occur in both signal and 391274f7445SRobert Watson * ptrace cases). 392274f7445SRobert Watson */ 393274f7445SRobert Watson kill(pid1, SIGKILL); 394274f7445SRobert Watson error = waitpid(pid2, NULL, 0); 395274f7445SRobert Watson } 396274f7445SRobert Watson 397274f7445SRobert Watson return (0); 398274f7445SRobert Watson } 399274f7445SRobert Watson 400274f7445SRobert Watson void 401274f7445SRobert Watson enact_scenarios(void) 402274f7445SRobert Watson { 403274f7445SRobert Watson int i, error; 404274f7445SRobert Watson 405274f7445SRobert Watson for (i = 0; i < scenarios_count; i++) { 406274f7445SRobert Watson error = enact_scenario(i); 407274f7445SRobert Watson if (error) 408274f7445SRobert Watson perror("enact_scenario"); 409274f7445SRobert Watson } 410274f7445SRobert Watson } 411