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