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