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