Mercurial > illumos > illumos-gate
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
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 {