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