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