Home | History | Annotate | Download | only in configd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * rc_node.c - In-memory SCF object management
     29  *
     30  * This layer manages the in-memory cache (the Repository Cache) of SCF
     31  * data.  Read requests are usually satisfied from here, but may require
     32  * load calls to the "object" layer.  Modify requests always write-through
     33  * to the object layer.
     34  *
     35  * SCF data comprises scopes, services, instances, snapshots, snaplevels,
     36  * property groups, properties, and property values.  All but the last are
     37  * known here as "entities" and are represented by rc_node_t data
     38  * structures.  (Property values are kept in the rn_values member of the
     39  * respective property, not as separate objects.)  All entities besides
     40  * the "localhost" scope have some entity as a parent, and therefore form
     41  * a tree.
     42  *
     43  * The entity tree is rooted at rc_scope, which rc_node_init() initializes to
     44  * the "localhost" scope.  The tree is filled in from the database on-demand
     45  * by rc_node_fill_children().
     46  *
     47  * rc_node_t's are also placed in the cache_hash[] hash table, for rapid
     48  * lookup.
     49  *
     50  * Multiple threads may service client requests, so access to each
     51  * rc_node_t is synchronized by its rn_lock member.  Some fields are
     52  * protected by bits in the rn_flags field instead, to support operations
     53  * which need to drop rn_lock, for example to respect locking order.  Such
     54  * flags should be manipulated with the rc_node_{hold,rele}_flag()
     55  * functions.
     56  *
     57  * We track references to nodes to tell when they can be free()d.  rn_refs
     58  * should be incremented with rc_node_hold() on the creation of client
     59  * references (rc_node_ptr_t's and rc_iter_t's).  rn_erefs ("ephemeral
     60  * references") should be incremented when a pointer is read into a local
     61  * variable of a thread, with rc_node_hold_ephemeral_locked().  This
     62  * hasn't been fully implemented, however, so rc_node_rele() tolerates
     63  * rn_erefs being 0.  Some code which predates rn_erefs counts ephemeral
     64  * references in rn_refs.  Other references are tracked by the
     65  * rn_other_refs field and the RC_NODE_DEAD, RC_NODE_IN_PARENT,
     66  * RC_NODE_OLD, and RC_NODE_ON_FORMER flags.
     67  *
     68  * Locking rules: To dereference an rc_node_t * (usually to lock it), you must
     69  * have a hold (rc_node_hold()) on it or otherwise be sure that it hasn't been
     70  * rc_node_destroy()ed (hold a lock on its parent or child, hold a flag,
     71  * etc.).  Once you have locked an rc_node_t you must check its rn_flags for
     72  * RC_NODE_DEAD before you can use it.  This is usually done with the
     73  * rc_node_{wait,hold}_flag() functions (often via the rc_node_check_*()
     74  * functions & RC_NODE_*() macros), which fail if the object has died.
     75  *
     76  * When a transactional node (property group or snapshot) is updated,
     77  * a new node takes the place of the old node in the global hash and the
     78  * old node is hung off of the rn_former list of the new node.  At the
     79  * same time, all of its children have their rn_parent_ref pointer set,
     80  * and any holds they have are reflected in the old node's rn_other_refs
     81  * count.  This is automatically kept up to date until the final reference
     82  * to the subgraph is dropped, at which point the node is unrefed and
     83  * destroyed, along with all of its children.
     84  *
     85  * Because name service lookups may take a long time and, more importantly
     86  * may trigger additional accesses to the repository, perm_granted() must be
     87  * called without holding any locks.
     88  *
     89  * An ITER_START for a non-ENTITY_VALUE induces an rc_node_fill_children()
     90  * call via rc_node_setup_iter() to populate the rn_children uu_list of the
     91  * rc_node_t * in question and a call to uu_list_walk_start() on that list.  For
     92  * ITER_READ, rc_iter_next() uses uu_list_walk_next() to find the next
     93  * apropriate child.
     94  *
     95  * An ITER_START for an ENTITY_VALUE makes sure the node has its values
     96  * filled, and sets up the iterator.  An ITER_READ_VALUE just copies out
     97  * the proper values and updates the offset information.
     98  *
     99  * To allow aliases, snapshots are implemented with a level of indirection.
    100  * A snapshot rc_node_t has a snapid which refers to an rc_snapshot_t in
    101  * snapshot.c which contains the authoritative snaplevel information.  The
    102  * snapid is "assigned" by rc_attach_snapshot().
    103  *
    104  * We provide the client layer with rc_node_ptr_t's to reference objects.
    105  * Objects referred to by them are automatically held & released by
    106  * rc_node_assign() & rc_node_clear().  The RC_NODE_PTR_*() macros are used at
    107  * client.c entry points to read the pointers.  They fetch the pointer to the
    108  * object, return (from the function) if it is dead, and lock, hold, or hold
    109  * a flag of the object.
    110  */
    111 
    112 /*
    113  * Permission checking is authorization-based: some operations may only
    114  * proceed if the user has been assigned at least one of a set of
    115  * authorization strings.  The set of enabling authorizations depends on the
    116  * operation and the target object.  The set of authorizations assigned to
    117  * a user is determined by reading /etc/security/policy.conf, querying the
    118  * user_attr database, and possibly querying the prof_attr database, as per
    119  * chkauthattr() in libsecdb.
    120  *
    121  * The fastest way to decide whether the two sets intersect is by entering the
    122  * strings into a hash table and detecting collisions, which takes linear time
    123  * in the total size of the sets.  Except for the authorization patterns which
    124  * may be assigned to users, which without advanced pattern-matching
    125  * algorithms will take O(n) in the number of enabling authorizations, per
    126  * pattern.
    127  *
    128  * We can achieve some practical speed-ups by noting that if we enter all of
    129  * the authorizations from one of the sets into the hash table we can merely
    130  * check the elements of the second set for existence without adding them.
    131  * This reduces memory requirements and hash table clutter.  The enabling set
    132  * is well suited for this because it is internal to configd (for now, at
    133  * least).  Combine this with short-circuiting and we can even minimize the
    134  * number of queries to the security databases (user_attr & prof_attr).
    135  *
    136  * To force this usage onto clients we provide functions for adding
    137  * authorizations to the enabling set of a permission context structure
    138  * (perm_add_*()) and one to decide whether the the user associated with the
    139  * current door call client possesses any of them (perm_granted()).
    140  *
    141  * At some point, a generic version of this should move to libsecdb.
    142  *
    143  * While entering the enabling strings into the hash table, we keep track
    144  * of which is the most specific for use in generating auditing events.
    145  * See the "Collecting the Authorization String" section of the "SMF Audit
    146  * Events" block comment below.
    147  */
    148 
    149 /*
    150  * Composition is the combination of sets of properties.  The sets are ordered
    151  * and properties in higher sets obscure properties of the same name in lower
    152  * sets.  Here we present a composed view of an instance's properties as the
    153  * union of its properties and its service's properties.  Similarly the
    154  * properties of snaplevels are combined to form a composed view of the
    155  * properties of a snapshot (which should match the composed view of the
    156  * properties of the instance when the snapshot was taken).
    157  *
    158  * In terms of the client interface, the client may request that a property
    159  * group iterator for an instance or snapshot be composed.  Property groups
    160  * traversed by such an iterator may not have the target entity as a parent.
    161  * Similarly, the properties traversed by a property iterator for those
    162  * property groups may not have the property groups iterated as parents.
    163  *
    164  * Implementation requires that iterators for instances and snapshots be
    165  * composition-savvy, and that we have a "composed property group" entity
    166  * which represents the composition of a number of property groups.  Iteration
    167  * over "composed property groups" yields properties which may have different
    168  * parents, but for all other operations a composed property group behaves
    169  * like the top-most property group it represents.
    170  *
    171  * The implementation is based on the rn_cchain[] array of rc_node_t pointers
    172  * in rc_node_t.  For instances, the pointers point to the instance and its
    173  * parent service.  For snapshots they point to the child snaplevels, and for
    174  * composed property groups they point to property groups.  A composed
    175  * iterator carries an index into rn_cchain[].  Thus most of the magic ends up
    176  * int the rc_iter_*() code.
    177  */
    178 /*
    179  * SMF Audit Events:
    180  * ================
    181  *
    182  * To maintain security, SMF generates audit events whenever
    183  * privileged operations are attempted.  See the System Administration
    184  * Guide:Security Services answerbook for a discussion of the Solaris
    185  * audit system.
    186  *
    187  * The SMF audit event codes are defined in adt_event.h by symbols
    188  * starting with ADT_smf_ and are described in audit_event.txt.  The
    189  * audit record structures are defined in the SMF section of adt.xml.
    190  * adt.xml is used to automatically generate adt_event.h which
    191  * contains the definitions that we code to in this file.  For the
    192  * most part the audit events map closely to actions that you would
    193  * perform with svcadm or svccfg, but there are some special cases
    194  * which we'll discuss later.
    195  *
    196  * The software associated with SMF audit events falls into three
    197  * categories:
    198  * 	- collecting information to be written to the audit
    199  *	  records
    200  *	- using the adt_* functions in
    201  *	  usr/src/lib/libbsm/common/adt.c to generate the audit
    202  *	  records.
    203  * 	- handling special cases
    204  *
    205  * Collecting Information:
    206  * ----------------------
    207  *
    208  * Most all of the audit events require the FMRI of the affected
    209  * object and the authorization string that was used.  The one
    210  * exception is ADT_smf_annotation which we'll talk about later.
    211  *
    212  * Collecting the FMRI:
    213  *
    214  * The rc_node structure has a member called rn_fmri which points to
    215  * its FMRI.  This is initialized by a call to rc_node_build_fmri()
    216  * when the node's parent is established.  The reason for doing it
    217  * at this time is that a node's FMRI is basically the concatenation
    218  * of the parent's FMRI and the node's name with the appropriate
    219  * decoration.  rc_node_build_fmri() does this concatenation and
    220  * decorating.  It is called from rc_node_link_child() and
    221  * rc_node_relink_child() where a node is linked to its parent.
    222  *
    223  * rc_node_get_fmri_or_fragment() is called to retrieve a node's FMRI
    224  * when it is needed.  It returns rn_fmri if it is set.  If the node
    225  * is at the top level, however, rn_fmri won't be set because it was
    226  * never linked to a parent.  In this case,
    227  * rc_node_get_fmri_or_fragment() constructs an FMRI fragment based on
    228  * its node type and its name, rn_name.
    229  *
    230  * Collecting the Authorization String:
    231  *
    232  * Naturally, the authorization string is captured during the
    233  * authorization checking process.  Acceptable authorization strings
    234  * are added to a permcheck_t hash table as noted in the section on
    235  * permission checking above.  Once all entries have been added to the
    236  * hash table, perm_granted() is called.  If the client is authorized,
    237  * perm_granted() returns with pc_auth_string of the permcheck_t
    238  * structure pointing to the authorization string.
    239  *
    240  * This works fine if the client is authorized, but what happens if
    241  * the client is not authorized?  We need to report the required
    242  * authorization string.  This is the authorization that would have
    243  * been used if permission had been granted.  perm_granted() will
    244  * find no match, so it needs to decide which string in the hash
    245  * table to use as the required authorization string.  It needs to do
    246  * this, because configd is still going to generate an event.  A
    247  * design decision was made to use the most specific authorization
    248  * in the hash table.  The pc_auth_type enum designates the
    249  * specificity of an authorization string.  For example, an
    250  * authorization string that is declared in an instance PG is more
    251  * specific than one that is declared in a service PG.
    252  *
    253  * The pc_add() function keeps track of the most specific
    254  * authorization in the hash table.  It does this using the
    255  * pc_specific and pc_specific_type members of the permcheck
    256  * structure.  pc_add() updates these members whenever a more
    257  * specific authorization string is added to the hash table.  Thus, if
    258  * an authorization match is not found, perm_granted() will return
    259  * with pc_auth_string in the permcheck_t pointing to the string that
    260  * is referenced by pc_specific.
    261  *
    262  * Generating the Audit Events:
    263  * ===========================
    264  *
    265  * As the functions in this file process requests for clients of
    266  * configd, they gather the information that is required for an audit
    267  * event.  Eventually, the request processing gets to the point where
    268  * the authorization is rejected or to the point where the requested
    269  * action was attempted.  At these two points smf_audit_event() is
    270  * called.
    271  *
    272  * smf_audit_event() takes 4 parameters:
    273  * 	- the event ID which is one of the ADT_smf_* symbols from
    274  *	  adt_event.h.
    275  * 	- status to pass to adt_put_event()
    276  * 	- return value to pass to adt_put_event()
    277  * 	- the event data (see audit_event_data structure)
    278  *
    279  * All interactions with the auditing software require an audit
    280  * session.  We use one audit session per configd client.  We keep
    281  * track of the audit session in the repcache_client structure.
    282  * smf_audit_event() calls get_audit_session() to get the session
    283  * pointer.
    284  *
    285  * smf_audit_event() then calls adt_alloc_event() to allocate an
    286  * adt_event_data union which is defined in adt_event.h, copies the
    287  * data into the appropriate members of the union and calls
    288  * adt_put_event() to generate the event.
    289  *
    290  * Special Cases:
    291  * =============
    292  *
    293  * There are three major types of special cases:
    294  *
    295  * 	- gathering event information for each action in a
    296  *	  transaction
    297  * 	- Higher level events represented by special property
    298  *	  group/property name combinations.  Many of these are
    299  *	  restarter actions.
    300  * 	- ADT_smf_annotation event
    301  *
    302  * Processing Transaction Actions:
    303  * ------------------------------
    304  *
    305  * A transaction can contain multiple actions to modify, create or
    306  * delete one or more properties.  We need to capture information so
    307  * that we can generate an event for each property action.  The
    308  * transaction information is stored in a tx_commmit_data_t, and
    309  * object.c provides accessor functions to retrieve data from this
    310  * structure.  rc_tx_commit() obtains a tx_commit_data_t by calling
    311  * tx_commit_data_new() and passes this to object_tx_commit() to
    312  * commit the transaction.  Then we call generate_property_events() to
    313  * generate an audit event for each property action.
    314  *
    315  * Special Properties:
    316  * ------------------
    317  *
    318  * There are combinations of property group/property name that are special.
    319  * They are special because they have specific meaning to startd.  startd
    320  * interprets them in a service-independent fashion.
    321  * restarter_actions/refresh and general/enabled are two examples of these.
    322  * A special event is generated for these properties in addition to the
    323  * regular property event described in the previous section.  The special
    324  * properties are declared as an array of audit_special_prop_item
    325  * structures at special_props_list in rc_node.c.
    326  *
    327  * In the previous section, we mentioned the
    328  * generate_property_event() function that generates an event for
    329  * every property action.  Before generating the event,
    330  * generate_property_event() calls special_property_event().
    331  * special_property_event() checks to see if the action involves a
    332  * special property.  If it does, it generates a special audit
    333  * event.
    334  *
    335  * ADT_smf_annotation event:
    336  * ------------------------
    337  *
    338  * This is a special event unlike any other.  It allows the svccfg
    339  * program to store an annotation in the event log before a series
    340  * of transactions is processed.  It is used with the import and
    341  * apply svccfg commands.  svccfg uses the rep_protocol_annotation
    342  * message to pass the operation (import or apply) and the file name
    343  * to configd.  The set_annotation() function in client.c stores
    344  * these away in the a repcache_client structure.  The address of
    345  * this structure is saved in the thread_info structure.
    346  *
    347  * Before it generates any events, smf_audit_event() calls
    348  * smf_annotation_event().  smf_annotation_event() calls
    349  * client_annotation_needed() which is defined in client.c.  If an
    350  * annotation is needed client_annotation_needed() returns the
    351  * operation and filename strings that were saved from the
    352  * rep_protocol_annotation message.  smf_annotation_event() then
    353  * generates the ADT_smf_annotation event.
    354  */
    355 
    356 #include <assert.h>
    357 #include <atomic.h>
    358 #include <bsm/adt_event.h>
    359 #include <errno.h>
    360 #include <libuutil.h>
    361 #include <libscf.h>
    362 #include <libscf_priv.h>
    363 #include <prof_attr.h>
    364 #include <pthread.h>
    365 #include <pwd.h>
    366 #include <stdio.h>
    367 #include <stdlib.h>
    368 #include <strings.h>
    369 #include <sys/types.h>
    370 #include <syslog.h>
    371 #include <unistd.h>
    372 #include <user_attr.h>
    373 
    374 #include "configd.h"
    375 
    376 #define	AUTH_PREFIX		"solaris.smf."
    377 #define	AUTH_MANAGE		AUTH_PREFIX "manage"
    378 #define	AUTH_MODIFY		AUTH_PREFIX "modify"
    379 #define	AUTH_MODIFY_PREFIX	AUTH_MODIFY "."
    380 #define	AUTH_PG_ACTIONS		SCF_PG_RESTARTER_ACTIONS
    381 #define	AUTH_PG_ACTIONS_TYPE	SCF_PG_RESTARTER_ACTIONS_TYPE
    382 #define	AUTH_PG_GENERAL		SCF_PG_GENERAL
    383 #define	AUTH_PG_GENERAL_TYPE	SCF_PG_GENERAL_TYPE
    384 #define	AUTH_PG_GENERAL_OVR	SCF_PG_GENERAL_OVR
    385 #define	AUTH_PG_GENERAL_OVR_TYPE  SCF_PG_GENERAL_OVR_TYPE
    386 #define	AUTH_PROP_ACTION	"action_authorization"
    387 #define	AUTH_PROP_ENABLED	"enabled"
    388 #define	AUTH_PROP_MODIFY	"modify_authorization"
    389 #define	AUTH_PROP_VALUE		"value_authorization"
    390 #define	AUTH_PROP_READ		"read_authorization"
    391 /* libsecdb should take care of this. */
    392 #define	RBAC_AUTH_SEP		","
    393 
    394 #define	MAX_VALID_CHILDREN 3
    395 
    396 /*
    397  * The ADT_smf_* symbols may not be defined on the build machine.  Because
    398  * of this, we do not want to compile the _smf_aud_event() function when
    399  * doing native builds.
    400  */
    401 #ifdef	NATIVE_BUILD
    402 #define	smf_audit_event(i, s, r, d)
    403 #else
    404 #define	smf_audit_event(i, s, r, d)	_smf_audit_event(i, s, r, d)
    405 #endif	/* NATIVE_BUILD */
    406 
    407 typedef struct rc_type_info {
    408 	uint32_t	rt_type;		/* matches array index */
    409 	uint32_t	rt_num_ids;
    410 	uint32_t	rt_name_flags;
    411 	uint32_t	rt_valid_children[MAX_VALID_CHILDREN];
    412 } rc_type_info_t;
    413 
    414 #define	RT_NO_NAME	-1U
    415 
    416 static rc_type_info_t rc_types[] = {
    417 	{REP_PROTOCOL_ENTITY_NONE, 0, RT_NO_NAME},
    418 	{REP_PROTOCOL_ENTITY_SCOPE, 0, 0,
    419 	    {REP_PROTOCOL_ENTITY_SERVICE, REP_PROTOCOL_ENTITY_SCOPE}},
    420 	{REP_PROTOCOL_ENTITY_SERVICE, 0, UU_NAME_DOMAIN | UU_NAME_PATH,
    421 	    {REP_PROTOCOL_ENTITY_INSTANCE, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
    422 	{REP_PROTOCOL_ENTITY_INSTANCE, 1, UU_NAME_DOMAIN,
    423 	    {REP_PROTOCOL_ENTITY_SNAPSHOT, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
    424 	{REP_PROTOCOL_ENTITY_SNAPSHOT, 2, UU_NAME_DOMAIN,
    425 	    {REP_PROTOCOL_ENTITY_SNAPLEVEL, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
    426 	{REP_PROTOCOL_ENTITY_SNAPLEVEL, 4, RT_NO_NAME,
    427 	    {REP_PROTOCOL_ENTITY_PROPERTYGRP}},
    428 	{REP_PROTOCOL_ENTITY_PROPERTYGRP, 5, UU_NAME_DOMAIN,
    429 	    {REP_PROTOCOL_ENTITY_PROPERTY}},
    430 	{REP_PROTOCOL_ENTITY_CPROPERTYGRP, 0, UU_NAME_DOMAIN,
    431 	    {REP_PROTOCOL_ENTITY_PROPERTY}},
    432 	{REP_PROTOCOL_ENTITY_PROPERTY, 7, UU_NAME_DOMAIN},
    433 	{-1UL}
    434 };
    435 #define	NUM_TYPES	((sizeof (rc_types) / sizeof (*rc_types)))
    436 
    437 /* Element of a permcheck_t hash table. */
    438 struct pc_elt {
    439 	struct pc_elt	*pce_next;
    440 	char		pce_auth[1];
    441 };
    442 
    443 /*
    444  * If an authorization fails, we must decide which of the elements in the
    445  * permcheck hash table to use in the audit event.  That is to say of all
    446  * the strings in the hash table, we must choose one and use it in the audit
    447  * event.  It is desirable to use the most specific string in the audit
    448  * event.
    449  *
    450  * The pc_auth_type specifies the types (sources) of authorization
    451  * strings.  The enum is ordered in increasing specificity.
    452  */
    453 typedef enum pc_auth_type {
    454 	PC_AUTH_NONE = 0,	/* no auth string available. */
    455 	PC_AUTH_SMF,		/* strings coded into SMF. */
    456 	PC_AUTH_SVC,		/* strings specified in PG of a service. */
    457 	PC_AUTH_INST		/* strings specified in PG of an instance. */
    458 } pc_auth_type_t;
    459 
    460 /*
    461  * The following enum is used to represent the results of the checks to see
    462  * if the client has the appropriate permissions to perform an action.
    463  */
    464 typedef enum perm_status {
    465 	PERM_DENIED = 0,	/* Permission denied. */
    466 	PERM_GRANTED,		/* Client has authorizations. */
    467 	PERM_GONE,		/* Door client went away. */
    468 	PERM_FAIL		/* Generic failure. e.g. resources */
    469 } perm_status_t;
    470 
    471 /* An authorization set hash table. */
    472 typedef struct {
    473 	struct pc_elt	**pc_buckets;
    474 	uint_t		pc_bnum;		/* number of buckets */
    475 	uint_t		pc_enum;		/* number of elements */
    476 	struct pc_elt	*pc_specific;		/* most specific element */
    477 	pc_auth_type_t	pc_specific_type;	/* type of pc_specific */
    478 	char		*pc_auth_string;	/* authorization string */
    479 						/* for audit events */
    480 } permcheck_t;
    481 
    482 /*
    483  * Structure for holding audit event data.  Not all events use all members
    484  * of the structure.
    485  */
    486 typedef struct audit_event_data {
    487 	char		*ed_auth;	/* authorization string. */
    488 	char		*ed_fmri;	/* affected FMRI. */
    489 	char		*ed_snapname;	/* name of snapshot. */
    490 	char		*ed_old_fmri;	/* old fmri in attach case. */
    491 	char		*ed_old_name;	/* old snapshot in attach case. */
    492 	char		*ed_type;	/* prop. group or prop. type. */
    493 	char		*ed_prop_value;	/* property value. */
    494 } audit_event_data_t;
    495 
    496 /*
    497  * Pointer to function to do special processing to get audit event ID.
    498  * Audit event IDs are defined in /usr/include/bsm/adt_event.h.  Function
    499  * returns 0 if ID successfully retrieved.  Otherwise it returns -1.
    500  */
    501 typedef int (*spc_getid_fn_t)(tx_commit_data_t *, size_t, const char *,
    502     au_event_t *);
    503 static int general_enable_id(tx_commit_data_t *, size_t, const char *,
    504     au_event_t *);
    505 
    506 static uu_list_pool_t *rc_children_pool;
    507 static uu_list_pool_t *rc_pg_notify_pool;
    508 static uu_list_pool_t *rc_notify_pool;
    509 static uu_list_pool_t *rc_notify_info_pool;
    510 
    511 static rc_node_t *rc_scope;
    512 
    513 static pthread_mutex_t	rc_pg_notify_lock = PTHREAD_MUTEX_INITIALIZER;
    514 static pthread_cond_t	rc_pg_notify_cv = PTHREAD_COND_INITIALIZER;
    515 static uint_t		rc_notify_in_use;	/* blocks removals */
    516 
    517 /*
    518  * Some combinations of property group/property name require a special
    519  * audit event to be generated when there is a change.
    520  * audit_special_prop_item_t is used to specify these special cases.  The
    521  * special_props_list array defines a list of these special properties.
    522  */
    523 typedef struct audit_special_prop_item {
    524 	const char	*api_pg_name;	/* property group name. */
    525 	const char	*api_prop_name;	/* property name. */
    526 	au_event_t	api_event_id;	/* event id or 0. */
    527 	spc_getid_fn_t	api_event_func; /* function to get event id. */
    528 } audit_special_prop_item_t;
    529 
    530 /*
    531  * Native builds are done using the build machine's standard include
    532  * files.  These files may not yet have the definitions for the ADT_smf_*
    533  * symbols.  Thus, we do not compile this table when doing native builds.
    534  */
    535 #ifndef	NATIVE_BUILD
    536 /*
    537  * The following special_props_list array specifies property group/property
    538  * name combinations that have specific meaning to startd.  A special event
    539  * is generated for these combinations in addition to the regular property
    540  * event.
    541  *
    542  * At run time this array gets sorted.  See the call to qsort(3C) in
    543  * rc_node_init().  The array is sorted, so that bsearch(3C) can be used
    544  * to do lookups.
    545  */
    546 static audit_special_prop_item_t special_props_list[] = {
    547 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADED, ADT_smf_degrade,
    548 	    NULL},
    549 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADE_IMMEDIATE,
    550 	    ADT_smf_immediate_degrade, NULL},
    551 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_OFF, ADT_smf_clear, NULL},
    552 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON,
    553 	    ADT_smf_maintenance, NULL},
    554 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMEDIATE,
    555 	    ADT_smf_immediate_maintenance, NULL},
    556 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMTEMP,
    557 	    ADT_smf_immtmp_maintenance, NULL},
    558 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_TEMPORARY,
    559 	    ADT_smf_tmp_maintenance, NULL},
    560 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_REFRESH, ADT_smf_refresh, NULL},
    561 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTART, ADT_smf_restart, NULL},
    562 	{SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTORE, ADT_smf_clear, NULL},
    563 	{SCF_PG_OPTIONS, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
    564 	{SCF_PG_OPTIONS_OVR, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
    565 	{SCF_PG_GENERAL, SCF_PROPERTY_ENABLED, 0, general_enable_id},
    566 	{SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 0, general_enable_id}
    567 };
    568 #define	SPECIAL_PROP_COUNT	(sizeof (special_props_list) /\
    569 	sizeof (audit_special_prop_item_t))
    570 #endif	/* NATIVE_BUILD */
    571 
    572 /*
    573  * We support an arbitrary number of clients interested in events for certain
    574  * types of changes.  Each client is represented by an rc_notify_info_t, and
    575  * all clients are chained onto the rc_notify_info_list.
    576  *
    577  * The rc_notify_list is the global notification list.  Each entry is of
    578  * type rc_notify_t, which is embedded in one of three other structures:
    579  *
    580  *	rc_node_t		property group update notification
    581  *	rc_notify_delete_t	object deletion notification
    582  *	rc_notify_info_t	notification clients
    583  *
    584  * Which type of object is determined by which pointer in the rc_notify_t is
    585  * non-NULL.
    586  *
    587  * New notifications and clients are added to the end of the list.
    588  * Notifications no-one is interested in are never added to the list.
    589  *
    590  * Clients use their position in the list to track which notifications they
    591  * have not yet reported.  As they process notifications, they move forward
    592  * in the list past them.  There is always a client at the beginning of the
    593  * list -- as he moves past notifications, he removes them from the list and
    594  * cleans them up.
    595  *
    596  * The rc_pg_notify_lock protects all notification state.  The rc_pg_notify_cv
    597  * is used for global signalling, and each client has a cv which he waits for
    598  * events of interest on.
    599  */
    600 static uu_list_t	*rc_notify_info_list;
    601 static uu_list_t	*rc_notify_list;
    602 
    603 #define	HASH_SIZE	512
    604 #define	HASH_MASK	(HASH_SIZE - 1)
    605 
    606 #pragma align 64(cache_hash)
    607 static cache_bucket_t cache_hash[HASH_SIZE];
    608 
    609 #define	CACHE_BUCKET(h)		(&cache_hash[(h) & HASH_MASK])
    610 
    611 
    612 static void rc_node_no_client_refs(rc_node_t *np);
    613 
    614 
    615 static uint32_t
    616 rc_node_hash(rc_node_lookup_t *lp)
    617 {
    618 	uint32_t type = lp->rl_type;
    619 	uint32_t backend = lp->rl_backend;
    620 	uint32_t mainid = lp->rl_main_id;
    621 	uint32_t *ids = lp->rl_ids;
    622 
    623 	rc_type_info_t *tp = &rc_types[type];
    624 	uint32_t num_ids;
    625 	uint32_t left;
    626 	uint32_t hash;
    627 
    628 	assert(backend == BACKEND_TYPE_NORMAL ||
    629 	    backend == BACKEND_TYPE_NONPERSIST);
    630 
    631 	assert(type > 0 && type < NUM_TYPES);
    632 	num_ids = tp->rt_num_ids;
    633 
    634 	left = MAX_IDS - num_ids;
    635 	assert(num_ids <= MAX_IDS);
    636 
    637 	hash = type * 7 + mainid * 5 + backend;
    638 
    639 	while (num_ids-- > 0)
    640 		hash = hash * 11 + *ids++ * 7;
    641 
    642 	/*
    643 	 * the rest should be zeroed
    644 	 */
    645 	while (left-- > 0)
    646 		assert(*ids++ == 0);
    647 
    648 	return (hash);
    649 }
    650 
    651 static int
    652 rc_node_match(rc_node_t *np, rc_node_lookup_t *l)
    653 {
    654 	rc_node_lookup_t *r = &np->rn_id;
    655 	rc_type_info_t *tp;
    656 	uint32_t type;
    657 	uint32_t num_ids;
    658 
    659 	if (r->rl_main_id != l->rl_main_id)
    660 		return (0);
    661 
    662 	type = r->rl_type;
    663 	if (type != l->rl_type)
    664 		return (0);
    665 
    666 	assert(type > 0 && type < NUM_TYPES);
    667 
    668 	tp = &rc_types[r->rl_type];
    669 	num_ids = tp->rt_num_ids;
    670 
    671 	assert(num_ids <= MAX_IDS);
    672 	while (num_ids-- > 0)
    673 		if (r->rl_ids[num_ids] != l->rl_ids[num_ids])
    674 			return (0);
    675 
    676 	return (1);
    677 }
    678 
    679 /*
    680  * Register an ephemeral reference to np.  This should be done while both
    681  * the persistent reference from which the np pointer was read is locked
    682  * and np itself is locked.  This guarantees that another thread which
    683  * thinks it has the last reference will yield without destroying the
    684  * node.
    685  */
    686 static void
    687 rc_node_hold_ephemeral_locked(rc_node_t *np)
    688 {
    689 	assert(MUTEX_HELD(&np->rn_lock));
    690 
    691 	++np->rn_erefs;
    692 }
    693 
    694 /*
    695  * the "other" references on a node are maintained in an atomically
    696  * updated refcount, rn_other_refs.  This can be bumped from arbitrary
    697  * context, and tracks references to a possibly out-of-date node's children.
    698  *
    699  * To prevent the node from disappearing between the final drop of
    700  * rn_other_refs and the unref handling, rn_other_refs_held is bumped on
    701  * 0->1 transitions and decremented (with the node lock held) on 1->0
    702  * transitions.
    703  */
    704 static void
    705 rc_node_hold_other(rc_node_t *np)
    706 {
    707 	if (atomic_add_32_nv(&np->rn_other_refs, 1) == 1) {
    708 		atomic_add_32(&np->rn_other_refs_held, 1);
    709 		assert(np->rn_other_refs_held > 0);
    710 	}
    711 	assert(np->rn_other_refs > 0);
    712 }
    713 
    714 /*
    715  * No node locks may be held
    716  */
    717 static void
    718 rc_node_rele_other(rc_node_t *np)
    719 {
    720 	assert(np->rn_other_refs > 0);
    721 	if (atomic_add_32_nv(&np->rn_other_refs, -1) == 0) {
    722 		(void) pthread_mutex_lock(&np->rn_lock);
    723 		assert(np->rn_other_refs_held > 0);
    724 		if (atomic_add_32_nv(&np->rn_other_refs_held, -1) == 0 &&
    725 		    np->rn_refs == 0 && (np->rn_flags & RC_NODE_OLD)) {
    726 			/*
    727 			 * This was the last client reference.  Destroy
    728 			 * any other references and free() the node.
    729 			 */
    730 			rc_node_no_client_refs(np);
    731 		} else {
    732 			(void) pthread_mutex_unlock(&np->rn_lock);
    733 		}
    734 	}
    735 }
    736 
    737 static void
    738 rc_node_hold_locked(rc_node_t *np)
    739 {
    740 	assert(MUTEX_HELD(&np->rn_lock));
    741 
    742 	if (np->rn_refs == 0 && (np->rn_flags & RC_NODE_PARENT_REF))
    743 		rc_node_hold_other(np->rn_parent_ref);
    744 	np->rn_refs++;
    745 	assert(np->rn_refs > 0);
    746 }
    747 
    748 static void
    749 rc_node_hold(rc_node_t *np)
    750 {
    751 	(void) pthread_mutex_lock(&np->rn_lock);
    752 	rc_node_hold_locked(np);
    753 	(void) pthread_mutex_unlock(&np->rn_lock);
    754 }
    755 
    756 static void
    757 rc_node_rele_locked(rc_node_t *np)
    758 {
    759 	int unref = 0;
    760 	rc_node_t *par_ref = NULL;
    761 
    762 	assert(MUTEX_HELD(&np->rn_lock));
    763 	assert(np->rn_refs > 0);
    764 
    765 	if (--np->rn_refs == 0) {
    766 		if (np->rn_flags & RC_NODE_PARENT_REF)
    767 			par_ref = np->rn_parent_ref;
    768 
    769 		/*
    770 		 * Composed property groups are only as good as their
    771 		 * references.
    772 		 */
    773 		if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
    774 			np->rn_flags |= RC_NODE_DEAD;
    775 
    776 		if ((np->rn_flags & (RC_NODE_DEAD|RC_NODE_OLD)) &&
    777 		    np->rn_other_refs == 0 && np->rn_other_refs_held == 0)
    778 			unref = 1;
    779 	}
    780 
    781 	if (unref) {
    782 		/*
    783 		 * This was the last client reference.  Destroy any other
    784 		 * references and free() the node.
    785 		 */
    786 		rc_node_no_client_refs(np);
    787 	} else {
    788 		/*
    789 		 * rn_erefs can be 0 if we acquired the reference in
    790 		 * a path which hasn't been updated to increment rn_erefs.
    791 		 * When all paths which end here are updated, we should
    792 		 * assert rn_erefs > 0 and always decrement it.
    793 		 */
    794 		if (np->rn_erefs > 0)
    795 			--np->rn_erefs;
    796 		(void) pthread_mutex_unlock(&np->rn_lock);
    797 	}
    798 
    799 	if (par_ref != NULL)
    800 		rc_node_rele_other(par_ref);
    801 }
    802 
    803 void
    804 rc_node_rele(rc_node_t *np)
    805 {
    806 	(void) pthread_mutex_lock(&np->rn_lock);
    807 	rc_node_rele_locked(np);
    808 }
    809 
    810 static cache_bucket_t *
    811 cache_hold(uint32_t h)
    812 {
    813 	cache_bucket_t *bp = CACHE_BUCKET(h);
    814 	(void) pthread_mutex_lock(&bp->cb_lock);
    815 	return (bp);
    816 }
    817 
    818 static void
    819 cache_release(cache_bucket_t *bp)
    820 {
    821 	(void) pthread_mutex_unlock(&bp->cb_lock);
    822 }
    823 
    824 static rc_node_t *
    825 cache_lookup_unlocked(cache_bucket_t *bp, rc_node_lookup_t *lp)
    826 {
    827 	uint32_t h = rc_node_hash(lp);
    828 	rc_node_t *np;
    829 
    830 	assert(MUTEX_HELD(&bp->cb_lock));
    831 	assert(bp == CACHE_BUCKET(h));
    832 
    833 	for (np = bp->cb_head; np != NULL; np = np->rn_hash_next) {
    834 		if (np->rn_hash == h && rc_node_match(np, lp)) {
    835 			rc_node_hold(np);
    836 			return (np);
    837 		}
    838 	}
    839 
    840 	return (NULL);
    841 }
    842 
    843 static rc_node_t *
    844 cache_lookup(rc_node_lookup_t *lp)
    845 {
    846 	uint32_t h;
    847 	cache_bucket_t *bp;
    848 	rc_node_t *np;
    849 
    850 	h = rc_node_hash(lp);
    851 	bp = cache_hold(h);
    852 
    853 	np = cache_lookup_unlocked(bp, lp);
    854 
    855 	cache_release(bp);
    856 
    857 	return (np);
    858 }
    859 
    860 static void
    861 cache_insert_unlocked(cache_bucket_t *bp, rc_node_t *np)
    862 {
    863 	assert(MUTEX_HELD(&bp->cb_lock));
    864 	assert(np->rn_hash == rc_node_hash(&np->rn_id));
    865 	assert(bp == CACHE_BUCKET(np->rn_hash));
    866 
    867 	assert(np->rn_hash_next == NULL);
    868 
    869 	np->rn_hash_next = bp->cb_head;
    870 	bp->cb_head = np;
    871 }
    872 
    873 static void
    874 cache_remove_unlocked(cache_bucket_t *bp, rc_node_t *np)
    875 {
    876 	rc_node_t **npp;
    877 
    878 	assert(MUTEX_HELD(&bp->cb_lock));
    879 	assert(np->rn_hash == rc_node_hash(&np->rn_id));
    880 	assert(bp == CACHE_BUCKET(np->rn_hash));
    881 
    882 	for (npp = &bp->cb_head; *npp != NULL; npp = &(*npp)->rn_hash_next)
    883 		if (*npp == np)
    884 			break;
    885 
    886 	assert(*npp == np);
    887 	*npp = np->rn_hash_next;
    888 	np->rn_hash_next = NULL;
    889 }
    890 
    891 /*
    892  * verify that the 'parent' type can have a child typed 'child'
    893  * Fails with
    894  *   _INVALID_TYPE - argument is invalid
    895  *   _TYPE_MISMATCH - parent type cannot have children of type child
    896  */
    897 static int
    898 rc_check_parent_child(uint32_t parent, uint32_t child)
    899 {
    900 	int idx;
    901 	uint32_t type;
    902 
    903 	if (parent == 0 || parent >= NUM_TYPES ||
    904 	    child == 0 || child >= NUM_TYPES)
    905 		return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
    906 
    907 	for (idx = 0; idx < MAX_VALID_CHILDREN; idx++) {
    908 		type = rc_types[parent].rt_valid_children[idx];
    909 		if (type == child)
    910 			return (REP_PROTOCOL_SUCCESS);
    911 	}
    912 
    913 	return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
    914 }
    915 
    916 /*
    917  * Fails with
    918  *   _INVALID_TYPE - type is invalid
    919  *   _BAD_REQUEST - name is an invalid name for a node of type type
    920  */
    921 int
    922 rc_check_type_name(uint32_t type, const char *name)
    923 {
    924 	if (type == 0 || type >= NUM_TYPES)
    925 		return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
    926 
    927 	if (uu_check_name(name, rc_types[type].rt_name_flags) == -1)
    928 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
    929 
    930 	return (REP_PROTOCOL_SUCCESS);
    931 }
    932 
    933 static int
    934 rc_check_pgtype_name(const char *name)
    935 {
    936 	if (uu_check_name(name, UU_NAME_DOMAIN) == -1)
    937 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
    938 
    939 	return (REP_PROTOCOL_SUCCESS);
    940 }
    941 
    942 /*
    943  * rc_node_free_fmri should be called whenever a node loses its parent.
    944  * The reason is that the node's fmri string is built up by concatenating
    945  * its name to the parent's fmri.  Thus, when the node no longer has a
    946  * parent, its fmri is no longer valid.
    947  */
    948 static void
    949 rc_node_free_fmri(rc_node_t *np)
    950 {
    951 	if (np->rn_fmri != NULL) {
    952 		free((void *)np->rn_fmri);
    953 		np->rn_fmri = NULL;
    954 	}
    955 }
    956 
    957 /*
    958  * Concatenate the appropriate separator and the FMRI element to the base
    959  * FMRI string at fmri.
    960  *
    961  * Fails with
    962  *	_TRUNCATED	Not enough room in buffer at fmri.
    963  */
    964 static int
    965 rc_concat_fmri_element(
    966 	char *fmri,			/* base fmri */
    967 	size_t bufsize,			/* size of buf at fmri */
    968 	size_t *sz_out,			/* receives result size. */
    969 	const char *element,		/* element name to concat */
    970 	rep_protocol_entity_t type)	/* type of element */
    971 {
    972 	size_t actual;
    973 	const char *name = element;
    974 	int rc;
    975 	const char *separator;
    976 
    977 	if (bufsize > 0)
    978 		*sz_out = strlen(fmri);
    979 	else
    980 		*sz_out = 0;
    981 
    982 	switch (type) {
    983 	case REP_PROTOCOL_ENTITY_SCOPE:
    984 		if (strcmp(element, SCF_FMRI_LOCAL_SCOPE) == 0) {
    985 			/*
    986 			 * No need to display scope information if we are
    987 			 * in the local scope.
    988 			 */
    989 			separator = SCF_FMRI_SVC_PREFIX;
    990 			name = NULL;
    991 		} else {
    992 			/*
    993 			 * Need to display scope information, because it is
    994 			 * not the local scope.
    995 			 */
    996 			separator = SCF_FMRI_SVC_PREFIX SCF_FMRI_SCOPE_PREFIX;
    997 		}
    998 		break;
    999 	case REP_PROTOCOL_ENTITY_SERVICE:
   1000 		separator = SCF_FMRI_SERVICE_PREFIX;
   1001 		break;
   1002 	case REP_PROTOCOL_ENTITY_INSTANCE:
   1003 		separator = SCF_FMRI_INSTANCE_PREFIX;
   1004 		break;
   1005 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   1006 	case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
   1007 		separator = SCF_FMRI_PROPERTYGRP_PREFIX;
   1008 		break;
   1009 	case REP_PROTOCOL_ENTITY_PROPERTY:
   1010 		separator = SCF_FMRI_PROPERTY_PREFIX;
   1011 		break;
   1012 	case REP_PROTOCOL_ENTITY_VALUE:
   1013 		/*
   1014 		 * A value does not have a separate FMRI from its property,
   1015 		 * so there is nothing to concat.
   1016 		 */
   1017 		return (REP_PROTOCOL_SUCCESS);
   1018 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
   1019 	case REP_PROTOCOL_ENTITY_SNAPLEVEL:
   1020 		/* Snapshots do not have FMRIs, so there is nothing to do. */
   1021 		return (REP_PROTOCOL_SUCCESS);
   1022 	default:
   1023 		(void) fprintf(stderr, "%s:%d: Unknown protocol type %d.\n",
   1024 		    __FILE__, __LINE__, type);
   1025 		abort();	/* Missing a case in switch if we get here. */
   1026 	}
   1027 
   1028 	/* Concatenate separator and element to the fmri buffer. */
   1029 
   1030 	actual = strlcat(fmri, separator, bufsize);
   1031 	if (name != NULL) {
   1032 		if (actual < bufsize) {
   1033 			actual = strlcat(fmri, name, bufsize);
   1034 		} else {
   1035 			actual += strlen(name);
   1036 		}
   1037 	}
   1038 	if (actual < bufsize) {
   1039 		rc = REP_PROTOCOL_SUCCESS;
   1040 	} else {
   1041 		rc = REP_PROTOCOL_FAIL_TRUNCATED;
   1042 	}
   1043 	*sz_out = actual;
   1044 	return (rc);
   1045 }
   1046 
   1047 /*
   1048  * Get the FMRI for the node at np.  The fmri will be placed in buf.  On
   1049  * success sz_out will be set to the size of the fmri in buf.  If
   1050  * REP_PROTOCOL_FAIL_TRUNCATED is returned, sz_out will be set to the size
   1051  * of the buffer that would be required to avoid truncation.
   1052  *
   1053  * Fails with
   1054  *	_TRUNCATED	not enough room in buf for the FMRI.
   1055  */
   1056 static int
   1057 rc_node_get_fmri_or_fragment(rc_node_t *np, char *buf, size_t bufsize,
   1058     size_t *sz_out)
   1059 {
   1060 	size_t fmri_len = 0;
   1061 	int r;
   1062 
   1063 	if (bufsize > 0)
   1064 		*buf = 0;
   1065 	*sz_out = 0;
   1066 
   1067 	if (np->rn_fmri == NULL) {
   1068 		/*
   1069 		 * A NULL rn_fmri implies that this is a top level scope.
   1070 		 * Child nodes will always have an rn_fmri established
   1071 		 * because both rc_node_link_child() and
   1072 		 * rc_node_relink_child() call rc_node_build_fmri().  In
   1073 		 * this case, we'll just return our name preceded by the
   1074 		 * appropriate FMRI decorations.
   1075 		 */
   1076 		assert(np->rn_parent == NULL);
   1077 		r = rc_concat_fmri_element(buf, bufsize, &fmri_len, np->rn_name,
   1078 		    np->rn_id.rl_type);
   1079 		if (r != REP_PROTOCOL_SUCCESS)
   1080 			return (r);
   1081 	} else {
   1082 		/* We have an fmri, so return it. */
   1083 		fmri_len = strlcpy(buf, np->rn_fmri, bufsize);
   1084 	}
   1085 
   1086 	*sz_out = fmri_len;
   1087 
   1088 	if (fmri_len >= bufsize)
   1089 		return (REP_PROTOCOL_FAIL_TRUNCATED);
   1090 
   1091 	return (REP_PROTOCOL_SUCCESS);
   1092 }
   1093 
   1094 /*
   1095  * Build an FMRI string for this node and save it in rn_fmri.
   1096  *
   1097  * The basic strategy here is to get the fmri of our parent and then
   1098  * concatenate the appropriate separator followed by our name.  If our name
   1099  * is null, the resulting fmri will just be a copy of the parent fmri.
   1100  * rc_node_build_fmri() should be called with the RC_NODE_USING_PARENT flag
   1101  * set.  Also the rn_lock for this node should be held.
   1102  *
   1103  * Fails with
   1104  *	_NO_RESOURCES	Could not allocate memory.
   1105  */
   1106 static int
   1107 rc_node_build_fmri(rc_node_t *np)
   1108 {
   1109 	size_t actual;
   1110 	char fmri[REP_PROTOCOL_FMRI_LEN];
   1111 	int rc;
   1112 	size_t	sz = REP_PROTOCOL_FMRI_LEN;
   1113 
   1114 	assert(MUTEX_HELD(&np->rn_lock));
   1115 	assert(np->rn_flags & RC_NODE_USING_PARENT);
   1116 
   1117 	rc_node_free_fmri(np);
   1118 
   1119 	rc = rc_node_get_fmri_or_fragment(np->rn_parent, fmri, sz, &actual);
   1120 	assert(rc == REP_PROTOCOL_SUCCESS);
   1121 
   1122 	if (np->rn_name != NULL) {
   1123 		rc = rc_concat_fmri_element(fmri, sz, &actual, np->rn_name,
   1124 		    np->rn_id.rl_type);
   1125 		assert(rc == REP_PROTOCOL_SUCCESS);
   1126 		np->rn_fmri = strdup(fmri);
   1127 	} else {
   1128 		np->rn_fmri = strdup(fmri);
   1129 	}
   1130 	if (np->rn_fmri == NULL) {
   1131 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   1132 	} else {
   1133 		rc = REP_PROTOCOL_SUCCESS;
   1134 	}
   1135 
   1136 	return (rc);
   1137 }
   1138 
   1139 /*
   1140  * Get the FMRI of the node at np placing the result in fmri.  Then
   1141  * concatenate the additional element to fmri.  The type variable indicates
   1142  * the type of element, so that the appropriate separator can be
   1143  * generated.  size is the number of bytes in the buffer at fmri, and
   1144  * sz_out receives the size of the generated string.  If the result is
   1145  * truncated, sz_out will receive the size of the buffer that would be
   1146  * required to avoid truncation.
   1147  *
   1148  * Fails with
   1149  *	_TRUNCATED	Not enough room in buffer at fmri.
   1150  */
   1151 static int
   1152 rc_get_fmri_and_concat(rc_node_t *np, char *fmri, size_t size, size_t *sz_out,
   1153     const char *element, rep_protocol_entity_t type)
   1154 {
   1155 	int rc;
   1156 
   1157 	if ((rc = rc_node_get_fmri_or_fragment(np, fmri, size, sz_out)) !=
   1158 	    REP_PROTOCOL_SUCCESS) {
   1159 		return (rc);
   1160 	}
   1161 	if ((rc = rc_concat_fmri_element(fmri, size, sz_out, element, type)) !=
   1162 	    REP_PROTOCOL_SUCCESS) {
   1163 		return (rc);
   1164 	}
   1165 
   1166 	return (REP_PROTOCOL_SUCCESS);
   1167 }
   1168 
   1169 static int
   1170 rc_notify_info_interested(rc_notify_info_t *rnip, rc_notify_t *np)
   1171 {
   1172 	rc_node_t *nnp = np->rcn_node;
   1173 	int i;
   1174 
   1175 	assert(MUTEX_HELD(&rc_pg_notify_lock));
   1176 
   1177 	if (np->rcn_delete != NULL) {
   1178 		assert(np->rcn_info == NULL && np->rcn_node == NULL);
   1179 		return (1);		/* everyone likes deletes */
   1180 	}
   1181 	if (np->rcn_node == NULL) {
   1182 		assert(np->rcn_info != NULL || np->rcn_delete != NULL);
   1183 		return (0);
   1184 	}
   1185 	assert(np->rcn_info == NULL);
   1186 
   1187 	for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
   1188 		if (rnip->rni_namelist[i] != NULL) {
   1189 			if (strcmp(nnp->rn_name, rnip->rni_namelist[i]) == 0)
   1190 				return (1);
   1191 		}
   1192 		if (rnip->rni_typelist[i] != NULL) {
   1193 			if (strcmp(nnp->rn_type, rnip->rni_typelist[i]) == 0)
   1194 				return (1);
   1195 		}
   1196 	}
   1197 	return (0);
   1198 }
   1199 
   1200 static void
   1201 rc_notify_insert_node(rc_node_t *nnp)
   1202 {
   1203 	rc_notify_t *np = &nnp->rn_notify;
   1204 	rc_notify_info_t *nip;
   1205 	int found = 0;
   1206 
   1207 	assert(np->rcn_info == NULL);
   1208 
   1209 	if (nnp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
   1210 		return;
   1211 
   1212 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   1213 	np->rcn_node = nnp;
   1214 	for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
   1215 	    nip = uu_list_next(rc_notify_info_list, nip)) {
   1216 		if (rc_notify_info_interested(nip, np)) {
   1217 			(void) pthread_cond_broadcast(&nip->rni_cv);
   1218 			found++;
   1219 		}
   1220 	}
   1221 	if (found)
   1222 		(void) uu_list_insert_before(rc_notify_list, NULL, np);
   1223 	else
   1224 		np->rcn_node = NULL;
   1225 
   1226 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   1227 }
   1228 
   1229 static void
   1230 rc_notify_deletion(rc_notify_delete_t *ndp, const char *service,
   1231     const char *instance, const char *pg)
   1232 {
   1233 	rc_notify_info_t *nip;
   1234 
   1235 	uu_list_node_init(&ndp->rnd_notify, &ndp->rnd_notify.rcn_list_node,
   1236 	    rc_notify_pool);
   1237 	ndp->rnd_notify.rcn_delete = ndp;
   1238 
   1239 	(void) snprintf(ndp->rnd_fmri, sizeof (ndp->rnd_fmri),
   1240 	    "svc:/%s%s%s%s%s", service,
   1241 	    (instance != NULL)? ":" : "", (instance != NULL)? instance : "",
   1242 	    (pg != NULL)? "/:properties/" : "", (pg != NULL)? pg : "");
   1243 
   1244 	/*
   1245 	 * add to notification list, notify watchers
   1246 	 */
   1247 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   1248 	for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
   1249 	    nip = uu_list_next(rc_notify_info_list, nip))
   1250 		(void) pthread_cond_broadcast(&nip->rni_cv);
   1251 	(void) uu_list_insert_before(rc_notify_list, NULL, ndp);
   1252 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   1253 }
   1254 
   1255 static void
   1256 rc_notify_remove_node(rc_node_t *nnp)
   1257 {
   1258 	rc_notify_t *np = &nnp->rn_notify;
   1259 
   1260 	assert(np->rcn_info == NULL);
   1261 	assert(!MUTEX_HELD(&nnp->rn_lock));
   1262 
   1263 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   1264 	while (np->rcn_node != NULL) {
   1265 		if (rc_notify_in_use) {
   1266 			(void) pthread_cond_wait(&rc_pg_notify_cv,
   1267 			    &rc_pg_notify_lock);
   1268 			continue;
   1269 		}
   1270 		(void) uu_list_remove(rc_notify_list, np);
   1271 		np->rcn_node = NULL;
   1272 		break;
   1273 	}
   1274 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   1275 }
   1276 
   1277 static void
   1278 rc_notify_remove_locked(rc_notify_t *np)
   1279 {
   1280 	assert(MUTEX_HELD(&rc_pg_notify_lock));
   1281 	assert(rc_notify_in_use == 0);
   1282 
   1283 	(void) uu_list_remove(rc_notify_list, np);
   1284 	if (np->rcn_node) {
   1285 		np->rcn_node = NULL;
   1286 	} else if (np->rcn_delete) {
   1287 		uu_free(np->rcn_delete);
   1288 	} else {
   1289 		assert(0);	/* CAN'T HAPPEN */
   1290 	}
   1291 }
   1292 
   1293 /*
   1294  * Permission checking functions.  See comment atop this file.
   1295  */
   1296 #ifndef NATIVE_BUILD
   1297 static permcheck_t *
   1298 pc_create()
   1299 {
   1300 	permcheck_t *p;
   1301 
   1302 	p = uu_zalloc(sizeof (*p));
   1303 	if (p == NULL)
   1304 		return (NULL);
   1305 	p->pc_bnum = 8;			/* Normal case will only have 2 elts. */
   1306 	p->pc_buckets = uu_zalloc(sizeof (*p->pc_buckets) * p->pc_bnum);
   1307 	if (p->pc_buckets == NULL) {
   1308 		uu_free(p);
   1309 		return (NULL);
   1310 	}
   1311 
   1312 	p->pc_enum = 0;
   1313 	return (p);
   1314 }
   1315 
   1316 static void
   1317 pc_free(permcheck_t *pcp)
   1318 {
   1319 	uint_t i;
   1320 	struct pc_elt *ep, *next;
   1321 
   1322 	for (i = 0; i < pcp->pc_bnum; ++i) {
   1323 		for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
   1324 			next = ep->pce_next;
   1325 			free(ep);
   1326 		}
   1327 	}
   1328 
   1329 	free(pcp->pc_buckets);
   1330 	free(pcp);
   1331 }
   1332 
   1333 static uint32_t
   1334 pc_hash(const char *auth)
   1335 {
   1336 	uint32_t h = 0, g;
   1337 	const char *p;
   1338 
   1339 	/*
   1340 	 * Generic hash function from uts/common/os/modhash.c.
   1341 	 */
   1342 	for (p = auth; *p != '\0'; ++p) {
   1343 		h = (h << 4) + *p;
   1344 		g = (h & 0xf0000000);
   1345 		if (g != 0) {
   1346 			h ^= (g >> 24);
   1347 			h ^= g;
   1348 		}
   1349 	}
   1350 
   1351 	return (h);
   1352 }
   1353 
   1354 static perm_status_t
   1355 pc_exists(permcheck_t *pcp, const char *auth)
   1356 {
   1357 	uint32_t h;
   1358 	struct pc_elt *ep;
   1359 
   1360 	h = pc_hash(auth);
   1361 	for (ep = pcp->pc_buckets[h & (pcp->pc_bnum - 1)];
   1362 	    ep != NULL;
   1363 	    ep = ep->pce_next) {
   1364 		if (strcmp(auth, ep->pce_auth) == 0) {
   1365 			pcp->pc_auth_string = ep->pce_auth;
   1366 			return (PERM_GRANTED);
   1367 		}
   1368 	}
   1369 
   1370 	return (PERM_DENIED);
   1371 }
   1372 
   1373 static perm_status_t
   1374 pc_match(permcheck_t *pcp, const char *pattern)
   1375 {
   1376 	uint_t i;
   1377 	struct pc_elt *ep;
   1378 
   1379 	for (i = 0; i < pcp->pc_bnum; ++i) {
   1380 		for (ep = pcp->pc_buckets[i]; ep != NULL; ep = ep->pce_next) {
   1381 			if (_auth_match(pattern, ep->pce_auth)) {
   1382 				pcp->pc_auth_string = ep->pce_auth;
   1383 				return (PERM_GRANTED);
   1384 			}
   1385 		}
   1386 	}
   1387 
   1388 	return (PERM_DENIED);
   1389 }
   1390 
   1391 static int
   1392 pc_grow(permcheck_t *pcp)
   1393 {
   1394 	uint_t new_bnum, i, j;
   1395 	struct pc_elt **new_buckets;
   1396 	struct pc_elt *ep, *next;
   1397 
   1398 	new_bnum = pcp->pc_bnum * 2;
   1399 	if (new_bnum < pcp->pc_bnum)
   1400 		/* Homey don't play that. */
   1401 		return (-1);
   1402 
   1403 	new_buckets = uu_zalloc(sizeof (*new_buckets) * new_bnum);
   1404 	if (new_buckets == NULL)
   1405 		return (-1);
   1406 
   1407 	for (i = 0; i < pcp->pc_bnum; ++i) {
   1408 		for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
   1409 			next = ep->pce_next;
   1410 			j = pc_hash(ep->pce_auth) & (new_bnum - 1);
   1411 			ep->pce_next = new_buckets[j];
   1412 			new_buckets[j] = ep;
   1413 		}
   1414 	}
   1415 
   1416 	uu_free(pcp->pc_buckets);
   1417 	pcp->pc_buckets = new_buckets;
   1418 	pcp->pc_bnum = new_bnum;
   1419 
   1420 	return (0);
   1421 }
   1422 
   1423 static int
   1424 pc_add(permcheck_t *pcp, const char *auth, pc_auth_type_t auth_type)
   1425 {
   1426 	struct pc_elt *ep;
   1427 	uint_t i;
   1428 
   1429 	ep = uu_zalloc(offsetof(struct pc_elt, pce_auth) + strlen(auth) + 1);
   1430 	if (ep == NULL)
   1431 		return (-1);
   1432 
   1433 	/* Grow if pc_enum / pc_bnum > 3/4. */
   1434 	if (pcp->pc_enum * 4 > 3 * pcp->pc_bnum)
   1435 		/* Failure is not a stopper; we'll try again next time. */
   1436 		(void) pc_grow(pcp);
   1437 
   1438 	(void) strcpy(ep->pce_auth, auth);
   1439 
   1440 	i = pc_hash(auth) & (pcp->pc_bnum - 1);
   1441 	ep->pce_next = pcp->pc_buckets[i];
   1442 	pcp->pc_buckets[i] = ep;
   1443 
   1444 	if (auth_type > pcp->pc_specific_type) {
   1445 		pcp->pc_specific_type = auth_type;
   1446 		pcp->pc_specific = ep;
   1447 	}
   1448 
   1449 	++pcp->pc_enum;
   1450 
   1451 	return (0);
   1452 }
   1453 
   1454 /*
   1455  * For the type of a property group, return the authorization which may be
   1456  * used to modify it.
   1457  */
   1458 static const char *
   1459 perm_auth_for_pgtype(const char *pgtype)
   1460 {
   1461 	if (strcmp(pgtype, SCF_GROUP_METHOD) == 0)
   1462 		return (AUTH_MODIFY_PREFIX "method");
   1463 	else if (strcmp(pgtype, SCF_GROUP_DEPENDENCY) == 0)
   1464 		return (AUTH_MODIFY_PREFIX "dependency");
   1465 	else if (strcmp(pgtype, SCF_GROUP_APPLICATION) == 0)
   1466 		return (AUTH_MODIFY_PREFIX "application");
   1467 	else if (strcmp(pgtype, SCF_GROUP_FRAMEWORK) == 0)
   1468 		return (AUTH_MODIFY_PREFIX "framework");
   1469 	else
   1470 		return (NULL);
   1471 }
   1472 
   1473 /*
   1474  * Fails with
   1475  *   _NO_RESOURCES - out of memory
   1476  */
   1477 static int
   1478 perm_add_enabling_type(permcheck_t *pcp, const char *auth,
   1479     pc_auth_type_t auth_type)
   1480 {
   1481 	return (pc_add(pcp, auth, auth_type) == 0 ? REP_PROTOCOL_SUCCESS :
   1482 	    REP_PROTOCOL_FAIL_NO_RESOURCES);
   1483 }
   1484 
   1485 /*
   1486  * Fails with
   1487  *   _NO_RESOURCES - out of memory
   1488  */
   1489 static int
   1490 perm_add_enabling(permcheck_t *pcp, const char *auth)
   1491 {
   1492 	return (perm_add_enabling_type(pcp, auth, PC_AUTH_SMF));
   1493 }
   1494 
   1495 /* Note that perm_add_enabling_values() is defined below. */
   1496 
   1497 /*
   1498  * perm_granted() returns PERM_GRANTED if the current door caller has one of
   1499  * the enabling authorizations in pcp, PERM_DENIED if it doesn't, PERM_GONE if
   1500  * the door client went away and PERM_FAIL if an error (usually lack of
   1501  * memory) occurs.  check_auth_list() checks an RBAC_AUTH_SEP-separated
   1502  * list of authorizations for existence in pcp, and check_prof_list()
   1503  * checks the authorizations granted to an RBAC_AUTH_SEP-separated list of
   1504  * profiles.
   1505  */
   1506 static perm_status_t
   1507 check_auth_list(permcheck_t *pcp, char *authlist)
   1508 {
   1509 	char *auth, *lasts;
   1510 	perm_status_t ret;
   1511 
   1512 	for (auth = (char *)strtok_r(authlist, RBAC_AUTH_SEP, &lasts);
   1513 	    auth != NULL;
   1514 	    auth = (char *)strtok_r(NULL, RBAC_AUTH_SEP, &lasts)) {
   1515 		if (strchr(auth, KV_WILDCHAR) == NULL)
   1516 			ret = pc_exists(pcp, auth);
   1517 		else
   1518 			ret = pc_match(pcp, auth);
   1519 
   1520 		if (ret != PERM_DENIED)
   1521 			return (ret);
   1522 	}
   1523 
   1524 	/*
   1525 	 * If we failed, choose the most specific auth string for use in
   1526 	 * the audit event.
   1527 	 */
   1528 	assert(pcp->pc_specific != NULL);
   1529 	pcp->pc_auth_string = pcp->pc_specific->pce_auth;
   1530 
   1531 	return (PERM_DENIED);
   1532 }
   1533 
   1534 static perm_status_t
   1535 check_prof_list(permcheck_t *pcp, char *proflist)
   1536 {
   1537 	char *prof, *lasts, *authlist, *subproflist;
   1538 	profattr_t *pap;
   1539 	perm_status_t ret = PERM_DENIED;
   1540 
   1541 	for (prof = strtok_r(proflist, RBAC_AUTH_SEP, &lasts);
   1542 	    prof != NULL;
   1543 	    prof = strtok_r(NULL, RBAC_AUTH_SEP, &lasts)) {
   1544 		pap = getprofnam(prof);
   1545 		if (pap == NULL)
   1546 			continue;
   1547 
   1548 		authlist = kva_match(pap->attr, PROFATTR_AUTHS_KW);
   1549 		if (authlist != NULL)
   1550 			ret = check_auth_list(pcp, authlist);
   1551 
   1552 		if (ret == PERM_DENIED) {
   1553 			subproflist = kva_match(pap->attr, PROFATTR_PROFS_KW);
   1554 			if (subproflist != NULL)
   1555 				/* depth check to avoid infinite recursion? */
   1556 				ret = check_prof_list(pcp, subproflist);
   1557 		}
   1558 
   1559 		free_profattr(pap);
   1560 		if (ret != PERM_DENIED)
   1561 			return (ret);
   1562 	}
   1563 
   1564 	return (ret);
   1565 }
   1566 
   1567 static perm_status_t
   1568 perm_granted(permcheck_t *pcp)
   1569 {
   1570 	ucred_t *uc;
   1571 
   1572 	perm_status_t ret = PERM_DENIED;
   1573 	int rv;
   1574 	uid_t uid;
   1575 	userattr_t *uap;
   1576 	char *authlist, *userattr_authlist, *proflist, *def_prof = NULL;
   1577 	struct passwd pw;
   1578 	char pwbuf[1024];	/* XXX should be NSS_BUFLEN_PASSWD */
   1579 
   1580 	/* Get the uid */
   1581 	if ((uc = get_ucred()) == NULL) {
   1582 		if (errno == EINVAL) {
   1583 			/*
   1584 			 * Client is no longer waiting for our response (e.g.,
   1585 			 * it received a signal & resumed with EINTR).
   1586 			 * Punting with door_return() would be nice but we
   1587 			 * need to release all of the locks & references we
   1588 			 * hold.  And we must report failure to the client
   1589 			 * layer to keep it from ignoring retries as
   1590 			 * already-done (idempotency & all that).  None of the
   1591 			 * error codes fit very well, so we might as well
   1592 			 * force the return of _PERMISSION_DENIED since we
   1593 			 * couldn't determine the user.
   1594 			 */
   1595 			return (PERM_GONE);
   1596 		}
   1597 		assert(0);
   1598 		abort();
   1599 	}
   1600 
   1601 	uid = ucred_geteuid(uc);
   1602 	assert(uid != (uid_t)-1);
   1603 
   1604 	if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
   1605 		return (PERM_FAIL);
   1606 	}
   1607 
   1608 	/*
   1609 	 * Get user's default authorizations from policy.conf
   1610 	 */
   1611 	rv = _get_user_defs(pw.pw_name, &authlist, &def_prof);
   1612 
   1613 	if (rv != 0)
   1614 		return (PERM_FAIL);
   1615 
   1616 	if (authlist != NULL) {
   1617 		ret = check_auth_list(pcp, authlist);
   1618 
   1619 		if (ret != PERM_DENIED) {
   1620 			_free_user_defs(authlist, def_prof);
   1621 			return (ret);
   1622 		}
   1623 	}
   1624 
   1625 	/*
   1626 	 * Put off checking def_prof for later in an attempt to consolidate
   1627 	 * prof_attr accesses.
   1628 	 */
   1629 
   1630 	uap = getusernam(pw.pw_name);
   1631 	if (uap != NULL) {
   1632 		/* Get the authorizations from user_attr. */
   1633 		userattr_authlist = kva_match(uap->attr, USERATTR_AUTHS_KW);
   1634 		if (userattr_authlist != NULL) {
   1635 			ret = check_auth_list(pcp, userattr_authlist);
   1636 		}
   1637 	}
   1638 
   1639 	if ((ret == PERM_DENIED) && (def_prof != NULL)) {
   1640 		/* Check generic profiles. */
   1641 		ret = check_prof_list(pcp, def_prof);
   1642 	}
   1643 
   1644 	if ((ret == PERM_DENIED) && (uap != NULL)) {
   1645 		proflist = kva_match(uap->attr, USERATTR_PROFILES_KW);
   1646 		if (proflist != NULL)
   1647 			ret = check_prof_list(pcp, proflist);
   1648 	}
   1649 
   1650 	_free_user_defs(authlist, def_prof);
   1651 	if (uap != NULL)
   1652 		free_userattr(uap);
   1653 
   1654 	return (ret);
   1655 }
   1656 
   1657 static int
   1658 map_granted_status(perm_status_t status, permcheck_t *pcp,
   1659     char **match_auth)
   1660 {
   1661 	int rc;
   1662 
   1663 	*match_auth = NULL;
   1664 	switch (status) {
   1665 	case PERM_DENIED:
   1666 		*match_auth = strdup(pcp->pc_auth_string);
   1667 		if (*match_auth == NULL)
   1668 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   1669 		else
   1670 			rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   1671 		break;
   1672 	case PERM_GRANTED:
   1673 		*match_auth = strdup(pcp->pc_auth_string);
   1674 		if (*match_auth == NULL)
   1675 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   1676 		else
   1677 			rc = REP_PROTOCOL_SUCCESS;
   1678 		break;
   1679 	case PERM_GONE:
   1680 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   1681 		break;
   1682 	case PERM_FAIL:
   1683 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   1684 		break;
   1685 	}
   1686 	return (rc);
   1687 }
   1688 #endif /* NATIVE_BUILD */
   1689 
   1690 /*
   1691  * flags in RC_NODE_WAITING_FLAGS are broadcast when unset, and are used to
   1692  * serialize certain actions, and to wait for certain operations to complete
   1693  *
   1694  * The waiting flags are:
   1695  *	RC_NODE_CHILDREN_CHANGING
   1696  *		The child list is being built or changed (due to creation
   1697  *		or deletion).  All iterators pause.
   1698  *
   1699  *	RC_NODE_USING_PARENT
   1700  *		Someone is actively using the parent pointer, so we can't
   1701  *		be removed from the parent list.
   1702  *
   1703  *	RC_NODE_CREATING_CHILD
   1704  *		A child is being created -- locks out other creations, to
   1705  *		prevent insert-insert races.
   1706  *
   1707  *	RC_NODE_IN_TX
   1708  *		This object is running a transaction.
   1709  *
   1710  *	RC_NODE_DYING
   1711  *		This node might be dying.  Always set as a set, using
   1712  *		RC_NODE_DYING_FLAGS (which is everything but
   1713  *		RC_NODE_USING_PARENT)
   1714  */
   1715 static int
   1716 rc_node_hold_flag(rc_node_t *np, uint32_t flag)
   1717 {
   1718 	assert(MUTEX_HELD(&np->rn_lock));
   1719 	assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
   1720 
   1721 	while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag)) {
   1722 		(void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
   1723 	}
   1724 	if (np->rn_flags & RC_NODE_DEAD)
   1725 		return (0);
   1726 
   1727 	np->rn_flags |= flag;
   1728 	return (1);
   1729 }
   1730 
   1731 static void
   1732 rc_node_rele_flag(rc_node_t *np, uint32_t flag)
   1733 {
   1734 	assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
   1735 	assert(MUTEX_HELD(&np->rn_lock));
   1736 	assert((np->rn_flags & flag) == flag);
   1737 	np->rn_flags &= ~flag;
   1738 	(void) pthread_cond_broadcast(&np->rn_cv);
   1739 }
   1740 
   1741 /*
   1742  * wait until a particular flag has cleared.  Fails if the object dies.
   1743  */
   1744 static int
   1745 rc_node_wait_flag(rc_node_t *np, uint32_t flag)
   1746 {
   1747 	assert(MUTEX_HELD(&np->rn_lock));
   1748 	while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag))
   1749 		(void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
   1750 
   1751 	return (!(np->rn_flags & RC_NODE_DEAD));
   1752 }
   1753 
   1754 /*
   1755  * On entry, np's lock must be held, and this thread must be holding
   1756  * RC_NODE_USING_PARENT.  On return, both of them are released.
   1757  *
   1758  * If the return value is NULL, np either does not have a parent, or
   1759  * the parent has been marked DEAD.
   1760  *
   1761  * If the return value is non-NULL, it is the parent of np, and both
   1762  * its lock and the requested flags are held.
   1763  */
   1764 static rc_node_t *
   1765 rc_node_hold_parent_flag(rc_node_t *np, uint32_t flag)
   1766 {
   1767 	rc_node_t *pp;
   1768 
   1769 	assert(MUTEX_HELD(&np->rn_lock));
   1770 	assert(np->rn_flags & RC_NODE_USING_PARENT);
   1771 
   1772 	if ((pp = np->rn_parent) == NULL) {
   1773 		rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   1774 		(void) pthread_mutex_unlock(&np->rn_lock);
   1775 		return (NULL);
   1776 	}
   1777 	(void) pthread_mutex_unlock(&np->rn_lock);
   1778 
   1779 	(void) pthread_mutex_lock(&pp->rn_lock);
   1780 	(void) pthread_mutex_lock(&np->rn_lock);
   1781 	rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   1782 	(void) pthread_mutex_unlock(&np->rn_lock);
   1783 
   1784 	if (!rc_node_hold_flag(pp, flag)) {
   1785 		(void) pthread_mutex_unlock(&pp->rn_lock);
   1786 		return (NULL);
   1787 	}
   1788 	return (pp);
   1789 }
   1790 
   1791 rc_node_t *
   1792 rc_node_alloc(void)
   1793 {
   1794 	rc_node_t *np = uu_zalloc(sizeof (*np));
   1795 
   1796 	if (np == NULL)
   1797 		return (NULL);
   1798 
   1799 	(void) pthread_mutex_init(&np->rn_lock, NULL);
   1800 	(void) pthread_cond_init(&np->rn_cv, NULL);
   1801 
   1802 	np->rn_children = uu_list_create(rc_children_pool, np, 0);
   1803 	np->rn_pg_notify_list = uu_list_create(rc_pg_notify_pool, np, 0);
   1804 
   1805 	uu_list_node_init(np, &np->rn_sibling_node, rc_children_pool);
   1806 
   1807 	uu_list_node_init(&np->rn_notify, &np->rn_notify.rcn_list_node,
   1808 	    rc_notify_pool);
   1809 
   1810 	return (np);
   1811 }
   1812 
   1813 void
   1814 rc_node_destroy(rc_node_t *np)
   1815 {
   1816 	int i;
   1817 
   1818 	if (np->rn_flags & RC_NODE_UNREFED)
   1819 		return;				/* being handled elsewhere */
   1820 
   1821 	assert(np->rn_refs == 0 && np->rn_other_refs == 0);
   1822 	assert(np->rn_former == NULL);
   1823 
   1824 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   1825 		/* Release the holds from rc_iter_next(). */
   1826 		for (i = 0; i < COMPOSITION_DEPTH; ++i) {
   1827 			/* rn_cchain[i] may be NULL for empty snapshots. */
   1828 			if (np->rn_cchain[i] != NULL)
   1829 				rc_node_rele(np->rn_cchain[i]);
   1830 		}
   1831 	}
   1832 
   1833 	if (np->rn_name != NULL)
   1834 		free((void *)np->rn_name);
   1835 	np->rn_name = NULL;
   1836 	if (np->rn_type != NULL)
   1837 		free((void *)np->rn_type);
   1838 	np->rn_type = NULL;
   1839 	if (np->rn_values != NULL)
   1840 		object_free_values(np->rn_values, np->rn_valtype,
   1841 		    np->rn_values_count, np->rn_values_size);
   1842 	np->rn_values = NULL;
   1843 	rc_node_free_fmri(np);
   1844 
   1845 	if (np->rn_snaplevel != NULL)
   1846 		rc_snaplevel_rele(np->rn_snaplevel);
   1847 	np->rn_snaplevel = NULL;
   1848 
   1849 	uu_list_node_fini(np, &np->rn_sibling_node, rc_children_pool);
   1850 
   1851 	uu_list_node_fini(&np->rn_notify, &np->rn_notify.rcn_list_node,
   1852 	    rc_notify_pool);
   1853 
   1854 	assert(uu_list_first(np->rn_children) == NULL);
   1855 	uu_list_destroy(np->rn_children);
   1856 	uu_list_destroy(np->rn_pg_notify_list);
   1857 
   1858 	(void) pthread_mutex_destroy(&np->rn_lock);
   1859 	(void) pthread_cond_destroy(&np->rn_cv);
   1860 
   1861 	uu_free(np);
   1862 }
   1863 
   1864 /*
   1865  * Link in a child node.
   1866  *
   1867  * Because of the lock ordering, cp has to already be in the hash table with
   1868  * its lock dropped before we get it.  To prevent anyone from noticing that
   1869  * it is parentless, the creation code sets the RC_NODE_USING_PARENT.  Once
   1870  * we've linked it in, we release the flag.
   1871  */
   1872 static void
   1873 rc_node_link_child(rc_node_t *np, rc_node_t *cp)
   1874 {
   1875 	assert(!MUTEX_HELD(&np->rn_lock));
   1876 	assert(!MUTEX_HELD(&cp->rn_lock));
   1877 
   1878 	(void) pthread_mutex_lock(&np->rn_lock);
   1879 	(void) pthread_mutex_lock(&cp->rn_lock);
   1880 	assert(!(cp->rn_flags & RC_NODE_IN_PARENT) &&
   1881 	    (cp->rn_flags & RC_NODE_USING_PARENT));
   1882 
   1883 	assert(rc_check_parent_child(np->rn_id.rl_type, cp->rn_id.rl_type) ==
   1884 	    REP_PROTOCOL_SUCCESS);
   1885 
   1886 	cp->rn_parent = np;
   1887 	cp->rn_flags |= RC_NODE_IN_PARENT;
   1888 	(void) uu_list_insert_before(np->rn_children, NULL, cp);
   1889 	(void) rc_node_build_fmri(cp);
   1890 
   1891 	(void) pthread_mutex_unlock(&np->rn_lock);
   1892 
   1893 	rc_node_rele_flag(cp, RC_NODE_USING_PARENT);
   1894 	(void) pthread_mutex_unlock(&cp->rn_lock);
   1895 }
   1896 
   1897 /*
   1898  * Sets the rn_parent_ref field of all the children of np to pp -- always
   1899  * initially invoked as rc_node_setup_parent_ref(np, np), we then recurse.
   1900  *
   1901  * This is used when we mark a node RC_NODE_OLD, so that when the object and
   1902  * its children are no longer referenced, they will all be deleted as a unit.
   1903  */
   1904 static void
   1905 rc_node_setup_parent_ref(rc_node_t *np, rc_node_t *pp)
   1906 {
   1907 	rc_node_t *cp;
   1908 
   1909 	assert(MUTEX_HELD(&np->rn_lock));
   1910 
   1911 	for (cp = uu_list_first(np->rn_children); cp != NULL;
   1912 	    cp = uu_list_next(np->rn_children, cp)) {
   1913 		(void) pthread_mutex_lock(&cp->rn_lock);
   1914 		if (cp->rn_flags & RC_NODE_PARENT_REF) {
   1915 			assert(cp->rn_parent_ref == pp);
   1916 		} else {
   1917 			assert(cp->rn_parent_ref == NULL);
   1918 
   1919 			cp->rn_flags |= RC_NODE_PARENT_REF;
   1920 			cp->rn_parent_ref = pp;
   1921 			if (cp->rn_refs != 0)
   1922 				rc_node_hold_other(pp);
   1923 		}
   1924 		rc_node_setup_parent_ref(cp, pp);		/* recurse */
   1925 		(void) pthread_mutex_unlock(&cp->rn_lock);
   1926 	}
   1927 }
   1928 
   1929 /*
   1930  * Atomically replace 'np' with 'newp', with a parent of 'pp'.
   1931  *
   1932  * Requirements:
   1933  *	*no* node locks may be held.
   1934  *	pp must be held with RC_NODE_CHILDREN_CHANGING
   1935  *	newp and np must be held with RC_NODE_IN_TX
   1936  *	np must be marked RC_NODE_IN_PARENT, newp must not be
   1937  *	np must be marked RC_NODE_OLD
   1938  *
   1939  * Afterwards:
   1940  *	pp's RC_NODE_CHILDREN_CHANGING is dropped
   1941  *	newp and np's RC_NODE_IN_TX is dropped
   1942  *	newp->rn_former = np;
   1943  *	newp is RC_NODE_IN_PARENT, np is not.
   1944  *	interested notify subscribers have been notified of newp's new status.
   1945  */
   1946 static void
   1947 rc_node_relink_child(rc_node_t *pp, rc_node_t *np, rc_node_t *newp)
   1948 {
   1949 	cache_bucket_t *bp;
   1950 	/*
   1951 	 * First, swap np and nnp in the cache.  newp's RC_NODE_IN_TX flag
   1952 	 * keeps rc_node_update() from seeing it until we are done.
   1953 	 */
   1954 	bp = cache_hold(newp->rn_hash);
   1955 	cache_remove_unlocked(bp, np);
   1956 	cache_insert_unlocked(bp, newp);
   1957 	cache_release(bp);
   1958 
   1959 	/*
   1960 	 * replace np with newp in pp's list, and attach it to newp's rn_former
   1961 	 * link.
   1962 	 */
   1963 	(void) pthread_mutex_lock(&pp->rn_lock);
   1964 	assert(pp->rn_flags & RC_NODE_CHILDREN_CHANGING);
   1965 
   1966 	(void) pthread_mutex_lock(&newp->rn_lock);
   1967 	assert(!(newp->rn_flags & RC_NODE_IN_PARENT));
   1968 	assert(newp->rn_flags & RC_NODE_IN_TX);
   1969 
   1970 	(void) pthread_mutex_lock(&np->rn_lock);
   1971 	assert(np->rn_flags & RC_NODE_IN_PARENT);
   1972 	assert(np->rn_flags & RC_NODE_OLD);
   1973 	assert(np->rn_flags & RC_NODE_IN_TX);
   1974 
   1975 	newp->rn_parent = pp;
   1976 	newp->rn_flags |= RC_NODE_IN_PARENT;
   1977 
   1978 	/*
   1979 	 * Note that we carefully add newp before removing np -- this
   1980 	 * keeps iterators on the list from missing us.
   1981 	 */
   1982 	(void) uu_list_insert_after(pp->rn_children, np, newp);
   1983 	(void) rc_node_build_fmri(newp);
   1984 	(void) uu_list_remove(pp->rn_children, np);
   1985 
   1986 	/*
   1987 	 * re-set np
   1988 	 */
   1989 	newp->rn_former = np;
   1990 	np->rn_parent = NULL;
   1991 	np->rn_flags &= ~RC_NODE_IN_PARENT;
   1992 	np->rn_flags |= RC_NODE_ON_FORMER;
   1993 
   1994 	rc_notify_insert_node(newp);
   1995 
   1996 	rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   1997 	(void) pthread_mutex_unlock(&pp->rn_lock);
   1998 	rc_node_rele_flag(newp, RC_NODE_USING_PARENT | RC_NODE_IN_TX);
   1999 	(void) pthread_mutex_unlock(&newp->rn_lock);
   2000 	rc_node_setup_parent_ref(np, np);
   2001 	rc_node_rele_flag(np, RC_NODE_IN_TX);
   2002 	(void) pthread_mutex_unlock(&np->rn_lock);
   2003 }
   2004 
   2005 /*
   2006  * makes sure a node with lookup 'nip', name 'name', and parent 'pp' exists.
   2007  * 'cp' is used (and returned) if the node does not yet exist.  If it does
   2008  * exist, 'cp' is freed, and the existent node is returned instead.
   2009  */
   2010 rc_node_t *
   2011 rc_node_setup(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
   2012     rc_node_t *pp)
   2013 {
   2014 	rc_node_t *np;
   2015 	cache_bucket_t *bp;
   2016 	uint32_t h = rc_node_hash(nip);
   2017 
   2018 	assert(cp->rn_refs == 0);
   2019 
   2020 	bp = cache_hold(h);
   2021 	if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
   2022 		cache_release(bp);
   2023 
   2024 		/*
   2025 		 * make sure it matches our expectations
   2026 		 */
   2027 		(void) pthread_mutex_lock(&np->rn_lock);
   2028 		if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   2029 			assert(np->rn_parent == pp);
   2030 			assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
   2031 			assert(strcmp(np->rn_name, name) == 0);
   2032 			assert(np->rn_type == NULL);
   2033 			assert(np->rn_flags & RC_NODE_IN_PARENT);
   2034 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   2035 		}
   2036 		(void) pthread_mutex_unlock(&np->rn_lock);
   2037 
   2038 		rc_node_destroy(cp);
   2039 		return (np);
   2040 	}
   2041 
   2042 	/*
   2043 	 * No one is there -- setup & install the new node.
   2044 	 */
   2045 	np = cp;
   2046 	rc_node_hold(np);
   2047 	np->rn_id = *nip;
   2048 	np->rn_hash = h;
   2049 	np->rn_name = strdup(name);
   2050 
   2051 	np->rn_flags |= RC_NODE_USING_PARENT;
   2052 
   2053 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE) {
   2054 #if COMPOSITION_DEPTH == 2
   2055 		np->rn_cchain[0] = np;
   2056 		np->rn_cchain[1] = pp;
   2057 #else
   2058 #error This code must be updated.
   2059 #endif
   2060 	}
   2061 
   2062 	cache_insert_unlocked(bp, np);
   2063 	cache_release(bp);		/* we are now visible */
   2064 
   2065 	rc_node_link_child(pp, np);
   2066 
   2067 	return (np);
   2068 }
   2069 
   2070 /*
   2071  * makes sure a snapshot with lookup 'nip', name 'name', and parent 'pp' exists.
   2072  * 'cp' is used (and returned) if the node does not yet exist.  If it does
   2073  * exist, 'cp' is freed, and the existent node is returned instead.
   2074  */
   2075 rc_node_t *
   2076 rc_node_setup_snapshot(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
   2077     uint32_t snap_id, rc_node_t *pp)
   2078 {
   2079 	rc_node_t *np;
   2080 	cache_bucket_t *bp;
   2081 	uint32_t h = rc_node_hash(nip);
   2082 
   2083 	assert(cp->rn_refs == 0);
   2084 
   2085 	bp = cache_hold(h);
   2086 	if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
   2087 		cache_release(bp);
   2088 
   2089 		/*
   2090 		 * make sure it matches our expectations
   2091 		 */
   2092 		(void) pthread_mutex_lock(&np->rn_lock);
   2093 		if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   2094 			assert(np->rn_parent == pp);
   2095 			assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
   2096 			assert(strcmp(np->rn_name, name) == 0);
   2097 			assert(np->rn_type == NULL);
   2098 			assert(np->rn_flags & RC_NODE_IN_PARENT);
   2099 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   2100 		}
   2101 		(void) pthread_mutex_unlock(&np->rn_lock);
   2102 
   2103 		rc_node_destroy(cp);
   2104 		return (np);
   2105 	}
   2106 
   2107 	/*
   2108 	 * No one is there -- create a new node.
   2109 	 */
   2110 	np = cp;
   2111 	rc_node_hold(np);
   2112 	np->rn_id = *nip;
   2113 	np->rn_hash = h;
   2114 	np->rn_name = strdup(name);
   2115 	np->rn_snapshot_id = snap_id;
   2116 
   2117 	np->rn_flags |= RC_NODE_USING_PARENT;
   2118 
   2119 	cache_insert_unlocked(bp, np);
   2120 	cache_release(bp);		/* we are now visible */
   2121 
   2122 	rc_node_link_child(pp, np);
   2123 
   2124 	return (np);
   2125 }
   2126 
   2127 /*
   2128  * makes sure a snaplevel with lookup 'nip' and parent 'pp' exists.  'cp' is
   2129  * used (and returned) if the node does not yet exist.  If it does exist, 'cp'
   2130  * is freed, and the existent node is returned instead.
   2131  */
   2132 rc_node_t *
   2133 rc_node_setup_snaplevel(rc_node_t *cp, rc_node_lookup_t *nip,
   2134     rc_snaplevel_t *lvl, rc_node_t *pp)
   2135 {
   2136 	rc_node_t *np;
   2137 	cache_bucket_t *bp;
   2138 	uint32_t h = rc_node_hash(nip);
   2139 
   2140 	assert(cp->rn_refs == 0);
   2141 
   2142 	bp = cache_hold(h);
   2143 	if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
   2144 		cache_release(bp);
   2145 
   2146 		/*
   2147 		 * make sure it matches our expectations
   2148 		 */
   2149 		(void) pthread_mutex_lock(&np->rn_lock);
   2150 		if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   2151 			assert(np->rn_parent == pp);
   2152 			assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
   2153 			assert(np->rn_name == NULL);
   2154 			assert(np->rn_type == NULL);
   2155 			assert(np->rn_flags & RC_NODE_IN_PARENT);
   2156 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   2157 		}
   2158 		(void) pthread_mutex_unlock(&np->rn_lock);
   2159 
   2160 		rc_node_destroy(cp);
   2161 		return (np);
   2162 	}
   2163 
   2164 	/*
   2165 	 * No one is there -- create a new node.
   2166 	 */
   2167 	np = cp;
   2168 	rc_node_hold(np);	/* released in snapshot_fill_children() */
   2169 	np->rn_id = *nip;
   2170 	np->rn_hash = h;
   2171 
   2172 	rc_snaplevel_hold(lvl);
   2173 	np->rn_snaplevel = lvl;
   2174 
   2175 	np->rn_flags |= RC_NODE_USING_PARENT;
   2176 
   2177 	cache_insert_unlocked(bp, np);
   2178 	cache_release(bp);		/* we are now visible */
   2179 
   2180 	/* Add this snaplevel to the snapshot's composition chain. */
   2181 	assert(pp->rn_cchain[lvl->rsl_level_num - 1] == NULL);
   2182 	pp->rn_cchain[lvl->rsl_level_num - 1] = np;
   2183 
   2184 	rc_node_link_child(pp, np);
   2185 
   2186 	return (np);
   2187 }
   2188 
   2189 /*
   2190  * Returns NULL if strdup() fails.
   2191  */
   2192 rc_node_t *
   2193 rc_node_setup_pg(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
   2194     const char *type, uint32_t flags, uint32_t gen_id, rc_node_t *pp)
   2195 {
   2196 	rc_node_t *np;
   2197 	cache_bucket_t *bp;
   2198 
   2199 	uint32_t h = rc_node_hash(nip);
   2200 	bp = cache_hold(h);
   2201 	if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
   2202 		cache_release(bp);
   2203 
   2204 		/*
   2205 		 * make sure it matches our expectations (don't check
   2206 		 * the generation number or parent, since someone could
   2207 		 * have gotten a transaction through while we weren't
   2208 		 * looking)
   2209 		 */
   2210 		(void) pthread_mutex_lock(&np->rn_lock);
   2211 		if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   2212 			assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
   2213 			assert(strcmp(np->rn_name, name) == 0);
   2214 			assert(strcmp(np->rn_type, type) == 0);
   2215 			assert(np->rn_pgflags == flags);
   2216 			assert(np->rn_flags & RC_NODE_IN_PARENT);
   2217 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   2218 		}
   2219 		(void) pthread_mutex_unlock(&np->rn_lock);
   2220 
   2221 		rc_node_destroy(cp);
   2222 		return (np);
   2223 	}
   2224 
   2225 	np = cp;
   2226 	rc_node_hold(np);		/* released in fill_pg_callback() */
   2227 	np->rn_id = *nip;
   2228 	np->rn_hash = h;
   2229 	np->rn_name = strdup(name);
   2230 	if (np->rn_name == NULL) {
   2231 		rc_node_rele(np);
   2232 		return (NULL);
   2233 	}
   2234 	np->rn_type = strdup(type);
   2235 	if (np->rn_type == NULL) {
   2236 		free((void *)np->rn_name);
   2237 		rc_node_rele(np);
   2238 		return (NULL);
   2239 	}
   2240 	np->rn_pgflags = flags;
   2241 	np->rn_gen_id = gen_id;
   2242 
   2243 	np->rn_flags |= RC_NODE_USING_PARENT;
   2244 
   2245 	cache_insert_unlocked(bp, np);
   2246 	cache_release(bp);		/* we are now visible */
   2247 
   2248 	rc_node_link_child(pp, np);
   2249 
   2250 	return (np);
   2251 }
   2252 
   2253 #if COMPOSITION_DEPTH == 2
   2254 /*
   2255  * Initialize a "composed property group" which represents the composition of
   2256  * property groups pg1 & pg2.  It is ephemeral: once created & returned for an
   2257  * ITER_READ request, keeping it out of cache_hash and any child lists
   2258  * prevents it from being looked up.  Operations besides iteration are passed
   2259  * through to pg1.
   2260  *
   2261  * pg1 & pg2 should be held before entering this function.  They will be
   2262  * released in rc_node_destroy().
   2263  */
   2264 static int
   2265 rc_node_setup_cpg(rc_node_t *cpg, rc_node_t *pg1, rc_node_t *pg2)
   2266 {
   2267 	if (strcmp(pg1->rn_type, pg2->rn_type) != 0)
   2268 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   2269 
   2270 	cpg->rn_id.rl_type = REP_PROTOCOL_ENTITY_CPROPERTYGRP;
   2271 	cpg->rn_name = strdup(pg1->rn_name);
   2272 	if (cpg->rn_name == NULL)
   2273 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   2274 
   2275 	cpg->rn_cchain[0] = pg1;
   2276 	cpg->rn_cchain[1] = pg2;
   2277 
   2278 	return (REP_PROTOCOL_SUCCESS);
   2279 }
   2280 #else
   2281 #error This code must be updated.
   2282 #endif
   2283 
   2284 /*
   2285  * Fails with _NO_RESOURCES.
   2286  */
   2287 int
   2288 rc_node_create_property(rc_node_t *pp, rc_node_lookup_t *nip,
   2289     const char *name, rep_protocol_value_type_t type,
   2290     const char *vals, size_t count, size_t size)
   2291 {
   2292 	rc_node_t *np;
   2293 	cache_bucket_t *bp;
   2294 
   2295 	uint32_t h = rc_node_hash(nip);
   2296 	bp = cache_hold(h);
   2297 	if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
   2298 		cache_release(bp);
   2299 		/*
   2300 		 * make sure it matches our expectations
   2301 		 */
   2302 		(void) pthread_mutex_lock(&np->rn_lock);
   2303 		if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   2304 			assert(np->rn_parent == pp);
   2305 			assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
   2306 			assert(strcmp(np->rn_name, name) == 0);
   2307 			assert(np->rn_valtype == type);
   2308 			assert(np->rn_values_count == count);
   2309 			assert(np->rn_values_size == size);
   2310 			assert(vals == NULL ||
   2311 			    memcmp(np->rn_values, vals, size) == 0);
   2312 			assert(np->rn_flags & RC_NODE_IN_PARENT);
   2313 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   2314 		}
   2315 		rc_node_rele_locked(np);
   2316 		object_free_values(vals, type, count, size);
   2317 		return (REP_PROTOCOL_SUCCESS);
   2318 	}
   2319 
   2320 	/*
   2321 	 * No one is there -- create a new node.
   2322 	 */
   2323 	np = rc_node_alloc();
   2324 	if (np == NULL) {
   2325 		cache_release(bp);
   2326 		object_free_values(vals, type, count, size);
   2327 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   2328 	}
   2329 	np->rn_id = *nip;
   2330 	np->rn_hash = h;
   2331 	np->rn_name = strdup(name);
   2332 	if (np->rn_name == NULL) {
   2333 		cache_release(bp);
   2334 		object_free_values(vals, type, count, size);
   2335 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   2336 	}
   2337 
   2338 	np->rn_valtype = type;
   2339 	np->rn_values = vals;
   2340 	np->rn_values_count = count;
   2341 	np->rn_values_size = size;
   2342 
   2343 	np->rn_flags |= RC_NODE_USING_PARENT;
   2344 
   2345 	cache_insert_unlocked(bp, np);
   2346 	cache_release(bp);		/* we are now visible */
   2347 
   2348 	rc_node_link_child(pp, np);
   2349 
   2350 	return (REP_PROTOCOL_SUCCESS);
   2351 }
   2352 
   2353 /*
   2354  * This function implements a decision table to determine the event ID for
   2355  * changes to the enabled (SCF_PROPERTY_ENABLED) property.  The event ID is
   2356  * determined by the value of the first property in the command specified
   2357  * by cmd_no and the name of the property group.  Here is the decision
   2358  * table:
   2359  *
   2360  *				Property Group Name
   2361  *	Property	------------------------------------------
   2362  *	Value		SCF_PG_GENERAL		SCF_PG_GENERAL_OVR
   2363  *	--------	--------------		------------------
   2364  *	"0"		ADT_smf_disable		ADT_smf_tmp_disable
   2365  *	"1"		ADT_smf_enable		ADT_smf_tmp_enable
   2366  *
   2367  * This function is called by special_property_event through a function
   2368  * pointer in the special_props_list array.
   2369  *
   2370  * Since the ADT_smf_* symbols may not be defined in the build machine's
   2371  * include files, this function is not compiled when doing native builds.
   2372  */
   2373 #ifndef NATIVE_BUILD
   2374 static int
   2375 general_enable_id(tx_commit_data_t *tx_data, size_t cmd_no, const char *pg,
   2376     au_event_t *event_id)
   2377 {
   2378 	const char *value;
   2379 	uint32_t nvalues;
   2380 	int enable;
   2381 
   2382 	/*
   2383 	 * First, check property value.
   2384 	 */
   2385 	if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
   2386 		return (-1);
   2387 	if (nvalues == 0)
   2388 		return (-1);
   2389 	if (tx_cmd_value(tx_data, cmd_no, 0, &value) != REP_PROTOCOL_SUCCESS)
   2390 		return (-1);
   2391 	if (strcmp(value, "0") == 0) {
   2392 		enable = 0;
   2393 	} else if (strcmp(value, "1") == 0) {
   2394 		enable = 1;
   2395 	} else {
   2396 		return (-1);
   2397 	}
   2398 
   2399 	/*
   2400 	 * Now check property group name.
   2401 	 */
   2402 	if (strcmp(pg, SCF_PG_GENERAL) == 0) {
   2403 		*event_id = enable ? ADT_smf_enable : ADT_smf_disable;
   2404 		return (0);
   2405 	} else if (strcmp(pg, SCF_PG_GENERAL_OVR) == 0) {
   2406 		*event_id = enable ? ADT_smf_tmp_enable : ADT_smf_tmp_disable;
   2407 		return (0);
   2408 	}
   2409 	return (-1);
   2410 }
   2411 #endif	/* NATIVE_BUILD */
   2412 
   2413 /*
   2414  * This function compares two audit_special_prop_item_t structures
   2415  * represented by item1 and item2.  It returns an integer greater than 0 if
   2416  * item1 is greater than item2.  It returns 0 if they are equal and an
   2417  * integer less than 0 if item1 is less than item2.  api_prop_name and
   2418  * api_pg_name are the key fields for sorting.
   2419  *
   2420  * This function is suitable for calls to bsearch(3C) and qsort(3C).
   2421  */
   2422 static int
   2423 special_prop_compare(const void *item1, const void *item2)
   2424 {
   2425 	const audit_special_prop_item_t *a = (audit_special_prop_item_t *)item1;
   2426 	const audit_special_prop_item_t *b = (audit_special_prop_item_t *)item2;
   2427 	int r;
   2428 
   2429 	r = strcmp(a->api_prop_name, b->api_prop_name);
   2430 	if (r == 0) {
   2431 		/*
   2432 		 * Primary keys are the same, so check the secondary key.
   2433 		 */
   2434 		r = strcmp(a->api_pg_name, b->api_pg_name);
   2435 	}
   2436 	return (r);
   2437 }
   2438 
   2439 int
   2440 rc_node_init(void)
   2441 {
   2442 	rc_node_t *np;
   2443 	cache_bucket_t *bp;
   2444 
   2445 	rc_children_pool = uu_list_pool_create("rc_children_pool",
   2446 	    sizeof (rc_node_t), offsetof(rc_node_t, rn_sibling_node),
   2447 	    NULL, UU_LIST_POOL_DEBUG);
   2448 
   2449 	rc_pg_notify_pool = uu_list_pool_create("rc_pg_notify_pool",
   2450 	    sizeof (rc_node_pg_notify_t),
   2451 	    offsetof(rc_node_pg_notify_t, rnpn_node),
   2452 	    NULL, UU_LIST_POOL_DEBUG);
   2453 
   2454 	rc_notify_pool = uu_list_pool_create("rc_notify_pool",
   2455 	    sizeof (rc_notify_t), offsetof(rc_notify_t, rcn_list_node),
   2456 	    NULL, UU_LIST_POOL_DEBUG);
   2457 
   2458 	rc_notify_info_pool = uu_list_pool_create("rc_notify_info_pool",
   2459 	    sizeof (rc_notify_info_t),
   2460 	    offsetof(rc_notify_info_t, rni_list_node),
   2461 	    NULL, UU_LIST_POOL_DEBUG);
   2462 
   2463 	if (rc_children_pool == NULL || rc_pg_notify_pool == NULL ||
   2464 	    rc_notify_pool == NULL || rc_notify_info_pool == NULL)
   2465 		uu_die("out of memory");
   2466 
   2467 	rc_notify_list = uu_list_create(rc_notify_pool,
   2468 	    &rc_notify_list, 0);
   2469 
   2470 	rc_notify_info_list = uu_list_create(rc_notify_info_pool,
   2471 	    &rc_notify_info_list, 0);
   2472 
   2473 	if (rc_notify_list == NULL || rc_notify_info_list == NULL)
   2474 		uu_die("out of memory");
   2475 
   2476 	/*
   2477 	 * Sort the special_props_list array so that it can be searched
   2478 	 * with bsearch(3C).
   2479 	 *
   2480 	 * The special_props_list array is not compiled into the native
   2481 	 * build code, so there is no need to call qsort if NATIVE_BUILD is
   2482 	 * defined.
   2483 	 */
   2484 #ifndef	NATIVE_BUILD
   2485 	qsort(special_props_list, SPECIAL_PROP_COUNT,
   2486 	    sizeof (special_props_list[0]), special_prop_compare);
   2487 #endif	/* NATIVE_BUILD */
   2488 
   2489 	if ((np = rc_node_alloc()) == NULL)
   2490 		uu_die("out of memory");
   2491 
   2492 	rc_node_hold(np);
   2493 	np->rn_id.rl_type = REP_PROTOCOL_ENTITY_SCOPE;
   2494 	np->rn_id.rl_backend = BACKEND_TYPE_NORMAL;
   2495 	np->rn_hash = rc_node_hash(&np->rn_id);
   2496 	np->rn_name = "localhost";
   2497 
   2498 	bp = cache_hold(np->rn_hash);
   2499 	cache_insert_unlocked(bp, np);
   2500 	cache_release(bp);
   2501 
   2502 	rc_scope = np;
   2503 	return (1);
   2504 }
   2505 
   2506 /*
   2507  * Fails with
   2508  *   _INVALID_TYPE - type is invalid
   2509  *   _TYPE_MISMATCH - np doesn't carry children of type type
   2510  *   _DELETED - np has been deleted
   2511  *   _NO_RESOURCES
   2512  */
   2513 static int
   2514 rc_node_fill_children(rc_node_t *np, uint32_t type)
   2515 {
   2516 	int rc;
   2517 
   2518 	assert(MUTEX_HELD(&np->rn_lock));
   2519 
   2520 	if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
   2521 	    REP_PROTOCOL_SUCCESS)
   2522 		return (rc);
   2523 
   2524 	if (!rc_node_hold_flag(np, RC_NODE_CHILDREN_CHANGING))
   2525 		return (REP_PROTOCOL_FAIL_DELETED);
   2526 
   2527 	if (np->rn_flags & RC_NODE_HAS_CHILDREN) {
   2528 		rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
   2529 		return (REP_PROTOCOL_SUCCESS);
   2530 	}
   2531 
   2532 	(void) pthread_mutex_unlock(&np->rn_lock);
   2533 	rc = object_fill_children(np);
   2534 	(void) pthread_mutex_lock(&np->rn_lock);
   2535 
   2536 	if (rc == REP_PROTOCOL_SUCCESS) {
   2537 		np->rn_flags |= RC_NODE_HAS_CHILDREN;
   2538 	}
   2539 	rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
   2540 
   2541 	return (rc);
   2542 }
   2543 
   2544 /*
   2545  * Returns
   2546  *   _INVALID_TYPE - type is invalid
   2547  *   _TYPE_MISMATCH - np doesn't carry children of type type
   2548  *   _DELETED - np has been deleted
   2549  *   _NO_RESOURCES
   2550  *   _SUCCESS - if *cpp is not NULL, it is held
   2551  */
   2552 static int
   2553 rc_node_find_named_child(rc_node_t *np, const char *name, uint32_t type,
   2554     rc_node_t **cpp)
   2555 {
   2556 	int ret;
   2557 	rc_node_t *cp;
   2558 
   2559 	assert(MUTEX_HELD(&np->rn_lock));
   2560 	assert(np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP);
   2561 
   2562 	ret = rc_node_fill_children(np, type);
   2563 	if (ret != REP_PROTOCOL_SUCCESS)
   2564 		return (ret);
   2565 
   2566 	for (cp = uu_list_first(np->rn_children);
   2567 	    cp != NULL;
   2568 	    cp = uu_list_next(np->rn_children, cp)) {
   2569 		if (cp->rn_id.rl_type == type && strcmp(cp->rn_name, name) == 0)
   2570 			break;
   2571 	}
   2572 
   2573 	if (cp != NULL)
   2574 		rc_node_hold(cp);
   2575 	*cpp = cp;
   2576 
   2577 	return (REP_PROTOCOL_SUCCESS);
   2578 }
   2579 
   2580 static int rc_node_parent(rc_node_t *, rc_node_t **);
   2581 
   2582 /*
   2583  * Returns
   2584  *   _INVALID_TYPE - type is invalid
   2585  *   _DELETED - np or an ancestor has been deleted
   2586  *   _NOT_FOUND - no ancestor of specified type exists
   2587  *   _SUCCESS - *app is held
   2588  */
   2589 static int
   2590 rc_node_find_ancestor(rc_node_t *np, uint32_t type, rc_node_t **app)
   2591 {
   2592 	int ret;
   2593 	rc_node_t *parent, *np_orig;
   2594 
   2595 	if (type >= REP_PROTOCOL_ENTITY_MAX)
   2596 		return (REP_PROTOCOL_FAIL_INVALID_TYPE);
   2597 
   2598 	np_orig = np;
   2599 
   2600 	while (np->rn_id.rl_type > type) {
   2601 		ret = rc_node_parent(np, &parent);
   2602 		if (np != np_orig)
   2603 			rc_node_rele(np);
   2604 		if (ret != REP_PROTOCOL_SUCCESS)
   2605 			return (ret);
   2606 		np = parent;
   2607 	}
   2608 
   2609 	if (np->rn_id.rl_type == type) {
   2610 		*app = parent;
   2611 		return (REP_PROTOCOL_SUCCESS);
   2612 	}
   2613 
   2614 	return (REP_PROTOCOL_FAIL_NOT_FOUND);
   2615 }
   2616 
   2617 #ifndef NATIVE_BUILD
   2618 /*
   2619  * If the propname property exists in pg, and it is of type string, add its
   2620  * values as authorizations to pcp.  pg must not be locked on entry, and it is
   2621  * returned unlocked.  Returns
   2622  *   _DELETED - pg was deleted
   2623  *   _NO_RESOURCES
   2624  *   _NOT_FOUND - pg has no property named propname
   2625  *   _SUCCESS
   2626  */
   2627 static int
   2628 perm_add_pg_prop_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
   2629 {
   2630 	rc_node_t *prop;
   2631 	int result;
   2632 
   2633 	uint_t count;
   2634 	const char *cp;
   2635 
   2636 	assert(!MUTEX_HELD(&pg->rn_lock));
   2637 	assert(pg->rn_id.rl_type == REP_PROTOCOL_ENTITY_PROPERTYGRP);
   2638 
   2639 	(void) pthread_mutex_lock(&pg->rn_lock);
   2640 	result = rc_node_find_named_child(pg, propname,
   2641 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop);
   2642 	(void) pthread_mutex_unlock(&pg->rn_lock);
   2643 	if (result != REP_PROTOCOL_SUCCESS) {
   2644 		switch (result) {
   2645 		case REP_PROTOCOL_FAIL_DELETED:
   2646 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
   2647 			return (result);
   2648 
   2649 		case REP_PROTOCOL_FAIL_INVALID_TYPE:
   2650 		case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
   2651 		default:
   2652 			bad_error("rc_node_find_named_child", result);
   2653 		}
   2654 	}
   2655 
   2656 	if (prop == NULL)
   2657 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   2658 
   2659 	/* rn_valtype is immutable, so no locking. */
   2660 	if (prop->rn_valtype != REP_PROTOCOL_TYPE_STRING) {
   2661 		rc_node_rele(prop);
   2662 		return (REP_PROTOCOL_SUCCESS);
   2663 	}
   2664 
   2665 	(void) pthread_mutex_lock(&prop->rn_lock);
   2666 	for (count = prop->rn_values_count, cp = prop->rn_values;
   2667 	    count > 0;
   2668 	    --count) {
   2669 		result = perm_add_enabling_type(pcp, cp,
   2670 		    (pg->rn_id.rl_ids[ID_INSTANCE]) ? PC_AUTH_INST :
   2671 		    PC_AUTH_SVC);
   2672 		if (result != REP_PROTOCOL_SUCCESS)
   2673 			break;
   2674 
   2675 		cp = strchr(cp, '\0') + 1;
   2676 	}
   2677 
   2678 	rc_node_rele_locked(prop);
   2679 
   2680 	return (result);
   2681 }
   2682 
   2683 /*
   2684  * Assuming that ent is a service or instance node, if the pgname property
   2685  * group has type pgtype, and it has a propname property with string type, add
   2686  * its values as authorizations to pcp.  If pgtype is NULL, it is not checked.
   2687  * Returns
   2688  *   _SUCCESS
   2689  *   _DELETED - ent was deleted
   2690  *   _NO_RESOURCES - no resources
   2691  *   _NOT_FOUND - ent does not have pgname pg or propname property
   2692  */
   2693 static int
   2694 perm_add_ent_prop_values(permcheck_t *pcp, rc_node_t *ent, const char *pgname,
   2695     const char *pgtype, const char *propname)
   2696 {
   2697 	int r;
   2698 	rc_node_t *pg;
   2699 
   2700 	assert(!MUTEX_HELD(&ent->rn_lock));
   2701 
   2702 	(void) pthread_mutex_lock(&ent->rn_lock);
   2703 	r = rc_node_find_named_child(ent, pgname,
   2704 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
   2705 	(void) pthread_mutex_unlock(&ent->rn_lock);
   2706 
   2707 	switch (r) {
   2708 	case REP_PROTOCOL_SUCCESS:
   2709 		break;
   2710 
   2711 	case REP_PROTOCOL_FAIL_DELETED:
   2712 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
   2713 		return (r);
   2714 
   2715 	default:
   2716 		bad_error("rc_node_find_named_child", r);
   2717 	}
   2718 
   2719 	if (pg == NULL)
   2720 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   2721 
   2722 	if (pgtype == NULL || strcmp(pg->rn_type, pgtype) == 0) {
   2723 		r = perm_add_pg_prop_values(pcp, pg, propname);
   2724 		switch (r) {
   2725 		case REP_PROTOCOL_FAIL_DELETED:
   2726 			r = REP_PROTOCOL_FAIL_NOT_FOUND;
   2727 			break;
   2728 
   2729 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
   2730 		case REP_PROTOCOL_SUCCESS:
   2731 		case REP_PROTOCOL_FAIL_NOT_FOUND:
   2732 			break;
   2733 
   2734 		default:
   2735 			bad_error("perm_add_pg_prop_values", r);
   2736 		}
   2737 	}
   2738 
   2739 	rc_node_rele(pg);
   2740 
   2741 	return (r);
   2742 }
   2743 
   2744 /*
   2745  * If pg has a property named propname, and is string typed, add its values as
   2746  * authorizations to pcp.  If pg has no such property, and its parent is an
   2747  * instance, walk up to the service and try doing the same with the property
   2748  * of the same name from the property group of the same name.  Returns
   2749  *   _SUCCESS
   2750  *   _NO_RESOURCES
   2751  *   _DELETED - pg (or an ancestor) was deleted
   2752  */
   2753 static int
   2754 perm_add_enabling_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
   2755 {
   2756 	int r;
   2757 	char pgname[REP_PROTOCOL_NAME_LEN + 1];
   2758 	rc_node_t *svc;
   2759 	size_t sz;
   2760 
   2761 	r = perm_add_pg_prop_values(pcp, pg, propname);
   2762 
   2763 	if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
   2764 		return (r);
   2765 
   2766 	assert(!MUTEX_HELD(&pg->rn_lock));
   2767 
   2768 	if (pg->rn_id.rl_ids[ID_INSTANCE] == 0)
   2769 		return (REP_PROTOCOL_SUCCESS);
   2770 
   2771 	sz = strlcpy(pgname, pg->rn_name, sizeof (pgname));
   2772 	assert(sz < sizeof (pgname));
   2773 
   2774 	/*
   2775 	 * If pg is a child of an instance or snapshot, we want to compose the
   2776 	 * authorization property with the service's (if it exists).  The
   2777 	 * snapshot case applies only to read_authorization.  In all other
   2778 	 * cases, the pg's parent will be the instance.
   2779 	 */
   2780 	r = rc_node_find_ancestor(pg, REP_PROTOCOL_ENTITY_SERVICE, &svc);
   2781 	if (r != REP_PROTOCOL_SUCCESS) {
   2782 		assert(r == REP_PROTOCOL_FAIL_DELETED);
   2783 		return (r);
   2784 	}
   2785 	assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
   2786 
   2787 	r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname);
   2788 
   2789 	rc_node_rele(svc);
   2790 
   2791 	if (r == REP_PROTOCOL_FAIL_NOT_FOUND)
   2792 		r = REP_PROTOCOL_SUCCESS;
   2793 
   2794 	return (r);
   2795 }
   2796 
   2797 /*
   2798  * Call perm_add_enabling_values() for the "action_authorization" property of
   2799  * the "general" property group of inst.  Returns
   2800  *   _DELETED - inst (or an ancestor) was deleted
   2801  *   _NO_RESOURCES
   2802  *   _SUCCESS
   2803  */
   2804 static int
   2805 perm_add_inst_action_auth(permcheck_t *pcp, rc_node_t *inst)
   2806 {
   2807 	int r;
   2808 	rc_node_t *svc;
   2809 
   2810 	assert(inst->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
   2811 
   2812 	r = perm_add_ent_prop_values(pcp, inst, AUTH_PG_GENERAL,
   2813 	    AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
   2814 
   2815 	if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
   2816 		return (r);
   2817 
   2818 	r = rc_node_parent(inst, &svc);
   2819 	if (r != REP_PROTOCOL_SUCCESS) {
   2820 		assert(r == REP_PROTOCOL_FAIL_DELETED);
   2821 		return (r);
   2822 	}
   2823 
   2824 	r = perm_add_ent_prop_values(pcp, svc, AUTH_PG_GENERAL,
   2825 	    AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
   2826 
   2827 	return (r == REP_PROTOCOL_FAIL_NOT_FOUND ? REP_PROTOCOL_SUCCESS : r);
   2828 }
   2829 #endif /* NATIVE_BUILD */
   2830 
   2831 void
   2832 rc_node_ptr_init(rc_node_ptr_t *out)
   2833 {
   2834 	out->rnp_node = NULL;
   2835 	out->rnp_auth_string = NULL;
   2836 	out->rnp_authorized = RC_AUTH_UNKNOWN;
   2837 	out->rnp_deleted = 0;
   2838 }
   2839 
   2840 void
   2841 rc_node_ptr_free_mem(rc_node_ptr_t *npp)
   2842 {
   2843 	if (npp->rnp_auth_string != NULL) {
   2844 		free((void *)npp->rnp_auth_string);
   2845 		npp->rnp_auth_string = NULL;
   2846 	}
   2847 }
   2848 
   2849 static void
   2850 rc_node_assign(rc_node_ptr_t *out, rc_node_t *val)
   2851 {
   2852 	rc_node_t *cur = out->rnp_node;
   2853 	if (val != NULL)
   2854 		rc_node_hold(val);
   2855 	out->rnp_node = val;
   2856 	if (cur != NULL) {
   2857 		NODE_LOCK(cur);
   2858 
   2859 		/*
   2860 		 * Register the ephemeral reference created by reading
   2861 		 * out->rnp_node into cur.  Note that the persistent
   2862 		 * reference we're destroying is locked by the client
   2863 		 * layer.
   2864 		 */
   2865 		rc_node_hold_ephemeral_locked(cur);
   2866 
   2867 		rc_node_rele_locked(cur);
   2868 	}
   2869 	out->rnp_authorized = RC_AUTH_UNKNOWN;
   2870 	rc_node_ptr_free_mem(out);
   2871 	out->rnp_deleted = 0;
   2872 }
   2873 
   2874 void
   2875 rc_node_clear(rc_node_ptr_t *out, int deleted)
   2876 {
   2877 	rc_node_assign(out, NULL);
   2878 	out->rnp_deleted = deleted;
   2879 }
   2880 
   2881 void
   2882 rc_node_ptr_assign(rc_node_ptr_t *out, const rc_node_ptr_t *val)
   2883 {
   2884 	rc_node_assign(out, val->rnp_node);
   2885 }
   2886 
   2887 /*
   2888  * rc_node_check()/RC_NODE_CHECK()
   2889  *	generic "entry" checks, run before the use of an rc_node pointer.
   2890  *
   2891  * Fails with
   2892  *   _NOT_SET
   2893  *   _DELETED
   2894  */
   2895 static int
   2896 rc_node_check_and_lock(rc_node_t *np)
   2897 {
   2898 	int result = REP_PROTOCOL_SUCCESS;
   2899 	if (np == NULL)
   2900 		return (REP_PROTOCOL_FAIL_NOT_SET);
   2901 
   2902 	(void) pthread_mutex_lock(&np->rn_lock);
   2903 	if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
   2904 		result = REP_PROTOCOL_FAIL_DELETED;
   2905 		(void) pthread_mutex_unlock(&np->rn_lock);
   2906 	}
   2907 
   2908 	return (result);
   2909 }
   2910 
   2911 /*
   2912  * Fails with
   2913  *   _NOT_SET - ptr is reset
   2914  *   _DELETED - node has been deleted
   2915  */
   2916 static rc_node_t *
   2917 rc_node_ptr_check_and_lock(rc_node_ptr_t *npp, int *res)
   2918 {
   2919 	rc_node_t *np = npp->rnp_node;
   2920 	if (np == NULL) {
   2921 		if (npp->rnp_deleted)
   2922 			*res = REP_PROTOCOL_FAIL_DELETED;
   2923 		else
   2924 			*res = REP_PROTOCOL_FAIL_NOT_SET;
   2925 		return (NULL);
   2926 	}
   2927 
   2928 	(void) pthread_mutex_lock(&np->rn_lock);
   2929 	if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
   2930 		(void) pthread_mutex_unlock(&np->rn_lock);
   2931 		rc_node_clear(npp, 1);
   2932 		*res = REP_PROTOCOL_FAIL_DELETED;
   2933 		return (NULL);
   2934 	}
   2935 	return (np);
   2936 }
   2937 
   2938 #define	RC_NODE_CHECK_AND_LOCK(n) {					\
   2939 	int rc__res;							\
   2940 	if ((rc__res = rc_node_check_and_lock(n)) != REP_PROTOCOL_SUCCESS) \
   2941 		return (rc__res);					\
   2942 }
   2943 
   2944 #define	RC_NODE_CHECK(n) {						\
   2945 	RC_NODE_CHECK_AND_LOCK(n);					\
   2946 	(void) pthread_mutex_unlock(&(n)->rn_lock);			\
   2947 }
   2948 
   2949 #define	RC_NODE_CHECK_AND_HOLD(n) {					\
   2950 	RC_NODE_CHECK_AND_LOCK(n);					\
   2951 	rc_node_hold_locked(n);						\
   2952 	(void) pthread_mutex_unlock(&(n)->rn_lock);			\
   2953 }
   2954 
   2955 #define	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp) {			\
   2956 	int rc__res;							\
   2957 	if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == NULL)	\
   2958 		return (rc__res);					\
   2959 }
   2960 
   2961 #define	RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, mem) {		\
   2962 	int rc__res;							\
   2963 	if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == 	\
   2964 	    NULL) {							\
   2965 		if ((mem) != NULL)					\
   2966 			free((mem));					\
   2967 		return (rc__res);					\
   2968 	}								\
   2969 }
   2970 
   2971 #define	RC_NODE_PTR_GET_CHECK(np, npp) {				\
   2972 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);			\
   2973 	(void) pthread_mutex_unlock(&(np)->rn_lock);			\
   2974 }
   2975 
   2976 #define	RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp) {			\
   2977 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);			\
   2978 	rc_node_hold_locked(np);					\
   2979 	(void) pthread_mutex_unlock(&(np)->rn_lock);			\
   2980 }
   2981 
   2982 #define	HOLD_FLAG_OR_RETURN(np, flag) {					\
   2983 	assert(MUTEX_HELD(&(np)->rn_lock));				\
   2984 	assert(!((np)->rn_flags & RC_NODE_DEAD));			\
   2985 	if (!rc_node_hold_flag((np), flag)) {				\
   2986 		(void) pthread_mutex_unlock(&(np)->rn_lock);		\
   2987 		return (REP_PROTOCOL_FAIL_DELETED);			\
   2988 	}								\
   2989 }
   2990 
   2991 #define	HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, flag, mem) {		\
   2992 	assert(MUTEX_HELD(&(np)->rn_lock));				\
   2993 	if (!rc_node_hold_flag((np), flag)) {				\
   2994 		(void) pthread_mutex_unlock(&(np)->rn_lock);		\
   2995 		assert((np) == (npp)->rnp_node);			\
   2996 		rc_node_clear(npp, 1);					\
   2997 		if ((mem) != NULL)					\
   2998 			free((mem));					\
   2999 		return (REP_PROTOCOL_FAIL_DELETED);			\
   3000 	}								\
   3001 }
   3002 
   3003 int
   3004 rc_local_scope(uint32_t type, rc_node_ptr_t *out)
   3005 {
   3006 	if (type != REP_PROTOCOL_ENTITY_SCOPE) {
   3007 		rc_node_clear(out, 0);
   3008 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3009 	}
   3010 
   3011 	/*
   3012 	 * the main scope never gets destroyed
   3013 	 */
   3014 	rc_node_assign(out, rc_scope);
   3015 
   3016 	return (REP_PROTOCOL_SUCCESS);
   3017 }
   3018 
   3019 /*
   3020  * Fails with
   3021  *   _NOT_SET - npp is not set
   3022  *   _DELETED - the node npp pointed at has been deleted
   3023  *   _TYPE_MISMATCH - type is not _SCOPE
   3024  *   _NOT_FOUND - scope has no parent
   3025  */
   3026 static int
   3027 rc_scope_parent_scope(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
   3028 {
   3029 	rc_node_t *np;
   3030 
   3031 	rc_node_clear(out, 0);
   3032 
   3033 	RC_NODE_PTR_GET_CHECK(np, npp);
   3034 
   3035 	if (type != REP_PROTOCOL_ENTITY_SCOPE)
   3036 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3037 
   3038 	return (REP_PROTOCOL_FAIL_NOT_FOUND);
   3039 }
   3040 
   3041 static int rc_node_pg_check_read_protect(rc_node_t *);
   3042 
   3043 /*
   3044  * Fails with
   3045  *   _NOT_SET
   3046  *   _DELETED
   3047  *   _NOT_APPLICABLE
   3048  *   _NOT_FOUND
   3049  *   _BAD_REQUEST
   3050  *   _TRUNCATED
   3051  *   _NO_RESOURCES
   3052  */
   3053 int
   3054 rc_node_name(rc_node_ptr_t *npp, char *buf, size_t sz, uint32_t answertype,
   3055     size_t *sz_out)
   3056 {
   3057 	size_t actual;
   3058 	rc_node_t *np;
   3059 
   3060 	assert(sz == *sz_out);
   3061 
   3062 	RC_NODE_PTR_GET_CHECK(np, npp);
   3063 
   3064 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   3065 		np = np->rn_cchain[0];
   3066 		RC_NODE_CHECK(np);
   3067 	}
   3068 
   3069 	switch (answertype) {
   3070 	case RP_ENTITY_NAME_NAME:
   3071 		if (np->rn_name == NULL)
   3072 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3073 		actual = strlcpy(buf, np->rn_name, sz);
   3074 		break;
   3075 	case RP_ENTITY_NAME_PGTYPE:
   3076 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
   3077 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3078 		actual = strlcpy(buf, np->rn_type, sz);
   3079 		break;
   3080 	case RP_ENTITY_NAME_PGFLAGS:
   3081 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
   3082 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3083 		actual = snprintf(buf, sz, "%d", np->rn_pgflags);
   3084 		break;
   3085 	case RP_ENTITY_NAME_SNAPLEVEL_SCOPE:
   3086 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
   3087 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3088 		actual = strlcpy(buf, np->rn_snaplevel->rsl_scope, sz);
   3089 		break;
   3090 	case RP_ENTITY_NAME_SNAPLEVEL_SERVICE:
   3091 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
   3092 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3093 		actual = strlcpy(buf, np->rn_snaplevel->rsl_service, sz);
   3094 		break;
   3095 	case RP_ENTITY_NAME_SNAPLEVEL_INSTANCE:
   3096 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
   3097 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3098 		if (np->rn_snaplevel->rsl_instance == NULL)
   3099 			return (REP_PROTOCOL_FAIL_NOT_FOUND);
   3100 		actual = strlcpy(buf, np->rn_snaplevel->rsl_instance, sz);
   3101 		break;
   3102 	case RP_ENTITY_NAME_PGREADPROT:
   3103 	{
   3104 		int ret;
   3105 
   3106 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
   3107 			return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   3108 		ret = rc_node_pg_check_read_protect(np);
   3109 		assert(ret != REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3110 		switch (ret) {
   3111 		case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
   3112 			actual = snprintf(buf, sz, "1");
   3113 			break;
   3114 		case REP_PROTOCOL_SUCCESS:
   3115 			actual = snprintf(buf, sz, "0");
   3116 			break;
   3117 		default:
   3118 			return (ret);
   3119 		}
   3120 		break;
   3121 	}
   3122 	default:
   3123 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   3124 	}
   3125 	if (actual >= sz)
   3126 		return (REP_PROTOCOL_FAIL_TRUNCATED);
   3127 
   3128 	*sz_out = actual;
   3129 	return (REP_PROTOCOL_SUCCESS);
   3130 }
   3131 
   3132 int
   3133 rc_node_get_property_type(rc_node_ptr_t *npp, rep_protocol_value_type_t *out)
   3134 {
   3135 	rc_node_t *np;
   3136 
   3137 	RC_NODE_PTR_GET_CHECK(np, npp);
   3138 
   3139 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
   3140 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3141 
   3142 	*out = np->rn_valtype;
   3143 
   3144 	return (REP_PROTOCOL_SUCCESS);
   3145 }
   3146 
   3147 /*
   3148  * Get np's parent.  If np is deleted, returns _DELETED.  Otherwise puts a hold
   3149  * on the parent, returns a pointer to it in *out, and returns _SUCCESS.
   3150  */
   3151 static int
   3152 rc_node_parent(rc_node_t *np, rc_node_t **out)
   3153 {
   3154 	rc_node_t *pnp;
   3155 	rc_node_t *np_orig;
   3156 
   3157 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   3158 		RC_NODE_CHECK_AND_LOCK(np);
   3159 	} else {
   3160 		np = np->rn_cchain[0];
   3161 		RC_NODE_CHECK_AND_LOCK(np);
   3162 	}
   3163 
   3164 	np_orig = np;
   3165 	rc_node_hold_locked(np);		/* simplifies the remainder */
   3166 
   3167 	for (;;) {
   3168 		if (!rc_node_wait_flag(np,
   3169 		    RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
   3170 			rc_node_rele_locked(np);
   3171 			return (REP_PROTOCOL_FAIL_DELETED);
   3172 		}
   3173 
   3174 		if (!(np->rn_flags & RC_NODE_OLD))
   3175 			break;
   3176 
   3177 		rc_node_rele_locked(np);
   3178 		np = cache_lookup(&np_orig->rn_id);
   3179 		assert(np != np_orig);
   3180 
   3181 		if (np == NULL)
   3182 			goto deleted;
   3183 		(void) pthread_mutex_lock(&np->rn_lock);
   3184 	}
   3185 
   3186 	/* guaranteed to succeed without dropping the lock */
   3187 	if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   3188 		(void) pthread_mutex_unlock(&np->rn_lock);
   3189 		*out = NULL;
   3190 		rc_node_rele(np);
   3191 		return (REP_PROTOCOL_FAIL_DELETED);
   3192 	}
   3193 
   3194 	assert(np->rn_parent != NULL);
   3195 	pnp = np->rn_parent;
   3196 	(void) pthread_mutex_unlock(&np->rn_lock);
   3197 
   3198 	(void) pthread_mutex_lock(&pnp->rn_lock);
   3199 	(void) pthread_mutex_lock(&np->rn_lock);
   3200 	rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   3201 	(void) pthread_mutex_unlock(&np->rn_lock);
   3202 
   3203 	rc_node_hold_locked(pnp);
   3204 
   3205 	(void) pthread_mutex_unlock(&pnp->rn_lock);
   3206 
   3207 	rc_node_rele(np);
   3208 	*out = pnp;
   3209 	return (REP_PROTOCOL_SUCCESS);
   3210 
   3211 deleted:
   3212 	rc_node_rele(np);
   3213 	return (REP_PROTOCOL_FAIL_DELETED);
   3214 }
   3215 
   3216 /*
   3217  * Fails with
   3218  *   _NOT_SET
   3219  *   _DELETED
   3220  */
   3221 static int
   3222 rc_node_ptr_parent(rc_node_ptr_t *npp, rc_node_t **out)
   3223 {
   3224 	rc_node_t *np;
   3225 
   3226 	RC_NODE_PTR_GET_CHECK(np, npp);
   3227 
   3228 	return (rc_node_parent(np, out));
   3229 }
   3230 
   3231 /*
   3232  * Fails with
   3233  *   _NOT_SET - npp is not set
   3234  *   _DELETED - the node npp pointed at has been deleted
   3235  *   _TYPE_MISMATCH - npp's node's parent is not of type type
   3236  *
   3237  * If npp points to a scope, can also fail with
   3238  *   _NOT_FOUND - scope has no parent
   3239  */
   3240 int
   3241 rc_node_get_parent(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
   3242 {
   3243 	rc_node_t *pnp;
   3244 	int rc;
   3245 
   3246 	if (npp->rnp_node != NULL &&
   3247 	    npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE)
   3248 		return (rc_scope_parent_scope(npp, type, out));
   3249 
   3250 	if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS) {
   3251 		rc_node_clear(out, 0);
   3252 		return (rc);
   3253 	}
   3254 
   3255 	if (type != pnp->rn_id.rl_type) {
   3256 		rc_node_rele(pnp);
   3257 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   3258 	}
   3259 
   3260 	rc_node_assign(out, pnp);
   3261 	rc_node_rele(pnp);
   3262 
   3263 	return (REP_PROTOCOL_SUCCESS);
   3264 }
   3265 
   3266 int
   3267 rc_node_parent_type(rc_node_ptr_t *npp, uint32_t *type_out)
   3268 {
   3269 	rc_node_t *pnp;
   3270 	int rc;
   3271 
   3272 	if (npp->rnp_node != NULL &&
   3273 	    npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE) {
   3274 		*type_out = REP_PROTOCOL_ENTITY_SCOPE;
   3275 		return (REP_PROTOCOL_SUCCESS);
   3276 	}
   3277 
   3278 	if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS)
   3279 		return (rc);
   3280 
   3281 	*type_out = pnp->rn_id.rl_type;
   3282 
   3283 	rc_node_rele(pnp);
   3284 
   3285 	return (REP_PROTOCOL_SUCCESS);
   3286 }
   3287 
   3288 /*
   3289  * Fails with
   3290  *   _INVALID_TYPE - type is invalid
   3291  *   _TYPE_MISMATCH - np doesn't carry children of type type
   3292  *   _DELETED - np has been deleted
   3293  *   _NOT_FOUND - no child with that name/type combo found
   3294  *   _NO_RESOURCES
   3295  *   _BACKEND_ACCESS
   3296  */
   3297 int
   3298 rc_node_get_child(rc_node_ptr_t *npp, const char *name, uint32_t type,
   3299     rc_node_ptr_t *outp)
   3300 {
   3301 	rc_node_t *np, *cp;
   3302 	rc_node_t *child = NULL;
   3303 	int ret, idx;
   3304 
   3305 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   3306 	if ((ret = rc_check_type_name(type, name)) == REP_PROTOCOL_SUCCESS) {
   3307 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   3308 			ret = rc_node_find_named_child(np, name, type, &child);
   3309 		} else {
   3310 			(void) pthread_mutex_unlock(&np->rn_lock);
   3311 			ret = REP_PROTOCOL_SUCCESS;
   3312 			for (idx = 0; idx < COMPOSITION_DEPTH; idx++) {
   3313 				cp = np->rn_cchain[idx];
   3314 				if (cp == NULL)
   3315 					break;
   3316 				RC_NODE_CHECK_AND_LOCK(cp);
   3317 				ret = rc_node_find_named_child(cp, name, type,
   3318 				    &child);
   3319 				(void) pthread_mutex_unlock(&cp->rn_lock);
   3320 				/*
   3321 				 * loop only if we succeeded, but no child of
   3322 				 * the correct name was found.
   3323 				 */
   3324 				if (ret != REP_PROTOCOL_SUCCESS ||
   3325 				    child != NULL)
   3326 					break;
   3327 			}
   3328 			(void) pthread_mutex_lock(&np->rn_lock);
   3329 		}
   3330 	}
   3331 	(void) pthread_mutex_unlock(&np->rn_lock);
   3332 
   3333 	if (ret == REP_PROTOCOL_SUCCESS) {
   3334 		rc_node_assign(outp, child);
   3335 		if (child != NULL)
   3336 			rc_node_rele(child);
   3337 		else
   3338 			ret = REP_PROTOCOL_FAIL_NOT_FOUND;
   3339 	} else {
   3340 		rc_node_assign(outp, NULL);
   3341 	}
   3342 	return (ret);
   3343 }
   3344 
   3345 int
   3346 rc_node_update(rc_node_ptr_t *npp)
   3347 {
   3348 	cache_bucket_t *bp;
   3349 	rc_node_t *np = npp->rnp_node;
   3350 	rc_node_t *nnp;
   3351 	rc_node_t *cpg = NULL;
   3352 
   3353 	if (np != NULL &&
   3354 	    np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   3355 		/*
   3356 		 * If we're updating a composed property group, actually
   3357 		 * update the top-level property group & return the
   3358 		 * appropriate value.  But leave *nnp pointing at us.
   3359 		 */
   3360 		cpg = np;
   3361 		np = np->rn_cchain[0];
   3362 	}
   3363 
   3364 	RC_NODE_CHECK(np);
   3365 
   3366 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP &&
   3367 	    np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)
   3368 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   3369 
   3370 	for (;;) {
   3371 		bp = cache_hold(np->rn_hash);
   3372 		nnp = cache_lookup_unlocked(bp, &np->rn_id);
   3373 		if (nnp == NULL) {
   3374 			cache_release(bp);
   3375 			rc_node_clear(npp, 1);
   3376 			return (REP_PROTOCOL_FAIL_DELETED);
   3377 		}
   3378 		/*
   3379 		 * grab the lock before dropping the cache bucket, so
   3380 		 * that no one else can sneak in
   3381 		 */
   3382 		(void) pthread_mutex_lock(&nnp->rn_lock);
   3383 		cache_release(bp);
   3384 
   3385 		if (!(nnp->rn_flags & RC_NODE_IN_TX) ||
   3386 		    !rc_node_wait_flag(nnp, RC_NODE_IN_TX))
   3387 			break;
   3388 
   3389 		rc_node_rele_locked(nnp);
   3390 	}
   3391 
   3392 	/*
   3393 	 * If it is dead, we want to update it so that it will continue to
   3394 	 * report being dead.
   3395 	 */
   3396 	if (nnp->rn_flags & RC_NODE_DEAD) {
   3397 		(void) pthread_mutex_unlock(&nnp->rn_lock);
   3398 		if (nnp != np && cpg == NULL)
   3399 			rc_node_assign(npp, nnp);	/* updated */
   3400 		rc_node_rele(nnp);
   3401 		return (REP_PROTOCOL_FAIL_DELETED);
   3402 	}
   3403 
   3404 	assert(!(nnp->rn_flags & RC_NODE_OLD));
   3405 	(void) pthread_mutex_unlock(&nnp->rn_lock);
   3406 
   3407 	if (nnp != np && cpg == NULL)
   3408 		rc_node_assign(npp, nnp);		/* updated */
   3409 
   3410 	rc_node_rele(nnp);
   3411 
   3412 	return ((nnp == np)? REP_PROTOCOL_SUCCESS : REP_PROTOCOL_DONE);
   3413 }
   3414 
   3415 /*
   3416  * does a generic modification check, for creation, deletion, and snapshot
   3417  * management only.  Property group transactions have different checks.
   3418  *
   3419  * The string returned to *match_auth must be freed.
   3420  */
   3421 static perm_status_t
   3422 rc_node_modify_permission_check(char **match_auth)
   3423 {
   3424 	permcheck_t *pcp;
   3425 	perm_status_t granted = PERM_GRANTED;
   3426 	int rc;
   3427 
   3428 	*match_auth = NULL;
   3429 #ifdef NATIVE_BUILD
   3430 	if (!client_is_privileged()) {
   3431 		granted = PERM_DENIED;
   3432 	}
   3433 	return (granted);
   3434 #else
   3435 	if (is_main_repository == 0)
   3436 		return (PERM_GRANTED);
   3437 	pcp = pc_create();
   3438 	if (pcp != NULL) {
   3439 		rc = perm_add_enabling(pcp, AUTH_MODIFY);
   3440 
   3441 		if (rc == REP_PROTOCOL_SUCCESS) {
   3442 			granted = perm_granted(pcp);
   3443 
   3444 			if ((granted == PERM_GRANTED) ||
   3445 			    (granted == PERM_DENIED)) {
   3446 				/*
   3447 				 * Copy off the authorization
   3448 				 * string before freeing pcp.
   3449 				 */
   3450 				*match_auth =
   3451 				    strdup(pcp->pc_auth_string);
   3452 				if (*match_auth == NULL)
   3453 					granted = PERM_FAIL;
   3454 			}
   3455 		} else {
   3456 			granted = PERM_FAIL;
   3457 		}
   3458 
   3459 		pc_free(pcp);
   3460 	} else {
   3461 		granted = PERM_FAIL;
   3462 	}
   3463 
   3464 	return (granted);
   3465 #endif /* NATIVE_BUILD */
   3466 }
   3467 
   3468 /*
   3469  * Native builds are done to create svc.configd-native.  This program runs
   3470  * only on the Solaris build machines to create the seed repository, and it
   3471  * is compiled against the build machine's header files.  The ADT_smf_*
   3472  * symbols may not be defined in these header files.  For this reason
   3473  * smf_annotation_event(), _smf_audit_event() and special_property_event()
   3474  * are not compiled for native builds.
   3475  */
   3476 #ifndef	NATIVE_BUILD
   3477 
   3478 /*
   3479  * This function generates an annotation audit event if one has been setup.
   3480  * Annotation events should only be generated immediately before the audit
   3481  * record from the first attempt to modify the repository from a client
   3482  * which has requested an annotation.
   3483  */
   3484 static void
   3485 smf_annotation_event(int status, int return_val)
   3486 {
   3487 	adt_session_data_t *session;
   3488 	adt_event_data_t *event = NULL;
   3489 	char file[MAXPATHLEN];
   3490 	char operation[REP_PROTOCOL_NAME_LEN];
   3491 
   3492 	/* Don't audit if we're using an alternate repository. */
   3493 	if (is_main_repository == 0)
   3494 		return;
   3495 
   3496 	if (client_annotation_needed(operation, sizeof (operation), file,
   3497 	    sizeof (file)) == 0) {
   3498 		return;
   3499 	}
   3500 	if (file[0] == 0) {
   3501 		(void) strlcpy(file, "NO FILE", sizeof (file));
   3502 	}
   3503 	if (operation[0] == 0) {
   3504 		(void) strlcpy(operation, "NO OPERATION",
   3505 		    sizeof (operation));
   3506 	}
   3507 	if ((session = get_audit_session()) == NULL)
   3508 		return;
   3509 	if ((event = adt_alloc_event(session, ADT_smf_annotation)) == NULL) {
   3510 		uu_warn("smf_annotation_event cannot allocate event "
   3511 		    "data.  %s\n", strerror(errno));
   3512 		return;
   3513 	}
   3514 	event->adt_smf_annotation.operation = operation;
   3515 	event->adt_smf_annotation.file = file;
   3516 	if (adt_put_event(event, status, return_val) == 0) {
   3517 		client_annotation_finished();
   3518 	} else {
   3519 		uu_warn("smf_annotation_event failed to put event.  "
   3520 		    "%s\n", strerror(errno));
   3521 	}
   3522 	adt_free_event(event);
   3523 }
   3524 
   3525 /*
   3526  * _smf_audit_event interacts with the security auditing system to generate
   3527  * an audit event structure.  It establishes an audit session and allocates
   3528  * an audit event.  The event is filled in from the audit data, and
   3529  * adt_put_event is called to generate the event.
   3530  */
   3531 static void
   3532 _smf_audit_event(au_event_t event_id, int status, int return_val,
   3533     audit_event_data_t *data)
   3534 {
   3535 	char *auth_used;
   3536 	char *fmri;
   3537 	char *prop_value;
   3538 	adt_session_data_t *session;
   3539 	adt_event_data_t *event = NULL;
   3540 
   3541 	/* Don't audit if we're using an alternate repository */
   3542 	if (is_main_repository == 0)
   3543 		return;
   3544 
   3545 	smf_annotation_event(status, return_val);
   3546 	if ((session = get_audit_session()) == NULL)
   3547 		return;
   3548 	if ((event = adt_alloc_event(session, event_id)) == NULL) {
   3549 		uu_warn("_smf_audit_event cannot allocate event "
   3550 		    "data.  %s\n", strerror(errno));
   3551 		return;
   3552 	}
   3553 
   3554 	/*
   3555 	 * Handle possibility of NULL authorization strings, FMRIs and
   3556 	 * property values.
   3557 	 */
   3558 	if (data->ed_auth == NULL) {
   3559 		auth_used = "PRIVILEGED";
   3560 	} else {
   3561 		auth_used = data->ed_auth;
   3562 	}
   3563 	if (data->ed_fmri == NULL) {
   3564 		syslog(LOG_WARNING, "_smf_audit_event called with "
   3565 		    "empty FMRI string");
   3566 		fmri = "UNKNOWN FMRI";
   3567 	} else {
   3568 		fmri = data->ed_fmri;
   3569 	}
   3570 	if (data->ed_prop_value == NULL) {
   3571 		prop_value = "";
   3572 	} else {
   3573 		prop_value = data->ed_prop_value;
   3574 	}
   3575 
   3576 	/* Fill in the event data. */
   3577 	switch (event_id) {
   3578 	case ADT_smf_attach_snap:
   3579 		event->adt_smf_attach_snap.auth_used = auth_used;
   3580 		event->adt_smf_attach_snap.old_fmri = data->ed_old_fmri;
   3581 		event->adt_smf_attach_snap.old_name = data->ed_old_name;
   3582 		event->adt_smf_attach_snap.new_fmri = fmri;
   3583 		event->adt_smf_attach_snap.new_name = data->ed_snapname;
   3584 		break;
   3585 	case ADT_smf_change_prop:
   3586 		event->adt_smf_change_prop.auth_used = auth_used;
   3587 		event->adt_smf_change_prop.fmri = fmri;
   3588 		event->adt_smf_change_prop.type = data->ed_type;
   3589 		event->adt_smf_change_prop.value = prop_value;
   3590 		break;
   3591 	case ADT_smf_clear:
   3592 		event->adt_smf_clear.auth_used = auth_used;
   3593 		event->adt_smf_clear.fmri = fmri;
   3594 		break;
   3595 	case ADT_smf_create:
   3596 		event->adt_smf_create.fmri = fmri;
   3597 		event->adt_smf_create.auth_used = auth_used;
   3598 		break;
   3599 	case ADT_smf_create_npg:
   3600 		event->adt_smf_create_npg.auth_used = auth_used;
   3601 		event->adt_smf_create_npg.fmri = fmri;
   3602 		event->adt_smf_create_npg.type = data->ed_type;
   3603 		break;
   3604 	case ADT_smf_create_pg:
   3605 		event->adt_smf_create_pg.auth_used = auth_used;
   3606 		event->adt_smf_create_pg.fmri = fmri;
   3607 		event->adt_smf_create_pg.type = data->ed_type;
   3608 		break;
   3609 	case ADT_smf_create_prop:
   3610 		event->adt_smf_create_prop.auth_used = auth_used;
   3611 		event->adt_smf_create_prop.fmri = fmri;
   3612 		event->adt_smf_create_prop.type = data->ed_type;
   3613 		event->adt_smf_create_prop.value = prop_value;
   3614 		break;
   3615 	case ADT_smf_create_snap:
   3616 		event->adt_smf_create_snap.auth_used = auth_used;
   3617 		event->adt_smf_create_snap.fmri = fmri;
   3618 		event->adt_smf_create_snap.name = data->ed_snapname;
   3619 		break;
   3620 	case ADT_smf_degrade:
   3621 		event->adt_smf_degrade.auth_used = auth_used;
   3622 		event->adt_smf_degrade.fmri = fmri;
   3623 		break;
   3624 	case ADT_smf_delete:
   3625 		event->adt_smf_delete.fmri = fmri;
   3626 		event->adt_smf_delete.auth_used = auth_used;
   3627 		break;
   3628 	case ADT_smf_delete_npg:
   3629 		event->adt_smf_delete_npg.auth_used = auth_used;
   3630 		event->adt_smf_delete_npg.fmri = fmri;
   3631 		event->adt_smf_delete_npg.type = data->ed_type;
   3632 		break;
   3633 	case ADT_smf_delete_pg:
   3634 		event->adt_smf_delete_pg.auth_used = auth_used;
   3635 		event->adt_smf_delete_pg.fmri = fmri;
   3636 		event->adt_smf_delete_pg.type = data->ed_type;
   3637 		break;
   3638 	case ADT_smf_delete_prop:
   3639 		event->adt_smf_delete_prop.auth_used = auth_used;
   3640 		event->adt_smf_delete_prop.fmri = fmri;
   3641 		break;
   3642 	case ADT_smf_delete_snap:
   3643 		event->adt_smf_delete_snap.auth_used = auth_used;
   3644 		event->adt_smf_delete_snap.fmri = fmri;
   3645 		event->adt_smf_delete_snap.name = data->ed_snapname;
   3646 		break;
   3647 	case ADT_smf_disable:
   3648 		event->adt_smf_disable.auth_used = auth_used;
   3649 		event->adt_smf_disable.fmri = fmri;
   3650 		break;
   3651 	case ADT_smf_enable:
   3652 		event->adt_smf_enable.auth_used = auth_used;
   3653 		event->adt_smf_enable.fmri = fmri;
   3654 		break;
   3655 	case ADT_smf_immediate_degrade:
   3656 		event->adt_smf_immediate_degrade.auth_used = auth_used;
   3657 		event->adt_smf_immediate_degrade.fmri = fmri;
   3658 		break;
   3659 	case ADT_smf_immediate_maintenance:
   3660 		event->adt_smf_immediate_maintenance.auth_used = auth_used;
   3661 		event->adt_smf_immediate_maintenance.fmri = fmri;
   3662 		break;
   3663 	case ADT_smf_immtmp_maintenance:
   3664 		event->adt_smf_immtmp_maintenance.auth_used = auth_used;
   3665 		event->adt_smf_immtmp_maintenance.fmri = fmri;
   3666 		break;
   3667 	case ADT_smf_maintenance:
   3668 		event->adt_smf_maintenance.auth_used = auth_used;
   3669 		event->adt_smf_maintenance.fmri = fmri;
   3670 		break;
   3671 	case ADT_smf_milestone:
   3672 		event->adt_smf_milestone.auth_used = auth_used;
   3673 		event->adt_smf_milestone.fmri = fmri;
   3674 		break;
   3675 	case ADT_smf_read_prop:
   3676 		event->adt_smf_read_prop.auth_used = auth_used;
   3677 		event->adt_smf_read_prop.fmri = fmri;
   3678 		break;
   3679 	case ADT_smf_refresh:
   3680 		event->adt_smf_refresh.auth_used = auth_used;
   3681 		event->adt_smf_refresh.fmri = fmri;
   3682 		break;
   3683 	case ADT_smf_restart:
   3684 		event->adt_smf_restart.auth_used = auth_used;
   3685 		event->adt_smf_restart.fmri = fmri;
   3686 		break;
   3687 	case ADT_smf_tmp_disable:
   3688 		event->adt_smf_tmp_disable.auth_used = auth_used;
   3689 		event->adt_smf_tmp_disable.fmri = fmri;
   3690 		break;
   3691 	case ADT_smf_tmp_enable:
   3692 		event->adt_smf_tmp_enable.auth_used = auth_used;
   3693 		event->adt_smf_tmp_enable.fmri = fmri;
   3694 		break;
   3695 	case ADT_smf_tmp_maintenance:
   3696 		event->adt_smf_tmp_maintenance.auth_used = auth_used;
   3697 		event->adt_smf_tmp_maintenance.fmri = fmri;
   3698 		break;
   3699 	default:
   3700 		abort();	/* Need to cover all SMF event IDs */
   3701 	}
   3702 
   3703 	if (adt_put_event(event, status, return_val) != 0) {
   3704 		uu_warn("_smf_audit_event failed to put event.  %s\n",
   3705 		    strerror(errno));
   3706 	}
   3707 	adt_free_event(event);
   3708 }
   3709 
   3710 /*
   3711  * Determine if the combination of the property group at pg_name and the
   3712  * property at prop_name are in the set of special startd properties.  If
   3713  * they are, a special audit event will be generated.
   3714  */
   3715 static void
   3716 special_property_event(audit_event_data_t *evdp, const char *prop_name,
   3717     char *pg_name, int status, int return_val, tx_commit_data_t *tx_data,
   3718     size_t cmd_no)
   3719 {
   3720 	au_event_t event_id;
   3721 	audit_special_prop_item_t search_key;
   3722 	audit_special_prop_item_t *found;
   3723 
   3724 	/* Use bsearch to find the special property information. */
   3725 	search_key.api_prop_name = prop_name;
   3726 	search_key.api_pg_name = pg_name;
   3727 	found = (audit_special_prop_item_t *)bsearch(&search_key,
   3728 	    special_props_list, SPECIAL_PROP_COUNT,
   3729 	    sizeof (special_props_list[0]), special_prop_compare);
   3730 	if (found == NULL) {
   3731 		/* Not a special property. */
   3732 		return;
   3733 	}
   3734 
   3735 	/* Get the event id */
   3736 	if (found->api_event_func == NULL) {
   3737 		event_id = found->api_event_id;
   3738 	} else {
   3739 		if ((*found->api_event_func)(tx_data, cmd_no,
   3740 		    found->api_pg_name, &event_id) < 0)
   3741 			return;
   3742 	}
   3743 
   3744 	/* Generate the event. */
   3745 	smf_audit_event(event_id, status, return_val, evdp);
   3746 }
   3747 #endif	/* NATIVE_BUILD */
   3748 
   3749 /*
   3750  * Return a pointer to a string containing all the values of the command
   3751  * specified by cmd_no with each value enclosed in quotes.  It is up to the
   3752  * caller to free the memory at the returned pointer.
   3753  */
   3754 static char *
   3755 generate_value_list(tx_commit_data_t *tx_data, size_t cmd_no)
   3756 {
   3757 	const char *cp;
   3758 	const char *cur_value;
   3759 	size_t byte_count = 0;
   3760 	uint32_t i;
   3761 	uint32_t nvalues;
   3762 	size_t str_size = 0;
   3763 	char *values = NULL;
   3764 	char *vp;
   3765 
   3766 	if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
   3767 		return (NULL);
   3768 	/*
   3769 	 * First determine the size of the buffer that we will need.  We
   3770 	 * will represent each property value surrounded by quotes with a
   3771 	 * space separating the values.  Thus, we need to find the total
   3772 	 * size of all the value strings and add 3 for each value.
   3773 	 *
   3774 	 * There is one catch, though.  We need to escape any internal
   3775 	 * quote marks in the values.  So for each quote in the value we
   3776 	 * need to add another byte to the buffer size.
   3777 	 */
   3778 	for (i = 0; i < nvalues; i++) {
   3779 		if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
   3780 		    REP_PROTOCOL_SUCCESS)
   3781 			return (NULL);
   3782 		for (cp = cur_value; *cp != 0; cp++) {
   3783 			byte_count += (*cp == '"') ? 2 : 1;
   3784 		}
   3785 		byte_count += 3;	/* surrounding quotes & space */
   3786 	}
   3787 	byte_count++;		/* nul terminator */
   3788 	values = malloc(byte_count);
   3789 	if (values == NULL)
   3790 		return (NULL);
   3791 	*values = 0;
   3792 
   3793 	/* Now build up the string of values. */
   3794 	for (i = 0; i < nvalues; i++) {
   3795 		if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
   3796 		    REP_PROTOCOL_SUCCESS) {
   3797 			free(values);
   3798 			return (NULL);
   3799 		}
   3800 		(void) strlcat(values, "\"", byte_count);
   3801 		for (cp = cur_value, vp = values + strlen(values);
   3802 		    *cp != 0; cp++) {
   3803 			if (*cp == '"') {
   3804 				*vp++ = '\\';
   3805 				*vp++ = '"';
   3806 			} else {
   3807 				*vp++ = *cp;
   3808 			}
   3809 		}
   3810 		*vp = 0;
   3811 		str_size = strlcat(values, "\" ", byte_count);
   3812 		assert(str_size < byte_count);
   3813 	}
   3814 	if (str_size > 0)
   3815 		values[str_size - 1] = 0;	/* get rid of trailing space */
   3816 	return (values);
   3817 }
   3818 
   3819 /*
   3820  * generate_property_events takes the transaction commit data at tx_data
   3821  * and generates an audit event for each command.
   3822  *
   3823  * Native builds are done to create svc.configd-native.  This program runs
   3824  * only on the Solaris build machines to create the seed repository.  Thus,
   3825  * no audit events should be generated when running svc.configd-native.
   3826  */
   3827 static void
   3828 generate_property_events(
   3829 	tx_commit_data_t *tx_data,
   3830 	char *pg_fmri,		/* FMRI of property group */
   3831 	char *auth_string,
   3832 	int auth_status,
   3833 	int auth_ret_value)
   3834 {
   3835 #ifndef	NATIVE_BUILD
   3836 	enum rep_protocol_transaction_action action;
   3837 	audit_event_data_t audit_data;
   3838 	size_t count;
   3839 	size_t cmd_no;
   3840 	char *cp;
   3841 	au_event_t event_id;
   3842 	char fmri[REP_PROTOCOL_FMRI_LEN];
   3843 	char pg_name[REP_PROTOCOL_NAME_LEN];
   3844 	char *pg_end;		/* End of prop. group fmri */
   3845 	const char *prop_name;
   3846 	uint32_t ptype;
   3847 	char prop_type[3];
   3848 	enum rep_protocol_responseid rc;
   3849 	size_t sz_out;
   3850 
   3851 	/* Make sure we have something to do. */
   3852 	if (tx_data == NULL)
   3853 		return;
   3854 	if ((count = tx_cmd_count(tx_data)) == 0)
   3855 		return;
   3856 
   3857 	/* Copy the property group fmri */
   3858 	pg_end = fmri;
   3859 	pg_end += strlcpy(fmri, pg_fmri, sizeof (fmri));
   3860 
   3861 	/*
   3862 	 * Get the property group name.  It is the first component after
   3863 	 * the last occurance of SCF_FMRI_PROPERTYGRP_PREFIX in the fmri.
   3864 	 */
   3865 	cp = strstr(pg_fmri, SCF_FMRI_PROPERTYGRP_PREFIX);
   3866 	if (cp == NULL) {
   3867 		pg_name[0] = 0;
   3868 	} else {
   3869 		cp += strlen(SCF_FMRI_PROPERTYGRP_PREFIX);
   3870 		(void) strlcpy(pg_name, cp, sizeof (pg_name));
   3871 	}
   3872 
   3873 	audit_data.ed_auth = auth_string;
   3874 	audit_data.ed_fmri = fmri;
   3875 	audit_data.ed_type = prop_type;
   3876 
   3877 	/*
   3878 	 * Property type is two characters (see
   3879 	 * rep_protocol_value_type_t), so terminate the string.
   3880 	 */
   3881 	prop_type[2] = 0;
   3882 
   3883 	for (cmd_no = 0; cmd_no < count; cmd_no++) {
   3884 		/* Construct FMRI of the property */
   3885 		*pg_end = 0;
   3886 		if (tx_cmd_prop(tx_data, cmd_no, &prop_name) !=
   3887 		    REP_PROTOCOL_SUCCESS) {
   3888 			continue;
   3889 		}
   3890 		rc = rc_concat_fmri_element(fmri, sizeof (fmri), &sz_out,
   3891 		    prop_name, REP_PROTOCOL_ENTITY_PROPERTY);
   3892 		if (rc != REP_PROTOCOL_SUCCESS) {
   3893 			/*
   3894 			 * If we can't get the FMRI, we'll abandon this
   3895 			 * command
   3896 			 */
   3897 			continue;
   3898 		}
   3899 
   3900 		/* Generate special property event if necessary. */
   3901 		special_property_event(&audit_data, prop_name, pg_name,
   3902 		    auth_status, auth_ret_value, tx_data, cmd_no);
   3903 
   3904 		/* Capture rest of audit data. */
   3905 		if (tx_cmd_prop_type(tx_data, cmd_no, &ptype) !=
   3906 		    REP_PROTOCOL_SUCCESS) {
   3907 			continue;
   3908 		}
   3909 		prop_type[0] = REP_PROTOCOL_BASE_TYPE(ptype);
   3910 		prop_type[1] = REP_PROTOCOL_SUBTYPE(ptype);
   3911 		audit_data.ed_prop_value = generate_value_list(tx_data, cmd_no);
   3912 
   3913 		/* Determine the event type. */
   3914 		if (tx_cmd_action(tx_data, cmd_no, &action) !=
   3915 		    REP_PROTOCOL_SUCCESS) {
   3916 			free(audit_data.ed_prop_value);
   3917 			continue;
   3918 		}
   3919 		switch (action) {
   3920 		case REP_PROTOCOL_TX_ENTRY_NEW:
   3921 			event_id = ADT_smf_create_prop;
   3922 			break;
   3923 		case REP_PROTOCOL_TX_ENTRY_CLEAR:
   3924 			event_id = ADT_smf_change_prop;
   3925 			break;
   3926 		case REP_PROTOCOL_TX_ENTRY_REPLACE:
   3927 			event_id = ADT_smf_change_prop;
   3928 			break;
   3929 		case REP_PROTOCOL_TX_ENTRY_DELETE:
   3930 			event_id = ADT_smf_delete_prop;
   3931 			break;
   3932 		default:
   3933 			assert(0);	/* Missing a case */
   3934 			free(audit_data.ed_prop_value);
   3935 			continue;
   3936 		}
   3937 
   3938 		/* Generate the event. */
   3939 		smf_audit_event(event_id, auth_status, auth_ret_value,
   3940 		    &audit_data);
   3941 		free(audit_data.ed_prop_value);
   3942 	}
   3943 #endif /* NATIVE_BUILD */
   3944 }
   3945 
   3946 /*
   3947  * Fails with
   3948  *   _DELETED - node has been deleted
   3949  *   _NOT_SET - npp is reset
   3950  *   _NOT_APPLICABLE - type is _PROPERTYGRP
   3951  *   _INVALID_TYPE - node is corrupt or type is invalid
   3952  *   _TYPE_MISMATCH - node cannot have children of type type
   3953  *   _BAD_REQUEST - name is invalid
   3954  *		    cannot create children for this type of node
   3955  *   _NO_RESOURCES - out of memory, or could not allocate new id
   3956  *   _PERMISSION_DENIED
   3957  *   _BACKEND_ACCESS
   3958  *   _BACKEND_READONLY
   3959  *   _EXISTS - child already exists
   3960  *   _TRUNCATED - truncated FMRI for the audit record
   3961  */
   3962 int
   3963 rc_node_create_child(rc_node_ptr_t *npp, uint32_t type, const char *name,
   3964     rc_node_ptr_t *cpp)
   3965 {
   3966 	rc_node_t *np;
   3967 	rc_node_t *cp = NULL;
   3968 	int rc;
   3969 	perm_status_t perm_rc;
   3970 	size_t sz_out;
   3971 	char fmri[REP_PROTOCOL_FMRI_LEN];
   3972 	audit_event_data_t audit_data;
   3973 
   3974 	rc_node_clear(cpp, 0);
   3975 
   3976 	/*
   3977 	 * rc_node_modify_permission_check() must be called before the node
   3978 	 * is locked.  This is because the library functions that check
   3979 	 * authorizations can trigger calls back into configd.
   3980 	 */
   3981 	perm_rc = rc_node_modify_permission_check(&audit_data.ed_auth);
   3982 	switch (perm_rc) {
   3983 	case PERM_DENIED:
   3984 		/*
   3985 		 * We continue in this case, so that an audit event can be
   3986 		 * generated later in the function.
   3987 		 */
   3988 		break;
   3989 	case PERM_GRANTED:
   3990 		break;
   3991 	case PERM_GONE:
   3992 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   3993 	case PERM_FAIL:
   3994 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   3995 	default:
   3996 		bad_error(rc_node_modify_permission_check, perm_rc);
   3997 	}
   3998 
   3999 	RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
   4000 
   4001 	audit_data.ed_fmri = fmri;
   4002 
   4003 	/*
   4004 	 * there is a separate interface for creating property groups
   4005 	 */
   4006 	if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   4007 		(void) pthread_mutex_unlock(&np->rn_lock);
   4008 		free(audit_data.ed_auth);
   4009 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   4010 	}
   4011 
   4012 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   4013 		(void) pthread_mutex_unlock(&np->rn_lock);
   4014 		np = np->rn_cchain[0];
   4015 		if ((rc = rc_node_check_and_lock(np)) != REP_PROTOCOL_SUCCESS) {
   4016 			free(audit_data.ed_auth);
   4017 			return (rc);
   4018 		}
   4019 	}
   4020 
   4021 	if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
   4022 	    REP_PROTOCOL_SUCCESS) {
   4023 		(void) pthread_mutex_unlock(&np->rn_lock);
   4024 		free(audit_data.ed_auth);
   4025 		return (rc);
   4026 	}
   4027 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS) {
   4028 		(void) pthread_mutex_unlock(&np->rn_lock);
   4029 		free(audit_data.ed_auth);
   4030 		return (rc);
   4031 	}
   4032 
   4033 	if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
   4034 	    name, type)) != REP_PROTOCOL_SUCCESS) {
   4035 		(void) pthread_mutex_unlock(&np->rn_lock);
   4036 		free(audit_data.ed_auth);
   4037 		return (rc);
   4038 	}
   4039 	if (perm_rc == PERM_DENIED) {
   4040 		(void) pthread_mutex_unlock(&np->rn_lock);
   4041 		smf_audit_event(ADT_smf_create, ADT_FAILURE,
   4042 		    ADT_FAIL_VALUE_AUTH, &audit_data);
   4043 		free(audit_data.ed_auth);
   4044 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   4045 	}
   4046 
   4047 	HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
   4048 	    audit_data.ed_auth);
   4049 	(void) pthread_mutex_unlock(&np->rn_lock);
   4050 
   4051 	rc = object_create(np, type, name, &cp);
   4052 	assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   4053 
   4054 	if (rc == REP_PROTOCOL_SUCCESS) {
   4055 		rc_node_assign(cpp, cp);
   4056 		rc_node_rele(cp);
   4057 	}
   4058 
   4059 	(void) pthread_mutex_lock(&np->rn_lock);
   4060 	rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
   4061 	(void) pthread_mutex_unlock(&np->rn_lock);
   4062 
   4063 	if (rc == REP_PROTOCOL_SUCCESS) {
   4064 		smf_audit_event(ADT_smf_create, ADT_SUCCESS, ADT_SUCCESS,
   4065 		    &audit_data);
   4066 	}
   4067 
   4068 	free(audit_data.ed_auth);
   4069 
   4070 	return (rc);
   4071 }
   4072 
   4073 int
   4074 rc_node_create_child_pg(rc_node_ptr_t *npp, uint32_t type, const char *name,
   4075     const char *pgtype, uint32_t flags, rc_node_ptr_t *cpp)
   4076 {
   4077 	rc_node_t *np;
   4078 	rc_node_t *cp;
   4079 	int rc;
   4080 	permcheck_t *pcp;
   4081 	perm_status_t granted;
   4082 	char fmri[REP_PROTOCOL_FMRI_LEN];
   4083 	audit_event_data_t audit_data;
   4084 	au_event_t event_id;
   4085 	size_t sz_out;
   4086 
   4087 	audit_data.ed_auth = NULL;
   4088 	audit_data.ed_fmri = fmri;
   4089 	audit_data.ed_type = (char *)pgtype;
   4090 
   4091 	rc_node_clear(cpp, 0);
   4092 
   4093 	/* verify flags is valid */
   4094 	if (flags & ~SCF_PG_FLAG_NONPERSISTENT)
   4095 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   4096 
   4097 	RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
   4098 
   4099 	if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   4100 		rc_node_rele(np);
   4101 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   4102 	}
   4103 
   4104 	if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
   4105 	    REP_PROTOCOL_SUCCESS) {
   4106 		rc_node_rele(np);
   4107 		return (rc);
   4108 	}
   4109 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS ||
   4110 	    (rc = rc_check_pgtype_name(pgtype)) != REP_PROTOCOL_SUCCESS) {
   4111 		rc_node_rele(np);
   4112 		return (rc);
   4113 	}
   4114 
   4115 #ifdef NATIVE_BUILD
   4116 	if (!client_is_privileged()) {
   4117 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   4118 	}
   4119 #else
   4120 	if (flags & SCF_PG_FLAG_NONPERSISTENT) {
   4121 		event_id = ADT_smf_create_npg;
   4122 	} else {
   4123 		event_id = ADT_smf_create_pg;
   4124 	}
   4125 	if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
   4126 	    name, REP_PROTOCOL_ENTITY_PROPERTYGRP)) != REP_PROTOCOL_SUCCESS) {
   4127 		rc_node_rele(np);
   4128 		return (rc);
   4129 	}
   4130 
   4131 	if (is_main_repository) {
   4132 		/* Must have .smf.modify or smf.modify.<type> authorization */
   4133 		pcp = pc_create();
   4134 		if (pcp != NULL) {
   4135 			rc = perm_add_enabling(pcp, AUTH_MODIFY);
   4136 
   4137 			if (rc == REP_PROTOCOL_SUCCESS) {
   4138 				const char * const auth =
   4139 				    perm_auth_for_pgtype(pgtype);
   4140 
   4141 				if (auth != NULL)
   4142 					rc = perm_add_enabling(pcp, auth);
   4143 			}
   4144 
   4145 			/*
   4146 			 * .manage or $action_authorization can be used to
   4147 			 * create the actions pg and the general_ovr pg.
   4148 			 */
   4149 			if (rc == REP_PROTOCOL_SUCCESS &&
   4150 			    (flags & SCF_PG_FLAG_NONPERSISTENT) != 0 &&
   4151 			    np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE &&
   4152 			    ((strcmp(name, AUTH_PG_ACTIONS) == 0 &&
   4153 			    strcmp(pgtype, AUTH_PG_ACTIONS_TYPE) == 0) ||
   4154 			    (strcmp(name, AUTH_PG_GENERAL_OVR) == 0 &&
   4155 			    strcmp(pgtype, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
   4156 				rc = perm_add_enabling(pcp, AUTH_MANAGE);
   4157 
   4158 				if (rc == REP_PROTOCOL_SUCCESS)
   4159 					rc = perm_add_inst_action_auth(pcp, np);
   4160 			}
   4161 
   4162 			if (rc == REP_PROTOCOL_SUCCESS) {
   4163 				granted = perm_granted(pcp);
   4164 
   4165 				rc = map_granted_status(granted, pcp,
   4166 				    &audit_data.ed_auth);
   4167 				if (granted == PERM_GONE) {
   4168 					/* No auditing if client gone. */
   4169 					pc_free(pcp);
   4170 					rc_node_rele(np);
   4171 					return (rc);
   4172 				}
   4173 			}
   4174 
   4175 			pc_free(pcp);
   4176 		} else {
   4177 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   4178 		}
   4179 
   4180 	} else {
   4181 		rc = REP_PROTOCOL_SUCCESS;
   4182 	}
   4183 #endif /* NATIVE_BUILD */
   4184 
   4185 
   4186 	if (rc != REP_PROTOCOL_SUCCESS) {
   4187 		rc_node_rele(np);
   4188 		if (rc != REP_PROTOCOL_FAIL_NO_RESOURCES) {
   4189 			smf_audit_event(event_id, ADT_FAILURE,
   4190 			    ADT_FAIL_VALUE_AUTH, &audit_data);
   4191 		}
   4192 		if (audit_data.ed_auth != NULL)
   4193 			free(audit_data.ed_auth);
   4194 		return (rc);
   4195 	}
   4196 
   4197 	(void) pthread_mutex_lock(&np->rn_lock);
   4198 	HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
   4199 	    audit_data.ed_auth);
   4200 	(void) pthread_mutex_unlock(&np->rn_lock);
   4201 
   4202 	rc = object_create_pg(np, type, name, pgtype, flags, &cp);
   4203 
   4204 	if (rc == REP_PROTOCOL_SUCCESS) {
   4205 		rc_node_assign(cpp, cp);
   4206 		rc_node_rele(cp);
   4207 	}
   4208 
   4209 	(void) pthread_mutex_lock(&np->rn_lock);
   4210 	rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
   4211 	(void) pthread_mutex_unlock(&np->rn_lock);
   4212 
   4213 	if (rc == REP_PROTOCOL_SUCCESS) {
   4214 		smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
   4215 		    &audit_data);
   4216 	}
   4217 	if (audit_data.ed_auth != NULL)
   4218 		free(audit_data.ed_auth);
   4219 
   4220 	return (rc);
   4221 }
   4222 
   4223 static void
   4224 rc_pg_notify_fire(rc_node_pg_notify_t *pnp)
   4225 {
   4226 	assert(MUTEX_HELD(&rc_pg_notify_lock));
   4227 
   4228 	if (pnp->rnpn_pg != NULL) {
   4229 		uu_list_remove(pnp->rnpn_pg->rn_pg_notify_list, pnp);
   4230 		(void) close(pnp->rnpn_fd);
   4231 
   4232 		pnp->rnpn_pg = NULL;
   4233 		pnp->rnpn_fd = -1;
   4234 	} else {
   4235 		assert(pnp->rnpn_fd == -1);
   4236 	}
   4237 }
   4238 
   4239 static void
   4240 rc_notify_node_delete(rc_notify_delete_t *ndp, rc_node_t *np_arg)
   4241 {
   4242 	rc_node_t *svc = NULL;
   4243 	rc_node_t *inst = NULL;
   4244 	rc_node_t *pg = NULL;
   4245 	rc_node_t *np = np_arg;
   4246 	rc_node_t *nnp;
   4247 
   4248 	while (svc == NULL) {
   4249 		(void) pthread_mutex_lock(&np->rn_lock);
   4250 		if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   4251 			(void) pthread_mutex_unlock(&np->rn_lock);
   4252 			goto cleanup;
   4253 		}
   4254 		nnp = np->rn_parent;
   4255 		rc_node_hold_locked(np);	/* hold it in place */
   4256 
   4257 		switch (np->rn_id.rl_type) {
   4258 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   4259 			assert(pg == NULL);
   4260 			pg = np;
   4261 			break;
   4262 		case REP_PROTOCOL_ENTITY_INSTANCE:
   4263 			assert(inst == NULL);
   4264 			inst = np;
   4265 			break;
   4266 		case REP_PROTOCOL_ENTITY_SERVICE:
   4267 			assert(svc == NULL);
   4268 			svc = np;
   4269 			break;
   4270 		default:
   4271 			rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   4272 			rc_node_rele_locked(np);
   4273 			goto cleanup;
   4274 		}
   4275 
   4276 		(void) pthread_mutex_unlock(&np->rn_lock);
   4277 
   4278 		np = nnp;
   4279 		if (np == NULL)
   4280 			goto cleanup;
   4281 	}
   4282 
   4283 	rc_notify_deletion(ndp,
   4284 	    svc->rn_name,
   4285 	    inst != NULL ? inst->rn_name : NULL,
   4286 	    pg != NULL ? pg->rn_name : NULL);
   4287 
   4288 	ndp = NULL;
   4289 
   4290 cleanup:
   4291 	if (ndp != NULL)
   4292 		uu_free(ndp);
   4293 
   4294 	for (;;) {
   4295 		if (svc != NULL) {
   4296 			np = svc;
   4297 			svc = NULL;
   4298 		} else if (inst != NULL) {
   4299 			np = inst;
   4300 			inst = NULL;
   4301 		} else if (pg != NULL) {
   4302 			np = pg;
   4303 			pg = NULL;
   4304 		} else
   4305 			break;
   4306 
   4307 		(void) pthread_mutex_lock(&np->rn_lock);
   4308 		rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   4309 		rc_node_rele_locked(np);
   4310 	}
   4311 }
   4312 
   4313 /*
   4314  * Hold RC_NODE_DYING_FLAGS on np's descendents.  If andformer is true, do
   4315  * the same down the rn_former chain.
   4316  */
   4317 static void
   4318 rc_node_delete_hold(rc_node_t *np, int andformer)
   4319 {
   4320 	rc_node_t *cp;
   4321 
   4322 again:
   4323 	assert(MUTEX_HELD(&np->rn_lock));
   4324 	assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
   4325 
   4326 	for (cp = uu_list_first(np->rn_children); cp != NULL;
   4327 	    cp = uu_list_next(np->rn_children, cp)) {
   4328 		(void) pthread_mutex_lock(&cp->rn_lock);
   4329 		(void) pthread_mutex_unlock(&np->rn_lock);
   4330 		if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS)) {
   4331 			/*
   4332 			 * already marked as dead -- can't happen, since that
   4333 			 * would require setting RC_NODE_CHILDREN_CHANGING
   4334 			 * in np, and we're holding that...
   4335 			 */
   4336 			abort();
   4337 		}
   4338 		rc_node_delete_hold(cp, andformer);	/* recurse, drop lock */
   4339 
   4340 		(void) pthread_mutex_lock(&np->rn_lock);
   4341 	}
   4342 	if (andformer && (cp = np->rn_former) != NULL) {
   4343 		(void) pthread_mutex_lock(&cp->rn_lock);
   4344 		(void) pthread_mutex_unlock(&np->rn_lock);
   4345 		if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS))
   4346 			abort();		/* can't happen, see above */
   4347 		np = cp;
   4348 		goto again;		/* tail-recurse down rn_former */
   4349 	}
   4350 	(void) pthread_mutex_unlock(&np->rn_lock);
   4351 }
   4352 
   4353 /*
   4354  * N.B.:  this function drops np->rn_lock on the way out.
   4355  */
   4356 static void
   4357 rc_node_delete_rele(rc_node_t *np, int andformer)
   4358 {
   4359 	rc_node_t *cp;
   4360 
   4361 again:
   4362 	assert(MUTEX_HELD(&np->rn_lock));
   4363 	assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
   4364 
   4365 	for (cp = uu_list_first(np->rn_children); cp != NULL;
   4366 	    cp = uu_list_next(np->rn_children, cp)) {
   4367 		(void) pthread_mutex_lock(&cp->rn_lock);
   4368 		(void) pthread_mutex_unlock(&np->rn_lock);
   4369 		rc_node_delete_rele(cp, andformer);	/* recurse, drop lock */
   4370 		(void) pthread_mutex_lock(&np->rn_lock);
   4371 	}
   4372 	if (andformer && (cp = np->rn_former) != NULL) {
   4373 		(void) pthread_mutex_lock(&cp->rn_lock);
   4374 		rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   4375 		(void) pthread_mutex_unlock(&np->rn_lock);
   4376 
   4377 		np = cp;
   4378 		goto again;		/* tail-recurse down rn_former */
   4379 	}
   4380 	rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   4381 	(void) pthread_mutex_unlock(&np->rn_lock);
   4382 }
   4383 
   4384 static void
   4385 rc_node_finish_delete(rc_node_t *cp)
   4386 {
   4387 	cache_bucket_t *bp;
   4388 	rc_node_pg_notify_t *pnp;
   4389 
   4390 	assert(MUTEX_HELD(&cp->rn_lock));
   4391 
   4392 	if (!(cp->rn_flags & RC_NODE_OLD)) {
   4393 		assert(cp->rn_flags & RC_NODE_IN_PARENT);
   4394 		if (!rc_node_wait_flag(cp, RC_NODE_USING_PARENT)) {
   4395 			abort();		/* can't happen, see above */
   4396 		}
   4397 		cp->rn_flags &= ~RC_NODE_IN_PARENT;
   4398 		cp->rn_parent = NULL;
   4399 		rc_node_free_fmri(cp);
   4400 	}
   4401 
   4402 	cp->rn_flags |= RC_NODE_DEAD;
   4403 
   4404 	/*
   4405 	 * If this node is not out-dated, we need to remove it from
   4406 	 * the notify list and cache hash table.
   4407 	 */
   4408 	if (!(cp->rn_flags & RC_NODE_OLD)) {
   4409 		assert(cp->rn_refs > 0);	/* can't go away yet */
   4410 		(void) pthread_mutex_unlock(&cp->rn_lock);
   4411 
   4412 		(void) pthread_mutex_lock(&rc_pg_notify_lock);
   4413 		while ((pnp = uu_list_first(cp->rn_pg_notify_list)) != NULL)
   4414 			rc_pg_notify_fire(pnp);
   4415 		(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   4416 		rc_notify_remove_node(cp);
   4417 
   4418 		bp = cache_hold(cp->rn_hash);
   4419 		(void) pthread_mutex_lock(&cp->rn_lock);
   4420 		cache_remove_unlocked(bp, cp);
   4421 		cache_release(bp);
   4422 	}
   4423 }
   4424 
   4425 /*
   4426  * For each child, call rc_node_finish_delete() and recurse.  If andformer
   4427  * is set, also recurse down rn_former.  Finally release np, which might
   4428  * free it.
   4429  */
   4430 static void
   4431 rc_node_delete_children(rc_node_t *np, int andformer)
   4432 {
   4433 	rc_node_t *cp;
   4434 
   4435 again:
   4436 	assert(np->rn_refs > 0);
   4437 	assert(MUTEX_HELD(&np->rn_lock));
   4438 	assert(np->rn_flags & RC_NODE_DEAD);
   4439 
   4440 	while ((cp = uu_list_first(np->rn_children)) != NULL) {
   4441 		uu_list_remove(np->rn_children, cp);
   4442 		(void) pthread_mutex_lock(&cp->rn_lock);
   4443 		(void) pthread_mutex_unlock(&np->rn_lock);
   4444 		rc_node_hold_locked(cp);	/* hold while we recurse */
   4445 		rc_node_finish_delete(cp);
   4446 		rc_node_delete_children(cp, andformer);	/* drops lock + ref */
   4447 		(void) pthread_mutex_lock(&np->rn_lock);
   4448 	}
   4449 
   4450 	/*
   4451 	 * When we drop cp's lock, all the children will be gone, so we
   4452 	 * can release DYING_FLAGS.
   4453 	 */
   4454 	rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   4455 	if (andformer && (cp = np->rn_former) != NULL) {
   4456 		np->rn_former = NULL;		/* unlink */
   4457 		(void) pthread_mutex_lock(&cp->rn_lock);
   4458 
   4459 		/*
   4460 		 * Register the ephemeral reference created by reading
   4461 		 * np->rn_former into cp.  Note that the persistent
   4462 		 * reference (np->rn_former) is locked because we haven't
   4463 		 * dropped np's lock since we dropped its RC_NODE_IN_TX
   4464 		 * (via RC_NODE_DYING_FLAGS).
   4465 		 */
   4466 		rc_node_hold_ephemeral_locked(cp);
   4467 
   4468 		(void) pthread_mutex_unlock(&np->rn_lock);
   4469 		cp->rn_flags &= ~RC_NODE_ON_FORMER;
   4470 
   4471 		rc_node_hold_locked(cp);	/* hold while we loop */
   4472 
   4473 		rc_node_finish_delete(cp);
   4474 
   4475 		rc_node_rele(np);		/* drop the old reference */
   4476 
   4477 		np = cp;
   4478 		goto again;		/* tail-recurse down rn_former */
   4479 	}
   4480 	rc_node_rele_locked(np);
   4481 }
   4482 
   4483 /*
   4484  * The last client or child reference to np, which must be either
   4485  * RC_NODE_OLD or RC_NODE_DEAD, has been destroyed.  We'll destroy any
   4486  * remaining references (e.g., rn_former) and call rc_node_destroy() to
   4487  * free np.
   4488  */
   4489 static void
   4490 rc_node_no_client_refs(rc_node_t *np)
   4491 {
   4492 	int unrefed;
   4493 	rc_node_t *current, *cur;
   4494 
   4495 	assert(MUTEX_HELD(&np->rn_lock));
   4496 	assert(np->rn_refs == 0);
   4497 	assert(np->rn_other_refs == 0);
   4498 	assert(np->rn_other_refs_held == 0);
   4499 
   4500 	if (np->rn_flags & RC_NODE_DEAD) {
   4501 		/*
   4502 		 * The node is DEAD, so the deletion code should have
   4503 		 * destroyed all rn_children or rn_former references.
   4504 		 * Since the last client or child reference has been
   4505 		 * destroyed, we're free to destroy np.  Unless another
   4506 		 * thread has an ephemeral reference, in which case we'll
   4507 		 * pass the buck.
   4508 		 */
   4509 		if (np->rn_erefs > 1) {
   4510 			--np->rn_erefs;
   4511 			NODE_UNLOCK(np);
   4512 			return;
   4513 		}
   4514 
   4515 		(void) pthread_mutex_unlock(&np->rn_lock);
   4516 		rc_node_destroy(np);
   4517 		return;
   4518 	}
   4519 
   4520 	/* We only collect DEAD and OLD nodes, thank you. */
   4521 	assert(np->rn_flags & RC_NODE_OLD);
   4522 
   4523 	/*
   4524 	 * RC_NODE_UNREFED keeps multiple threads from processing OLD
   4525 	 * nodes.  But it's vulnerable to unfriendly scheduling, so full
   4526 	 * use of rn_erefs should supersede it someday.
   4527 	 */
   4528 	if (np->rn_flags & RC_NODE_UNREFED) {
   4529 		(void) pthread_mutex_unlock(&np->rn_lock);
   4530 		return;
   4531 	}
   4532 	np->rn_flags |= RC_NODE_UNREFED;
   4533 
   4534 	/*
   4535 	 * Now we'll remove the node from the rn_former chain and take its
   4536 	 * DYING_FLAGS.
   4537 	 */
   4538 
   4539 	/*
   4540 	 * Since this node is OLD, it should be on an rn_former chain.  To
   4541 	 * remove it, we must find the current in-hash object and grab its
   4542 	 * RC_NODE_IN_TX flag to protect the entire rn_former chain.
   4543 	 */
   4544 
   4545 	(void) pthread_mutex_unlock(&np->rn_lock);
   4546 
   4547 	for (;;) {
   4548 		current = cache_lookup(&np->rn_id);
   4549 
   4550 		if (current == NULL) {
   4551 			(void) pthread_mutex_lock(&np->rn_lock);
   4552 
   4553 			if (np->rn_flags & RC_NODE_DEAD)
   4554 				goto died;
   4555 
   4556 			/*
   4557 			 * We are trying to unreference this node, but the
   4558 			 * owner of the former list does not exist.  It must
   4559 			 * be the case that another thread is deleting this
   4560 			 * entire sub-branch, but has not yet reached us.
   4561 			 * We will in short order be deleted.
   4562 			 */
   4563 			np->rn_flags &= ~RC_NODE_UNREFED;
   4564 			(void) pthread_mutex_unlock(&np->rn_lock);
   4565 			return;
   4566 		}
   4567 
   4568 		if (current == np) {
   4569 			/*
   4570 			 * no longer unreferenced
   4571 			 */
   4572 			(void) pthread_mutex_lock(&np->rn_lock);
   4573 			np->rn_flags &= ~RC_NODE_UNREFED;
   4574 			/* held in cache_lookup() */
   4575 			rc_node_rele_locked(np);
   4576 			return;
   4577 		}
   4578 
   4579 		(void) pthread_mutex_lock(&current->rn_lock);
   4580 		if (current->rn_flags & RC_NODE_OLD) {
   4581 			/*
   4582 			 * current has been replaced since we looked it
   4583 			 * up.  Try again.
   4584 			 */
   4585 			/* held in cache_lookup() */
   4586 			rc_node_rele_locked(current);
   4587 			continue;
   4588 		}
   4589 
   4590 		if (!rc_node_hold_flag(current, RC_NODE_IN_TX)) {
   4591 			/*
   4592 			 * current has been deleted since we looked it up.  Try
   4593 			 * again.
   4594 			 */
   4595 			/* held in cache_lookup() */
   4596 			rc_node_rele_locked(current);
   4597 			continue;
   4598 		}
   4599 
   4600 		/*
   4601 		 * rc_node_hold_flag() might have dropped current's lock, so
   4602 		 * check OLD again.
   4603 		 */
   4604 		if (!(current->rn_flags & RC_NODE_OLD)) {
   4605 			/* Not old.  Stop looping. */
   4606 			(void) pthread_mutex_unlock(&current->rn_lock);
   4607 			break;
   4608 		}
   4609 
   4610 		rc_node_rele_flag(current, RC_NODE_IN_TX);
   4611 		rc_node_rele_locked(current);
   4612 	}
   4613 
   4614 	/* To take np's RC_NODE_DYING_FLAGS, we need its lock. */
   4615 	(void) pthread_mutex_lock(&np->rn_lock);
   4616 
   4617 	/*
   4618 	 * While we didn't have the lock, a thread may have added
   4619 	 * a reference or changed the flags.
   4620 	 */
   4621 	if (!(np->rn_flags & (RC_NODE_OLD | RC_NODE_DEAD)) ||
   4622 	    np->rn_refs != 0 || np->rn_other_refs != 0 ||
   4623 	    np->rn_other_refs_held != 0) {
   4624 		np->rn_flags &= ~RC_NODE_UNREFED;
   4625 
   4626 		(void) pthread_mutex_lock(&current->rn_lock);
   4627 		rc_node_rele_flag(current, RC_NODE_IN_TX);
   4628 		/* held by cache_lookup() */
   4629 		rc_node_rele_locked(current);
   4630 		return;
   4631 	}
   4632 
   4633 	if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
   4634 		/*
   4635 		 * Someone deleted the node while we were waiting for
   4636 		 * DYING_FLAGS.  Undo the modifications to current.
   4637 		 */
   4638 		(void) pthread_mutex_unlock(&np->rn_lock);
   4639 
   4640 		rc_node_rele_flag(current, RC_NODE_IN_TX);
   4641 		/* held by cache_lookup() */
   4642 		rc_node_rele_locked(current);
   4643 
   4644 		(void) pthread_mutex_lock(&np->rn_lock);
   4645 		goto died;
   4646 	}
   4647 
   4648 	/* Take RC_NODE_DYING_FLAGS on np's descendents. */
   4649 	rc_node_delete_hold(np, 0);		/* drops np->rn_lock */
   4650 
   4651 	/* Mark np DEAD.  This requires the lock. */
   4652 	(void) pthread_mutex_lock(&np->rn_lock);
   4653 
   4654 	/* Recheck for new references. */
   4655 	if (!(np->rn_flags & RC_NODE_OLD) ||
   4656 	    np->rn_refs != 0 || np->rn_other_refs != 0 ||
   4657 	    np->rn_other_refs_held != 0) {
   4658 		np->rn_flags &= ~RC_NODE_UNREFED;
   4659 		rc_node_delete_rele(np, 0);	/* drops np's lock */
   4660 
   4661 		(void) pthread_mutex_lock(&current->rn_lock);
   4662 		rc_node_rele_flag(current, RC_NODE_IN_TX);
   4663 		/* held by cache_lookup() */
   4664 		rc_node_rele_locked(current);
   4665 		return;
   4666 	}
   4667 
   4668 	np->rn_flags |= RC_NODE_DEAD;
   4669 
   4670 	/*
   4671 	 * Delete the children.  This calls rc_node_rele_locked() on np at
   4672 	 * the end, so add a reference to keep the count from going
   4673 	 * negative.  It will recurse with RC_NODE_DEAD set, so we'll call
   4674 	 * rc_node_destroy() above, but RC_NODE_UNREFED is also set, so it
   4675 	 * shouldn't actually free() np.
   4676 	 */
   4677 	rc_node_hold_locked(np);
   4678 	rc_node_delete_children(np, 0);		/* unlocks np */
   4679 
   4680 	/* Remove np from current's rn_former chain. */
   4681 	(void) pthread_mutex_lock(&current->rn_lock);
   4682 	for (cur = current; cur != NULL && cur->rn_former != np;
   4683 	    cur = cur->rn_former)
   4684 		;
   4685 	assert(cur != NULL && cur != np);
   4686 
   4687 	cur->rn_former = np->rn_former;
   4688 	np->rn_former = NULL;
   4689 
   4690 	rc_node_rele_flag(current, RC_NODE_IN_TX);
   4691 	/* held by cache_lookup() */
   4692 	rc_node_rele_locked(current);
   4693 
   4694 	/* Clear ON_FORMER and UNREFED, and destroy. */
   4695 	(void) pthread_mutex_lock(&np->rn_lock);
   4696 	assert(np->rn_flags & RC_NODE_ON_FORMER);
   4697 	np->rn_flags &= ~(RC_NODE_UNREFED | RC_NODE_ON_FORMER);
   4698 
   4699 	if (np->rn_erefs > 1) {
   4700 		/* Still referenced.  Stay execution. */
   4701 		--np->rn_erefs;
   4702 		NODE_UNLOCK(np);
   4703 		return;
   4704 	}
   4705 
   4706 	(void) pthread_mutex_unlock(&np->rn_lock);
   4707 	rc_node_destroy(np);
   4708 	return;
   4709 
   4710 died:
   4711 	/*
   4712 	 * Another thread marked np DEAD.  If there still aren't any
   4713 	 * persistent references, destroy the node.
   4714 	 */
   4715 	np->rn_flags &= ~RC_NODE_UNREFED;
   4716 
   4717 	unrefed = (np->rn_refs == 0 && np->rn_other_refs == 0 &&
   4718 	    np->rn_other_refs_held == 0);
   4719 
   4720 	if (np->rn_erefs > 0)
   4721 		--np->rn_erefs;
   4722 
   4723 	if (unrefed && np->rn_erefs > 0) {
   4724 		NODE_UNLOCK(np);
   4725 		return;
   4726 	}
   4727 
   4728 	(void) pthread_mutex_unlock(&np->rn_lock);
   4729 
   4730 	if (unrefed)
   4731 		rc_node_destroy(np);
   4732 }
   4733 
   4734 static au_event_t
   4735 get_delete_event_id(rep_protocol_entity_t entity, uint32_t pgflags)
   4736 {
   4737 	au_event_t	id = 0;
   4738 
   4739 #ifndef NATIVE_BUILD
   4740 	switch (entity) {
   4741 	case REP_PROTOCOL_ENTITY_SERVICE:
   4742 	case REP_PROTOCOL_ENTITY_INSTANCE:
   4743 		id = ADT_smf_delete;
   4744 		break;
   4745 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
   4746 		id = ADT_smf_delete_snap;
   4747 		break;
   4748 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   4749 	case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
   4750 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT) {
   4751 			id = ADT_smf_delete_npg;
   4752 		} else {
   4753 			id = ADT_smf_delete_pg;
   4754 		}
   4755 		break;
   4756 	default:
   4757 		abort();
   4758 	}
   4759 #endif	/* NATIVE_BUILD */
   4760 	return (id);
   4761 }
   4762 
   4763 /*
   4764  * Fails with
   4765  *   _NOT_SET
   4766  *   _DELETED
   4767  *   _BAD_REQUEST
   4768  *   _PERMISSION_DENIED
   4769  *   _NO_RESOURCES
   4770  *   _TRUNCATED
   4771  * and whatever object_delete() fails with.
   4772  */
   4773 int
   4774 rc_node_delete(rc_node_ptr_t *npp)
   4775 {
   4776 	rc_node_t *np, *np_orig;
   4777 	rc_node_t *pp = NULL;
   4778 	int rc;
   4779 	rc_node_pg_notify_t *pnp;
   4780 	cache_bucket_t *bp;
   4781 	rc_notify_delete_t *ndp;
   4782 	permcheck_t *pcp;
   4783 	int granted;
   4784 	au_event_t event_id = 0;
   4785 	size_t sz_out;
   4786 	audit_event_data_t audit_data;
   4787 	int audit_failure = 0;
   4788 
   4789 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   4790 
   4791 	audit_data.ed_fmri = NULL;
   4792 	audit_data.ed_auth = NULL;
   4793 	audit_data.ed_snapname = NULL;
   4794 	audit_data.ed_type = NULL;
   4795 
   4796 	switch (np->rn_id.rl_type) {
   4797 	case REP_PROTOCOL_ENTITY_SERVICE:
   4798 		event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SERVICE,
   4799 		    np->rn_pgflags);
   4800 		break;
   4801 	case REP_PROTOCOL_ENTITY_INSTANCE:
   4802 		event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_INSTANCE,
   4803 		    np->rn_pgflags);
   4804 		break;
   4805 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
   4806 		event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SNAPSHOT,
   4807 		    np->rn_pgflags);
   4808 		audit_data.ed_snapname = strdup(np->rn_name);
   4809 		if (audit_data.ed_snapname == NULL) {
   4810 			(void) pthread_mutex_unlock(&np->rn_lock);
   4811 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   4812 		}
   4813 		break;			/* deletable */
   4814 
   4815 	case REP_PROTOCOL_ENTITY_SCOPE:
   4816 	case REP_PROTOCOL_ENTITY_SNAPLEVEL:
   4817 		/* Scopes and snaplevels are indelible. */
   4818 		(void) pthread_mutex_unlock(&np->rn_lock);
   4819 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   4820 
   4821 	case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
   4822 		(void) pthread_mutex_unlock(&np->rn_lock);
   4823 		np = np->rn_cchain[0];
   4824 		RC_NODE_CHECK_AND_LOCK(np);
   4825 		event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_CPROPERTYGRP,
   4826 		    np->rn_pgflags);
   4827 		break;
   4828 
   4829 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
   4830 		if (np->rn_id.rl_ids[ID_SNAPSHOT] == 0) {
   4831 			event_id =
   4832 			    get_delete_event_id(REP_PROTOCOL_ENTITY_PROPERTYGRP,
   4833 			    np->rn_pgflags);
   4834 			audit_data.ed_type = strdup(np->rn_type);
   4835 			if (audit_data.ed_type == NULL) {
   4836 				(void) pthread_mutex_unlock(&np->rn_lock);
   4837 				return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   4838 			}
   4839 			break;
   4840 		}
   4841 
   4842 		/* Snapshot property groups are indelible. */
   4843 		(void) pthread_mutex_unlock(&np->rn_lock);
   4844 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   4845 
   4846 	case REP_PROTOCOL_ENTITY_PROPERTY:
   4847 		(void) pthread_mutex_unlock(&np->rn_lock);
   4848 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   4849 
   4850 	default:
   4851 		assert(0);
   4852 		abort();
   4853 		break;
   4854 	}
   4855 
   4856 	audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
   4857 	if (audit_data.ed_fmri == NULL) {
   4858 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   4859 		goto cleanout;
   4860 	}
   4861 	np_orig = np;
   4862 	rc_node_hold_locked(np);	/* simplifies rest of the code */
   4863 
   4864 again:
   4865 	/*
   4866 	 * The following loop is to deal with the fact that snapshots and
   4867 	 * property groups are moving targets -- changes to them result
   4868 	 * in a new "child" node.  Since we can only delete from the top node,
   4869 	 * we have to loop until we have a non-RC_NODE_OLD version.
   4870 	 */
   4871 	for (;;) {
   4872 		if (!rc_node_wait_flag(np,
   4873 		    RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
   4874 			rc_node_rele_locked(np);
   4875 			rc = REP_PROTOCOL_FAIL_DELETED;
   4876 			goto cleanout;
   4877 		}
   4878 
   4879 		if (np->rn_flags & RC_NODE_OLD) {
   4880 			rc_node_rele_locked(np);
   4881 			np = cache_lookup(&np_orig->rn_id);
   4882 			assert(np != np_orig);
   4883 
   4884 			if (np == NULL) {
   4885 				rc = REP_PROTOCOL_FAIL_DELETED;
   4886 				goto fail;
   4887 			}
   4888 			(void) pthread_mutex_lock(&np->rn_lock);
   4889 			continue;
   4890 		}
   4891 
   4892 		if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   4893 			rc_node_rele_locked(np);
   4894 			rc_node_clear(npp, 1);
   4895 			rc = REP_PROTOCOL_FAIL_DELETED;
   4896 		}
   4897 
   4898 		/*
   4899 		 * Mark our parent as children changing.  this call drops our
   4900 		 * lock and the RC_NODE_USING_PARENT flag, and returns with
   4901 		 * pp's lock held
   4902 		 */
   4903 		pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
   4904 		if (pp == NULL) {
   4905 			/* our parent is gone, we're going next... */
   4906 			rc_node_rele(np);
   4907 
   4908 			rc_node_clear(npp, 1);
   4909 			rc = REP_PROTOCOL_FAIL_DELETED;
   4910 			goto cleanout;
   4911 		}
   4912 
   4913 		rc_node_hold_locked(pp);		/* hold for later */
   4914 		(void) pthread_mutex_unlock(&pp->rn_lock);
   4915 
   4916 		(void) pthread_mutex_lock(&np->rn_lock);
   4917 		if (!(np->rn_flags & RC_NODE_OLD))
   4918 			break;			/* not old -- we're done */
   4919 
   4920 		(void) pthread_mutex_unlock(&np->rn_lock);
   4921 		(void) pthread_mutex_lock(&pp->rn_lock);
   4922 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   4923 		rc_node_rele_locked(pp);
   4924 		(void) pthread_mutex_lock(&np->rn_lock);
   4925 		continue;			/* loop around and try again */
   4926 	}
   4927 	/*
   4928 	 * Everyone out of the pool -- we grab everything but
   4929 	 * RC_NODE_USING_PARENT (including RC_NODE_DYING) to keep
   4930 	 * any changes from occurring while we are attempting to
   4931 	 * delete the node.
   4932 	 */
   4933 	if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
   4934 		(void) pthread_mutex_unlock(&np->rn_lock);
   4935 		rc = REP_PROTOCOL_FAIL_DELETED;
   4936 		goto fail;
   4937 	}
   4938 
   4939 	assert(!(np->rn_flags & RC_NODE_OLD));
   4940 
   4941 	if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
   4942 	    REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
   4943 		rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   4944 		(void) pthread_mutex_unlock(&np->rn_lock);
   4945 		goto fail;
   4946 	}
   4947 
   4948 #ifdef NATIVE_BUILD
   4949 	if (!client_is_privileged()) {
   4950 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   4951 	}
   4952 #else
   4953 	if (is_main_repository) {
   4954 		/* permission check */
   4955 		(void) pthread_mutex_unlock(&np->rn_lock);
   4956 		pcp = pc_create();
   4957 		if (pcp != NULL) {
   4958 			rc = perm_add_enabling(pcp, AUTH_MODIFY);
   4959 
   4960 			/* add .smf.modify.<type> for pgs. */
   4961 			if (rc == REP_PROTOCOL_SUCCESS && np->rn_id.rl_type ==
   4962 			    REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   4963 				const char * const auth =
   4964 				    perm_auth_for_pgtype(np->rn_type);
   4965 
   4966 				if (auth != NULL)
   4967 					rc = perm_add_enabling(pcp, auth);
   4968 			}
   4969 
   4970 			if (rc == REP_PROTOCOL_SUCCESS) {
   4971 				granted = perm_granted(pcp);
   4972 
   4973 				rc = map_granted_status(granted, pcp,
   4974 				    &audit_data.ed_auth);
   4975 				if (granted == PERM_GONE) {
   4976 					/* No need to audit if client gone. */
   4977 					pc_free(pcp);
   4978 					rc_node_rele_flag(np,
   4979 					    RC_NODE_DYING_FLAGS);
   4980 					return (rc);
   4981 				}
   4982 				if (granted == PERM_DENIED)
   4983 					audit_failure = 1;
   4984 			}
   4985 
   4986 			pc_free(pcp);
   4987 		} else {
   4988 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   4989 		}
   4990 
   4991 		(void) pthread_mutex_lock(&np->rn_lock);
   4992 	} else {
   4993 		rc = REP_PROTOCOL_SUCCESS;
   4994 	}
   4995 #endif /* NATIVE_BUILD */
   4996 
   4997 	if (rc != REP_PROTOCOL_SUCCESS) {
   4998 		rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   4999 		(void) pthread_mutex_unlock(&np->rn_lock);
   5000 		goto fail;
   5001 	}
   5002 
   5003 	ndp = uu_zalloc(sizeof (*ndp));
   5004 	if (ndp == NULL) {
   5005 		rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
   5006 		(void) pthread_mutex_unlock(&np->rn_lock);
   5007 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5008 		goto fail;
   5009 	}
   5010 
   5011 	rc_node_delete_hold(np, 1);	/* hold entire subgraph, drop lock */
   5012 
   5013 	rc = object_delete(np);
   5014 
   5015 	if (rc != REP_PROTOCOL_SUCCESS) {
   5016 		(void) pthread_mutex_lock(&np->rn_lock);
   5017 		rc_node_delete_rele(np, 1);		/* drops lock */
   5018 		uu_free(ndp);
   5019 		goto fail;
   5020 	}
   5021 
   5022 	/*
   5023 	 * Now, delicately unlink and delete the object.
   5024 	 *
   5025 	 * Create the delete notification, atomically remove
   5026 	 * from the hash table and set the NODE_DEAD flag, and
   5027 	 * remove from the parent's children list.
   5028 	 */
   5029 	rc_notify_node_delete(ndp, np); /* frees or uses ndp */
   5030 
   5031 	bp = cache_hold(np->rn_hash);
   5032 
   5033 	(void) pthread_mutex_lock(&np->rn_lock);
   5034 	cache_remove_unlocked(bp, np);
   5035 	cache_release(bp);
   5036 
   5037 	np->rn_flags |= RC_NODE_DEAD;
   5038 
   5039 	if (pp != NULL) {
   5040 		/*
   5041 		 * Remove from pp's rn_children.  This requires pp's lock,
   5042 		 * so we must drop np's lock to respect lock order.
   5043 		 */
   5044 		(void) pthread_mutex_unlock(&np->rn_lock);
   5045 		(void) pthread_mutex_lock(&pp->rn_lock);
   5046 		(void) pthread_mutex_lock(&np->rn_lock);
   5047 
   5048 		uu_list_remove(pp->rn_children, np);
   5049 
   5050 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   5051 
   5052 		(void) pthread_mutex_unlock(&pp->rn_lock);
   5053 
   5054 		np->rn_flags &= ~RC_NODE_IN_PARENT;
   5055 	}
   5056 
   5057 	/*
   5058 	 * finally, propagate death to our children (including marking
   5059 	 * them DEAD), handle notifications, and release our hold.
   5060 	 */
   5061 	rc_node_hold_locked(np);	/* hold for delete */
   5062 	rc_node_delete_children(np, 1);	/* drops DYING_FLAGS, lock, ref */
   5063 
   5064 	rc_node_clear(npp, 1);
   5065 
   5066 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   5067 	while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
   5068 		rc_pg_notify_fire(pnp);
   5069 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   5070 	rc_notify_remove_node(np);
   5071 
   5072 	rc_node_rele(np);
   5073 
   5074 	smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
   5075 	    &audit_data);
   5076 	free(audit_data.ed_auth);
   5077 	free(audit_data.ed_snapname);
   5078 	free(audit_data.ed_type);
   5079 	free(audit_data.ed_fmri);
   5080 	return (rc);
   5081 
   5082 fail:
   5083 	rc_node_rele(np);
   5084 	if (rc == REP_PROTOCOL_FAIL_DELETED)
   5085 		rc_node_clear(npp, 1);
   5086 	if (pp != NULL) {
   5087 		(void) pthread_mutex_lock(&pp->rn_lock);
   5088 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   5089 		rc_node_rele_locked(pp);	/* drop ref and lock */
   5090 	}
   5091 	if (audit_failure) {
   5092 		smf_audit_event(event_id, ADT_FAILURE,
   5093 		    ADT_FAIL_VALUE_AUTH, &audit_data);
   5094 	}
   5095 cleanout:
   5096 	free(audit_data.ed_auth);
   5097 	free(audit_data.ed_snapname);
   5098 	free(audit_data.ed_type);
   5099 	free(audit_data.ed_fmri);
   5100 	return (rc);
   5101 }
   5102 
   5103 int
   5104 rc_node_next_snaplevel(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
   5105 {
   5106 	rc_node_t *np;
   5107 	rc_node_t *cp, *pp;
   5108 	int res;
   5109 
   5110 	rc_node_clear(cpp, 0);
   5111 
   5112 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   5113 
   5114 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT &&
   5115 	    np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) {
   5116 		(void) pthread_mutex_unlock(&np->rn_lock);
   5117 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   5118 	}
   5119 
   5120 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
   5121 		if ((res = rc_node_fill_children(np,
   5122 		    REP_PROTOCOL_ENTITY_SNAPLEVEL)) != REP_PROTOCOL_SUCCESS) {
   5123 			(void) pthread_mutex_unlock(&np->rn_lock);
   5124 			return (res);
   5125 		}
   5126 
   5127 		for (cp = uu_list_first(np->rn_children);
   5128 		    cp != NULL;
   5129 		    cp = uu_list_next(np->rn_children, cp)) {
   5130 			if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
   5131 				continue;
   5132 			rc_node_hold(cp);
   5133 			break;
   5134 		}
   5135 
   5136 		(void) pthread_mutex_unlock(&np->rn_lock);
   5137 	} else {
   5138 		if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   5139 			(void) pthread_mutex_unlock(&np->rn_lock);
   5140 			rc_node_clear(npp, 1);
   5141 			return (REP_PROTOCOL_FAIL_DELETED);
   5142 		}
   5143 
   5144 		/*
   5145 		 * mark our parent as children changing.  This call drops our
   5146 		 * lock and the RC_NODE_USING_PARENT flag, and returns with
   5147 		 * pp's lock held
   5148 		 */
   5149 		pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
   5150 		if (pp == NULL) {
   5151 			/* our parent is gone, we're going next... */
   5152 
   5153 			rc_node_clear(npp, 1);
   5154 			return (REP_PROTOCOL_FAIL_DELETED);
   5155 		}
   5156 
   5157 		/*
   5158 		 * find the next snaplevel
   5159 		 */
   5160 		cp = np;
   5161 		while ((cp = uu_list_next(pp->rn_children, cp)) != NULL &&
   5162 		    cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
   5163 			;
   5164 
   5165 		/* it must match the snaplevel list */
   5166 		assert((cp == NULL && np->rn_snaplevel->rsl_next == NULL) ||
   5167 		    (cp != NULL && np->rn_snaplevel->rsl_next ==
   5168 		    cp->rn_snaplevel));
   5169 
   5170 		if (cp != NULL)
   5171 			rc_node_hold(cp);
   5172 
   5173 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   5174 
   5175 		(void) pthread_mutex_unlock(&pp->rn_lock);
   5176 	}
   5177 
   5178 	rc_node_assign(cpp, cp);
   5179 	if (cp != NULL) {
   5180 		rc_node_rele(cp);
   5181 
   5182 		return (REP_PROTOCOL_SUCCESS);
   5183 	}
   5184 	return (REP_PROTOCOL_FAIL_NOT_FOUND);
   5185 }
   5186 
   5187 /*
   5188  * This call takes a snapshot (np) and either:
   5189  *	an existing snapid (to be associated with np), or
   5190  *	a non-NULL parentp (from which a new snapshot is taken, and associated
   5191  *	    with np)
   5192  *
   5193  * To do the association, np is duplicated, the duplicate is made to
   5194  * represent the new snapid, and np is replaced with the new rc_node_t on
   5195  * np's parent's child list. np is placed on the new node's rn_former list,
   5196  * and replaces np in cache_hash (so rc_node_update() will find the new one).
   5197  *
   5198  * old_fmri and old_name point to the original snap shot's FMRI and name.
   5199  * These values are used when generating audit events.
   5200  *
   5201  * Fails with
   5202  *	_BAD_REQUEST
   5203  *	_BACKEND_READONLY
   5204  *	_DELETED
   5205  *	_NO_RESOURCES
   5206  *	_TRUNCATED
   5207  *	_TYPE_MISMATCH
   5208  */
   5209 static int
   5210 rc_attach_snapshot(
   5211 	rc_node_t *np,
   5212 	uint32_t snapid,
   5213 	rc_node_t *parentp,
   5214 	char *old_fmri,
   5215 	char *old_name)
   5216 {
   5217 	rc_node_t *np_orig;
   5218 	rc_node_t *nnp, *prev;
   5219 	rc_node_t *pp;
   5220 	int rc;
   5221 	size_t sz_out;
   5222 	perm_status_t granted;
   5223 	au_event_t event_id;
   5224 	audit_event_data_t audit_data;
   5225 
   5226 	if (parentp == NULL) {
   5227 		assert(old_fmri != NULL);
   5228 	} else {
   5229 		assert(snapid == 0);
   5230 	}
   5231 	assert(MUTEX_HELD(&np->rn_lock));
   5232 
   5233 	/* Gather the audit data. */
   5234 	/*
   5235 	 * ADT_smf_* symbols may not be defined in the /usr/include header
   5236 	 * files on the build machine.  Thus, the following if-else will
   5237 	 * not be compiled when doing native builds.
   5238 	 */
   5239 #ifndef	NATIVE_BUILD
   5240 	if (parentp == NULL) {
   5241 		event_id = ADT_smf_attach_snap;
   5242 	} else {
   5243 		event_id = ADT_smf_create_snap;
   5244 	}
   5245 #endif	/* NATIVE_BUILD */
   5246 	audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
   5247 	audit_data.ed_snapname = malloc(REP_PROTOCOL_NAME_LEN);
   5248 	if ((audit_data.ed_fmri == NULL) || (audit_data.ed_snapname == NULL)) {
   5249 		(void) pthread_mutex_unlock(&np->rn_lock);
   5250 		free(audit_data.ed_fmri);
   5251 		free(audit_data.ed_snapname);
   5252 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   5253 	}
   5254 	audit_data.ed_auth = NULL;
   5255 	if (strlcpy(audit_data.ed_snapname, np->rn_name,
   5256 	    REP_PROTOCOL_NAME_LEN) >= REP_PROTOCOL_NAME_LEN) {
   5257 		abort();
   5258 	}
   5259 	audit_data.ed_old_fmri = old_fmri;
   5260 	audit_data.ed_old_name = old_name ? old_name : "NO NAME";
   5261 
   5262 	if (parentp == NULL) {
   5263 		/*
   5264 		 * In the attach case, get the instance FMRIs of the
   5265 		 * snapshots.
   5266 		 */
   5267 		if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
   5268 		    REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
   5269 			(void) pthread_mutex_unlock(&np->rn_lock);
   5270 			free(audit_data.ed_fmri);
   5271 			free(audit_data.ed_snapname);
   5272 			return (rc);
   5273 		}
   5274 	} else {
   5275 		/*
   5276 		 * Capture the FMRI of the parent if we're actually going
   5277 		 * to take the snapshot.
   5278 		 */
   5279 		if ((rc = rc_node_get_fmri_or_fragment(parentp,
   5280 		    audit_data.ed_fmri, REP_PROTOCOL_FMRI_LEN, &sz_out)) !=
   5281 		    REP_PROTOCOL_SUCCESS) {
   5282 			(void) pthread_mutex_unlock(&np->rn_lock);
   5283 			free(audit_data.ed_fmri);
   5284 			free(audit_data.ed_snapname);
   5285 			return (rc);
   5286 		}
   5287 	}
   5288 
   5289 	np_orig = np;
   5290 	rc_node_hold_locked(np);		/* simplifies the remainder */
   5291 
   5292 	(void) pthread_mutex_unlock(&np->rn_lock);
   5293 	granted = rc_node_modify_permission_check(&audit_data.ed_auth);
   5294 	switch (granted) {
   5295 	case PERM_DENIED:
   5296 		smf_audit_event(event_id, ADT_FAILURE, ADT_FAIL_VALUE_AUTH,
   5297 		    &audit_data);
   5298 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   5299 		rc_node_rele(np);
   5300 		goto cleanout;
   5301 	case PERM_GRANTED:
   5302 		break;
   5303 	case PERM_GONE:
   5304 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   5305 		rc_node_rele(np);
   5306 		goto cleanout;
   5307 	case PERM_FAIL:
   5308 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5309 		rc_node_rele(np);
   5310 		goto cleanout;
   5311 	default:
   5312 		bad_error(rc_node_modify_permission_check, granted);
   5313 	}
   5314 	(void) pthread_mutex_lock(&np->rn_lock);
   5315 
   5316 	/*
   5317 	 * get the latest node, holding RC_NODE_IN_TX to keep the rn_former
   5318 	 * list from changing.
   5319 	 */
   5320 	for (;;) {
   5321 		if (!(np->rn_flags & RC_NODE_OLD)) {
   5322 			if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   5323 				goto again;
   5324 			}
   5325 			pp = rc_node_hold_parent_flag(np,
   5326 			    RC_NODE_CHILDREN_CHANGING);
   5327 
   5328 			(void) pthread_mutex_lock(&np->rn_lock);
   5329 			if (pp == NULL) {
   5330 				goto again;
   5331 			}
   5332 			if (np->rn_flags & RC_NODE_OLD) {
   5333 				rc_node_rele_flag(pp,
   5334 				    RC_NODE_CHILDREN_CHANGING);
   5335 				(void) pthread_mutex_unlock(&pp->rn_lock);
   5336 				goto again;
   5337 			}
   5338 			(void) pthread_mutex_unlock(&pp->rn_lock);
   5339 
   5340 			if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
   5341 				/*
   5342 				 * Can't happen, since we're holding our
   5343 				 * parent's CHILDREN_CHANGING flag...
   5344 				 */
   5345 				abort();
   5346 			}
   5347 			break;			/* everything's ready */
   5348 		}
   5349 again:
   5350 		rc_node_rele_locked(np);
   5351 		np = cache_lookup(&np_orig->rn_id);
   5352 
   5353 		if (np == NULL) {
   5354 			rc = REP_PROTOCOL_FAIL_DELETED;
   5355 			goto cleanout;
   5356 		}
   5357 
   5358 		(void) pthread_mutex_lock(&np->rn_lock);
   5359 	}
   5360 
   5361 	if (parentp != NULL) {
   5362 		if (pp != parentp) {
   5363 			rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
   5364 			goto fail;
   5365 		}
   5366 		nnp = NULL;
   5367 	} else {
   5368 		/*
   5369 		 * look for a former node with the snapid we need.
   5370 		 */
   5371 		if (np->rn_snapshot_id == snapid) {
   5372 			rc_node_rele_flag(np, RC_NODE_IN_TX);
   5373 			rc_node_rele_locked(np);
   5374 
   5375 			(void) pthread_mutex_lock(&pp->rn_lock);
   5376 			rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   5377 			(void) pthread_mutex_unlock(&pp->rn_lock);
   5378 			rc = REP_PROTOCOL_SUCCESS;	/* nothing to do */
   5379 			goto cleanout;
   5380 		}
   5381 
   5382 		prev = np;
   5383 		while ((nnp = prev->rn_former) != NULL) {
   5384 			if (nnp->rn_snapshot_id == snapid) {
   5385 				rc_node_hold(nnp);
   5386 				break;		/* existing node with that id */
   5387 			}
   5388 			prev = nnp;
   5389 		}
   5390 	}
   5391 
   5392 	if (nnp == NULL) {
   5393 		prev = NULL;
   5394 		nnp = rc_node_alloc();
   5395 		if (nnp == NULL) {
   5396 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5397 			goto fail;
   5398 		}
   5399 
   5400 		nnp->rn_id = np->rn_id;		/* structure assignment */
   5401 		nnp->rn_hash = np->rn_hash;
   5402 		nnp->rn_name = strdup(np->rn_name);
   5403 		nnp->rn_snapshot_id = snapid;
   5404 		nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
   5405 
   5406 		if (nnp->rn_name == NULL) {
   5407 			rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5408 			goto fail;
   5409 		}
   5410 	}
   5411 
   5412 	(void) pthread_mutex_unlock(&np->rn_lock);
   5413 
   5414 	rc = object_snapshot_attach(&np->rn_id, &snapid, (parentp != NULL));
   5415 
   5416 	if (parentp != NULL)
   5417 		nnp->rn_snapshot_id = snapid;	/* fill in new snapid */
   5418 	else
   5419 		assert(nnp->rn_snapshot_id == snapid);
   5420 
   5421 	(void) pthread_mutex_lock(&np->rn_lock);
   5422 	if (rc != REP_PROTOCOL_SUCCESS)
   5423 		goto fail;
   5424 
   5425 	/*
   5426 	 * fix up the former chain
   5427 	 */
   5428 	if (prev != NULL) {
   5429 		prev->rn_former = nnp->rn_former;
   5430 		(void) pthread_mutex_lock(&nnp->rn_lock);
   5431 		nnp->rn_flags &= ~RC_NODE_ON_FORMER;
   5432 		nnp->rn_former = NULL;
   5433 		(void) pthread_mutex_unlock(&nnp->rn_lock);
   5434 	}
   5435 	np->rn_flags |= RC_NODE_OLD;
   5436 	(void) pthread_mutex_unlock(&np->rn_lock);
   5437 
   5438 	/*
   5439 	 * replace np with nnp
   5440 	 */
   5441 	rc_node_relink_child(pp, np, nnp);
   5442 
   5443 	rc_node_rele(np);
   5444 	smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, &audit_data);
   5445 	rc = REP_PROTOCOL_SUCCESS;
   5446 
   5447 cleanout:
   5448 	free(audit_data.ed_auth);
   5449 	free(audit_data.ed_fmri);
   5450 	free(audit_data.ed_snapname);
   5451 	return (rc);
   5452 
   5453 fail:
   5454 	rc_node_rele_flag(np, RC_NODE_IN_TX);
   5455 	rc_node_rele_locked(np);
   5456 	(void) pthread_mutex_lock(&pp->rn_lock);
   5457 	rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   5458 	(void) pthread_mutex_unlock(&pp->rn_lock);
   5459 
   5460 	if (nnp != NULL) {
   5461 		if (prev == NULL)
   5462 			rc_node_destroy(nnp);
   5463 		else
   5464 			rc_node_rele(nnp);
   5465 	}
   5466 
   5467 	free(audit_data.ed_auth);
   5468 	free(audit_data.ed_fmri);
   5469 	free(audit_data.ed_snapname);
   5470 	return (rc);
   5471 }
   5472 
   5473 int
   5474 rc_snapshot_take_new(rc_node_ptr_t *npp, const char *svcname,
   5475     const char *instname, const char *name, rc_node_ptr_t *outpp)
   5476 {
   5477 	perm_status_t granted;
   5478 	rc_node_t *np;
   5479 	rc_node_t *outp = NULL;
   5480 	int rc, perm_rc;
   5481 	char fmri[REP_PROTOCOL_FMRI_LEN];
   5482 	audit_event_data_t audit_data;
   5483 	size_t sz_out;
   5484 
   5485 	rc_node_clear(outpp, 0);
   5486 
   5487 	/*
   5488 	 * rc_node_modify_permission_check() must be called before the node
   5489 	 * is locked.  This is because the library functions that check
   5490 	 * authorizations can trigger calls back into configd.
   5491 	 */
   5492 	granted = rc_node_modify_permission_check(&audit_data.ed_auth);
   5493 	switch (granted) {
   5494 	case PERM_DENIED:
   5495 		/*
   5496 		 * We continue in this case, so that we can generate an
   5497 		 * audit event later in this function.
   5498 		 */
   5499 		perm_rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   5500 		break;
   5501 	case PERM_GRANTED:
   5502 		perm_rc = REP_PROTOCOL_SUCCESS;
   5503 		break;
   5504 	case PERM_GONE:
   5505 		/* No need to produce audit event if client is gone. */
   5506 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   5507 	case PERM_FAIL:
   5508 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   5509 	default:
   5510 		bad_error("rc_node_modify_permission_check", granted);
   5511 		break;
   5512 	}
   5513 
   5514 	RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
   5515 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
   5516 		(void) pthread_mutex_unlock(&np->rn_lock);
   5517 		free(audit_data.ed_auth);
   5518 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   5519 	}
   5520 
   5521 	rc = rc_check_type_name(REP_PROTOCOL_ENTITY_SNAPSHOT, name);
   5522 	if (rc != REP_PROTOCOL_SUCCESS) {
   5523 		(void) pthread_mutex_unlock(&np->rn_lock);
   5524 		free(audit_data.ed_auth);
   5525 		return (rc);
   5526 	}
   5527 
   5528 	if (svcname != NULL && (rc =
   5529 	    rc_check_type_name(REP_PROTOCOL_ENTITY_SERVICE, svcname)) !=
   5530 	    REP_PROTOCOL_SUCCESS) {
   5531 		(void) pthread_mutex_unlock(&np->rn_lock);
   5532 		free(audit_data.ed_auth);
   5533 		return (rc);
   5534 	}
   5535 
   5536 	if (instname != NULL && (rc =
   5537 	    rc_check_type_name(REP_PROTOCOL_ENTITY_INSTANCE, instname)) !=
   5538 	    REP_PROTOCOL_SUCCESS) {
   5539 		(void) pthread_mutex_unlock(&np->rn_lock);
   5540 		free(audit_data.ed_auth);
   5541 		return (rc);
   5542 	}
   5543 
   5544 	audit_data.ed_fmri = fmri;
   5545 	audit_data.ed_snapname = (char *)name;
   5546 
   5547 	if ((rc = rc_node_get_fmri_or_fragment(np, fmri, sizeof (fmri),
   5548 	    &sz_out)) != REP_PROTOCOL_SUCCESS) {
   5549 		(void) pthread_mutex_unlock(&np->rn_lock);
   5550 		free(audit_data.ed_auth);
   5551 		return (rc);
   5552 	}
   5553 	if (perm_rc != REP_PROTOCOL_SUCCESS) {
   5554 		(void) pthread_mutex_unlock(&np->rn_lock);
   5555 		smf_audit_event(ADT_smf_create_snap, ADT_FAILURE,
   5556 		    ADT_FAIL_VALUE_AUTH, &audit_data);
   5557 		free(audit_data.ed_auth);
   5558 		return (perm_rc);
   5559 	}
   5560 
   5561 	HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
   5562 	    audit_data.ed_auth);
   5563 	(void) pthread_mutex_unlock(&np->rn_lock);
   5564 
   5565 	rc = object_snapshot_take_new(np, svcname, instname, name, &outp);
   5566 
   5567 	if (rc == REP_PROTOCOL_SUCCESS) {
   5568 		rc_node_assign(outpp, outp);
   5569 		rc_node_rele(outp);
   5570 	}
   5571 
   5572 	(void) pthread_mutex_lock(&np->rn_lock);
   5573 	rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
   5574 	(void) pthread_mutex_unlock(&np->rn_lock);
   5575 
   5576 	if (rc == REP_PROTOCOL_SUCCESS) {
   5577 		smf_audit_event(ADT_smf_create_snap, ADT_SUCCESS, ADT_SUCCESS,
   5578 		    &audit_data);
   5579 	}
   5580 	if (audit_data.ed_auth != NULL)
   5581 		free(audit_data.ed_auth);
   5582 	return (rc);
   5583 }
   5584 
   5585 int
   5586 rc_snapshot_take_attach(rc_node_ptr_t *npp, rc_node_ptr_t *outpp)
   5587 {
   5588 	rc_node_t *np, *outp;
   5589 
   5590 	RC_NODE_PTR_GET_CHECK(np, npp);
   5591 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
   5592 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   5593 	}
   5594 
   5595 	RC_NODE_PTR_GET_CHECK_AND_LOCK(outp, outpp);
   5596 	if (outp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
   5597 		(void) pthread_mutex_unlock(&outp->rn_lock);
   5598 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   5599 	}
   5600 
   5601 	return (rc_attach_snapshot(outp, 0, np, NULL,
   5602 	    NULL));					/* drops outp's lock */
   5603 }
   5604 
   5605 int
   5606 rc_snapshot_attach(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
   5607 {
   5608 	rc_node_t *np;
   5609 	rc_node_t *cp;
   5610 	uint32_t snapid;
   5611 	char old_name[REP_PROTOCOL_NAME_LEN];
   5612 	int rc;
   5613 	size_t sz_out;
   5614 	char old_fmri[REP_PROTOCOL_FMRI_LEN];
   5615 
   5616 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   5617 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
   5618 		(void) pthread_mutex_unlock(&np->rn_lock);
   5619 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   5620 	}
   5621 	snapid = np->rn_snapshot_id;
   5622 	rc = rc_node_get_fmri_or_fragment(np, old_fmri, sizeof (old_fmri),
   5623 	    &sz_out);
   5624 	(void) pthread_mutex_unlock(&np->rn_lock);
   5625 	if (rc != REP_PROTOCOL_SUCCESS)
   5626 		return (rc);
   5627 	if (np->rn_name != NULL) {
   5628 		if (strlcpy(old_name, np->rn_name, sizeof (old_name)) >=
   5629 		    sizeof (old_name)) {
   5630 			return (REP_PROTOCOL_FAIL_TRUNCATED);
   5631 		}
   5632 	}
   5633 
   5634 	RC_NODE_PTR_GET_CHECK_AND_LOCK(cp, cpp);
   5635 	if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
   5636 		(void) pthread_mutex_unlock(&cp->rn_lock);
   5637 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   5638 	}
   5639 
   5640 	rc = rc_attach_snapshot(cp, snapid, NULL,
   5641 	    old_fmri, old_name);			/* drops cp's lock */
   5642 	return (rc);
   5643 }
   5644 
   5645 /*
   5646  * If the pgname property group under ent has type pgtype, and it has a
   5647  * propname property with type ptype, return _SUCCESS.  If pgtype is NULL,
   5648  * it is not checked.  If ent is not a service node, we will return _SUCCESS if
   5649  * a property meeting the requirements exists in either the instance or its
   5650  * parent.
   5651  *
   5652  * Returns
   5653  *   _SUCCESS - see above
   5654  *   _DELETED - ent or one of its ancestors was deleted
   5655  *   _NO_RESOURCES - no resources
   5656  *   _NOT_FOUND - no matching property was found
   5657  */
   5658 static int
   5659 rc_svc_prop_exists(rc_node_t *ent, const char *pgname, const char *pgtype,
   5660     const char *propname, rep_protocol_value_type_t ptype)
   5661 {
   5662 	int ret;
   5663 	rc_node_t *pg = NULL, *spg = NULL, *svc, *prop;
   5664 
   5665 	assert(!MUTEX_HELD(&ent->rn_lock));
   5666 
   5667 	(void) pthread_mutex_lock(&ent->rn_lock);
   5668 	ret = rc_node_find_named_child(ent, pgname,
   5669 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
   5670 	(void) pthread_mutex_unlock(&ent->rn_lock);
   5671 
   5672 	switch (ret) {
   5673 	case REP_PROTOCOL_SUCCESS:
   5674 		break;
   5675 
   5676 	case REP_PROTOCOL_FAIL_DELETED:
   5677 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
   5678 		return (ret);
   5679 
   5680 	default:
   5681 		bad_error("rc_node_find_named_child", ret);
   5682 	}
   5683 
   5684 	if (ent->rn_id.rl_type != REP_PROTOCOL_ENTITY_SERVICE) {
   5685 		ret = rc_node_find_ancestor(ent, REP_PROTOCOL_ENTITY_SERVICE,
   5686 		    &svc);
   5687 		if (ret != REP_PROTOCOL_SUCCESS) {
   5688 			assert(ret == REP_PROTOCOL_FAIL_DELETED);
   5689 			if (pg != NULL)
   5690 				rc_node_rele(pg);
   5691 			return (ret);
   5692 		}
   5693 		assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
   5694 
   5695 		(void) pthread_mutex_lock(&svc->rn_lock);
   5696 		ret = rc_node_find_named_child(svc, pgname,
   5697 		    REP_PROTOCOL_ENTITY_PROPERTYGRP, &spg);
   5698 		(void) pthread_mutex_unlock(&svc->rn_lock);
   5699 
   5700 		rc_node_rele(svc);
   5701 
   5702 		switch (ret) {
   5703 		case REP_PROTOCOL_SUCCESS:
   5704 			break;
   5705 
   5706 		case REP_PROTOCOL_FAIL_DELETED:
   5707 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
   5708 			if (pg != NULL)
   5709 				rc_node_rele(pg);
   5710 			return (ret);
   5711 
   5712 		default:
   5713 			bad_error("rc_node_find_named_child", ret);
   5714 		}
   5715 	}
   5716 
   5717 	if (pg != NULL &&
   5718 	    pgtype != NULL && strcmp(pg->rn_type, pgtype) != 0) {
   5719 		rc_node_rele(pg);
   5720 		pg = NULL;
   5721 	}
   5722 
   5723 	if (spg != NULL &&
   5724 	    pgtype != NULL && strcmp(spg->rn_type, pgtype) != 0) {
   5725 		rc_node_rele(spg);
   5726 		spg = NULL;
   5727 	}
   5728 
   5729 	if (pg == NULL) {
   5730 		if (spg == NULL)
   5731 			return (REP_PROTOCOL_FAIL_NOT_FOUND);
   5732 		pg = spg;
   5733 		spg = NULL;
   5734 	}
   5735 
   5736 	/*
   5737 	 * At this point, pg is non-NULL, and is a property group node of the
   5738 	 * correct type.  spg, if non-NULL, is also a property group node of
   5739 	 * the correct type.  Check for the property in pg first, then spg
   5740 	 * (if applicable).
   5741 	 */
   5742 	(void) pthread_mutex_lock(&pg->rn_lock);
   5743 	ret = rc_node_find_named_child(pg, propname,
   5744 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop);
   5745 	(void) pthread_mutex_unlock(&pg->rn_lock);
   5746 	rc_node_rele(pg);
   5747 	switch (ret) {
   5748 	case REP_PROTOCOL_SUCCESS:
   5749 		if (prop != NULL) {
   5750 			if (prop->rn_valtype == ptype) {
   5751 				rc_node_rele(prop);
   5752 				if (spg != NULL)
   5753 					rc_node_rele(spg);
   5754 				return (REP_PROTOCOL_SUCCESS);
   5755 			}
   5756 			rc_node_rele(prop);
   5757 		}
   5758 		break;
   5759 
   5760 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
   5761 		if (spg != NULL)
   5762 			rc_node_rele(spg);
   5763 		return (ret);
   5764 
   5765 	case REP_PROTOCOL_FAIL_DELETED:
   5766 		break;
   5767 
   5768 	default:
   5769 		bad_error("rc_node_find_named_child", ret);
   5770 	}
   5771 
   5772 	if (spg == NULL)
   5773 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   5774 
   5775 	pg = spg;
   5776 
   5777 	(void) pthread_mutex_lock(&pg->rn_lock);
   5778 	ret = rc_node_find_named_child(pg, propname,
   5779 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop);
   5780 	(void) pthread_mutex_unlock(&pg->rn_lock);
   5781 	rc_node_rele(pg);
   5782 	switch (ret) {
   5783 	case REP_PROTOCOL_SUCCESS:
   5784 		if (prop != NULL) {
   5785 			if (prop->rn_valtype == ptype) {
   5786 				rc_node_rele(prop);
   5787 				return (REP_PROTOCOL_SUCCESS);
   5788 			}
   5789 			rc_node_rele(prop);
   5790 		}
   5791 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   5792 
   5793 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
   5794 		return (ret);
   5795 
   5796 	case REP_PROTOCOL_FAIL_DELETED:
   5797 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   5798 
   5799 	default:
   5800 		bad_error("rc_node_find_named_child", ret);
   5801 	}
   5802 
   5803 	return (REP_PROTOCOL_SUCCESS);
   5804 }
   5805 
   5806 /*
   5807  * Given a property group node, returns _SUCCESS if the property group may
   5808  * be read without any special authorization.
   5809  *
   5810  * Fails with:
   5811  *   _DELETED - np or an ancestor node was deleted
   5812  *   _TYPE_MISMATCH - np does not refer to a property group
   5813  *   _NO_RESOURCES - no resources
   5814  *   _PERMISSION_DENIED - authorization is required
   5815  */
   5816 static int
   5817 rc_node_pg_check_read_protect(rc_node_t *np)
   5818 {
   5819 	int ret;
   5820 	rc_node_t *ent;
   5821 
   5822 	assert(!MUTEX_HELD(&np->rn_lock));
   5823 
   5824 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
   5825 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   5826 
   5827 	if (strcmp(np->rn_type, SCF_GROUP_FRAMEWORK) == 0 ||
   5828 	    strcmp(np->rn_type, SCF_GROUP_DEPENDENCY) == 0 ||
   5829 	    strcmp(np->rn_type, SCF_GROUP_METHOD) == 0)
   5830 		return (REP_PROTOCOL_SUCCESS);
   5831 
   5832 	ret = rc_node_parent(np, &ent);
   5833 
   5834 	if (ret != REP_PROTOCOL_SUCCESS)
   5835 		return (ret);
   5836 
   5837 	ret = rc_svc_prop_exists(ent, np->rn_name, np->rn_type,
   5838 	    AUTH_PROP_READ, REP_PROTOCOL_TYPE_STRING);
   5839 
   5840 	rc_node_rele(ent);
   5841 
   5842 	switch (ret) {
   5843 	case REP_PROTOCOL_FAIL_NOT_FOUND:
   5844 		return (REP_PROTOCOL_SUCCESS);
   5845 	case REP_PROTOCOL_SUCCESS:
   5846 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   5847 	case REP_PROTOCOL_FAIL_DELETED:
   5848 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
   5849 		return (ret);
   5850 	default:
   5851 		bad_error("rc_svc_prop_exists", ret);
   5852 	}
   5853 
   5854 	return (REP_PROTOCOL_SUCCESS);
   5855 }
   5856 
   5857 /*
   5858  * Fails with
   5859  *   _DELETED - np's node or parent has been deleted
   5860  *   _TYPE_MISMATCH - np's node is not a property
   5861  *   _NO_RESOURCES - out of memory
   5862  *   _PERMISSION_DENIED - no authorization to read this property's value(s)
   5863  *   _BAD_REQUEST - np's parent is not a property group
   5864  */
   5865 static int
   5866 rc_node_property_may_read(rc_node_t *np)
   5867 {
   5868 	int ret;
   5869 	perm_status_t granted = PERM_DENIED;
   5870 	rc_node_t *pgp;
   5871 	permcheck_t *pcp;
   5872 	audit_event_data_t audit_data;
   5873 	size_t sz_out;
   5874 
   5875 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
   5876 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   5877 
   5878 	if (client_is_privileged())
   5879 		return (REP_PROTOCOL_SUCCESS);
   5880 
   5881 #ifdef NATIVE_BUILD
   5882 	return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   5883 #else
   5884 	ret = rc_node_parent(np, &pgp);
   5885 
   5886 	if (ret != REP_PROTOCOL_SUCCESS)
   5887 		return (ret);
   5888 
   5889 	if (pgp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   5890 		rc_node_rele(pgp);
   5891 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   5892 	}
   5893 
   5894 	ret = rc_node_pg_check_read_protect(pgp);
   5895 
   5896 	if (ret != REP_PROTOCOL_FAIL_PERMISSION_DENIED) {
   5897 		rc_node_rele(pgp);
   5898 		return (ret);
   5899 	}
   5900 
   5901 	pcp = pc_create();
   5902 
   5903 	if (pcp == NULL) {
   5904 		rc_node_rele(pgp);
   5905 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   5906 	}
   5907 
   5908 	ret = perm_add_enabling(pcp, AUTH_MODIFY);
   5909 
   5910 	if (ret == REP_PROTOCOL_SUCCESS) {
   5911 		const char * const auth =
   5912 		    perm_auth_for_pgtype(pgp->rn_type);
   5913 
   5914 		if (auth != NULL)
   5915 			ret = perm_add_enabling(pcp, auth);
   5916 	}
   5917 
   5918 	/*
   5919 	 * If you are permitted to modify the value, you may also
   5920 	 * read it.  This means that both the MODIFY and VALUE
   5921 	 * authorizations are acceptable.  We don't allow requests
   5922 	 * for AUTH_PROP_MODIFY if all you have is $AUTH_PROP_VALUE,
   5923 	 * however, to avoid leaking possibly valuable information
   5924 	 * since such a user can't change the property anyway.
   5925 	 */
   5926 	if (ret == REP_PROTOCOL_SUCCESS)
   5927 		ret = perm_add_enabling_values(pcp, pgp,
   5928 		    AUTH_PROP_MODIFY);
   5929 
   5930 	if (ret == REP_PROTOCOL_SUCCESS &&
   5931 	    strcmp(np->rn_name, AUTH_PROP_MODIFY) != 0)
   5932 		ret = perm_add_enabling_values(pcp, pgp,
   5933 		    AUTH_PROP_VALUE);
   5934 
   5935 	if (ret == REP_PROTOCOL_SUCCESS)
   5936 		ret = perm_add_enabling_values(pcp, pgp,
   5937 		    AUTH_PROP_READ);
   5938 
   5939 	rc_node_rele(pgp);
   5940 
   5941 	if (ret == REP_PROTOCOL_SUCCESS) {
   5942 		granted = perm_granted(pcp);
   5943 		if (granted == PERM_FAIL)
   5944 			ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5945 		if (granted == PERM_GONE)
   5946 			ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   5947 	}
   5948 
   5949 	if (ret == REP_PROTOCOL_SUCCESS) {
   5950 		/* Generate a read_prop audit event. */
   5951 		audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
   5952 		if (audit_data.ed_fmri == NULL)
   5953 			ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
   5954 	}
   5955 	if (ret == REP_PROTOCOL_SUCCESS) {
   5956 		ret = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
   5957 		    REP_PROTOCOL_FMRI_LEN, &sz_out);
   5958 	}
   5959 	if (ret == REP_PROTOCOL_SUCCESS) {
   5960 		int status;
   5961 		int ret_value;
   5962 
   5963 		if (granted == PERM_DENIED) {
   5964 			status = ADT_FAILURE;
   5965 			ret_value = ADT_FAIL_VALUE_AUTH;
   5966 		} else {
   5967 			status = ADT_SUCCESS;
   5968 			ret_value = ADT_SUCCESS;
   5969 		}
   5970 		audit_data.ed_auth = pcp->pc_auth_string;
   5971 		smf_audit_event(ADT_smf_read_prop,
   5972 		    status, ret_value, &audit_data);
   5973 	}
   5974 	free(audit_data.ed_fmri);
   5975 
   5976 	pc_free(pcp);
   5977 
   5978 	if ((ret == REP_PROTOCOL_SUCCESS) && (granted == PERM_DENIED))
   5979 		ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   5980 
   5981 	return (ret);
   5982 #endif	/* NATIVE_BUILD */
   5983 }
   5984 
   5985 /*
   5986  * Iteration
   5987  */
   5988 static int
   5989 rc_iter_filter_name(rc_node_t *np, void *s)
   5990 {
   5991 	const char *name = s;
   5992 
   5993 	return (strcmp(np->rn_name, name) == 0);
   5994 }
   5995 
   5996 static int
   5997 rc_iter_filter_type(rc_node_t *np, void *s)
   5998 {
   5999 	const char *type = s;
   6000 
   6001 	return (np->rn_type != NULL && strcmp(np->rn_type, type) == 0);
   6002 }
   6003 
   6004 /*ARGSUSED*/
   6005 static int
   6006 rc_iter_null_filter(rc_node_t *np, void *s)
   6007 {
   6008 	return (1);
   6009 }
   6010 
   6011 /*
   6012  * Allocate & initialize an rc_node_iter_t structure.  Essentially, ensure
   6013  * np->rn_children is populated and call uu_list_walk_start(np->rn_children).
   6014  * If successful, leaves a hold on np & increments np->rn_other_refs
   6015  *
   6016  * If composed is true, then set up for iteration across the top level of np's
   6017  * composition chain.  If successful, leaves a hold on np and increments
   6018  * rn_other_refs for the top level of np's composition chain.
   6019  *
   6020  * Fails with
   6021  *   _NO_RESOURCES
   6022  *   _INVALID_TYPE
   6023  *   _TYPE_MISMATCH - np cannot carry type children
   6024  *   _DELETED
   6025  */
   6026 static int
   6027 rc_iter_create(rc_node_iter_t **resp, rc_node_t *np, uint32_t type,
   6028     rc_iter_filter_func *filter, void *arg, boolean_t composed)
   6029 {
   6030 	rc_node_iter_t *nip;
   6031 	int res;
   6032 
   6033 	assert(*resp == NULL);
   6034 
   6035 	nip = uu_zalloc(sizeof (*nip));
   6036 	if (nip == NULL)
   6037 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6038 
   6039 	/* np is held by the client's rc_node_ptr_t */
   6040 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
   6041 		composed = 1;
   6042 
   6043 	if (!composed) {
   6044 		(void) pthread_mutex_lock(&np->rn_lock);
   6045 
   6046 		if ((res = rc_node_fill_children(np, type)) !=
   6047 		    REP_PROTOCOL_SUCCESS) {
   6048 			(void) pthread_mutex_unlock(&np->rn_lock);
   6049 			uu_free(nip);
   6050 			return (res);
   6051 		}
   6052 
   6053 		nip->rni_clevel = -1;
   6054 
   6055 		nip->rni_iter = uu_list_walk_start(np->rn_children,
   6056 		    UU_WALK_ROBUST);
   6057 		if (nip->rni_iter != NULL) {
   6058 			nip->rni_iter_node = np;
   6059 			rc_node_hold_other(np);
   6060 		} else {
   6061 			(void) pthread_mutex_unlock(&np->rn_lock);
   6062 			uu_free(nip);
   6063 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6064 		}
   6065 		(void) pthread_mutex_unlock(&np->rn_lock);
   6066 	} else {
   6067 		rc_node_t *ent;
   6068 
   6069 		if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
   6070 			/* rn_cchain isn't valid until children are loaded. */
   6071 			(void) pthread_mutex_lock(&np->rn_lock);
   6072 			res = rc_node_fill_children(np,
   6073 			    REP_PROTOCOL_ENTITY_SNAPLEVEL);
   6074 			(void) pthread_mutex_unlock(&np->rn_lock);
   6075 			if (res != REP_PROTOCOL_SUCCESS) {
   6076 				uu_free(nip);
   6077 				return (res);
   6078 			}
   6079 
   6080 			/* Check for an empty snapshot. */
   6081 			if (np->rn_cchain[0] == NULL)
   6082 				goto empty;
   6083 		}
   6084 
   6085 		/* Start at the top of the composition chain. */
   6086 		for (nip->rni_clevel = 0; ; ++nip->rni_clevel) {
   6087 			if (nip->rni_clevel >= COMPOSITION_DEPTH) {
   6088 				/* Empty composition chain. */
   6089 empty:
   6090 				nip->rni_clevel = -1;
   6091 				nip->rni_iter = NULL;
   6092 				/* It's ok, iter_next() will return _DONE. */
   6093 				goto out;
   6094 			}
   6095 
   6096 			ent = np->rn_cchain[nip->rni_clevel];
   6097 			assert(ent != NULL);
   6098 
   6099 			if (rc_node_check_and_lock(ent) == REP_PROTOCOL_SUCCESS)
   6100 				break;
   6101 
   6102 			/* Someone deleted it, so try the next one. */
   6103 		}
   6104 
   6105 		res = rc_node_fill_children(ent, type);
   6106 
   6107 		if (res == REP_PROTOCOL_SUCCESS) {
   6108 			nip->rni_iter = uu_list_walk_start(ent->rn_children,
   6109 			    UU_WALK_ROBUST);
   6110 
   6111 			if (nip->rni_iter == NULL)
   6112 				res = REP_PROTOCOL_FAIL_NO_RESOURCES;
   6113 			else {
   6114 				nip->rni_iter_node = ent;
   6115 				rc_node_hold_other(ent);
   6116 			}
   6117 		}
   6118 
   6119 		if (res != REP_PROTOCOL_SUCCESS) {
   6120 			(void) pthread_mutex_unlock(&ent->rn_lock);
   6121 			uu_free(nip);
   6122 			return (res);
   6123 		}
   6124 
   6125 		(void) pthread_mutex_unlock(&ent->rn_lock);
   6126 	}
   6127 
   6128 out:
   6129 	rc_node_hold(np);		/* released by rc_iter_end() */
   6130 	nip->rni_parent = np;
   6131 	nip->rni_type = type;
   6132 	nip->rni_filter = (filter != NULL)? filter : rc_iter_null_filter;
   6133 	nip->rni_filter_arg = arg;
   6134 	*resp = nip;
   6135 	return (REP_PROTOCOL_SUCCESS);
   6136 }
   6137 
   6138 static void
   6139 rc_iter_end(rc_node_iter_t *iter)
   6140 {
   6141 	rc_node_t *np = iter->rni_parent;
   6142 
   6143 	if (iter->rni_clevel >= 0)
   6144 		np = np->rn_cchain[iter->rni_clevel];
   6145 
   6146 	assert(MUTEX_HELD(&np->rn_lock));
   6147 	if (iter->rni_iter != NULL)
   6148 		uu_list_walk_end(iter->rni_iter);
   6149 	iter->rni_iter = NULL;
   6150 
   6151 	(void) pthread_mutex_unlock(&np->rn_lock);
   6152 	rc_node_rele(iter->rni_parent);
   6153 	if (iter->rni_iter_node != NULL)
   6154 		rc_node_rele_other(iter->rni_iter_node);
   6155 }
   6156 
   6157 /*
   6158  * Fails with
   6159  *   _NOT_SET - npp is reset
   6160  *   _DELETED - npp's node has been deleted
   6161  *   _NOT_APPLICABLE - npp's node is not a property
   6162  *   _NO_RESOURCES - out of memory
   6163  */
   6164 static int
   6165 rc_node_setup_value_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp)
   6166 {
   6167 	rc_node_t *np;
   6168 
   6169 	rc_node_iter_t *nip;
   6170 
   6171 	assert(*iterp == NULL);
   6172 
   6173 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   6174 
   6175 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
   6176 		(void) pthread_mutex_unlock(&np->rn_lock);
   6177 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   6178 	}
   6179 
   6180 	nip = uu_zalloc(sizeof (*nip));
   6181 	if (nip == NULL) {
   6182 		(void) pthread_mutex_unlock(&np->rn_lock);
   6183 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6184 	}
   6185 
   6186 	nip->rni_parent = np;
   6187 	nip->rni_iter = NULL;
   6188 	nip->rni_clevel = -1;
   6189 	nip->rni_type = REP_PROTOCOL_ENTITY_VALUE;
   6190 	nip->rni_offset = 0;
   6191 	nip->rni_last_offset = 0;
   6192 
   6193 	rc_node_hold_locked(np);
   6194 
   6195 	*iterp = nip;
   6196 	(void) pthread_mutex_unlock(&np->rn_lock);
   6197 
   6198 	return (REP_PROTOCOL_SUCCESS);
   6199 }
   6200 
   6201 /*
   6202  * Returns:
   6203  *   _NO_RESOURCES - out of memory
   6204  *   _NOT_SET - npp is reset
   6205  *   _DELETED - npp's node has been deleted
   6206  *   _TYPE_MISMATCH - npp's node is not a property
   6207  *   _NOT_FOUND - property has no values
   6208  *   _TRUNCATED - property has >1 values (first is written into out)
   6209  *   _SUCCESS - property has 1 value (which is written into out)
   6210  *   _PERMISSION_DENIED - no authorization to read property value(s)
   6211  *
   6212  * We shorten *sz_out to not include anything after the final '\0'.
   6213  */
   6214 int
   6215 rc_node_get_property_value(rc_node_ptr_t *npp,
   6216     struct rep_protocol_value_response *out, size_t *sz_out)
   6217 {
   6218 	rc_node_t *np;
   6219 	size_t w;
   6220 	int ret;
   6221 
   6222 	assert(*sz_out == sizeof (*out));
   6223 
   6224 	RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
   6225 	ret = rc_node_property_may_read(np);
   6226 	rc_node_rele(np);
   6227 
   6228 	if (ret != REP_PROTOCOL_SUCCESS)
   6229 		return (ret);
   6230 
   6231 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   6232 
   6233 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
   6234 		(void) pthread_mutex_unlock(&np->rn_lock);
   6235 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   6236 	}
   6237 
   6238 	if (np->rn_values_size == 0) {
   6239 		(void) pthread_mutex_unlock(&np->rn_lock);
   6240 		return (REP_PROTOCOL_FAIL_NOT_FOUND);
   6241 	}
   6242 	out->rpr_type = np->rn_valtype;
   6243 	w = strlcpy(out->rpr_value, &np->rn_values[0],
   6244 	    sizeof (out->rpr_value));
   6245 
   6246 	if (w >= sizeof (out->rpr_value))
   6247 		backend_panic("value too large");
   6248 
   6249 	*sz_out = offsetof(struct rep_protocol_value_response,
   6250 	    rpr_value[w + 1]);
   6251 
   6252 	ret = (np->rn_values_count != 1)? REP_PROTOCOL_FAIL_TRUNCATED :
   6253 	    REP_PROTOCOL_SUCCESS;
   6254 	(void) pthread_mutex_unlock(&np->rn_lock);
   6255 	return (ret);
   6256 }
   6257 
   6258 int
   6259 rc_iter_next_value(rc_node_iter_t *iter,
   6260     struct rep_protocol_value_response *out, size_t *sz_out, int repeat)
   6261 {
   6262 	rc_node_t *np = iter->rni_parent;
   6263 	const char *vals;
   6264 	size_t len;
   6265 
   6266 	size_t start;
   6267 	size_t w;
   6268 	int ret;
   6269 
   6270 	rep_protocol_responseid_t result;
   6271 
   6272 	assert(*sz_out == sizeof (*out));
   6273 
   6274 	(void) memset(out, '\0', *sz_out);
   6275 
   6276 	if (iter->rni_type != REP_PROTOCOL_ENTITY_VALUE)
   6277 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6278 
   6279 	RC_NODE_CHECK(np);
   6280 	ret = rc_node_property_may_read(np);
   6281 
   6282 	if (ret != REP_PROTOCOL_SUCCESS)
   6283 		return (ret);
   6284 
   6285 	RC_NODE_CHECK_AND_LOCK(np);
   6286 
   6287 	vals = np->rn_values;
   6288 	len = np->rn_values_size;
   6289 
   6290 	out->rpr_type = np->rn_valtype;
   6291 
   6292 	start = (repeat)? iter->rni_last_offset : iter->rni_offset;
   6293 
   6294 	if (len == 0 || start >= len) {
   6295 		result = REP_PROTOCOL_DONE;
   6296 		*sz_out -= sizeof (out->rpr_value);
   6297 	} else {
   6298 		w = strlcpy(out->rpr_value, &vals[start],
   6299 		    sizeof (out->rpr_value));
   6300 
   6301 		if (w >= sizeof (out->rpr_value))
   6302 			backend_panic("value too large");
   6303 
   6304 		*sz_out = offsetof(struct rep_protocol_value_response,
   6305 		    rpr_value[w + 1]);
   6306 
   6307 		/*
   6308 		 * update the offsets if we're not repeating
   6309 		 */
   6310 		if (!repeat) {
   6311 			iter->rni_last_offset = iter->rni_offset;
   6312 			iter->rni_offset += (w + 1);
   6313 		}
   6314 
   6315 		result = REP_PROTOCOL_SUCCESS;
   6316 	}
   6317 
   6318 	(void) pthread_mutex_unlock(&np->rn_lock);
   6319 	return (result);
   6320 }
   6321 
   6322 /*
   6323  * Entry point for ITER_START from client.c.  Validate the arguments & call
   6324  * rc_iter_create().
   6325  *
   6326  * Fails with
   6327  *   _NOT_SET
   6328  *   _DELETED
   6329  *   _TYPE_MISMATCH - np cannot carry type children
   6330  *   _BAD_REQUEST - flags is invalid
   6331  *		    pattern is invalid
   6332  *   _NO_RESOURCES
   6333  *   _INVALID_TYPE
   6334  *   _TYPE_MISMATCH - *npp cannot have children of type
   6335  *   _BACKEND_ACCESS
   6336  */
   6337 int
   6338 rc_node_setup_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp,
   6339     uint32_t type, uint32_t flags, const char *pattern)
   6340 {
   6341 	rc_node_t *np;
   6342 	rc_iter_filter_func *f = NULL;
   6343 	int rc;
   6344 
   6345 	RC_NODE_PTR_GET_CHECK(np, npp);
   6346 
   6347 	if (pattern != NULL && pattern[0] == '\0')
   6348 		pattern = NULL;
   6349 
   6350 	if (type == REP_PROTOCOL_ENTITY_VALUE) {
   6351 		if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
   6352 			return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   6353 		if (flags != RP_ITER_START_ALL || pattern != NULL)
   6354 			return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6355 
   6356 		rc = rc_node_setup_value_iter(npp, iterp);
   6357 		assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
   6358 		return (rc);
   6359 	}
   6360 
   6361 	if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
   6362 	    REP_PROTOCOL_SUCCESS)
   6363 		return (rc);
   6364 
   6365 	if (((flags & RP_ITER_START_FILT_MASK) == RP_ITER_START_ALL) ^
   6366 	    (pattern == NULL))
   6367 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6368 
   6369 	/* Composition only works for instances & snapshots. */
   6370 	if ((flags & RP_ITER_START_COMPOSED) &&
   6371 	    (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE &&
   6372 	    np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT))
   6373 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6374 
   6375 	if (pattern != NULL) {
   6376 		if ((rc = rc_check_type_name(type, pattern)) !=
   6377 		    REP_PROTOCOL_SUCCESS)
   6378 			return (rc);
   6379 		pattern = strdup(pattern);
   6380 		if (pattern == NULL)
   6381 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6382 	}
   6383 
   6384 	switch (flags & RP_ITER_START_FILT_MASK) {
   6385 	case RP_ITER_START_ALL:
   6386 		f = NULL;
   6387 		break;
   6388 	case RP_ITER_START_EXACT:
   6389 		f = rc_iter_filter_name;
   6390 		break;
   6391 	case RP_ITER_START_PGTYPE:
   6392 		if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   6393 			free((void *)pattern);
   6394 			return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6395 		}
   6396 		f = rc_iter_filter_type;
   6397 		break;
   6398 	default:
   6399 		free((void *)pattern);
   6400 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6401 	}
   6402 
   6403 	rc = rc_iter_create(iterp, np, type, f, (void *)pattern,
   6404 	    flags & RP_ITER_START_COMPOSED);
   6405 	if (rc != REP_PROTOCOL_SUCCESS && pattern != NULL)
   6406 		free((void *)pattern);
   6407 
   6408 	return (rc);
   6409 }
   6410 
   6411 /*
   6412  * Do uu_list_walk_next(iter->rni_iter) until we find a child which matches
   6413  * the filter.
   6414  * For composed iterators, then check to see if there's an overlapping entity
   6415  * (see embedded comments).  If we reach the end of the list, start over at
   6416  * the next level.
   6417  *
   6418  * Returns
   6419  *   _BAD_REQUEST - iter walks values
   6420  *   _TYPE_MISMATCH - iter does not walk type entities
   6421  *   _DELETED - parent was deleted
   6422  *   _NO_RESOURCES
   6423  *   _INVALID_TYPE - type is invalid
   6424  *   _DONE
   6425  *   _SUCCESS
   6426  *
   6427  * For composed property group iterators, can also return
   6428  *   _TYPE_MISMATCH - parent cannot have type children
   6429  */
   6430 int
   6431 rc_iter_next(rc_node_iter_t *iter, rc_node_ptr_t *out, uint32_t type)
   6432 {
   6433 	rc_node_t *np = iter->rni_parent;
   6434 	rc_node_t *res;
   6435 	int rc;
   6436 
   6437 	if (iter->rni_type == REP_PROTOCOL_ENTITY_VALUE)
   6438 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   6439 
   6440 	if (iter->rni_iter == NULL) {
   6441 		rc_node_clear(out, 0);
   6442 		return (REP_PROTOCOL_DONE);
   6443 	}
   6444 
   6445 	if (iter->rni_type != type) {
   6446 		rc_node_clear(out, 0);
   6447 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   6448 	}
   6449 
   6450 	(void) pthread_mutex_lock(&np->rn_lock);  /* held by _iter_create() */
   6451 
   6452 	if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
   6453 		(void) pthread_mutex_unlock(&np->rn_lock);
   6454 		rc_node_clear(out, 1);
   6455 		return (REP_PROTOCOL_FAIL_DELETED);
   6456 	}
   6457 
   6458 	if (iter->rni_clevel >= 0) {
   6459 		/* Composed iterator.  Iterate over appropriate level. */
   6460 		(void) pthread_mutex_unlock(&np->rn_lock);
   6461 		np = np->rn_cchain[iter->rni_clevel];
   6462 		/*
   6463 		 * If iter->rni_parent is an instance or a snapshot, np must
   6464 		 * be valid since iter holds iter->rni_parent & possible
   6465 		 * levels (service, instance, snaplevel) cannot be destroyed
   6466 		 * while rni_parent is held.  If iter->rni_parent is
   6467 		 * a composed property group then rc_node_setup_cpg() put
   6468 		 * a hold on np.
   6469 		 */
   6470 
   6471 		(void) pthread_mutex_lock(&np->rn_lock);
   6472 
   6473 		if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
   6474 			(void) pthread_mutex_unlock(&np->rn_lock);
   6475 			rc_node_clear(out, 1);
   6476 			return (REP_PROTOCOL_FAIL_DELETED);
   6477 		}
   6478 	}
   6479 
   6480 	assert(np->rn_flags & RC_NODE_HAS_CHILDREN);
   6481 
   6482 	for (;;) {
   6483 		res = uu_list_walk_next(iter->rni_iter);
   6484 		if (res == NULL) {
   6485 			rc_node_t *parent = iter->rni_parent;
   6486 
   6487 #if COMPOSITION_DEPTH == 2
   6488 			if (iter->rni_clevel < 0 || iter->rni_clevel == 1) {
   6489 				/* release walker and lock */
   6490 				rc_iter_end(iter);
   6491 				break;
   6492 			}
   6493 
   6494 			/* Stop walking current level. */
   6495 			uu_list_walk_end(iter->rni_iter);
   6496 			iter->rni_iter = NULL;
   6497 			(void) pthread_mutex_unlock(&np->rn_lock);
   6498 			rc_node_rele_other(iter->rni_iter_node);
   6499 			iter->rni_iter_node = NULL;
   6500 
   6501 			/* Start walking next level. */
   6502 			++iter->rni_clevel;
   6503 			np = parent->rn_cchain[iter->rni_clevel];
   6504 			assert(np != NULL);
   6505 #else
   6506 #error This code must be updated.
   6507 #endif
   6508 
   6509 			(void) pthread_mutex_lock(&np->rn_lock);
   6510 
   6511 			rc = rc_node_fill_children(np, iter->rni_type);
   6512 
   6513 			if (rc == REP_PROTOCOL_SUCCESS) {
   6514 				iter->rni_iter =
   6515 				    uu_list_walk_start(np->rn_children,
   6516 				    UU_WALK_ROBUST);
   6517 
   6518 				if (iter->rni_iter == NULL)
   6519 					rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   6520 				else {
   6521 					iter->rni_iter_node = np;
   6522 					rc_node_hold_other(np);
   6523 				}
   6524 			}
   6525 
   6526 			if (rc != REP_PROTOCOL_SUCCESS) {
   6527 				(void) pthread_mutex_unlock(&np->rn_lock);
   6528 				rc_node_clear(out, 0);
   6529 				return (rc);
   6530 			}
   6531 
   6532 			continue;
   6533 		}
   6534 
   6535 		if (res->rn_id.rl_type != type ||
   6536 		    !iter->rni_filter(res, iter->rni_filter_arg))
   6537 			continue;
   6538 
   6539 		/*
   6540 		 * If we're composed and not at the top level, check to see if
   6541 		 * there's an entity at a higher level with the same name.  If
   6542 		 * so, skip this one.
   6543 		 */
   6544 		if (iter->rni_clevel > 0) {
   6545 			rc_node_t *ent = iter->rni_parent->rn_cchain[0];
   6546 			rc_node_t *pg;
   6547 
   6548 #if COMPOSITION_DEPTH == 2
   6549 			assert(iter->rni_clevel == 1);
   6550 
   6551 			(void) pthread_mutex_unlock(&np->rn_lock);
   6552 			(void) pthread_mutex_lock(&ent->rn_lock);
   6553 			rc = rc_node_find_named_child(ent, res->rn_name, type,
   6554 			    &pg);
   6555 			if (rc == REP_PROTOCOL_SUCCESS && pg != NULL)
   6556 				rc_node_rele(pg);
   6557 			(void) pthread_mutex_unlock(&ent->rn_lock);
   6558 			if (rc != REP_PROTOCOL_SUCCESS) {
   6559 				rc_node_clear(out, 0);
   6560 				return (rc);
   6561 			}
   6562 			(void) pthread_mutex_lock(&np->rn_lock);
   6563 
   6564 			/* Make sure np isn't being deleted all of a sudden. */
   6565 			if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
   6566 				(void) pthread_mutex_unlock(&np->rn_lock);
   6567 				rc_node_clear(out, 1);
   6568 				return (REP_PROTOCOL_FAIL_DELETED);
   6569 			}
   6570 
   6571 			if (pg != NULL)
   6572 				/* Keep going. */
   6573 				continue;
   6574 #else
   6575 #error This code must be updated.
   6576 #endif
   6577 		}
   6578 
   6579 		/*
   6580 		 * If we're composed, iterating over property groups, and not
   6581 		 * at the bottom level, check to see if there's a pg at lower
   6582 		 * level with the same name.  If so, return a cpg.
   6583 		 */
   6584 		if (iter->rni_clevel >= 0 &&
   6585 		    type == REP_PROTOCOL_ENTITY_PROPERTYGRP &&
   6586 		    iter->rni_clevel < COMPOSITION_DEPTH - 1) {
   6587 #if COMPOSITION_DEPTH == 2
   6588 			rc_node_t *pg;
   6589 			rc_node_t *ent = iter->rni_parent->rn_cchain[1];
   6590 
   6591 			rc_node_hold(res);	/* While we drop np->rn_lock */
   6592 
   6593 			(void) pthread_mutex_unlock(&np->rn_lock);
   6594 			(void) pthread_mutex_lock(&ent->rn_lock);
   6595 			rc = rc_node_find_named_child(ent, res->rn_name, type,
   6596 			    &pg);
   6597 			/* holds pg if not NULL */
   6598 			(void) pthread_mutex_unlock(&ent->rn_lock);
   6599 			if (rc != REP_PROTOCOL_SUCCESS) {
   6600 				rc_node_rele(res);
   6601 				rc_node_clear(out, 0);
   6602 				return (rc);
   6603 			}
   6604 
   6605 			(void) pthread_mutex_lock(&np->rn_lock);
   6606 			if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
   6607 				(void) pthread_mutex_unlock(&np->rn_lock);
   6608 				rc_node_rele(res);
   6609 				if (pg != NULL)
   6610 					rc_node_rele(pg);
   6611 				rc_node_clear(out, 1);
   6612 				return (REP_PROTOCOL_FAIL_DELETED);
   6613 			}
   6614 
   6615 			if (pg == NULL) {
   6616 				rc_node_rele(res);
   6617 			} else {
   6618 				rc_node_t *cpg;
   6619 
   6620 				/* Keep res held for rc_node_setup_cpg(). */
   6621 
   6622 				cpg = rc_node_alloc();
   6623 				if (cpg == NULL) {
   6624 					(void) pthread_mutex_unlock(
   6625 					    &np->rn_lock);
   6626 					rc_node_rele(res);
   6627 					rc_node_rele(pg);
   6628 					rc_node_clear(out, 0);
   6629 					return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6630 				}
   6631 
   6632 				switch (rc_node_setup_cpg(cpg, res, pg)) {
   6633 				case REP_PROTOCOL_SUCCESS:
   6634 					res = cpg;
   6635 					break;
   6636 
   6637 				case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
   6638 					/* Nevermind. */
   6639 					rc_node_destroy(cpg);
   6640 					rc_node_rele(pg);
   6641 					rc_node_rele(res);
   6642 					break;
   6643 
   6644 				case REP_PROTOCOL_FAIL_NO_RESOURCES:
   6645 					rc_node_destroy(cpg);
   6646 					(void) pthread_mutex_unlock(
   6647 					    &np->rn_lock);
   6648 					rc_node_rele(res);
   6649 					rc_node_rele(pg);
   6650 					rc_node_clear(out, 0);
   6651 					return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6652 
   6653 				default:
   6654 					assert(0);
   6655 					abort();
   6656 				}
   6657 			}
   6658 #else
   6659 #error This code must be updated.
   6660 #endif
   6661 		}
   6662 
   6663 		rc_node_hold(res);
   6664 		(void) pthread_mutex_unlock(&np->rn_lock);
   6665 		break;
   6666 	}
   6667 	rc_node_assign(out, res);
   6668 
   6669 	if (res == NULL)
   6670 		return (REP_PROTOCOL_DONE);
   6671 	rc_node_rele(res);
   6672 	return (REP_PROTOCOL_SUCCESS);
   6673 }
   6674 
   6675 void
   6676 rc_iter_destroy(rc_node_iter_t **nipp)
   6677 {
   6678 	rc_node_iter_t *nip = *nipp;
   6679 	rc_node_t *np;
   6680 
   6681 	if (nip == NULL)
   6682 		return;				/* already freed */
   6683 
   6684 	np = nip->rni_parent;
   6685 
   6686 	if (nip->rni_filter_arg != NULL)
   6687 		free(nip->rni_filter_arg);
   6688 	nip->rni_filter_arg = NULL;
   6689 
   6690 	if (nip->rni_type == REP_PROTOCOL_ENTITY_VALUE ||
   6691 	    nip->rni_iter != NULL) {
   6692 		if (nip->rni_clevel < 0)
   6693 			(void) pthread_mutex_lock(&np->rn_lock);
   6694 		else
   6695 			(void) pthread_mutex_lock(
   6696 			    &np->rn_cchain[nip->rni_clevel]->rn_lock);
   6697 		rc_iter_end(nip);		/* release walker and lock */
   6698 	}
   6699 	nip->rni_parent = NULL;
   6700 
   6701 	uu_free(nip);
   6702 	*nipp = NULL;
   6703 }
   6704 
   6705 int
   6706 rc_node_setup_tx(rc_node_ptr_t *npp, rc_node_ptr_t *txp)
   6707 {
   6708 	rc_node_t *np;
   6709 	permcheck_t *pcp;
   6710 	int ret;
   6711 	perm_status_t granted;
   6712 	rc_auth_state_t authorized = RC_AUTH_UNKNOWN;
   6713 	char *auth_string = NULL;
   6714 
   6715 	RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
   6716 
   6717 	if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
   6718 		rc_node_rele(np);
   6719 		np = np->rn_cchain[0];
   6720 		RC_NODE_CHECK_AND_HOLD(np);
   6721 	}
   6722 
   6723 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   6724 		rc_node_rele(np);
   6725 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
   6726 	}
   6727 
   6728 	if (np->rn_id.rl_ids[ID_SNAPSHOT] != 0) {
   6729 		rc_node_rele(np);
   6730 		return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   6731 	}
   6732 
   6733 #ifdef NATIVE_BUILD
   6734 	if (client_is_privileged())
   6735 		goto skip_checks;
   6736 	rc_node_rele(np);
   6737 	return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   6738 #else
   6739 	if (is_main_repository == 0)
   6740 		goto skip_checks;
   6741 
   6742 	/* permission check */
   6743 	pcp = pc_create();
   6744 	if (pcp == NULL) {
   6745 		rc_node_rele(np);
   6746 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   6747 	}
   6748 
   6749 	if (np->rn_id.rl_ids[ID_INSTANCE] != 0 &&	/* instance pg */
   6750 	    ((strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0 &&
   6751 	    strcmp(np->rn_type, AUTH_PG_ACTIONS_TYPE) == 0) ||
   6752 	    (strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
   6753 	    strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
   6754 		rc_node_t *instn;
   6755 
   6756 		/* solaris.smf.manage can be used. */
   6757 		ret = perm_add_enabling(pcp, AUTH_MANAGE);
   6758 
   6759 		if (ret != REP_PROTOCOL_SUCCESS) {
   6760 			pc_free(pcp);
   6761 			rc_node_rele(np);
   6762 			return (ret);
   6763 		}
   6764 
   6765 		/* general/action_authorization values can be used. */
   6766 		ret = rc_node_parent(np, &instn);
   6767 		if (ret != REP_PROTOCOL_SUCCESS) {
   6768 			assert(ret == REP_PROTOCOL_FAIL_DELETED);
   6769 			rc_node_rele(np);
   6770 			pc_free(pcp);
   6771 			return (REP_PROTOCOL_FAIL_DELETED);
   6772 		}
   6773 
   6774 		assert(instn->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
   6775 
   6776 		ret = perm_add_inst_action_auth(pcp, instn);
   6777 		rc_node_rele(instn);
   6778 		switch (ret) {
   6779 		case REP_PROTOCOL_SUCCESS:
   6780 			break;
   6781 
   6782 		case REP_PROTOCOL_FAIL_DELETED:
   6783 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
   6784 			rc_node_rele(np);
   6785 			pc_free(pcp);
   6786 			return (ret);
   6787 
   6788 		default:
   6789 			bad_error("perm_add_inst_action_auth", ret);
   6790 		}
   6791 
   6792 		if (strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0)
   6793 			authorized = RC_AUTH_PASSED; /* No check on commit. */
   6794 	} else {
   6795 		ret = perm_add_enabling(pcp, AUTH_MODIFY);
   6796 
   6797 		if (ret == REP_PROTOCOL_SUCCESS) {
   6798 			/* propertygroup-type-specific authorization */
   6799 			/* no locking because rn_type won't change anyway */
   6800 			const char * const auth =
   6801 			    perm_auth_for_pgtype(np->rn_type);
   6802 
   6803 			if (auth != NULL)
   6804 				ret = perm_add_enabling(pcp, auth);
   6805 		}
   6806 
   6807 		if (ret == REP_PROTOCOL_SUCCESS)
   6808 			/* propertygroup/transaction-type-specific auths */
   6809 			ret =
   6810 			    perm_add_enabling_values(pcp, np, AUTH_PROP_VALUE);
   6811 
   6812 		if (ret == REP_PROTOCOL_SUCCESS)
   6813 			ret =
   6814 			    perm_add_enabling_values(pcp, np, AUTH_PROP_MODIFY);
   6815 
   6816 		/* AUTH_MANAGE can manipulate general/AUTH_PROP_ACTION */
   6817 		if (ret == REP_PROTOCOL_SUCCESS &&
   6818 		    strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
   6819 		    strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0)
   6820 			ret = perm_add_enabling(pcp, AUTH_MANAGE);
   6821 
   6822 		if (ret != REP_PROTOCOL_SUCCESS) {
   6823 			pc_free(pcp);
   6824 			rc_node_rele(np);
   6825 			return (ret);
   6826 		}
   6827 	}
   6828 
   6829 	granted = perm_granted(pcp);
   6830 	ret = map_granted_status(granted, pcp, &auth_string);
   6831 	pc_free(pcp);
   6832 
   6833 	if ((granted == PERM_GONE) || (granted == PERM_FAIL) ||
   6834 	    (ret == REP_PROTOCOL_FAIL_NO_RESOURCES)) {
   6835 		free(auth_string);
   6836 		rc_node_rele(np);
   6837 		return (ret);
   6838 	}
   6839 
   6840 	if (granted == PERM_DENIED) {
   6841 		/*
   6842 		 * If we get here, the authorization failed.
   6843 		 * Unfortunately, we don't have enough information at this
   6844 		 * point to generate the security audit events.  We'll only
   6845 		 * get that information when the client tries to commit the
   6846 		 * event.  Thus, we'll remember the failed authorization,
   6847 		 * so that we can generate the audit events later.
   6848 		 */
   6849 		authorized = RC_AUTH_FAILED;
   6850 	}
   6851 #endif /* NATIVE_BUILD */
   6852 
   6853 skip_checks:
   6854 	rc_node_assign(txp, np);
   6855 	txp->rnp_authorized = authorized;
   6856 	if (authorized != RC_AUTH_UNKNOWN) {
   6857 		/* Save the authorization string. */
   6858 		if (txp->rnp_auth_string != NULL)
   6859 			free((void *)txp->rnp_auth_string);
   6860 		txp->rnp_auth_string = auth_string;
   6861 		auth_string = NULL;	/* Don't free until done with txp. */
   6862 	}
   6863 
   6864 	rc_node_rele(np);
   6865 	if (auth_string != NULL)
   6866 		free(auth_string);
   6867 	return (REP_PROTOCOL_SUCCESS);
   6868 }
   6869 
   6870 /*
   6871  * Return 1 if the given transaction commands only modify the values of
   6872  * properties other than "modify_authorization".  Return -1 if any of the
   6873  * commands are invalid, and 0 otherwise.
   6874  */
   6875 static int
   6876 tx_allow_value(const void *cmds_arg, size_t cmds_sz, rc_node_t *pg)
   6877 {
   6878 	const struct rep_protocol_transaction_cmd *cmds;
   6879 	uintptr_t loc;
   6880 	uint32_t sz;
   6881 	rc_node_t *prop;
   6882 	boolean_t ok;
   6883 
   6884 	assert(!MUTEX_HELD(&pg->rn_lock));
   6885 
   6886 	loc = (uintptr_t)cmds_arg;
   6887 
   6888 	while (cmds_sz > 0) {
   6889 		cmds = (struct rep_protocol_transaction_cmd *)loc;
   6890 
   6891 		if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6892 			return (-1);
   6893 
   6894 		sz = cmds->rptc_size;
   6895 		if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6896 			return (-1);
   6897 
   6898 		sz = TX_SIZE(sz);
   6899 		if (sz > cmds_sz)
   6900 			return (-1);
   6901 
   6902 		switch (cmds[0].rptc_action) {
   6903 		case REP_PROTOCOL_TX_ENTRY_CLEAR:
   6904 			break;
   6905 
   6906 		case REP_PROTOCOL_TX_ENTRY_REPLACE:
   6907 			/* Check type */
   6908 			(void) pthread_mutex_lock(&pg->rn_lock);
   6909 			if (rc_node_find_named_child(pg,
   6910 			    (const char *)cmds[0].rptc_data,
   6911 			    REP_PROTOCOL_ENTITY_PROPERTY, &prop) ==
   6912 			    REP_PROTOCOL_SUCCESS) {
   6913 				ok = (prop != NULL &&
   6914 				    prop->rn_valtype == cmds[0].rptc_type);
   6915 			} else {
   6916 				/* Return more particular error? */
   6917 				ok = B_FALSE;
   6918 			}
   6919 			(void) pthread_mutex_unlock(&pg->rn_lock);
   6920 			if (ok)
   6921 				break;
   6922 			return (0);
   6923 
   6924 		default:
   6925 			return (0);
   6926 		}
   6927 
   6928 		if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_MODIFY)
   6929 		    == 0)
   6930 			return (0);
   6931 
   6932 		loc += sz;
   6933 		cmds_sz -= sz;
   6934 	}
   6935 
   6936 	return (1);
   6937 }
   6938 
   6939 /*
   6940  * Return 1 if any of the given transaction commands affect
   6941  * "action_authorization".  Return -1 if any of the commands are invalid and
   6942  * 0 in all other cases.
   6943  */
   6944 static int
   6945 tx_modifies_action(const void *cmds_arg, size_t cmds_sz)
   6946 {
   6947 	const struct rep_protocol_transaction_cmd *cmds;
   6948 	uintptr_t loc;
   6949 	uint32_t sz;
   6950 
   6951 	loc = (uintptr_t)cmds_arg;
   6952 
   6953 	while (cmds_sz > 0) {
   6954 		cmds = (struct rep_protocol_transaction_cmd *)loc;
   6955 
   6956 		if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6957 			return (-1);
   6958 
   6959 		sz = cmds->rptc_size;
   6960 		if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6961 			return (-1);
   6962 
   6963 		sz = TX_SIZE(sz);
   6964 		if (sz > cmds_sz)
   6965 			return (-1);
   6966 
   6967 		if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_ACTION)
   6968 		    == 0)
   6969 			return (1);
   6970 
   6971 		loc += sz;
   6972 		cmds_sz -= sz;
   6973 	}
   6974 
   6975 	return (0);
   6976 }
   6977 
   6978 /*
   6979  * Returns 1 if the transaction commands only modify properties named
   6980  * 'enabled'.
   6981  */
   6982 static int
   6983 tx_only_enabled(const void *cmds_arg, size_t cmds_sz)
   6984 {
   6985 	const struct rep_protocol_transaction_cmd *cmd;
   6986 	uintptr_t loc;
   6987 	uint32_t sz;
   6988 
   6989 	loc = (uintptr_t)cmds_arg;
   6990 
   6991 	while (cmds_sz > 0) {
   6992 		cmd = (struct rep_protocol_transaction_cmd *)loc;
   6993 
   6994 		if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6995 			return (-1);
   6996 
   6997 		sz = cmd->rptc_size;
   6998 		if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
   6999 			return (-1);
   7000 
   7001 		sz = TX_SIZE(sz);
   7002 		if (sz > cmds_sz)
   7003 			return (-1);
   7004 
   7005 		if (strcmp((const char *)cmd->rptc_data, AUTH_PROP_ENABLED)
   7006 		    != 0)
   7007 			return (0);
   7008 
   7009 		loc += sz;
   7010 		cmds_sz -= sz;
   7011 	}
   7012 
   7013 	return (1);
   7014 }
   7015 
   7016 int
   7017 rc_tx_commit(rc_node_ptr_t *txp, const void *cmds, size_t cmds_sz)
   7018 {
   7019 	rc_node_t *np = txp->rnp_node;
   7020 	rc_node_t *pp;
   7021 	rc_node_t *nnp;
   7022 	rc_node_pg_notify_t *pnp;
   7023 	int rc;
   7024 	permcheck_t *pcp;
   7025 	perm_status_t granted;
   7026 	int normal;
   7027 	char *pg_fmri = NULL;
   7028 	char *auth_string = NULL;
   7029 	int auth_status = ADT_SUCCESS;
   7030 	int auth_ret_value = ADT_SUCCESS;
   7031 	size_t sz_out;
   7032 	int tx_flag = 1;
   7033 	tx_commit_data_t *tx_data = NULL;
   7034 
   7035 	RC_NODE_CHECK(np);
   7036 
   7037 	if ((txp->rnp_authorized != RC_AUTH_UNKNOWN) &&
   7038 	    (txp->rnp_auth_string != NULL)) {
   7039 		auth_string = strdup(txp->rnp_auth_string);
   7040 		if (auth_string == NULL)
   7041 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   7042 	}
   7043 
   7044 	if ((txp->rnp_authorized == RC_AUTH_UNKNOWN) &&
   7045 	    is_main_repository) {
   7046 #ifdef NATIVE_BUILD
   7047 		if (!client_is_privileged()) {
   7048 			return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
   7049 		}
   7050 #else
   7051 		/* permission check: depends on contents of transaction */
   7052 		pcp = pc_create();
   7053 		if (pcp == NULL)
   7054 			return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   7055 
   7056 		/* If normal is cleared, we won't do the normal checks. */
   7057 		normal = 1;
   7058 		rc = REP_PROTOCOL_SUCCESS;
   7059 
   7060 		if (strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
   7061 		    strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0) {
   7062 			/* Touching general[framework]/action_authorization? */
   7063 			rc = tx_modifies_action(cmds, cmds_sz);
   7064 			if (rc == -1) {
   7065 				pc_free(pcp);
   7066 				return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   7067 			}
   7068 
   7069 			if (rc) {
   7070 				/* Yes: only AUTH_MANAGE can be used. */
   7071 				rc = perm_add_enabling(pcp, AUTH_MANAGE);
   7072 				normal = 0;
   7073 			} else {
   7074 				rc = REP_PROTOCOL_SUCCESS;
   7075 			}
   7076 		} else if (np->rn_id.rl_ids[ID_INSTANCE] != 0 &&
   7077 		    strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
   7078 		    strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0) {
   7079 			rc_node_t *instn;
   7080 
   7081 			rc = tx_only_enabled(cmds, cmds_sz);
   7082 			if (rc == -1) {
   7083 				pc_free(pcp);
   7084 				return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   7085 			}
   7086 
   7087 			if (rc) {
   7088 				rc = rc_node_parent(np, &instn);
   7089 				if (rc != REP_PROTOCOL_SUCCESS) {
   7090 					assert(rc == REP_PROTOCOL_FAIL_DELETED);
   7091 					pc_free(pcp);
   7092 					return (rc);
   7093 				}
   7094 
   7095 				assert(instn->rn_id.rl_type ==
   7096 				    REP_PROTOCOL_ENTITY_INSTANCE);
   7097 
   7098 				rc = perm_add_inst_action_auth(pcp, instn);
   7099 				rc_node_rele(instn);
   7100 				switch (rc) {
   7101 				case REP_PROTOCOL_SUCCESS:
   7102 					break;
   7103 
   7104 				case REP_PROTOCOL_FAIL_DELETED:
   7105 				case REP_PROTOCOL_FAIL_NO_RESOURCES:
   7106 					pc_free(pcp);
   7107 					return (rc);
   7108 
   7109 				default:
   7110 					bad_error("perm_add_inst_action_auth",
   7111 					    rc);
   7112 				}
   7113 			} else {
   7114 				rc = REP_PROTOCOL_SUCCESS;
   7115 			}
   7116 		}
   7117 
   7118 		if (rc == REP_PROTOCOL_SUCCESS && normal) {
   7119 			rc = perm_add_enabling(pcp, AUTH_MODIFY);
   7120 
   7121 			if (rc == REP_PROTOCOL_SUCCESS) {
   7122 				/* Add pgtype-specific authorization. */
   7123 				const char * const auth =
   7124 				    perm_auth_for_pgtype(np->rn_type);
   7125 
   7126 				if (auth != NULL)
   7127 					rc = perm_add_enabling(pcp, auth);
   7128 			}
   7129 
   7130 			/* Add pg-specific modify_authorization auths. */
   7131 			if (rc == REP_PROTOCOL_SUCCESS)
   7132 				rc = perm_add_enabling_values(pcp, np,
   7133 				    AUTH_PROP_MODIFY);
   7134 
   7135 			/* If value_authorization values are ok, add them. */
   7136 			if (rc == REP_PROTOCOL_SUCCESS) {
   7137 				rc = tx_allow_value(cmds, cmds_sz, np);
   7138 				if (rc == -1)
   7139 					rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
   7140 				else if (rc)
   7141 					rc = perm_add_enabling_values(pcp, np,
   7142 					    AUTH_PROP_VALUE);
   7143 			}
   7144 		}
   7145 
   7146 		if (rc == REP_PROTOCOL_SUCCESS) {
   7147 			granted = perm_granted(pcp);
   7148 			rc = map_granted_status(granted, pcp, &auth_string);
   7149 			if ((granted == PERM_DENIED) && auth_string) {
   7150 				/*
   7151 				 * _PERMISSION_DENIED should not cause us
   7152 				 * to exit at this point, because we still
   7153 				 * want to generate an audit event.
   7154 				 */
   7155 				rc = REP_PROTOCOL_SUCCESS;
   7156 			}
   7157 		}
   7158 
   7159 		pc_free(pcp);
   7160 
   7161 		if (rc != REP_PROTOCOL_SUCCESS)
   7162 			goto cleanout;
   7163 
   7164 		if (granted == PERM_DENIED) {
   7165 			auth_status = ADT_FAILURE;
   7166 			auth_ret_value = ADT_FAIL_VALUE_AUTH;
   7167 			tx_flag = 0;
   7168 		}
   7169 #endif /* NATIVE_BUILD */
   7170 	} else if (txp->rnp_authorized == RC_AUTH_FAILED) {
   7171 		auth_status = ADT_FAILURE;
   7172 		auth_ret_value = ADT_FAIL_VALUE_AUTH;
   7173 		tx_flag = 0;
   7174 	}
   7175 
   7176 	pg_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
   7177 	if (pg_fmri == NULL) {
   7178 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   7179 		goto cleanout;
   7180 	}
   7181 	if ((rc = rc_node_get_fmri_or_fragment(np, pg_fmri,
   7182 	    REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
   7183 		goto cleanout;
   7184 	}
   7185 
   7186 	/*
   7187 	 * Parse the transaction commands into a useful form.
   7188 	 */
   7189 	if ((rc = tx_commit_data_new(cmds, cmds_sz, &tx_data)) !=
   7190 	    REP_PROTOCOL_SUCCESS) {
   7191 		goto cleanout;
   7192 	}
   7193 
   7194 	if (tx_flag == 0) {
   7195 		/* Authorization failed.  Generate audit events. */
   7196 		generate_property_events(tx_data, pg_fmri, auth_string,
   7197 		    auth_status, auth_ret_value);
   7198 		rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
   7199 		goto cleanout;
   7200 	}
   7201 
   7202 	nnp = rc_node_alloc();
   7203 	if (nnp == NULL) {
   7204 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   7205 		goto cleanout;
   7206 	}
   7207 
   7208 	nnp->rn_id = np->rn_id;			/* structure assignment */
   7209 	nnp->rn_hash = np->rn_hash;
   7210 	nnp->rn_name = strdup(np->rn_name);
   7211 	nnp->rn_type = strdup(np->rn_type);
   7212 	nnp->rn_pgflags = np->rn_pgflags;
   7213 
   7214 	nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
   7215 
   7216 	if (nnp->rn_name == NULL || nnp->rn_type == NULL) {
   7217 		rc_node_destroy(nnp);
   7218 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
   7219 		goto cleanout;
   7220 	}
   7221 
   7222 	(void) pthread_mutex_lock(&np->rn_lock);
   7223 
   7224 	/*
   7225 	 * We must have all of the old properties in the cache, or the
   7226 	 * database deletions could cause inconsistencies.
   7227 	 */
   7228 	if ((rc = rc_node_fill_children(np, REP_PROTOCOL_ENTITY_PROPERTY)) !=
   7229 	    REP_PROTOCOL_SUCCESS) {
   7230 		(void) pthread_mutex_unlock(&np->rn_lock);
   7231 		rc_node_destroy(nnp);
   7232 		goto cleanout;
   7233 	}
   7234 
   7235 	if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
   7236 		(void) pthread_mutex_unlock(&np->rn_lock);
   7237 		rc_node_destroy(nnp);
   7238 		rc = REP_PROTOCOL_FAIL_DELETED;
   7239 		goto cleanout;
   7240 	}
   7241 
   7242 	if (np->rn_flags & RC_NODE_OLD) {
   7243 		rc_node_rele_flag(np, RC_NODE_USING_PARENT);
   7244 		(void) pthread_mutex_unlock(&np->rn_lock);
   7245 		rc_node_destroy(nnp);
   7246 		rc = REP_PROTOCOL_FAIL_NOT_LATEST;
   7247 		goto cleanout;
   7248 	}
   7249 
   7250 	pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
   7251 	if (pp == NULL) {
   7252 		/* our parent is gone, we're going next... */
   7253 		rc_node_destroy(nnp);
   7254 		(void) pthread_mutex_lock(&np->rn_lock);
   7255 		if (np->rn_flags & RC_NODE_OLD) {
   7256 			(void) pthread_mutex_unlock(&np->rn_lock);
   7257 			rc = REP_PROTOCOL_FAIL_NOT_LATEST;
   7258 			goto cleanout;
   7259 		}
   7260 		(void) pthread_mutex_unlock(&np->rn_lock);
   7261 		rc = REP_PROTOCOL_FAIL_DELETED;
   7262 		goto cleanout;
   7263 	}
   7264 	(void) pthread_mutex_unlock(&pp->rn_lock);
   7265 
   7266 	/*
   7267 	 * prepare for the transaction
   7268 	 */
   7269 	(void) pthread_mutex_lock(&np->rn_lock);
   7270 	if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
   7271 		(void) pthread_mutex_unlock(&np->rn_lock);
   7272 		(void) pthread_mutex_lock(&pp->rn_lock);
   7273 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   7274 		(void) pthread_mutex_unlock(&pp->rn_lock);
   7275 		rc_node_destroy(nnp);
   7276 		rc = REP_PROTOCOL_FAIL_DELETED;
   7277 		goto cleanout;
   7278 	}
   7279 	nnp->rn_gen_id = np->rn_gen_id;
   7280 	(void) pthread_mutex_unlock(&np->rn_lock);
   7281 
   7282 	/* Sets nnp->rn_gen_id on success. */
   7283 	rc = object_tx_commit(&np->rn_id, tx_data, &nnp->rn_gen_id);
   7284 
   7285 	(void) pthread_mutex_lock(&np->rn_lock);
   7286 	if (rc != REP_PROTOCOL_SUCCESS) {
   7287 		rc_node_rele_flag(np, RC_NODE_IN_TX);
   7288 		(void) pthread_mutex_unlock(&np->rn_lock);
   7289 		(void) pthread_mutex_lock(&pp->rn_lock);
   7290 		rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
   7291 		(void) pthread_mutex_unlock(&pp->rn_lock);
   7292 		rc_node_destroy(nnp);
   7293 		rc_node_clear(txp, 0);
   7294 		if (rc == REP_PROTOCOL_DONE)
   7295 			rc = REP_PROTOCOL_SUCCESS; /* successful empty tx */
   7296 		goto cleanout;
   7297 	}
   7298 
   7299 	/*
   7300 	 * Notify waiters
   7301 	 */
   7302 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7303 	while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
   7304 		rc_pg_notify_fire(pnp);
   7305 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7306 
   7307 	np->rn_flags |= RC_NODE_OLD;
   7308 	(void) pthread_mutex_unlock(&np->rn_lock);
   7309 
   7310 	rc_notify_remove_node(np);
   7311 
   7312 	/*
   7313 	 * replace np with nnp
   7314 	 */
   7315 	rc_node_relink_child(pp, np, nnp);
   7316 
   7317 	/*
   7318 	 * all done -- clear the transaction.
   7319 	 */
   7320 	rc_node_clear(txp, 0);
   7321 	generate_property_events(tx_data, pg_fmri, auth_string,
   7322 	    auth_status, auth_ret_value);
   7323 
   7324 	rc = REP_PROTOCOL_SUCCESS;
   7325 
   7326 cleanout:
   7327 	free(auth_string);
   7328 	free(pg_fmri);
   7329 	tx_commit_data_free(tx_data);
   7330 	return (rc);
   7331 }
   7332 
   7333 void
   7334 rc_pg_notify_init(rc_node_pg_notify_t *pnp)
   7335 {
   7336 	uu_list_node_init(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
   7337 	pnp->rnpn_pg = NULL;
   7338 	pnp->rnpn_fd = -1;
   7339 }
   7340 
   7341 int
   7342 rc_pg_notify_setup(rc_node_pg_notify_t *pnp, rc_node_ptr_t *npp, int fd)
   7343 {
   7344 	rc_node_t *np;
   7345 
   7346 	RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
   7347 
   7348 	if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
   7349 		(void) pthread_mutex_unlock(&np->rn_lock);
   7350 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
   7351 	}
   7352 
   7353 	/*
   7354 	 * wait for any transaction in progress to complete
   7355 	 */
   7356 	if (!rc_node_wait_flag(np, RC_NODE_IN_TX)) {
   7357 		(void) pthread_mutex_unlock(&np->rn_lock);
   7358 		return (REP_PROTOCOL_FAIL_DELETED);
   7359 	}
   7360 
   7361 	if (np->rn_flags & RC_NODE_OLD) {
   7362 		(void) pthread_mutex_unlock(&np->rn_lock);
   7363 		return (REP_PROTOCOL_FAIL_NOT_LATEST);
   7364 	}
   7365 
   7366 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7367 	rc_pg_notify_fire(pnp);
   7368 	pnp->rnpn_pg = np;
   7369 	pnp->rnpn_fd = fd;
   7370 	(void) uu_list_insert_after(np->rn_pg_notify_list, NULL, pnp);
   7371 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7372 
   7373 	(void) pthread_mutex_unlock(&np->rn_lock);
   7374 	return (REP_PROTOCOL_SUCCESS);
   7375 }
   7376 
   7377 void
   7378 rc_pg_notify_fini(rc_node_pg_notify_t *pnp)
   7379 {
   7380 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7381 	rc_pg_notify_fire(pnp);
   7382 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7383 
   7384 	uu_list_node_fini(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
   7385 }
   7386 
   7387 void
   7388 rc_notify_info_init(rc_notify_info_t *rnip)
   7389 {
   7390 	int i;
   7391 
   7392 	uu_list_node_init(rnip, &rnip->rni_list_node, rc_notify_info_pool);
   7393 	uu_list_node_init(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
   7394 	    rc_notify_pool);
   7395 
   7396 	rnip->rni_notify.rcn_node = NULL;
   7397 	rnip->rni_notify.rcn_info = rnip;
   7398 
   7399 	bzero(rnip->rni_namelist, sizeof (rnip->rni_namelist));
   7400 	bzero(rnip->rni_typelist, sizeof (rnip->rni_typelist));
   7401 
   7402 	(void) pthread_cond_init(&rnip->rni_cv, NULL);
   7403 
   7404 	for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
   7405 		rnip->rni_namelist[i] = NULL;
   7406 		rnip->rni_typelist[i] = NULL;
   7407 	}
   7408 }
   7409 
   7410 static void
   7411 rc_notify_info_insert_locked(rc_notify_info_t *rnip)
   7412 {
   7413 	assert(MUTEX_HELD(&rc_pg_notify_lock));
   7414 
   7415 	assert(!(rnip->rni_flags & RC_NOTIFY_ACTIVE));
   7416 
   7417 	rnip->rni_flags |= RC_NOTIFY_ACTIVE;
   7418 	(void) uu_list_insert_after(rc_notify_info_list, NULL, rnip);
   7419 	(void) uu_list_insert_before(rc_notify_list, NULL, &rnip->rni_notify);
   7420 }
   7421 
   7422 static void
   7423 rc_notify_info_remove_locked(rc_notify_info_t *rnip)
   7424 {
   7425 	rc_notify_t *me = &rnip->rni_notify;
   7426 	rc_notify_t *np;
   7427 
   7428 	assert(MUTEX_HELD(&rc_pg_notify_lock));
   7429 
   7430 	assert(rnip->rni_flags & RC_NOTIFY_ACTIVE);
   7431 
   7432 	assert(!(rnip->rni_flags & RC_NOTIFY_DRAIN));
   7433 	rnip->rni_flags |= RC_NOTIFY_DRAIN;
   7434 	(void) pthread_cond_broadcast(&rnip->rni_cv);
   7435 
   7436 	(void) uu_list_remove(rc_notify_info_list, rnip);
   7437 
   7438 	/*
   7439 	 * clean up any notifications at the beginning of the list
   7440 	 */
   7441 	if (uu_list_first(rc_notify_list) == me) {
   7442 		while ((np = uu_list_next(rc_notify_list, me)) != NULL &&
   7443 		    np->rcn_info == NULL)
   7444 			rc_notify_remove_locked(np);
   7445 	}
   7446 	(void) uu_list_remove(rc_notify_list, me);
   7447 
   7448 	while (rnip->rni_waiters) {
   7449 		(void) pthread_cond_broadcast(&rc_pg_notify_cv);
   7450 		(void) pthread_cond_broadcast(&rnip->rni_cv);
   7451 		(void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
   7452 	}
   7453 
   7454 	rnip->rni_flags &= ~(RC_NOTIFY_DRAIN | RC_NOTIFY_ACTIVE);
   7455 }
   7456 
   7457 static int
   7458 rc_notify_info_add_watch(rc_notify_info_t *rnip, const char **arr,
   7459     const char *name)
   7460 {
   7461 	int i;
   7462 	int rc;
   7463 	char *f;
   7464 
   7465 	rc = rc_check_type_name(REP_PROTOCOL_ENTITY_PROPERTYGRP, name);
   7466 	if (rc != REP_PROTOCOL_SUCCESS)
   7467 		return (rc);
   7468 
   7469 	f = strdup(name);
   7470 	if (f == NULL)
   7471 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   7472 
   7473 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7474 
   7475 	while (rnip->rni_flags & RC_NOTIFY_EMPTYING)
   7476 		(void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
   7477 
   7478 	for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
   7479 		if (arr[i] == NULL)
   7480 			break;
   7481 
   7482 		/*
   7483 		 * Don't add name if it's already being tracked.
   7484 		 */
   7485 		if (strcmp(arr[i], f) == 0) {
   7486 			free(f);
   7487 			goto out;
   7488 		}
   7489 	}
   7490 
   7491 	if (i == RC_NOTIFY_MAX_NAMES) {
   7492 		(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7493 		free(f);
   7494 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
   7495 	}
   7496 
   7497 	arr[i] = f;
   7498 
   7499 out:
   7500 	if (!(rnip->rni_flags & RC_NOTIFY_ACTIVE))
   7501 		rc_notify_info_insert_locked(rnip);
   7502 
   7503 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7504 	return (REP_PROTOCOL_SUCCESS);
   7505 }
   7506 
   7507 int
   7508 rc_notify_info_add_name(rc_notify_info_t *rnip, const char *name)
   7509 {
   7510 	return (rc_notify_info_add_watch(rnip, rnip->rni_namelist, name));
   7511 }
   7512 
   7513 int
   7514 rc_notify_info_add_type(rc_notify_info_t *rnip, const char *type)
   7515 {
   7516 	return (rc_notify_info_add_watch(rnip, rnip->rni_typelist, type));
   7517 }
   7518 
   7519 /*
   7520  * Wait for and report an event of interest to rnip, a notification client
   7521  */
   7522 int
   7523 rc_notify_info_wait(rc_notify_info_t *rnip, rc_node_ptr_t *out,
   7524     char *outp, size_t sz)
   7525 {
   7526 	rc_notify_t *np;
   7527 	rc_notify_t *me = &rnip->rni_notify;
   7528 	rc_node_t *nnp;
   7529 	rc_notify_delete_t *ndp;
   7530 
   7531 	int am_first_info;
   7532 
   7533 	if (sz > 0)
   7534 		outp[0] = 0;
   7535 
   7536 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7537 
   7538 	while ((rnip->rni_flags & (RC_NOTIFY_ACTIVE | RC_NOTIFY_DRAIN)) ==
   7539 	    RC_NOTIFY_ACTIVE) {
   7540 		/*
   7541 		 * If I'm first on the notify list, it is my job to
   7542 		 * clean up any notifications I pass by.  I can't do that
   7543 		 * if someone is blocking the list from removals, so I
   7544 		 * have to wait until they have all drained.
   7545 		 */
   7546 		am_first_info = (uu_list_first(rc_notify_list) == me);
   7547 		if (am_first_info && rc_notify_in_use) {
   7548 			rnip->rni_waiters++;
   7549 			(void) pthread_cond_wait(&rc_pg_notify_cv,
   7550 			    &rc_pg_notify_lock);
   7551 			rnip->rni_waiters--;
   7552 			continue;
   7553 		}
   7554 
   7555 		/*
   7556 		 * Search the list for a node of interest.
   7557 		 */
   7558 		np = uu_list_next(rc_notify_list, me);
   7559 		while (np != NULL && !rc_notify_info_interested(rnip, np)) {
   7560 			rc_notify_t *next = uu_list_next(rc_notify_list, np);
   7561 
   7562 			if (am_first_info) {
   7563 				if (np->rcn_info) {
   7564 					/*
   7565 					 * Passing another client -- stop
   7566 					 * cleaning up notifications
   7567 					 */
   7568 					am_first_info = 0;
   7569 				} else {
   7570 					rc_notify_remove_locked(np);
   7571 				}
   7572 			}
   7573 			np = next;
   7574 		}
   7575 
   7576 		/*
   7577 		 * Nothing of interest -- wait for notification
   7578 		 */
   7579 		if (np == NULL) {
   7580 			rnip->rni_waiters++;
   7581 			(void) pthread_cond_wait(&rnip->rni_cv,
   7582 			    &rc_pg_notify_lock);
   7583 			rnip->rni_waiters--;
   7584 			continue;
   7585 		}
   7586 
   7587 		/*
   7588 		 * found something to report -- move myself after the
   7589 		 * notification and process it.
   7590 		 */
   7591 		(void) uu_list_remove(rc_notify_list, me);
   7592 		(void) uu_list_insert_after(rc_notify_list, np, me);
   7593 
   7594 		if ((ndp = np->rcn_delete) != NULL) {
   7595 			(void) strlcpy(outp, ndp->rnd_fmri, sz);
   7596 			if (am_first_info)
   7597 				rc_notify_remove_locked(np);
   7598 			(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7599 			rc_node_clear(out, 0);
   7600 			return (REP_PROTOCOL_SUCCESS);
   7601 		}
   7602 
   7603 		nnp = np->rcn_node;
   7604 		assert(nnp != NULL);
   7605 
   7606 		/*
   7607 		 * We can't bump nnp's reference count without grabbing its
   7608 		 * lock, and rc_pg_notify_lock is a leaf lock.  So we
   7609 		 * temporarily block all removals to keep nnp from
   7610 		 * disappearing.
   7611 		 */
   7612 		rc_notify_in_use++;
   7613 		assert(rc_notify_in_use > 0);
   7614 		(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7615 
   7616 		rc_node_assign(out, nnp);
   7617 
   7618 		(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7619 		assert(rc_notify_in_use > 0);
   7620 		rc_notify_in_use--;
   7621 		if (am_first_info)
   7622 			rc_notify_remove_locked(np);
   7623 		if (rc_notify_in_use == 0)
   7624 			(void) pthread_cond_broadcast(&rc_pg_notify_cv);
   7625 		(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7626 
   7627 		return (REP_PROTOCOL_SUCCESS);
   7628 	}
   7629 	/*
   7630 	 * If we're the last one out, let people know it's clear.
   7631 	 */
   7632 	if (rnip->rni_waiters == 0)
   7633 		(void) pthread_cond_broadcast(&rnip->rni_cv);
   7634 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7635 	return (REP_PROTOCOL_DONE);
   7636 }
   7637 
   7638 static void
   7639 rc_notify_info_reset(rc_notify_info_t *rnip)
   7640 {
   7641 	int i;
   7642 
   7643 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7644 	if (rnip->rni_flags & RC_NOTIFY_ACTIVE)
   7645 		rc_notify_info_remove_locked(rnip);
   7646 	assert(!(rnip->rni_flags & (RC_NOTIFY_DRAIN | RC_NOTIFY_EMPTYING)));
   7647 	rnip->rni_flags |= RC_NOTIFY_EMPTYING;
   7648 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7649 
   7650 	for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
   7651 		if (rnip->rni_namelist[i] != NULL) {
   7652 			free((void *)rnip->rni_namelist[i]);
   7653 			rnip->rni_namelist[i] = NULL;
   7654 		}
   7655 		if (rnip->rni_typelist[i] != NULL) {
   7656 			free((void *)rnip->rni_typelist[i]);
   7657 			rnip->rni_typelist[i] = NULL;
   7658 		}
   7659 	}
   7660 
   7661 	(void) pthread_mutex_lock(&rc_pg_notify_lock);
   7662 	rnip->rni_flags &= ~RC_NOTIFY_EMPTYING;
   7663 	(void) pthread_mutex_unlock(&rc_pg_notify_lock);
   7664 }
   7665 
   7666 void
   7667 rc_notify_info_fini(rc_notify_info_t *rnip)
   7668 {
   7669 	rc_notify_info_reset(rnip);
   7670 
   7671 	uu_list_node_fini(rnip, &rnip->rni_list_node, rc_notify_info_pool);
   7672 	uu_list_node_fini(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
   7673 	    rc_notify_pool);
   7674 }
   7675