changeset 5040:ff6ebd8761a6

PSARC 2007/177 SMF read-protected property storage PSARC 2007/519 svccfg(1M) restore 6537749 SMF should support read-protection of data 6538452 svccfg delete leaks memory on syntax error with options 6546699 svccfg archive should be able to be reimported 6559692 svccfg fails to import a manifest with an empty <property> 6597168 startd is setting $SMF_METHOD incorrectly 6597173 allocation failure can induce crash in scf_handle_decode_fmri() 6597183 allocation failure can induce crash in scf_simple_app_props_free() 6597190 scf_simple_app_props_get() can return with unset error code 6598922 rc_node_modify_permission_check() calls perm_granted() with rn_lock held
author wesolows
date Thu, 13 Sep 2007 10:10:42 -0700
parents 75097ff1169e
children 8bd749a329c9
files usr/src/cmd/svc/configd/rc_node.c usr/src/cmd/svc/startd/graph.c usr/src/cmd/svc/startd/libscf.c usr/src/cmd/svc/startd/method.c usr/src/cmd/svc/startd/startd.c usr/src/cmd/svc/svccfg/svccfg.h usr/src/cmd/svc/svccfg/svccfg.l usr/src/cmd/svc/svccfg/svccfg.y usr/src/cmd/svc/svccfg/svccfg_engine.c usr/src/cmd/svc/svccfg/svccfg_help.c usr/src/cmd/svc/svccfg/svccfg_internal.c usr/src/cmd/svc/svccfg/svccfg_libscf.c usr/src/cmd/svc/svccfg/svccfg_xml.c usr/src/cmd/svc/svcprop/svcprop.c usr/src/cmd/svc/svcs/explain.c usr/src/cmd/svc/svcs/svcs.c usr/src/common/svc/repcache_protocol.h usr/src/lib/librestart/common/librestart.c usr/src/lib/libscf/common/lowlevel.c usr/src/lib/libscf/common/mapfile-vers usr/src/lib/libscf/common/midlevel.c usr/src/lib/libscf/inc/libscf_priv.h
diffstat 22 files changed, 882 insertions(+), 213 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/svc/configd/rc_node.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/configd/rc_node.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -67,6 +68,10 @@
  * rc_node_{wait,hold}_flag() functions (often via the rc_node_check_*()
  * functions & RC_NODE_*() macros), which fail if the object has died.
  *
+ * Because name service lookups may take a long time and, more importantly
+ * may trigger additional accesses to the repository, perm_granted() must be
+ * called without holding any locks.
+ *
  * An ITER_START for a non-ENTITY_VALUE induces an rc_node_fill_children()
  * call via rc_node_setup_iter() to populate the rn_children uu_list of the
  * rc_node_t * in question and a call to uu_list_walk_start() on that list.  For
@@ -186,6 +191,7 @@
 #define	AUTH_PROP_ENABLED	"enabled"
 #define	AUTH_PROP_MODIFY	"modify_authorization"
 #define	AUTH_PROP_VALUE		"value_authorization"
+#define	AUTH_PROP_READ		"read_authorization"
 /* libsecdb should take care of this. */
 #define	RBAC_AUTH_SEP		","
 
@@ -1829,9 +1835,44 @@
 	return (REP_PROTOCOL_SUCCESS);
 }
 
+static int rc_node_parent(rc_node_t *, rc_node_t **);
+
+/*
+ * Returns
+ *   _INVALID_TYPE - type is invalid
+ *   _DELETED - np or an ancestor has been deleted
+ *   _NOT_FOUND - no ancestor of specified type exists
+ *   _SUCCESS - *app is held
+ */
+static int
+rc_node_find_ancestor(rc_node_t *np, uint32_t type, rc_node_t **app)
+{
+	int ret;
+	rc_node_t *parent, *np_orig;
+
+	if (type >= REP_PROTOCOL_ENTITY_MAX)
+		return (REP_PROTOCOL_FAIL_INVALID_TYPE);
+
+	np_orig = np;
+
+	while (np->rn_id.rl_type > type) {
+		ret = rc_node_parent(np, &parent);
+		if (np != np_orig)
+			rc_node_rele(np);
+		if (ret != REP_PROTOCOL_SUCCESS)
+			return (ret);
+		np = parent;
+	}
+
+	if (np->rn_id.rl_type == type) {
+		*app = parent;
+		return (REP_PROTOCOL_SUCCESS);
+	}
+
+	return (REP_PROTOCOL_FAIL_NOT_FOUND);
+}
+
 #ifndef NATIVE_BUILD
-static int rc_node_parent(rc_node_t *, rc_node_t **);
-
 /*
  * If the propname property exists in pg, and it is of type string, add its
  * values as authorizations to pcp.  pg must not be locked on entry, and it is
@@ -1852,7 +1893,6 @@
 
 	assert(!MUTEX_HELD(&pg->rn_lock));
 	assert(pg->rn_id.rl_type == REP_PROTOCOL_ENTITY_PROPERTYGRP);
-	assert(pg->rn_id.rl_ids[ID_SNAPSHOT] == 0);
 
 	(void) pthread_mutex_lock(&pg->rn_lock);
 	result = rc_node_find_named_child(pg, propname,
@@ -1958,7 +1998,7 @@
 }
 
 /*
- * If pg has a property named propname, and it string typed, add its values as
+ * If pg has a property named propname, and is string typed, add its values as
  * authorizations to pcp.  If pg has no such property, and its parent is an
  * instance, walk up to the service and try doing the same with the property
  * of the same name from the property group of the same name.  Returns
@@ -1970,50 +2010,42 @@
 perm_add_enabling_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
 {
 	int r;
+	char pgname[REP_PROTOCOL_NAME_LEN + 1];
+	rc_node_t *svc;
+	size_t sz;
 
 	r = perm_add_pg_prop_values(pcp, pg, propname);
 
-	if (r == REP_PROTOCOL_FAIL_NOT_FOUND) {
-		char pgname[REP_PROTOCOL_NAME_LEN + 1];
-		rc_node_t *inst, *svc;
-		size_t sz;
-
-		assert(!MUTEX_HELD(&pg->rn_lock));
-
-		if (pg->rn_id.rl_ids[ID_INSTANCE] == 0) {
-			/* not an instance pg */
-			return (REP_PROTOCOL_SUCCESS);
-		}
-
-		sz = strlcpy(pgname, pg->rn_name, sizeof (pgname));
-		assert(sz < sizeof (pgname));
-
-		/* get pg's parent */
-		r = rc_node_parent(pg, &inst);
-		if (r != REP_PROTOCOL_SUCCESS) {
-			assert(r == REP_PROTOCOL_FAIL_DELETED);
-			return (r);
-		}
-
-		assert(inst->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
-
-		/* get instance's parent */
-		r = rc_node_parent(inst, &svc);
-		rc_node_rele(inst);
-		if (r != REP_PROTOCOL_SUCCESS) {
-			assert(r == REP_PROTOCOL_FAIL_DELETED);
-			return (r);
-		}
-
-		assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
-
-		r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname);
-
-		rc_node_rele(svc);
-
-		if (r == REP_PROTOCOL_FAIL_NOT_FOUND)
-			r = REP_PROTOCOL_SUCCESS;
-	}
+	if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
+		return (r);
+
+	assert(!MUTEX_HELD(&pg->rn_lock));
+
+	if (pg->rn_id.rl_ids[ID_INSTANCE] == 0)
+		return (REP_PROTOCOL_SUCCESS);
+
+	sz = strlcpy(pgname, pg->rn_name, sizeof (pgname));
+	assert(sz < sizeof (pgname));
+
+	/*
+	 * If pg is a child of an instance or snapshot, we want to compose the
+	 * authorization property with the service's (if it exists).  The
+	 * snapshot case applies only to read_authorization.  In all other
+	 * cases, the pg's parent will be the instance.
+	 */
+	r = rc_node_find_ancestor(pg, REP_PROTOCOL_ENTITY_SERVICE, &svc);
+	if (r != REP_PROTOCOL_SUCCESS) {
+		assert(r == REP_PROTOCOL_FAIL_DELETED);
+		return (r);
+	}
+	assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
+
+	r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname);
+
+	rc_node_rele(svc);
+
+	if (r == REP_PROTOCOL_FAIL_NOT_FOUND)
+		r = REP_PROTOCOL_SUCCESS;
 
 	return (r);
 }
@@ -2229,6 +2261,8 @@
 	return (REP_PROTOCOL_FAIL_NOT_FOUND);
 }
 
+static int rc_node_pg_check_read_protect(rc_node_t *);
+
 /*
  * Fails with
  *   _NOT_SET
@@ -2237,6 +2271,7 @@
  *   _NOT_FOUND
  *   _BAD_REQUEST
  *   _TRUNCATED
+ *   _NO_RESOURCES
  */
 int
 rc_node_name(rc_node_ptr_t *npp, char *buf, size_t sz, uint32_t answertype,
@@ -2287,6 +2322,26 @@
 			return (REP_PROTOCOL_FAIL_NOT_FOUND);
 		actual = strlcpy(buf, np->rn_snaplevel->rsl_instance, sz);
 		break;
+	case RP_ENTITY_NAME_PGREADPROT:
+	{
+		int ret;
+
+		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
+			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
+		ret = rc_node_pg_check_read_protect(np);
+		assert(ret != REP_PROTOCOL_FAIL_TYPE_MISMATCH);
+		switch (ret) {
+		case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
+			actual = snprintf(buf, sz, "1");
+			break;
+		case REP_PROTOCOL_SUCCESS:
+			actual = snprintf(buf, sz, "0");
+			break;
+		default:
+			return (ret);
+		}
+		break;
+	}
 	default:
 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
 	}
@@ -2639,10 +2694,12 @@
 {
 	rc_node_t *np;
 	rc_node_t *cp = NULL;
-	int rc;
+	int rc, perm_rc;
 
 	rc_node_clear(cpp, 0);
 
+	perm_rc = rc_node_modify_permission_check();
+
 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
 
 	/*
@@ -2669,9 +2726,9 @@
 		return (rc);
 	}
 
-	if ((rc = rc_node_modify_permission_check()) != REP_PROTOCOL_SUCCESS) {
+	if (perm_rc != REP_PROTOCOL_SUCCESS) {
 		(void) pthread_mutex_unlock(&np->rn_lock);
-		return (rc);
+		return (perm_rc);
 	}
 
 	HOLD_PTR_FLAG_OR_RETURN(np, npp, RC_NODE_CREATING_CHILD);
@@ -3551,14 +3608,14 @@
 
 	assert(MUTEX_HELD(&np->rn_lock));
 
-	if ((rc = rc_node_modify_permission_check()) != REP_PROTOCOL_SUCCESS) {
-		(void) pthread_mutex_unlock(&np->rn_lock);
-		return (rc);
-	}
-
 	np_orig = np;
 	rc_node_hold_locked(np);		/* simplifies the remainder */
 
+	(void) pthread_mutex_unlock(&np->rn_lock);
+	if ((rc = rc_node_modify_permission_check()) != REP_PROTOCOL_SUCCESS)
+		return (rc);
+	(void) pthread_mutex_lock(&np->rn_lock);
+
 	/*
 	 * get the latest node, holding RC_NODE_IN_TX to keep the rn_former
 	 * list from changing.
@@ -3710,10 +3767,12 @@
 {
 	rc_node_t *np;
 	rc_node_t *outp = NULL;
-	int rc;
+	int rc, perm_rc;
 
 	rc_node_clear(outpp, 0);
 
+	perm_rc = rc_node_modify_permission_check();
+
 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
 		(void) pthread_mutex_unlock(&np->rn_lock);
@@ -3740,9 +3799,9 @@
 		return (rc);
 	}
 
-	if ((rc = rc_node_modify_permission_check()) != REP_PROTOCOL_SUCCESS) {
+	if (perm_rc != REP_PROTOCOL_SUCCESS) {
 		(void) pthread_mutex_unlock(&np->rn_lock);
-		return (rc);
+		return (perm_rc);
 	}
 
 	HOLD_PTR_FLAG_OR_RETURN(np, npp, RC_NODE_CREATING_CHILD);
@@ -3806,6 +3865,314 @@
 }
 
 /*
+ * If the pgname property group under ent has type pgtype, and it has a
+ * propname property with type ptype, return _SUCCESS.  If pgtype is NULL,
+ * it is not checked.  If ent is not a service node, we will return _SUCCESS if
+ * a property meeting the requirements exists in either the instance or its
+ * parent.
+ *
+ * Returns
+ *   _SUCCESS - see above
+ *   _DELETED - ent or one of its ancestors was deleted
+ *   _NO_RESOURCES - no resources
+ *   _NOT_FOUND - no matching property was found
+ */
+static int
+rc_svc_prop_exists(rc_node_t *ent, const char *pgname, const char *pgtype,
+    const char *propname, rep_protocol_value_type_t ptype)
+{
+	int ret;
+	rc_node_t *pg = NULL, *spg = NULL, *svc, *prop;
+
+	assert(!MUTEX_HELD(&ent->rn_lock));
+
+	(void) pthread_mutex_lock(&ent->rn_lock);
+	ret = rc_node_find_named_child(ent, pgname,
+	    REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
+	(void) pthread_mutex_unlock(&ent->rn_lock);
+
+	switch (ret) {
+	case REP_PROTOCOL_SUCCESS:
+		break;
+
+	case REP_PROTOCOL_FAIL_DELETED:
+	case REP_PROTOCOL_FAIL_NO_RESOURCES:
+		return (ret);
+
+	default:
+		bad_error("rc_node_find_named_child", ret);
+	}
+
+	if (ent->rn_id.rl_type != REP_PROTOCOL_ENTITY_SERVICE) {
+		ret = rc_node_find_ancestor(ent, REP_PROTOCOL_ENTITY_SERVICE,
+		    &svc);
+		if (ret != REP_PROTOCOL_SUCCESS) {
+			assert(ret == REP_PROTOCOL_FAIL_DELETED);
+			if (pg != NULL)
+				rc_node_rele(pg);
+			return (ret);
+		}
+		assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
+
+		(void) pthread_mutex_lock(&svc->rn_lock);
+		ret = rc_node_find_named_child(svc, pgname,
+		    REP_PROTOCOL_ENTITY_PROPERTYGRP, &spg);
+		(void) pthread_mutex_unlock(&svc->rn_lock);
+
+		rc_node_rele(svc);
+
+		switch (ret) {
+		case REP_PROTOCOL_SUCCESS:
+			break;
+
+		case REP_PROTOCOL_FAIL_DELETED:
+		case REP_PROTOCOL_FAIL_NO_RESOURCES:
+			if (pg != NULL)
+				rc_node_rele(pg);
+			return (ret);
+
+		default:
+			bad_error("rc_node_find_named_child", ret);
+		}
+	}
+
+	if (pg != NULL &&
+	    pgtype != NULL && strcmp(pg->rn_type, pgtype) != 0) {
+		rc_node_rele(pg);
+		pg = NULL;
+	}
+
+	if (spg != NULL &&
+	    pgtype != NULL && strcmp(spg->rn_type, pgtype) != 0) {
+		rc_node_rele(spg);
+		spg = NULL;
+	}
+
+	if (pg == NULL) {
+		if (spg == NULL)
+			return (REP_PROTOCOL_FAIL_NOT_FOUND);
+		pg = spg;
+		spg = NULL;
+	}
+
+	/*
+	 * At this point, pg is non-NULL, and is a property group node of the
+	 * correct type.  spg, if non-NULL, is also a property group node of
+	 * the correct type.  Check for the property in pg first, then spg
+	 * (if applicable).
+	 */
+	(void) pthread_mutex_lock(&pg->rn_lock);
+	ret = rc_node_find_named_child(pg, propname,
+	    REP_PROTOCOL_ENTITY_PROPERTY, &prop);
+	(void) pthread_mutex_unlock(&pg->rn_lock);
+	rc_node_rele(pg);
+	switch (ret) {
+	case REP_PROTOCOL_SUCCESS:
+		if (prop != NULL) {
+			if (prop->rn_valtype == ptype) {
+				rc_node_rele(prop);
+				if (spg != NULL)
+					rc_node_rele(spg);
+				return (REP_PROTOCOL_SUCCESS);
+			}
+			rc_node_rele(prop);
+		}
+		break;
+
+	case REP_PROTOCOL_FAIL_NO_RESOURCES:
+		if (spg != NULL)
+			rc_node_rele(spg);
+		return (ret);
+
+	case REP_PROTOCOL_FAIL_DELETED:
+		break;
+
+	default:
+		bad_error("rc_node_find_named_child", ret);
+	}
+
+	if (spg == NULL)
+		return (REP_PROTOCOL_FAIL_NOT_FOUND);
+
+	pg = spg;
+
+	(void) pthread_mutex_lock(&pg->rn_lock);
+	ret = rc_node_find_named_child(pg, propname,
+	    REP_PROTOCOL_ENTITY_PROPERTY, &prop);
+	(void) pthread_mutex_unlock(&pg->rn_lock);
+	rc_node_rele(pg);
+	switch (ret) {
+	case REP_PROTOCOL_SUCCESS:
+		if (prop != NULL) {
+			if (prop->rn_valtype == ptype) {
+				rc_node_rele(prop);
+				return (REP_PROTOCOL_SUCCESS);
+			}
+			rc_node_rele(prop);
+		}
+		return (REP_PROTOCOL_FAIL_NOT_FOUND);
+
+	case REP_PROTOCOL_FAIL_NO_RESOURCES:
+		return (ret);
+
+	case REP_PROTOCOL_FAIL_DELETED:
+		return (REP_PROTOCOL_FAIL_NOT_FOUND);
+
+	default:
+		bad_error("rc_node_find_named_child", ret);
+	}
+
+	return (REP_PROTOCOL_SUCCESS);
+}
+
+/*
+ * Given a property group node, returns _SUCCESS if the property group may
+ * be read without any special authorization.
+ *
+ * Fails with:
+ *   _DELETED - np or an ancestor node was deleted
+ *   _TYPE_MISMATCH - np does not refer to a property group
+ *   _NO_RESOURCES - no resources
+ *   _PERMISSION_DENIED - authorization is required
+ */
+static int
+rc_node_pg_check_read_protect(rc_node_t *np)
+{
+	int ret;
+	rc_node_t *ent;
+
+	assert(!MUTEX_HELD(&np->rn_lock));
+
+	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
+		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
+
+	if (strcmp(np->rn_type, SCF_GROUP_FRAMEWORK) == 0 ||
+	    strcmp(np->rn_type, SCF_GROUP_DEPENDENCY) == 0 ||
+	    strcmp(np->rn_type, SCF_GROUP_METHOD) == 0)
+		return (REP_PROTOCOL_SUCCESS);
+
+	ret = rc_node_parent(np, &ent);
+
+	if (ret != REP_PROTOCOL_SUCCESS)
+		return (ret);
+
+	ret = rc_svc_prop_exists(ent, np->rn_name, np->rn_type,
+	    AUTH_PROP_READ, REP_PROTOCOL_TYPE_STRING);
+
+	rc_node_rele(ent);
+
+	switch (ret) {
+	case REP_PROTOCOL_FAIL_NOT_FOUND:
+		return (REP_PROTOCOL_SUCCESS);
+	case REP_PROTOCOL_SUCCESS:
+		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
+	case REP_PROTOCOL_FAIL_DELETED:
+	case REP_PROTOCOL_FAIL_NO_RESOURCES:
+		return (ret);
+	default:
+		bad_error("rc_svc_prop_exists", ret);
+	}
+
+	return (REP_PROTOCOL_SUCCESS);
+}
+
+/*
+ * Fails with
+ *   _DELETED - np's node or parent has been deleted
+ *   _TYPE_MISMATCH - np's node is not a property
+ *   _NO_RESOURCES - out of memory
+ *   _PERMISSION_DENIED - no authorization to read this property's value(s)
+ *   _BAD_REQUEST - np's parent is not a property group
+ */
+static int
+rc_node_property_may_read(rc_node_t *np)
+{
+	int ret, granted = 0;
+	rc_node_t *pgp;
+	permcheck_t *pcp;
+
+	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
+		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
+
+	if (client_is_privileged())
+		return (REP_PROTOCOL_SUCCESS);
+
+#ifdef NATIVE_BUILD
+	return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
+#else
+	ret = rc_node_parent(np, &pgp);
+
+	if (ret != REP_PROTOCOL_SUCCESS)
+		return (ret);
+
+	if (pgp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
+		rc_node_rele(pgp);
+		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
+	}
+
+	ret = rc_node_pg_check_read_protect(pgp);
+
+	if (ret != REP_PROTOCOL_FAIL_PERMISSION_DENIED) {
+		rc_node_rele(pgp);
+		return (ret);
+	}
+
+	pcp = pc_create();
+
+	if (pcp == NULL) {
+		rc_node_rele(pgp);
+		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
+	}
+
+	ret = perm_add_enabling(pcp, AUTH_MODIFY);
+
+	if (ret == REP_PROTOCOL_SUCCESS) {
+		const char * const auth =
+		    perm_auth_for_pgtype(pgp->rn_type);
+
+		if (auth != NULL)
+			ret = perm_add_enabling(pcp, auth);
+	}
+
+	/*
+	 * If you are permitted to modify the value, you may also
+	 * read it.  This means that both the MODIFY and VALUE
+	 * authorizations are acceptable.  We don't allow requests
+	 * for AUTH_PROP_MODIFY if all you have is $AUTH_PROP_VALUE,
+	 * however, to avoid leaking possibly valuable information
+	 * since such a user can't change the property anyway.
+	 */
+	if (ret == REP_PROTOCOL_SUCCESS)
+		ret = perm_add_enabling_values(pcp, pgp,
+		    AUTH_PROP_MODIFY);
+
+	if (ret == REP_PROTOCOL_SUCCESS &&
+	    strcmp(np->rn_name, AUTH_PROP_MODIFY) != 0)
+		ret = perm_add_enabling_values(pcp, pgp,
+		    AUTH_PROP_VALUE);
+
+	if (ret == REP_PROTOCOL_SUCCESS)
+		ret = perm_add_enabling_values(pcp, pgp,
+		    AUTH_PROP_READ);
+
+	rc_node_rele(pgp);
+
+	if (ret == REP_PROTOCOL_SUCCESS) {
+		granted = perm_granted(pcp);
+		if (granted < 0)
+			ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
+	}
+
+	pc_free(pcp);
+
+	if (ret == REP_PROTOCOL_SUCCESS && !granted)
+		ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
+
+	return (ret);
+#endif	/* NATIVE_BUILD */
+}
+
+/*
  * Iteration
  */
 static int
@@ -4023,12 +4390,14 @@
 
 /*
  * Returns:
+ *   _NO_RESOURCES - out of memory
  *   _NOT_SET - npp is reset
  *   _DELETED - npp's node has been deleted
  *   _TYPE_MISMATCH - npp's node is not a property
  *   _NOT_FOUND - property has no values
  *   _TRUNCATED - property has >1 values (first is written into out)
  *   _SUCCESS - property has 1 value (which is written into out)
+ *   _PERMISSION_DENIED - no authorization to read property value(s)
  *
  * We shorten *sz_out to not include anything after the final '\0'.
  */
@@ -4042,6 +4411,13 @@
 
 	assert(*sz_out == sizeof (*out));
 
+	RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
+	ret = rc_node_property_may_read(np);
+	rc_node_rele(np);
+
+	if (ret != REP_PROTOCOL_SUCCESS)
+		return (ret);
+
 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
 
 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
@@ -4079,6 +4455,7 @@
 
 	size_t start;
 	size_t w;
+	int ret;
 
 	rep_protocol_responseid_t result;
 
@@ -4089,6 +4466,12 @@
 	if (iter->rni_type != REP_PROTOCOL_ENTITY_VALUE)
 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
 
+	RC_NODE_CHECK(np);
+	ret = rc_node_property_may_read(np);
+
+	if (ret != REP_PROTOCOL_SUCCESS)
+		return (ret);
+
 	RC_NODE_CHECK_AND_LOCK(np);
 
 	vals = np->rn_values;
@@ -4320,7 +4703,7 @@
 			if (rc == REP_PROTOCOL_SUCCESS) {
 				iter->rni_iter =
 				    uu_list_walk_start(np->rn_children,
-					UU_WALK_ROBUST);
+				    UU_WALK_ROBUST);
 
 				if (iter->rni_iter == NULL)
 					rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
--- a/usr/src/cmd/svc/startd/graph.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/startd/graph.c	Thu Sep 13 10:10:42 2007 -0700
@@ -1953,7 +1953,7 @@
 		case SCF_ERROR_HANDLE_MISMATCH:
 		case SCF_ERROR_NOT_BOUND:
 		case SCF_ERROR_NOT_SET:
-			bad_error("scf_iter_service_instances", scf_error())
+			bad_error("scf_iter_service_instances", scf_error());
 		}
 	}
 
@@ -3381,9 +3381,9 @@
 
 	assert(sulogin_thread_running);
 
-	do
+	do {
 		(void) run_sulogin("Console login service(s) cannot run\n");
-	while (!can_come_up());
+	} while (!can_come_up());
 
 	sulogin_thread_running = B_FALSE;
 	MUTEX_UNLOCK(&dgraph_lock);
@@ -5595,6 +5595,7 @@
 				continue;
 
 			case SCF_ERROR_NOT_SET:
+			case SCF_ERROR_PERMISSION_DENIED:
 				bad_error("scf_property_get_value",
 				    scf_error());
 			}
--- a/usr/src/cmd/svc/startd/libscf.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/startd/libscf.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,8 +18,9 @@
  *
  * 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.
  */
 
@@ -630,6 +631,7 @@
  *     ENOENT - the property doesn't exist or has no values
  *     EINVAL - the property has the wrong type
  *		the property is not single-valued
+ *     EACCES - the current user does not have permission to read the value
  */
 static int
 get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
@@ -703,6 +705,10 @@
 			ret = EINVAL;
 			goto out;
 
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = EACCES;
+			goto out;
+
 		case SCF_ERROR_NOT_SET:
 			bad_error("scf_property_get_value", scf_error());
 		}
@@ -728,6 +734,7 @@
  *     ENOENT - the property doesn't exist or has no values
  *     EINVAL - the property has the wrong type
  *              the property is not single-valued
+ *     EACCES - the current user does not have permission to read the value
  */
 static int
 get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
@@ -804,6 +811,10 @@
 			ret = EINVAL;
 			goto out;
 
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = EACCES;
+			goto out;
+
 		case SCF_ERROR_NOT_SET:
 			bad_error("scf_property_get_value", scf_error());
 		}
@@ -978,6 +989,7 @@
 			*enabled_ovrp = -1;
 			break;
 
+		case EACCES:
 		default:
 			bad_error("get_boolean", r);
 		}
@@ -1035,6 +1047,7 @@
 		*enabledp = -1;
 		break;
 
+	case EACCES:
 	default:
 		bad_error("get_boolean", r);
 	}
@@ -1693,6 +1706,7 @@
 			return (EINVAL);
 
 		case SCF_ERROR_NOT_SET:
+		case SCF_ERROR_PERMISSION_DENIED:
 			bad_error("scf_property_get_value", scf_error());
 		}
 	}
@@ -1829,6 +1843,7 @@
 
 		case SCF_ERROR_HANDLE_MISMATCH:
 		case SCF_ERROR_NOT_BOUND:
+		case SCF_ERROR_PERMISSION_DENIED:
 		default:
 			bad_error("scf_property_get_value", scf_error());
 		}
@@ -2335,6 +2350,7 @@
 	case ECANCELED:
 		goto read_id_err;
 
+	case EACCES:
 	default:
 		bad_error("get_count", ret);
 	}
@@ -2361,6 +2377,7 @@
 	case ECANCELED:
 		goto read_id_err;
 
+	case EACCES:
 	default:
 		bad_error("get_count", ret);
 	}
@@ -2386,6 +2403,7 @@
 	case ECANCELED:
 		goto read_id_err;
 
+	case EACCES:
 	default:
 		bad_error("get_count", ret);
 	}
@@ -2897,6 +2915,7 @@
 		*timeout = METHOD_TIMEOUT_INFINITE;
 		break;
 
+	case EACCES:
 	default:
 		bad_error("get_count", r);
 	}
@@ -2969,6 +2988,7 @@
 			*need_sessionp = 0;
 			break;
 
+		case EACCES:
 		default:
 			bad_error("get_boolean", r);
 		}
@@ -2994,6 +3014,7 @@
 			*timeout_retry = 1;
 			break;
 
+		case EACCES:
 		default:
 			bad_error("get_boolean", r);
 		}
@@ -3177,6 +3198,7 @@
 				rep_ts = ts;
 				break;
 
+			case SCF_ERROR_PERMISSION_DENIED:
 			case SCF_ERROR_NOT_SET:
 				assert(0);
 				abort();
@@ -3494,6 +3516,7 @@
 			case SCF_ERROR_INVALID_ARGUMENT:
 			case SCF_ERROR_NOT_BOUND:
 			case SCF_ERROR_HANDLE_MISMATCH:
+			case SCF_ERROR_PERMISSION_DENIED:
 			default:
 				bad_error("scf_iter_next_value", scf_error());
 			}
--- a/usr/src/cmd/svc/startd/method.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/startd/method.c	Thu Sep 13 10:10:42 2007 -0700
@@ -524,7 +524,8 @@
 		}
 	}
 
-	nenv = set_smf_env(mcp->env, mcp->env_sz, NULL, inst, method);
+	nenv = set_smf_env(mcp->env, mcp->env_sz, NULL, inst,
+	    method_names[type]);
 
 	log_preexec();
 
--- a/usr/src/cmd/svc/startd/startd.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/startd/startd.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,8 +18,9 @@
  *
  * 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.
  */
 
@@ -519,6 +520,12 @@
 				    "values; ignored.\n", buf);
 				continue;
 
+			case SCF_ERROR_PERMISSION_DENIED:
+				uu_warn("property \"options/%s\" cannot be "
+				    "read because startd has insufficient "
+				    "permission; ignored.\n", buf);
+				continue;
+
 			case SCF_ERROR_HANDLE_MISMATCH:
 			case SCF_ERROR_NOT_BOUND:
 			case SCF_ERROR_NOT_SET:
--- a/usr/src/cmd/svc/svccfg/svccfg.h	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg.h	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -55,6 +55,10 @@
 #define	SCI_FRESH	0x10		/* Freshly imported service */
 #define	SCI_FORCE	0x20		/* Override-import. */
 #define	SCI_KEEP	0x40		/* Don't delete when SCI_FORCEing */
+#define	SCI_NOSNAP	0x80		/* Don't take last-import snapshot */
+
+/* Flags for lscf_service_export() */
+#define	SCE_ALL_VALUES	0x01		/* Include all property values */
 
 #ifdef lint
 extern int yyerror(const char *);
@@ -111,6 +115,12 @@
 	IMPORT_REFRESHED
 };
 
+typedef enum svccfg_op {
+	SVCCFG_OP_IMPORT = 0,
+	SVCCFG_OP_APPLY,
+	SVCCFG_OP_RESTORE
+} svccfg_op_t;
+
 typedef struct entity {
 	uu_list_node_t	sc_node;
 	entity_type_t sc_etype;
@@ -340,7 +350,7 @@
 CPL_MATCH_FN(complete_command);
 
 int lxml_init(void);
-int lxml_get_bundle_file(bundle_t *, const char *, int);
+int lxml_get_bundle_file(bundle_t *, const char *, svccfg_op_t);
 
 void engine_init(void);
 int engine_exec_cmd(void);
--- a/usr/src/cmd/svc/svccfg/svccfg.l	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg.l	Thu Sep 13 10:10:42 2007 -0700
@@ -3,9 +3,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.
@@ -19,8 +18,10 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * 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.
  */
 
@@ -79,6 +80,7 @@
 <INITIAL>import		{ BEGIN WORD; return (SCC_IMPORT); }
 <INITIAL>export		{ BEGIN WORD; return (SCC_EXPORT); }
 <INITIAL>archive	{ BEGIN WORD; return (SCC_ARCHIVE); }
+<INITIAL>restore	{ BEGIN WORD; return (SCC_RESTORE); }
 <INITIAL>apply		{ BEGIN WORD; return (SCC_APPLY); }
 <INITIAL>extract	{ BEGIN WORD; return (SCC_EXTRACT); }
 <INITIAL>repository	{ BEGIN WORD; return (SCC_REPOSITORY); }
--- a/usr/src/cmd/svc/svccfg/svccfg.y	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg.y	Thu Sep 13 10:10:42 2007 -0700
@@ -19,6 +19,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -43,7 +44,7 @@
 %start commands
 
 %token SCC_VALIDATE SCC_IMPORT SCC_EXPORT SCC_ARCHIVE SCC_APPLY SCC_EXTRACT
-%token SCC_REPOSITORY SCC_INVENTORY SCC_SET SCC_END SCC_HELP
+%token SCC_REPOSITORY SCC_INVENTORY SCC_SET SCC_END SCC_HELP SCC_RESTORE
 %token SCC_LIST SCC_ADD SCC_DELETE SCC_SELECT SCC_UNSELECT
 %token SCC_LISTPG SCC_ADDPG SCC_DELPG
 %token SCC_LISTPROP SCC_SETPROP SCC_DELPROP SCC_EDITPROP
@@ -75,6 +76,7 @@
 	| import_cmd
 	| export_cmd
 	| archive_cmd
+	| restore_cmd
 	| apply_cmd
 	| extract_cmd
 	| repository_cmd
@@ -128,7 +130,7 @@
 validate_cmd : SCC_VALIDATE SCV_WORD terminator
 	{
 		bundle_t *b = internal_bundle_new();
-		lxml_get_bundle_file(b, $2, 0);
+		lxml_get_bundle_file(b, $2, SVCCFG_OP_IMPORT);
 		(void) internal_bundle_free(b);
 		free($2);
 	}
@@ -155,28 +157,87 @@
 
 export_cmd : SCC_EXPORT SCV_WORD terminator
 	{
-		lscf_service_export($2, NULL);
+		lscf_service_export($2, NULL, 0);
 		free($2);
 	}
 	| SCC_EXPORT SCV_WORD SCS_REDIRECT SCV_WORD terminator
 	{
-		lscf_service_export($2, $4);
+		lscf_service_export($2, $4, 0);
 		free($2);
 		free($4);
 	}
+	| SCC_EXPORT SCV_WORD SCV_WORD terminator
+	{
+		if (strcmp($2, "-a") == 0) {
+			lscf_service_export($3, NULL, SCE_ALL_VALUES);
+			free($2);
+			free($3);
+		} else {
+			synerr(SCC_EXPORT);
+			free($2);
+			free($3);
+			return (0);
+		}
+	}
+	| SCC_EXPORT SCV_WORD SCV_WORD SCS_REDIRECT SCV_WORD terminator
+	{
+		if (strcmp($2, "-a") == 0) {
+			lscf_service_export($3, $5, SCE_ALL_VALUES);
+			free($2);
+			free($3);
+			free($5);
+		} else {
+			synerr(SCC_EXPORT);
+			free($2);
+			free($3);
+			free($5);
+			return (0);
+		}
+	}
 	| SCC_EXPORT error terminator	{ synerr(SCC_EXPORT); return(0); }
 
 archive_cmd : SCC_ARCHIVE terminator
 	{
-		lscf_archive(NULL);
+		lscf_archive(NULL, 0);
+	}
+	| SCC_ARCHIVE SCV_WORD terminator
+	{
+		if (strcmp($2, "-a") == 0) {
+			lscf_archive(NULL, SCE_ALL_VALUES);
+			free($2);
+		} else {
+			synerr(SCC_ARCHIVE);
+			free($2);
+			return (0);
+		}
 	}
 	| SCC_ARCHIVE SCS_REDIRECT SCV_WORD terminator
 	{
-		lscf_archive($3);
+		lscf_archive($3, 0);
 		free($3);
 	}
+	| SCC_ARCHIVE SCV_WORD SCS_REDIRECT SCV_WORD terminator
+	{
+		if (strcmp($2, "-a") == 0) {
+			lscf_archive($4, SCE_ALL_VALUES);
+			free($2);
+			free($4);
+		} else {
+			synerr(SCC_ARCHIVE);
+			free($2);
+			free($4);
+			return (0);
+		}
+	}
 	| SCC_ARCHIVE error terminator	{ synerr(SCC_ARCHIVE); return(0); }
 
+restore_cmd : SCC_RESTORE SCV_WORD terminator
+	{
+		(void) engine_restore($2);
+		free($2);
+	}
+	| SCC_RESTORE error terminator	{ synerr(SCC_RESTORE); return(0); }
+
 apply_cmd : SCC_APPLY SCV_WORD terminator
 					{ (void) engine_apply($2); free($2); }
 	| SCC_APPLY error terminator	{ synerr(SCC_APPLY); return(0); }
@@ -254,6 +315,8 @@
 			free($3);
 		} else {
 			synerr(SCC_DELETE);
+			free($2);
+			free($3);
 			return(0);
 		}
 	}
--- a/usr/src/cmd/svc/svccfg/svccfg_engine.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_engine.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,8 +18,9 @@
  *
  * 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.
  */
 
@@ -409,9 +410,9 @@
 			goto fail;
 		}
 
-		do
+		do {
 			ret = fstat(fileno(est->sc_cmd_file), &st);
-		while (ret != 0 && errno == EINTR);
+		} while (ret != 0 && errno == EINTR);
 		if (ret != 0) {
 			(void) fclose(est->sc_cmd_file);
 			est->sc_cmd_file = NULL;	/* for semerr() */
@@ -570,7 +571,7 @@
 	/* Load */
 	b = internal_bundle_new();
 
-	if (lxml_get_bundle_file(b, file, 0) != 0) {
+	if (lxml_get_bundle_file(b, file, SVCCFG_OP_IMPORT) != 0) {
 		internal_bundle_free(b);
 		return (-1);
 	}
@@ -594,7 +595,7 @@
 				semerr(errstr);
 			else
 				semerr(gettext("Unknown error from "
-					"mhash_store_entry()\n"));
+				    "mhash_store_entry()\n"));
 		}
 
 		free(pname);
@@ -623,7 +624,7 @@
 
 	b = internal_bundle_new();
 
-	if (lxml_get_bundle_file(b, file, 1) != 0) {
+	if (lxml_get_bundle_file(b, file, SVCCFG_OP_APPLY) != 0) {
 		internal_bundle_free(b);
 		return (-1);
 	}
@@ -647,6 +648,30 @@
 }
 
 int
+engine_restore(const char *file)
+{
+	bundle_t *b;
+
+	lscf_prep_hndl();
+
+	b = internal_bundle_new();
+
+	if (lxml_get_bundle_file(b, file, SVCCFG_OP_RESTORE) != 0) {
+		internal_bundle_free(b);
+		return (-1);
+	}
+
+	if (lscf_bundle_import(b, file, SCI_NOSNAP) != 0) {
+		internal_bundle_free(b);
+		return (-1);
+	}
+
+	internal_bundle_free(b);
+
+	return (0);
+}
+
+int
 engine_set(uu_list_t *args)
 {
 	uu_list_walk_t *walk;
--- a/usr/src/cmd/svc/svccfg/svccfg_help.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_help.c	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * 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.
  */
 
@@ -34,12 +34,15 @@
 		"Process a manifest file without changing the repository."
 	},
 	{ SCC_IMPORT, "import file\n\nImport a manifest into the repository." },
-	{ SCC_EXPORT, "export {service | pattern} [> file]\n\n"
+	{ SCC_EXPORT, "export [-a] {service | pattern} [> file]\n\n"
 "Print a manifest for service to file, or standard output if not specified."
 	},
-	{ SCC_ARCHIVE, "archive [> file]\n\n"
+	{ SCC_ARCHIVE, "archive [-a] [> file]\n\n"
 "Print an archive to file, or standard output if not specified."
 	},
+	{ SCC_RESTORE, "restore file\n\n"
+"Restore the contents of a previously-generated archive."
+	},
 	{ SCC_APPLY, "apply file\n\nApply a profile." },
 	{ SCC_EXTRACT, "extract [> file]\n\n"
 "Print a profile to file, or standard output if not specified." },
--- a/usr/src/cmd/svc/svccfg/svccfg_internal.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_internal.c	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -738,6 +738,7 @@
  *   ECANCELED - prop's pg was deleted
  *   ECONNABORTED - repository disconnected
  *   ENOMEM - out of memory
+ *   EACCES - permission denied when reading property
  */
 static int
 load_property(scf_property_t *prop, property_t **ipp)
@@ -822,6 +823,10 @@
 				r = ECONNABORTED;
 				goto out;
 
+			case SCF_ERROR_PERMISSION_DENIED:
+				r = EACCES;
+				goto out;
+
 			case SCF_ERROR_HANDLE_MISMATCH:
 			case SCF_ERROR_NOT_BOUND:
 			case SCF_ERROR_NOT_SET:
@@ -978,6 +983,7 @@
  *   ECONNABORTED - repository disconnected
  *   EBADF - pg is corrupt (error printed if fmri is given)
  *   ENOMEM - out of memory
+ *   EACCES - permission denied when reading property
  */
 int
 load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri,
@@ -1050,6 +1056,7 @@
 		case ECANCELED:
 		case ECONNABORTED:
 		case ENOMEM:
+		case EACCES:
 			goto out;
 
 		default:
--- a/usr/src/cmd/svc/svccfg/svccfg_libscf.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_libscf.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -40,6 +41,7 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 #include <wait.h>
 
@@ -107,6 +109,14 @@
 	scf_snaplevel_t	*sl;
 };
 
+/*
+ * This is used for communication between lscf_service_export and
+ * export_callback.
+ */
+struct export_args {
+	const char	*filename;
+	int 		flags;
+};
 
 const char * const scf_pg_general = SCF_PG_GENERAL;
 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
@@ -1057,7 +1067,9 @@
 
 	err = scf_error();
 
-	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_CONSTRAINT_VIOLATED)
+	if (err != SCF_ERROR_NOT_FOUND &&
+	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
+	    err != SCF_ERROR_PERMISSION_DENIED)
 		scfdie();
 
 	if (g_verbose) {
@@ -1076,9 +1088,11 @@
 		if (err == SCF_ERROR_NOT_FOUND)
 			emsg = gettext("Property %s has no values; expected "
 			    "one.\n");
-		else
+		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
 			emsg = gettext("Property %s has multiple values; "
 			    "expected one.\n");
+		else
+			emsg = gettext("No permission to read property %s.\n");
 
 		warn(emsg, fmri);
 
@@ -3057,6 +3071,7 @@
 			case SCF_ERROR_HANDLE_MISMATCH:
 			case SCF_ERROR_NOT_BOUND:
 			case SCF_ERROR_NOT_SET:
+			case SCF_ERROR_PERMISSION_DENIED:
 			default:
 				bad_error("scf_property_get_value",
 				    scf_error());
@@ -3103,6 +3118,7 @@
 			case SCF_ERROR_HANDLE_MISMATCH:
 			case SCF_ERROR_NOT_BOUND:
 			case SCF_ERROR_NOT_SET:
+			case SCF_ERROR_PERMISSION_DENIED:
 			default:
 				bad_error("scf_property_get_value",
 				    scf_error());
@@ -3169,6 +3185,7 @@
 		case EBADF:
 			return (r);
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -3233,6 +3250,7 @@
 			internal_pgroup_free(old_dpt_pgroup);
 			return (r);
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -3366,6 +3384,7 @@
 		case SCF_ERROR_HANDLE_MISMATCH:
 		case SCF_ERROR_NOT_BOUND:
 		case SCF_ERROR_NOT_SET:
+		case SCF_ERROR_PERMISSION_DENIED:
 		default:
 			bad_error("scf_property_get_value", scf_error());
 		}
@@ -3413,6 +3432,7 @@
 		case EBADF:
 			return (r);
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -3494,6 +3514,7 @@
 		case SCF_ERROR_HANDLE_MISMATCH:
 		case SCF_ERROR_NOT_BOUND:
 		case SCF_ERROR_NOT_SET:
+		case SCF_ERROR_PERMISSION_DENIED:
 		default:
 			bad_error("scf_property_get_value", scf_error());
 		}
@@ -3601,6 +3622,7 @@
 		case EBADF:
 			goto out;
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -3653,6 +3675,7 @@
 		case EBADF:
 			return (r);
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -3716,6 +3739,7 @@
 	case EBADF:
 		goto out;
 
+	case EACCES:
 	default:
 		bad_error("load_pg", r);
 	}
@@ -3821,6 +3845,7 @@
 		case EBADF:
 			goto out;
 
+		case EACCES:
 		default:
 			bad_error("load_pg", r);
 		}
@@ -4073,6 +4098,7 @@
 		case SCF_ERROR_HANDLE_MISMATCH:
 		case SCF_ERROR_NOT_BOUND:
 		case SCF_ERROR_NOT_SET:
+		case SCF_ERROR_PERMISSION_DENIED:
 		default:
 			bad_error("scf_property_get_value",
 			    scf_error());
@@ -4201,6 +4227,7 @@
 		internal_pgroup_free(pgroup);
 		return (0);
 
+	case EACCES:
 	default:
 		bad_error("load_pg", r);
 	}
@@ -4239,6 +4266,7 @@
  *	    - couldn't upgrade dependents (backend access denied)
  *	    - couldn't import pg (backend access denied)
  *	    - couldn't upgrade pg (backend access denied)
+ *	    - couldn't read property (backend access denied)
  *   EBUSY - property group was added (error printed)
  *	   - property group was deleted (error printed)
  *	   - property group changed (error printed)
@@ -4385,6 +4413,7 @@
 		case ECONNABORTED:
 		case ENOMEM:
 		case EBADF:
+		case EACCES:
 			return (r);
 
 		default:
@@ -4400,6 +4429,7 @@
 		case ECONNABORTED:
 		case ENOMEM:
 		case EBADF:
+		case EACCES:
 			internal_pgroup_free(lipg_i);
 			return (r);
 
@@ -4454,6 +4484,7 @@
 	case ECONNABORTED:
 	case EBADF:
 	case ENOMEM:
+	case EACCES:
 		return (r);
 
 	default:
@@ -4541,6 +4572,7 @@
 	case ECONNABORTED:
 	case EBADF:
 	case ENOMEM:
+	case EACCES:
 		goto out;
 
 	default:
@@ -4936,6 +4968,7 @@
 		case ECONNABORTED:
 		case EBADF:
 		case ENOMEM:
+		case EACCES:
 			return (r);
 
 		default:
@@ -5591,6 +5624,9 @@
 	}
 
 lionly:
+	if (lcbdata->sc_flags & SCI_NOSNAP)
+		goto deltemp;
+
 	/* transfer snapshot from temporary instance */
 	if (g_verbose)
 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
@@ -7245,10 +7281,10 @@
  */
 static void
 export_property(scf_property_t *prop, const char *name_arg,
-    struct pg_elts *elts)
+    struct pg_elts *elts, int flags)
 {
 	const char *type;
-	scf_error_t err;
+	scf_error_t err = 0;
 	xmlNodePtr pnode, lnode;
 	char *lnname;
 	int ret;
@@ -7267,7 +7303,10 @@
 		uu_die(gettext("Can't export property %s: unknown type.\n"),
 		    exp_str);
 
-	/* Is there a single value? */
+	/* If we're exporting values, and there's just one, export it here. */
+	if (!(flags & SCE_ALL_VALUES))
+		goto empty;
+
 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
 		xmlNodePtr n;
 
@@ -7292,9 +7331,18 @@
 	}
 
 	err = scf_error();
-	if (err != SCF_ERROR_CONSTRAINT_VIOLATED && err != SCF_ERROR_NOT_FOUND)
-		scfdie();
-
+
+	if (err == SCF_ERROR_PERMISSION_DENIED) {
+		semerr(emsg_permission_denied);
+		return;
+	}
+
+	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
+	    err != SCF_ERROR_NOT_FOUND &&
+	    err != SCF_ERROR_PERMISSION_DENIED)
+		scfdie();
+
+empty:
 	/* Multiple (or no) values, so use property */
 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
 	if (pnode == NULL)
@@ -7345,11 +7393,12 @@
  * Add a property_group element for this property group to elts.
  */
 static void
-export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts)
+export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
 {
 	xmlNodePtr n;
 	struct pg_elts elts;
 	int ret;
+	boolean_t read_protected;
 
 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
 
@@ -7369,6 +7418,17 @@
 
 	(void) memset(&elts, 0, sizeof (elts));
 
+	/*
+	 * If this property group is not read protected, we always want to
+	 * output all the values.  Otherwise, we only output the values if the
+	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
+	 */
+	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
+		scfdie();
+
+	if (!read_protected)
+		flags |= SCE_ALL_VALUES;
+
 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
 			scfdie();
@@ -7388,7 +7448,7 @@
 			xmlFreeNode(m);
 		}
 
-		export_property(exp_prop, NULL, &elts);
+		export_property(exp_prop, NULL, &elts, flags);
 	}
 	if (ret == -1)
 		scfdie();
@@ -7504,7 +7564,7 @@
 	if (err) {
 		xmlFreeNode(n);
 
-		export_pg(pg, eelts);
+		export_pg(pg, eelts, 0);
 
 		return;
 	}
@@ -7539,7 +7599,7 @@
 			xmlFreeNode(m);
 		}
 
-		export_property(exp_prop, exp_str, &elts);
+		export_property(exp_prop, exp_str, &elts, 0);
 	}
 	if (ret == -1)
 		scfdie();
@@ -7667,7 +7727,7 @@
 	if (err) {
 		xmlFreeNode(n);
 
-		export_pg(pg, eelts);
+		export_pg(pg, eelts, 0);
 
 		return;
 	}
@@ -7842,7 +7902,7 @@
 				continue;
 		}
 
-		export_property(exp_prop, exp_str, &elts);
+		export_property(exp_prop, exp_str, &elts, 0);
 	}
 	if (ret == -1)
 		scfdie();
@@ -7958,7 +8018,7 @@
 			xmlFreeNode(s);
 		}
 
-		export_property(exp_prop, exp_str, &elts);
+		export_property(exp_prop, exp_str, &elts, 0);
 	}
 	if (ret == -1)
 		scfdie();
@@ -7988,7 +8048,7 @@
 			elts->method_context = n;
 		} else {
 			xmlFreeNode(n);
-			export_pg(pg, elts);
+			export_pg(pg, elts, 0);
 		}
 		return;
 	}
@@ -8060,7 +8120,7 @@
 
 	if (err && env == NULL) {
 		xmlFreeNode(n);
-		export_pg(pg, elts);
+		export_pg(pg, elts, 0);
 		return;
 	}
 
@@ -8174,7 +8234,7 @@
 			xmlFreeNode(s);
 		}
 
-		export_property(exp_prop, exp_str, &pgelts);
+		export_property(exp_prop, exp_str, &pgelts, 0);
 	}
 	if (ret == -1)
 		scfdie();
@@ -8223,7 +8283,7 @@
 		if ((ty != SCF_TYPE_ASTRING &&
 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
 		    prop_get_val(exp_prop, exp_val) != 0) {
-			export_property(exp_prop, NULL, &pgelts);
+			export_property(exp_prop, NULL, &pgelts, 0);
 			continue;
 		}
 
@@ -8254,7 +8314,7 @@
 				    "FMRI.\n"), fmri);
 			}
 
-			export_property(exp_prop, exp_str, &pgelts);
+			export_property(exp_prop, exp_str, &pgelts, 0);
 			continue;
 
 		case SCF_ERROR_CONSTRAINT_VIOLATED:
@@ -8267,7 +8327,7 @@
 				    "a service or an instance.\n"), fmri);
 			}
 
-			export_property(exp_prop, exp_str, &pgelts);
+			export_property(exp_prop, exp_str, &pgelts, 0);
 			continue;
 
 		case SCF_ERROR_NOT_FOUND:
@@ -8280,7 +8340,7 @@
 				    "not exist.\n"), fmri);
 			}
 
-			export_property(exp_prop, exp_str, &pgelts);
+			export_property(exp_prop, exp_str, &pgelts, 0);
 			continue;
 
 		default:
@@ -8299,7 +8359,7 @@
 			warn(gettext("Entity %s is missing dependency property "
 			    "group %s.\n"), fmri, exp_str);
 
-			export_property(exp_prop, NULL, &pgelts);
+			export_property(exp_prop, NULL, &pgelts, 0);
 			continue;
 		}
 
@@ -8313,13 +8373,13 @@
 			warn(gettext("Property group %s is not of "
 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
 
-			export_property(exp_prop, NULL, &pgelts);
+			export_property(exp_prop, NULL, &pgelts, 0);
 			continue;
 		}
 
 		n = export_dependent(opg, exp_str, fmri);
 		if (n == NULL)
-			export_property(exp_prop, exp_str, &pgelts);
+			export_property(exp_prop, exp_str, &pgelts, 0);
 		else {
 			if (eelts->dependents == NULL)
 				eelts->dependents = n;
@@ -8444,12 +8504,12 @@
 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
 		telts->common_name = export_tm_loctext(pg, "common_name");
 		if (telts->common_name == NULL)
-			export_pg(pg, elts);
+			export_pg(pg, elts, 0);
 		return;
 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
 		telts->description = export_tm_loctext(pg, "description");
 		if (telts->description == NULL)
-			export_pg(pg, elts);
+			export_pg(pg, elts, 0);
 		return;
 	}
 
@@ -8463,7 +8523,7 @@
 		make_node(&telts->documentation, "documentation");
 		(void) xmlAddChild(telts->documentation, child);
 	} else {
-		export_pg(pg, elts);
+		export_pg(pg, elts, 0);
 	}
 }
 
@@ -8522,7 +8582,7 @@
 			xmlFreeNode(rnode);
 		}
 
-		export_property(exp_prop, exp_str, &pgelts);
+		export_property(exp_prop, exp_str, &pgelts, 0);
 	}
 	if (ret == -1)
 		scfdie();
@@ -8536,7 +8596,7 @@
  * Put an instance element for the given instance into selts.
  */
 static void
-export_instance(scf_instance_t *inst, struct entity_elts *selts)
+export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
 {
 	xmlNodePtr n;
 	boolean_t isdefault;
@@ -8590,12 +8650,12 @@
 	(void) memset(&template_elts, 0, sizeof (template_elts));
 
 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
-		uint32_t flags;
-
-		if (scf_pg_get_flags(exp_pg, &flags) != 0)
-			scfdie();
-
-		if (flags & SCF_PG_FLAG_NONPERSISTENT)
+		uint32_t pgflags;
+
+		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
+			scfdie();
+
+		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
 			continue;
 
 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
@@ -8629,7 +8689,7 @@
 		}
 
 		/* Ordinary pg. */
-		export_pg(exp_pg, &elts);
+		export_pg(exp_pg, &elts, flags);
 	}
 	if (ret == -1)
 		scfdie();
@@ -8684,7 +8744,7 @@
  * Return a service element for the given service.
  */
 static xmlNodePtr
-export_service(scf_service_t *svc)
+export_service(scf_service_t *svc, int flags)
 {
 	xmlNodePtr snode;
 	struct entity_elts elts;
@@ -8711,12 +8771,12 @@
 	(void) memset(&template_elts, 0, sizeof (template_elts));
 
 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
-		uint32_t flags;
-
-		if (scf_pg_get_flags(exp_pg, &flags) != 0)
-			scfdie();
-
-		if (flags & SCF_PG_FLAG_NONPERSISTENT)
+		uint32_t pgflags;
+
+		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
+			scfdie();
+
+		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
 			continue;
 
 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
@@ -8749,7 +8809,7 @@
 			continue;
 		}
 
-		export_pg(exp_pg, &elts);
+		export_pg(exp_pg, &elts, flags);
 	}
 	if (ret == -1)
 		scfdie();
@@ -8769,7 +8829,7 @@
 		scfdie();
 
 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
-		export_instance(exp_inst, &elts);
+		export_instance(exp_inst, &elts, flags);
 	if (ret == -1)
 		scfdie();
 
@@ -8796,7 +8856,7 @@
 	xmlDocPtr doc;
 	xmlNodePtr sb;
 	int result;
-	char *filename = data;
+	struct export_args *argsp = (struct export_args *)data;
 
 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
@@ -8811,16 +8871,16 @@
 	exp_str_sz = max_scf_len + 1;
 	exp_str = safe_malloc(exp_str_sz);
 
-	if (filename != NULL) {
+	if (argsp->filename != NULL) {
 		errno = 0;
-		f = fopen(filename, "wb");
+		f = fopen(argsp->filename, "wb");
 		if (f == NULL) {
 			if (errno == 0)
 				uu_die(gettext("Could not open \"%s\": no free "
-				    "stdio streams.\n"), filename);
+				    "stdio streams.\n"), argsp->filename);
 			else
 				uu_die(gettext("Could not open \"%s\""),
-				    filename);
+				    argsp->filename);
 		}
 	} else
 		f = stdout;
@@ -8840,7 +8900,7 @@
 	safe_setprop(sb, name_attr, "export");
 	(void) xmlAddSibling(doc->children, sb);
 
-	(void) xmlAddChild(sb, export_service(wip->svc));
+	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
 
 	result = write_service_bundle(doc, f);
 
@@ -8867,16 +8927,21 @@
  * dump it into filename (or stdout if filename is NULL).
  */
 int
-lscf_service_export(char *fmri, const char *filename)
-{
+lscf_service_export(char *fmri, const char *filename, int flags)
+{
+	struct export_args args;
 	int ret, err;
 
 	lscf_prep_hndl();
 
+	bzero(&args, sizeof (args));
+	args.filename = filename;
+	args.flags = flags;
+
 	err = 0;
 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
-	    (void *)filename, &err, semerr)) != 0) {
+	    &args, &err, semerr)) != 0) {
 		if (ret != -1)
 			semerr(gettext("Failed to walk instances: %s\n"),
 			    scf_strerror(ret));
@@ -8898,7 +8963,7 @@
  */
 
 static xmlNodePtr
-make_archive()
+make_archive(int flags)
 {
 	xmlNodePtr sb;
 	scf_scope_t *scope;
@@ -8947,7 +9012,7 @@
 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
 			continue;
 
-		xmlAddChild(sb, export_service(svc));
+		xmlAddChild(sb, export_service(svc, flags));
 	}
 
 	free(exp_str);
@@ -8968,7 +9033,7 @@
 }
 
 int
-lscf_archive(const char *filename)
+lscf_archive(const char *filename, int flags)
 {
 	FILE *f;
 	xmlDocPtr doc;
@@ -8998,7 +9063,7 @@
 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
 		uu_die(emsg_create_xml);
 
-	(void) xmlAddSibling(doc->children, make_archive());
+	(void) xmlAddSibling(doc->children, make_archive(flags));
 
 	result = write_service_bundle(doc, f);
 
@@ -10169,6 +10234,7 @@
 		switch (scf_error()) {
 		case SCF_ERROR_NOT_FOUND:
 			return (B_FALSE);
+		case SCF_ERROR_PERMISSION_DENIED:
 		case SCF_ERROR_CONSTRAINT_VIOLATED:
 			return (B_TRUE);
 		default:
@@ -10234,7 +10300,7 @@
 
 		free(buf);
 	}
-	if (ret != 0)
+	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
 		scfdie();
 
 	if (putchar('\n') != '\n')
@@ -11003,7 +11069,8 @@
 
 				free(buf);
 			}
-			if (ret3 < 0)
+			if (ret3 < 0 &&
+			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
 				scfdie();
 
 			/* Write closing paren if mult-value property */
--- a/usr/src/cmd/svc/svccfg/svccfg_xml.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svccfg/svccfg_xml.c	Thu Sep 13 10:10:42 2007 -0700
@@ -500,6 +500,18 @@
 		    "property \'%s/%s\'\n"), pgrp->sc_pgroup_name,
 		    p->sc_property_name);
 
+	for (r = 0; r < sizeof (lxml_prop_types) / sizeof (char *); r++) {
+		if (xmlStrcmp(type, (const xmlChar *)lxml_prop_types[r]) == 0)
+			break;
+	}
+
+	if (r >= sizeof (lxml_prop_types) / sizeof (char *)) {
+		uu_die(gettext("property type invalid for property '%s/%s'\n"),
+		    pgrp->sc_pgroup_name, p->sc_property_name);
+	}
+
+	p->sc_value_type = lxml_element_to_type(r);
+
 	for (cursor = property->xmlChildrenNode; cursor != NULL;
 	    cursor = cursor->next) {
 		if (lxml_ignorable_block(cursor))
@@ -524,7 +536,6 @@
 				    "type-to-list mismatch\n"),
 				    p->sc_property_name);
 
-			p->sc_value_type = lxml_element_to_type(r);
 			(void) lxml_get_value(p, r, cursor);
 			break;
 		default:
@@ -1487,11 +1498,11 @@
 
 /*
  * Translate an instance element into an internal property tree, added to
- * service.  If apply is true, forbid subelements and set the enabled property
- * to override.
+ * service.  If op is SVCCFG_OP_APPLY (i.e., apply a profile), forbid
+ * subelements and set the enabled property to override.
  */
 static int
-lxml_get_instance(entity_t *service, xmlNodePtr inst, int apply)
+lxml_get_instance(entity_t *service, xmlNodePtr inst, svccfg_op_t op)
 {
 	entity_t *i;
 	pgroup_t *pg;
@@ -1529,7 +1540,7 @@
 	p = internal_property_create(SCF_PROPERTY_ENABLED, SCF_TYPE_BOOLEAN, 1,
 	    (uint64_t)(strcmp(true, (const char *)enabled) == 0 ? 1 : 0));
 
-	p->sc_property_override = apply;
+	p->sc_property_override = (op == SVCCFG_OP_APPLY);
 
 	(void) internal_attach_property(pg, p);
 
@@ -1543,7 +1554,7 @@
 		if (lxml_ignorable_block(cursor))
 			continue;
 
-		if (apply) {
+		if (op == SVCCFG_OP_APPLY) {
 			semerr(gettext("Instance \"%s\" may not contain "
 			    "elements in profiles.\n"), i->sc_name,
 			    cursor->name);
@@ -1608,10 +1619,10 @@
 
 /*
  * Translate a service element into an internal instance/property tree, added
- * to bundle.  If apply is true, allow only instance subelements.
+ * to bundle.  If op is SVCCFG_OP_APPLY, allow only instance subelements.
  */
 static int
-lxml_get_service(bundle_t *bundle, xmlNodePtr svc, int apply)
+lxml_get_service(bundle_t *bundle, xmlNodePtr svc, svccfg_op_t op)
 {
 	entity_t *s;
 	xmlNodePtr cursor;
@@ -1643,7 +1654,7 @@
 
 		e = lxml_xlate_element(cursor->name);
 
-		if (apply && e != SC_INSTANCE) {
+		if (op == SVCCFG_OP_APPLY && e != SC_INSTANCE) {
 			semerr(gettext("Service \"%s\" may not contain the "
 			    "non-instance element \"%s\" in a profile.\n"),
 			    s->sc_name, cursor->name);
@@ -1653,7 +1664,7 @@
 
 		switch (e) {
 		case SC_INSTANCE:
-			(void) lxml_get_instance(s, cursor, apply);
+			(void) lxml_get_instance(s, cursor, op);
 			break;
 		case SC_TEMPLATE:
 			(void) lxml_get_template(s, cursor);
@@ -1721,7 +1732,7 @@
 
 static int
 lxml_get_bundle(bundle_t *bundle, bundle_type_t bundle_type,
-    xmlNodePtr subbundle, int apply)
+    xmlNodePtr subbundle, svccfg_op_t op)
 {
 	xmlNodePtr cursor;
 	xmlChar *type;
@@ -1740,16 +1751,25 @@
 
 	xmlFree(type);
 
-	if (!apply) {
+	switch (op) {
+	case SVCCFG_OP_IMPORT:
 		if (bundle->sc_bundle_type != SVCCFG_MANIFEST) {
 			semerr(gettext("document is not a manifest.\n"));
 			return (-1);
 		}
-	} else {
+		break;
+	case SVCCFG_OP_APPLY:
 		if (bundle->sc_bundle_type != SVCCFG_PROFILE) {
 			semerr(gettext("document is not a profile.\n"));
 			return (-1);
 		}
+		break;
+	case SVCCFG_OP_RESTORE:
+		if (bundle->sc_bundle_type != SVCCFG_ARCHIVE) {
+			semerr(gettext("document is not an archive.\n"));
+			return (-1);
+		}
+		break;
 	}
 
 	if ((bundle->sc_bundle_name = xmlGetProp(subbundle,
@@ -1773,11 +1793,11 @@
 			continue;
 
 		case SC_SERVICE_BUNDLE:
-			if (lxml_get_bundle(bundle, bundle_type, cursor, apply))
+			if (lxml_get_bundle(bundle, bundle_type, cursor, op))
 				return (-1);
 			break;
 		case SC_SERVICE:
-			(void) lxml_get_service(bundle, cursor, apply);
+			(void) lxml_get_service(bundle, cursor, op);
 			break;
 		}
 	}
@@ -1787,11 +1807,11 @@
 
 /*
  * Load an XML tree from filename and translate it into an internal service
- * tree bundle.  If apply is false, require that the the bundle be of type
- * manifest, or type profile otherwise.
+ * tree bundle.  Require that the bundle be of appropriate type for the
+ * operation: archive for RESTORE, manifest for IMPORT, profile for APPLY.
  */
 int
-lxml_get_bundle_file(bundle_t *bundle, const char *filename, int apply)
+lxml_get_bundle_file(bundle_t *bundle, const char *filename, svccfg_op_t op)
 {
 	xmlDocPtr document;
 	xmlNodePtr cursor;
@@ -1813,7 +1833,8 @@
 	 * Until libxml2 addresses DTD-based validation with XInclude, we don't
 	 * validate service profiles (i.e. the apply path).
 	 */
-	do_validate = (apply == 0) && (getenv("SVCCFG_NOVALIDATE") == NULL);
+	do_validate = (op != SVCCFG_OP_APPLY) &&
+	    (getenv("SVCCFG_NOVALIDATE") == NULL);
 	if (do_validate)
 		dtdpath = getenv("SVCCFG_DTD");
 
@@ -1894,7 +1915,7 @@
 	lxml_dump(0, cursor);
 #endif /* DEBUG */
 
-	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, apply);
+	r = lxml_get_bundle(bundle, SVCCFG_UNKNOWN_BUNDLE, cursor, op);
 
 	xmlFreeDoc(document);
 
@@ -1910,7 +1931,7 @@
 
 	b = internal_bundle_new();
 
-	if (lxml_get_bundle_file(b, filename, 0) != 0) {
+	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) != 0) {
 		internal_bundle_free(b);
 		return (-1);
 	}
--- a/usr/src/cmd/svc/svcprop/svcprop.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svcprop/svcprop.c	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -222,7 +222,10 @@
 {
 	scf_value_t *val;
 	scf_iter_t *iter;
-	int ret, first;
+	int ret, first, err;
+
+	const char * const permission_denied_emsg =
+	    gettext("Permission denied.\n");
 
 	if (types) {
 		scf_type_t ty;
@@ -277,8 +280,15 @@
 			(void) putchar(' ');
 		print_value(val);
 	}
-	if (ret == -1)
-		scfdie();
+	if (ret == -1) {
+		err = scf_error();
+		if (err == SCF_ERROR_PERMISSION_DENIED) {
+			if (uu_list_numnodes(prop_list) > 0)
+				die(permission_denied_emsg);
+		} else {
+			scfdie();
+		}
+	}
 
 	(void) putchar('\n');
 
--- a/usr/src/cmd/svc/svcs/explain.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svcs/explain.c	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1391,6 +1391,7 @@
 		switch (scf_error()) {
 		case SCF_ERROR_NOT_FOUND:
 		case SCF_ERROR_CONSTRAINT_VIOLATED:
+		case SCF_ERROR_PERMISSION_DENIED:
 			g_msgbase = NULL;
 			return;
 
@@ -1968,7 +1969,7 @@
 	for (tbsz = 50; ; tbsz *= 2) {
 		timebuf = safe_malloc(tbsz);
 		if (strftime(timebuf, tbsz, NULL, tmp) != 0)
-		    break;
+			break;
 		free(timebuf);
 	}
 
--- a/usr/src/cmd/svc/svcs/svcs.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/cmd/svc/svcs/svcs.c	Thu Sep 13 10:10:42 2007 -0700
@@ -17,8 +17,10 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * 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.
  */
 
@@ -376,6 +378,7 @@
 			}
 			goto misconfigured;
 
+		case SCF_ERROR_PERMISSION_DENIED:
 		default:
 			scfdie();
 		}
@@ -1092,7 +1095,7 @@
 		newsize = (*buf ? strlen(*buf) : 0) + DESC_COLUMN_WIDTH + 1;
 	newbuf = safe_malloc(newsize);
 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
-			DESC_COLUMN_WIDTH, common_name_buf);
+	    DESC_COLUMN_WIDTH, common_name_buf);
 	if (*buf)
 		free(*buf);
 	*buf = newbuf;
@@ -1629,13 +1632,13 @@
 	 */
 	if (now - then < 24 * 60 * 60)
 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_TIME),
-				tm);
+		    tm);
 	else if (now - then < 12 * 30 * 24 * 60 * 60)
 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_DATE),
-				tm);
+		    tm);
 	else
 		(void) strftime(st_buf, sizeof (st_buf), gettext(FORMAT_YEAR),
-				tm);
+		    tm);
 
 	(void) snprintf(newbuf, newsize, "%s%-*s ", *buf ? *buf : "",
 	    STIME_COLUMN_WIDTH + 1, st_buf);
@@ -2455,14 +2458,14 @@
 		 * than 12 months ago.
 		 */
 		if (now - psi.pr_start.tv_sec < 24 * 60 * 60)
-		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_TIME),
-			tm);
+			(void) strftime(stime, sizeof (stime),
+			    gettext(FORMAT_TIME), tm);
 		else if (now - psi.pr_start.tv_sec < 12 * 30 * 24 * 60 * 60)
-		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_DATE),
-			tm);
+			(void) strftime(stime, sizeof (stime),
+			    gettext(FORMAT_DATE), tm);
 		else
-		    (void) strftime(stime, sizeof (stime), gettext(FORMAT_YEAR),
-			tm);
+			(void) strftime(stime, sizeof (stime),
+			    gettext(FORMAT_YEAR), tm);
 
 		(void) snprintf(cp, len, "\n               %-8s   %6ld %.*s",
 		    stime, pids[i], PRFNSZ, psi.pr_fname);
--- a/usr/src/common/svc/repcache_protocol.h	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/common/svc/repcache_protocol.h	Thu Sep 13 10:10:42 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.
@@ -19,8 +18,9 @@
  *
  * 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.
  */
 
@@ -353,7 +353,6 @@
  *
  * BACKUP(name) -> result
  *	Backs up the persistant repository with a particular name.
- *
  */
 
 #include <door.h>
@@ -626,6 +625,7 @@
 #define	RP_ENTITY_NAME_SNAPLEVEL_SCOPE		3
 #define	RP_ENTITY_NAME_SNAPLEVEL_SERVICE	4
 #define	RP_ENTITY_NAME_SNAPLEVEL_INSTANCE	5
+#define	RP_ENTITY_NAME_PGREADPROT		6
 
 struct rep_protocol_entity_update {
 	enum rep_protocol_requestid rpr_request;	/* ENTITY_UPDATE */
--- a/usr/src/lib/librestart/common/librestart.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/lib/librestart/common/librestart.c	Thu Sep 13 10:10:42 2007 -0700
@@ -1069,6 +1069,7 @@
 
 					case SCF_ERROR_HANDLE_MISMATCH:
 					case SCF_ERROR_INVALID_ARGUMENT:
+					case SCF_ERROR_PERMISSION_DENIED:
 					default:
 						bad_fail("scf_iter_next_value",
 						    scf_error());
@@ -1367,6 +1368,7 @@
 
 					case SCF_ERROR_HANDLE_MISMATCH:
 					case SCF_ERROR_INVALID_ARGUMENT:
+					case SCF_ERROR_PERMISSION_DENIED:
 						bad_fail(
 						    "scf_iter_next_value",
 						    scf_error());
@@ -2532,7 +2534,7 @@
 
 		/* get resource pool */
 		if (get_astring_val(pg, SCF_PROPERTY_RESOURCE_POOL, cip->vbuf,
-			cip->vbuf_sz, prop, val) != 0) {
+		    cip->vbuf_sz, prop, val) != 0) {
 			errstr = "Could not get value of resource pool.";
 			goto out;
 		}
@@ -2839,9 +2841,9 @@
 	 * have access to the specified directory.
 	 */
 	if (cip->working_dir != NULL) {
-		do
+		do {
 			r = chdir(cip->working_dir);
-		while (r != 0 && errno == EINTR);
+		} while (r != 0 && errno == EINTR);
 		if (r != 0) {
 			*fp = "chdir";
 			ret = errno;
--- a/usr/src/lib/libscf/common/lowlevel.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/lib/libscf/common/lowlevel.c	Thu Sep 13 10:10:42 2007 -0700
@@ -6854,3 +6854,20 @@
 		return (scf_set_error(proto_error(response.rpr_response)));
 	return (SCF_SUCCESS);
 }
+
+int
+_scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
+{
+	char buf[REP_PROTOCOL_NAME_LEN];
+	ssize_t res;
+
+	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
+	    RP_ENTITY_NAME_PGREADPROT);
+
+	if (res == -1)
+		return (-1);
+
+	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
+		return (scf_set_error(SCF_ERROR_INTERNAL));
+	return (SCF_SUCCESS);
+}
--- a/usr/src/lib/libscf/common/mapfile-vers	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/lib/libscf/common/mapfile-vers	Thu Sep 13 10:10:42 2007 -0700
@@ -232,6 +232,7 @@
 	scf_set_count_property;
 	scf_simple_handle_destroy;
 	gen_filenms_from_fmri;
+	_scf_pg_is_read_protected;
     local:
 	*;
 };
--- a/usr/src/lib/libscf/common/midlevel.c	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/lib/libscf/common/midlevel.c	Thu Sep 13 10:10:42 2007 -0700
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -303,7 +304,9 @@
 	}
 
 	if (iterret == -1) {
-		if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
+		int err = scf_error();
+		if (err != SCF_ERROR_CONNECTION_BROKEN &&
+		    err != SCF_ERROR_PERMISSION_DENIED)
 			(void) scf_set_error(SCF_ERROR_INTERNAL);
 		goto error1;
 	}
@@ -1804,7 +1807,12 @@
 			return (NULL);
 		}
 	} else {
-		sys_fmri = strdup(inst_fmri);
+		if ((sys_fmri = strdup(inst_fmri)) == NULL) {
+			if (local_h)
+				scf_handle_destroy(h);
+			(void) scf_set_error(SCF_ERROR_NO_MEMORY);
+			return (NULL);
+		}
 	}
 
 	if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) {
@@ -1856,6 +1864,9 @@
 				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
 				goto error1;
 			}
+			nextpg->pg_name = NULL;
+			nextpg->pg_next = NULL;
+			nextpg->pg_proplist = NULL;
 			thispg->pg_next = nextpg;
 			thispg = nextpg;
 		} else {
@@ -1874,8 +1885,6 @@
 			goto error1;
 		}
 
-		nextpg->pg_next = NULL;
-		nextpg->pg_proplist = NULL;
 		thisprop = NULL;
 
 		scf_iter_reset(propiter);
@@ -2005,6 +2014,7 @@
 			thisprop = NULL;
 
 			if ((nextpg->pg_name = strdup(pgname)) == NULL) {
+				(void) scf_set_error(SCF_ERROR_NO_MEMORY);
 				free(nextpg);
 				goto error1;
 			}
--- a/usr/src/lib/libscf/inc/libscf_priv.h	Thu Sep 13 08:30:20 2007 -0700
+++ b/usr/src/lib/libscf/inc/libscf_priv.h	Thu Sep 13 10:10:42 2007 -0700
@@ -292,6 +292,18 @@
 int _scf_request_backup(scf_handle_t *, const char *);
 
 /*
+ * Determines whether a property group requires authorization to read; this
+ * does not in any way reflect whether the caller has that authorization.
+ * To determine that, the caller must attempt to read the value of one of the
+ * group's properties.
+ *
+ * Can fail with:
+ *	_NOT_BOUND, _CONNECTION_BROKEN, _INVALID_ARGUMENT, _INTERNAL,
+ *	_NO_RESOURCES, _CONSTRAINT_VIOLATED, _DELETED.
+ */
+int _scf_pg_is_read_protected(const scf_propertygroup_t *, boolean_t *);
+
+/*
  * scf_pattern_t
  */
 typedef struct scf_pattern {