login.c revision 38374
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if 0
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
43#endif
44static const char rcsid[] =
45	"$Id: login.c,v 1.37 1998/07/31 07:22:31 bde Exp $";
46#endif /* not lint */
47
48/*
49 * login [ name ]
50 * login -h hostname	(for telnetd, etc.)
51 * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
52 */
53
54#include <sys/copyright.h>
55#include <sys/param.h>
56#include <sys/stat.h>
57#include <sys/time.h>
58#include <sys/resource.h>
59#include <sys/file.h>
60#include <netinet/in.h>
61#include <arpa/inet.h>
62
63#include <err.h>
64#include <errno.h>
65#include <grp.h>
66#include <netdb.h>
67#include <pwd.h>
68#include <setjmp.h>
69#include <signal.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <syslog.h>
74#include <ttyent.h>
75#include <unistd.h>
76#include <utmp.h>
77
78#ifdef LOGIN_CAP
79#include <login_cap.h>
80#else /* Undef AUTH as well */
81#undef LOGIN_CAP_AUTH
82#endif
83
84/*
85 * If LOGIN_CAP_AUTH is activated:
86 * kerberose & skey logins are runtime selected via login
87 * login_getstyle() and authentication types for login classes
88 * The actual login itself is handled via /usr/libexec/login_<style>
89 * Valid styles are determined by the auth-type=style,style entries
90 * in the login class.
91 */
92#ifdef LOGIN_CAP_AUTH
93#undef KERBEROS
94#undef SKEY
95#endif /* LOGIN_CAP_AUTH */
96
97#ifdef	SKEY
98#include <skey.h>
99#endif /* SKEY */
100
101#include "pathnames.h"
102
103void	 badlogin __P((char *));
104void	 checknologin __P((void));
105void	 dolastlog __P((int));
106void	 getloginname __P((void));
107void	 motd __P((char *));
108int	 rootterm __P((char *));
109void	 sigint __P((int));
110void	 sleepexit __P((int));
111void	 refused __P((char *,char *,int));
112char	*stypeof __P((char *));
113void	 timedout __P((int));
114int	 login_access __P((char *, char *));
115void     login_fbtab __P((char *, uid_t, gid_t));
116#ifdef KERBEROS
117int	 klogin __P((struct passwd *, char *, char *, char *));
118#endif
119
120extern void login __P((struct utmp *));
121extern void trimdomain __P((char *, int));
122static void usage __P((void));
123
124#define	TTYGRPNAME	"tty"		/* name of group to own ttys */
125#define	DEFAULT_BACKOFF	3
126#define	DEFAULT_RETRIES	10
127
128/*
129 * This bounds the time given to login.  Not a define so it can
130 * be patched on machines where it's too small.
131 */
132u_int	timeout = 300;
133
134#ifdef KERBEROS
135int	notickets = 1;
136int	noticketsdontcomplain = 1;
137char	*instance;
138char	*krbtkfile_env;
139int	authok;
140#endif
141
142struct	passwd *pwd;
143int	failures;
144char	*term, *envinit[1], *hostname, *username, *tty;
145char    full_hostname[MAXHOSTNAMELEN];
146
147int
148main(argc, argv)
149	int argc;
150	char *argv[];
151{
152	extern char **environ;
153	struct group *gr;
154	struct stat st;
155	struct timeval tp;
156	struct utmp utmp;
157	int rootok, retries, backoff;
158	int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
159	int changepass;
160	time_t warntime;
161	uid_t uid, euid;
162	char *domain, *p, *ep, *salt, *ttyn;
163	char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
164	char localhost[MAXHOSTNAMELEN];
165	char *shell = NULL;
166#ifdef LOGIN_CAP
167	login_cap_t *lc = NULL;
168#ifdef LOGIN_CAP_AUTH
169	char *style, *authtype;
170	char *auth_method = NULL;
171	char *instance = NULL;
172	int authok;
173#endif /* LOGIN_CAP_AUTH */
174#endif /* LOGIN_CAP */
175#ifdef SKEY
176	int permit_passwd = 0;
177#endif /* SKEY */
178
179	(void)signal(SIGALRM, timedout);
180	(void)alarm(timeout);
181	(void)signal(SIGQUIT, SIG_IGN);
182	(void)signal(SIGINT, SIG_IGN);
183	(void)setpriority(PRIO_PROCESS, 0, 0);
184
185	openlog("login", LOG_ODELAY, LOG_AUTH);
186
187	/*
188	 * -p is used by getty to tell login not to destroy the environment
189	 * -f is used to skip a second login authentication
190	 * -h is used by other servers to pass the name of the remote
191	 *    host to login so that it may be placed in utmp and wtmp
192	 */
193	*full_hostname = '\0';
194	domain = NULL;
195	term = NULL;
196	if (gethostname(localhost, sizeof(localhost)) < 0)
197		syslog(LOG_ERR, "couldn't get local hostname: %m");
198	else
199		domain = strchr(localhost, '.');
200
201	fflag = hflag = pflag = 0;
202	uid = getuid();
203	euid = geteuid();
204	while ((ch = getopt(argc, argv, "fh:p")) != -1)
205		switch (ch) {
206		case 'f':
207			fflag = 1;
208			break;
209		case 'h':
210			if (uid)
211				errx(1, "-h option: %s", strerror(EPERM));
212			hflag = 1;
213			strncpy(full_hostname, optarg, sizeof(full_hostname)-1);
214			if (domain && (p = strchr(optarg, '.')) &&
215			    strcasecmp(p, domain) == 0)
216				*p = 0;
217
218			trimdomain(optarg, UT_HOSTSIZE );
219
220			if (strlen(optarg) > UT_HOSTSIZE) {
221				struct hostent *hp = gethostbyname(optarg);
222
223				if (hp != NULL) {
224					struct in_addr in;
225
226					memmove(&in, hp->h_addr, sizeof(in));
227					optarg = strdup(inet_ntoa(in));
228				} else
229					optarg = "invalid hostname";
230			}
231			hostname = optarg;
232			break;
233		case 'p':
234			pflag = 1;
235			break;
236		case '?':
237		default:
238			if (!uid)
239				syslog(LOG_ERR, "invalid flag %c", ch);
240			usage();
241		}
242	argc -= optind;
243	argv += optind;
244
245	if (*argv) {
246		username = *argv;
247		ask = 0;
248	} else
249		ask = 1;
250
251	for (cnt = getdtablesize(); cnt > 2; cnt--)
252		(void)close(cnt);
253
254	ttyn = ttyname(STDIN_FILENO);
255	if (ttyn == NULL || *ttyn == '\0') {
256		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
257		ttyn = tname;
258	}
259	if ((tty = strrchr(ttyn, '/')) != NULL)
260		++tty;
261	else
262		tty = ttyn;
263
264#ifdef LOGIN_CAP_AUTH
265	authtype = hostname ? "rlogin" : "login";
266#endif
267#ifdef LOGIN_CAP
268	/*
269	 * Get "login-retries" & "login-backoff" from default class
270	 */
271	lc = login_getclass(NULL);
272	retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES, DEFAULT_RETRIES);
273	backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF, DEFAULT_BACKOFF);
274	login_close(lc);
275	lc = NULL;
276#else
277	retries = DEFAULT_RETRIES;
278	backoff = DEFAULT_BACKOFF;
279#endif
280
281	for (cnt = 0;; ask = 1) {
282		if (ask) {
283			fflag = 0;
284			getloginname();
285		}
286		rootlogin = 0;
287		rootok = rootterm(tty); /* Default (auth may change) */
288#ifdef LOGIN_CAP_AUTH
289		authok = 0;
290		if (auth_method = strchr(username, ':')) {
291			*auth_method = '\0';
292			auth_method++;
293			if (*auth_method == '\0')
294				auth_method = NULL;
295		}
296		/*
297		 * We need to do this regardless of whether
298		 * kerberos is available.
299		 */
300		if ((instance = strchr(username, '.')) != NULL) {
301			if (strncmp(instance, ".root", 5) == 0)
302				rootlogin = 1;
303			*instance++ = '\0';
304		} else
305			instance = "";
306#else /* !LOGIN_CAP_AUTH */
307#ifdef KERBEROS
308		if ((instance = strchr(username, '.')) != NULL) {
309			if (strncmp(instance, ".root", 5) == 0)
310				rootlogin = 1;
311			*instance++ = '\0';
312		} else
313			instance = "";
314#endif /* KERBEROS */
315#endif /* LOGIN_CAP_AUTH */
316
317		if (strlen(username) > UT_NAMESIZE)
318			username[UT_NAMESIZE] = '\0';
319
320		/*
321		 * Note if trying multiple user names; log failures for
322		 * previous user name, but don't bother logging one failure
323		 * for nonexistent name (mistyped username).
324		 */
325		if (failures && strcmp(tbuf, username)) {
326			if (failures > (pwd ? 0 : 1))
327				badlogin(tbuf);
328			failures = 0;
329		}
330		(void)strncpy(tbuf, username, sizeof tbuf-1);
331		tbuf[sizeof tbuf-1] = '\0';
332
333		if ((pwd = getpwnam(username)) != NULL)
334			salt = pwd->pw_passwd;
335		else
336			salt = "xx";
337
338#ifdef LOGIN_CAP
339		/*
340		 * Establish the class now, before we might goto
341		 * within the next block. pwd can be NULL since it
342		 * falls back to the "default" class if it is.
343		 */
344		if (pwd != NULL)
345			(void)seteuid(rootlogin ? 0 : pwd->pw_uid);
346		lc = login_getpwclass(pwd);
347		seteuid(euid);
348#endif /* LOGIN_CAP */
349
350		/*
351		 * if we have a valid account name, and it doesn't have a
352		 * password, or the -f option was specified and the caller
353		 * is root or the caller isn't changing their uid, don't
354		 * authenticate.
355		 */
356		rval = 1;
357		if (pwd != NULL) {
358			if (pwd->pw_uid == 0)
359				rootlogin = 1;
360
361			if (fflag && (uid == (uid_t)0 ||
362				      uid == (uid_t)pwd->pw_uid)) {
363				/* already authenticated */
364				break;
365			} else if (pwd->pw_passwd[0] == '\0') {
366				if (!rootlogin || rootok) {
367					/* pretend password okay */
368					rval = 0;
369					goto ttycheck;
370				}
371			}
372		}
373
374		fflag = 0;
375
376		(void)setpriority(PRIO_PROCESS, 0, -4);
377
378#ifdef LOGIN_CAP_AUTH
379		/*
380		 * This hands off authorization to an authorization program,
381		 * depending on the styles available for the "auth-login",
382		 * auth-rlogin (or default) authorization styles.
383		 * We do this regardless of whether an account exists so that
384		 * the remote user cannot tell a "real" from an invented
385		 * account name. If we don't have an account we just fall
386		 * back to the first method for the "default" class.
387		 */
388		if (!(style = login_getstyle(lc, auth_method, authtype))) {
389
390			/*
391			 * No available authorization method
392			 */
393			rval = 1;
394			(void)printf("No auth method available for %s.\n",
395				     authtype);
396		} else {
397
398			/*
399			 * Put back the kerberos instance, if any was given.
400			 * Don't worry about the non-kerberos case here, since
401			 * if kerberos is not available or not selected and an
402			 * instance is given at the login prompt, su or rlogin -l,
403			 * then anything else should fail as well.
404			 */
405			if (*instance)
406				*(instance - 1) = '.';
407
408			rval = authenticate(username,
409					    lc ? lc->lc_class : "default",
410					    style, authtype);
411			/* Junk it again */
412			if (*instance)
413				*(instance - 1) = '\0';
414		}
415
416		if (!rval) {
417			char * approvep;
418
419			/*
420			 * If authentication succeeds, run any approval
421			 * program, if applicable for this class.
422			 */
423			approvep = login_getcapstr(lc, "approve", NULL, NULL);
424			rval = 1; /* Assume bad login again */
425
426			if (approvep==NULL ||
427			    auth_script(approvep, approvep, username,
428					lc->lc_class, 0) == 0) {
429				int     r;
430
431				r = auth_scan(AUTH_OKAY);
432				/*
433				 * See what the authorize program says
434				 */
435				if (r != 0) {
436					rval = 0;
437
438					if (!rootok && (r & AUTH_ROOTOKAY))
439						rootok = 1; /* root approved */
440					else
441						rootlogin = 0;
442
443					if (!authok && (r & AUTH_SECURE))
444						authok = 1; /* secure */
445				}
446			}
447		}
448#else /* !LOGIN_CAP_AUTH */
449#ifdef SKEY
450		permit_passwd = skeyaccess(username, tty,
451					   hostname ? full_hostname : NULL,
452					   NULL);
453		p = skey_getpass("Password:", pwd, permit_passwd);
454		ep = skey_crypt(p, salt, pwd, permit_passwd);
455#else /* !SKEY */
456		p = getpass("Password:");
457		ep = crypt(p, salt);
458#endif/* SKEY */
459
460		if (pwd) {
461			if (!p[0] && pwd->pw_passwd[0])
462				ep = ":";
463#ifdef KERBEROS
464#ifdef SKEY
465			/*
466			 * Do not allow user to type in kerberos password
467			 * over the net (actually, this is ok for encrypted
468			 * links, but we have no way of determining if the
469			 * link is encrypted.
470			 */
471			if (!permit_passwd) {
472				rval = 1;		/* failed */
473			} else
474#endif /* SKEY */
475			rval = klogin(pwd, instance, localhost, p);
476			if (rval != 0 && rootlogin && pwd->pw_uid != 0)
477				rootlogin = 0;
478			if (rval == 0)
479				authok = 1; /* kerberos authenticated ok */
480			else if (rval == 1) /* fallback to unix passwd */
481				rval = strcmp(ep, pwd->pw_passwd);
482#else /* !KERBEROS */
483			rval = strcmp(ep, pwd->pw_passwd);
484#endif /* KERBEROS */
485		}
486
487		/* clear entered password */
488		memset(p, 0, strlen(p));
489#endif /* LOGIN_CAP_AUTH */
490
491		(void)setpriority(PRIO_PROCESS, 0, 0);
492
493#ifdef LOGIN_CAP_AUTH
494		if (rval)
495			auth_rmfiles();
496#endif
497	ttycheck:
498		/*
499		 * If trying to log in as root without Kerberos,
500		 * but with insecure terminal, refuse the login attempt.
501		 */
502		if (pwd && !rval) {
503#if defined(KERBEROS) || defined(LOGIN_CAP_AUTH)
504			if (authok == 0 && rootlogin && !rootok)
505#else
506			if (rootlogin && !rootok)
507#endif
508				refused(NULL, "NOROOT", 0);
509			else	/* valid password & authenticated */
510				break;
511		}
512
513		(void)printf("Login incorrect\n");
514		failures++;
515
516		/*
517		 * we allow up to 'retry' (10) tries,
518		 * but after 'backoff' (3) we start backing off
519		 */
520		if (++cnt > backoff) {
521			if (cnt >= retries) {
522				badlogin(username);
523				sleepexit(1);
524			}
525			sleep((u_int)((cnt - backoff) * 5));
526		}
527	}
528
529	/* committed to login -- turn off timeout */
530	(void)alarm((u_int)0);
531
532	endpwent();
533
534	/* if user not super-user, check for disabled logins */
535#ifdef LOGIN_CAP
536	if (!rootlogin)
537		auth_checknologin(lc);
538#else
539	if (!rootlogin)
540		checknologin();
541#endif
542
543#ifdef LOGIN_CAP
544	quietlog = login_getcapbool(lc, "hushlogin", 0);
545#else
546	quietlog = 0;
547#endif
548	(void)seteuid(rootlogin ? 0 : pwd->pw_uid);
549	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
550#ifdef LOGIN_CAP
551		if (login_getcapbool(lc, "requirehome", 0))
552			refused("Home directory not available", "HOMEDIR", 1);
553#endif
554		if (chdir("/") < 0)
555			refused("Cannot find root directory", "ROOTDIR", 1);
556		pwd->pw_dir = "/";
557		if (!quietlog || *pwd->pw_dir)
558			printf("No home directory.\nLogging in with home = \"/\".\n");
559	}
560	(void)seteuid(euid);
561	if (!quietlog)
562		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
563
564	if (pwd->pw_change || pwd->pw_expire)
565		(void)gettimeofday(&tp, (struct timezone *)NULL);
566
567#define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
568
569#ifdef LOGIN_CAP
570	warntime = login_getcaptime(lc, "warnpassword",
571				    DEFAULT_WARN, DEFAULT_WARN);
572#else
573	warntime = DEFAULT_WARN;
574#endif
575
576	changepass=0;
577	if (pwd->pw_change) {
578		if (tp.tv_sec >= pwd->pw_change) {
579			(void)printf("Sorry -- your password has expired.\n");
580			changepass=1;
581			syslog(LOG_INFO,
582			       "%s Password expired - forcing change",
583			       pwd->pw_name);
584		} else if (pwd->pw_change - tp.tv_sec < warntime && !quietlog)
585		    (void)printf("Warning: your password expires on %s",
586				 ctime(&pwd->pw_change));
587	}
588
589#ifdef LOGIN_CAP
590	warntime = login_getcaptime(lc, "warnexpire",
591				    DEFAULT_WARN, DEFAULT_WARN);
592#else
593	warntime = DEFAULT_WARN;
594#endif
595
596	if (pwd->pw_expire) {
597		if (tp.tv_sec >= pwd->pw_expire) {
598			refused("Sorry -- your account has expired",
599				"EXPIRED", 1);
600		} else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
601		    (void)printf("Warning: your account expires on %s",
602				 ctime(&pwd->pw_expire));
603	}
604
605#ifdef LOGIN_CAP
606	if (lc != NULL) {
607		if (hostname) {
608			struct hostent *hp = gethostbyname(full_hostname);
609
610			if (hp == NULL)
611				optarg = NULL;
612			else {
613				struct in_addr in;
614				memmove(&in, hp->h_addr, sizeof(in));
615				optarg = strdup(inet_ntoa(in));
616			}
617			if (!auth_hostok(lc, full_hostname, optarg))
618				refused("Permission denied", "HOST", 1);
619		}
620
621		if (!auth_ttyok(lc, tty))
622			refused("Permission denied", "TTY", 1);
623
624		if (!auth_timeok(lc, time(NULL)))
625			refused("Logins not available right now", "TIME", 1);
626	}
627        shell=login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
628#else /* !LOGIN_CAP */
629       shell=pwd->pw_shell;
630#endif /* LOGIN_CAP */
631	if (*pwd->pw_shell == '\0')
632		pwd->pw_shell = _PATH_BSHELL;
633	if (*shell == '\0')   /* Not overridden */
634		shell = pwd->pw_shell;
635	if ((shell = strdup(shell)) == NULL) {
636		syslog(LOG_NOTICE, "memory allocation error");
637		sleepexit(1);
638	}
639
640#ifdef LOGIN_ACCESS
641	if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
642		refused("Permission denied", "ACCESS", 1);
643#endif /* LOGIN_ACCESS */
644
645	/* Nothing else left to fail -- really log in. */
646	memset((void *)&utmp, 0, sizeof(utmp));
647	(void)time(&utmp.ut_time);
648	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
649	if (hostname)
650		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
651	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
652	login(&utmp);
653
654	dolastlog(quietlog);
655
656	/*
657	 * Set device protections, depending on what terminal the
658	 * user is logged in. This feature is used on Suns to give
659	 * console users better privacy.
660	 */
661	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
662
663	(void)chown(ttyn, pwd->pw_uid,
664		    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
665
666	/*
667	 * Preserve TERM if it happens to be already set.
668	 */
669	if ((term = getenv("TERM")) != NULL)
670		term = strdup(term);
671
672	/*
673	 * Exclude cons/vt/ptys only, assume dialup otherwise
674	 * TODO: Make dialup tty determination a library call
675	 * for consistency (finger etc.)
676	 */
677	if (hostname==NULL && isdialuptty(tty))
678		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
679
680#ifdef KERBEROS
681	if (!quietlog && notickets == 1 && !noticketsdontcomplain)
682		(void)printf("Warning: no Kerberos tickets issued.\n");
683#endif
684
685#ifdef LOGALL
686	/*
687	 * Syslog each successful login, so we don't have to watch hundreds
688	 * of wtmp or lastlogin files.
689	 */
690	if (hostname)
691		syslog(LOG_INFO, "login from %s on %s as %s",
692		       full_hostname, tty, pwd->pw_name);
693	else
694		syslog(LOG_INFO, "login on %s as %s",
695		       tty, pwd->pw_name);
696#endif
697
698	/*
699	 * If fflag is on, assume caller/authenticator has logged root login.
700	 */
701	if (rootlogin && fflag == 0)
702	{
703		if (hostname)
704			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
705			       username, tty, full_hostname);
706		else
707			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
708			       username, tty);
709	}
710
711	/*
712	 * Destroy environment unless user has requested its preservation.
713	 * We need to do this before setusercontext() because that may
714	 * set or reset some environment variables.
715	 */
716	if (!pflag)
717		environ = envinit;
718
719	/*
720	 * We don't need to be root anymore, so
721	 * set the user and session context
722	 */
723#ifdef LOGIN_CAP
724	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) {
725                syslog(LOG_ERR, "setusercontext() failed - exiting");
726		exit(1);
727	}
728#else
729     	if (setlogin(pwd->pw_name) < 0)
730                syslog(LOG_ERR, "setlogin() failure: %m");
731
732	(void)setgid(pwd->pw_gid);
733	initgroups(username, pwd->pw_gid);
734	(void)setuid(rootlogin ? 0 : pwd->pw_uid);
735#endif
736
737	(void)setenv("SHELL", pwd->pw_shell, 1);
738	(void)setenv("HOME", pwd->pw_dir, 1);
739	if (term != NULL && *term != '\0')
740		(void)setenv("TERM", term, 1);	/* Preset overrides */
741	else {
742		(void)setenv("TERM", stypeof(tty), 0);	/* Fallback doesn't */
743	}
744	(void)setenv("LOGNAME", pwd->pw_name, 1);
745	(void)setenv("USER", pwd->pw_name, 1);
746	(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
747#ifdef KERBEROS
748	if (krbtkfile_env)
749		(void)setenv("KRBTKFILE", krbtkfile_env, 1);
750#endif
751#if LOGIN_CAP_AUTH
752	auth_env();
753#endif
754
755#ifdef LOGIN_CAP
756	if (!quietlog) {
757		char	*cw;
758
759		cw = login_getcapstr(lc, "copyright", NULL, NULL);
760		if (cw != NULL && access(cw, F_OK) == 0)
761			motd(cw);
762		else
763		    (void)printf("%s\n\t%s %s\n",
764	"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
765	"The Regents of the University of California. ",
766	"All rights reserved.");
767
768		(void)printf("\n");
769
770		cw = login_getcapstr(lc, "welcome", NULL, NULL);
771		if (cw == NULL || access(cw, F_OK) != 0)
772			cw = _PATH_MOTDFILE;
773		motd(cw);
774
775		cw = getenv("MAIL");	/* $MAIL may have been set by class */
776		if (cw != NULL) {
777			strncpy(tbuf, cw, sizeof(tbuf));
778			tbuf[sizeof(tbuf)-1] = '\0';
779		} else
780			snprintf(tbuf, sizeof(tbuf), "%s/%s",
781				 _PATH_MAILDIR, pwd->pw_name);
782#else
783	if (!quietlog) {
784		    (void)printf("%s\n\t%s %s\n",
785	"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
786	"The Regents of the University of California. ",
787	"All rights reserved.");
788		motd(_PATH_MOTDFILE);
789		snprintf(tbuf, sizeof(tbuf), "%s/%s",
790			 _PATH_MAILDIR, pwd->pw_name);
791#endif
792		if (stat(tbuf, &st) == 0 && st.st_size != 0)
793			(void)printf("You have %smail.\n",
794				     (st.st_mtime > st.st_atime) ? "new " : "");
795	}
796
797#ifdef LOGIN_CAP
798	login_close(lc);
799#endif
800
801	(void)signal(SIGALRM, SIG_DFL);
802	(void)signal(SIGQUIT, SIG_DFL);
803	(void)signal(SIGINT, SIG_DFL);
804	(void)signal(SIGTSTP, SIG_IGN);
805
806	if (changepass) {
807		if (system(_PATH_CHPASS) != 0)
808			sleepexit(1);
809	}
810
811	/*
812	 * Login shells have a leading '-' in front of argv[0]
813	 */
814	tbuf[0] = '-';
815	(void)strcpy(tbuf + 1, (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell);
816
817	execlp(shell, tbuf, 0);
818	err(1, "%s", shell);
819}
820
821static void
822usage()
823{
824	(void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
825	exit(1);
826}
827
828/*
829 * Allow for authentication style and/or kerberos instance
830 * */
831
832#define	NBUFSIZ		UT_NAMESIZE + 64
833
834void
835getloginname()
836{
837	int ch;
838	char *p;
839	static char nbuf[NBUFSIZ];
840
841	for (;;) {
842		(void)printf("login: ");
843		for (p = nbuf; (ch = getchar()) != '\n'; ) {
844			if (ch == EOF) {
845				badlogin(username);
846				exit(0);
847			}
848			if (p < nbuf + (NBUFSIZ - 1))
849				*p++ = ch;
850		}
851		if (p > nbuf)
852			if (nbuf[0] == '-')
853				(void)fprintf(stderr,
854				    "login names may not start with '-'.\n");
855			else {
856				*p = '\0';
857				username = nbuf;
858				break;
859			}
860	}
861}
862
863int
864rootterm(ttyn)
865	char *ttyn;
866{
867	struct ttyent *t;
868
869	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
870}
871
872volatile int motdinterrupt;
873
874/* ARGSUSED */
875void
876sigint(signo)
877	int signo;
878{
879	motdinterrupt = 1;
880}
881
882void
883motd(motdfile)
884	char *motdfile;
885{
886	int fd, nchars;
887	sig_t oldint;
888	char tbuf[256];
889
890	if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
891		return;
892	motdinterrupt = 0;
893	oldint = signal(SIGINT, sigint);
894	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
895		(void)write(fileno(stdout), tbuf, nchars);
896	(void)signal(SIGINT, oldint);
897	(void)close(fd);
898}
899
900/* ARGSUSED */
901void
902timedout(signo)
903	int signo;
904{
905	(void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
906	exit(0);
907}
908
909#ifndef LOGIN_CAP
910void
911checknologin()
912{
913	int fd, nchars;
914	char tbuf[8192];
915
916	if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
917		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
918			(void)write(fileno(stdout), tbuf, nchars);
919		sleepexit(0);
920	}
921}
922#endif
923
924void
925dolastlog(quiet)
926	int quiet;
927{
928	struct lastlog ll;
929	int fd;
930
931	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
932		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
933		if (!quiet) {
934			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
935			    ll.ll_time != 0) {
936				(void)printf("Last login: %.*s ",
937				    24-5, (char *)ctime(&ll.ll_time));
938				if (*ll.ll_host != '\0')
939					(void)printf("from %.*s\n",
940					    (int)sizeof(ll.ll_host),
941					    ll.ll_host);
942				else
943					(void)printf("on %.*s\n",
944					    (int)sizeof(ll.ll_line),
945					    ll.ll_line);
946			}
947			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
948		}
949		memset((void *)&ll, 0, sizeof(ll));
950		(void)time(&ll.ll_time);
951		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
952		if (hostname)
953			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
954		(void)write(fd, (char *)&ll, sizeof(ll));
955		(void)close(fd);
956	}
957}
958
959void
960badlogin(name)
961	char *name;
962{
963
964	if (failures == 0)
965		return;
966	if (hostname) {
967		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
968		    failures, failures > 1 ? "S" : "", full_hostname);
969		syslog(LOG_AUTHPRIV|LOG_NOTICE,
970		    "%d LOGIN FAILURE%s FROM %s, %s",
971		    failures, failures > 1 ? "S" : "", full_hostname, name);
972	} else {
973		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
974		    failures, failures > 1 ? "S" : "", tty);
975		syslog(LOG_AUTHPRIV|LOG_NOTICE,
976		    "%d LOGIN FAILURE%s ON %s, %s",
977		    failures, failures > 1 ? "S" : "", tty, name);
978	}
979}
980
981#undef	UNKNOWN
982#define	UNKNOWN	"su"
983
984char *
985stypeof(ttyid)
986	char *ttyid;
987{
988
989	struct ttyent *t;
990
991	return (ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
992}
993
994void
995refused(msg, rtype, lout)
996	char *msg;
997	char *rtype;
998	int lout;
999{
1000
1001	if (msg != NULL)
1002	    printf("%s.\n", msg);
1003	if (hostname)
1004		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1005		       pwd->pw_name, rtype, full_hostname, tty);
1006	else
1007		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1008		       pwd->pw_name, rtype, tty);
1009	if (lout)
1010		sleepexit(1);
1011}
1012
1013void
1014sleepexit(eval)
1015	int eval;
1016{
1017
1018	(void)sleep(5);
1019	exit(eval);
1020}
1021