Home | History | Annotate | Line # | Download | only in login
login.c revision 1.82.2.2.2.1
      1      1.82.2.1     jwise /*     $NetBSD: login.c,v 1.82.2.2.2.1 2006/03/09 16:48:47 tron Exp $       */
      2          1.12       jtc 
      3           1.1       cgd /*-
      4          1.12       jtc  * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
      5          1.10    brezak  *	The Regents of the University of California.  All rights reserved.
      6           1.1       cgd  *
      7           1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8           1.1       cgd  * modification, are permitted provided that the following conditions
      9           1.1       cgd  * are met:
     10           1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11           1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12           1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13           1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14           1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15          1.73       agc  * 3. Neither the name of the University nor the names of its contributors
     16           1.1       cgd  *    may be used to endorse or promote products derived from this software
     17           1.1       cgd  *    without specific prior written permission.
     18           1.1       cgd  *
     19           1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20           1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21           1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22           1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23           1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24           1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25           1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26           1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27           1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28           1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29           1.1       cgd  * SUCH DAMAGE.
     30           1.1       cgd  */
     31           1.1       cgd 
     32          1.24     lukem #include <sys/cdefs.h>
     33           1.1       cgd #ifndef lint
     34          1.24     lukem __COPYRIGHT(
     35          1.12       jtc "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
     36          1.24     lukem 	The Regents of the University of California.  All rights reserved.\n");
     37           1.1       cgd #endif /* not lint */
     38           1.1       cgd 
     39           1.1       cgd #ifndef lint
     40          1.12       jtc #if 0
     41          1.12       jtc static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
     42          1.12       jtc #endif
     43      1.82.2.1     jwise __RCSID("$NetBSD: login.c,v 1.82.2.2.2.1 2006/03/09 16:48:47 tron Exp $");
     44           1.1       cgd #endif /* not lint */
     45           1.1       cgd 
     46           1.1       cgd /*
     47           1.1       cgd  * login [ name ]
     48           1.1       cgd  * login -h hostname	(for telnetd, etc.)
     49           1.1       cgd  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
     50           1.1       cgd  */
     51           1.1       cgd 
     52           1.1       cgd #include <sys/param.h>
     53           1.1       cgd #include <sys/stat.h>
     54           1.1       cgd #include <sys/time.h>
     55           1.1       cgd #include <sys/resource.h>
     56           1.1       cgd #include <sys/file.h>
     57          1.38       mrg #include <sys/wait.h>
     58          1.67  christos #include <sys/socket.h>
     59           1.1       cgd 
     60          1.12       jtc #include <err.h>
     61           1.5       cgd #include <errno.h>
     62           1.1       cgd #include <grp.h>
     63           1.1       cgd #include <pwd.h>
     64          1.12       jtc #include <setjmp.h>
     65          1.12       jtc #include <signal.h>
     66          1.19     veego #include <stdio.h>
     67           1.5       cgd #include <stdlib.h>
     68           1.1       cgd #include <string.h>
     69          1.12       jtc #include <syslog.h>
     70          1.36    kleink #include <time.h>
     71          1.12       jtc #include <ttyent.h>
     72          1.12       jtc #include <tzfile.h>
     73          1.12       jtc #include <unistd.h>
     74          1.67  christos #ifdef SUPPORT_UTMP
     75          1.12       jtc #include <utmp.h>
     76          1.66  christos #endif
     77          1.67  christos #ifdef SUPPORT_UTMPX
     78          1.66  christos #include <utmpx.h>
     79          1.66  christos #endif
     80          1.13       jtc #include <util.h>
     81          1.29   mycroft #ifdef SKEY
     82          1.29   mycroft #include <skey.h>
     83          1.29   mycroft #endif
     84          1.25   mycroft #ifdef KERBEROS5
     85          1.45  christos #include <krb5/krb5.h>
     86          1.54     aidan #include <com_err.h>
     87          1.25   mycroft #endif
     88          1.48       mjl #ifdef LOGIN_CAP
     89          1.48       mjl #include <login_cap.h>
     90          1.48       mjl #endif
     91          1.79  christos #include <vis.h>
     92          1.25   mycroft 
     93           1.1       cgd #include "pathnames.h"
     94           1.1       cgd 
     95          1.57     aidan #ifdef KERBEROS5
     96          1.57     aidan int login_krb5_get_tickets = 1;
     97          1.57     aidan int login_krb4_get_tickets = 0;
     98          1.57     aidan int login_krb5_forwardable_tgt = 0;
     99          1.57     aidan int login_krb5_retain_ccache = 0;
    100          1.57     aidan #endif
    101          1.57     aidan 
    102          1.81   xtraeme void	 badlogin(char *);
    103          1.81   xtraeme void	 checknologin(char *);
    104          1.67  christos #ifdef SUPPORT_UTMP
    105          1.81   xtraeme static void	 doutmp(void);
    106          1.81   xtraeme static void	 dolastlog(int);
    107          1.66  christos #endif
    108          1.67  christos #ifdef SUPPORT_UTMPX
    109          1.81   xtraeme static void	 doutmpx(void);
    110          1.81   xtraeme static void	 dolastlogx(int);
    111          1.66  christos #endif
    112          1.81   xtraeme static void	 update_db(int);
    113          1.81   xtraeme void	 getloginname(void);
    114          1.81   xtraeme void	 motd(char *);
    115          1.81   xtraeme int	 rootterm(char *);
    116          1.81   xtraeme void	 sigint(int);
    117          1.81   xtraeme void	 sleepexit(int);
    118          1.81   xtraeme const	 char *stypeof(const char *);
    119          1.81   xtraeme void	 timedout(int);
    120          1.57     aidan #if defined(KERBEROS)
    121          1.81   xtraeme int	 klogin(struct passwd *, char *, char *, char *);
    122          1.81   xtraeme void	 kdestroy(void);
    123           1.5       cgd #endif
    124          1.44     aidan #ifdef KERBEROS5
    125          1.81   xtraeme int	 k5login(struct passwd *, char *, char *, char *);
    126          1.81   xtraeme void	 k5destroy(void);
    127          1.81   xtraeme int	 k5_read_creds(char*);
    128          1.81   xtraeme int	 k5_write_creds(void);
    129          1.57     aidan #endif
    130          1.57     aidan #if defined(KERBEROS) || defined(KERBEROS5)
    131          1.81   xtraeme void	 dofork(void);
    132          1.44     aidan #endif
    133          1.81   xtraeme void	 decode_ss(const char *);
    134          1.81   xtraeme void	 usage(void);
    135          1.12       jtc 
    136           1.1       cgd #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
    137           1.1       cgd 
    138          1.50       mjl #define DEFAULT_BACKOFF 3
    139          1.50       mjl #define DEFAULT_RETRIES 10
    140          1.48       mjl 
    141           1.1       cgd /*
    142           1.1       cgd  * This bounds the time given to login.  Not a define so it can
    143           1.1       cgd  * be patched on machines where it's too small.
    144           1.1       cgd  */
    145          1.12       jtc u_int	timeout = 300;
    146           1.5       cgd 
    147          1.10    brezak #if defined(KERBEROS) || defined(KERBEROS5)
    148           1.1       cgd int	notickets = 1;
    149           1.1       cgd char	*instance;
    150          1.57     aidan int	has_ccache = 0;
    151          1.57     aidan #endif
    152          1.57     aidan #ifdef KERBEROS
    153          1.57     aidan extern char	*krbtkfile_env;
    154          1.60   thorpej extern int	krb_configured;
    155           1.1       cgd #endif
    156          1.25   mycroft #ifdef KERBEROS5
    157          1.25   mycroft extern krb5_context kcontext;
    158          1.44     aidan extern int	have_forward;
    159          1.57     aidan extern char	*krb5tkfile_env;
    160          1.60   thorpej extern int	krb5_configured;
    161          1.60   thorpej #endif
    162          1.60   thorpej 
    163          1.60   thorpej #if defined(KERBEROS) && defined(KERBEROS5)
    164          1.60   thorpej #define	KERBEROS_CONFIGURED	(krb_configured || krb5_configured)
    165          1.60   thorpej #elif defined(KERBEROS)
    166          1.60   thorpej #define	KERBEROS_CONFIGURED	krb_configured
    167          1.60   thorpej #elif defined(KERBEROS5)
    168          1.60   thorpej #define	KERBEROS_CONFIGURED	krb5_configured
    169          1.25   mycroft #endif
    170           1.1       cgd 
    171           1.1       cgd struct	passwd *pwd;
    172          1.79  christos int	failures, have_ss;
    173          1.70    itojun char	term[64], *envinit[1], *hostname, *username, *tty, *nested;
    174          1.66  christos struct timeval now;
    175          1.66  christos struct sockaddr_storage ss;
    176           1.1       cgd 
    177          1.77     lukem extern const char copyrightstr[];
    178          1.34   thorpej 
    179           1.5       cgd int
    180          1.80   xtraeme main(int argc, char *argv[])
    181           1.1       cgd {
    182           1.5       cgd 	extern char **environ;
    183           1.5       cgd 	struct group *gr;
    184           1.5       cgd 	struct stat st;
    185          1.29   mycroft 	int ask, ch, cnt, fflag, hflag, pflag, sflag, quietlog, rootlogin, rval;
    186          1.44     aidan 	int Fflag;
    187          1.33   hubertf 	uid_t uid, saved_uid;
    188          1.35   hubertf 	gid_t saved_gid, saved_gids[NGROUPS_MAX];
    189          1.35   hubertf 	int nsaved_gids;
    190          1.39   mycroft 	char *domain, *p, *ttyn, *pwprompt;
    191          1.39   mycroft 	const char *salt;
    192           1.1       cgd 	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
    193          1.37       mrg 	char localhost[MAXHOSTNAMELEN + 1];
    194          1.29   mycroft 	int need_chpass, require_chpass;
    195          1.48       mjl 	int login_retries = DEFAULT_RETRIES,
    196          1.48       mjl 	    login_backoff = DEFAULT_BACKOFF;
    197          1.48       mjl 	time_t pw_warntime = _PASSWORD_WARNDAYS * SECSPERDAY;
    198          1.25   mycroft #ifdef KERBEROS5
    199          1.25   mycroft 	krb5_error_code kerror;
    200          1.25   mycroft #endif
    201          1.57     aidan #if defined(KERBEROS) || defined(KERBEROS5)
    202          1.57     aidan 	int got_tickets = 0;
    203          1.57     aidan #endif
    204          1.48       mjl #ifdef LOGIN_CAP
    205          1.49       mjl 	char *shell = NULL;
    206          1.48       mjl 	login_cap_t *lc = NULL;
    207          1.48       mjl #endif
    208           1.1       cgd 
    209          1.20     lukem 	tbuf[0] = '\0';
    210          1.20     lukem 	rval = 0;
    211          1.20     lukem 	pwprompt = NULL;
    212          1.70    itojun 	nested = NULL;
    213          1.29   mycroft 	need_chpass = require_chpass = 0;
    214          1.20     lukem 
    215           1.1       cgd 	(void)signal(SIGALRM, timedout);
    216          1.12       jtc 	(void)alarm(timeout);
    217           1.1       cgd 	(void)signal(SIGQUIT, SIG_IGN);
    218           1.1       cgd 	(void)signal(SIGINT, SIG_IGN);
    219           1.1       cgd 	(void)setpriority(PRIO_PROCESS, 0, 0);
    220           1.1       cgd 
    221          1.63     lukem 	openlog("login", 0, LOG_AUTH);
    222           1.1       cgd 
    223           1.1       cgd 	/*
    224           1.1       cgd 	 * -p is used by getty to tell login not to destroy the environment
    225           1.5       cgd 	 * -f is used to skip a second login authentication
    226          1.66  christos 	 * -h is used by other servers to pass the name of the remote host to
    227          1.66  christos 	 *    login so that it may be placed in utmp/utmpx and wtmp/wtmpx
    228  1.82.2.2.2.1      tron 	 * -a in addition to -h, a server may supply -a to pass the actual
    229          1.79  christos 	 *    server address.
    230          1.20     lukem 	 * -s is used to force use of S/Key or equivalent.
    231           1.1       cgd 	 */
    232           1.1       cgd 	domain = NULL;
    233           1.1       cgd 	if (gethostname(localhost, sizeof(localhost)) < 0)
    234           1.1       cgd 		syslog(LOG_ERR, "couldn't get local hostname: %m");
    235           1.1       cgd 	else
    236          1.12       jtc 		domain = strchr(localhost, '.');
    237          1.37       mrg 	localhost[sizeof(localhost) - 1] = '\0';
    238           1.1       cgd 
    239          1.44     aidan 	Fflag = fflag = hflag = pflag = sflag = 0;
    240          1.79  christos 	have_ss = 0;
    241          1.44     aidan #ifdef KERBEROS5
    242          1.44     aidan 	have_forward = 0;
    243          1.44     aidan #endif
    244           1.1       cgd 	uid = getuid();
    245          1.79  christos 	while ((ch = getopt(argc, argv, "a:Ffh:ps")) != -1)
    246           1.1       cgd 		switch (ch) {
    247          1.79  christos 		case 'a':
    248          1.79  christos 			if (uid)
    249          1.79  christos 				errx(1, "-a option: %s", strerror(EPERM));
    250          1.79  christos 			decode_ss(optarg);
    251          1.82  christos #ifdef notdef
    252          1.82  christos 			(void)sockaddr_snprintf(optarg,
    253          1.82  christos 			    sizeof(struct sockaddr_storage), "%a", (void *)&ss);
    254          1.82  christos #endif
    255          1.79  christos 			break;
    256          1.44     aidan 		case 'F':
    257          1.44     aidan 			Fflag = 1;
    258          1.44     aidan 			/* FALLTHROUGH */
    259           1.1       cgd 		case 'f':
    260           1.1       cgd 			fflag = 1;
    261           1.1       cgd 			break;
    262           1.1       cgd 		case 'h':
    263          1.12       jtc 			if (uid)
    264          1.12       jtc 				errx(1, "-h option: %s", strerror(EPERM));
    265           1.1       cgd 			hflag = 1;
    266          1.79  christos #ifdef notdef
    267          1.23     mikel 			if (domain && (p = strchr(optarg, '.')) != NULL &&
    268           1.1       cgd 			    strcasecmp(p, domain) == 0)
    269          1.79  christos 				*p = '\0';
    270          1.79  christos #endif
    271           1.1       cgd 			hostname = optarg;
    272           1.1       cgd 			break;
    273           1.1       cgd 		case 'p':
    274           1.1       cgd 			pflag = 1;
    275           1.1       cgd 			break;
    276          1.20     lukem 		case 's':
    277          1.29   mycroft 			sflag = 1;
    278          1.20     lukem 			break;
    279          1.29   mycroft 		default:
    280           1.1       cgd 		case '?':
    281          1.79  christos 			usage();
    282          1.79  christos 			break;
    283           1.1       cgd 		}
    284          1.82  christos 
    285          1.82  christos 	setproctitle(NULL);
    286           1.1       cgd 	argc -= optind;
    287           1.1       cgd 	argv += optind;
    288           1.5       cgd 
    289           1.1       cgd 	if (*argv) {
    290           1.1       cgd 		username = *argv;
    291           1.1       cgd 		ask = 0;
    292           1.1       cgd 	} else
    293           1.1       cgd 		ask = 1;
    294           1.1       cgd 
    295          1.82  christos #ifdef F_CLOSEM
    296          1.82  christos 	(void)fcntl(3, F_CLOSEM, 0);
    297          1.82  christos #else
    298           1.1       cgd 	for (cnt = getdtablesize(); cnt > 2; cnt--)
    299           1.5       cgd 		(void)close(cnt);
    300          1.82  christos #endif
    301           1.1       cgd 
    302           1.5       cgd 	ttyn = ttyname(STDIN_FILENO);
    303           1.1       cgd 	if (ttyn == NULL || *ttyn == '\0') {
    304           1.5       cgd 		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
    305           1.1       cgd 		ttyn = tname;
    306           1.1       cgd 	}
    307          1.82  christos 	if ((tty = strstr(ttyn, "/pts/")) != NULL)
    308          1.82  christos 		++tty;
    309          1.82  christos 	else if ((tty = strrchr(ttyn, '/')) != NULL)
    310           1.1       cgd 		++tty;
    311           1.1       cgd 	else
    312           1.1       cgd 		tty = ttyn;
    313          1.25   mycroft 
    314          1.70    itojun 	if (issetugid()) {
    315          1.70    itojun 		nested = strdup(user_from_uid(getuid(), 0));
    316          1.70    itojun 		if (nested == NULL) {
    317          1.70    itojun                 	syslog(LOG_ERR, "strdup: %m");
    318          1.70    itojun                 	sleepexit(1);
    319          1.70    itojun 		}
    320          1.70    itojun 	}
    321          1.70    itojun 
    322          1.48       mjl #ifdef LOGIN_CAP
    323          1.48       mjl 	/* Get "login-retries" and "login-backoff" from default class */
    324          1.55     enami 	if ((lc = login_getclass(NULL)) != NULL) {
    325          1.55     enami 		login_retries = (int)login_getcapnum(lc, "login-retries",
    326          1.55     enami 		    DEFAULT_RETRIES, DEFAULT_RETRIES);
    327          1.55     enami 		login_backoff = (int)login_getcapnum(lc, "login-backoff",
    328          1.55     enami 		    DEFAULT_BACKOFF, DEFAULT_BACKOFF);
    329          1.48       mjl 		login_close(lc);
    330          1.48       mjl 		lc = NULL;
    331          1.55     enami 	}
    332          1.48       mjl #endif
    333          1.48       mjl 
    334          1.25   mycroft #ifdef KERBEROS5
    335          1.25   mycroft 	kerror = krb5_init_context(&kcontext);
    336          1.25   mycroft 	if (kerror) {
    337          1.61   thorpej 		/*
    338          1.61   thorpej 		 * If Kerberos is not configured, that is, we are
    339          1.61   thorpej 		 * not using Kerberos, do not log the error message.
    340          1.61   thorpej 		 * However, if Kerberos is configured,  and the
    341          1.61   thorpej 		 * context init fails for some other reason, we need
    342          1.61   thorpej 		 * to issue a no tickets warning to the user when the
    343          1.61   thorpej 		 * login succeeds.
    344          1.61   thorpej 		 */
    345          1.61   thorpej 		if (kerror != ENXIO) {	/* XXX NetBSD-local Heimdal hack */
    346          1.61   thorpej 			syslog(LOG_NOTICE,
    347          1.61   thorpej 			    "%s when initializing Kerberos context",
    348          1.61   thorpej 			    error_message(kerror));
    349          1.61   thorpej 			krb5_configured = 1;
    350          1.61   thorpej 		}
    351          1.57     aidan 		login_krb5_get_tickets = 0;
    352          1.58     aidan 	}
    353          1.64       cgd #endif /* KERBEROS5 */
    354           1.1       cgd 
    355           1.1       cgd 	for (cnt = 0;; ask = 1) {
    356          1.57     aidan #if defined(KERBEROS)
    357          1.10    brezak 	        kdestroy();
    358          1.10    brezak #endif
    359          1.57     aidan #if defined(KERBEROS5)
    360          1.57     aidan 		if (login_krb5_get_tickets)
    361          1.57     aidan 			k5destroy();
    362          1.57     aidan #endif
    363           1.1       cgd 		if (ask) {
    364           1.1       cgd 			fflag = 0;
    365           1.1       cgd 			getloginname();
    366           1.1       cgd 		}
    367           1.5       cgd 		rootlogin = 0;
    368          1.29   mycroft #ifdef KERBEROS
    369          1.29   mycroft 		if ((instance = strchr(username, '.')) != NULL)
    370           1.1       cgd 			*instance++ = '\0';
    371          1.29   mycroft 		else
    372           1.1       cgd 			instance = "";
    373           1.1       cgd #endif
    374          1.10    brezak #ifdef KERBEROS5
    375          1.29   mycroft 		if ((instance = strchr(username, '/')) != NULL)
    376          1.10    brezak 			*instance++ = '\0';
    377          1.29   mycroft 		else
    378          1.10    brezak 			instance = "";
    379          1.10    brezak #endif
    380          1.16  sommerfe 		if (strlen(username) > MAXLOGNAME)
    381          1.16  sommerfe 			username[MAXLOGNAME] = '\0';
    382           1.1       cgd 
    383           1.1       cgd 		/*
    384           1.1       cgd 		 * Note if trying multiple user names; log failures for
    385           1.1       cgd 		 * previous user name, but don't bother logging one failure
    386           1.1       cgd 		 * for nonexistent name (mistyped username).
    387           1.1       cgd 		 */
    388           1.1       cgd 		if (failures && strcmp(tbuf, username)) {
    389           1.1       cgd 			if (failures > (pwd ? 0 : 1))
    390           1.1       cgd 				badlogin(tbuf);
    391           1.1       cgd 			failures = 0;
    392           1.1       cgd 		}
    393          1.71    itojun 		(void)strlcpy(tbuf, username, sizeof(tbuf));
    394           1.1       cgd 
    395          1.23     mikel 		if ((pwd = getpwnam(username)) != NULL)
    396           1.1       cgd 			salt = pwd->pw_passwd;
    397           1.1       cgd 		else
    398           1.1       cgd 			salt = "xx";
    399           1.1       cgd 
    400          1.48       mjl #ifdef LOGIN_CAP
    401          1.48       mjl 		/*
    402          1.48       mjl 		 * Establish the class now, before we might goto
    403          1.48       mjl 		 * within the next block. pwd can be NULL since it
    404          1.52       mjl 		 * falls back to the "default" class if it is.
    405          1.52       mjl 		 */
    406          1.52       mjl 		lc = login_getclass(pwd ? pwd->pw_class : NULL);
    407          1.48       mjl #endif
    408           1.1       cgd 		/*
    409           1.1       cgd 		 * if we have a valid account name, and it doesn't have a
    410           1.1       cgd 		 * password, or the -f option was specified and the caller
    411           1.1       cgd 		 * is root or the caller isn't changing their uid, don't
    412           1.1       cgd 		 * authenticate.
    413           1.1       cgd 		 */
    414           1.7   mycroft 		if (pwd) {
    415           1.7   mycroft 			if (pwd->pw_uid == 0)
    416           1.7   mycroft 				rootlogin = 1;
    417           1.7   mycroft 
    418           1.8   mycroft 			if (fflag && (uid == 0 || uid == pwd->pw_uid)) {
    419           1.7   mycroft 				/* already authenticated */
    420          1.44     aidan #ifdef KERBEROS5
    421          1.57     aidan 				if (login_krb5_get_tickets && Fflag)
    422          1.44     aidan 					k5_read_creds(username);
    423          1.44     aidan #endif
    424           1.7   mycroft 				break;
    425           1.7   mycroft 			} else if (pwd->pw_passwd[0] == '\0') {
    426           1.7   mycroft 				/* pretend password okay */
    427           1.7   mycroft 				rval = 0;
    428           1.7   mycroft 				goto ttycheck;
    429           1.7   mycroft 			}
    430           1.7   mycroft 		}
    431           1.7   mycroft 
    432           1.1       cgd 		fflag = 0;
    433           1.1       cgd 
    434           1.1       cgd 		(void)setpriority(PRIO_PROCESS, 0, -4);
    435           1.1       cgd 
    436          1.27   mycroft #ifdef SKEY
    437          1.29   mycroft 		if (skey_haskey(username) == 0) {
    438          1.29   mycroft 			static char skprompt[80];
    439          1.59   thorpej 			const char *skinfo = skey_keyinfo(username);
    440          1.20     lukem 
    441          1.75    itojun 			(void)snprintf(skprompt, sizeof(skprompt),
    442      1.82.2.1     jwise 			    "Password [ %s ]:",
    443          1.29   mycroft 			    skinfo ? skinfo : "error getting challenge");
    444          1.29   mycroft 			pwprompt = skprompt;
    445          1.29   mycroft 		} else
    446          1.27   mycroft #endif
    447          1.29   mycroft 			pwprompt = "Password:";
    448          1.27   mycroft 
    449          1.29   mycroft 		p = getpass(pwprompt);
    450           1.1       cgd 
    451          1.29   mycroft 		if (pwd == NULL) {
    452          1.29   mycroft 			rval = 1;
    453          1.29   mycroft 			goto skip;
    454          1.29   mycroft 		}
    455          1.29   mycroft #ifdef KERBEROS
    456          1.57     aidan 		if (
    457          1.57     aidan #ifdef KERBEROS5
    458          1.57     aidan 		    /* allow a user to get both krb4 and krb5 tickets, if
    459          1.57     aidan 		     * desired.  If krb5 is compiled in, the default action
    460          1.57     aidan 		     * is to ignore krb4 and get krb5 tickets, but the user
    461          1.57     aidan 		     * can override this in the krb5.conf. */
    462          1.57     aidan 		    login_krb4_get_tickets &&
    463          1.57     aidan #endif
    464          1.57     aidan 		    klogin(pwd, instance, localhost, p) == 0) {
    465          1.29   mycroft 			rval = 0;
    466          1.57     aidan 			got_tickets = 1;
    467          1.29   mycroft 		}
    468           1.1       cgd #endif
    469          1.29   mycroft #ifdef KERBEROS5
    470          1.57     aidan 		if (login_krb5_get_tickets &&
    471          1.57     aidan 		    k5login(pwd, instance, localhost, p) == 0) {
    472          1.29   mycroft 			rval = 0;
    473          1.57     aidan 			got_tickets = 1;
    474          1.57     aidan 		}
    475          1.57     aidan #endif
    476          1.57     aidan #if defined(KERBEROS) || defined(KERBEROS5)
    477          1.57     aidan 		if (got_tickets)
    478          1.29   mycroft 			goto skip;
    479          1.29   mycroft #endif
    480          1.20     lukem #ifdef SKEY
    481          1.29   mycroft 		if (skey_haskey(username) == 0 &&
    482          1.29   mycroft 		    skey_passcheck(username, p) != -1) {
    483          1.29   mycroft 			rval = 0;
    484          1.29   mycroft 			goto skip;
    485          1.29   mycroft 		}
    486          1.20     lukem #endif
    487          1.29   mycroft 		if (!sflag && *pwd->pw_passwd != '\0' &&
    488          1.29   mycroft 		    !strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd)) {
    489          1.29   mycroft 			rval = 0;
    490          1.29   mycroft 			require_chpass = 1;
    491          1.29   mycroft 			goto skip;
    492          1.29   mycroft 		}
    493          1.29   mycroft 		rval = 1;
    494          1.29   mycroft 
    495          1.29   mycroft 	skip:
    496          1.29   mycroft 		memset(p, 0, strlen(p));
    497           1.1       cgd 
    498           1.1       cgd 		(void)setpriority(PRIO_PROCESS, 0, 0);
    499           1.1       cgd 
    500           1.7   mycroft 	ttycheck:
    501           1.1       cgd 		/*
    502           1.1       cgd 		 * If trying to log in as root without Kerberos,
    503           1.1       cgd 		 * but with insecure terminal, refuse the login attempt.
    504           1.1       cgd 		 */
    505           1.7   mycroft 		if (pwd && !rval && rootlogin && !rootterm(tty)) {
    506  1.82.2.2.2.1      tron 			(void)printf("Login incorrect or refused on this "
    507  1.82.2.2.2.1      tron 			    "terminal.\n");
    508           1.1       cgd 			if (hostname)
    509           1.1       cgd 				syslog(LOG_NOTICE,
    510           1.1       cgd 				    "LOGIN %s REFUSED FROM %s ON TTY %s",
    511           1.1       cgd 				    pwd->pw_name, hostname, tty);
    512           1.1       cgd 			else
    513           1.1       cgd 				syslog(LOG_NOTICE,
    514           1.1       cgd 				    "LOGIN %s REFUSED ON TTY %s",
    515           1.1       cgd 				     pwd->pw_name, tty);
    516           1.1       cgd 			continue;
    517           1.1       cgd 		}
    518           1.1       cgd 
    519           1.1       cgd 		if (pwd && !rval)
    520           1.1       cgd 			break;
    521           1.1       cgd 
    522  1.82.2.2.2.1      tron 		(void)printf("Login incorrect or refused on this "
    523  1.82.2.2.2.1      tron 		    "terminal.\n");
    524           1.1       cgd 		failures++;
    525          1.48       mjl 		cnt++;
    526           1.1       cgd 		/* we allow 10 tries, but after 3 we start backing off */
    527          1.50       mjl 		if (cnt > login_backoff) {
    528          1.48       mjl 			if (cnt >= login_retries) {
    529           1.1       cgd 				badlogin(username);
    530           1.1       cgd 				sleepexit(1);
    531           1.1       cgd 			}
    532           1.1       cgd 			sleep((u_int)((cnt - 3) * 5));
    533           1.1       cgd 		}
    534           1.1       cgd 	}
    535           1.1       cgd 
    536           1.1       cgd 	/* committed to login -- turn off timeout */
    537           1.1       cgd 	(void)alarm((u_int)0);
    538           1.1       cgd 
    539           1.1       cgd 	endpwent();
    540           1.1       cgd 
    541           1.1       cgd 	/* if user not super-user, check for disabled logins */
    542          1.48       mjl #ifdef LOGIN_CAP
    543          1.56     enami         if (!login_getcapbool(lc, "ignorenologin", rootlogin))
    544          1.52       mjl 		checknologin(login_getcapstr(lc, "nologin", NULL, NULL));
    545          1.48       mjl #else
    546          1.48       mjl         if (!rootlogin)
    547          1.48       mjl                 checknologin(NULL);
    548          1.48       mjl #endif
    549           1.1       cgd 
    550          1.48       mjl #ifdef LOGIN_CAP
    551          1.48       mjl         quietlog = login_getcapbool(lc, "hushlogin", 0);
    552          1.48       mjl #else
    553          1.48       mjl         quietlog = 0;
    554          1.48       mjl #endif
    555          1.33   hubertf 	/* Temporarily give up special privileges so we can change */
    556          1.33   hubertf 	/* into NFS-mounted homes that are exported for non-root */
    557          1.33   hubertf 	/* access and have mode 7x0 */
    558          1.33   hubertf 	saved_uid = geteuid();
    559          1.35   hubertf 	saved_gid = getegid();
    560          1.35   hubertf 	nsaved_gids = getgroups(NGROUPS_MAX, saved_gids);
    561          1.35   hubertf 
    562          1.35   hubertf 	(void)setegid(pwd->pw_gid);
    563          1.35   hubertf 	initgroups(username, pwd->pw_gid);
    564          1.35   hubertf 	(void)seteuid(pwd->pw_uid);
    565          1.33   hubertf 
    566           1.1       cgd 	if (chdir(pwd->pw_dir) < 0) {
    567          1.48       mjl #ifdef LOGIN_CAP
    568          1.48       mjl                 if (login_getcapbool(lc, "requirehome", 0)) {
    569          1.55     enami 			(void)printf("Home directory %s required\n",
    570          1.55     enami 			    pwd->pw_dir);
    571          1.48       mjl                         sleepexit(1);
    572          1.48       mjl 		}
    573          1.48       mjl #endif
    574           1.1       cgd 		(void)printf("No home directory %s!\n", pwd->pw_dir);
    575           1.1       cgd 		if (chdir("/"))
    576           1.1       cgd 			exit(0);
    577           1.1       cgd 		pwd->pw_dir = "/";
    578           1.1       cgd 		(void)printf("Logging in with home = \"/\".\n");
    579           1.1       cgd 	}
    580           1.1       cgd 
    581          1.55     enami 	if (!quietlog)
    582          1.48       mjl 		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
    583          1.33   hubertf 
    584          1.33   hubertf 	/* regain special privileges */
    585          1.33   hubertf 	(void)seteuid(saved_uid);
    586          1.35   hubertf 	setgroups(nsaved_gids, saved_gids);
    587          1.35   hubertf 	(void)setegid(saved_gid);
    588           1.1       cgd 
    589          1.48       mjl #ifdef LOGIN_CAP
    590          1.48       mjl         pw_warntime = login_getcaptime(lc, "password-warn",
    591          1.55     enami             _PASSWORD_WARNDAYS * SECSPERDAY,
    592          1.55     enami             _PASSWORD_WARNDAYS * SECSPERDAY);
    593          1.48       mjl #endif
    594          1.48       mjl 
    595          1.66  christos 	(void)gettimeofday(&now, (struct timezone *)NULL);
    596          1.40      ross 	if (pwd->pw_expire) {
    597          1.66  christos 		if (now.tv_sec >= pwd->pw_expire) {
    598           1.1       cgd 			(void)printf("Sorry -- your account has expired.\n");
    599           1.1       cgd 			sleepexit(1);
    600          1.66  christos 		} else if (pwd->pw_expire - now.tv_sec < pw_warntime &&
    601          1.55     enami 		    !quietlog)
    602           1.1       cgd 			(void)printf("Warning: your account expires on %s",
    603           1.1       cgd 			    ctime(&pwd->pw_expire));
    604          1.40      ross 	}
    605          1.40      ross 	if (pwd->pw_change) {
    606          1.30   mycroft 		if (pwd->pw_change == _PASSWORD_CHGNOW)
    607          1.30   mycroft 			need_chpass = 1;
    608          1.66  christos 		else if (now.tv_sec >= pwd->pw_change) {
    609          1.31   mycroft 			(void)printf("Sorry -- your password has expired.\n");
    610          1.31   mycroft 			sleepexit(1);
    611          1.66  christos 		} else if (pwd->pw_change - now.tv_sec < pw_warntime &&
    612          1.55     enami 		    !quietlog)
    613          1.30   mycroft 			(void)printf("Warning: your password expires on %s",
    614          1.30   mycroft 			    ctime(&pwd->pw_change));
    615           1.1       cgd 
    616          1.40      ross 	}
    617           1.5       cgd 	/* Nothing else left to fail -- really log in. */
    618          1.66  christos 	update_db(quietlog);
    619           1.1       cgd 
    620           1.1       cgd 	(void)chown(ttyn, pwd->pw_uid,
    621           1.1       cgd 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
    622          1.15       gwr 
    623          1.15       gwr 	if (ttyaction(ttyn, "login", pwd->pw_name))
    624          1.15       gwr 		(void)printf("Warning: ttyaction failed.\n");
    625          1.15       gwr 
    626          1.10    brezak #if defined(KERBEROS) || defined(KERBEROS5)
    627          1.10    brezak 	/* Fork so that we can call kdestroy */
    628          1.57     aidan 	if (
    629          1.57     aidan #ifdef KERBEROS5
    630          1.57     aidan 	    ! login_krb5_retain_ccache &&
    631          1.57     aidan #endif
    632          1.57     aidan 	    has_ccache)
    633          1.29   mycroft 		dofork();
    634          1.10    brezak #endif
    635          1.53       mjl 
    636          1.53       mjl 	/* Destroy environment unless user has requested its preservation. */
    637          1.53       mjl 	if (!pflag)
    638          1.53       mjl 		environ = envinit;
    639          1.53       mjl 
    640          1.48       mjl #ifdef LOGIN_CAP
    641          1.70    itojun 	if (nested == NULL && setusercontext(lc, pwd, pwd->pw_uid,
    642          1.70    itojun 	    LOGIN_SETLOGIN) != 0) {
    643          1.70    itojun 		syslog(LOG_ERR, "setusercontext failed");
    644          1.70    itojun 		exit(1);
    645          1.70    itojun 	}
    646          1.70    itojun 	if (setusercontext(lc, pwd, pwd->pw_uid,
    647          1.70    itojun 	    (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETLOGIN))) != 0) {
    648          1.52       mjl 		syslog(LOG_ERR, "setusercontext failed");
    649          1.52       mjl 		exit(1);
    650          1.48       mjl 	}
    651          1.52       mjl #else
    652           1.1       cgd 	(void)setgid(pwd->pw_gid);
    653           1.1       cgd 
    654           1.1       cgd 	initgroups(username, pwd->pw_gid);
    655          1.48       mjl 
    656          1.70    itojun 	if (nested == NULL && setlogin(pwd->pw_name) < 0)
    657          1.48       mjl 		syslog(LOG_ERR, "setlogin() failure: %m");
    658          1.48       mjl 
    659          1.48       mjl 	/* Discard permissions last so can't get killed and drop core. */
    660          1.48       mjl 	if (rootlogin)
    661          1.48       mjl 		(void)setuid(0);
    662          1.48       mjl 	else
    663          1.48       mjl 		(void)setuid(pwd->pw_uid);
    664          1.52       mjl #endif
    665           1.1       cgd 
    666           1.1       cgd 	if (*pwd->pw_shell == '\0')
    667           1.1       cgd 		pwd->pw_shell = _PATH_BSHELL;
    668          1.48       mjl #ifdef LOGIN_CAP
    669          1.55     enami 	if ((shell = login_getcapstr(lc, "shell", NULL, NULL)) != NULL) {
    670          1.55     enami 		if ((shell = strdup(shell)) == NULL) {
    671          1.63     lukem                 	syslog(LOG_ERR, "Cannot alloc mem");
    672          1.48       mjl                 	sleepexit(1);
    673          1.48       mjl 		}
    674          1.48       mjl 		pwd->pw_shell = shell;
    675          1.48       mjl 	}
    676          1.48       mjl #endif
    677          1.48       mjl 
    678           1.1       cgd 	(void)setenv("HOME", pwd->pw_dir, 1);
    679           1.1       cgd 	(void)setenv("SHELL", pwd->pw_shell, 1);
    680          1.48       mjl 	if (term[0] == '\0') {
    681          1.55     enami 		char *tt = (char *)stypeof(tty);
    682          1.48       mjl #ifdef LOGIN_CAP
    683          1.55     enami 		if (tt == NULL)
    684          1.48       mjl 			tt = login_getcapstr(lc, "term", NULL, NULL);
    685          1.48       mjl #endif
    686          1.48       mjl 		/* unknown term -> "su" */
    687          1.71    itojun 		(void)strlcpy(term, tt != NULL ? tt : "su", sizeof(term));
    688          1.55     enami 	}
    689           1.1       cgd 	(void)setenv("TERM", term, 0);
    690           1.1       cgd 	(void)setenv("LOGNAME", pwd->pw_name, 1);
    691           1.1       cgd 	(void)setenv("USER", pwd->pw_name, 1);
    692          1.51       mjl 
    693          1.48       mjl #ifdef LOGIN_CAP
    694          1.52       mjl 	setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH);
    695          1.48       mjl #else
    696           1.1       cgd 	(void)setenv("PATH", _PATH_DEFPATH, 0);
    697          1.48       mjl #endif
    698          1.51       mjl 
    699           1.1       cgd #ifdef KERBEROS
    700           1.1       cgd 	if (krbtkfile_env)
    701           1.1       cgd 		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
    702           1.1       cgd #endif
    703          1.10    brezak #ifdef KERBEROS5
    704          1.57     aidan 	if (krb5tkfile_env)
    705          1.57     aidan 		(void)setenv("KRB5CCNAME", krb5tkfile_env, 1);
    706          1.10    brezak #endif
    707           1.1       cgd 
    708          1.12       jtc 	if (tty[sizeof("tty")-1] == 'd')
    709          1.12       jtc 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
    710          1.12       jtc 
    711           1.5       cgd 	/* If fflag is on, assume caller/authenticator has logged root login. */
    712          1.40      ross 	if (rootlogin && fflag == 0) {
    713           1.1       cgd 		if (hostname)
    714           1.1       cgd 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
    715           1.1       cgd 			    username, tty, hostname);
    716           1.1       cgd 		else
    717          1.55     enami 			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
    718          1.55     enami 			    username, tty);
    719          1.40      ross 	}
    720           1.1       cgd 
    721          1.10    brezak #if defined(KERBEROS) || defined(KERBEROS5)
    722          1.60   thorpej 	if (KERBEROS_CONFIGURED && !quietlog && notickets == 1)
    723           1.1       cgd 		(void)printf("Warning: no Kerberos tickets issued.\n");
    724           1.1       cgd #endif
    725           1.1       cgd 
    726           1.1       cgd 	if (!quietlog) {
    727          1.51       mjl 		char *fname;
    728          1.48       mjl #ifdef LOGIN_CAP
    729          1.48       mjl 		fname = login_getcapstr(lc, "copyright", NULL, NULL);
    730          1.55     enami 		if (fname != NULL && access(fname, F_OK) == 0)
    731          1.48       mjl 			motd(fname);
    732          1.48       mjl 		else
    733          1.55     enami #endif
    734          1.69    itojun 			(void)printf("%s", copyrightstr);
    735          1.48       mjl 
    736          1.48       mjl #ifdef LOGIN_CAP
    737          1.48       mjl                 fname = login_getcapstr(lc, "welcome", NULL, NULL);
    738          1.48       mjl                 if (fname == NULL || access(fname, F_OK) != 0)
    739          1.48       mjl #endif
    740          1.48       mjl                         fname = _PATH_MOTDFILE;
    741          1.48       mjl                 motd(fname);
    742          1.48       mjl 
    743           1.5       cgd 		(void)snprintf(tbuf,
    744           1.5       cgd 		    sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
    745           1.1       cgd 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
    746           1.1       cgd 			(void)printf("You have %smail.\n",
    747           1.1       cgd 			    (st.st_mtime > st.st_atime) ? "new " : "");
    748           1.1       cgd 	}
    749           1.1       cgd 
    750          1.48       mjl #ifdef LOGIN_CAP
    751          1.48       mjl 	login_close(lc);
    752          1.48       mjl #endif
    753          1.48       mjl 
    754           1.1       cgd 	(void)signal(SIGALRM, SIG_DFL);
    755           1.1       cgd 	(void)signal(SIGQUIT, SIG_DFL);
    756           1.1       cgd 	(void)signal(SIGINT, SIG_DFL);
    757           1.1       cgd 	(void)signal(SIGTSTP, SIG_IGN);
    758           1.1       cgd 
    759           1.1       cgd 	tbuf[0] = '-';
    760          1.71    itojun 	(void)strlcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ?
    761          1.71    itojun 	    p + 1 : pwd->pw_shell, sizeof(tbuf) - 1);
    762           1.1       cgd 
    763          1.24     lukem 	/* Wait to change password until we're unprivileged */
    764          1.24     lukem 	if (need_chpass) {
    765          1.29   mycroft 		if (!require_chpass)
    766          1.24     lukem 			(void)printf(
    767          1.24     lukem "Warning: your password has expired. Please change it as soon as possible.\n");
    768          1.29   mycroft 		else {
    769          1.38       mrg 			int	status;
    770          1.38       mrg 
    771          1.29   mycroft 			(void)printf(
    772          1.24     lukem 		    "Your password has expired. Please choose a new one.\n");
    773          1.38       mrg 			switch (fork()) {
    774          1.38       mrg 			case -1:
    775          1.38       mrg 				warn("fork");
    776          1.29   mycroft 				sleepexit(1);
    777          1.38       mrg 			case 0:
    778          1.38       mrg 				execl(_PATH_BINPASSWD, "passwd", 0);
    779          1.38       mrg 				_exit(1);
    780          1.38       mrg 			default:
    781          1.38       mrg 				if (wait(&status) == -1 ||
    782          1.38       mrg 				    WEXITSTATUS(status))
    783          1.38       mrg 					sleepexit(1);
    784          1.38       mrg 			}
    785          1.29   mycroft 		}
    786          1.24     lukem 	}
    787           1.1       cgd 
    788          1.44     aidan #ifdef KERBEROS5
    789          1.57     aidan 	if (login_krb5_get_tickets)
    790          1.57     aidan 		k5_write_creds();
    791          1.44     aidan #endif
    792           1.1       cgd 	execlp(pwd->pw_shell, tbuf, 0);
    793          1.12       jtc 	err(1, "%s", pwd->pw_shell);
    794           1.1       cgd }
    795          1.57     aidan 
    796          1.10    brezak #if defined(KERBEROS) || defined(KERBEROS5)
    797          1.16  sommerfe #define	NBUFSIZ		(MAXLOGNAME + 1 + 5)	/* .root suffix */
    798           1.1       cgd #else
    799          1.16  sommerfe #define	NBUFSIZ		(MAXLOGNAME + 1)
    800          1.10    brezak #endif
    801          1.10    brezak 
    802          1.10    brezak #if defined(KERBEROS) || defined(KERBEROS5)
    803          1.10    brezak /*
    804          1.10    brezak  * This routine handles cleanup stuff, and the like.
    805          1.10    brezak  * It exists only in the child process.
    806          1.10    brezak  */
    807          1.10    brezak #include <sys/wait.h>
    808          1.10    brezak void
    809          1.80   xtraeme dofork(void)
    810          1.10    brezak {
    811          1.38       mrg 	int child;
    812          1.38       mrg 
    813          1.38       mrg 	if (!(child = fork()))
    814          1.38       mrg 		return; /* Child process */
    815          1.38       mrg 
    816          1.55     enami 	/*
    817          1.55     enami 	 * Setup stuff?  This would be things we could do in parallel
    818          1.55     enami 	 * with login
    819          1.55     enami 	 */
    820          1.55     enami 	(void)chdir("/");	/* Let's not keep the fs busy... */
    821          1.10    brezak 
    822          1.38       mrg 	/* If we're the parent, watch the child until it dies */
    823          1.38       mrg 	while (wait(0) != child)
    824          1.38       mrg 		;
    825          1.10    brezak 
    826          1.38       mrg 	/* Cleanup stuff */
    827          1.38       mrg 	/* Run kdestroy to destroy tickets */
    828          1.57     aidan #ifdef KERBEROS
    829          1.38       mrg 	kdestroy();
    830          1.57     aidan #endif
    831          1.57     aidan #ifdef KERBEROS5
    832          1.57     aidan 	if (login_krb5_get_tickets)
    833          1.57     aidan 		k5destroy();
    834          1.57     aidan #endif
    835          1.10    brezak 
    836          1.38       mrg 	/* Leave */
    837          1.38       mrg 	exit(0);
    838          1.10    brezak }
    839           1.1       cgd #endif
    840           1.1       cgd 
    841           1.5       cgd void
    842          1.80   xtraeme getloginname(void)
    843           1.1       cgd {
    844          1.12       jtc 	int ch;
    845          1.12       jtc 	char *p;
    846           1.1       cgd 	static char nbuf[NBUFSIZ];
    847           1.1       cgd 
    848           1.1       cgd 	for (;;) {
    849           1.1       cgd 		(void)printf("login: ");
    850           1.1       cgd 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
    851           1.1       cgd 			if (ch == EOF) {
    852           1.1       cgd 				badlogin(username);
    853           1.1       cgd 				exit(0);
    854           1.1       cgd 			}
    855           1.1       cgd 			if (p < nbuf + (NBUFSIZ - 1))
    856           1.1       cgd 				*p++ = ch;
    857           1.1       cgd 		}
    858          1.40      ross 		if (p > nbuf) {
    859           1.1       cgd 			if (nbuf[0] == '-')
    860           1.1       cgd 				(void)fprintf(stderr,
    861           1.1       cgd 				    "login names may not start with '-'.\n");
    862           1.1       cgd 			else {
    863           1.1       cgd 				*p = '\0';
    864           1.1       cgd 				username = nbuf;
    865           1.1       cgd 				break;
    866           1.1       cgd 			}
    867          1.40      ross 		}
    868           1.1       cgd 	}
    869           1.1       cgd }
    870           1.1       cgd 
    871           1.5       cgd int
    872          1.80   xtraeme rootterm(char *ttyn)
    873           1.1       cgd {
    874           1.1       cgd 	struct ttyent *t;
    875           1.1       cgd 
    876          1.12       jtc 	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
    877           1.1       cgd }
    878           1.1       cgd 
    879           1.1       cgd jmp_buf motdinterrupt;
    880           1.1       cgd 
    881           1.5       cgd void
    882          1.80   xtraeme motd(char *fname)
    883           1.1       cgd {
    884          1.12       jtc 	int fd, nchars;
    885           1.1       cgd 	sig_t oldint;
    886           1.1       cgd 	char tbuf[8192];
    887           1.1       cgd 
    888          1.48       mjl 	if ((fd = open(fname ? fname : _PATH_MOTDFILE, O_RDONLY, 0)) < 0)
    889           1.1       cgd 		return;
    890           1.1       cgd 	oldint = signal(SIGINT, sigint);
    891           1.1       cgd 	if (setjmp(motdinterrupt) == 0)
    892           1.1       cgd 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    893           1.1       cgd 			(void)write(fileno(stdout), tbuf, nchars);
    894           1.1       cgd 	(void)signal(SIGINT, oldint);
    895           1.1       cgd 	(void)close(fd);
    896           1.1       cgd }
    897           1.1       cgd 
    898           1.5       cgd /* ARGSUSED */
    899           1.1       cgd void
    900          1.80   xtraeme sigint(int signo)
    901           1.1       cgd {
    902          1.38       mrg 
    903           1.1       cgd 	longjmp(motdinterrupt, 1);
    904           1.1       cgd }
    905           1.1       cgd 
    906           1.5       cgd /* ARGSUSED */
    907           1.5       cgd void
    908          1.80   xtraeme timedout(int signo)
    909           1.5       cgd {
    910          1.38       mrg 
    911           1.5       cgd 	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
    912           1.5       cgd 	exit(0);
    913           1.5       cgd }
    914           1.5       cgd 
    915           1.5       cgd void
    916          1.80   xtraeme checknologin(char *fname)
    917           1.1       cgd {
    918          1.12       jtc 	int fd, nchars;
    919           1.1       cgd 	char tbuf[8192];
    920           1.1       cgd 
    921          1.48       mjl 	if ((fd = open(fname ? fname : _PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
    922           1.1       cgd 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
    923           1.1       cgd 			(void)write(fileno(stdout), tbuf, nchars);
    924           1.1       cgd 		sleepexit(0);
    925           1.1       cgd 	}
    926           1.1       cgd }
    927           1.1       cgd 
    928          1.66  christos static void
    929          1.66  christos update_db(int quietlog)
    930          1.66  christos {
    931          1.70    itojun 	if (nested != NULL) {
    932          1.70    itojun 		if (hostname != NULL)
    933          1.70    itojun 			syslog(LOG_NOTICE, "%s to %s on tty %s from %s",
    934          1.70    itojun 			    nested, pwd->pw_name, tty, hostname);
    935          1.70    itojun 		else
    936          1.70    itojun 			syslog(LOG_NOTICE, "%s to %s on tty %s", nested,
    937          1.70    itojun 			    pwd->pw_name, tty);
    938          1.70    itojun 
    939          1.70    itojun 		return;
    940          1.70    itojun 	}
    941          1.79  christos 	if (hostname != NULL && have_ss == 0) {
    942          1.66  christos 		socklen_t len = sizeof(ss);
    943          1.66  christos 		(void)getpeername(STDIN_FILENO, (struct sockaddr *)&ss, &len);
    944          1.66  christos 	}
    945          1.66  christos 	(void)gettimeofday(&now, NULL);
    946          1.67  christos #ifdef SUPPORT_UTMPX
    947          1.66  christos 	doutmpx();
    948          1.66  christos 	dolastlogx(quietlog);
    949          1.66  christos 	quietlog = 1;
    950          1.66  christos #endif
    951          1.67  christos #ifdef SUPPORT_UTMP
    952          1.66  christos 	doutmp();
    953          1.66  christos 	dolastlog(quietlog);
    954          1.66  christos #endif
    955          1.66  christos }
    956          1.66  christos 
    957          1.67  christos #ifdef SUPPORT_UTMPX
    958          1.66  christos static void
    959          1.80   xtraeme doutmpx(void)
    960          1.66  christos {
    961          1.66  christos 	struct utmpx utmpx;
    962          1.66  christos 	char *t;
    963          1.66  christos 
    964          1.66  christos 	memset((void *)&utmpx, 0, sizeof(utmpx));
    965          1.66  christos 	utmpx.ut_tv = now;
    966          1.66  christos 	(void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
    967          1.66  christos 	if (hostname) {
    968          1.66  christos 		(void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
    969          1.66  christos 		utmpx.ut_ss = ss;
    970          1.66  christos 	}
    971          1.66  christos 	(void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
    972          1.66  christos 	utmpx.ut_type = USER_PROCESS;
    973          1.66  christos 	utmpx.ut_pid = getpid();
    974          1.66  christos 	t = tty + strlen(tty);
    975          1.66  christos 	if (t - tty >= sizeof(utmpx.ut_id)) {
    976          1.66  christos 	    (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
    977          1.66  christos 		sizeof(utmpx.ut_id));
    978          1.66  christos 	} else {
    979          1.66  christos 	    (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
    980          1.66  christos 	}
    981          1.66  christos 	if (pututxline(&utmpx) == NULL)
    982      1.82.2.2      tron 		syslog(LOG_NOTICE, "Cannot update utmpx: %m");
    983          1.66  christos 	endutxent();
    984          1.66  christos 	if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
    985      1.82.2.2      tron 		syslog(LOG_NOTICE, "Cannot update wtmpx: %m");
    986          1.66  christos }
    987          1.66  christos 
    988          1.66  christos static void
    989          1.80   xtraeme dolastlogx(int quiet)
    990          1.66  christos {
    991          1.66  christos 	struct lastlogx ll;
    992          1.74       wiz 	if (getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) {
    993          1.66  christos 		time_t t = (time_t)ll.ll_tv.tv_sec;
    994          1.66  christos 		(void)printf("Last login: %.24s ", ctime(&t));
    995          1.66  christos 		if (*ll.ll_host != '\0')
    996          1.66  christos 			(void)printf("from %.*s ",
    997          1.66  christos 			    (int)sizeof(ll.ll_host),
    998          1.66  christos 			    ll.ll_host);
    999          1.66  christos 		(void)printf("on %.*s\n",
   1000          1.66  christos 		    (int)sizeof(ll.ll_line),
   1001          1.66  christos 		    ll.ll_line);
   1002          1.66  christos 	}
   1003          1.66  christos 	ll.ll_tv = now;
   1004          1.66  christos 	(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
   1005          1.66  christos 	if (hostname) {
   1006          1.66  christos 		(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
   1007          1.66  christos 		ll.ll_ss = ss;
   1008          1.66  christos 	}
   1009          1.66  christos 	if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
   1010      1.82.2.2      tron 		syslog(LOG_NOTICE, "Cannot update lastlogx: %m");
   1011          1.66  christos }
   1012          1.66  christos #endif
   1013          1.66  christos 
   1014          1.67  christos #ifdef SUPPORT_UTMP
   1015          1.66  christos static void
   1016          1.80   xtraeme doutmp(void)
   1017          1.66  christos {
   1018          1.66  christos 	struct utmp utmp;
   1019          1.66  christos 
   1020          1.66  christos 	(void)memset((void *)&utmp, 0, sizeof(utmp));
   1021          1.66  christos 	utmp.ut_time = now.tv_sec;
   1022          1.66  christos 	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
   1023          1.66  christos 	if (hostname)
   1024          1.66  christos 		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
   1025          1.66  christos 	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
   1026          1.66  christos 	login(&utmp);
   1027          1.66  christos }
   1028          1.66  christos 
   1029          1.66  christos static void
   1030          1.80   xtraeme dolastlog(int quiet)
   1031           1.1       cgd {
   1032           1.1       cgd 	struct lastlog ll;
   1033           1.1       cgd 	int fd;
   1034           1.1       cgd 
   1035           1.1       cgd 	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
   1036          1.26    kleink 		(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
   1037           1.1       cgd 		if (!quiet) {
   1038           1.1       cgd 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
   1039           1.1       cgd 			    ll.ll_time != 0) {
   1040          1.66  christos 				(void)printf("Last login: %.24s ",
   1041          1.66  christos 				    ctime(&ll.ll_time));
   1042           1.1       cgd 				if (*ll.ll_host != '\0')
   1043          1.66  christos 					(void)printf("from %.*s ",
   1044           1.5       cgd 					    (int)sizeof(ll.ll_host),
   1045           1.5       cgd 					    ll.ll_host);
   1046          1.66  christos 				(void)printf("on %.*s\n",
   1047          1.66  christos 				    (int)sizeof(ll.ll_line), ll.ll_line);
   1048           1.1       cgd 			}
   1049          1.26    kleink 			(void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)),
   1050          1.26    kleink 			    SEEK_SET);
   1051           1.1       cgd 		}
   1052          1.12       jtc 		memset((void *)&ll, 0, sizeof(ll));
   1053          1.66  christos 		ll.ll_time = now.tv_sec;
   1054           1.5       cgd 		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
   1055           1.1       cgd 		if (hostname)
   1056           1.5       cgd 			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
   1057           1.1       cgd 		(void)write(fd, (char *)&ll, sizeof(ll));
   1058           1.1       cgd 		(void)close(fd);
   1059           1.1       cgd 	}
   1060           1.1       cgd }
   1061          1.66  christos #endif
   1062           1.1       cgd 
   1063           1.5       cgd void
   1064          1.80   xtraeme badlogin(char *name)
   1065           1.1       cgd {
   1066          1.55     enami 
   1067           1.1       cgd 	if (failures == 0)
   1068           1.1       cgd 		return;
   1069           1.1       cgd 	if (hostname) {
   1070           1.1       cgd 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
   1071           1.1       cgd 		    failures, failures > 1 ? "S" : "", hostname);
   1072           1.1       cgd 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
   1073           1.1       cgd 		    "%d LOGIN FAILURE%s FROM %s, %s",
   1074           1.1       cgd 		    failures, failures > 1 ? "S" : "", hostname, name);
   1075           1.1       cgd 	} else {
   1076           1.1       cgd 		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
   1077           1.1       cgd 		    failures, failures > 1 ? "S" : "", tty);
   1078           1.1       cgd 		syslog(LOG_AUTHPRIV|LOG_NOTICE,
   1079           1.1       cgd 		    "%d LOGIN FAILURE%s ON %s, %s",
   1080           1.1       cgd 		    failures, failures > 1 ? "S" : "", tty, name);
   1081           1.1       cgd 	}
   1082           1.1       cgd }
   1083           1.1       cgd 
   1084          1.39   mycroft const char *
   1085          1.80   xtraeme stypeof(const char *ttyid)
   1086           1.1       cgd {
   1087           1.1       cgd 	struct ttyent *t;
   1088           1.1       cgd 
   1089          1.48       mjl 	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : NULL);
   1090           1.1       cgd }
   1091           1.1       cgd 
   1092           1.5       cgd void
   1093          1.80   xtraeme sleepexit(int eval)
   1094           1.1       cgd {
   1095          1.38       mrg 
   1096          1.12       jtc 	(void)sleep(5);
   1097           1.1       cgd 	exit(eval);
   1098           1.1       cgd }
   1099          1.79  christos 
   1100          1.79  christos void
   1101          1.80   xtraeme decode_ss(const char *arg)
   1102          1.79  christos {
   1103          1.79  christos 	struct sockaddr_storage *ssp;
   1104          1.79  christos 	size_t len = strlen(arg);
   1105          1.79  christos 
   1106          1.79  christos 	if (len > sizeof(*ssp) * 4 + 1 || len < sizeof(*ssp))
   1107          1.79  christos 		errx(1, "Bad argument");
   1108          1.79  christos 
   1109          1.79  christos 	if ((ssp = malloc(len)) == NULL)
   1110          1.79  christos 		err(1, NULL);
   1111          1.79  christos 
   1112          1.79  christos 	if (strunvis((char *)ssp, arg) != sizeof(*ssp))
   1113          1.79  christos 		errx(1, "Decoding error");
   1114          1.79  christos 
   1115          1.79  christos 	(void)memcpy(&ss, ssp, sizeof(ss));
   1116          1.79  christos 	have_ss = 1;
   1117          1.79  christos }
   1118          1.79  christos 
   1119          1.79  christos void
   1120          1.80   xtraeme usage(void)
   1121          1.79  christos {
   1122          1.79  christos 	(void)fprintf(stderr,
   1123          1.79  christos 	    "Usage: %s [-Ffps] [-a address] [-h hostname] [username]\n",
   1124          1.79  christos 	    getprogname());
   1125          1.79  christos 	exit(1);
   1126          1.79  christos }
   1127