PSARC 2007/606 nvlist extensions
authoreschrock
Fri, 26 Oct 2007 13:47:19 -0700
changeset 5345 44060de1d838
parent 5344 2d3435ff5f3d
child 5346 50a411989ef0
PSARC 2007/606 nvlist extensions 6608068 typo in ipmi_sdr_refresh() can cause segfault on allocation failure 6608069 libipmi should have support for user management 6608070 nvlist_lookup_nvpair() would be useful 6608094 nvlist_exists() would be useful 6608096 zprop_parse_value() should accept boolean values for boolean types 6608098 startd's fsminimal filesystem checks could be a little more explicit
usr/src/cmd/svc/startd/specials.c
usr/src/common/nvpair/nvpair.c
usr/src/lib/libipmi/Makefile.com
usr/src/lib/libipmi/common/ipmi_impl.h
usr/src/lib/libipmi/common/ipmi_sdr.c
usr/src/lib/libipmi/common/ipmi_user.c
usr/src/lib/libipmi/common/ipmi_util.c
usr/src/lib/libipmi/common/libipmi.c
usr/src/lib/libipmi/common/libipmi.h
usr/src/lib/libipmi/common/mapfile-vers
usr/src/lib/libnvpair/mapfile-vers
usr/src/lib/libzfs/common/libzfs_util.c
usr/src/uts/common/sys/nvpair.h
--- a/usr/src/cmd/svc/startd/specials.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/cmd/svc/startd/specials.c	Fri Oct 26 13:47:19 2007 -0700
@@ -100,91 +100,87 @@
 }
 
 static void
-special_fsminimal_post_online()
+special_fsminimal_post_online(void)
 {
-	ulong_t rfsid, vfsid;
+	ulong_t rfsid, fsid;
 	pid_t init_pid;
+	int ret;
 
 	log_framework(LOG_DEBUG, "special_fsminimal_post_online hook "
 	    "executed\n");
 
 	/*
-	 * Are / and /var really writeable?
+	 * If /var is still read-only, and it is on a separate filesystem, then
+	 * attempt to mount it read-write now.
 	 */
-	switch (fs_is_read_only("/", &rfsid)) {
-	case 1:
-		return;		/* still read-only: install / ro root */
-	case 0:
-		break;
-	case -1:
-	default:
-		log_error(LOG_WARNING, gettext("couldn't check status of "
-		    "root filesystem: %s\n"), strerror(errno));
-		break;
-	}
+	if ((ret = fs_is_read_only("/var", &fsid)) == 1) {
+		(void) fs_is_read_only("/", &rfsid);
 
-	switch (fs_is_read_only("/var", &vfsid)) {
-	case 1:
-		if (vfsid != rfsid) {
+		if (rfsid != fsid) {
 			log_framework(LOG_WARNING, "/var filesystem "
 			    "read-only after system/filesystem/minimal\n");
 			if (fs_remount("/var"))
 				log_framework(LOG_WARNING, "/var "
 				    "filesystem remount failed\n");
 		}
-		break;
-	case 0:
-		break;
-	case -1:
-	default:
-		log_error(LOG_WARNING, gettext("couldn't check status of "
-		    "/var filesystem: %s\n"), strerror(errno));
-		break;
 	}
 
-	/*
-	 * Clear (dead) entries and record boot time.
-	 */
-	utmpx_clear_old();
-	utmpx_write_boottime();
+	if ((ret = fs_is_read_only("/var", &fsid)) != 1) {
+		if (ret != 0)
+			log_error(LOG_WARNING, gettext("couldn't check status "
+			    "of /var filesystem: %s\n"), strerror(errno));
 
-	/*
-	 * Reinitialize the logs to point to LOG_PREFIX_NORMAL.
-	 */
-	log_init();
+		/*
+		 * Clear (dead) entries and record boot time.
+		 */
+		utmpx_clear_old();
+		utmpx_write_boottime();
+
+		/*
+		 * Reinitialize the logs to point to LOG_PREFIX_NORMAL.
+		 */
+		log_init();
 
-	/*
-	 * Poke init so it will create /var/run/initpipe.
-	 */
-	if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
-	    sizeof (init_pid)) != sizeof (init_pid)) {
-		log_error(LOG_WARNING, "Could not get pid of init: %s.\n",
-		    strerror(errno));
-	} else {
-		if (kill(init_pid, SIGHUP) != 0) {
-			switch (errno) {
-			case EPERM:
-			case ESRCH:
-				log_error(LOG_WARNING,
-				    "Could not signal init: %s.\n",
-				    strerror(errno));
-				break;
+		/*
+		 * Poke init so it will create /var/run/initpipe.
+		 */
+		if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid,
+		    sizeof (init_pid)) != sizeof (init_pid)) {
+			log_error(LOG_WARNING, "Could not get pid of init: "
+			    "%s.\n", strerror(errno));
+		} else {
+			if (kill(init_pid, SIGHUP) != 0) {
+				switch (errno) {
+				case EPERM:
+				case ESRCH:
+					log_error(LOG_WARNING,
+					    "Could not signal init: %s.\n",
+					    strerror(errno));
+					break;
 
-			case EINVAL:
-			default:
-				bad_error("kill", errno);
+				case EINVAL:
+				default:
+					bad_error("kill", errno);
+				}
 			}
 		}
 	}
 
-	/*
-	 * Take pending snapshots and create a svc.startd instance.
-	 */
-	(void) startd_thread_create(restarter_post_fsminimal_thread, NULL);
+	if ((ret = fs_is_read_only("/etc/svc", &fsid)) != 1) {
+		if (ret != 0)
+			log_error(LOG_WARNING, gettext("couldn't check status "
+			    "of /etc/svc filesystem: %s\n"), strerror(errno));
+
+		/*
+		 * Take pending snapshots and create a svc.startd instance.
+		 */
+		(void) startd_thread_create(restarter_post_fsminimal_thread,
+		    NULL);
+	}
 }
 
 static void
-special_single_post_online()
+special_single_post_online(void)
 {
 	int r;
 
--- a/usr/src/common/nvpair/nvpair.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/common/nvpair/nvpair.c	Fri Oct 26 13:47:19 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1483,6 +1483,53 @@
 }
 
 int
+nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
+{
+	nvpriv_t *priv;
+	nvpair_t *nvp;
+	i_nvp_t *curr;
+
+	if (name == NULL || nvl == NULL ||
+	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+		return (EINVAL);
+
+	if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
+		return (ENOTSUP);
+
+	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+		nvp = &curr->nvi_nvp;
+
+		if (strcmp(name, NVP_NAME(nvp)) == 0) {
+			*ret = nvp;
+			return (0);
+		}
+	}
+
+	return (ENOENT);
+}
+
+boolean_t
+nvlist_exists(nvlist_t *nvl, const char *name)
+{
+	nvpriv_t *priv;
+	nvpair_t *nvp;
+	i_nvp_t *curr;
+
+	if (name == NULL || nvl == NULL ||
+	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+		return (B_FALSE);
+
+	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+		nvp = &curr->nvi_nvp;
+
+		if (strcmp(name, NVP_NAME(nvp)) == 0)
+			return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
+int
 nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
 {
 	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
--- a/usr/src/lib/libipmi/Makefile.com	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/Makefile.com	Fri Oct 26 13:47:19 2007 -0700
@@ -33,6 +33,7 @@
 		ipmi_sdr.o	\
 		ipmi_sensor.o	\
 		ipmi_sunoem.o	\
+		ipmi_user.o	\
 		ipmi_util.o	\
 		libipmi.o
 
--- a/usr/src/lib/libipmi/common/ipmi_impl.h	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/ipmi_impl.h	Fri Oct 26 13:47:19 2007 -0700
@@ -63,6 +63,7 @@
 	boolean_t		ih_deviceid_valid;
 	char			ih_errmsg[1024];
 	char			ih_errbuf[1024];
+	ipmi_user_t		*ih_users;
 };
 
 /*
@@ -77,6 +78,7 @@
 extern void *ipmi_zalloc(ipmi_handle_t *, size_t);
 extern void ipmi_free(ipmi_handle_t *, void *);
 extern void *impi_realloc(ipmi_handle_t *, void *, size_t);
+extern char *ipmi_strdup(ipmi_handle_t *, const char *);
 
 /*
  * Supported transports
@@ -87,6 +89,7 @@
  * Miscellaneous routines
  */
 extern void ipmi_sdr_clear(ipmi_handle_t *);
+extern void ipmi_user_clear(ipmi_handle_t *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libipmi/common/ipmi_sdr.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/ipmi_sdr.c	Fri Oct 26 13:47:19 2007 -0700
@@ -126,6 +126,7 @@
 		    sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
 			ipmi_free(ihp, gen_dst);
 			ipmi_free(ihp, fru_dst);
+			return (-1);
 		}
 
 		ent->isc_generic = gen_dst;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_user.c	Fri Oct 26 13:47:19 2007 -0700
@@ -0,0 +1,339 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <string.h>
+
+#include "ipmi_impl.h"
+
+/*
+ * Get User Access.  See section 22.27.
+ *
+ * See libipmi.h for a complete description of IPMI reference material.
+ */
+
+typedef struct ipmi_get_user_access_req {
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		igua_channel:4;
+	uint8_t		__reserved1:4;
+	uint8_t		igua_uid:2;
+	uint8_t		__reserved2:6;
+#else
+	uint8_t		__reserved1:4;
+	uint8_t		igua_channel:4;
+	uint8_t		__reserved2:2;
+	uint8_t		igua_uid:6;
+#endif
+} ipmi_get_user_access_req_t;
+
+#define	IPMI_CMD_GET_USER_ACCESS	0x44
+
+typedef struct ipmi_get_user_access {
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		igua_max_uid:4;
+	uint8_t		__reserved1:4;
+	uint8_t		igua_enable_status:4;
+	uint8_t		igua_enabled_uid:4;
+	uint8_t		__reserved2:4;
+	uint8_t		igua_fixed_uid:4;
+	uint8_t		__reserved3:1;
+	uint8_t		igua_only_callback:1;
+	uint8_t		igua_link_auth_enable:1;
+	uint8_t		igua_ipmi_msg_enable:1;
+	uint8_t		igua_privilege_level:4;
+#else
+	uint8_t		__reserved1:4;
+	uint8_t		igua_max_uid:4;
+	uint8_t		igua_enabled_uid:4;
+	uint8_t		igua_enable_status:4;
+	uint8_t		igua_fixed_uid:4;
+	uint8_t		__reserved2:4;
+	uint8_t		igua_privilege_level:4;
+	uint8_t		igua_ipmi_msg_enable:1;
+	uint8_t		igua_link_auth_enable:1;
+	uint8_t		igua_only_callback:1;
+	uint8_t		__reserved3:1;
+#endif
+} ipmi_get_user_access_t;
+
+#define	IPMI_USER_ENABLE_UNSPECIFIED	0x00
+#define	IPMI_USER_ENABLE_SETPASSWD	0x01
+#define	IPMI_USER_DISABLE_SETPASSWD	0x02
+
+#define	IPMI_USER_CHANNEL_CURRENT	0xe
+
+/*
+ * Get User Name.  See section 22.29
+ */
+
+#define	IPMI_CMD_GET_USER_NAME		0x46
+
+/*
+ * Set User Password.  See section 22.30
+ */
+
+#define	IPMI_CMD_SET_USER_PASSWORD	0x47
+
+typedef struct ipmi_set_user_password {
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		isup_uid:6;
+	uint8_t		__reserved1:1;
+	uint8_t		isup_len20:1;
+	uint8_t		isup_op:2;
+	uint8_t		__reserved2:6;
+#else
+	uint8_t		isup_len20:1;
+	uint8_t		__reserved1:1;
+	uint8_t		isup_uid:6;
+	uint8_t		__reserved2:6;
+	uint8_t		isup_op:2;
+#endif
+	char		isup_passwd[20];
+} ipmi_set_user_password_t;
+
+#define	IPMI_PASSWORD_OP_DISABLE	0x0
+#define	IPMI_PASSWORD_OP_ENABLE		0x1
+#define	IPMI_PASSWORD_OP_SET		0x2
+#define	IPMI_PASSWORD_OP_TEST		0x3
+
+static ipmi_get_user_access_t *
+ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid)
+{
+	ipmi_cmd_t cmd, *resp;
+	ipmi_get_user_access_req_t req = { 0 };
+
+	req.igua_channel = channel;
+	req.igua_uid = uid;
+
+	cmd.ic_netfn = IPMI_NETFN_APP;
+	cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
+	cmd.ic_lun = 0;
+	cmd.ic_data = &req;
+	cmd.ic_dlen = sizeof (req);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
+		/*
+		 * If sessions aren't supported on the current channel, some
+		 * service processors (notably Sun's ILOM) will return an
+		 * invalid request completion code (0xCC).  For these SPs, we
+		 * translate this to the more appropriate EIPMI_INVALID_COMMAND.
+		 */
+		if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
+			(void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND,
+			    NULL);
+		return (NULL);
+	}
+
+	if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (NULL);
+	}
+
+	return (resp->ic_data);
+}
+
+static const char *
+ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
+{
+	ipmi_cmd_t cmd, *resp;
+
+	cmd.ic_netfn = IPMI_NETFN_APP;
+	cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
+	cmd.ic_lun = 0;
+	cmd.ic_data = &uid;
+	cmd.ic_dlen = sizeof (uid);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (NULL);
+
+	if (resp->ic_dlen < 16) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (NULL);
+	}
+
+	return (resp->ic_data);
+}
+
+void
+ipmi_user_clear(ipmi_handle_t *ihp)
+{
+	ipmi_user_t *up, *next;
+
+	while ((up = ihp->ih_users) != NULL) {
+		next = up->iu_next;
+		ipmi_free(ihp, up->iu_name);
+		ipmi_free(ihp, up);
+		ihp->ih_users = next;
+	}
+}
+
+/*
+ * Returns user information in a well-defined structure.
+ */
+int
+ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
+    void *data)
+{
+	ipmi_get_user_access_t *resp;
+	uint8_t i;
+	ipmi_user_t *up;
+	const char *name;
+
+	ipmi_user_clear(ihp);
+
+	/*
+	 * First get the number of active users on the system by requesting the
+	 * reserved user ID (0).
+	 */
+	if ((resp = ipmi_get_user_access(ihp,
+	    IPMI_USER_CHANNEL_CURRENT, 0)) == NULL)
+		return (-1);
+
+	for (i = 1; i <= resp->igua_max_uid; i++) {
+		if ((resp = ipmi_get_user_access(ihp,
+		    IPMI_USER_CHANNEL_CURRENT, i)) == NULL)
+			return (-1);
+
+		if ((up = ipmi_zalloc(ihp, sizeof (ipmi_user_t))) == NULL)
+			return (-1);
+
+		up->iu_enabled = resp->igua_enabled_uid;
+		up->iu_uid = i;
+		up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable;
+		up->iu_link_auth_enable = resp->igua_link_auth_enable;
+		up->iu_priv = resp->igua_privilege_level;
+		up->iu_next = ihp->ih_users;
+		ihp->ih_users = up;
+
+		if ((name = ipmi_get_user_name(ihp, i)) == NULL)
+			return (-1);
+
+		if (*name != '\0' &&
+		    (up->iu_name = ipmi_strdup(ihp, name)) == NULL)
+			return (-1);
+	}
+
+	for (up = ihp->ih_users; up != NULL; up = up->iu_next) {
+		if (func(up, data) != 0)
+			return (-1);
+	}
+
+	return (0);
+}
+
+typedef struct ipmi_user_cb {
+	const char	*uic_name;
+	uint8_t		uic_uid;
+	ipmi_user_t	*uic_result;
+} ipmi_user_cb_t;
+
+static int
+ipmi_user_callback(ipmi_user_t *up, void *data)
+{
+	ipmi_user_cb_t *cbp = data;
+
+	if (cbp->uic_result != NULL)
+		return (0);
+
+	if (up->iu_name) {
+		if (strcmp(up->iu_name, cbp->uic_name) == 0)
+			cbp->uic_result = up;
+	} else if (up->iu_uid == cbp->uic_uid) {
+		cbp->uic_result = up;
+	}
+
+	return (0);
+}
+
+ipmi_user_t *
+ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name)
+{
+	ipmi_user_cb_t cb = { 0 };
+
+	cb.uic_name = name;
+	cb.uic_result = NULL;
+
+	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
+		return (NULL);
+
+	if (cb.uic_result == NULL)
+		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
+		    "no such user");
+
+	return (cb.uic_result);
+}
+
+ipmi_user_t *
+ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid)
+{
+	ipmi_user_cb_t cb = { 0 };
+
+	cb.uic_uid = uid;
+	cb.uic_result = NULL;
+
+	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
+		return (NULL);
+
+	if (cb.uic_result == NULL)
+		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
+		    "no such user");
+
+	return (cb.uic_result);
+}
+
+int
+ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd)
+{
+	ipmi_set_user_password_t req = { 0 };
+	ipmi_cmd_t cmd;
+
+	req.isup_uid = uid;
+	req.isup_op = IPMI_PASSWORD_OP_SET;
+
+	if (strlen(passwd) > 19)
+		return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST,
+		    "password length must be less than 20 characters"));
+
+	if (strlen(passwd) > 15)
+		req.isup_len20 = 1;
+
+	(void) strcpy(req.isup_passwd, passwd);
+
+	cmd.ic_netfn = IPMI_NETFN_APP;
+	cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD;
+	cmd.ic_lun = 0;
+	cmd.ic_data = &req;
+	if (req.isup_len20)
+		cmd.ic_dlen = sizeof (req);
+	else
+		cmd.ic_dlen = sizeof (req) - 4;
+
+	if (ipmi_send(ihp, &cmd) == NULL)
+		return (-1);
+
+	return (0);
+}
--- a/usr/src/lib/libipmi/common/ipmi_util.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/ipmi_util.c	Fri Oct 26 13:47:19 2007 -0700
@@ -139,6 +139,17 @@
 	return (ptr);
 }
 
+char *
+ipmi_strdup(ipmi_handle_t *ihp, const char *str)
+{
+	char *ptr;
+
+	if ((ptr = strdup(str)) == NULL)
+		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
+
+	return (ptr);
+}
+
 /* ARGSUSED */
 void
 ipmi_free(ipmi_handle_t *ihp, void *ptr)
--- a/usr/src/lib/libipmi/common/libipmi.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/libipmi.c	Fri Oct 26 13:47:19 2007 -0700
@@ -71,6 +71,7 @@
 	if (ihp->ih_transport && ihp->ih_tdata)
 		ihp->ih_transport->it_close(ihp->ih_tdata);
 	ipmi_sdr_clear(ihp);
+	ipmi_user_clear(ihp);
 	free(ihp);
 }
 
--- a/usr/src/lib/libipmi/common/libipmi.h	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/libipmi.h	Fri Oct 26 13:47:19 2007 -0700
@@ -445,6 +445,35 @@
 int ipmi_fru_parse_product(ipmi_handle_t *, char *, ipmi_fru_prod_info_t *);
 
 /*
+ * User management.  The raw functions are private to libipmi, and only the
+ * higher level abstraction (ipmi_user_t) is exported to consumers of the
+ * library.
+ */
+
+#define	IPMI_USER_PRIV_CALLBACK		0x1
+#define	IPMI_USER_PRIV_USER		0x2
+#define	IPMI_USER_PRIV_OPERATOR		0x3
+#define	IPMI_USER_PRIV_ADMIN		0x4
+#define	IPMI_USER_PRIV_OEM		0x5
+#define	IPMI_USER_PRIV_NONE		0xf
+
+typedef struct ipmi_user {
+	uint8_t		iu_uid;
+	char		*iu_name;
+	boolean_t	iu_enabled;
+	boolean_t	iu_ipmi_msg_enable;
+	boolean_t	iu_link_auth_enable;
+	uint8_t		iu_priv;
+	struct ipmi_user *iu_next;
+} ipmi_user_t;
+
+extern int ipmi_user_iter(ipmi_handle_t *,
+    int (*)(ipmi_user_t *, void *), void *);
+extern ipmi_user_t *ipmi_user_lookup_name(ipmi_handle_t *, const char *);
+extern ipmi_user_t *ipmi_user_lookup_id(ipmi_handle_t *, uint8_t);
+extern int ipmi_user_set_password(ipmi_handle_t *, uint8_t, const char *);
+
+/*
  * The remaining functions are private to the implementation of the Sun ILOM
  * service processor.  These function first check the manufacturer from the IPMI
  * device ID, and will return EIPMI_NOT_SUPPORTED if attempted for non-Sun
--- a/usr/src/lib/libipmi/common/mapfile-vers	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libipmi/common/mapfile-vers	Fri Oct 26 13:47:19 2007 -0700
@@ -44,6 +44,10 @@
 	ipmi_sunoem_led_set;
 	ipmi_sunoem_update_fru;
 	ipmi_sunoem_uptime;
+	ipmi_user_iter;
+	ipmi_user_lookup_id;
+	ipmi_user_lookup_name;
+	ipmi_user_set_password;
     local:
 	*;
 };
--- a/usr/src/lib/libnvpair/mapfile-vers	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libnvpair/mapfile-vers	Fri Oct 26 13:47:19 2007 -0700
@@ -19,12 +19,18 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
 
+SUNW_1.3 {
+    global:
+	nvlist_exists;
+	nvlist_lookup_nvpair;
+} SUNW_1.2;
+
 SUNW_1.2 {
     global:
 	nv_alloc_fini;
--- a/usr/src/lib/libzfs/common/libzfs_util.c	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_util.c	Fri Oct 26 13:47:19 2007 -0700
@@ -1063,6 +1063,7 @@
 	const char *propname;
 	char *value;
 	boolean_t isnone = B_FALSE;
+	boolean_t boolval;
 
 	if (type == ZFS_TYPE_POOL) {
 		proptype = zpool_prop_get_type(prop);
@@ -1122,14 +1123,25 @@
 		break;
 
 	case PROP_TYPE_INDEX:
-		if (datatype != DATA_TYPE_STRING) {
+		switch (datatype) {
+		case DATA_TYPE_STRING:
+			(void) nvpair_value_string(elem, &value);
+			break;
+
+		case DATA_TYPE_BOOLEAN_VALUE:
+			(void) nvpair_value_boolean_value(elem, &boolval);
+			if (boolval)
+				value = "on";
+			else
+				value = "off";
+			break;
+
+		default:
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "'%s' must be a string"), nvpair_name(elem));
 			goto error;
 		}
 
-		(void) nvpair_value_string(elem, &value);
-
 		if (zprop_string_to_index(prop, value, ivalp, type) != 0) {
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 			    "'%s' must be one of '%s'"), propname,
--- a/usr/src/uts/common/sys/nvpair.h	Fri Oct 26 13:06:58 2007 -0700
+++ b/usr/src/uts/common/sys/nvpair.h	Fri Oct 26 13:47:19 2007 -0700
@@ -2,9 +2,8 @@
  * 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.
+ * 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.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -223,6 +222,9 @@
 int nvlist_lookup_hrtime(nvlist_t *, const char *, hrtime_t *);
 int nvlist_lookup_pairs(nvlist_t *nvl, int, ...);
 
+int nvlist_lookup_nvpair(nvlist_t *nvl, const char *, nvpair_t **);
+boolean_t nvlist_exists(nvlist_t *nvl, const char *);
+
 /* processing nvpair */
 nvpair_t *nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *);
 char *nvpair_name(nvpair_t *);