17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5d3186a0eSjeanm * Common Development and Distribution License (the "License").
6d3186a0eSjeanm * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
213eae19d9Swesolows
227c478bd9Sstevel@tonic-gate /*
23134a1f4eSCasper H.S. Dik * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24*a29160b0SRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
286643e1ffSbustos * rc_node.c - In-memory SCF object management
297c478bd9Sstevel@tonic-gate *
306643e1ffSbustos * This layer manages the in-memory cache (the Repository Cache) of SCF
316643e1ffSbustos * data. Read requests are usually satisfied from here, but may require
326643e1ffSbustos * load calls to the "object" layer. Modify requests always write-through
336643e1ffSbustos * to the object layer.
346643e1ffSbustos *
356643e1ffSbustos * SCF data comprises scopes, services, instances, snapshots, snaplevels,
366643e1ffSbustos * property groups, properties, and property values. All but the last are
376643e1ffSbustos * known here as "entities" and are represented by rc_node_t data
386643e1ffSbustos * structures. (Property values are kept in the rn_values member of the
396643e1ffSbustos * respective property, not as separate objects.) All entities besides
406643e1ffSbustos * the "localhost" scope have some entity as a parent, and therefore form
416643e1ffSbustos * a tree.
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * The entity tree is rooted at rc_scope, which rc_node_init() initializes to
447c478bd9Sstevel@tonic-gate * the "localhost" scope. The tree is filled in from the database on-demand
456643e1ffSbustos * by rc_node_fill_children().
467c478bd9Sstevel@tonic-gate *
476643e1ffSbustos * rc_node_t's are also placed in the cache_hash[] hash table, for rapid
486643e1ffSbustos * lookup.
497c478bd9Sstevel@tonic-gate *
506643e1ffSbustos * Multiple threads may service client requests, so access to each
516643e1ffSbustos * rc_node_t is synchronized by its rn_lock member. Some fields are
526643e1ffSbustos * protected by bits in the rn_flags field instead, to support operations
536643e1ffSbustos * which need to drop rn_lock, for example to respect locking order. Such
546643e1ffSbustos * flags should be manipulated with the rc_node_{hold,rele}_flag()
556643e1ffSbustos * functions.
566643e1ffSbustos *
576643e1ffSbustos * We track references to nodes to tell when they can be free()d. rn_refs
586643e1ffSbustos * should be incremented with rc_node_hold() on the creation of client
596643e1ffSbustos * references (rc_node_ptr_t's and rc_iter_t's). rn_erefs ("ephemeral
606643e1ffSbustos * references") should be incremented when a pointer is read into a local
616643e1ffSbustos * variable of a thread, with rc_node_hold_ephemeral_locked(). This
626643e1ffSbustos * hasn't been fully implemented, however, so rc_node_rele() tolerates
636643e1ffSbustos * rn_erefs being 0. Some code which predates rn_erefs counts ephemeral
646643e1ffSbustos * references in rn_refs. Other references are tracked by the
656643e1ffSbustos * rn_other_refs field and the RC_NODE_DEAD, RC_NODE_IN_PARENT,
666643e1ffSbustos * RC_NODE_OLD, and RC_NODE_ON_FORMER flags.
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * Locking rules: To dereference an rc_node_t * (usually to lock it), you must
697c478bd9Sstevel@tonic-gate * have a hold (rc_node_hold()) on it or otherwise be sure that it hasn't been
707c478bd9Sstevel@tonic-gate * rc_node_destroy()ed (hold a lock on its parent or child, hold a flag,
717c478bd9Sstevel@tonic-gate * etc.). Once you have locked an rc_node_t you must check its rn_flags for
727c478bd9Sstevel@tonic-gate * RC_NODE_DEAD before you can use it. This is usually done with the
737c478bd9Sstevel@tonic-gate * rc_node_{wait,hold}_flag() functions (often via the rc_node_check_*()
747c478bd9Sstevel@tonic-gate * functions & RC_NODE_*() macros), which fail if the object has died.
757c478bd9Sstevel@tonic-gate *
766643e1ffSbustos * When a transactional node (property group or snapshot) is updated,
776643e1ffSbustos * a new node takes the place of the old node in the global hash and the
786643e1ffSbustos * old node is hung off of the rn_former list of the new node. At the
796643e1ffSbustos * same time, all of its children have their rn_parent_ref pointer set,
806643e1ffSbustos * and any holds they have are reflected in the old node's rn_other_refs
816643e1ffSbustos * count. This is automatically kept up to date until the final reference
826643e1ffSbustos * to the subgraph is dropped, at which point the node is unrefed and
836643e1ffSbustos * destroyed, along with all of its children.
846643e1ffSbustos *
853eae19d9Swesolows * Because name service lookups may take a long time and, more importantly
863eae19d9Swesolows * may trigger additional accesses to the repository, perm_granted() must be
873eae19d9Swesolows * called without holding any locks.
883eae19d9Swesolows *
897c478bd9Sstevel@tonic-gate * An ITER_START for a non-ENTITY_VALUE induces an rc_node_fill_children()
907c478bd9Sstevel@tonic-gate * call via rc_node_setup_iter() to populate the rn_children uu_list of the
917c478bd9Sstevel@tonic-gate * rc_node_t * in question and a call to uu_list_walk_start() on that list. For
927c478bd9Sstevel@tonic-gate * ITER_READ, rc_iter_next() uses uu_list_walk_next() to find the next
937c478bd9Sstevel@tonic-gate * apropriate child.
947c478bd9Sstevel@tonic-gate *
957c478bd9Sstevel@tonic-gate * An ITER_START for an ENTITY_VALUE makes sure the node has its values
967c478bd9Sstevel@tonic-gate * filled, and sets up the iterator. An ITER_READ_VALUE just copies out
977c478bd9Sstevel@tonic-gate * the proper values and updates the offset information.
987c478bd9Sstevel@tonic-gate *
997c478bd9Sstevel@tonic-gate * To allow aliases, snapshots are implemented with a level of indirection.
1007c478bd9Sstevel@tonic-gate * A snapshot rc_node_t has a snapid which refers to an rc_snapshot_t in
1017c478bd9Sstevel@tonic-gate * snapshot.c which contains the authoritative snaplevel information. The
1027c478bd9Sstevel@tonic-gate * snapid is "assigned" by rc_attach_snapshot().
1037c478bd9Sstevel@tonic-gate *
1047c478bd9Sstevel@tonic-gate * We provide the client layer with rc_node_ptr_t's to reference objects.
1057c478bd9Sstevel@tonic-gate * Objects referred to by them are automatically held & released by
1067c478bd9Sstevel@tonic-gate * rc_node_assign() & rc_node_clear(). The RC_NODE_PTR_*() macros are used at
1077c478bd9Sstevel@tonic-gate * client.c entry points to read the pointers. They fetch the pointer to the
1087c478bd9Sstevel@tonic-gate * object, return (from the function) if it is dead, and lock, hold, or hold
1097c478bd9Sstevel@tonic-gate * a flag of the object.
1107c478bd9Sstevel@tonic-gate */
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate * Permission checking is authorization-based: some operations may only
1147c478bd9Sstevel@tonic-gate * proceed if the user has been assigned at least one of a set of
1157c478bd9Sstevel@tonic-gate * authorization strings. The set of enabling authorizations depends on the
1167c478bd9Sstevel@tonic-gate * operation and the target object. The set of authorizations assigned to
117134a1f4eSCasper H.S. Dik * a user is determined by an algorithm defined in libsecdb.
1187c478bd9Sstevel@tonic-gate *
1197c478bd9Sstevel@tonic-gate * The fastest way to decide whether the two sets intersect is by entering the
1207c478bd9Sstevel@tonic-gate * strings into a hash table and detecting collisions, which takes linear time
1217c478bd9Sstevel@tonic-gate * in the total size of the sets. Except for the authorization patterns which
1227c478bd9Sstevel@tonic-gate * may be assigned to users, which without advanced pattern-matching
1237c478bd9Sstevel@tonic-gate * algorithms will take O(n) in the number of enabling authorizations, per
1247c478bd9Sstevel@tonic-gate * pattern.
1257c478bd9Sstevel@tonic-gate *
1267c478bd9Sstevel@tonic-gate * We can achieve some practical speed-ups by noting that if we enter all of
1277c478bd9Sstevel@tonic-gate * the authorizations from one of the sets into the hash table we can merely
1287c478bd9Sstevel@tonic-gate * check the elements of the second set for existence without adding them.
1297c478bd9Sstevel@tonic-gate * This reduces memory requirements and hash table clutter. The enabling set
1307c478bd9Sstevel@tonic-gate * is well suited for this because it is internal to configd (for now, at
1317c478bd9Sstevel@tonic-gate * least). Combine this with short-circuiting and we can even minimize the
1327c478bd9Sstevel@tonic-gate * number of queries to the security databases (user_attr & prof_attr).
1337c478bd9Sstevel@tonic-gate *
1347c478bd9Sstevel@tonic-gate * To force this usage onto clients we provide functions for adding
1357c478bd9Sstevel@tonic-gate * authorizations to the enabling set of a permission context structure
1367c478bd9Sstevel@tonic-gate * (perm_add_*()) and one to decide whether the the user associated with the
1377c478bd9Sstevel@tonic-gate * current door call client possesses any of them (perm_granted()).
1387c478bd9Sstevel@tonic-gate *
1397c478bd9Sstevel@tonic-gate * At some point, a generic version of this should move to libsecdb.
1405b7f77adStw21770 *
1415b7f77adStw21770 * While entering the enabling strings into the hash table, we keep track
1425b7f77adStw21770 * of which is the most specific for use in generating auditing events.
1435b7f77adStw21770 * See the "Collecting the Authorization String" section of the "SMF Audit
1445b7f77adStw21770 * Events" block comment below.
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate * Composition is the combination of sets of properties. The sets are ordered
1497c478bd9Sstevel@tonic-gate * and properties in higher sets obscure properties of the same name in lower
1507c478bd9Sstevel@tonic-gate * sets. Here we present a composed view of an instance's properties as the
1517c478bd9Sstevel@tonic-gate * union of its properties and its service's properties. Similarly the
1527c478bd9Sstevel@tonic-gate * properties of snaplevels are combined to form a composed view of the
1537c478bd9Sstevel@tonic-gate * properties of a snapshot (which should match the composed view of the
1547c478bd9Sstevel@tonic-gate * properties of the instance when the snapshot was taken).
1557c478bd9Sstevel@tonic-gate *
1567c478bd9Sstevel@tonic-gate * In terms of the client interface, the client may request that a property
1577c478bd9Sstevel@tonic-gate * group iterator for an instance or snapshot be composed. Property groups
1587c478bd9Sstevel@tonic-gate * traversed by such an iterator may not have the target entity as a parent.
1597c478bd9Sstevel@tonic-gate * Similarly, the properties traversed by a property iterator for those
1607c478bd9Sstevel@tonic-gate * property groups may not have the property groups iterated as parents.
1617c478bd9Sstevel@tonic-gate *
1627c478bd9Sstevel@tonic-gate * Implementation requires that iterators for instances and snapshots be
1637c478bd9Sstevel@tonic-gate * composition-savvy, and that we have a "composed property group" entity
1647c478bd9Sstevel@tonic-gate * which represents the composition of a number of property groups. Iteration
1657c478bd9Sstevel@tonic-gate * over "composed property groups" yields properties which may have different
1667c478bd9Sstevel@tonic-gate * parents, but for all other operations a composed property group behaves
1677c478bd9Sstevel@tonic-gate * like the top-most property group it represents.
1687c478bd9Sstevel@tonic-gate *
1697c478bd9Sstevel@tonic-gate * The implementation is based on the rn_cchain[] array of rc_node_t pointers
1707c478bd9Sstevel@tonic-gate * in rc_node_t. For instances, the pointers point to the instance and its
1717c478bd9Sstevel@tonic-gate * parent service. For snapshots they point to the child snaplevels, and for
1727c478bd9Sstevel@tonic-gate * composed property groups they point to property groups. A composed
1737c478bd9Sstevel@tonic-gate * iterator carries an index into rn_cchain[]. Thus most of the magic ends up
1747c478bd9Sstevel@tonic-gate * int the rc_iter_*() code.
1757c478bd9Sstevel@tonic-gate */
1765b7f77adStw21770 /*
1775b7f77adStw21770 * SMF Audit Events:
1785b7f77adStw21770 * ================
1795b7f77adStw21770 *
1805b7f77adStw21770 * To maintain security, SMF generates audit events whenever
1815b7f77adStw21770 * privileged operations are attempted. See the System Administration
1825b7f77adStw21770 * Guide:Security Services answerbook for a discussion of the Solaris
1835b7f77adStw21770 * audit system.
1845b7f77adStw21770 *
1855b7f77adStw21770 * The SMF audit event codes are defined in adt_event.h by symbols
1865b7f77adStw21770 * starting with ADT_smf_ and are described in audit_event.txt. The
1875b7f77adStw21770 * audit record structures are defined in the SMF section of adt.xml.
1885b7f77adStw21770 * adt.xml is used to automatically generate adt_event.h which
1895b7f77adStw21770 * contains the definitions that we code to in this file. For the
1905b7f77adStw21770 * most part the audit events map closely to actions that you would
1915b7f77adStw21770 * perform with svcadm or svccfg, but there are some special cases
1925b7f77adStw21770 * which we'll discuss later.
1935b7f77adStw21770 *
1945b7f77adStw21770 * The software associated with SMF audit events falls into three
1955b7f77adStw21770 * categories:
1965b7f77adStw21770 * - collecting information to be written to the audit
1975b7f77adStw21770 * records
1985b7f77adStw21770 * - using the adt_* functions in
1995b7f77adStw21770 * usr/src/lib/libbsm/common/adt.c to generate the audit
2005b7f77adStw21770 * records.
2015b7f77adStw21770 * - handling special cases
2025b7f77adStw21770 *
2035b7f77adStw21770 * Collecting Information:
2045b7f77adStw21770 * ----------------------
2055b7f77adStw21770 *
2065b7f77adStw21770 * Most all of the audit events require the FMRI of the affected
2075b7f77adStw21770 * object and the authorization string that was used. The one
2085b7f77adStw21770 * exception is ADT_smf_annotation which we'll talk about later.
2095b7f77adStw21770 *
2105b7f77adStw21770 * Collecting the FMRI:
2115b7f77adStw21770 *
2125b7f77adStw21770 * The rc_node structure has a member called rn_fmri which points to
2135b7f77adStw21770 * its FMRI. This is initialized by a call to rc_node_build_fmri()
2145b7f77adStw21770 * when the node's parent is established. The reason for doing it
2155b7f77adStw21770 * at this time is that a node's FMRI is basically the concatenation
2165b7f77adStw21770 * of the parent's FMRI and the node's name with the appropriate
2175b7f77adStw21770 * decoration. rc_node_build_fmri() does this concatenation and
2185b7f77adStw21770 * decorating. It is called from rc_node_link_child() and
2195b7f77adStw21770 * rc_node_relink_child() where a node is linked to its parent.
2205b7f77adStw21770 *
2215b7f77adStw21770 * rc_node_get_fmri_or_fragment() is called to retrieve a node's FMRI
2225b7f77adStw21770 * when it is needed. It returns rn_fmri if it is set. If the node
2235b7f77adStw21770 * is at the top level, however, rn_fmri won't be set because it was
2245b7f77adStw21770 * never linked to a parent. In this case,
2255b7f77adStw21770 * rc_node_get_fmri_or_fragment() constructs an FMRI fragment based on
2265b7f77adStw21770 * its node type and its name, rn_name.
2275b7f77adStw21770 *
2285b7f77adStw21770 * Collecting the Authorization String:
2295b7f77adStw21770 *
2305b7f77adStw21770 * Naturally, the authorization string is captured during the
2315b7f77adStw21770 * authorization checking process. Acceptable authorization strings
2325b7f77adStw21770 * are added to a permcheck_t hash table as noted in the section on
2335b7f77adStw21770 * permission checking above. Once all entries have been added to the
2345b7f77adStw21770 * hash table, perm_granted() is called. If the client is authorized,
2355b7f77adStw21770 * perm_granted() returns with pc_auth_string of the permcheck_t
2365b7f77adStw21770 * structure pointing to the authorization string.
2375b7f77adStw21770 *
2385b7f77adStw21770 * This works fine if the client is authorized, but what happens if
2395b7f77adStw21770 * the client is not authorized? We need to report the required
2405b7f77adStw21770 * authorization string. This is the authorization that would have
2415b7f77adStw21770 * been used if permission had been granted. perm_granted() will
2425b7f77adStw21770 * find no match, so it needs to decide which string in the hash
2435b7f77adStw21770 * table to use as the required authorization string. It needs to do
2445b7f77adStw21770 * this, because configd is still going to generate an event. A
2455b7f77adStw21770 * design decision was made to use the most specific authorization
2465b7f77adStw21770 * in the hash table. The pc_auth_type enum designates the
2475b7f77adStw21770 * specificity of an authorization string. For example, an
2485b7f77adStw21770 * authorization string that is declared in an instance PG is more
2495b7f77adStw21770 * specific than one that is declared in a service PG.
2505b7f77adStw21770 *
2515b7f77adStw21770 * The pc_add() function keeps track of the most specific
2525b7f77adStw21770 * authorization in the hash table. It does this using the
2535b7f77adStw21770 * pc_specific and pc_specific_type members of the permcheck
2545b7f77adStw21770 * structure. pc_add() updates these members whenever a more
2555b7f77adStw21770 * specific authorization string is added to the hash table. Thus, if
2565b7f77adStw21770 * an authorization match is not found, perm_granted() will return
2575b7f77adStw21770 * with pc_auth_string in the permcheck_t pointing to the string that
2585b7f77adStw21770 * is referenced by pc_specific.
2595b7f77adStw21770 *
2605b7f77adStw21770 * Generating the Audit Events:
2615b7f77adStw21770 * ===========================
2625b7f77adStw21770 *
2635b7f77adStw21770 * As the functions in this file process requests for clients of
2645b7f77adStw21770 * configd, they gather the information that is required for an audit
2655b7f77adStw21770 * event. Eventually, the request processing gets to the point where
2665b7f77adStw21770 * the authorization is rejected or to the point where the requested
2675b7f77adStw21770 * action was attempted. At these two points smf_audit_event() is
2685b7f77adStw21770 * called.
2695b7f77adStw21770 *
2705b7f77adStw21770 * smf_audit_event() takes 4 parameters:
2715b7f77adStw21770 * - the event ID which is one of the ADT_smf_* symbols from
2725b7f77adStw21770 * adt_event.h.
2735b7f77adStw21770 * - status to pass to adt_put_event()
2745b7f77adStw21770 * - return value to pass to adt_put_event()
2755b7f77adStw21770 * - the event data (see audit_event_data structure)
2765b7f77adStw21770 *
2775b7f77adStw21770 * All interactions with the auditing software require an audit
2785b7f77adStw21770 * session. We use one audit session per configd client. We keep
2795b7f77adStw21770 * track of the audit session in the repcache_client structure.
2805b7f77adStw21770 * smf_audit_event() calls get_audit_session() to get the session
2815b7f77adStw21770 * pointer.
2825b7f77adStw21770 *
2835b7f77adStw21770 * smf_audit_event() then calls adt_alloc_event() to allocate an
2845b7f77adStw21770 * adt_event_data union which is defined in adt_event.h, copies the
2855b7f77adStw21770 * data into the appropriate members of the union and calls
2865b7f77adStw21770 * adt_put_event() to generate the event.
2875b7f77adStw21770 *
2885b7f77adStw21770 * Special Cases:
2895b7f77adStw21770 * =============
2905b7f77adStw21770 *
2915b7f77adStw21770 * There are three major types of special cases:
2925b7f77adStw21770 *
2935b7f77adStw21770 * - gathering event information for each action in a
2945b7f77adStw21770 * transaction
2955b7f77adStw21770 * - Higher level events represented by special property
2965b7f77adStw21770 * group/property name combinations. Many of these are
2975b7f77adStw21770 * restarter actions.
2985b7f77adStw21770 * - ADT_smf_annotation event
2995b7f77adStw21770 *
3005b7f77adStw21770 * Processing Transaction Actions:
3015b7f77adStw21770 * ------------------------------
3025b7f77adStw21770 *
3035b7f77adStw21770 * A transaction can contain multiple actions to modify, create or
3045b7f77adStw21770 * delete one or more properties. We need to capture information so
3055b7f77adStw21770 * that we can generate an event for each property action. The
3065b7f77adStw21770 * transaction information is stored in a tx_commmit_data_t, and
3075b7f77adStw21770 * object.c provides accessor functions to retrieve data from this
3085b7f77adStw21770 * structure. rc_tx_commit() obtains a tx_commit_data_t by calling
3095b7f77adStw21770 * tx_commit_data_new() and passes this to object_tx_commit() to
3105b7f77adStw21770 * commit the transaction. Then we call generate_property_events() to
3115b7f77adStw21770 * generate an audit event for each property action.
3125b7f77adStw21770 *
3135b7f77adStw21770 * Special Properties:
3145b7f77adStw21770 * ------------------
3155b7f77adStw21770 *
3165b7f77adStw21770 * There are combinations of property group/property name that are special.
3175b7f77adStw21770 * They are special because they have specific meaning to startd. startd
3185b7f77adStw21770 * interprets them in a service-independent fashion.
3195b7f77adStw21770 * restarter_actions/refresh and general/enabled are two examples of these.
3205b7f77adStw21770 * A special event is generated for these properties in addition to the
3215b7f77adStw21770 * regular property event described in the previous section. The special
3225b7f77adStw21770 * properties are declared as an array of audit_special_prop_item
3235b7f77adStw21770 * structures at special_props_list in rc_node.c.
3245b7f77adStw21770 *
3255b7f77adStw21770 * In the previous section, we mentioned the
3265b7f77adStw21770 * generate_property_event() function that generates an event for
3275b7f77adStw21770 * every property action. Before generating the event,
3285b7f77adStw21770 * generate_property_event() calls special_property_event().
3295b7f77adStw21770 * special_property_event() checks to see if the action involves a
3305b7f77adStw21770 * special property. If it does, it generates a special audit
3315b7f77adStw21770 * event.
3325b7f77adStw21770 *
3335b7f77adStw21770 * ADT_smf_annotation event:
3345b7f77adStw21770 * ------------------------
3355b7f77adStw21770 *
3365b7f77adStw21770 * This is a special event unlike any other. It allows the svccfg
3375b7f77adStw21770 * program to store an annotation in the event log before a series
3385b7f77adStw21770 * of transactions is processed. It is used with the import and
3395b7f77adStw21770 * apply svccfg commands. svccfg uses the rep_protocol_annotation
3405b7f77adStw21770 * message to pass the operation (import or apply) and the file name
3415b7f77adStw21770 * to configd. The set_annotation() function in client.c stores
3425b7f77adStw21770 * these away in the a repcache_client structure. The address of
3435b7f77adStw21770 * this structure is saved in the thread_info structure.
3445b7f77adStw21770 *
3455b7f77adStw21770 * Before it generates any events, smf_audit_event() calls
3465b7f77adStw21770 * smf_annotation_event(). smf_annotation_event() calls
3475b7f77adStw21770 * client_annotation_needed() which is defined in client.c. If an
3485b7f77adStw21770 * annotation is needed client_annotation_needed() returns the
3495b7f77adStw21770 * operation and filename strings that were saved from the
3505b7f77adStw21770 * rep_protocol_annotation message. smf_annotation_event() then
3515b7f77adStw21770 * generates the ADT_smf_annotation event.
3525b7f77adStw21770 */
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate #include <assert.h>
3557c478bd9Sstevel@tonic-gate #include <atomic.h>
3565b7f77adStw21770 #include <bsm/adt_event.h>
3577c478bd9Sstevel@tonic-gate #include <errno.h>
3587c478bd9Sstevel@tonic-gate #include <libuutil.h>
3597c478bd9Sstevel@tonic-gate #include <libscf.h>
3607c478bd9Sstevel@tonic-gate #include <libscf_priv.h>
3617c478bd9Sstevel@tonic-gate #include <pthread.h>
362499fd601Sgww #include <pwd.h>
3637c478bd9Sstevel@tonic-gate #include <stdio.h>
3647c478bd9Sstevel@tonic-gate #include <stdlib.h>
3657c478bd9Sstevel@tonic-gate #include <strings.h>
3667c478bd9Sstevel@tonic-gate #include <sys/types.h>
3675b7f77adStw21770 #include <syslog.h>
3687c478bd9Sstevel@tonic-gate #include <unistd.h>
369134a1f4eSCasper H.S. Dik #include <secdb.h>
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate #include "configd.h"
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate #define AUTH_PREFIX "solaris.smf."
3747c478bd9Sstevel@tonic-gate #define AUTH_MANAGE AUTH_PREFIX "manage"
3757c478bd9Sstevel@tonic-gate #define AUTH_MODIFY AUTH_PREFIX "modify"
3767c478bd9Sstevel@tonic-gate #define AUTH_MODIFY_PREFIX AUTH_MODIFY "."
3777c478bd9Sstevel@tonic-gate #define AUTH_PG_ACTIONS SCF_PG_RESTARTER_ACTIONS
3787c478bd9Sstevel@tonic-gate #define AUTH_PG_ACTIONS_TYPE SCF_PG_RESTARTER_ACTIONS_TYPE
3797c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL SCF_PG_GENERAL
3807c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_TYPE SCF_PG_GENERAL_TYPE
3817c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR SCF_PG_GENERAL_OVR
3827c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR_TYPE SCF_PG_GENERAL_OVR_TYPE
3837c478bd9Sstevel@tonic-gate #define AUTH_PROP_ACTION "action_authorization"
3847c478bd9Sstevel@tonic-gate #define AUTH_PROP_ENABLED "enabled"
3857c478bd9Sstevel@tonic-gate #define AUTH_PROP_MODIFY "modify_authorization"
3867c478bd9Sstevel@tonic-gate #define AUTH_PROP_VALUE "value_authorization"
3873eae19d9Swesolows #define AUTH_PROP_READ "read_authorization"
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate #define MAX_VALID_CHILDREN 3
3907c478bd9Sstevel@tonic-gate
3915b7f77adStw21770 /*
3925b7f77adStw21770 * The ADT_smf_* symbols may not be defined on the build machine. Because
3935b7f77adStw21770 * of this, we do not want to compile the _smf_aud_event() function when
3945b7f77adStw21770 * doing native builds.
3955b7f77adStw21770 */
3965b7f77adStw21770 #ifdef NATIVE_BUILD
3975b7f77adStw21770 #define smf_audit_event(i, s, r, d)
3985b7f77adStw21770 #else
3995b7f77adStw21770 #define smf_audit_event(i, s, r, d) _smf_audit_event(i, s, r, d)
4005b7f77adStw21770 #endif /* NATIVE_BUILD */
4015b7f77adStw21770
4027c478bd9Sstevel@tonic-gate typedef struct rc_type_info {
4037c478bd9Sstevel@tonic-gate uint32_t rt_type; /* matches array index */
4047c478bd9Sstevel@tonic-gate uint32_t rt_num_ids;
4057c478bd9Sstevel@tonic-gate uint32_t rt_name_flags;
4067c478bd9Sstevel@tonic-gate uint32_t rt_valid_children[MAX_VALID_CHILDREN];
4077c478bd9Sstevel@tonic-gate } rc_type_info_t;
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate #define RT_NO_NAME -1U
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate static rc_type_info_t rc_types[] = {
4127c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_NONE, 0, RT_NO_NAME},
4137c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SCOPE, 0, 0,
4147c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, REP_PROTOCOL_ENTITY_SCOPE}},
4157c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, 0, UU_NAME_DOMAIN | UU_NAME_PATH,
4167c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4177c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, 1, UU_NAME_DOMAIN,
4187c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4197c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, 2, UU_NAME_DOMAIN,
4207c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4217c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, 4, RT_NO_NAME,
4227c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4237c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP, 5, UU_NAME_DOMAIN,
4247c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}},
4257c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_CPROPERTYGRP, 0, UU_NAME_DOMAIN,
4267c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}},
4277c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY, 7, UU_NAME_DOMAIN},
4287c478bd9Sstevel@tonic-gate {-1UL}
4297c478bd9Sstevel@tonic-gate };
4307c478bd9Sstevel@tonic-gate #define NUM_TYPES ((sizeof (rc_types) / sizeof (*rc_types)))
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate /* Element of a permcheck_t hash table. */
4337c478bd9Sstevel@tonic-gate struct pc_elt {
4347c478bd9Sstevel@tonic-gate struct pc_elt *pce_next;
4357c478bd9Sstevel@tonic-gate char pce_auth[1];
4367c478bd9Sstevel@tonic-gate };
4377c478bd9Sstevel@tonic-gate
4385b7f77adStw21770 /*
4395b7f77adStw21770 * If an authorization fails, we must decide which of the elements in the
4405b7f77adStw21770 * permcheck hash table to use in the audit event. That is to say of all
4415b7f77adStw21770 * the strings in the hash table, we must choose one and use it in the audit
4425b7f77adStw21770 * event. It is desirable to use the most specific string in the audit
4435b7f77adStw21770 * event.
4445b7f77adStw21770 *
4455b7f77adStw21770 * The pc_auth_type specifies the types (sources) of authorization
4465b7f77adStw21770 * strings. The enum is ordered in increasing specificity.
4475b7f77adStw21770 */
4485b7f77adStw21770 typedef enum pc_auth_type {
4495b7f77adStw21770 PC_AUTH_NONE = 0, /* no auth string available. */
4505b7f77adStw21770 PC_AUTH_SMF, /* strings coded into SMF. */
4515b7f77adStw21770 PC_AUTH_SVC, /* strings specified in PG of a service. */
4525b7f77adStw21770 PC_AUTH_INST /* strings specified in PG of an instance. */
4535b7f77adStw21770 } pc_auth_type_t;
4545b7f77adStw21770
455a4dc1477STom Whitten /*
456a4dc1477STom Whitten * The following enum is used to represent the results of the checks to see
457a4dc1477STom Whitten * if the client has the appropriate permissions to perform an action.
458a4dc1477STom Whitten */
459a4dc1477STom Whitten typedef enum perm_status {
460a4dc1477STom Whitten PERM_DENIED = 0, /* Permission denied. */
461a4dc1477STom Whitten PERM_GRANTED, /* Client has authorizations. */
462a4dc1477STom Whitten PERM_GONE, /* Door client went away. */
463a4dc1477STom Whitten PERM_FAIL /* Generic failure. e.g. resources */
464a4dc1477STom Whitten } perm_status_t;
465a4dc1477STom Whitten
4667c478bd9Sstevel@tonic-gate /* An authorization set hash table. */
4677c478bd9Sstevel@tonic-gate typedef struct {
4687c478bd9Sstevel@tonic-gate struct pc_elt **pc_buckets;
4697c478bd9Sstevel@tonic-gate uint_t pc_bnum; /* number of buckets */
4707c478bd9Sstevel@tonic-gate uint_t pc_enum; /* number of elements */
4715b7f77adStw21770 struct pc_elt *pc_specific; /* most specific element */
4725b7f77adStw21770 pc_auth_type_t pc_specific_type; /* type of pc_specific */
4735b7f77adStw21770 char *pc_auth_string; /* authorization string */
4745b7f77adStw21770 /* for audit events */
4757c478bd9Sstevel@tonic-gate } permcheck_t;
4767c478bd9Sstevel@tonic-gate
4775b7f77adStw21770 /*
4785b7f77adStw21770 * Structure for holding audit event data. Not all events use all members
4795b7f77adStw21770 * of the structure.
4805b7f77adStw21770 */
4815b7f77adStw21770 typedef struct audit_event_data {
4825b7f77adStw21770 char *ed_auth; /* authorization string. */
4835b7f77adStw21770 char *ed_fmri; /* affected FMRI. */
4845b7f77adStw21770 char *ed_snapname; /* name of snapshot. */
4855b7f77adStw21770 char *ed_old_fmri; /* old fmri in attach case. */
4865b7f77adStw21770 char *ed_old_name; /* old snapshot in attach case. */
4875b7f77adStw21770 char *ed_type; /* prop. group or prop. type. */
4885b7f77adStw21770 char *ed_prop_value; /* property value. */
4895b7f77adStw21770 } audit_event_data_t;
4905b7f77adStw21770
4915b7f77adStw21770 /*
4925b7f77adStw21770 * Pointer to function to do special processing to get audit event ID.
4935b7f77adStw21770 * Audit event IDs are defined in /usr/include/bsm/adt_event.h. Function
4945b7f77adStw21770 * returns 0 if ID successfully retrieved. Otherwise it returns -1.
4955b7f77adStw21770 */
4965b7f77adStw21770 typedef int (*spc_getid_fn_t)(tx_commit_data_t *, size_t, const char *,
4975b7f77adStw21770 au_event_t *);
4985b7f77adStw21770 static int general_enable_id(tx_commit_data_t *, size_t, const char *,
4995b7f77adStw21770 au_event_t *);
5005b7f77adStw21770
5017c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_children_pool;
5027c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_pg_notify_pool;
5037c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_notify_pool;
5047c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_notify_info_pool;
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate static rc_node_t *rc_scope;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate static pthread_mutex_t rc_pg_notify_lock = PTHREAD_MUTEX_INITIALIZER;
5097c478bd9Sstevel@tonic-gate static pthread_cond_t rc_pg_notify_cv = PTHREAD_COND_INITIALIZER;
5107c478bd9Sstevel@tonic-gate static uint_t rc_notify_in_use; /* blocks removals */
5117c478bd9Sstevel@tonic-gate
5125b7f77adStw21770 /*
5135b7f77adStw21770 * Some combinations of property group/property name require a special
5145b7f77adStw21770 * audit event to be generated when there is a change.
5155b7f77adStw21770 * audit_special_prop_item_t is used to specify these special cases. The
5165b7f77adStw21770 * special_props_list array defines a list of these special properties.
5175b7f77adStw21770 */
5185b7f77adStw21770 typedef struct audit_special_prop_item {
5195b7f77adStw21770 const char *api_pg_name; /* property group name. */
5205b7f77adStw21770 const char *api_prop_name; /* property name. */
5215b7f77adStw21770 au_event_t api_event_id; /* event id or 0. */
5225b7f77adStw21770 spc_getid_fn_t api_event_func; /* function to get event id. */
5235b7f77adStw21770 } audit_special_prop_item_t;
5245b7f77adStw21770
5255b7f77adStw21770 /*
5265b7f77adStw21770 * Native builds are done using the build machine's standard include
5275b7f77adStw21770 * files. These files may not yet have the definitions for the ADT_smf_*
5285b7f77adStw21770 * symbols. Thus, we do not compile this table when doing native builds.
5295b7f77adStw21770 */
5305b7f77adStw21770 #ifndef NATIVE_BUILD
5315b7f77adStw21770 /*
5325b7f77adStw21770 * The following special_props_list array specifies property group/property
5335b7f77adStw21770 * name combinations that have specific meaning to startd. A special event
5345b7f77adStw21770 * is generated for these combinations in addition to the regular property
5355b7f77adStw21770 * event.
5365b7f77adStw21770 *
5375b7f77adStw21770 * At run time this array gets sorted. See the call to qsort(3C) in
5385b7f77adStw21770 * rc_node_init(). The array is sorted, so that bsearch(3C) can be used
5395b7f77adStw21770 * to do lookups.
5405b7f77adStw21770 */
5415b7f77adStw21770 static audit_special_prop_item_t special_props_list[] = {
5425b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADED, ADT_smf_degrade,
5435b7f77adStw21770 NULL},
5445b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADE_IMMEDIATE,
5455b7f77adStw21770 ADT_smf_immediate_degrade, NULL},
5465b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_OFF, ADT_smf_clear, NULL},
5475b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON,
5485b7f77adStw21770 ADT_smf_maintenance, NULL},
5495b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMEDIATE,
5505b7f77adStw21770 ADT_smf_immediate_maintenance, NULL},
5515b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMTEMP,
5525b7f77adStw21770 ADT_smf_immtmp_maintenance, NULL},
5535b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_TEMPORARY,
5545b7f77adStw21770 ADT_smf_tmp_maintenance, NULL},
5555b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_REFRESH, ADT_smf_refresh, NULL},
5565b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTART, ADT_smf_restart, NULL},
5575b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTORE, ADT_smf_clear, NULL},
5585b7f77adStw21770 {SCF_PG_OPTIONS, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
5595b7f77adStw21770 {SCF_PG_OPTIONS_OVR, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
5605b7f77adStw21770 {SCF_PG_GENERAL, SCF_PROPERTY_ENABLED, 0, general_enable_id},
5615b7f77adStw21770 {SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 0, general_enable_id}
5625b7f77adStw21770 };
5635b7f77adStw21770 #define SPECIAL_PROP_COUNT (sizeof (special_props_list) /\
5645b7f77adStw21770 sizeof (audit_special_prop_item_t))
5655b7f77adStw21770 #endif /* NATIVE_BUILD */
5665b7f77adStw21770
5677c478bd9Sstevel@tonic-gate /*
5687c478bd9Sstevel@tonic-gate * We support an arbitrary number of clients interested in events for certain
5697c478bd9Sstevel@tonic-gate * types of changes. Each client is represented by an rc_notify_info_t, and
5707c478bd9Sstevel@tonic-gate * all clients are chained onto the rc_notify_info_list.
5717c478bd9Sstevel@tonic-gate *
5727c478bd9Sstevel@tonic-gate * The rc_notify_list is the global notification list. Each entry is of
5737c478bd9Sstevel@tonic-gate * type rc_notify_t, which is embedded in one of three other structures:
5747c478bd9Sstevel@tonic-gate *
5757c478bd9Sstevel@tonic-gate * rc_node_t property group update notification
5767c478bd9Sstevel@tonic-gate * rc_notify_delete_t object deletion notification
5777c478bd9Sstevel@tonic-gate * rc_notify_info_t notification clients
5787c478bd9Sstevel@tonic-gate *
5797c478bd9Sstevel@tonic-gate * Which type of object is determined by which pointer in the rc_notify_t is
5807c478bd9Sstevel@tonic-gate * non-NULL.
5817c478bd9Sstevel@tonic-gate *
5827c478bd9Sstevel@tonic-gate * New notifications and clients are added to the end of the list.
5837c478bd9Sstevel@tonic-gate * Notifications no-one is interested in are never added to the list.
5847c478bd9Sstevel@tonic-gate *
5857c478bd9Sstevel@tonic-gate * Clients use their position in the list to track which notifications they
5867c478bd9Sstevel@tonic-gate * have not yet reported. As they process notifications, they move forward
5877c478bd9Sstevel@tonic-gate * in the list past them. There is always a client at the beginning of the
5887c478bd9Sstevel@tonic-gate * list -- as he moves past notifications, he removes them from the list and
5897c478bd9Sstevel@tonic-gate * cleans them up.
5907c478bd9Sstevel@tonic-gate *
5917c478bd9Sstevel@tonic-gate * The rc_pg_notify_lock protects all notification state. The rc_pg_notify_cv
5927c478bd9Sstevel@tonic-gate * is used for global signalling, and each client has a cv which he waits for
5937c478bd9Sstevel@tonic-gate * events of interest on.
594b5cbdab0STom Whitten *
595b5cbdab0STom Whitten * rc_notify_in_use is used to protect rc_notify_list from deletions when
596b5cbdab0STom Whitten * the rc_pg_notify_lock is dropped. Specifically, rc_notify_info_wait()
597b5cbdab0STom Whitten * must drop the lock to call rc_node_assign(), and then it reacquires the
598b5cbdab0STom Whitten * lock. Deletions from rc_notify_list during this period are not
599b5cbdab0STom Whitten * allowed. Insertions do not matter, because they are always done at the
600b5cbdab0STom Whitten * end of the list.
6017c478bd9Sstevel@tonic-gate */
6027c478bd9Sstevel@tonic-gate static uu_list_t *rc_notify_info_list;
6037c478bd9Sstevel@tonic-gate static uu_list_t *rc_notify_list;
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate #define HASH_SIZE 512
6067c478bd9Sstevel@tonic-gate #define HASH_MASK (HASH_SIZE - 1)
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate #pragma align 64(cache_hash)
6097c478bd9Sstevel@tonic-gate static cache_bucket_t cache_hash[HASH_SIZE];
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate #define CACHE_BUCKET(h) (&cache_hash[(h) & HASH_MASK])
6127c478bd9Sstevel@tonic-gate
6136643e1ffSbustos
6146643e1ffSbustos static void rc_node_no_client_refs(rc_node_t *np);
6156643e1ffSbustos
6166643e1ffSbustos
6177c478bd9Sstevel@tonic-gate static uint32_t
rc_node_hash(rc_node_lookup_t * lp)6187c478bd9Sstevel@tonic-gate rc_node_hash(rc_node_lookup_t *lp)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate uint32_t type = lp->rl_type;
6217c478bd9Sstevel@tonic-gate uint32_t backend = lp->rl_backend;
6220b5c9250Shg115875 uint32_t mainid = lp->rl_main_id;
6237c478bd9Sstevel@tonic-gate uint32_t *ids = lp->rl_ids;
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate rc_type_info_t *tp = &rc_types[type];
6267c478bd9Sstevel@tonic-gate uint32_t num_ids;
6277c478bd9Sstevel@tonic-gate uint32_t left;
6287c478bd9Sstevel@tonic-gate uint32_t hash;
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate assert(backend == BACKEND_TYPE_NORMAL ||
6317c478bd9Sstevel@tonic-gate backend == BACKEND_TYPE_NONPERSIST);
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES);
6347c478bd9Sstevel@tonic-gate num_ids = tp->rt_num_ids;
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate left = MAX_IDS - num_ids;
6377c478bd9Sstevel@tonic-gate assert(num_ids <= MAX_IDS);
6387c478bd9Sstevel@tonic-gate
6390b5c9250Shg115875 hash = type * 7 + mainid * 5 + backend;
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate while (num_ids-- > 0)
6427c478bd9Sstevel@tonic-gate hash = hash * 11 + *ids++ * 7;
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate /*
6457c478bd9Sstevel@tonic-gate * the rest should be zeroed
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate while (left-- > 0)
6487c478bd9Sstevel@tonic-gate assert(*ids++ == 0);
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate return (hash);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate static int
rc_node_match(rc_node_t * np,rc_node_lookup_t * l)6547c478bd9Sstevel@tonic-gate rc_node_match(rc_node_t *np, rc_node_lookup_t *l)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate rc_node_lookup_t *r = &np->rn_id;
6577c478bd9Sstevel@tonic-gate rc_type_info_t *tp;
6587c478bd9Sstevel@tonic-gate uint32_t type;
6597c478bd9Sstevel@tonic-gate uint32_t num_ids;
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate if (r->rl_main_id != l->rl_main_id)
6627c478bd9Sstevel@tonic-gate return (0);
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate type = r->rl_type;
6657c478bd9Sstevel@tonic-gate if (type != l->rl_type)
6667c478bd9Sstevel@tonic-gate return (0);
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES);
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate tp = &rc_types[r->rl_type];
6717c478bd9Sstevel@tonic-gate num_ids = tp->rt_num_ids;
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate assert(num_ids <= MAX_IDS);
6747c478bd9Sstevel@tonic-gate while (num_ids-- > 0)
6757c478bd9Sstevel@tonic-gate if (r->rl_ids[num_ids] != l->rl_ids[num_ids])
6767c478bd9Sstevel@tonic-gate return (0);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate return (1);
6797c478bd9Sstevel@tonic-gate }
6807c478bd9Sstevel@tonic-gate
6817c478bd9Sstevel@tonic-gate /*
6826643e1ffSbustos * Register an ephemeral reference to np. This should be done while both
6836643e1ffSbustos * the persistent reference from which the np pointer was read is locked
6846643e1ffSbustos * and np itself is locked. This guarantees that another thread which
6856643e1ffSbustos * thinks it has the last reference will yield without destroying the
6866643e1ffSbustos * node.
6876643e1ffSbustos */
6886643e1ffSbustos static void
rc_node_hold_ephemeral_locked(rc_node_t * np)6896643e1ffSbustos rc_node_hold_ephemeral_locked(rc_node_t *np)
6906643e1ffSbustos {
6916643e1ffSbustos assert(MUTEX_HELD(&np->rn_lock));
6926643e1ffSbustos
6936643e1ffSbustos ++np->rn_erefs;
6946643e1ffSbustos }
6956643e1ffSbustos
6966643e1ffSbustos /*
6977c478bd9Sstevel@tonic-gate * the "other" references on a node are maintained in an atomically
6987c478bd9Sstevel@tonic-gate * updated refcount, rn_other_refs. This can be bumped from arbitrary
6997c478bd9Sstevel@tonic-gate * context, and tracks references to a possibly out-of-date node's children.
7007c478bd9Sstevel@tonic-gate *
7017c478bd9Sstevel@tonic-gate * To prevent the node from disappearing between the final drop of
7027c478bd9Sstevel@tonic-gate * rn_other_refs and the unref handling, rn_other_refs_held is bumped on
7037c478bd9Sstevel@tonic-gate * 0->1 transitions and decremented (with the node lock held) on 1->0
7047c478bd9Sstevel@tonic-gate * transitions.
7057c478bd9Sstevel@tonic-gate */
7067c478bd9Sstevel@tonic-gate static void
rc_node_hold_other(rc_node_t * np)7077c478bd9Sstevel@tonic-gate rc_node_hold_other(rc_node_t *np)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, 1) == 1) {
7107c478bd9Sstevel@tonic-gate atomic_add_32(&np->rn_other_refs_held, 1);
7117c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held > 0);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate assert(np->rn_other_refs > 0);
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate /*
7177c478bd9Sstevel@tonic-gate * No node locks may be held
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate static void
rc_node_rele_other(rc_node_t * np)7207c478bd9Sstevel@tonic-gate rc_node_rele_other(rc_node_t *np)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate assert(np->rn_other_refs > 0);
7237c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, -1) == 0) {
7247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
7257c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held > 0);
7267c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs_held, -1) == 0 &&
7276643e1ffSbustos np->rn_refs == 0 && (np->rn_flags & RC_NODE_OLD)) {
7286643e1ffSbustos /*
7296643e1ffSbustos * This was the last client reference. Destroy
7306643e1ffSbustos * any other references and free() the node.
7316643e1ffSbustos */
7326643e1ffSbustos rc_node_no_client_refs(np);
7336643e1ffSbustos } else {
7347c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate }
7376643e1ffSbustos }
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate static void
rc_node_hold_locked(rc_node_t * np)7407c478bd9Sstevel@tonic-gate rc_node_hold_locked(rc_node_t *np)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate if (np->rn_refs == 0 && (np->rn_flags & RC_NODE_PARENT_REF))
7457c478bd9Sstevel@tonic-gate rc_node_hold_other(np->rn_parent_ref);
7467c478bd9Sstevel@tonic-gate np->rn_refs++;
7477c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0);
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate static void
rc_node_hold(rc_node_t * np)7517c478bd9Sstevel@tonic-gate rc_node_hold(rc_node_t *np)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
7547c478bd9Sstevel@tonic-gate rc_node_hold_locked(np);
7557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate static void
rc_node_rele_locked(rc_node_t * np)7597c478bd9Sstevel@tonic-gate rc_node_rele_locked(rc_node_t *np)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate int unref = 0;
7627c478bd9Sstevel@tonic-gate rc_node_t *par_ref = NULL;
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
7657c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0);
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate if (--np->rn_refs == 0) {
7687c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_PARENT_REF)
7697c478bd9Sstevel@tonic-gate par_ref = np->rn_parent_ref;
7707c478bd9Sstevel@tonic-gate
771fda74dabSbustos /*
772fda74dabSbustos * Composed property groups are only as good as their
773fda74dabSbustos * references.
774fda74dabSbustos */
775fda74dabSbustos if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
776fda74dabSbustos np->rn_flags |= RC_NODE_DEAD;
777fda74dabSbustos
7787c478bd9Sstevel@tonic-gate if ((np->rn_flags & (RC_NODE_DEAD|RC_NODE_OLD)) &&
7797c478bd9Sstevel@tonic-gate np->rn_other_refs == 0 && np->rn_other_refs_held == 0)
7807c478bd9Sstevel@tonic-gate unref = 1;
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate
7836643e1ffSbustos if (unref) {
7846643e1ffSbustos /*
7856643e1ffSbustos * This was the last client reference. Destroy any other
7866643e1ffSbustos * references and free() the node.
7876643e1ffSbustos */
7886643e1ffSbustos rc_node_no_client_refs(np);
7896643e1ffSbustos } else {
7906643e1ffSbustos /*
7916643e1ffSbustos * rn_erefs can be 0 if we acquired the reference in
7926643e1ffSbustos * a path which hasn't been updated to increment rn_erefs.
7936643e1ffSbustos * When all paths which end here are updated, we should
7946643e1ffSbustos * assert rn_erefs > 0 and always decrement it.
7956643e1ffSbustos */
7966643e1ffSbustos if (np->rn_erefs > 0)
7976643e1ffSbustos --np->rn_erefs;
7987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7996643e1ffSbustos }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate if (par_ref != NULL)
8027c478bd9Sstevel@tonic-gate rc_node_rele_other(par_ref);
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate
8057c478bd9Sstevel@tonic-gate void
rc_node_rele(rc_node_t * np)8067c478bd9Sstevel@tonic-gate rc_node_rele(rc_node_t *np)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
8097c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate static cache_bucket_t *
cache_hold(uint32_t h)8137c478bd9Sstevel@tonic-gate cache_hold(uint32_t h)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate cache_bucket_t *bp = CACHE_BUCKET(h);
8167c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock);
8177c478bd9Sstevel@tonic-gate return (bp);
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate static void
cache_release(cache_bucket_t * bp)8217c478bd9Sstevel@tonic-gate cache_release(cache_bucket_t *bp)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate static rc_node_t *
cache_lookup_unlocked(cache_bucket_t * bp,rc_node_lookup_t * lp)8277c478bd9Sstevel@tonic-gate cache_lookup_unlocked(cache_bucket_t *bp, rc_node_lookup_t *lp)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(lp);
8307c478bd9Sstevel@tonic-gate rc_node_t *np;
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8337c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(h));
8347c478bd9Sstevel@tonic-gate
8357c478bd9Sstevel@tonic-gate for (np = bp->cb_head; np != NULL; np = np->rn_hash_next) {
8367c478bd9Sstevel@tonic-gate if (np->rn_hash == h && rc_node_match(np, lp)) {
8377c478bd9Sstevel@tonic-gate rc_node_hold(np);
8387c478bd9Sstevel@tonic-gate return (np);
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate return (NULL);
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate static rc_node_t *
cache_lookup(rc_node_lookup_t * lp)8467c478bd9Sstevel@tonic-gate cache_lookup(rc_node_lookup_t *lp)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate uint32_t h;
8497c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
8507c478bd9Sstevel@tonic-gate rc_node_t *np;
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate h = rc_node_hash(lp);
8537c478bd9Sstevel@tonic-gate bp = cache_hold(h);
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate np = cache_lookup_unlocked(bp, lp);
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate cache_release(bp);
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate return (np);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate static void
cache_insert_unlocked(cache_bucket_t * bp,rc_node_t * np)8637c478bd9Sstevel@tonic-gate cache_insert_unlocked(cache_bucket_t *bp, rc_node_t *np)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8667c478bd9Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id));
8677c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash));
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate assert(np->rn_hash_next == NULL);
8707c478bd9Sstevel@tonic-gate
8717c478bd9Sstevel@tonic-gate np->rn_hash_next = bp->cb_head;
8727c478bd9Sstevel@tonic-gate bp->cb_head = np;
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate static void
cache_remove_unlocked(cache_bucket_t * bp,rc_node_t * np)8767c478bd9Sstevel@tonic-gate cache_remove_unlocked(cache_bucket_t *bp, rc_node_t *np)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate rc_node_t **npp;
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8817c478bd9Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id));
8827c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash));
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate for (npp = &bp->cb_head; *npp != NULL; npp = &(*npp)->rn_hash_next)
8857c478bd9Sstevel@tonic-gate if (*npp == np)
8867c478bd9Sstevel@tonic-gate break;
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate assert(*npp == np);
8897c478bd9Sstevel@tonic-gate *npp = np->rn_hash_next;
8907c478bd9Sstevel@tonic-gate np->rn_hash_next = NULL;
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate * verify that the 'parent' type can have a child typed 'child'
8957c478bd9Sstevel@tonic-gate * Fails with
8967c478bd9Sstevel@tonic-gate * _INVALID_TYPE - argument is invalid
8977c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent type cannot have children of type child
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate static int
rc_check_parent_child(uint32_t parent,uint32_t child)9007c478bd9Sstevel@tonic-gate rc_check_parent_child(uint32_t parent, uint32_t child)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate int idx;
9037c478bd9Sstevel@tonic-gate uint32_t type;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate if (parent == 0 || parent >= NUM_TYPES ||
9067c478bd9Sstevel@tonic-gate child == 0 || child >= NUM_TYPES)
9077c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate for (idx = 0; idx < MAX_VALID_CHILDREN; idx++) {
9107c478bd9Sstevel@tonic-gate type = rc_types[parent].rt_valid_children[idx];
9117c478bd9Sstevel@tonic-gate if (type == child)
9127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate /*
9197c478bd9Sstevel@tonic-gate * Fails with
9207c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
9217c478bd9Sstevel@tonic-gate * _BAD_REQUEST - name is an invalid name for a node of type type
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate int
rc_check_type_name(uint32_t type,const char * name)9247c478bd9Sstevel@tonic-gate rc_check_type_name(uint32_t type, const char *name)
9257c478bd9Sstevel@tonic-gate {
9267c478bd9Sstevel@tonic-gate if (type == 0 || type >= NUM_TYPES)
9277c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate if (uu_check_name(name, rc_types[type].rt_name_flags) == -1)
9307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate static int
rc_check_pgtype_name(const char * name)9367c478bd9Sstevel@tonic-gate rc_check_pgtype_name(const char *name)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate if (uu_check_name(name, UU_NAME_DOMAIN) == -1)
9397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate
9445b7f77adStw21770 /*
9455b7f77adStw21770 * rc_node_free_fmri should be called whenever a node loses its parent.
9465b7f77adStw21770 * The reason is that the node's fmri string is built up by concatenating
9475b7f77adStw21770 * its name to the parent's fmri. Thus, when the node no longer has a
9485b7f77adStw21770 * parent, its fmri is no longer valid.
9495b7f77adStw21770 */
9505b7f77adStw21770 static void
rc_node_free_fmri(rc_node_t * np)9515b7f77adStw21770 rc_node_free_fmri(rc_node_t *np)
9525b7f77adStw21770 {
9535b7f77adStw21770 if (np->rn_fmri != NULL) {
9545b7f77adStw21770 free((void *)np->rn_fmri);
9555b7f77adStw21770 np->rn_fmri = NULL;
9565b7f77adStw21770 }
9575b7f77adStw21770 }
9585b7f77adStw21770
9595b7f77adStw21770 /*
9605b7f77adStw21770 * Concatenate the appropriate separator and the FMRI element to the base
9615b7f77adStw21770 * FMRI string at fmri.
9625b7f77adStw21770 *
9635b7f77adStw21770 * Fails with
9645b7f77adStw21770 * _TRUNCATED Not enough room in buffer at fmri.
9655b7f77adStw21770 */
9665b7f77adStw21770 static int
rc_concat_fmri_element(char * fmri,size_t bufsize,size_t * sz_out,const char * element,rep_protocol_entity_t type)9675b7f77adStw21770 rc_concat_fmri_element(
9685b7f77adStw21770 char *fmri, /* base fmri */
9695b7f77adStw21770 size_t bufsize, /* size of buf at fmri */
9705b7f77adStw21770 size_t *sz_out, /* receives result size. */
9715b7f77adStw21770 const char *element, /* element name to concat */
9725b7f77adStw21770 rep_protocol_entity_t type) /* type of element */
9735b7f77adStw21770 {
9745b7f77adStw21770 size_t actual;
9755b7f77adStw21770 const char *name = element;
9765b7f77adStw21770 int rc;
9775b7f77adStw21770 const char *separator;
9785b7f77adStw21770
9795b7f77adStw21770 if (bufsize > 0)
9805b7f77adStw21770 *sz_out = strlen(fmri);
9815b7f77adStw21770 else
9825b7f77adStw21770 *sz_out = 0;
9835b7f77adStw21770
9845b7f77adStw21770 switch (type) {
9855b7f77adStw21770 case REP_PROTOCOL_ENTITY_SCOPE:
9865b7f77adStw21770 if (strcmp(element, SCF_FMRI_LOCAL_SCOPE) == 0) {
9875b7f77adStw21770 /*
9885b7f77adStw21770 * No need to display scope information if we are
9895b7f77adStw21770 * in the local scope.
9905b7f77adStw21770 */
9915b7f77adStw21770 separator = SCF_FMRI_SVC_PREFIX;
9925b7f77adStw21770 name = NULL;
9935b7f77adStw21770 } else {
9945b7f77adStw21770 /*
9955b7f77adStw21770 * Need to display scope information, because it is
9965b7f77adStw21770 * not the local scope.
9975b7f77adStw21770 */
9985b7f77adStw21770 separator = SCF_FMRI_SVC_PREFIX SCF_FMRI_SCOPE_PREFIX;
9995b7f77adStw21770 }
10005b7f77adStw21770 break;
10015b7f77adStw21770 case REP_PROTOCOL_ENTITY_SERVICE:
10025b7f77adStw21770 separator = SCF_FMRI_SERVICE_PREFIX;
10035b7f77adStw21770 break;
10045b7f77adStw21770 case REP_PROTOCOL_ENTITY_INSTANCE:
10055b7f77adStw21770 separator = SCF_FMRI_INSTANCE_PREFIX;
10065b7f77adStw21770 break;
10075b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
10085b7f77adStw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
10095b7f77adStw21770 separator = SCF_FMRI_PROPERTYGRP_PREFIX;
10105b7f77adStw21770 break;
10115b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTY:
10125b7f77adStw21770 separator = SCF_FMRI_PROPERTY_PREFIX;
10135b7f77adStw21770 break;
10145b7f77adStw21770 case REP_PROTOCOL_ENTITY_VALUE:
10155b7f77adStw21770 /*
10165b7f77adStw21770 * A value does not have a separate FMRI from its property,
10175b7f77adStw21770 * so there is nothing to concat.
10185b7f77adStw21770 */
10195b7f77adStw21770 return (REP_PROTOCOL_SUCCESS);
10205b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT:
10215b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
10225b7f77adStw21770 /* Snapshots do not have FMRIs, so there is nothing to do. */
10235b7f77adStw21770 return (REP_PROTOCOL_SUCCESS);
10245b7f77adStw21770 default:
10255b7f77adStw21770 (void) fprintf(stderr, "%s:%d: Unknown protocol type %d.\n",
10265b7f77adStw21770 __FILE__, __LINE__, type);
10275b7f77adStw21770 abort(); /* Missing a case in switch if we get here. */
10285b7f77adStw21770 }
10295b7f77adStw21770
10305b7f77adStw21770 /* Concatenate separator and element to the fmri buffer. */
10315b7f77adStw21770
10325b7f77adStw21770 actual = strlcat(fmri, separator, bufsize);
10335b7f77adStw21770 if (name != NULL) {
10345b7f77adStw21770 if (actual < bufsize) {
10355b7f77adStw21770 actual = strlcat(fmri, name, bufsize);
10365b7f77adStw21770 } else {
10375b7f77adStw21770 actual += strlen(name);
10385b7f77adStw21770 }
10395b7f77adStw21770 }
10405b7f77adStw21770 if (actual < bufsize) {
10415b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
10425b7f77adStw21770 } else {
10435b7f77adStw21770 rc = REP_PROTOCOL_FAIL_TRUNCATED;
10445b7f77adStw21770 }
10455b7f77adStw21770 *sz_out = actual;
10465b7f77adStw21770 return (rc);
10475b7f77adStw21770 }
10485b7f77adStw21770
10495b7f77adStw21770 /*
10505b7f77adStw21770 * Get the FMRI for the node at np. The fmri will be placed in buf. On
10515b7f77adStw21770 * success sz_out will be set to the size of the fmri in buf. If
10525b7f77adStw21770 * REP_PROTOCOL_FAIL_TRUNCATED is returned, sz_out will be set to the size
10535b7f77adStw21770 * of the buffer that would be required to avoid truncation.
10545b7f77adStw21770 *
10555b7f77adStw21770 * Fails with
10565b7f77adStw21770 * _TRUNCATED not enough room in buf for the FMRI.
10575b7f77adStw21770 */
10585b7f77adStw21770 static int
rc_node_get_fmri_or_fragment(rc_node_t * np,char * buf,size_t bufsize,size_t * sz_out)10595b7f77adStw21770 rc_node_get_fmri_or_fragment(rc_node_t *np, char *buf, size_t bufsize,
10605b7f77adStw21770 size_t *sz_out)
10615b7f77adStw21770 {
10625b7f77adStw21770 size_t fmri_len = 0;
10635b7f77adStw21770 int r;
10645b7f77adStw21770
10655b7f77adStw21770 if (bufsize > 0)
10665b7f77adStw21770 *buf = 0;
10675b7f77adStw21770 *sz_out = 0;
10685b7f77adStw21770
10695b7f77adStw21770 if (np->rn_fmri == NULL) {
10705b7f77adStw21770 /*
10715b7f77adStw21770 * A NULL rn_fmri implies that this is a top level scope.
10725b7f77adStw21770 * Child nodes will always have an rn_fmri established
10735b7f77adStw21770 * because both rc_node_link_child() and
10745b7f77adStw21770 * rc_node_relink_child() call rc_node_build_fmri(). In
10755b7f77adStw21770 * this case, we'll just return our name preceded by the
10765b7f77adStw21770 * appropriate FMRI decorations.
10775b7f77adStw21770 */
10785b7f77adStw21770 assert(np->rn_parent == NULL);
10795b7f77adStw21770 r = rc_concat_fmri_element(buf, bufsize, &fmri_len, np->rn_name,
10805b7f77adStw21770 np->rn_id.rl_type);
10815b7f77adStw21770 if (r != REP_PROTOCOL_SUCCESS)
10825b7f77adStw21770 return (r);
10835b7f77adStw21770 } else {
10845b7f77adStw21770 /* We have an fmri, so return it. */
10855b7f77adStw21770 fmri_len = strlcpy(buf, np->rn_fmri, bufsize);
10865b7f77adStw21770 }
10875b7f77adStw21770
10885b7f77adStw21770 *sz_out = fmri_len;
10895b7f77adStw21770
10905b7f77adStw21770 if (fmri_len >= bufsize)
10915b7f77adStw21770 return (REP_PROTOCOL_FAIL_TRUNCATED);
10925b7f77adStw21770
10935b7f77adStw21770 return (REP_PROTOCOL_SUCCESS);
10945b7f77adStw21770 }
10955b7f77adStw21770
10965b7f77adStw21770 /*
10975b7f77adStw21770 * Build an FMRI string for this node and save it in rn_fmri.
10985b7f77adStw21770 *
10995b7f77adStw21770 * The basic strategy here is to get the fmri of our parent and then
11005b7f77adStw21770 * concatenate the appropriate separator followed by our name. If our name
11015b7f77adStw21770 * is null, the resulting fmri will just be a copy of the parent fmri.
11025b7f77adStw21770 * rc_node_build_fmri() should be called with the RC_NODE_USING_PARENT flag
11035b7f77adStw21770 * set. Also the rn_lock for this node should be held.
11045b7f77adStw21770 *
11055b7f77adStw21770 * Fails with
11065b7f77adStw21770 * _NO_RESOURCES Could not allocate memory.
11075b7f77adStw21770 */
11085b7f77adStw21770 static int
rc_node_build_fmri(rc_node_t * np)11095b7f77adStw21770 rc_node_build_fmri(rc_node_t *np)
11105b7f77adStw21770 {
11115b7f77adStw21770 size_t actual;
11125b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
11135b7f77adStw21770 int rc;
11145b7f77adStw21770 size_t sz = REP_PROTOCOL_FMRI_LEN;
11155b7f77adStw21770
11165b7f77adStw21770 assert(MUTEX_HELD(&np->rn_lock));
11175b7f77adStw21770 assert(np->rn_flags & RC_NODE_USING_PARENT);
11185b7f77adStw21770
11195b7f77adStw21770 rc_node_free_fmri(np);
11205b7f77adStw21770
11215b7f77adStw21770 rc = rc_node_get_fmri_or_fragment(np->rn_parent, fmri, sz, &actual);
11225b7f77adStw21770 assert(rc == REP_PROTOCOL_SUCCESS);
11235b7f77adStw21770
11245b7f77adStw21770 if (np->rn_name != NULL) {
11255b7f77adStw21770 rc = rc_concat_fmri_element(fmri, sz, &actual, np->rn_name,
11265b7f77adStw21770 np->rn_id.rl_type);
11275b7f77adStw21770 assert(rc == REP_PROTOCOL_SUCCESS);
11285b7f77adStw21770 np->rn_fmri = strdup(fmri);
11295b7f77adStw21770 } else {
11305b7f77adStw21770 np->rn_fmri = strdup(fmri);
11315b7f77adStw21770 }
11325b7f77adStw21770 if (np->rn_fmri == NULL) {
11335b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
11345b7f77adStw21770 } else {
11355b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
11365b7f77adStw21770 }
11375b7f77adStw21770
11385b7f77adStw21770 return (rc);
11395b7f77adStw21770 }
11405b7f77adStw21770
11415b7f77adStw21770 /*
11425b7f77adStw21770 * Get the FMRI of the node at np placing the result in fmri. Then
11435b7f77adStw21770 * concatenate the additional element to fmri. The type variable indicates
11445b7f77adStw21770 * the type of element, so that the appropriate separator can be
11455b7f77adStw21770 * generated. size is the number of bytes in the buffer at fmri, and
11465b7f77adStw21770 * sz_out receives the size of the generated string. If the result is
11475b7f77adStw21770 * truncated, sz_out will receive the size of the buffer that would be
11485b7f77adStw21770 * required to avoid truncation.
11495b7f77adStw21770 *
11505b7f77adStw21770 * Fails with
11515b7f77adStw21770 * _TRUNCATED Not enough room in buffer at fmri.
11525b7f77adStw21770 */
11535b7f77adStw21770 static int
rc_get_fmri_and_concat(rc_node_t * np,char * fmri,size_t size,size_t * sz_out,const char * element,rep_protocol_entity_t type)11545b7f77adStw21770 rc_get_fmri_and_concat(rc_node_t *np, char *fmri, size_t size, size_t *sz_out,
11555b7f77adStw21770 const char *element, rep_protocol_entity_t type)
11565b7f77adStw21770 {
11575b7f77adStw21770 int rc;
11585b7f77adStw21770
11595b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, size, sz_out)) !=
11605b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
11615b7f77adStw21770 return (rc);
11625b7f77adStw21770 }
11635b7f77adStw21770 if ((rc = rc_concat_fmri_element(fmri, size, sz_out, element, type)) !=
11645b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
11655b7f77adStw21770 return (rc);
11665b7f77adStw21770 }
11675b7f77adStw21770
11685b7f77adStw21770 return (REP_PROTOCOL_SUCCESS);
11695b7f77adStw21770 }
11705b7f77adStw21770
11717c478bd9Sstevel@tonic-gate static int
rc_notify_info_interested(rc_notify_info_t * rnip,rc_notify_t * np)11727c478bd9Sstevel@tonic-gate rc_notify_info_interested(rc_notify_info_t *rnip, rc_notify_t *np)
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate rc_node_t *nnp = np->rcn_node;
11757c478bd9Sstevel@tonic-gate int i;
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate if (np->rcn_delete != NULL) {
11807c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL && np->rcn_node == NULL);
11817c478bd9Sstevel@tonic-gate return (1); /* everyone likes deletes */
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate if (np->rcn_node == NULL) {
11847c478bd9Sstevel@tonic-gate assert(np->rcn_info != NULL || np->rcn_delete != NULL);
11857c478bd9Sstevel@tonic-gate return (0);
11867c478bd9Sstevel@tonic-gate }
11877c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL);
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
11907c478bd9Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) {
11917c478bd9Sstevel@tonic-gate if (strcmp(nnp->rn_name, rnip->rni_namelist[i]) == 0)
11927c478bd9Sstevel@tonic-gate return (1);
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) {
11957c478bd9Sstevel@tonic-gate if (strcmp(nnp->rn_type, rnip->rni_typelist[i]) == 0)
11967c478bd9Sstevel@tonic-gate return (1);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate return (0);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate static void
rc_notify_insert_node(rc_node_t * nnp)12037c478bd9Sstevel@tonic-gate rc_notify_insert_node(rc_node_t *nnp)
12047c478bd9Sstevel@tonic-gate {
12057c478bd9Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify;
12067c478bd9Sstevel@tonic-gate rc_notify_info_t *nip;
12077c478bd9Sstevel@tonic-gate int found = 0;
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL);
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate if (nnp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
12127c478bd9Sstevel@tonic-gate return;
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12157c478bd9Sstevel@tonic-gate np->rcn_node = nnp;
12167c478bd9Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
12177c478bd9Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip)) {
12187c478bd9Sstevel@tonic-gate if (rc_notify_info_interested(nip, np)) {
12197c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv);
12207c478bd9Sstevel@tonic-gate found++;
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate }
12237c478bd9Sstevel@tonic-gate if (found)
12247c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, np);
12257c478bd9Sstevel@tonic-gate else
12267c478bd9Sstevel@tonic-gate np->rcn_node = NULL;
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12297c478bd9Sstevel@tonic-gate }
12307c478bd9Sstevel@tonic-gate
12317c478bd9Sstevel@tonic-gate static void
rc_notify_deletion(rc_notify_delete_t * ndp,const char * service,const char * instance,const char * pg)12327c478bd9Sstevel@tonic-gate rc_notify_deletion(rc_notify_delete_t *ndp, const char *service,
12337c478bd9Sstevel@tonic-gate const char *instance, const char *pg)
12347c478bd9Sstevel@tonic-gate {
12357c478bd9Sstevel@tonic-gate rc_notify_info_t *nip;
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate uu_list_node_init(&ndp->rnd_notify, &ndp->rnd_notify.rcn_list_node,
12387c478bd9Sstevel@tonic-gate rc_notify_pool);
12397c478bd9Sstevel@tonic-gate ndp->rnd_notify.rcn_delete = ndp;
12407c478bd9Sstevel@tonic-gate
12417c478bd9Sstevel@tonic-gate (void) snprintf(ndp->rnd_fmri, sizeof (ndp->rnd_fmri),
12427c478bd9Sstevel@tonic-gate "svc:/%s%s%s%s%s", service,
12437c478bd9Sstevel@tonic-gate (instance != NULL)? ":" : "", (instance != NULL)? instance : "",
12447c478bd9Sstevel@tonic-gate (pg != NULL)? "/:properties/" : "", (pg != NULL)? pg : "");
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate * add to notification list, notify watchers
12487c478bd9Sstevel@tonic-gate */
12497c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12507c478bd9Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
12517c478bd9Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip))
12527c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv);
12537c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, ndp);
12547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate static void
rc_notify_remove_node(rc_node_t * nnp)12587c478bd9Sstevel@tonic-gate rc_notify_remove_node(rc_node_t *nnp)
12597c478bd9Sstevel@tonic-gate {
12607c478bd9Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify;
12617c478bd9Sstevel@tonic-gate
12627c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL);
12637c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&nnp->rn_lock));
12647c478bd9Sstevel@tonic-gate
12657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12667c478bd9Sstevel@tonic-gate while (np->rcn_node != NULL) {
12677c478bd9Sstevel@tonic-gate if (rc_notify_in_use) {
12687c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv,
12697c478bd9Sstevel@tonic-gate &rc_pg_notify_lock);
12707c478bd9Sstevel@tonic-gate continue;
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np);
12737c478bd9Sstevel@tonic-gate np->rcn_node = NULL;
12747c478bd9Sstevel@tonic-gate break;
12757c478bd9Sstevel@tonic-gate }
12767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12777c478bd9Sstevel@tonic-gate }
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate static void
rc_notify_remove_locked(rc_notify_t * np)12807c478bd9Sstevel@tonic-gate rc_notify_remove_locked(rc_notify_t *np)
12817c478bd9Sstevel@tonic-gate {
12827c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
12837c478bd9Sstevel@tonic-gate assert(rc_notify_in_use == 0);
12847c478bd9Sstevel@tonic-gate
12857c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np);
12867c478bd9Sstevel@tonic-gate if (np->rcn_node) {
12877c478bd9Sstevel@tonic-gate np->rcn_node = NULL;
12887c478bd9Sstevel@tonic-gate } else if (np->rcn_delete) {
12897c478bd9Sstevel@tonic-gate uu_free(np->rcn_delete);
12907c478bd9Sstevel@tonic-gate } else {
12917c478bd9Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */
12927c478bd9Sstevel@tonic-gate }
12937c478bd9Sstevel@tonic-gate }
12947c478bd9Sstevel@tonic-gate
12957c478bd9Sstevel@tonic-gate /*
12967c478bd9Sstevel@tonic-gate * Permission checking functions. See comment atop this file.
12977c478bd9Sstevel@tonic-gate */
12987c478bd9Sstevel@tonic-gate #ifndef NATIVE_BUILD
12997c478bd9Sstevel@tonic-gate static permcheck_t *
pc_create()13007c478bd9Sstevel@tonic-gate pc_create()
13017c478bd9Sstevel@tonic-gate {
13027c478bd9Sstevel@tonic-gate permcheck_t *p;
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate p = uu_zalloc(sizeof (*p));
13057c478bd9Sstevel@tonic-gate if (p == NULL)
13067c478bd9Sstevel@tonic-gate return (NULL);
13077c478bd9Sstevel@tonic-gate p->pc_bnum = 8; /* Normal case will only have 2 elts. */
13087c478bd9Sstevel@tonic-gate p->pc_buckets = uu_zalloc(sizeof (*p->pc_buckets) * p->pc_bnum);
13097c478bd9Sstevel@tonic-gate if (p->pc_buckets == NULL) {
13107c478bd9Sstevel@tonic-gate uu_free(p);
13117c478bd9Sstevel@tonic-gate return (NULL);
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate p->pc_enum = 0;
13157c478bd9Sstevel@tonic-gate return (p);
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate static void
pc_free(permcheck_t * pcp)13197c478bd9Sstevel@tonic-gate pc_free(permcheck_t *pcp)
13207c478bd9Sstevel@tonic-gate {
13217c478bd9Sstevel@tonic-gate uint_t i;
13227c478bd9Sstevel@tonic-gate struct pc_elt *ep, *next;
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
13257c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
13267c478bd9Sstevel@tonic-gate next = ep->pce_next;
13277c478bd9Sstevel@tonic-gate free(ep);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate }
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate free(pcp->pc_buckets);
13327c478bd9Sstevel@tonic-gate free(pcp);
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate static uint32_t
pc_hash(const char * auth)13367c478bd9Sstevel@tonic-gate pc_hash(const char *auth)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate uint32_t h = 0, g;
13397c478bd9Sstevel@tonic-gate const char *p;
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate /*
13427c478bd9Sstevel@tonic-gate * Generic hash function from uts/common/os/modhash.c.
13437c478bd9Sstevel@tonic-gate */
13447c478bd9Sstevel@tonic-gate for (p = auth; *p != '\0'; ++p) {
13457c478bd9Sstevel@tonic-gate h = (h << 4) + *p;
13467c478bd9Sstevel@tonic-gate g = (h & 0xf0000000);
13477c478bd9Sstevel@tonic-gate if (g != 0) {
13487c478bd9Sstevel@tonic-gate h ^= (g >> 24);
13497c478bd9Sstevel@tonic-gate h ^= g;
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate return (h);
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate
1356a4dc1477STom Whitten static perm_status_t
pc_exists(permcheck_t * pcp,const char * auth)13575b7f77adStw21770 pc_exists(permcheck_t *pcp, const char *auth)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate uint32_t h;
13607c478bd9Sstevel@tonic-gate struct pc_elt *ep;
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate h = pc_hash(auth);
13637c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[h & (pcp->pc_bnum - 1)];
13647c478bd9Sstevel@tonic-gate ep != NULL;
13657c478bd9Sstevel@tonic-gate ep = ep->pce_next) {
13665b7f77adStw21770 if (strcmp(auth, ep->pce_auth) == 0) {
13675b7f77adStw21770 pcp->pc_auth_string = ep->pce_auth;
1368a4dc1477STom Whitten return (PERM_GRANTED);
13697c478bd9Sstevel@tonic-gate }
13705b7f77adStw21770 }
13717c478bd9Sstevel@tonic-gate
1372a4dc1477STom Whitten return (PERM_DENIED);
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate
1375a4dc1477STom Whitten static perm_status_t
pc_match(permcheck_t * pcp,const char * pattern)13765b7f77adStw21770 pc_match(permcheck_t *pcp, const char *pattern)
13777c478bd9Sstevel@tonic-gate {
13787c478bd9Sstevel@tonic-gate uint_t i;
13797c478bd9Sstevel@tonic-gate struct pc_elt *ep;
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
13827c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = ep->pce_next) {
13835b7f77adStw21770 if (_auth_match(pattern, ep->pce_auth)) {
13845b7f77adStw21770 pcp->pc_auth_string = ep->pce_auth;
1385a4dc1477STom Whitten return (PERM_GRANTED);
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate }
13885b7f77adStw21770 }
13897c478bd9Sstevel@tonic-gate
1390a4dc1477STom Whitten return (PERM_DENIED);
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate static int
pc_grow(permcheck_t * pcp)13947c478bd9Sstevel@tonic-gate pc_grow(permcheck_t *pcp)
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate uint_t new_bnum, i, j;
13977c478bd9Sstevel@tonic-gate struct pc_elt **new_buckets;
13987c478bd9Sstevel@tonic-gate struct pc_elt *ep, *next;
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate new_bnum = pcp->pc_bnum * 2;
14017c478bd9Sstevel@tonic-gate if (new_bnum < pcp->pc_bnum)
14027c478bd9Sstevel@tonic-gate /* Homey don't play that. */
14037c478bd9Sstevel@tonic-gate return (-1);
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate new_buckets = uu_zalloc(sizeof (*new_buckets) * new_bnum);
14067c478bd9Sstevel@tonic-gate if (new_buckets == NULL)
14077c478bd9Sstevel@tonic-gate return (-1);
14087c478bd9Sstevel@tonic-gate
14097c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
14107c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
14117c478bd9Sstevel@tonic-gate next = ep->pce_next;
14127c478bd9Sstevel@tonic-gate j = pc_hash(ep->pce_auth) & (new_bnum - 1);
14137c478bd9Sstevel@tonic-gate ep->pce_next = new_buckets[j];
14147c478bd9Sstevel@tonic-gate new_buckets[j] = ep;
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate }
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate uu_free(pcp->pc_buckets);
14197c478bd9Sstevel@tonic-gate pcp->pc_buckets = new_buckets;
14207c478bd9Sstevel@tonic-gate pcp->pc_bnum = new_bnum;
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate return (0);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate static int
pc_add(permcheck_t * pcp,const char * auth,pc_auth_type_t auth_type)14265b7f77adStw21770 pc_add(permcheck_t *pcp, const char *auth, pc_auth_type_t auth_type)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate struct pc_elt *ep;
14297c478bd9Sstevel@tonic-gate uint_t i;
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate ep = uu_zalloc(offsetof(struct pc_elt, pce_auth) + strlen(auth) + 1);
14327c478bd9Sstevel@tonic-gate if (ep == NULL)
14337c478bd9Sstevel@tonic-gate return (-1);
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate /* Grow if pc_enum / pc_bnum > 3/4. */
14367c478bd9Sstevel@tonic-gate if (pcp->pc_enum * 4 > 3 * pcp->pc_bnum)
14377c478bd9Sstevel@tonic-gate /* Failure is not a stopper; we'll try again next time. */
14387c478bd9Sstevel@tonic-gate (void) pc_grow(pcp);
14397c478bd9Sstevel@tonic-gate
14407c478bd9Sstevel@tonic-gate (void) strcpy(ep->pce_auth, auth);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate i = pc_hash(auth) & (pcp->pc_bnum - 1);
14437c478bd9Sstevel@tonic-gate ep->pce_next = pcp->pc_buckets[i];
14447c478bd9Sstevel@tonic-gate pcp->pc_buckets[i] = ep;
14457c478bd9Sstevel@tonic-gate
14465b7f77adStw21770 if (auth_type > pcp->pc_specific_type) {
14475b7f77adStw21770 pcp->pc_specific_type = auth_type;
14485b7f77adStw21770 pcp->pc_specific = ep;
14495b7f77adStw21770 }
14505b7f77adStw21770
14517c478bd9Sstevel@tonic-gate ++pcp->pc_enum;
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate return (0);
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate /*
14577c478bd9Sstevel@tonic-gate * For the type of a property group, return the authorization which may be
14587c478bd9Sstevel@tonic-gate * used to modify it.
14597c478bd9Sstevel@tonic-gate */
14607c478bd9Sstevel@tonic-gate static const char *
perm_auth_for_pgtype(const char * pgtype)14617c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(const char *pgtype)
14627c478bd9Sstevel@tonic-gate {
14637c478bd9Sstevel@tonic-gate if (strcmp(pgtype, SCF_GROUP_METHOD) == 0)
14647c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "method");
14657c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_DEPENDENCY) == 0)
14667c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "dependency");
14677c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_APPLICATION) == 0)
14687c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "application");
14697c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_FRAMEWORK) == 0)
14707c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "framework");
14717c478bd9Sstevel@tonic-gate else
14727c478bd9Sstevel@tonic-gate return (NULL);
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate /*
14767c478bd9Sstevel@tonic-gate * Fails with
14777c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory
14787c478bd9Sstevel@tonic-gate */
14797c478bd9Sstevel@tonic-gate static int
perm_add_enabling_type(permcheck_t * pcp,const char * auth,pc_auth_type_t auth_type)14805b7f77adStw21770 perm_add_enabling_type(permcheck_t *pcp, const char *auth,
14815b7f77adStw21770 pc_auth_type_t auth_type)
14825b7f77adStw21770 {
14835b7f77adStw21770 return (pc_add(pcp, auth, auth_type) == 0 ? REP_PROTOCOL_SUCCESS :
14845b7f77adStw21770 REP_PROTOCOL_FAIL_NO_RESOURCES);
14855b7f77adStw21770 }
14865b7f77adStw21770
14875b7f77adStw21770 /*
14885b7f77adStw21770 * Fails with
14895b7f77adStw21770 * _NO_RESOURCES - out of memory
14905b7f77adStw21770 */
14915b7f77adStw21770 static int
perm_add_enabling(permcheck_t * pcp,const char * auth)14927c478bd9Sstevel@tonic-gate perm_add_enabling(permcheck_t *pcp, const char *auth)
14937c478bd9Sstevel@tonic-gate {
14945b7f77adStw21770 return (perm_add_enabling_type(pcp, auth, PC_AUTH_SMF));
14957c478bd9Sstevel@tonic-gate }
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate /* Note that perm_add_enabling_values() is defined below. */
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate /*
1500a4dc1477STom Whitten * perm_granted() returns PERM_GRANTED if the current door caller has one of
1501a4dc1477STom Whitten * the enabling authorizations in pcp, PERM_DENIED if it doesn't, PERM_GONE if
1502a4dc1477STom Whitten * the door client went away and PERM_FAIL if an error (usually lack of
1503134a1f4eSCasper H.S. Dik * memory) occurs. auth_cb() checks each and every authorizations as
1504134a1f4eSCasper H.S. Dik * enumerated by _enum_auths. When we find a result other than PERM_DENIED,
1505134a1f4eSCasper H.S. Dik * we short-cut the enumeration and return non-zero.
15067c478bd9Sstevel@tonic-gate */
1507134a1f4eSCasper H.S. Dik
1508134a1f4eSCasper H.S. Dik static int
auth_cb(const char * auth,void * ctxt,void * vres)1509134a1f4eSCasper H.S. Dik auth_cb(const char *auth, void *ctxt, void *vres)
15107c478bd9Sstevel@tonic-gate {
1511134a1f4eSCasper H.S. Dik permcheck_t *pcp = ctxt;
1512134a1f4eSCasper H.S. Dik int *pret = vres;
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate if (strchr(auth, KV_WILDCHAR) == NULL)
1515134a1f4eSCasper H.S. Dik *pret = pc_exists(pcp, auth);
15167c478bd9Sstevel@tonic-gate else
1517134a1f4eSCasper H.S. Dik *pret = pc_match(pcp, auth);
15187c478bd9Sstevel@tonic-gate
1519134a1f4eSCasper H.S. Dik if (*pret != PERM_DENIED)
1520134a1f4eSCasper H.S. Dik return (1);
15215b7f77adStw21770 /*
15225b7f77adStw21770 * If we failed, choose the most specific auth string for use in
15235b7f77adStw21770 * the audit event.
15245b7f77adStw21770 */
15255b7f77adStw21770 assert(pcp->pc_specific != NULL);
15265b7f77adStw21770 pcp->pc_auth_string = pcp->pc_specific->pce_auth;
15275b7f77adStw21770
1528134a1f4eSCasper H.S. Dik return (0); /* Tells that we need to continue */
15297c478bd9Sstevel@tonic-gate }
15307c478bd9Sstevel@tonic-gate
1531a4dc1477STom Whitten static perm_status_t
perm_granted(permcheck_t * pcp)15325b7f77adStw21770 perm_granted(permcheck_t *pcp)
15337c478bd9Sstevel@tonic-gate {
15347c478bd9Sstevel@tonic-gate ucred_t *uc;
15357c478bd9Sstevel@tonic-gate
1536a4dc1477STom Whitten perm_status_t ret = PERM_DENIED;
15377c478bd9Sstevel@tonic-gate uid_t uid;
1538499fd601Sgww struct passwd pw;
1539499fd601Sgww char pwbuf[1024]; /* XXX should be NSS_BUFLEN_PASSWD */
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate /* Get the uid */
15427c478bd9Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) {
15437c478bd9Sstevel@tonic-gate if (errno == EINVAL) {
15447c478bd9Sstevel@tonic-gate /*
15457c478bd9Sstevel@tonic-gate * Client is no longer waiting for our response (e.g.,
15467c478bd9Sstevel@tonic-gate * it received a signal & resumed with EINTR).
15477c478bd9Sstevel@tonic-gate * Punting with door_return() would be nice but we
15487c478bd9Sstevel@tonic-gate * need to release all of the locks & references we
15497c478bd9Sstevel@tonic-gate * hold. And we must report failure to the client
15507c478bd9Sstevel@tonic-gate * layer to keep it from ignoring retries as
15517c478bd9Sstevel@tonic-gate * already-done (idempotency & all that). None of the
15527c478bd9Sstevel@tonic-gate * error codes fit very well, so we might as well
15537c478bd9Sstevel@tonic-gate * force the return of _PERMISSION_DENIED since we
15547c478bd9Sstevel@tonic-gate * couldn't determine the user.
15557c478bd9Sstevel@tonic-gate */
1556a4dc1477STom Whitten return (PERM_GONE);
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate assert(0);
15597c478bd9Sstevel@tonic-gate abort();
15607c478bd9Sstevel@tonic-gate }
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate uid = ucred_geteuid(uc);
1563f48205beScasper assert(uid != (uid_t)-1);
15647c478bd9Sstevel@tonic-gate
1565499fd601Sgww if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
1566a4dc1477STom Whitten return (PERM_FAIL);
1567499fd601Sgww }
1568499fd601Sgww
1569499fd601Sgww /*
1570134a1f4eSCasper H.S. Dik * Enumerate all the auths defined for the user and return the
1571134a1f4eSCasper H.S. Dik * result in ret.
1572499fd601Sgww */
1573134a1f4eSCasper H.S. Dik if (_enum_auths(pw.pw_name, auth_cb, pcp, &ret) < 0)
1574a4dc1477STom Whitten return (PERM_FAIL);
1575499fd601Sgww
15767c478bd9Sstevel@tonic-gate return (ret);
15777c478bd9Sstevel@tonic-gate }
1578a4dc1477STom Whitten
1579a4dc1477STom Whitten static int
map_granted_status(perm_status_t status,permcheck_t * pcp,char ** match_auth)1580a4dc1477STom Whitten map_granted_status(perm_status_t status, permcheck_t *pcp,
1581a4dc1477STom Whitten char **match_auth)
1582a4dc1477STom Whitten {
1583a4dc1477STom Whitten int rc;
1584a4dc1477STom Whitten
1585a4dc1477STom Whitten *match_auth = NULL;
1586a4dc1477STom Whitten switch (status) {
1587a4dc1477STom Whitten case PERM_DENIED:
1588a4dc1477STom Whitten *match_auth = strdup(pcp->pc_auth_string);
1589a4dc1477STom Whitten if (*match_auth == NULL)
1590a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1591a4dc1477STom Whitten else
1592a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
1593a4dc1477STom Whitten break;
1594a4dc1477STom Whitten case PERM_GRANTED:
1595a4dc1477STom Whitten *match_auth = strdup(pcp->pc_auth_string);
1596a4dc1477STom Whitten if (*match_auth == NULL)
1597a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1598a4dc1477STom Whitten else
1599a4dc1477STom Whitten rc = REP_PROTOCOL_SUCCESS;
1600a4dc1477STom Whitten break;
1601a4dc1477STom Whitten case PERM_GONE:
1602a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
1603a4dc1477STom Whitten break;
1604a4dc1477STom Whitten case PERM_FAIL:
1605a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1606a4dc1477STom Whitten break;
1607a4dc1477STom Whitten }
1608a4dc1477STom Whitten return (rc);
1609a4dc1477STom Whitten }
16107c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate /*
16137c478bd9Sstevel@tonic-gate * flags in RC_NODE_WAITING_FLAGS are broadcast when unset, and are used to
16147c478bd9Sstevel@tonic-gate * serialize certain actions, and to wait for certain operations to complete
16157c478bd9Sstevel@tonic-gate *
16167c478bd9Sstevel@tonic-gate * The waiting flags are:
16177c478bd9Sstevel@tonic-gate * RC_NODE_CHILDREN_CHANGING
16187c478bd9Sstevel@tonic-gate * The child list is being built or changed (due to creation
16197c478bd9Sstevel@tonic-gate * or deletion). All iterators pause.
16207c478bd9Sstevel@tonic-gate *
16217c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT
16227c478bd9Sstevel@tonic-gate * Someone is actively using the parent pointer, so we can't
16237c478bd9Sstevel@tonic-gate * be removed from the parent list.
16247c478bd9Sstevel@tonic-gate *
16257c478bd9Sstevel@tonic-gate * RC_NODE_CREATING_CHILD
16267c478bd9Sstevel@tonic-gate * A child is being created -- locks out other creations, to
16277c478bd9Sstevel@tonic-gate * prevent insert-insert races.
16287c478bd9Sstevel@tonic-gate *
16297c478bd9Sstevel@tonic-gate * RC_NODE_IN_TX
16307c478bd9Sstevel@tonic-gate * This object is running a transaction.
16317c478bd9Sstevel@tonic-gate *
16327c478bd9Sstevel@tonic-gate * RC_NODE_DYING
16337c478bd9Sstevel@tonic-gate * This node might be dying. Always set as a set, using
16347c478bd9Sstevel@tonic-gate * RC_NODE_DYING_FLAGS (which is everything but
16357c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT)
16367c478bd9Sstevel@tonic-gate */
16377c478bd9Sstevel@tonic-gate static int
rc_node_hold_flag(rc_node_t * np,uint32_t flag)16387c478bd9Sstevel@tonic-gate rc_node_hold_flag(rc_node_t *np, uint32_t flag)
16397c478bd9Sstevel@tonic-gate {
16407c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16417c478bd9Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag)) {
16447c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
16457c478bd9Sstevel@tonic-gate }
16467c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD)
16477c478bd9Sstevel@tonic-gate return (0);
16487c478bd9Sstevel@tonic-gate
16497c478bd9Sstevel@tonic-gate np->rn_flags |= flag;
16507c478bd9Sstevel@tonic-gate return (1);
16517c478bd9Sstevel@tonic-gate }
16527c478bd9Sstevel@tonic-gate
16537c478bd9Sstevel@tonic-gate static void
rc_node_rele_flag(rc_node_t * np,uint32_t flag)16547c478bd9Sstevel@tonic-gate rc_node_rele_flag(rc_node_t *np, uint32_t flag)
16557c478bd9Sstevel@tonic-gate {
16567c478bd9Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
16577c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16587c478bd9Sstevel@tonic-gate assert((np->rn_flags & flag) == flag);
16597c478bd9Sstevel@tonic-gate np->rn_flags &= ~flag;
16607c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&np->rn_cv);
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate /*
16647c478bd9Sstevel@tonic-gate * wait until a particular flag has cleared. Fails if the object dies.
16657c478bd9Sstevel@tonic-gate */
16667c478bd9Sstevel@tonic-gate static int
rc_node_wait_flag(rc_node_t * np,uint32_t flag)16677c478bd9Sstevel@tonic-gate rc_node_wait_flag(rc_node_t *np, uint32_t flag)
16687c478bd9Sstevel@tonic-gate {
16697c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16707c478bd9Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag))
16717c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
16727c478bd9Sstevel@tonic-gate
16737c478bd9Sstevel@tonic-gate return (!(np->rn_flags & RC_NODE_DEAD));
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /*
16777c478bd9Sstevel@tonic-gate * On entry, np's lock must be held, and this thread must be holding
16787c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT. On return, both of them are released.
16797c478bd9Sstevel@tonic-gate *
16807c478bd9Sstevel@tonic-gate * If the return value is NULL, np either does not have a parent, or
16817c478bd9Sstevel@tonic-gate * the parent has been marked DEAD.
16827c478bd9Sstevel@tonic-gate *
16837c478bd9Sstevel@tonic-gate * If the return value is non-NULL, it is the parent of np, and both
16847c478bd9Sstevel@tonic-gate * its lock and the requested flags are held.
16857c478bd9Sstevel@tonic-gate */
16867c478bd9Sstevel@tonic-gate static rc_node_t *
rc_node_hold_parent_flag(rc_node_t * np,uint32_t flag)16877c478bd9Sstevel@tonic-gate rc_node_hold_parent_flag(rc_node_t *np, uint32_t flag)
16887c478bd9Sstevel@tonic-gate {
16897c478bd9Sstevel@tonic-gate rc_node_t *pp;
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16927c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_USING_PARENT);
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate if ((pp = np->rn_parent) == NULL) {
16957c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
16967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
16977c478bd9Sstevel@tonic-gate return (NULL);
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
17027c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
17037c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
17047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(pp, flag)) {
17077c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
17087c478bd9Sstevel@tonic-gate return (NULL);
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate return (pp);
17117c478bd9Sstevel@tonic-gate }
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate rc_node_t *
rc_node_alloc(void)17147c478bd9Sstevel@tonic-gate rc_node_alloc(void)
17157c478bd9Sstevel@tonic-gate {
17167c478bd9Sstevel@tonic-gate rc_node_t *np = uu_zalloc(sizeof (*np));
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate if (np == NULL)
17197c478bd9Sstevel@tonic-gate return (NULL);
17207c478bd9Sstevel@tonic-gate
17217c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&np->rn_lock, NULL);
17227c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&np->rn_cv, NULL);
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate np->rn_children = uu_list_create(rc_children_pool, np, 0);
17257c478bd9Sstevel@tonic-gate np->rn_pg_notify_list = uu_list_create(rc_pg_notify_pool, np, 0);
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate uu_list_node_init(np, &np->rn_sibling_node, rc_children_pool);
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate uu_list_node_init(&np->rn_notify, &np->rn_notify.rcn_list_node,
17307c478bd9Sstevel@tonic-gate rc_notify_pool);
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate return (np);
17337c478bd9Sstevel@tonic-gate }
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate void
rc_node_destroy(rc_node_t * np)17367c478bd9Sstevel@tonic-gate rc_node_destroy(rc_node_t *np)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate int i;
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED)
17417c478bd9Sstevel@tonic-gate return; /* being handled elsewhere */
17427c478bd9Sstevel@tonic-gate
17437c478bd9Sstevel@tonic-gate assert(np->rn_refs == 0 && np->rn_other_refs == 0);
17447c478bd9Sstevel@tonic-gate assert(np->rn_former == NULL);
17457c478bd9Sstevel@tonic-gate
17467c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
17477c478bd9Sstevel@tonic-gate /* Release the holds from rc_iter_next(). */
17487c478bd9Sstevel@tonic-gate for (i = 0; i < COMPOSITION_DEPTH; ++i) {
17497c478bd9Sstevel@tonic-gate /* rn_cchain[i] may be NULL for empty snapshots. */
17507c478bd9Sstevel@tonic-gate if (np->rn_cchain[i] != NULL)
17517c478bd9Sstevel@tonic-gate rc_node_rele(np->rn_cchain[i]);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate if (np->rn_name != NULL)
17567c478bd9Sstevel@tonic-gate free((void *)np->rn_name);
17577c478bd9Sstevel@tonic-gate np->rn_name = NULL;
17587c478bd9Sstevel@tonic-gate if (np->rn_type != NULL)
17597c478bd9Sstevel@tonic-gate free((void *)np->rn_type);
17607c478bd9Sstevel@tonic-gate np->rn_type = NULL;
17617c478bd9Sstevel@tonic-gate if (np->rn_values != NULL)
17627c478bd9Sstevel@tonic-gate object_free_values(np->rn_values, np->rn_valtype,
17637c478bd9Sstevel@tonic-gate np->rn_values_count, np->rn_values_size);
17647c478bd9Sstevel@tonic-gate np->rn_values = NULL;
17655b7f77adStw21770 rc_node_free_fmri(np);
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate if (np->rn_snaplevel != NULL)
17687c478bd9Sstevel@tonic-gate rc_snaplevel_rele(np->rn_snaplevel);
17697c478bd9Sstevel@tonic-gate np->rn_snaplevel = NULL;
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate uu_list_node_fini(np, &np->rn_sibling_node, rc_children_pool);
17727c478bd9Sstevel@tonic-gate
17737c478bd9Sstevel@tonic-gate uu_list_node_fini(&np->rn_notify, &np->rn_notify.rcn_list_node,
17747c478bd9Sstevel@tonic-gate rc_notify_pool);
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate assert(uu_list_first(np->rn_children) == NULL);
17777c478bd9Sstevel@tonic-gate uu_list_destroy(np->rn_children);
17787c478bd9Sstevel@tonic-gate uu_list_destroy(np->rn_pg_notify_list);
17797c478bd9Sstevel@tonic-gate
17807c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&np->rn_lock);
17817c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&np->rn_cv);
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate uu_free(np);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate
17867c478bd9Sstevel@tonic-gate /*
17877c478bd9Sstevel@tonic-gate * Link in a child node.
17887c478bd9Sstevel@tonic-gate *
17897c478bd9Sstevel@tonic-gate * Because of the lock ordering, cp has to already be in the hash table with
17907c478bd9Sstevel@tonic-gate * its lock dropped before we get it. To prevent anyone from noticing that
17917c478bd9Sstevel@tonic-gate * it is parentless, the creation code sets the RC_NODE_USING_PARENT. Once
17927c478bd9Sstevel@tonic-gate * we've linked it in, we release the flag.
17937c478bd9Sstevel@tonic-gate */
17947c478bd9Sstevel@tonic-gate static void
rc_node_link_child(rc_node_t * np,rc_node_t * cp)17957c478bd9Sstevel@tonic-gate rc_node_link_child(rc_node_t *np, rc_node_t *cp)
17967c478bd9Sstevel@tonic-gate {
17977c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&np->rn_lock));
17987c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&cp->rn_lock));
17997c478bd9Sstevel@tonic-gate
18007c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
18017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
18027c478bd9Sstevel@tonic-gate assert(!(cp->rn_flags & RC_NODE_IN_PARENT) &&
18037c478bd9Sstevel@tonic-gate (cp->rn_flags & RC_NODE_USING_PARENT));
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate assert(rc_check_parent_child(np->rn_id.rl_type, cp->rn_id.rl_type) ==
18067c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate cp->rn_parent = np;
18097c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_IN_PARENT;
18107c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(np->rn_children, NULL, cp);
18115b7f77adStw21770 (void) rc_node_build_fmri(cp);
18127c478bd9Sstevel@tonic-gate
18137c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate rc_node_rele_flag(cp, RC_NODE_USING_PARENT);
18167c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate /*
18207c478bd9Sstevel@tonic-gate * Sets the rn_parent_ref field of all the children of np to pp -- always
18217c478bd9Sstevel@tonic-gate * initially invoked as rc_node_setup_parent_ref(np, np), we then recurse.
18227c478bd9Sstevel@tonic-gate *
18237c478bd9Sstevel@tonic-gate * This is used when we mark a node RC_NODE_OLD, so that when the object and
18247c478bd9Sstevel@tonic-gate * its children are no longer referenced, they will all be deleted as a unit.
18257c478bd9Sstevel@tonic-gate */
18267c478bd9Sstevel@tonic-gate static void
rc_node_setup_parent_ref(rc_node_t * np,rc_node_t * pp)18277c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(rc_node_t *np, rc_node_t *pp)
18287c478bd9Sstevel@tonic-gate {
18297c478bd9Sstevel@tonic-gate rc_node_t *cp;
18307c478bd9Sstevel@tonic-gate
18317c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
18347c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
18357c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
18367c478bd9Sstevel@tonic-gate if (cp->rn_flags & RC_NODE_PARENT_REF) {
18377c478bd9Sstevel@tonic-gate assert(cp->rn_parent_ref == pp);
18387c478bd9Sstevel@tonic-gate } else {
18397c478bd9Sstevel@tonic-gate assert(cp->rn_parent_ref == NULL);
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_PARENT_REF;
18427c478bd9Sstevel@tonic-gate cp->rn_parent_ref = pp;
18437c478bd9Sstevel@tonic-gate if (cp->rn_refs != 0)
18447c478bd9Sstevel@tonic-gate rc_node_hold_other(pp);
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(cp, pp); /* recurse */
18477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
18487c478bd9Sstevel@tonic-gate }
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate * Atomically replace 'np' with 'newp', with a parent of 'pp'.
18537c478bd9Sstevel@tonic-gate *
18547c478bd9Sstevel@tonic-gate * Requirements:
18557c478bd9Sstevel@tonic-gate * *no* node locks may be held.
18567c478bd9Sstevel@tonic-gate * pp must be held with RC_NODE_CHILDREN_CHANGING
18577c478bd9Sstevel@tonic-gate * newp and np must be held with RC_NODE_IN_TX
18587c478bd9Sstevel@tonic-gate * np must be marked RC_NODE_IN_PARENT, newp must not be
18597c478bd9Sstevel@tonic-gate * np must be marked RC_NODE_OLD
18607c478bd9Sstevel@tonic-gate *
18617c478bd9Sstevel@tonic-gate * Afterwards:
18627c478bd9Sstevel@tonic-gate * pp's RC_NODE_CHILDREN_CHANGING is dropped
18637c478bd9Sstevel@tonic-gate * newp and np's RC_NODE_IN_TX is dropped
18647c478bd9Sstevel@tonic-gate * newp->rn_former = np;
18657c478bd9Sstevel@tonic-gate * newp is RC_NODE_IN_PARENT, np is not.
18667c478bd9Sstevel@tonic-gate * interested notify subscribers have been notified of newp's new status.
18677c478bd9Sstevel@tonic-gate */
18687c478bd9Sstevel@tonic-gate static void
rc_node_relink_child(rc_node_t * pp,rc_node_t * np,rc_node_t * newp)18697c478bd9Sstevel@tonic-gate rc_node_relink_child(rc_node_t *pp, rc_node_t *np, rc_node_t *newp)
18707c478bd9Sstevel@tonic-gate {
18717c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
18727c478bd9Sstevel@tonic-gate /*
18737c478bd9Sstevel@tonic-gate * First, swap np and nnp in the cache. newp's RC_NODE_IN_TX flag
18747c478bd9Sstevel@tonic-gate * keeps rc_node_update() from seeing it until we are done.
18757c478bd9Sstevel@tonic-gate */
18767c478bd9Sstevel@tonic-gate bp = cache_hold(newp->rn_hash);
18777c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, np);
18787c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, newp);
18797c478bd9Sstevel@tonic-gate cache_release(bp);
18807c478bd9Sstevel@tonic-gate
18817c478bd9Sstevel@tonic-gate /*
18827c478bd9Sstevel@tonic-gate * replace np with newp in pp's list, and attach it to newp's rn_former
18837c478bd9Sstevel@tonic-gate * link.
18847c478bd9Sstevel@tonic-gate */
18857c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
18867c478bd9Sstevel@tonic-gate assert(pp->rn_flags & RC_NODE_CHILDREN_CHANGING);
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&newp->rn_lock);
18897c478bd9Sstevel@tonic-gate assert(!(newp->rn_flags & RC_NODE_IN_PARENT));
18907c478bd9Sstevel@tonic-gate assert(newp->rn_flags & RC_NODE_IN_TX);
18917c478bd9Sstevel@tonic-gate
18927c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
18937c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
18947c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD);
18957c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_TX);
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate newp->rn_parent = pp;
18987c478bd9Sstevel@tonic-gate newp->rn_flags |= RC_NODE_IN_PARENT;
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate /*
19017c478bd9Sstevel@tonic-gate * Note that we carefully add newp before removing np -- this
19027c478bd9Sstevel@tonic-gate * keeps iterators on the list from missing us.
19037c478bd9Sstevel@tonic-gate */
19047c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(pp->rn_children, np, newp);
19055b7f77adStw21770 (void) rc_node_build_fmri(newp);
19067c478bd9Sstevel@tonic-gate (void) uu_list_remove(pp->rn_children, np);
19077c478bd9Sstevel@tonic-gate
19087c478bd9Sstevel@tonic-gate /*
19097c478bd9Sstevel@tonic-gate * re-set np
19107c478bd9Sstevel@tonic-gate */
19117c478bd9Sstevel@tonic-gate newp->rn_former = np;
19127c478bd9Sstevel@tonic-gate np->rn_parent = NULL;
19137c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT;
19147c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_ON_FORMER;
19157c478bd9Sstevel@tonic-gate
19167c478bd9Sstevel@tonic-gate rc_notify_insert_node(newp);
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
19197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
19207c478bd9Sstevel@tonic-gate rc_node_rele_flag(newp, RC_NODE_USING_PARENT | RC_NODE_IN_TX);
19217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&newp->rn_lock);
19227c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(np, np);
19237c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
19247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
19257c478bd9Sstevel@tonic-gate }
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate /*
19287c478bd9Sstevel@tonic-gate * makes sure a node with lookup 'nip', name 'name', and parent 'pp' exists.
19297c478bd9Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does
19307c478bd9Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead.
19317c478bd9Sstevel@tonic-gate */
19327c478bd9Sstevel@tonic-gate rc_node_t *
rc_node_setup(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,rc_node_t * pp)19337c478bd9Sstevel@tonic-gate rc_node_setup(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
19347c478bd9Sstevel@tonic-gate rc_node_t *pp)
19357c478bd9Sstevel@tonic-gate {
19367c478bd9Sstevel@tonic-gate rc_node_t *np;
19377c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
19387c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
19397c478bd9Sstevel@tonic-gate
19407c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0);
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate bp = cache_hold(h);
19437c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
19447c478bd9Sstevel@tonic-gate cache_release(bp);
19457c478bd9Sstevel@tonic-gate
19467c478bd9Sstevel@tonic-gate /*
19477c478bd9Sstevel@tonic-gate * make sure it matches our expectations
19487c478bd9Sstevel@tonic-gate */
1949cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
1950cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
19517c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp);
19527c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
19537c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0);
19547c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL);
19557c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
1956cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
1957cfae1de8Shg115875 }
1958cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
19597c478bd9Sstevel@tonic-gate
19607c478bd9Sstevel@tonic-gate rc_node_destroy(cp);
19617c478bd9Sstevel@tonic-gate return (np);
19627c478bd9Sstevel@tonic-gate }
19637c478bd9Sstevel@tonic-gate
19647c478bd9Sstevel@tonic-gate /*
19656643e1ffSbustos * No one is there -- setup & install the new node.
19667c478bd9Sstevel@tonic-gate */
19677c478bd9Sstevel@tonic-gate np = cp;
19687c478bd9Sstevel@tonic-gate rc_node_hold(np);
19697c478bd9Sstevel@tonic-gate np->rn_id = *nip;
19707c478bd9Sstevel@tonic-gate np->rn_hash = h;
19717c478bd9Sstevel@tonic-gate np->rn_name = strdup(name);
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
19747c478bd9Sstevel@tonic-gate
19757c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE) {
19767c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
19777c478bd9Sstevel@tonic-gate np->rn_cchain[0] = np;
19787c478bd9Sstevel@tonic-gate np->rn_cchain[1] = pp;
19797c478bd9Sstevel@tonic-gate #else
19807c478bd9Sstevel@tonic-gate #error This code must be updated.
19817c478bd9Sstevel@tonic-gate #endif
19827c478bd9Sstevel@tonic-gate }
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
19857c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */
19867c478bd9Sstevel@tonic-gate
19877c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np);
19887c478bd9Sstevel@tonic-gate
19897c478bd9Sstevel@tonic-gate return (np);
19907c478bd9Sstevel@tonic-gate }
19917c478bd9Sstevel@tonic-gate
19927c478bd9Sstevel@tonic-gate /*
19937c478bd9Sstevel@tonic-gate * makes sure a snapshot with lookup 'nip', name 'name', and parent 'pp' exists.
19947c478bd9Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does
19957c478bd9Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead.
19967c478bd9Sstevel@tonic-gate */
19977c478bd9Sstevel@tonic-gate rc_node_t *
rc_node_setup_snapshot(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,uint32_t snap_id,rc_node_t * pp)19987c478bd9Sstevel@tonic-gate rc_node_setup_snapshot(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
19997c478bd9Sstevel@tonic-gate uint32_t snap_id, rc_node_t *pp)
20007c478bd9Sstevel@tonic-gate {
20017c478bd9Sstevel@tonic-gate rc_node_t *np;
20027c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
20037c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
20047c478bd9Sstevel@tonic-gate
20057c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0);
20067c478bd9Sstevel@tonic-gate
20077c478bd9Sstevel@tonic-gate bp = cache_hold(h);
20087c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
20097c478bd9Sstevel@tonic-gate cache_release(bp);
20107c478bd9Sstevel@tonic-gate
20117c478bd9Sstevel@tonic-gate /*
20127c478bd9Sstevel@tonic-gate * make sure it matches our expectations
20137c478bd9Sstevel@tonic-gate */
2014cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2015cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
20167c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp);
20177c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
20187c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0);
20197c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL);
20207c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
2021cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2022cfae1de8Shg115875 }
2023cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate rc_node_destroy(cp);
20267c478bd9Sstevel@tonic-gate return (np);
20277c478bd9Sstevel@tonic-gate }
20287c478bd9Sstevel@tonic-gate
20297c478bd9Sstevel@tonic-gate /*
20307c478bd9Sstevel@tonic-gate * No one is there -- create a new node.
20317c478bd9Sstevel@tonic-gate */
20327c478bd9Sstevel@tonic-gate np = cp;
20337c478bd9Sstevel@tonic-gate rc_node_hold(np);
20347c478bd9Sstevel@tonic-gate np->rn_id = *nip;
20357c478bd9Sstevel@tonic-gate np->rn_hash = h;
20367c478bd9Sstevel@tonic-gate np->rn_name = strdup(name);
20377c478bd9Sstevel@tonic-gate np->rn_snapshot_id = snap_id;
20387c478bd9Sstevel@tonic-gate
20397c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
20427c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */
20437c478bd9Sstevel@tonic-gate
20447c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np);
20457c478bd9Sstevel@tonic-gate
20467c478bd9Sstevel@tonic-gate return (np);
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate
20497c478bd9Sstevel@tonic-gate /*
20507c478bd9Sstevel@tonic-gate * makes sure a snaplevel with lookup 'nip' and parent 'pp' exists. 'cp' is
20517c478bd9Sstevel@tonic-gate * used (and returned) if the node does not yet exist. If it does exist, 'cp'
20527c478bd9Sstevel@tonic-gate * is freed, and the existent node is returned instead.
20537c478bd9Sstevel@tonic-gate */
20547c478bd9Sstevel@tonic-gate rc_node_t *
rc_node_setup_snaplevel(rc_node_t * cp,rc_node_lookup_t * nip,rc_snaplevel_t * lvl,rc_node_t * pp)20557c478bd9Sstevel@tonic-gate rc_node_setup_snaplevel(rc_node_t *cp, rc_node_lookup_t *nip,
20567c478bd9Sstevel@tonic-gate rc_snaplevel_t *lvl, rc_node_t *pp)
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate rc_node_t *np;
20597c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
20607c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0);
20637c478bd9Sstevel@tonic-gate
20647c478bd9Sstevel@tonic-gate bp = cache_hold(h);
20657c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
20667c478bd9Sstevel@tonic-gate cache_release(bp);
20677c478bd9Sstevel@tonic-gate
20687c478bd9Sstevel@tonic-gate /*
20697c478bd9Sstevel@tonic-gate * make sure it matches our expectations
20707c478bd9Sstevel@tonic-gate */
2071cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2072cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
20737c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp);
20747c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
20757c478bd9Sstevel@tonic-gate assert(np->rn_name == NULL);
20767c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL);
20777c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
2078cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2079cfae1de8Shg115875 }
2080cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate rc_node_destroy(cp);
20837c478bd9Sstevel@tonic-gate return (np);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate
20867c478bd9Sstevel@tonic-gate /*
20877c478bd9Sstevel@tonic-gate * No one is there -- create a new node.
20887c478bd9Sstevel@tonic-gate */
20897c478bd9Sstevel@tonic-gate np = cp;
20907c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released in snapshot_fill_children() */
20917c478bd9Sstevel@tonic-gate np->rn_id = *nip;
20927c478bd9Sstevel@tonic-gate np->rn_hash = h;
20937c478bd9Sstevel@tonic-gate
20947c478bd9Sstevel@tonic-gate rc_snaplevel_hold(lvl);
20957c478bd9Sstevel@tonic-gate np->rn_snaplevel = lvl;
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
20987c478bd9Sstevel@tonic-gate
20997c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
21007c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */
21017c478bd9Sstevel@tonic-gate
21027c478bd9Sstevel@tonic-gate /* Add this snaplevel to the snapshot's composition chain. */
21037c478bd9Sstevel@tonic-gate assert(pp->rn_cchain[lvl->rsl_level_num - 1] == NULL);
21047c478bd9Sstevel@tonic-gate pp->rn_cchain[lvl->rsl_level_num - 1] = np;
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np);
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate return (np);
21097c478bd9Sstevel@tonic-gate }
21107c478bd9Sstevel@tonic-gate
21117c478bd9Sstevel@tonic-gate /*
21127c478bd9Sstevel@tonic-gate * Returns NULL if strdup() fails.
21137c478bd9Sstevel@tonic-gate */
21147c478bd9Sstevel@tonic-gate rc_node_t *
rc_node_setup_pg(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,const char * type,uint32_t flags,uint32_t gen_id,rc_node_t * pp)21157c478bd9Sstevel@tonic-gate rc_node_setup_pg(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
21167c478bd9Sstevel@tonic-gate const char *type, uint32_t flags, uint32_t gen_id, rc_node_t *pp)
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate rc_node_t *np;
21197c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
21207c478bd9Sstevel@tonic-gate
21217c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
21227c478bd9Sstevel@tonic-gate bp = cache_hold(h);
21237c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
21247c478bd9Sstevel@tonic-gate cache_release(bp);
21257c478bd9Sstevel@tonic-gate
21267c478bd9Sstevel@tonic-gate /*
21277c478bd9Sstevel@tonic-gate * make sure it matches our expectations (don't check
21287c478bd9Sstevel@tonic-gate * the generation number or parent, since someone could
21297c478bd9Sstevel@tonic-gate * have gotten a transaction through while we weren't
21307c478bd9Sstevel@tonic-gate * looking)
21317c478bd9Sstevel@tonic-gate */
2132cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2133cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
21347c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
21357c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0);
21367c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_type, type) == 0);
21377c478bd9Sstevel@tonic-gate assert(np->rn_pgflags == flags);
21387c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
2139cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2140cfae1de8Shg115875 }
2141cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate rc_node_destroy(cp);
21447c478bd9Sstevel@tonic-gate return (np);
21457c478bd9Sstevel@tonic-gate }
21467c478bd9Sstevel@tonic-gate
21477c478bd9Sstevel@tonic-gate np = cp;
21487c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released in fill_pg_callback() */
21497c478bd9Sstevel@tonic-gate np->rn_id = *nip;
21507c478bd9Sstevel@tonic-gate np->rn_hash = h;
21517c478bd9Sstevel@tonic-gate np->rn_name = strdup(name);
21527c478bd9Sstevel@tonic-gate if (np->rn_name == NULL) {
21537c478bd9Sstevel@tonic-gate rc_node_rele(np);
21547c478bd9Sstevel@tonic-gate return (NULL);
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate np->rn_type = strdup(type);
21577c478bd9Sstevel@tonic-gate if (np->rn_type == NULL) {
21587c478bd9Sstevel@tonic-gate free((void *)np->rn_name);
21597c478bd9Sstevel@tonic-gate rc_node_rele(np);
21607c478bd9Sstevel@tonic-gate return (NULL);
21617c478bd9Sstevel@tonic-gate }
21627c478bd9Sstevel@tonic-gate np->rn_pgflags = flags;
21637c478bd9Sstevel@tonic-gate np->rn_gen_id = gen_id;
21647c478bd9Sstevel@tonic-gate
21657c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
21667c478bd9Sstevel@tonic-gate
21677c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
21687c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */
21697c478bd9Sstevel@tonic-gate
21707c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np);
21717c478bd9Sstevel@tonic-gate
21727c478bd9Sstevel@tonic-gate return (np);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
21767c478bd9Sstevel@tonic-gate /*
21777c478bd9Sstevel@tonic-gate * Initialize a "composed property group" which represents the composition of
21787c478bd9Sstevel@tonic-gate * property groups pg1 & pg2. It is ephemeral: once created & returned for an
21797c478bd9Sstevel@tonic-gate * ITER_READ request, keeping it out of cache_hash and any child lists
21807c478bd9Sstevel@tonic-gate * prevents it from being looked up. Operations besides iteration are passed
21817c478bd9Sstevel@tonic-gate * through to pg1.
21827c478bd9Sstevel@tonic-gate *
21837c478bd9Sstevel@tonic-gate * pg1 & pg2 should be held before entering this function. They will be
21847c478bd9Sstevel@tonic-gate * released in rc_node_destroy().
21857c478bd9Sstevel@tonic-gate */
21867c478bd9Sstevel@tonic-gate static int
rc_node_setup_cpg(rc_node_t * cpg,rc_node_t * pg1,rc_node_t * pg2)21877c478bd9Sstevel@tonic-gate rc_node_setup_cpg(rc_node_t *cpg, rc_node_t *pg1, rc_node_t *pg2)
21887c478bd9Sstevel@tonic-gate {
21897c478bd9Sstevel@tonic-gate if (strcmp(pg1->rn_type, pg2->rn_type) != 0)
21907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
21917c478bd9Sstevel@tonic-gate
21927c478bd9Sstevel@tonic-gate cpg->rn_id.rl_type = REP_PROTOCOL_ENTITY_CPROPERTYGRP;
21937c478bd9Sstevel@tonic-gate cpg->rn_name = strdup(pg1->rn_name);
21947c478bd9Sstevel@tonic-gate if (cpg->rn_name == NULL)
21957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
21967c478bd9Sstevel@tonic-gate
21977c478bd9Sstevel@tonic-gate cpg->rn_cchain[0] = pg1;
21987c478bd9Sstevel@tonic-gate cpg->rn_cchain[1] = pg2;
21997c478bd9Sstevel@tonic-gate
22007c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate #else
22037c478bd9Sstevel@tonic-gate #error This code must be updated.
22047c478bd9Sstevel@tonic-gate #endif
22057c478bd9Sstevel@tonic-gate
22067c478bd9Sstevel@tonic-gate /*
22077c478bd9Sstevel@tonic-gate * Fails with _NO_RESOURCES.
22087c478bd9Sstevel@tonic-gate */
22097c478bd9Sstevel@tonic-gate int
rc_node_create_property(rc_node_t * pp,rc_node_lookup_t * nip,const char * name,rep_protocol_value_type_t type,const char * vals,size_t count,size_t size)22107c478bd9Sstevel@tonic-gate rc_node_create_property(rc_node_t *pp, rc_node_lookup_t *nip,
22117c478bd9Sstevel@tonic-gate const char *name, rep_protocol_value_type_t type,
22127c478bd9Sstevel@tonic-gate const char *vals, size_t count, size_t size)
22137c478bd9Sstevel@tonic-gate {
22147c478bd9Sstevel@tonic-gate rc_node_t *np;
22157c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
22167c478bd9Sstevel@tonic-gate
22177c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
22187c478bd9Sstevel@tonic-gate bp = cache_hold(h);
22197c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
22207c478bd9Sstevel@tonic-gate cache_release(bp);
22217c478bd9Sstevel@tonic-gate /*
22227c478bd9Sstevel@tonic-gate * make sure it matches our expectations
22237c478bd9Sstevel@tonic-gate */
22247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
22257c478bd9Sstevel@tonic-gate if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
22267c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp);
22277c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
22287c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0);
22297c478bd9Sstevel@tonic-gate assert(np->rn_valtype == type);
22307c478bd9Sstevel@tonic-gate assert(np->rn_values_count == count);
22317c478bd9Sstevel@tonic-gate assert(np->rn_values_size == size);
22327c478bd9Sstevel@tonic-gate assert(vals == NULL ||
22337c478bd9Sstevel@tonic-gate memcmp(np->rn_values, vals, size) == 0);
22347c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
22357c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
22387c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size);
22397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate
22427c478bd9Sstevel@tonic-gate /*
22437c478bd9Sstevel@tonic-gate * No one is there -- create a new node.
22447c478bd9Sstevel@tonic-gate */
22457c478bd9Sstevel@tonic-gate np = rc_node_alloc();
22467c478bd9Sstevel@tonic-gate if (np == NULL) {
22477c478bd9Sstevel@tonic-gate cache_release(bp);
22487c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size);
22497c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
22507c478bd9Sstevel@tonic-gate }
22517c478bd9Sstevel@tonic-gate np->rn_id = *nip;
22527c478bd9Sstevel@tonic-gate np->rn_hash = h;
22537c478bd9Sstevel@tonic-gate np->rn_name = strdup(name);
22547c478bd9Sstevel@tonic-gate if (np->rn_name == NULL) {
22557c478bd9Sstevel@tonic-gate cache_release(bp);
22567c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size);
22577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
22587c478bd9Sstevel@tonic-gate }
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate np->rn_valtype = type;
22617c478bd9Sstevel@tonic-gate np->rn_values = vals;
22627c478bd9Sstevel@tonic-gate np->rn_values_count = count;
22637c478bd9Sstevel@tonic-gate np->rn_values_size = size;
22647c478bd9Sstevel@tonic-gate
22657c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
22667c478bd9Sstevel@tonic-gate
22677c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
22687c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np);
22717c478bd9Sstevel@tonic-gate
22727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22737c478bd9Sstevel@tonic-gate }
22747c478bd9Sstevel@tonic-gate
22755b7f77adStw21770 /*
22765b7f77adStw21770 * This function implements a decision table to determine the event ID for
22775b7f77adStw21770 * changes to the enabled (SCF_PROPERTY_ENABLED) property. The event ID is
22785b7f77adStw21770 * determined by the value of the first property in the command specified
22795b7f77adStw21770 * by cmd_no and the name of the property group. Here is the decision
22805b7f77adStw21770 * table:
22815b7f77adStw21770 *
22825b7f77adStw21770 * Property Group Name
22835b7f77adStw21770 * Property ------------------------------------------
22845b7f77adStw21770 * Value SCF_PG_GENERAL SCF_PG_GENERAL_OVR
22855b7f77adStw21770 * -------- -------------- ------------------
22865b7f77adStw21770 * "0" ADT_smf_disable ADT_smf_tmp_disable
22875b7f77adStw21770 * "1" ADT_smf_enable ADT_smf_tmp_enable
22885b7f77adStw21770 *
22895b7f77adStw21770 * This function is called by special_property_event through a function
22905b7f77adStw21770 * pointer in the special_props_list array.
22915b7f77adStw21770 *
22925b7f77adStw21770 * Since the ADT_smf_* symbols may not be defined in the build machine's
22935b7f77adStw21770 * include files, this function is not compiled when doing native builds.
22945b7f77adStw21770 */
22955b7f77adStw21770 #ifndef NATIVE_BUILD
22965b7f77adStw21770 static int
general_enable_id(tx_commit_data_t * tx_data,size_t cmd_no,const char * pg,au_event_t * event_id)22975b7f77adStw21770 general_enable_id(tx_commit_data_t *tx_data, size_t cmd_no, const char *pg,
22985b7f77adStw21770 au_event_t *event_id)
22995b7f77adStw21770 {
23005b7f77adStw21770 const char *value;
23015b7f77adStw21770 uint32_t nvalues;
23025b7f77adStw21770 int enable;
23035b7f77adStw21770
23045b7f77adStw21770 /*
23055b7f77adStw21770 * First, check property value.
23065b7f77adStw21770 */
23075b7f77adStw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
23085b7f77adStw21770 return (-1);
23095b7f77adStw21770 if (nvalues == 0)
23105b7f77adStw21770 return (-1);
23115b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, 0, &value) != REP_PROTOCOL_SUCCESS)
23125b7f77adStw21770 return (-1);
23135b7f77adStw21770 if (strcmp(value, "0") == 0) {
23145b7f77adStw21770 enable = 0;
23155b7f77adStw21770 } else if (strcmp(value, "1") == 0) {
23165b7f77adStw21770 enable = 1;
23175b7f77adStw21770 } else {
23185b7f77adStw21770 return (-1);
23195b7f77adStw21770 }
23205b7f77adStw21770
23215b7f77adStw21770 /*
23225b7f77adStw21770 * Now check property group name.
23235b7f77adStw21770 */
23245b7f77adStw21770 if (strcmp(pg, SCF_PG_GENERAL) == 0) {
23255b7f77adStw21770 *event_id = enable ? ADT_smf_enable : ADT_smf_disable;
23265b7f77adStw21770 return (0);
23275b7f77adStw21770 } else if (strcmp(pg, SCF_PG_GENERAL_OVR) == 0) {
23285b7f77adStw21770 *event_id = enable ? ADT_smf_tmp_enable : ADT_smf_tmp_disable;
23295b7f77adStw21770 return (0);
23305b7f77adStw21770 }
23315b7f77adStw21770 return (-1);
23325b7f77adStw21770 }
23335b7f77adStw21770 #endif /* NATIVE_BUILD */
23345b7f77adStw21770
23355b7f77adStw21770 /*
23365b7f77adStw21770 * This function compares two audit_special_prop_item_t structures
23375b7f77adStw21770 * represented by item1 and item2. It returns an integer greater than 0 if
23385b7f77adStw21770 * item1 is greater than item2. It returns 0 if they are equal and an
23395b7f77adStw21770 * integer less than 0 if item1 is less than item2. api_prop_name and
23405b7f77adStw21770 * api_pg_name are the key fields for sorting.
23415b7f77adStw21770 *
23425b7f77adStw21770 * This function is suitable for calls to bsearch(3C) and qsort(3C).
23435b7f77adStw21770 */
23445b7f77adStw21770 static int
special_prop_compare(const void * item1,const void * item2)23455b7f77adStw21770 special_prop_compare(const void *item1, const void *item2)
23465b7f77adStw21770 {
23475b7f77adStw21770 const audit_special_prop_item_t *a = (audit_special_prop_item_t *)item1;
23485b7f77adStw21770 const audit_special_prop_item_t *b = (audit_special_prop_item_t *)item2;
23495b7f77adStw21770 int r;
23505b7f77adStw21770
23515b7f77adStw21770 r = strcmp(a->api_prop_name, b->api_prop_name);
23525b7f77adStw21770 if (r == 0) {
23535b7f77adStw21770 /*
23545b7f77adStw21770 * Primary keys are the same, so check the secondary key.
23555b7f77adStw21770 */
23565b7f77adStw21770 r = strcmp(a->api_pg_name, b->api_pg_name);
23575b7f77adStw21770 }
23585b7f77adStw21770 return (r);
23595b7f77adStw21770 }
23605b7f77adStw21770
23617c478bd9Sstevel@tonic-gate int
rc_node_init(void)23627c478bd9Sstevel@tonic-gate rc_node_init(void)
23637c478bd9Sstevel@tonic-gate {
23647c478bd9Sstevel@tonic-gate rc_node_t *np;
23657c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
23667c478bd9Sstevel@tonic-gate
23677c478bd9Sstevel@tonic-gate rc_children_pool = uu_list_pool_create("rc_children_pool",
23687c478bd9Sstevel@tonic-gate sizeof (rc_node_t), offsetof(rc_node_t, rn_sibling_node),
23697c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23707c478bd9Sstevel@tonic-gate
23717c478bd9Sstevel@tonic-gate rc_pg_notify_pool = uu_list_pool_create("rc_pg_notify_pool",
23727c478bd9Sstevel@tonic-gate sizeof (rc_node_pg_notify_t),
23737c478bd9Sstevel@tonic-gate offsetof(rc_node_pg_notify_t, rnpn_node),
23747c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23757c478bd9Sstevel@tonic-gate
23767c478bd9Sstevel@tonic-gate rc_notify_pool = uu_list_pool_create("rc_notify_pool",
23777c478bd9Sstevel@tonic-gate sizeof (rc_notify_t), offsetof(rc_notify_t, rcn_list_node),
23787c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate rc_notify_info_pool = uu_list_pool_create("rc_notify_info_pool",
23817c478bd9Sstevel@tonic-gate sizeof (rc_notify_info_t),
23827c478bd9Sstevel@tonic-gate offsetof(rc_notify_info_t, rni_list_node),
23837c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23847c478bd9Sstevel@tonic-gate
23857c478bd9Sstevel@tonic-gate if (rc_children_pool == NULL || rc_pg_notify_pool == NULL ||
23867c478bd9Sstevel@tonic-gate rc_notify_pool == NULL || rc_notify_info_pool == NULL)
23877c478bd9Sstevel@tonic-gate uu_die("out of memory");
23887c478bd9Sstevel@tonic-gate
23897c478bd9Sstevel@tonic-gate rc_notify_list = uu_list_create(rc_notify_pool,
23907c478bd9Sstevel@tonic-gate &rc_notify_list, 0);
23917c478bd9Sstevel@tonic-gate
23927c478bd9Sstevel@tonic-gate rc_notify_info_list = uu_list_create(rc_notify_info_pool,
23937c478bd9Sstevel@tonic-gate &rc_notify_info_list, 0);
23947c478bd9Sstevel@tonic-gate
23957c478bd9Sstevel@tonic-gate if (rc_notify_list == NULL || rc_notify_info_list == NULL)
23967c478bd9Sstevel@tonic-gate uu_die("out of memory");
23977c478bd9Sstevel@tonic-gate
23985b7f77adStw21770 /*
23995b7f77adStw21770 * Sort the special_props_list array so that it can be searched
24005b7f77adStw21770 * with bsearch(3C).
24015b7f77adStw21770 *
24025b7f77adStw21770 * The special_props_list array is not compiled into the native
24035b7f77adStw21770 * build code, so there is no need to call qsort if NATIVE_BUILD is
24045b7f77adStw21770 * defined.
24055b7f77adStw21770 */
24065b7f77adStw21770 #ifndef NATIVE_BUILD
24075b7f77adStw21770 qsort(special_props_list, SPECIAL_PROP_COUNT,
24085b7f77adStw21770 sizeof (special_props_list[0]), special_prop_compare);
24095b7f77adStw21770 #endif /* NATIVE_BUILD */
24105b7f77adStw21770
24117c478bd9Sstevel@tonic-gate if ((np = rc_node_alloc()) == NULL)
24127c478bd9Sstevel@tonic-gate uu_die("out of memory");
24137c478bd9Sstevel@tonic-gate
24147c478bd9Sstevel@tonic-gate rc_node_hold(np);
24157c478bd9Sstevel@tonic-gate np->rn_id.rl_type = REP_PROTOCOL_ENTITY_SCOPE;
24167c478bd9Sstevel@tonic-gate np->rn_id.rl_backend = BACKEND_TYPE_NORMAL;
24177c478bd9Sstevel@tonic-gate np->rn_hash = rc_node_hash(&np->rn_id);
24187c478bd9Sstevel@tonic-gate np->rn_name = "localhost";
24197c478bd9Sstevel@tonic-gate
24207c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
24217c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np);
24227c478bd9Sstevel@tonic-gate cache_release(bp);
24237c478bd9Sstevel@tonic-gate
24247c478bd9Sstevel@tonic-gate rc_scope = np;
24257c478bd9Sstevel@tonic-gate return (1);
24267c478bd9Sstevel@tonic-gate }
24277c478bd9Sstevel@tonic-gate
24287c478bd9Sstevel@tonic-gate /*
24297c478bd9Sstevel@tonic-gate * Fails with
24307c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
24317c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
24327c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted
24337c478bd9Sstevel@tonic-gate * _NO_RESOURCES
24347c478bd9Sstevel@tonic-gate */
24357c478bd9Sstevel@tonic-gate static int
rc_node_fill_children(rc_node_t * np,uint32_t type)24367c478bd9Sstevel@tonic-gate rc_node_fill_children(rc_node_t *np, uint32_t type)
24377c478bd9Sstevel@tonic-gate {
24387c478bd9Sstevel@tonic-gate int rc;
24397c478bd9Sstevel@tonic-gate
24407c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
24417c478bd9Sstevel@tonic-gate
24427c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
24437c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
24447c478bd9Sstevel@tonic-gate return (rc);
24457c478bd9Sstevel@tonic-gate
24467c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_CHILDREN_CHANGING))
24477c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
24487c478bd9Sstevel@tonic-gate
24497c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_HAS_CHILDREN) {
24507c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
24517c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
24527c478bd9Sstevel@tonic-gate }
24537c478bd9Sstevel@tonic-gate
24547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
24557c478bd9Sstevel@tonic-gate rc = object_fill_children(np);
24567c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
24577c478bd9Sstevel@tonic-gate
24587c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
24597c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_HAS_CHILDREN;
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
24627c478bd9Sstevel@tonic-gate
24637c478bd9Sstevel@tonic-gate return (rc);
24647c478bd9Sstevel@tonic-gate }
24657c478bd9Sstevel@tonic-gate
24667c478bd9Sstevel@tonic-gate /*
24677c478bd9Sstevel@tonic-gate * Returns
24687c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
24697c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
24707c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted
24717c478bd9Sstevel@tonic-gate * _NO_RESOURCES
24727c478bd9Sstevel@tonic-gate * _SUCCESS - if *cpp is not NULL, it is held
24737c478bd9Sstevel@tonic-gate */
24747c478bd9Sstevel@tonic-gate static int
rc_node_find_named_child(rc_node_t * np,const char * name,uint32_t type,rc_node_t ** cpp)24757c478bd9Sstevel@tonic-gate rc_node_find_named_child(rc_node_t *np, const char *name, uint32_t type,
24767c478bd9Sstevel@tonic-gate rc_node_t **cpp)
24777c478bd9Sstevel@tonic-gate {
24787c478bd9Sstevel@tonic-gate int ret;
24797c478bd9Sstevel@tonic-gate rc_node_t *cp;
24807c478bd9Sstevel@tonic-gate
24817c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
24827c478bd9Sstevel@tonic-gate assert(np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP);
24837c478bd9Sstevel@tonic-gate
24847c478bd9Sstevel@tonic-gate ret = rc_node_fill_children(np, type);
24857c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS)
24867c478bd9Sstevel@tonic-gate return (ret);
24877c478bd9Sstevel@tonic-gate
24887c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children);
24897c478bd9Sstevel@tonic-gate cp != NULL;
24907c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
24917c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type == type && strcmp(cp->rn_name, name) == 0)
24927c478bd9Sstevel@tonic-gate break;
24937c478bd9Sstevel@tonic-gate }
24947c478bd9Sstevel@tonic-gate
24957c478bd9Sstevel@tonic-gate if (cp != NULL)
24967c478bd9Sstevel@tonic-gate rc_node_hold(cp);
24977c478bd9Sstevel@tonic-gate *cpp = cp;
24987c478bd9Sstevel@tonic-gate
24997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
25007c478bd9Sstevel@tonic-gate }
25017c478bd9Sstevel@tonic-gate
25027c478bd9Sstevel@tonic-gate static int rc_node_parent(rc_node_t *, rc_node_t **);
25037c478bd9Sstevel@tonic-gate
25047c478bd9Sstevel@tonic-gate /*
25053eae19d9Swesolows * Returns
25063eae19d9Swesolows * _INVALID_TYPE - type is invalid
25073eae19d9Swesolows * _DELETED - np or an ancestor has been deleted
25083eae19d9Swesolows * _NOT_FOUND - no ancestor of specified type exists
25093eae19d9Swesolows * _SUCCESS - *app is held
25103eae19d9Swesolows */
25113eae19d9Swesolows static int
rc_node_find_ancestor(rc_node_t * np,uint32_t type,rc_node_t ** app)25123eae19d9Swesolows rc_node_find_ancestor(rc_node_t *np, uint32_t type, rc_node_t **app)
25133eae19d9Swesolows {
25143eae19d9Swesolows int ret;
25153eae19d9Swesolows rc_node_t *parent, *np_orig;
25163eae19d9Swesolows
25173eae19d9Swesolows if (type >= REP_PROTOCOL_ENTITY_MAX)
25183eae19d9Swesolows return (REP_PROTOCOL_FAIL_INVALID_TYPE);
25193eae19d9Swesolows
25203eae19d9Swesolows np_orig = np;
25213eae19d9Swesolows
25223eae19d9Swesolows while (np->rn_id.rl_type > type) {
25233eae19d9Swesolows ret = rc_node_parent(np, &parent);
25243eae19d9Swesolows if (np != np_orig)
25253eae19d9Swesolows rc_node_rele(np);
25263eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS)
25273eae19d9Swesolows return (ret);
25283eae19d9Swesolows np = parent;
25293eae19d9Swesolows }
25303eae19d9Swesolows
25313eae19d9Swesolows if (np->rn_id.rl_type == type) {
25323eae19d9Swesolows *app = parent;
25333eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
25343eae19d9Swesolows }
25353eae19d9Swesolows
25363eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
25373eae19d9Swesolows }
25383eae19d9Swesolows
25393eae19d9Swesolows #ifndef NATIVE_BUILD
25403eae19d9Swesolows /*
25417c478bd9Sstevel@tonic-gate * If the propname property exists in pg, and it is of type string, add its
25427c478bd9Sstevel@tonic-gate * values as authorizations to pcp. pg must not be locked on entry, and it is
25437c478bd9Sstevel@tonic-gate * returned unlocked. Returns
25447c478bd9Sstevel@tonic-gate * _DELETED - pg was deleted
25457c478bd9Sstevel@tonic-gate * _NO_RESOURCES
25467c478bd9Sstevel@tonic-gate * _NOT_FOUND - pg has no property named propname
25477c478bd9Sstevel@tonic-gate * _SUCCESS
25487c478bd9Sstevel@tonic-gate */
25497c478bd9Sstevel@tonic-gate static int
perm_add_pg_prop_values(permcheck_t * pcp,rc_node_t * pg,const char * propname)25507c478bd9Sstevel@tonic-gate perm_add_pg_prop_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate rc_node_t *prop;
25537c478bd9Sstevel@tonic-gate int result;
25547c478bd9Sstevel@tonic-gate
25557c478bd9Sstevel@tonic-gate uint_t count;
25567c478bd9Sstevel@tonic-gate const char *cp;
25577c478bd9Sstevel@tonic-gate
25587c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock));
25597c478bd9Sstevel@tonic-gate assert(pg->rn_id.rl_type == REP_PROTOCOL_ENTITY_PROPERTYGRP);
25607c478bd9Sstevel@tonic-gate
25617c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock);
25627c478bd9Sstevel@tonic-gate result = rc_node_find_named_child(pg, propname,
25637c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop);
25647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock);
25657c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) {
25667c478bd9Sstevel@tonic-gate switch (result) {
25677c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
25687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
25697c478bd9Sstevel@tonic-gate return (result);
25707c478bd9Sstevel@tonic-gate
25717c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_INVALID_TYPE:
25727c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
25737c478bd9Sstevel@tonic-gate default:
25747c478bd9Sstevel@tonic-gate bad_error("rc_node_find_named_child", result);
25757c478bd9Sstevel@tonic-gate }
25767c478bd9Sstevel@tonic-gate }
25777c478bd9Sstevel@tonic-gate
25787c478bd9Sstevel@tonic-gate if (prop == NULL)
25797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
25807c478bd9Sstevel@tonic-gate
25817c478bd9Sstevel@tonic-gate /* rn_valtype is immutable, so no locking. */
25827c478bd9Sstevel@tonic-gate if (prop->rn_valtype != REP_PROTOCOL_TYPE_STRING) {
25837c478bd9Sstevel@tonic-gate rc_node_rele(prop);
25847c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
25857c478bd9Sstevel@tonic-gate }
25867c478bd9Sstevel@tonic-gate
25877c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&prop->rn_lock);
25887c478bd9Sstevel@tonic-gate for (count = prop->rn_values_count, cp = prop->rn_values;
25897c478bd9Sstevel@tonic-gate count > 0;
25907c478bd9Sstevel@tonic-gate --count) {
25915b7f77adStw21770 result = perm_add_enabling_type(pcp, cp,
25925b7f77adStw21770 (pg->rn_id.rl_ids[ID_INSTANCE]) ? PC_AUTH_INST :
25935b7f77adStw21770 PC_AUTH_SVC);
25947c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS)
25957c478bd9Sstevel@tonic-gate break;
25967c478bd9Sstevel@tonic-gate
25977c478bd9Sstevel@tonic-gate cp = strchr(cp, '\0') + 1;
25987c478bd9Sstevel@tonic-gate }
25997c478bd9Sstevel@tonic-gate
26007c478bd9Sstevel@tonic-gate rc_node_rele_locked(prop);
26017c478bd9Sstevel@tonic-gate
26027c478bd9Sstevel@tonic-gate return (result);
26037c478bd9Sstevel@tonic-gate }
26047c478bd9Sstevel@tonic-gate
26057c478bd9Sstevel@tonic-gate /*
26067c478bd9Sstevel@tonic-gate * Assuming that ent is a service or instance node, if the pgname property
26077c478bd9Sstevel@tonic-gate * group has type pgtype, and it has a propname property with string type, add
26087c478bd9Sstevel@tonic-gate * its values as authorizations to pcp. If pgtype is NULL, it is not checked.
26097c478bd9Sstevel@tonic-gate * Returns
26107c478bd9Sstevel@tonic-gate * _SUCCESS
26117c478bd9Sstevel@tonic-gate * _DELETED - ent was deleted
26127c478bd9Sstevel@tonic-gate * _NO_RESOURCES - no resources
26137c478bd9Sstevel@tonic-gate * _NOT_FOUND - ent does not have pgname pg or propname property
26147c478bd9Sstevel@tonic-gate */
26157c478bd9Sstevel@tonic-gate static int
perm_add_ent_prop_values(permcheck_t * pcp,rc_node_t * ent,const char * pgname,const char * pgtype,const char * propname)26167c478bd9Sstevel@tonic-gate perm_add_ent_prop_values(permcheck_t *pcp, rc_node_t *ent, const char *pgname,
26177c478bd9Sstevel@tonic-gate const char *pgtype, const char *propname)
26187c478bd9Sstevel@tonic-gate {
26197c478bd9Sstevel@tonic-gate int r;
26207c478bd9Sstevel@tonic-gate rc_node_t *pg;
26217c478bd9Sstevel@tonic-gate
26227c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&ent->rn_lock));
26237c478bd9Sstevel@tonic-gate
26247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
26257c478bd9Sstevel@tonic-gate r = rc_node_find_named_child(ent, pgname,
26267c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
26277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
26287c478bd9Sstevel@tonic-gate
26297c478bd9Sstevel@tonic-gate switch (r) {
26307c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
26317c478bd9Sstevel@tonic-gate break;
26327c478bd9Sstevel@tonic-gate
26337c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
26347c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
26357c478bd9Sstevel@tonic-gate return (r);
26367c478bd9Sstevel@tonic-gate
26377c478bd9Sstevel@tonic-gate default:
26387c478bd9Sstevel@tonic-gate bad_error("rc_node_find_named_child", r);
26397c478bd9Sstevel@tonic-gate }
26407c478bd9Sstevel@tonic-gate
26417c478bd9Sstevel@tonic-gate if (pg == NULL)
26427c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
26437c478bd9Sstevel@tonic-gate
26447c478bd9Sstevel@tonic-gate if (pgtype == NULL || strcmp(pg->rn_type, pgtype) == 0) {
26457c478bd9Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname);
26467c478bd9Sstevel@tonic-gate switch (r) {
26477c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
26487c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_FAIL_NOT_FOUND;
26497c478bd9Sstevel@tonic-gate break;
26507c478bd9Sstevel@tonic-gate
26517c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
26527c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
26537c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NOT_FOUND:
26547c478bd9Sstevel@tonic-gate break;
26557c478bd9Sstevel@tonic-gate
26567c478bd9Sstevel@tonic-gate default:
26577c478bd9Sstevel@tonic-gate bad_error("perm_add_pg_prop_values", r);
26587c478bd9Sstevel@tonic-gate }
26597c478bd9Sstevel@tonic-gate }
26607c478bd9Sstevel@tonic-gate
26617c478bd9Sstevel@tonic-gate rc_node_rele(pg);
26627c478bd9Sstevel@tonic-gate
26637c478bd9Sstevel@tonic-gate return (r);
26647c478bd9Sstevel@tonic-gate }
26657c478bd9Sstevel@tonic-gate
26667c478bd9Sstevel@tonic-gate /*
26673eae19d9Swesolows * If pg has a property named propname, and is string typed, add its values as
26687c478bd9Sstevel@tonic-gate * authorizations to pcp. If pg has no such property, and its parent is an
26697c478bd9Sstevel@tonic-gate * instance, walk up to the service and try doing the same with the property
26707c478bd9Sstevel@tonic-gate * of the same name from the property group of the same name. Returns
26717c478bd9Sstevel@tonic-gate * _SUCCESS
26727c478bd9Sstevel@tonic-gate * _NO_RESOURCES
26737c478bd9Sstevel@tonic-gate * _DELETED - pg (or an ancestor) was deleted
26747c478bd9Sstevel@tonic-gate */
26757c478bd9Sstevel@tonic-gate static int
perm_add_enabling_values(permcheck_t * pcp,rc_node_t * pg,const char * propname)26767c478bd9Sstevel@tonic-gate perm_add_enabling_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
26777c478bd9Sstevel@tonic-gate {
26787c478bd9Sstevel@tonic-gate int r;
26793eae19d9Swesolows char pgname[REP_PROTOCOL_NAME_LEN + 1];
26803eae19d9Swesolows rc_node_t *svc;
26813eae19d9Swesolows size_t sz;
26827c478bd9Sstevel@tonic-gate
26837c478bd9Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname);
26847c478bd9Sstevel@tonic-gate
26853eae19d9Swesolows if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
26863eae19d9Swesolows return (r);
26877c478bd9Sstevel@tonic-gate
26887c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock));
26897c478bd9Sstevel@tonic-gate
26903eae19d9Swesolows if (pg->rn_id.rl_ids[ID_INSTANCE] == 0)
26917c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
26927c478bd9Sstevel@tonic-gate
26937c478bd9Sstevel@tonic-gate sz = strlcpy(pgname, pg->rn_name, sizeof (pgname));
26947c478bd9Sstevel@tonic-gate assert(sz < sizeof (pgname));
26957c478bd9Sstevel@tonic-gate
26963eae19d9Swesolows /*
26973eae19d9Swesolows * If pg is a child of an instance or snapshot, we want to compose the
26983eae19d9Swesolows * authorization property with the service's (if it exists). The
26993eae19d9Swesolows * snapshot case applies only to read_authorization. In all other
27003eae19d9Swesolows * cases, the pg's parent will be the instance.
27013eae19d9Swesolows */
27023eae19d9Swesolows r = rc_node_find_ancestor(pg, REP_PROTOCOL_ENTITY_SERVICE, &svc);
27037c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) {
27047c478bd9Sstevel@tonic-gate assert(r == REP_PROTOCOL_FAIL_DELETED);
27057c478bd9Sstevel@tonic-gate return (r);
27067c478bd9Sstevel@tonic-gate }
27077c478bd9Sstevel@tonic-gate assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
27087c478bd9Sstevel@tonic-gate
27097c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname);
27107c478bd9Sstevel@tonic-gate
27117c478bd9Sstevel@tonic-gate rc_node_rele(svc);
27127c478bd9Sstevel@tonic-gate
27137c478bd9Sstevel@tonic-gate if (r == REP_PROTOCOL_FAIL_NOT_FOUND)
27147c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_SUCCESS;
27157c478bd9Sstevel@tonic-gate
27167c478bd9Sstevel@tonic-gate return (r);
27177c478bd9Sstevel@tonic-gate }
27187c478bd9Sstevel@tonic-gate
27197c478bd9Sstevel@tonic-gate /*
27207c478bd9Sstevel@tonic-gate * Call perm_add_enabling_values() for the "action_authorization" property of
27217c478bd9Sstevel@tonic-gate * the "general" property group of inst. Returns
27227c478bd9Sstevel@tonic-gate * _DELETED - inst (or an ancestor) was deleted
27237c478bd9Sstevel@tonic-gate * _NO_RESOURCES
27247c478bd9Sstevel@tonic-gate * _SUCCESS
27257c478bd9Sstevel@tonic-gate */
27267c478bd9Sstevel@tonic-gate static int
perm_add_inst_action_auth(permcheck_t * pcp,rc_node_t * inst)27277c478bd9Sstevel@tonic-gate perm_add_inst_action_auth(permcheck_t *pcp, rc_node_t *inst)
27287c478bd9Sstevel@tonic-gate {
27297c478bd9Sstevel@tonic-gate int r;
27307c478bd9Sstevel@tonic-gate rc_node_t *svc;
27317c478bd9Sstevel@tonic-gate
27327c478bd9Sstevel@tonic-gate assert(inst->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, inst, AUTH_PG_GENERAL,
27357c478bd9Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
27367c478bd9Sstevel@tonic-gate
27377c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
27387c478bd9Sstevel@tonic-gate return (r);
27397c478bd9Sstevel@tonic-gate
27407c478bd9Sstevel@tonic-gate r = rc_node_parent(inst, &svc);
27417c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) {
27427c478bd9Sstevel@tonic-gate assert(r == REP_PROTOCOL_FAIL_DELETED);
27437c478bd9Sstevel@tonic-gate return (r);
27447c478bd9Sstevel@tonic-gate }
27457c478bd9Sstevel@tonic-gate
27467c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, svc, AUTH_PG_GENERAL,
27477c478bd9Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
27487c478bd9Sstevel@tonic-gate
27497c478bd9Sstevel@tonic-gate return (r == REP_PROTOCOL_FAIL_NOT_FOUND ? REP_PROTOCOL_SUCCESS : r);
27507c478bd9Sstevel@tonic-gate }
27517c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
27527c478bd9Sstevel@tonic-gate
27537c478bd9Sstevel@tonic-gate void
rc_node_ptr_init(rc_node_ptr_t * out)27547c478bd9Sstevel@tonic-gate rc_node_ptr_init(rc_node_ptr_t *out)
27557c478bd9Sstevel@tonic-gate {
27567c478bd9Sstevel@tonic-gate out->rnp_node = NULL;
27575b7f77adStw21770 out->rnp_auth_string = NULL;
27585b7f77adStw21770 out->rnp_authorized = RC_AUTH_UNKNOWN;
27597c478bd9Sstevel@tonic-gate out->rnp_deleted = 0;
27607c478bd9Sstevel@tonic-gate }
27617c478bd9Sstevel@tonic-gate
27625b7f77adStw21770 void
rc_node_ptr_free_mem(rc_node_ptr_t * npp)27635b7f77adStw21770 rc_node_ptr_free_mem(rc_node_ptr_t *npp)
27645b7f77adStw21770 {
27655b7f77adStw21770 if (npp->rnp_auth_string != NULL) {
27665b7f77adStw21770 free((void *)npp->rnp_auth_string);
27675b7f77adStw21770 npp->rnp_auth_string = NULL;
27685b7f77adStw21770 }
27695b7f77adStw21770 }
27705b7f77adStw21770
27717c478bd9Sstevel@tonic-gate static void
rc_node_assign(rc_node_ptr_t * out,rc_node_t * val)27727c478bd9Sstevel@tonic-gate rc_node_assign(rc_node_ptr_t *out, rc_node_t *val)
27737c478bd9Sstevel@tonic-gate {
27747c478bd9Sstevel@tonic-gate rc_node_t *cur = out->rnp_node;
27757c478bd9Sstevel@tonic-gate if (val != NULL)
27767c478bd9Sstevel@tonic-gate rc_node_hold(val);
27777c478bd9Sstevel@tonic-gate out->rnp_node = val;
27786643e1ffSbustos if (cur != NULL) {
27796643e1ffSbustos NODE_LOCK(cur);
27806643e1ffSbustos
27816643e1ffSbustos /*
27826643e1ffSbustos * Register the ephemeral reference created by reading
27836643e1ffSbustos * out->rnp_node into cur. Note that the persistent
27846643e1ffSbustos * reference we're destroying is locked by the client
27856643e1ffSbustos * layer.
27866643e1ffSbustos */
27876643e1ffSbustos rc_node_hold_ephemeral_locked(cur);
27886643e1ffSbustos
27896643e1ffSbustos rc_node_rele_locked(cur);
27906643e1ffSbustos }
27915b7f77adStw21770 out->rnp_authorized = RC_AUTH_UNKNOWN;
27925b7f77adStw21770 rc_node_ptr_free_mem(out);
27937c478bd9Sstevel@tonic-gate out->rnp_deleted = 0;
27947c478bd9Sstevel@tonic-gate }
27957c478bd9Sstevel@tonic-gate
27967c478bd9Sstevel@tonic-gate void
rc_node_clear(rc_node_ptr_t * out,int deleted)27977c478bd9Sstevel@tonic-gate rc_node_clear(rc_node_ptr_t *out, int deleted)
27987c478bd9Sstevel@tonic-gate {
27997c478bd9Sstevel@tonic-gate rc_node_assign(out, NULL);
28007c478bd9Sstevel@tonic-gate out->rnp_deleted = deleted;
28017c478bd9Sstevel@tonic-gate }
28027c478bd9Sstevel@tonic-gate
28037c478bd9Sstevel@tonic-gate void
rc_node_ptr_assign(rc_node_ptr_t * out,const rc_node_ptr_t * val)28047c478bd9Sstevel@tonic-gate rc_node_ptr_assign(rc_node_ptr_t *out, const rc_node_ptr_t *val)
28057c478bd9Sstevel@tonic-gate {
28067c478bd9Sstevel@tonic-gate rc_node_assign(out, val->rnp_node);
28077c478bd9Sstevel@tonic-gate }
28087c478bd9Sstevel@tonic-gate
28097c478bd9Sstevel@tonic-gate /*
28107c478bd9Sstevel@tonic-gate * rc_node_check()/RC_NODE_CHECK()
28117c478bd9Sstevel@tonic-gate * generic "entry" checks, run before the use of an rc_node pointer.
28127c478bd9Sstevel@tonic-gate *
28137c478bd9Sstevel@tonic-gate * Fails with
28147c478bd9Sstevel@tonic-gate * _NOT_SET
28157c478bd9Sstevel@tonic-gate * _DELETED
28167c478bd9Sstevel@tonic-gate */
28177c478bd9Sstevel@tonic-gate static int
rc_node_check_and_lock(rc_node_t * np)28187c478bd9Sstevel@tonic-gate rc_node_check_and_lock(rc_node_t *np)
28197c478bd9Sstevel@tonic-gate {
28207c478bd9Sstevel@tonic-gate int result = REP_PROTOCOL_SUCCESS;
28217c478bd9Sstevel@tonic-gate if (np == NULL)
28227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET);
28237c478bd9Sstevel@tonic-gate
28247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
28257c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
28267c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_DELETED;
28277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
28287c478bd9Sstevel@tonic-gate }
28297c478bd9Sstevel@tonic-gate
28307c478bd9Sstevel@tonic-gate return (result);
28317c478bd9Sstevel@tonic-gate }
28327c478bd9Sstevel@tonic-gate
28337c478bd9Sstevel@tonic-gate /*
28347c478bd9Sstevel@tonic-gate * Fails with
28357c478bd9Sstevel@tonic-gate * _NOT_SET - ptr is reset
28367c478bd9Sstevel@tonic-gate * _DELETED - node has been deleted
28377c478bd9Sstevel@tonic-gate */
28387c478bd9Sstevel@tonic-gate static rc_node_t *
rc_node_ptr_check_and_lock(rc_node_ptr_t * npp,int * res)28397c478bd9Sstevel@tonic-gate rc_node_ptr_check_and_lock(rc_node_ptr_t *npp, int *res)
28407c478bd9Sstevel@tonic-gate {
28417c478bd9Sstevel@tonic-gate rc_node_t *np = npp->rnp_node;
28427c478bd9Sstevel@tonic-gate if (np == NULL) {
28437c478bd9Sstevel@tonic-gate if (npp->rnp_deleted)
28447c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED;
28457c478bd9Sstevel@tonic-gate else
28467c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_NOT_SET;
28477c478bd9Sstevel@tonic-gate return (NULL);
28487c478bd9Sstevel@tonic-gate }
28497c478bd9Sstevel@tonic-gate
28507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
28517c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
28527c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
28537c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
28547c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED;
28557c478bd9Sstevel@tonic-gate return (NULL);
28567c478bd9Sstevel@tonic-gate }
28577c478bd9Sstevel@tonic-gate return (np);
28587c478bd9Sstevel@tonic-gate }
28597c478bd9Sstevel@tonic-gate
28607c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK_AND_LOCK(n) { \
28617c478bd9Sstevel@tonic-gate int rc__res; \
28627c478bd9Sstevel@tonic-gate if ((rc__res = rc_node_check_and_lock(n)) != REP_PROTOCOL_SUCCESS) \
28637c478bd9Sstevel@tonic-gate return (rc__res); \
28647c478bd9Sstevel@tonic-gate }
28657c478bd9Sstevel@tonic-gate
28667c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK(n) { \
28677c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \
28687c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \
28697c478bd9Sstevel@tonic-gate }
28707c478bd9Sstevel@tonic-gate
28717c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK_AND_HOLD(n) { \
28727c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \
28737c478bd9Sstevel@tonic-gate rc_node_hold_locked(n); \
28747c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \
28757c478bd9Sstevel@tonic-gate }
28767c478bd9Sstevel@tonic-gate
28777c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp) { \
28787c478bd9Sstevel@tonic-gate int rc__res; \
28797c478bd9Sstevel@tonic-gate if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == NULL) \
28807c478bd9Sstevel@tonic-gate return (rc__res); \
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate
2883a4dc1477STom Whitten #define RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, mem) { \
2884a4dc1477STom Whitten int rc__res; \
2885a4dc1477STom Whitten if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == \
2886a4dc1477STom Whitten NULL) { \
2887a4dc1477STom Whitten if ((mem) != NULL) \
2888a4dc1477STom Whitten free((mem)); \
2889a4dc1477STom Whitten return (rc__res); \
2890a4dc1477STom Whitten } \
2891a4dc1477STom Whitten }
2892a4dc1477STom Whitten
28937c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK(np, npp) { \
28947c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \
28957c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
28967c478bd9Sstevel@tonic-gate }
28977c478bd9Sstevel@tonic-gate
28987c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp) { \
28997c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \
29007c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); \
29017c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
29027c478bd9Sstevel@tonic-gate }
29037c478bd9Sstevel@tonic-gate
29047c478bd9Sstevel@tonic-gate #define HOLD_FLAG_OR_RETURN(np, flag) { \
29057c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&(np)->rn_lock)); \
29067c478bd9Sstevel@tonic-gate assert(!((np)->rn_flags & RC_NODE_DEAD)); \
29077c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag((np), flag)) { \
29087c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
29097c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); \
29107c478bd9Sstevel@tonic-gate } \
29117c478bd9Sstevel@tonic-gate }
29127c478bd9Sstevel@tonic-gate
29135b7f77adStw21770 #define HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, flag, mem) { \
29145b7f77adStw21770 assert(MUTEX_HELD(&(np)->rn_lock)); \
29155b7f77adStw21770 if (!rc_node_hold_flag((np), flag)) { \
29165b7f77adStw21770 (void) pthread_mutex_unlock(&(np)->rn_lock); \
29175b7f77adStw21770 assert((np) == (npp)->rnp_node); \
29185b7f77adStw21770 rc_node_clear(npp, 1); \
29195b7f77adStw21770 if ((mem) != NULL) \
29205b7f77adStw21770 free((mem)); \
29215b7f77adStw21770 return (REP_PROTOCOL_FAIL_DELETED); \
29225b7f77adStw21770 } \
29235b7f77adStw21770 }
29245b7f77adStw21770
29257c478bd9Sstevel@tonic-gate int
rc_local_scope(uint32_t type,rc_node_ptr_t * out)29267c478bd9Sstevel@tonic-gate rc_local_scope(uint32_t type, rc_node_ptr_t *out)
29277c478bd9Sstevel@tonic-gate {
29287c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE) {
29297c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
29307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
29317c478bd9Sstevel@tonic-gate }
29327c478bd9Sstevel@tonic-gate
29337c478bd9Sstevel@tonic-gate /*
29347c478bd9Sstevel@tonic-gate * the main scope never gets destroyed
29357c478bd9Sstevel@tonic-gate */
29367c478bd9Sstevel@tonic-gate rc_node_assign(out, rc_scope);
29377c478bd9Sstevel@tonic-gate
29387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
29397c478bd9Sstevel@tonic-gate }
29407c478bd9Sstevel@tonic-gate
29417c478bd9Sstevel@tonic-gate /*
29427c478bd9Sstevel@tonic-gate * Fails with
29437c478bd9Sstevel@tonic-gate * _NOT_SET - npp is not set
29447c478bd9Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted
29457c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - type is not _SCOPE
29467c478bd9Sstevel@tonic-gate * _NOT_FOUND - scope has no parent
29477c478bd9Sstevel@tonic-gate */
29487c478bd9Sstevel@tonic-gate static int
rc_scope_parent_scope(rc_node_ptr_t * npp,uint32_t type,rc_node_ptr_t * out)29497c478bd9Sstevel@tonic-gate rc_scope_parent_scope(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
29507c478bd9Sstevel@tonic-gate {
29517c478bd9Sstevel@tonic-gate rc_node_t *np;
29527c478bd9Sstevel@tonic-gate
29537c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
29547c478bd9Sstevel@tonic-gate
29557c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
29567c478bd9Sstevel@tonic-gate
29577c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE)
29587c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
29597c478bd9Sstevel@tonic-gate
29607c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
29617c478bd9Sstevel@tonic-gate }
29627c478bd9Sstevel@tonic-gate
29633eae19d9Swesolows static int rc_node_pg_check_read_protect(rc_node_t *);
29643eae19d9Swesolows
29657c478bd9Sstevel@tonic-gate /*
29667c478bd9Sstevel@tonic-gate * Fails with
29677c478bd9Sstevel@tonic-gate * _NOT_SET
29687c478bd9Sstevel@tonic-gate * _DELETED
29697c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE
29707c478bd9Sstevel@tonic-gate * _NOT_FOUND
29717c478bd9Sstevel@tonic-gate * _BAD_REQUEST
29727c478bd9Sstevel@tonic-gate * _TRUNCATED
29733eae19d9Swesolows * _NO_RESOURCES
29747c478bd9Sstevel@tonic-gate */
29757c478bd9Sstevel@tonic-gate int
rc_node_name(rc_node_ptr_t * npp,char * buf,size_t sz,uint32_t answertype,size_t * sz_out)29767c478bd9Sstevel@tonic-gate rc_node_name(rc_node_ptr_t *npp, char *buf, size_t sz, uint32_t answertype,
29777c478bd9Sstevel@tonic-gate size_t *sz_out)
29787c478bd9Sstevel@tonic-gate {
29797c478bd9Sstevel@tonic-gate size_t actual;
29807c478bd9Sstevel@tonic-gate rc_node_t *np;
29817c478bd9Sstevel@tonic-gate
29827c478bd9Sstevel@tonic-gate assert(sz == *sz_out);
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
29857c478bd9Sstevel@tonic-gate
29867c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
29877c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
29887c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np);
29897c478bd9Sstevel@tonic-gate }
29907c478bd9Sstevel@tonic-gate
29917c478bd9Sstevel@tonic-gate switch (answertype) {
29927c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_NAME:
29937c478bd9Sstevel@tonic-gate if (np->rn_name == NULL)
29947c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
29957c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_name, sz);
29967c478bd9Sstevel@tonic-gate break;
29977c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_PGTYPE:
29987c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
29997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30007c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_type, sz);
30017c478bd9Sstevel@tonic-gate break;
30027c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_PGFLAGS:
30037c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
30047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30057c478bd9Sstevel@tonic-gate actual = snprintf(buf, sz, "%d", np->rn_pgflags);
30067c478bd9Sstevel@tonic-gate break;
30077c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SCOPE:
30087c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30097c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30107c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_scope, sz);
30117c478bd9Sstevel@tonic-gate break;
30127c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SERVICE:
30137c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30157c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_service, sz);
30167c478bd9Sstevel@tonic-gate break;
30177c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_INSTANCE:
30187c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30197c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30207c478bd9Sstevel@tonic-gate if (np->rn_snaplevel->rsl_instance == NULL)
30217c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
30227c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_instance, sz);
30237c478bd9Sstevel@tonic-gate break;
30243eae19d9Swesolows case RP_ENTITY_NAME_PGREADPROT:
30253eae19d9Swesolows {
30263eae19d9Swesolows int ret;
30273eae19d9Swesolows
30283eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
30293eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30303eae19d9Swesolows ret = rc_node_pg_check_read_protect(np);
30313eae19d9Swesolows assert(ret != REP_PROTOCOL_FAIL_TYPE_MISMATCH);
30323eae19d9Swesolows switch (ret) {
30333eae19d9Swesolows case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
30343eae19d9Swesolows actual = snprintf(buf, sz, "1");
30353eae19d9Swesolows break;
30363eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
30373eae19d9Swesolows actual = snprintf(buf, sz, "0");
30383eae19d9Swesolows break;
30393eae19d9Swesolows default:
30403eae19d9Swesolows return (ret);
30413eae19d9Swesolows }
30423eae19d9Swesolows break;
30433eae19d9Swesolows }
30447c478bd9Sstevel@tonic-gate default:
30457c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
30467c478bd9Sstevel@tonic-gate }
30477c478bd9Sstevel@tonic-gate if (actual >= sz)
30487c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TRUNCATED);
30497c478bd9Sstevel@tonic-gate
30507c478bd9Sstevel@tonic-gate *sz_out = actual;
30517c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
30527c478bd9Sstevel@tonic-gate }
30537c478bd9Sstevel@tonic-gate
30547c478bd9Sstevel@tonic-gate int
rc_node_get_property_type(rc_node_ptr_t * npp,rep_protocol_value_type_t * out)30557c478bd9Sstevel@tonic-gate rc_node_get_property_type(rc_node_ptr_t *npp, rep_protocol_value_type_t *out)
30567c478bd9Sstevel@tonic-gate {
30577c478bd9Sstevel@tonic-gate rc_node_t *np;
30587c478bd9Sstevel@tonic-gate
30597c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
30607c478bd9Sstevel@tonic-gate
30617c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
30627c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
30637c478bd9Sstevel@tonic-gate
30647c478bd9Sstevel@tonic-gate *out = np->rn_valtype;
30657c478bd9Sstevel@tonic-gate
30667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
30677c478bd9Sstevel@tonic-gate }
30687c478bd9Sstevel@tonic-gate
30697c478bd9Sstevel@tonic-gate /*
30707c478bd9Sstevel@tonic-gate * Get np's parent. If np is deleted, returns _DELETED. Otherwise puts a hold
30717c478bd9Sstevel@tonic-gate * on the parent, returns a pointer to it in *out, and returns _SUCCESS.
30727c478bd9Sstevel@tonic-gate */
30737c478bd9Sstevel@tonic-gate static int
rc_node_parent(rc_node_t * np,rc_node_t ** out)30747c478bd9Sstevel@tonic-gate rc_node_parent(rc_node_t *np, rc_node_t **out)
30757c478bd9Sstevel@tonic-gate {
30767c478bd9Sstevel@tonic-gate rc_node_t *pnp;
30777c478bd9Sstevel@tonic-gate rc_node_t *np_orig;
30787c478bd9Sstevel@tonic-gate
30797c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
30807c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
30817c478bd9Sstevel@tonic-gate } else {
30827c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
30837c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
30847c478bd9Sstevel@tonic-gate }
30857c478bd9Sstevel@tonic-gate
30867c478bd9Sstevel@tonic-gate np_orig = np;
30877c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */
30887c478bd9Sstevel@tonic-gate
30897c478bd9Sstevel@tonic-gate for (;;) {
30907c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np,
30917c478bd9Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
30927c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
30937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
30947c478bd9Sstevel@tonic-gate }
30957c478bd9Sstevel@tonic-gate
30967c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD))
30977c478bd9Sstevel@tonic-gate break;
30987c478bd9Sstevel@tonic-gate
30997c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
31007c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
31017c478bd9Sstevel@tonic-gate assert(np != np_orig);
31027c478bd9Sstevel@tonic-gate
31037c478bd9Sstevel@tonic-gate if (np == NULL)
31047c478bd9Sstevel@tonic-gate goto deleted;
31057c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
31067c478bd9Sstevel@tonic-gate }
31077c478bd9Sstevel@tonic-gate
31087c478bd9Sstevel@tonic-gate /* guaranteed to succeed without dropping the lock */
31097c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
31107c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31117c478bd9Sstevel@tonic-gate *out = NULL;
31127c478bd9Sstevel@tonic-gate rc_node_rele(np);
31137c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
31147c478bd9Sstevel@tonic-gate }
31157c478bd9Sstevel@tonic-gate
31167c478bd9Sstevel@tonic-gate assert(np->rn_parent != NULL);
31177c478bd9Sstevel@tonic-gate pnp = np->rn_parent;
31187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31197c478bd9Sstevel@tonic-gate
31207c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pnp->rn_lock);
31217c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
31227c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
31237c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31247c478bd9Sstevel@tonic-gate
31257c478bd9Sstevel@tonic-gate rc_node_hold_locked(pnp);
31267c478bd9Sstevel@tonic-gate
31277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pnp->rn_lock);
31287c478bd9Sstevel@tonic-gate
31297c478bd9Sstevel@tonic-gate rc_node_rele(np);
31307c478bd9Sstevel@tonic-gate *out = pnp;
31317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31327c478bd9Sstevel@tonic-gate
31337c478bd9Sstevel@tonic-gate deleted:
31347c478bd9Sstevel@tonic-gate rc_node_rele(np);
31357c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
31367c478bd9Sstevel@tonic-gate }
31377c478bd9Sstevel@tonic-gate
31387c478bd9Sstevel@tonic-gate /*
31397c478bd9Sstevel@tonic-gate * Fails with
31407c478bd9Sstevel@tonic-gate * _NOT_SET
31417c478bd9Sstevel@tonic-gate * _DELETED
31427c478bd9Sstevel@tonic-gate */
31437c478bd9Sstevel@tonic-gate static int
rc_node_ptr_parent(rc_node_ptr_t * npp,rc_node_t ** out)31447c478bd9Sstevel@tonic-gate rc_node_ptr_parent(rc_node_ptr_t *npp, rc_node_t **out)
31457c478bd9Sstevel@tonic-gate {
31467c478bd9Sstevel@tonic-gate rc_node_t *np;
31477c478bd9Sstevel@tonic-gate
31487c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
31497c478bd9Sstevel@tonic-gate
31507c478bd9Sstevel@tonic-gate return (rc_node_parent(np, out));
31517c478bd9Sstevel@tonic-gate }
31527c478bd9Sstevel@tonic-gate
31537c478bd9Sstevel@tonic-gate /*
31547c478bd9Sstevel@tonic-gate * Fails with
31557c478bd9Sstevel@tonic-gate * _NOT_SET - npp is not set
31567c478bd9Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted
31577c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node's parent is not of type type
31587c478bd9Sstevel@tonic-gate *
31597c478bd9Sstevel@tonic-gate * If npp points to a scope, can also fail with
31607c478bd9Sstevel@tonic-gate * _NOT_FOUND - scope has no parent
31617c478bd9Sstevel@tonic-gate */
31627c478bd9Sstevel@tonic-gate int
rc_node_get_parent(rc_node_ptr_t * npp,uint32_t type,rc_node_ptr_t * out)31637c478bd9Sstevel@tonic-gate rc_node_get_parent(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
31647c478bd9Sstevel@tonic-gate {
31657c478bd9Sstevel@tonic-gate rc_node_t *pnp;
31667c478bd9Sstevel@tonic-gate int rc;
31677c478bd9Sstevel@tonic-gate
31687c478bd9Sstevel@tonic-gate if (npp->rnp_node != NULL &&
31697c478bd9Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE)
31707c478bd9Sstevel@tonic-gate return (rc_scope_parent_scope(npp, type, out));
31717c478bd9Sstevel@tonic-gate
31727c478bd9Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS) {
31737c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
31747c478bd9Sstevel@tonic-gate return (rc);
31757c478bd9Sstevel@tonic-gate }
31767c478bd9Sstevel@tonic-gate
31777c478bd9Sstevel@tonic-gate if (type != pnp->rn_id.rl_type) {
31787c478bd9Sstevel@tonic-gate rc_node_rele(pnp);
31797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
31807c478bd9Sstevel@tonic-gate }
31817c478bd9Sstevel@tonic-gate
31827c478bd9Sstevel@tonic-gate rc_node_assign(out, pnp);
31837c478bd9Sstevel@tonic-gate rc_node_rele(pnp);
31847c478bd9Sstevel@tonic-gate
31857c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31867c478bd9Sstevel@tonic-gate }
31877c478bd9Sstevel@tonic-gate
31887c478bd9Sstevel@tonic-gate int
rc_node_parent_type(rc_node_ptr_t * npp,uint32_t * type_out)31897c478bd9Sstevel@tonic-gate rc_node_parent_type(rc_node_ptr_t *npp, uint32_t *type_out)
31907c478bd9Sstevel@tonic-gate {
31917c478bd9Sstevel@tonic-gate rc_node_t *pnp;
31927c478bd9Sstevel@tonic-gate int rc;
31937c478bd9Sstevel@tonic-gate
31947c478bd9Sstevel@tonic-gate if (npp->rnp_node != NULL &&
31957c478bd9Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE) {
31967c478bd9Sstevel@tonic-gate *type_out = REP_PROTOCOL_ENTITY_SCOPE;
31977c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31987c478bd9Sstevel@tonic-gate }
31997c478bd9Sstevel@tonic-gate
32007c478bd9Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS)
32017c478bd9Sstevel@tonic-gate return (rc);
32027c478bd9Sstevel@tonic-gate
32037c478bd9Sstevel@tonic-gate *type_out = pnp->rn_id.rl_type;
32047c478bd9Sstevel@tonic-gate
32057c478bd9Sstevel@tonic-gate rc_node_rele(pnp);
32067c478bd9Sstevel@tonic-gate
32077c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
32087c478bd9Sstevel@tonic-gate }
32097c478bd9Sstevel@tonic-gate
32107c478bd9Sstevel@tonic-gate /*
32117c478bd9Sstevel@tonic-gate * Fails with
32127c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
32137c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
32147c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted
32157c478bd9Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found
32167c478bd9Sstevel@tonic-gate * _NO_RESOURCES
32177c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS
32187c478bd9Sstevel@tonic-gate */
32197c478bd9Sstevel@tonic-gate int
rc_node_get_child(rc_node_ptr_t * npp,const char * name,uint32_t type,rc_node_ptr_t * outp)32207c478bd9Sstevel@tonic-gate rc_node_get_child(rc_node_ptr_t *npp, const char *name, uint32_t type,
32217c478bd9Sstevel@tonic-gate rc_node_ptr_t *outp)
32227c478bd9Sstevel@tonic-gate {
32237c478bd9Sstevel@tonic-gate rc_node_t *np, *cp;
32247c478bd9Sstevel@tonic-gate rc_node_t *child = NULL;
32257c478bd9Sstevel@tonic-gate int ret, idx;
32267c478bd9Sstevel@tonic-gate
32277c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
32287c478bd9Sstevel@tonic-gate if ((ret = rc_check_type_name(type, name)) == REP_PROTOCOL_SUCCESS) {
32297c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
32307c478bd9Sstevel@tonic-gate ret = rc_node_find_named_child(np, name, type, &child);
32317c478bd9Sstevel@tonic-gate } else {
32327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
32337c478bd9Sstevel@tonic-gate ret = REP_PROTOCOL_SUCCESS;
32347c478bd9Sstevel@tonic-gate for (idx = 0; idx < COMPOSITION_DEPTH; idx++) {
32357c478bd9Sstevel@tonic-gate cp = np->rn_cchain[idx];
32367c478bd9Sstevel@tonic-gate if (cp == NULL)
32377c478bd9Sstevel@tonic-gate break;
32387c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(cp);
32397c478bd9Sstevel@tonic-gate ret = rc_node_find_named_child(cp, name, type,
32407c478bd9Sstevel@tonic-gate &child);
32417c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
32427c478bd9Sstevel@tonic-gate /*
32437c478bd9Sstevel@tonic-gate * loop only if we succeeded, but no child of
32447c478bd9Sstevel@tonic-gate * the correct name was found.
32457c478bd9Sstevel@tonic-gate */
32467c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS ||
32477c478bd9Sstevel@tonic-gate child != NULL)
32487c478bd9Sstevel@tonic-gate break;
32497c478bd9Sstevel@tonic-gate }
32507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
32517c478bd9Sstevel@tonic-gate }
32527c478bd9Sstevel@tonic-gate }
32537c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
32547c478bd9Sstevel@tonic-gate
32557c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) {
32567c478bd9Sstevel@tonic-gate rc_node_assign(outp, child);
32577c478bd9Sstevel@tonic-gate if (child != NULL)
32587c478bd9Sstevel@tonic-gate rc_node_rele(child);
32597c478bd9Sstevel@tonic-gate else
32607c478bd9Sstevel@tonic-gate ret = REP_PROTOCOL_FAIL_NOT_FOUND;
32617c478bd9Sstevel@tonic-gate } else {
32627c478bd9Sstevel@tonic-gate rc_node_assign(outp, NULL);
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate return (ret);
32657c478bd9Sstevel@tonic-gate }
32667c478bd9Sstevel@tonic-gate
32677c478bd9Sstevel@tonic-gate int
rc_node_update(rc_node_ptr_t * npp)32687c478bd9Sstevel@tonic-gate rc_node_update(rc_node_ptr_t *npp)
32697c478bd9Sstevel@tonic-gate {
32707c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
32717c478bd9Sstevel@tonic-gate rc_node_t *np = npp->rnp_node;
32727c478bd9Sstevel@tonic-gate rc_node_t *nnp;
32737c478bd9Sstevel@tonic-gate rc_node_t *cpg = NULL;
32747c478bd9Sstevel@tonic-gate
32757c478bd9Sstevel@tonic-gate if (np != NULL &&
32767c478bd9Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
32777c478bd9Sstevel@tonic-gate /*
32787c478bd9Sstevel@tonic-gate * If we're updating a composed property group, actually
32797c478bd9Sstevel@tonic-gate * update the top-level property group & return the
32807c478bd9Sstevel@tonic-gate * appropriate value. But leave *nnp pointing at us.
32817c478bd9Sstevel@tonic-gate */
32827c478bd9Sstevel@tonic-gate cpg = np;
32837c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
32847c478bd9Sstevel@tonic-gate }
32857c478bd9Sstevel@tonic-gate
32867c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np);
32877c478bd9Sstevel@tonic-gate
32887c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP &&
32897c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)
32907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
32917c478bd9Sstevel@tonic-gate
32927c478bd9Sstevel@tonic-gate for (;;) {
32937c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
32947c478bd9Sstevel@tonic-gate nnp = cache_lookup_unlocked(bp, &np->rn_id);
32957c478bd9Sstevel@tonic-gate if (nnp == NULL) {
32967c478bd9Sstevel@tonic-gate cache_release(bp);
32977c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
32987c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
32997c478bd9Sstevel@tonic-gate }
33007c478bd9Sstevel@tonic-gate /*
33017c478bd9Sstevel@tonic-gate * grab the lock before dropping the cache bucket, so
33027c478bd9Sstevel@tonic-gate * that no one else can sneak in
33037c478bd9Sstevel@tonic-gate */
33047c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock);
33057c478bd9Sstevel@tonic-gate cache_release(bp);
33067c478bd9Sstevel@tonic-gate
33077c478bd9Sstevel@tonic-gate if (!(nnp->rn_flags & RC_NODE_IN_TX) ||
33087c478bd9Sstevel@tonic-gate !rc_node_wait_flag(nnp, RC_NODE_IN_TX))
33097c478bd9Sstevel@tonic-gate break;
33107c478bd9Sstevel@tonic-gate
33117c478bd9Sstevel@tonic-gate rc_node_rele_locked(nnp);
33127c478bd9Sstevel@tonic-gate }
33137c478bd9Sstevel@tonic-gate
33147c478bd9Sstevel@tonic-gate /*
33157c478bd9Sstevel@tonic-gate * If it is dead, we want to update it so that it will continue to
33167c478bd9Sstevel@tonic-gate * report being dead.
33177c478bd9Sstevel@tonic-gate */
33187c478bd9Sstevel@tonic-gate if (nnp->rn_flags & RC_NODE_DEAD) {
33197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
33207c478bd9Sstevel@tonic-gate if (nnp != np && cpg == NULL)
33217c478bd9Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */
33227c478bd9Sstevel@tonic-gate rc_node_rele(nnp);
33237c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
33247c478bd9Sstevel@tonic-gate }
33257c478bd9Sstevel@tonic-gate
33267c478bd9Sstevel@tonic-gate assert(!(nnp->rn_flags & RC_NODE_OLD));
33277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
33287c478bd9Sstevel@tonic-gate
33297c478bd9Sstevel@tonic-gate if (nnp != np && cpg == NULL)
33307c478bd9Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */
33317c478bd9Sstevel@tonic-gate
33327c478bd9Sstevel@tonic-gate rc_node_rele(nnp);
33337c478bd9Sstevel@tonic-gate
33347c478bd9Sstevel@tonic-gate return ((nnp == np)? REP_PROTOCOL_SUCCESS : REP_PROTOCOL_DONE);
33357c478bd9Sstevel@tonic-gate }
33367c478bd9Sstevel@tonic-gate
33377c478bd9Sstevel@tonic-gate /*
33387c478bd9Sstevel@tonic-gate * does a generic modification check, for creation, deletion, and snapshot
33397c478bd9Sstevel@tonic-gate * management only. Property group transactions have different checks.
33405b7f77adStw21770 *
33415b7f77adStw21770 * The string returned to *match_auth must be freed.
33427c478bd9Sstevel@tonic-gate */
3343a4dc1477STom Whitten static perm_status_t
rc_node_modify_permission_check(char ** match_auth)33445b7f77adStw21770 rc_node_modify_permission_check(char **match_auth)
33457c478bd9Sstevel@tonic-gate {
33467c478bd9Sstevel@tonic-gate permcheck_t *pcp;
3347a4dc1477STom Whitten perm_status_t granted = PERM_GRANTED;
3348a4dc1477STom Whitten int rc;
33497c478bd9Sstevel@tonic-gate
33505b7f77adStw21770 *match_auth = NULL;
3351273264cdSdm120769 #ifdef NATIVE_BUILD
33525b7f77adStw21770 if (!client_is_privileged()) {
3353a4dc1477STom Whitten granted = PERM_DENIED;
33545b7f77adStw21770 }
3355a4dc1477STom Whitten return (granted);
33567c478bd9Sstevel@tonic-gate #else
33575b7f77adStw21770 if (is_main_repository == 0)
3358a4dc1477STom Whitten return (PERM_GRANTED);
33597c478bd9Sstevel@tonic-gate pcp = pc_create();
33607c478bd9Sstevel@tonic-gate if (pcp != NULL) {
33617c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
33627c478bd9Sstevel@tonic-gate
33637c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
33647c478bd9Sstevel@tonic-gate granted = perm_granted(pcp);
33657c478bd9Sstevel@tonic-gate
3366a4dc1477STom Whitten if ((granted == PERM_GRANTED) ||
3367a4dc1477STom Whitten (granted == PERM_DENIED)) {
33685b7f77adStw21770 /*
33695b7f77adStw21770 * Copy off the authorization
33705b7f77adStw21770 * string before freeing pcp.
33715b7f77adStw21770 */
33725b7f77adStw21770 *match_auth =
33735b7f77adStw21770 strdup(pcp->pc_auth_string);
33745b7f77adStw21770 if (*match_auth == NULL)
3375a4dc1477STom Whitten granted = PERM_FAIL;
33765b7f77adStw21770 }
3377a4dc1477STom Whitten } else {
3378a4dc1477STom Whitten granted = PERM_FAIL;
33797c478bd9Sstevel@tonic-gate }
33807c478bd9Sstevel@tonic-gate
33817c478bd9Sstevel@tonic-gate pc_free(pcp);
33827c478bd9Sstevel@tonic-gate } else {
3383a4dc1477STom Whitten granted = PERM_FAIL;
33847c478bd9Sstevel@tonic-gate }
33857c478bd9Sstevel@tonic-gate
3386a4dc1477STom Whitten return (granted);
3387273264cdSdm120769 #endif /* NATIVE_BUILD */
3388273264cdSdm120769 }
33895b7f77adStw21770
33905b7f77adStw21770 /*
33915b7f77adStw21770 * Native builds are done to create svc.configd-native. This program runs
33925b7f77adStw21770 * only on the Solaris build machines to create the seed repository, and it
33935b7f77adStw21770 * is compiled against the build machine's header files. The ADT_smf_*
33945b7f77adStw21770 * symbols may not be defined in these header files. For this reason
33955b7f77adStw21770 * smf_annotation_event(), _smf_audit_event() and special_property_event()
33965b7f77adStw21770 * are not compiled for native builds.
33975b7f77adStw21770 */
33985b7f77adStw21770 #ifndef NATIVE_BUILD
33995b7f77adStw21770
34005b7f77adStw21770 /*
34015b7f77adStw21770 * This function generates an annotation audit event if one has been setup.
34025b7f77adStw21770 * Annotation events should only be generated immediately before the audit
34035b7f77adStw21770 * record from the first attempt to modify the repository from a client
34045b7f77adStw21770 * which has requested an annotation.
34055b7f77adStw21770 */
34065b7f77adStw21770 static void
smf_annotation_event(int status,int return_val)34075b7f77adStw21770 smf_annotation_event(int status, int return_val)
34085b7f77adStw21770 {
34095b7f77adStw21770 adt_session_data_t *session;
34105b7f77adStw21770 adt_event_data_t *event = NULL;
34115b7f77adStw21770 char file[MAXPATHLEN];
34125b7f77adStw21770 char operation[REP_PROTOCOL_NAME_LEN];
34135b7f77adStw21770
34145b7f77adStw21770 /* Don't audit if we're using an alternate repository. */
34155b7f77adStw21770 if (is_main_repository == 0)
34165b7f77adStw21770 return;
34175b7f77adStw21770
34185b7f77adStw21770 if (client_annotation_needed(operation, sizeof (operation), file,
34195b7f77adStw21770 sizeof (file)) == 0) {
34205b7f77adStw21770 return;
34215b7f77adStw21770 }
34225b7f77adStw21770 if (file[0] == 0) {
34235b7f77adStw21770 (void) strlcpy(file, "NO FILE", sizeof (file));
34245b7f77adStw21770 }
34255b7f77adStw21770 if (operation[0] == 0) {
34265b7f77adStw21770 (void) strlcpy(operation, "NO OPERATION",
34275b7f77adStw21770 sizeof (operation));
34285b7f77adStw21770 }
34295b7f77adStw21770 if ((session = get_audit_session()) == NULL)
34305b7f77adStw21770 return;
34315b7f77adStw21770 if ((event = adt_alloc_event(session, ADT_smf_annotation)) == NULL) {
34325b7f77adStw21770 uu_warn("smf_annotation_event cannot allocate event "
34335b7f77adStw21770 "data. %s\n", strerror(errno));
34345b7f77adStw21770 return;
34355b7f77adStw21770 }
34365b7f77adStw21770 event->adt_smf_annotation.operation = operation;
34375b7f77adStw21770 event->adt_smf_annotation.file = file;
34385b7f77adStw21770 if (adt_put_event(event, status, return_val) == 0) {
34395b7f77adStw21770 client_annotation_finished();
34405b7f77adStw21770 } else {
34415b7f77adStw21770 uu_warn("smf_annotation_event failed to put event. "
34425b7f77adStw21770 "%s\n", strerror(errno));
34435b7f77adStw21770 }
34445b7f77adStw21770 adt_free_event(event);
34455b7f77adStw21770 }
34465b7f77adStw21770
34475b7f77adStw21770 /*
34485b7f77adStw21770 * _smf_audit_event interacts with the security auditing system to generate
34495b7f77adStw21770 * an audit event structure. It establishes an audit session and allocates
34505b7f77adStw21770 * an audit event. The event is filled in from the audit data, and
34515b7f77adStw21770 * adt_put_event is called to generate the event.
34525b7f77adStw21770 */
34535b7f77adStw21770 static void
_smf_audit_event(au_event_t event_id,int status,int return_val,audit_event_data_t * data)34545b7f77adStw21770 _smf_audit_event(au_event_t event_id, int status, int return_val,
34555b7f77adStw21770 audit_event_data_t *data)
34565b7f77adStw21770 {
34575b7f77adStw21770 char *auth_used;
34585b7f77adStw21770 char *fmri;
34595b7f77adStw21770 char *prop_value;
34605b7f77adStw21770 adt_session_data_t *session;
34615b7f77adStw21770 adt_event_data_t *event = NULL;
34625b7f77adStw21770
34635b7f77adStw21770 /* Don't audit if we're using an alternate repository */
34645b7f77adStw21770 if (is_main_repository == 0)
34655b7f77adStw21770 return;
34665b7f77adStw21770
34675b7f77adStw21770 smf_annotation_event(status, return_val);
34685b7f77adStw21770 if ((session = get_audit_session()) == NULL)
34695b7f77adStw21770 return;
34705b7f77adStw21770 if ((event = adt_alloc_event(session, event_id)) == NULL) {
34715b7f77adStw21770 uu_warn("_smf_audit_event cannot allocate event "
34725b7f77adStw21770 "data. %s\n", strerror(errno));
34735b7f77adStw21770 return;
34745b7f77adStw21770 }
34755b7f77adStw21770
34765b7f77adStw21770 /*
34775b7f77adStw21770 * Handle possibility of NULL authorization strings, FMRIs and
34785b7f77adStw21770 * property values.
34795b7f77adStw21770 */
34805b7f77adStw21770 if (data->ed_auth == NULL) {
34815b7f77adStw21770 auth_used = "PRIVILEGED";
34825b7f77adStw21770 } else {
34835b7f77adStw21770 auth_used = data->ed_auth;
34845b7f77adStw21770 }
34855b7f77adStw21770 if (data->ed_fmri == NULL) {
34865b7f77adStw21770 syslog(LOG_WARNING, "_smf_audit_event called with "
34875b7f77adStw21770 "empty FMRI string");
34885b7f77adStw21770 fmri = "UNKNOWN FMRI";
34895b7f77adStw21770 } else {
34905b7f77adStw21770 fmri = data->ed_fmri;
34915b7f77adStw21770 }
34925b7f77adStw21770 if (data->ed_prop_value == NULL) {
34935b7f77adStw21770 prop_value = "";
34945b7f77adStw21770 } else {
34955b7f77adStw21770 prop_value = data->ed_prop_value;
34965b7f77adStw21770 }
34975b7f77adStw21770
34985b7f77adStw21770 /* Fill in the event data. */
34995b7f77adStw21770 switch (event_id) {
35005b7f77adStw21770 case ADT_smf_attach_snap:
35015b7f77adStw21770 event->adt_smf_attach_snap.auth_used = auth_used;
35025b7f77adStw21770 event->adt_smf_attach_snap.old_fmri = data->ed_old_fmri;
35035b7f77adStw21770 event->adt_smf_attach_snap.old_name = data->ed_old_name;
35045b7f77adStw21770 event->adt_smf_attach_snap.new_fmri = fmri;
35055b7f77adStw21770 event->adt_smf_attach_snap.new_name = data->ed_snapname;
35065b7f77adStw21770 break;
35075b7f77adStw21770 case ADT_smf_change_prop:
35085b7f77adStw21770 event->adt_smf_change_prop.auth_used = auth_used;
35095b7f77adStw21770 event->adt_smf_change_prop.fmri = fmri;
35105b7f77adStw21770 event->adt_smf_change_prop.type = data->ed_type;
35115b7f77adStw21770 event->adt_smf_change_prop.value = prop_value;
35125b7f77adStw21770 break;
35135b7f77adStw21770 case ADT_smf_clear:
35145b7f77adStw21770 event->adt_smf_clear.auth_used = auth_used;
35155b7f77adStw21770 event->adt_smf_clear.fmri = fmri;
35165b7f77adStw21770 break;
35175b7f77adStw21770 case ADT_smf_create:
35185b7f77adStw21770 event->adt_smf_create.fmri = fmri;
35195b7f77adStw21770 event->adt_smf_create.auth_used = auth_used;
35205b7f77adStw21770 break;
35215b7f77adStw21770 case ADT_smf_create_npg:
35225b7f77adStw21770 event->adt_smf_create_npg.auth_used = auth_used;
35235b7f77adStw21770 event->adt_smf_create_npg.fmri = fmri;
35245b7f77adStw21770 event->adt_smf_create_npg.type = data->ed_type;
35255b7f77adStw21770 break;
35265b7f77adStw21770 case ADT_smf_create_pg:
35275b7f77adStw21770 event->adt_smf_create_pg.auth_used = auth_used;
35285b7f77adStw21770 event->adt_smf_create_pg.fmri = fmri;
35295b7f77adStw21770 event->adt_smf_create_pg.type = data->ed_type;
35305b7f77adStw21770 break;
35315b7f77adStw21770 case ADT_smf_create_prop:
35325b7f77adStw21770 event->adt_smf_create_prop.auth_used = auth_used;
35335b7f77adStw21770 event->adt_smf_create_prop.fmri = fmri;
35345b7f77adStw21770 event->adt_smf_create_prop.type = data->ed_type;
35355b7f77adStw21770 event->adt_smf_create_prop.value = prop_value;
35365b7f77adStw21770 break;
35375b7f77adStw21770 case ADT_smf_create_snap:
35385b7f77adStw21770 event->adt_smf_create_snap.auth_used = auth_used;
35395b7f77adStw21770 event->adt_smf_create_snap.fmri = fmri;
35405b7f77adStw21770 event->adt_smf_create_snap.name = data->ed_snapname;
35415b7f77adStw21770 break;
35425b7f77adStw21770 case ADT_smf_degrade:
35435b7f77adStw21770 event->adt_smf_degrade.auth_used = auth_used;
35445b7f77adStw21770 event->adt_smf_degrade.fmri = fmri;
35455b7f77adStw21770 break;
35465b7f77adStw21770 case ADT_smf_delete:
35475b7f77adStw21770 event->adt_smf_delete.fmri = fmri;
35485b7f77adStw21770 event->adt_smf_delete.auth_used = auth_used;
35495b7f77adStw21770 break;
35505b7f77adStw21770 case ADT_smf_delete_npg:
35515b7f77adStw21770 event->adt_smf_delete_npg.auth_used = auth_used;
35525b7f77adStw21770 event->adt_smf_delete_npg.fmri = fmri;
35535b7f77adStw21770 event->adt_smf_delete_npg.type = data->ed_type;
35545b7f77adStw21770 break;
35555b7f77adStw21770 case ADT_smf_delete_pg:
35565b7f77adStw21770 event->adt_smf_delete_pg.auth_used = auth_used;
35575b7f77adStw21770 event->adt_smf_delete_pg.fmri = fmri;
35585b7f77adStw21770 event->adt_smf_delete_pg.type = data->ed_type;
35595b7f77adStw21770 break;
35605b7f77adStw21770 case ADT_smf_delete_prop:
35615b7f77adStw21770 event->adt_smf_delete_prop.auth_used = auth_used;
35625b7f77adStw21770 event->adt_smf_delete_prop.fmri = fmri;
35635b7f77adStw21770 break;
35645b7f77adStw21770 case ADT_smf_delete_snap:
35655b7f77adStw21770 event->adt_smf_delete_snap.auth_used = auth_used;
35665b7f77adStw21770 event->adt_smf_delete_snap.fmri = fmri;
35675b7f77adStw21770 event->adt_smf_delete_snap.name = data->ed_snapname;
35685b7f77adStw21770 break;
35695b7f77adStw21770 case ADT_smf_disable:
35705b7f77adStw21770 event->adt_smf_disable.auth_used = auth_used;
35715b7f77adStw21770 event->adt_smf_disable.fmri = fmri;
35725b7f77adStw21770 break;
35735b7f77adStw21770 case ADT_smf_enable:
35745b7f77adStw21770 event->adt_smf_enable.auth_used = auth_used;
35755b7f77adStw21770 event->adt_smf_enable.fmri = fmri;
35765b7f77adStw21770 break;
35775b7f77adStw21770 case ADT_smf_immediate_degrade:
35785b7f77adStw21770 event->adt_smf_immediate_degrade.auth_used = auth_used;
35795b7f77adStw21770 event->adt_smf_immediate_degrade.fmri = fmri;
35805b7f77adStw21770 break;
35815b7f77adStw21770 case ADT_smf_immediate_maintenance:
35825b7f77adStw21770 event->adt_smf_immediate_maintenance.auth_used = auth_used;
35835b7f77adStw21770 event->adt_smf_immediate_maintenance.fmri = fmri;
35845b7f77adStw21770 break;
35855b7f77adStw21770 case ADT_smf_immtmp_maintenance:
35865b7f77adStw21770 event->adt_smf_immtmp_maintenance.auth_used = auth_used;
35875b7f77adStw21770 event->adt_smf_immtmp_maintenance.fmri = fmri;
35885b7f77adStw21770 break;
35895b7f77adStw21770 case ADT_smf_maintenance:
35905b7f77adStw21770 event->adt_smf_maintenance.auth_used = auth_used;
35915b7f77adStw21770 event->adt_smf_maintenance.fmri = fmri;
35925b7f77adStw21770 break;
35935b7f77adStw21770 case ADT_smf_milestone:
35945b7f77adStw21770 event->adt_smf_milestone.auth_used = auth_used;
35955b7f77adStw21770 event->adt_smf_milestone.fmri = fmri;
35965b7f77adStw21770 break;
35975b7f77adStw21770 case ADT_smf_read_prop:
35985b7f77adStw21770 event->adt_smf_read_prop.auth_used = auth_used;
35995b7f77adStw21770 event->adt_smf_read_prop.fmri = fmri;
36005b7f77adStw21770 break;
36015b7f77adStw21770 case ADT_smf_refresh:
36025b7f77adStw21770 event->adt_smf_refresh.auth_used = auth_used;
36035b7f77adStw21770 event->adt_smf_refresh.fmri = fmri;
36045b7f77adStw21770 break;
36055b7f77adStw21770 case ADT_smf_restart:
36065b7f77adStw21770 event->adt_smf_restart.auth_used = auth_used;
36075b7f77adStw21770 event->adt_smf_restart.fmri = fmri;
36085b7f77adStw21770 break;
36095b7f77adStw21770 case ADT_smf_tmp_disable:
36105b7f77adStw21770 event->adt_smf_tmp_disable.auth_used = auth_used;
36115b7f77adStw21770 event->adt_smf_tmp_disable.fmri = fmri;
36125b7f77adStw21770 break;
36135b7f77adStw21770 case ADT_smf_tmp_enable:
36145b7f77adStw21770 event->adt_smf_tmp_enable.auth_used = auth_used;
36155b7f77adStw21770 event->adt_smf_tmp_enable.fmri = fmri;
36165b7f77adStw21770 break;
36175b7f77adStw21770 case ADT_smf_tmp_maintenance:
36185b7f77adStw21770 event->adt_smf_tmp_maintenance.auth_used = auth_used;
36195b7f77adStw21770 event->adt_smf_tmp_maintenance.fmri = fmri;
36205b7f77adStw21770 break;
36215b7f77adStw21770 default:
36225b7f77adStw21770 abort(); /* Need to cover all SMF event IDs */
36235b7f77adStw21770 }
36245b7f77adStw21770
36255b7f77adStw21770 if (adt_put_event(event, status, return_val) != 0) {
36265b7f77adStw21770 uu_warn("_smf_audit_event failed to put event. %s\n",
36275b7f77adStw21770 strerror(errno));
36285b7f77adStw21770 }
36295b7f77adStw21770 adt_free_event(event);
36305b7f77adStw21770 }
36315b7f77adStw21770
36325b7f77adStw21770 /*
36335b7f77adStw21770 * Determine if the combination of the property group at pg_name and the
36345b7f77adStw21770 * property at prop_name are in the set of special startd properties. If
36355b7f77adStw21770 * they are, a special audit event will be generated.
36365b7f77adStw21770 */
36375b7f77adStw21770 static void
special_property_event(audit_event_data_t * evdp,const char * prop_name,char * pg_name,int status,int return_val,tx_commit_data_t * tx_data,size_t cmd_no)36385b7f77adStw21770 special_property_event(audit_event_data_t *evdp, const char *prop_name,
36395b7f77adStw21770 char *pg_name, int status, int return_val, tx_commit_data_t *tx_data,
36405b7f77adStw21770 size_t cmd_no)
36415b7f77adStw21770 {
36425b7f77adStw21770 au_event_t event_id;
36435b7f77adStw21770 audit_special_prop_item_t search_key;
36445b7f77adStw21770 audit_special_prop_item_t *found;
36455b7f77adStw21770
36465b7f77adStw21770 /* Use bsearch to find the special property information. */
36475b7f77adStw21770 search_key.api_prop_name = prop_name;
36485b7f77adStw21770 search_key.api_pg_name = pg_name;
36495b7f77adStw21770 found = (audit_special_prop_item_t *)bsearch(&search_key,
36505b7f77adStw21770 special_props_list, SPECIAL_PROP_COUNT,
36515b7f77adStw21770 sizeof (special_props_list[0]), special_prop_compare);
36525b7f77adStw21770 if (found == NULL) {
36535b7f77adStw21770 /* Not a special property. */
36545b7f77adStw21770 return;
36555b7f77adStw21770 }
36565b7f77adStw21770
36575b7f77adStw21770 /* Get the event id */
36585b7f77adStw21770 if (found->api_event_func == NULL) {
36595b7f77adStw21770 event_id = found->api_event_id;
36605b7f77adStw21770 } else {
36615b7f77adStw21770 if ((*found->api_event_func)(tx_data, cmd_no,
36625b7f77adStw21770 found->api_pg_name, &event_id) < 0)
36635b7f77adStw21770 return;
36645b7f77adStw21770 }
36655b7f77adStw21770
36665b7f77adStw21770 /* Generate the event. */
36675b7f77adStw21770 smf_audit_event(event_id, status, return_val, evdp);
36685b7f77adStw21770 }
36695b7f77adStw21770 #endif /* NATIVE_BUILD */
36705b7f77adStw21770
36715b7f77adStw21770 /*
36725b7f77adStw21770 * Return a pointer to a string containing all the values of the command
36735b7f77adStw21770 * specified by cmd_no with each value enclosed in quotes. It is up to the
36745b7f77adStw21770 * caller to free the memory at the returned pointer.
36755b7f77adStw21770 */
36765b7f77adStw21770 static char *
generate_value_list(tx_commit_data_t * tx_data,size_t cmd_no)36775b7f77adStw21770 generate_value_list(tx_commit_data_t *tx_data, size_t cmd_no)
36785b7f77adStw21770 {
36795b7f77adStw21770 const char *cp;
36805b7f77adStw21770 const char *cur_value;
36815b7f77adStw21770 size_t byte_count = 0;
36825b7f77adStw21770 uint32_t i;
36835b7f77adStw21770 uint32_t nvalues;
36845b7f77adStw21770 size_t str_size = 0;
36855b7f77adStw21770 char *values = NULL;
36865b7f77adStw21770 char *vp;
36875b7f77adStw21770
36885b7f77adStw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
36895b7f77adStw21770 return (NULL);
36905b7f77adStw21770 /*
36915b7f77adStw21770 * First determine the size of the buffer that we will need. We
36925b7f77adStw21770 * will represent each property value surrounded by quotes with a
36935b7f77adStw21770 * space separating the values. Thus, we need to find the total
36945b7f77adStw21770 * size of all the value strings and add 3 for each value.
36955b7f77adStw21770 *
36965b7f77adStw21770 * There is one catch, though. We need to escape any internal
36975b7f77adStw21770 * quote marks in the values. So for each quote in the value we
36985b7f77adStw21770 * need to add another byte to the buffer size.
36995b7f77adStw21770 */
37005b7f77adStw21770 for (i = 0; i < nvalues; i++) {
37015b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
37025b7f77adStw21770 REP_PROTOCOL_SUCCESS)
37035b7f77adStw21770 return (NULL);
37045b7f77adStw21770 for (cp = cur_value; *cp != 0; cp++) {
37055b7f77adStw21770 byte_count += (*cp == '"') ? 2 : 1;
37065b7f77adStw21770 }
37075b7f77adStw21770 byte_count += 3; /* surrounding quotes & space */
37085b7f77adStw21770 }
37095b7f77adStw21770 byte_count++; /* nul terminator */
37105b7f77adStw21770 values = malloc(byte_count);
37115b7f77adStw21770 if (values == NULL)
37125b7f77adStw21770 return (NULL);
37135b7f77adStw21770 *values = 0;
37145b7f77adStw21770
37155b7f77adStw21770 /* Now build up the string of values. */
37165b7f77adStw21770 for (i = 0; i < nvalues; i++) {
37175b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
37185b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
37195b7f77adStw21770 free(values);
37205b7f77adStw21770 return (NULL);
37215b7f77adStw21770 }
37225b7f77adStw21770 (void) strlcat(values, "\"", byte_count);
37235b7f77adStw21770 for (cp = cur_value, vp = values + strlen(values);
37245b7f77adStw21770 *cp != 0; cp++) {
37255b7f77adStw21770 if (*cp == '"') {
37265b7f77adStw21770 *vp++ = '\\';
37275b7f77adStw21770 *vp++ = '"';
37285b7f77adStw21770 } else {
37295b7f77adStw21770 *vp++ = *cp;
37305b7f77adStw21770 }
37315b7f77adStw21770 }
37325b7f77adStw21770 *vp = 0;
37335b7f77adStw21770 str_size = strlcat(values, "\" ", byte_count);
37345b7f77adStw21770 assert(str_size < byte_count);
37355b7f77adStw21770 }
37365b7f77adStw21770 if (str_size > 0)
37375b7f77adStw21770 values[str_size - 1] = 0; /* get rid of trailing space */
37385b7f77adStw21770 return (values);
37395b7f77adStw21770 }
37405b7f77adStw21770
37415b7f77adStw21770 /*
37425b7f77adStw21770 * generate_property_events takes the transaction commit data at tx_data
37435b7f77adStw21770 * and generates an audit event for each command.
37445b7f77adStw21770 *
37455b7f77adStw21770 * Native builds are done to create svc.configd-native. This program runs
37465b7f77adStw21770 * only on the Solaris build machines to create the seed repository. Thus,
37475b7f77adStw21770 * no audit events should be generated when running svc.configd-native.
37485b7f77adStw21770 */
37495b7f77adStw21770 static void
generate_property_events(tx_commit_data_t * tx_data,char * pg_fmri,char * auth_string,int auth_status,int auth_ret_value)37505b7f77adStw21770 generate_property_events(
37515b7f77adStw21770 tx_commit_data_t *tx_data,
37525b7f77adStw21770 char *pg_fmri, /* FMRI of property group */
37535b7f77adStw21770 char *auth_string,
37545b7f77adStw21770 int auth_status,
37555b7f77adStw21770 int auth_ret_value)
37565b7f77adStw21770 {
37575b7f77adStw21770 #ifndef NATIVE_BUILD
37585b7f77adStw21770 enum rep_protocol_transaction_action action;
37595b7f77adStw21770 audit_event_data_t audit_data;
37605b7f77adStw21770 size_t count;
37615b7f77adStw21770 size_t cmd_no;
37625b7f77adStw21770 char *cp;
37635b7f77adStw21770 au_event_t event_id;
37645b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
37655b7f77adStw21770 char pg_name[REP_PROTOCOL_NAME_LEN];
37665b7f77adStw21770 char *pg_end; /* End of prop. group fmri */
37675b7f77adStw21770 const char *prop_name;
37685b7f77adStw21770 uint32_t ptype;
37695b7f77adStw21770 char prop_type[3];
37705b7f77adStw21770 enum rep_protocol_responseid rc;
37715b7f77adStw21770 size_t sz_out;
37725b7f77adStw21770
37735b7f77adStw21770 /* Make sure we have something to do. */
37745b7f77adStw21770 if (tx_data == NULL)
37755b7f77adStw21770 return;
37765b7f77adStw21770 if ((count = tx_cmd_count(tx_data)) == 0)
37775b7f77adStw21770 return;
37785b7f77adStw21770
37795b7f77adStw21770 /* Copy the property group fmri */
37805b7f77adStw21770 pg_end = fmri;
37815b7f77adStw21770 pg_end += strlcpy(fmri, pg_fmri, sizeof (fmri));
37825b7f77adStw21770
37835b7f77adStw21770 /*
37845b7f77adStw21770 * Get the property group name. It is the first component after
37855b7f77adStw21770 * the last occurance of SCF_FMRI_PROPERTYGRP_PREFIX in the fmri.
37865b7f77adStw21770 */
37875b7f77adStw21770 cp = strstr(pg_fmri, SCF_FMRI_PROPERTYGRP_PREFIX);
37885b7f77adStw21770 if (cp == NULL) {
37895b7f77adStw21770 pg_name[0] = 0;
37905b7f77adStw21770 } else {
37915b7f77adStw21770 cp += strlen(SCF_FMRI_PROPERTYGRP_PREFIX);
37925b7f77adStw21770 (void) strlcpy(pg_name, cp, sizeof (pg_name));
37935b7f77adStw21770 }
37945b7f77adStw21770
37955b7f77adStw21770 audit_data.ed_auth = auth_string;
37965b7f77adStw21770 audit_data.ed_fmri = fmri;
37975b7f77adStw21770 audit_data.ed_type = prop_type;
37985b7f77adStw21770
37995b7f77adStw21770 /*
38005b7f77adStw21770 * Property type is two characters (see
38015b7f77adStw21770 * rep_protocol_value_type_t), so terminate the string.
38025b7f77adStw21770 */
38035b7f77adStw21770 prop_type[2] = 0;
38045b7f77adStw21770
38055b7f77adStw21770 for (cmd_no = 0; cmd_no < count; cmd_no++) {
38065b7f77adStw21770 /* Construct FMRI of the property */
38075b7f77adStw21770 *pg_end = 0;
38085b7f77adStw21770 if (tx_cmd_prop(tx_data, cmd_no, &prop_name) !=
38095b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
38105b7f77adStw21770 continue;
38115b7f77adStw21770 }
38125b7f77adStw21770 rc = rc_concat_fmri_element(fmri, sizeof (fmri), &sz_out,
38135b7f77adStw21770 prop_name, REP_PROTOCOL_ENTITY_PROPERTY);
38145b7f77adStw21770 if (rc != REP_PROTOCOL_SUCCESS) {
38155b7f77adStw21770 /*
38165b7f77adStw21770 * If we can't get the FMRI, we'll abandon this
38175b7f77adStw21770 * command
38185b7f77adStw21770 */
38195b7f77adStw21770 continue;
38205b7f77adStw21770 }
38215b7f77adStw21770
38225b7f77adStw21770 /* Generate special property event if necessary. */
38235b7f77adStw21770 special_property_event(&audit_data, prop_name, pg_name,
38245b7f77adStw21770 auth_status, auth_ret_value, tx_data, cmd_no);
38255b7f77adStw21770
38265b7f77adStw21770 /* Capture rest of audit data. */
38275b7f77adStw21770 if (tx_cmd_prop_type(tx_data, cmd_no, &ptype) !=
38285b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
38295b7f77adStw21770 continue;
38305b7f77adStw21770 }
38315b7f77adStw21770 prop_type[0] = REP_PROTOCOL_BASE_TYPE(ptype);
38325b7f77adStw21770 prop_type[1] = REP_PROTOCOL_SUBTYPE(ptype);
38335b7f77adStw21770 audit_data.ed_prop_value = generate_value_list(tx_data, cmd_no);
38345b7f77adStw21770
38355b7f77adStw21770 /* Determine the event type. */
38365b7f77adStw21770 if (tx_cmd_action(tx_data, cmd_no, &action) !=
38375b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
38385b7f77adStw21770 free(audit_data.ed_prop_value);
38395b7f77adStw21770 continue;
38405b7f77adStw21770 }
38415b7f77adStw21770 switch (action) {
38425b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_NEW:
38435b7f77adStw21770 event_id = ADT_smf_create_prop;
38445b7f77adStw21770 break;
38455b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_CLEAR:
38465b7f77adStw21770 event_id = ADT_smf_change_prop;
38475b7f77adStw21770 break;
38485b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_REPLACE:
38495b7f77adStw21770 event_id = ADT_smf_change_prop;
38505b7f77adStw21770 break;
38515b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_DELETE:
38525b7f77adStw21770 event_id = ADT_smf_delete_prop;
38535b7f77adStw21770 break;
38545b7f77adStw21770 default:
38555b7f77adStw21770 assert(0); /* Missing a case */
38565b7f77adStw21770 free(audit_data.ed_prop_value);
38575b7f77adStw21770 continue;
38585b7f77adStw21770 }
38595b7f77adStw21770
38605b7f77adStw21770 /* Generate the event. */
38615b7f77adStw21770 smf_audit_event(event_id, auth_status, auth_ret_value,
38625b7f77adStw21770 &audit_data);
38635b7f77adStw21770 free(audit_data.ed_prop_value);
38645b7f77adStw21770 }
38655b7f77adStw21770 #endif /* NATIVE_BUILD */
38667c478bd9Sstevel@tonic-gate }
38677c478bd9Sstevel@tonic-gate
38687c478bd9Sstevel@tonic-gate /*
38697c478bd9Sstevel@tonic-gate * Fails with
38707c478bd9Sstevel@tonic-gate * _DELETED - node has been deleted
38717c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset
38727c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - type is _PROPERTYGRP
38737c478bd9Sstevel@tonic-gate * _INVALID_TYPE - node is corrupt or type is invalid
38747c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - node cannot have children of type type
38757c478bd9Sstevel@tonic-gate * _BAD_REQUEST - name is invalid
38767c478bd9Sstevel@tonic-gate * cannot create children for this type of node
38777c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory, or could not allocate new id
38787c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED
38797c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS
38807c478bd9Sstevel@tonic-gate * _BACKEND_READONLY
38817c478bd9Sstevel@tonic-gate * _EXISTS - child already exists
38825b7f77adStw21770 * _TRUNCATED - truncated FMRI for the audit record
38837c478bd9Sstevel@tonic-gate */
38847c478bd9Sstevel@tonic-gate int
rc_node_create_child(rc_node_ptr_t * npp,uint32_t type,const char * name,rc_node_ptr_t * cpp)38857c478bd9Sstevel@tonic-gate rc_node_create_child(rc_node_ptr_t *npp, uint32_t type, const char *name,
38867c478bd9Sstevel@tonic-gate rc_node_ptr_t *cpp)
38877c478bd9Sstevel@tonic-gate {
38887c478bd9Sstevel@tonic-gate rc_node_t *np;
38897c478bd9Sstevel@tonic-gate rc_node_t *cp = NULL;
3890a4dc1477STom Whitten int rc;
3891a4dc1477STom Whitten perm_status_t perm_rc;
38925b7f77adStw21770 size_t sz_out;
38935b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
38945b7f77adStw21770 audit_event_data_t audit_data;
38957c478bd9Sstevel@tonic-gate
38967c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0);
38977c478bd9Sstevel@tonic-gate
3898a4dc1477STom Whitten /*
3899a4dc1477STom Whitten * rc_node_modify_permission_check() must be called before the node
3900a4dc1477STom Whitten * is locked. This is because the library functions that check
3901a4dc1477STom Whitten * authorizations can trigger calls back into configd.
3902a4dc1477STom Whitten */
39035b7f77adStw21770 perm_rc = rc_node_modify_permission_check(&audit_data.ed_auth);
3904a4dc1477STom Whitten switch (perm_rc) {
3905a4dc1477STom Whitten case PERM_DENIED:
3906a4dc1477STom Whitten /*
3907a4dc1477STom Whitten * We continue in this case, so that an audit event can be
3908a4dc1477STom Whitten * generated later in the function.
3909a4dc1477STom Whitten */
3910a4dc1477STom Whitten break;
3911a4dc1477STom Whitten case PERM_GRANTED:
3912a4dc1477STom Whitten break;
3913a4dc1477STom Whitten case PERM_GONE:
3914a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
3915a4dc1477STom Whitten case PERM_FAIL:
3916a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_NO_RESOURCES);
3917a4dc1477STom Whitten default:
3918a4dc1477STom Whitten bad_error(rc_node_modify_permission_check, perm_rc);
3919a4dc1477STom Whitten }
39203eae19d9Swesolows
3921a4dc1477STom Whitten RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
39227c478bd9Sstevel@tonic-gate
39235b7f77adStw21770 audit_data.ed_fmri = fmri;
39245b7f77adStw21770
39257c478bd9Sstevel@tonic-gate /*
39267c478bd9Sstevel@tonic-gate * there is a separate interface for creating property groups
39277c478bd9Sstevel@tonic-gate */
39287c478bd9Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
39297c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39305b7f77adStw21770 free(audit_data.ed_auth);
39317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
39327c478bd9Sstevel@tonic-gate }
39337c478bd9Sstevel@tonic-gate
39347c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
39357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39367c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
3937a4dc1477STom Whitten if ((rc = rc_node_check_and_lock(np)) != REP_PROTOCOL_SUCCESS) {
3938a4dc1477STom Whitten free(audit_data.ed_auth);
3939a4dc1477STom Whitten return (rc);
3940a4dc1477STom Whitten }
39417c478bd9Sstevel@tonic-gate }
39427c478bd9Sstevel@tonic-gate
39437c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
39447c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
39457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39465b7f77adStw21770 free(audit_data.ed_auth);
39477c478bd9Sstevel@tonic-gate return (rc);
39487c478bd9Sstevel@tonic-gate }
39497c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS) {
39507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39515b7f77adStw21770 free(audit_data.ed_auth);
39527c478bd9Sstevel@tonic-gate return (rc);
39537c478bd9Sstevel@tonic-gate }
39547c478bd9Sstevel@tonic-gate
39555b7f77adStw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
39565b7f77adStw21770 name, type)) != REP_PROTOCOL_SUCCESS) {
39575b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
39585b7f77adStw21770 free(audit_data.ed_auth);
39595b7f77adStw21770 return (rc);
39605b7f77adStw21770 }
3961a4dc1477STom Whitten if (perm_rc == PERM_DENIED) {
39627c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39635b7f77adStw21770 smf_audit_event(ADT_smf_create, ADT_FAILURE,
39645b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
39655b7f77adStw21770 free(audit_data.ed_auth);
3966a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
39677c478bd9Sstevel@tonic-gate }
39687c478bd9Sstevel@tonic-gate
39695b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
39705b7f77adStw21770 audit_data.ed_auth);
39717c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39727c478bd9Sstevel@tonic-gate
39737c478bd9Sstevel@tonic-gate rc = object_create(np, type, name, &cp);
39747c478bd9Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
39757c478bd9Sstevel@tonic-gate
39767c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
39777c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp);
39787c478bd9Sstevel@tonic-gate rc_node_rele(cp);
39797c478bd9Sstevel@tonic-gate }
39807c478bd9Sstevel@tonic-gate
39817c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
39827c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
39837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39847c478bd9Sstevel@tonic-gate
39855b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) {
39865b7f77adStw21770 smf_audit_event(ADT_smf_create, ADT_SUCCESS, ADT_SUCCESS,
39875b7f77adStw21770 &audit_data);
39885b7f77adStw21770 }
39895b7f77adStw21770
39905b7f77adStw21770 free(audit_data.ed_auth);
39915b7f77adStw21770
39927c478bd9Sstevel@tonic-gate return (rc);
39937c478bd9Sstevel@tonic-gate }
39947c478bd9Sstevel@tonic-gate
39957c478bd9Sstevel@tonic-gate int
rc_node_create_child_pg(rc_node_ptr_t * npp,uint32_t type,const char * name,const char * pgtype,uint32_t flags,rc_node_ptr_t * cpp)39967c478bd9Sstevel@tonic-gate rc_node_create_child_pg(rc_node_ptr_t *npp, uint32_t type, const char *name,
39977c478bd9Sstevel@tonic-gate const char *pgtype, uint32_t flags, rc_node_ptr_t *cpp)
39987c478bd9Sstevel@tonic-gate {
39997c478bd9Sstevel@tonic-gate rc_node_t *np;
40007c478bd9Sstevel@tonic-gate rc_node_t *cp;
40017c478bd9Sstevel@tonic-gate int rc;
40027c478bd9Sstevel@tonic-gate permcheck_t *pcp;
4003a4dc1477STom Whitten perm_status_t granted;
40045b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
40055b7f77adStw21770 audit_event_data_t audit_data;
40065b7f77adStw21770 au_event_t event_id;
40075b7f77adStw21770 size_t sz_out;
40085b7f77adStw21770
40095b7f77adStw21770 audit_data.ed_auth = NULL;
40105b7f77adStw21770 audit_data.ed_fmri = fmri;
40115b7f77adStw21770 audit_data.ed_type = (char *)pgtype;
40127c478bd9Sstevel@tonic-gate
40137c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0);
40147c478bd9Sstevel@tonic-gate
40157c478bd9Sstevel@tonic-gate /* verify flags is valid */
40167c478bd9Sstevel@tonic-gate if (flags & ~SCF_PG_FLAG_NONPERSISTENT)
40177c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
40187c478bd9Sstevel@tonic-gate
40197c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
40207c478bd9Sstevel@tonic-gate
40217c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
40227c478bd9Sstevel@tonic-gate rc_node_rele(np);
40237c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
40247c478bd9Sstevel@tonic-gate }
40257c478bd9Sstevel@tonic-gate
40267c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
40277c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
40287c478bd9Sstevel@tonic-gate rc_node_rele(np);
40297c478bd9Sstevel@tonic-gate return (rc);
40307c478bd9Sstevel@tonic-gate }
40317c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS ||
40327c478bd9Sstevel@tonic-gate (rc = rc_check_pgtype_name(pgtype)) != REP_PROTOCOL_SUCCESS) {
40337c478bd9Sstevel@tonic-gate rc_node_rele(np);
40347c478bd9Sstevel@tonic-gate return (rc);
40357c478bd9Sstevel@tonic-gate }
40367c478bd9Sstevel@tonic-gate
4037273264cdSdm120769 #ifdef NATIVE_BUILD
40385b7f77adStw21770 if (!client_is_privileged()) {
40397c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
40405b7f77adStw21770 }
40417c478bd9Sstevel@tonic-gate #else
40425b7f77adStw21770 if (flags & SCF_PG_FLAG_NONPERSISTENT) {
40435b7f77adStw21770 event_id = ADT_smf_create_npg;
40445b7f77adStw21770 } else {
40455b7f77adStw21770 event_id = ADT_smf_create_pg;
40465b7f77adStw21770 }
40475b7f77adStw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
40485b7f77adStw21770 name, REP_PROTOCOL_ENTITY_PROPERTYGRP)) != REP_PROTOCOL_SUCCESS) {
40495b7f77adStw21770 rc_node_rele(np);
40505b7f77adStw21770 return (rc);
40515b7f77adStw21770 }
40525b7f77adStw21770
40535b7f77adStw21770 if (is_main_repository) {
40547c478bd9Sstevel@tonic-gate /* Must have .smf.modify or smf.modify.<type> authorization */
40557c478bd9Sstevel@tonic-gate pcp = pc_create();
40567c478bd9Sstevel@tonic-gate if (pcp != NULL) {
40577c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
40587c478bd9Sstevel@tonic-gate
40597c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
40607c478bd9Sstevel@tonic-gate const char * const auth =
40617c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(pgtype);
40627c478bd9Sstevel@tonic-gate
40637c478bd9Sstevel@tonic-gate if (auth != NULL)
40647c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
40657c478bd9Sstevel@tonic-gate }
40667c478bd9Sstevel@tonic-gate
40677c478bd9Sstevel@tonic-gate /*
40687c478bd9Sstevel@tonic-gate * .manage or $action_authorization can be used to
40697c478bd9Sstevel@tonic-gate * create the actions pg and the general_ovr pg.
40707c478bd9Sstevel@tonic-gate */
40717c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS &&
40727c478bd9Sstevel@tonic-gate (flags & SCF_PG_FLAG_NONPERSISTENT) != 0 &&
40737c478bd9Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE &&
40747c478bd9Sstevel@tonic-gate ((strcmp(name, AUTH_PG_ACTIONS) == 0 &&
40757c478bd9Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_ACTIONS_TYPE) == 0) ||
40767c478bd9Sstevel@tonic-gate (strcmp(name, AUTH_PG_GENERAL_OVR) == 0 &&
40777c478bd9Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
40787c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MANAGE);
40797c478bd9Sstevel@tonic-gate
40807c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS)
40817c478bd9Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, np);
40827c478bd9Sstevel@tonic-gate }
40837c478bd9Sstevel@tonic-gate
40847c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
40857c478bd9Sstevel@tonic-gate granted = perm_granted(pcp);
40867c478bd9Sstevel@tonic-gate
4087a4dc1477STom Whitten rc = map_granted_status(granted, pcp,
4088a4dc1477STom Whitten &audit_data.ed_auth);
4089a4dc1477STom Whitten if (granted == PERM_GONE) {
4090a4dc1477STom Whitten /* No auditing if client gone. */
4091a4dc1477STom Whitten pc_free(pcp);
4092a4dc1477STom Whitten rc_node_rele(np);
4093a4dc1477STom Whitten return (rc);
40945b7f77adStw21770 }
40957c478bd9Sstevel@tonic-gate }
40967c478bd9Sstevel@tonic-gate
40977c478bd9Sstevel@tonic-gate pc_free(pcp);
40987c478bd9Sstevel@tonic-gate } else {
40997c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
41007c478bd9Sstevel@tonic-gate }
41017c478bd9Sstevel@tonic-gate
41025b7f77adStw21770 } else {
41035b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
41045b7f77adStw21770 }
41057c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
41067c478bd9Sstevel@tonic-gate
4107a4dc1477STom Whitten
41087c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
41097c478bd9Sstevel@tonic-gate rc_node_rele(np);
4110a4dc1477STom Whitten if (rc != REP_PROTOCOL_FAIL_NO_RESOURCES) {
41115b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE,
41125b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
4113a4dc1477STom Whitten }
41145b7f77adStw21770 if (audit_data.ed_auth != NULL)
41155b7f77adStw21770 free(audit_data.ed_auth);
41167c478bd9Sstevel@tonic-gate return (rc);
41177c478bd9Sstevel@tonic-gate }
41187c478bd9Sstevel@tonic-gate
41197c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41205b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
41215b7f77adStw21770 audit_data.ed_auth);
41227c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41237c478bd9Sstevel@tonic-gate
41247c478bd9Sstevel@tonic-gate rc = object_create_pg(np, type, name, pgtype, flags, &cp);
41257c478bd9Sstevel@tonic-gate
41267c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
41277c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp);
41287c478bd9Sstevel@tonic-gate rc_node_rele(cp);
41297c478bd9Sstevel@tonic-gate }
41307c478bd9Sstevel@tonic-gate
41317c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41327c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
41337c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41347c478bd9Sstevel@tonic-gate
41355b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) {
41365b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
41375b7f77adStw21770 &audit_data);
41385b7f77adStw21770 }
41395b7f77adStw21770 if (audit_data.ed_auth != NULL)
41405b7f77adStw21770 free(audit_data.ed_auth);
41415b7f77adStw21770
41427c478bd9Sstevel@tonic-gate return (rc);
41437c478bd9Sstevel@tonic-gate }
41447c478bd9Sstevel@tonic-gate
41457c478bd9Sstevel@tonic-gate static void
rc_pg_notify_fire(rc_node_pg_notify_t * pnp)41467c478bd9Sstevel@tonic-gate rc_pg_notify_fire(rc_node_pg_notify_t *pnp)
41477c478bd9Sstevel@tonic-gate {
41487c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
41497c478bd9Sstevel@tonic-gate
41507c478bd9Sstevel@tonic-gate if (pnp->rnpn_pg != NULL) {
41517c478bd9Sstevel@tonic-gate uu_list_remove(pnp->rnpn_pg->rn_pg_notify_list, pnp);
41527c478bd9Sstevel@tonic-gate (void) close(pnp->rnpn_fd);
41537c478bd9Sstevel@tonic-gate
41547c478bd9Sstevel@tonic-gate pnp->rnpn_pg = NULL;
41557c478bd9Sstevel@tonic-gate pnp->rnpn_fd = -1;
41567c478bd9Sstevel@tonic-gate } else {
41577c478bd9Sstevel@tonic-gate assert(pnp->rnpn_fd == -1);
41587c478bd9Sstevel@tonic-gate }
41597c478bd9Sstevel@tonic-gate }
41607c478bd9Sstevel@tonic-gate
41617c478bd9Sstevel@tonic-gate static void
rc_notify_node_delete(rc_notify_delete_t * ndp,rc_node_t * np_arg)41627c478bd9Sstevel@tonic-gate rc_notify_node_delete(rc_notify_delete_t *ndp, rc_node_t *np_arg)
41637c478bd9Sstevel@tonic-gate {
41647c478bd9Sstevel@tonic-gate rc_node_t *svc = NULL;
41657c478bd9Sstevel@tonic-gate rc_node_t *inst = NULL;
41667c478bd9Sstevel@tonic-gate rc_node_t *pg = NULL;
41677c478bd9Sstevel@tonic-gate rc_node_t *np = np_arg;
41687c478bd9Sstevel@tonic-gate rc_node_t *nnp;
41697c478bd9Sstevel@tonic-gate
41707c478bd9Sstevel@tonic-gate while (svc == NULL) {
41717c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41727c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
41737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41747c478bd9Sstevel@tonic-gate goto cleanup;
41757c478bd9Sstevel@tonic-gate }
41767c478bd9Sstevel@tonic-gate nnp = np->rn_parent;
41777c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* hold it in place */
41787c478bd9Sstevel@tonic-gate
41797c478bd9Sstevel@tonic-gate switch (np->rn_id.rl_type) {
41807c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP:
41817c478bd9Sstevel@tonic-gate assert(pg == NULL);
41827c478bd9Sstevel@tonic-gate pg = np;
41837c478bd9Sstevel@tonic-gate break;
41847c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE:
41857c478bd9Sstevel@tonic-gate assert(inst == NULL);
41867c478bd9Sstevel@tonic-gate inst = np;
41877c478bd9Sstevel@tonic-gate break;
41887c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE:
41897c478bd9Sstevel@tonic-gate assert(svc == NULL);
41907c478bd9Sstevel@tonic-gate svc = np;
41917c478bd9Sstevel@tonic-gate break;
41927c478bd9Sstevel@tonic-gate default:
41937c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
41947c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
41957c478bd9Sstevel@tonic-gate goto cleanup;
41967c478bd9Sstevel@tonic-gate }
41977c478bd9Sstevel@tonic-gate
41987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41997c478bd9Sstevel@tonic-gate
42007c478bd9Sstevel@tonic-gate np = nnp;
42017c478bd9Sstevel@tonic-gate if (np == NULL)
42027c478bd9Sstevel@tonic-gate goto cleanup;
42037c478bd9Sstevel@tonic-gate }
42047c478bd9Sstevel@tonic-gate
42057c478bd9Sstevel@tonic-gate rc_notify_deletion(ndp,
42067c478bd9Sstevel@tonic-gate svc->rn_name,
42077c478bd9Sstevel@tonic-gate inst != NULL ? inst->rn_name : NULL,
42087c478bd9Sstevel@tonic-gate pg != NULL ? pg->rn_name : NULL);
42097c478bd9Sstevel@tonic-gate
42107c478bd9Sstevel@tonic-gate ndp = NULL;
42117c478bd9Sstevel@tonic-gate
42127c478bd9Sstevel@tonic-gate cleanup:
42137c478bd9Sstevel@tonic-gate if (ndp != NULL)
42147c478bd9Sstevel@tonic-gate uu_free(ndp);
42157c478bd9Sstevel@tonic-gate
42167c478bd9Sstevel@tonic-gate for (;;) {
42177c478bd9Sstevel@tonic-gate if (svc != NULL) {
42187c478bd9Sstevel@tonic-gate np = svc;
42197c478bd9Sstevel@tonic-gate svc = NULL;
42207c478bd9Sstevel@tonic-gate } else if (inst != NULL) {
42217c478bd9Sstevel@tonic-gate np = inst;
42227c478bd9Sstevel@tonic-gate inst = NULL;
42237c478bd9Sstevel@tonic-gate } else if (pg != NULL) {
42247c478bd9Sstevel@tonic-gate np = pg;
42257c478bd9Sstevel@tonic-gate pg = NULL;
42267c478bd9Sstevel@tonic-gate } else
42277c478bd9Sstevel@tonic-gate break;
42287c478bd9Sstevel@tonic-gate
42297c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42307c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
42317c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
42327c478bd9Sstevel@tonic-gate }
42337c478bd9Sstevel@tonic-gate }
42347c478bd9Sstevel@tonic-gate
42357c478bd9Sstevel@tonic-gate /*
42366643e1ffSbustos * Hold RC_NODE_DYING_FLAGS on np's descendents. If andformer is true, do
42376643e1ffSbustos * the same down the rn_former chain.
42387c478bd9Sstevel@tonic-gate */
42397c478bd9Sstevel@tonic-gate static void
rc_node_delete_hold(rc_node_t * np,int andformer)42407c478bd9Sstevel@tonic-gate rc_node_delete_hold(rc_node_t *np, int andformer)
42417c478bd9Sstevel@tonic-gate {
42427c478bd9Sstevel@tonic-gate rc_node_t *cp;
42437c478bd9Sstevel@tonic-gate
42447c478bd9Sstevel@tonic-gate again:
42457c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
42467c478bd9Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
42477c478bd9Sstevel@tonic-gate
42487c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
42497c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
42507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42527c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS)) {
42537c478bd9Sstevel@tonic-gate /*
42547c478bd9Sstevel@tonic-gate * already marked as dead -- can't happen, since that
42557c478bd9Sstevel@tonic-gate * would require setting RC_NODE_CHILDREN_CHANGING
42567c478bd9Sstevel@tonic-gate * in np, and we're holding that...
42577c478bd9Sstevel@tonic-gate */
42587c478bd9Sstevel@tonic-gate abort();
42597c478bd9Sstevel@tonic-gate }
42607c478bd9Sstevel@tonic-gate rc_node_delete_hold(cp, andformer); /* recurse, drop lock */
42617c478bd9Sstevel@tonic-gate
42627c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42637c478bd9Sstevel@tonic-gate }
42647c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
42657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42667c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42677c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS))
42687c478bd9Sstevel@tonic-gate abort(); /* can't happen, see above */
42697c478bd9Sstevel@tonic-gate np = cp;
42707c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
42717c478bd9Sstevel@tonic-gate }
42727c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42737c478bd9Sstevel@tonic-gate }
42747c478bd9Sstevel@tonic-gate
42757c478bd9Sstevel@tonic-gate /*
42767c478bd9Sstevel@tonic-gate * N.B.: this function drops np->rn_lock on the way out.
42777c478bd9Sstevel@tonic-gate */
42787c478bd9Sstevel@tonic-gate static void
rc_node_delete_rele(rc_node_t * np,int andformer)42797c478bd9Sstevel@tonic-gate rc_node_delete_rele(rc_node_t *np, int andformer)
42807c478bd9Sstevel@tonic-gate {
42817c478bd9Sstevel@tonic-gate rc_node_t *cp;
42827c478bd9Sstevel@tonic-gate
42837c478bd9Sstevel@tonic-gate again:
42847c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
42857c478bd9Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
42867c478bd9Sstevel@tonic-gate
42877c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
42887c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
42897c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42907c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42917c478bd9Sstevel@tonic-gate rc_node_delete_rele(cp, andformer); /* recurse, drop lock */
42927c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42937c478bd9Sstevel@tonic-gate }
42947c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
42957c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42967c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
42977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42987c478bd9Sstevel@tonic-gate
42997c478bd9Sstevel@tonic-gate np = cp;
43007c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
43017c478bd9Sstevel@tonic-gate }
43027c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
43037c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
43047c478bd9Sstevel@tonic-gate }
43057c478bd9Sstevel@tonic-gate
43067c478bd9Sstevel@tonic-gate static void
rc_node_finish_delete(rc_node_t * cp)43077c478bd9Sstevel@tonic-gate rc_node_finish_delete(rc_node_t *cp)
43087c478bd9Sstevel@tonic-gate {
43097c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
43107c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
43117c478bd9Sstevel@tonic-gate
43127c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&cp->rn_lock));
43137c478bd9Sstevel@tonic-gate
43147c478bd9Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) {
43157c478bd9Sstevel@tonic-gate assert(cp->rn_flags & RC_NODE_IN_PARENT);
43167c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(cp, RC_NODE_USING_PARENT)) {
43177c478bd9Sstevel@tonic-gate abort(); /* can't happen, see above */
43187c478bd9Sstevel@tonic-gate }
43197c478bd9Sstevel@tonic-gate cp->rn_flags &= ~RC_NODE_IN_PARENT;
43207c478bd9Sstevel@tonic-gate cp->rn_parent = NULL;
43215b7f77adStw21770 rc_node_free_fmri(cp);
43227c478bd9Sstevel@tonic-gate }
43237c478bd9Sstevel@tonic-gate
43247c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_DEAD;
43257c478bd9Sstevel@tonic-gate
43267c478bd9Sstevel@tonic-gate /*
43277c478bd9Sstevel@tonic-gate * If this node is not out-dated, we need to remove it from
43287c478bd9Sstevel@tonic-gate * the notify list and cache hash table.
43297c478bd9Sstevel@tonic-gate */
43307c478bd9Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) {
43317c478bd9Sstevel@tonic-gate assert(cp->rn_refs > 0); /* can't go away yet */
43327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
43337c478bd9Sstevel@tonic-gate
43347c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
43357c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(cp->rn_pg_notify_list)) != NULL)
43367c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp);
43377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
43387c478bd9Sstevel@tonic-gate rc_notify_remove_node(cp);
43397c478bd9Sstevel@tonic-gate
43407c478bd9Sstevel@tonic-gate bp = cache_hold(cp->rn_hash);
43417c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43427c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, cp);
43437c478bd9Sstevel@tonic-gate cache_release(bp);
43447c478bd9Sstevel@tonic-gate }
43457c478bd9Sstevel@tonic-gate }
43467c478bd9Sstevel@tonic-gate
43477c478bd9Sstevel@tonic-gate /*
43486643e1ffSbustos * For each child, call rc_node_finish_delete() and recurse. If andformer
43496643e1ffSbustos * is set, also recurse down rn_former. Finally release np, which might
43506643e1ffSbustos * free it.
43517c478bd9Sstevel@tonic-gate */
43527c478bd9Sstevel@tonic-gate static void
rc_node_delete_children(rc_node_t * np,int andformer)43537c478bd9Sstevel@tonic-gate rc_node_delete_children(rc_node_t *np, int andformer)
43547c478bd9Sstevel@tonic-gate {
43557c478bd9Sstevel@tonic-gate rc_node_t *cp;
43567c478bd9Sstevel@tonic-gate
43577c478bd9Sstevel@tonic-gate again:
43587c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0);
43597c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
43607c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_DEAD);
43617c478bd9Sstevel@tonic-gate
43627c478bd9Sstevel@tonic-gate while ((cp = uu_list_first(np->rn_children)) != NULL) {
43637c478bd9Sstevel@tonic-gate uu_list_remove(np->rn_children, cp);
43647c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
43667c478bd9Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we recurse */
43677c478bd9Sstevel@tonic-gate rc_node_finish_delete(cp);
43687c478bd9Sstevel@tonic-gate rc_node_delete_children(cp, andformer); /* drops lock + ref */
43697c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
43707c478bd9Sstevel@tonic-gate }
43717c478bd9Sstevel@tonic-gate
43727c478bd9Sstevel@tonic-gate /*
4373addbbe95Srm88369 * When we drop cp's lock, all the children will be gone, so we
43747c478bd9Sstevel@tonic-gate * can release DYING_FLAGS.
43757c478bd9Sstevel@tonic-gate */
43767c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
43777c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
43787c478bd9Sstevel@tonic-gate np->rn_former = NULL; /* unlink */
43797c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43806643e1ffSbustos
43816643e1ffSbustos /*
43826643e1ffSbustos * Register the ephemeral reference created by reading
43836643e1ffSbustos * np->rn_former into cp. Note that the persistent
43846643e1ffSbustos * reference (np->rn_former) is locked because we haven't
43856643e1ffSbustos * dropped np's lock since we dropped its RC_NODE_IN_TX
43866643e1ffSbustos * (via RC_NODE_DYING_FLAGS).
43876643e1ffSbustos */
43886643e1ffSbustos rc_node_hold_ephemeral_locked(cp);
43896643e1ffSbustos
43907c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
4391addbbe95Srm88369 cp->rn_flags &= ~RC_NODE_ON_FORMER;
43927c478bd9Sstevel@tonic-gate
43937c478bd9Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we loop */
43947c478bd9Sstevel@tonic-gate
43957c478bd9Sstevel@tonic-gate rc_node_finish_delete(cp);
43967c478bd9Sstevel@tonic-gate
43977c478bd9Sstevel@tonic-gate rc_node_rele(np); /* drop the old reference */
43987c478bd9Sstevel@tonic-gate
43997c478bd9Sstevel@tonic-gate np = cp;
44007c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
44017c478bd9Sstevel@tonic-gate }
44027c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
44037c478bd9Sstevel@tonic-gate }
44047c478bd9Sstevel@tonic-gate
44056643e1ffSbustos /*
44066643e1ffSbustos * The last client or child reference to np, which must be either
44076643e1ffSbustos * RC_NODE_OLD or RC_NODE_DEAD, has been destroyed. We'll destroy any
44086643e1ffSbustos * remaining references (e.g., rn_former) and call rc_node_destroy() to
44096643e1ffSbustos * free np.
44106643e1ffSbustos */
44117c478bd9Sstevel@tonic-gate static void
rc_node_no_client_refs(rc_node_t * np)44126643e1ffSbustos rc_node_no_client_refs(rc_node_t *np)
44137c478bd9Sstevel@tonic-gate {
44147c478bd9Sstevel@tonic-gate int unrefed;
44156643e1ffSbustos rc_node_t *current, *cur;
44167c478bd9Sstevel@tonic-gate
44177c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
44187c478bd9Sstevel@tonic-gate assert(np->rn_refs == 0);
44197c478bd9Sstevel@tonic-gate assert(np->rn_other_refs == 0);
44207c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held == 0);
44217c478bd9Sstevel@tonic-gate
44227c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD) {
44236643e1ffSbustos /*
44246643e1ffSbustos * The node is DEAD, so the deletion code should have
44256643e1ffSbustos * destroyed all rn_children or rn_former references.
44266643e1ffSbustos * Since the last client or child reference has been
44276643e1ffSbustos * destroyed, we're free to destroy np. Unless another
44286643e1ffSbustos * thread has an ephemeral reference, in which case we'll
44296643e1ffSbustos * pass the buck.
44306643e1ffSbustos */
44316643e1ffSbustos if (np->rn_erefs > 1) {
44326643e1ffSbustos --np->rn_erefs;
44336643e1ffSbustos NODE_UNLOCK(np);
44346643e1ffSbustos return;
44356643e1ffSbustos }
44366643e1ffSbustos
44377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44387c478bd9Sstevel@tonic-gate rc_node_destroy(np);
44397c478bd9Sstevel@tonic-gate return;
44407c478bd9Sstevel@tonic-gate }
44417c478bd9Sstevel@tonic-gate
44426643e1ffSbustos /* We only collect DEAD and OLD nodes, thank you. */
44437c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD);
44446643e1ffSbustos
44456643e1ffSbustos /*
44466643e1ffSbustos * RC_NODE_UNREFED keeps multiple threads from processing OLD
44476643e1ffSbustos * nodes. But it's vulnerable to unfriendly scheduling, so full
44486643e1ffSbustos * use of rn_erefs should supersede it someday.
44496643e1ffSbustos */
44507c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED) {
44517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44527c478bd9Sstevel@tonic-gate return;
44537c478bd9Sstevel@tonic-gate }
44547c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_UNREFED;
44557c478bd9Sstevel@tonic-gate
44566643e1ffSbustos /*
44576643e1ffSbustos * Now we'll remove the node from the rn_former chain and take its
44586643e1ffSbustos * DYING_FLAGS.
44596643e1ffSbustos */
44607c478bd9Sstevel@tonic-gate
44617c478bd9Sstevel@tonic-gate /*
44626643e1ffSbustos * Since this node is OLD, it should be on an rn_former chain. To
44636643e1ffSbustos * remove it, we must find the current in-hash object and grab its
44646643e1ffSbustos * RC_NODE_IN_TX flag to protect the entire rn_former chain.
44657c478bd9Sstevel@tonic-gate */
44666643e1ffSbustos
44676643e1ffSbustos (void) pthread_mutex_unlock(&np->rn_lock);
44686643e1ffSbustos
44697c478bd9Sstevel@tonic-gate for (;;) {
44706643e1ffSbustos current = cache_lookup(&np->rn_id);
44716643e1ffSbustos
44726643e1ffSbustos if (current == NULL) {
44737c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
44746643e1ffSbustos
44757c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD)
44767c478bd9Sstevel@tonic-gate goto died;
44776643e1ffSbustos
44787c478bd9Sstevel@tonic-gate /*
44797c478bd9Sstevel@tonic-gate * We are trying to unreference this node, but the
44807c478bd9Sstevel@tonic-gate * owner of the former list does not exist. It must
44817c478bd9Sstevel@tonic-gate * be the case that another thread is deleting this
44827c478bd9Sstevel@tonic-gate * entire sub-branch, but has not yet reached us.
44837c478bd9Sstevel@tonic-gate * We will in short order be deleted.
44847c478bd9Sstevel@tonic-gate */
44857c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
44867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44877c478bd9Sstevel@tonic-gate return;
44887c478bd9Sstevel@tonic-gate }
44896643e1ffSbustos
44906643e1ffSbustos if (current == np) {
44917c478bd9Sstevel@tonic-gate /*
44927c478bd9Sstevel@tonic-gate * no longer unreferenced
44937c478bd9Sstevel@tonic-gate */
44947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
44957c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
44966643e1ffSbustos /* held in cache_lookup() */
44977c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
44987c478bd9Sstevel@tonic-gate return;
44997c478bd9Sstevel@tonic-gate }
45006643e1ffSbustos
45016643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock);
45026643e1ffSbustos if (current->rn_flags & RC_NODE_OLD) {
45036643e1ffSbustos /*
45046643e1ffSbustos * current has been replaced since we looked it
45056643e1ffSbustos * up. Try again.
45066643e1ffSbustos */
45076643e1ffSbustos /* held in cache_lookup() */
45086643e1ffSbustos rc_node_rele_locked(current);
45097c478bd9Sstevel@tonic-gate continue;
45107c478bd9Sstevel@tonic-gate }
45116643e1ffSbustos
45126643e1ffSbustos if (!rc_node_hold_flag(current, RC_NODE_IN_TX)) {
45136643e1ffSbustos /*
45146643e1ffSbustos * current has been deleted since we looked it up. Try
45156643e1ffSbustos * again.
45166643e1ffSbustos */
45176643e1ffSbustos /* held in cache_lookup() */
45186643e1ffSbustos rc_node_rele_locked(current);
45196643e1ffSbustos continue;
45207c478bd9Sstevel@tonic-gate }
45217c478bd9Sstevel@tonic-gate
45226643e1ffSbustos /*
45236643e1ffSbustos * rc_node_hold_flag() might have dropped current's lock, so
45246643e1ffSbustos * check OLD again.
45256643e1ffSbustos */
45266643e1ffSbustos if (!(current->rn_flags & RC_NODE_OLD)) {
45276643e1ffSbustos /* Not old. Stop looping. */
45286643e1ffSbustos (void) pthread_mutex_unlock(¤t->rn_lock);
45296643e1ffSbustos break;
45306643e1ffSbustos }
45316643e1ffSbustos
45326643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45336643e1ffSbustos rc_node_rele_locked(current);
45346643e1ffSbustos }
45356643e1ffSbustos
45366643e1ffSbustos /* To take np's RC_NODE_DYING_FLAGS, we need its lock. */
45377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45386643e1ffSbustos
45396643e1ffSbustos /*
45406643e1ffSbustos * While we didn't have the lock, a thread may have added
45416643e1ffSbustos * a reference or changed the flags.
45426643e1ffSbustos */
45437c478bd9Sstevel@tonic-gate if (!(np->rn_flags & (RC_NODE_OLD | RC_NODE_DEAD)) ||
45447c478bd9Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 ||
45457c478bd9Sstevel@tonic-gate np->rn_other_refs_held != 0) {
45467c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
45477c478bd9Sstevel@tonic-gate
45486643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock);
45496643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45506643e1ffSbustos /* held by cache_lookup() */
45516643e1ffSbustos rc_node_rele_locked(current);
45527c478bd9Sstevel@tonic-gate return;
45537c478bd9Sstevel@tonic-gate }
45547c478bd9Sstevel@tonic-gate
45557c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
45566643e1ffSbustos /*
45576643e1ffSbustos * Someone deleted the node while we were waiting for
45586643e1ffSbustos * DYING_FLAGS. Undo the modifications to current.
45596643e1ffSbustos */
45607c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
45617c478bd9Sstevel@tonic-gate
45626643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45636643e1ffSbustos /* held by cache_lookup() */
45646643e1ffSbustos rc_node_rele_locked(current);
45657c478bd9Sstevel@tonic-gate
45667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45677c478bd9Sstevel@tonic-gate goto died;
45687c478bd9Sstevel@tonic-gate }
45697c478bd9Sstevel@tonic-gate
45706643e1ffSbustos /* Take RC_NODE_DYING_FLAGS on np's descendents. */
45716643e1ffSbustos rc_node_delete_hold(np, 0); /* drops np->rn_lock */
45727c478bd9Sstevel@tonic-gate
45736643e1ffSbustos /* Mark np DEAD. This requires the lock. */
45747c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45756643e1ffSbustos
45766643e1ffSbustos /* Recheck for new references. */
45777c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD) ||
45787c478bd9Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 ||
45797c478bd9Sstevel@tonic-gate np->rn_other_refs_held != 0) {
45807c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
45816643e1ffSbustos rc_node_delete_rele(np, 0); /* drops np's lock */
45827c478bd9Sstevel@tonic-gate
45836643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock);
45846643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45856643e1ffSbustos /* held by cache_lookup() */
45866643e1ffSbustos rc_node_rele_locked(current);
45877c478bd9Sstevel@tonic-gate return;
45887c478bd9Sstevel@tonic-gate }
45897c478bd9Sstevel@tonic-gate
45907c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD;
45917c478bd9Sstevel@tonic-gate
45927c478bd9Sstevel@tonic-gate /*
45936643e1ffSbustos * Delete the children. This calls rc_node_rele_locked() on np at
45946643e1ffSbustos * the end, so add a reference to keep the count from going
45956643e1ffSbustos * negative. It will recurse with RC_NODE_DEAD set, so we'll call
45966643e1ffSbustos * rc_node_destroy() above, but RC_NODE_UNREFED is also set, so it
45976643e1ffSbustos * shouldn't actually free() np.
45987c478bd9Sstevel@tonic-gate */
45996643e1ffSbustos rc_node_hold_locked(np);
46006643e1ffSbustos rc_node_delete_children(np, 0); /* unlocks np */
46016643e1ffSbustos
46026643e1ffSbustos /* Remove np from current's rn_former chain. */
46036643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock);
46046643e1ffSbustos for (cur = current; cur != NULL && cur->rn_former != np;
46057c478bd9Sstevel@tonic-gate cur = cur->rn_former)
46067c478bd9Sstevel@tonic-gate ;
46077c478bd9Sstevel@tonic-gate assert(cur != NULL && cur != np);
46087c478bd9Sstevel@tonic-gate
46097c478bd9Sstevel@tonic-gate cur->rn_former = np->rn_former;
46107c478bd9Sstevel@tonic-gate np->rn_former = NULL;
46117c478bd9Sstevel@tonic-gate
46126643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
46136643e1ffSbustos /* held by cache_lookup() */
46146643e1ffSbustos rc_node_rele_locked(current);
46157c478bd9Sstevel@tonic-gate
46166643e1ffSbustos /* Clear ON_FORMER and UNREFED, and destroy. */
46177c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
46187c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_ON_FORMER);
46197c478bd9Sstevel@tonic-gate np->rn_flags &= ~(RC_NODE_UNREFED | RC_NODE_ON_FORMER);
46206643e1ffSbustos
46216643e1ffSbustos if (np->rn_erefs > 1) {
46226643e1ffSbustos /* Still referenced. Stay execution. */
46236643e1ffSbustos --np->rn_erefs;
46246643e1ffSbustos NODE_UNLOCK(np);
46256643e1ffSbustos return;
46266643e1ffSbustos }
46276643e1ffSbustos
46287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
46297c478bd9Sstevel@tonic-gate rc_node_destroy(np);
46307c478bd9Sstevel@tonic-gate return;
46317c478bd9Sstevel@tonic-gate
46327c478bd9Sstevel@tonic-gate died:
46336643e1ffSbustos /*
46346643e1ffSbustos * Another thread marked np DEAD. If there still aren't any
46356643e1ffSbustos * persistent references, destroy the node.
46366643e1ffSbustos */
46377c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
46386643e1ffSbustos
46397c478bd9Sstevel@tonic-gate unrefed = (np->rn_refs == 0 && np->rn_other_refs == 0 &&
46407c478bd9Sstevel@tonic-gate np->rn_other_refs_held == 0);
46416643e1ffSbustos
46426643e1ffSbustos if (np->rn_erefs > 0)
46436643e1ffSbustos --np->rn_erefs;
46446643e1ffSbustos
46456643e1ffSbustos if (unrefed && np->rn_erefs > 0) {
46466643e1ffSbustos NODE_UNLOCK(np);
46476643e1ffSbustos return;
46486643e1ffSbustos }
46496643e1ffSbustos
46507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
46516643e1ffSbustos
46527c478bd9Sstevel@tonic-gate if (unrefed)
46537c478bd9Sstevel@tonic-gate rc_node_destroy(np);
46547c478bd9Sstevel@tonic-gate }
46557c478bd9Sstevel@tonic-gate
46565b7f77adStw21770 static au_event_t
get_delete_event_id(rep_protocol_entity_t entity,uint32_t pgflags)46575b7f77adStw21770 get_delete_event_id(rep_protocol_entity_t entity, uint32_t pgflags)
46585b7f77adStw21770 {
46595b7f77adStw21770 au_event_t id = 0;
46605b7f77adStw21770
46615b7f77adStw21770 #ifndef NATIVE_BUILD
46625b7f77adStw21770 switch (entity) {
46635b7f77adStw21770 case REP_PROTOCOL_ENTITY_SERVICE:
46645b7f77adStw21770 case REP_PROTOCOL_ENTITY_INSTANCE:
46655b7f77adStw21770 id = ADT_smf_delete;
46665b7f77adStw21770 break;
46675b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT:
46685b7f77adStw21770 id = ADT_smf_delete_snap;
46695b7f77adStw21770 break;
46705b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
46715b7f77adStw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
46725b7f77adStw21770 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) {
46735b7f77adStw21770 id = ADT_smf_delete_npg;
46745b7f77adStw21770 } else {
46755b7f77adStw21770 id = ADT_smf_delete_pg;
46765b7f77adStw21770 }
46775b7f77adStw21770 break;
46785b7f77adStw21770 default:
46795b7f77adStw21770 abort();
46805b7f77adStw21770 }
46815b7f77adStw21770 #endif /* NATIVE_BUILD */
46825b7f77adStw21770 return (id);
46835b7f77adStw21770 }
46845b7f77adStw21770
46857c478bd9Sstevel@tonic-gate /*
46867c478bd9Sstevel@tonic-gate * Fails with
46877c478bd9Sstevel@tonic-gate * _NOT_SET
46887c478bd9Sstevel@tonic-gate * _DELETED
46897c478bd9Sstevel@tonic-gate * _BAD_REQUEST
46907c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED
46917c478bd9Sstevel@tonic-gate * _NO_RESOURCES
46925b7f77adStw21770 * _TRUNCATED
46937c478bd9Sstevel@tonic-gate * and whatever object_delete() fails with.
46947c478bd9Sstevel@tonic-gate */
46957c478bd9Sstevel@tonic-gate int
rc_node_delete(rc_node_ptr_t * npp)46967c478bd9Sstevel@tonic-gate rc_node_delete(rc_node_ptr_t *npp)
46977c478bd9Sstevel@tonic-gate {
46987c478bd9Sstevel@tonic-gate rc_node_t *np, *np_orig;
46997c478bd9Sstevel@tonic-gate rc_node_t *pp = NULL;
47007c478bd9Sstevel@tonic-gate int rc;
47017c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
47027c478bd9Sstevel@tonic-gate cache_bucket_t *bp;
47037c478bd9Sstevel@tonic-gate rc_notify_delete_t *ndp;
47047c478bd9Sstevel@tonic-gate permcheck_t *pcp;
47057c478bd9Sstevel@tonic-gate int granted;
47065b7f77adStw21770 au_event_t event_id = 0;
47075b7f77adStw21770 size_t sz_out;
47085b7f77adStw21770 audit_event_data_t audit_data;
47095b7f77adStw21770 int audit_failure = 0;
47107c478bd9Sstevel@tonic-gate
47117c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
47127c478bd9Sstevel@tonic-gate
47135b7f77adStw21770 audit_data.ed_fmri = NULL;
47145b7f77adStw21770 audit_data.ed_auth = NULL;
47155b7f77adStw21770 audit_data.ed_snapname = NULL;
47165b7f77adStw21770 audit_data.ed_type = NULL;
47175b7f77adStw21770
47187c478bd9Sstevel@tonic-gate switch (np->rn_id.rl_type) {
47197c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE:
47205b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SERVICE,
47215b7f77adStw21770 np->rn_pgflags);
47225b7f77adStw21770 break;
47237c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE:
47245b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_INSTANCE,
47255b7f77adStw21770 np->rn_pgflags);
47265b7f77adStw21770 break;
47277c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT:
47285b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SNAPSHOT,
47295b7f77adStw21770 np->rn_pgflags);
47305b7f77adStw21770 audit_data.ed_snapname = strdup(np->rn_name);
47315b7f77adStw21770 if (audit_data.ed_snapname == NULL) {
47325b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
47335b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
47345b7f77adStw21770 }
47357c478bd9Sstevel@tonic-gate break; /* deletable */
47367c478bd9Sstevel@tonic-gate
47377c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE:
47387c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL:
47397c478bd9Sstevel@tonic-gate /* Scopes and snaplevels are indelible. */
47407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
47427c478bd9Sstevel@tonic-gate
47437c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
47447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47457c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
47467c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
47475b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_CPROPERTYGRP,
47485b7f77adStw21770 np->rn_pgflags);
47497c478bd9Sstevel@tonic-gate break;
47507c478bd9Sstevel@tonic-gate
47517c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP:
47525b7f77adStw21770 if (np->rn_id.rl_ids[ID_SNAPSHOT] == 0) {
47535b7f77adStw21770 event_id =
47545b7f77adStw21770 get_delete_event_id(REP_PROTOCOL_ENTITY_PROPERTYGRP,
47555b7f77adStw21770 np->rn_pgflags);
47565b7f77adStw21770 audit_data.ed_type = strdup(np->rn_type);
47575b7f77adStw21770 if (audit_data.ed_type == NULL) {
47585b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
47595b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
47605b7f77adStw21770 }
47617c478bd9Sstevel@tonic-gate break;
47625b7f77adStw21770 }
47637c478bd9Sstevel@tonic-gate
47647c478bd9Sstevel@tonic-gate /* Snapshot property groups are indelible. */
47657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
47677c478bd9Sstevel@tonic-gate
47687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY:
47697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47707c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
47717c478bd9Sstevel@tonic-gate
47727c478bd9Sstevel@tonic-gate default:
47737c478bd9Sstevel@tonic-gate assert(0);
47747c478bd9Sstevel@tonic-gate abort();
47757c478bd9Sstevel@tonic-gate break;
47767c478bd9Sstevel@tonic-gate }
47777c478bd9Sstevel@tonic-gate
47785b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
47795b7f77adStw21770 if (audit_data.ed_fmri == NULL) {
47805b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
47815b7f77adStw21770 goto cleanout;
47825b7f77adStw21770 }
47837c478bd9Sstevel@tonic-gate np_orig = np;
47847c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies rest of the code */
47857c478bd9Sstevel@tonic-gate
47867c478bd9Sstevel@tonic-gate again:
47877c478bd9Sstevel@tonic-gate /*
47887c478bd9Sstevel@tonic-gate * The following loop is to deal with the fact that snapshots and
47897c478bd9Sstevel@tonic-gate * property groups are moving targets -- changes to them result
47907c478bd9Sstevel@tonic-gate * in a new "child" node. Since we can only delete from the top node,
47917c478bd9Sstevel@tonic-gate * we have to loop until we have a non-RC_NODE_OLD version.
47927c478bd9Sstevel@tonic-gate */
47937c478bd9Sstevel@tonic-gate for (;;) {
47947c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np,
47957c478bd9Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
47967c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
47975b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
47985b7f77adStw21770 goto cleanout;
47997c478bd9Sstevel@tonic-gate }
48007c478bd9Sstevel@tonic-gate
48017c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
48027c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
48037c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
48047c478bd9Sstevel@tonic-gate assert(np != np_orig);
48057c478bd9Sstevel@tonic-gate
48067c478bd9Sstevel@tonic-gate if (np == NULL) {
48077c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED;
48087c478bd9Sstevel@tonic-gate goto fail;
48097c478bd9Sstevel@tonic-gate }
48107c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48117c478bd9Sstevel@tonic-gate continue;
48127c478bd9Sstevel@tonic-gate }
48137c478bd9Sstevel@tonic-gate
48147c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
48157c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
48167c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
48175b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
48187c478bd9Sstevel@tonic-gate }
48197c478bd9Sstevel@tonic-gate
48207c478bd9Sstevel@tonic-gate /*
48217c478bd9Sstevel@tonic-gate * Mark our parent as children changing. this call drops our
48227c478bd9Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with
48237c478bd9Sstevel@tonic-gate * pp's lock held
48247c478bd9Sstevel@tonic-gate */
48257c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
48267c478bd9Sstevel@tonic-gate if (pp == NULL) {
48277c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */
48287c478bd9Sstevel@tonic-gate rc_node_rele(np);
48297c478bd9Sstevel@tonic-gate
48307c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
48315b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
48325b7f77adStw21770 goto cleanout;
48337c478bd9Sstevel@tonic-gate }
48347c478bd9Sstevel@tonic-gate
48357c478bd9Sstevel@tonic-gate rc_node_hold_locked(pp); /* hold for later */
48367c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
48377c478bd9Sstevel@tonic-gate
48387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48397c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD))
48407c478bd9Sstevel@tonic-gate break; /* not old -- we're done */
48417c478bd9Sstevel@tonic-gate
48427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
48437c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
48447c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
48457c478bd9Sstevel@tonic-gate rc_node_rele_locked(pp);
48467c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48477c478bd9Sstevel@tonic-gate continue; /* loop around and try again */
48487c478bd9Sstevel@tonic-gate }
48497c478bd9Sstevel@tonic-gate /*
48507c478bd9Sstevel@tonic-gate * Everyone out of the pool -- we grab everything but
48517c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT (including RC_NODE_DYING) to keep
48527c478bd9Sstevel@tonic-gate * any changes from occurring while we are attempting to
48537c478bd9Sstevel@tonic-gate * delete the node.
48547c478bd9Sstevel@tonic-gate */
48557c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
48567c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
48577c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED;
48587c478bd9Sstevel@tonic-gate goto fail;
48597c478bd9Sstevel@tonic-gate }
48607c478bd9Sstevel@tonic-gate
48617c478bd9Sstevel@tonic-gate assert(!(np->rn_flags & RC_NODE_OLD));
48627c478bd9Sstevel@tonic-gate
48635b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
48645b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
48655b7f77adStw21770 rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
4866582271e8Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
48675b7f77adStw21770 goto fail;
48685b7f77adStw21770 }
4869273264cdSdm120769
4870273264cdSdm120769 #ifdef NATIVE_BUILD
48715b7f77adStw21770 if (!client_is_privileged()) {
4872273264cdSdm120769 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
48735b7f77adStw21770 }
4874273264cdSdm120769 #else
48755b7f77adStw21770 if (is_main_repository) {
48765b7f77adStw21770 /* permission check */
48775b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
48787c478bd9Sstevel@tonic-gate pcp = pc_create();
48797c478bd9Sstevel@tonic-gate if (pcp != NULL) {
48807c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
48817c478bd9Sstevel@tonic-gate
48827c478bd9Sstevel@tonic-gate /* add .smf.modify.<type> for pgs. */
48837c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && np->rn_id.rl_type ==
48847c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP) {
48857c478bd9Sstevel@tonic-gate const char * const auth =
48867c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
48877c478bd9Sstevel@tonic-gate
48887c478bd9Sstevel@tonic-gate if (auth != NULL)
48897c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
48907c478bd9Sstevel@tonic-gate }
48917c478bd9Sstevel@tonic-gate
48927c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
48937c478bd9Sstevel@tonic-gate granted = perm_granted(pcp);
48947c478bd9Sstevel@tonic-gate
4895a4dc1477STom Whitten rc = map_granted_status(granted, pcp,
4896a4dc1477STom Whitten &audit_data.ed_auth);
4897a4dc1477STom Whitten if (granted == PERM_GONE) {
4898a4dc1477STom Whitten /* No need to audit if client gone. */
4899a4dc1477STom Whitten pc_free(pcp);
4900a4dc1477STom Whitten rc_node_rele_flag(np,
4901a4dc1477STom Whitten RC_NODE_DYING_FLAGS);
4902a4dc1477STom Whitten return (rc);
49035b7f77adStw21770 }
4904a4dc1477STom Whitten if (granted == PERM_DENIED)
4905a4dc1477STom Whitten audit_failure = 1;
49067c478bd9Sstevel@tonic-gate }
49077c478bd9Sstevel@tonic-gate
49087c478bd9Sstevel@tonic-gate pc_free(pcp);
49097c478bd9Sstevel@tonic-gate } else {
49107c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
49117c478bd9Sstevel@tonic-gate }
49127c478bd9Sstevel@tonic-gate
49135b7f77adStw21770 (void) pthread_mutex_lock(&np->rn_lock);
49145b7f77adStw21770 } else {
49155b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
49165b7f77adStw21770 }
49177c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
49187c478bd9Sstevel@tonic-gate
49197c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
49207c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
49217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
49227c478bd9Sstevel@tonic-gate goto fail;
49237c478bd9Sstevel@tonic-gate }
49247c478bd9Sstevel@tonic-gate
49257c478bd9Sstevel@tonic-gate ndp = uu_zalloc(sizeof (*ndp));
49267c478bd9Sstevel@tonic-gate if (ndp == NULL) {
49277c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
49287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
49297c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
49307c478bd9Sstevel@tonic-gate goto fail;
49317c478bd9Sstevel@tonic-gate }
49327c478bd9Sstevel@tonic-gate
49337c478bd9Sstevel@tonic-gate rc_node_delete_hold(np, 1); /* hold entire subgraph, drop lock */
49347c478bd9Sstevel@tonic-gate
49357c478bd9Sstevel@tonic-gate rc = object_delete(np);
49367c478bd9Sstevel@tonic-gate
49377c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
49387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49397c478bd9Sstevel@tonic-gate rc_node_delete_rele(np, 1); /* drops lock */
49407c478bd9Sstevel@tonic-gate uu_free(ndp);
49417c478bd9Sstevel@tonic-gate goto fail;
49427c478bd9Sstevel@tonic-gate }
49437c478bd9Sstevel@tonic-gate
49447c478bd9Sstevel@tonic-gate /*
49457c478bd9Sstevel@tonic-gate * Now, delicately unlink and delete the object.
49467c478bd9Sstevel@tonic-gate *
49477c478bd9Sstevel@tonic-gate * Create the delete notification, atomically remove
49487c478bd9Sstevel@tonic-gate * from the hash table and set the NODE_DEAD flag, and
49497c478bd9Sstevel@tonic-gate * remove from the parent's children list.
49507c478bd9Sstevel@tonic-gate */
49517c478bd9Sstevel@tonic-gate rc_notify_node_delete(ndp, np); /* frees or uses ndp */
49527c478bd9Sstevel@tonic-gate
49537c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
49547c478bd9Sstevel@tonic-gate
49557c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49567c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, np);
49577c478bd9Sstevel@tonic-gate cache_release(bp);
49587c478bd9Sstevel@tonic-gate
49597c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD;
49607c478bd9Sstevel@tonic-gate
49616643e1ffSbustos if (pp != NULL) {
49626643e1ffSbustos /*
49636643e1ffSbustos * Remove from pp's rn_children. This requires pp's lock,
49646643e1ffSbustos * so we must drop np's lock to respect lock order.
49656643e1ffSbustos */
49666643e1ffSbustos (void) pthread_mutex_unlock(&np->rn_lock);
49677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
49687c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49696643e1ffSbustos
49707c478bd9Sstevel@tonic-gate uu_list_remove(pp->rn_children, np);
49716643e1ffSbustos
49727c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
49736643e1ffSbustos
49747c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
49756643e1ffSbustos
49767c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT;
49777c478bd9Sstevel@tonic-gate }
49786643e1ffSbustos
49797c478bd9Sstevel@tonic-gate /*
49806643e1ffSbustos * finally, propagate death to our children (including marking
49816643e1ffSbustos * them DEAD), handle notifications, and release our hold.
49827c478bd9Sstevel@tonic-gate */
49837c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* hold for delete */
49847c478bd9Sstevel@tonic-gate rc_node_delete_children(np, 1); /* drops DYING_FLAGS, lock, ref */
49857c478bd9Sstevel@tonic-gate
49867c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
49877c478bd9Sstevel@tonic-gate
49887c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
49897c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
49907c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp);
49917c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
49927c478bd9Sstevel@tonic-gate rc_notify_remove_node(np);
49937c478bd9Sstevel@tonic-gate
49947c478bd9Sstevel@tonic-gate rc_node_rele(np);
49957c478bd9Sstevel@tonic-gate
49965b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
49975b7f77adStw21770 &audit_data);
49985b7f77adStw21770 free(audit_data.ed_auth);
49995b7f77adStw21770 free(audit_data.ed_snapname);
50005b7f77adStw21770 free(audit_data.ed_type);
50015b7f77adStw21770 free(audit_data.ed_fmri);
50027c478bd9Sstevel@tonic-gate return (rc);
50037c478bd9Sstevel@tonic-gate
50047c478bd9Sstevel@tonic-gate fail:
50057c478bd9Sstevel@tonic-gate rc_node_rele(np);
50067c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_FAIL_DELETED)
50077c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
50087c478bd9Sstevel@tonic-gate if (pp != NULL) {
50097c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
50107c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
50117c478bd9Sstevel@tonic-gate rc_node_rele_locked(pp); /* drop ref and lock */
50127c478bd9Sstevel@tonic-gate }
50135b7f77adStw21770 if (audit_failure) {
50145b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE,
50155b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
50165b7f77adStw21770 }
50175b7f77adStw21770 cleanout:
50185b7f77adStw21770 free(audit_data.ed_auth);
50195b7f77adStw21770 free(audit_data.ed_snapname);
50205b7f77adStw21770 free(audit_data.ed_type);
50215b7f77adStw21770 free(audit_data.ed_fmri);
50227c478bd9Sstevel@tonic-gate return (rc);
50237c478bd9Sstevel@tonic-gate }
50247c478bd9Sstevel@tonic-gate
50257c478bd9Sstevel@tonic-gate int
rc_node_next_snaplevel(rc_node_ptr_t * npp,rc_node_ptr_t * cpp)50267c478bd9Sstevel@tonic-gate rc_node_next_snaplevel(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
50277c478bd9Sstevel@tonic-gate {
50287c478bd9Sstevel@tonic-gate rc_node_t *np;
50297c478bd9Sstevel@tonic-gate rc_node_t *cp, *pp;
50307c478bd9Sstevel@tonic-gate int res;
50317c478bd9Sstevel@tonic-gate
50327c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0);
50337c478bd9Sstevel@tonic-gate
50347c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
50357c478bd9Sstevel@tonic-gate
50367c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT &&
50377c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) {
50387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
50407c478bd9Sstevel@tonic-gate }
50417c478bd9Sstevel@tonic-gate
50427c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
50437c478bd9Sstevel@tonic-gate if ((res = rc_node_fill_children(np,
50447c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL)) != REP_PROTOCOL_SUCCESS) {
50457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50467c478bd9Sstevel@tonic-gate return (res);
50477c478bd9Sstevel@tonic-gate }
50487c478bd9Sstevel@tonic-gate
50497c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children);
50507c478bd9Sstevel@tonic-gate cp != NULL;
50517c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
50527c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
50537c478bd9Sstevel@tonic-gate continue;
50547c478bd9Sstevel@tonic-gate rc_node_hold(cp);
50557c478bd9Sstevel@tonic-gate break;
50567c478bd9Sstevel@tonic-gate }
50577c478bd9Sstevel@tonic-gate
50587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50597c478bd9Sstevel@tonic-gate } else {
5060a4dc1477STom Whitten if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
5061a4dc1477STom Whitten (void) pthread_mutex_unlock(&np->rn_lock);
5062a4dc1477STom Whitten rc_node_clear(npp, 1);
5063a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_DELETED);
5064a4dc1477STom Whitten }
5065a4dc1477STom Whitten
50667c478bd9Sstevel@tonic-gate /*
50677c478bd9Sstevel@tonic-gate * mark our parent as children changing. This call drops our
50687c478bd9Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with
50697c478bd9Sstevel@tonic-gate * pp's lock held
50707c478bd9Sstevel@tonic-gate */
50717c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
50727c478bd9Sstevel@tonic-gate if (pp == NULL) {
50737c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */
50747c478bd9Sstevel@tonic-gate
50757c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1);
50767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
50777c478bd9Sstevel@tonic-gate }
50787c478bd9Sstevel@tonic-gate
50797c478bd9Sstevel@tonic-gate /*
50807c478bd9Sstevel@tonic-gate * find the next snaplevel
50817c478bd9Sstevel@tonic-gate */
50827c478bd9Sstevel@tonic-gate cp = np;
50837c478bd9Sstevel@tonic-gate while ((cp = uu_list_next(pp->rn_children, cp)) != NULL &&
50847c478bd9Sstevel@tonic-gate cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
50857c478bd9Sstevel@tonic-gate ;
50867c478bd9Sstevel@tonic-gate
50877c478bd9Sstevel@tonic-gate /* it must match the snaplevel list */
50887c478bd9Sstevel@tonic-gate assert((cp == NULL && np->rn_snaplevel->rsl_next == NULL) ||
50897c478bd9Sstevel@tonic-gate (cp != NULL && np->rn_snaplevel->rsl_next ==
50907c478bd9Sstevel@tonic-gate cp->rn_snaplevel));
50917c478bd9Sstevel@tonic-gate
50927c478bd9Sstevel@tonic-gate if (cp != NULL)
50937c478bd9Sstevel@tonic-gate rc_node_hold(cp);
50947c478bd9Sstevel@tonic-gate
50957c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
50967c478bd9Sstevel@tonic-gate
50977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
50987c478bd9Sstevel@tonic-gate }
50997c478bd9Sstevel@tonic-gate
51007c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp);
51017c478bd9Sstevel@tonic-gate if (cp != NULL) {
51027c478bd9Sstevel@tonic-gate rc_node_rele(cp);
51037c478bd9Sstevel@tonic-gate
51047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
51057c478bd9Sstevel@tonic-gate }
51067c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
51077c478bd9Sstevel@tonic-gate }
51087c478bd9Sstevel@tonic-gate
51097c478bd9Sstevel@tonic-gate /*
51107c478bd9Sstevel@tonic-gate * This call takes a snapshot (np) and either:
51117c478bd9Sstevel@tonic-gate * an existing snapid (to be associated with np), or
51127c478bd9Sstevel@tonic-gate * a non-NULL parentp (from which a new snapshot is taken, and associated
51137c478bd9Sstevel@tonic-gate * with np)
51147c478bd9Sstevel@tonic-gate *
51157c478bd9Sstevel@tonic-gate * To do the association, np is duplicated, the duplicate is made to
51167c478bd9Sstevel@tonic-gate * represent the new snapid, and np is replaced with the new rc_node_t on
51177c478bd9Sstevel@tonic-gate * np's parent's child list. np is placed on the new node's rn_former list,
51187c478bd9Sstevel@tonic-gate * and replaces np in cache_hash (so rc_node_update() will find the new one).
51195b7f77adStw21770 *
51205b7f77adStw21770 * old_fmri and old_name point to the original snap shot's FMRI and name.
51215b7f77adStw21770 * These values are used when generating audit events.
51225b7f77adStw21770 *
51235b7f77adStw21770 * Fails with
51245b7f77adStw21770 * _BAD_REQUEST
51255b7f77adStw21770 * _BACKEND_READONLY
51265b7f77adStw21770 * _DELETED
51275b7f77adStw21770 * _NO_RESOURCES
51285b7f77adStw21770 * _TRUNCATED
51295b7f77adStw21770 * _TYPE_MISMATCH
51307c478bd9Sstevel@tonic-gate */
51317c478bd9Sstevel@tonic-gate static int
rc_attach_snapshot(rc_node_t * np,uint32_t snapid,rc_node_t * parentp,char * old_fmri,char * old_name)51325b7f77adStw21770 rc_attach_snapshot(
51335b7f77adStw21770 rc_node_t *np,
51345b7f77adStw21770 uint32_t snapid,
51355b7f77adStw21770 rc_node_t *parentp,
51365b7f77adStw21770 char *old_fmri,
51375b7f77adStw21770 char *old_name)
51387c478bd9Sstevel@tonic-gate {
51397c478bd9Sstevel@tonic-gate rc_node_t *np_orig;
51407c478bd9Sstevel@tonic-gate rc_node_t *nnp, *prev;
51417c478bd9Sstevel@tonic-gate rc_node_t *pp;
51427c478bd9Sstevel@tonic-gate int rc;
51435b7f77adStw21770 size_t sz_out;
5144a4dc1477STom Whitten perm_status_t granted;
51455b7f77adStw21770 au_event_t event_id;
51465b7f77adStw21770 audit_event_data_t audit_data;
51477c478bd9Sstevel@tonic-gate
51485b7f77adStw21770 if (parentp == NULL) {
51495b7f77adStw21770 assert(old_fmri != NULL);
51505b7f77adStw21770 } else {
51517c478bd9Sstevel@tonic-gate assert(snapid == 0);
51525b7f77adStw21770 }
51537c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
51547c478bd9Sstevel@tonic-gate
51555b7f77adStw21770 /* Gather the audit data. */
51565b7f77adStw21770 /*
51575b7f77adStw21770 * ADT_smf_* symbols may not be defined in the /usr/include header
51585b7f77adStw21770 * files on the build machine. Thus, the following if-else will
51595b7f77adStw21770 * not be compiled when doing native builds.
51605b7f77adStw21770 */
51615b7f77adStw21770 #ifndef NATIVE_BUILD
51625b7f77adStw21770 if (parentp == NULL) {
51635b7f77adStw21770 event_id = ADT_smf_attach_snap;
51645b7f77adStw21770 } else {
51655b7f77adStw21770 event_id = ADT_smf_create_snap;
51665b7f77adStw21770 }
51675b7f77adStw21770 #endif /* NATIVE_BUILD */
51685b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
51695b7f77adStw21770 audit_data.ed_snapname = malloc(REP_PROTOCOL_NAME_LEN);
51705b7f77adStw21770 if ((audit_data.ed_fmri == NULL) || (audit_data.ed_snapname == NULL)) {
51715b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
51725b7f77adStw21770 free(audit_data.ed_fmri);
51735b7f77adStw21770 free(audit_data.ed_snapname);
51745b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
51755b7f77adStw21770 }
51765b7f77adStw21770 audit_data.ed_auth = NULL;
51775b7f77adStw21770 if (strlcpy(audit_data.ed_snapname, np->rn_name,
51785b7f77adStw21770 REP_PROTOCOL_NAME_LEN) >= REP_PROTOCOL_NAME_LEN) {
51795b7f77adStw21770 abort();
51805b7f77adStw21770 }
51815b7f77adStw21770 audit_data.ed_old_fmri = old_fmri;
51825b7f77adStw21770 audit_data.ed_old_name = old_name ? old_name : "NO NAME";
51835b7f77adStw21770
51845b7f77adStw21770 if (parentp == NULL) {
51855b7f77adStw21770 /*
51865b7f77adStw21770 * In the attach case, get the instance FMRIs of the
51875b7f77adStw21770 * snapshots.
51885b7f77adStw21770 */
51895b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
51905b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
51915b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
51925b7f77adStw21770 free(audit_data.ed_fmri);
51935b7f77adStw21770 free(audit_data.ed_snapname);
51945b7f77adStw21770 return (rc);
51955b7f77adStw21770 }
51965b7f77adStw21770 } else {
51975b7f77adStw21770 /*
51985b7f77adStw21770 * Capture the FMRI of the parent if we're actually going
51995b7f77adStw21770 * to take the snapshot.
52005b7f77adStw21770 */
52015b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(parentp,
52025b7f77adStw21770 audit_data.ed_fmri, REP_PROTOCOL_FMRI_LEN, &sz_out)) !=
52035b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
52045b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
52055b7f77adStw21770 free(audit_data.ed_fmri);
52065b7f77adStw21770 free(audit_data.ed_snapname);
52075b7f77adStw21770 return (rc);
52085b7f77adStw21770 }
52095b7f77adStw21770 }
52105b7f77adStw21770
52117c478bd9Sstevel@tonic-gate np_orig = np;
52127c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */
52137c478bd9Sstevel@tonic-gate
52143eae19d9Swesolows (void) pthread_mutex_unlock(&np->rn_lock);
5215a4dc1477STom Whitten granted = rc_node_modify_permission_check(&audit_data.ed_auth);
5216a4dc1477STom Whitten switch (granted) {
5217a4dc1477STom Whitten case PERM_DENIED:
52185b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE, ADT_FAIL_VALUE_AUTH,
52195b7f77adStw21770 &audit_data);
5220a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
5221a4dc1477STom Whitten rc_node_rele(np);
52225b7f77adStw21770 goto cleanout;
5223a4dc1477STom Whitten case PERM_GRANTED:
5224a4dc1477STom Whitten break;
5225a4dc1477STom Whitten case PERM_GONE:
5226a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
5227a4dc1477STom Whitten rc_node_rele(np);
5228a4dc1477STom Whitten goto cleanout;
5229a4dc1477STom Whitten case PERM_FAIL:
5230a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
5231a4dc1477STom Whitten rc_node_rele(np);
5232a4dc1477STom Whitten goto cleanout;
5233a4dc1477STom Whitten default:
5234a4dc1477STom Whitten bad_error(rc_node_modify_permission_check, granted);
52355b7f77adStw21770 }
52363eae19d9Swesolows (void) pthread_mutex_lock(&np->rn_lock);
52373eae19d9Swesolows
52387c478bd9Sstevel@tonic-gate /*
52397c478bd9Sstevel@tonic-gate * get the latest node, holding RC_NODE_IN_TX to keep the rn_former
52407c478bd9Sstevel@tonic-gate * list from changing.
52417c478bd9Sstevel@tonic-gate */
52427c478bd9Sstevel@tonic-gate for (;;) {
52437c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD)) {
52447c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
52457c478bd9Sstevel@tonic-gate goto again;
52467c478bd9Sstevel@tonic-gate }
52477c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np,
52487c478bd9Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING);
52497c478bd9Sstevel@tonic-gate
52507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
52517c478bd9Sstevel@tonic-gate if (pp == NULL) {
52527c478bd9Sstevel@tonic-gate goto again;
52537c478bd9Sstevel@tonic-gate }
52547c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
52557c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp,
52567c478bd9Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING);
52577c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
52587c478bd9Sstevel@tonic-gate goto again;
52597c478bd9Sstevel@tonic-gate }
52607c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
52617c478bd9Sstevel@tonic-gate
52627c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
52637c478bd9Sstevel@tonic-gate /*
52647c478bd9Sstevel@tonic-gate * Can't happen, since we're holding our
52657c478bd9Sstevel@tonic-gate * parent's CHILDREN_CHANGING flag...
52667c478bd9Sstevel@tonic-gate */
52677c478bd9Sstevel@tonic-gate abort();
52687c478bd9Sstevel@tonic-gate }
52697c478bd9Sstevel@tonic-gate break; /* everything's ready */
52707c478bd9Sstevel@tonic-gate }
52717c478bd9Sstevel@tonic-gate again:
52727c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
52737c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
52747c478bd9Sstevel@tonic-gate
52755b7f77adStw21770 if (np == NULL) {
52765b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
52775b7f77adStw21770 goto cleanout;
52785b7f77adStw21770 }
52797c478bd9Sstevel@tonic-gate
52807c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
52817c478bd9Sstevel@tonic-gate }
52827c478bd9Sstevel@tonic-gate
52837c478bd9Sstevel@tonic-gate if (parentp != NULL) {
52847c478bd9Sstevel@tonic-gate if (pp != parentp) {
52857c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
52867c478bd9Sstevel@tonic-gate goto fail;
52877c478bd9Sstevel@tonic-gate }
52887c478bd9Sstevel@tonic-gate nnp = NULL;
52897c478bd9Sstevel@tonic-gate } else {
52907c478bd9Sstevel@tonic-gate /*
52917c478bd9Sstevel@tonic-gate * look for a former node with the snapid we need.
52927c478bd9Sstevel@tonic-gate */
52937c478bd9Sstevel@tonic-gate if (np->rn_snapshot_id == snapid) {
52947c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
52957c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
52967c478bd9Sstevel@tonic-gate
52977c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
52987c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
52997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
53005b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; /* nothing to do */
53015b7f77adStw21770 goto cleanout;
53027c478bd9Sstevel@tonic-gate }
53037c478bd9Sstevel@tonic-gate
53047c478bd9Sstevel@tonic-gate prev = np;
53057c478bd9Sstevel@tonic-gate while ((nnp = prev->rn_former) != NULL) {
53067c478bd9Sstevel@tonic-gate if (nnp->rn_snapshot_id == snapid) {
53077c478bd9Sstevel@tonic-gate rc_node_hold(nnp);
53087c478bd9Sstevel@tonic-gate break; /* existing node with that id */
53097c478bd9Sstevel@tonic-gate }
53107c478bd9Sstevel@tonic-gate prev = nnp;
53117c478bd9Sstevel@tonic-gate }
53127c478bd9Sstevel@tonic-gate }
53137c478bd9Sstevel@tonic-gate
53147c478bd9Sstevel@tonic-gate if (nnp == NULL) {
53157c478bd9Sstevel@tonic-gate prev = NULL;
53167c478bd9Sstevel@tonic-gate nnp = rc_node_alloc();
53177c478bd9Sstevel@tonic-gate if (nnp == NULL) {
53187c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
53197c478bd9Sstevel@tonic-gate goto fail;
53207c478bd9Sstevel@tonic-gate }
53217c478bd9Sstevel@tonic-gate
53227c478bd9Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */
53237c478bd9Sstevel@tonic-gate nnp->rn_hash = np->rn_hash;
53247c478bd9Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name);
53257c478bd9Sstevel@tonic-gate nnp->rn_snapshot_id = snapid;
53267c478bd9Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
53277c478bd9Sstevel@tonic-gate
53287c478bd9Sstevel@tonic-gate if (nnp->rn_name == NULL) {
53297c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
53307c478bd9Sstevel@tonic-gate goto fail;
53317c478bd9Sstevel@tonic-gate }
53327c478bd9Sstevel@tonic-gate }
53337c478bd9Sstevel@tonic-gate
53347c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
53357c478bd9Sstevel@tonic-gate
53367c478bd9Sstevel@tonic-gate rc = object_snapshot_attach(&np->rn_id, &snapid, (parentp != NULL));
53377c478bd9Sstevel@tonic-gate
53387c478bd9Sstevel@tonic-gate if (parentp != NULL)
53397c478bd9Sstevel@tonic-gate nnp->rn_snapshot_id = snapid; /* fill in new snapid */
53407c478bd9Sstevel@tonic-gate else
53417c478bd9Sstevel@tonic-gate assert(nnp->rn_snapshot_id == snapid);
53427c478bd9Sstevel@tonic-gate
53437c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
53447c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
53457c478bd9Sstevel@tonic-gate goto fail;
53467c478bd9Sstevel@tonic-gate
53477c478bd9Sstevel@tonic-gate /*
53487c478bd9Sstevel@tonic-gate * fix up the former chain
53497c478bd9Sstevel@tonic-gate */
53507c478bd9Sstevel@tonic-gate if (prev != NULL) {
53517c478bd9Sstevel@tonic-gate prev->rn_former = nnp->rn_former;
53527c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock);
53537c478bd9Sstevel@tonic-gate nnp->rn_flags &= ~RC_NODE_ON_FORMER;
53547c478bd9Sstevel@tonic-gate nnp->rn_former = NULL;
53557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
53567c478bd9Sstevel@tonic-gate }
53577c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD;
53587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
53597c478bd9Sstevel@tonic-gate
53607c478bd9Sstevel@tonic-gate /*
53617c478bd9Sstevel@tonic-gate * replace np with nnp
53627c478bd9Sstevel@tonic-gate */
53637c478bd9Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp);
53647c478bd9Sstevel@tonic-gate
53657c478bd9Sstevel@tonic-gate rc_node_rele(np);
53665b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, &audit_data);
53675b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
53687c478bd9Sstevel@tonic-gate
53695b7f77adStw21770 cleanout:
53705b7f77adStw21770 free(audit_data.ed_auth);
53715b7f77adStw21770 free(audit_data.ed_fmri);
53725b7f77adStw21770 free(audit_data.ed_snapname);
53735b7f77adStw21770 return (rc);
53747c478bd9Sstevel@tonic-gate
53757c478bd9Sstevel@tonic-gate fail:
53767c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
53777c478bd9Sstevel@tonic-gate rc_node_rele_locked(np);
53787c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
53797c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
53807c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
53817c478bd9Sstevel@tonic-gate
53827c478bd9Sstevel@tonic-gate if (nnp != NULL) {
53837c478bd9Sstevel@tonic-gate if (prev == NULL)
53847c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
53857c478bd9Sstevel@tonic-gate else
53867c478bd9Sstevel@tonic-gate rc_node_rele(nnp);
53877c478bd9Sstevel@tonic-gate }
53887c478bd9Sstevel@tonic-gate
53895b7f77adStw21770 free(audit_data.ed_auth);
53905b7f77adStw21770 free(audit_data.ed_fmri);
53915b7f77adStw21770 free(audit_data.ed_snapname);
53927c478bd9Sstevel@tonic-gate return (rc);
53937c478bd9Sstevel@tonic-gate }
53947c478bd9Sstevel@tonic-gate
53957c478bd9Sstevel@tonic-gate int
rc_snapshot_take_new(rc_node_ptr_t * npp,const char * svcname,const char * instname,const char * name,rc_node_ptr_t * outpp)53967c478bd9Sstevel@tonic-gate rc_snapshot_take_new(rc_node_ptr_t *npp, const char *svcname,
53977c478bd9Sstevel@tonic-gate const char *instname, const char *name, rc_node_ptr_t *outpp)
53987c478bd9Sstevel@tonic-gate {
5399a4dc1477STom Whitten perm_status_t granted;
54007c478bd9Sstevel@tonic-gate rc_node_t *np;
54017c478bd9Sstevel@tonic-gate rc_node_t *outp = NULL;
54023eae19d9Swesolows int rc, perm_rc;
54035b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
54045b7f77adStw21770 audit_event_data_t audit_data;
54055b7f77adStw21770 size_t sz_out;
54067c478bd9Sstevel@tonic-gate
54077c478bd9Sstevel@tonic-gate rc_node_clear(outpp, 0);
54087c478bd9Sstevel@tonic-gate
5409a4dc1477STom Whitten /*
5410a4dc1477STom Whitten * rc_node_modify_permission_check() must be called before the node
5411a4dc1477STom Whitten * is locked. This is because the library functions that check
5412a4dc1477STom Whitten * authorizations can trigger calls back into configd.
5413a4dc1477STom Whitten */
5414a4dc1477STom Whitten granted = rc_node_modify_permission_check(&audit_data.ed_auth);
5415a4dc1477STom Whitten switch (granted) {
5416a4dc1477STom Whitten case PERM_DENIED:
5417a4dc1477STom Whitten /*
5418a4dc1477STom Whitten * We continue in this case, so that we can generate an
5419a4dc1477STom Whitten * audit event later in this function.
5420a4dc1477STom Whitten */
5421a4dc1477STom Whitten perm_rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
5422a4dc1477STom Whitten break;
5423a4dc1477STom Whitten case PERM_GRANTED:
5424a4dc1477STom Whitten perm_rc = REP_PROTOCOL_SUCCESS;
5425a4dc1477STom Whitten break;
5426a4dc1477STom Whitten case PERM_GONE:
5427a4dc1477STom Whitten /* No need to produce audit event if client is gone. */
5428a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
5429a4dc1477STom Whitten case PERM_FAIL:
5430a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_NO_RESOURCES);
5431a4dc1477STom Whitten default:
5432a4dc1477STom Whitten bad_error("rc_node_modify_permission_check", granted);
5433a4dc1477STom Whitten break;
5434a4dc1477STom Whitten }
54353eae19d9Swesolows
5436a4dc1477STom Whitten RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
54377c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
54387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54395b7f77adStw21770 free(audit_data.ed_auth);
54407c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
54417c478bd9Sstevel@tonic-gate }
54427c478bd9Sstevel@tonic-gate
54437c478bd9Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_SNAPSHOT, name);
54447c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
54457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54465b7f77adStw21770 free(audit_data.ed_auth);
54477c478bd9Sstevel@tonic-gate return (rc);
54487c478bd9Sstevel@tonic-gate }
54497c478bd9Sstevel@tonic-gate
54507c478bd9Sstevel@tonic-gate if (svcname != NULL && (rc =
54517c478bd9Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_SERVICE, svcname)) !=
54527c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
54537c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54545b7f77adStw21770 free(audit_data.ed_auth);
54557c478bd9Sstevel@tonic-gate return (rc);
54567c478bd9Sstevel@tonic-gate }
54577c478bd9Sstevel@tonic-gate
54587c478bd9Sstevel@tonic-gate if (instname != NULL && (rc =
54597c478bd9Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_INSTANCE, instname)) !=
54607c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
54617c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54625b7f77adStw21770 free(audit_data.ed_auth);
54637c478bd9Sstevel@tonic-gate return (rc);
54647c478bd9Sstevel@tonic-gate }
54657c478bd9Sstevel@tonic-gate
54665b7f77adStw21770 audit_data.ed_fmri = fmri;
54675b7f77adStw21770 audit_data.ed_snapname = (char *)name;
54685b7f77adStw21770
54695b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, sizeof (fmri),
54705b7f77adStw21770 &sz_out)) != REP_PROTOCOL_SUCCESS) {
54715b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock);
54725b7f77adStw21770 free(audit_data.ed_auth);
54735b7f77adStw21770 return (rc);
54745b7f77adStw21770 }
54753eae19d9Swesolows if (perm_rc != REP_PROTOCOL_SUCCESS) {
54767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54775b7f77adStw21770 smf_audit_event(ADT_smf_create_snap, ADT_FAILURE,
54785b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
54795b7f77adStw21770 free(audit_data.ed_auth);
54803eae19d9Swesolows return (perm_rc);
54817c478bd9Sstevel@tonic-gate }
54827c478bd9Sstevel@tonic-gate
54835b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
54845b7f77adStw21770 audit_data.ed_auth);
54857c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54867c478bd9Sstevel@tonic-gate
54877c478bd9Sstevel@tonic-gate rc = object_snapshot_take_new(np, svcname, instname, name, &outp);
54887c478bd9Sstevel@tonic-gate
54897c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
54907c478bd9Sstevel@tonic-gate rc_node_assign(outpp, outp);
54917c478bd9Sstevel@tonic-gate rc_node_rele(outp);
54927c478bd9Sstevel@tonic-gate }
54937c478bd9Sstevel@tonic-gate
54947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
54957c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
54967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54977c478bd9Sstevel@tonic-gate
54985b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) {
54995b7f77adStw21770 smf_audit_event(ADT_smf_create_snap, ADT_SUCCESS, ADT_SUCCESS,
55005b7f77adStw21770 &audit_data);
55015b7f77adStw21770 }
55025b7f77adStw21770 if (audit_data.ed_auth != NULL)
55035b7f77adStw21770 free(audit_data.ed_auth);
55047c478bd9Sstevel@tonic-gate return (rc);
55057c478bd9Sstevel@tonic-gate }
55067c478bd9Sstevel@tonic-gate
55077c478bd9Sstevel@tonic-gate int
rc_snapshot_take_attach(rc_node_ptr_t * npp,rc_node_ptr_t * outpp)55087c478bd9Sstevel@tonic-gate rc_snapshot_take_attach(rc_node_ptr_t *npp, rc_node_ptr_t *outpp)
55097c478bd9Sstevel@tonic-gate {
55107c478bd9Sstevel@tonic-gate rc_node_t *np, *outp;
55117c478bd9Sstevel@tonic-gate
55127c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
55137c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
55147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
55157c478bd9Sstevel@tonic-gate }
55167c478bd9Sstevel@tonic-gate
55177c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(outp, outpp);
55187c478bd9Sstevel@tonic-gate if (outp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&outp->rn_lock);
55207c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55217c478bd9Sstevel@tonic-gate }
55227c478bd9Sstevel@tonic-gate
55235b7f77adStw21770 return (rc_attach_snapshot(outp, 0, np, NULL,
55245b7f77adStw21770 NULL)); /* drops outp's lock */
55257c478bd9Sstevel@tonic-gate }
55267c478bd9Sstevel@tonic-gate
55277c478bd9Sstevel@tonic-gate int
rc_snapshot_attach(rc_node_ptr_t * npp,rc_node_ptr_t * cpp)55287c478bd9Sstevel@tonic-gate rc_snapshot_attach(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
55297c478bd9Sstevel@tonic-gate {
55307c478bd9Sstevel@tonic-gate rc_node_t *np;
55317c478bd9Sstevel@tonic-gate rc_node_t *cp;
55327c478bd9Sstevel@tonic-gate uint32_t snapid;
55335b7f77adStw21770 char old_name[REP_PROTOCOL_NAME_LEN];
55345b7f77adStw21770 int rc;
55355b7f77adStw21770 size_t sz_out;
55365b7f77adStw21770 char old_fmri[REP_PROTOCOL_FMRI_LEN];
55377c478bd9Sstevel@tonic-gate
55387c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
55397c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
55417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55427c478bd9Sstevel@tonic-gate }
55437c478bd9Sstevel@tonic-gate snapid = np->rn_snapshot_id;
55445b7f77adStw21770 rc = rc_node_get_fmri_or_fragment(np, old_fmri, sizeof (old_fmri),
55455b7f77adStw21770 &sz_out);
55467c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
55475b7f77adStw21770 if (rc != REP_PROTOCOL_SUCCESS)
55485b7f77adStw21770 return (rc);
55495b7f77adStw21770 if (np->rn_name != NULL) {
55505b7f77adStw21770 if (strlcpy(old_name, np->rn_name, sizeof (old_name)) >=
55515b7f77adStw21770 sizeof (old_name)) {
55525b7f77adStw21770 return (REP_PROTOCOL_FAIL_TRUNCATED);
55535b7f77adStw21770 }
55545b7f77adStw21770 }
55557c478bd9Sstevel@tonic-gate
55567c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(cp, cpp);
55577c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
55597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55607c478bd9Sstevel@tonic-gate }
55617c478bd9Sstevel@tonic-gate
55625b7f77adStw21770 rc = rc_attach_snapshot(cp, snapid, NULL,
55635b7f77adStw21770 old_fmri, old_name); /* drops cp's lock */
55645b7f77adStw21770 return (rc);
55657c478bd9Sstevel@tonic-gate }
55667c478bd9Sstevel@tonic-gate
55677c478bd9Sstevel@tonic-gate /*
55683eae19d9Swesolows * If the pgname property group under ent has type pgtype, and it has a
55693eae19d9Swesolows * propname property with type ptype, return _SUCCESS. If pgtype is NULL,
55703eae19d9Swesolows * it is not checked. If ent is not a service node, we will return _SUCCESS if
55713eae19d9Swesolows * a property meeting the requirements exists in either the instance or its
55723eae19d9Swesolows * parent.
55733eae19d9Swesolows *
55743eae19d9Swesolows * Returns
55753eae19d9Swesolows * _SUCCESS - see above
55763eae19d9Swesolows * _DELETED - ent or one of its ancestors was deleted
55773eae19d9Swesolows * _NO_RESOURCES - no resources
55783eae19d9Swesolows * _NOT_FOUND - no matching property was found
55793eae19d9Swesolows */
55803eae19d9Swesolows 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)55813eae19d9Swesolows rc_svc_prop_exists(rc_node_t *ent, const char *pgname, const char *pgtype,
55823eae19d9Swesolows const char *propname, rep_protocol_value_type_t ptype)
55833eae19d9Swesolows {
55843eae19d9Swesolows int ret;
55853eae19d9Swesolows rc_node_t *pg = NULL, *spg = NULL, *svc, *prop;
55863eae19d9Swesolows
55873eae19d9Swesolows assert(!MUTEX_HELD(&ent->rn_lock));
55883eae19d9Swesolows
55893eae19d9Swesolows (void) pthread_mutex_lock(&ent->rn_lock);
55903eae19d9Swesolows ret = rc_node_find_named_child(ent, pgname,
55913eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
55923eae19d9Swesolows (void) pthread_mutex_unlock(&ent->rn_lock);
55933eae19d9Swesolows
55943eae19d9Swesolows switch (ret) {
55953eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
55963eae19d9Swesolows break;
55973eae19d9Swesolows
55983eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED:
55993eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
56003eae19d9Swesolows return (ret);
56013eae19d9Swesolows
56023eae19d9Swesolows default:
56033eae19d9Swesolows bad_error("rc_node_find_named_child", ret);
56043eae19d9Swesolows }
56053eae19d9Swesolows
56063eae19d9Swesolows if (ent->rn_id.rl_type != REP_PROTOCOL_ENTITY_SERVICE) {
56073eae19d9Swesolows ret = rc_node_find_ancestor(ent, REP_PROTOCOL_ENTITY_SERVICE,
56083eae19d9Swesolows &svc);
56093eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) {
56103eae19d9Swesolows assert(ret == REP_PROTOCOL_FAIL_DELETED);
56113eae19d9Swesolows if (pg != NULL)
56123eae19d9Swesolows rc_node_rele(pg);
56133eae19d9Swesolows return (ret);
56143eae19d9Swesolows }
56153eae19d9Swesolows assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
56163eae19d9Swesolows
56173eae19d9Swesolows (void) pthread_mutex_lock(&svc->rn_lock);
56183eae19d9Swesolows ret = rc_node_find_named_child(svc, pgname,
56193eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &spg);
56203eae19d9Swesolows (void) pthread_mutex_unlock(&svc->rn_lock);
56213eae19d9Swesolows
56223eae19d9Swesolows rc_node_rele(svc);
56233eae19d9Swesolows
56243eae19d9Swesolows switch (ret) {
56253eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
56263eae19d9Swesolows break;
56273eae19d9Swesolows
56283eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED:
56293eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
56303eae19d9Swesolows if (pg != NULL)
56313eae19d9Swesolows rc_node_rele(pg);
56323eae19d9Swesolows return (ret);
56333eae19d9Swesolows
56343eae19d9Swesolows default:
56353eae19d9Swesolows bad_error("rc_node_find_named_child", ret);
56363eae19d9Swesolows }
56373eae19d9Swesolows }
56383eae19d9Swesolows
56393eae19d9Swesolows if (pg != NULL &&
56403eae19d9Swesolows pgtype != NULL && strcmp(pg->rn_type, pgtype) != 0) {
56413eae19d9Swesolows rc_node_rele(pg);
56423eae19d9Swesolows pg = NULL;
56433eae19d9Swesolows }
56443eae19d9Swesolows
56453eae19d9Swesolows if (spg != NULL &&
56463eae19d9Swesolows pgtype != NULL && strcmp(spg->rn_type, pgtype) != 0) {
56473eae19d9Swesolows rc_node_rele(spg);
56483eae19d9Swesolows spg = NULL;
56493eae19d9Swesolows }
56503eae19d9Swesolows
56513eae19d9Swesolows if (pg == NULL) {
56523eae19d9Swesolows if (spg == NULL)
56533eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
56543eae19d9Swesolows pg = spg;
56553eae19d9Swesolows spg = NULL;
56563eae19d9Swesolows }
56573eae19d9Swesolows
56583eae19d9Swesolows /*
56593eae19d9Swesolows * At this point, pg is non-NULL, and is a property group node of the
56603eae19d9Swesolows * correct type. spg, if non-NULL, is also a property group node of
56613eae19d9Swesolows * the correct type. Check for the property in pg first, then spg
56623eae19d9Swesolows * (if applicable).
56633eae19d9Swesolows */
56643eae19d9Swesolows (void) pthread_mutex_lock(&pg->rn_lock);
56653eae19d9Swesolows ret = rc_node_find_named_child(pg, propname,
56663eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop);
56673eae19d9Swesolows (void) pthread_mutex_unlock(&pg->rn_lock);
56683eae19d9Swesolows rc_node_rele(pg);
56693eae19d9Swesolows switch (ret) {
56703eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
56713eae19d9Swesolows if (prop != NULL) {
56723eae19d9Swesolows if (prop->rn_valtype == ptype) {
56733eae19d9Swesolows rc_node_rele(prop);
56743eae19d9Swesolows if (spg != NULL)
56753eae19d9Swesolows rc_node_rele(spg);
56763eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
56773eae19d9Swesolows }
56783eae19d9Swesolows rc_node_rele(prop);
56793eae19d9Swesolows }
56803eae19d9Swesolows break;
56813eae19d9Swesolows
56823eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
56833eae19d9Swesolows if (spg != NULL)
56843eae19d9Swesolows rc_node_rele(spg);
56853eae19d9Swesolows return (ret);
56863eae19d9Swesolows
56873eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED:
56883eae19d9Swesolows break;
56893eae19d9Swesolows
56903eae19d9Swesolows default:
56913eae19d9Swesolows bad_error("rc_node_find_named_child", ret);
56923eae19d9Swesolows }
56933eae19d9Swesolows
56943eae19d9Swesolows if (spg == NULL)
56953eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
56963eae19d9Swesolows
56973eae19d9Swesolows pg = spg;
56983eae19d9Swesolows
56993eae19d9Swesolows (void) pthread_mutex_lock(&pg->rn_lock);
57003eae19d9Swesolows ret = rc_node_find_named_child(pg, propname,
57013eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop);
57023eae19d9Swesolows (void) pthread_mutex_unlock(&pg->rn_lock);
57033eae19d9Swesolows rc_node_rele(pg);
57043eae19d9Swesolows switch (ret) {
57053eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
57063eae19d9Swesolows if (prop != NULL) {
57073eae19d9Swesolows if (prop->rn_valtype == ptype) {
57083eae19d9Swesolows rc_node_rele(prop);
57093eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
57103eae19d9Swesolows }
57113eae19d9Swesolows rc_node_rele(prop);
57123eae19d9Swesolows }
57133eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
57143eae19d9Swesolows
57153eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
57163eae19d9Swesolows return (ret);
57173eae19d9Swesolows
57183eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED:
57193eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
57203eae19d9Swesolows
57213eae19d9Swesolows default:
57223eae19d9Swesolows bad_error("rc_node_find_named_child", ret);
57233eae19d9Swesolows }
57243eae19d9Swesolows
57253eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
57263eae19d9Swesolows }
57273eae19d9Swesolows
57283eae19d9Swesolows /*
57293eae19d9Swesolows * Given a property group node, returns _SUCCESS if the property group may
57303eae19d9Swesolows * be read without any special authorization.
57313eae19d9Swesolows *
57323eae19d9Swesolows * Fails with:
57333eae19d9Swesolows * _DELETED - np or an ancestor node was deleted
57343eae19d9Swesolows * _TYPE_MISMATCH - np does not refer to a property group
57353eae19d9Swesolows * _NO_RESOURCES - no resources
57363eae19d9Swesolows * _PERMISSION_DENIED - authorization is required
57373eae19d9Swesolows */
57383eae19d9Swesolows static int
rc_node_pg_check_read_protect(rc_node_t * np)57393eae19d9Swesolows rc_node_pg_check_read_protect(rc_node_t *np)
57403eae19d9Swesolows {
57413eae19d9Swesolows int ret;
57423eae19d9Swesolows rc_node_t *ent;
57433eae19d9Swesolows
57443eae19d9Swesolows assert(!MUTEX_HELD(&np->rn_lock));
57453eae19d9Swesolows
57463eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
57473eae19d9Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
57483eae19d9Swesolows
57493eae19d9Swesolows if (strcmp(np->rn_type, SCF_GROUP_FRAMEWORK) == 0 ||
57503eae19d9Swesolows strcmp(np->rn_type, SCF_GROUP_DEPENDENCY) == 0 ||
57513eae19d9Swesolows strcmp(np->rn_type, SCF_GROUP_METHOD) == 0)
57523eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
57533eae19d9Swesolows
57543eae19d9Swesolows ret = rc_node_parent(np, &ent);
57553eae19d9Swesolows
57563eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS)
57573eae19d9Swesolows return (ret);
57583eae19d9Swesolows
57593eae19d9Swesolows ret = rc_svc_prop_exists(ent, np->rn_name, np->rn_type,
57603eae19d9Swesolows AUTH_PROP_READ, REP_PROTOCOL_TYPE_STRING);
57613eae19d9Swesolows
57623eae19d9Swesolows rc_node_rele(ent);
57633eae19d9Swesolows
57643eae19d9Swesolows switch (ret) {
57653eae19d9Swesolows case REP_PROTOCOL_FAIL_NOT_FOUND:
57663eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
57673eae19d9Swesolows case REP_PROTOCOL_SUCCESS:
57683eae19d9Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
57693eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED:
57703eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
57713eae19d9Swesolows return (ret);
57723eae19d9Swesolows default:
57733eae19d9Swesolows bad_error("rc_svc_prop_exists", ret);
57743eae19d9Swesolows }
57753eae19d9Swesolows
57763eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
57773eae19d9Swesolows }
57783eae19d9Swesolows
57793eae19d9Swesolows /*
57803eae19d9Swesolows * Fails with
57813eae19d9Swesolows * _DELETED - np's node or parent has been deleted
57823eae19d9Swesolows * _TYPE_MISMATCH - np's node is not a property
57833eae19d9Swesolows * _NO_RESOURCES - out of memory
57843eae19d9Swesolows * _PERMISSION_DENIED - no authorization to read this property's value(s)
57853eae19d9Swesolows * _BAD_REQUEST - np's parent is not a property group
57863eae19d9Swesolows */
57873eae19d9Swesolows static int
rc_node_property_may_read(rc_node_t * np)57883eae19d9Swesolows rc_node_property_may_read(rc_node_t *np)
57893eae19d9Swesolows {
5790a4dc1477STom Whitten int ret;
5791a4dc1477STom Whitten perm_status_t granted = PERM_DENIED;
57923eae19d9Swesolows rc_node_t *pgp;
57933eae19d9Swesolows permcheck_t *pcp;
57945b7f77adStw21770 audit_event_data_t audit_data;
57955b7f77adStw21770 size_t sz_out;
57963eae19d9Swesolows
57973eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
57983eae19d9Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
57993eae19d9Swesolows
58003eae19d9Swesolows if (client_is_privileged())
58013eae19d9Swesolows return (REP_PROTOCOL_SUCCESS);
58023eae19d9Swesolows
58033eae19d9Swesolows #ifdef NATIVE_BUILD
58043eae19d9Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
58053eae19d9Swesolows #else
58063eae19d9Swesolows ret = rc_node_parent(np, &pgp);
58073eae19d9Swesolows
58083eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS)
58093eae19d9Swesolows return (ret);
58103eae19d9Swesolows
58113eae19d9Swesolows if (pgp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
58123eae19d9Swesolows rc_node_rele(pgp);
58133eae19d9Swesolows return (REP_PROTOCOL_FAIL_BAD_REQUEST);
58143eae19d9Swesolows }
58153eae19d9Swesolows
58163eae19d9Swesolows ret = rc_node_pg_check_read_protect(pgp);
58173eae19d9Swesolows
58183eae19d9Swesolows if (ret != REP_PROTOCOL_FAIL_PERMISSION_DENIED) {
58193eae19d9Swesolows rc_node_rele(pgp);
58203eae19d9Swesolows return (ret);
58213eae19d9Swesolows }
58223eae19d9Swesolows
58233eae19d9Swesolows pcp = pc_create();
58243eae19d9Swesolows
58253eae19d9Swesolows if (pcp == NULL) {
58263eae19d9Swesolows rc_node_rele(pgp);
58273eae19d9Swesolows return (REP_PROTOCOL_FAIL_NO_RESOURCES);
58283eae19d9Swesolows }
58293eae19d9Swesolows
58303eae19d9Swesolows ret = perm_add_enabling(pcp, AUTH_MODIFY);
58313eae19d9Swesolows
58323eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) {
58333eae19d9Swesolows const char * const auth =
58343eae19d9Swesolows perm_auth_for_pgtype(pgp->rn_type);
58353eae19d9Swesolows
58363eae19d9Swesolows if (auth != NULL)
58373eae19d9Swesolows ret = perm_add_enabling(pcp, auth);
58383eae19d9Swesolows }
58393eae19d9Swesolows
58403eae19d9Swesolows /*
58413eae19d9Swesolows * If you are permitted to modify the value, you may also
58423eae19d9Swesolows * read it. This means that both the MODIFY and VALUE
58433eae19d9Swesolows * authorizations are acceptable. We don't allow requests
58443eae19d9Swesolows * for AUTH_PROP_MODIFY if all you have is $AUTH_PROP_VALUE,
58453eae19d9Swesolows * however, to avoid leaking possibly valuable information
58463eae19d9Swesolows * since such a user can't change the property anyway.
58473eae19d9Swesolows */
58483eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS)
58493eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp,
58503eae19d9Swesolows AUTH_PROP_MODIFY);
58513eae19d9Swesolows
58523eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS &&
58533eae19d9Swesolows strcmp(np->rn_name, AUTH_PROP_MODIFY) != 0)
58543eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp,
58553eae19d9Swesolows AUTH_PROP_VALUE);
58563eae19d9Swesolows
58573eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS)
58583eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp,
58593eae19d9Swesolows AUTH_PROP_READ);
58603eae19d9Swesolows
58613eae19d9Swesolows rc_node_rele(pgp);
58623eae19d9Swesolows
58633eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) {
58643eae19d9Swesolows granted = perm_granted(pcp);
5865a4dc1477STom Whitten if (granted == PERM_FAIL)
58663eae19d9Swesolows ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
5867a4dc1477STom Whitten if (granted == PERM_GONE)
5868a4dc1477STom Whitten ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
58693eae19d9Swesolows }
5870a4dc1477STom Whitten
58715b7f77adStw21770 if (ret == REP_PROTOCOL_SUCCESS) {
58725b7f77adStw21770 /* Generate a read_prop audit event. */
58735b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
58745b7f77adStw21770 if (audit_data.ed_fmri == NULL)
58755b7f77adStw21770 ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
58765b7f77adStw21770 }
5877a4dc1477STom Whitten if (ret == REP_PROTOCOL_SUCCESS) {
58785b7f77adStw21770 ret = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
58795b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out);
5880a4dc1477STom Whitten }
58815b7f77adStw21770 if (ret == REP_PROTOCOL_SUCCESS) {
58825b7f77adStw21770 int status;
58835b7f77adStw21770 int ret_value;
58845b7f77adStw21770
5885a4dc1477STom Whitten if (granted == PERM_DENIED) {
58865b7f77adStw21770 status = ADT_FAILURE;
58875b7f77adStw21770 ret_value = ADT_FAIL_VALUE_AUTH;
58885b7f77adStw21770 } else {
58895b7f77adStw21770 status = ADT_SUCCESS;
58905b7f77adStw21770 ret_value = ADT_SUCCESS;
58915b7f77adStw21770 }
58925b7f77adStw21770 audit_data.ed_auth = pcp->pc_auth_string;
58935b7f77adStw21770 smf_audit_event(ADT_smf_read_prop,
58945b7f77adStw21770 status, ret_value, &audit_data);
58955b7f77adStw21770 }
58965b7f77adStw21770 free(audit_data.ed_fmri);
58973eae19d9Swesolows
58983eae19d9Swesolows pc_free(pcp);
58993eae19d9Swesolows
5900a4dc1477STom Whitten if ((ret == REP_PROTOCOL_SUCCESS) && (granted == PERM_DENIED))
59013eae19d9Swesolows ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
59023eae19d9Swesolows
59033eae19d9Swesolows return (ret);
59043eae19d9Swesolows #endif /* NATIVE_BUILD */
59053eae19d9Swesolows }
59063eae19d9Swesolows
59073eae19d9Swesolows /*
59087c478bd9Sstevel@tonic-gate * Iteration
59097c478bd9Sstevel@tonic-gate */
59107c478bd9Sstevel@tonic-gate static int
rc_iter_filter_name(rc_node_t * np,void * s)59117c478bd9Sstevel@tonic-gate rc_iter_filter_name(rc_node_t *np, void *s)
59127c478bd9Sstevel@tonic-gate {
59137c478bd9Sstevel@tonic-gate const char *name = s;
59147c478bd9Sstevel@tonic-gate
59157c478bd9Sstevel@tonic-gate return (strcmp(np->rn_name, name) == 0);
59167c478bd9Sstevel@tonic-gate }
59177c478bd9Sstevel@tonic-gate
59187c478bd9Sstevel@tonic-gate static int
rc_iter_filter_type(rc_node_t * np,void * s)59197c478bd9Sstevel@tonic-gate rc_iter_filter_type(rc_node_t *np, void *s)
59207c478bd9Sstevel@tonic-gate {
59217c478bd9Sstevel@tonic-gate const char *type = s;
59227c478bd9Sstevel@tonic-gate
59237c478bd9Sstevel@tonic-gate return (np->rn_type != NULL && strcmp(np->rn_type, type) == 0);
59247c478bd9Sstevel@tonic-gate }
59257c478bd9Sstevel@tonic-gate
59267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
59277c478bd9Sstevel@tonic-gate static int
rc_iter_null_filter(rc_node_t * np,void * s)59287c478bd9Sstevel@tonic-gate rc_iter_null_filter(rc_node_t *np, void *s)
59297c478bd9Sstevel@tonic-gate {
59307c478bd9Sstevel@tonic-gate return (1);
59317c478bd9Sstevel@tonic-gate }
59327c478bd9Sstevel@tonic-gate
59337c478bd9Sstevel@tonic-gate /*
59347c478bd9Sstevel@tonic-gate * Allocate & initialize an rc_node_iter_t structure. Essentially, ensure
59357c478bd9Sstevel@tonic-gate * np->rn_children is populated and call uu_list_walk_start(np->rn_children).
59367c478bd9Sstevel@tonic-gate * If successful, leaves a hold on np & increments np->rn_other_refs
59377c478bd9Sstevel@tonic-gate *
59387c478bd9Sstevel@tonic-gate * If composed is true, then set up for iteration across the top level of np's
59397c478bd9Sstevel@tonic-gate * composition chain. If successful, leaves a hold on np and increments
59407c478bd9Sstevel@tonic-gate * rn_other_refs for the top level of np's composition chain.
59417c478bd9Sstevel@tonic-gate *
59427c478bd9Sstevel@tonic-gate * Fails with
59437c478bd9Sstevel@tonic-gate * _NO_RESOURCES
59447c478bd9Sstevel@tonic-gate * _INVALID_TYPE
59457c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children
59467c478bd9Sstevel@tonic-gate * _DELETED
59477c478bd9Sstevel@tonic-gate */
59487c478bd9Sstevel@tonic-gate static int
rc_iter_create(rc_node_iter_t ** resp,rc_node_t * np,uint32_t type,rc_iter_filter_func * filter,void * arg,boolean_t composed)59497c478bd9Sstevel@tonic-gate rc_iter_create(rc_node_iter_t **resp, rc_node_t *np, uint32_t type,
59507c478bd9Sstevel@tonic-gate rc_iter_filter_func *filter, void *arg, boolean_t composed)
59517c478bd9Sstevel@tonic-gate {
59527c478bd9Sstevel@tonic-gate rc_node_iter_t *nip;
59537c478bd9Sstevel@tonic-gate int res;
59547c478bd9Sstevel@tonic-gate
59557c478bd9Sstevel@tonic-gate assert(*resp == NULL);
59567c478bd9Sstevel@tonic-gate
59577c478bd9Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip));
59587c478bd9Sstevel@tonic-gate if (nip == NULL)
59597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
59607c478bd9Sstevel@tonic-gate
59617c478bd9Sstevel@tonic-gate /* np is held by the client's rc_node_ptr_t */
59627c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
59637c478bd9Sstevel@tonic-gate composed = 1;
59647c478bd9Sstevel@tonic-gate
59657c478bd9Sstevel@tonic-gate if (!composed) {
59667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
59677c478bd9Sstevel@tonic-gate
59687c478bd9Sstevel@tonic-gate if ((res = rc_node_fill_children(np, type)) !=
59697c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
59707c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59717c478bd9Sstevel@tonic-gate uu_free(nip);
59727c478bd9Sstevel@tonic-gate return (res);
59737c478bd9Sstevel@tonic-gate }
59747c478bd9Sstevel@tonic-gate
59757c478bd9Sstevel@tonic-gate nip->rni_clevel = -1;
59767c478bd9Sstevel@tonic-gate
59777c478bd9Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(np->rn_children,
59787c478bd9Sstevel@tonic-gate UU_WALK_ROBUST);
59797c478bd9Sstevel@tonic-gate if (nip->rni_iter != NULL) {
59807c478bd9Sstevel@tonic-gate nip->rni_iter_node = np;
59817c478bd9Sstevel@tonic-gate rc_node_hold_other(np);
59827c478bd9Sstevel@tonic-gate } else {
59837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59847c478bd9Sstevel@tonic-gate uu_free(nip);
59857c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
59867c478bd9Sstevel@tonic-gate }
59877c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59887c478bd9Sstevel@tonic-gate } else {
59897c478bd9Sstevel@tonic-gate rc_node_t *ent;
59907c478bd9Sstevel@tonic-gate
59917c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
59927c478bd9Sstevel@tonic-gate /* rn_cchain isn't valid until children are loaded. */
59937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
59947c478bd9Sstevel@tonic-gate res = rc_node_fill_children(np,
59957c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL);
59967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59977c478bd9Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) {
59987c478bd9Sstevel@tonic-gate uu_free(nip);
59997c478bd9Sstevel@tonic-gate return (res);
60007c478bd9Sstevel@tonic-gate }
60017c478bd9Sstevel@tonic-gate
60027c478bd9Sstevel@tonic-gate /* Check for an empty snapshot. */
60037c478bd9Sstevel@tonic-gate if (np->rn_cchain[0] == NULL)
60047c478bd9Sstevel@tonic-gate goto empty;
60057c478bd9Sstevel@tonic-gate }
60067c478bd9Sstevel@tonic-gate
60077c478bd9Sstevel@tonic-gate /* Start at the top of the composition chain. */
60087c478bd9Sstevel@tonic-gate for (nip->rni_clevel = 0; ; ++nip->rni_clevel) {
60097c478bd9Sstevel@tonic-gate if (nip->rni_clevel >= COMPOSITION_DEPTH) {
60107c478bd9Sstevel@tonic-gate /* Empty composition chain. */
60117c478bd9Sstevel@tonic-gate empty:
60127c478bd9Sstevel@tonic-gate nip->rni_clevel = -1;
60137c478bd9Sstevel@tonic-gate nip->rni_iter = NULL;
60147c478bd9Sstevel@tonic-gate /* It's ok, iter_next() will return _DONE. */
60157c478bd9Sstevel@tonic-gate goto out;
60167c478bd9Sstevel@tonic-gate }
60177c478bd9Sstevel@tonic-gate
60187c478bd9Sstevel@tonic-gate ent = np->rn_cchain[nip->rni_clevel];
60197c478bd9Sstevel@tonic-gate assert(ent != NULL);
60207c478bd9Sstevel@tonic-gate
60217c478bd9Sstevel@tonic-gate if (rc_node_check_and_lock(ent) == REP_PROTOCOL_SUCCESS)
60227c478bd9Sstevel@tonic-gate break;
60237c478bd9Sstevel@tonic-gate
60247c478bd9Sstevel@tonic-gate /* Someone deleted it, so try the next one. */
60257c478bd9Sstevel@tonic-gate }
60267c478bd9Sstevel@tonic-gate
60277c478bd9Sstevel@tonic-gate res = rc_node_fill_children(ent, type);
60287c478bd9Sstevel@tonic-gate
60297c478bd9Sstevel@tonic-gate if (res == REP_PROTOCOL_SUCCESS) {
60307c478bd9Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(ent->rn_children,
60317c478bd9Sstevel@tonic-gate UU_WALK_ROBUST);
60327c478bd9Sstevel@tonic-gate
60337c478bd9Sstevel@tonic-gate if (nip->rni_iter == NULL)
60347c478bd9Sstevel@tonic-gate res = REP_PROTOCOL_FAIL_NO_RESOURCES;
60357c478bd9Sstevel@tonic-gate else {
60367c478bd9Sstevel@tonic-gate nip->rni_iter_node = ent;
60377c478bd9Sstevel@tonic-gate rc_node_hold_other(ent);
60387c478bd9Sstevel@tonic-gate }
60397c478bd9Sstevel@tonic-gate }
60407c478bd9Sstevel@tonic-gate
60417c478bd9Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) {
60427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
60437c478bd9Sstevel@tonic-gate uu_free(nip);
60447c478bd9Sstevel@tonic-gate return (res);
60457c478bd9Sstevel@tonic-gate }
60467c478bd9Sstevel@tonic-gate
60477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
60487c478bd9Sstevel@tonic-gate }
60497c478bd9Sstevel@tonic-gate
60507c478bd9Sstevel@tonic-gate out:
60517c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released by rc_iter_end() */
60527c478bd9Sstevel@tonic-gate nip->rni_parent = np;
60537c478bd9Sstevel@tonic-gate nip->rni_type = type;
60547c478bd9Sstevel@tonic-gate nip->rni_filter = (filter != NULL)? filter : rc_iter_null_filter;
60557c478bd9Sstevel@tonic-gate nip->rni_filter_arg = arg;
60567c478bd9Sstevel@tonic-gate *resp = nip;
60577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
60587c478bd9Sstevel@tonic-gate }
60597c478bd9Sstevel@tonic-gate
60607c478bd9Sstevel@tonic-gate static void
rc_iter_end(rc_node_iter_t * iter)60617c478bd9Sstevel@tonic-gate rc_iter_end(rc_node_iter_t *iter)
60627c478bd9Sstevel@tonic-gate {
60637c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
60647c478bd9Sstevel@tonic-gate
60657c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0)
60667c478bd9Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel];
60677c478bd9Sstevel@tonic-gate
60687c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
60697c478bd9Sstevel@tonic-gate if (iter->rni_iter != NULL)
60707c478bd9Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter);
60717c478bd9Sstevel@tonic-gate iter->rni_iter = NULL;
60727c478bd9Sstevel@tonic-gate
60737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
60747c478bd9Sstevel@tonic-gate rc_node_rele(iter->rni_parent);
60757c478bd9Sstevel@tonic-gate if (iter->rni_iter_node != NULL)
60767c478bd9Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node);
60777c478bd9Sstevel@tonic-gate }
60787c478bd9Sstevel@tonic-gate
60797c478bd9Sstevel@tonic-gate /*
60807c478bd9Sstevel@tonic-gate * Fails with
60817c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset
60827c478bd9Sstevel@tonic-gate * _DELETED - npp's node has been deleted
60837c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - npp's node is not a property
60847c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory
60857c478bd9Sstevel@tonic-gate */
60867c478bd9Sstevel@tonic-gate static int
rc_node_setup_value_iter(rc_node_ptr_t * npp,rc_node_iter_t ** iterp)60877c478bd9Sstevel@tonic-gate rc_node_setup_value_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp)
60887c478bd9Sstevel@tonic-gate {
60897c478bd9Sstevel@tonic-gate rc_node_t *np;
60907c478bd9Sstevel@tonic-gate
60917c478bd9Sstevel@tonic-gate rc_node_iter_t *nip;
60927c478bd9Sstevel@tonic-gate
60937c478bd9Sstevel@tonic-gate assert(*iterp == NULL);
60947c478bd9Sstevel@tonic-gate
60957c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
60967c478bd9Sstevel@tonic-gate
60977c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
60987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
60997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
61007c478bd9Sstevel@tonic-gate }
61017c478bd9Sstevel@tonic-gate
61027c478bd9Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip));
61037c478bd9Sstevel@tonic-gate if (nip == NULL) {
61047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61057c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
61067c478bd9Sstevel@tonic-gate }
61077c478bd9Sstevel@tonic-gate
61087c478bd9Sstevel@tonic-gate nip->rni_parent = np;
61097c478bd9Sstevel@tonic-gate nip->rni_iter = NULL;
61107c478bd9Sstevel@tonic-gate nip->rni_clevel = -1;
61117c478bd9Sstevel@tonic-gate nip->rni_type = REP_PROTOCOL_ENTITY_VALUE;
61127c478bd9Sstevel@tonic-gate nip->rni_offset = 0;
61137c478bd9Sstevel@tonic-gate nip->rni_last_offset = 0;
61147c478bd9Sstevel@tonic-gate
61157c478bd9Sstevel@tonic-gate rc_node_hold_locked(np);
61167c478bd9Sstevel@tonic-gate
61177c478bd9Sstevel@tonic-gate *iterp = nip;
61187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61197c478bd9Sstevel@tonic-gate
61207c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
61217c478bd9Sstevel@tonic-gate }
61227c478bd9Sstevel@tonic-gate
61237c478bd9Sstevel@tonic-gate /*
61247c478bd9Sstevel@tonic-gate * Returns:
61253eae19d9Swesolows * _NO_RESOURCES - out of memory
61267c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset
61277c478bd9Sstevel@tonic-gate * _DELETED - npp's node has been deleted
61287c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node is not a property
61297c478bd9Sstevel@tonic-gate * _NOT_FOUND - property has no values
61307c478bd9Sstevel@tonic-gate * _TRUNCATED - property has >1 values (first is written into out)
61317c478bd9Sstevel@tonic-gate * _SUCCESS - property has 1 value (which is written into out)
61323eae19d9Swesolows * _PERMISSION_DENIED - no authorization to read property value(s)
61337c478bd9Sstevel@tonic-gate *
61347c478bd9Sstevel@tonic-gate * We shorten *sz_out to not include anything after the final '\0'.
61357c478bd9Sstevel@tonic-gate */
61367c478bd9Sstevel@tonic-gate int
rc_node_get_property_value(rc_node_ptr_t * npp,struct rep_protocol_value_response * out,size_t * sz_out)61377c478bd9Sstevel@tonic-gate rc_node_get_property_value(rc_node_ptr_t *npp,
61387c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out)
61397c478bd9Sstevel@tonic-gate {
61407c478bd9Sstevel@tonic-gate rc_node_t *np;
61417c478bd9Sstevel@tonic-gate size_t w;
61427c478bd9Sstevel@tonic-gate int ret;
61437c478bd9Sstevel@tonic-gate
61447c478bd9Sstevel@tonic-gate assert(*sz_out == sizeof (*out));
61457c478bd9Sstevel@tonic-gate
61463eae19d9Swesolows RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
61473eae19d9Swesolows ret = rc_node_property_may_read(np);
61483eae19d9Swesolows rc_node_rele(np);
61493eae19d9Swesolows
61503eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS)
61513eae19d9Swesolows return (ret);
61523eae19d9Swesolows
61537c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
61547c478bd9Sstevel@tonic-gate
61557c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
61567c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
61587c478bd9Sstevel@tonic-gate }
61597c478bd9Sstevel@tonic-gate
61607c478bd9Sstevel@tonic-gate if (np->rn_values_size == 0) {
61617c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61627c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
61637c478bd9Sstevel@tonic-gate }
61647c478bd9Sstevel@tonic-gate out->rpr_type = np->rn_valtype;
61657c478bd9Sstevel@tonic-gate w = strlcpy(out->rpr_value, &np->rn_values[0],
61667c478bd9Sstevel@tonic-gate sizeof (out->rpr_value));
61677c478bd9Sstevel@tonic-gate
61687c478bd9Sstevel@tonic-gate if (w >= sizeof (out->rpr_value))
61697c478bd9Sstevel@tonic-gate backend_panic("value too large");
61707c478bd9Sstevel@tonic-gate
61717c478bd9Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response,
61727c478bd9Sstevel@tonic-gate rpr_value[w + 1]);
61737c478bd9Sstevel@tonic-gate
61747c478bd9Sstevel@tonic-gate ret = (np->rn_values_count != 1)? REP_PROTOCOL_FAIL_TRUNCATED :
61757c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS;
61767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61777c478bd9Sstevel@tonic-gate return (ret);
61787c478bd9Sstevel@tonic-gate }
61797c478bd9Sstevel@tonic-gate
61807c478bd9Sstevel@tonic-gate int
rc_iter_next_value(rc_node_iter_t * iter,struct rep_protocol_value_response * out,size_t * sz_out,int repeat)61817c478bd9Sstevel@tonic-gate rc_iter_next_value(rc_node_iter_t *iter,
61827c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out, int repeat)
61837c478bd9Sstevel@tonic-gate {
61847c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
61857c478bd9Sstevel@tonic-gate const char *vals;
61867c478bd9Sstevel@tonic-gate size_t len;
61877c478bd9Sstevel@tonic-gate
61887c478bd9Sstevel@tonic-gate size_t start;
61897c478bd9Sstevel@tonic-gate size_t w;
61903eae19d9Swesolows int ret;
61917c478bd9Sstevel@tonic-gate
61927c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result;
61937c478bd9Sstevel@tonic-gate
61947c478bd9Sstevel@tonic-gate assert(*sz_out == sizeof (*out));
61957c478bd9Sstevel@tonic-gate
61967c478bd9Sstevel@tonic-gate (void) memset(out, '\0', *sz_out);
61977c478bd9Sstevel@tonic-gate
61987c478bd9Sstevel@tonic-gate if (iter->rni_type != REP_PROTOCOL_ENTITY_VALUE)
61997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62007c478bd9Sstevel@tonic-gate
62013eae19d9Swesolows RC_NODE_CHECK(np);
62023eae19d9Swesolows ret = rc_node_property_may_read(np);
62033eae19d9Swesolows
62043eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS)
62053eae19d9Swesolows return (ret);
62063eae19d9Swesolows
62077c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
62087c478bd9Sstevel@tonic-gate
62097c478bd9Sstevel@tonic-gate vals = np->rn_values;
62107c478bd9Sstevel@tonic-gate len = np->rn_values_size;
62117c478bd9Sstevel@tonic-gate
62127c478bd9Sstevel@tonic-gate out->rpr_type = np->rn_valtype;
62137c478bd9Sstevel@tonic-gate
62147c478bd9Sstevel@tonic-gate start = (repeat)? iter->rni_last_offset : iter->rni_offset;
62157c478bd9Sstevel@tonic-gate
62167c478bd9Sstevel@tonic-gate if (len == 0 || start >= len) {
62177c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_DONE;
62187c478bd9Sstevel@tonic-gate *sz_out -= sizeof (out->rpr_value);
62197c478bd9Sstevel@tonic-gate } else {
62207c478bd9Sstevel@tonic-gate w = strlcpy(out->rpr_value, &vals[start],
62217c478bd9Sstevel@tonic-gate sizeof (out->rpr_value));
62227c478bd9Sstevel@tonic-gate
62237c478bd9Sstevel@tonic-gate if (w >= sizeof (out->rpr_value))
62247c478bd9Sstevel@tonic-gate backend_panic("value too large");
62257c478bd9Sstevel@tonic-gate
62267c478bd9Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response,
62277c478bd9Sstevel@tonic-gate rpr_value[w + 1]);
62287c478bd9Sstevel@tonic-gate
62297c478bd9Sstevel@tonic-gate /*
62307c478bd9Sstevel@tonic-gate * update the offsets if we're not repeating
62317c478bd9Sstevel@tonic-gate */
62327c478bd9Sstevel@tonic-gate if (!repeat) {
62337c478bd9Sstevel@tonic-gate iter->rni_last_offset = iter->rni_offset;
62347c478bd9Sstevel@tonic-gate iter->rni_offset += (w + 1);
62357c478bd9Sstevel@tonic-gate }
62367c478bd9Sstevel@tonic-gate
62377c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS;
62387c478bd9Sstevel@tonic-gate }
62397c478bd9Sstevel@tonic-gate
62407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
62417c478bd9Sstevel@tonic-gate return (result);
62427c478bd9Sstevel@tonic-gate }
62437c478bd9Sstevel@tonic-gate
62447c478bd9Sstevel@tonic-gate /*
62457c478bd9Sstevel@tonic-gate * Entry point for ITER_START from client.c. Validate the arguments & call
62467c478bd9Sstevel@tonic-gate * rc_iter_create().
62477c478bd9Sstevel@tonic-gate *
62487c478bd9Sstevel@tonic-gate * Fails with
62497c478bd9Sstevel@tonic-gate * _NOT_SET
62507c478bd9Sstevel@tonic-gate * _DELETED
62517c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children
62527c478bd9Sstevel@tonic-gate * _BAD_REQUEST - flags is invalid
62537c478bd9Sstevel@tonic-gate * pattern is invalid
62547c478bd9Sstevel@tonic-gate * _NO_RESOURCES
62557c478bd9Sstevel@tonic-gate * _INVALID_TYPE
62567c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - *npp cannot have children of type
62577c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS
62587c478bd9Sstevel@tonic-gate */
62597c478bd9Sstevel@tonic-gate int
rc_node_setup_iter(rc_node_ptr_t * npp,rc_node_iter_t ** iterp,uint32_t type,uint32_t flags,const char * pattern)62607c478bd9Sstevel@tonic-gate rc_node_setup_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp,
62617c478bd9Sstevel@tonic-gate uint32_t type, uint32_t flags, const char *pattern)
62627c478bd9Sstevel@tonic-gate {
62637c478bd9Sstevel@tonic-gate rc_node_t *np;
62647c478bd9Sstevel@tonic-gate rc_iter_filter_func *f = NULL;
62657c478bd9Sstevel@tonic-gate int rc;
62667c478bd9Sstevel@tonic-gate
62677c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
62687c478bd9Sstevel@tonic-gate
62697c478bd9Sstevel@tonic-gate if (pattern != NULL && pattern[0] == '\0')
62707c478bd9Sstevel@tonic-gate pattern = NULL;
62717c478bd9Sstevel@tonic-gate
62727c478bd9Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_VALUE) {
62737c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
62747c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
62757c478bd9Sstevel@tonic-gate if (flags != RP_ITER_START_ALL || pattern != NULL)
62767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62777c478bd9Sstevel@tonic-gate
62787c478bd9Sstevel@tonic-gate rc = rc_node_setup_value_iter(npp, iterp);
62797c478bd9Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
62807c478bd9Sstevel@tonic-gate return (rc);
62817c478bd9Sstevel@tonic-gate }
62827c478bd9Sstevel@tonic-gate
62837c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
62847c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
62857c478bd9Sstevel@tonic-gate return (rc);
62867c478bd9Sstevel@tonic-gate
62877c478bd9Sstevel@tonic-gate if (((flags & RP_ITER_START_FILT_MASK) == RP_ITER_START_ALL) ^
62887c478bd9Sstevel@tonic-gate (pattern == NULL))
62897c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62907c478bd9Sstevel@tonic-gate
62917c478bd9Sstevel@tonic-gate /* Composition only works for instances & snapshots. */
62927c478bd9Sstevel@tonic-gate if ((flags & RP_ITER_START_COMPOSED) &&
62937c478bd9Sstevel@tonic-gate (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE &&
62947c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT))
62957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62967c478bd9Sstevel@tonic-gate
62977c478bd9Sstevel@tonic-gate if (pattern != NULL) {
62987c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, pattern)) !=
62997c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
63007c478bd9Sstevel@tonic-gate return (rc);
63017c478bd9Sstevel@tonic-gate pattern = strdup(pattern);
63027c478bd9Sstevel@tonic-gate if (pattern == NULL)
63037c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
63047c478bd9Sstevel@tonic-gate }
63057c478bd9Sstevel@tonic-gate
63067c478bd9Sstevel@tonic-gate switch (flags & RP_ITER_START_FILT_MASK) {
63077c478bd9Sstevel@tonic-gate case RP_ITER_START_ALL:
63087c478bd9Sstevel@tonic-gate f = NULL;
63097c478bd9Sstevel@tonic-gate break;
63107c478bd9Sstevel@tonic-gate case RP_ITER_START_EXACT:
63117c478bd9Sstevel@tonic-gate f = rc_iter_filter_name;
63127c478bd9Sstevel@tonic-gate break;
63137c478bd9Sstevel@tonic-gate case RP_ITER_START_PGTYPE:
63147c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
63157c478bd9Sstevel@tonic-gate free((void *)pattern);
63167c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63177c478bd9Sstevel@tonic-gate }
63187c478bd9Sstevel@tonic-gate f = rc_iter_filter_type;
63197c478bd9Sstevel@tonic-gate break;
63207c478bd9Sstevel@tonic-gate default:
63217c478bd9Sstevel@tonic-gate free((void *)pattern);
63227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63237c478bd9Sstevel@tonic-gate }
63247c478bd9Sstevel@tonic-gate
63257c478bd9Sstevel@tonic-gate rc = rc_iter_create(iterp, np, type, f, (void *)pattern,
63267c478bd9Sstevel@tonic-gate flags & RP_ITER_START_COMPOSED);
63277c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS && pattern != NULL)
63287c478bd9Sstevel@tonic-gate free((void *)pattern);
63297c478bd9Sstevel@tonic-gate
63307c478bd9Sstevel@tonic-gate return (rc);
63317c478bd9Sstevel@tonic-gate }
63327c478bd9Sstevel@tonic-gate
63337c478bd9Sstevel@tonic-gate /*
63347c478bd9Sstevel@tonic-gate * Do uu_list_walk_next(iter->rni_iter) until we find a child which matches
63357c478bd9Sstevel@tonic-gate * the filter.
63367c478bd9Sstevel@tonic-gate * For composed iterators, then check to see if there's an overlapping entity
63377c478bd9Sstevel@tonic-gate * (see embedded comments). If we reach the end of the list, start over at
63387c478bd9Sstevel@tonic-gate * the next level.
63397c478bd9Sstevel@tonic-gate *
63407c478bd9Sstevel@tonic-gate * Returns
63417c478bd9Sstevel@tonic-gate * _BAD_REQUEST - iter walks values
63427c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities
63437c478bd9Sstevel@tonic-gate * _DELETED - parent was deleted
63447c478bd9Sstevel@tonic-gate * _NO_RESOURCES
63457c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
63467c478bd9Sstevel@tonic-gate * _DONE
63477c478bd9Sstevel@tonic-gate * _SUCCESS
63487c478bd9Sstevel@tonic-gate *
63497c478bd9Sstevel@tonic-gate * For composed property group iterators, can also return
63507c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children
63517c478bd9Sstevel@tonic-gate */
63527c478bd9Sstevel@tonic-gate int
rc_iter_next(rc_node_iter_t * iter,rc_node_ptr_t * out,uint32_t type)63537c478bd9Sstevel@tonic-gate rc_iter_next(rc_node_iter_t *iter, rc_node_ptr_t *out, uint32_t type)
63547c478bd9Sstevel@tonic-gate {
63557c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
63567c478bd9Sstevel@tonic-gate rc_node_t *res;
63577c478bd9Sstevel@tonic-gate int rc;
63587c478bd9Sstevel@tonic-gate
63597c478bd9Sstevel@tonic-gate if (iter->rni_type == REP_PROTOCOL_ENTITY_VALUE)
63607c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63617c478bd9Sstevel@tonic-gate
63627c478bd9Sstevel@tonic-gate if (iter->rni_iter == NULL) {
63637c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
63647c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
63657c478bd9Sstevel@tonic-gate }
63667c478bd9Sstevel@tonic-gate
63677c478bd9Sstevel@tonic-gate if (iter->rni_type != type) {
63687c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
63697c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
63707c478bd9Sstevel@tonic-gate }
63717c478bd9Sstevel@tonic-gate
63727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); /* held by _iter_create() */
63737c478bd9Sstevel@tonic-gate
63747c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
63757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63767c478bd9Sstevel@tonic-gate rc_node_clear(out, 1);
63777c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
63787c478bd9Sstevel@tonic-gate }
63797c478bd9Sstevel@tonic-gate
63807c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0) {
63817c478bd9Sstevel@tonic-gate /* Composed iterator. Iterate over appropriate level. */
63827c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63837c478bd9Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel];
63847c478bd9Sstevel@tonic-gate /*
63857c478bd9Sstevel@tonic-gate * If iter->rni_parent is an instance or a snapshot, np must
63867c478bd9Sstevel@tonic-gate * be valid since iter holds iter->rni_parent & possible
63877c478bd9Sstevel@tonic-gate * levels (service, instance, snaplevel) cannot be destroyed
63887c478bd9Sstevel@tonic-gate * while rni_parent is held. If iter->rni_parent is
63897c478bd9Sstevel@tonic-gate * a composed property group then rc_node_setup_cpg() put
63907c478bd9Sstevel@tonic-gate * a hold on np.
63917c478bd9Sstevel@tonic-gate */
63927c478bd9Sstevel@tonic-gate
63937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
63947c478bd9Sstevel@tonic-gate
63957c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
63967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63977c478bd9Sstevel@tonic-gate rc_node_clear(out, 1);
63987c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
63997c478bd9Sstevel@tonic-gate }
64007c478bd9Sstevel@tonic-gate }
64017c478bd9Sstevel@tonic-gate
64027c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_HAS_CHILDREN);
64037c478bd9Sstevel@tonic-gate
64047c478bd9Sstevel@tonic-gate for (;;) {
64057c478bd9Sstevel@tonic-gate res = uu_list_walk_next(iter->rni_iter);
64067c478bd9Sstevel@tonic-gate if (res == NULL) {
64077c478bd9Sstevel@tonic-gate rc_node_t *parent = iter->rni_parent;
64087c478bd9Sstevel@tonic-gate
64097c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
64107c478bd9Sstevel@tonic-gate if (iter->rni_clevel < 0 || iter->rni_clevel == 1) {
64117c478bd9Sstevel@tonic-gate /* release walker and lock */
64127c478bd9Sstevel@tonic-gate rc_iter_end(iter);
64137c478bd9Sstevel@tonic-gate break;
64147c478bd9Sstevel@tonic-gate }
64157c478bd9Sstevel@tonic-gate
64167c478bd9Sstevel@tonic-gate /* Stop walking current level. */
64177c478bd9Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter);
64187c478bd9Sstevel@tonic-gate iter->rni_iter = NULL;
64197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64207c478bd9Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node);
64217c478bd9Sstevel@tonic-gate iter->rni_iter_node = NULL;
64227c478bd9Sstevel@tonic-gate
64237c478bd9Sstevel@tonic-gate /* Start walking next level. */
64247c478bd9Sstevel@tonic-gate ++iter->rni_clevel;
64257c478bd9Sstevel@tonic-gate np = parent->rn_cchain[iter->rni_clevel];
64267c478bd9Sstevel@tonic-gate assert(np != NULL);
64277c478bd9Sstevel@tonic-gate #else
64287c478bd9Sstevel@tonic-gate #error This code must be updated.
64297c478bd9Sstevel@tonic-gate #endif
64307c478bd9Sstevel@tonic-gate
64317c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
64327c478bd9Sstevel@tonic-gate
64337c478bd9Sstevel@tonic-gate rc = rc_node_fill_children(np, iter->rni_type);
64347c478bd9Sstevel@tonic-gate
64357c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
64367c478bd9Sstevel@tonic-gate iter->rni_iter =
64377c478bd9Sstevel@tonic-gate uu_list_walk_start(np->rn_children,
64387c478bd9Sstevel@tonic-gate UU_WALK_ROBUST);
64397c478bd9Sstevel@tonic-gate
64407c478bd9Sstevel@tonic-gate if (iter->rni_iter == NULL)
64417c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
64427c478bd9Sstevel@tonic-gate else {
64437c478bd9Sstevel@tonic-gate iter->rni_iter_node = np;
64447c478bd9Sstevel@tonic-gate rc_node_hold_other(np);
64457c478bd9Sstevel@tonic-gate }
64467c478bd9Sstevel@tonic-gate }
64477c478bd9Sstevel@tonic-gate
64487c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
64497c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64507c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
64517c478bd9Sstevel@tonic-gate return (rc);
64527c478bd9Sstevel@tonic-gate }
64537c478bd9Sstevel@tonic-gate
64547c478bd9Sstevel@tonic-gate continue;
64557c478bd9Sstevel@tonic-gate }
64567c478bd9Sstevel@tonic-gate
64577c478bd9Sstevel@tonic-gate if (res->rn_id.rl_type != type ||
64587c478bd9Sstevel@tonic-gate !iter->rni_filter(res, iter->rni_filter_arg))
64597c478bd9Sstevel@tonic-gate continue;
64607c478bd9Sstevel@tonic-gate
64617c478bd9Sstevel@tonic-gate /*
64627c478bd9Sstevel@tonic-gate * If we're composed and not at the top level, check to see if
64637c478bd9Sstevel@tonic-gate * there's an entity at a higher level with the same name. If
64647c478bd9Sstevel@tonic-gate * so, skip this one.
64657c478bd9Sstevel@tonic-gate */
64667c478bd9Sstevel@tonic-gate if (iter->rni_clevel > 0) {
64677c478bd9Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[0];
64687c478bd9Sstevel@tonic-gate rc_node_t *pg;
64697c478bd9Sstevel@tonic-gate
64707c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
64717c478bd9Sstevel@tonic-gate assert(iter->rni_clevel == 1);
64727c478bd9Sstevel@tonic-gate
64737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64747c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
64757c478bd9Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type,
64767c478bd9Sstevel@tonic-gate &pg);
64777c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && pg != NULL)
64787c478bd9Sstevel@tonic-gate rc_node_rele(pg);
64797c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
64807c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
64817c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
64827c478bd9Sstevel@tonic-gate return (rc);
64837c478bd9Sstevel@tonic-gate }
64847c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
64857c478bd9Sstevel@tonic-gate
64867c478bd9Sstevel@tonic-gate /* Make sure np isn't being deleted all of a sudden. */
64877c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
64887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64897c478bd9Sstevel@tonic-gate rc_node_clear(out, 1);
64907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
64917c478bd9Sstevel@tonic-gate }
64927c478bd9Sstevel@tonic-gate
64937c478bd9Sstevel@tonic-gate if (pg != NULL)
64947c478bd9Sstevel@tonic-gate /* Keep going. */
64957c478bd9Sstevel@tonic-gate continue;
64967c478bd9Sstevel@tonic-gate #else
64977c478bd9Sstevel@tonic-gate #error This code must be updated.
64987c478bd9Sstevel@tonic-gate #endif
64997c478bd9Sstevel@tonic-gate }
65007c478bd9Sstevel@tonic-gate
65017c478bd9Sstevel@tonic-gate /*
65027c478bd9Sstevel@tonic-gate * If we're composed, iterating over property groups, and not
65037c478bd9Sstevel@tonic-gate * at the bottom level, check to see if there's a pg at lower
65047c478bd9Sstevel@tonic-gate * level with the same name. If so, return a cpg.
65057c478bd9Sstevel@tonic-gate */
65067c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0 &&
65077c478bd9Sstevel@tonic-gate type == REP_PROTOCOL_ENTITY_PROPERTYGRP &&
65087c478bd9Sstevel@tonic-gate iter->rni_clevel < COMPOSITION_DEPTH - 1) {
65097c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
65107c478bd9Sstevel@tonic-gate rc_node_t *pg;
65117c478bd9Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[1];
65127c478bd9Sstevel@tonic-gate
65137c478bd9Sstevel@tonic-gate rc_node_hold(res); /* While we drop np->rn_lock */
65147c478bd9Sstevel@tonic-gate
65157c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
65167c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
65177c478bd9Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type,
65187c478bd9Sstevel@tonic-gate &pg);
65197c478bd9Sstevel@tonic-gate /* holds pg if not NULL */
65207c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
65217c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
65227c478bd9Sstevel@tonic-gate rc_node_rele(res);
65237c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
65247c478bd9Sstevel@tonic-gate return (rc);
65257c478bd9Sstevel@tonic-gate }
65267c478bd9Sstevel@tonic-gate
65277c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
65287c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
65297c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
65307c478bd9Sstevel@tonic-gate rc_node_rele(res);
65317c478bd9Sstevel@tonic-gate if (pg != NULL)
65327c478bd9Sstevel@tonic-gate rc_node_rele(pg);
65337c478bd9Sstevel@tonic-gate rc_node_clear(out, 1);
65347c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
65357c478bd9Sstevel@tonic-gate }
65367c478bd9Sstevel@tonic-gate
65377c478bd9Sstevel@tonic-gate if (pg == NULL) {
6538*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np->rn_lock);
65397c478bd9Sstevel@tonic-gate rc_node_rele(res);
6540*a29160b0SRobert Mustacchi (void) pthread_mutex_lock(&np->rn_lock);
6541*a29160b0SRobert Mustacchi if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
6542*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np->
6543*a29160b0SRobert Mustacchi rn_lock);
6544*a29160b0SRobert Mustacchi rc_node_clear(out, 1);
6545*a29160b0SRobert Mustacchi return (REP_PROTOCOL_FAIL_DELETED);
6546*a29160b0SRobert Mustacchi }
65477c478bd9Sstevel@tonic-gate } else {
65487c478bd9Sstevel@tonic-gate rc_node_t *cpg;
65497c478bd9Sstevel@tonic-gate
65507c478bd9Sstevel@tonic-gate /* Keep res held for rc_node_setup_cpg(). */
65517c478bd9Sstevel@tonic-gate
65527c478bd9Sstevel@tonic-gate cpg = rc_node_alloc();
65537c478bd9Sstevel@tonic-gate if (cpg == NULL) {
65547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(
65557c478bd9Sstevel@tonic-gate &np->rn_lock);
65567c478bd9Sstevel@tonic-gate rc_node_rele(res);
65577c478bd9Sstevel@tonic-gate rc_node_rele(pg);
65587c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
65597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
65607c478bd9Sstevel@tonic-gate }
65617c478bd9Sstevel@tonic-gate
65627c478bd9Sstevel@tonic-gate switch (rc_node_setup_cpg(cpg, res, pg)) {
65637c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
65647c478bd9Sstevel@tonic-gate res = cpg;
65657c478bd9Sstevel@tonic-gate break;
65667c478bd9Sstevel@tonic-gate
65677c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
65687c478bd9Sstevel@tonic-gate /* Nevermind. */
6569*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np->
6570*a29160b0SRobert Mustacchi rn_lock);
65717c478bd9Sstevel@tonic-gate rc_node_destroy(cpg);
65727c478bd9Sstevel@tonic-gate rc_node_rele(pg);
65737c478bd9Sstevel@tonic-gate rc_node_rele(res);
6574*a29160b0SRobert Mustacchi (void) pthread_mutex_lock(&np->
6575*a29160b0SRobert Mustacchi rn_lock);
6576*a29160b0SRobert Mustacchi if (!rc_node_wait_flag(np,
6577*a29160b0SRobert Mustacchi RC_NODE_DYING)) {
6578*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&
6579*a29160b0SRobert Mustacchi np->rn_lock);
6580*a29160b0SRobert Mustacchi rc_node_clear(out, 1);
6581*a29160b0SRobert Mustacchi return
6582*a29160b0SRobert Mustacchi (REP_PROTOCOL_FAIL_DELETED);
6583*a29160b0SRobert Mustacchi }
65847c478bd9Sstevel@tonic-gate break;
65857c478bd9Sstevel@tonic-gate
65867c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
65877c478bd9Sstevel@tonic-gate rc_node_destroy(cpg);
65887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(
65897c478bd9Sstevel@tonic-gate &np->rn_lock);
65907c478bd9Sstevel@tonic-gate rc_node_rele(res);
65917c478bd9Sstevel@tonic-gate rc_node_rele(pg);
65927c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
65937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
65947c478bd9Sstevel@tonic-gate
65957c478bd9Sstevel@tonic-gate default:
65967c478bd9Sstevel@tonic-gate assert(0);
65977c478bd9Sstevel@tonic-gate abort();
65987c478bd9Sstevel@tonic-gate }
65997c478bd9Sstevel@tonic-gate }
66007c478bd9Sstevel@tonic-gate #else
66017c478bd9Sstevel@tonic-gate #error This code must be updated.
66027c478bd9Sstevel@tonic-gate #endif
66037c478bd9Sstevel@tonic-gate }
66047c478bd9Sstevel@tonic-gate
66057c478bd9Sstevel@tonic-gate rc_node_hold(res);
66067c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
66077c478bd9Sstevel@tonic-gate break;
66087c478bd9Sstevel@tonic-gate }
66097c478bd9Sstevel@tonic-gate rc_node_assign(out, res);
66107c478bd9Sstevel@tonic-gate
66117c478bd9Sstevel@tonic-gate if (res == NULL)
66127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
66137c478bd9Sstevel@tonic-gate rc_node_rele(res);
66147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
66157c478bd9Sstevel@tonic-gate }
66167c478bd9Sstevel@tonic-gate
66177c478bd9Sstevel@tonic-gate void
rc_iter_destroy(rc_node_iter_t ** nipp)66187c478bd9Sstevel@tonic-gate rc_iter_destroy(rc_node_iter_t **nipp)
66197c478bd9Sstevel@tonic-gate {
66207c478bd9Sstevel@tonic-gate rc_node_iter_t *nip = *nipp;
66217c478bd9Sstevel@tonic-gate rc_node_t *np;
66227c478bd9Sstevel@tonic-gate
66237c478bd9Sstevel@tonic-gate if (nip == NULL)
66247c478bd9Sstevel@tonic-gate return; /* already freed */
66257c478bd9Sstevel@tonic-gate
66267c478bd9Sstevel@tonic-gate np = nip->rni_parent;
66277c478bd9Sstevel@tonic-gate
66287c478bd9Sstevel@tonic-gate if (nip->rni_filter_arg != NULL)
66297c478bd9Sstevel@tonic-gate free(nip->rni_filter_arg);
66307c478bd9Sstevel@tonic-gate nip->rni_filter_arg = NULL;
66317c478bd9Sstevel@tonic-gate
66327c478bd9Sstevel@tonic-gate if (nip->rni_type == REP_PROTOCOL_ENTITY_VALUE ||
66337c478bd9Sstevel@tonic-gate nip->rni_iter != NULL) {
66347c478bd9Sstevel@tonic-gate if (nip->rni_clevel < 0)
66357c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
66367c478bd9Sstevel@tonic-gate else
66377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(
66387c478bd9Sstevel@tonic-gate &np->rn_cchain[nip->rni_clevel]->rn_lock);
66397c478bd9Sstevel@tonic-gate rc_iter_end(nip); /* release walker and lock */
66407c478bd9Sstevel@tonic-gate }
66417c478bd9Sstevel@tonic-gate nip->rni_parent = NULL;
66427c478bd9Sstevel@tonic-gate
66437c478bd9Sstevel@tonic-gate uu_free(nip);
66447c478bd9Sstevel@tonic-gate *nipp = NULL;
66457c478bd9Sstevel@tonic-gate }
66467c478bd9Sstevel@tonic-gate
66477c478bd9Sstevel@tonic-gate int
rc_node_setup_tx(rc_node_ptr_t * npp,rc_node_ptr_t * txp)66487c478bd9Sstevel@tonic-gate rc_node_setup_tx(rc_node_ptr_t *npp, rc_node_ptr_t *txp)
66497c478bd9Sstevel@tonic-gate {
66507c478bd9Sstevel@tonic-gate rc_node_t *np;
66517c478bd9Sstevel@tonic-gate permcheck_t *pcp;
66527c478bd9Sstevel@tonic-gate int ret;
6653a4dc1477STom Whitten perm_status_t granted;
66545b7f77adStw21770 rc_auth_state_t authorized = RC_AUTH_UNKNOWN;
66555b7f77adStw21770 char *auth_string = NULL;
66567c478bd9Sstevel@tonic-gate
66577c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
66587c478bd9Sstevel@tonic-gate
66597c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
66607c478bd9Sstevel@tonic-gate rc_node_rele(np);
66617c478bd9Sstevel@tonic-gate np = np->rn_cchain[0];
66627c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_HOLD(np);
66637c478bd9Sstevel@tonic-gate }
66647c478bd9Sstevel@tonic-gate
66657c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
66667c478bd9Sstevel@tonic-gate rc_node_rele(np);
66677c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
66687c478bd9Sstevel@tonic-gate }
66697c478bd9Sstevel@tonic-gate
66707c478bd9Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_SNAPSHOT] != 0) {
66717c478bd9Sstevel@tonic-gate rc_node_rele(np);
66727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
66737c478bd9Sstevel@tonic-gate }
66747c478bd9Sstevel@tonic-gate
66755b7f77adStw21770 #ifdef NATIVE_BUILD
66767c478bd9Sstevel@tonic-gate if (client_is_privileged())
66777c478bd9Sstevel@tonic-gate goto skip_checks;
66787c478bd9Sstevel@tonic-gate rc_node_rele(np);
66797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
66807c478bd9Sstevel@tonic-gate #else
66815b7f77adStw21770 if (is_main_repository == 0)
66825b7f77adStw21770 goto skip_checks;
66835b7f77adStw21770
66847c478bd9Sstevel@tonic-gate /* permission check */
66857c478bd9Sstevel@tonic-gate pcp = pc_create();
66867c478bd9Sstevel@tonic-gate if (pcp == NULL) {
66877c478bd9Sstevel@tonic-gate rc_node_rele(np);
66887c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
66897c478bd9Sstevel@tonic-gate }
66907c478bd9Sstevel@tonic-gate
66917c478bd9Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_INSTANCE] != 0 && /* instance pg */
66927c478bd9Sstevel@tonic-gate ((strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0 &&
66937c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_ACTIONS_TYPE) == 0) ||
66947c478bd9Sstevel@tonic-gate (strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
66957c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
66967c478bd9Sstevel@tonic-gate rc_node_t *instn;
66977c478bd9Sstevel@tonic-gate
6698e8f5b3f5STruong Nguyen /* solaris.smf.modify can be used */
6699e8f5b3f5STruong Nguyen ret = perm_add_enabling(pcp, AUTH_MODIFY);
6700e8f5b3f5STruong Nguyen if (ret != REP_PROTOCOL_SUCCESS) {
6701e8f5b3f5STruong Nguyen pc_free(pcp);
6702e8f5b3f5STruong Nguyen rc_node_rele(np);
6703e8f5b3f5STruong Nguyen return (ret);
6704e8f5b3f5STruong Nguyen }
6705e8f5b3f5STruong Nguyen
67067c478bd9Sstevel@tonic-gate /* solaris.smf.manage can be used. */
67077c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE);
67087c478bd9Sstevel@tonic-gate
67097c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
67107c478bd9Sstevel@tonic-gate pc_free(pcp);
67117c478bd9Sstevel@tonic-gate rc_node_rele(np);
67127c478bd9Sstevel@tonic-gate return (ret);
67137c478bd9Sstevel@tonic-gate }
67147c478bd9Sstevel@tonic-gate
67157c478bd9Sstevel@tonic-gate /* general/action_authorization values can be used. */
67167c478bd9Sstevel@tonic-gate ret = rc_node_parent(np, &instn);
67177c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
67187c478bd9Sstevel@tonic-gate assert(ret == REP_PROTOCOL_FAIL_DELETED);
67197c478bd9Sstevel@tonic-gate rc_node_rele(np);
67207c478bd9Sstevel@tonic-gate pc_free(pcp);
67217c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
67227c478bd9Sstevel@tonic-gate }
67237c478bd9Sstevel@tonic-gate
67247c478bd9Sstevel@tonic-gate assert(instn->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
67257c478bd9Sstevel@tonic-gate
67267c478bd9Sstevel@tonic-gate ret = perm_add_inst_action_auth(pcp, instn);
67277c478bd9Sstevel@tonic-gate rc_node_rele(instn);
67287c478bd9Sstevel@tonic-gate switch (ret) {
67297c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
67307c478bd9Sstevel@tonic-gate break;
67317c478bd9Sstevel@tonic-gate
67327c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
67337c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
67347c478bd9Sstevel@tonic-gate rc_node_rele(np);
67357c478bd9Sstevel@tonic-gate pc_free(pcp);
67367c478bd9Sstevel@tonic-gate return (ret);
67377c478bd9Sstevel@tonic-gate
67387c478bd9Sstevel@tonic-gate default:
67397c478bd9Sstevel@tonic-gate bad_error("perm_add_inst_action_auth", ret);
67407c478bd9Sstevel@tonic-gate }
67417c478bd9Sstevel@tonic-gate
67427c478bd9Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0)
67435b7f77adStw21770 authorized = RC_AUTH_PASSED; /* No check on commit. */
67447c478bd9Sstevel@tonic-gate } else {
67457c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MODIFY);
67467c478bd9Sstevel@tonic-gate
67477c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) {
67487c478bd9Sstevel@tonic-gate /* propertygroup-type-specific authorization */
67497c478bd9Sstevel@tonic-gate /* no locking because rn_type won't change anyway */
67507c478bd9Sstevel@tonic-gate const char * const auth =
67517c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
67527c478bd9Sstevel@tonic-gate
67537c478bd9Sstevel@tonic-gate if (auth != NULL)
67547c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, auth);
67557c478bd9Sstevel@tonic-gate }
67567c478bd9Sstevel@tonic-gate
67577c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS)
67587c478bd9Sstevel@tonic-gate /* propertygroup/transaction-type-specific auths */
67597c478bd9Sstevel@tonic-gate ret =
67607c478bd9Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_VALUE);
67617c478bd9Sstevel@tonic-gate
67627c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS)
67637c478bd9Sstevel@tonic-gate ret =
67647c478bd9Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_MODIFY);
67657c478bd9Sstevel@tonic-gate
67667c478bd9Sstevel@tonic-gate /* AUTH_MANAGE can manipulate general/AUTH_PROP_ACTION */
67677c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS &&
67687c478bd9Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
67697c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0)
67707c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE);
67717c478bd9Sstevel@tonic-gate
67727c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
67737c478bd9Sstevel@tonic-gate pc_free(pcp);
67747c478bd9Sstevel@tonic-gate rc_node_rele(np);
67757c478bd9Sstevel@tonic-gate return (ret);
67767c478bd9Sstevel@tonic-gate }
67777c478bd9Sstevel@tonic-gate }
67787c478bd9Sstevel@tonic-gate
6779a4dc1477STom Whitten granted = perm_granted(pcp);
6780a4dc1477STom Whitten ret = map_granted_status(granted, pcp, &auth_string);
67817c478bd9Sstevel@tonic-gate pc_free(pcp);
6782a4dc1477STom Whitten
6783a4dc1477STom Whitten if ((granted == PERM_GONE) || (granted == PERM_FAIL) ||
6784a4dc1477STom Whitten (ret == REP_PROTOCOL_FAIL_NO_RESOURCES)) {
6785a4dc1477STom Whitten free(auth_string);
67867c478bd9Sstevel@tonic-gate rc_node_rele(np);
6787a4dc1477STom Whitten return (ret);
67887c478bd9Sstevel@tonic-gate }
67897c478bd9Sstevel@tonic-gate
6790a4dc1477STom Whitten if (granted == PERM_DENIED) {
67915b7f77adStw21770 /*
67925b7f77adStw21770 * If we get here, the authorization failed.
67935b7f77adStw21770 * Unfortunately, we don't have enough information at this
67945b7f77adStw21770 * point to generate the security audit events. We'll only
67955b7f77adStw21770 * get that information when the client tries to commit the
67965b7f77adStw21770 * event. Thus, we'll remember the failed authorization,
67975b7f77adStw21770 * so that we can generate the audit events later.
67985b7f77adStw21770 */
67995b7f77adStw21770 authorized = RC_AUTH_FAILED;
68005b7f77adStw21770 }
68017c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
68027c478bd9Sstevel@tonic-gate
68037c478bd9Sstevel@tonic-gate skip_checks:
68047c478bd9Sstevel@tonic-gate rc_node_assign(txp, np);
68057c478bd9Sstevel@tonic-gate txp->rnp_authorized = authorized;
68065b7f77adStw21770 if (authorized != RC_AUTH_UNKNOWN) {
68075b7f77adStw21770 /* Save the authorization string. */
68085b7f77adStw21770 if (txp->rnp_auth_string != NULL)
68095b7f77adStw21770 free((void *)txp->rnp_auth_string);
68105b7f77adStw21770 txp->rnp_auth_string = auth_string;
68115b7f77adStw21770 auth_string = NULL; /* Don't free until done with txp. */
68125b7f77adStw21770 }
68137c478bd9Sstevel@tonic-gate
68147c478bd9Sstevel@tonic-gate rc_node_rele(np);
68155b7f77adStw21770 if (auth_string != NULL)
68165b7f77adStw21770 free(auth_string);
68177c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
68187c478bd9Sstevel@tonic-gate }
68197c478bd9Sstevel@tonic-gate
68207c478bd9Sstevel@tonic-gate /*
68217c478bd9Sstevel@tonic-gate * Return 1 if the given transaction commands only modify the values of
68227c478bd9Sstevel@tonic-gate * properties other than "modify_authorization". Return -1 if any of the
68237c478bd9Sstevel@tonic-gate * commands are invalid, and 0 otherwise.
68247c478bd9Sstevel@tonic-gate */
68257c478bd9Sstevel@tonic-gate static int
tx_allow_value(const void * cmds_arg,size_t cmds_sz,rc_node_t * pg)68267c478bd9Sstevel@tonic-gate tx_allow_value(const void *cmds_arg, size_t cmds_sz, rc_node_t *pg)
68277c478bd9Sstevel@tonic-gate {
68287c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds;
68297c478bd9Sstevel@tonic-gate uintptr_t loc;
68307c478bd9Sstevel@tonic-gate uint32_t sz;
68317c478bd9Sstevel@tonic-gate rc_node_t *prop;
68327c478bd9Sstevel@tonic-gate boolean_t ok;
68337c478bd9Sstevel@tonic-gate
68347c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock));
68357c478bd9Sstevel@tonic-gate
68367c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
68377c478bd9Sstevel@tonic-gate
68387c478bd9Sstevel@tonic-gate while (cmds_sz > 0) {
68397c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc;
68407c478bd9Sstevel@tonic-gate
68417c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68427c478bd9Sstevel@tonic-gate return (-1);
68437c478bd9Sstevel@tonic-gate
68447c478bd9Sstevel@tonic-gate sz = cmds->rptc_size;
68457c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68467c478bd9Sstevel@tonic-gate return (-1);
68477c478bd9Sstevel@tonic-gate
68487c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz);
68497c478bd9Sstevel@tonic-gate if (sz > cmds_sz)
68507c478bd9Sstevel@tonic-gate return (-1);
68517c478bd9Sstevel@tonic-gate
68527c478bd9Sstevel@tonic-gate switch (cmds[0].rptc_action) {
68537c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_CLEAR:
68547c478bd9Sstevel@tonic-gate break;
68557c478bd9Sstevel@tonic-gate
68567c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_REPLACE:
68577c478bd9Sstevel@tonic-gate /* Check type */
68587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock);
68591ad2c453STom Whitten ok = B_FALSE;
68607c478bd9Sstevel@tonic-gate if (rc_node_find_named_child(pg,
68617c478bd9Sstevel@tonic-gate (const char *)cmds[0].rptc_data,
68627c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop) ==
68637c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
68641ad2c453STom Whitten if (prop != NULL) {
68651ad2c453STom Whitten ok = prop->rn_valtype ==
68661ad2c453STom Whitten cmds[0].rptc_type;
68671ad2c453STom Whitten /*
68681ad2c453STom Whitten * rc_node_find_named_child()
68691ad2c453STom Whitten * places a hold on prop which we
68701ad2c453STom Whitten * do not need to hang on to.
68711ad2c453STom Whitten */
68721ad2c453STom Whitten rc_node_rele(prop);
68731ad2c453STom Whitten }
68747c478bd9Sstevel@tonic-gate }
68757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock);
68767c478bd9Sstevel@tonic-gate if (ok)
68777c478bd9Sstevel@tonic-gate break;
68787c478bd9Sstevel@tonic-gate return (0);
68797c478bd9Sstevel@tonic-gate
68807c478bd9Sstevel@tonic-gate default:
68817c478bd9Sstevel@tonic-gate return (0);
68827c478bd9Sstevel@tonic-gate }
68837c478bd9Sstevel@tonic-gate
68847c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_MODIFY)
68857c478bd9Sstevel@tonic-gate == 0)
68867c478bd9Sstevel@tonic-gate return (0);
68877c478bd9Sstevel@tonic-gate
68887c478bd9Sstevel@tonic-gate loc += sz;
68897c478bd9Sstevel@tonic-gate cmds_sz -= sz;
68907c478bd9Sstevel@tonic-gate }
68917c478bd9Sstevel@tonic-gate
68927c478bd9Sstevel@tonic-gate return (1);
68937c478bd9Sstevel@tonic-gate }
68947c478bd9Sstevel@tonic-gate
68957c478bd9Sstevel@tonic-gate /*
68967c478bd9Sstevel@tonic-gate * Return 1 if any of the given transaction commands affect
68977c478bd9Sstevel@tonic-gate * "action_authorization". Return -1 if any of the commands are invalid and
68987c478bd9Sstevel@tonic-gate * 0 in all other cases.
68997c478bd9Sstevel@tonic-gate */
69007c478bd9Sstevel@tonic-gate static int
tx_modifies_action(const void * cmds_arg,size_t cmds_sz)69017c478bd9Sstevel@tonic-gate tx_modifies_action(const void *cmds_arg, size_t cmds_sz)
69027c478bd9Sstevel@tonic-gate {
69037c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds;
69047c478bd9Sstevel@tonic-gate uintptr_t loc;
69057c478bd9Sstevel@tonic-gate uint32_t sz;
69067c478bd9Sstevel@tonic-gate
69077c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
69087c478bd9Sstevel@tonic-gate
69097c478bd9Sstevel@tonic-gate while (cmds_sz > 0) {
69107c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc;
69117c478bd9Sstevel@tonic-gate
69127c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69137c478bd9Sstevel@tonic-gate return (-1);
69147c478bd9Sstevel@tonic-gate
69157c478bd9Sstevel@tonic-gate sz = cmds->rptc_size;
69167c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69177c478bd9Sstevel@tonic-gate return (-1);
69187c478bd9Sstevel@tonic-gate
69197c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz);
69207c478bd9Sstevel@tonic-gate if (sz > cmds_sz)
69217c478bd9Sstevel@tonic-gate return (-1);
69227c478bd9Sstevel@tonic-gate
69237c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_ACTION)
69247c478bd9Sstevel@tonic-gate == 0)
69257c478bd9Sstevel@tonic-gate return (1);
69267c478bd9Sstevel@tonic-gate
69277c478bd9Sstevel@tonic-gate loc += sz;
69287c478bd9Sstevel@tonic-gate cmds_sz -= sz;
69297c478bd9Sstevel@tonic-gate }
69307c478bd9Sstevel@tonic-gate
69317c478bd9Sstevel@tonic-gate return (0);
69327c478bd9Sstevel@tonic-gate }
69337c478bd9Sstevel@tonic-gate
69347c478bd9Sstevel@tonic-gate /*
69357c478bd9Sstevel@tonic-gate * Returns 1 if the transaction commands only modify properties named
69367c478bd9Sstevel@tonic-gate * 'enabled'.
69377c478bd9Sstevel@tonic-gate */
69387c478bd9Sstevel@tonic-gate static int
tx_only_enabled(const void * cmds_arg,size_t cmds_sz)69397c478bd9Sstevel@tonic-gate tx_only_enabled(const void *cmds_arg, size_t cmds_sz)
69407c478bd9Sstevel@tonic-gate {
69417c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmd;
69427c478bd9Sstevel@tonic-gate uintptr_t loc;
69437c478bd9Sstevel@tonic-gate uint32_t sz;
69447c478bd9Sstevel@tonic-gate
69457c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
69467c478bd9Sstevel@tonic-gate
69477c478bd9Sstevel@tonic-gate while (cmds_sz > 0) {
69487c478bd9Sstevel@tonic-gate cmd = (struct rep_protocol_transaction_cmd *)loc;
69497c478bd9Sstevel@tonic-gate
69507c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69517c478bd9Sstevel@tonic-gate return (-1);
69527c478bd9Sstevel@tonic-gate
69537c478bd9Sstevel@tonic-gate sz = cmd->rptc_size;
69547c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69557c478bd9Sstevel@tonic-gate return (-1);
69567c478bd9Sstevel@tonic-gate
69577c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz);
69587c478bd9Sstevel@tonic-gate if (sz > cmds_sz)
69597c478bd9Sstevel@tonic-gate return (-1);
69607c478bd9Sstevel@tonic-gate
69617c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmd->rptc_data, AUTH_PROP_ENABLED)
69627c478bd9Sstevel@tonic-gate != 0)
69637c478bd9Sstevel@tonic-gate return (0);
69647c478bd9Sstevel@tonic-gate
69657c478bd9Sstevel@tonic-gate loc += sz;
69667c478bd9Sstevel@tonic-gate cmds_sz -= sz;
69677c478bd9Sstevel@tonic-gate }
69687c478bd9Sstevel@tonic-gate
69697c478bd9Sstevel@tonic-gate return (1);
69707c478bd9Sstevel@tonic-gate }
69717c478bd9Sstevel@tonic-gate
69727c478bd9Sstevel@tonic-gate int
rc_tx_commit(rc_node_ptr_t * txp,const void * cmds,size_t cmds_sz)69737c478bd9Sstevel@tonic-gate rc_tx_commit(rc_node_ptr_t *txp, const void *cmds, size_t cmds_sz)
69747c478bd9Sstevel@tonic-gate {
69757c478bd9Sstevel@tonic-gate rc_node_t *np = txp->rnp_node;
69767c478bd9Sstevel@tonic-gate rc_node_t *pp;
69777c478bd9Sstevel@tonic-gate rc_node_t *nnp;
69787c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
69797c478bd9Sstevel@tonic-gate int rc;
69807c478bd9Sstevel@tonic-gate permcheck_t *pcp;
6981a4dc1477STom Whitten perm_status_t granted;
6982a4dc1477STom Whitten int normal;
69835b7f77adStw21770 char *pg_fmri = NULL;
69845b7f77adStw21770 char *auth_string = NULL;
69855b7f77adStw21770 int auth_status = ADT_SUCCESS;
69865b7f77adStw21770 int auth_ret_value = ADT_SUCCESS;
69875b7f77adStw21770 size_t sz_out;
69885b7f77adStw21770 int tx_flag = 1;
69895b7f77adStw21770 tx_commit_data_t *tx_data = NULL;
69907c478bd9Sstevel@tonic-gate
69917c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np);
69927c478bd9Sstevel@tonic-gate
69935b7f77adStw21770 if ((txp->rnp_authorized != RC_AUTH_UNKNOWN) &&
69945b7f77adStw21770 (txp->rnp_auth_string != NULL)) {
69955b7f77adStw21770 auth_string = strdup(txp->rnp_auth_string);
69965b7f77adStw21770 if (auth_string == NULL)
69975b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
69985b7f77adStw21770 }
69995b7f77adStw21770
70005b7f77adStw21770 if ((txp->rnp_authorized == RC_AUTH_UNKNOWN) &&
70015b7f77adStw21770 is_main_repository) {
70027c478bd9Sstevel@tonic-gate #ifdef NATIVE_BUILD
70035b7f77adStw21770 if (!client_is_privileged()) {
70047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
70055b7f77adStw21770 }
70067c478bd9Sstevel@tonic-gate #else
70077c478bd9Sstevel@tonic-gate /* permission check: depends on contents of transaction */
70087c478bd9Sstevel@tonic-gate pcp = pc_create();
70097c478bd9Sstevel@tonic-gate if (pcp == NULL)
70107c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
70117c478bd9Sstevel@tonic-gate
70127c478bd9Sstevel@tonic-gate /* If normal is cleared, we won't do the normal checks. */
70137c478bd9Sstevel@tonic-gate normal = 1;
70147c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
70157c478bd9Sstevel@tonic-gate
70167c478bd9Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
70177c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0) {
70187c478bd9Sstevel@tonic-gate /* Touching general[framework]/action_authorization? */
70197c478bd9Sstevel@tonic-gate rc = tx_modifies_action(cmds, cmds_sz);
70207c478bd9Sstevel@tonic-gate if (rc == -1) {
70217c478bd9Sstevel@tonic-gate pc_free(pcp);
70227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
70237c478bd9Sstevel@tonic-gate }
70247c478bd9Sstevel@tonic-gate
70257c478bd9Sstevel@tonic-gate if (rc) {
7026e8f5b3f5STruong Nguyen /*
7027e8f5b3f5STruong Nguyen * Yes: only AUTH_MODIFY and AUTH_MANAGE
7028e8f5b3f5STruong Nguyen * can be used.
7029e8f5b3f5STruong Nguyen */
7030e8f5b3f5STruong Nguyen rc = perm_add_enabling(pcp, AUTH_MODIFY);
7031e8f5b3f5STruong Nguyen
7032e8f5b3f5STruong Nguyen if (rc == REP_PROTOCOL_SUCCESS)
7033e8f5b3f5STruong Nguyen rc = perm_add_enabling(pcp,
7034e8f5b3f5STruong Nguyen AUTH_MANAGE);
7035e8f5b3f5STruong Nguyen
70367c478bd9Sstevel@tonic-gate normal = 0;
70377c478bd9Sstevel@tonic-gate } else {
70387c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
70397c478bd9Sstevel@tonic-gate }
70407c478bd9Sstevel@tonic-gate } else if (np->rn_id.rl_ids[ID_INSTANCE] != 0 &&
70417c478bd9Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
70427c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0) {
70437c478bd9Sstevel@tonic-gate rc_node_t *instn;
70447c478bd9Sstevel@tonic-gate
70457c478bd9Sstevel@tonic-gate rc = tx_only_enabled(cmds, cmds_sz);
70467c478bd9Sstevel@tonic-gate if (rc == -1) {
70477c478bd9Sstevel@tonic-gate pc_free(pcp);
70487c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
70497c478bd9Sstevel@tonic-gate }
70507c478bd9Sstevel@tonic-gate
70517c478bd9Sstevel@tonic-gate if (rc) {
70527c478bd9Sstevel@tonic-gate rc = rc_node_parent(np, &instn);
70537c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
70547c478bd9Sstevel@tonic-gate assert(rc == REP_PROTOCOL_FAIL_DELETED);
70557c478bd9Sstevel@tonic-gate pc_free(pcp);
70567c478bd9Sstevel@tonic-gate return (rc);
70577c478bd9Sstevel@tonic-gate }
70587c478bd9Sstevel@tonic-gate
70597c478bd9Sstevel@tonic-gate assert(instn->rn_id.rl_type ==
70607c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_INSTANCE);
70617c478bd9Sstevel@tonic-gate
70627c478bd9Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, instn);
70637c478bd9Sstevel@tonic-gate rc_node_rele(instn);
70647c478bd9Sstevel@tonic-gate switch (rc) {
70657c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
70667c478bd9Sstevel@tonic-gate break;
70677c478bd9Sstevel@tonic-gate
70687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
70697c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
70707c478bd9Sstevel@tonic-gate pc_free(pcp);
70717c478bd9Sstevel@tonic-gate return (rc);
70727c478bd9Sstevel@tonic-gate
70737c478bd9Sstevel@tonic-gate default:
70747c478bd9Sstevel@tonic-gate bad_error("perm_add_inst_action_auth",
70757c478bd9Sstevel@tonic-gate rc);
70767c478bd9Sstevel@tonic-gate }
70777c478bd9Sstevel@tonic-gate } else {
70787c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
70797c478bd9Sstevel@tonic-gate }
70807c478bd9Sstevel@tonic-gate }
70817c478bd9Sstevel@tonic-gate
70827c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && normal) {
70837c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
70847c478bd9Sstevel@tonic-gate
70857c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
70867c478bd9Sstevel@tonic-gate /* Add pgtype-specific authorization. */
70877c478bd9Sstevel@tonic-gate const char * const auth =
70887c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
70897c478bd9Sstevel@tonic-gate
70907c478bd9Sstevel@tonic-gate if (auth != NULL)
70917c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
70927c478bd9Sstevel@tonic-gate }
70937c478bd9Sstevel@tonic-gate
70947c478bd9Sstevel@tonic-gate /* Add pg-specific modify_authorization auths. */
70957c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS)
70967c478bd9Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np,
70977c478bd9Sstevel@tonic-gate AUTH_PROP_MODIFY);
70987c478bd9Sstevel@tonic-gate
70997c478bd9Sstevel@tonic-gate /* If value_authorization values are ok, add them. */
71007c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
71017c478bd9Sstevel@tonic-gate rc = tx_allow_value(cmds, cmds_sz, np);
71027c478bd9Sstevel@tonic-gate if (rc == -1)
71037c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
71047c478bd9Sstevel@tonic-gate else if (rc)
71057c478bd9Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np,
71067c478bd9Sstevel@tonic-gate AUTH_PROP_VALUE);
71077c478bd9Sstevel@tonic-gate }
71087c478bd9Sstevel@tonic-gate }
71097c478bd9Sstevel@tonic-gate
71107c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
71117c478bd9Sstevel@tonic-gate granted = perm_granted(pcp);
7112a4dc1477STom Whitten rc = map_granted_status(granted, pcp, &auth_string);
7113a4dc1477STom Whitten if ((granted == PERM_DENIED) && auth_string) {
71145b7f77adStw21770 /*
7115a4dc1477STom Whitten * _PERMISSION_DENIED should not cause us
7116a4dc1477STom Whitten * to exit at this point, because we still
7117a4dc1477STom Whitten * want to generate an audit event.
71185b7f77adStw21770 */
7119a4dc1477STom Whitten rc = REP_PROTOCOL_SUCCESS;
71205b7f77adStw21770 }
71217c478bd9Sstevel@tonic-gate }
71227c478bd9Sstevel@tonic-gate
71237c478bd9Sstevel@tonic-gate pc_free(pcp);
71247c478bd9Sstevel@tonic-gate
71257c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
71265b7f77adStw21770 goto cleanout;
71277c478bd9Sstevel@tonic-gate
7128a4dc1477STom Whitten if (granted == PERM_DENIED) {
71295b7f77adStw21770 auth_status = ADT_FAILURE;
71305b7f77adStw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH;
71315b7f77adStw21770 tx_flag = 0;
71325b7f77adStw21770 }
71337c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */
71345b7f77adStw21770 } else if (txp->rnp_authorized == RC_AUTH_FAILED) {
71355b7f77adStw21770 auth_status = ADT_FAILURE;
71365b7f77adStw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH;
71375b7f77adStw21770 tx_flag = 0;
71385b7f77adStw21770 }
71395b7f77adStw21770
71405b7f77adStw21770 pg_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
71415b7f77adStw21770 if (pg_fmri == NULL) {
71425b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71435b7f77adStw21770 goto cleanout;
71445b7f77adStw21770 }
71455b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, pg_fmri,
71465b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
71475b7f77adStw21770 goto cleanout;
71485b7f77adStw21770 }
71495b7f77adStw21770
71505b7f77adStw21770 /*
71515b7f77adStw21770 * Parse the transaction commands into a useful form.
71525b7f77adStw21770 */
71535b7f77adStw21770 if ((rc = tx_commit_data_new(cmds, cmds_sz, &tx_data)) !=
71545b7f77adStw21770 REP_PROTOCOL_SUCCESS) {
71555b7f77adStw21770 goto cleanout;
71565b7f77adStw21770 }
71575b7f77adStw21770
71585b7f77adStw21770 if (tx_flag == 0) {
71595b7f77adStw21770 /* Authorization failed. Generate audit events. */
71605b7f77adStw21770 generate_property_events(tx_data, pg_fmri, auth_string,
71615b7f77adStw21770 auth_status, auth_ret_value);
71625b7f77adStw21770 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
71635b7f77adStw21770 goto cleanout;
71647c478bd9Sstevel@tonic-gate }
71657c478bd9Sstevel@tonic-gate
71667c478bd9Sstevel@tonic-gate nnp = rc_node_alloc();
71675b7f77adStw21770 if (nnp == NULL) {
71685b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71695b7f77adStw21770 goto cleanout;
71705b7f77adStw21770 }
71717c478bd9Sstevel@tonic-gate
71727c478bd9Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */
71737c478bd9Sstevel@tonic-gate nnp->rn_hash = np->rn_hash;
71747c478bd9Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name);
71757c478bd9Sstevel@tonic-gate nnp->rn_type = strdup(np->rn_type);
71767c478bd9Sstevel@tonic-gate nnp->rn_pgflags = np->rn_pgflags;
71777c478bd9Sstevel@tonic-gate
71787c478bd9Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
71797c478bd9Sstevel@tonic-gate
71807c478bd9Sstevel@tonic-gate if (nnp->rn_name == NULL || nnp->rn_type == NULL) {
71817c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
71825b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71835b7f77adStw21770 goto cleanout;
71847c478bd9Sstevel@tonic-gate }
71857c478bd9Sstevel@tonic-gate
71867c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
71875b7f77adStw21770
71887c478bd9Sstevel@tonic-gate /*
71897c478bd9Sstevel@tonic-gate * We must have all of the old properties in the cache, or the
71907c478bd9Sstevel@tonic-gate * database deletions could cause inconsistencies.
71917c478bd9Sstevel@tonic-gate */
71927c478bd9Sstevel@tonic-gate if ((rc = rc_node_fill_children(np, REP_PROTOCOL_ENTITY_PROPERTY)) !=
71937c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
71947c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
71957c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
71965b7f77adStw21770 goto cleanout;
71977c478bd9Sstevel@tonic-gate }
71987c478bd9Sstevel@tonic-gate
71997c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
72007c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72017c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
72025b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
72035b7f77adStw21770 goto cleanout;
72047c478bd9Sstevel@tonic-gate }
72057c478bd9Sstevel@tonic-gate
72067c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
72077c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
72087c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72097c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
72105b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST;
72115b7f77adStw21770 goto cleanout;
72127c478bd9Sstevel@tonic-gate }
72137c478bd9Sstevel@tonic-gate
72147c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
72157c478bd9Sstevel@tonic-gate if (pp == NULL) {
72167c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */
72177c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
72187c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
72197c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
72207c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72215b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST;
72225b7f77adStw21770 goto cleanout;
72237c478bd9Sstevel@tonic-gate }
72247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72255b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
72265b7f77adStw21770 goto cleanout;
72277c478bd9Sstevel@tonic-gate }
72287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72297c478bd9Sstevel@tonic-gate
72307c478bd9Sstevel@tonic-gate /*
72317c478bd9Sstevel@tonic-gate * prepare for the transaction
72327c478bd9Sstevel@tonic-gate */
72337c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
72347c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
72357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72367c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
72377c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
72387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72397c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
72405b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED;
72415b7f77adStw21770 goto cleanout;
72427c478bd9Sstevel@tonic-gate }
72437c478bd9Sstevel@tonic-gate nnp->rn_gen_id = np->rn_gen_id;
72447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72457c478bd9Sstevel@tonic-gate
72467c478bd9Sstevel@tonic-gate /* Sets nnp->rn_gen_id on success. */
72475b7f77adStw21770 rc = object_tx_commit(&np->rn_id, tx_data, &nnp->rn_gen_id);
72487c478bd9Sstevel@tonic-gate
72497c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
72507c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
72517c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
72527c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72537c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
72547c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
72557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72567c478bd9Sstevel@tonic-gate rc_node_destroy(nnp);
72577c478bd9Sstevel@tonic-gate rc_node_clear(txp, 0);
72587c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_DONE)
72597c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; /* successful empty tx */
72605b7f77adStw21770 goto cleanout;
72617c478bd9Sstevel@tonic-gate }
72627c478bd9Sstevel@tonic-gate
72637c478bd9Sstevel@tonic-gate /*
72647c478bd9Sstevel@tonic-gate * Notify waiters
72657c478bd9Sstevel@tonic-gate */
72667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
72677c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
72687c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp);
72697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
72707c478bd9Sstevel@tonic-gate
72717c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD;
72727c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72737c478bd9Sstevel@tonic-gate
72747c478bd9Sstevel@tonic-gate rc_notify_remove_node(np);
72757c478bd9Sstevel@tonic-gate
72767c478bd9Sstevel@tonic-gate /*
72777c478bd9Sstevel@tonic-gate * replace np with nnp
72787c478bd9Sstevel@tonic-gate */
72797c478bd9Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp);
72807c478bd9Sstevel@tonic-gate
72817c478bd9Sstevel@tonic-gate /*
72827c478bd9Sstevel@tonic-gate * all done -- clear the transaction.
72837c478bd9Sstevel@tonic-gate */
72847c478bd9Sstevel@tonic-gate rc_node_clear(txp, 0);
72855b7f77adStw21770 generate_property_events(tx_data, pg_fmri, auth_string,
72865b7f77adStw21770 auth_status, auth_ret_value);
72877c478bd9Sstevel@tonic-gate
72885b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS;
72895b7f77adStw21770
72905b7f77adStw21770 cleanout:
72915b7f77adStw21770 free(auth_string);
72925b7f77adStw21770 free(pg_fmri);
72935b7f77adStw21770 tx_commit_data_free(tx_data);
72945b7f77adStw21770 return (rc);
72957c478bd9Sstevel@tonic-gate }
72967c478bd9Sstevel@tonic-gate
72977c478bd9Sstevel@tonic-gate void
rc_pg_notify_init(rc_node_pg_notify_t * pnp)72987c478bd9Sstevel@tonic-gate rc_pg_notify_init(rc_node_pg_notify_t *pnp)
72997c478bd9Sstevel@tonic-gate {
73007c478bd9Sstevel@tonic-gate uu_list_node_init(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
73017c478bd9Sstevel@tonic-gate pnp->rnpn_pg = NULL;
73027c478bd9Sstevel@tonic-gate pnp->rnpn_fd = -1;
73037c478bd9Sstevel@tonic-gate }
73047c478bd9Sstevel@tonic-gate
73057c478bd9Sstevel@tonic-gate int
rc_pg_notify_setup(rc_node_pg_notify_t * pnp,rc_node_ptr_t * npp,int fd)73067c478bd9Sstevel@tonic-gate rc_pg_notify_setup(rc_node_pg_notify_t *pnp, rc_node_ptr_t *npp, int fd)
73077c478bd9Sstevel@tonic-gate {
73087c478bd9Sstevel@tonic-gate rc_node_t *np;
73097c478bd9Sstevel@tonic-gate
73107c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
73117c478bd9Sstevel@tonic-gate
73127c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
73137c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
73157c478bd9Sstevel@tonic-gate }
73167c478bd9Sstevel@tonic-gate
73177c478bd9Sstevel@tonic-gate /*
73187c478bd9Sstevel@tonic-gate * wait for any transaction in progress to complete
73197c478bd9Sstevel@tonic-gate */
73207c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_IN_TX)) {
73217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
73237c478bd9Sstevel@tonic-gate }
73247c478bd9Sstevel@tonic-gate
73257c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
73267c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73277c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_LATEST);
73287c478bd9Sstevel@tonic-gate }
73297c478bd9Sstevel@tonic-gate
73307c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
73317c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp);
73327c478bd9Sstevel@tonic-gate pnp->rnpn_pg = np;
73337c478bd9Sstevel@tonic-gate pnp->rnpn_fd = fd;
73347c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(np->rn_pg_notify_list, NULL, pnp);
73357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
73367c478bd9Sstevel@tonic-gate
73377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
73397c478bd9Sstevel@tonic-gate }
73407c478bd9Sstevel@tonic-gate
73417c478bd9Sstevel@tonic-gate void
rc_pg_notify_fini(rc_node_pg_notify_t * pnp)73427c478bd9Sstevel@tonic-gate rc_pg_notify_fini(rc_node_pg_notify_t *pnp)
73437c478bd9Sstevel@tonic-gate {
73447c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
73457c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp);
73467c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
73477c478bd9Sstevel@tonic-gate
73487c478bd9Sstevel@tonic-gate uu_list_node_fini(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
73497c478bd9Sstevel@tonic-gate }
73507c478bd9Sstevel@tonic-gate
73517c478bd9Sstevel@tonic-gate void
rc_notify_info_init(rc_notify_info_t * rnip)73527c478bd9Sstevel@tonic-gate rc_notify_info_init(rc_notify_info_t *rnip)
73537c478bd9Sstevel@tonic-gate {
73547c478bd9Sstevel@tonic-gate int i;
73557c478bd9Sstevel@tonic-gate
73567c478bd9Sstevel@tonic-gate uu_list_node_init(rnip, &rnip->rni_list_node, rc_notify_info_pool);
73577c478bd9Sstevel@tonic-gate uu_list_node_init(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
73587c478bd9Sstevel@tonic-gate rc_notify_pool);
73597c478bd9Sstevel@tonic-gate
73607c478bd9Sstevel@tonic-gate rnip->rni_notify.rcn_node = NULL;
73617c478bd9Sstevel@tonic-gate rnip->rni_notify.rcn_info = rnip;
73627c478bd9Sstevel@tonic-gate
73637c478bd9Sstevel@tonic-gate bzero(rnip->rni_namelist, sizeof (rnip->rni_namelist));
73647c478bd9Sstevel@tonic-gate bzero(rnip->rni_typelist, sizeof (rnip->rni_typelist));
73657c478bd9Sstevel@tonic-gate
73667c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&rnip->rni_cv, NULL);
73677c478bd9Sstevel@tonic-gate
73687c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
73697c478bd9Sstevel@tonic-gate rnip->rni_namelist[i] = NULL;
73707c478bd9Sstevel@tonic-gate rnip->rni_typelist[i] = NULL;
73717c478bd9Sstevel@tonic-gate }
73727c478bd9Sstevel@tonic-gate }
73737c478bd9Sstevel@tonic-gate
73747c478bd9Sstevel@tonic-gate static void
rc_notify_info_insert_locked(rc_notify_info_t * rnip)73757c478bd9Sstevel@tonic-gate rc_notify_info_insert_locked(rc_notify_info_t *rnip)
73767c478bd9Sstevel@tonic-gate {
73777c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
73787c478bd9Sstevel@tonic-gate
73797c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_ACTIVE));
73807c478bd9Sstevel@tonic-gate
73817c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_ACTIVE;
73827c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_info_list, NULL, rnip);
73837c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, &rnip->rni_notify);
73847c478bd9Sstevel@tonic-gate }
73857c478bd9Sstevel@tonic-gate
73867c478bd9Sstevel@tonic-gate static void
rc_notify_info_remove_locked(rc_notify_info_t * rnip)73877c478bd9Sstevel@tonic-gate rc_notify_info_remove_locked(rc_notify_info_t *rnip)
73887c478bd9Sstevel@tonic-gate {
73897c478bd9Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify;
73907c478bd9Sstevel@tonic-gate rc_notify_t *np;
73917c478bd9Sstevel@tonic-gate
73927c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
73937c478bd9Sstevel@tonic-gate
73947c478bd9Sstevel@tonic-gate assert(rnip->rni_flags & RC_NOTIFY_ACTIVE);
73957c478bd9Sstevel@tonic-gate
73967c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_DRAIN));
73977c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_DRAIN;
73987c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
73997c478bd9Sstevel@tonic-gate
74007c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_info_list, rnip);
74017c478bd9Sstevel@tonic-gate
74027c478bd9Sstevel@tonic-gate /*
74037c478bd9Sstevel@tonic-gate * clean up any notifications at the beginning of the list
74047c478bd9Sstevel@tonic-gate */
74057c478bd9Sstevel@tonic-gate if (uu_list_first(rc_notify_list) == me) {
7406b5cbdab0STom Whitten /*
7407b5cbdab0STom Whitten * We can't call rc_notify_remove_locked() unless
7408b5cbdab0STom Whitten * rc_notify_in_use is 0.
7409b5cbdab0STom Whitten */
7410b5cbdab0STom Whitten while (rc_notify_in_use) {
7411b5cbdab0STom Whitten (void) pthread_cond_wait(&rc_pg_notify_cv,
7412b5cbdab0STom Whitten &rc_pg_notify_lock);
7413b5cbdab0STom Whitten }
74147c478bd9Sstevel@tonic-gate while ((np = uu_list_next(rc_notify_list, me)) != NULL &&
74157c478bd9Sstevel@tonic-gate np->rcn_info == NULL)
74167c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np);
74177c478bd9Sstevel@tonic-gate }
74187c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me);
74197c478bd9Sstevel@tonic-gate
74207c478bd9Sstevel@tonic-gate while (rnip->rni_waiters) {
74217c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv);
74227c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
74237c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
74247c478bd9Sstevel@tonic-gate }
74257c478bd9Sstevel@tonic-gate
74267c478bd9Sstevel@tonic-gate rnip->rni_flags &= ~(RC_NOTIFY_DRAIN | RC_NOTIFY_ACTIVE);
74277c478bd9Sstevel@tonic-gate }
74287c478bd9Sstevel@tonic-gate
74297c478bd9Sstevel@tonic-gate static int
rc_notify_info_add_watch(rc_notify_info_t * rnip,const char ** arr,const char * name)74307c478bd9Sstevel@tonic-gate rc_notify_info_add_watch(rc_notify_info_t *rnip, const char **arr,
74317c478bd9Sstevel@tonic-gate const char *name)
74327c478bd9Sstevel@tonic-gate {
74337c478bd9Sstevel@tonic-gate int i;
74347c478bd9Sstevel@tonic-gate int rc;
74357c478bd9Sstevel@tonic-gate char *f;
74367c478bd9Sstevel@tonic-gate
74377c478bd9Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_PROPERTYGRP, name);
74387c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
74397c478bd9Sstevel@tonic-gate return (rc);
74407c478bd9Sstevel@tonic-gate
74417c478bd9Sstevel@tonic-gate f = strdup(name);
74427c478bd9Sstevel@tonic-gate if (f == NULL)
74437c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
74447c478bd9Sstevel@tonic-gate
74457c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
74467c478bd9Sstevel@tonic-gate
74477c478bd9Sstevel@tonic-gate while (rnip->rni_flags & RC_NOTIFY_EMPTYING)
74487c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
74497c478bd9Sstevel@tonic-gate
745042958ef4Stn143363 for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
74517c478bd9Sstevel@tonic-gate if (arr[i] == NULL)
74527c478bd9Sstevel@tonic-gate break;
74537c478bd9Sstevel@tonic-gate
745442958ef4Stn143363 /*
745542958ef4Stn143363 * Don't add name if it's already being tracked.
745642958ef4Stn143363 */
745742958ef4Stn143363 if (strcmp(arr[i], f) == 0) {
745842958ef4Stn143363 free(f);
745942958ef4Stn143363 goto out;
746042958ef4Stn143363 }
746142958ef4Stn143363 }
746242958ef4Stn143363
74637c478bd9Sstevel@tonic-gate if (i == RC_NOTIFY_MAX_NAMES) {
74647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
74657c478bd9Sstevel@tonic-gate free(f);
74667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
74677c478bd9Sstevel@tonic-gate }
74687c478bd9Sstevel@tonic-gate
74697c478bd9Sstevel@tonic-gate arr[i] = f;
747042958ef4Stn143363
747142958ef4Stn143363 out:
74727c478bd9Sstevel@tonic-gate if (!(rnip->rni_flags & RC_NOTIFY_ACTIVE))
74737c478bd9Sstevel@tonic-gate rc_notify_info_insert_locked(rnip);
74747c478bd9Sstevel@tonic-gate
74757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
74767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
74777c478bd9Sstevel@tonic-gate }
74787c478bd9Sstevel@tonic-gate
74797c478bd9Sstevel@tonic-gate int
rc_notify_info_add_name(rc_notify_info_t * rnip,const char * name)74807c478bd9Sstevel@tonic-gate rc_notify_info_add_name(rc_notify_info_t *rnip, const char *name)
74817c478bd9Sstevel@tonic-gate {
74827c478bd9Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_namelist, name));
74837c478bd9Sstevel@tonic-gate }
74847c478bd9Sstevel@tonic-gate
74857c478bd9Sstevel@tonic-gate int
rc_notify_info_add_type(rc_notify_info_t * rnip,const char * type)74867c478bd9Sstevel@tonic-gate rc_notify_info_add_type(rc_notify_info_t *rnip, const char *type)
74877c478bd9Sstevel@tonic-gate {
74887c478bd9Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_typelist, type));
74897c478bd9Sstevel@tonic-gate }
74907c478bd9Sstevel@tonic-gate
74917c478bd9Sstevel@tonic-gate /*
74927c478bd9Sstevel@tonic-gate * Wait for and report an event of interest to rnip, a notification client
74937c478bd9Sstevel@tonic-gate */
74947c478bd9Sstevel@tonic-gate int
rc_notify_info_wait(rc_notify_info_t * rnip,rc_node_ptr_t * out,char * outp,size_t sz)74957c478bd9Sstevel@tonic-gate rc_notify_info_wait(rc_notify_info_t *rnip, rc_node_ptr_t *out,
74967c478bd9Sstevel@tonic-gate char *outp, size_t sz)
74977c478bd9Sstevel@tonic-gate {
74987c478bd9Sstevel@tonic-gate rc_notify_t *np;
74997c478bd9Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify;
75007c478bd9Sstevel@tonic-gate rc_node_t *nnp;
75017c478bd9Sstevel@tonic-gate rc_notify_delete_t *ndp;
75027c478bd9Sstevel@tonic-gate
75037c478bd9Sstevel@tonic-gate int am_first_info;
75047c478bd9Sstevel@tonic-gate
75057c478bd9Sstevel@tonic-gate if (sz > 0)
75067c478bd9Sstevel@tonic-gate outp[0] = 0;
75077c478bd9Sstevel@tonic-gate
75087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
75097c478bd9Sstevel@tonic-gate
75107c478bd9Sstevel@tonic-gate while ((rnip->rni_flags & (RC_NOTIFY_ACTIVE | RC_NOTIFY_DRAIN)) ==
75117c478bd9Sstevel@tonic-gate RC_NOTIFY_ACTIVE) {
75127c478bd9Sstevel@tonic-gate /*
75137c478bd9Sstevel@tonic-gate * If I'm first on the notify list, it is my job to
75147c478bd9Sstevel@tonic-gate * clean up any notifications I pass by. I can't do that
75157c478bd9Sstevel@tonic-gate * if someone is blocking the list from removals, so I
75167c478bd9Sstevel@tonic-gate * have to wait until they have all drained.
75177c478bd9Sstevel@tonic-gate */
75187c478bd9Sstevel@tonic-gate am_first_info = (uu_list_first(rc_notify_list) == me);
75197c478bd9Sstevel@tonic-gate if (am_first_info && rc_notify_in_use) {
75207c478bd9Sstevel@tonic-gate rnip->rni_waiters++;
75217c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv,
75227c478bd9Sstevel@tonic-gate &rc_pg_notify_lock);
75237c478bd9Sstevel@tonic-gate rnip->rni_waiters--;
75247c478bd9Sstevel@tonic-gate continue;
75257c478bd9Sstevel@tonic-gate }
75267c478bd9Sstevel@tonic-gate
75277c478bd9Sstevel@tonic-gate /*
75287c478bd9Sstevel@tonic-gate * Search the list for a node of interest.
75297c478bd9Sstevel@tonic-gate */
75307c478bd9Sstevel@tonic-gate np = uu_list_next(rc_notify_list, me);
75317c478bd9Sstevel@tonic-gate while (np != NULL && !rc_notify_info_interested(rnip, np)) {
75327c478bd9Sstevel@tonic-gate rc_notify_t *next = uu_list_next(rc_notify_list, np);
75337c478bd9Sstevel@tonic-gate
75347c478bd9Sstevel@tonic-gate if (am_first_info) {
75357c478bd9Sstevel@tonic-gate if (np->rcn_info) {
75367c478bd9Sstevel@tonic-gate /*
75377c478bd9Sstevel@tonic-gate * Passing another client -- stop
75387c478bd9Sstevel@tonic-gate * cleaning up notifications
75397c478bd9Sstevel@tonic-gate */
75407c478bd9Sstevel@tonic-gate am_first_info = 0;
75417c478bd9Sstevel@tonic-gate } else {
75427c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np);
75437c478bd9Sstevel@tonic-gate }
75447c478bd9Sstevel@tonic-gate }
75457c478bd9Sstevel@tonic-gate np = next;
75467c478bd9Sstevel@tonic-gate }
75477c478bd9Sstevel@tonic-gate
75487c478bd9Sstevel@tonic-gate /*
75497c478bd9Sstevel@tonic-gate * Nothing of interest -- wait for notification
75507c478bd9Sstevel@tonic-gate */
75517c478bd9Sstevel@tonic-gate if (np == NULL) {
75527c478bd9Sstevel@tonic-gate rnip->rni_waiters++;
75537c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv,
75547c478bd9Sstevel@tonic-gate &rc_pg_notify_lock);
75557c478bd9Sstevel@tonic-gate rnip->rni_waiters--;
75567c478bd9Sstevel@tonic-gate continue;
75577c478bd9Sstevel@tonic-gate }
75587c478bd9Sstevel@tonic-gate
75597c478bd9Sstevel@tonic-gate /*
75607c478bd9Sstevel@tonic-gate * found something to report -- move myself after the
75617c478bd9Sstevel@tonic-gate * notification and process it.
75627c478bd9Sstevel@tonic-gate */
75637c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me);
75647c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_list, np, me);
75657c478bd9Sstevel@tonic-gate
75667c478bd9Sstevel@tonic-gate if ((ndp = np->rcn_delete) != NULL) {
75677c478bd9Sstevel@tonic-gate (void) strlcpy(outp, ndp->rnd_fmri, sz);
75687c478bd9Sstevel@tonic-gate if (am_first_info)
75697c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np);
75707c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75717c478bd9Sstevel@tonic-gate rc_node_clear(out, 0);
75727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
75737c478bd9Sstevel@tonic-gate }
75747c478bd9Sstevel@tonic-gate
75757c478bd9Sstevel@tonic-gate nnp = np->rcn_node;
75767c478bd9Sstevel@tonic-gate assert(nnp != NULL);
75777c478bd9Sstevel@tonic-gate
75787c478bd9Sstevel@tonic-gate /*
75797c478bd9Sstevel@tonic-gate * We can't bump nnp's reference count without grabbing its
75807c478bd9Sstevel@tonic-gate * lock, and rc_pg_notify_lock is a leaf lock. So we
75817c478bd9Sstevel@tonic-gate * temporarily block all removals to keep nnp from
75827c478bd9Sstevel@tonic-gate * disappearing.
75837c478bd9Sstevel@tonic-gate */
75847c478bd9Sstevel@tonic-gate rc_notify_in_use++;
75857c478bd9Sstevel@tonic-gate assert(rc_notify_in_use > 0);
75867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75877c478bd9Sstevel@tonic-gate
75887c478bd9Sstevel@tonic-gate rc_node_assign(out, nnp);
75897c478bd9Sstevel@tonic-gate
75907c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
75917c478bd9Sstevel@tonic-gate assert(rc_notify_in_use > 0);
75927c478bd9Sstevel@tonic-gate rc_notify_in_use--;
7593b5cbdab0STom Whitten
7594b5cbdab0STom Whitten if (am_first_info) {
7595b5cbdab0STom Whitten /*
7596b5cbdab0STom Whitten * While we had the lock dropped, another thread
7597b5cbdab0STom Whitten * may have also incremented rc_notify_in_use. We
7598b5cbdab0STom Whitten * need to make sure that we're back to 0 before
7599b5cbdab0STom Whitten * removing the node.
7600b5cbdab0STom Whitten */
7601b5cbdab0STom Whitten while (rc_notify_in_use) {
7602b5cbdab0STom Whitten (void) pthread_cond_wait(&rc_pg_notify_cv,
7603b5cbdab0STom Whitten &rc_pg_notify_lock);
7604b5cbdab0STom Whitten }
76057c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np);
7606b5cbdab0STom Whitten }
76077c478bd9Sstevel@tonic-gate if (rc_notify_in_use == 0)
76087c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv);
76097c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76107c478bd9Sstevel@tonic-gate
76117c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
76127c478bd9Sstevel@tonic-gate }
76137c478bd9Sstevel@tonic-gate /*
76147c478bd9Sstevel@tonic-gate * If we're the last one out, let people know it's clear.
76157c478bd9Sstevel@tonic-gate */
76167c478bd9Sstevel@tonic-gate if (rnip->rni_waiters == 0)
76177c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
76187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76197c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
76207c478bd9Sstevel@tonic-gate }
76217c478bd9Sstevel@tonic-gate
76227c478bd9Sstevel@tonic-gate static void
rc_notify_info_reset(rc_notify_info_t * rnip)76237c478bd9Sstevel@tonic-gate rc_notify_info_reset(rc_notify_info_t *rnip)
76247c478bd9Sstevel@tonic-gate {
76257c478bd9Sstevel@tonic-gate int i;
76267c478bd9Sstevel@tonic-gate
76277c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
76287c478bd9Sstevel@tonic-gate if (rnip->rni_flags & RC_NOTIFY_ACTIVE)
76297c478bd9Sstevel@tonic-gate rc_notify_info_remove_locked(rnip);
76307c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & (RC_NOTIFY_DRAIN | RC_NOTIFY_EMPTYING)));
76317c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_EMPTYING;
76327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76337c478bd9Sstevel@tonic-gate
76347c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
76357c478bd9Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) {
76367c478bd9Sstevel@tonic-gate free((void *)rnip->rni_namelist[i]);
76377c478bd9Sstevel@tonic-gate rnip->rni_namelist[i] = NULL;
76387c478bd9Sstevel@tonic-gate }
76397c478bd9Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) {
76407c478bd9Sstevel@tonic-gate free((void *)rnip->rni_typelist[i]);
76417c478bd9Sstevel@tonic-gate rnip->rni_typelist[i] = NULL;
76427c478bd9Sstevel@tonic-gate }
76437c478bd9Sstevel@tonic-gate }
76447c478bd9Sstevel@tonic-gate
76457c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
76467c478bd9Sstevel@tonic-gate rnip->rni_flags &= ~RC_NOTIFY_EMPTYING;
76477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76487c478bd9Sstevel@tonic-gate }
76497c478bd9Sstevel@tonic-gate
76507c478bd9Sstevel@tonic-gate void
rc_notify_info_fini(rc_notify_info_t * rnip)76517c478bd9Sstevel@tonic-gate rc_notify_info_fini(rc_notify_info_t *rnip)
76527c478bd9Sstevel@tonic-gate {
76537c478bd9Sstevel@tonic-gate rc_notify_info_reset(rnip);
76547c478bd9Sstevel@tonic-gate
76557c478bd9Sstevel@tonic-gate uu_list_node_fini(rnip, &rnip->rni_list_node, rc_notify_info_pool);
76567c478bd9Sstevel@tonic-gate uu_list_node_fini(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
76577c478bd9Sstevel@tonic-gate rc_notify_pool);
76587c478bd9Sstevel@tonic-gate }
7659