xref: /illumos-gate/usr/src/cmd/sulogin/sulogin.c (revision b9ccdc5a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
28  *	All rights reserved.
29  *
30  *	Copyright (c) 1987, 1988 Microsoft Corporation.
31  *	All rights reserved.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 /*
37  *	sulogin - special login program exec'd from init to let user
38  *	come up single user, or go to default init state straight away.
39  *
40  *	Explain the scoop to the user, and prompt for root password or
41  *	^D. Good root password gets you single user, ^D exits sulogin,
42  *	and init will go to default init state.
43  *
44  *	If /etc/passwd is missing, or there's no entry for root,
45  *	go single user, no questions asked.
46  */
47 
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/param.h>
51 #include <sys/sysmsg_impl.h>
52 #include <sys/mkdev.h>
53 #include <sys/resource.h>
54 #include <sys/uadmin.h>
55 #include <sys/wait.h>
56 #include <sys/stermio.h>
57 #include <fcntl.h>
58 #include <termio.h>
59 #include <pwd.h>
60 #include <shadow.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <signal.h>
64 #include <siginfo.h>
65 #include <utmpx.h>
66 #include <unistd.h>
67 #include <ucontext.h>
68 #include <string.h>
69 #include <strings.h>
70 #include <deflt.h>
71 #include <limits.h>
72 #include <errno.h>
73 #include <crypt.h>
74 
75 /*
76  * Intervals to sleep after failed login
77  */
78 #ifndef SLEEPTIME
79 #define	SLEEPTIME	4	/* sleeptime before login incorrect msg */
80 #endif
81 
82 #define	SLEEPTIME_MAX	5	/* maximum sleeptime */
83 
84 /*
85  *	the name of the file containing the login defaults we deliberately
86  *	use the same file as login(1)
87  */
88 
89 #define	DEFAULT_LOGIN	"/etc/default/login"
90 #define	DEFAULT_SULOGIN	"/etc/default/sulogin"
91 #define	DEFAULT_CONSOLE	"/dev/console"
92 
93 static char	shell[]	= "/sbin/sh";
94 static char	su[]	= "/sbin/su.static";
95 static int	sleeptime	= SLEEPTIME;
96 static int	nchild = 0;
97 static pid_t	pidlist[10];
98 static pid_t	masterpid = 0;
99 static pid_t	originalpid = 0;
100 static struct sigaction	sa;
101 static struct termio	ttymodes;
102 
103 static char	*findttyname(int fd);
104 static char	*stripttyname(char *);
105 static char	*sulogin_getpass(char *);
106 static void	noop(int);
107 static void	single(const char *, char *);
108 static void	main_loop(char *, struct spwd *, boolean_t);
109 static void	parenthandler();
110 static void	termhandler(int);
111 static void	setupsigs(void);
112 static int	pathcmp(char *, char *);
113 static void	doit(char *, char *, struct spwd *);
114 static void	childcleanup(int);
115 
116 /* ARGSUSED */
117 int
118 main(int argc, char **argv)
119 {
120 	struct spwd	*shpw;
121 	int		passreq = B_TRUE;
122 	int		flags;
123 	int		fd;
124 	char		*infop, *ptr, *p;
125 	pid_t		pid;
126 	int		bufsize;
127 	struct stat	st;
128 	char		cttyname[100];
129 	char		namedlist[500];
130 	char		scratchlist[500];
131 	dev_t		cttyd;
132 
133 	if (geteuid() != 0) {
134 		(void) fprintf(stderr, "%s: must be root\n", argv[0]);
135 		return (EXIT_FAILURE);
136 	}
137 
138 	/* Do the magic to determine the children */
139 	if ((fd = open(SYSMSG, 0)) < 0)
140 		return (EXIT_FAILURE);
141 
142 	/*
143 	 * If the console supports the CIOCTTYCONSOLE ioctl, then fetch
144 	 * its console device list.  If not, then we use the default
145 	 * console name.
146 	 */
147 	if (ioctl(fd, CIOCTTYCONSOLE, &cttyd) == 0) {
148 		if ((bufsize = ioctl(fd, CIOCGETCONSOLE, NULL)) < 0)
149 			return (EXIT_FAILURE);
150 
151 		if (bufsize > 0) {
152 			if ((infop = calloc(bufsize, sizeof (char))) == NULL)
153 				return (EXIT_FAILURE);
154 
155 			if (ioctl(fd, CIOCGETCONSOLE, infop) < 0)
156 				return (EXIT_FAILURE);
157 
158 			(void) snprintf(namedlist, sizeof (namedlist), "%s %s",
159 			    DEFAULT_CONSOLE, infop);
160 		} else
161 			(void) snprintf(namedlist, sizeof (namedlist), "%s",
162 			    DEFAULT_CONSOLE);
163 	} else {
164 		(void) snprintf(namedlist, sizeof (namedlist), "%s",
165 		    DEFAULT_CONSOLE);
166 		cttyd = NODEV;
167 	}
168 
169 	/*
170 	 * The attempt to turn the controlling terminals dev_t into a string
171 	 * may not be successful, thus leaving the variable cttyname as a
172 	 * NULL.  This occurs if during boot we find
173 	 * the root partition (or some other partition)
174 	 * requires manual fsck, thus resulting in sulogin
175 	 * getting invoked.  The ioctl for CIOCTTYCONSOLE
176 	 * called above returned NODEV for cttyd
177 	 * in these cases.  NODEV gets returned when the vnode pointer
178 	 * in our session structure is NULL.  In these cases it
179 	 * must be assumed that the default console is used.
180 	 *
181 	 * See uts/common/os/session.c:cttydev().
182 	 */
183 	(void) strcpy(cttyname, DEFAULT_CONSOLE);
184 	(void) strcpy(scratchlist, namedlist);
185 	ptr = scratchlist;
186 	while (ptr != NULL) {
187 		p = strchr(ptr, ' ');
188 		if (p == NULL) {
189 			if (stat(ptr, &st))
190 				return (EXIT_FAILURE);
191 			if (st.st_rdev == cttyd)
192 				(void) strcpy(cttyname, ptr);
193 			break;
194 		}
195 		*p++ = '\0';
196 		if (stat(ptr, &st))
197 			return (EXIT_FAILURE);
198 		if (st.st_rdev == cttyd) {
199 			(void) strcpy(cttyname, ptr);
200 			break;
201 		}
202 		ptr = p;
203 	}
204 
205 	/*
206 	 * Use the same value of SLEEPTIME that login(1) uses.  This
207 	 * is obtained by reading the file /etc/default/login using
208 	 * the def*() functions.
209 	 */
210 
211 	if (defopen(DEFAULT_LOGIN) == 0) {
212 
213 		/* ignore case */
214 
215 		flags = defcntl(DC_GETFLAGS, 0);
216 		TURNOFF(flags, DC_CASE);
217 		(void) defcntl(DC_SETFLAGS, flags);
218 
219 		if ((ptr = defread("SLEEPTIME=")) != NULL)
220 			sleeptime = atoi(ptr);
221 
222 		if (sleeptime < 0 || sleeptime > SLEEPTIME_MAX)
223 			sleeptime = SLEEPTIME;
224 
225 		(void) defopen(NULL);	/* closes DEFAULT_LOGIN */
226 	}
227 
228 	/*
229 	 * Use our own value of PASSREQ, separate from the one login(1) uses.
230 	 * This is obtained by reading the file /etc/default/sulogin using
231 	 * the def*() functions.
232 	 */
233 
234 	if (defopen(DEFAULT_SULOGIN) == 0) {
235 		if ((ptr = defread("PASSREQ=")) != NULL)
236 			if (strcmp("NO", ptr) == 0)
237 				passreq = B_FALSE;
238 
239 		(void) defopen(NULL);	/* closes DEFAULT_SULOGIN */
240 	}
241 
242 	if (passreq == B_FALSE)
243 		single(shell, NULL);
244 
245 	/*
246 	 * if no 'root' entry in /etc/shadow, give maint. mode single
247 	 * user shell prompt
248 	 */
249 	setspent();
250 	if ((shpw = getspnam("root")) == NULL) {
251 		(void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
252 		    "in shadow password file ***\n\n");
253 		single(shell, NULL);
254 	}
255 	endspent();
256 	/*
257 	 * if no 'root' entry in /etc/passwd, give maint. mode single
258 	 * user shell prompt
259 	 */
260 	setpwent();
261 	if (getpwnam("root") == NULL) {
262 		(void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
263 		    "in password file ***\n\n");
264 		single(shell, NULL);
265 	}
266 	endpwent();
267 	/* process with controlling tty treated special */
268 	if ((pid = fork()) != (pid_t)0) {
269 		if (pid == -1)
270 			return (EXIT_FAILURE);
271 		else {
272 			setupsigs();
273 			masterpid = pid;
274 			originalpid = getpid();
275 			/*
276 			 * init() was invoked from a console that was not
277 			 * the default console, nor was it an auxiliary.
278 			 */
279 			if (cttyname[0] == NULL)
280 				termhandler(0);
281 				/* Never returns */
282 
283 			main_loop(cttyname, shpw, B_TRUE);
284 			/* Never returns */
285 		}
286 	}
287 	masterpid = getpid();
288 	originalpid = getppid();
289 	pidlist[nchild++] = originalpid;
290 
291 	sa.sa_handler = childcleanup;
292 	sa.sa_flags = 0;
293 	(void) sigemptyset(&sa.sa_mask);
294 	(void) sigaction(SIGTERM, &sa, NULL);
295 	(void) sigaction(SIGHUP, &sa, NULL);
296 	sa.sa_handler = parenthandler;
297 	sa.sa_flags = SA_SIGINFO;
298 	(void) sigemptyset(&sa.sa_mask);
299 	(void) sigaction(SIGUSR1, &sa, NULL);
300 
301 	sa.sa_handler = SIG_IGN;
302 	sa.sa_flags = 0;
303 	(void) sigemptyset(&sa.sa_mask);
304 	(void) sigaction(SIGCHLD, &sa, NULL);
305 	/*
306 	 * If there isn't a password on root, then don't permit
307 	 * the fanout capability of sulogin.
308 	 */
309 	if (*shpw->sp_pwdp != '\0') {
310 		ptr = namedlist;
311 		while (ptr != NULL) {
312 			p = strchr(ptr, ' ');
313 			if (p == NULL) {
314 				doit(ptr, cttyname, shpw);
315 				break;
316 			}
317 			*p++ = '\0';
318 			doit(ptr, cttyname, shpw);
319 			ptr = p;
320 		}
321 	}
322 	if (pathcmp(cttyname, DEFAULT_CONSOLE) != 0) {
323 		if ((pid = fork()) == (pid_t)0) {
324 			setupsigs();
325 			main_loop(DEFAULT_CONSOLE, shpw, B_FALSE);
326 		} else if (pid == -1)
327 			return (EXIT_FAILURE);
328 		pidlist[nchild++] = pid;
329 	}
330 	/*
331 	 * When parent is all done, it pauses until one of its children
332 	 * signals that its time to kill the underpriviledged.
333 	 */
334 	(void) wait(NULL);
335 
336 	return (0);
337 }
338 
339 /*
340  * These flags are taken from stty's "sane" table entries in
341  * usr/src/cmd/ttymon/sttytable.c
342  */
343 #define	SET_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON|IMAXBEL)
344 #define	RESET_IFLAG (IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF|IXANY)
345 #define	SET_OFLAG (OPOST|ONLCR)
346 #define	RESET_OFLAG (OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL| \
347 	NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY)
348 #define	SET_LFLAG (ISIG|ICANON|IEXTEN|ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL)
349 #define	RESET_LFLAG (XCASE|ECHONL|NOFLSH|STFLUSH|STWRAP|STAPPL)
350 
351 /*
352  * Do the equivalent of 'stty sane' on the terminal since we don't know
353  * what state it was in on startup.
354  */
355 static void
356 sanitize_tty(int fd)
357 {
358 	(void) ioctl(fd, TCGETA, &ttymodes);
359 	ttymodes.c_iflag &= ~RESET_IFLAG;
360 	ttymodes.c_iflag |= SET_IFLAG;
361 	ttymodes.c_oflag &= ~RESET_OFLAG;
362 	ttymodes.c_oflag |= SET_OFLAG;
363 	ttymodes.c_lflag &= ~RESET_LFLAG;
364 	ttymodes.c_lflag |= SET_LFLAG;
365 	ttymodes.c_cc[VERASE] = CERASE;
366 	ttymodes.c_cc[VKILL] = CKILL;
367 	ttymodes.c_cc[VQUIT] = CQUIT;
368 	ttymodes.c_cc[VINTR] = CINTR;
369 	ttymodes.c_cc[VEOF] = CEOF;
370 	ttymodes.c_cc[VEOL] = CNUL;
371 	(void) ioctl(fd, TCSETAF, &ttymodes);
372 }
373 
374 /*
375  * Fork a child of sulogin for each of the auxiliary consoles.
376  */
377 static void
378 doit(char *ptr, char *cttyname, struct spwd *shpw)
379 {
380 	pid_t	pid;
381 
382 	if (pathcmp(ptr, DEFAULT_CONSOLE) != 0 &&
383 	    pathcmp(ptr, cttyname) != 0) {
384 		if ((pid = fork()) == (pid_t)0) {
385 			setupsigs();
386 			main_loop(ptr, shpw, B_FALSE);
387 		} else if (pid == -1)
388 			exit(EXIT_FAILURE);
389 		pidlist[nchild++] = pid;
390 	}
391 }
392 
393 static int
394 pathcmp(char *adev, char *bdev)
395 {
396 	struct stat	st1;
397 	struct stat	st2;
398 
399 	if (adev == NULL || bdev == NULL)
400 		return (1);
401 
402 	if (strcmp(adev, bdev) == 0)
403 		return (0);
404 
405 	if (stat(adev, &st1) || !S_ISCHR(st1.st_mode))
406 		return (1);
407 
408 	if (stat(bdev, &st2) || !S_ISCHR(st2.st_mode))
409 		return (1);
410 
411 	if (st1.st_rdev == st2.st_rdev)
412 		return (0);
413 
414 	return (1);
415 }
416 
417 /* Handlers for the children at initialization */
418 static void
419 setupsigs()
420 {
421 	sa.sa_handler = noop;
422 	sa.sa_flags = 0;
423 	(void) sigemptyset(&sa.sa_mask);
424 	(void) sigaction(SIGINT, &sa, NULL);
425 	(void) sigaction(SIGQUIT, &sa, NULL);
426 
427 	sa.sa_handler = termhandler;
428 	sa.sa_flags = 0;
429 	(void) sigemptyset(&sa.sa_mask);
430 	(void) sigaction(SIGTERM, &sa, NULL);
431 	(void) sigaction(SIGKILL, &sa, NULL);
432 	(void) sigaction(SIGHUP, &sa, NULL);
433 }
434 
435 static void
436 main_loop(char *devname, struct spwd *shpw, boolean_t cttyflag)
437 {
438 	int		fd, i;
439 	char		*pass;			/* password from user */
440 	FILE		*sysmsgfd;
441 
442 	for (i = 0; i < 3; i++)
443 		(void) close(i);
444 	if (cttyflag == B_FALSE) {
445 		if (setsid() == -1)
446 			exit(EXIT_FAILURE);
447 	}
448 	if ((fd = open(devname, O_RDWR)) < 0)
449 		exit(EXIT_FAILURE);
450 	if (fd != 0)
451 		(void) dup2(fd, STDIN_FILENO);
452 	if (fd != 1)
453 		(void) dup2(fd, STDOUT_FILENO);
454 	if (fd != 2)
455 		(void) dup2(fd, STDERR_FILENO);
456 	if (fd > 2)
457 		(void) close(fd);
458 
459 	sysmsgfd = fopen("/dev/sysmsg", "w");
460 
461 	sanitize_tty(fileno(stdin));
462 
463 	for (;;) {
464 		(void) fputs("\nRoot password for system maintenance "
465 		    "(control-d to bypass): ", stdout);
466 
467 		if ((pass = sulogin_getpass(devname)) == NULL) {
468 			/* signal other children to exit */
469 			(void) sigsend(P_PID, masterpid, SIGUSR1);
470 			/* ^D, so straight to default init state */
471 			exit(EXIT_FAILURE);
472 		}
473 		if (*shpw->sp_pwdp == '\0' && *pass == '\0') {
474 			(void) fprintf(sysmsgfd,
475 			    "\nsingle-user privilege assigned to %s.\n",
476 			    devname);
477 			(void) sigsend(P_PID, masterpid, SIGUSR1);
478 			(void) wait(NULL);
479 			single(su, devname);
480 		} else if (*shpw->sp_pwdp != '\0') {
481 			/*
482 			 * There is a special case error to catch here,
483 			 * because sulogin is statically linked:
484 			 * If the root password is hashed with an algorithm
485 			 * other than the old unix crypt the call to crypt(3c)
486 			 * could fail if /usr is corrupt or not available
487 			 * since by default /etc/security/crypt.conf will
488 			 * have the crypt_ modules located under /usr/lib.
489 			 *
490 			 * If this happens crypt(3c) will return NULL and
491 			 * set errno to ELIBACC, in this case we just give
492 			 * access because this is similar to the case of
493 			 * root not existing in /etc/passwd.
494 			 */
495 			pass = crypt(pass, shpw->sp_pwdp);
496 			if ((strcmp(pass, shpw->sp_pwdp) == 0) ||
497 			    ((pass == NULL) && (errno == ELIBACC) &&
498 			    (shpw->sp_pwdp[0] == '$'))) {
499 				(void) fprintf(sysmsgfd,
500 			    "\nsingle-user privilege assigned to %s.\n",
501 				    devname);
502 				(void) sigsend(P_PID, masterpid, SIGUSR1);
503 				(void) wait(NULL);
504 				single(su, devname);
505 			}
506 		}
507 		(void) sleep(sleeptime);
508 		(void) printf("Login incorrect\n");
509 	}
510 }
511 
512 /*
513  * single() - exec shell for single user mode
514  */
515 
516 static void
517 single(const char *cmd, char *ttyn)
518 {
519 	struct utmpx	*u;
520 	char		found = B_FALSE;
521 
522 	if (ttyn == NULL)
523 		ttyn = findttyname(STDIN_FILENO);
524 
525 	/*
526 	 * utmpx records on the console device are expected to be "console"
527 	 * by other processes, such as dtlogin.
528 	 */
529 	ttyn = stripttyname(ttyn);
530 
531 	/* update the utmpx file. */
532 	while ((u = getutxent()) != NULL) {
533 		if (strcmp(u->ut_line, ttyn) == 0) {
534 			u->ut_tv.tv_sec = time(NULL);
535 			u->ut_type = USER_PROCESS;
536 			u->ut_pid = getpid();
537 			if (strcmp(u->ut_user, "root") != 0)
538 				(void) strcpy(u->ut_user, "root");
539 			(void) pututxline(u);
540 			found = B_TRUE;
541 			break;
542 		}
543 	}
544 	if (!found) {
545 		struct utmpx entryx;
546 
547 		entryx.ut_tv.tv_sec = time(NULL);
548 		entryx.ut_type = USER_PROCESS;
549 		entryx.ut_pid = getpid();
550 		(void) strcpy(entryx.ut_user, "root");
551 		(void) strcpy(entryx.ut_line, ttyn);
552 		entryx.ut_tv.tv_usec = 0;
553 		entryx.ut_session = 0;
554 		entryx.ut_id[0] = 'c';
555 		entryx.ut_id[1] = 'o';
556 		entryx.ut_id[2] = 's';
557 		entryx.ut_id[3] = 'u';
558 		entryx.ut_syslen = 1;
559 		entryx.ut_host[0] = '\0';
560 		entryx.ut_exit.e_termination = WTERMSIG(0);
561 		entryx.ut_exit.e_exit = WEXITSTATUS(0);
562 		(void) pututxline(&entryx);
563 	}
564 	endutxent();
565 	(void) printf("Entering System Maintenance Mode\n\n");
566 
567 	if (execl(cmd, cmd, "-", (char *)0) < 0)
568 		exit(EXIT_FAILURE);
569 }
570 
571 /*
572  * sulogin_getpass() - hacked from the stdio library version so we can
573  *		       distinguish newline and EOF.  also don't need this
574  *		       routine to give a prompt.
575  *
576  * returns the password string, or NULL if the used typed EOF.
577  */
578 
579 static char *
580 sulogin_getpass(char *devname)
581 {
582 	struct termio	ttyb;
583 	int		c;
584 	FILE		*fi;
585 	static char	pbuf[PASS_MAX + 1];
586 	void		(*saved_handler)();
587 	char		*rval = pbuf;
588 	int		i = 0;
589 
590 	if ((fi = fopen(devname, "r")) == NULL)
591 		fi = stdin;
592 	else
593 		setbuf(fi, NULL);
594 
595 	saved_handler = signal(SIGINT, SIG_IGN);
596 
597 	ttyb = ttymodes;
598 	ttyb.c_lflag &= ~(ECHO | ECHOE | ECHONL);
599 	(void) ioctl(fileno(fi), TCSETAF, &ttyb);
600 
601 	while ((c = getc(fi)) != '\n') {
602 
603 		if (c == EOF && i == 0) { 	/* ^D, No password */
604 			rval = NULL;
605 			break;
606 		}
607 
608 		if (i < PASS_MAX)
609 			pbuf[i++] = c;
610 	}
611 	pbuf[i] = '\0';
612 	(void) fputc('\n', fi);
613 	(void) ioctl(fileno(fi), TCSETAW, &ttymodes);
614 
615 	if (saved_handler != SIG_ERR)
616 		(void) signal(SIGINT, saved_handler);
617 
618 	return (rval);
619 }
620 
621 static char *
622 findttyname(int fd)
623 {
624 	char	*ttyn = ttyname(fd);
625 
626 	if (ttyn == NULL)
627 		ttyn = "/dev/???";
628 	else {
629 		/*
630 		 * /dev/syscon and /dev/systty are usually links to
631 		 * /dev/console.  prefer /dev/console.
632 		 */
633 		if (((strcmp(ttyn, "/dev/syscon") == 0) ||
634 		    (strcmp(ttyn, "/dev/systty") == 0)) &&
635 		    access("/dev/console", F_OK))
636 			ttyn = "/dev/console";
637 	}
638 	return (ttyn);
639 }
640 
641 static char *
642 stripttyname(char *ttyn)
643 {
644 	/* saw off the /dev/ */
645 	if (strncmp(ttyn, "/dev/", sizeof ("/dev/") -1) == 0)
646 		return (ttyn + sizeof ("/dev/") - 1);
647 	else
648 		return (ttyn);
649 }
650 
651 
652 /* ARGSUSED */
653 static	void
654 noop(int sig)
655 {
656 	/*
657 	 * This signal handler does nothing except return.  We use it
658 	 * as the signal disposition in this program instead of
659 	 * SIG_IGN so that we do not have to restore the disposition
660 	 * back to SIG_DFL. Instead we allow exec(2) to set the
661 	 * dispostion to SIG_DFL to avoid a race condition.
662 	 */
663 }
664 
665 /* ARGSUSED */
666 static void
667 parenthandler(int sig, siginfo_t *si, ucontext_t *uc)
668 {
669 	int i;
670 
671 	/*
672 	 * We get here if someone has successfully entered a password
673 	 * from the auxiliary console and is getting the single-user shell.
674 	 * When this happens, the parent needs to kill the children
675 	 * that didn't get the shell.
676 	 *
677 	 */
678 	for (i = 0; i < nchild; i++) {
679 		if (pidlist[i] != si->__data.__proc.__pid)
680 			(void) sigsend(P_PID, pidlist[i], SIGTERM);
681 	}
682 	sa.sa_handler = SIG_IGN;
683 	sa.sa_flags = 0;
684 	(void) sigemptyset(&sa.sa_mask);
685 	(void) sigaction(SIGINT, &sa, NULL);
686 	(void) sigaction(SIGQUIT, &sa, NULL);
687 	(void) sigaction(SIGTERM, &sa, NULL);
688 	(void) wait(NULL);
689 }
690 
691 /*
692  * The master pid will get SIGTERM or SIGHUP from init, and then
693  * has to make sure the shell isn't still running.
694  */
695 
696 /* ARGSUSED */
697 static	void
698 childcleanup(int sig)
699 {
700 	int i;
701 
702 	/* Only need to kill the child that became the shell. */
703 	for (i = 0; i < nchild; i++) {
704 		/* Don't kill gramps before his time */
705 		if (pidlist[i] != getppid())
706 			(void) sigsend(P_PID, pidlist[i], SIGHUP);
707 	}
708 }
709 
710 /* ARGSUSED */
711 static	void
712 termhandler(int sig)
713 {
714 	FILE *fi;
715 	pid_t pid;
716 
717 	/* Processes come here when they fail to receive the password. */
718 	if ((fi = fopen("/dev/tty", "r+")) == NULL)
719 		fi = stdin;
720 	else
721 		setbuf(fi, NULL);
722 	sanitize_tty(fileno(fi));
723 	/* If you're the controlling tty, then just wait */
724 	pid = getpid();
725 	if (pid == originalpid || pid == masterpid) {
726 		sa.sa_handler = SIG_IGN;
727 		sa.sa_flags = 0;
728 		(void) sigemptyset(&sa.sa_mask);
729 		(void) sigaction(SIGINT, &sa, NULL);
730 		(void) sigaction(SIGQUIT, &sa, NULL);
731 		sa.sa_handler = SIG_DFL;
732 		sa.sa_flags = 0;
733 		(void) sigemptyset(&sa.sa_mask);
734 		(void) sigaction(SIGTERM, &sa, NULL);
735 		(void) sigaction(SIGHUP, &sa, NULL);
736 		(void) wait(NULL);
737 	}
738 	exit(0);
739 }
740