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