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