login.c revision 1.47 1 /* $NetBSD: login.c,v 1.47 2000/01/07 00:00:37 billc 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.47 2000/01/07 00:00:37 billc 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 #include <sys/wait.h>
62
63 #include <err.h>
64 #include <errno.h>
65 #include <grp.h>
66 #include <pwd.h>
67 #include <setjmp.h>
68 #include <signal.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <syslog.h>
73 #include <time.h>
74 #include <ttyent.h>
75 #include <tzfile.h>
76 #include <unistd.h>
77 #include <utmp.h>
78 #include <util.h>
79 #ifdef SKEY
80 #include <skey.h>
81 #endif
82 #ifdef KERBEROS5
83 #include <krb5/krb5.h>
84 #include <kerberosIV/com_err.h>
85 #endif
86
87 #include "pathnames.h"
88
89 void badlogin __P((char *));
90 void checknologin __P((void));
91 void dolastlog __P((int));
92 void getloginname __P((void));
93 int main __P((int, char *[]));
94 void motd __P((void));
95 int rootterm __P((char *));
96 void sigint __P((int));
97 void sleepexit __P((int));
98 const char *stypeof __P((const char *));
99 void timedout __P((int));
100 #if defined(KERBEROS) || defined(KERBEROS5)
101 int klogin __P((struct passwd *, char *, char *, char *));
102 void kdestroy __P((void));
103 void dofork __P((void));
104 #endif
105 #ifdef KERBEROS5
106 int k5_read_creds __P((char*));
107 int k5_write_creds __P((void));
108 #endif
109
110 #define TTYGRPNAME "tty" /* name of group to own ttys */
111
112 /*
113 * This bounds the time given to login. Not a define so it can
114 * be patched on machines where it's too small.
115 */
116 u_int timeout = 300;
117
118 #if defined(KERBEROS) || defined(KERBEROS5)
119 int notickets = 1;
120 char *instance;
121 char *krbtkfile_env;
122 #endif
123 #ifdef KERBEROS5
124 extern krb5_context kcontext;
125 extern int have_forward;
126 extern int use_krb5;
127 #endif
128
129 struct passwd *pwd;
130 int failures;
131 char term[64], *envinit[1], *hostname, *username, *tty;
132
133 static const char copyrightstr[] = "\
134 Copyright (c) 1996, 1997, 1998, 1999, 2000
135 \tThe NetBSD Foundation, Inc. All rights reserved.
136 Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
137 \tThe Regents of the University of California. All rights reserved.\n\n";
138
139 int
140 main(argc, argv)
141 int argc;
142 char *argv[];
143 {
144 extern char **environ;
145 struct group *gr;
146 struct stat st;
147 struct timeval tp;
148 struct utmp utmp;
149 int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
150 int Fflag;
151 uid_t uid, saved_uid;
152 gid_t saved_gid, saved_gids[NGROUPS_MAX];
153 int nsaved_gids;
154 char *domain, *p, *ttyn, *pwprompt;
155 const char *salt;
156 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
157 char localhost[MAXHOSTNAMELEN + 1];
158 int need_chpass, require_chpass;
159 #ifdef KERBEROS5
160 krb5_error_code kerror;
161 #endif
162
163 tbuf[0] = '\0';
164 rval = 0;
165 pwprompt = NULL;
166 need_chpass = require_chpass = 0;
167
168 (void)signal(SIGALRM, timedout);
169 (void)alarm(timeout);
170 (void)signal(SIGQUIT, SIG_IGN);
171 (void)signal(SIGINT, SIG_IGN);
172 (void)setpriority(PRIO_PROCESS, 0, 0);
173
174 openlog("login", LOG_ODELAY, LOG_AUTH);
175
176 /*
177 * -p is used by getty to tell login not to destroy the environment
178 * -f is used to skip a second login authentication
179 * -h is used by other servers to pass the name of the remote
180 * host to login so that it may be placed in utmp and wtmp
181 * -s is used to force use of S/Key or equivalent.
182 */
183 domain = NULL;
184 if (gethostname(localhost, sizeof(localhost)) < 0)
185 syslog(LOG_ERR, "couldn't get local hostname: %m");
186 else
187 domain = strchr(localhost, '.');
188 localhost[sizeof(localhost) - 1] = '\0';
189
190 Fflag = fflag = hflag = pflag = sflag = 0;
191 #ifdef KERBEROS5
192 have_forward = 0;
193 use_krb5 = 1;
194 #endif
195 uid = getuid();
196 while ((ch = getopt(argc, argv, "Ffh:ps")) != -1)
197 switch (ch) {
198 case 'F':
199 Fflag = 1;
200 /* FALLTHROUGH */
201 case 'f':
202 fflag = 1;
203 break;
204 case 'h':
205 if (uid)
206 errx(1, "-h option: %s", strerror(EPERM));
207 hflag = 1;
208 if (domain && (p = strchr(optarg, '.')) != NULL &&
209 strcasecmp(p, domain) == 0)
210 *p = 0;
211 hostname = optarg;
212 break;
213 case 'p':
214 pflag = 1;
215 break;
216 case 's':
217 sflag = 1;
218 break;
219 default:
220 case '?':
221 (void)fprintf(stderr,
222 "usage: login [-fps] [-h hostname] [username]\n");
223 exit(1);
224 }
225 argc -= optind;
226 argv += optind;
227
228 if (*argv) {
229 username = *argv;
230 ask = 0;
231 } else
232 ask = 1;
233
234 for (cnt = getdtablesize(); cnt > 2; cnt--)
235 (void)close(cnt);
236
237 ttyn = ttyname(STDIN_FILENO);
238 if (ttyn == NULL || *ttyn == '\0') {
239 (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
240 ttyn = tname;
241 }
242 if ((tty = strrchr(ttyn, '/')) != NULL)
243 ++tty;
244 else
245 tty = ttyn;
246
247 #ifdef KERBEROS5
248 kerror = krb5_init_context(&kcontext);
249 if (kerror) {
250 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
251 error_message(kerror));
252 use_krb5 = 0;
253 }
254 #endif KERBEROS5
255
256 for (cnt = 0;; ask = 1) {
257 #if defined(KERBEROS) || defined(KERBEROS5)
258 kdestroy();
259 #endif
260 if (ask) {
261 fflag = 0;
262 getloginname();
263 }
264 rootlogin = 0;
265 #ifdef KERBEROS
266 if ((instance = strchr(username, '.')) != NULL)
267 *instance++ = '\0';
268 else
269 instance = "";
270 #endif
271 #ifdef KERBEROS5
272 if ((instance = strchr(username, '/')) != NULL)
273 *instance++ = '\0';
274 else
275 instance = "";
276 #endif
277 if (strlen(username) > MAXLOGNAME)
278 username[MAXLOGNAME] = '\0';
279
280 /*
281 * Note if trying multiple user names; log failures for
282 * previous user name, but don't bother logging one failure
283 * for nonexistent name (mistyped username).
284 */
285 if (failures && strcmp(tbuf, username)) {
286 if (failures > (pwd ? 0 : 1))
287 badlogin(tbuf);
288 failures = 0;
289 }
290 (void)strncpy(tbuf, username, sizeof(tbuf) - 1);
291 tbuf[sizeof(tbuf) - 1] = '\0';
292
293 if ((pwd = getpwnam(username)) != NULL)
294 salt = pwd->pw_passwd;
295 else
296 salt = "xx";
297
298 /*
299 * if we have a valid account name, and it doesn't have a
300 * password, or the -f option was specified and the caller
301 * is root or the caller isn't changing their uid, don't
302 * authenticate.
303 */
304 if (pwd) {
305 if (pwd->pw_uid == 0)
306 rootlogin = 1;
307
308 if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
309 /* already authenticated */
310 #ifdef KERBEROS5
311 if (Fflag)
312 k5_read_creds(username);
313 #endif
314 break;
315 } else if (pwd->pw_passwd[0] == '\0') {
316 /* pretend password okay */
317 rval = 0;
318 goto ttycheck;
319 }
320 }
321
322 fflag = 0;
323
324 (void)setpriority(PRIO_PROCESS, 0, -4);
325
326 #ifdef SKEY
327 if (skey_haskey(username) == 0) {
328 static char skprompt[80];
329 char *skinfo = skey_keyinfo(username);
330
331 (void)snprintf(skprompt, sizeof(skprompt)-1,
332 "Password [%s]:",
333 skinfo ? skinfo : "error getting challenge");
334 pwprompt = skprompt;
335 } else
336 #endif
337 pwprompt = "Password:";
338
339 p = getpass(pwprompt);
340
341 if (pwd == NULL) {
342 rval = 1;
343 goto skip;
344 }
345 #ifdef KERBEROS
346 if (klogin(pwd, instance, localhost, p) == 0) {
347 rval = 0;
348 goto skip;
349 }
350 #endif
351 #ifdef KERBEROS5
352 if (klogin(pwd, instance, localhost, p) == 0) {
353 rval = 0;
354 goto skip;
355 }
356 #endif
357 #ifdef SKEY
358 if (skey_haskey(username) == 0 &&
359 skey_passcheck(username, p) != -1) {
360 rval = 0;
361 goto skip;
362 }
363 #endif
364 if (!sflag && *pwd->pw_passwd != '\0' &&
365 !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
366 rval = 0;
367 require_chpass = 1;
368 goto skip;
369 }
370 rval = 1;
371
372 skip:
373 memset(p, 0, strlen(p));
374
375 (void)setpriority(PRIO_PROCESS, 0, 0);
376
377 ttycheck:
378 /*
379 * If trying to log in as root without Kerberos,
380 * but with insecure terminal, refuse the login attempt.
381 */
382 if (pwd && !rval && rootlogin && !rootterm(tty)) {
383 (void)fprintf(stderr,
384 "%s login refused on this terminal.\n",
385 pwd->pw_name);
386 if (hostname)
387 syslog(LOG_NOTICE,
388 "LOGIN %s REFUSED FROM %s ON TTY %s",
389 pwd->pw_name, hostname, tty);
390 else
391 syslog(LOG_NOTICE,
392 "LOGIN %s REFUSED ON TTY %s",
393 pwd->pw_name, tty);
394 continue;
395 }
396
397 if (pwd && !rval)
398 break;
399
400 (void)printf("Login incorrect\n");
401 failures++;
402 /* we allow 10 tries, but after 3 we start backing off */
403 if (++cnt > 3) {
404 if (cnt >= 10) {
405 badlogin(username);
406 sleepexit(1);
407 }
408 sleep((u_int)((cnt - 3) * 5));
409 }
410 }
411
412 /* committed to login -- turn off timeout */
413 (void)alarm((u_int)0);
414
415 endpwent();
416
417 /* if user not super-user, check for disabled logins */
418 if (!rootlogin)
419 checknologin();
420
421 /* Temporarily give up special privileges so we can change */
422 /* into NFS-mounted homes that are exported for non-root */
423 /* access and have mode 7x0 */
424 saved_uid = geteuid();
425 saved_gid = getegid();
426 nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
427
428 (void)setegid(pwd->pw_gid);
429 initgroups(username, pwd->pw_gid);
430 (void)seteuid(pwd->pw_uid);
431
432 if (chdir(pwd->pw_dir) < 0) {
433 (void)printf("No home directory %s!\n", pwd->pw_dir);
434 if (chdir("/"))
435 exit(0);
436 pwd->pw_dir = "/";
437 (void)printf("Logging in with home = \"/\".\n");
438 }
439
440 quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
441
442 /* regain special privileges */
443 (void)seteuid(saved_uid);
444 setgroups(nsaved_gids, saved_gids);
445 (void)setegid(saved_gid);
446
447 if (pwd->pw_change || pwd->pw_expire)
448 (void)gettimeofday(&tp, (struct timezone *)NULL);
449 if (pwd->pw_expire) {
450 if (tp.tv_sec >= pwd->pw_expire) {
451 (void)printf("Sorry -- your account has expired.\n");
452 sleepexit(1);
453 } else if (pwd->pw_expire - tp.tv_sec <
454 _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
455 (void)printf("Warning: your account expires on %s",
456 ctime(&pwd->pw_expire));
457 }
458 if (pwd->pw_change) {
459 if (pwd->pw_change == _PASSWORD_CHGNOW)
460 need_chpass = 1;
461 else if (tp.tv_sec >= pwd->pw_change) {
462 (void)printf("Sorry -- your password has expired.\n");
463 sleepexit(1);
464 } else if (pwd->pw_change - tp.tv_sec <
465 _PASSWORD_WARNDAYS * SECSPERDAY && !quietlog)
466 (void)printf("Warning: your password expires on %s",
467 ctime(&pwd->pw_change));
468
469 }
470 /* Nothing else left to fail -- really log in. */
471 memset((void *)&utmp, 0, sizeof(utmp));
472 (void)time(&utmp.ut_time);
473 (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
474 if (hostname)
475 (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
476 (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
477 login(&utmp);
478
479 dolastlog(quietlog);
480
481 (void)chown(ttyn, pwd->pw_uid,
482 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
483
484 if (ttyaction(ttyn, "login", pwd->pw_name))
485 (void)printf("Warning: ttyaction failed.\n");
486
487 #if defined(KERBEROS) || defined(KERBEROS5)
488 /* Fork so that we can call kdestroy */
489 if (krbtkfile_env)
490 dofork();
491 #endif
492 (void)setgid(pwd->pw_gid);
493
494 initgroups(username, pwd->pw_gid);
495
496 if (*pwd->pw_shell == '\0')
497 pwd->pw_shell = _PATH_BSHELL;
498
499 /* Destroy environment unless user has requested its preservation. */
500 if (!pflag)
501 environ = envinit;
502 (void)setenv("HOME", pwd->pw_dir, 1);
503 (void)setenv("SHELL", pwd->pw_shell, 1);
504 if (term[0] == '\0')
505 (void)strncpy(term, stypeof(tty), sizeof(term));
506 (void)setenv("TERM", term, 0);
507 (void)setenv("LOGNAME", pwd->pw_name, 1);
508 (void)setenv("USER", pwd->pw_name, 1);
509 (void)setenv("PATH", _PATH_DEFPATH, 0);
510 #ifdef KERBEROS
511 if (krbtkfile_env)
512 (void)setenv("KRBTKFILE", krbtkfile_env, 1);
513 #endif
514 #ifdef KERBEROS5
515 if (krbtkfile_env)
516 (void)setenv("KRB5CCNAME", krbtkfile_env, 1);
517 #endif
518
519 if (tty[sizeof("tty")-1] == 'd')
520 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
521
522 /* If fflag is on, assume caller/authenticator has logged root login. */
523 if (rootlogin && fflag == 0) {
524 if (hostname)
525 syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
526 username, tty, hostname);
527 else
528 syslog(LOG_NOTICE,
529 "ROOT LOGIN (%s) ON %s", username, tty);
530 }
531
532 #if defined(KERBEROS) || defined(KERBEROS5)
533 if (!quietlog && notickets == 1)
534 (void)printf("Warning: no Kerberos tickets issued.\n");
535 #endif
536
537 if (!quietlog) {
538 (void)printf(copyrightstr);
539 motd();
540 (void)snprintf(tbuf,
541 sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
542 if (stat(tbuf, &st) == 0 && st.st_size != 0)
543 (void)printf("You have %smail.\n",
544 (st.st_mtime > st.st_atime) ? "new " : "");
545 }
546
547 (void)signal(SIGALRM, SIG_DFL);
548 (void)signal(SIGQUIT, SIG_DFL);
549 (void)signal(SIGINT, SIG_DFL);
550 (void)signal(SIGTSTP, SIG_IGN);
551
552 tbuf[0] = '-';
553 (void)strncpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
554 p + 1 : pwd->pw_shell, sizeof(tbuf) - 2);
555
556 if (setlogin(pwd->pw_name) < 0)
557 syslog(LOG_ERR, "setlogin() failure: %m");
558
559 /* Discard permissions last so can't get killed and drop core. */
560 if (rootlogin)
561 (void)setuid(0);
562 else
563 (void)setuid(pwd->pw_uid);
564
565 /* Wait to change password until we're unprivileged */
566 if (need_chpass) {
567 if (!require_chpass)
568 (void)printf(
569 "Warning: your password has expired. Please change it as soon as possible.\n");
570 else {
571 int status;
572
573 (void)printf(
574 "Your password has expired. Please choose a new one.\n");
575 switch (fork()) {
576 case -1:
577 warn("fork");
578 sleepexit(1);
579 case 0:
580 execl(_PATH_BINPASSWD, "passwd", 0);
581 _exit(1);
582 default:
583 if (wait(&status) == -1 ||
584 WEXITSTATUS(status))
585 sleepexit(1);
586 }
587 }
588 }
589
590 #ifdef KERBEROS5
591 k5_write_creds();
592 #endif
593 execlp(pwd->pw_shell, tbuf, 0);
594 err(1, "%s", pwd->pw_shell);
595 }
596
597 #if defined(KERBEROS) || defined(KERBEROS5)
598 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
599 #else
600 #define NBUFSIZ (MAXLOGNAME + 1)
601 #endif
602
603 #if defined(KERBEROS) || defined(KERBEROS5)
604 /*
605 * This routine handles cleanup stuff, and the like.
606 * It exists only in the child process.
607 */
608 #include <sys/wait.h>
609 void
610 dofork()
611 {
612 int child;
613
614 if (!(child = fork()))
615 return; /* Child process */
616
617 /* Setup stuff? This would be things we could do in parallel with login */
618 (void) chdir("/"); /* Let's not keep the fs busy... */
619
620 /* If we're the parent, watch the child until it dies */
621 while (wait(0) != child)
622 ;
623
624 /* Cleanup stuff */
625 /* Run kdestroy to destroy tickets */
626 kdestroy();
627
628 /* Leave */
629 exit(0);
630 }
631 #endif
632
633 void
634 getloginname()
635 {
636 int ch;
637 char *p;
638 static char nbuf[NBUFSIZ];
639
640 for (;;) {
641 (void)printf("login: ");
642 for (p = nbuf; (ch = getchar()) != '\n'; ) {
643 if (ch == EOF) {
644 badlogin(username);
645 exit(0);
646 }
647 if (p < nbuf + (NBUFSIZ - 1))
648 *p++ = ch;
649 }
650 if (p > nbuf) {
651 if (nbuf[0] == '-')
652 (void)fprintf(stderr,
653 "login names may not start with '-'.\n");
654 else {
655 *p = '\0';
656 username = nbuf;
657 break;
658 }
659 }
660 }
661 }
662
663 int
664 rootterm(ttyn)
665 char *ttyn;
666 {
667 struct ttyent *t;
668
669 return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
670 }
671
672 jmp_buf motdinterrupt;
673
674 void
675 motd()
676 {
677 int fd, nchars;
678 sig_t oldint;
679 char tbuf[8192];
680
681 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
682 return;
683 oldint = signal(SIGINT, sigint);
684 if (setjmp(motdinterrupt) == 0)
685 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
686 (void)write(fileno(stdout), tbuf, nchars);
687 (void)signal(SIGINT, oldint);
688 (void)close(fd);
689 }
690
691 /* ARGSUSED */
692 void
693 sigint(signo)
694 int signo;
695 {
696
697 longjmp(motdinterrupt, 1);
698 }
699
700 /* ARGSUSED */
701 void
702 timedout(signo)
703 int signo;
704 {
705
706 (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
707 exit(0);
708 }
709
710 void
711 checknologin()
712 {
713 int fd, nchars;
714 char tbuf[8192];
715
716 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
717 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
718 (void)write(fileno(stdout), tbuf, nchars);
719 sleepexit(0);
720 }
721 }
722
723 void
724 dolastlog(quiet)
725 int quiet;
726 {
727 struct lastlog ll;
728 int fd;
729
730 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
731 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
732 if (!quiet) {
733 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
734 ll.ll_time != 0) {
735 (void)printf("Last login: %.*s ",
736 24, (char *)ctime(&ll.ll_time));
737 if (*ll.ll_host != '\0')
738 (void)printf("from %.*s\n",
739 (int)sizeof(ll.ll_host),
740 ll.ll_host);
741 else
742 (void)printf("on %.*s\n",
743 (int)sizeof(ll.ll_line),
744 ll.ll_line);
745 }
746 (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
747 SEEK_SET);
748 }
749 memset((void *)&ll, 0, sizeof(ll));
750 (void)time(&ll.ll_time);
751 (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
752 if (hostname)
753 (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
754 (void)write(fd, (char *)&ll, sizeof(ll));
755 (void)close(fd);
756 }
757 }
758
759 void
760 badlogin(name)
761 char *name;
762 {
763 if (failures == 0)
764 return;
765 if (hostname) {
766 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
767 failures, failures > 1 ? "S" : "", hostname);
768 syslog(LOG_AUTHPRIV|LOG_NOTICE,
769 "%d LOGIN FAILURE%s FROM %s, %s",
770 failures, failures > 1 ? "S" : "", hostname, name);
771 } else {
772 syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
773 failures, failures > 1 ? "S" : "", tty);
774 syslog(LOG_AUTHPRIV|LOG_NOTICE,
775 "%d LOGIN FAILURE%s ON %s, %s",
776 failures, failures > 1 ? "S" : "", tty, name);
777 }
778 }
779
780 #undef UNKNOWN
781 #define UNKNOWN "su"
782
783 const char *
784 stypeof(ttyid)
785 const char *ttyid;
786 {
787 struct ttyent *t;
788
789 return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
790 }
791
792 void
793 sleepexit(eval)
794 int eval;
795 {
796
797 (void)sleep(5);
798 exit(eval);
799 }
800