Backed out changeset e05f5705283d (wrong name)
[unleashed.git] / usr / src / cmd / sulogin / sulogin.c
blob9d7f42c9183ea2fce2957f758c9aeca8aaea3af2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
28 * All rights reserved.
30 * Copyright (c) 1987, 1988 Microsoft Corporation.
31 * All rights reserved.
35 * sulogin - special login program exec'd from init to let user
36 * come up single user, or go to default init state straight away.
38 * Explain the scoop to the user, prompt for an authorized user
39 * name or ^D and then prompt for password or ^D. If the password
40 * is correct, check if the user is authorized, if so enter
41 * single user. ^D exits sulogin, and init will go to default init state.
43 * If /etc/passwd is missing, or there's no entry for root,
44 * go single user, no questions asked.
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/param.h>
50 #include <sys/sysmsg_impl.h>
51 #include <sys/mkdev.h>
52 #include <sys/resource.h>
53 #include <sys/uadmin.h>
54 #include <sys/wait.h>
55 #include <sys/stermio.h>
56 #include <fcntl.h>
57 #include <termio.h>
58 #include <pwd.h>
59 #include <shadow.h>
60 #include <stdlib.h>
61 #include <stdio.h>
62 #include <signal.h>
63 #include <siginfo.h>
64 #include <utmpx.h>
65 #include <unistd.h>
66 #include <ucontext.h>
67 #include <string.h>
68 #include <strings.h>
69 #include <deflt.h>
70 #include <limits.h>
71 #include <errno.h>
72 #include <crypt.h>
73 #include <auth_attr.h>
74 #include <auth_list.h>
75 #include <nss_dbdefs.h>
76 #include <user_attr.h>
77 #include <sys/vt.h>
80 * Intervals to sleep after failed login
82 #ifndef SLEEPTIME
83 #define SLEEPTIME 4 /* sleeptime before login incorrect msg */
84 #endif
86 #define SLEEPTIME_MAX 5 /* maximum sleeptime */
89 * the name of the file containing the login defaults we deliberately
90 * use the same file as login(1)
93 #define DEFAULT_LOGIN "/etc/default/login"
94 #define DEFAULT_SULOGIN "/etc/default/sulogin"
95 #define DEFAULT_CONSOLE "/dev/console"
97 static char shell[] = "/sbin/sh";
98 static char su[] = "/sbin/su.static";
99 static int sleeptime = SLEEPTIME;
100 static int nchild = 0;
101 static pid_t pidlist[10];
102 static pid_t masterpid = 0;
103 static pid_t originalpid = 0;
104 static struct sigaction sa;
105 static struct termio ttymodes;
107 static char *findttyname(int fd);
108 static char *stripttyname(char *);
109 static char *sulogin_getinput(char *, int);
110 static void noop(int);
111 static void single(const char *, char *);
112 static void main_loop(char *, boolean_t);
113 static void parenthandler();
114 static void termhandler(int);
115 static void setupsigs(void);
116 static int pathcmp(char *, char *);
117 static void doit(char *, char *);
118 static void childcleanup(int);
120 #define ECHOON 0
121 #define ECHOOFF 1
123 /* ARGSUSED */
125 main(int argc, char **argv)
127 struct spwd *shpw;
128 int passreq = B_TRUE;
129 int flags;
130 int fd;
131 char *infop, *ptr, *p;
132 pid_t pid;
133 int bufsize;
134 struct stat st;
135 char cttyname[100];
136 char namedlist[500];
137 char scratchlist[500];
138 dev_t cttyd;
140 if (geteuid() != 0) {
141 (void) fprintf(stderr, "%s: must be root\n", argv[0]);
142 return (EXIT_FAILURE);
145 /* Do the magic to determine the children */
146 if ((fd = open(SYSMSG, 0)) < 0)
147 return (EXIT_FAILURE);
150 * If the console supports the CIOCTTYCONSOLE ioctl, then fetch
151 * its console device list. If not, then we use the default
152 * console name.
154 if (ioctl(fd, CIOCTTYCONSOLE, &cttyd) == 0) {
155 if ((bufsize = ioctl(fd, CIOCGETCONSOLE, NULL)) < 0)
156 return (EXIT_FAILURE);
158 if (bufsize > 0) {
159 if ((infop = calloc(bufsize, sizeof (char))) == NULL)
160 return (EXIT_FAILURE);
162 if (ioctl(fd, CIOCGETCONSOLE, infop) < 0)
163 return (EXIT_FAILURE);
165 (void) snprintf(namedlist, sizeof (namedlist), "%s %s",
166 DEFAULT_CONSOLE, infop);
167 } else
168 (void) snprintf(namedlist, sizeof (namedlist), "%s",
169 DEFAULT_CONSOLE);
170 } else {
171 (void) snprintf(namedlist, sizeof (namedlist), "%s",
172 DEFAULT_CONSOLE);
173 cttyd = NODEV;
177 * The attempt to turn the controlling terminals dev_t into a string
178 * may not be successful, thus leaving the variable cttyname as a
179 * NULL. This occurs if during boot we find
180 * the root partition (or some other partition)
181 * requires manual fsck, thus resulting in sulogin
182 * getting invoked. The ioctl for CIOCTTYCONSOLE
183 * called above returned NODEV for cttyd
184 * in these cases. NODEV gets returned when the vnode pointer
185 * in our session structure is NULL. In these cases it
186 * must be assumed that the default console is used.
188 * See uts/common/os/session.c:cttydev().
190 (void) strcpy(cttyname, DEFAULT_CONSOLE);
191 (void) strcpy(scratchlist, namedlist);
192 ptr = scratchlist;
193 while (ptr != NULL) {
194 p = strchr(ptr, ' ');
195 if (p == NULL) {
196 if (stat(ptr, &st))
197 return (EXIT_FAILURE);
198 if (st.st_rdev == cttyd)
199 (void) strcpy(cttyname, ptr);
200 break;
202 *p++ = '\0';
203 if (stat(ptr, &st))
204 return (EXIT_FAILURE);
205 if (st.st_rdev == cttyd) {
206 (void) strcpy(cttyname, ptr);
207 break;
209 ptr = p;
213 * Use the same value of SLEEPTIME that login(1) uses. This
214 * is obtained by reading the file /etc/default/login using
215 * the def*() functions.
218 if (defopen(DEFAULT_LOGIN) == 0) {
220 /* ignore case */
222 flags = defcntl(DC_GETFLAGS, 0);
223 TURNOFF(flags, DC_CASE);
224 (void) defcntl(DC_SETFLAGS, flags);
226 if ((ptr = defread("SLEEPTIME=")) != NULL)
227 sleeptime = atoi(ptr);
229 if (sleeptime < 0 || sleeptime > SLEEPTIME_MAX)
230 sleeptime = SLEEPTIME;
232 (void) defopen(NULL); /* closes DEFAULT_LOGIN */
236 * Use our own value of PASSREQ, separate from the one login(1) uses.
237 * This is obtained by reading the file /etc/default/sulogin using
238 * the def*() functions.
241 if (defopen(DEFAULT_SULOGIN) == 0) {
242 if ((ptr = defread("PASSREQ=")) != NULL)
243 if (strcmp("NO", ptr) == 0)
244 passreq = B_FALSE;
246 (void) defopen(NULL); /* closes DEFAULT_SULOGIN */
249 if (passreq == B_FALSE)
250 single(shell, NULL);
253 * if no 'root' entry in /etc/shadow, give maint. mode single
254 * user shell prompt
256 setspent();
257 if ((shpw = getspnam("root")) == NULL) {
258 (void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
259 "in shadow password file ***\n\n");
260 single(shell, NULL);
262 endspent();
264 * if no 'root' entry in /etc/passwd, give maint. mode single
265 * user shell prompt
267 setpwent();
268 if (getpwnam("root") == NULL) {
269 (void) fprintf(stderr, "\n*** Unable to retrieve `root' entry "
270 "in password file ***\n\n");
271 single(shell, NULL);
273 endpwent();
274 /* process with controlling tty treated special */
275 if ((pid = fork()) != (pid_t)0) {
276 if (pid == -1)
277 return (EXIT_FAILURE);
278 else {
279 setupsigs();
280 masterpid = pid;
281 originalpid = getpid();
283 * init() was invoked from a console that was not
284 * the default console, nor was it an auxiliary.
286 if (cttyname[0] == NULL)
287 termhandler(0);
288 /* Never returns */
290 main_loop(cttyname, B_TRUE);
291 /* Never returns */
294 masterpid = getpid();
295 originalpid = getppid();
296 pidlist[nchild++] = originalpid;
298 sa.sa_handler = childcleanup;
299 sa.sa_flags = 0;
300 (void) sigemptyset(&sa.sa_mask);
301 (void) sigaction(SIGTERM, &sa, NULL);
302 (void) sigaction(SIGHUP, &sa, NULL);
303 sa.sa_handler = parenthandler;
304 sa.sa_flags = SA_SIGINFO;
305 (void) sigemptyset(&sa.sa_mask);
306 (void) sigaction(SIGUSR1, &sa, NULL);
308 sa.sa_handler = SIG_IGN;
309 sa.sa_flags = 0;
310 (void) sigemptyset(&sa.sa_mask);
311 (void) sigaction(SIGCHLD, &sa, NULL);
313 * If there isn't a password on root, then don't permit
314 * the fanout capability of sulogin.
316 if (*shpw->sp_pwdp != '\0') {
317 ptr = namedlist;
318 while (ptr != NULL) {
319 p = strchr(ptr, ' ');
320 if (p == NULL) {
321 doit(ptr, cttyname);
322 break;
324 *p++ = '\0';
325 doit(ptr, cttyname);
326 ptr = p;
329 if (pathcmp(cttyname, DEFAULT_CONSOLE) != 0) {
330 if ((pid = fork()) == (pid_t)0) {
331 setupsigs();
332 main_loop(DEFAULT_CONSOLE, B_FALSE);
333 } else if (pid == -1)
334 return (EXIT_FAILURE);
335 pidlist[nchild++] = pid;
338 * When parent is all done, it pauses until one of its children
339 * signals that its time to kill the underpriviledged.
341 (void) wait(NULL);
343 return (0);
347 * These flags are taken from stty's "sane" table entries in
348 * usr/src/cmd/ttymon/sttytable.c
350 #define SET_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON|IMAXBEL)
351 #define RESET_IFLAG (IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF|IXANY)
352 #define SET_OFLAG (OPOST|ONLCR)
353 #define RESET_OFLAG (OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL| \
354 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY)
355 #define SET_LFLAG (ISIG|ICANON|IEXTEN|ECHO|ECHOK|ECHOE|ECHOKE|ECHOCTL)
356 #define RESET_LFLAG (XCASE|ECHONL|NOFLSH|STFLUSH|STWRAP|STAPPL)
359 * Do the equivalent of 'stty sane' on the terminal since we don't know
360 * what state it was in on startup.
362 static void
363 sanitize_tty(int fd)
365 (void) ioctl(fd, TCGETA, &ttymodes);
366 ttymodes.c_iflag &= ~RESET_IFLAG;
367 ttymodes.c_iflag |= SET_IFLAG;
368 ttymodes.c_oflag &= ~RESET_OFLAG;
369 ttymodes.c_oflag |= SET_OFLAG;
370 ttymodes.c_lflag &= ~RESET_LFLAG;
371 ttymodes.c_lflag |= SET_LFLAG;
372 ttymodes.c_cc[VERASE] = CERASE;
373 ttymodes.c_cc[VKILL] = CKILL;
374 ttymodes.c_cc[VQUIT] = CQUIT;
375 ttymodes.c_cc[VINTR] = CINTR;
376 ttymodes.c_cc[VEOF] = CEOF;
377 ttymodes.c_cc[VEOL] = CNUL;
378 (void) ioctl(fd, TCSETAF, &ttymodes);
382 * Fork a child of sulogin for each of the auxiliary consoles.
384 static void
385 doit(char *ptr, char *cttyname)
387 pid_t pid;
389 if (pathcmp(ptr, DEFAULT_CONSOLE) != 0 &&
390 pathcmp(ptr, cttyname) != 0) {
391 if ((pid = fork()) == (pid_t)0) {
392 setupsigs();
393 main_loop(ptr, B_FALSE);
394 } else if (pid == -1)
395 exit(EXIT_FAILURE);
396 pidlist[nchild++] = pid;
400 static int
401 pathcmp(char *adev, char *bdev)
403 struct stat st1;
404 struct stat st2;
406 if (adev == NULL || bdev == NULL)
407 return (1);
409 if (strcmp(adev, bdev) == 0)
410 return (0);
412 if (stat(adev, &st1) || !S_ISCHR(st1.st_mode))
413 return (1);
415 if (stat(bdev, &st2) || !S_ISCHR(st2.st_mode))
416 return (1);
418 if (st1.st_rdev == st2.st_rdev)
419 return (0);
421 return (1);
424 /* Handlers for the children at initialization */
425 static void
426 setupsigs()
428 sa.sa_handler = noop;
429 sa.sa_flags = 0;
430 (void) sigemptyset(&sa.sa_mask);
431 (void) sigaction(SIGINT, &sa, NULL);
432 (void) sigaction(SIGQUIT, &sa, NULL);
434 sa.sa_handler = termhandler;
435 sa.sa_flags = 0;
436 (void) sigemptyset(&sa.sa_mask);
437 (void) sigaction(SIGTERM, &sa, NULL);
438 (void) sigaction(SIGKILL, &sa, NULL);
439 (void) sigaction(SIGHUP, &sa, NULL);
442 static void
443 main_loop(char *devname, boolean_t cttyflag)
445 int fd, i;
446 char *user = NULL; /* authorized user */
447 char *pass; /* password from user */
448 char *cpass; /* crypted password */
449 struct spwd spwd;
450 struct spwd *lshpw; /* local shadow */
451 char shadow[NSS_BUFLEN_SHADOW];
452 FILE *sysmsgfd;
454 for (i = 0; i < 3; i++)
455 (void) close(i);
456 if (cttyflag == B_FALSE) {
457 if (setsid() == -1)
458 exit(EXIT_FAILURE);
460 if ((fd = open(devname, O_RDWR)) < 0)
461 exit(EXIT_FAILURE);
464 * In system maintenance mode, all virtual console instances
465 * of the svc:/system/console-login service are not available
466 * any more, and only the system console is available. So here
467 * we always switch to the system console in case at the moment
468 * the active console isn't it.
470 (void) ioctl(fd, VT_ACTIVATE, 1);
472 if (fd != 0)
473 (void) dup2(fd, STDIN_FILENO);
474 if (fd != 1)
475 (void) dup2(fd, STDOUT_FILENO);
476 if (fd != 2)
477 (void) dup2(fd, STDERR_FILENO);
478 if (fd > 2)
479 (void) close(fd);
481 sysmsgfd = fopen("/dev/sysmsg", "w");
483 sanitize_tty(fileno(stdin));
485 for (;;) {
486 do {
487 (void) printf("\nEnter user name for system "
488 "maintenance (control-d to bypass): ");
489 user = sulogin_getinput(devname, ECHOON);
490 if (user == NULL) {
491 /* signal other children to exit */
492 (void) sigsend(P_PID, masterpid, SIGUSR1);
493 /* ^D, so straight to default init state */
494 exit(EXIT_FAILURE);
496 } while (user[0] == '\0');
497 (void) printf("Enter %s password (control-d to bypass): ",
498 user);
500 if ((pass = sulogin_getinput(devname, ECHOOFF)) == NULL) {
501 /* signal other children to exit */
502 (void) sigsend(P_PID, masterpid, SIGUSR1);
503 /* ^D, so straight to default init state */
504 free(user);
505 exit(EXIT_FAILURE);
507 lshpw = getspnam_r(user, &spwd, shadow, sizeof (shadow));
508 if (lshpw == NULL) {
510 * the user entered doesn't exist, too bad.
512 goto sorry;
516 * There is a special case error to catch here:
517 * If the password is hashed with an algorithm
518 * other than the old unix crypt the call to crypt(3c)
519 * could fail if /usr is corrupt or not available
520 * since by default /etc/security/crypt.conf will
521 * have the crypt_ modules located under /usr/lib.
522 * Or it could happen if /etc/security/crypt.conf
523 * is corrupted.
525 * If this happens crypt(3c) will return NULL and
526 * set errno to ELIBACC for the former condition or
527 * EINVAL for the latter, in this case we bypass
528 * authentication and just verify that the user is
529 * authorized.
532 errno = 0;
533 cpass = crypt(pass, lshpw->sp_pwdp);
534 if (((cpass == NULL) && (lshpw->sp_pwdp[0] == '$')) &&
535 ((errno == ELIBACC) || (errno == EINVAL))) {
536 goto checkauth;
537 } else if ((cpass == NULL) ||
538 (strcmp(cpass, lshpw->sp_pwdp) != 0)) {
539 goto sorry;
542 checkauth:
544 * There is a special case error here as well.
545 * If /etc/user_attr is corrupt, getusernam("root")
546 * returns NULL.
547 * In this case, we just give access because this is similar
548 * to the case of root not existing in /etc/passwd.
551 if ((getusernam("root") != NULL) &&
552 (chkauthattr(MAINTENANCE_AUTH, user) != 1)) {
553 goto sorry;
555 (void) fprintf(sysmsgfd, "\nsingle-user privilege "
556 "assigned to %s on %s.\n", user, devname);
557 (void) sigsend(P_PID, masterpid, SIGUSR1);
558 (void) wait(NULL);
559 free(user);
560 free(pass);
561 single(su, devname);
562 /* single never returns */
564 sorry:
565 (void) printf("\nLogin incorrect or user %s not authorized\n",
566 user);
567 free(user);
568 free(pass);
569 (void) sleep(sleeptime);
574 * single() - exec shell for single user mode
577 static void
578 single(const char *cmd, char *ttyn)
580 struct utmpx *u;
581 char found = B_FALSE;
583 if (ttyn == NULL)
584 ttyn = findttyname(STDIN_FILENO);
587 * utmpx records on the console device are expected to be "console"
588 * by other processes, such as dtlogin.
590 ttyn = stripttyname(ttyn);
592 /* update the utmpx file. */
593 while ((u = getutxent()) != NULL) {
594 if (strcmp(u->ut_line, ttyn) == 0) {
595 u->ut_tv.tv_sec = time(NULL);
596 u->ut_type = USER_PROCESS;
597 u->ut_pid = getpid();
598 if (strcmp(u->ut_user, "root") != 0)
599 (void) strcpy(u->ut_user, "root");
600 (void) pututxline(u);
601 found = B_TRUE;
602 break;
605 if (!found) {
606 struct utmpx entryx;
608 entryx.ut_tv.tv_sec = time(NULL);
609 entryx.ut_type = USER_PROCESS;
610 entryx.ut_pid = getpid();
611 (void) strcpy(entryx.ut_user, "root");
612 (void) strcpy(entryx.ut_line, ttyn);
613 entryx.ut_tv.tv_usec = 0;
614 entryx.ut_session = 0;
615 entryx.ut_id[0] = 'c';
616 entryx.ut_id[1] = 'o';
617 entryx.ut_id[2] = 's';
618 entryx.ut_id[3] = 'u';
619 entryx.ut_syslen = 1;
620 entryx.ut_host[0] = '\0';
621 entryx.ut_exit.e_termination = WTERMSIG(0);
622 entryx.ut_exit.e_exit = WEXITSTATUS(0);
623 (void) pututxline(&entryx);
625 endutxent();
626 (void) printf("Entering System Maintenance Mode\n\n");
628 if (execl(cmd, cmd, "-", (char *)0) < 0)
629 exit(EXIT_FAILURE);
633 * sulogin_getinput() - hacked from the standard PAM tty conversation
634 * function getpassphrase() library version
635 * so we can distinguish newline and EOF.
636 * also don't need this routine to give a prompt.
638 * returns the password string, or NULL if the used typed EOF.
641 static char *
642 sulogin_getinput(char *devname, int echooff)
644 struct termio ttyb;
645 int c;
646 FILE *fi;
647 static char input[PASS_MAX + 1];
648 void (*saved_handler)();
649 char *rval = input;
650 int i = 0;
652 if ((fi = fopen(devname, "r")) == NULL) {
653 fi = stdin;
656 saved_handler = signal(SIGINT, SIG_IGN);
658 if (echooff) {
659 ttyb = ttymodes;
660 ttyb.c_lflag &= ~(ECHO | ECHOE | ECHONL);
661 (void) ioctl(fileno(fi), TCSETAF, &ttyb);
664 /* get characters up to PASS_MAX, but don't overflow */
665 while ((c = getc(fi)) != '\n' && (c != '\r')) {
666 if (c == EOF && i == 0) { /* ^D, no input */
667 rval = NULL;
668 break;
670 if (i < PASS_MAX) {
671 input[i++] = (char)c;
674 input[i] = '\0';
675 (void) fputc('\n', fi);
676 if (echooff) {
677 (void) ioctl(fileno(fi), TCSETAW, &ttymodes);
680 if (saved_handler != SIG_ERR)
681 (void) signal(SIGINT, saved_handler);
682 return (rval == NULL ? NULL : strdup(rval));
685 static char *
686 findttyname(int fd)
688 char *ttyn = ttyname(fd);
690 if (ttyn == NULL)
691 ttyn = "/dev/???";
692 else {
694 * /dev/syscon and /dev/systty are usually links to
695 * /dev/console. prefer /dev/console.
697 if (((strcmp(ttyn, "/dev/syscon") == 0) ||
698 (strcmp(ttyn, "/dev/systty") == 0)) &&
699 access("/dev/console", F_OK))
700 ttyn = "/dev/console";
702 return (ttyn);
705 static char *
706 stripttyname(char *ttyn)
708 /* saw off the /dev/ */
709 if (strncmp(ttyn, "/dev/", sizeof ("/dev/") -1) == 0)
710 return (ttyn + sizeof ("/dev/") - 1);
711 else
712 return (ttyn);
716 /* ARGSUSED */
717 static void
718 noop(int sig)
721 * This signal handler does nothing except return. We use it
722 * as the signal disposition in this program instead of
723 * SIG_IGN so that we do not have to restore the disposition
724 * back to SIG_DFL. Instead we allow exec(2) to set the
725 * dispostion to SIG_DFL to avoid a race condition.
729 /* ARGSUSED */
730 static void
731 parenthandler(int sig, siginfo_t *si, ucontext_t *uc)
733 int i;
736 * We get here if someone has successfully entered a password
737 * from the auxiliary console and is getting the single-user shell.
738 * When this happens, the parent needs to kill the children
739 * that didn't get the shell.
742 for (i = 0; i < nchild; i++) {
743 if (pidlist[i] != si->__data.__proc.__pid)
744 (void) sigsend(P_PID, pidlist[i], SIGTERM);
746 sa.sa_handler = SIG_IGN;
747 sa.sa_flags = 0;
748 (void) sigemptyset(&sa.sa_mask);
749 (void) sigaction(SIGINT, &sa, NULL);
750 (void) sigaction(SIGQUIT, &sa, NULL);
751 (void) sigaction(SIGTERM, &sa, NULL);
752 (void) wait(NULL);
756 * The master pid will get SIGTERM or SIGHUP from init, and then
757 * has to make sure the shell isn't still running.
760 /* ARGSUSED */
761 static void
762 childcleanup(int sig)
764 int i;
766 /* Only need to kill the child that became the shell. */
767 for (i = 0; i < nchild; i++) {
768 /* Don't kill gramps before his time */
769 if (pidlist[i] != getppid())
770 (void) sigsend(P_PID, pidlist[i], SIGHUP);
774 /* ARGSUSED */
775 static void
776 termhandler(int sig)
778 FILE *fi;
779 pid_t pid;
781 /* Processes come here when they fail to receive the password. */
782 if ((fi = fopen("/dev/tty", "r+")) == NULL)
783 fi = stdin;
784 else
785 setbuf(fi, NULL);
786 sanitize_tty(fileno(fi));
787 /* If you're the controlling tty, then just wait */
788 pid = getpid();
789 if (pid == originalpid || pid == masterpid) {
790 sa.sa_handler = SIG_IGN;
791 sa.sa_flags = 0;
792 (void) sigemptyset(&sa.sa_mask);
793 (void) sigaction(SIGINT, &sa, NULL);
794 (void) sigaction(SIGQUIT, &sa, NULL);
795 sa.sa_handler = SIG_DFL;
796 sa.sa_flags = 0;
797 (void) sigemptyset(&sa.sa_mask);
798 (void) sigaction(SIGTERM, &sa, NULL);
799 (void) sigaction(SIGHUP, &sa, NULL);
800 (void) wait(NULL);
802 exit(0);