login.c revision 89615
1/*-
2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 2002 Networks Associates Technologies, Inc.
5 * All rights reserved.
6 *
7 * Portions of this software were developed for the FreeBSD Project by
8 * ThinkSec AS and NAI Labs, the Security Research Division of Network
9 * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
10 * ("CBOSS"), as part of the DARPA CHATS research program.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#if 0
42#ifndef lint
43static char sccsid[] = "@(#)login.c	8.4 (Berkeley) 4/2/94";
44#endif
45#endif
46
47#include <sys/cdefs.h>
48__FBSDID("$FreeBSD: head/usr.bin/login/login.c 89615 2002-01-21 16:19:38Z des $");
49
50/*
51 * login [ name ]
52 * login -h hostname	(for telnetd, etc.)
53 * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
54 */
55
56#include <sys/copyright.h>
57#include <sys/param.h>
58#include <sys/file.h>
59#include <sys/socket.h>
60#include <sys/stat.h>
61#include <sys/time.h>
62#include <sys/resource.h>
63#include <sys/wait.h>
64#include <netinet/in.h>
65#include <arpa/inet.h>
66
67#include <err.h>
68#include <errno.h>
69#include <grp.h>
70#include <libutil.h>
71#include <login_cap.h>
72#include <netdb.h>
73#include <pwd.h>
74#include <setjmp.h>
75#include <signal.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <syslog.h>
80#include <ttyent.h>
81#include <unistd.h>
82#include <utmp.h>
83
84#ifndef NO_PAM
85#include <security/pam_appl.h>
86#include <security/pam_misc.h>
87#endif
88
89#include "login.h"
90#include "pathnames.h"
91
92/* wrapper for KAME-special getnameinfo() */
93#ifndef NI_WITHSCOPEID
94#define	NI_WITHSCOPEID	0
95#endif
96
97static int	auth_traditional __P((void));
98static void	badlogin __P((char *));
99static void	dolastlog __P((int));
100static void	getloginname __P((void));
101static void	motd __P((const char *));
102static void	refused __P((const char *,const char *,int));
103static int	rootterm __P((char *));
104static void	sigint __P((int));
105static void	sleepexit __P((int));
106static const char *stypeof __P((char *));
107static void	timedout __P((int));
108static void	usage __P((void));
109
110#ifndef NO_PAM
111static int	auth_pam __P((void));
112static int	export_pam_environment __P((void));
113static int	ok_to_export __P((const char *));
114
115static pam_handle_t *pamh = NULL;
116static char	**environ_pam;
117
118#define PAM_END { \
119	if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
120		syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \
121	if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \
122		syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \
123	if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \
124		syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \
125}
126#endif /* NO_PAM */
127
128#define	TTYGRPNAME		"tty"			/* group to own ttys */
129#define	DEFAULT_BACKOFF		3
130#define	DEFAULT_RETRIES		10
131#define	DEFAULT_PROMPT		"login: "
132#define	DEFAULT_PASSWD_PROMPT	"Password:"
133#define	INVALID_HOST		"invalid hostname"
134#define	UNKNOWN			"su"
135#define	DEFAULT_WARN		(2L * 7L * 86400L)	/* Two weeks */
136#define	NBUFSIZ			UT_NAMESIZE + 64
137
138/*
139 * This bounds the time given to login.  Not a define so it can
140 * be patched on machines where it's too small.
141 */
142u_int	timeout = 300;
143
144/* Buffer for signal handling of timeout */
145jmp_buf timeout_buf;
146
147struct	passwd *pwd;
148int	failures;
149char	*term, *envinit[1], *hostname, *passwd_prompt, *prompt, *tty, *username;
150char    full_hostname[MAXHOSTNAMELEN];
151
152int
153main(argc, argv)
154	int argc;
155	char *argv[];
156{
157	struct group *gr;
158	struct stat st;
159	struct timeval tp;
160	struct utmp utmp;
161	int rootok, retries, backoff;
162	int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
163	time_t warntime;
164	uid_t uid, euid;
165	gid_t egid;
166	char *p, *ttyn;
167	char tbuf[MAXPATHLEN + 2];
168	char tname[sizeof(_PATH_TTY) + 10];
169	char *shell = NULL;
170	static char default_prompt[] = DEFAULT_PROMPT;
171	static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
172	static char invalid_host[] = INVALID_HOST;
173	login_cap_t *lc = NULL;
174#ifndef NO_PAM
175	pid_t pid;
176	int e;
177#endif /* NO_PAM */
178
179	(void)signal(SIGQUIT, SIG_IGN);
180	(void)signal(SIGINT, SIG_IGN);
181	(void)signal(SIGHUP, SIG_IGN);
182	if (setjmp(timeout_buf)) {
183		if (failures)
184			badlogin(tbuf);
185		(void)fprintf(stderr, "Login timed out after %d seconds\n",
186		    timeout);
187		exit(0);
188	}
189	(void)signal(SIGALRM, timedout);
190	(void)alarm(timeout);
191	(void)setpriority(PRIO_PROCESS, 0, 0);
192
193	openlog("login", LOG_ODELAY, LOG_AUTH);
194
195	/*
196	 * -p is used by getty to tell login not to destroy the environment
197	 * -f is used to skip a second login authentication
198	 * -h is used by other servers to pass the name of the remote
199	 *    host to login so that it may be placed in utmp and wtmp
200	 */
201	*full_hostname = '\0';
202	term = NULL;
203
204	fflag = hflag = pflag = 0;
205	uid = getuid();
206	euid = geteuid();
207	egid = getegid();
208	while ((ch = getopt(argc, argv, "fh:p")) != -1)
209		switch (ch) {
210		case 'f':
211			fflag = 1;
212			break;
213		case 'h':
214			if (uid)
215				errx(1, "-h option: %s", strerror(EPERM));
216			hflag = 1;
217			if (strlcpy(full_hostname, optarg,
218			    sizeof(full_hostname)) >= sizeof(full_hostname))
219				errx(1, "-h option: %s: exceeds maximum "
220				    "hostname size", optarg);
221
222			trimdomain(optarg, UT_HOSTSIZE);
223
224			if (strlen(optarg) > UT_HOSTSIZE) {
225				struct addrinfo hints, *res;
226				int ga_err;
227
228				memset(&hints, 0, sizeof(hints));
229				hints.ai_family = AF_UNSPEC;
230				ga_err = getaddrinfo(optarg, NULL, &hints,
231				    &res);
232				if (ga_err == 0) {
233					char hostbuf[MAXHOSTNAMELEN];
234
235					getnameinfo(res->ai_addr,
236					    res->ai_addrlen,
237					    hostbuf,
238					    sizeof(hostbuf), NULL, 0,
239					    NI_NUMERICHOST|
240					    NI_WITHSCOPEID);
241					optarg = strdup(hostbuf);
242					if (optarg == NULL) {
243						syslog(LOG_NOTICE,
244						    "strdup(): %m");
245						sleepexit(1);
246					}
247				} else
248					optarg = invalid_host;
249				if (res != NULL)
250					freeaddrinfo(res);
251			}
252			hostname = optarg;
253			break;
254		case 'p':
255			pflag = 1;
256			break;
257		case '?':
258		default:
259			if (!uid)
260				syslog(LOG_ERR, "invalid flag %c", ch);
261			usage();
262		}
263	argc -= optind;
264	argv += optind;
265
266	if (*argv) {
267		username = *argv;
268		ask = 0;
269	} else
270		ask = 1;
271
272	for (cnt = getdtablesize(); cnt > 2; cnt--)
273		(void)close(cnt);
274
275	ttyn = ttyname(STDIN_FILENO);
276	if (ttyn == NULL || *ttyn == '\0') {
277		(void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
278		ttyn = tname;
279	}
280	if ((tty = strrchr(ttyn, '/')) != NULL)
281		++tty;
282	else
283		tty = ttyn;
284
285	/*
286	 * Get "login-retries" & "login-backoff" from default class
287	 */
288	lc = login_getclass(NULL);
289	prompt = login_getcapstr(lc, "prompt", default_prompt, default_prompt);
290	passwd_prompt = login_getcapstr(lc, "passwd_prompt",
291	    default_passwd_prompt, default_passwd_prompt);
292	retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES,
293	    DEFAULT_RETRIES);
294	backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF,
295	    DEFAULT_BACKOFF);
296	login_close(lc);
297	lc = NULL;
298
299	for (cnt = 0;; ask = 1) {
300		if (ask) {
301			fflag = 0;
302			getloginname();
303		}
304		rootlogin = 0;
305		rootok = rootterm(tty); /* Default (auth may change) */
306
307		if (strlen(username) > UT_NAMESIZE)
308			username[UT_NAMESIZE] = '\0';
309
310		/*
311		 * Note if trying multiple user names; log failures for
312		 * previous user name, but don't bother logging one failure
313		 * for nonexistent name (mistyped username).
314		 */
315		if (failures && strcmp(tbuf, username)) {
316			if (failures > (pwd ? 0 : 1))
317				badlogin(tbuf);
318		}
319		(void)strlcpy(tbuf, username, sizeof(tbuf));
320
321		pwd = getpwnam(username);
322
323		/*
324		 * if we have a valid account name, and it doesn't have a
325		 * password, or the -f option was specified and the caller
326		 * is root or the caller isn't changing their uid, don't
327		 * authenticate.
328		 */
329		if (pwd != NULL) {
330			if (pwd->pw_uid == 0)
331				rootlogin = 1;
332
333			if (fflag && (uid == (uid_t)0 ||
334			    uid == (uid_t)pwd->pw_uid)) {
335				/* already authenticated */
336				break;
337			} else if (pwd->pw_passwd[0] == '\0') {
338				if (!rootlogin || rootok) {
339					/* pretend password okay */
340					rval = 0;
341					goto ttycheck;
342				}
343			}
344		}
345
346		fflag = 0;
347
348		(void)setpriority(PRIO_PROCESS, 0, -4);
349
350#ifndef NO_PAM
351		/*
352		 * Try to authenticate using PAM.  If a PAM system error
353		 * occurs, perhaps because of a botched configuration,
354		 * then fall back to using traditional Unix authentication.
355		 */
356		if ((rval = auth_pam()) == -1)
357#endif /* NO_PAM */
358			rval = auth_traditional();
359
360		(void)setpriority(PRIO_PROCESS, 0, 0);
361
362		/*
363		 * PAM authentication may have changed "pwd" to the
364		 * entry for the template user.  Check again to see if
365		 * this is a root login after all.
366		 */
367		if (pwd != NULL && pwd->pw_uid == 0)
368			rootlogin = 1;
369
370	ttycheck:
371		/*
372		 * If trying to log in as root without Kerberos,
373		 * but with insecure terminal, refuse the login attempt.
374		 */
375		if (pwd && !rval) {
376			if (rootlogin && !rootok)
377				refused(NULL, "NOROOT", 0);
378			else	/* valid password & authenticated */
379				break;
380		}
381
382		(void)printf("Login incorrect\n");
383		failures++;
384
385		/*
386		 * we allow up to 'retry' (10) tries,
387		 * but after 'backoff' (3) we start backing off
388		 */
389		if (++cnt > backoff) {
390			if (cnt >= retries) {
391				badlogin(username);
392				sleepexit(1);
393			}
394			sleep((u_int)((cnt - backoff) * 5));
395		}
396	}
397
398	/* committed to login -- turn off timeout */
399	(void)alarm((u_int)0);
400	(void)signal(SIGHUP, SIG_DFL);
401
402	endpwent();
403
404	/*
405	 * Establish the login class.
406	 */
407	lc = login_getpwclass(pwd);
408
409	quietlog = login_getcapbool(lc, "hushlogin", 0);
410	/*
411	 * Switching needed for NFS with root access disabled.
412	 *
413	 * XXX: This change fails to modify the additional groups for the
414	 * process, and as such, may restrict rights normally granted
415	 * through those groups.
416	 */
417	(void)setegid(pwd->pw_gid);
418	(void)seteuid(rootlogin ? 0 : pwd->pw_uid);
419	if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
420		if (login_getcapbool(lc, "requirehome", 0))
421			refused("Home directory not available", "HOMEDIR", 1);
422		if (chdir("/") < 0)
423			refused("Cannot find root directory", "ROOTDIR", 1);
424		if (!quietlog || *pwd->pw_dir)
425			printf("No home directory.\nLogging in with home = \"/\".\n");
426		pwd->pw_dir = strdup("/");
427		if (pwd->pw_dir == NULL) {
428			syslog(LOG_NOTICE, "strdup(): %m");
429			sleepexit(1);
430		}
431	}
432	(void)seteuid(euid);
433	(void)setegid(egid);
434	if (!quietlog)
435		quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
436
437	if (pwd->pw_change || pwd->pw_expire)
438		(void)gettimeofday(&tp, (struct timezone *)NULL);
439
440	warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
441	    DEFAULT_WARN);
442
443	if (pwd->pw_expire) {
444		if (tp.tv_sec >= pwd->pw_expire) {
445			refused("Sorry -- your account has expired", "EXPIRED",
446			    1);
447		} else if (pwd->pw_expire - tp.tv_sec < warntime && !quietlog)
448			(void)printf("Warning: your account expires on %s",
449			    ctime(&pwd->pw_expire));
450	}
451
452	if (lc != NULL) {
453		if (hostname) {
454			struct addrinfo hints, *res;
455			int ga_err;
456
457			memset(&hints, 0, sizeof(hints));
458			hints.ai_family = AF_UNSPEC;
459			ga_err = getaddrinfo(full_hostname, NULL, &hints,
460					     &res);
461			if (ga_err == 0) {
462				char hostbuf[MAXHOSTNAMELEN];
463
464				getnameinfo(res->ai_addr, res->ai_addrlen,
465				    hostbuf, sizeof(hostbuf), NULL, 0,
466				    NI_NUMERICHOST|NI_WITHSCOPEID);
467				if ((optarg = strdup(hostbuf)) == NULL) {
468					syslog(LOG_NOTICE, "strdup(): %m");
469					sleepexit(1);
470				}
471			} else
472				optarg = NULL;
473			if (res != NULL)
474				freeaddrinfo(res);
475			if (!auth_hostok(lc, full_hostname, optarg))
476				refused("Permission denied", "HOST", 1);
477		}
478
479		if (!auth_ttyok(lc, tty))
480			refused("Permission denied", "TTY", 1);
481
482		if (!auth_timeok(lc, time(NULL)))
483			refused("Logins not available right now", "TIME", 1);
484	}
485        shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
486	if (*pwd->pw_shell == '\0')
487		pwd->pw_shell = strdup(_PATH_BSHELL);
488	if (pwd->pw_shell == NULL) {
489		syslog(LOG_NOTICE, "strdup(): %m");
490		sleepexit(1);
491	}
492	if (*shell == '\0')   /* Not overridden */
493		shell = pwd->pw_shell;
494	if ((shell = strdup(shell)) == NULL) {
495		syslog(LOG_NOTICE, "strdup(): %m");
496		sleepexit(1);
497	}
498
499#ifdef LOGIN_ACCESS
500	if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
501		refused("Permission denied", "ACCESS", 1);
502#endif /* LOGIN_ACCESS */
503
504	/* Nothing else left to fail -- really log in. */
505	memset((void *)&utmp, 0, sizeof(utmp));
506	(void)time(&utmp.ut_time);
507	(void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
508	if (hostname)
509		(void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
510	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
511	login(&utmp);
512
513	dolastlog(quietlog);
514
515	/*
516	 * Set device protections, depending on what terminal the
517	 * user is logged in. This feature is used on Suns to give
518	 * console users better privacy.
519	 */
520	login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
521
522	/*
523	 * Clear flags of the tty.  None should be set, and when the
524	 * user sets them otherwise, this can cause the chown to fail.
525	 * Since it isn't clear that flags are useful on character
526	 * devices, we just clear them.
527	 */
528	if (chflags(ttyn, 0) && errno != EOPNOTSUPP)
529		syslog(LOG_ERR, "chmod(%s): %m", ttyn);
530	if (chown(ttyn, pwd->pw_uid,
531	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
532		syslog(LOG_ERR, "chmod(%s): %m", ttyn);
533
534
535	/*
536	 * Preserve TERM if it happens to be already set.
537	 */
538	if ((term = getenv("TERM")) != NULL) {
539		if ((term = strdup(term)) == NULL) {
540			syslog(LOG_NOTICE,
541			    "strdup(): %m");
542			sleepexit(1);
543		}
544	}
545
546	/*
547	 * Exclude cons/vt/ptys only, assume dialup otherwise
548	 * TODO: Make dialup tty determination a library call
549	 * for consistency (finger etc.)
550	 */
551	if (hostname==NULL && isdialuptty(tty))
552		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
553
554#ifdef LOGALL
555	/*
556	 * Syslog each successful login, so we don't have to watch hundreds
557	 * of wtmp or lastlogin files.
558	 */
559	if (hostname)
560		syslog(LOG_INFO, "login from %s on %s as %s",
561		       full_hostname, tty, pwd->pw_name);
562	else
563		syslog(LOG_INFO, "login on %s as %s",
564		       tty, pwd->pw_name);
565#endif
566
567	/*
568	 * If fflag is on, assume caller/authenticator has logged root login.
569	 */
570	if (rootlogin && fflag == 0)
571	{
572		if (hostname)
573			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
574			    username, tty, full_hostname);
575		else
576			syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
577			    username, tty);
578	}
579
580	/*
581	 * Destroy environment unless user has requested its preservation.
582	 * We need to do this before setusercontext() because that may
583	 * set or reset some environment variables.
584	 */
585	if (!pflag)
586		environ = envinit;
587
588	/*
589	 * PAM modules might add supplementary groups during pam_setcred().
590	 */
591	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
592                syslog(LOG_ERR, "setusercontext() failed - exiting");
593		exit(1);
594	}
595
596#ifndef NO_PAM
597	if (pamh) {
598		if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
599			syslog(LOG_ERR, "pam_open_session: %s",
600			    pam_strerror(pamh, e));
601		} else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
602		    != PAM_SUCCESS) {
603			syslog(LOG_ERR, "pam_setcred: %s",
604			    pam_strerror(pamh, e));
605		}
606
607	        /*
608	         * Add any environmental variables that the
609	         * PAM modules may have set.
610		 * Call *after* opening session!
611		 */
612		if (pamh) {
613		  environ_pam = pam_getenvlist(pamh);
614		  if (environ_pam)
615			export_pam_environment();
616		}
617
618		/*
619		 * We must fork() before setuid() because we need to call
620		 * pam_close_session() as root.
621		 */
622		pid = fork();
623		if (pid < 0) {
624			err(1, "fork");
625			PAM_END;
626			exit(0);
627		} else if (pid) {
628			/* parent - wait for child to finish, then cleanup
629			   session */
630			wait(NULL);
631			PAM_END;
632			exit(0);
633		} else {
634			if ((e = pam_end(pamh, PAM_DATA_SILENT)) != PAM_SUCCESS)
635				syslog(LOG_ERR, "pam_end: %s",
636				    pam_strerror(pamh, e));
637		}
638	}
639#endif /* NO_PAM */
640
641	/*
642	 * We don't need to be root anymore, so
643	 * set the user and session context
644	 */
645	if (setlogin(username) != 0) {
646                syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
647		exit(1);
648	}
649	if (setusercontext(lc, pwd, pwd->pw_uid,
650	    LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
651                syslog(LOG_ERR, "setusercontext() failed - exiting");
652		exit(1);
653	}
654
655	(void)setenv("SHELL", pwd->pw_shell, 1);
656	(void)setenv("HOME", pwd->pw_dir, 1);
657	if (term != NULL && *term != '\0')
658		(void)setenv("TERM", term, 1);		/* Preset overrides */
659	else {
660		(void)setenv("TERM", stypeof(tty), 0);	/* Fallback doesn't */
661	}
662	(void)setenv("LOGNAME", username, 1);
663	(void)setenv("USER", username, 1);
664	(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
665
666	if (!quietlog) {
667		const char *cw;
668
669		cw = login_getcapstr(lc, "copyright", NULL, NULL);
670		if (cw != NULL && access(cw, F_OK) == 0)
671			motd(cw);
672		else
673		    (void)printf("%s\n\t%s %s\n",
674	"Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
675	"The Regents of the University of California. ",
676	"All rights reserved.");
677
678		(void)printf("\n");
679
680		cw = login_getcapstr(lc, "welcome", NULL, NULL);
681		if (cw == NULL || access(cw, F_OK) != 0)
682			cw = _PATH_MOTDFILE;
683		motd(cw);
684
685		if (login_getcapbool(lc, "nocheckmail", 0) == 0) {
686			/* $MAIL may have been set by class. */
687			cw = getenv("MAIL");
688			if (cw != NULL)
689				strlcpy(tbuf, cw, sizeof(tbuf));
690			else
691				snprintf(tbuf, sizeof(tbuf), "%s/%s",
692				    _PATH_MAILDIR, pwd->pw_name);
693			if (stat(tbuf, &st) == 0 && st.st_size != 0)
694				(void)printf("You have %smail.\n",
695				    (st.st_mtime > st.st_atime) ? "new " : "");
696		}
697	}
698
699	login_close(lc);
700
701	(void)signal(SIGALRM, SIG_DFL);
702	(void)signal(SIGQUIT, SIG_DFL);
703	(void)signal(SIGINT, SIG_DFL);
704	(void)signal(SIGTSTP, SIG_IGN);
705
706	/*
707	 * Login shells have a leading '-' in front of argv[0]
708	 */
709	if ((u_int)snprintf(tbuf, sizeof(tbuf), "-%s",
710	    (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >=
711	    sizeof(tbuf)) {
712		syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
713		    username);
714		errx(1, "shell exceeds maximum pathname size");
715	}
716
717	execlp(shell, tbuf, (char *)0);
718	err(1, "%s", shell);
719}
720
721static int
722auth_traditional()
723{
724	int rval;
725	char *p;
726	const char *ep;
727	const char *salt;
728
729	rval = 1;
730	salt = pwd != NULL ? pwd->pw_passwd : "xx";
731
732	p = getpass(passwd_prompt);
733	ep = crypt(p, salt);
734
735	if (pwd) {
736		if (!p[0] && pwd->pw_passwd[0])
737			ep = ":";
738		if (strcmp(ep, pwd->pw_passwd) == 0)
739			rval = 0;
740	}
741
742	/* clear entered password */
743	memset(p, 0, strlen(p));
744	return rval;
745}
746
747#ifndef NO_PAM
748/*
749 * Attempt to authenticate the user using PAM.  Returns 0 if the user is
750 * authenticated, or 1 if not authenticated.  If some sort of PAM system
751 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
752 * function returns -1.  This can be used as an indication that we should
753 * fall back to a different authentication mechanism.
754 */
755static int
756auth_pam()
757{
758	const char *tmpl_user;
759	const void *item;
760	int rval;
761	int e;
762	static struct pam_conv conv = { misc_conv, NULL };
763
764	if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) {
765		syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
766		return -1;
767	}
768	if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) {
769		syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s",
770		    pam_strerror(pamh, e));
771		return -1;
772	}
773	if (hostname == NULL)
774		gethostname(full_hostname, sizeof full_hostname);
775	if ((e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) {
776		syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
777		    pam_strerror(pamh, e));
778		return -1;
779	}
780	e = pam_authenticate(pamh, 0);
781	switch (e) {
782
783	case PAM_SUCCESS:
784		/*
785		 * With PAM we support the concept of a "template"
786		 * user.  The user enters a login name which is
787		 * authenticated by PAM, usually via a remote service
788		 * such as RADIUS or TACACS+.  If authentication
789		 * succeeds, a different but related "template" name
790		 * is used for setting the credentials, shell, and
791		 * home directory.  The name the user enters need only
792		 * exist on the remote authentication server, but the
793		 * template name must be present in the local password
794		 * database.
795		 *
796		 * This is supported by two various mechanisms in the
797		 * individual modules.  However, from the application's
798		 * point of view, the template user is always passed
799		 * back as a changed value of the PAM_USER item.
800		 */
801		if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
802		    PAM_SUCCESS) {
803			tmpl_user = (const char *) item;
804			if (strcmp(username, tmpl_user) != 0)
805				pwd = getpwnam(tmpl_user);
806		} else
807			syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
808			    pam_strerror(pamh, e));
809		rval = 0;
810		break;
811
812	case PAM_AUTH_ERR:
813	case PAM_USER_UNKNOWN:
814	case PAM_MAXTRIES:
815		rval = 1;
816		break;
817
818	default:
819		syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
820		rval = -1;
821		break;
822	}
823
824	if (rval == 0) {
825		e = pam_acct_mgmt(pamh, 0);
826		if (e == PAM_NEW_AUTHTOK_REQD) {
827			e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
828			if (e != PAM_SUCCESS) {
829				syslog(LOG_ERR, "pam_chauthtok: %s",
830				    pam_strerror(pamh, e));
831				rval = 1;
832			}
833		} else if (e != PAM_SUCCESS) {
834			rval = 1;
835		}
836	}
837
838	if (rval != 0) {
839		if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
840			syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
841		}
842		pamh = NULL;
843	}
844	return rval;
845}
846
847static int
848export_pam_environment()
849{
850	char	**pp;
851
852	for (pp = environ_pam; *pp != NULL; pp++) {
853		if (ok_to_export(*pp))
854			(void) putenv(*pp);
855		free(*pp);
856	}
857	return PAM_SUCCESS;
858}
859
860/*
861 * Sanity checks on PAM environmental variables:
862 * - Make sure there is an '=' in the string.
863 * - Make sure the string doesn't run on too long.
864 * - Do not export certain variables.  This list was taken from the
865 *   Solaris pam_putenv(3) man page.
866 */
867static int
868ok_to_export(s)
869	const char *s;
870{
871	static const char *noexport[] = {
872		"SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
873		"IFS", "PATH", NULL
874	};
875	const char **pp;
876	size_t n;
877
878	if (strlen(s) > 1024 || strchr(s, '=') == NULL)
879		return 0;
880	if (strncmp(s, "LD_", 3) == 0)
881		return 0;
882	for (pp = noexport; *pp != NULL; pp++) {
883		n = strlen(*pp);
884		if (s[n] == '=' && strncmp(s, *pp, n) == 0)
885			return 0;
886	}
887	return 1;
888}
889#endif /* NO_PAM */
890
891static void
892usage()
893{
894
895	(void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
896	exit(1);
897}
898
899/*
900 * Allow for authentication style and/or kerberos instance
901 */
902
903void
904getloginname()
905{
906	int ch;
907	char *p;
908	static char nbuf[NBUFSIZ];
909
910	for (;;) {
911		(void)printf("%s", prompt);
912		for (p = nbuf; (ch = getchar()) != '\n'; ) {
913			if (ch == EOF) {
914				badlogin(username);
915				exit(0);
916			}
917			if (p < nbuf + (NBUFSIZ - 1))
918				*p++ = ch;
919		}
920		if (p > nbuf) {
921			if (nbuf[0] == '-')
922				(void)fprintf(stderr,
923				    "login names may not start with '-'.\n");
924			else {
925				*p = '\0';
926				username = nbuf;
927				break;
928			}
929		}
930	}
931}
932
933int
934rootterm(ttyn)
935	char *ttyn;
936{
937	struct ttyent *t;
938
939	return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
940}
941
942volatile int motdinterrupt;
943
944void
945sigint(signo)
946	int signo __unused;
947{
948	motdinterrupt = 1;
949}
950
951void
952motd(motdfile)
953	const char *motdfile;
954{
955	int fd, nchars;
956	sig_t oldint;
957	char tbuf[256];
958
959	if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
960		return;
961	motdinterrupt = 0;
962	oldint = signal(SIGINT, sigint);
963	while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
964		(void)write(fileno(stdout), tbuf, nchars);
965	(void)signal(SIGINT, oldint);
966	(void)close(fd);
967}
968
969/* ARGSUSED */
970void
971timedout(signo)
972	int signo;
973{
974
975	longjmp(timeout_buf, signo);
976}
977
978
979void
980dolastlog(quiet)
981	int quiet;
982{
983	struct lastlog ll;
984	int fd;
985
986	if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
987		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
988		if (!quiet) {
989			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
990			    ll.ll_time != 0) {
991				(void)printf("Last login: %.*s ",
992				    24-5, (char *)ctime(&ll.ll_time));
993				if (*ll.ll_host != '\0')
994					(void)printf("from %.*s\n",
995					    (int)sizeof(ll.ll_host),
996					    ll.ll_host);
997				else
998					(void)printf("on %.*s\n",
999					    (int)sizeof(ll.ll_line),
1000					    ll.ll_line);
1001			}
1002			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
1003		}
1004		memset((void *)&ll, 0, sizeof(ll));
1005		(void)time(&ll.ll_time);
1006		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1007		if (hostname)
1008			(void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1009		(void)write(fd, (char *)&ll, sizeof(ll));
1010		(void)close(fd);
1011	} else {
1012		syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG);
1013	}
1014}
1015
1016void
1017badlogin(name)
1018	char *name;
1019{
1020
1021	if (failures == 0)
1022		return;
1023	if (hostname) {
1024		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
1025		    failures, failures > 1 ? "S" : "", full_hostname);
1026		syslog(LOG_AUTHPRIV|LOG_NOTICE,
1027		    "%d LOGIN FAILURE%s FROM %s, %s",
1028		    failures, failures > 1 ? "S" : "", full_hostname, name);
1029	} else {
1030		syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
1031		    failures, failures > 1 ? "S" : "", tty);
1032		syslog(LOG_AUTHPRIV|LOG_NOTICE,
1033		    "%d LOGIN FAILURE%s ON %s, %s",
1034		    failures, failures > 1 ? "S" : "", tty, name);
1035	}
1036	failures = 0;
1037}
1038
1039const char *
1040stypeof(ttyid)
1041	char *ttyid;
1042{
1043	struct ttyent *t;
1044
1045	if (ttyid != NULL && *ttyid != '\0') {
1046		t = getttynam(ttyid);
1047		if (t != NULL && t->ty_type != NULL)
1048			return (t->ty_type);
1049	}
1050	return (UNKNOWN);
1051}
1052
1053void
1054refused(msg, rtype, lout)
1055	const char *msg;
1056	const char *rtype;
1057	int lout;
1058{
1059
1060	if (msg != NULL)
1061	    printf("%s.\n", msg);
1062	if (hostname)
1063		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1064		    pwd->pw_name, rtype, full_hostname, tty);
1065	else
1066		syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
1067		    pwd->pw_name, rtype, tty);
1068	if (lout)
1069		sleepexit(1);
1070}
1071
1072void
1073sleepexit(eval)
1074	int eval;
1075{
1076
1077	(void)sleep(5);
1078	exit(eval);
1079}
1080