changeset 25454:3e5a54d0c9d0

[illumos-gate merge] commit 9e678d632bda8e6911719d88b7c2d44a886aba5b 13195 would like roleauth user_attr
author Dan McDonald <danmcd@joyent.com>
date Mon, 12 Oct 2020 16:02:42 -0400
parents 096aae768136 (current diff) 79a02f3e02d2 (diff)
children 8b3fc37f1d32
files
diffstat 10 files changed, 159 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/oamuser/user/funcs.c	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/oamuser/user/funcs.c	Mon Oct 12 16:02:42 2020 -0400
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 RackTop Systems.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #include <stdio.h>
@@ -58,6 +59,7 @@
 static const char auth[] = "authorization";
 static const char type[] = "user type";
 static const char lock[] = "lock_after_retries value";
+static const char roleauth[] = "roleauth";
 static const char label[] = "label";
 static const char auditflags[] = "audit mask";
 static char	  auditerr[256];
@@ -70,6 +72,7 @@
 static const char *check_privset(const char *);
 static const char *check_type(const char *);
 static const char *check_lock_after_retries(const char *);
+static const char *check_roleauth(const char *);
 static const char *check_label(const char *);
 static const char *check_auditflags(const char *);
 
@@ -84,7 +87,8 @@
 	{ USERATTR_DEFAULTPROJ_KW,	check_proj,	proj },
 	{ USERATTR_LIMPRIV_KW,	check_privset,	priv },
 	{ USERATTR_DFLTPRIV_KW,	check_privset,	priv },
-	{ USERATTR_LOCK_AFTER_RETRIES_KW, check_lock_after_retries,  lock },
+	{ USERATTR_LOCK_AFTER_RETRIES_KW, check_lock_after_retries, lock },
+	{ USERATTR_ROLEAUTH_KW,	check_roleauth, roleauth },
 	{ USERATTR_CLEARANCE,	check_label,	label },
 	{ USERATTR_MINLABEL,	check_label,	label },
 	{ USERATTR_AUDIT_FLAGS_KW, check_auditflags, auditflags },
@@ -414,9 +418,22 @@
 check_lock_after_retries(const char *keyval)
 {
 	if (keyval != NULL) {
-		if ((strcasecmp(keyval, "no") != 0) &&
-		    (strcasecmp(keyval, "yes") != 0) &&
-		    (*keyval != '\0'))   {
+		if (strcasecmp(keyval, USERATTR_LOCK_NO) != 0 &&
+		    strcasecmp(keyval, USERATTR_LOCK_YES) != 0 &&
+		    *keyval != '\0')   {
+			return (keyval);
+		}
+	}
+	return (NULL);
+}
+
+static const char *
+check_roleauth(const char *keyval)
+{
+	if (keyval != NULL) {
+		if (strcasecmp(keyval, USERATTR_ROLEAUTH_USER) != 0 &&
+		    strcasecmp(keyval, USERATTR_ROLEAUTH_ROLE) != 0 &&
+		    *keyval != '\0')   {
 			return (keyval);
 		}
 	}
--- a/usr/src/cmd/oamuser/user/userdefs.c	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/oamuser/user/userdefs.c	Mon Oct 12 16:02:42 2020 -0400
@@ -26,14 +26,13 @@
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*	  All Rights Reserved	*/
 
 /*
  * Copyright (c) 2013 RackTop Systems.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
-/*LINTLIBRARY*/
-
 #include	<sys/types.h>
 #include	<stdio.h>
 #include	<string.h>
@@ -55,7 +54,7 @@
 		(void) fprintf(fptr, "\n"); \
 	}
 
-#define	SKIPWS(ptr)	while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++
+#define	SKIPWS(ptr)	while (*(ptr) == ' ' || *(ptr) == '\t') (ptr)++
 
 static char *dup_to_nl(char *);
 
@@ -63,7 +62,7 @@
 	DEFRID, DEFGROUP, DEFGNAME, DEFPARENT, DEFSKL,
 	DEFSHL, DEFINACT, DEFEXPIRE, DEFAUTH, DEFPROF,
 	DEFROLE, DEFPROJ, DEFPROJNAME, DEFLIMPRIV,
-	DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES
+	DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES, DEFROLEAUTH
 };
 
 #define	INT	0
@@ -104,6 +103,8 @@
 	{ LOCK_AFTER_RETRIESSTR,	sizeof (LOCK_AFTER_RETRIESSTR) - 1,
 		STR,	DEFOFF(deflock_after_retries),
 		USERATTR_LOCK_AFTER_RETRIES_KW },
+	{ ROLEAUTHSTR,	sizeof (ROLEAUTHSTR) - 1, STR,	DEFOFF(defroleauth),
+		USERATTR_ROLEAUTH_KW },
 };
 
 #define	NDEF	(sizeof (tab) / sizeof (parsent_t))
@@ -152,12 +153,13 @@
  *		defauth = 0
  *		defprof = 0
  *		defrole = 0
+ *		defroleauth = role
  *
  *	If getusrdef() is unable to access the defaults file, it
  *	returns a NULL pointer.
  *
- * 	If user defaults file exists, then getusrdef uses values
- *  in it to override the above values.
+ *	If user defaults file exists, then getusrdef uses values
+ *	in it to override the above values.
  */
 
 struct userdefs *
@@ -170,6 +172,7 @@
 		if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) {
 			defaults.defshell = DEFROLESHL;
 			defaults.defprof = DEFROLEPROF;
+			defaults.defroleauth = DEFROLEROLEAUTH;
 			return (&defaults);
 		}
 	} else {
@@ -191,11 +194,11 @@
 			switch (pe->type) {
 			case INT:
 				FIELD(&defaults, pe, int) =
-					(int)strtol(ptr, NULL, 10);
+				    (int)strtol(ptr, NULL, 10);
 				break;
 			case PROJID:
 				FIELD(&defaults, pe, projid_t) =
-					(projid_t)strtol(ptr, NULL, 10);
+				    (projid_t)strtol(ptr, NULL, 10);
 				break;
 			case STR:
 				FIELD(&defaults, pe, char *) = dup_to_nl(ptr);
@@ -231,7 +234,7 @@
 
 	if (flags & D_GROUP) {
 		outcount += fprintf(fptr, "group=%s,%ld  ",
-			deflts->defgname, deflts->defgroup);
+		    deflts->defgname, deflts->defgroup);
 		PRINTNL();
 	}
 
@@ -288,20 +291,25 @@
 	}
 
 	if (flags & D_LPRIV) {
-		outcount += fprintf(fptr, "limitpriv=%s  ",
-			deflts->deflimpriv);
+		outcount += fprintf(fptr, "limitpriv=%s  ", deflts->deflimpriv);
 		PRINTNL();
 	}
 
 	if (flags & D_DPRIV) {
 		outcount += fprintf(fptr, "defaultpriv=%s  ",
-			deflts->defdfltpriv);
+		    deflts->defdfltpriv);
 		PRINTNL();
 	}
 
 	if (flags & D_LOCK) {
 		outcount += fprintf(fptr, "lock_after_retries=%s  ",
 		    deflts->deflock_after_retries);
+		PRINTNL();
+	}
+
+	if ((flags & D_ROLEAUTH) && is_role(usertype)) {
+		outcount += fprintf(fptr, "roleauth=%s  ",
+		    deflts->defroleauth);
 	}
 
 	if (outcount > 0)
@@ -310,7 +318,7 @@
 
 /*
  * putusrdef -
- * 	changes default values in defadduser file
+ *	changes default values in defadduser file
  */
 int
 putusrdef(struct userdefs *defs, char *usertype)
@@ -353,10 +361,11 @@
 
 	if (is_role(usertype)) {
 		/* If it's a role, we must skip the defrole field */
-		skip = offsetof(struct userdefs, defrole);
+		skip = DEFOFF(defrole);
 		hdr = FHEADER_ROLE;
 	} else {
-		skip = -1;
+		/* If it's a user, we must skip the defroleauth field */
+		skip = DEFOFF(defroleauth);
 		hdr = FHEADER;
 	}
 
@@ -378,15 +387,15 @@
 		switch (tab[i].type) {
 		case INT:
 			res = fprintf(defptr, "%s%d\n", tab[i].name,
-					FIELD(defs, &tab[i], int));
+			    FIELD(defs, &tab[i], int));
 			break;
 		case STR:
 			res = fprintf(defptr, "%s%s\n", tab[i].name,
-					FIELD(defs, &tab[i], char *));
+			    FIELD(defs, &tab[i], char *));
 			break;
 		case PROJID:
 			res = fprintf(defptr, "%s%d\n", tab[i].name,
-					(int)FIELD(defs, &tab[i], projid_t));
+			    (int)FIELD(defs, &tab[i], projid_t));
 			break;
 		}
 
--- a/usr/src/cmd/oamuser/user/userdisp.h	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/oamuser/user/userdisp.h	Mon Oct 12 16:02:42 2020 -0400
@@ -25,14 +25,15 @@
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*	  All Rights Reserved	*/
 
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
 
 #ifndef	_USERDISP_H
 #define	_USERDISP_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -52,10 +53,11 @@
 #define	D_LPRIV		0x0800
 #define	D_DPRIV		0x1000
 #define	D_LOCK		0x2000
+#define	D_ROLEAUTH	0x4000
 
 #define	D_ALL	(D_GROUP | D_BASEDIR | D_RID | D_SKEL | D_SHELL \
 	| D_INACT | D_EXPIRE | D_AUTH | D_PROF | D_ROLE | D_PROJ | \
-	D_LPRIV | D_DPRIV | D_LOCK)
+	D_LPRIV | D_DPRIV | D_LOCK | D_ROLEAUTH)
 
 #ifdef	__cplusplus
 }
--- a/usr/src/cmd/passmgmt/Makefile	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/passmgmt/Makefile	Mon Oct 12 16:02:42 2020 -0400
@@ -22,15 +22,16 @@
 # Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 # Copyright (c) 2018, Joyent, Inc.
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 
 
-PROG= 		passmgmt
-FILE= 		datemsk
-TXTS= 		$(FILE)
+PROG=		passmgmt
+FILE=		datemsk
+TXTS=		$(FILE)
 
 include ../Makefile.cmd
 
-FILEMODE= 	0555
+FILEMODE=	0555
 ROOTFILE=	$(ROOTETC)/$(FILE)
 
 # conditional assignment
@@ -48,7 +49,7 @@
 
 all: $(PROG) $(TXTS)
 
-XGETFLAGS= -a -x $(PROG).xcl 
+XGETFLAGS= -a -x $(PROG).xcl
 
 install: all $(ROOTLIBPROG) $(ROOTFILE)
 
@@ -64,6 +65,4 @@
 clean:
 	$(RM) datemsk
 
-lint:	lint_PROG
-
 include ../Makefile.targ
--- a/usr/src/cmd/passmgmt/passmgmt.c	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/passmgmt/passmgmt.c	Mon Oct 12 16:02:42 2020 -0400
@@ -20,10 +20,11 @@
  */
 /*
  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
-/*	  All Rights Reserved  	*/
+/*	  All Rights Reserved	*/
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -90,6 +91,7 @@
 { '\0',	USERATTR_LIMPRIV_KW },
 { '\0',	USERATTR_DFLTPRIV_KW },
 { '\0', USERATTR_LOCK_AFTER_RETRIES_KW },
+{ '\0', USERATTR_ROLEAUTH_KW },
 { '\0', USERATTR_LABELVIEW },
 { '\0', USERATTR_CLEARANCE },
 { '\0', USERATTR_MINLABEL },
@@ -346,7 +348,7 @@
 	shadow_st.sp_lstchg = -1;	/* no lastchanged date */
 	shadow_st.sp_min = -1;	/* no min */
 	shadow_st.sp_max = -1;	/* no max */
-	shadow_st.sp_warn = -1; 	/* no warn */
+	shadow_st.sp_warn = -1;		/* no warn */
 	shadow_st.sp_inact = -1;	/* no inactive */
 	shadow_st.sp_expire = -1;	/* no expire */
 	shadow_st.sp_flag = 0;	/* no flag */
--- a/usr/src/cmd/su/Makefile	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/su/Makefile	Mon Oct 12 16:02:42 2020 -0400
@@ -22,6 +22,8 @@
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+# Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+#
 # build two versions, su and su.static
 # su.static is dynamically linked; the .static suffix is historical.
 
@@ -44,20 +46,14 @@
 # A reduced su.static is created, with just enough functionality
 # to satisfy the needs of a single-user login with /usr not mounted.
 # In particular, nss_files.so.1 may be dlopen()'ed at runtime.
-$(ROOTFS_PROG) :=	LDLIBS += -lbsm -lpam -lsecdb
+$(ROOTFS_PROG) :=	LDLIBS += -lbsm -lpam
 
 # The standard su is fully functional.
 $(PROG) :=	CPPFLAGS += -DDYNAMIC_SU
 $(PROG) :=	LDLIBS += -lbsm -lpam -lsecdb
 
-LINTFLAGS += -DDYNAMIC_SU
-
 CLOBBERFILES	+= $(ROOTFS_PROG) $(EMB_PROG)
 
-CERRWARN +=	-_gcc=-Wno-parentheses
-
-lint :=		LDLIBS += -lbsm -lpam -lsecdb
-
 .KEEP_STATE:
 
 all:		$(PROG) $(ROOTFS_PROG) $(EMB_PROG)
@@ -85,6 +81,4 @@
 
 clean:
 
-lint:		lint_PROG
-
 include		../Makefile.targ
--- a/usr/src/cmd/su/su.c	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/cmd/su/su.c	Mon Oct 12 16:02:42 2020 -0400
@@ -22,6 +22,7 @@
  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Milan Jurik. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
 /*	  All Rights Reserved	*/
@@ -120,12 +121,12 @@
 static char *alloc_vsprintf(const char *, va_list);
 static char *tail(char *);
 
-static void audit_success(int, struct passwd *);
+static void audit_success(int, struct passwd *, boolean_t);
 static void audit_logout(adt_session_data_t *, au_event_t);
-static void audit_failure(int, struct passwd *, char *, int);
+static void audit_failure(int, struct passwd *, char *, int, boolean_t);
 
 #ifdef DYNAMIC_SU
-static void validate(char *, int *);
+static void validate(char *, int *, boolean_t);
 static int legalenvvar(char *);
 static int su_conv(int, struct pam_message **, struct pam_response **, void *);
 static int emb_su_conv(int, struct pam_message **, struct pam_response **,
@@ -190,8 +191,11 @@
 	int flags = 0;
 	int retcode;
 	int idx = 0;
+	userattr_t *user_entry;
+	char *authname;
 #endif	/* DYNAMIC_SU */
 	int pw_change = PW_FALSE;
+	boolean_t isrole = B_FALSE;
 
 	(void) setlocale(LC_ALL, "");
 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
@@ -245,13 +249,13 @@
 
 	if (defopen(DEFFILE) == 0) {
 
-		if (Sulog = defread("SULOG="))
+		if ((Sulog = defread("SULOG=")) != NULL)
 			Sulog = strdup(Sulog);
-		if (Console = defread("CONSOLE="))
+		if ((Console = defread("CONSOLE=")) != NULL)
 			Console = strdup(Console);
-		if (Path = defread("PATH="))
+		if ((Path = defread("PATH=")) != NULL)
 			Path = strdup(Path);
-		if (Supath = defread("SUPATH="))
+		if ((Supath = defread("SUPATH=")) != NULL)
 			Supath = strdup(Supath);
 		if ((ptr = defread("SYSLOG=")) != NULL)
 			dosyslog = strcmp(ptr, "YES") == 0;
@@ -279,7 +283,31 @@
 	}
 
 #ifdef DYNAMIC_SU
-	if (pam_start(embedded ? EMBEDDED_NAME : "su", nptr,
+	authname = nptr;
+
+	if (((user_entry = getusernam(authname)) != NULL)) {
+		kva_t *attr = user_entry->attr;
+		char *kv;
+
+		if ((kv = kva_match(attr, USERATTR_TYPE_KW)) != NULL &&
+		    ((strcmp(kv, USERATTR_TYPE_NONADMIN_KW) == 0) ||
+		    (strcmp(kv, USERATTR_TYPE_ADMIN_KW) == 0))) {
+			isrole = B_TRUE;
+
+			if ((kv = kva_match(attr,
+			    USERATTR_ROLEAUTH_KW)) != NULL &&
+			    strcmp(kv, USERATTR_ROLEAUTH_USER) == 0) {
+				authname = cuserid(NULL);
+			}
+
+		}
+		free_userattr(user_entry);
+	}
+
+	if (authname == NULL)
+		exit(1);
+
+	if (pam_start(embedded ? EMBEDDED_NAME : "su", authname,
 	    embedded ? &emb_pam_conv : &pam_conv, &pamh) != PAM_SUCCESS)
 		exit(1);
 	if (pam_set_item(pamh, PAM_TTY, ttyn) != PAM_SUCCESS)
@@ -333,7 +361,7 @@
 		 * 3rd step: print out message to user.
 		 */
 		/* don't let audit_failure distinguish a role here */
-		audit_failure(PW_FALSE, NULL, nptr, retcode);
+		audit_failure(PW_FALSE, NULL, nptr, retcode, B_FALSE);
 		switch (retcode) {
 		case PAM_USER_UNKNOWN:
 			closelog();
@@ -368,7 +396,7 @@
 		exit(1);
 	}
 	if (flags)
-		validate(username, &pw_change);
+		validate(username, &pw_change, isrole);
 	if (pam_setcred(pamh, PAM_REINITIALIZE_CRED) != PAM_SUCCESS) {
 		message(ERR, gettext("unable to set credentials"));
 		exit(2);
@@ -384,7 +412,7 @@
 	if ((getpwnam_r(nptr, &pwd, pwdbuf, sizeof (pwdbuf)) == NULL) ||
 	    (getspnam_r(nptr, &sp, spbuf, sizeof (spbuf)) == NULL)) {
 		message(ERR, gettext("Unknown id: %s"), nptr);
-		audit_failure(PW_FALSE, NULL, nptr, PAM_USER_UNKNOWN);
+		audit_failure(PW_FALSE, NULL, nptr, PAM_USER_UNKNOWN, B_FALSE);
 		closelog();
 		exit(1);
 	}
@@ -403,7 +431,7 @@
 		if (Sulog != NULL)
 			log(Sulog, nptr, 0);    /* log entry */
 		message(ERR, gettext("Sorry"));
-		audit_failure(PW_FALSE, NULL, nptr, PAM_AUTH_ERR);
+		audit_failure(PW_FALSE, NULL, nptr, PAM_AUTH_ERR, B_FALSE);
 		if (dosyslog)
 			syslog(LOG_CRIT, "'su %s' failed for %s on %s",
 			    pwd.pw_name, username, ttyn);
@@ -421,7 +449,7 @@
 		    pwd.pw_name, username, ttyn);
 #endif	/* DYNAMIC_SU */
 
-	audit_success(pw_change, &pwd);
+	audit_success(pw_change, &pwd, isrole);
 	uid = pwd.pw_uid;
 	gid = pwd.pw_gid;
 	dir = strdup(pwd.pw_dir);
@@ -489,7 +517,7 @@
 		}
 		(void) strlcat(homedir, dir, sizeof (homedir));
 		(void) strlcat(logname, name, sizeof (logname));
-		if (hz = getenv("HZ"))
+		if ((hz = getenv("HZ")) != NULL)
 			(void) strlcat(hzname, hz, sizeof (hzname));
 
 		(void) strlcat(shelltyp, pshell, sizeof (shelltyp));
@@ -522,7 +550,7 @@
 		 */
 		tznam[0] = '\0';
 		for (j = 0; initenv[j] != 0; j++) {
-			if (initvar = getenv(initenv[j])) {
+			if ((initvar = getenv(initenv[j])) != NULL) {
 
 				/*
 				 * Skip over values beginning with '/' for
@@ -558,7 +586,7 @@
 		 */
 		if (tznam[0] == '\0') {
 			if (defopen(DEFAULT_LOGIN) == 0) {
-				if (initvar = defread("TIMEZONE=")) {
+				if ((initvar = defread("TIMEZONE=")) != NULL) {
 					(void) strcpy(tznam, "TZ=");
 					(void) strlcat(tznam, initvar,
 					    sizeof (tznam));
@@ -783,27 +811,19 @@
  */
 
 static void
-audit_success(int pw_change, struct passwd *pwd)
+audit_success(int pw_change, struct passwd *pwd, boolean_t isrole)
 {
 	adt_session_data_t	*ah = NULL;
 	adt_event_data_t	*event;
 	au_event_t		event_id = ADT_su;
-	userattr_t		*user_entry;
-	char			*kva_value;
 
 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 		syslog(LOG_AUTH | LOG_ALERT,
 		    "adt_start_session(ADT_su): %m");
 		return;
 	}
-	if (((user_entry = getusernam(pwd->pw_name)) != NULL) &&
-	    ((kva_value = kva_match((kva_t *)user_entry->attr,
-	    USERATTR_TYPE_KW)) != NULL) &&
-	    ((strcmp(kva_value, USERATTR_TYPE_NONADMIN_KW) == 0) ||
-	    (strcmp(kva_value, USERATTR_TYPE_ADMIN_KW) == 0))) {
+	if (isrole)
 		event_id = ADT_role_login;
-	}
-	free_userattr(user_entry);	/* OK to use, checks for NULL */
 
 	/* since proc uid/gid not yet updated */
 	if (adt_set_user(ah, pwd->pw_uid, pwd->pw_gid, pwd->pw_uid,
@@ -1004,13 +1024,12 @@
  */
 
 static void
-audit_failure(int pw_change, struct passwd *pwd, char *user, int pamerr)
+audit_failure(int pw_change, struct passwd *pwd, char *user, int pamerr,
+    boolean_t isrole)
 {
 	adt_session_data_t	*ah;	/* audit session handle */
 	adt_event_data_t	*event;	/* event to generate */
 	au_event_t		event_id = ADT_su;
-	userattr_t		*user_entry;
-	char			*kva_value;
 
 	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 		syslog(LOG_AUTH | LOG_ALERT,
@@ -1025,14 +1044,8 @@
 			syslog(LOG_AUTH | LOG_ERR,
 			    "adt_set_user(ADT_su, ADT_FAILURE): %m");
 		}
-		if (((user_entry = getusernam(pwd->pw_name)) != NULL) &&
-		    ((kva_value = kva_match((kva_t *)user_entry->attr,
-		    USERATTR_TYPE_KW)) != NULL) &&
-		    ((strcmp(kva_value, USERATTR_TYPE_NONADMIN_KW) == 0) ||
-		    (strcmp(kva_value, USERATTR_TYPE_ADMIN_KW) == 0))) {
+		if (isrole)
 			event_id = ADT_role_login;
-		}
-		free_userattr(user_entry);	/* OK to use, checks for NULL */
 	}
 	if ((event = adt_alloc_event(ah, event_id)) == NULL) {
 		syslog(LOG_AUTH | LOG_ALERT,
@@ -1320,7 +1333,7 @@
  * validate - Check that the account is valid for switching to.
  */
 static void
-validate(char *usernam, int *pw_change)
+validate(char *usernam, int *pw_change, boolean_t isrole)
 {
 	int error;
 	int tries;
@@ -1340,7 +1353,8 @@
 					continue;
 				}
 				message(ERR, gettext("Sorry"));
-				audit_failure(PW_FAILED, &pwd, NULL, error);
+				audit_failure(PW_FAILED, &pwd, NULL, error,
+				    isrole);
 				if (dosyslog)
 					syslog(LOG_CRIT,
 					    "'su %s' failed for %s on %s",
@@ -1352,7 +1366,7 @@
 			return;
 		} else {
 			message(ERR, gettext("Sorry"));
-			audit_failure(PW_FALSE, &pwd, NULL, error);
+			audit_failure(PW_FALSE, &pwd, NULL, error, isrole);
 			if (dosyslog)
 				syslog(LOG_CRIT, "'su %s' failed for %s on %s",
 				    pwd.pw_name, usernam, ttyn);
--- a/usr/src/head/user_attr.h	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/head/user_attr.h	Mon Oct 12 16:02:42 2020 -0400
@@ -21,6 +21,7 @@
 /*
  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #ifndef	_USER_ATTR_H
@@ -102,6 +103,9 @@
 #define	USERATTR_PASSWD_MANUAL		"manual"
 #define	USERATTR_TYPE_ROLE		USERATTR_TYPE_NONADMIN_KW
 #define	USERATTR_AUDIT_FLAGS_KW		"audit_flags"
+#define	USERATTR_ROLEAUTH_KW		"roleauth"
+#define	USERATTR_ROLEAUTH_USER		"user"
+#define	USERATTR_ROLEAUTH_ROLE		"role"
 
 
 /*
--- a/usr/src/head/userdefs.h	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/head/userdefs.h	Mon Oct 12 16:02:42 2020 -0400
@@ -27,6 +27,9 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved	*/
 
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
 
 #ifndef	_USERDEFS_H
 #define	_USERDEFS_H
@@ -62,6 +65,8 @@
 #define	DEFLIMPRIV	""
 #define	DEFDFLTPRIV	""
 #define	DEFLOCK_AFTER_RETRIES	""
+#define	DEFROLEAUTH	""
+#define	DEFROLEROLEAUTH	"role"
 
 /* Defaults file keywords */
 #define	RIDSTR		"defrid="
@@ -82,6 +87,7 @@
 #define	FHEADER		"#	Default values for useradd.  Changed "
 #define	FHEADER_ROLE	"#	Default values for roleadd.  Changed "
 #define	LOCK_AFTER_RETRIESSTR	"deflock_after_retries="
+#define	ROLEAUTHSTR	"defroleauth="
 
 /* Defaults file */
 #define	DEFFILE		"/usr/sadm/defadduser"
@@ -110,6 +116,7 @@
 	char *deflimpriv;	/* default limitpriv */
 	char *defdfltpriv;	/* default defaultpriv */
 	char *deflock_after_retries;	/* default lock_after_retries */
+	char *defroleauth;		/* default roleauth */
 
 };
 
--- a/usr/src/man/man4/user_attr.4	Mon Oct 12 13:55:36 2020 +0000
+++ b/usr/src/man/man4/user_attr.4	Mon Oct 12 16:02:42 2020 -0400
@@ -1,19 +1,18 @@
 '\" te
+.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 .\"  Copyright (C) 2008 Sun Microsystems, Inc. All Rights Reserved
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH USER_ATTR 4 "Aug 3, 2017"
+.TH USER_ATTR 4 "Oct 1, 2020"
 .SH NAME
 user_attr \- extended user attributes database
 .SH SYNOPSIS
-.LP
 .nf
 \fB/etc/user_attr\fR
 .fi
 
 .SH DESCRIPTION
-.LP
 \fB/etc/user_attr\fR is a local source of extended attributes associated with
 users and roles. \fBuser_attr\fR can be used with other user attribute sources,
 including the LDAP people container and the \fBuser_attr\fR \fBNIS\fR map.
@@ -90,7 +89,7 @@
 .sp
 .ne 2
 .na
-\fB\fBauths\fR\fR
+\fBauths\fR
 .ad
 .sp .6
 .RS 4n
@@ -103,7 +102,7 @@
 .sp
 .ne 2
 .na
-\fB\fBprofiles\fR\fR
+\fBprofiles\fR
 .ad
 .sp .6
 .RS 4n
@@ -117,7 +116,20 @@
 .sp
 .ne 2
 .na
-\fB\fBroles\fR\fR
+\fBroleauth\fR
+.ad
+.sp .6
+.RS 4n
+Specifies whether a user assuming a role is required to use the role password
+or their own password.
+If the \fBroleauth\fR key value is not specified, the role password is required
+for users assuming the role.
+.RE
+
+.sp
+.ne 2
+.na
+\fBroles\fR
 .ad
 .sp .6
 .RS 4n
@@ -130,7 +142,7 @@
 .sp
 .ne 2
 .na
-\fB\fBtype\fR\fR
+\fBtype\fR
 .ad
 .sp .6
 .RS 4n
@@ -143,7 +155,7 @@
 .sp
 .ne 2
 .na
-\fB\fBproject\fR\fR
+\fBproject\fR
 .ad
 .sp .6
 .RS 4n
@@ -155,7 +167,7 @@
 .sp
 .ne 2
 .na
-\fB\fBdefaultpriv\fR\fR
+\fBdefaultpriv\fR
 .ad
 .sp .6
 .RS 4n
@@ -166,7 +178,7 @@
 .sp
 .ne 2
 .na
-\fB\fBlimitpriv\fR\fR
+\fBlimitpriv\fR
 .ad
 .sp .6
 .RS 4n
@@ -181,7 +193,7 @@
 .sp
 .ne 2
 .na
-\fB\fBlock_after_retries\fR\fR
+\fBlock_after_retries\fR
 .ad
 .sp .6
 .RS 4n
@@ -197,7 +209,7 @@
 .sp
 .ne 2
 .na
-\fB\fBclearance\fR\fR
+\fBclearance\fR
 .ad
 .sp .6
 .RS 4n
@@ -210,7 +222,7 @@
 .sp
 .ne 2
 .na
-\fB\fBmin_label\fR\fR
+\fBmin_label\fR
 .ad
 .sp .6
 .RS 4n
@@ -231,7 +243,6 @@
 of the \fBtype\fR key is restricted as described in \fBrolemod\fR and
 \fBusermod\fR.
 .SS "Privileges Keywords"
-.LP
 The \fBdefaultpriv\fR and \fBlimitpriv\fR are the privileges-related keywords
 and are described above.
 .sp
@@ -248,7 +259,6 @@
 See \fBusermod\fR(1M) for examples of commands that
 modify privileges and their subsequent effect on \fBuser_attr\fR.
 .SH EXAMPLES
-.LP
 \fBExample 1 \fRAssigning a Profile to Root
 .sp
 .LP
@@ -274,7 +284,7 @@
 .SH FILES
 .ne 2
 .na
-\fB\fB/etc/nsswitch.conf\fR\fR
+\fB/etc/nsswitch.conf\fR
 .ad
 .sp .6
 .RS 4n
@@ -284,7 +294,7 @@
 .sp
 .ne 2
 .na
-\fB\fB/etc/user_attr\fR\fR
+\fB/etc/user_attr\fR
 .ad
 .sp .6
 .RS 4n
@@ -292,7 +302,6 @@
 .RE
 
 .SH ATTRIBUTES
-.LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
 
@@ -312,7 +321,6 @@
 .LP
 The command-line syntax is Committed. The output is Uncommitted.
 .SH SEE ALSO
-.LP
 \fBauths\fR(1), \fBpfcsh\fR(1), \fBpfksh\fR(1), \fBpfsh\fR(1), \fBppriv\fR(1),
 \fBprofiles\fR(1), \fBroles\fR(1), \fBroleadd\fR(1M), \fBrolemod\fR(1M),
 \fBuseradd\fR(1M), \fBusermod\fR(1M), \fBgetdefaultproj\fR(3PROJECT),
@@ -323,7 +331,6 @@
 .LP
 \fISystem Administration Guide: Security Services\fR
 .SH NOTES
-.LP
 The root user is usually defined in local databases for a number of reasons,
 including the fact that root needs to be able to log in and do system
 maintenance in single-user mode, before the network name service databases are