login.c revision 1.32 1 /* $NetBSD: login.c,v 1.32 1997/11/07 20:32:05 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT(
39 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n");
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
46 #endif
47 __RCSID("$NetBSD: login.c,v 1.32 1997/11/07 20:32:05 mrg Exp $");
48 #endif /* not lint */
49
50 /*
51 * login [ name ]
52 * login -h hostname (for telnetd, etc.)
53 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
54 */
55
56 #include <sys/param.h>
57 #include <sys/stat.h>
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 #include <sys/file.h>
61
62 #include <err.h>
63 #include <errno.h>
64 #include <grp.h>
65 #include <pwd.h>
66 #include <setjmp.h>
67 #include <signal.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <syslog.h>
72 #include <ttyent.h>
73 #include <tzfile.h>
74 #include <unistd.h>
75 #include <utmp.h>
76 #include <util.h>
77 #ifdef SKEY
78 #include <skey.h>
79 #endif
80 #ifdef KERBEROS5
81 #include <krb5.h>
82 #endif
83
84 #include "pathnames.h"
85
86 void badlogin __P((char *));
87 void checknologin __P((void));
88 void dolastlog __P((int));
89 void getloginname __P((void));
90 int main __P((int, char *[]));
91 void motd __P((void));
92 int rootterm __P((char *));
93 void sigint __P((int));
94 void sleepexit __P((int));
95 char *stypeof __P((char *));
96 void timedout __P((int));
97 #if defined(KERBEROS) || defined(KERBEROS5)
98 int klogin __P((struct passwd *, char *, char *, char *));
99 void kdestroy __P((void));
100 void dofork __P((void));
101 #endif
102
103 extern void login __P((struct utmp *));
104
105 #define TTYGRPNAME "tty" /* name of group to own ttys */
106
107 /*
108 * This bounds the time given to login. Not a define so it can
109 * be patched on machines where it's too small.
110 */
111 u_int timeout = 300;
112
113 #if defined(KERBEROS) || defined(KERBEROS5)
114 int notickets = 1;
115 char *instance;
116 char *krbtkfile_env;
117 #endif
118 #ifdef KERBEROS5
119 extern krb5_context kcontext;
120 #endif
121
122 struct passwd *pwd;
123 int failures;
124 char term[64], *envinit[1], *hostname, *username, *tty;
125
126 int
127 main(argc, argv)
128 int argc;
129 char *argv[];
130 {
131 extern char **environ;
132 struct group *gr;
133 struct stat st;
134 struct timeval tp;
135 struct utmp utmp;
136 int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
137 uid_t uid;
138 char *domain, *p, *salt, *ttyn, *pwprompt;
139 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
140 char localhost[MAXHOSTNAMELEN];
141 int need_chpass, require_chpass;
142 #ifdef KERBEROS5
143 krb5_error_code kerror;
144 #endif
145
146 tbuf[0] = '\0';
147 rval = 0;
148 pwprompt = NULL;
149 need_chpass = require_chpass = 0;
150
151 (void)signal(SIGALRM, timedout);
152 (void)alarm(timeout);
153 (void)signal(SIGQUIT, SIG_IGN);
154 (void)signal(SIGINT, SIG_IGN);
155 (void)setpriority(PRIO_PROCESS, 0, 0);
156
157 openlog("login", LOG_ODELAY, LOG_AUTH);
158
159 /*
160 * -p is used by getty to tell login not to destroy the environment
161 * -f is used to skip a second login authentication
162 * -h is used by other servers to pass the name of the remote
163 * host to login so that it may be placed in utmp and wtmp
164 * -s is used to force use of S/Key or equivalent.
165 */
166 domain = NULL;
167 if (gethostname(localhost, sizeof(localhost)) < 0)
168 syslog(LOG_ERR, "couldn't get local hostname: %m");
169 else
170 domain = strchr(localhost, '.');
171
172 fflag = hflag = pflag = sflag = 0;
173 uid = getuid();
174 while ((ch = getopt(argc, argv, "fh:ps")) != -1)
175 switch (ch) {
176 case 'f':
177 fflag = 1;
178 break;
179 case 'h':
180 if (uid)
181 errx(1, "-h option: %s", strerror(EPERM));
182 hflag = 1;
183 if (domain && (p = strchr(optarg, '.')) != NULL &&
184 strcasecmp(p, domain) == 0)
185 *p = 0;
186 hostname = optarg;
187 break;
188 case 'p':
189 pflag = 1;
190 break;
191 case 's':
192 sflag = 1;
193 break;
194 default:
195 case '?':
196 (void)fprintf(stderr,
197 "usage: login [-fps] [-h hostname] [username]\n");
198 exit(1);
199 }
200 argc -= optind;
201 argv += optind;
202
203 if (*argv) {
204 username = *argv;
205 ask = 0;
206 } else
207 ask = 1;
208
209 for (cnt = getdtablesize(); cnt > 2; cnt--)
210 (void)close(cnt);
211
212 ttyn = ttyname(STDIN_FILENO);
213 if (ttyn == NULL || *ttyn == '\0') {
214 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
215 ttyn = tname;
216 }
217 if ((tty = strrchr(ttyn, '/')) != NULL)
218 ++tty;
219 else
220 tty = ttyn;
221
222 #ifdef KERBEROS5
223 kerror = krb5_init_context(&kcontext);
224 if (kerror) {
225 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
226 error_message(kerror));
227 exit(1);
228 }
229 #endif KERBEROS5
230
231 for (cnt = 0;; ask = 1) {
232 #if defined(KERBEROS) || defined(KERBEROS5)
233 kdestroy();
234 #endif
235 if (ask) {
236 fflag = 0;
237 getloginname();
238 }
239 rootlogin = 0;
240 #ifdef KERBEROS
241 if ((instance = strchr(username, '.')) != NULL)
242 *instance++ = '\0';
243 else
244 instance = "";
245 #endif
246 #ifdef KERBEROS5
247 if ((instance = strchr(username, '/')) != NULL)
248 *instance++ = '\0';
249 else
250 instance = "";
251 #endif
252 if (strlen(username) > MAXLOGNAME)
253 username[MAXLOGNAME] = '\0';
254
255 /*
256 * Note if trying multiple user names; log failures for
257 * previous user name, but don't bother logging one failure
258 * for nonexistent name (mistyped username).
259 */
260 if (failures && strcmp(tbuf, username)) {
261 if (failures > (pwd ? 0 : 1))
262 badlogin(tbuf);
263 failures = 0;
264 }
265 (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
266
267 if ((pwd = getpwnam(username)) != NULL)
268 salt = pwd->pw_passwd;
269 else
270 salt = "xx";
271
272 /*
273 * if we have a valid account name, and it doesn't have a
274 * password, or the -f option was specified and the caller
275 * is root or the caller isn't changing their uid, don't
276 * authenticate.
277 */
278 if (pwd) {
279 if (pwd->pw_uid == 0)
280 rootlogin = 1;
281
282 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
283 /* already authenticated */
284 break;
285 } else if (pwd->pw_passwd[0] == '\0') {
286 /* pretend password okay */
287 rval = 0;
288 goto ttycheck;
289 }
290 }
291
292 fflag = 0;
293
294 (void)setpriority(PRIO_PROCESS, 0, -4);
295
296 #ifdef SKEY
297 if (skey_haskey(username) == 0) {
298 static char skprompt[80];
299 char *skinfo = skey_keyinfo(username);
300
301 (void)snprintf(skprompt, sizeof(skprompt)-1,
302 "Password [%s]:",
303 skinfo ? skinfo : "error getting challenge");
304 pwprompt = skprompt;
305 } else
306 #endif
307 pwprompt = "Password:";
308
309 p = getpass(pwprompt);
310
311 if (pwd == NULL) {
312 rval = 1;
313 goto skip;
314 }
315 #ifdef KERBEROS
316 if (klogin(pwd, instance, localhost, p) == 0) {
317 rval = 0;
318 goto skip;
319 }
320 #endif
321 #ifdef KERBEROS5
322 if (klogin(pwd, instance, localhost, p) == 0) {
323 rval = 0;
324 goto skip;
325 }
326 #endif
327 #ifdef SKEY
328 if (skey_haskey(username) == 0 &&
329 skey_passcheck(username, p) != -1) {
330 rval = 0;
331 goto skip;
332 }
333 #endif
334 if (!sflag && *pwd->pw_passwd != '\0' &&
335 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
336 rval = 0;
337 require_chpass = 1;
338 goto skip;
339 }
340 rval = 1;
341
342 skip:
343 memset(p, 0, strlen(p));
344
345 (void)setpriority(PRIO_PROCESS, 0, 0);
346
347 ttycheck:
348 /*
349 * If trying to log in as root without Kerberos,
350 * but with insecure terminal, refuse the login attempt.
351 */
352 if (pwd && !rval && rootlogin && !rootterm(tty)) {
353 (void)fprintf(stderr,
354 "%s login refused on this terminal.\n",
355 pwd->pw_name);
356 if (hostname)
357 syslog(LOG_NOTICE,
358 "LOGIN %s REFUSED FROM %s ON TTY %s",
359 pwd->pw_name, hostname, tty);
360 else
361 syslog(LOG_NOTICE,
362 "LOGIN %s REFUSED ON TTY %s",
363 pwd->pw_name, tty);
364 continue;
365 }
366
367 if (pwd && !rval)
368 break;
369
370 (void)printf("Login incorrect\n");
371 failures++;
372 /* we allow 10 tries, but after 3 we start backing off */
373 if (++cnt > 3) {
374 if (cnt >= 10) {
375 badlogin(username);
376 sleepexit(1);
377 }
378 sleep((u_int)((cnt - 3) * 5));
379 }
380 }
381
382 /* committed to login -- turn off timeout */
383 (void)alarm((u_int)0);
384
385 endpwent();
386
387 /* if user not super-user, check for disabled logins */
388 if (!rootlogin)
389 checknologin();
390
391 if (chdir(pwd->pw_dir) < 0) {
392 (void)printf("No home directory %s!\n", pwd->pw_dir);
393 if (chdir("/"))
394 exit(0);
395 pwd->pw_dir = "/";
396 (void)printf("Logging in with home = \"/\".\n");
397 }
398
399 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
400
401 if (pwd->pw_change || pwd->pw_expire)
402 (void)gettimeofday(&tp, (struct timezone *)NULL);
403 if (pwd->pw_expire)
404 if (tp.tv_sec >= pwd->pw_expire) {
405 (void)printf("Sorry -- your account has expired.\n");
406 sleepexit(1);
407 } else if (pwd->pw_expire - tp.tv_sec <
408 _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
409 (void)printf("Warning: your account expires on %s",
410 ctime(&pwd->pw_expire));
411 if (pwd->pw_change)
412 if (pwd->pw_change == _PASSWORD_CHGNOW)
413 need_chpass = 1;
414 else if (tp.tv_sec >= pwd->pw_change) {
415 (void)printf("Sorry -- your password has expired.\n");
416 sleepexit(1);
417 } else if (pwd->pw_change - tp.tv_sec <
418 _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
419 (void)printf("Warning: your password expires on %s",
420 ctime(&pwd->pw_change));
421
422 /* Nothing else left to fail -- really log in. */
423 memset((void *)&utmp, 0, sizeof(utmp));
424 (void)time(&utmp.ut_time);
425 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
426 if (hostname)
427 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
428 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
429 login(&utmp);
430
431 dolastlog(quietlog);
432
433 (void)chown(ttyn, pwd->pw_uid,
434 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
435
436 if (ttyaction(ttyn, "login", pwd->pw_name))
437 (void)printf("Warning: ttyaction failed.\n");
438
439 #if defined(KERBEROS) || defined(KERBEROS5)
440 /* Fork so that we can call kdestroy */
441 if (krbtkfile_env)
442 dofork();
443 #endif
444 (void)setgid(pwd->pw_gid);
445
446 initgroups(username, pwd->pw_gid);
447
448 if (*pwd->pw_shell == '\0')
449 pwd->pw_shell = _PATH_BSHELL;
450
451 /* Destroy environment unless user has requested its preservation. */
452 if (!pflag)
453 environ = envinit;
454 (void)setenv("HOME", pwd->pw_dir, 1);
455 (void)setenv("SHELL", pwd->pw_shell, 1);
456 if (term[0] == '\0')
457 (void)strncpy(term, stypeof(tty), sizeof(term));
458 (void)setenv("TERM", term, 0);
459 (void)setenv("LOGNAME", pwd->pw_name, 1);
460 (void)setenv("USER", pwd->pw_name, 1);
461 (void)setenv("PATH", _PATH_DEFPATH, 0);
462 #ifdef KERBEROS
463 if (krbtkfile_env)
464 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
465 #endif
466 #ifdef KERBEROS5
467 if (krbtkfile_env)
468 (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
469 #endif
470
471 if (tty[sizeof("tty")-1] == 'd')
472 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
473
474 /* If fflag is on, assume caller/authenticator has logged root login. */
475 if (rootlogin && fflag == 0)
476 if (hostname)
477 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
478 username, tty, hostname);
479 else
480 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty);
481
482 #if defined(KERBEROS) || defined(KERBEROS5)
483 if (!quietlog && notickets == 1)
484 (void)printf("Warning: no Kerberos tickets issued.\n");
485 #endif
486
487 if (!quietlog) {
488 (void)printf("%s %s\n%s\n\t%s %s\n\n",
489 "Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.",
490 "All rights reserved.",
491 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
492 "The Regents of the University of California. ",
493 "All rights reserved.");
494 motd();
495 (void)snprintf(tbuf,
496 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
497 if (stat(tbuf, &st) == 0 && st.st_size != 0)
498 (void)printf("You have %smail.\n",
499 (st.st_mtime > st.st_atime) ? "new " : "");
500 }
501
502 (void)signal(SIGALRM, SIG_DFL);
503 (void)signal(SIGQUIT, SIG_DFL);
504 (void)signal(SIGINT, SIG_DFL);
505 (void)signal(SIGTSTP, SIG_IGN);
506
507 tbuf[0] = '-';
508 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
509 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
510
511 if (setlogin(pwd->pw_name) < 0)
512 syslog(LOG_ERR, "setlogin() failure: %m");
513
514 /* Discard permissions last so can't get killed and drop core. */
515 if (rootlogin)
516 (void)setuid(0);
517 else
518 (void)setuid(pwd->pw_uid);
519
520 /* Wait to change password until we're unprivileged */
521 if (need_chpass) {
522 if (!require_chpass)
523 (void)printf(
524 "Warning: your password has expired. Please change it as soon as possible.\n");
525 else {
526 (void)printf(
527 "Your password has expired. Please choose a new one.\n");
528 if (system(_PATH_BINPASSWD) != 0)
529 sleepexit(1);
530 }
531 }
532
533 execlp(pwd->pw_shell, tbuf, 0);
534 err(1, "%s", pwd->pw_shell);
535 }
536
537 #if defined(KERBEROS) || defined(KERBEROS5)
538 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
539 #else
540 #define NBUFSIZ (MAXLOGNAME + 1)
541 #endif
542
543 #if defined(KERBEROS) || defined(KERBEROS5)
544 /*
545 * This routine handles cleanup stuff, and the like.
546 * It exists only in the child process.
547 */
548 #include <sys/wait.h>
549 void
550 dofork()
551 {
552 int child;
553
554 if (!(child = fork()))
555 return; /* Child process */
556
557 /* Setup stuff? This would be things we could do in parallel with login */
558 (void) chdir("/"); /* Let's not keep the fs busy... */
559
560 /* If we're the parent, watch the child until it dies */
561 while (wait(0) != child)
562 ;
563
564 /* Cleanup stuff */
565 /* Run kdestroy to destroy tickets */
566 kdestroy();
567
568 /* Leave */
569 exit(0);
570 }
571 #endif
572
573 void
574 getloginname()
575 {
576 int ch;
577 char *p;
578 static char nbuf[NBUFSIZ];
579
580 for (;;) {
581 (void)printf("login: ");
582 for (p = nbuf; (ch = getchar()) != '\n'; ) {
583 if (ch == EOF) {
584 badlogin(username);
585 exit(0);
586 }
587 if (p < nbuf + (NBUFSIZ - 1))
588 *p++ = ch;
589 }
590 if (p > nbuf)
591 if (nbuf[0] == '-')
592 (void)fprintf(stderr,
593 "login names may not start with '-'.\n");
594 else {
595 *p = '\0';
596 username = nbuf;
597 break;
598 }
599 }
600 }
601
602 int
603 rootterm(ttyn)
604 char *ttyn;
605 {
606 struct ttyent *t;
607
608 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
609 }
610
611 jmp_buf motdinterrupt;
612
613 void
614 motd()
615 {
616 int fd, nchars;
617 sig_t oldint;
618 char tbuf[8192];
619
620 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
621 return;
622 oldint = signal(SIGINT, sigint);
623 if (setjmp(motdinterrupt) == 0)
624 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
625 (void)write(fileno(stdout), tbuf, nchars);
626 (void)signal(SIGINT, oldint);
627 (void)close(fd);
628 }
629
630 /* ARGSUSED */
631 void
632 sigint(signo)
633 int signo;
634 {
635 longjmp(motdinterrupt, 1);
636 }
637
638 /* ARGSUSED */
639 void
640 timedout(signo)
641 int signo;
642 {
643 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
644 exit(0);
645 }
646
647 void
648 checknologin()
649 {
650 int fd, nchars;
651 char tbuf[8192];
652
653 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
654 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
655 (void)write(fileno(stdout), tbuf, nchars);
656 sleepexit(0);
657 }
658 }
659
660 void
661 dolastlog(quiet)
662 int quiet;
663 {
664 struct lastlog ll;
665 int fd;
666
667 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
668 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
669 if (!quiet) {
670 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
671 ll.ll_time != 0) {
672 (void)printf("Last login: %.*s ",
673 24-5, (char *)ctime(&ll.ll_time));
674 if (*ll.ll_host != '\0')
675 (void)printf("from %.*s\n",
676 (int)sizeof(ll.ll_host),
677 ll.ll_host);
678 else
679 (void)printf("on %.*s\n",
680 (int)sizeof(ll.ll_line),
681 ll.ll_line);
682 }
683 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
684 SEEK_SET);
685 }
686 memset((void *)&ll, 0, sizeof(ll));
687 (void)time(&ll.ll_time);
688 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
689 if (hostname)
690 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
691 (void)write(fd, (char *)&ll, sizeof(ll));
692 (void)close(fd);
693 }
694 }
695
696 void
697 badlogin(name)
698 char *name;
699 {
700 if (failures == 0)
701 return;
702 if (hostname) {
703 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
704 failures, failures > 1 ? "S" : "", hostname);
705 syslog(LOG_AUTHPRIV|LOG_NOTICE,
706 "%d LOGIN FAILURE%s FROM %s, %s",
707 failures, failures > 1 ? "S" : "", hostname, name);
708 } else {
709 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
710 failures, failures > 1 ? "S" : "", tty);
711 syslog(LOG_AUTHPRIV|LOG_NOTICE,
712 "%d LOGIN FAILURE%s ON %s, %s",
713 failures, failures > 1 ? "S" : "", tty, name);
714 }
715 }
716
717 #undef UNKNOWN
718 #define UNKNOWN "su"
719
720 char *
721 stypeof(ttyid)
722 char *ttyid;
723 {
724 struct ttyent *t;
725
726 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
727 }
728
729 void
730 sleepexit(eval)
731 int eval;
732 {
733 (void)sleep(5);
734 exit(eval);
735 }
736