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