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