xref: /illumos-gate/usr/src/cmd/login/login.c (revision cbea7aca3fd7787405cbdbd93752998f03dfc25f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57d080b24Sas145665  * Common Development and Distribution License (the "License").
67d080b24Sas145665  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21aecfc01dSrui zang - Sun Microsystems - Beijing China 
227c478bd9Sstevel@tonic-gate /*
23de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*cbea7acaSDominik Hassler  *
26*cbea7acaSDominik Hassler  * Copyright 2023 OmniOS Community Edition (OmniOSce) Association.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
307c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
347c478bd9Sstevel@tonic-gate  * The Regents of the University of California
357c478bd9Sstevel@tonic-gate  * All Rights Reserved
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
387c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
397c478bd9Sstevel@tonic-gate  * contributors.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
437c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * For a complete reference to login(1), see the manual page.  However,
477c478bd9Sstevel@tonic-gate  * login has accreted some intentionally undocumented options, which are
487c478bd9Sstevel@tonic-gate  * explained here:
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * -a: This legacy flag appears to be unused.
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  * -f <username>: This flag was introduced by PSARC 1995/039 in support
537c478bd9Sstevel@tonic-gate  *    of Kerberos.  But it's not used by Sun's Kerberos implementation.
547c478bd9Sstevel@tonic-gate  *    It is however employed by zlogin(1), since it allows one to tell
557c478bd9Sstevel@tonic-gate  *    login: "This user is authenticated."  In the case of zlogin that's
567c478bd9Sstevel@tonic-gate  *    true because the zone always trusts the global zone.
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * -z <zonename>: This flag is passed to login when zlogin(1) executes a
597c478bd9Sstevel@tonic-gate  *    zone login.  This tells login(1) to skip it's normal CONSOLE check
607c478bd9Sstevel@tonic-gate  *    (i.e. that the root login must be on /dev/console) and tells us the
61da6c28aaSamw  *    name of the zone from which the login is occurring.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <sys/types.h>
657c478bd9Sstevel@tonic-gate #include <sys/param.h>
667c478bd9Sstevel@tonic-gate #include <unistd.h>	/* For logfile locking */
677c478bd9Sstevel@tonic-gate #include <signal.h>
687c478bd9Sstevel@tonic-gate #include <stdio.h>
697c478bd9Sstevel@tonic-gate #include <sys/stat.h>
707c478bd9Sstevel@tonic-gate #include <string.h>
717c478bd9Sstevel@tonic-gate #include <deflt.h>
727c478bd9Sstevel@tonic-gate #include <grp.h>
737c478bd9Sstevel@tonic-gate #include <fcntl.h>
742de0a7d6SDan McDonald #include <lastlog.h>
757c478bd9Sstevel@tonic-gate #include <termio.h>
767c478bd9Sstevel@tonic-gate #include <utmpx.h>
777c478bd9Sstevel@tonic-gate #include <stdlib.h>
787c478bd9Sstevel@tonic-gate #include <wait.h>
797c478bd9Sstevel@tonic-gate #include <errno.h>
807c478bd9Sstevel@tonic-gate #include <ctype.h>
817c478bd9Sstevel@tonic-gate #include <syslog.h>
827c478bd9Sstevel@tonic-gate #include <ulimit.h>
837c478bd9Sstevel@tonic-gate #include <libgen.h>
847c478bd9Sstevel@tonic-gate #include <pwd.h>
857c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
867c478bd9Sstevel@tonic-gate #include <strings.h>
877c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
887c478bd9Sstevel@tonic-gate #include <zone.h>
897c478bd9Sstevel@tonic-gate #include "login_audit.h"
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #include <krb5_repository.h>
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  *	    *** Defines, Macros, and String Constants  ***
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  *
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate #define	ISSUEFILE "/etc/issue"	/* file to print before prompt */
1007c478bd9Sstevel@tonic-gate #define	NOLOGIN	"/etc/nologin"	/* file to lock users out during shutdown */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * These need to be defined for UTMPX management.
1047c478bd9Sstevel@tonic-gate  * If we add in the utility functions later, we
1057c478bd9Sstevel@tonic-gate  * can remove them.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate #define	__UPDATE_ENTRY	1
1087c478bd9Sstevel@tonic-gate #define	__LOGIN		2
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * Intervals to sleep after failed login
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate #ifndef	SLEEPTIME
1147c478bd9Sstevel@tonic-gate #define	SLEEPTIME 4	/* sleeptime before login incorrect msg */
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate static int	Sleeptime = SLEEPTIME;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * seconds login disabled after allowable number of unsuccessful attempts
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate #ifndef	DISABLETIME
1227c478bd9Sstevel@tonic-gate #define	DISABLETIME	20
1237c478bd9Sstevel@tonic-gate #endif
1247c478bd9Sstevel@tonic-gate static int	Disabletime = DISABLETIME;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #define	MAXTRYS		5
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static int	retry = MAXTRYS;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /*
1317c478bd9Sstevel@tonic-gate  * Login logging support
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate #define	LOGINLOG	"/var/adm/loginlog"	/* login log file */
1347c478bd9Sstevel@tonic-gate #define	LNAME_SIZE	20	/* size of logged logname */
1357c478bd9Sstevel@tonic-gate #define	TTYN_SIZE	15	/* size of logged tty name */
1367c478bd9Sstevel@tonic-gate #define	TIME_SIZE	30	/* size of logged time string */
1377c478bd9Sstevel@tonic-gate #define	ENT_SIZE	(LNAME_SIZE + TTYN_SIZE + TIME_SIZE + 3)
1387c478bd9Sstevel@tonic-gate #define	L_WAITTIME	5	/* waittime for log file to unlock */
1397c478bd9Sstevel@tonic-gate #define	LOGTRYS		10	/* depth of 'try' logging */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * String manipulation macros: SCPYN, SCPYL, EQN and ENVSTRNCAT
1437c478bd9Sstevel@tonic-gate  * SCPYL is the safer version of SCPYN
1447c478bd9Sstevel@tonic-gate  */
1457c478bd9Sstevel@tonic-gate #define	SCPYL(a, b)	(void) strlcpy(a, b, sizeof (a))
1467c478bd9Sstevel@tonic-gate #define	SCPYN(a, b)	(void) strncpy(a, b, sizeof (a))
1477c478bd9Sstevel@tonic-gate #define	EQN(a, b)	(strncmp(a, b, sizeof (a)-1) == 0)
1487c478bd9Sstevel@tonic-gate #define	ENVSTRNCAT(to, from) {int deflen; deflen = strlen(to); \
1497c478bd9Sstevel@tonic-gate 	(void) strncpy((to)+ deflen, (from), sizeof (to) - (1 + deflen)); }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Other macros
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate #define	NMAX	sizeof (((struct utmpx *)0)->ut_name)
1557c478bd9Sstevel@tonic-gate #define	HMAX	sizeof (((struct utmpx *)0)->ut_host)
1567c478bd9Sstevel@tonic-gate #define	min(a, b)	(((a) < (b)) ? (a) : (b))
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Various useful files and string constants
1607c478bd9Sstevel@tonic-gate  */
1617c478bd9Sstevel@tonic-gate #define	SHELL		"/usr/bin/sh"
1627c478bd9Sstevel@tonic-gate #define	SHELL2		"/sbin/sh"
1637c478bd9Sstevel@tonic-gate #define	SUBLOGIN	"<!sublogin>"
1642de0a7d6SDan McDonald #define	LASTLOG		"/var/adm/lastlog"
1657c478bd9Sstevel@tonic-gate #define	PROG_NAME	"login"
1667c478bd9Sstevel@tonic-gate #define	HUSHLOGIN	".hushlogin"
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * Array and Buffer sizes
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate #define	PBUFSIZE 8	/* max significant characters in a password */
1727c478bd9Sstevel@tonic-gate #define	MAXARGS 63	/* change value below if changing this */
1737c478bd9Sstevel@tonic-gate #define	MAXARGSWIDTH 2	/* log10(MAXARGS) */
1747c478bd9Sstevel@tonic-gate #define	MAXENV 1024
1757c478bd9Sstevel@tonic-gate #define	MAXLINE 2048
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * Miscellaneous constants
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate #define	ROOTUID		0
1817c478bd9Sstevel@tonic-gate #define	ERROR		1
1827c478bd9Sstevel@tonic-gate #define	OK		0
1837c478bd9Sstevel@tonic-gate #define	LOG_ERROR	1
1847c478bd9Sstevel@tonic-gate #define	DONT_LOG_ERROR	0
1857c478bd9Sstevel@tonic-gate #define	TRUE		1
1867c478bd9Sstevel@tonic-gate #define	FALSE		0
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * Counters for counting the number of failed login attempts
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate static int trys = 0;
1927c478bd9Sstevel@tonic-gate static int count = 1;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * error value for login_exit() audit output (0 == no audit record)
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate static int	audit_error = 0;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * Externs a plenty
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate extern	int	getsecretkey();
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * The current user name
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate static	char	user_name[NMAX];
2087c478bd9Sstevel@tonic-gate static	char	minusnam[16] = "-";
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
211f0243e0aSrz201010  * login_pid, used to find utmpx entry to update.
212f0243e0aSrz201010  */
213f0243e0aSrz201010 static pid_t	login_pid;
214f0243e0aSrz201010 
215f0243e0aSrz201010 /*
2167c478bd9Sstevel@tonic-gate  * locale environments to be passed to shells.
2177c478bd9Sstevel@tonic-gate  */
2187c478bd9Sstevel@tonic-gate static char *localeenv[] = {
2197c478bd9Sstevel@tonic-gate 	"LANG",
2207c478bd9Sstevel@tonic-gate 	"LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE",
2217c478bd9Sstevel@tonic-gate 	"LC_MONETARY", "LC_MESSAGES", "LC_ALL", 0};
2227c478bd9Sstevel@tonic-gate static int locale_envmatch(char *, char *);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
2257c478bd9Sstevel@tonic-gate  * Environment variable support
2267c478bd9Sstevel@tonic-gate  */
2277c478bd9Sstevel@tonic-gate static	char	shell[256] = { "SHELL=" };
2287c478bd9Sstevel@tonic-gate static	char	home[MAXPATHLEN] = { "HOME=" };
2297c478bd9Sstevel@tonic-gate static	char	term[64] = { "TERM=" };
2307c478bd9Sstevel@tonic-gate static	char	logname[30] = { "LOGNAME=" };
2317c478bd9Sstevel@tonic-gate static	char	timez[100] = { "TZ=" };
2327c478bd9Sstevel@tonic-gate static	char	hertz[10] = { "HZ=" };
2337c478bd9Sstevel@tonic-gate static	char	path[MAXPATHLEN] = { "PATH=" };
2347c478bd9Sstevel@tonic-gate static	char	*newenv[10+MAXARGS] =
2357c478bd9Sstevel@tonic-gate 	{home, path, logname, hertz, term, 0, 0};
2367c478bd9Sstevel@tonic-gate static	char	**envinit = newenv;
2377c478bd9Sstevel@tonic-gate static	int	basicenv;
2387c478bd9Sstevel@tonic-gate static	char	*zero = (char *)0;
2397c478bd9Sstevel@tonic-gate static	char	**envp;
2407c478bd9Sstevel@tonic-gate #ifndef	NO_MAIL
2417c478bd9Sstevel@tonic-gate static	char	mail[30] = { "MAIL=/var/mail/" };
2427c478bd9Sstevel@tonic-gate #endif
2437c478bd9Sstevel@tonic-gate extern char **environ;
2447c478bd9Sstevel@tonic-gate static	char inputline[MAXLINE];
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate #define	MAX_ID_LEN 256
2477c478bd9Sstevel@tonic-gate #define	MAX_REPOSITORY_LEN 256
2487c478bd9Sstevel@tonic-gate #define	MAX_PAMSERVICE_LEN 256
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static char identity[MAX_ID_LEN];
2517c478bd9Sstevel@tonic-gate static char repository[MAX_REPOSITORY_LEN];
2527c478bd9Sstevel@tonic-gate static char progname[MAX_PAMSERVICE_LEN];
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*
2567c478bd9Sstevel@tonic-gate  * Strings used to prompt the user.
2577c478bd9Sstevel@tonic-gate  */
2587c478bd9Sstevel@tonic-gate static	char	loginmsg[] = "login: ";
2597c478bd9Sstevel@tonic-gate static	char	passwdmsg[] = "Password:";
2607c478bd9Sstevel@tonic-gate static	char	incorrectmsg[] = "Login incorrect\n";
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * Password file support
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate static	struct	passwd *pwd = NULL;
2667c478bd9Sstevel@tonic-gate static	char	remote_host[HMAX];
2677c478bd9Sstevel@tonic-gate static	char	zone_name[ZONENAME_MAX];
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate /*
2707c478bd9Sstevel@tonic-gate  * Illegal passwd entries.
2717c478bd9Sstevel@tonic-gate  */
272f48205beScasper static	struct	passwd nouser = { "", "no:password", (uid_t)-1 };
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * Log file support
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate static	char	*log_entry[LOGTRYS];
2787c478bd9Sstevel@tonic-gate static	int	writelog = 0;
2792de0a7d6SDan McDonald static	int	lastlogok = 0;
2802de0a7d6SDan McDonald static	struct lastlog ll;
2817c478bd9Sstevel@tonic-gate static	int	dosyslog = 0;
2827c478bd9Sstevel@tonic-gate static	int	flogin = MAXTRYS;	/* flag for SYSLOG_FAILED_LOGINS */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate  * Default file toggles
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate static	char	*Pndefault	= "/etc/default/login";
2887c478bd9Sstevel@tonic-gate static	char	*Altshell	= NULL;
2897c478bd9Sstevel@tonic-gate static	char	*Console	= NULL;
2907c478bd9Sstevel@tonic-gate static	int	Passreqflag	= 0;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate #define	DEFUMASK	022
2937c478bd9Sstevel@tonic-gate static	mode_t	Umask		= DEFUMASK;
2947c478bd9Sstevel@tonic-gate static	char	*Def_tz		= NULL;
2957c478bd9Sstevel@tonic-gate static	char	*tmp_tz		= NULL;
2967c478bd9Sstevel@tonic-gate static	char	*Def_hertz	= NULL;
2977c478bd9Sstevel@tonic-gate #define	SET_FSIZ	2			/* ulimit() command arg */
2987c478bd9Sstevel@tonic-gate static	long	Def_ulimit	= 0;
2997c478bd9Sstevel@tonic-gate #define	MAX_TIMEOUT	(15 * 60)
3007c478bd9Sstevel@tonic-gate #define	DEF_TIMEOUT	(5 * 60)
3017c478bd9Sstevel@tonic-gate static	unsigned Def_timeout	= DEF_TIMEOUT;
3027c478bd9Sstevel@tonic-gate static	char	*Def_path	= NULL;
3037c478bd9Sstevel@tonic-gate static	char	*Def_supath	= NULL;
3047c478bd9Sstevel@tonic-gate #define	DEF_PATH	"/usr/bin:"	/* same as PATH */
3057c478bd9Sstevel@tonic-gate #define	DEF_SUPATH	"/usr/sbin:/usr/bin" /* same as ROOTPATH */
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate  * Defaults for updating expired passwords
3097c478bd9Sstevel@tonic-gate  */
3107c478bd9Sstevel@tonic-gate #define	DEF_ATTEMPTS	3
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /*
3137c478bd9Sstevel@tonic-gate  * ttyprompt will point to the environment variable TTYPROMPT.
3147c478bd9Sstevel@tonic-gate  * TTYPROMPT is set by ttymon if ttymon already wrote out the prompt.
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate static	char	*ttyprompt = NULL;
3177c478bd9Sstevel@tonic-gate static	char	*ttyn = NULL;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * Pass inherited environment.  Used by telnetd in support of the telnet
3217c478bd9Sstevel@tonic-gate  * ENVIRON option.
3227c478bd9Sstevel@tonic-gate  */
3237c478bd9Sstevel@tonic-gate static	boolean_t pflag = B_FALSE;
3247c478bd9Sstevel@tonic-gate static  boolean_t uflag = B_FALSE;
3257c478bd9Sstevel@tonic-gate static  boolean_t Rflag = B_FALSE;
3267c478bd9Sstevel@tonic-gate static  boolean_t sflag = B_FALSE;
3277c478bd9Sstevel@tonic-gate static  boolean_t Uflag = B_FALSE;
3287c478bd9Sstevel@tonic-gate static  boolean_t tflag = B_FALSE;
3297c478bd9Sstevel@tonic-gate static	boolean_t hflag = B_FALSE;
3307c478bd9Sstevel@tonic-gate static  boolean_t rflag = B_FALSE;
3317c478bd9Sstevel@tonic-gate static  boolean_t zflag = B_FALSE;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate /*
3347c478bd9Sstevel@tonic-gate  * Remote login support
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate static	char	rusername[NMAX+1], lusername[NMAX+1];
3377c478bd9Sstevel@tonic-gate static	char	terminal[MAXPATHLEN];
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * Pre-authentication flag support
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static	int	fflag;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate static char ** getargs(char *);
3457c478bd9Sstevel@tonic-gate 
346*cbea7acaSDominik Hassler static int login_conv(int, const struct pam_message **,
3477c478bd9Sstevel@tonic-gate     struct pam_response **, void *);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate static struct pam_conv pam_conv = {login_conv, NULL};
3507c478bd9Sstevel@tonic-gate static pam_handle_t *pamh;	/* Authentication handle */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * Function declarations
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate static	void	turn_on_logging(void);
3567c478bd9Sstevel@tonic-gate static	void	defaults(void);
3577c478bd9Sstevel@tonic-gate static	void	usage(void);
3587c478bd9Sstevel@tonic-gate static	void	process_rlogin(void);
3597c478bd9Sstevel@tonic-gate static	void	login_authenticate();
3607c478bd9Sstevel@tonic-gate static	void	setup_credentials(void);
3617c478bd9Sstevel@tonic-gate static	void	adjust_nice(void);
3622de0a7d6SDan McDonald static	void	update_utmpx_entry(int);
3637c478bd9Sstevel@tonic-gate static	void	establish_user_environment(char **);
3642de0a7d6SDan McDonald static	void	print_banner(void);
3652de0a7d6SDan McDonald static	void	display_last_login_time(void);
3667c478bd9Sstevel@tonic-gate static	void	exec_the_shell(void);
3677c478bd9Sstevel@tonic-gate static	int	process_chroot_logins(void);
3687c478bd9Sstevel@tonic-gate static	void	chdir_to_dir_user(void);
3692de0a7d6SDan McDonald static	void	check_log(void);
3707c478bd9Sstevel@tonic-gate static	void	validate_account(void);
3717c478bd9Sstevel@tonic-gate static	void	doremoteterm(char *);
3727c478bd9Sstevel@tonic-gate static	int	get_options(int, char **);
3737c478bd9Sstevel@tonic-gate static	void	getstr(char *, int, char *);
3747c478bd9Sstevel@tonic-gate static	int	legalenvvar(char *);
3757c478bd9Sstevel@tonic-gate static	void	check_for_console(void);
3767c478bd9Sstevel@tonic-gate static	void	check_for_dueling_unix(char *);
3777c478bd9Sstevel@tonic-gate static	void	get_user_name(void);
3787c478bd9Sstevel@tonic-gate static	uint_t	get_audit_id(void);
379032624d5Sbasabi static	void	login_exit(int)__NORETURN;
3807c478bd9Sstevel@tonic-gate static	int	logins_disabled(char *);
3817c478bd9Sstevel@tonic-gate static	void	log_bad_attempts(void);
3827c478bd9Sstevel@tonic-gate static	int	is_number(char *);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  *			*** main ***
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  *	The primary flow of control is directed in this routine.
3887c478bd9Sstevel@tonic-gate  *	Control moves in line from top to bottom calling subfunctions
3897c478bd9Sstevel@tonic-gate  *	which perform the bulk of the work.  Many of these calls exit
3907c478bd9Sstevel@tonic-gate  *	when a fatal error is encountered and do not return to main.
3917c478bd9Sstevel@tonic-gate  *
3927c478bd9Sstevel@tonic-gate  *
3937c478bd9Sstevel@tonic-gate  */
3947c478bd9Sstevel@tonic-gate 
395032624d5Sbasabi int
main(int argc,char * argv[],char ** renvp)3967c478bd9Sstevel@tonic-gate main(int argc, char *argv[], char **renvp)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	int sublogin;
3997c478bd9Sstevel@tonic-gate 	int pam_rc;
4007c478bd9Sstevel@tonic-gate 
401f0243e0aSrz201010 	login_pid = getpid();
402f0243e0aSrz201010 
4037c478bd9Sstevel@tonic-gate 	/*
4047c478bd9Sstevel@tonic-gate 	 * Set up Defaults and flags
4057c478bd9Sstevel@tonic-gate 	 */
4067c478bd9Sstevel@tonic-gate 	defaults();
4077c478bd9Sstevel@tonic-gate 	SCPYL(progname, PROG_NAME);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * Set up default umask
4117c478bd9Sstevel@tonic-gate 	 */
4127c478bd9Sstevel@tonic-gate 	if (Umask > ((mode_t)0777))
4137c478bd9Sstevel@tonic-gate 		Umask = DEFUMASK;
4147c478bd9Sstevel@tonic-gate 	(void) umask(Umask);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * Set up default timeouts and delays
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	if (Def_timeout > MAX_TIMEOUT)
4207c478bd9Sstevel@tonic-gate 		Def_timeout = MAX_TIMEOUT;
4217c478bd9Sstevel@tonic-gate 	if (Sleeptime < 0 || Sleeptime > 5)
4227c478bd9Sstevel@tonic-gate 		Sleeptime = SLEEPTIME;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	(void) alarm(Def_timeout);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * Ignore SIGQUIT and SIGINT and set nice to 0
4287c478bd9Sstevel@tonic-gate 	 */
4297c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_IGN);
4307c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);
4317c478bd9Sstevel@tonic-gate 	(void) nice(0);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/*
4347c478bd9Sstevel@tonic-gate 	 * Set flag to disable the pid check if you find that you are
4357c478bd9Sstevel@tonic-gate 	 * a subsystem login.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	sublogin = 0;
4387c478bd9Sstevel@tonic-gate 	if (*renvp && strcmp(*renvp, SUBLOGIN) == 0)
4397c478bd9Sstevel@tonic-gate 		sublogin = 1;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	/*
4427c478bd9Sstevel@tonic-gate 	 * Parse Arguments
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	if (get_options(argc, argv) == -1) {
4457c478bd9Sstevel@tonic-gate 		usage();
4467c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_VALUE_BAD_CMD;
4477c478bd9Sstevel@tonic-gate 		login_exit(1);
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * if devicename is not passed as argument, call ttyname(0)
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (ttyn == NULL) {
4547c478bd9Sstevel@tonic-gate 		ttyn = ttyname(0);
4557c478bd9Sstevel@tonic-gate 		if (ttyn == NULL)
4567c478bd9Sstevel@tonic-gate 			ttyn = "/dev/???";
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * Call pam_start to initiate a PAM authentication operation
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if ((pam_rc = pam_start(progname, user_name, &pam_conv, &pamh))
4647c478bd9Sstevel@tonic-gate 	    != PAM_SUCCESS) {
4657c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + pam_rc;
4667c478bd9Sstevel@tonic-gate 		login_exit(1);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	if ((pam_rc = pam_set_item(pamh, PAM_TTY, ttyn)) != PAM_SUCCESS) {
4697c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + pam_rc;
4707c478bd9Sstevel@tonic-gate 		login_exit(1);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 	if ((pam_rc = pam_set_item(pamh, PAM_RHOST, remote_host)) !=
4737c478bd9Sstevel@tonic-gate 	    PAM_SUCCESS) {
4747c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + pam_rc;
4757c478bd9Sstevel@tonic-gate 		login_exit(1);
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	/*
4797c478bd9Sstevel@tonic-gate 	 * We currently only support special handling of the KRB5 PAM repository
4807c478bd9Sstevel@tonic-gate 	 */
4817c478bd9Sstevel@tonic-gate 	if ((Rflag && strlen(repository)) &&
4827c478bd9Sstevel@tonic-gate 	    strcmp(repository, KRB5_REPOSITORY_NAME) == 0 &&
4837c478bd9Sstevel@tonic-gate 	    (uflag && strlen(identity))) {
4847c478bd9Sstevel@tonic-gate 		krb5_repository_data_t krb5_data;
4857c478bd9Sstevel@tonic-gate 		pam_repository_t pam_rep_data;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		krb5_data.principal = identity;
4887c478bd9Sstevel@tonic-gate 		krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		pam_rep_data.type = repository;
4917c478bd9Sstevel@tonic-gate 		pam_rep_data.scope = (void *)&krb5_data;
4927c478bd9Sstevel@tonic-gate 		pam_rep_data.scope_len = sizeof (krb5_data);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_REPOSITORY,
4957c478bd9Sstevel@tonic-gate 		    (void *)&pam_rep_data);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	/*
4997c478bd9Sstevel@tonic-gate 	 * Open the log file which contains a record of successful and failed
5007c478bd9Sstevel@tonic-gate 	 * login attempts
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 	turn_on_logging();
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/*
5057c478bd9Sstevel@tonic-gate 	 * say "hi" to syslogd ..
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	openlog("login", 0, LOG_AUTH);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * Do special processing for -r (rlogin) flag
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 	if (rflag)
5137c478bd9Sstevel@tonic-gate 		process_rlogin();
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	/*
5167c478bd9Sstevel@tonic-gate 	 * validate user
5177c478bd9Sstevel@tonic-gate 	 */
5187c478bd9Sstevel@tonic-gate 	/* we are already authenticated. fill in what we must, then continue */
5197c478bd9Sstevel@tonic-gate 	if (fflag) {
5207c478bd9Sstevel@tonic-gate 		if ((pwd = getpwnam(user_name)) == NULL) {
5217c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_VALUE_USERNAME;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			log_bad_attempts();
5247c478bd9Sstevel@tonic-gate 			(void) printf("Login failed: unknown user '%s'.\n",
5257c478bd9Sstevel@tonic-gate 			    user_name);
5267c478bd9Sstevel@tonic-gate 			login_exit(1);
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 	} else {
5297c478bd9Sstevel@tonic-gate 		/*
5307c478bd9Sstevel@tonic-gate 		 * Perform the primary login authentication activity.
5317c478bd9Sstevel@tonic-gate 		 */
5327c478bd9Sstevel@tonic-gate 		login_authenticate();
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	/* change root login, then we exec another login and try again */
5367c478bd9Sstevel@tonic-gate 	if (process_chroot_logins() != OK)
5377c478bd9Sstevel@tonic-gate 		login_exit(1);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	/*
5407c478bd9Sstevel@tonic-gate 	 * If root login and not on system console then call exit(2)
5417c478bd9Sstevel@tonic-gate 	 */
5427c478bd9Sstevel@tonic-gate 	check_for_console();
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * Check to see if a shutdown is in progress, if it is and
5467c478bd9Sstevel@tonic-gate 	 * we are not root then throw the user off the system
5477c478bd9Sstevel@tonic-gate 	 */
5487c478bd9Sstevel@tonic-gate 	if (logins_disabled(user_name) == TRUE) {
5497c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_VALUE_LOGIN_DISABLED;
5507c478bd9Sstevel@tonic-gate 		login_exit(1);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	if (pwd->pw_uid == 0) {
5547c478bd9Sstevel@tonic-gate 		if (Def_supath != NULL)
5557c478bd9Sstevel@tonic-gate 			Def_path = Def_supath;
5567c478bd9Sstevel@tonic-gate 		else
5577c478bd9Sstevel@tonic-gate 			Def_path = DEF_SUPATH;
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/*
5617c478bd9Sstevel@tonic-gate 	 * Check account expiration and passwd aging
5627c478bd9Sstevel@tonic-gate 	 */
5637c478bd9Sstevel@tonic-gate 	validate_account();
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	/*
5667c478bd9Sstevel@tonic-gate 	 * We only get here if we've been authenticated.
5677c478bd9Sstevel@tonic-gate 	 */
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/*
5707c478bd9Sstevel@tonic-gate 	 * Now we set up the environment for the new user, which includes
5717c478bd9Sstevel@tonic-gate 	 * the users ulimit, nice value, ownership of this tty, uid, gid,
5727c478bd9Sstevel@tonic-gate 	 * and environment variables.
5737c478bd9Sstevel@tonic-gate 	 */
5747c478bd9Sstevel@tonic-gate 	if (Def_ulimit > 0L && ulimit(SET_FSIZ, Def_ulimit) < 0L)
5757c478bd9Sstevel@tonic-gate 		(void) printf("Could not set ULIMIT to %ld\n", Def_ulimit);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/* di_devperm_login() sends detailed errors to syslog */
5787c478bd9Sstevel@tonic-gate 	if (di_devperm_login((const char *)ttyn, pwd->pw_uid, pwd->pw_gid,
5797c478bd9Sstevel@tonic-gate 	    NULL) == -1) {
5807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "error processing /etc/logindevperm,"
5817c478bd9Sstevel@tonic-gate 		    " see syslog for more details\n");
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	adjust_nice();		/* passwd file can specify nice value */
5857c478bd9Sstevel@tonic-gate 
586f0243e0aSrz201010 	setup_credentials();	/* Set user credentials  - exits on failure */
587f0243e0aSrz201010 
588f0243e0aSrz201010 	/*
589f0243e0aSrz201010 	 * NOTE: telnetd and rlogind rely upon this updating of utmpx
590f0243e0aSrz201010 	 * to indicate that the authentication completed  successfully,
591f0243e0aSrz201010 	 * pam_open_session was called and therefore they are required to
592f0243e0aSrz201010 	 * call pam_close_session.
593f0243e0aSrz201010 	 */
5942de0a7d6SDan McDonald 	update_utmpx_entry(sublogin);
595f0243e0aSrz201010 
596f0243e0aSrz201010 	/* set the real (and effective) UID */
597f0243e0aSrz201010 	if (setuid(pwd->pw_uid) == -1) {
598f0243e0aSrz201010 		login_exit(1);
599f0243e0aSrz201010 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/*
6027c478bd9Sstevel@tonic-gate 	 * Set up the basic environment for the exec.  This includes
6037c478bd9Sstevel@tonic-gate 	 * HOME, PATH, LOGNAME, SHELL, TERM, TZ, HZ, and MAIL.
6047c478bd9Sstevel@tonic-gate 	 */
6057c478bd9Sstevel@tonic-gate 	chdir_to_dir_user();
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	establish_user_environment(renvp);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	(void) pam_end(pamh, PAM_SUCCESS);	/* Done using PAM */
6107c478bd9Sstevel@tonic-gate 	pamh = NULL;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	if (pwd->pw_uid == 0) {
6137c478bd9Sstevel@tonic-gate 		if (dosyslog) {
6147c478bd9Sstevel@tonic-gate 			if (remote_host[0]) {
6157c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
6167c478bd9Sstevel@tonic-gate 				    ttyn, HMAX, remote_host);
6177c478bd9Sstevel@tonic-gate 			} else
6187c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE, "ROOT LOGIN %s", ttyn);
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	closelog();
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_DFL);
6247c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_DFL);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/*
6272de0a7d6SDan McDonald 	 * Display some useful information to the new user like the banner
6282de0a7d6SDan McDonald 	 * and last login time if not a quiet login.
6292de0a7d6SDan McDonald 	 */
6302de0a7d6SDan McDonald 
6312de0a7d6SDan McDonald 	if (access(HUSHLOGIN, F_OK) != 0) {
6322de0a7d6SDan McDonald 		print_banner();
6332de0a7d6SDan McDonald 		display_last_login_time();
6342de0a7d6SDan McDonald 	}
6352de0a7d6SDan McDonald 
6362de0a7d6SDan McDonald 	/*
6377c478bd9Sstevel@tonic-gate 	 * Set SIGXCPU and SIGXFSZ to default disposition.
6387c478bd9Sstevel@tonic-gate 	 * Shells inherit signal disposition from parent.
6397c478bd9Sstevel@tonic-gate 	 * And the shells should have default dispositions
6407c478bd9Sstevel@tonic-gate 	 * for the two below signals.
6417c478bd9Sstevel@tonic-gate 	 */
6427c478bd9Sstevel@tonic-gate 	(void) signal(SIGXCPU, SIG_DFL);
6437c478bd9Sstevel@tonic-gate 	(void) signal(SIGXFSZ, SIG_DFL);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	/*
6467c478bd9Sstevel@tonic-gate 	 * Now fire off the shell of choice
6477c478bd9Sstevel@tonic-gate 	 */
6487c478bd9Sstevel@tonic-gate 	exec_the_shell();
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	/*
6517c478bd9Sstevel@tonic-gate 	 * All done
6527c478bd9Sstevel@tonic-gate 	 */
6537c478bd9Sstevel@tonic-gate 	login_exit(1);
654032624d5Sbasabi 	return (0);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate /*
6597c478bd9Sstevel@tonic-gate  *			*** Utility functions ***
6607c478bd9Sstevel@tonic-gate  */
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate  * donothing & catch	- Signal catching functions
6667c478bd9Sstevel@tonic-gate  */
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6697c478bd9Sstevel@tonic-gate static void
donothing(int sig)6707c478bd9Sstevel@tonic-gate donothing(int sig)
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate 	if (pamh)
6737c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, PAM_ABORT);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate #ifdef notdef
6777c478bd9Sstevel@tonic-gate static	int	intrupt;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6807c478bd9Sstevel@tonic-gate static void
catch(int sig)6817c478bd9Sstevel@tonic-gate catch(int sig)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	++intrupt;
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate #endif
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate  *			*** Bad login logging support ***
6897c478bd9Sstevel@tonic-gate  */
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * badlogin()		- log to the log file 'trys'
6937c478bd9Sstevel@tonic-gate  *			  unsuccessful attempts
6947c478bd9Sstevel@tonic-gate  */
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate static void
badlogin(void)6977c478bd9Sstevel@tonic-gate badlogin(void)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	int retval, count1, fildes;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/*
7027c478bd9Sstevel@tonic-gate 	 * Tries to open the log file. If succeed, lock it and write
7037c478bd9Sstevel@tonic-gate 	 * in the failed attempts
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 	if ((fildes = open(LOGINLOG, O_APPEND|O_WRONLY)) != -1) {
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 		(void) sigset(SIGALRM, donothing);
7087c478bd9Sstevel@tonic-gate 		(void) alarm(L_WAITTIME);
7097c478bd9Sstevel@tonic-gate 		retval = lockf(fildes, F_LOCK, 0L);
7107c478bd9Sstevel@tonic-gate 		(void) alarm(0);
7117c478bd9Sstevel@tonic-gate 		(void) sigset(SIGALRM, SIG_DFL);
7127c478bd9Sstevel@tonic-gate 		if (retval == 0) {
7137c478bd9Sstevel@tonic-gate 			for (count1 = 0; count1 < trys; count1++)
7147c478bd9Sstevel@tonic-gate 				(void) write(fildes, log_entry[count1],
7157c478bd9Sstevel@tonic-gate 				    (unsigned)strlen(log_entry[count1]));
7167c478bd9Sstevel@tonic-gate 			(void) lockf(fildes, F_ULOCK, 0L);
7177c478bd9Sstevel@tonic-gate 		}
7187c478bd9Sstevel@tonic-gate 		(void) close(fildes);
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * log_bad_attempts	- log each bad login attempt - called from
7257c478bd9Sstevel@tonic-gate  *			  login_authenticate.  Exits when the maximum attempt
7267c478bd9Sstevel@tonic-gate  *			  count is exceeded.
7277c478bd9Sstevel@tonic-gate  */
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate static void
log_bad_attempts(void)7307c478bd9Sstevel@tonic-gate log_bad_attempts(void)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	time_t timenow;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (trys >= LOGTRYS)
7357c478bd9Sstevel@tonic-gate 		return;
7367c478bd9Sstevel@tonic-gate 	if (writelog) {
7377c478bd9Sstevel@tonic-gate 		(void) time(&timenow);
7387c478bd9Sstevel@tonic-gate 		(void) strncat(log_entry[trys], user_name, LNAME_SIZE);
7397c478bd9Sstevel@tonic-gate 		(void) strncat(log_entry[trys], ":", (size_t)1);
7407c478bd9Sstevel@tonic-gate 		(void) strncat(log_entry[trys], ttyn, TTYN_SIZE);
7417c478bd9Sstevel@tonic-gate 		(void) strncat(log_entry[trys], ":", (size_t)1);
7422a0352b4Sgww 		(void) strncat(log_entry[trys], ctime(&timenow), TIME_SIZE);
7437c478bd9Sstevel@tonic-gate 		trys++;
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 	if (count > flogin) {
7467c478bd9Sstevel@tonic-gate 		if ((pwd = getpwnam(user_name)) != NULL) {
7477c478bd9Sstevel@tonic-gate 			if (remote_host[0]) {
7487c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE,
7497c478bd9Sstevel@tonic-gate 				    "Login failure on %s from %.*s, "
7507c478bd9Sstevel@tonic-gate 				    "%.*s", ttyn, HMAX, remote_host,
7517c478bd9Sstevel@tonic-gate 				    NMAX, user_name);
7527c478bd9Sstevel@tonic-gate 			} else {
7537c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE,
7547c478bd9Sstevel@tonic-gate 				    "Login failure on %s, %.*s",
7557c478bd9Sstevel@tonic-gate 				    ttyn, NMAX, user_name);
7567c478bd9Sstevel@tonic-gate 			}
7577c478bd9Sstevel@tonic-gate 		} else {
7587c478bd9Sstevel@tonic-gate 			if (remote_host[0]) {
7597c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE,
7607c478bd9Sstevel@tonic-gate 				    "Login failure on %s from %.*s",
7617c478bd9Sstevel@tonic-gate 				    ttyn, HMAX, remote_host);
7627c478bd9Sstevel@tonic-gate 			} else {
7637c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE,
7647c478bd9Sstevel@tonic-gate 				    "Login failure on %s", ttyn);
7657c478bd9Sstevel@tonic-gate 			}
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate  * turn_on_logging	- if the logfile exist, turn on attempt logging and
7737c478bd9Sstevel@tonic-gate  *			  initialize the string storage area
7747c478bd9Sstevel@tonic-gate  */
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate static void
turn_on_logging(void)7777c478bd9Sstevel@tonic-gate turn_on_logging(void)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate 	struct stat dbuf;
7807c478bd9Sstevel@tonic-gate 	int i;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if (stat(LOGINLOG, &dbuf) == 0) {
7837c478bd9Sstevel@tonic-gate 		writelog = 1;
7847c478bd9Sstevel@tonic-gate 		for (i = 0; i < LOGTRYS; i++) {
7857c478bd9Sstevel@tonic-gate 			if (!(log_entry[i] = malloc((size_t)ENT_SIZE))) {
7867c478bd9Sstevel@tonic-gate 				writelog = 0;
7877c478bd9Sstevel@tonic-gate 				break;
7887c478bd9Sstevel@tonic-gate 			}
7897c478bd9Sstevel@tonic-gate 			*log_entry[i] = '\0';
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*
7967c478bd9Sstevel@tonic-gate  * login_conv():
7977c478bd9Sstevel@tonic-gate  *	This is the conv (conversation) function called from
7987c478bd9Sstevel@tonic-gate  *	a PAM authentication module to print error messages
7997c478bd9Sstevel@tonic-gate  *	or garner information from the user.
8007c478bd9Sstevel@tonic-gate  */
8017c478bd9Sstevel@tonic-gate static int
login_conv(int num_msg,const struct pam_message ** msg,struct pam_response ** response,void * appdata_ptr)802*cbea7acaSDominik Hassler login_conv(int num_msg, const struct pam_message **msg,
8037c478bd9Sstevel@tonic-gate     struct pam_response **response, void *appdata_ptr)
8047c478bd9Sstevel@tonic-gate {
805*cbea7acaSDominik Hassler 	const struct pam_message *m;
8067c478bd9Sstevel@tonic-gate 	struct pam_response *r;
8077c478bd9Sstevel@tonic-gate 	char *temp;
8087c478bd9Sstevel@tonic-gate 	int k, i;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	if (num_msg <= 0)
8117c478bd9Sstevel@tonic-gate 		return (PAM_CONV_ERR);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	*response = calloc(num_msg, sizeof (struct pam_response));
8147c478bd9Sstevel@tonic-gate 	if (*response == NULL)
8157c478bd9Sstevel@tonic-gate 		return (PAM_BUF_ERR);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	k = num_msg;
8187c478bd9Sstevel@tonic-gate 	m = *msg;
8197c478bd9Sstevel@tonic-gate 	r = *response;
8207c478bd9Sstevel@tonic-gate 	while (k--) {
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 		switch (m->msg_style) {
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		case PAM_PROMPT_ECHO_OFF:
8257d080b24Sas145665 			errno = 0;
8267c478bd9Sstevel@tonic-gate 			temp = getpassphrase(m->msg);
8277c478bd9Sstevel@tonic-gate 			if (temp != NULL) {
8287d080b24Sas145665 				if (errno == EINTR)
8297d080b24Sas145665 					return (PAM_CONV_ERR);
8307d080b24Sas145665 
8317c478bd9Sstevel@tonic-gate 				r->resp = strdup(temp);
8327c478bd9Sstevel@tonic-gate 				if (r->resp == NULL) {
8337c478bd9Sstevel@tonic-gate 					/* free responses */
8347c478bd9Sstevel@tonic-gate 					r = *response;
8357c478bd9Sstevel@tonic-gate 					for (i = 0; i < num_msg; i++, r++) {
8367c478bd9Sstevel@tonic-gate 						if (r->resp)
8377c478bd9Sstevel@tonic-gate 							free(r->resp);
8387c478bd9Sstevel@tonic-gate 					}
8397c478bd9Sstevel@tonic-gate 					free(*response);
8407c478bd9Sstevel@tonic-gate 					*response = NULL;
8417c478bd9Sstevel@tonic-gate 					return (PAM_BUF_ERR);
8427c478bd9Sstevel@tonic-gate 				}
8437c478bd9Sstevel@tonic-gate 			}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 			m++;
8467c478bd9Sstevel@tonic-gate 			r++;
8477c478bd9Sstevel@tonic-gate 			break;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 		case PAM_PROMPT_ECHO_ON:
8507c478bd9Sstevel@tonic-gate 			if (m->msg != NULL)
8517c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stdout);
8527c478bd9Sstevel@tonic-gate 			r->resp = calloc(1, PAM_MAX_RESP_SIZE);
8537c478bd9Sstevel@tonic-gate 			if (r->resp == NULL) {
8547c478bd9Sstevel@tonic-gate 				/* free responses */
8557c478bd9Sstevel@tonic-gate 				r = *response;
8567c478bd9Sstevel@tonic-gate 				for (i = 0; i < num_msg; i++, r++) {
8577c478bd9Sstevel@tonic-gate 					if (r->resp)
8587c478bd9Sstevel@tonic-gate 						free(r->resp);
8597c478bd9Sstevel@tonic-gate 				}
8607c478bd9Sstevel@tonic-gate 				free(*response);
8617c478bd9Sstevel@tonic-gate 				*response = NULL;
8627c478bd9Sstevel@tonic-gate 				return (PAM_BUF_ERR);
8637c478bd9Sstevel@tonic-gate 			}
8647c478bd9Sstevel@tonic-gate 			/*
8657c478bd9Sstevel@tonic-gate 			 * The response might include environment variables
8667c478bd9Sstevel@tonic-gate 			 * information. We should store that information in
8677c478bd9Sstevel@tonic-gate 			 * envp if there is any; otherwise, envp is set to
8687c478bd9Sstevel@tonic-gate 			 * NULL.
8697c478bd9Sstevel@tonic-gate 			 */
8707c478bd9Sstevel@tonic-gate 			bzero((void *)inputline, MAXLINE);
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 			envp = getargs(inputline);
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 			/* If we read in any input, process it. */
8757c478bd9Sstevel@tonic-gate 			if (inputline[0] != '\0') {
8767c478bd9Sstevel@tonic-gate 				int len;
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 				if (envp != (char **)NULL)
8797c478bd9Sstevel@tonic-gate 					/*
8807c478bd9Sstevel@tonic-gate 					 * If getargs() did not return NULL,
8817c478bd9Sstevel@tonic-gate 					 * *envp is the first string in
8827c478bd9Sstevel@tonic-gate 					 * inputline. envp++ makes envp point
8837c478bd9Sstevel@tonic-gate 					 * to environment variables information
8847c478bd9Sstevel@tonic-gate 					 *  or be NULL.
8857c478bd9Sstevel@tonic-gate 					 */
8867c478bd9Sstevel@tonic-gate 					envp++;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 				(void) strncpy(r->resp, inputline,
8897c478bd9Sstevel@tonic-gate 				    PAM_MAX_RESP_SIZE-1);
890723f377cSToomas Soome 				r->resp[PAM_MAX_RESP_SIZE-1] = '\0';
8917c478bd9Sstevel@tonic-gate 				len = strlen(r->resp);
8927c478bd9Sstevel@tonic-gate 				if (r->resp[len-1] == '\n')
8937c478bd9Sstevel@tonic-gate 					r->resp[len-1] = '\0';
8947c478bd9Sstevel@tonic-gate 			} else {
8957c478bd9Sstevel@tonic-gate 				login_exit(1);
8967c478bd9Sstevel@tonic-gate 			}
8977c478bd9Sstevel@tonic-gate 			m++;
8987c478bd9Sstevel@tonic-gate 			r++;
8997c478bd9Sstevel@tonic-gate 			break;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 		case PAM_ERROR_MSG:
9027c478bd9Sstevel@tonic-gate 			if (m->msg != NULL) {
9037c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stderr);
9047c478bd9Sstevel@tonic-gate 				(void) fputs("\n", stderr);
9057c478bd9Sstevel@tonic-gate 			}
9067c478bd9Sstevel@tonic-gate 			m++;
9077c478bd9Sstevel@tonic-gate 			r++;
9087c478bd9Sstevel@tonic-gate 			break;
9097c478bd9Sstevel@tonic-gate 		case PAM_TEXT_INFO:
9107c478bd9Sstevel@tonic-gate 			if (m->msg != NULL) {
9117c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stdout);
9127c478bd9Sstevel@tonic-gate 				(void) fputs("\n", stdout);
9137c478bd9Sstevel@tonic-gate 			}
9147c478bd9Sstevel@tonic-gate 			m++;
9157c478bd9Sstevel@tonic-gate 			r++;
9167c478bd9Sstevel@tonic-gate 			break;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		default:
9197c478bd9Sstevel@tonic-gate 			break;
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 	}
9227c478bd9Sstevel@tonic-gate 	return (PAM_SUCCESS);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate /*
9267c478bd9Sstevel@tonic-gate  * verify_passwd - Authenticates the user.
9277c478bd9Sstevel@tonic-gate  *	Returns: PAM_SUCCESS if authentication successful,
9287c478bd9Sstevel@tonic-gate  *		 PAM error code if authentication fails.
9297c478bd9Sstevel@tonic-gate  */
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate static int
verify_passwd(void)932032624d5Sbasabi verify_passwd(void)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate 	int error;
935*cbea7acaSDominik Hassler 	const char *user;
93657c40785SJoep Vesseur 	int flag = (Passreqflag ? PAM_DISALLOW_NULL_AUTHTOK : 0);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	/*
9397c478bd9Sstevel@tonic-gate 	 * PAM authenticates the user for us.
9407c478bd9Sstevel@tonic-gate 	 */
9412a0352b4Sgww 	error = pam_authenticate(pamh, flag);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	/* get the user_name from the pam handle */
944*cbea7acaSDominik Hassler 	(void) pam_get_item(pamh, PAM_USER, (const void **)&user);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	if (user == NULL || *user == '\0')
9477c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	SCPYL(user_name, user);
9507c478bd9Sstevel@tonic-gate 	check_for_dueling_unix(user_name);
9517c478bd9Sstevel@tonic-gate 
9522a0352b4Sgww 	if (((pwd = getpwnam(user_name)) == NULL) &&
9532a0352b4Sgww 	    (error != PAM_USER_UNKNOWN)) {
9547c478bd9Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	return (error);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate  * quotec		- Called by getargs
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate static int
quotec(void)9657c478bd9Sstevel@tonic-gate quotec(void)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate 	int c, i, num;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	switch (c = getc(stdin)) {
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		case 'n':
9727c478bd9Sstevel@tonic-gate 			c = '\n';
9737c478bd9Sstevel@tonic-gate 			break;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		case 'r':
9767c478bd9Sstevel@tonic-gate 			c = '\r';
9777c478bd9Sstevel@tonic-gate 			break;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 		case 'v':
9807c478bd9Sstevel@tonic-gate 			c = '\013';
9817c478bd9Sstevel@tonic-gate 			break;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 		case 'b':
9847c478bd9Sstevel@tonic-gate 			c = '\b';
9857c478bd9Sstevel@tonic-gate 			break;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 		case 't':
9887c478bd9Sstevel@tonic-gate 			c = '\t';
9897c478bd9Sstevel@tonic-gate 			break;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		case 'f':
9927c478bd9Sstevel@tonic-gate 			c = '\f';
9937c478bd9Sstevel@tonic-gate 			break;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 		case '0':
9967c478bd9Sstevel@tonic-gate 		case '1':
9977c478bd9Sstevel@tonic-gate 		case '2':
9987c478bd9Sstevel@tonic-gate 		case '3':
9997c478bd9Sstevel@tonic-gate 		case '4':
10007c478bd9Sstevel@tonic-gate 		case '5':
10017c478bd9Sstevel@tonic-gate 		case '6':
10027c478bd9Sstevel@tonic-gate 		case '7':
10037c478bd9Sstevel@tonic-gate 			for (num = 0, i = 0; i < 3; i++) {
10047c478bd9Sstevel@tonic-gate 				num = num * 8 + (c - '0');
10057c478bd9Sstevel@tonic-gate 				if ((c = getc(stdin)) < '0' || c > '7')
10067c478bd9Sstevel@tonic-gate 					break;
10077c478bd9Sstevel@tonic-gate 			}
10087c478bd9Sstevel@tonic-gate 			(void) ungetc(c, stdin);
10097c478bd9Sstevel@tonic-gate 			c = num & 0377;
10107c478bd9Sstevel@tonic-gate 			break;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 		default:
10137c478bd9Sstevel@tonic-gate 			break;
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 	return (c);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate /*
10197c478bd9Sstevel@tonic-gate  * getargs		- returns an input line.  Exits if EOF encountered.
10207c478bd9Sstevel@tonic-gate  */
10217c478bd9Sstevel@tonic-gate #define	WHITESPACE	0
10227c478bd9Sstevel@tonic-gate #define	ARGUMENT	1
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate static char **
getargs(char * input_line)10257c478bd9Sstevel@tonic-gate getargs(char *input_line)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	static char envbuf[MAXLINE];
10287c478bd9Sstevel@tonic-gate 	static char *args[MAXARGS];
10297c478bd9Sstevel@tonic-gate 	char *ptr, **answer;
10307c478bd9Sstevel@tonic-gate 	int c;
10317c478bd9Sstevel@tonic-gate 	int state;
10327c478bd9Sstevel@tonic-gate 	char *p = input_line;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	ptr = envbuf;
10357c478bd9Sstevel@tonic-gate 	answer = &args[0];
10367c478bd9Sstevel@tonic-gate 	state = WHITESPACE;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	while ((c = getc(stdin)) != EOF && answer < &args[MAXARGS-1]) {
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 		*(input_line++) = c;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 		switch (c) {
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		case '\n':
10457c478bd9Sstevel@tonic-gate 			if (ptr == &envbuf[0])
10467c478bd9Sstevel@tonic-gate 				return ((char **)NULL);
10477c478bd9Sstevel@tonic-gate 			*input_line = *ptr = '\0';
10487c478bd9Sstevel@tonic-gate 			*answer = NULL;
10497c478bd9Sstevel@tonic-gate 			return (&args[0]);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 		case ' ':
10527c478bd9Sstevel@tonic-gate 		case '\t':
10537c478bd9Sstevel@tonic-gate 			if (state == ARGUMENT) {
10547c478bd9Sstevel@tonic-gate 				*ptr++ = '\0';
10557c478bd9Sstevel@tonic-gate 				state = WHITESPACE;
10567c478bd9Sstevel@tonic-gate 			}
10577c478bd9Sstevel@tonic-gate 			break;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		case '\\':
10607c478bd9Sstevel@tonic-gate 			c = quotec();
10615196acaeSToomas Soome 			/* FALLTHROUGH */
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 		default:
10647c478bd9Sstevel@tonic-gate 			if (state == WHITESPACE) {
10657c478bd9Sstevel@tonic-gate 				*answer++ = ptr;
10667c478bd9Sstevel@tonic-gate 				state = ARGUMENT;
10677c478bd9Sstevel@tonic-gate 			}
10687c478bd9Sstevel@tonic-gate 			*ptr++ = c;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		/* Attempt at overflow, exit */
10727c478bd9Sstevel@tonic-gate 		if (input_line - p >= MAXLINE - 1 ||
10737c478bd9Sstevel@tonic-gate 		    ptr >= &envbuf[sizeof (envbuf) - 1]) {
10747c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_VALUE_INPUT_OVERFLOW;
10757c478bd9Sstevel@tonic-gate 			login_exit(1);
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	/*
10807c478bd9Sstevel@tonic-gate 	 * If we left loop because an EOF was received or we've overflown
10817c478bd9Sstevel@tonic-gate 	 * args[], exit immediately.
10827c478bd9Sstevel@tonic-gate 	 */
10837c478bd9Sstevel@tonic-gate 	login_exit(0);
10847c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate  * get_user_name	- Gets the user name either passed in, or from the
10897c478bd9Sstevel@tonic-gate  *			  login: prompt.
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate static void
get_user_name(void)1093032624d5Sbasabi get_user_name(void)
10947c478bd9Sstevel@tonic-gate {
10957c478bd9Sstevel@tonic-gate 	FILE	*fp;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	if ((fp = fopen(ISSUEFILE, "r")) != NULL) {
10987c478bd9Sstevel@tonic-gate 		char    *ptr, buffer[BUFSIZ];
10992a0352b4Sgww 		while ((ptr = fgets(buffer, sizeof (buffer), fp)) != NULL) {
11007c478bd9Sstevel@tonic-gate 			(void) fputs(ptr, stdout);
11017c478bd9Sstevel@tonic-gate 		}
11027c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	/*
11067c478bd9Sstevel@tonic-gate 	 * if TTYPROMPT is not set, use our own prompt
11077c478bd9Sstevel@tonic-gate 	 * otherwise, use ttyprompt. We just set PAM_USER_PROMPT
11087c478bd9Sstevel@tonic-gate 	 * and let the module do the prompting.
11097c478bd9Sstevel@tonic-gate 	 */
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if ((ttyprompt == NULL) || (*ttyprompt == '\0'))
11127c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)loginmsg);
11137c478bd9Sstevel@tonic-gate 	else
11147c478bd9Sstevel@tonic-gate 		(void) pam_set_item(pamh, PAM_USER_PROMPT, (void *)ttyprompt);
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	envp = &zero; /* XXX: is this right? */
11177c478bd9Sstevel@tonic-gate }
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate /*
11217c478bd9Sstevel@tonic-gate  * Check_for_dueling_unix   -	Check to see if the another login is talking
11227c478bd9Sstevel@tonic-gate  *				to the line we've got open as a login port
11237c478bd9Sstevel@tonic-gate  *				Exits if we're talking to another unix system
11247c478bd9Sstevel@tonic-gate  */
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate static void
check_for_dueling_unix(char * inputline)11277c478bd9Sstevel@tonic-gate check_for_dueling_unix(char *inputline)
11287c478bd9Sstevel@tonic-gate {
11297c478bd9Sstevel@tonic-gate 	if (EQN(loginmsg, inputline) || EQN(passwdmsg, inputline) ||
11307c478bd9Sstevel@tonic-gate 	    EQN(incorrectmsg, inputline)) {
11317c478bd9Sstevel@tonic-gate 		(void) printf("Looking at a login line.\n");
11327c478bd9Sstevel@tonic-gate 		login_exit(8);
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate /*
11377c478bd9Sstevel@tonic-gate  * logins_disabled -	if the file /etc/nologin exists and the user is not
11387c478bd9Sstevel@tonic-gate  *			root then do not permit them to login
11397c478bd9Sstevel@tonic-gate  */
11407c478bd9Sstevel@tonic-gate static int
logins_disabled(char * user_name)11417c478bd9Sstevel@tonic-gate logins_disabled(char *user_name)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	FILE	*nlfd;
11447c478bd9Sstevel@tonic-gate 	int	c;
11457c478bd9Sstevel@tonic-gate 	if (!EQN("root", user_name) &&
11467c478bd9Sstevel@tonic-gate 	    ((nlfd = fopen(NOLOGIN, "r")) != (FILE *)NULL)) {
11477c478bd9Sstevel@tonic-gate 		while ((c = getc(nlfd)) != EOF)
11487c478bd9Sstevel@tonic-gate 			(void) putchar(c);
11497c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
11507c478bd9Sstevel@tonic-gate 		(void) sleep(5);
11517c478bd9Sstevel@tonic-gate 		return (TRUE);
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 	return (FALSE);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate 
1156aecfc01dSrui zang - Sun Microsystems - Beijing China #define	DEFAULT_CONSOLE	"/dev/console"
1157aecfc01dSrui zang - Sun Microsystems - Beijing China 
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate  * check_for_console -  Checks if we're getting a root login on the
11607c478bd9Sstevel@tonic-gate  *			console, or a login from the global zone. Exits if not.
11617c478bd9Sstevel@tonic-gate  *
1162aecfc01dSrui zang - Sun Microsystems - Beijing China  * If CONSOLE is set to /dev/console in /etc/default/login, then root logins
1163aecfc01dSrui zang - Sun Microsystems - Beijing China  * on /dev/vt/# are permitted as well. /dev/vt/# does not exist in non-global
1164aecfc01dSrui zang - Sun Microsystems - Beijing China  * zones, but checking them does no harm.
11657c478bd9Sstevel@tonic-gate  */
11667c478bd9Sstevel@tonic-gate static void
check_for_console(void)11677c478bd9Sstevel@tonic-gate check_for_console(void)
11687c478bd9Sstevel@tonic-gate {
1169aecfc01dSrui zang - Sun Microsystems - Beijing China 	const char *consoles[] = { "/dev/console", "/dev/vt/", NULL };
1170aecfc01dSrui zang - Sun Microsystems - Beijing China 	int i;
1171aecfc01dSrui zang - Sun Microsystems - Beijing China 
1172aecfc01dSrui zang - Sun Microsystems - Beijing China 	if (pwd == NULL || pwd->pw_uid != 0 || zflag != B_FALSE ||
1173aecfc01dSrui zang - Sun Microsystems - Beijing China 	    Console == NULL)
1174aecfc01dSrui zang - Sun Microsystems - Beijing China 		return;
1175aecfc01dSrui zang - Sun Microsystems - Beijing China 
1176aecfc01dSrui zang - Sun Microsystems - Beijing China 	if (strcmp(Console, DEFAULT_CONSOLE) == 0) {
1177aecfc01dSrui zang - Sun Microsystems - Beijing China 		for (i = 0; consoles[i] != NULL; i ++) {
1178aecfc01dSrui zang - Sun Microsystems - Beijing China 			if (strncmp(ttyn, consoles[i],
1179aecfc01dSrui zang - Sun Microsystems - Beijing China 			    strlen(consoles[i])) == 0)
1180aecfc01dSrui zang - Sun Microsystems - Beijing China 				return;
1181aecfc01dSrui zang - Sun Microsystems - Beijing China 		}
1182aecfc01dSrui zang - Sun Microsystems - Beijing China 	} else {
1183aecfc01dSrui zang - Sun Microsystems - Beijing China 		if (strcmp(ttyn, Console) == 0)
1184aecfc01dSrui zang - Sun Microsystems - Beijing China 			return;
1185aecfc01dSrui zang - Sun Microsystems - Beijing China 	}
1186aecfc01dSrui zang - Sun Microsystems - Beijing China 
11877c478bd9Sstevel@tonic-gate 	(void) printf("Not on system console\n");
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	audit_error = ADT_FAIL_VALUE_CONSOLE;
11907c478bd9Sstevel@tonic-gate 	login_exit(10);
1191aecfc01dSrui zang - Sun Microsystems - Beijing China 
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate /*
11957c478bd9Sstevel@tonic-gate  * List of environment variables or environment variable prefixes that should
11967c478bd9Sstevel@tonic-gate  * not be propagated across logins, such as when the login -p option is used.
11977c478bd9Sstevel@tonic-gate  */
11987c478bd9Sstevel@tonic-gate static const char *const illegal[] = {
11997c478bd9Sstevel@tonic-gate 	"SHELL=",
12007c478bd9Sstevel@tonic-gate 	"HOME=",
12017c478bd9Sstevel@tonic-gate 	"LOGNAME=",
12027c478bd9Sstevel@tonic-gate #ifndef	NO_MAIL
12037c478bd9Sstevel@tonic-gate 	"MAIL=",
12047c478bd9Sstevel@tonic-gate #endif
12057c478bd9Sstevel@tonic-gate 	"CDPATH=",
12067c478bd9Sstevel@tonic-gate 	"IFS=",
12077c478bd9Sstevel@tonic-gate 	"PATH=",
12087c478bd9Sstevel@tonic-gate 	"LD_",
12097c478bd9Sstevel@tonic-gate 	"SMF_",
12107c478bd9Sstevel@tonic-gate 	NULL
12117c478bd9Sstevel@tonic-gate };
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate /*
12147c478bd9Sstevel@tonic-gate  * legalenvvar		- Is it legal to insert this environmental variable?
12157c478bd9Sstevel@tonic-gate  */
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate static int
legalenvvar(char * s)12187c478bd9Sstevel@tonic-gate legalenvvar(char *s)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate 	const char *const *p;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	for (p = &illegal[0]; *p; p++) {
12237c478bd9Sstevel@tonic-gate 		if (strncmp(s, *p, strlen(*p)) == 0)
12247c478bd9Sstevel@tonic-gate 			return (0);
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	return (1);
12287c478bd9Sstevel@tonic-gate }
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate /*
12327c478bd9Sstevel@tonic-gate  * getstr		- Get a string from standard input
12337c478bd9Sstevel@tonic-gate  *			  Calls exit if read(2) fails.
12347c478bd9Sstevel@tonic-gate  */
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate static void
getstr(char * buf,int cnt,char * err)12377c478bd9Sstevel@tonic-gate getstr(char *buf, int cnt, char *err)
12387c478bd9Sstevel@tonic-gate {
12397c478bd9Sstevel@tonic-gate 	char c;
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	do {
12427c478bd9Sstevel@tonic-gate 		if (read(0, &c, 1) != 1)
12437c478bd9Sstevel@tonic-gate 			login_exit(1);
12447c478bd9Sstevel@tonic-gate 		*buf++ = c;
12457c478bd9Sstevel@tonic-gate 	} while (--cnt > 1 && c != 0);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	*buf = 0;
12487c478bd9Sstevel@tonic-gate 	err = err;	/* For lint */
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate /*
12537c478bd9Sstevel@tonic-gate  * defaults		- read defaults
12547c478bd9Sstevel@tonic-gate  */
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate static void
defaults(void)12577c478bd9Sstevel@tonic-gate defaults(void)
12587c478bd9Sstevel@tonic-gate {
12597c478bd9Sstevel@tonic-gate 	int  flags;
12607c478bd9Sstevel@tonic-gate 	char *ptr;
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	if (defopen(Pndefault) == 0) {
12637c478bd9Sstevel@tonic-gate 		/*
12647c478bd9Sstevel@tonic-gate 		 * ignore case
12657c478bd9Sstevel@tonic-gate 		 */
12667c478bd9Sstevel@tonic-gate 		flags = defcntl(DC_GETFLAGS, 0);
12677c478bd9Sstevel@tonic-gate 		TURNOFF(flags, DC_CASE);
12687c478bd9Sstevel@tonic-gate 		(void) defcntl(DC_SETFLAGS, flags);
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 		if ((Console = defread("CONSOLE=")) != NULL)
12717c478bd9Sstevel@tonic-gate 			Console = strdup(Console);
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 		if ((Altshell = defread("ALTSHELL=")) != NULL)
12747c478bd9Sstevel@tonic-gate 			Altshell = strdup(Altshell);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 		if ((ptr = defread("PASSREQ=")) != NULL &&
12777c478bd9Sstevel@tonic-gate 		    strcasecmp("YES", ptr) == 0)
12787c478bd9Sstevel@tonic-gate 				Passreqflag = 1;
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 		if ((Def_tz = defread("TIMEZONE=")) != NULL)
12817c478bd9Sstevel@tonic-gate 			Def_tz = strdup(Def_tz);
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 		if ((Def_hertz = defread("HZ=")) != NULL)
12847c478bd9Sstevel@tonic-gate 			Def_hertz = strdup(Def_hertz);
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 		if ((Def_path   = defread("PATH=")) != NULL)
12877c478bd9Sstevel@tonic-gate 			Def_path = strdup(Def_path);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 		if ((Def_supath = defread("SUPATH=")) != NULL)
12907c478bd9Sstevel@tonic-gate 			Def_supath = strdup(Def_supath);
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 		if ((ptr = defread("ULIMIT=")) != NULL)
12937c478bd9Sstevel@tonic-gate 			Def_ulimit = atol(ptr);
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 		if ((ptr = defread("TIMEOUT=")) != NULL)
12967c478bd9Sstevel@tonic-gate 			Def_timeout = (unsigned)atoi(ptr);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 		if ((ptr = defread("UMASK=")) != NULL)
12997c478bd9Sstevel@tonic-gate 			if (sscanf(ptr, "%lo", &Umask) != 1)
13007c478bd9Sstevel@tonic-gate 				Umask = DEFUMASK;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		if ((ptr = defread("SLEEPTIME=")) != NULL) {
13037c478bd9Sstevel@tonic-gate 			if (is_number(ptr))
13047c478bd9Sstevel@tonic-gate 				Sleeptime = atoi(ptr);
13057c478bd9Sstevel@tonic-gate 		}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 		if ((ptr = defread("DISABLETIME=")) != NULL) {
13087c478bd9Sstevel@tonic-gate 			if (is_number(ptr))
13097c478bd9Sstevel@tonic-gate 				Disabletime = atoi(ptr);
13107c478bd9Sstevel@tonic-gate 		}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 		if ((ptr = defread("SYSLOG=")) != NULL)
13137c478bd9Sstevel@tonic-gate 			dosyslog = strcmp(ptr, "YES") == 0;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 		if ((ptr = defread("RETRIES=")) != NULL) {
13167c478bd9Sstevel@tonic-gate 			if (is_number(ptr))
13177c478bd9Sstevel@tonic-gate 				retry = atoi(ptr);
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 		if ((ptr = defread("SYSLOG_FAILED_LOGINS=")) != NULL) {
13217c478bd9Sstevel@tonic-gate 			if (is_number(ptr))
13227c478bd9Sstevel@tonic-gate 				flogin = atoi(ptr);
13237c478bd9Sstevel@tonic-gate 			else
13247c478bd9Sstevel@tonic-gate 				flogin = retry;
13257c478bd9Sstevel@tonic-gate 		} else
13267c478bd9Sstevel@tonic-gate 			flogin = retry;
13277c478bd9Sstevel@tonic-gate 		(void) defopen((char *)NULL);
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate }
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate /*
13337c478bd9Sstevel@tonic-gate  * get_options(argc, argv)
13347c478bd9Sstevel@tonic-gate  *			- parse the cmd line.
13357c478bd9Sstevel@tonic-gate  *			- return 0 if successful, -1 if failed.
13367c478bd9Sstevel@tonic-gate  *			Calls login_exit() on misuse of -r, -h, and -z flags
13377c478bd9Sstevel@tonic-gate  */
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate static	int
get_options(int argc,char * argv[])13407c478bd9Sstevel@tonic-gate get_options(int argc, char *argv[])
13417c478bd9Sstevel@tonic-gate {
13427c478bd9Sstevel@tonic-gate 	int	c;
13437c478bd9Sstevel@tonic-gate 	int	errflg = 0;
13447c478bd9Sstevel@tonic-gate 	char	sflagname[NMAX+1];
13457c478bd9Sstevel@tonic-gate 	const	char *flags_message = "Only one of -r, -h and -z allowed\n";
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "u:s:R:f:h:r:pad:t:U:z:")) != -1) {
13487c478bd9Sstevel@tonic-gate 		switch (c) {
13497c478bd9Sstevel@tonic-gate 		case 'a':
13507c478bd9Sstevel@tonic-gate 			break;
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 		case 'd':
13537c478bd9Sstevel@tonic-gate 			/*
13547c478bd9Sstevel@tonic-gate 			 * Must be root to pass in device name
13557c478bd9Sstevel@tonic-gate 			 * otherwise we exit() as punishment for trying.
13567c478bd9Sstevel@tonic-gate 			 */
13577c478bd9Sstevel@tonic-gate 			if (getuid() != 0 || geteuid() != 0) {
13587c478bd9Sstevel@tonic-gate 				audit_error = ADT_FAIL_VALUE_DEVICE_PERM;
13597c478bd9Sstevel@tonic-gate 				login_exit(1);	/* sigh */
13607c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
13617c478bd9Sstevel@tonic-gate 			}
13627c478bd9Sstevel@tonic-gate 			ttyn = optarg;
13637c478bd9Sstevel@tonic-gate 			break;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		case 'h':
13667c478bd9Sstevel@tonic-gate 			if (hflag || rflag || zflag) {
13677c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, flags_message);
13687c478bd9Sstevel@tonic-gate 				login_exit(1);
13697c478bd9Sstevel@tonic-gate 			}
13707c478bd9Sstevel@tonic-gate 			hflag = B_TRUE;
13717c478bd9Sstevel@tonic-gate 			SCPYL(remote_host, optarg);
13727c478bd9Sstevel@tonic-gate 			if (argv[optind]) {
13737c478bd9Sstevel@tonic-gate 				if (argv[optind][0] != '-') {
13747c478bd9Sstevel@tonic-gate 					SCPYL(terminal, argv[optind]);
13757c478bd9Sstevel@tonic-gate 					optind++;
13767c478bd9Sstevel@tonic-gate 				} else {
13777c478bd9Sstevel@tonic-gate 					/*
13787c478bd9Sstevel@tonic-gate 					 * Allow "login -h hostname -" to
13797c478bd9Sstevel@tonic-gate 					 * skip setting up an username as "-".
13807c478bd9Sstevel@tonic-gate 					 */
13817c478bd9Sstevel@tonic-gate 					if (argv[optind][1] == '\0')
13827c478bd9Sstevel@tonic-gate 						optind++;
13837c478bd9Sstevel@tonic-gate 				}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 			}
13867c478bd9Sstevel@tonic-gate 			SCPYL(progname, "telnet");
13877c478bd9Sstevel@tonic-gate 			break;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 		case 'r':
13907c478bd9Sstevel@tonic-gate 			if (hflag || rflag || zflag) {
13917c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, flags_message);
13927c478bd9Sstevel@tonic-gate 				login_exit(1);
13937c478bd9Sstevel@tonic-gate 			}
13947c478bd9Sstevel@tonic-gate 			rflag = B_TRUE;
13957c478bd9Sstevel@tonic-gate 			SCPYL(remote_host, optarg);
13967c478bd9Sstevel@tonic-gate 			SCPYL(progname, "rlogin");
13977c478bd9Sstevel@tonic-gate 			break;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 		case 'p':
14007c478bd9Sstevel@tonic-gate 			pflag = B_TRUE;
14017c478bd9Sstevel@tonic-gate 			break;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 		case 'f':
14047c478bd9Sstevel@tonic-gate 			/*
14057c478bd9Sstevel@tonic-gate 			 * Must be root to bypass authentication
14067c478bd9Sstevel@tonic-gate 			 * otherwise we exit() as punishment for trying.
14077c478bd9Sstevel@tonic-gate 			 */
14087c478bd9Sstevel@tonic-gate 			if (getuid() != 0 || geteuid() != 0) {
14097c478bd9Sstevel@tonic-gate 				audit_error = ADT_FAIL_VALUE_AUTH_BYPASS;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 				login_exit(1);	/* sigh */
14127c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
14137c478bd9Sstevel@tonic-gate 			}
14147c478bd9Sstevel@tonic-gate 			/* save fflag user name for future use */
14157c478bd9Sstevel@tonic-gate 			SCPYL(user_name, optarg);
14167c478bd9Sstevel@tonic-gate 			fflag = B_TRUE;
14177c478bd9Sstevel@tonic-gate 			break;
14187c478bd9Sstevel@tonic-gate 		case 'u':
14197c478bd9Sstevel@tonic-gate 			if (!strlen(optarg)) {
14207c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14217c478bd9Sstevel@tonic-gate 				    "Empty string supplied with -u\n");
14227c478bd9Sstevel@tonic-gate 				login_exit(1);
14237c478bd9Sstevel@tonic-gate 			}
14247c478bd9Sstevel@tonic-gate 			SCPYL(identity, optarg);
14257c478bd9Sstevel@tonic-gate 			uflag = B_TRUE;
14267c478bd9Sstevel@tonic-gate 			break;
14277c478bd9Sstevel@tonic-gate 		case 's':
14287c478bd9Sstevel@tonic-gate 			if (!strlen(optarg)) {
14297c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14307c478bd9Sstevel@tonic-gate 				    "Empty string supplied with -s\n");
14317c478bd9Sstevel@tonic-gate 				login_exit(1);
14327c478bd9Sstevel@tonic-gate 			}
14337c478bd9Sstevel@tonic-gate 			SCPYL(sflagname, optarg);
14347c478bd9Sstevel@tonic-gate 			sflag = B_TRUE;
14357c478bd9Sstevel@tonic-gate 			break;
14367c478bd9Sstevel@tonic-gate 		case 'R':
14377c478bd9Sstevel@tonic-gate 			if (!strlen(optarg)) {
14387c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14397c478bd9Sstevel@tonic-gate 				    "Empty string supplied with -R\n");
14407c478bd9Sstevel@tonic-gate 				login_exit(1);
14417c478bd9Sstevel@tonic-gate 			}
14427c478bd9Sstevel@tonic-gate 			SCPYL(repository, optarg);
14437c478bd9Sstevel@tonic-gate 			Rflag =	B_TRUE;
14447c478bd9Sstevel@tonic-gate 			break;
14457c478bd9Sstevel@tonic-gate 		case 't':
14467c478bd9Sstevel@tonic-gate 			if (!strlen(optarg)) {
14477c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
14487c478bd9Sstevel@tonic-gate 				    "Empty string supplied with -t\n");
14497c478bd9Sstevel@tonic-gate 				login_exit(1);
14507c478bd9Sstevel@tonic-gate 			}
14517c478bd9Sstevel@tonic-gate 			SCPYL(terminal, optarg);
14527c478bd9Sstevel@tonic-gate 			tflag = B_TRUE;
14537c478bd9Sstevel@tonic-gate 			break;
14547c478bd9Sstevel@tonic-gate 		case 'U':
14557c478bd9Sstevel@tonic-gate 			/*
14567c478bd9Sstevel@tonic-gate 			 * Kerberized rlogind may fork us with
14577c478bd9Sstevel@tonic-gate 			 * -U "" if the rlogin client used the "-a"
14587c478bd9Sstevel@tonic-gate 			 * option to send a NULL username.  This is done
14597c478bd9Sstevel@tonic-gate 			 * to force login to prompt for a user/password.
14607c478bd9Sstevel@tonic-gate 			 * However, if Kerberos auth was used, we dont need
14617c478bd9Sstevel@tonic-gate 			 * to prompt, so we will accept the option and
14627c478bd9Sstevel@tonic-gate 			 * handle the situation later.
14637c478bd9Sstevel@tonic-gate 			 */
14647c478bd9Sstevel@tonic-gate 			SCPYL(rusername, optarg);
14657c478bd9Sstevel@tonic-gate 			Uflag = B_TRUE;
14667c478bd9Sstevel@tonic-gate 			break;
14677c478bd9Sstevel@tonic-gate 		case 'z':
14687c478bd9Sstevel@tonic-gate 			if (hflag || rflag || zflag) {
14697c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, flags_message);
14707c478bd9Sstevel@tonic-gate 				login_exit(1);
14717c478bd9Sstevel@tonic-gate 			}
14727c478bd9Sstevel@tonic-gate 			(void) snprintf(zone_name, sizeof (zone_name),
14737c478bd9Sstevel@tonic-gate 			    "zone:%s", optarg);
14747c478bd9Sstevel@tonic-gate 			SCPYL(progname, "zlogin");
14757c478bd9Sstevel@tonic-gate 			zflag = B_TRUE;
14767c478bd9Sstevel@tonic-gate 			break;
14777c478bd9Sstevel@tonic-gate 		default:
14787c478bd9Sstevel@tonic-gate 			errflg++;
14797c478bd9Sstevel@tonic-gate 			break;
14807c478bd9Sstevel@tonic-gate 		}	/* end switch */
14817c478bd9Sstevel@tonic-gate 	}		/* end while */
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	/*
14847c478bd9Sstevel@tonic-gate 	 * If the 's svcname' flag was used, override the progname
14857c478bd9Sstevel@tonic-gate 	 * value that is to be used in the pam_start call.
14867c478bd9Sstevel@tonic-gate 	 */
14877c478bd9Sstevel@tonic-gate 	if (sflag)
14887c478bd9Sstevel@tonic-gate 		SCPYL(progname, sflagname);
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	/*
14917c478bd9Sstevel@tonic-gate 	 * get the prompt set by ttymon
14927c478bd9Sstevel@tonic-gate 	 */
14937c478bd9Sstevel@tonic-gate 	ttyprompt = getenv("TTYPROMPT");
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	if ((ttyprompt != NULL) && (*ttyprompt != '\0')) {
14967c478bd9Sstevel@tonic-gate 		/*
14977c478bd9Sstevel@tonic-gate 		 * if ttyprompt is set, there should be data on
14987c478bd9Sstevel@tonic-gate 		 * the stream already.
14997c478bd9Sstevel@tonic-gate 		 */
15007c478bd9Sstevel@tonic-gate 		if ((envp = getargs(inputline)) != (char **)NULL) {
15017c478bd9Sstevel@tonic-gate 			/*
15027c478bd9Sstevel@tonic-gate 			 * don't get name if name passed as argument.
15037c478bd9Sstevel@tonic-gate 			 */
15047c478bd9Sstevel@tonic-gate 			SCPYL(user_name, *envp++);
15057c478bd9Sstevel@tonic-gate 		}
15067c478bd9Sstevel@tonic-gate 	} else if (optind < argc) {
15077c478bd9Sstevel@tonic-gate 		SCPYL(user_name, argv[optind]);
15087c478bd9Sstevel@tonic-gate 		(void) SCPYL(inputline, user_name);
15097c478bd9Sstevel@tonic-gate 		(void) strlcat(inputline, "   \n", sizeof (inputline));
15107c478bd9Sstevel@tonic-gate 		envp = &argv[optind+1];
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 		if (!fflag)
15137c478bd9Sstevel@tonic-gate 			SCPYL(lusername, user_name);
15147c478bd9Sstevel@tonic-gate 	}
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	if (errflg)
15177c478bd9Sstevel@tonic-gate 		return (-1);
15187c478bd9Sstevel@tonic-gate 	return (0);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate /*
15227c478bd9Sstevel@tonic-gate  * usage		- Print usage message
15237c478bd9Sstevel@tonic-gate  *
15247c478bd9Sstevel@tonic-gate  */
15257c478bd9Sstevel@tonic-gate static void
usage(void)15267c478bd9Sstevel@tonic-gate usage(void)
15277c478bd9Sstevel@tonic-gate {
15287c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
15297c478bd9Sstevel@tonic-gate 	    "usage:\n"
15307c478bd9Sstevel@tonic-gate 	    "    login [-p] [-d device] [-R repository] [-s service]\n"
15317c478bd9Sstevel@tonic-gate 	    "\t[-t terminal]  [-u identity] [-U ruser]\n"
15327c478bd9Sstevel@tonic-gate 	    "\t[-h hostname [terminal] | -r hostname] [name [environ]...]\n");
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate  * doremoteterm		- Sets the appropriate ioctls for a remote terminal
15387c478bd9Sstevel@tonic-gate  */
15397c478bd9Sstevel@tonic-gate static char	*speeds[] = {
15407c478bd9Sstevel@tonic-gate 	"0", "50", "75", "110", "134", "150", "200", "300",
15417c478bd9Sstevel@tonic-gate 	"600", "1200", "1800", "2400", "4800", "9600", "19200", "38400",
1542de81e71eSTim Marsland 	"57600", "76800", "115200", "153600", "230400", "307200", "460800",
1543d9c3e05cSJoshua M. Clulow 	"921600", "1000000", "1152000", "1500000", "2000000", "2500000",
1544d9c3e05cSJoshua M. Clulow 	"3000000", "3500000", "4000000"
15457c478bd9Sstevel@tonic-gate };
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate #define	NSPEEDS	(sizeof (speeds) / sizeof (speeds[0]))
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate static void
doremoteterm(char * term)15517c478bd9Sstevel@tonic-gate doremoteterm(char *term)
15527c478bd9Sstevel@tonic-gate {
15537c478bd9Sstevel@tonic-gate 	struct termios tp;
15547c478bd9Sstevel@tonic-gate 	char *cp = strchr(term, '/'), **cpp;
15557c478bd9Sstevel@tonic-gate 	char *speed;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	(void) ioctl(0, TCGETS, &tp);
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	if (cp) {
15607c478bd9Sstevel@tonic-gate 		*cp++ = '\0';
15617c478bd9Sstevel@tonic-gate 		speed = cp;
15627c478bd9Sstevel@tonic-gate 		cp = strchr(speed, '/');
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 		if (cp)
15657c478bd9Sstevel@tonic-gate 			*cp++ = '\0';
15667c478bd9Sstevel@tonic-gate 
1567d9c3e05cSJoshua M. Clulow 		for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) {
15687c478bd9Sstevel@tonic-gate 			if (strcmp(*cpp, speed) == 0) {
15697c478bd9Sstevel@tonic-gate 				(void) cfsetospeed(&tp, cpp-speeds);
15707c478bd9Sstevel@tonic-gate 				break;
15717c478bd9Sstevel@tonic-gate 			}
15727c478bd9Sstevel@tonic-gate 		}
1573d9c3e05cSJoshua M. Clulow 	}
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	tp.c_lflag |= ECHO|ICANON;
15767c478bd9Sstevel@tonic-gate 	tp.c_iflag |= IGNPAR|ICRNL;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	(void) ioctl(0, TCSETS, &tp);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate /*
15837c478bd9Sstevel@tonic-gate  * Process_rlogin		- Does the work that rlogin and telnet
15847c478bd9Sstevel@tonic-gate  *				  need done
15857c478bd9Sstevel@tonic-gate  */
15867c478bd9Sstevel@tonic-gate static void
process_rlogin(void)15877c478bd9Sstevel@tonic-gate process_rlogin(void)
15887c478bd9Sstevel@tonic-gate {
15897c478bd9Sstevel@tonic-gate 	/*
15907c478bd9Sstevel@tonic-gate 	 * If a Kerberized rlogin was initiated, then these fields
15917c478bd9Sstevel@tonic-gate 	 * must be read by rlogin daemon itself and passed down via
15927c478bd9Sstevel@tonic-gate 	 * cmd line args.
15937c478bd9Sstevel@tonic-gate 	 */
15947c478bd9Sstevel@tonic-gate 	if (!Uflag && !strlen(rusername))
15957c478bd9Sstevel@tonic-gate 		getstr(rusername, sizeof (rusername), "remuser");
15967c478bd9Sstevel@tonic-gate 	if (!strlen(lusername))
15977c478bd9Sstevel@tonic-gate 		getstr(lusername, sizeof (lusername), "locuser");
15987c478bd9Sstevel@tonic-gate 	if (!tflag && !strlen(terminal))
15997c478bd9Sstevel@tonic-gate 		getstr(terminal, sizeof (terminal), "Terminal type");
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	if (strlen(terminal))
16027c478bd9Sstevel@tonic-gate 		doremoteterm(terminal);
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	/* fflag has precedence over stuff passed by rlogind */
16057c478bd9Sstevel@tonic-gate 	if (fflag || getuid()) {
16067c478bd9Sstevel@tonic-gate 		pwd = &nouser;
16077c478bd9Sstevel@tonic-gate 		return;
16087c478bd9Sstevel@tonic-gate 	} else {
16097c478bd9Sstevel@tonic-gate 		if (pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
16107c478bd9Sstevel@tonic-gate 			login_exit(1);
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 		pwd = getpwnam(lusername);
16137c478bd9Sstevel@tonic-gate 		if (pwd == NULL) {
16147c478bd9Sstevel@tonic-gate 			pwd = &nouser;
16157c478bd9Sstevel@tonic-gate 			return;
16167c478bd9Sstevel@tonic-gate 		}
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	/*
16207c478bd9Sstevel@tonic-gate 	 * Update PAM on the user name
16217c478bd9Sstevel@tonic-gate 	 */
16227c478bd9Sstevel@tonic-gate 	if (strlen(lusername) &&
16237c478bd9Sstevel@tonic-gate 	    pam_set_item(pamh, PAM_USER, lusername) != PAM_SUCCESS)
16247c478bd9Sstevel@tonic-gate 		login_exit(1);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	if (strlen(rusername) &&
16277c478bd9Sstevel@tonic-gate 	    pam_set_item(pamh, PAM_RUSER, rusername) != PAM_SUCCESS)
16287c478bd9Sstevel@tonic-gate 		login_exit(1);
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	SCPYL(user_name, lusername);
16317c478bd9Sstevel@tonic-gate 	envp = &zero;
16327c478bd9Sstevel@tonic-gate 	lusername[0] = '\0';
16337c478bd9Sstevel@tonic-gate }
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate /*
16367c478bd9Sstevel@tonic-gate  *		*** Account validation routines ***
16377c478bd9Sstevel@tonic-gate  *
16387c478bd9Sstevel@tonic-gate  */
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate /*
16417c478bd9Sstevel@tonic-gate  * validate_account		- This is the PAM version of validate.
16427c478bd9Sstevel@tonic-gate  */
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate static void
validate_account(void)16457c478bd9Sstevel@tonic-gate validate_account(void)
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate 	int	error;
16487c478bd9Sstevel@tonic-gate 	int	flag;
16497c478bd9Sstevel@tonic-gate 	int	tries;		/* new password retries */
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	(void) alarm(0);	/* give user time to come up with password */
16527c478bd9Sstevel@tonic-gate 
16532de0a7d6SDan McDonald 	check_log();
16542de0a7d6SDan McDonald 
16557c478bd9Sstevel@tonic-gate 	if (Passreqflag)
16567c478bd9Sstevel@tonic-gate 		flag = PAM_DISALLOW_NULL_AUTHTOK;
16577c478bd9Sstevel@tonic-gate 	else
16587c478bd9Sstevel@tonic-gate 		flag = 0;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	if ((error = pam_acct_mgmt(pamh, flag)) != PAM_SUCCESS) {
16617c478bd9Sstevel@tonic-gate 		if (error == PAM_NEW_AUTHTOK_REQD) {
16627c478bd9Sstevel@tonic-gate 			tries = 1;
16637c478bd9Sstevel@tonic-gate 			error = PAM_AUTHTOK_ERR;
16647c478bd9Sstevel@tonic-gate 			while (error == PAM_AUTHTOK_ERR &&
16657c478bd9Sstevel@tonic-gate 			    tries <= DEF_ATTEMPTS) {
16667c478bd9Sstevel@tonic-gate 				if (tries > 1)
16677c478bd9Sstevel@tonic-gate 					(void) printf("Try again\n\n");
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 				(void) printf("Choose a new password.\n");
16707c478bd9Sstevel@tonic-gate 
1671f00e6aa6Sdarrenm 				error = pam_chauthtok(pamh,
1672f00e6aa6Sdarrenm 				    PAM_CHANGE_EXPIRED_AUTHTOK);
16737c478bd9Sstevel@tonic-gate 				if (error == PAM_TRY_AGAIN) {
16747c478bd9Sstevel@tonic-gate 					(void) sleep(1);
1675f00e6aa6Sdarrenm 					error = pam_chauthtok(pamh,
1676f00e6aa6Sdarrenm 					    PAM_CHANGE_EXPIRED_AUTHTOK);
16777c478bd9Sstevel@tonic-gate 				}
16787c478bd9Sstevel@tonic-gate 				tries++;
16797c478bd9Sstevel@tonic-gate 			}
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 			if (error != PAM_SUCCESS) {
16827c478bd9Sstevel@tonic-gate 				if (dosyslog)
16837c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
16847c478bd9Sstevel@tonic-gate 					    "change password failure: %s",
16857c478bd9Sstevel@tonic-gate 					    pam_strerror(pamh, error));
16867c478bd9Sstevel@tonic-gate 				audit_error = ADT_FAIL_PAM + error;
16877c478bd9Sstevel@tonic-gate 				login_exit(1);
16887c478bd9Sstevel@tonic-gate 			} else {
16897c478bd9Sstevel@tonic-gate 				audit_success(ADT_passwd, pwd, zone_name);
16907c478bd9Sstevel@tonic-gate 			}
16917c478bd9Sstevel@tonic-gate 		} else {
16927c478bd9Sstevel@tonic-gate 			(void) printf(incorrectmsg);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 			if (dosyslog)
16957c478bd9Sstevel@tonic-gate 				syslog(LOG_CRIT,
16967c478bd9Sstevel@tonic-gate 				    "login account failure: %s",
16977c478bd9Sstevel@tonic-gate 				    pam_strerror(pamh, error));
16987c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_PAM + error;
16997c478bd9Sstevel@tonic-gate 			login_exit(1);
17007c478bd9Sstevel@tonic-gate 		}
17017c478bd9Sstevel@tonic-gate 	}
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate /*
17052de0a7d6SDan McDonald  * Check_log	- This is really a hack because PAM checks the log, but login
17062de0a7d6SDan McDonald  *		  wants to know if the log is okay and PAM doesn't have
17072de0a7d6SDan McDonald  *		  a module independent way of handing this info back.
17082de0a7d6SDan McDonald  */
17092de0a7d6SDan McDonald 
17102de0a7d6SDan McDonald static void
check_log(void)17112de0a7d6SDan McDonald check_log(void)
17122de0a7d6SDan McDonald {
17132de0a7d6SDan McDonald 	int fdl;
17142de0a7d6SDan McDonald 	long long offset;
17152de0a7d6SDan McDonald 
17162de0a7d6SDan McDonald 	offset = (long long) pwd->pw_uid * (long long) sizeof (struct lastlog);
17172de0a7d6SDan McDonald 
17182de0a7d6SDan McDonald 	if ((fdl = open(LASTLOG, O_RDWR|O_CREAT, 0444)) >= 0) {
17192de0a7d6SDan McDonald 		if (llseek(fdl, offset, SEEK_SET) == offset &&
17202de0a7d6SDan McDonald 		    read(fdl, (char *)&ll, sizeof (ll)) == sizeof (ll) &&
17212de0a7d6SDan McDonald 		    ll.ll_time != 0)
17222de0a7d6SDan McDonald 			lastlogok = 1;
17232de0a7d6SDan McDonald 		(void) close(fdl);
17242de0a7d6SDan McDonald 	}
17252de0a7d6SDan McDonald }
17262de0a7d6SDan McDonald 
17272de0a7d6SDan McDonald /*
17287c478bd9Sstevel@tonic-gate  * chdir_to_dir_user	- Now chdir after setuid/setgid have happened to
17297c478bd9Sstevel@tonic-gate  *			  place us in the user's home directory just in
17307c478bd9Sstevel@tonic-gate  *			  case it was protected and the first chdir failed.
17317c478bd9Sstevel@tonic-gate  *			  No chdir errors should happen at this point because
17327c478bd9Sstevel@tonic-gate  *			  all failures should have happened on the first
17337c478bd9Sstevel@tonic-gate  *			  time around.
17347c478bd9Sstevel@tonic-gate  */
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate static void
chdir_to_dir_user(void)17377c478bd9Sstevel@tonic-gate chdir_to_dir_user(void)
17387c478bd9Sstevel@tonic-gate {
17397c478bd9Sstevel@tonic-gate 	if (chdir(pwd->pw_dir) < 0) {
17407c478bd9Sstevel@tonic-gate 		if (chdir("/") < 0) {
17417c478bd9Sstevel@tonic-gate 			(void) printf("No directory!\n");
17427c478bd9Sstevel@tonic-gate 			/*
17437c478bd9Sstevel@tonic-gate 			 * This probably won't work since we can't get to /.
17447c478bd9Sstevel@tonic-gate 			 */
17457c478bd9Sstevel@tonic-gate 			if (dosyslog) {
17467c478bd9Sstevel@tonic-gate 				if (remote_host[0]) {
17477c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
17487c478bd9Sstevel@tonic-gate 					    "LOGIN FAILURES ON %s FROM %.*s ",
17497c478bd9Sstevel@tonic-gate 					    " %.*s", ttyn, HMAX,
17507c478bd9Sstevel@tonic-gate 					    remote_host, NMAX, pwd->pw_name);
17517c478bd9Sstevel@tonic-gate 				} else {
17527c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
17537c478bd9Sstevel@tonic-gate 					    "LOGIN FAILURES ON %s, %.*s",
17547c478bd9Sstevel@tonic-gate 					    ttyn, NMAX, pwd->pw_name);
17557c478bd9Sstevel@tonic-gate 				}
17567c478bd9Sstevel@tonic-gate 			}
17577c478bd9Sstevel@tonic-gate 			closelog();
17587c478bd9Sstevel@tonic-gate 			(void) sleep(Disabletime);
17597c478bd9Sstevel@tonic-gate 			exit(1);
17607c478bd9Sstevel@tonic-gate 		} else {
17617c478bd9Sstevel@tonic-gate 			(void) printf("No directory! Logging in with home=/\n");
17627c478bd9Sstevel@tonic-gate 			pwd->pw_dir = "/";
17637c478bd9Sstevel@tonic-gate 		}
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate /*
17697c478bd9Sstevel@tonic-gate  * login_authenticate	- Performs the main authentication work
17707c478bd9Sstevel@tonic-gate  *			  1. Prints the login prompt
17717c478bd9Sstevel@tonic-gate  *			  2. Requests and verifys the password
17727c478bd9Sstevel@tonic-gate  *			  3. Checks the port password
17737c478bd9Sstevel@tonic-gate  */
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate static void
login_authenticate(void)1776032624d5Sbasabi login_authenticate(void)
17777c478bd9Sstevel@tonic-gate {
1778*cbea7acaSDominik Hassler 	const char *user;
17797c478bd9Sstevel@tonic-gate 	int err;
17807c478bd9Sstevel@tonic-gate 	int login_successful = 0;
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	do {
17837c478bd9Sstevel@tonic-gate 		/* if scheme broken, then nothing to do but quit */
1784*cbea7acaSDominik Hassler 		if (pam_get_item(pamh, PAM_USER, (const void **)&user) !=
1785*cbea7acaSDominik Hassler 		    PAM_SUCCESS) {
17867c478bd9Sstevel@tonic-gate 			exit(1);
1787*cbea7acaSDominik Hassler 		}
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 		/*
17907c478bd9Sstevel@tonic-gate 		 * only get name from utility if it is not already
17917c478bd9Sstevel@tonic-gate 		 * supplied by pam_start or a pam_set_item.
17927c478bd9Sstevel@tonic-gate 		 */
17937c478bd9Sstevel@tonic-gate 		if (!user || !user[0]) {
17947c478bd9Sstevel@tonic-gate 			/* use call back to get user name */
17957c478bd9Sstevel@tonic-gate 			get_user_name();
17967c478bd9Sstevel@tonic-gate 		}
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 		err = verify_passwd();
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 		/*
18017c478bd9Sstevel@tonic-gate 		 * If root login and not on system console then call exit(2)
18027c478bd9Sstevel@tonic-gate 		 */
18037c478bd9Sstevel@tonic-gate 		check_for_console();
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 		switch (err) {
18067c478bd9Sstevel@tonic-gate 		case PAM_SUCCESS:
18077c478bd9Sstevel@tonic-gate 		case PAM_NEW_AUTHTOK_REQD:
18087c478bd9Sstevel@tonic-gate 			/*
18097c478bd9Sstevel@tonic-gate 			 * Officially, pam_authenticate() shouldn't return this
18107c478bd9Sstevel@tonic-gate 			 * but it's probably the right thing to return if
18117c478bd9Sstevel@tonic-gate 			 * PAM_DISALLOW_NULL_AUTHTOK is set so the user will
18127c478bd9Sstevel@tonic-gate 			 * be forced to change password later in this code.
18137c478bd9Sstevel@tonic-gate 			 */
18147c478bd9Sstevel@tonic-gate 			count = 0;
18157c478bd9Sstevel@tonic-gate 			login_successful = 1;
18167c478bd9Sstevel@tonic-gate 			break;
18177c478bd9Sstevel@tonic-gate 		case PAM_MAXTRIES:
18187c478bd9Sstevel@tonic-gate 			count = retry;
18197c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
18207c478bd9Sstevel@tonic-gate 		case PAM_AUTH_ERR:
18217c478bd9Sstevel@tonic-gate 		case PAM_AUTHINFO_UNAVAIL:
18227c478bd9Sstevel@tonic-gate 		case PAM_USER_UNKNOWN:
18237c478bd9Sstevel@tonic-gate 			audit_failure(get_audit_id(), ADT_FAIL_PAM + err, pwd,
18247c478bd9Sstevel@tonic-gate 			    remote_host, ttyn, zone_name);
18257c478bd9Sstevel@tonic-gate 			log_bad_attempts();
18267c478bd9Sstevel@tonic-gate 			break;
18277c478bd9Sstevel@tonic-gate 		case PAM_ABORT:
18287c478bd9Sstevel@tonic-gate 			log_bad_attempts();
18297c478bd9Sstevel@tonic-gate 			(void) sleep(Disabletime);
18307c478bd9Sstevel@tonic-gate 			(void) printf(incorrectmsg);
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_PAM + err;
18337c478bd9Sstevel@tonic-gate 			login_exit(1);
18347c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
18357c478bd9Sstevel@tonic-gate 		default:	/* Some other PAM error */
18367c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_PAM + err;
18377c478bd9Sstevel@tonic-gate 			login_exit(1);
18387c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
18397c478bd9Sstevel@tonic-gate 		}
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		if (login_successful)
18427c478bd9Sstevel@tonic-gate 			break;
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 		/* sleep after bad passwd */
18457c478bd9Sstevel@tonic-gate 		if (count)
18467c478bd9Sstevel@tonic-gate 			(void) sleep(Sleeptime);
18477c478bd9Sstevel@tonic-gate 		(void) printf(incorrectmsg);
18487c478bd9Sstevel@tonic-gate 		/* force name to be null in this case */
18497c478bd9Sstevel@tonic-gate 		if (pam_set_item(pamh, PAM_USER, NULL) != PAM_SUCCESS)
18507c478bd9Sstevel@tonic-gate 			login_exit(1);
18517c478bd9Sstevel@tonic-gate 		if (pam_set_item(pamh, PAM_RUSER, NULL) != PAM_SUCCESS)
18527c478bd9Sstevel@tonic-gate 			login_exit(1);
18537c478bd9Sstevel@tonic-gate 	} while (count++ < retry);
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	if (count >= retry) {
18567c478bd9Sstevel@tonic-gate 		audit_failure(get_audit_id(), ADT_FAIL_VALUE_MAX_TRIES, pwd,
18577c478bd9Sstevel@tonic-gate 		    remote_host, ttyn, zone_name);
18587c478bd9Sstevel@tonic-gate 		/*
18597c478bd9Sstevel@tonic-gate 		 * If logging is turned on, output the
18607c478bd9Sstevel@tonic-gate 		 * string storage area to the log file,
18617c478bd9Sstevel@tonic-gate 		 * and sleep for Disabletime
18627c478bd9Sstevel@tonic-gate 		 * seconds before exiting.
18637c478bd9Sstevel@tonic-gate 		 */
18647c478bd9Sstevel@tonic-gate 		if (writelog)
18657c478bd9Sstevel@tonic-gate 			badlogin();
18667c478bd9Sstevel@tonic-gate 		if (dosyslog) {
18677c478bd9Sstevel@tonic-gate 			if ((pwd = getpwnam(user_name)) != NULL) {
18687c478bd9Sstevel@tonic-gate 				if (remote_host[0]) {
18697c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
18702a0352b4Sgww 					    "REPEATED LOGIN FAILURES ON %s "
18712a0352b4Sgww 					    "FROM %.*s, %.*s",
18727c478bd9Sstevel@tonic-gate 					    ttyn, HMAX, remote_host, NMAX,
18737c478bd9Sstevel@tonic-gate 					    user_name);
18747c478bd9Sstevel@tonic-gate 				} else {
18757c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
18762a0352b4Sgww 					    "REPEATED LOGIN FAILURES ON "
18772a0352b4Sgww 					    "%s, %.*s",
18787c478bd9Sstevel@tonic-gate 					    ttyn, NMAX, user_name);
18797c478bd9Sstevel@tonic-gate 				}
18807c478bd9Sstevel@tonic-gate 			} else {
18817c478bd9Sstevel@tonic-gate 				if (remote_host[0]) {
18827c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
18832a0352b4Sgww 					    "REPEATED LOGIN FAILURES ON %s "
18842a0352b4Sgww 					    "FROM %.*s",
18857c478bd9Sstevel@tonic-gate 					    ttyn, HMAX, remote_host);
18867c478bd9Sstevel@tonic-gate 				} else {
18877c478bd9Sstevel@tonic-gate 					syslog(LOG_CRIT,
18882a0352b4Sgww 					    "REPEATED LOGIN FAILURES ON %s",
18892a0352b4Sgww 					    ttyn);
18907c478bd9Sstevel@tonic-gate 				}
18917c478bd9Sstevel@tonic-gate 			}
18927c478bd9Sstevel@tonic-gate 		}
18937c478bd9Sstevel@tonic-gate 		(void) sleep(Disabletime);
18947c478bd9Sstevel@tonic-gate 		exit(1);
18957c478bd9Sstevel@tonic-gate 	}
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate }
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate /*
19007c478bd9Sstevel@tonic-gate  *			*** Credential Related routines ***
19017c478bd9Sstevel@tonic-gate  *
19027c478bd9Sstevel@tonic-gate  */
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate /*
19057c478bd9Sstevel@tonic-gate  * setup_credentials		- sets the group ID, initializes the groups
19067c478bd9Sstevel@tonic-gate  *				  and sets up the secretkey.
19077c478bd9Sstevel@tonic-gate  *				  Exits if a failure occurrs.
19087c478bd9Sstevel@tonic-gate  */
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 
19117c478bd9Sstevel@tonic-gate /*
19127c478bd9Sstevel@tonic-gate  * setup_credentials		- PAM does all the work for us on this one.
19137c478bd9Sstevel@tonic-gate  */
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate static void
setup_credentials(void)19167c478bd9Sstevel@tonic-gate setup_credentials(void)
19177c478bd9Sstevel@tonic-gate {
19187c478bd9Sstevel@tonic-gate 	int	error = 0;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 	/* set the real (and effective) GID */
19217c478bd9Sstevel@tonic-gate 	if (setgid(pwd->pw_gid) == -1) {
19227c478bd9Sstevel@tonic-gate 		login_exit(1);
19237c478bd9Sstevel@tonic-gate 	}
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	/*
19267c478bd9Sstevel@tonic-gate 	 * Initialize the supplementary group access list.
19277c478bd9Sstevel@tonic-gate 	 */
19287c478bd9Sstevel@tonic-gate 	if ((user_name[0] == '\0') ||
19297c478bd9Sstevel@tonic-gate 	    (initgroups(user_name, pwd->pw_gid) == -1)) {
19307c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_VALUE_PROGRAM;
19317c478bd9Sstevel@tonic-gate 		login_exit(1);
19327c478bd9Sstevel@tonic-gate 	}
19337c478bd9Sstevel@tonic-gate 
19341117ab72SJan Friedel 	if ((error = pam_setcred(pamh, zflag ? PAM_REINITIALIZE_CRED :
19351117ab72SJan Friedel 	    PAM_ESTABLISH_CRED)) != PAM_SUCCESS) {
19367c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + error;
19377c478bd9Sstevel@tonic-gate 		login_exit(error);
19387c478bd9Sstevel@tonic-gate 	}
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 	/*
19417c478bd9Sstevel@tonic-gate 	 * Record successful login and fork process that records logout.
19427c478bd9Sstevel@tonic-gate 	 * We have to do this after setting credentials because pam_setcred()
19437c478bd9Sstevel@tonic-gate 	 * loads key audit info into the cred, but before setuid() so audit
19447c478bd9Sstevel@tonic-gate 	 * system calls will work.
19457c478bd9Sstevel@tonic-gate 	 */
19467c478bd9Sstevel@tonic-gate 	audit_success(get_audit_id(), pwd, zone_name);
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate static uint_t
get_audit_id(void)1950032624d5Sbasabi get_audit_id(void)
1951032624d5Sbasabi {
19527c478bd9Sstevel@tonic-gate 	if (rflag)
19537c478bd9Sstevel@tonic-gate 		return (ADT_rlogin);
19547c478bd9Sstevel@tonic-gate 	else if (hflag)
19557c478bd9Sstevel@tonic-gate 		return (ADT_telnet);
19567c478bd9Sstevel@tonic-gate 	else if (zflag)
19577c478bd9Sstevel@tonic-gate 		return (ADT_zlogin);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	return (ADT_login);
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate /*
19637c478bd9Sstevel@tonic-gate  *
19647c478bd9Sstevel@tonic-gate  *		*** Routines to get a new user set up and running ***
19657c478bd9Sstevel@tonic-gate  *
19667c478bd9Sstevel@tonic-gate  *			Things to do when starting up a new user:
19677c478bd9Sstevel@tonic-gate  *				adjust_nice
19687c478bd9Sstevel@tonic-gate  *				update_utmpx_entry
19697c478bd9Sstevel@tonic-gate  *				establish_user_environment
19702de0a7d6SDan McDonald  *				print_banner
19712de0a7d6SDan McDonald  *				display_last_login_time
19727c478bd9Sstevel@tonic-gate  *				exec_the_shell
19737c478bd9Sstevel@tonic-gate  *
19747c478bd9Sstevel@tonic-gate  */
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate /*
19787c478bd9Sstevel@tonic-gate  * adjust_nice		- Set the nice (process priority) value if the
19797c478bd9Sstevel@tonic-gate  *			  gecos value contains an appropriate value.
19807c478bd9Sstevel@tonic-gate  */
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate static void
adjust_nice(void)19837c478bd9Sstevel@tonic-gate adjust_nice(void)
19847c478bd9Sstevel@tonic-gate {
19857c478bd9Sstevel@tonic-gate 	int pri, mflg, i;
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	if (strncmp("pri=", pwd->pw_gecos, 4) == 0) {
19887c478bd9Sstevel@tonic-gate 		pri = 0;
19897c478bd9Sstevel@tonic-gate 		mflg = 0;
19907c478bd9Sstevel@tonic-gate 		i = 4;
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 		if (pwd->pw_gecos[i] == '-') {
19937c478bd9Sstevel@tonic-gate 			mflg++;
19947c478bd9Sstevel@tonic-gate 			i++;
19957c478bd9Sstevel@tonic-gate 		}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 		while (pwd->pw_gecos[i] >= '0' && pwd->pw_gecos[i] <= '9')
19987c478bd9Sstevel@tonic-gate 			pri = (pri * 10) + pwd->pw_gecos[i++] - '0';
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 		if (mflg)
20017c478bd9Sstevel@tonic-gate 			pri = -pri;
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 		(void) nice(pri);
20047c478bd9Sstevel@tonic-gate 	}
20057c478bd9Sstevel@tonic-gate }
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate /*
20087c478bd9Sstevel@tonic-gate  * update_utmpx_entry	- Searchs for the correct utmpx entry, making an
20097c478bd9Sstevel@tonic-gate  *			  entry there if it finds one, otherwise exits.
20107c478bd9Sstevel@tonic-gate  */
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate static void
update_utmpx_entry(int sublogin)20132de0a7d6SDan McDonald update_utmpx_entry(int sublogin)
20147c478bd9Sstevel@tonic-gate {
20157c478bd9Sstevel@tonic-gate 	int err;
2016*cbea7acaSDominik Hassler 	const char *user;
20177c478bd9Sstevel@tonic-gate 	static char *errmsg = "No utmpx entry. "
20187c478bd9Sstevel@tonic-gate 	    "You must exec \"login\" from the lowest level \"shell\".";
20197c478bd9Sstevel@tonic-gate 	int tmplen;
2020*cbea7acaSDominik Hassler 	struct utmpx *u = NULL;
20217c478bd9Sstevel@tonic-gate 	struct utmpx utmpx;
20227c478bd9Sstevel@tonic-gate 	char *ttyntail;
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	/*
20257c478bd9Sstevel@tonic-gate 	 * If we're not a sublogin then
20267c478bd9Sstevel@tonic-gate 	 * we'll get an error back if our PID doesn't match the PID of the
20277c478bd9Sstevel@tonic-gate 	 * entry we are updating, otherwise if its a sublogin the flags
20287c478bd9Sstevel@tonic-gate 	 * field is set to 0, which means we just write a matching entry
20297c478bd9Sstevel@tonic-gate 	 * (without checking the pid), or a new entry if an entry doesn't
20307c478bd9Sstevel@tonic-gate 	 * exist.
20317c478bd9Sstevel@tonic-gate 	 */
20327c478bd9Sstevel@tonic-gate 
20332de0a7d6SDan McDonald 	if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
20347c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + err;
20357c478bd9Sstevel@tonic-gate 		login_exit(1);
20367c478bd9Sstevel@tonic-gate 	}
20377c478bd9Sstevel@tonic-gate 
2038*cbea7acaSDominik Hassler 	if ((err = pam_get_item(pamh, PAM_USER, (const void **)&user)) !=
20397c478bd9Sstevel@tonic-gate 	    PAM_SUCCESS) {
20407c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_PAM + err;
20417c478bd9Sstevel@tonic-gate 		login_exit(1);
20427c478bd9Sstevel@tonic-gate 	}
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 	(void) memset((void *)&utmpx, 0, sizeof (utmpx));
20457c478bd9Sstevel@tonic-gate 	(void) time(&utmpx.ut_tv.tv_sec);
20467c478bd9Sstevel@tonic-gate 	utmpx.ut_pid = getpid();
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	if (rflag || hflag) {
20497c478bd9Sstevel@tonic-gate 		SCPYN(utmpx.ut_host, remote_host);
20507c478bd9Sstevel@tonic-gate 		tmplen = strlen(remote_host) + 1;
20517c478bd9Sstevel@tonic-gate 		if (tmplen < sizeof (utmpx.ut_host))
20527c478bd9Sstevel@tonic-gate 			utmpx.ut_syslen = tmplen;
20537c478bd9Sstevel@tonic-gate 		else
20547c478bd9Sstevel@tonic-gate 			utmpx.ut_syslen = sizeof (utmpx.ut_host);
20557c478bd9Sstevel@tonic-gate 	} else if (zflag) {
20567c478bd9Sstevel@tonic-gate 		/*
20577c478bd9Sstevel@tonic-gate 		 * If this is a login from another zone, put the
20587c478bd9Sstevel@tonic-gate 		 * zone:<zonename> string in the utmpx entry.
20597c478bd9Sstevel@tonic-gate 		 */
20607c478bd9Sstevel@tonic-gate 		SCPYN(utmpx.ut_host, zone_name);
20617c478bd9Sstevel@tonic-gate 		tmplen = strlen(zone_name) + 1;
20627c478bd9Sstevel@tonic-gate 		if (tmplen < sizeof (utmpx.ut_host))
20637c478bd9Sstevel@tonic-gate 			utmpx.ut_syslen = tmplen;
20647c478bd9Sstevel@tonic-gate 		else
20657c478bd9Sstevel@tonic-gate 			utmpx.ut_syslen = sizeof (utmpx.ut_host);
20667c478bd9Sstevel@tonic-gate 	} else {
20677c478bd9Sstevel@tonic-gate 		utmpx.ut_syslen = 0;
20687c478bd9Sstevel@tonic-gate 	}
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	SCPYN(utmpx.ut_user, user);
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	/* skip over "/dev/" */
20737c478bd9Sstevel@tonic-gate 	ttyntail = basename(ttyn);
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	while ((u = getutxent()) != NULL) {
20767c478bd9Sstevel@tonic-gate 		if ((u->ut_type == INIT_PROCESS ||
20777c478bd9Sstevel@tonic-gate 		    u->ut_type == LOGIN_PROCESS ||
20787c478bd9Sstevel@tonic-gate 		    u->ut_type == USER_PROCESS) &&
20797c478bd9Sstevel@tonic-gate 		    ((sublogin && strncmp(u->ut_line, ttyntail,
20807c478bd9Sstevel@tonic-gate 		    sizeof (u->ut_line)) == 0) ||
2081f0243e0aSrz201010 		    u->ut_pid == login_pid)) {
20827c478bd9Sstevel@tonic-gate 			SCPYN(utmpx.ut_line, (ttyn+sizeof ("/dev/")-1));
20837c478bd9Sstevel@tonic-gate 			(void) memcpy(utmpx.ut_id, u->ut_id,
20847c478bd9Sstevel@tonic-gate 			    sizeof (utmpx.ut_id));
20857c478bd9Sstevel@tonic-gate 			utmpx.ut_exit.e_exit = u->ut_exit.e_exit;
20867c478bd9Sstevel@tonic-gate 			utmpx.ut_type = USER_PROCESS;
20877c478bd9Sstevel@tonic-gate 			(void) pututxline(&utmpx);
20887c478bd9Sstevel@tonic-gate 			break;
20897c478bd9Sstevel@tonic-gate 		}
20907c478bd9Sstevel@tonic-gate 	}
20917c478bd9Sstevel@tonic-gate 	endutxent();
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	if (u == (struct utmpx *)NULL) {
20947c478bd9Sstevel@tonic-gate 		if (!sublogin) {
20957c478bd9Sstevel@tonic-gate 			/*
20967c478bd9Sstevel@tonic-gate 			 * no utmpx entry already setup
20977c478bd9Sstevel@tonic-gate 			 * (init or rlogind/telnetd)
20987c478bd9Sstevel@tonic-gate 			 */
20997c478bd9Sstevel@tonic-gate 			(void) puts(errmsg);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 			audit_error = ADT_FAIL_VALUE_PROGRAM;
21027c478bd9Sstevel@tonic-gate 			login_exit(1);
21037c478bd9Sstevel@tonic-gate 		}
21047c478bd9Sstevel@tonic-gate 	} else {
21057c478bd9Sstevel@tonic-gate 		/* Now attempt to write out this entry to the wtmp file if */
21067c478bd9Sstevel@tonic-gate 		/* we were successful in getting it from the utmpx file and */
21077c478bd9Sstevel@tonic-gate 		/* the wtmp file exists.				   */
21087c478bd9Sstevel@tonic-gate 		updwtmpx(WTMPX_FILE, &utmpx);
21097c478bd9Sstevel@tonic-gate 	}
21107c478bd9Sstevel@tonic-gate }
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate /*
21157c478bd9Sstevel@tonic-gate  * process_chroot_logins	- Chroots to the specified subdirectory and
21167c478bd9Sstevel@tonic-gate  *				  re executes login.
21177c478bd9Sstevel@tonic-gate  */
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate static int
process_chroot_logins(void)21207c478bd9Sstevel@tonic-gate process_chroot_logins(void)
21217c478bd9Sstevel@tonic-gate {
21227c478bd9Sstevel@tonic-gate 	/*
21237c478bd9Sstevel@tonic-gate 	 * If the shell field starts with a '*', do a chroot to the home
21247c478bd9Sstevel@tonic-gate 	 * directory and perform a new login.
21257c478bd9Sstevel@tonic-gate 	 */
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 	if (*pwd->pw_shell == '*') {
21287c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, PAM_SUCCESS);	/* Done using PAM */
21297c478bd9Sstevel@tonic-gate 		pamh = NULL;				/* really done */
21307c478bd9Sstevel@tonic-gate 		if (chroot(pwd->pw_dir) < 0) {
21317c478bd9Sstevel@tonic-gate 			(void) printf("No Root Directory\n");
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 			audit_failure(get_audit_id(),
21347c478bd9Sstevel@tonic-gate 			    ADT_FAIL_VALUE_CHDIR_FAILED,
21357c478bd9Sstevel@tonic-gate 			    pwd, remote_host, ttyn, zone_name);
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 			return (ERROR);
21387c478bd9Sstevel@tonic-gate 		}
21397c478bd9Sstevel@tonic-gate 		/*
21407c478bd9Sstevel@tonic-gate 		 * Set the environment flag <!sublogin> so that the next login
21417c478bd9Sstevel@tonic-gate 		 * knows that it is a sublogin.
21427c478bd9Sstevel@tonic-gate 		 */
21437c478bd9Sstevel@tonic-gate 		envinit[0] = SUBLOGIN;
21447c478bd9Sstevel@tonic-gate 		envinit[1] = (char *)NULL;
21457c478bd9Sstevel@tonic-gate 		(void) printf("Subsystem root: %s\n", pwd->pw_dir);
21467c478bd9Sstevel@tonic-gate 		(void) execle("/usr/bin/login", "login", (char *)0,
21477c478bd9Sstevel@tonic-gate 		    &envinit[0]);
21487c478bd9Sstevel@tonic-gate 		(void) execle("/etc/login", "login", (char *)0, &envinit[0]);
21497c478bd9Sstevel@tonic-gate 		(void) printf("No /usr/bin/login or /etc/login on root\n");
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 		audit_error = ADT_FAIL_VALUE_PROGRAM;
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 		login_exit(1);
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate 	return (OK);
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate /*
21597c478bd9Sstevel@tonic-gate  * establish_user_environment	- Set up the new users enviornment
21607c478bd9Sstevel@tonic-gate  */
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate static void
establish_user_environment(char ** renvp)21637c478bd9Sstevel@tonic-gate establish_user_environment(char **renvp)
21647c478bd9Sstevel@tonic-gate {
21657c478bd9Sstevel@tonic-gate 	int i, j, k, l_index, length, idx = 0;
21667c478bd9Sstevel@tonic-gate 	char *endptr;
21677c478bd9Sstevel@tonic-gate 	char **lenvp;
21687c478bd9Sstevel@tonic-gate 	char **pam_env;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 	lenvp = environ;
21717c478bd9Sstevel@tonic-gate 	while (*lenvp++)
21727c478bd9Sstevel@tonic-gate 		;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	/* count the number of PAM environment variables set by modules */
21757c478bd9Sstevel@tonic-gate 	if ((pam_env = pam_getenvlist(pamh)) != 0) {
21767c478bd9Sstevel@tonic-gate 		for (idx = 0; pam_env[idx] != 0; idx++)
21777c478bd9Sstevel@tonic-gate 				;
21787c478bd9Sstevel@tonic-gate 	}
21797c478bd9Sstevel@tonic-gate 
21802a0352b4Sgww 	envinit = (char **)calloc(lenvp - environ + 10 + MAXARGS + idx,
21812a0352b4Sgww 	    sizeof (char *));
21827c478bd9Sstevel@tonic-gate 	if (envinit == NULL) {
21837c478bd9Sstevel@tonic-gate 		(void) printf("Calloc failed - out of swap space.\n");
21847c478bd9Sstevel@tonic-gate 		login_exit(8);
21857c478bd9Sstevel@tonic-gate 	}
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	/*
21887c478bd9Sstevel@tonic-gate 	 * add PAM environment variables first so they
21897c478bd9Sstevel@tonic-gate 	 * can be overwritten at login's discretion.
21907c478bd9Sstevel@tonic-gate 	 * check for illegal environment variables.
21917c478bd9Sstevel@tonic-gate 	 */
21927c478bd9Sstevel@tonic-gate 	idx = 0;	basicenv = 0;
21937c478bd9Sstevel@tonic-gate 	if (pam_env != 0) {
21947c478bd9Sstevel@tonic-gate 		while (pam_env[idx] != 0) {
21957c478bd9Sstevel@tonic-gate 			if (legalenvvar(pam_env[idx])) {
21967c478bd9Sstevel@tonic-gate 				envinit[basicenv] = pam_env[idx];
21977c478bd9Sstevel@tonic-gate 				basicenv++;
21987c478bd9Sstevel@tonic-gate 			}
21997c478bd9Sstevel@tonic-gate 			idx++;
22007c478bd9Sstevel@tonic-gate 		}
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate 	(void) memcpy(&envinit[basicenv], newenv, sizeof (newenv));
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	/* Set up environment */
22057c478bd9Sstevel@tonic-gate 	if (rflag) {
22067c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(term, terminal);
22077c478bd9Sstevel@tonic-gate 	} else if (hflag) {
22087c478bd9Sstevel@tonic-gate 		if (strlen(terminal)) {
22097c478bd9Sstevel@tonic-gate 			ENVSTRNCAT(term, terminal);
22107c478bd9Sstevel@tonic-gate 		}
22117c478bd9Sstevel@tonic-gate 	} else {
22127c478bd9Sstevel@tonic-gate 		char *tp = getenv("TERM");
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 		if ((tp != NULL) && (*tp != '\0'))
22157c478bd9Sstevel@tonic-gate 			ENVSTRNCAT(term, tp);
22167c478bd9Sstevel@tonic-gate 	}
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 	ENVSTRNCAT(logname, pwd->pw_name);
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	/*
22217c478bd9Sstevel@tonic-gate 	 * There are three places to get timezone info.  init.c sets
2222052519c2SGarrett D'Amore 	 * TZ if the file /etc/default/init contains a value for TZ.
22237c478bd9Sstevel@tonic-gate 	 * login.c looks in the file /etc/default/login for a
22247c478bd9Sstevel@tonic-gate 	 * variable called TIMEZONE being set.  If TIMEZONE has a
22257c478bd9Sstevel@tonic-gate 	 *  value, TZ is set to that value; no environment variable
22267c478bd9Sstevel@tonic-gate 	 * TIMEZONE is set, only TZ.  If neither of these methods
22277c478bd9Sstevel@tonic-gate 	 * work to set TZ, then the library routines  will default
22287c478bd9Sstevel@tonic-gate 	 * to using the file /usr/lib/locale/TZ/localtime.
22297c478bd9Sstevel@tonic-gate 	 *
2230052519c2SGarrett D'Amore 	 * There is a priority set up here.  If /etc/default/init has
22317c478bd9Sstevel@tonic-gate 	 * a value for TZ, that value remains top priority.  If the
22327c478bd9Sstevel@tonic-gate 	 * file /etc/default/login has TIMEZONE set, that has second
22337c478bd9Sstevel@tonic-gate 	 * highest priority not overriding the value of TZ in
2234052519c2SGarrett D'Amore 	 * /etc/default/init.  The reason for this priority is that the
2235052519c2SGarrett D'Amore 	 * file /etc/default/init is supposed to be sourced by
22367c478bd9Sstevel@tonic-gate 	 * /etc/profile.  We are doing the "sourcing" prematurely in
22377c478bd9Sstevel@tonic-gate 	 * init.c.  Additionally, a login C shell doesn't source the
2238052519c2SGarrett D'Amore 	 * file /etc/profile thus not sourcing /etc/default/init thus not
22397c478bd9Sstevel@tonic-gate 	 * allowing an adminstrator to globally set TZ for all users
22407c478bd9Sstevel@tonic-gate 	 */
22417c478bd9Sstevel@tonic-gate 	if (Def_tz != NULL)	/* Is there a TZ from defaults/login? */
22427c478bd9Sstevel@tonic-gate 		tmp_tz = Def_tz;
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if ((Def_tz = getenv("TZ")) != NULL) {
22457c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(timez, Def_tz);
22467c478bd9Sstevel@tonic-gate 	} else if (tmp_tz != NULL) {
22477c478bd9Sstevel@tonic-gate 		Def_tz = tmp_tz;
22487c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(timez, Def_tz);
22497c478bd9Sstevel@tonic-gate 	}
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	if (Def_hertz == NULL)
22527c478bd9Sstevel@tonic-gate 		(void) sprintf(hertz + strlen(hertz), "%lu", HZ);
22537c478bd9Sstevel@tonic-gate 	else
22547c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(hertz, Def_hertz);
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	if (Def_path == NULL)
22577c478bd9Sstevel@tonic-gate 		(void) strlcat(path, DEF_PATH, sizeof (path));
22587c478bd9Sstevel@tonic-gate 	else
22597c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(path, Def_path);
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 	ENVSTRNCAT(home, pwd->pw_dir);
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	/*
22647c478bd9Sstevel@tonic-gate 	 * Find the end of the basic environment
22657c478bd9Sstevel@tonic-gate 	 */
22667c478bd9Sstevel@tonic-gate 	for (basicenv = 0; envinit[basicenv] != NULL; basicenv++)
22677c478bd9Sstevel@tonic-gate 		;
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	/*
22707c478bd9Sstevel@tonic-gate 	 * If TZ has a value, add it.
22717c478bd9Sstevel@tonic-gate 	 */
22727c478bd9Sstevel@tonic-gate 	if (strcmp(timez, "TZ=") != 0)
22737c478bd9Sstevel@tonic-gate 		envinit[basicenv++] = timez;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	if (*pwd->pw_shell == '\0') {
22767c478bd9Sstevel@tonic-gate 		/*
22777c478bd9Sstevel@tonic-gate 		 * If possible, use the primary default shell,
22787c478bd9Sstevel@tonic-gate 		 * otherwise, use the secondary one.
22797c478bd9Sstevel@tonic-gate 		 */
22807c478bd9Sstevel@tonic-gate 		if (access(SHELL, X_OK) == 0)
22817c478bd9Sstevel@tonic-gate 			pwd->pw_shell = SHELL;
22827c478bd9Sstevel@tonic-gate 		else
22837c478bd9Sstevel@tonic-gate 			pwd->pw_shell = SHELL2;
22847c478bd9Sstevel@tonic-gate 	} else if (Altshell != NULL && strcmp(Altshell, "YES") == 0) {
22857c478bd9Sstevel@tonic-gate 		envinit[basicenv++] = shell;
22867c478bd9Sstevel@tonic-gate 		ENVSTRNCAT(shell, pwd->pw_shell);
22877c478bd9Sstevel@tonic-gate 	}
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate #ifndef	NO_MAIL
22907c478bd9Sstevel@tonic-gate 	envinit[basicenv++] = mail;
22917c478bd9Sstevel@tonic-gate 	(void) strlcat(mail, pwd->pw_name, sizeof (mail));
22927c478bd9Sstevel@tonic-gate #endif
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 	/*
22957c478bd9Sstevel@tonic-gate 	 * Pick up locale environment variables, if any.
22967c478bd9Sstevel@tonic-gate 	 */
22977c478bd9Sstevel@tonic-gate 	lenvp = renvp;
22987c478bd9Sstevel@tonic-gate 	while (*lenvp != NULL) {
22997c478bd9Sstevel@tonic-gate 		j = 0;
23007c478bd9Sstevel@tonic-gate 		while (localeenv[j] != 0) {
23017c478bd9Sstevel@tonic-gate 			/*
23027c478bd9Sstevel@tonic-gate 			 * locale_envmatch() returns 1 if
23037c478bd9Sstevel@tonic-gate 			 * *lenvp is localenev[j] and valid.
23047c478bd9Sstevel@tonic-gate 			 */
23057c478bd9Sstevel@tonic-gate 			if (locale_envmatch(localeenv[j], *lenvp) == 1) {
23067c478bd9Sstevel@tonic-gate 				envinit[basicenv++] = *lenvp;
23077c478bd9Sstevel@tonic-gate 				break;
23087c478bd9Sstevel@tonic-gate 			}
23097c478bd9Sstevel@tonic-gate 			j++;
23107c478bd9Sstevel@tonic-gate 		}
23117c478bd9Sstevel@tonic-gate 		lenvp++;
23127c478bd9Sstevel@tonic-gate 	}
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	/*
23157c478bd9Sstevel@tonic-gate 	 * If '-p' flag, then try to pass on allowable environment
23167c478bd9Sstevel@tonic-gate 	 * variables.  Note that by processing this first, what is
23177c478bd9Sstevel@tonic-gate 	 * passed on the final "login:" line may over-ride the invocation
23187c478bd9Sstevel@tonic-gate 	 * values.  XXX is this correct?
23197c478bd9Sstevel@tonic-gate 	 */
23207c478bd9Sstevel@tonic-gate 	if (pflag) {
23217c478bd9Sstevel@tonic-gate 		for (lenvp = renvp; *lenvp; lenvp++) {
23227c478bd9Sstevel@tonic-gate 			if (!legalenvvar(*lenvp)) {
23237c478bd9Sstevel@tonic-gate 				continue;
23247c478bd9Sstevel@tonic-gate 			}
23257c478bd9Sstevel@tonic-gate 			/*
23267c478bd9Sstevel@tonic-gate 			 * If this isn't 'xxx=yyy', skip it.  XXX
23277c478bd9Sstevel@tonic-gate 			 */
23287c478bd9Sstevel@tonic-gate 			if ((endptr = strchr(*lenvp, '=')) == NULL) {
23297c478bd9Sstevel@tonic-gate 				continue;
23307c478bd9Sstevel@tonic-gate 			}
23317c478bd9Sstevel@tonic-gate 			length = endptr + 1 - *lenvp;
23327c478bd9Sstevel@tonic-gate 			for (j = 0; j < basicenv; j++) {
23337c478bd9Sstevel@tonic-gate 				if (strncmp(envinit[j], *lenvp, length) == 0) {
23347c478bd9Sstevel@tonic-gate 					/*
23357c478bd9Sstevel@tonic-gate 					 * Replace previously established value
23367c478bd9Sstevel@tonic-gate 					 */
23377c478bd9Sstevel@tonic-gate 					envinit[j] = *lenvp;
23387c478bd9Sstevel@tonic-gate 					break;
23397c478bd9Sstevel@tonic-gate 				}
23407c478bd9Sstevel@tonic-gate 			}
23417c478bd9Sstevel@tonic-gate 			if (j == basicenv) {
23427c478bd9Sstevel@tonic-gate 				/*
23437c478bd9Sstevel@tonic-gate 				 * It's a new definition, so add it at the end.
23447c478bd9Sstevel@tonic-gate 				 */
23457c478bd9Sstevel@tonic-gate 				envinit[basicenv++] = *lenvp;
23467c478bd9Sstevel@tonic-gate 			}
23477c478bd9Sstevel@tonic-gate 		}
23487c478bd9Sstevel@tonic-gate 	}
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	/*
23517c478bd9Sstevel@tonic-gate 	 * Add in all the environment variables picked up from the
23527c478bd9Sstevel@tonic-gate 	 * argument list to "login" or from the user response to the
23537c478bd9Sstevel@tonic-gate 	 * "login" request, if any.
23547c478bd9Sstevel@tonic-gate 	 */
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 	if (envp == NULL)
23577c478bd9Sstevel@tonic-gate 		goto switch_env;	/* done */
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 	for (j = 0, k = 0, l_index = 0;
23607c478bd9Sstevel@tonic-gate 	    *envp != NULL && j < (MAXARGS-1);
23617c478bd9Sstevel@tonic-gate 	    j++, envp++) {
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 		/*
23647c478bd9Sstevel@tonic-gate 		 * Scan each string provided.  If it doesn't have the
23657c478bd9Sstevel@tonic-gate 		 * format xxx=yyy, then add the string "Ln=" to the beginning.
23667c478bd9Sstevel@tonic-gate 		 */
23677c478bd9Sstevel@tonic-gate 		if ((endptr = strchr(*envp, '=')) == NULL) {
23687c478bd9Sstevel@tonic-gate 			/*
23697c478bd9Sstevel@tonic-gate 			 * This much to be malloc'd:
23707c478bd9Sstevel@tonic-gate 			 *   strlen(*envp) + 1 char for 'L' +
23717c478bd9Sstevel@tonic-gate 			 *   MAXARGSWIDTH + 1 char for '=' + 1 for null char;
23727c478bd9Sstevel@tonic-gate 			 *
23737c478bd9Sstevel@tonic-gate 			 * total = strlen(*envp) + MAXARGSWIDTH + 3
23747c478bd9Sstevel@tonic-gate 			 */
23757c478bd9Sstevel@tonic-gate 			int total = strlen(*envp) + MAXARGSWIDTH + 3;
23767c478bd9Sstevel@tonic-gate 			envinit[basicenv+k] = malloc(total);
23777c478bd9Sstevel@tonic-gate 			if (envinit[basicenv+k] == NULL) {
23787c478bd9Sstevel@tonic-gate 				(void) printf("%s: malloc failed\n", PROG_NAME);
23797c478bd9Sstevel@tonic-gate 				login_exit(1);
23807c478bd9Sstevel@tonic-gate 			}
23817c478bd9Sstevel@tonic-gate 			(void) snprintf(envinit[basicenv+k], total, "L%d=%s",
23827c478bd9Sstevel@tonic-gate 			    l_index, *envp);
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 			k++;
23857c478bd9Sstevel@tonic-gate 			l_index++;
23867c478bd9Sstevel@tonic-gate 		} else  {
23877c478bd9Sstevel@tonic-gate 			if (!legalenvvar(*envp)) { /* this env var permited? */
23887c478bd9Sstevel@tonic-gate 				continue;
23897c478bd9Sstevel@tonic-gate 			} else {
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 				/*
23927c478bd9Sstevel@tonic-gate 				 * Check to see whether this string replaces
23937c478bd9Sstevel@tonic-gate 				 * any previously defined string
23947c478bd9Sstevel@tonic-gate 				 */
23957c478bd9Sstevel@tonic-gate 				for (i = 0, length = endptr + 1 - *envp;
23967c478bd9Sstevel@tonic-gate 				    i < basicenv + k; i++) {
23977c478bd9Sstevel@tonic-gate 					if (strncmp(*envp, envinit[i], length)
23987c478bd9Sstevel@tonic-gate 					    == 0) {
23997c478bd9Sstevel@tonic-gate 						envinit[i] = *envp;
24007c478bd9Sstevel@tonic-gate 						break;
24017c478bd9Sstevel@tonic-gate 					}
24027c478bd9Sstevel@tonic-gate 				}
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 				/*
24057c478bd9Sstevel@tonic-gate 				 * If it doesn't, place it at the end of
24067c478bd9Sstevel@tonic-gate 				 * environment array.
24077c478bd9Sstevel@tonic-gate 				 */
24087c478bd9Sstevel@tonic-gate 				if (i == basicenv+k) {
24097c478bd9Sstevel@tonic-gate 					envinit[basicenv+k] = *envp;
24107c478bd9Sstevel@tonic-gate 					k++;
24117c478bd9Sstevel@tonic-gate 				}
24127c478bd9Sstevel@tonic-gate 			}
24137c478bd9Sstevel@tonic-gate 		}
24147c478bd9Sstevel@tonic-gate 	}		/* for (j = 0 ... ) */
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate switch_env:
24177c478bd9Sstevel@tonic-gate 	/*
24187c478bd9Sstevel@tonic-gate 	 * Switch to the new environment.
24197c478bd9Sstevel@tonic-gate 	 */
24207c478bd9Sstevel@tonic-gate 	environ = envinit;
24217c478bd9Sstevel@tonic-gate }
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate /*
24242de0a7d6SDan McDonald  * print_banner		- Print the banner at start up
24252de0a7d6SDan McDonald  *			   Do not turn on DOBANNER ifdef.  This is not
24262de0a7d6SDan McDonald  *			   relevant to SunOS.
24272de0a7d6SDan McDonald  */
24282de0a7d6SDan McDonald 
24292de0a7d6SDan McDonald static void
print_banner(void)24302de0a7d6SDan McDonald print_banner(void)
24312de0a7d6SDan McDonald {
24322de0a7d6SDan McDonald #ifdef DOBANNER
24332de0a7d6SDan McDonald 	uname(&un);
24342de0a7d6SDan McDonald #if i386
24352de0a7d6SDan McDonald 	(void) printf("UNIX System V/386 Release %s\n%s\n"
24362de0a7d6SDan McDonald 	    "Copyright (C) 1984, 1986, 1987, 1988 AT&T\n"
24372de0a7d6SDan McDonald 	    "Copyright (C) 1987, 1988 Microsoft Corp.\nAll Rights Reserved\n",
24382de0a7d6SDan McDonald 	    un.release, un.nodename);
24392de0a7d6SDan McDonald #elif sun
24402de0a7d6SDan McDonald 	(void) printf("SunOS Release %s Sun Microsystems %s\n%s\n"
24412de0a7d6SDan McDonald 	    "Copyright (c) 1984, 1986, 1987, 1988 AT&T\n"
24422de0a7d6SDan McDonald 	    "Copyright (c) 1988, 1989, 1990, 1991 Sun Microsystems\n"
24432de0a7d6SDan McDonald 	    "All Rights Reserved\n",
24442de0a7d6SDan McDonald 	    un.release, un.machine, un.nodename);
24452de0a7d6SDan McDonald #else
24462de0a7d6SDan McDonald 	(void) printf("UNIX System V Release %s AT&T %s\n%s\n"
24472de0a7d6SDan McDonald 	    "Copyright (c) 1984, 1986, 1987, 1988 AT&T\nAll Rights Reserved\n",
24482de0a7d6SDan McDonald 	    un.release, un.machine, un.nodename);
24492de0a7d6SDan McDonald #endif /* i386 */
24502de0a7d6SDan McDonald #endif /* DOBANNER */
24512de0a7d6SDan McDonald }
24522de0a7d6SDan McDonald 
24532de0a7d6SDan McDonald /*
24542de0a7d6SDan McDonald  * display_last_login_time	- Advise the user the time and date
24552de0a7d6SDan McDonald  *				  that this login-id was last used.
24562de0a7d6SDan McDonald  */
24572de0a7d6SDan McDonald 
24582de0a7d6SDan McDonald static void
display_last_login_time(void)24592de0a7d6SDan McDonald display_last_login_time(void)
24602de0a7d6SDan McDonald {
24612de0a7d6SDan McDonald 	if (lastlogok) {
24622de0a7d6SDan McDonald 		(void) printf("Last login: %.*s ", 24-5, ctime(&ll.ll_time));
24632de0a7d6SDan McDonald 
24642de0a7d6SDan McDonald 		if (*ll.ll_host != '\0')
24652de0a7d6SDan McDonald 			(void) printf("from %.*s\n", sizeof (ll.ll_host),
24662de0a7d6SDan McDonald 			    ll.ll_host);
24672de0a7d6SDan McDonald 		else
24682de0a7d6SDan McDonald 			(void) printf("on %.*s\n", sizeof (ll.ll_line),
24692de0a7d6SDan McDonald 			    ll.ll_line);
24702de0a7d6SDan McDonald 	}
24712de0a7d6SDan McDonald }
24722de0a7d6SDan McDonald 
24732de0a7d6SDan McDonald /*
24747c478bd9Sstevel@tonic-gate  * exec_the_shell	- invoke the specified shell or start up program
24757c478bd9Sstevel@tonic-gate  */
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate static void
exec_the_shell(void)24787c478bd9Sstevel@tonic-gate exec_the_shell(void)
24797c478bd9Sstevel@tonic-gate {
24807c478bd9Sstevel@tonic-gate 	char *endptr;
24817c478bd9Sstevel@tonic-gate 	int i;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	(void) strlcat(minusnam, basename(pwd->pw_shell),
24847c478bd9Sstevel@tonic-gate 	    sizeof (minusnam));
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	/*
24877c478bd9Sstevel@tonic-gate 	 * Exec the shell
24887c478bd9Sstevel@tonic-gate 	 */
24897c478bd9Sstevel@tonic-gate 	(void) execl(pwd->pw_shell, minusnam, (char *)0);
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/*
24927c478bd9Sstevel@tonic-gate 	 * pwd->pw_shell was not an executable object file, maybe it
24937c478bd9Sstevel@tonic-gate 	 * is a shell proceedure or a command line with arguments.
24947c478bd9Sstevel@tonic-gate 	 * If so, turn off the SHELL= environment variable.
24957c478bd9Sstevel@tonic-gate 	 */
24967c478bd9Sstevel@tonic-gate 	for (i = 0; envinit[i] != NULL; ++i) {
24977c478bd9Sstevel@tonic-gate 		if ((envinit[i] == shell) &&
24987c478bd9Sstevel@tonic-gate 		    ((endptr = strchr(shell, '=')) != NULL))
24997c478bd9Sstevel@tonic-gate 			(*++endptr) = '\0';
25007c478bd9Sstevel@tonic-gate 		}
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	if (access(pwd->pw_shell, R_OK|X_OK) == 0) {
25037c478bd9Sstevel@tonic-gate 		(void) execl(SHELL, "sh", pwd->pw_shell, (char *)0);
25047c478bd9Sstevel@tonic-gate 		(void) execl(SHELL2, "sh", pwd->pw_shell, (char *)0);
25057c478bd9Sstevel@tonic-gate 	}
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 	(void) printf("No shell\n");
25087c478bd9Sstevel@tonic-gate }
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate /*
25117c478bd9Sstevel@tonic-gate  * login_exit		- Call exit()  and terminate.
25127c478bd9Sstevel@tonic-gate  *			  This function is here for PAM so cleanup can
25137c478bd9Sstevel@tonic-gate  *			  be done before the process exits.
25147c478bd9Sstevel@tonic-gate  */
25157c478bd9Sstevel@tonic-gate static void
login_exit(int exit_code)25167c478bd9Sstevel@tonic-gate login_exit(int exit_code)
25177c478bd9Sstevel@tonic-gate {
25187c478bd9Sstevel@tonic-gate 	if (pamh)
25197c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, PAM_ABORT);
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	if (audit_error)
25227c478bd9Sstevel@tonic-gate 		audit_failure(get_audit_id(), audit_error,
25237c478bd9Sstevel@tonic-gate 		    pwd, remote_host, ttyn, zone_name);
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate 	exit(exit_code);
25267c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
25277c478bd9Sstevel@tonic-gate }
25287c478bd9Sstevel@tonic-gate 
25297c478bd9Sstevel@tonic-gate /*
25307c478bd9Sstevel@tonic-gate  * Check if lenv and penv matches or not.
25317c478bd9Sstevel@tonic-gate  */
25327c478bd9Sstevel@tonic-gate static int
locale_envmatch(char * lenv,char * penv)25337c478bd9Sstevel@tonic-gate locale_envmatch(char *lenv, char *penv)
25347c478bd9Sstevel@tonic-gate {
25357c478bd9Sstevel@tonic-gate 	while ((*lenv == *penv) && *lenv && *penv != '=') {
25367c478bd9Sstevel@tonic-gate 		lenv++;
25377c478bd9Sstevel@tonic-gate 		penv++;
25387c478bd9Sstevel@tonic-gate 	}
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	/*
25417c478bd9Sstevel@tonic-gate 	 * '/' is eliminated for security reason.
25427c478bd9Sstevel@tonic-gate 	 */
25437c478bd9Sstevel@tonic-gate 	if (*lenv == '\0' && *penv == '=' && *(penv + 1) != '/')
25447c478bd9Sstevel@tonic-gate 		return (1);
25457c478bd9Sstevel@tonic-gate 	return (0);
25467c478bd9Sstevel@tonic-gate }
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate static int
is_number(char * ptr)25497c478bd9Sstevel@tonic-gate is_number(char *ptr)
25507c478bd9Sstevel@tonic-gate {
25517c478bd9Sstevel@tonic-gate 	while (*ptr != '\0') {
25527c478bd9Sstevel@tonic-gate 		if (!isdigit(*ptr))
25537c478bd9Sstevel@tonic-gate 			return (0);
25547c478bd9Sstevel@tonic-gate 		ptr++;
25557c478bd9Sstevel@tonic-gate 	}
25567c478bd9Sstevel@tonic-gate 	return (1);
25577c478bd9Sstevel@tonic-gate }
2558