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