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