xref: /onnv-gate/usr/src/lib/pam_modules/unix_cred/unix_cred.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51590Scasper  * Common Development and Distribution License (the "License").
61590Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212143Sgww@eng.sun.com  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <nss_dbdefs.h>
260Sstevel@tonic-gate #include <pwd.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <syslog.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <auth_attr.h>
320Sstevel@tonic-gate #include <deflt.h>
330Sstevel@tonic-gate #include <priv.h>
340Sstevel@tonic-gate #include <secdb.h>
350Sstevel@tonic-gate #include <user_attr.h>
360Sstevel@tonic-gate #include <sys/task.h>
370Sstevel@tonic-gate #include <libintl.h>
380Sstevel@tonic-gate #include <project.h>
390Sstevel@tonic-gate #include <errno.h>
401590Scasper #include <alloca.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <bsm/adt.h>
430Sstevel@tonic-gate #include <bsm/adt_event.h>	/* adt_get_auid() */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <security/pam_appl.h>
460Sstevel@tonic-gate #include <security/pam_modules.h>
470Sstevel@tonic-gate #include <security/pam_impl.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #define	PROJECT		"project="
500Sstevel@tonic-gate #define	PROJSZ		(sizeof (PROJECT) - 1)
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  *	unix_cred - PAM auth modules must contain both pam_sm_authenticate
540Sstevel@tonic-gate  *		and pam_sm_setcred.  Some other auth module is responsible
550Sstevel@tonic-gate  *		for authentication (e.g., pam_unix_auth.so), this module
560Sstevel@tonic-gate  *		only implements pam_sm_setcred so that the authentication
570Sstevel@tonic-gate  *		can be separated without knowledge of the Solaris Unix style
580Sstevel@tonic-gate  *		credential setting.
590Sstevel@tonic-gate  *		Solaris Unix style credential setting includes initializing
600Sstevel@tonic-gate  *		the audit characteristics if not already initialized and
610Sstevel@tonic-gate  *		setting the user's default and limit privileges.
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  *	unix_cred - pam_sm_authenticate
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  *	Returns	PAM_IGNORE.
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*ARGSUSED*/
710Sstevel@tonic-gate int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)720Sstevel@tonic-gate pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	return (PAM_IGNORE);
750Sstevel@tonic-gate }
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
78*12273SCasper.Dik@Sun.COM  * Set the privilege set.  The attributes are enumerated by _enum_attrs,
79*12273SCasper.Dik@Sun.COM  * including the attribues user_attr, prof_attr and policy.conf
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate static int
getset(char * str,priv_set_t ** res)82*12273SCasper.Dik@Sun.COM getset(char *str, priv_set_t **res)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	priv_set_t *tmp;
851590Scasper 	char *badp;
861590Scasper 	int len;
870Sstevel@tonic-gate 
88*12273SCasper.Dik@Sun.COM 	if (str == NULL)
890Sstevel@tonic-gate 		return (0);
900Sstevel@tonic-gate 
911590Scasper 	len = strlen(str) + 1;
921590Scasper 	badp = alloca(len);
931590Scasper 	(void) memset(badp, '\0', len);
941590Scasper 	do {
951590Scasper 		const char *q, *endp;
961590Scasper 		tmp = priv_str_to_set(str, ",", &endp);
971590Scasper 		if (tmp == NULL) {
981590Scasper 			if (endp == NULL)
991590Scasper 				break;
1001590Scasper 
1011590Scasper 			/* Now remove the bad privilege endp points to */
1021590Scasper 			q = strchr(endp, ',');
1031590Scasper 			if (q == NULL)
1041590Scasper 				q = endp + strlen(endp);
1051590Scasper 
1061590Scasper 			if (*badp != '\0')
1071590Scasper 				(void) strlcat(badp, ",", len);
1081590Scasper 			/* Memset above guarantees NUL termination */
1091590Scasper 			/* LINTED */
1101590Scasper 			(void) strncat(badp, endp, q - endp);
1111590Scasper 			/* excise bad privilege; strtok ignores 2x sep */
1121590Scasper 			(void) memmove((void *)endp, q, strlen(q) + 1);
1131590Scasper 		}
1141590Scasper 	} while (tmp == NULL && *str != '\0');
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if (tmp == NULL) {
1170Sstevel@tonic-gate 		syslog(LOG_AUTH|LOG_ERR,
1181590Scasper 		    "pam_setcred: can't parse privilege specification: %m\n");
1190Sstevel@tonic-gate 		return (-1);
1201590Scasper 	} else if (*badp != '\0') {
1211590Scasper 		syslog(LOG_AUTH|LOG_DEBUG,
1221590Scasper 		    "pam_setcred: unrecognized privilege(s): %s\n", badp);
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 	*res = tmp;
1250Sstevel@tonic-gate 	return (0);
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate 
128*12273SCasper.Dik@Sun.COM typedef struct deflim {
129*12273SCasper.Dik@Sun.COM 	char *def;
130*12273SCasper.Dik@Sun.COM 	char *lim;
131*12273SCasper.Dik@Sun.COM } deflim_t;
132*12273SCasper.Dik@Sun.COM 
133*12273SCasper.Dik@Sun.COM /*ARGSUSED*/
134*12273SCasper.Dik@Sun.COM static int
finddeflim(const char * name,kva_t * kva,void * ctxt,void * pres)135*12273SCasper.Dik@Sun.COM finddeflim(const char *name, kva_t *kva, void *ctxt, void *pres)
136*12273SCasper.Dik@Sun.COM {
137*12273SCasper.Dik@Sun.COM 	deflim_t *pdef = pres;
138*12273SCasper.Dik@Sun.COM 	char *val;
139*12273SCasper.Dik@Sun.COM 
140*12273SCasper.Dik@Sun.COM 	if (pdef->def == NULL) {
141*12273SCasper.Dik@Sun.COM 		val = kva_match(kva, USERATTR_DFLTPRIV_KW);
142*12273SCasper.Dik@Sun.COM 		if (val != NULL)
143*12273SCasper.Dik@Sun.COM 			pdef->def = strdup(val);
144*12273SCasper.Dik@Sun.COM 	}
145*12273SCasper.Dik@Sun.COM 	if (pdef->lim == NULL) {
146*12273SCasper.Dik@Sun.COM 		val = kva_match(kva, USERATTR_LIMPRIV_KW);
147*12273SCasper.Dik@Sun.COM 		if (val != NULL)
148*12273SCasper.Dik@Sun.COM 			pdef->lim = strdup(val);
149*12273SCasper.Dik@Sun.COM 	}
150*12273SCasper.Dik@Sun.COM 	return (pdef->lim != NULL && pdef->def != NULL);
151*12273SCasper.Dik@Sun.COM }
152*12273SCasper.Dik@Sun.COM 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  *	unix_cred - pam_sm_setcred
1550Sstevel@tonic-gate  *
1560Sstevel@tonic-gate  *	Entry flags = 	PAM_ESTABLISH_CRED, set up Solaris Unix cred.
1570Sstevel@tonic-gate  *			PAM_DELETE_CRED, NOP, return PAM_SUCCESS.
1580Sstevel@tonic-gate  *			PAM_REINITIALIZE_CRED, set up Solaris Unix cred,
1590Sstevel@tonic-gate  *				or merge the current context with the new
1600Sstevel@tonic-gate  *				user.
1610Sstevel@tonic-gate  *			PAM_REFRESH_CRED, set up Solaris Unix cred.
1620Sstevel@tonic-gate  *			PAM_SILENT, print no messages to user.
1630Sstevel@tonic-gate  *
1640Sstevel@tonic-gate  *	Returns	PAM_SUCCESS, if all successful.
1650Sstevel@tonic-gate  *		PAM_CRED_ERR, if unable to set credentials.
1660Sstevel@tonic-gate  *		PAM_USER_UNKNOWN, if PAM_USER not set, or unable to find
1670Sstevel@tonic-gate  *			user in databases.
1680Sstevel@tonic-gate  *		PAM_SYSTEM_ERR, if no valid flag, or unable to get/set
1690Sstevel@tonic-gate  *			user's audit state.
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)1730Sstevel@tonic-gate pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	int	i;
1760Sstevel@tonic-gate 	int	debug = 0;
1770Sstevel@tonic-gate 	uint_t	nowarn = flags & PAM_SILENT;
1780Sstevel@tonic-gate 	int	ret = PAM_SUCCESS;
1790Sstevel@tonic-gate 	char	*user;
1802815Sgww 	char	*auser;
1810Sstevel@tonic-gate 	char	*rhost;
1820Sstevel@tonic-gate 	char	*tty;
1830Sstevel@tonic-gate 	au_id_t	auid;
1840Sstevel@tonic-gate 	adt_session_data_t *ah;
1850Sstevel@tonic-gate 	adt_termid_t	*termid = NULL;
1861590Scasper 	priv_set_t	*lim, *def, *tset;
1870Sstevel@tonic-gate 	char		messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
1880Sstevel@tonic-gate 	char		buf[PROJECT_BUFSZ];
1890Sstevel@tonic-gate 	struct project	proj, *pproj;
1900Sstevel@tonic-gate 	int		error;
1910Sstevel@tonic-gate 	char		*projname;
1920Sstevel@tonic-gate 	char		*kvs;
1930Sstevel@tonic-gate 	struct passwd	pwd;
1940Sstevel@tonic-gate 	char		pwbuf[NSS_BUFLEN_PASSWD];
195*12273SCasper.Dik@Sun.COM 	deflim_t	deflim;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
1980Sstevel@tonic-gate 		if (strcmp(argv[i], "debug") == 0)
1990Sstevel@tonic-gate 			debug = 1;
2000Sstevel@tonic-gate 		else if (strcmp(argv[i], "nowarn") == 0)
2010Sstevel@tonic-gate 			nowarn |= 1;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (debug)
2050Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_DEBUG,
2060Sstevel@tonic-gate 		    "pam_unix_cred: pam_sm_setcred(flags = %x, argc= %d)",
2070Sstevel@tonic-gate 		    flags, argc);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	if (user == NULL || *user == '\0') {
2120Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
2130Sstevel@tonic-gate 		    "pam_unix_cred: USER NULL or empty!\n");
2140Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
2150Sstevel@tonic-gate 	}
2162815Sgww 	(void) pam_get_item(pamh, PAM_AUSER, (void **)&auser);
2170Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_RHOST, (void **)&rhost);
2180Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_TTY, (void **)&tty);
2190Sstevel@tonic-gate 	if (debug)
2200Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_DEBUG,
2212815Sgww 		    "pam_unix_cred: user = %s, auser = %s, rhost = %s, "
2220Sstevel@tonic-gate 		    "tty = %s", user,
2232815Sgww 		    (auser == NULL) ? "NULL" : (*auser == '\0') ? "ZERO" :
2242815Sgww 		    auser,
2250Sstevel@tonic-gate 		    (rhost == NULL) ? "NULL" : (*rhost == '\0') ? "ZERO" :
2260Sstevel@tonic-gate 		    rhost,
2270Sstevel@tonic-gate 		    (tty == NULL) ? "NULL" : (*tty == '\0') ? "ZERO" :
2280Sstevel@tonic-gate 		    tty);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	/* validate flags */
2310Sstevel@tonic-gate 	switch (flags & (PAM_ESTABLISH_CRED | PAM_DELETE_CRED |
2320Sstevel@tonic-gate 	    PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED)) {
2330Sstevel@tonic-gate 	case 0:
2340Sstevel@tonic-gate 		/* set default flag */
2350Sstevel@tonic-gate 		flags |= PAM_ESTABLISH_CRED;
2360Sstevel@tonic-gate 		break;
2370Sstevel@tonic-gate 	case PAM_ESTABLISH_CRED:
2380Sstevel@tonic-gate 	case PAM_REINITIALIZE_CRED:
2390Sstevel@tonic-gate 	case PAM_REFRESH_CRED:
2400Sstevel@tonic-gate 		break;
2410Sstevel@tonic-gate 	case PAM_DELETE_CRED:
2420Sstevel@tonic-gate 		return (PAM_SUCCESS);
2430Sstevel@tonic-gate 	default:
2440Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
2450Sstevel@tonic-gate 		    "pam_unix_cred: invalid flags %x", flags);
2460Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * if auditing on and process audit state not set,
2510Sstevel@tonic-gate 	 * setup audit context for process.
2520Sstevel@tonic-gate 	 */
2530Sstevel@tonic-gate 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
2540Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
2550Sstevel@tonic-gate 		    "pam_unix_cred: cannot create start audit session %m");
2560Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 	adt_get_auid(ah, &auid);
2590Sstevel@tonic-gate 	if (debug) {
2600Sstevel@tonic-gate 		int	auditstate;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		if (auditon(A_GETCOND, (caddr_t)&auditstate,
2630Sstevel@tonic-gate 		    sizeof (auditstate)) != 0) {
2640Sstevel@tonic-gate 			auditstate = AUC_DISABLED;
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_DEBUG,
2670Sstevel@tonic-gate 		    "pam_unix_cred: state = %d, auid = %d", auditstate,
2680Sstevel@tonic-gate 		    auid);
2690Sstevel@tonic-gate 	}
270498Sgww 	if (getpwnam_r(user, &pwd, pwbuf, sizeof (pwbuf)) == NULL) {
2710Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
2720Sstevel@tonic-gate 		    "pam_unix_cred: cannot get passwd entry for user = %s",
2730Sstevel@tonic-gate 		    user);
2740Sstevel@tonic-gate 		ret = PAM_USER_UNKNOWN;
2750Sstevel@tonic-gate 		goto adt_done;
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2781114Sgww 	if ((auid == AU_NOAUDITID) &&
2791114Sgww 	    (flags & PAM_ESTABLISH_CRED)) {
2802815Sgww 		struct passwd	apwd;
2812815Sgww 		char	apwbuf[NSS_BUFLEN_PASSWD];
2820Sstevel@tonic-gate 
2839138SJoep.Vesseur@Sun.COM 		errno = 0;
2840Sstevel@tonic-gate 		if ((rhost == NULL || *rhost == '\0')) {
2850Sstevel@tonic-gate 			if (adt_load_ttyname(tty, &termid) != 0) {
28612143Sgww@eng.sun.com 				if (errno == ENETDOWN) {
28712143Sgww@eng.sun.com 					/*
28812143Sgww@eng.sun.com 					 * tolerate not being able to
28912143Sgww@eng.sun.com 					 * translate local hostname
29012143Sgww@eng.sun.com 					 * to a termid -- it will be
29112143Sgww@eng.sun.com 					 * "loopback".
29212143Sgww@eng.sun.com 					 */
29312143Sgww@eng.sun.com 					syslog(LOG_AUTH | LOG_ERR,
29412143Sgww@eng.sun.com 					    "pam_unix_cred: cannot load "
29512143Sgww@eng.sun.com 					    "ttyname: %m, continuing.");
29612143Sgww@eng.sun.com 					goto adt_setuser;
29712143Sgww@eng.sun.com 				} else if (errno != 0) {
2989138SJoep.Vesseur@Sun.COM 					syslog(LOG_AUTH | LOG_ERR,
2999138SJoep.Vesseur@Sun.COM 					    "pam_unix_cred: cannot load "
3009138SJoep.Vesseur@Sun.COM 					    "ttyname: %m.");
30112143Sgww@eng.sun.com 				} else {
3029138SJoep.Vesseur@Sun.COM 					syslog(LOG_AUTH | LOG_ERR,
3039138SJoep.Vesseur@Sun.COM 					    "pam_unix_cred: cannot load "
3049138SJoep.Vesseur@Sun.COM 					    "ttyname.");
30512143Sgww@eng.sun.com 				}
3060Sstevel@tonic-gate 				ret = PAM_SYSTEM_ERR;
3070Sstevel@tonic-gate 				goto adt_done;
3080Sstevel@tonic-gate 			}
3090Sstevel@tonic-gate 		} else {
3100Sstevel@tonic-gate 			if (adt_load_hostname(rhost, &termid) != 0) {
31112143Sgww@eng.sun.com 				if (errno != 0) {
3129138SJoep.Vesseur@Sun.COM 					syslog(LOG_AUTH | LOG_ERR,
3139138SJoep.Vesseur@Sun.COM 					    "pam_unix_cred: cannot load "
3149138SJoep.Vesseur@Sun.COM 					    "hostname: %m.");
31512143Sgww@eng.sun.com 				} else {
3169138SJoep.Vesseur@Sun.COM 					syslog(LOG_AUTH | LOG_ERR,
3179138SJoep.Vesseur@Sun.COM 					    "pam_unix_cred: cannot load "
3189138SJoep.Vesseur@Sun.COM 					    "hostname.");
31912143Sgww@eng.sun.com 				}
3200Sstevel@tonic-gate 				ret = PAM_SYSTEM_ERR;
3210Sstevel@tonic-gate 				goto adt_done;
3220Sstevel@tonic-gate 			}
3230Sstevel@tonic-gate 		}
32412143Sgww@eng.sun.com adt_setuser:
3252815Sgww 		if ((auser != NULL) && (*auser != '\0') &&
3262815Sgww 		    (getpwnam_r(auser, &apwd, apwbuf,
3272815Sgww 		    sizeof (apwbuf)) != NULL)) {
3280Sstevel@tonic-gate 			/*
3290Sstevel@tonic-gate 			 * set up the initial audit for user coming
3300Sstevel@tonic-gate 			 * from another user
3310Sstevel@tonic-gate 			 */
3322815Sgww 			if (adt_set_user(ah, apwd.pw_uid, apwd.pw_gid,
3332815Sgww 			    apwd.pw_uid, apwd.pw_gid, termid, ADT_NEW) != 0) {
3340Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
3352815Sgww 				    "pam_unix_cred: cannot set auser audit "
3360Sstevel@tonic-gate 				    "%m");
3370Sstevel@tonic-gate 				ret = PAM_SYSTEM_ERR;
3380Sstevel@tonic-gate 				goto adt_done;
3390Sstevel@tonic-gate 			}
3400Sstevel@tonic-gate 			if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
3410Sstevel@tonic-gate 			    pwd.pw_uid, pwd.pw_gid, NULL,
3420Sstevel@tonic-gate 			    ADT_UPDATE) != 0) {
3430Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
3440Sstevel@tonic-gate 				    "pam_unix_cred: cannot merge user audit "
3450Sstevel@tonic-gate 				    "%m");
3460Sstevel@tonic-gate 				ret = PAM_SYSTEM_ERR;
3470Sstevel@tonic-gate 				goto adt_done;
3480Sstevel@tonic-gate 			}
3490Sstevel@tonic-gate 			if (debug) {
3500Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_DEBUG,
3510Sstevel@tonic-gate 				    "pam_unix_cred: new audit set for %d:%d",
3522815Sgww 				    apwd.pw_uid, pwd.pw_uid);
3530Sstevel@tonic-gate 			}
3540Sstevel@tonic-gate 		} else {
3550Sstevel@tonic-gate 			/*
3562815Sgww 			 * No authenticated user or authenticated user is
3572815Sgww 			 * not a local user, no remote attribution, set
3582815Sgww 			 * up the initial audit as for direct user login
3590Sstevel@tonic-gate 			 */
3600Sstevel@tonic-gate 			if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid,
3610Sstevel@tonic-gate 			    pwd.pw_uid, pwd.pw_gid, termid, ADT_NEW) != 0) {
3620Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
3630Sstevel@tonic-gate 				    "pam_unix_cred: cannot set user audit %m");
3640Sstevel@tonic-gate 				ret = PAM_SYSTEM_ERR;
3650Sstevel@tonic-gate 				goto adt_done;
3660Sstevel@tonic-gate 			}
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 		if (adt_set_proc(ah) != 0) {
3690Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_ERR,
3700Sstevel@tonic-gate 			    "pam_unix_cred: cannot set process audit %m");
3710Sstevel@tonic-gate 			ret = PAM_CRED_ERR;
3720Sstevel@tonic-gate 			goto adt_done;
3730Sstevel@tonic-gate 		}
3740Sstevel@tonic-gate 		if (debug) {
3750Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_DEBUG,
3760Sstevel@tonic-gate 			    "pam_unix_cred: new audit set for %d",
3770Sstevel@tonic-gate 			    pwd.pw_uid);
3780Sstevel@tonic-gate 		}
3791114Sgww 	} else if ((auid != AU_NOAUDITID) &&
3801114Sgww 	    (flags & PAM_REINITIALIZE_CRED)) {
3810Sstevel@tonic-gate 		if (adt_set_user(ah, pwd.pw_uid, pwd.pw_gid, pwd.pw_uid,
3820Sstevel@tonic-gate 		    pwd.pw_gid, NULL, ADT_UPDATE) != 0) {
3830Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_ERR,
3840Sstevel@tonic-gate 			    "pam_unix_cred: cannot set user audit %m");
3850Sstevel@tonic-gate 			ret = PAM_SYSTEM_ERR;
3860Sstevel@tonic-gate 			goto adt_done;
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 		if (adt_set_proc(ah) != 0) {
3890Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_ERR,
3900Sstevel@tonic-gate 			    "pam_unix_cred: cannot set process audit %m");
3910Sstevel@tonic-gate 			ret = PAM_CRED_ERR;
3920Sstevel@tonic-gate 			goto adt_done;
3930Sstevel@tonic-gate 		}
3940Sstevel@tonic-gate 		if (debug) {
3950Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_DEBUG,
3960Sstevel@tonic-gate 			    "pam_unix_cred: audit merged for %d:%d",
3970Sstevel@tonic-gate 			    auid, pwd.pw_uid);
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 	} else if (debug) {
4000Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_DEBUG,
4010Sstevel@tonic-gate 		    "pam_unix_cred: audit already set for %d", auid);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate adt_done:
4040Sstevel@tonic-gate 	if (termid != NULL)
4050Sstevel@tonic-gate 		free(termid);
4060Sstevel@tonic-gate 	if (adt_end_session(ah) != 0) {
4070Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
4080Sstevel@tonic-gate 		    "pam_unix_cred: unable to end audit session");
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if (ret != PAM_SUCCESS)
4120Sstevel@tonic-gate 		return (ret);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/* Initialize the user's project */
4150Sstevel@tonic-gate 	(void) pam_get_item(pamh, PAM_RESOURCE, (void **)&kvs);
4160Sstevel@tonic-gate 	if (kvs != NULL) {
4170Sstevel@tonic-gate 		char *tmp, *lasts, *tok;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		kvs = tmp = strdup(kvs);
4200Sstevel@tonic-gate 		if (kvs == NULL)
4210Sstevel@tonic-gate 			return (PAM_BUF_ERR);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		while ((tok = strtok_r(tmp, ";", &lasts)) != NULL) {
4240Sstevel@tonic-gate 			if (strncmp(tok, PROJECT, PROJSZ) == 0) {
4250Sstevel@tonic-gate 				projname = tok + PROJSZ;
4260Sstevel@tonic-gate 				break;
4270Sstevel@tonic-gate 			}
4280Sstevel@tonic-gate 			tmp = NULL;
4290Sstevel@tonic-gate 		}
4300Sstevel@tonic-gate 	} else {
4310Sstevel@tonic-gate 		projname = NULL;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	if (projname == NULL || *projname == '\0') {
4350Sstevel@tonic-gate 		pproj = getdefaultproj(user, &proj, (void *)&buf,
4360Sstevel@tonic-gate 		    PROJECT_BUFSZ);
4370Sstevel@tonic-gate 	} else {
4380Sstevel@tonic-gate 		pproj = getprojbyname(projname, &proj, (void *)&buf,
4390Sstevel@tonic-gate 		    PROJECT_BUFSZ);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 	/* projname points into kvs, so this is the first opportunity to free */
4420Sstevel@tonic-gate 	if (kvs != NULL)
4430Sstevel@tonic-gate 		free(kvs);
4440Sstevel@tonic-gate 	if (pproj == NULL) {
4450Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
4460Sstevel@tonic-gate 		    "pam_unix_cred: no default project for user %s", user);
4470Sstevel@tonic-gate 		if (!nowarn) {
4480Sstevel@tonic-gate 			(void) snprintf(messages[0], sizeof (messages[0]),
4490Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN, "No default project!"));
4500Sstevel@tonic-gate 			(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
4510Sstevel@tonic-gate 			    1, messages, NULL);
4520Sstevel@tonic-gate 		}
4530Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 	if ((error = setproject(proj.pj_name, user, TASK_NORMAL)) != 0) {
4560Sstevel@tonic-gate 		kva_t *kv_array;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 		switch (error) {
4590Sstevel@tonic-gate 		case SETPROJ_ERR_TASK:
4600Sstevel@tonic-gate 			if (errno == EAGAIN) {
4610Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
4620Sstevel@tonic-gate 				    "pam_unix_cred: project \"%s\" resource "
4630Sstevel@tonic-gate 				    "control limit has been reached",
4640Sstevel@tonic-gate 				    proj.pj_name);
4650Sstevel@tonic-gate 				(void) snprintf(messages[0],
4660Sstevel@tonic-gate 				    sizeof (messages[0]), dgettext(
4670Sstevel@tonic-gate 				    TEXT_DOMAIN,
4680Sstevel@tonic-gate 				    "Resource control limit has been "
4690Sstevel@tonic-gate 				    "reached"));
4700Sstevel@tonic-gate 			} else {
4710Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
4720Sstevel@tonic-gate 				    "pam_unix_cred: user %s could not join "
4730Sstevel@tonic-gate 				    "project \"%s\": %m", user, proj.pj_name);
4740Sstevel@tonic-gate 				(void) snprintf(messages[0],
4750Sstevel@tonic-gate 				    sizeof (messages[0]), dgettext(
4760Sstevel@tonic-gate 				    TEXT_DOMAIN,
4770Sstevel@tonic-gate 				    "Could not join default project"));
4780Sstevel@tonic-gate 			}
4790Sstevel@tonic-gate 			if (!nowarn)
4800Sstevel@tonic-gate 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1,
4810Sstevel@tonic-gate 				    messages, NULL);
4820Sstevel@tonic-gate 			break;
4830Sstevel@tonic-gate 		case SETPROJ_ERR_POOL:
4840Sstevel@tonic-gate 			(void) snprintf(messages[0], sizeof (messages[0]),
4850Sstevel@tonic-gate 			    dgettext(TEXT_DOMAIN,
4860Sstevel@tonic-gate 			    "Could not bind to resource pool"));
4870Sstevel@tonic-gate 			switch (errno) {
4880Sstevel@tonic-gate 			case EACCES:
4890Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
4900Sstevel@tonic-gate 				    "pam_unix_cred: project \"%s\" could not "
4910Sstevel@tonic-gate 				    "bind to resource pool: No resource pool "
4920Sstevel@tonic-gate 				    "accepting default bindings exists",
4930Sstevel@tonic-gate 				    proj.pj_name);
4940Sstevel@tonic-gate 				(void) snprintf(messages[1],
4950Sstevel@tonic-gate 				    sizeof (messages[1]),
4960Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
4970Sstevel@tonic-gate 				    "No resource pool accepting "
4980Sstevel@tonic-gate 				    "default bindings exists"));
4990Sstevel@tonic-gate 				break;
5000Sstevel@tonic-gate 			case ESRCH:
5010Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
5020Sstevel@tonic-gate 				    "pam_unix_cred: project \"%s\" could not "
5030Sstevel@tonic-gate 				    "bind to resource pool: The resource pool "
5040Sstevel@tonic-gate 				    "is unknown", proj.pj_name);
5050Sstevel@tonic-gate 				(void) snprintf(messages[1],
5060Sstevel@tonic-gate 				    sizeof (messages[1]),
5070Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
5080Sstevel@tonic-gate 				    "The specified resource pool "
5090Sstevel@tonic-gate 				    "is unknown"));
5100Sstevel@tonic-gate 				break;
5110Sstevel@tonic-gate 			default:
5120Sstevel@tonic-gate 				(void) snprintf(messages[1],
5130Sstevel@tonic-gate 				    sizeof (messages[1]),
5140Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
5150Sstevel@tonic-gate 				    "Failure during pool binding"));
5160Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
5170Sstevel@tonic-gate 				    "pam_unix_cred: project \"%s\" could not "
5180Sstevel@tonic-gate 				    "bind to resource pool: %m", proj.pj_name);
5190Sstevel@tonic-gate 			}
5200Sstevel@tonic-gate 			if (!nowarn)
5210Sstevel@tonic-gate 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
5220Sstevel@tonic-gate 				    2, messages, NULL);
5230Sstevel@tonic-gate 			break;
5240Sstevel@tonic-gate 		default:
5250Sstevel@tonic-gate 			/*
5260Sstevel@tonic-gate 			 * Resource control assignment failed.  Unlike
5270Sstevel@tonic-gate 			 * newtask(1m), we treat this as an error.
5280Sstevel@tonic-gate 			 */
5290Sstevel@tonic-gate 			if (error < 0) {
5300Sstevel@tonic-gate 				/*
5310Sstevel@tonic-gate 				 * This isn't supposed to happen, but in
5320Sstevel@tonic-gate 				 * case it does, this error message
5330Sstevel@tonic-gate 				 * doesn't use error as an index, like
5340Sstevel@tonic-gate 				 * the others might.
5350Sstevel@tonic-gate 				 */
5360Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
5370Sstevel@tonic-gate 				    "pam_unix_cred: unkwown error joining "
5380Sstevel@tonic-gate 				    "project \"%s\" (%d)", proj.pj_name, error);
5390Sstevel@tonic-gate 				(void) snprintf(messages[0],
5400Sstevel@tonic-gate 				    sizeof (messages[0]),
5410Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
5420Sstevel@tonic-gate 				    "unkwown error joining project \"%s\""
5430Sstevel@tonic-gate 				    " (%d)"), proj.pj_name, error);
5440Sstevel@tonic-gate 			} else if ((kv_array = _str2kva(proj.pj_attr, KV_ASSIGN,
5450Sstevel@tonic-gate 			    KV_DELIMITER)) != NULL) {
5460Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
5470Sstevel@tonic-gate 				    "pam_unix_cred: %s resource control "
5480Sstevel@tonic-gate 				    "assignment failed for project \"%s\"",
5490Sstevel@tonic-gate 				    kv_array->data[error - 1].key,
5500Sstevel@tonic-gate 				    proj.pj_name);
5510Sstevel@tonic-gate 				(void) snprintf(messages[0],
5520Sstevel@tonic-gate 				    sizeof (messages[0]),
5530Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
5540Sstevel@tonic-gate 				    "%s resource control assignment failed for "
5550Sstevel@tonic-gate 				    "project \"%s\""),
5560Sstevel@tonic-gate 				    kv_array->data[error - 1].key,
5570Sstevel@tonic-gate 				    proj.pj_name);
5580Sstevel@tonic-gate 				_kva_free(kv_array);
5590Sstevel@tonic-gate 			} else {
5600Sstevel@tonic-gate 				syslog(LOG_AUTH | LOG_ERR,
5610Sstevel@tonic-gate 				    "pam_unix_cred: resource control "
5620Sstevel@tonic-gate 				    "assignment failed for project \"%s\""
5630Sstevel@tonic-gate 				    "attribute %d", proj.pj_name, error);
5640Sstevel@tonic-gate 				(void) snprintf(messages[0],
5650Sstevel@tonic-gate 				    sizeof (messages[0]),
5660Sstevel@tonic-gate 				    dgettext(TEXT_DOMAIN,
5670Sstevel@tonic-gate 				    "resource control assignment failed for "
5680Sstevel@tonic-gate 				    "project \"%s\" attribute %d"),
5690Sstevel@tonic-gate 				    proj.pj_name, error);
5700Sstevel@tonic-gate 			}
5710Sstevel@tonic-gate 			if (!nowarn)
5720Sstevel@tonic-gate 				(void) __pam_display_msg(pamh, PAM_ERROR_MSG,
5730Sstevel@tonic-gate 				    1, messages, NULL);
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 		return (PAM_SYSTEM_ERR);
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
578*12273SCasper.Dik@Sun.COM 	tset = def = lim = NULL;
579*12273SCasper.Dik@Sun.COM 	deflim.def = deflim.lim = NULL;
5800Sstevel@tonic-gate 
581*12273SCasper.Dik@Sun.COM 	(void) _enum_attrs(user, finddeflim, NULL, &deflim);
5820Sstevel@tonic-gate 
583*12273SCasper.Dik@Sun.COM 	if (getset(deflim.lim, &lim) != 0 || getset(deflim.def, &def) != 0) {
5840Sstevel@tonic-gate 		ret = PAM_SYSTEM_ERR;
5850Sstevel@tonic-gate 		goto out;
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (def == NULL) {
589*12273SCasper.Dik@Sun.COM 		def = priv_allocset();
590*12273SCasper.Dik@Sun.COM 		if (def == NULL) {
591*12273SCasper.Dik@Sun.COM 			ret = PAM_SYSTEM_ERR;
592*12273SCasper.Dik@Sun.COM 			goto out;
593*12273SCasper.Dik@Sun.COM 		}
594*12273SCasper.Dik@Sun.COM 		priv_basicset(def);
5957476Snils.goroll@hamburg.de 		errno = 0;
5967476Snils.goroll@hamburg.de 		if ((pathconf("/", _PC_CHOWN_RESTRICTED) == -1) && (errno == 0))
5970Sstevel@tonic-gate 			(void) priv_addset(def, PRIV_FILE_CHOWN_SELF);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 	/*
6001590Scasper 	 * Silently limit the privileges to those actually available
6011590Scasper 	 * in the current zone.
6021590Scasper 	 */
6031590Scasper 	tset = priv_allocset();
6041590Scasper 	if (tset == NULL) {
6051590Scasper 		ret = PAM_SYSTEM_ERR;
6061590Scasper 		goto out;
6071590Scasper 	}
6081590Scasper 	if (getppriv(PRIV_PERMITTED, tset) != 0) {
6091590Scasper 		ret = PAM_SYSTEM_ERR;
6101590Scasper 		goto out;
6111590Scasper 	}
6121590Scasper 	if (!priv_issubset(def, tset))
6131590Scasper 		priv_intersect(tset, def);
6141590Scasper 	/*
6150Sstevel@tonic-gate 	 * We set privilege awareness here so that I gets copied to
6160Sstevel@tonic-gate 	 * P & E when the final setuid(uid) happens.
6170Sstevel@tonic-gate 	 */
6180Sstevel@tonic-gate 	(void) setpflags(PRIV_AWARE, 1);
6190Sstevel@tonic-gate 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, def) != 0) {
6200Sstevel@tonic-gate 		syslog(LOG_AUTH | LOG_ERR,
6217476Snils.goroll@hamburg.de 		    "pam_setcred: setppriv(defaultpriv) failed: %m");
6220Sstevel@tonic-gate 		ret = PAM_CRED_ERR;
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (lim != NULL) {
6260Sstevel@tonic-gate 		/*
6271590Scasper 		 * Silently limit the privileges to the limit set available.
6281590Scasper 		 */
6291590Scasper 		if (getppriv(PRIV_LIMIT, tset) != 0) {
6301590Scasper 			ret = PAM_SYSTEM_ERR;
6311590Scasper 			goto out;
6321590Scasper 		}
6331590Scasper 		if (!priv_issubset(lim, tset))
6341590Scasper 			priv_intersect(tset, lim);
6359799SCasper.Dik@Sun.COM 		if (setppriv(PRIV_SET, PRIV_LIMIT, lim) != 0) {
6360Sstevel@tonic-gate 			syslog(LOG_AUTH | LOG_ERR,
6377476Snils.goroll@hamburg.de 			    "pam_setcred: setppriv(limitpriv) failed: %m");
6380Sstevel@tonic-gate 			ret = PAM_CRED_ERR;
6399799SCasper.Dik@Sun.COM 			goto out;
6400Sstevel@tonic-gate 		}
6419799SCasper.Dik@Sun.COM 		/*
6429799SCasper.Dik@Sun.COM 		 * In order not to surprise certain applications, we
6439799SCasper.Dik@Sun.COM 		 * need to get rid of privilege awareness and thus we must
6449799SCasper.Dik@Sun.COM 		 * set this flag which will cause a reset on set*uid().
6459799SCasper.Dik@Sun.COM 		 */
6469799SCasper.Dik@Sun.COM 		(void) setpflags(PRIV_AWARE_RESET, 1);
6470Sstevel@tonic-gate 	}
6489799SCasper.Dik@Sun.COM 	/*
6499799SCasper.Dik@Sun.COM 	 * This may fail but we do not care as this will be reset later
6509799SCasper.Dik@Sun.COM 	 * when the uids are set to their final values.
6519799SCasper.Dik@Sun.COM 	 */
6520Sstevel@tonic-gate 	(void) setpflags(PRIV_AWARE, 0);
653*12273SCasper.Dik@Sun.COM 	/*
654*12273SCasper.Dik@Sun.COM 	 * Remove PRIV_PFEXEC; stop running as if we are under a profile
655*12273SCasper.Dik@Sun.COM 	 * shell.  A user with a profile shell will set PRIV_PFEXEC.
656*12273SCasper.Dik@Sun.COM 	 */
657*12273SCasper.Dik@Sun.COM 	(void) setpflags(PRIV_PFEXEC, 0);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate out:
660*12273SCasper.Dik@Sun.COM 	free(deflim.lim);
661*12273SCasper.Dik@Sun.COM 	free(deflim.def);
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	if (lim != NULL)
6640Sstevel@tonic-gate 		priv_freeset(lim);
6650Sstevel@tonic-gate 	if (def != NULL)
6660Sstevel@tonic-gate 		priv_freeset(def);
6671590Scasper 	if (tset != NULL)
6681590Scasper 		priv_freeset(tset);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	return (ret);
6710Sstevel@tonic-gate }
672