xref: /original-bsd/usr.bin/login/login.c (revision 7b081c7c)
1 /*
2  * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)login.c	5.49 (Berkeley) 02/02/90";
26 #endif /* not lint */
27 
28 /*
29  * login [ name ]
30  * login -h hostname	(for telnetd, etc.)
31  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
32  */
33 
34 #include <sys/param.h>
35 #include <ufs/quota.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/resource.h>
39 #include <sys/file.h>
40 #include <sgtty.h>
41 
42 #include <utmp.h>
43 #include <signal.h>
44 #include <errno.h>
45 #include <ttyent.h>
46 #include <syslog.h>
47 #include <grp.h>
48 #include <pwd.h>
49 #include <setjmp.h>
50 #include <stdio.h>
51 #include <strings.h>
52 #include <tzfile.h>
53 #include "pathnames.h"
54 
55 #ifdef	KERBEROS
56 #include <krb.h>
57 #include <netdb.h>
58 char		realm[REALM_SZ];
59 int		kerror = KSUCCESS, notickets = 1;
60 KTEXT_ST	ticket;
61 AUTH_DAT	authdata;
62 char		savehost[MAXHOSTNAMELEN];
63 char		tkfile[MAXPATHLEN];
64 unsigned long	faddr;
65 struct	hostent	*hp;
66 #define	PRINCIPAL_NAME	pwd->pw_name
67 #define	PRINCIPAL_INST	""
68 #define	INITIAL_TICKET	"krbtgt"
69 #define	VERIFY_SERVICE	"rcmd"
70 #endif
71 
72 #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
73 
74 /*
75  * This bounds the time given to login.  Not a define so it can
76  * be patched on machines where it's too small.
77  */
78 int	timeout = 300;
79 
80 struct	passwd *pwd;
81 int	failures;
82 char	term[64], *hostname, *username, *tty;
83 
84 struct	sgttyb sgttyb;
85 struct	tchars tc = {
86 	CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
87 };
88 struct	ltchars ltc = {
89 	CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
90 };
91 
92 char *months[] =
93 	{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
94 	  "Sep", "Oct", "Nov", "Dec" };
95 
96 main(argc, argv)
97 	int argc;
98 	char **argv;
99 {
100 	extern int errno, optind;
101 	extern char *optarg, **environ;
102 	struct timeval tp;
103 	struct tm *ttp;
104 	struct group *gr;
105 	register int ch;
106 	register char *p;
107 	int ask, fflag, hflag, pflag, cnt, uid;
108 	int quietlog, passwd_req, ioctlval, timedout();
109 	char *domain, *salt, *envinit[1], *ttyn, *pp;
110 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
111 	char localhost[MAXHOSTNAMELEN];
112 	char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass();
113 	time_t time();
114 	off_t lseek();
115 
116 	(void)signal(SIGALRM, timedout);
117 	(void)alarm((u_int)timeout);
118 	(void)signal(SIGQUIT, SIG_IGN);
119 	(void)signal(SIGINT, SIG_IGN);
120 	(void)setpriority(PRIO_PROCESS, 0, 0);
121 	(void)quota(Q_SETUID, 0, 0, 0);
122 
123 	/*
124 	 * -p is used by getty to tell login not to destroy the environment
125  	 * -f is used to skip a second login authentication
126 	 * -h is used by other servers to pass the name of the remote
127 	 *    host to login so that it may be placed in utmp and wtmp
128 	 */
129 	domain = NULL;
130 	if (gethostname(localhost, sizeof(localhost)) < 0)
131 		syslog(LOG_ERR, "couldn't get local hostname: %m");
132 	else
133 		domain = index(localhost, '.');
134 
135 	openlog("login", LOG_ODELAY, LOG_AUTH);
136 
137 	fflag = hflag = pflag = 0;
138 	passwd_req = 1;
139 	uid = getuid();
140 	while ((ch = getopt(argc, argv, "fh:p")) != EOF)
141 		switch (ch) {
142 		case 'f':
143 			fflag = 1;
144 			break;
145 		case 'h':
146 			if (uid) {
147 				(void)fprintf(stderr,
148 				    "login: -h for super-user only.\n");
149 				exit(1);
150 			}
151 			hflag = 1;
152 			if (domain && (p = index(optarg, '.')) &&
153 			    strcasecmp(p, domain) == 0)
154 				*p = 0;
155 			hostname = optarg;
156 			break;
157 		case 'p':
158 			pflag = 1;
159 			break;
160 		case '?':
161 		default:
162 			if (!uid)
163 				syslog(LOG_ERR, "invalid flag %c", ch);
164 			(void)fprintf(stderr,
165 			    "usage: login [-fp] [username]\n");
166 			exit(1);
167 		}
168 	argc -= optind;
169 	argv += optind;
170 	if (*argv) {
171 		username = *argv;
172 		ask = 0;
173 	} else
174 		ask = 1;
175 
176 	ioctlval = 0;
177 	(void)ioctl(0, TIOCLSET, &ioctlval);
178 	(void)ioctl(0, TIOCNXCL, 0);
179 	(void)fcntl(0, F_SETFL, ioctlval);
180 	(void)ioctl(0, TIOCGETP, &sgttyb);
181 	sgttyb.sg_erase = CERASE;
182 	sgttyb.sg_kill = CKILL;
183 	(void)ioctl(0, TIOCSLTC, &ltc);
184 	(void)ioctl(0, TIOCSETC, &tc);
185 	(void)ioctl(0, TIOCSETP, &sgttyb);
186 
187 	for (cnt = getdtablesize(); cnt > 2; cnt--)
188 		close(cnt);
189 
190 	ttyn = ttyname(0);
191 	if (ttyn == NULL || *ttyn == '\0') {
192 		(void)sprintf(tname, "%s??", _PATH_TTY);
193 		ttyn = tname;
194 	}
195 	if (tty = rindex(ttyn, '/'))
196 		++tty;
197 	else
198 		tty = ttyn;
199 
200 	for (cnt = 0;; ask = 1) {
201 		ioctlval = TTYDISC;
202 		(void)ioctl(0, TIOCSETD, &ioctlval);
203 
204 		if (ask) {
205 			fflag = 0;
206 			getloginname();
207 		}
208 		/*
209 		 * Note if trying multiple user names; log failures for
210 		 * previous user name, but don't bother logging one failure
211 		 * for nonexistent name (mistyped username).
212 		 */
213 		if (failures && strcmp(tbuf, username)) {
214 			if (failures > (pwd ? 0 : 1))
215 				badlogin(tbuf);
216 			failures = 0;
217 		}
218 		(void)strcpy(tbuf, username);
219 		if (pwd = getpwnam(username))
220 			salt = pwd->pw_passwd;
221 		else
222 			salt = "xx";
223 
224 		/* if user not super-user, check for disabled logins */
225 		if (pwd == NULL || pwd->pw_uid)
226 			checknologin();
227 
228 		/*
229 		 * Disallow automatic login to root; if not invoked by
230 		 * root, disallow if the uid's differ.
231 		 */
232 		if (fflag && pwd) {
233 			passwd_req =
234 #ifndef	KERBEROS
235 			     pwd->pw_uid == 0 ||
236 #endif
237 			    (uid && uid != pwd->pw_uid);
238 		}
239 
240 		/*
241 		 * If no pre-authentication and a password exists
242 		 * for this user, prompt for one and verify it.
243 		 */
244 		if (!passwd_req || (pwd && !*pwd->pw_passwd))
245 			break;
246 
247 		/*
248 		 * If trying to log in as root, but with insecure terminal,
249 		 * refuse the login attempt.
250 		 */
251 		if (pwd->pw_uid == 0 && !rootterm(tty)) {
252 			(void)fprintf(stderr,
253 			    "%s login refused on this terminal.\n",
254 			    pwd->pw_name);
255 			if (hostname)
256 				syslog(LOG_NOTICE,
257 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
258 				    pwd->pw_name, hostname, tty);
259 			else
260 				syslog(LOG_NOTICE,
261 				    "LOGIN %s REFUSED ON TTY %s",
262 				     pwd->pw_name, tty);
263 			continue;
264 		}
265 
266 		setpriority(PRIO_PROCESS, 0, -4);
267 		pp = getpass("Password:");
268 		p = crypt(pp, salt);
269 		setpriority(PRIO_PROCESS, 0, 0);
270 
271 #ifdef	KERBEROS
272 
273 		/*
274 		 * If not present in pw file, act as old login would.
275 		 * If we aren't Kerberos-authenticated, try the normal
276 		 * pw file for a password.  If that's ok, log the user
277 		 * in without issueing any tickets.
278 		 */
279 
280 		if (pwd && (krb_get_lrealm(realm,1) == KSUCCESS)) {
281 
282 			/*
283 			 * get TGT for local realm
284 			 * convention: store tickets in file associated
285 			 * with tty name, which should be available
286 			 */
287 			(void)sprintf(tkfile, "%s_%s", TKT_ROOT, tty);
288 			kerror = INTK_ERR;
289 			if (setenv("KRBTKFILE", tkfile, 1) < 0)
290 				syslog(LOG_ERR, "couldn't set tkfile environ");
291 			else {
292 				(void) unlink(tkfile);
293 				kerror = krb_get_pw_in_tkt(
294 					PRINCIPAL_NAME,	/* user */
295 					PRINCIPAL_INST,	/* (null) */
296 					realm,
297 					INITIAL_TICKET, realm,
298 					DEFAULT_TKT_LIFE,
299 					pp);
300 			}
301 			/*
302 			 * If we got a TGT, get a local "rcmd" ticket and
303 			 * check it so as to ensure that we are not
304 			 * talking to a bogus Kerberos server
305 			 *
306 			 * There are 2 cases where we still allow a login:
307 			 *	1> the VERIFY_SERVICE doesn't exist in the KDC
308 			 *	2> local host has no srvtab, as (hopefully)
309 			 *	   indicated by a return value of RD_AP_UNDEC
310 			 *	   from krb_rd_req()
311 			 */
312 			if (kerror == INTK_OK) {
313 				if (chown(tkfile, pwd->pw_uid, pwd->pw_gid) < 0)
314 					syslog(LOG_ERR, "chown tkfile: %m");
315 				(void) strncpy(savehost,
316 					krb_get_phost(localhost),
317 					sizeof(savehost));
318 				savehost[sizeof(savehost)-1] = NULL;
319 				kerror = krb_mk_req(&ticket, VERIFY_SERVICE,
320 					savehost, realm, 33);
321 				/*
322 				 * if the "VERIFY_SERVICE" doesn't exist in
323 				 * the KDC for this host, still allow login,
324 				 * but log the error condition
325 				 */
326 				if (kerror == KDC_PR_UNKNOWN) {
327 					syslog(LOG_NOTICE,
328 					    "Warning: TGT not verified (%s)",
329 						krb_err_txt[kerror]);
330 					bzero(pp, strlen(pp));
331 					notickets = 0;
332 					break;		/* ok */
333 				} else if (kerror != KSUCCESS) {
334 					printf("Unable to use TGT: (%s)\n",
335 						krb_err_txt[kerror]);
336 					syslog(LOG_NOTICE,
337 					    "Unable to use TGT: (%s)",
338 						krb_err_txt[kerror]);
339 					dest_tkt();
340 					/* fall thru: no login */
341 				} else {
342 					if (!(hp = gethostbyname(localhost))) {
343 						syslog(LOG_ERR,
344 						    "couldn't get local host address");
345 					} else {
346 					    bcopy((char *) hp->h_addr,
347 						(char *) &faddr, sizeof(faddr));
348 					    if ((kerror = krb_rd_req(&ticket,
349 						VERIFY_SERVICE, savehost, faddr,
350 						&authdata, "")) != KSUCCESS) {
351 
352 						if (kerror = RD_AP_UNDEC) {
353 							syslog(LOG_NOTICE,
354 							  "krb_rd_req: (%s)\n",
355 							  krb_err_txt[kerror]);
356 							bzero(pp, strlen(pp));
357 							notickets = 0;
358 							break;	/* ok */
359 						} else {
360 						    printf("Unable to verify %s ticket: (%s)\n",
361 							VERIFY_SERVICE,
362 							krb_err_txt[kerror]);
363 						    syslog(LOG_NOTICE,
364 						    "couldn't verify %s ticket: %s",
365 							VERIFY_SERVICE,
366 							krb_err_txt[kerror]);
367 						}
368 						/* fall thru: no login */
369 					    } else {
370 						bzero(pp, strlen(pp));
371 						notickets = 0;	/* got ticket */
372 						break;		/* ok */
373 					    }
374 					}
375 				}
376 
377 			} else {
378 				(void) unlink(tkfile);
379 				if ((kerror != INTK_BADPW) &&
380 				    kerror != KDC_PR_UNKNOWN)
381 					syslog(LOG_ERR,
382 						"Kerberos intkt error: %s",
383 						krb_err_txt[kerror]);
384 			}
385 		}
386 
387 #endif
388 		(void) bzero(pp, strlen(pp));
389 		if (pwd && !strcmp(p, pwd->pw_passwd))
390 			break;
391 
392 		(void)printf("Login incorrect\n");
393 		failures++;
394 		/* we allow 10 tries, but after 3 we start backing off */
395 		if (++cnt > 3) {
396 			if (cnt >= 10) {
397 				badlogin(username);
398 				(void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL);
399 				sleepexit(1);
400 			}
401 			sleep((u_int)((cnt - 3) * 5));
402 		}
403 	}
404 
405 	/* committed to login -- turn off timeout */
406 	(void)alarm((u_int)0);
407 
408 	/* paranoia... */
409 	endpwent();
410 
411 	if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
412 		switch(errno) {
413 		case EUSERS:
414 			(void)fprintf(stderr,
415 		"Too many users logged on already.\nTry again later.\n");
416 			break;
417 		case EPROCLIM:
418 			(void)fprintf(stderr,
419 			    "You have too many processes running.\n");
420 			break;
421 		default:
422 			perror("quota (Q_SETUID)");
423 		}
424 		sleepexit(0);
425 	}
426 
427 	if (chdir(pwd->pw_dir) < 0) {
428 		(void)printf("No directory %s!\n", pwd->pw_dir);
429 		if (chdir("/"))
430 			exit(0);
431 		pwd->pw_dir = "/";
432 		(void)printf("Logging in with home = \"/\".\n");
433 	}
434 
435 	quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
436 
437 #ifdef KERBEROS
438 	if (notickets && !quietlog)
439 		(void)printf("Warning: no Kerberos tickets issued\n");
440 #endif
441 
442 	if (pwd->pw_change || pwd->pw_expire)
443 		(void)gettimeofday(&tp, (struct timezone *)NULL);
444 	if (pwd->pw_change)
445 		if (tp.tv_sec >= pwd->pw_change) {
446 			(void)printf("Sorry -- your password has expired.\n");
447 			sleepexit(1);
448 		}
449 		else if (pwd->pw_change - tp.tv_sec <
450 		    2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
451 			ttp = localtime(&pwd->pw_change);
452 			(void)printf("Warning: your password expires on %s %d, %d\n",
453 			    months[ttp->tm_mon], ttp->tm_mday,
454 			    TM_YEAR_BASE + ttp->tm_year);
455 		}
456 	if (pwd->pw_expire)
457 		if (tp.tv_sec >= pwd->pw_expire) {
458 			(void)printf("Sorry -- your account has expired.\n");
459 			sleepexit(1);
460 		}
461 		else if (pwd->pw_expire - tp.tv_sec <
462 		    2 * DAYSPERWEEK * SECSPERDAY && !quietlog) {
463 			ttp = localtime(&pwd->pw_expire);
464 			(void)printf("Warning: your account expires on %s %d, %d\n",
465 			    months[ttp->tm_mon], ttp->tm_mday,
466 			    TM_YEAR_BASE + ttp->tm_year);
467 		}
468 
469 	/* nothing else left to fail -- really log in */
470 	{
471 		struct utmp utmp;
472 
473 		bzero((char *)&utmp, sizeof(utmp));
474 		(void)time(&utmp.ut_time);
475 		strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
476 		if (hostname)
477 			strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
478 		strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
479 		login(&utmp);
480 	}
481 
482 	dolastlog(quietlog);
483 
484 	if (!hflag) {					/* XXX */
485 		static struct winsize win = { 0, 0, 0, 0 };
486 
487 		(void)ioctl(0, TIOCSWINSZ, &win);
488 	}
489 
490 	(void)chown(ttyn, pwd->pw_uid,
491 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
492 	(void)chmod(ttyn, 0620);
493 	(void)setgid(pwd->pw_gid);
494 
495 	initgroups(username, pwd->pw_gid);
496 
497 	quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
498 
499 	if (*pwd->pw_shell == '\0')
500 		pwd->pw_shell = _PATH_BSHELL;
501 
502 	/* destroy environment unless user has requested preservation */
503 	if (!pflag)
504 		environ = envinit;
505 	(void)setenv("HOME", pwd->pw_dir, 1);
506 	(void)setenv("SHELL", pwd->pw_shell, 1);
507 	if (term[0] == '\0')
508 		strncpy(term, stypeof(tty), sizeof(term));
509 	(void)setenv("TERM", term, 0);
510 	(void)setenv("USER", pwd->pw_name, 1);
511 	(void)setenv("PATH", _PATH_DEFPATH, 0);
512 
513 	if (tty[sizeof("tty")-1] == 'd')
514 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
515 	if (pwd->pw_uid == 0)
516 		if (hostname)
517 			syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s",
518 			    tty, hostname);
519 		else
520 			syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty);
521 
522 	if (!quietlog) {
523 		struct stat st;
524 
525 		motd();
526 		(void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
527 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
528 			(void)printf("You have %smail.\n",
529 			    (st.st_mtime > st.st_atime) ? "new " : "");
530 	}
531 
532 	(void)signal(SIGALRM, SIG_DFL);
533 	(void)signal(SIGQUIT, SIG_DFL);
534 	(void)signal(SIGINT, SIG_DFL);
535 	(void)signal(SIGTSTP, SIG_IGN);
536 
537 	tbuf[0] = '-';
538 	strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
539 	    p + 1 : pwd->pw_shell);
540 
541 	if (setlogin(pwd->pw_name) < 0)
542 		syslog(LOG_ERR, "setlogin() failure: %m");
543 
544 	/* discard permissions last so can't get killed and drop core */
545 	(void)setuid(pwd->pw_uid);
546 
547 	execlp(pwd->pw_shell, tbuf, 0);
548 	(void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno));
549 	exit(0);
550 }
551 
552 getloginname()
553 {
554 	register int ch;
555 	register char *p;
556 	static char nbuf[UT_NAMESIZE + 1];
557 
558 	for (;;) {
559 		(void)printf("login: ");
560 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
561 			if (ch == EOF) {
562 				badlogin(username);
563 				exit(0);
564 			}
565 			if (p < nbuf + UT_NAMESIZE)
566 				*p++ = ch;
567 		}
568 		if (p > nbuf)
569 			if (nbuf[0] == '-')
570 				(void)fprintf(stderr,
571 				    "login names may not start with '-'.\n");
572 			else {
573 				*p = '\0';
574 				username = nbuf;
575 				break;
576 			}
577 	}
578 }
579 
580 timedout()
581 {
582 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
583 	exit(0);
584 }
585 
586 rootterm(ttyn)
587 	char *ttyn;
588 {
589 	struct ttyent *t;
590 
591 	return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE);
592 }
593 
594 jmp_buf motdinterrupt;
595 
596 motd()
597 {
598 	register int fd, nchars;
599 	sig_t oldint;
600 	int sigint();
601 	char tbuf[8192];
602 
603 	if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
604 		return;
605 	oldint = signal(SIGINT, sigint);
606 	if (setjmp(motdinterrupt) == 0)
607 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
608 			(void)write(fileno(stdout), tbuf, nchars);
609 	(void)signal(SIGINT, oldint);
610 	(void)close(fd);
611 }
612 
613 sigint()
614 {
615 	longjmp(motdinterrupt, 1);
616 }
617 
618 checknologin()
619 {
620 	register int fd, nchars;
621 	char tbuf[8192];
622 
623 	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
624 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
625 			(void)write(fileno(stdout), tbuf, nchars);
626 		sleepexit(0);
627 	}
628 }
629 
630 dolastlog(quiet)
631 	int quiet;
632 {
633 	struct lastlog ll;
634 	int fd;
635 	char *ctime();
636 
637 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
638 		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
639 		if (!quiet) {
640 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
641 			    ll.ll_time != 0) {
642 				(void)printf("Last login: %.*s ",
643 				    24-5, (char *)ctime(&ll.ll_time));
644 				if (*ll.ll_host != '\0')
645 					(void)printf("from %.*s\n",
646 					    sizeof(ll.ll_host), ll.ll_host);
647 				else
648 					(void)printf("on %.*s\n",
649 					    sizeof(ll.ll_line), ll.ll_line);
650 			}
651 			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
652 		}
653 		bzero((char *)&ll, sizeof(ll));
654 		(void)time(&ll.ll_time);
655 		strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
656 		if (hostname)
657 			strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
658 		(void)write(fd, (char *)&ll, sizeof(ll));
659 		(void)close(fd);
660 	}
661 }
662 
663 badlogin(name)
664 	char *name;
665 {
666 	if (failures == 0)
667 		return;
668 	if (hostname)
669 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s",
670 		    failures, failures > 1 ? "S" : "", hostname, name);
671 	else
672 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s",
673 		    failures, failures > 1 ? "S" : "", tty, name);
674 }
675 
676 #undef	UNKNOWN
677 #define	UNKNOWN	"su"
678 
679 char *
680 stypeof(ttyid)
681 	char *ttyid;
682 {
683 	struct ttyent *t;
684 
685 	return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
686 }
687 
688 getstr(buf, cnt, err)
689 	char *buf, *err;
690 	int cnt;
691 {
692 	char ch;
693 
694 	do {
695 		if (read(0, &ch, sizeof(ch)) != sizeof(ch))
696 			exit(1);
697 		if (--cnt < 0) {
698 			(void)fprintf(stderr, "%s too long\r\n", err);
699 			sleepexit(1);
700 		}
701 		*buf++ = ch;
702 	} while (ch);
703 }
704 
705 sleepexit(eval)
706 	int eval;
707 {
708 	sleep((u_int)5);
709 	exit(eval);
710 }
711