--- old/usr/src/cmd/cmd-inet/usr.sbin/in.routed/main.c	Mon Mar 27 17:24:28 2017
+++ new/usr/src/cmd/cmd-inet/usr.sbin/in.routed/main.c	Mon Mar 27 17:24:28 2017
@@ -43,7 +43,6 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <sys/file.h>
-#include <userdefs.h>
 #include <sys/stat.h>
 
 #define	IN_ROUTED_VERSION	"2.22"
--- old/usr/src/cmd/oamuser/group/Makefile	Mon Mar 27 17:24:28 2017
+++ new/usr/src/cmd/oamuser/group/Makefile	Mon Mar 27 17:24:28 2017
@@ -55,13 +55,13 @@
 FILEMODE= 	0555
 
 $(GROUPADD) :=	OBJS = $(ADD_OBJ)
-$(GROUPADD) :=	LDLIBS += $(LIBUSRGRP) -lcmdutils
+$(GROUPADD) :=	LDLIBS += $(LIBUSRGRP) -luserdefs -lcmdutils
 
 $(GROUPDEL) :=	OBJS = $(DEL_OBJ)
 $(GROUPDEL) :=	LDLIBS += $(LIBUSRGRP)
 
 $(GROUPMOD) :=	OBJS = $(MOD_OBJ)
-$(GROUPMOD) :=	LDLIBS += $(LIBUSRGRP)
+$(GROUPMOD) :=	LDLIBS += $(LIBUSRGRP) -luserdefs
 
 all: 		$(PROG)
 
--- old/usr/src/cmd/oamuser/user/Makefile	Mon Mar 27 17:24:28 2017
+++ new/usr/src/cmd/oamuser/user/Makefile	Mon Mar 27 17:24:28 2017
@@ -90,7 +90,7 @@
 $(USERMOD) :=	OBJS = $(MOD_OBJ)
 $(USERMOD) :=	LIBS = $(LIBUSRGRP)
 
-LDLIBS +=	-lbsm -lnsl -lsecdb -lproject -lzfs -ltsol
+LDLIBS +=	-luserdefs -lbsm -lnsl -lsecdb -lproject -lzfs -ltsol
 
 .PARALLEL: $(OBJECTS)
 
--- old/usr/src/cmd/oamuser/user/funcs.c	Mon Mar 27 17:24:29 2017
+++ new/usr/src/cmd/oamuser/user/funcs.c	Mon Mar 27 17:24:29 2017
@@ -98,6 +98,33 @@
 
 #define	NKEYS	(sizeof (keys)/sizeof (ua_key_t))
 
+/* Import default keys for ordinary useradd */
+void
+import_def(struct userdefs *ud)
+{
+	int i;
+
+	/* Don't import the user type (skip i = 0) */
+	for (i = 1; i < NKEYS; i++) {
+		if (keys[i].newvalue == NULL)
+			keys[i].newvalue =
+			    userdef_get_by_uakey(ud, keys[i].key);
+	}
+}
+
+/* Export command line keys to defaults for useradd -D */
+void
+update_def(struct userdefs *ud)
+{
+	int i;
+
+	for (i = 0; i < NKEYS; i++) {
+		if (keys[i].newvalue != NULL)
+			userdef_set_by_uakey(ud, keys[i].key,
+			    keys[i].newvalue);
+	}
+}
+
 /*
  * Change a key, there are three different call sequences:
  *
--- old/usr/src/cmd/oamuser/user/funcs.h	Mon Mar 27 17:24:29 2017
+++ new/usr/src/cmd/oamuser/user/funcs.h	Mon Mar 27 17:24:29 2017
@@ -43,6 +43,9 @@
 
 int is_role(char *usertype);
 
+struct userdefs;
+void import_def(struct userdefs *ud);
+void update_def(struct userdefs *ud);
 void change_key(const char *, char *);
 void addkey_args(char **, int *);
 char *getsetdefval(const char *, char *);
--- old/usr/src/cmd/oamuser/user/useradd.c	Mon Mar 27 17:24:29 2017
+++ new/usr/src/cmd/oamuser/user/useradd.c	Mon Mar 27 17:24:29 2017
@@ -95,8 +95,6 @@
 extern int edit_project();
 extern int **valid_lgroup();
 extern projid_t **valid_lproject();
-extern void update_def(struct userdefs *);
-extern void import_def(struct userdefs *);
 extern int get_default_zfs_flags();
 
 static uid_t uid;			/* new uid */
--- old/usr/src/cmd/oamuser/user/userdefs.c	Mon Mar 27 17:24:29 2017
+++ new/usr/src/cmd/oamuser/user/userdefs.c	Mon Mar 27 17:24:29 2017
@@ -55,172 +55,24 @@
 		(void) fprintf(fptr, "\n"); \
 	}
 
-#define	SKIPWS(ptr)	while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++
-
-static char *dup_to_nl(char *);
-
-static struct userdefs defaults = {
-	DEFRID, DEFGROUP, DEFGNAME, DEFPARENT, DEFSKL,
-	DEFSHL, DEFINACT, DEFEXPIRE, DEFAUTH, DEFPROF,
-	DEFROLE, DEFPROJ, DEFPROJNAME, DEFLIMPRIV,
-	DEFDFLTPRIV, DEFLOCK_AFTER_RETRIES
-};
-
-#define	INT	0
-#define	STR	1
-#define	PROJID	2
-
-#define	DEFOFF(field)		offsetof(struct userdefs, field)
-#define	FIELD(up, pe, type)	(*(type *)((char *)(up) + (pe)->off))
-
-typedef struct parsent {
-	const char *name;	/* deffoo= */
-	const size_t nmsz;	/* length of def= string (excluding \0) */
-	const int type;		/* type of entry */
-	const ptrdiff_t off;	/* offset in userdefs structure */
-	const char *uakey;	/* user_attr key, if defined */
-} parsent_t;
-
-static const parsent_t tab[] = {
-	{ GIDSTR,	sizeof (GIDSTR) - 1,	INT,	DEFOFF(defgroup) },
-	{ GNAMSTR,	sizeof (GNAMSTR) - 1,	STR,	DEFOFF(defgname) },
-	{ PARSTR,	sizeof (PARSTR) - 1,	STR,	DEFOFF(defparent) },
-	{ SKLSTR,	sizeof (SKLSTR) - 1,	STR,	DEFOFF(defskel) },
-	{ SHELLSTR,	sizeof (SHELLSTR) - 1,	STR,	DEFOFF(defshell) },
-	{ INACTSTR,	sizeof (INACTSTR) - 1,	INT,	DEFOFF(definact) },
-	{ EXPIRESTR,	sizeof (EXPIRESTR) - 1,	STR,	DEFOFF(defexpire) },
-	{ AUTHSTR,	sizeof (AUTHSTR) - 1,	STR,	DEFOFF(defauth),
-		USERATTR_AUTHS_KW },
-	{ ROLESTR,	sizeof (ROLESTR) - 1,	STR,	DEFOFF(defrole),
-		USERATTR_ROLES_KW },
-	{ PROFSTR,	sizeof (PROFSTR) - 1,	STR,	DEFOFF(defprof),
-		USERATTR_PROFILES_KW },
-	{ PROJSTR,	sizeof (PROJSTR) - 1,	PROJID,	DEFOFF(defproj) },
-	{ PROJNMSTR,	sizeof (PROJNMSTR) - 1,	STR,	DEFOFF(defprojname) },
-	{ LIMPRSTR,	sizeof (LIMPRSTR) - 1,	STR,	DEFOFF(deflimpriv),
-		USERATTR_LIMPRIV_KW },
-	{ DFLTPRSTR,	sizeof (DFLTPRSTR) - 1,	STR,	DEFOFF(defdfltpriv),
-		USERATTR_DFLTPRIV_KW },
-	{ LOCK_AFTER_RETRIESSTR,	sizeof (LOCK_AFTER_RETRIESSTR) - 1,
-		STR,	DEFOFF(deflock_after_retries),
-		USERATTR_LOCK_AFTER_RETRIES_KW },
-};
-
-#define	NDEF	(sizeof (tab) / sizeof (parsent_t))
-
-FILE *defptr;		/* default file - fptr */
-
-static const parsent_t *
-scan(char **start_p)
-{
-	static int ind = NDEF - 1;
-	char *cur_p = *start_p;
-	int lastind = ind;
-
-	if (!*cur_p || *cur_p == '\n' || *cur_p == '#')
-		return (NULL);
-
-	/*
-	 * The magic in this loop is remembering the last index when
-	 * reentering the function; the entries above are also used to
-	 * order the output to the default file.
-	 */
-	do {
-		ind++;
-		ind %= NDEF;
-
-		if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) {
-			*start_p = cur_p + tab[ind].nmsz;
-			return (&tab[ind]);
-		}
-	} while (ind != lastind);
-
-	return (NULL);
-}
-
 /*
- * getusrdef - access the user defaults file.  If it doesn't exist,
- *		then returns default values of (values in userdefs.h):
- *		defrid = 100
- *		defgroup = 1
- *		defgname = other
- *		defparent = /home
- *		defskel	= /usr/sadm/skel
- *		defshell = /bin/sh
- *		definact = 0
- *		defexpire = 0
- *		defauth = 0
- *		defprof = 0
- *		defrole = 0
- *
- *	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.
+ * getusrdef - get the user defaults file for the type of
+ * user entry (user or role).  See libuserdefs
  */
 
 struct userdefs *
 getusrdef(char *usertype)
 {
-	char instr[512], *ptr;
-	const parsent_t *pe;
+	struct userdefs *ud;
 
-	if (is_role(usertype)) {
-		if ((defptr = fopen(DEFROLEFILE, "r")) == NULL) {
-			defaults.defshell = DEFROLESHL;
-			defaults.defprof = DEFROLEPROF;
-			return (&defaults);
-		}
-	} else {
-		if ((defptr = fopen(DEFFILE, "r")) == NULL)
-			return (&defaults);
-	}
+	if (is_role(usertype))
+		ud = _get_roledefs();
+	else
+		ud = _get_userdefs();
 
-	while (fgets(instr, sizeof (instr), defptr) != NULL) {
-		ptr = instr;
-
-		SKIPWS(ptr);
-
-		if (*ptr == '#')
-			continue;
-
-		pe = scan(&ptr);
-
-		if (pe != NULL) {
-			switch (pe->type) {
-			case INT:
-				FIELD(&defaults, pe, int) =
-					(int)strtol(ptr, NULL, 10);
-				break;
-			case PROJID:
-				FIELD(&defaults, pe, projid_t) =
-					(projid_t)strtol(ptr, NULL, 10);
-				break;
-			case STR:
-				FIELD(&defaults, pe, char *) = dup_to_nl(ptr);
-				break;
-			}
-		}
-	}
-
-	(void) fclose(defptr);
-
-	return (&defaults);
+	return (ud);
 }
 
-static char *
-dup_to_nl(char *from)
-{
-	char *res = strdup(from);
-
-	char *p = strchr(res, '\n');
-	if (p)
-		*p = '\0';
-
-	return (res);
-}
-
 void
 dispusrdef(FILE *fptr, unsigned flags, char *usertype)
 {
@@ -231,7 +83,7 @@
 
 	if (flags & D_GROUP) {
 		outcount += fprintf(fptr, "group=%s,%ld  ",
-			deflts->defgname, deflts->defgroup);
+		    deflts->defgname, deflts->defgroup);
 		PRINTNL();
 	}
 
@@ -289,13 +141,13 @@
 
 	if (flags & D_LPRIV) {
 		outcount += fprintf(fptr, "limitpriv=%s  ",
-			deflts->deflimpriv);
+		    deflts->deflimpriv);
 		PRINTNL();
 	}
 
 	if (flags & D_DPRIV) {
 		outcount += fprintf(fptr, "defaultpriv=%s  ",
-			deflts->defdfltpriv);
+		    deflts->defdfltpriv);
 		PRINTNL();
 	}
 
@@ -315,118 +167,45 @@
 int
 putusrdef(struct userdefs *defs, char *usertype)
 {
-	time_t timeval;		/* time value from time */
-	int i;
-	ptrdiff_t skip;
-	char *hdr;
+	FILE *fp = NULL;	/* default file - fptr */
+	boolean_t locked = B_FALSE;
+	int res;
+	int ex = EX_UPDATE;
 
-	/*
-	 * file format is:
-	 * #<tab>Default values for adduser.  Changed mm/dd/yy hh:mm:ss.
-	 * defgroup=m	(m=default group id)
-	 * defgname=str1	(str1=default group name)
-	 * defparent=str2	(str2=default base directory)
-	 * definactive=x	(x=default inactive)
-	 * defexpire=y		(y=default expire)
-	 * defproj=z		(z=numeric project id)
-	 * defprojname=str3	(str3=default project name)
-	 * ... etc ...
-	 */
-
 	if (is_role(usertype)) {
-		if ((defptr = fopen(DEFROLEFILE, "w")) == NULL) {
-			errmsg(M_FAILED);
-			return (EX_UPDATE);
-		}
+		fp = fopen(DEFROLEFILE, "w");
 	} else {
-		if ((defptr = fopen(DEFFILE, "w")) == NULL) {
-			errmsg(M_FAILED);
-			return (EX_UPDATE);
-		}
+		fp = fopen(DEFFILE, "w");
 	}
+	if (fp == NULL) {
+		errmsg(M_FAILED);
+		goto out;
+	}
 
-	if (lockf(fileno(defptr), F_LOCK, 0) != 0) {
+	if (lockf(fileno(fp), F_LOCK, 0) != 0) {
 		/* print error if can't lock whole of DEFFILE */
 		errmsg(M_UPDATE, "created");
-		return (EX_UPDATE);
+		goto out;
 	}
+	locked = B_TRUE;
 
 	if (is_role(usertype)) {
-		/* If it's a role, we must skip the defrole field */
-		skip = offsetof(struct userdefs, defrole);
-		hdr = FHEADER_ROLE;
+		res = fwrite_roledefs(fp, defs);
 	} else {
-		skip = -1;
-		hdr = FHEADER;
+		res = fwrite_userdefs(fp, defs);
 	}
-
-	/* get time */
-	timeval = time(NULL);
-
-	/* write it to file */
-	if (fprintf(defptr, "%s%s\n", hdr, ctime(&timeval)) <= 0) {
+	if (res <= 0) {
 		errmsg(M_UPDATE, "created");
-		return (EX_UPDATE);
+		goto out;
 	}
+	ex = EX_SUCCESS;
 
-	for (i = 0; i < NDEF; i++) {
-		int res = 0;
-
-		if (tab[i].off == skip)
-			continue;
-
-		switch (tab[i].type) {
-		case INT:
-			res = fprintf(defptr, "%s%d\n", tab[i].name,
-					FIELD(defs, &tab[i], int));
-			break;
-		case STR:
-			res = fprintf(defptr, "%s%s\n", tab[i].name,
-					FIELD(defs, &tab[i], char *));
-			break;
-		case PROJID:
-			res = fprintf(defptr, "%s%d\n", tab[i].name,
-					(int)FIELD(defs, &tab[i], projid_t));
-			break;
-		}
-
-		if (res <= 0) {
-			errmsg(M_UPDATE, "created");
-			return (EX_UPDATE);
-		}
+out:
+	if (fp != NULL) {
+		if (locked)
+			(void) lockf(fileno(fp), F_ULOCK, 0);
+		(void) fclose(fp);
 	}
 
-	(void) lockf(fileno(defptr), F_ULOCK, 0);
-	(void) fclose(defptr);
-
-	return (EX_SUCCESS);
-}
-
-/* Export command line keys to defaults for useradd -D */
-void
-update_def(struct userdefs *ud)
-{
-	int i;
-
-	for (i = 0; i < NDEF; i++) {
-		char *val;
-		if (tab[i].uakey != NULL &&
-		    (val = getsetdefval(tab[i].uakey, NULL)) != NULL)
-			FIELD(ud, &tab[i], char *) = val;
-	}
-}
-
-/* Import default keys for ordinary useradd */
-void
-import_def(struct userdefs *ud)
-{
-	int i;
-
-	for (i = 0; i < NDEF; i++) {
-		if (tab[i].uakey != NULL && tab[i].type == STR) {
-			char *val = FIELD(ud, &tab[i], char *);
-			if (val == getsetdefval(tab[i].uakey, val))
-				nkeys ++;
-		}
-	}
+	return (ex);
 }
--- old/usr/src/cmd/passwd/Makefile	Mon Mar 27 17:24:30 2017
+++ new/usr/src/cmd/passwd/Makefile	Mon Mar 27 17:24:30 2017
@@ -31,7 +31,7 @@
 passwd := LDLIBS += $(ROOT)/usr/lib/passwdutil.so.1 
 lint := LDLIBS += -lpasswdutil
 LDFLAGS += $(ZIGNORE)
-LDLIBS += -lbsm -lpam -lnsl
+LDLIBS += -luserdefs -lbsm -lpam -lnsl
 
 FILEMODE = 06555
 XGETFLAGS += -a -x $(PROG).xcl
--- old/usr/src/head/userdefs.h	Mon Mar 27 17:24:30 2017
+++ new/usr/src/head/userdefs.h	Mon Mar 27 17:24:30 2017
@@ -20,6 +20,8 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright 2016 Gordon W. Ross
+ *
  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -31,9 +33,8 @@
 #ifndef	_USERDEFS_H
 #define	_USERDEFS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.7.1.1 */
-
 #include <project.h>
+#include <stdio_tag.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -42,29 +43,32 @@
 /*
  * The definitions in this file are local to the OA&M subsystem.  General
  * use is not encouraged.
+ *
+ * Default values are taken from (in precedence order)
+ *	/etc/default/add{user,role}
+ *	/usr/sadm/defadd{user,role}
+ *	(compiled-in values)
+ *
+ * Note that the "old" default locations may be used as a
+ * "vendor" (or distro.) override of the compiled-in defaults.
+ * If an administrator runs "useradd -D ...", those values are
+ * stored in /etc/default/add*,  which overrides all others.
  */
 
-/* User/group default values */
-#define	DEFGID		99	/* max reserved group id */
-#define	DEFRID		99
-#define	DEFPROJ		3
-#define	DEFPROJNAME	"default"
-#define	DEFGROUP	1
-#define	DEFGNAME	"other"
-#define	DEFPARENT	"/home"
-#define	DEFSKL		"/etc/skel"
-#define	DEFSHL		"/bin/sh"
-#define	DEFROLESHL	"/bin/pfsh"
-#define	DEFINACT	0
-#define	DEFEXPIRE	""
-#define	DEFAUTH		""
-#define	DEFPROF		""
-#define	DEFROLEPROF	"All"
-#define	DEFROLE		""
-#define	DEFLIMPRIV	""
-#define	DEFDFLTPRIV	""
-#define	DEFLOCK_AFTER_RETRIES	""
+/* Defaults files */
+#define	DEFFILE		"/etc/default/adduser"
+#define	DEFROLEFILE	"/etc/default/addrole"
 
+/* Old defaults files */
+#define	ODEFFILE	"/usr/sadm/defadduser"
+#define	ODEFROLEFILE	"/usr/sadm/defaddrole"
+
+#define	GROUP		"/etc/group"
+
+/* various limits */
+#define	MAXGLEN		9	/* max length of group name */
+#define	MAXDLEN		80	/* max length of a date string */
+
 /* Defaults file keywords */
 #define	RIDSTR		"defrid="
 #define	GIDSTR		"defgroup="
@@ -85,15 +89,6 @@
 #define	FHEADER_ROLE	"#	Default values for roleadd.  Changed "
 #define	LOCK_AFTER_RETRIESSTR	"deflock_after_retries="
 
-/* Defaults file */
-#define	DEFFILE		"/usr/sadm/defadduser"
-#define	DEFROLEFILE	"/usr/sadm/defaddrole"
-#define	GROUP		"/etc/group"
-
-/* various limits */
-#define	MAXGLEN		9	/* max length of group name */
-#define	MAXDLEN		80	/* max length of a date string */
-
 /* defaults structure */
 struct userdefs {
 	int defrid;		/* highest reserved uid */
@@ -112,9 +107,66 @@
 	char *deflimpriv;	/* default limitpriv */
 	char *defdfltpriv;	/* default defaultpriv */
 	char *deflock_after_retries;	/* default lock_after_retries */
-
 };
 
+extern struct userdefs *_get_userdefs(void);
+extern struct userdefs *_get_roledefs(void);
+
+extern void fread_defs(FILE *fp, struct userdefs *, boolean_t);
+extern int fwrite_roledefs(struct __FILE *, struct userdefs *);
+extern int fwrite_userdefs(struct __FILE *, struct userdefs *);
+
+extern char *userdef_get_by_uakey(struct userdefs *, const char *);
+void userdef_set_by_uakey(struct userdefs *, const char *, char *);
+
+/*
+ * User/group default values
+ * These are constants _only_ when compiling libuserdefs
+ */
+#ifdef _USERDEFS_INTERNAL
+#define	DEFRID		99	/* max reserved group id */
+#define	DEFGROUP	1
+#define	DEFGNAME	"other"
+#define	DEFPARENT	"/home"
+#define	DEFSKL		"/etc/skel"
+#define	DEFSHL		"/bin/sh"
+#define	DEFROLESHL	"/bin/pfsh"
+#define	DEFINACT	0
+#define	DEFEXPIRE	""
+#define	DEFAUTH		""
+#define	DEFPROF		""
+#define	DEFROLEPROF	"All"
+#define	DEFROLE		""
+#define	DEFPROJ		3
+#define	DEFPROJNAME	"default"
+#define	DEFLIMPRIV	""
+#define	DEFDFLTPRIV	""
+#define	DEFLOCK_AFTER_RETRIES	""
+#else	/* _USERDEFS_INTERNAL */
+/* Get these from libuserdefs */
+#define	DEFRID		(_get_userdefs()->defrid)
+#define	DEFGROUP	(_get_userdefs()->defgroup)
+#define	DEFGNAME	(_get_userdefs()->defgname)
+#define	DEFPARENT	(_get_userdefs()->defparent)
+#define	DEFSKL		(_get_userdefs()->defskel)
+#define	DEFSHL		(_get_userdefs()->defshell)
+#define	DEFROLESHL	(_get_roledefs()->defshell)	/* ROLE */
+#define	DEFINACT	(_get_userdefs()->definact)
+#define	DEFEXPIRE	(_get_userdefs()->defexpire)
+#define	DEFAUTH		(_get_userdefs()->defauth)
+#define	DEFPROF		(_get_userdefs()->defprof
+#define	DEFROLEPROF	(_get_roledefs()->defprof)	/* ROLE */
+#define	DEFROLE		(_get_userdefs()->defrole)
+#define	DEFPROJ		(_get_userdefs()->defproj)
+#define	DEFPROJNAME	(_get_userdefs()->defprogname)
+#define	DEFLIMPRIV	(_get_userdefs()->deflimpriv)
+#define	DEFDFLTPRIV	(_get_userdefs()->defdfltpriv)
+#define	DEFLOCK_AFTER_RETRIES	(_get_userdefs()->deflock_after_retries)
+#endif	/* _USERDEFS_INTERNAL */
+
+/* DEFGID is an alias for DEFRID.  Misleading... (!= DEFGROUP) */
+#define	DEFGID		DEFRID		/* XXX delete this? */
+
 /* exit() values for user/group commands */
 
 /* Everything succeeded */
--- old/usr/src/lib/Makefile	Mon Mar 27 17:24:30 2017
+++ new/usr/src/lib/Makefile	Mon Mar 27 17:24:30 2017
@@ -223,6 +223,7 @@
 	libtsol		\
 	libumem		\
 	libunistat	\
+	libuserdefs	\
 	libuuid		\
 	libuutil	\
 	libvolmgt	\
--- old/usr/src/lib/libcmdutils/common/gid.c	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libcmdutils/common/gid.c	Mon Mar 27 17:24:31 2017
@@ -33,7 +33,6 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <stdio.h>
-#include <userdefs.h>
 #include <grp.h>
 #include <libcmdutils.h>
 
--- old/usr/src/lib/libcmdutils/common/uid.c	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libcmdutils/common/uid.c	Mon Mar 27 17:24:31 2017
@@ -34,7 +34,6 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <stdio.h>
-#include <userdefs.h>
 #include <pwd.h>
 #include <libcmdutils.h>
 
--- /dev/null	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libuserdefs/Makefile	Mon Mar 27 17:24:31 2017
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = $(MACH)
+# Not bothering with 64-bit libs for this.
+# $(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber lint: $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
--- /dev/null	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libuserdefs/Makefile.com	Mon Mar 27 17:24:31 2017
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY= 	libuserdefs.a
+VERS=		.1
+
+OBJECTS= 	defaults.o
+
+include ../../Makefile.lib
+
+LIBS=		$(DYNLIB) $(LINTLIB)
+
+SRCDIR=		../common
+
+LINTOUT =	lint.out
+
+LINTSRC =	$(LINTLIB:%.ln=%)
+ROOTLINTDIR =	$(ROOTLIBDIR)
+ROOTLINT =	$(LINTSRC:%=$(ROOTLINTDIR)/%)
+
+CPPFLAGS=	-I. -I$(SRCDIR) $(CPPFLAGS.master)
+LDLIBS +=	-lc
+
+LINTFLAGS=	-u
+LINTFLAGS +=	-erroff=E_BAD_PTR_CAST_ALIGN
+LINTFLAGS64 +=	-erroff=E_BAD_PTR_CAST_ALIGN
+
+$(LINTLIB) :=	SRCS= $(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all:		$(LIBS)
+
+lint:		lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libuserdefs/common/defaults.c	Mon Mar 27 17:24:31 2017
@@ -0,0 +1,466 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+/*
+ * Copyright (c) 2013 RackTop Systems.
+ *
+ * Copyright 2016 Gordon W. Ross
+ */
+
+/*
+ * Get values for things that were historically constants in userdefs.h
+ * i.e. DEFRID, DEFSHL
+ *
+ * Several things copied or moved from:
+ * $SRC/cmd/oamuser/user/userdefs.c
+ */
+
+/*LINTLIBRARY*/
+#define	_USERDEFS_INTERNAL 1
+
+#include	<sys/types.h>
+#include	<stdio.h>
+#include	<string.h>
+#include	<userdefs.h>
+#include	<user_attr.h>
+#include	<limits.h>
+#include	<stdlib.h>
+#include	<stddef.h>
+#include	<time.h>
+#include	<unistd.h>
+
+#define	STR_SZ	512
+#define	SKIPWS(ptr)	while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++
+
+static char *zap_nl(char *);
+static int fwrite_defs(FILE *, struct userdefs *, char *, ptrdiff_t);
+
+static char user_defgname[STR_SZ]  = DEFGNAME;
+static char user_defparent[STR_SZ] = DEFPARENT;
+static char user_defskel[STR_SZ]   = DEFSKL;
+static char user_defshell[STR_SZ]  = DEFSHL;
+static char user_defexpire[STR_SZ] = DEFEXPIRE;
+static char user_defauth[STR_SZ]   = DEFAUTH;
+static char user_defprof[STR_SZ]   = DEFPROF;
+static char user_defrole[STR_SZ]   = DEFROLE;
+static char user_defprojname[STR_SZ] = DEFPROJNAME;
+static char user_deflimpriv[STR_SZ]  = DEFLIMPRIV;
+static char user_defdfltpriv[STR_SZ] = DEFDFLTPRIV;
+static char user_deflock_a_r[STR_SZ] = DEFLOCK_AFTER_RETRIES;
+
+static struct userdefs userdefs = {
+	DEFRID,
+	DEFGROUP,
+	user_defgname,
+	user_defparent,
+	user_defskel,
+	user_defshell,
+	DEFINACT,
+	user_defexpire,
+	user_defauth,
+	user_defprof,
+	user_defrole,
+	DEFPROJ,
+	user_defprojname,
+	user_deflimpriv,
+	user_defdfltpriv,
+	user_deflock_a_r
+};
+
+static char role_defgname[STR_SZ]  = DEFGNAME;
+static char role_defparent[STR_SZ] = DEFPARENT;
+static char role_defskel[STR_SZ]   = DEFSKL;
+static char role_defshell[STR_SZ]  = DEFROLESHL;	/* role! */
+static char role_defexpire[STR_SZ] = DEFEXPIRE;
+static char role_defauth[STR_SZ]   = DEFAUTH;
+static char role_defprof[STR_SZ]   = DEFROLEPROF;	/* role! */
+static char role_defprojname[STR_SZ] = DEFPROJNAME;
+static char role_deflimpriv[STR_SZ]  = DEFLIMPRIV;
+static char role_defdfltpriv[STR_SZ] = DEFDFLTPRIV;
+static char role_deflock_a_r[STR_SZ] = DEFLOCK_AFTER_RETRIES;
+
+static struct userdefs roledefs = {
+	DEFRID,
+	DEFGROUP,
+	role_defgname,
+	role_defparent,
+	role_defskel,
+	role_defshell,
+	DEFINACT,
+	role_defexpire,
+	role_defauth,
+	role_defprof,
+	"",		/* not changeable */
+	DEFPROJ,
+	role_defprojname,
+	role_deflimpriv,
+	role_defdfltpriv,
+	role_deflock_a_r
+};
+
+#define	INT	0
+#define	STR	1
+#define	PROJID	2
+
+#define	DEFOFF(field)		offsetof(struct userdefs, field)
+#define	FIELD(up, pe, type)	(*(type *)((char *)(up) + (pe)->off))
+
+typedef struct parsent {
+	const char *name;	/* deffoo= */
+	const size_t nmsz;	/* length of def= string (excluding \0) */
+	const int type;		/* type of entry */
+	const ptrdiff_t off;	/* offset in userdefs structure */
+	const char *uakey;	/* user_attr key, if defined */
+} parsent_t;
+
+/* BEGIN CSTYLED */
+static const parsent_t tab[] = {
+	{ RIDSTR,	sizeof (RIDSTR) - 1,	INT,	DEFOFF(defrid) },	/* DEFRID */
+	{ GIDSTR,	sizeof (GIDSTR) - 1,	INT,	DEFOFF(defgroup) },	/* DEFGROUP */
+	{ GNAMSTR,	sizeof (GNAMSTR) - 1,	STR,	DEFOFF(defgname) },	/* DEFGNAME */
+	{ PARSTR,	sizeof (PARSTR) - 1,	STR,	DEFOFF(defparent) },	/* DEFPARENT */
+	{ SKLSTR,	sizeof (SKLSTR) - 1,	STR,	DEFOFF(defskel) },	/* DEFSKL */
+	{ SHELLSTR,	sizeof (SHELLSTR) - 1,	STR,	DEFOFF(defshell) },	/* DEFSHL, DEFROLESHL */
+	{ INACTSTR,	sizeof (INACTSTR) - 1,	INT,	DEFOFF(definact) },	/* DEFINACT */
+	{ EXPIRESTR,	sizeof (EXPIRESTR) - 1,	STR,	DEFOFF(defexpire) },	/* DEFEXPIRE */
+	{ AUTHSTR,	sizeof (AUTHSTR) - 1,	STR,	DEFOFF(defauth),	/* DEFAUTH */
+		USERATTR_AUTHS_KW },
+	{ PROFSTR,	sizeof (PROFSTR) - 1,	STR,	DEFOFF(defprof),	/* DEFPROF, DEFROLEPROF */
+		USERATTR_PROFILES_KW },
+	{ ROLESTR,	sizeof (ROLESTR) - 1,	STR,	DEFOFF(defrole),	/* DEFROLE */
+		USERATTR_ROLES_KW },
+	{ PROJSTR,	sizeof (PROJSTR) - 1,	PROJID,	DEFOFF(defproj) },	/* DEFPROJ */
+	{ PROJNMSTR,	sizeof (PROJNMSTR) - 1,	STR,	DEFOFF(defprojname) },	/* DEFPROJNAME */
+	{ LIMPRSTR,	sizeof (LIMPRSTR) - 1,	STR,	DEFOFF(deflimpriv),	/* DEFLIMPRIV */
+		USERATTR_LIMPRIV_KW },
+	{ DFLTPRSTR,	sizeof (DFLTPRSTR) - 1,	STR,	DEFOFF(defdfltpriv),	/* DEFDFLTPRIV */
+		USERATTR_DFLTPRIV_KW },
+	{ LOCK_AFTER_RETRIESSTR,	sizeof (LOCK_AFTER_RETRIESSTR) - 1,	/* DEFLOCK_AFTER_RETRIES */
+		STR,	DEFOFF(deflock_after_retries),
+		USERATTR_LOCK_AFTER_RETRIES_KW },
+};
+/* END CSTYLED */
+
+#define	NDEF	(sizeof (tab) / sizeof (parsent_t))
+
+static const parsent_t *
+scan(char **start_p)
+{
+	static int ind = NDEF - 1;
+	char *cur_p = *start_p;
+	int lastind = ind;
+
+	if (!*cur_p || *cur_p == '\n' || *cur_p == '#')
+		return (NULL);
+
+	/*
+	 * The magic in this loop is remembering the last index when
+	 * reentering the function; the entries above are also used to
+	 * order the output to the default file.
+	 */
+	do {
+		ind++;
+		ind %= NDEF;
+
+		if (strncmp(cur_p, tab[ind].name, tab[ind].nmsz) == 0) {
+			*start_p = cur_p + tab[ind].nmsz;
+			return (&tab[ind]);
+		}
+	} while (ind != lastind);
+
+	return (NULL);
+}
+
+/*
+ * getusrdef - access the user defaults file.  If it doesn't exist,
+ *		then returns default values of (values in userdefs.h):
+ *		defrid = 100
+ *		defgroup = 1
+ *		defgname = other
+ *		defparent = /home
+ *		defskel	= /usr/sadm/skel
+ *		defshell = /bin/sh
+ *		definact = 0
+ *		defexpire = 0
+ *		defauth = 0
+ *		defprof = 0
+ *		defrole = 0
+ *
+ *	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.
+ *
+ *	Note that the userdefs_loaded, roledefs_loaded flags are
+ *	more than an optimization.  Once we've return the struct
+ *	to the caller, they may change any of the string members
+ *	with pointers to constant strings etc.  If we were to run
+ *	fread_defs() after that, it could segv trying to copy the
+ *	strings from the scanner onto those constant strings.
+ */
+
+static int roledefs_loaded = 0;
+
+struct userdefs *
+_get_roledefs()
+{
+	FILE *fp;
+
+	if (roledefs_loaded == 0) {
+
+		fp = fopen(ODEFROLEFILE, "r");
+		if (fp != NULL) {
+			fread_defs(fp, &roledefs, B_TRUE);
+			(void) fclose(fp);
+		}
+
+		fp = fopen(DEFROLEFILE, "r");
+		if (fp != NULL) {
+			fread_defs(fp, &roledefs, B_TRUE);
+			(void) fclose(fp);
+		}
+
+		roledefs_loaded = 1;
+	}
+	return (&roledefs);
+}
+
+static int userdefs_loaded = 0;
+
+struct userdefs *
+_get_userdefs()
+{
+	FILE *fp;
+
+	if (userdefs_loaded == 0) {
+
+		fp = fopen(ODEFFILE, "r");
+		if (fp != NULL) {
+			fread_defs(fp, &userdefs, B_FALSE);
+			(void) fclose(fp);
+		}
+
+		fp = fopen(DEFFILE, "r");
+		if (fp != NULL) {
+			fread_defs(fp, &userdefs, B_FALSE);
+			(void) fclose(fp);
+		}
+
+		userdefs_loaded = 1;
+	}
+	return (&userdefs);
+}
+
+void
+fread_defs(FILE *fp, struct userdefs *ud, boolean_t role)
+{
+	char instr[STR_SZ], *ptr;
+	const parsent_t *pe;
+
+	while (fgets(instr, sizeof (instr), fp) != NULL) {
+		ptr = instr;
+
+		SKIPWS(ptr);
+
+		if (*ptr == '#')
+			continue;
+
+		pe = scan(&ptr);
+
+		if (pe != NULL) {
+			/*
+			 * If reading a role file, should not see defrole,
+			 * but in case we do, just skip it.
+			 */
+			if (role && pe->off == DEFOFF(defrole))
+				continue;
+
+			switch (pe->type) {
+			case INT:
+				FIELD(ud, pe, int) =
+				    (int)strtol(ptr, NULL, 10);
+				break;
+			case PROJID:
+				FIELD(ud, pe, projid_t) =
+				    (projid_t)strtol(ptr, NULL, 10);
+				break;
+			case STR:
+				/*
+				 * Copy into static storage here (avoiding
+				 * strdup) so _get_userdefs() doesn't leak.
+				 * In here we know the userdefs struct has
+				 * all STR struct members pointing to our
+				 * static buffers of size STR_SZ.
+				 */
+				(void) strlcpy(FIELD(ud, pe, char *),
+				    zap_nl(ptr), STR_SZ);
+				break;
+			}
+		}
+	}
+}
+
+static char *
+zap_nl(char *s)
+{
+	char *p = strchr(s, '\n');
+	if (p != NULL)
+		*p = '\0';
+
+	return (s);
+}
+
+extern int
+fwrite_roledefs(struct __FILE *fp, struct userdefs *defs)
+{
+	ptrdiff_t skip;
+	char *hdr;
+
+	/* This is a role, so we must skip the defrole field */
+	skip = offsetof(struct userdefs, defrole);
+	hdr = FHEADER_ROLE;
+
+	return (fwrite_defs(fp, defs, hdr, skip));
+}
+
+extern int
+fwrite_userdefs(struct __FILE *fp, struct userdefs *defs)
+{
+	ptrdiff_t skip;
+	char *hdr;
+
+	skip = -1;
+	hdr = FHEADER;
+
+	return (fwrite_defs(fp, defs, hdr, skip));
+}
+
+/*
+ * fwrite_defs
+ * 	changes default values in defadduser file
+ * Returns:
+ *  <= 0: error
+ * > 0: success
+ */
+static int
+fwrite_defs(FILE *fp, struct userdefs *defs, char *hdr, ptrdiff_t skip)
+{
+	time_t timeval;		/* time value from time */
+	int i, res;
+
+	/*
+	 * file format is:
+	 * #<tab>Default values for adduser.  Changed mm/dd/yy hh:mm:ss.
+	 * defgroup=m	(m=default group id)
+	 * defgname=str1	(str1=default group name)
+	 * defparent=str2	(str2=default base directory)
+	 * definactive=x	(x=default inactive)
+	 * defexpire=y		(y=default expire)
+	 * defproj=z		(z=numeric project id)
+	 * defprojname=str3	(str3=default project name)
+	 * ... etc ...
+	 */
+
+	/* get time */
+	timeval = time(NULL);
+
+	/* write it to file */
+	res = fprintf(fp, "%s%s\n", hdr, ctime(&timeval));
+	if (res <= 0)
+		return (res);
+
+	for (i = 0; i < NDEF; i++) {
+		res = 0;
+
+		if (tab[i].off == skip)
+			continue;
+
+		switch (tab[i].type) {
+		case INT:
+			res = fprintf(fp, "%s%d\n", tab[i].name,
+			    FIELD(defs, &tab[i], int));
+			break;
+		case STR:
+			res = fprintf(fp, "%s%s\n", tab[i].name,
+			    FIELD(defs, &tab[i], char *));
+			break;
+		case PROJID:
+			res = fprintf(fp, "%s%d\n", tab[i].name,
+			    (int)FIELD(defs, &tab[i], projid_t));
+			break;
+		}
+
+		if (res <= 0) {
+			return (res);
+		}
+	}
+
+	return (1);
+}
+
+/*
+ * Import a default key for ordinary useradd.
+ * Caller already did: ud = getusrdef();
+ */
+char *
+userdef_get_by_uakey(struct userdefs *ud, const char *key)
+{
+	int i;
+
+	for (i = 0; i < NDEF; i++) {
+		if (tab[i].uakey != NULL &&
+		    tab[i].type == STR &&
+		    strcmp(tab[i].uakey, key) == 0)
+			return (FIELD(ud, &tab[i], char *));
+	}
+	return (NULL);
+}
+
+/* Export a command line key to defaults for useradd -D */
+void
+userdef_set_by_uakey(struct userdefs *ud, const char *key, char *val)
+{
+	int i;
+
+	for (i = 0; i < NDEF; i++) {
+		if (tab[i].uakey != NULL &&
+		    tab[i].type == STR &&
+		    strcmp(tab[i].uakey, key) == 0) {
+			/*
+			 * Don't strlcpy here because the calling program
+			 * may have changed the struct member to point to
+			 * something other than our static buffers.
+			 * If this leaks, it's the caller's fault.
+			 */
+			FIELD(ud, &tab[i], char *) = val;
+		}
+	}
+}
--- /dev/null	Mon Mar 27 17:24:31 2017
+++ new/usr/src/lib/libuserdefs/common/llib-luserdefs	Mon Mar 27 17:24:31 2017
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <sys/types.h>
+#include <userdefs.h>
--- /dev/null	Mon Mar 27 17:24:32 2017
+++ new/usr/src/lib/libuserdefs/common/mapfile-vers	Mon Mar 27 17:24:32 2017
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2016 Gordon W. Ross
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.1 {
+    global:
+	_get_roledefs;
+	_get_userdefs;
+	fread_defs;
+	fwrite_roledefs;
+	fwrite_userdefs;
+	userdef_set_by_uakey;
+	userdef_get_by_uakey;
+
+    local:
+	*;
+};
--- /dev/null	Mon Mar 27 17:24:32 2017
+++ new/usr/src/lib/libuserdefs/i386/Makefile	Mon Mar 27 17:24:32 2017
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Mon Mar 27 17:24:32 2017
+++ new/usr/src/lib/libuserdefs/sparc/Makefile	Mon Mar 27 17:24:32 2017
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- old/usr/src/lib/pam_modules/unix_auth/unix_auth.c	Mon Mar 27 17:24:32 2017
+++ new/usr/src/lib/pam_modules/unix_auth/unix_auth.c	Mon Mar 27 17:24:32 2017
@@ -34,7 +34,6 @@
 #include <unistd.h>
 #include <user_attr.h>
 #include <auth_attr.h>
-#include <userdefs.h>
 #include <deflt.h>
 #include <sys/stat.h>
 #include <sys/param.h>
--- old/usr/src/pkg/manifests/developer-library-lint.mf	Mon Mar 27 17:24:32 2017
+++ new/usr/src/pkg/manifests/developer-library-lint.mf	Mon Mar 27 17:24:32 2017
@@ -319,6 +319,8 @@
 file path=usr/lib/llib-lsldap.ln
 file path=usr/lib/llib-lsmbios
 file path=usr/lib/llib-lsmbios.ln
+file path=usr/lib/llib-luserdefs
+file path=usr/lib/llib-luserdefs.ln
 $(sparc_ONLY)file path=usr/lib/llib-lv12n
 $(sparc_ONLY)file path=usr/lib/llib-lv12n.ln
 file path=usr/lib/llib-lvolmgt
--- old/usr/src/pkg/manifests/system-library.mf	Mon Mar 27 17:24:32 2017
+++ new/usr/src/pkg/manifests/system-library.mf	Mon Mar 27 17:24:32 2017
@@ -444,6 +444,7 @@
 file path=usr/lib/libsoftcrypto.so.1
 file path=usr/lib/libsum.so.1
 file path=usr/lib/libsys.so.1
+file path=usr/lib/libuserdefs.so.1
 $(sparc_ONLY)file path=usr/lib/libv12n.so.1
 file path=usr/lib/libvolmgt.so.1
 file path=usr/lib/libwrap.so.1.0
@@ -1187,6 +1188,7 @@
 link path=usr/lib/libtsol.so.2 target=../../lib/libtsol.so.2
 link path=usr/lib/libumem.so target=../../lib/libumem.so.1
 link path=usr/lib/libumem.so.1 target=../../lib/libumem.so.1
+link path=usr/lib/libuserdefs.so target=./libuserdefs.so.1
 link path=usr/lib/libuuid.so target=../../lib/libuuid.so.1
 link path=usr/lib/libuuid.so.1 target=../../lib/libuuid.so.1
 link path=usr/lib/libuutil.so.1 target=../../lib/libuutil.so.1
--- old/usr/src/pkg/manifests/system-test-utiltest.mf	Mon Mar 27 17:24:33 2017
+++ new/usr/src/pkg/manifests/system-test-utiltest.mf	Mon Mar 27 17:24:33 2017
@@ -28,7 +28,10 @@
 dir path=opt/util-tests/tests/dis/i386
 dir path=opt/util-tests/tests/dis/sparc
 dir path=opt/util-tests/tests/libnvpair_json
+dir path=opt/util-tests/tests/libuserdefs
 file path=opt/util-tests/README mode=0444
+file path=opt/util-tests/bin/oamu_defs mode=0555
+file path=opt/util-tests/bin/oamu_uakey mode=0555
 file path=opt/util-tests/bin/print_json mode=0555
 file path=opt/util-tests/bin/utiltest mode=0555
 file path=opt/util-tests/runfiles/default.run mode=0444
@@ -154,6 +157,9 @@
 file path=opt/util-tests/tests/libnvpair_json/json_06_nested mode=0555
 file path=opt/util-tests/tests/libnvpair_json/json_07_nested_arrays mode=0555
 file path=opt/util-tests/tests/libnvpair_json/json_common mode=0555
+file path=opt/util-tests/tests/libuserdefs/oamu_01 mode=0555
+file path=opt/util-tests/tests/libuserdefs/oamu_02 mode=0555
+file path=opt/util-tests/tests/libuserdefs/oamu_03 mode=0555
 file path=opt/util-tests/tests/printf_test mode=0555
 file path=opt/util-tests/tests/xargs_test mode=0555
 license lic_CDDL license=lic_CDDL
--- old/usr/src/test/util-tests/tests/Makefile	Mon Mar 27 17:24:33 2017
+++ new/usr/src/test/util-tests/tests/Makefile	Mon Mar 27 17:24:33 2017
@@ -14,6 +14,6 @@
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 #
 
-SUBDIRS = dis dladm iconv libnvpair_json printf xargs
+SUBDIRS = dis dladm iconv libnvpair_json libuserdefs printf xargs
 
 include $(SRC)/test/Makefile.com
--- /dev/null	Mon Mar 27 17:24:33 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/Makefile	Mon Mar 27 17:24:33 2017
@@ -0,0 +1,52 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2014 Joyent, Inc.
+# Copyright 2017 Gordon W. Ross
+#
+
+# OAM User Test program
+PROG=		oamu_defs oamu_uakey
+TESTS=		oamu_01 oamu_02 oamu_03
+
+include $(SRC)/cmd/Makefile.cmd
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+ROOTCMDDIR = $(ROOTOPTPKG)/bin
+TESTDIR    = $(ROOTOPTPKG)/tests/libuserdefs
+ROOTTESTS  = $(TESTS:%=$(TESTDIR)/%)
+
+LDLIBS += -luserdefs
+
+all: $(PROG)
+
+install: $(ROOTCMD) $(ROOTTESTS)
+$(ROOTTESTS) : $(TESTDIR)
+$(ROOTCMD) : $(PROG)
+
+clean:
+
+# lint_PROG doesn't handle multiple programs...
+lint:
+	for p in $(PROG); do \
+	$(LINT.c) $$p.c $(LDLIBS) ;\
+	done
+
+$(TESTDIR)/%: %.ksh
+	$(INS.rename)
+
+$(TESTDIR):
+	$(INS.dir)
+
+.KEEP_STATE:
+
+include $(SRC)/cmd/Makefile.targ
--- /dev/null	Mon Mar 27 17:24:33 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/oamu_01.ksh	Mon Mar 27 17:24:33 2017
@@ -0,0 +1,87 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Gordon W. Ross
+#
+
+errs=
+DEFS=$ROOT/opt/util-tests/bin/oamu_defs
+if [ -n "$ROOT" ] ; then
+  export LD_LIBRARY_PATH=$ROOT/usr/lib
+fi
+
+#
+# Make test data files
+#
+
+# user.def (same as compiled-in defaults)
+echo '
+defrid=99
+defgroup=1
+defgname=other
+defparent=/home
+defskel=/etc/skel
+defshell=/bin/sh
+definact=0
+defexpire=
+defauthorization=
+defprofile=
+defrole=
+defproj=3
+defprojname=default
+deflimitpriv=
+defdefaultpriv=
+deflock_after_retries=' > user.def
+
+# user.tst (different from defaults)
+echo '
+defrid=1001
+defgroup=20
+defgname=test20group
+defparent=/tank/home
+defskel=/etc/skel.testuser
+defshell=/bin/pfsh.testuser
+definact=0
+defexpire=
+defauthorization=
+defprofile=TestUser
+defrole=TestRole
+defproj=4
+defprojname=TestProj
+deflimitpriv=TestLimPriv
+defdefaultpriv=TestDefPriv
+deflock_after_retries=' > user.tst
+
+#
+# Run some tests
+#
+
+# Override compiled-in user defaults
+$DEFS user.def |tail +2 > user1.out
+if cmp -s user.def user1.out ; then
+    echo "PASS: user1.out"
+else
+    echo "FAIL: user1.out is wrong"
+    errs="$errs user1.out"
+fi
+
+# Override user.def values
+$DEFS user.def user.tst |tail +2 > user2.out
+if cmp -s user.tst user2.out ; then
+    echo "PASS: user2.out"
+else
+    echo "FAIL: user2.out is wrong"
+    errs="$errs user2.out"
+fi
+
+rm -f user.def user.tst user1.out user2.out
--- /dev/null	Mon Mar 27 17:24:34 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/oamu_02.ksh	Mon Mar 27 17:24:34 2017
@@ -0,0 +1,85 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Gordon W. Ross
+#
+
+errs=
+DEFS=$ROOT/opt/util-tests/bin/oamu_defs
+if [ -n "$ROOT" ] ; then
+  export LD_LIBRARY_PATH=$ROOT/usr/lib
+fi
+
+#
+# Make test data files
+#
+
+# role.def (same as compiled-in defaults)
+echo '
+defrid=99
+defgroup=1
+defgname=other
+defparent=/home
+defskel=/etc/skel
+defshell=/bin/pfsh
+definact=0
+defexpire=
+defauthorization=
+defprofile=All
+defproj=3
+defprojname=default
+deflimitpriv=
+defdefaultpriv=
+deflock_after_retries=' > role.def
+
+# role.tst (different from defaults)
+echo '
+defrid=101
+defgroup=10
+defgname=testrole
+defparent=/home/testrole
+defskel=/etc/skel.testrole
+defshell=/bin/pfsh.testrole
+definact=0
+defexpire=
+defauthorization=
+defprofile=All,TestRole
+defproj=4
+defprojname=default
+deflimitpriv=
+defdefaultpriv=
+deflock_after_retries=' > role.tst
+
+#
+# Run some tests
+#
+
+# Override compiled-in role defaults
+$DEFS -r role.def |tail +2 > role1.out
+if cmp -s role.def role1.out ; then
+    echo "PASS: role1.out"
+else
+    echo "FAIL: role1.out is wrong"
+    errs="$errs role1.out"
+fi
+
+# Override role.def values
+$DEFS -r role.def role.tst |tail +2 > role2.out
+if cmp -s role.tst role2.out ; then
+    echo "PASS: role2.out"
+else
+    echo "FAIL: role2.out is wrong"
+    errs="$errs role2.out"
+fi
+
+rm -f role.def role.tst role1.out role2.out
--- /dev/null	Mon Mar 27 17:24:34 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/oamu_03.ksh	Mon Mar 27 17:24:34 2017
@@ -0,0 +1,75 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2017 Gordon W. Ross
+#
+
+errs=
+UAKEY=$ROOT/opt/util-tests/bin/oamu_uakey
+if [ -n "$ROOT" ] ; then
+  export LD_LIBRARY_PATH=$ROOT/usr/lib
+fi
+
+#
+# Make test data files
+#
+# uakey.tst (what we should get)
+echo '
+defrid=123
+defgroup=456
+defgname=TestGroup
+defparent=TestDefParent
+defskel=TestDefSkel
+defshell=TestDefShell
+definact=3
+defexpire=TestDefExpire
+defauthorization=TestAuths
+defprofile=TestProfiles
+defrole=TestRoles
+defproj=7
+defprojname=TestProject
+deflimitpriv=TestLimPriv
+defdefaultpriv=TestDefPriv
+deflock_after_retries=TestLAR' > user.tst
+
+
+#
+# Run some tests
+#
+# Override all the values we can with non-defaults.
+#define	USERATTR_TYPE_KW		"type"
+#define	USERATTR_AUTHS_KW		"auths"
+#define	USERATTR_PROFILES_KW		"profiles"
+#define	USERATTR_ROLES_KW		"roles"
+#define	USERATTR_DEFAULTPROJ_KW		"project"
+#define	USERATTR_LIMPRIV_KW		"limitpriv"
+#define	USERATTR_DFLTPRIV_KW		"defaultpriv"
+#define	USERATTR_LOCK_AFTER_RETRIES_KW	"lock_after_retries"
+#
+
+$UAKEY	-K auths=TestAuths \
+	-K profiles=TestProfiles \
+	-K roles=TestRoles \
+	-K limitpriv=TestLimPriv \
+	-K defaultpriv=TestDefPriv \
+	-K lock_after_retries=TestLAR |
+  tail +2 > user1.out
+
+if cmp -s user.tst user1.out ; then
+    echo "PASS: user1.out"
+else
+    echo "FAIL: user1.out is wrong"
+    errs="$errs user1.out"
+fi
+
+rm -f user.tst user1.out
--- /dev/null	Mon Mar 27 17:24:34 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/oamu_defs.c	Mon Mar 27 17:24:34 2017
@@ -0,0 +1,90 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Gordon W. Ross
+ */
+
+/*
+ * OAM User Test program: read/write defaults
+ */
+
+#include	<sys/types.h>
+#include	<stdio.h>
+#include	<string.h>
+#include	<stdlib.h>
+#include	<stddef.h>
+#include	<getopt.h>
+#include	<userdefs.h>
+
+extern const char *__progname;
+boolean_t rflag = B_FALSE;
+int vflag = 0;
+
+int
+main(int argc, char **argv)
+{
+	struct userdefs *ud;
+	int c, i, errs = 0;
+
+	while ((c = getopt(argc, argv, "rv")) != EOF) {
+		switch (c) {
+		case 'r': /* role */
+			rflag = B_TRUE;
+			break;
+		case 'v': /* verbose */
+			vflag++;
+			break;
+		case '?':
+			(void) fprintf(stderr,
+			    "usage: %s [-rv] [file [file...]]\n",
+			    __progname);
+			break;
+		}
+	}
+
+	if (rflag) {
+		ud = _get_roledefs();
+	} else {
+		ud = _get_userdefs();
+	}
+
+	if (vflag) {
+		(void) printf("# Defaults:\n");
+		if (rflag) {
+			(void) fwrite_roledefs(stdout, ud);
+		} else {
+			(void) fwrite_userdefs(stdout, ud);
+		}
+		(void) printf("\n");
+	}
+
+	for (i = optind; i < argc; i++) {
+		FILE *fp;
+
+		fp = fopen(argv[i], "r");
+		if (fp == NULL) {
+			perror(argv[i]);
+			errs++;
+		} else {
+			fread_defs(fp, ud, rflag);
+			(void) fclose(fp);
+		}
+	}
+
+	if (rflag) {
+		(void) fwrite_roledefs(stdout, ud);
+	} else {
+		(void) fwrite_userdefs(stdout, ud);
+	}
+
+	return ((errs == 0) ? 0 : 1);
+}
--- /dev/null	Mon Mar 27 17:24:34 2017
+++ new/usr/src/test/util-tests/tests/libuserdefs/oamu_uakey.c	Mon Mar 27 17:24:34 2017
@@ -0,0 +1,193 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 RackTop Systems.
+ * Copyright 2017 Gordon W. Ross
+ */
+
+/*
+ * OAM User Test program: get/set by UA key
+ * See: $SRC/cmd/oamuser/user/useradd.c
+ * and: $SRC/cmd/oamuser/user/funcs.c
+ * (some code copied from funcs.c)
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <userdefs.h>
+#include <user_attr.h>
+
+void import_def(struct userdefs *ud);
+void update_def(struct userdefs *ud);
+void change_key(const char *, char *);
+
+extern const char *__progname;
+int vflag = 0;
+
+int
+main(int argc, char **argv)
+{
+	struct userdefs *ud = NULL;
+	int c;
+
+	ud = _get_userdefs();
+
+	while ((c = getopt(argc, argv, "vK:")) != EOF) {
+		switch (c) {
+		case 'K': /* Keyword=value */
+			change_key(NULL, optarg);
+			break;
+		case 'v': /* verbose */
+			vflag++;
+			break;
+		case '?':
+			(void) fprintf(stderr,
+			    "usage: %s [-v] [-K key=value] [ -K ... ]\n",
+			    __progname);
+			break;
+		}
+	}
+
+	/*
+	 * Override ud values we can't set by uakey, so they
+	 * don't depend on the test machine defaults file.
+	 */
+	ud->defrid = 123;
+	ud->defgroup = 456;
+	ud->defgname = "TestGroup";
+	ud->defparent = "TestDefParent";
+	ud->defskel = "TestDefSkel";
+	ud->defshell = "TestDefShell";
+	ud->definact = 3;
+	ud->defexpire = "TestDefExpire";
+
+	ud->defproj = 7;
+	ud->defprojname = "TestProject";
+
+	import_def(ud);
+
+	if (vflag) {
+		(void) printf("# Defaults:\n");
+		(void) fwrite_userdefs(stdout, ud);
+		(void) printf("\n");
+	}
+
+	update_def(ud);
+
+	(void) fwrite_userdefs(stdout, ud);
+
+	return (0);
+}
+
+/*
+ * Some code copied from $SRC/cmd/oamuser/user/funcs.c
+ * so we can simulate part of what that does without
+ * dragging in all the parameter validation stuff.
+ */
+
+typedef struct ua_key {
+	const char	*key;
+	char		*newvalue;
+} ua_key_t;
+
+static ua_key_t keys[] = {
+	/* Only the keywords that appear in libuserdefs */
+	{ USERATTR_AUTHS_KW },
+	{ USERATTR_PROFILES_KW },
+	{ USERATTR_ROLES_KW },
+	{ USERATTR_LIMPRIV_KW },
+	{ USERATTR_DFLTPRIV_KW },
+	{ USERATTR_LOCK_AFTER_RETRIES_KW },
+};
+
+#define	NKEYS	(sizeof (keys)/sizeof (ua_key_t))
+
+/* Import default keys for ordinary useradd */
+void
+import_def(struct userdefs *ud)
+{
+	int i;
+
+	/* Don't import the user type (skip i = 0) */
+	for (i = 1; i < NKEYS; i++) {
+		if (keys[i].newvalue == NULL)
+			keys[i].newvalue =
+			    userdef_get_by_uakey(ud, keys[i].key);
+	}
+}
+
+/* Export command line keys to defaults for useradd -D */
+void
+update_def(struct userdefs *ud)
+{
+	int i;
+
+	for (i = 0; i < NKEYS; i++) {
+		if (keys[i].newvalue != NULL)
+			userdef_set_by_uakey(ud, keys[i].key,
+			    keys[i].newvalue);
+	}
+}
+
+/*
+ * Change a key, there are three different call sequences:
+ *
+ *		key, value	- key with option letter, value.
+ *		NULL, value	- -K key=value option.
+ */
+
+void
+change_key(const char *key, char *value)
+{
+	int i;
+
+	if (key == NULL) {
+		key = value;
+		value = strchr(value, '=');
+		/* Bad value */
+		if (value == NULL) {
+			(void) fprintf(stderr, "Invalid value (missing)\n");
+			exit(EX_BADARG);
+		}
+		*value++ = '\0';
+	}
+
+	for (i = 0; i < NKEYS; i++) {
+		if (strcmp(key, keys[i].key) == 0) {
+			if (keys[i].newvalue != NULL) {
+				/* Can't set a value twice */
+				(void) fprintf(stderr,
+				    "Invalid value (duplicate)\n");
+				exit(EX_BADARG);
+			}
+
+			keys[i].newvalue = value;
+			return;
+		}
+	}
+	(void) fprintf(stderr, "Invalid key: %s\n", key);
+	exit(EX_BADARG);
+}
