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