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