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