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