17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5d3186a0eSjeanm * Common Development and Distribution License (the "License"). 6d3186a0eSjeanm * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 213eae19d9Swesolows 227c478bd9Sstevel@tonic-gate /* 23134a1f4eSCasper H.S. Dik * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24*a29160b0SRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 286643e1ffSbustos * rc_node.c - In-memory SCF object management 297c478bd9Sstevel@tonic-gate * 306643e1ffSbustos * This layer manages the in-memory cache (the Repository Cache) of SCF 316643e1ffSbustos * data. Read requests are usually satisfied from here, but may require 326643e1ffSbustos * load calls to the "object" layer. Modify requests always write-through 336643e1ffSbustos * to the object layer. 346643e1ffSbustos * 356643e1ffSbustos * SCF data comprises scopes, services, instances, snapshots, snaplevels, 366643e1ffSbustos * property groups, properties, and property values. All but the last are 376643e1ffSbustos * known here as "entities" and are represented by rc_node_t data 386643e1ffSbustos * structures. (Property values are kept in the rn_values member of the 396643e1ffSbustos * respective property, not as separate objects.) All entities besides 406643e1ffSbustos * the "localhost" scope have some entity as a parent, and therefore form 416643e1ffSbustos * a tree. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * The entity tree is rooted at rc_scope, which rc_node_init() initializes to 447c478bd9Sstevel@tonic-gate * the "localhost" scope. The tree is filled in from the database on-demand 456643e1ffSbustos * by rc_node_fill_children(). 467c478bd9Sstevel@tonic-gate * 476643e1ffSbustos * rc_node_t's are also placed in the cache_hash[] hash table, for rapid 486643e1ffSbustos * lookup. 497c478bd9Sstevel@tonic-gate * 506643e1ffSbustos * Multiple threads may service client requests, so access to each 516643e1ffSbustos * rc_node_t is synchronized by its rn_lock member. Some fields are 526643e1ffSbustos * protected by bits in the rn_flags field instead, to support operations 536643e1ffSbustos * which need to drop rn_lock, for example to respect locking order. Such 546643e1ffSbustos * flags should be manipulated with the rc_node_{hold,rele}_flag() 556643e1ffSbustos * functions. 566643e1ffSbustos * 576643e1ffSbustos * We track references to nodes to tell when they can be free()d. rn_refs 586643e1ffSbustos * should be incremented with rc_node_hold() on the creation of client 596643e1ffSbustos * references (rc_node_ptr_t's and rc_iter_t's). rn_erefs ("ephemeral 606643e1ffSbustos * references") should be incremented when a pointer is read into a local 616643e1ffSbustos * variable of a thread, with rc_node_hold_ephemeral_locked(). This 626643e1ffSbustos * hasn't been fully implemented, however, so rc_node_rele() tolerates 636643e1ffSbustos * rn_erefs being 0. Some code which predates rn_erefs counts ephemeral 646643e1ffSbustos * references in rn_refs. Other references are tracked by the 656643e1ffSbustos * rn_other_refs field and the RC_NODE_DEAD, RC_NODE_IN_PARENT, 666643e1ffSbustos * RC_NODE_OLD, and RC_NODE_ON_FORMER flags. 677c478bd9Sstevel@tonic-gate * 687c478bd9Sstevel@tonic-gate * Locking rules: To dereference an rc_node_t * (usually to lock it), you must 697c478bd9Sstevel@tonic-gate * have a hold (rc_node_hold()) on it or otherwise be sure that it hasn't been 707c478bd9Sstevel@tonic-gate * rc_node_destroy()ed (hold a lock on its parent or child, hold a flag, 717c478bd9Sstevel@tonic-gate * etc.). Once you have locked an rc_node_t you must check its rn_flags for 727c478bd9Sstevel@tonic-gate * RC_NODE_DEAD before you can use it. This is usually done with the 737c478bd9Sstevel@tonic-gate * rc_node_{wait,hold}_flag() functions (often via the rc_node_check_*() 747c478bd9Sstevel@tonic-gate * functions & RC_NODE_*() macros), which fail if the object has died. 757c478bd9Sstevel@tonic-gate * 766643e1ffSbustos * When a transactional node (property group or snapshot) is updated, 776643e1ffSbustos * a new node takes the place of the old node in the global hash and the 786643e1ffSbustos * old node is hung off of the rn_former list of the new node. At the 796643e1ffSbustos * same time, all of its children have their rn_parent_ref pointer set, 806643e1ffSbustos * and any holds they have are reflected in the old node's rn_other_refs 816643e1ffSbustos * count. This is automatically kept up to date until the final reference 826643e1ffSbustos * to the subgraph is dropped, at which point the node is unrefed and 836643e1ffSbustos * destroyed, along with all of its children. 846643e1ffSbustos * 853eae19d9Swesolows * Because name service lookups may take a long time and, more importantly 863eae19d9Swesolows * may trigger additional accesses to the repository, perm_granted() must be 873eae19d9Swesolows * called without holding any locks. 883eae19d9Swesolows * 897c478bd9Sstevel@tonic-gate * An ITER_START for a non-ENTITY_VALUE induces an rc_node_fill_children() 907c478bd9Sstevel@tonic-gate * call via rc_node_setup_iter() to populate the rn_children uu_list of the 917c478bd9Sstevel@tonic-gate * rc_node_t * in question and a call to uu_list_walk_start() on that list. For 927c478bd9Sstevel@tonic-gate * ITER_READ, rc_iter_next() uses uu_list_walk_next() to find the next 937c478bd9Sstevel@tonic-gate * apropriate child. 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * An ITER_START for an ENTITY_VALUE makes sure the node has its values 967c478bd9Sstevel@tonic-gate * filled, and sets up the iterator. An ITER_READ_VALUE just copies out 977c478bd9Sstevel@tonic-gate * the proper values and updates the offset information. 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * To allow aliases, snapshots are implemented with a level of indirection. 1007c478bd9Sstevel@tonic-gate * A snapshot rc_node_t has a snapid which refers to an rc_snapshot_t in 1017c478bd9Sstevel@tonic-gate * snapshot.c which contains the authoritative snaplevel information. The 1027c478bd9Sstevel@tonic-gate * snapid is "assigned" by rc_attach_snapshot(). 1037c478bd9Sstevel@tonic-gate * 1047c478bd9Sstevel@tonic-gate * We provide the client layer with rc_node_ptr_t's to reference objects. 1057c478bd9Sstevel@tonic-gate * Objects referred to by them are automatically held & released by 1067c478bd9Sstevel@tonic-gate * rc_node_assign() & rc_node_clear(). The RC_NODE_PTR_*() macros are used at 1077c478bd9Sstevel@tonic-gate * client.c entry points to read the pointers. They fetch the pointer to the 1087c478bd9Sstevel@tonic-gate * object, return (from the function) if it is dead, and lock, hold, or hold 1097c478bd9Sstevel@tonic-gate * a flag of the object. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Permission checking is authorization-based: some operations may only 1147c478bd9Sstevel@tonic-gate * proceed if the user has been assigned at least one of a set of 1157c478bd9Sstevel@tonic-gate * authorization strings. The set of enabling authorizations depends on the 1167c478bd9Sstevel@tonic-gate * operation and the target object. The set of authorizations assigned to 117134a1f4eSCasper H.S. Dik * a user is determined by an algorithm defined in libsecdb. 1187c478bd9Sstevel@tonic-gate * 1197c478bd9Sstevel@tonic-gate * The fastest way to decide whether the two sets intersect is by entering the 1207c478bd9Sstevel@tonic-gate * strings into a hash table and detecting collisions, which takes linear time 1217c478bd9Sstevel@tonic-gate * in the total size of the sets. Except for the authorization patterns which 1227c478bd9Sstevel@tonic-gate * may be assigned to users, which without advanced pattern-matching 1237c478bd9Sstevel@tonic-gate * algorithms will take O(n) in the number of enabling authorizations, per 1247c478bd9Sstevel@tonic-gate * pattern. 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * We can achieve some practical speed-ups by noting that if we enter all of 1277c478bd9Sstevel@tonic-gate * the authorizations from one of the sets into the hash table we can merely 1287c478bd9Sstevel@tonic-gate * check the elements of the second set for existence without adding them. 1297c478bd9Sstevel@tonic-gate * This reduces memory requirements and hash table clutter. The enabling set 1307c478bd9Sstevel@tonic-gate * is well suited for this because it is internal to configd (for now, at 1317c478bd9Sstevel@tonic-gate * least). Combine this with short-circuiting and we can even minimize the 1327c478bd9Sstevel@tonic-gate * number of queries to the security databases (user_attr & prof_attr). 1337c478bd9Sstevel@tonic-gate * 1347c478bd9Sstevel@tonic-gate * To force this usage onto clients we provide functions for adding 1357c478bd9Sstevel@tonic-gate * authorizations to the enabling set of a permission context structure 1367c478bd9Sstevel@tonic-gate * (perm_add_*()) and one to decide whether the the user associated with the 1377c478bd9Sstevel@tonic-gate * current door call client possesses any of them (perm_granted()). 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * At some point, a generic version of this should move to libsecdb. 1405b7f77adStw21770 * 1415b7f77adStw21770 * While entering the enabling strings into the hash table, we keep track 1425b7f77adStw21770 * of which is the most specific for use in generating auditing events. 1435b7f77adStw21770 * See the "Collecting the Authorization String" section of the "SMF Audit 1445b7f77adStw21770 * Events" block comment below. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * Composition is the combination of sets of properties. The sets are ordered 1497c478bd9Sstevel@tonic-gate * and properties in higher sets obscure properties of the same name in lower 1507c478bd9Sstevel@tonic-gate * sets. Here we present a composed view of an instance's properties as the 1517c478bd9Sstevel@tonic-gate * union of its properties and its service's properties. Similarly the 1527c478bd9Sstevel@tonic-gate * properties of snaplevels are combined to form a composed view of the 1537c478bd9Sstevel@tonic-gate * properties of a snapshot (which should match the composed view of the 1547c478bd9Sstevel@tonic-gate * properties of the instance when the snapshot was taken). 1557c478bd9Sstevel@tonic-gate * 1567c478bd9Sstevel@tonic-gate * In terms of the client interface, the client may request that a property 1577c478bd9Sstevel@tonic-gate * group iterator for an instance or snapshot be composed. Property groups 1587c478bd9Sstevel@tonic-gate * traversed by such an iterator may not have the target entity as a parent. 1597c478bd9Sstevel@tonic-gate * Similarly, the properties traversed by a property iterator for those 1607c478bd9Sstevel@tonic-gate * property groups may not have the property groups iterated as parents. 1617c478bd9Sstevel@tonic-gate * 1627c478bd9Sstevel@tonic-gate * Implementation requires that iterators for instances and snapshots be 1637c478bd9Sstevel@tonic-gate * composition-savvy, and that we have a "composed property group" entity 1647c478bd9Sstevel@tonic-gate * which represents the composition of a number of property groups. Iteration 1657c478bd9Sstevel@tonic-gate * over "composed property groups" yields properties which may have different 1667c478bd9Sstevel@tonic-gate * parents, but for all other operations a composed property group behaves 1677c478bd9Sstevel@tonic-gate * like the top-most property group it represents. 1687c478bd9Sstevel@tonic-gate * 1697c478bd9Sstevel@tonic-gate * The implementation is based on the rn_cchain[] array of rc_node_t pointers 1707c478bd9Sstevel@tonic-gate * in rc_node_t. For instances, the pointers point to the instance and its 1717c478bd9Sstevel@tonic-gate * parent service. For snapshots they point to the child snaplevels, and for 1727c478bd9Sstevel@tonic-gate * composed property groups they point to property groups. A composed 1737c478bd9Sstevel@tonic-gate * iterator carries an index into rn_cchain[]. Thus most of the magic ends up 1747c478bd9Sstevel@tonic-gate * int the rc_iter_*() code. 1757c478bd9Sstevel@tonic-gate */ 1765b7f77adStw21770 /* 1775b7f77adStw21770 * SMF Audit Events: 1785b7f77adStw21770 * ================ 1795b7f77adStw21770 * 1805b7f77adStw21770 * To maintain security, SMF generates audit events whenever 1815b7f77adStw21770 * privileged operations are attempted. See the System Administration 1825b7f77adStw21770 * Guide:Security Services answerbook for a discussion of the Solaris 1835b7f77adStw21770 * audit system. 1845b7f77adStw21770 * 1855b7f77adStw21770 * The SMF audit event codes are defined in adt_event.h by symbols 1865b7f77adStw21770 * starting with ADT_smf_ and are described in audit_event.txt. The 1875b7f77adStw21770 * audit record structures are defined in the SMF section of adt.xml. 1885b7f77adStw21770 * adt.xml is used to automatically generate adt_event.h which 1895b7f77adStw21770 * contains the definitions that we code to in this file. For the 1905b7f77adStw21770 * most part the audit events map closely to actions that you would 1915b7f77adStw21770 * perform with svcadm or svccfg, but there are some special cases 1925b7f77adStw21770 * which we'll discuss later. 1935b7f77adStw21770 * 1945b7f77adStw21770 * The software associated with SMF audit events falls into three 1955b7f77adStw21770 * categories: 1965b7f77adStw21770 * - collecting information to be written to the audit 1975b7f77adStw21770 * records 1985b7f77adStw21770 * - using the adt_* functions in 1995b7f77adStw21770 * usr/src/lib/libbsm/common/adt.c to generate the audit 2005b7f77adStw21770 * records. 2015b7f77adStw21770 * - handling special cases 2025b7f77adStw21770 * 2035b7f77adStw21770 * Collecting Information: 2045b7f77adStw21770 * ---------------------- 2055b7f77adStw21770 * 2065b7f77adStw21770 * Most all of the audit events require the FMRI of the affected 2075b7f77adStw21770 * object and the authorization string that was used. The one 2085b7f77adStw21770 * exception is ADT_smf_annotation which we'll talk about later. 2095b7f77adStw21770 * 2105b7f77adStw21770 * Collecting the FMRI: 2115b7f77adStw21770 * 2125b7f77adStw21770 * The rc_node structure has a member called rn_fmri which points to 2135b7f77adStw21770 * its FMRI. This is initialized by a call to rc_node_build_fmri() 2145b7f77adStw21770 * when the node's parent is established. The reason for doing it 2155b7f77adStw21770 * at this time is that a node's FMRI is basically the concatenation 2165b7f77adStw21770 * of the parent's FMRI and the node's name with the appropriate 2175b7f77adStw21770 * decoration. rc_node_build_fmri() does this concatenation and 2185b7f77adStw21770 * decorating. It is called from rc_node_link_child() and 2195b7f77adStw21770 * rc_node_relink_child() where a node is linked to its parent. 2205b7f77adStw21770 * 2215b7f77adStw21770 * rc_node_get_fmri_or_fragment() is called to retrieve a node's FMRI 2225b7f77adStw21770 * when it is needed. It returns rn_fmri if it is set. If the node 2235b7f77adStw21770 * is at the top level, however, rn_fmri won't be set because it was 2245b7f77adStw21770 * never linked to a parent. In this case, 2255b7f77adStw21770 * rc_node_get_fmri_or_fragment() constructs an FMRI fragment based on 2265b7f77adStw21770 * its node type and its name, rn_name. 2275b7f77adStw21770 * 2285b7f77adStw21770 * Collecting the Authorization String: 2295b7f77adStw21770 * 2305b7f77adStw21770 * Naturally, the authorization string is captured during the 2315b7f77adStw21770 * authorization checking process. Acceptable authorization strings 2325b7f77adStw21770 * are added to a permcheck_t hash table as noted in the section on 2335b7f77adStw21770 * permission checking above. Once all entries have been added to the 2345b7f77adStw21770 * hash table, perm_granted() is called. If the client is authorized, 2355b7f77adStw21770 * perm_granted() returns with pc_auth_string of the permcheck_t 2365b7f77adStw21770 * structure pointing to the authorization string. 2375b7f77adStw21770 * 2385b7f77adStw21770 * This works fine if the client is authorized, but what happens if 2395b7f77adStw21770 * the client is not authorized? We need to report the required 2405b7f77adStw21770 * authorization string. This is the authorization that would have 2415b7f77adStw21770 * been used if permission had been granted. perm_granted() will 2425b7f77adStw21770 * find no match, so it needs to decide which string in the hash 2435b7f77adStw21770 * table to use as the required authorization string. It needs to do 2445b7f77adStw21770 * this, because configd is still going to generate an event. A 2455b7f77adStw21770 * design decision was made to use the most specific authorization 2465b7f77adStw21770 * in the hash table. The pc_auth_type enum designates the 2475b7f77adStw21770 * specificity of an authorization string. For example, an 2485b7f77adStw21770 * authorization string that is declared in an instance PG is more 2495b7f77adStw21770 * specific than one that is declared in a service PG. 2505b7f77adStw21770 * 2515b7f77adStw21770 * The pc_add() function keeps track of the most specific 2525b7f77adStw21770 * authorization in the hash table. It does this using the 2535b7f77adStw21770 * pc_specific and pc_specific_type members of the permcheck 2545b7f77adStw21770 * structure. pc_add() updates these members whenever a more 2555b7f77adStw21770 * specific authorization string is added to the hash table. Thus, if 2565b7f77adStw21770 * an authorization match is not found, perm_granted() will return 2575b7f77adStw21770 * with pc_auth_string in the permcheck_t pointing to the string that 2585b7f77adStw21770 * is referenced by pc_specific. 2595b7f77adStw21770 * 2605b7f77adStw21770 * Generating the Audit Events: 2615b7f77adStw21770 * =========================== 2625b7f77adStw21770 * 2635b7f77adStw21770 * As the functions in this file process requests for clients of 2645b7f77adStw21770 * configd, they gather the information that is required for an audit 2655b7f77adStw21770 * event. Eventually, the request processing gets to the point where 2665b7f77adStw21770 * the authorization is rejected or to the point where the requested 2675b7f77adStw21770 * action was attempted. At these two points smf_audit_event() is 2685b7f77adStw21770 * called. 2695b7f77adStw21770 * 2705b7f77adStw21770 * smf_audit_event() takes 4 parameters: 2715b7f77adStw21770 * - the event ID which is one of the ADT_smf_* symbols from 2725b7f77adStw21770 * adt_event.h. 2735b7f77adStw21770 * - status to pass to adt_put_event() 2745b7f77adStw21770 * - return value to pass to adt_put_event() 2755b7f77adStw21770 * - the event data (see audit_event_data structure) 2765b7f77adStw21770 * 2775b7f77adStw21770 * All interactions with the auditing software require an audit 2785b7f77adStw21770 * session. We use one audit session per configd client. We keep 2795b7f77adStw21770 * track of the audit session in the repcache_client structure. 2805b7f77adStw21770 * smf_audit_event() calls get_audit_session() to get the session 2815b7f77adStw21770 * pointer. 2825b7f77adStw21770 * 2835b7f77adStw21770 * smf_audit_event() then calls adt_alloc_event() to allocate an 2845b7f77adStw21770 * adt_event_data union which is defined in adt_event.h, copies the 2855b7f77adStw21770 * data into the appropriate members of the union and calls 2865b7f77adStw21770 * adt_put_event() to generate the event. 2875b7f77adStw21770 * 2885b7f77adStw21770 * Special Cases: 2895b7f77adStw21770 * ============= 2905b7f77adStw21770 * 2915b7f77adStw21770 * There are three major types of special cases: 2925b7f77adStw21770 * 2935b7f77adStw21770 * - gathering event information for each action in a 2945b7f77adStw21770 * transaction 2955b7f77adStw21770 * - Higher level events represented by special property 2965b7f77adStw21770 * group/property name combinations. Many of these are 2975b7f77adStw21770 * restarter actions. 2985b7f77adStw21770 * - ADT_smf_annotation event 2995b7f77adStw21770 * 3005b7f77adStw21770 * Processing Transaction Actions: 3015b7f77adStw21770 * ------------------------------ 3025b7f77adStw21770 * 3035b7f77adStw21770 * A transaction can contain multiple actions to modify, create or 3045b7f77adStw21770 * delete one or more properties. We need to capture information so 3055b7f77adStw21770 * that we can generate an event for each property action. The 3065b7f77adStw21770 * transaction information is stored in a tx_commmit_data_t, and 3075b7f77adStw21770 * object.c provides accessor functions to retrieve data from this 3085b7f77adStw21770 * structure. rc_tx_commit() obtains a tx_commit_data_t by calling 3095b7f77adStw21770 * tx_commit_data_new() and passes this to object_tx_commit() to 3105b7f77adStw21770 * commit the transaction. Then we call generate_property_events() to 3115b7f77adStw21770 * generate an audit event for each property action. 3125b7f77adStw21770 * 3135b7f77adStw21770 * Special Properties: 3145b7f77adStw21770 * ------------------ 3155b7f77adStw21770 * 3165b7f77adStw21770 * There are combinations of property group/property name that are special. 3175b7f77adStw21770 * They are special because they have specific meaning to startd. startd 3185b7f77adStw21770 * interprets them in a service-independent fashion. 3195b7f77adStw21770 * restarter_actions/refresh and general/enabled are two examples of these. 3205b7f77adStw21770 * A special event is generated for these properties in addition to the 3215b7f77adStw21770 * regular property event described in the previous section. The special 3225b7f77adStw21770 * properties are declared as an array of audit_special_prop_item 3235b7f77adStw21770 * structures at special_props_list in rc_node.c. 3245b7f77adStw21770 * 3255b7f77adStw21770 * In the previous section, we mentioned the 3265b7f77adStw21770 * generate_property_event() function that generates an event for 3275b7f77adStw21770 * every property action. Before generating the event, 3285b7f77adStw21770 * generate_property_event() calls special_property_event(). 3295b7f77adStw21770 * special_property_event() checks to see if the action involves a 3305b7f77adStw21770 * special property. If it does, it generates a special audit 3315b7f77adStw21770 * event. 3325b7f77adStw21770 * 3335b7f77adStw21770 * ADT_smf_annotation event: 3345b7f77adStw21770 * ------------------------ 3355b7f77adStw21770 * 3365b7f77adStw21770 * This is a special event unlike any other. It allows the svccfg 3375b7f77adStw21770 * program to store an annotation in the event log before a series 3385b7f77adStw21770 * of transactions is processed. It is used with the import and 3395b7f77adStw21770 * apply svccfg commands. svccfg uses the rep_protocol_annotation 3405b7f77adStw21770 * message to pass the operation (import or apply) and the file name 3415b7f77adStw21770 * to configd. The set_annotation() function in client.c stores 3425b7f77adStw21770 * these away in the a repcache_client structure. The address of 3435b7f77adStw21770 * this structure is saved in the thread_info structure. 3445b7f77adStw21770 * 3455b7f77adStw21770 * Before it generates any events, smf_audit_event() calls 3465b7f77adStw21770 * smf_annotation_event(). smf_annotation_event() calls 3475b7f77adStw21770 * client_annotation_needed() which is defined in client.c. If an 3485b7f77adStw21770 * annotation is needed client_annotation_needed() returns the 3495b7f77adStw21770 * operation and filename strings that were saved from the 3505b7f77adStw21770 * rep_protocol_annotation message. smf_annotation_event() then 3515b7f77adStw21770 * generates the ADT_smf_annotation event. 3525b7f77adStw21770 */ 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate #include <assert.h> 3557c478bd9Sstevel@tonic-gate #include <atomic.h> 3565b7f77adStw21770 #include <bsm/adt_event.h> 3577c478bd9Sstevel@tonic-gate #include <errno.h> 3587c478bd9Sstevel@tonic-gate #include <libuutil.h> 3597c478bd9Sstevel@tonic-gate #include <libscf.h> 3607c478bd9Sstevel@tonic-gate #include <libscf_priv.h> 3617c478bd9Sstevel@tonic-gate #include <pthread.h> 362499fd601Sgww #include <pwd.h> 3637c478bd9Sstevel@tonic-gate #include <stdio.h> 3647c478bd9Sstevel@tonic-gate #include <stdlib.h> 3657c478bd9Sstevel@tonic-gate #include <strings.h> 3667c478bd9Sstevel@tonic-gate #include <sys/types.h> 3675b7f77adStw21770 #include <syslog.h> 3687c478bd9Sstevel@tonic-gate #include <unistd.h> 369134a1f4eSCasper H.S. Dik #include <secdb.h> 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate #include "configd.h" 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate #define AUTH_PREFIX "solaris.smf." 3747c478bd9Sstevel@tonic-gate #define AUTH_MANAGE AUTH_PREFIX "manage" 3757c478bd9Sstevel@tonic-gate #define AUTH_MODIFY AUTH_PREFIX "modify" 3767c478bd9Sstevel@tonic-gate #define AUTH_MODIFY_PREFIX AUTH_MODIFY "." 3777c478bd9Sstevel@tonic-gate #define AUTH_PG_ACTIONS SCF_PG_RESTARTER_ACTIONS 3787c478bd9Sstevel@tonic-gate #define AUTH_PG_ACTIONS_TYPE SCF_PG_RESTARTER_ACTIONS_TYPE 3797c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL SCF_PG_GENERAL 3807c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_TYPE SCF_PG_GENERAL_TYPE 3817c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR SCF_PG_GENERAL_OVR 3827c478bd9Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR_TYPE SCF_PG_GENERAL_OVR_TYPE 3837c478bd9Sstevel@tonic-gate #define AUTH_PROP_ACTION "action_authorization" 3847c478bd9Sstevel@tonic-gate #define AUTH_PROP_ENABLED "enabled" 3857c478bd9Sstevel@tonic-gate #define AUTH_PROP_MODIFY "modify_authorization" 3867c478bd9Sstevel@tonic-gate #define AUTH_PROP_VALUE "value_authorization" 3873eae19d9Swesolows #define AUTH_PROP_READ "read_authorization" 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate #define MAX_VALID_CHILDREN 3 3907c478bd9Sstevel@tonic-gate 3915b7f77adStw21770 /* 3925b7f77adStw21770 * The ADT_smf_* symbols may not be defined on the build machine. Because 3935b7f77adStw21770 * of this, we do not want to compile the _smf_aud_event() function when 3945b7f77adStw21770 * doing native builds. 3955b7f77adStw21770 */ 3965b7f77adStw21770 #ifdef NATIVE_BUILD 3975b7f77adStw21770 #define smf_audit_event(i, s, r, d) 3985b7f77adStw21770 #else 3995b7f77adStw21770 #define smf_audit_event(i, s, r, d) _smf_audit_event(i, s, r, d) 4005b7f77adStw21770 #endif /* NATIVE_BUILD */ 4015b7f77adStw21770 4027c478bd9Sstevel@tonic-gate typedef struct rc_type_info { 4037c478bd9Sstevel@tonic-gate uint32_t rt_type; /* matches array index */ 4047c478bd9Sstevel@tonic-gate uint32_t rt_num_ids; 4057c478bd9Sstevel@tonic-gate uint32_t rt_name_flags; 4067c478bd9Sstevel@tonic-gate uint32_t rt_valid_children[MAX_VALID_CHILDREN]; 4077c478bd9Sstevel@tonic-gate } rc_type_info_t; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate #define RT_NO_NAME -1U 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate static rc_type_info_t rc_types[] = { 4127c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_NONE, 0, RT_NO_NAME}, 4137c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SCOPE, 0, 0, 4147c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, REP_PROTOCOL_ENTITY_SCOPE}}, 4157c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, 0, UU_NAME_DOMAIN | UU_NAME_PATH, 4167c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, REP_PROTOCOL_ENTITY_PROPERTYGRP}}, 4177c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, 1, UU_NAME_DOMAIN, 4187c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, REP_PROTOCOL_ENTITY_PROPERTYGRP}}, 4197c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, 2, UU_NAME_DOMAIN, 4207c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, REP_PROTOCOL_ENTITY_PROPERTYGRP}}, 4217c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, 4, RT_NO_NAME, 4227c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP}}, 4237c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP, 5, UU_NAME_DOMAIN, 4247c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}}, 4257c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_CPROPERTYGRP, 0, UU_NAME_DOMAIN, 4267c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}}, 4277c478bd9Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY, 7, UU_NAME_DOMAIN}, 4287c478bd9Sstevel@tonic-gate {-1UL} 4297c478bd9Sstevel@tonic-gate }; 4307c478bd9Sstevel@tonic-gate #define NUM_TYPES ((sizeof (rc_types) / sizeof (*rc_types))) 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* Element of a permcheck_t hash table. */ 4337c478bd9Sstevel@tonic-gate struct pc_elt { 4347c478bd9Sstevel@tonic-gate struct pc_elt *pce_next; 4357c478bd9Sstevel@tonic-gate char pce_auth[1]; 4367c478bd9Sstevel@tonic-gate }; 4377c478bd9Sstevel@tonic-gate 4385b7f77adStw21770 /* 4395b7f77adStw21770 * If an authorization fails, we must decide which of the elements in the 4405b7f77adStw21770 * permcheck hash table to use in the audit event. That is to say of all 4415b7f77adStw21770 * the strings in the hash table, we must choose one and use it in the audit 4425b7f77adStw21770 * event. It is desirable to use the most specific string in the audit 4435b7f77adStw21770 * event. 4445b7f77adStw21770 * 4455b7f77adStw21770 * The pc_auth_type specifies the types (sources) of authorization 4465b7f77adStw21770 * strings. The enum is ordered in increasing specificity. 4475b7f77adStw21770 */ 4485b7f77adStw21770 typedef enum pc_auth_type { 4495b7f77adStw21770 PC_AUTH_NONE = 0, /* no auth string available. */ 4505b7f77adStw21770 PC_AUTH_SMF, /* strings coded into SMF. */ 4515b7f77adStw21770 PC_AUTH_SVC, /* strings specified in PG of a service. */ 4525b7f77adStw21770 PC_AUTH_INST /* strings specified in PG of an instance. */ 4535b7f77adStw21770 } pc_auth_type_t; 4545b7f77adStw21770 455a4dc1477STom Whitten /* 456a4dc1477STom Whitten * The following enum is used to represent the results of the checks to see 457a4dc1477STom Whitten * if the client has the appropriate permissions to perform an action. 458a4dc1477STom Whitten */ 459a4dc1477STom Whitten typedef enum perm_status { 460a4dc1477STom Whitten PERM_DENIED = 0, /* Permission denied. */ 461a4dc1477STom Whitten PERM_GRANTED, /* Client has authorizations. */ 462a4dc1477STom Whitten PERM_GONE, /* Door client went away. */ 463a4dc1477STom Whitten PERM_FAIL /* Generic failure. e.g. resources */ 464a4dc1477STom Whitten } perm_status_t; 465a4dc1477STom Whitten 4667c478bd9Sstevel@tonic-gate /* An authorization set hash table. */ 4677c478bd9Sstevel@tonic-gate typedef struct { 4687c478bd9Sstevel@tonic-gate struct pc_elt **pc_buckets; 4697c478bd9Sstevel@tonic-gate uint_t pc_bnum; /* number of buckets */ 4707c478bd9Sstevel@tonic-gate uint_t pc_enum; /* number of elements */ 4715b7f77adStw21770 struct pc_elt *pc_specific; /* most specific element */ 4725b7f77adStw21770 pc_auth_type_t pc_specific_type; /* type of pc_specific */ 4735b7f77adStw21770 char *pc_auth_string; /* authorization string */ 4745b7f77adStw21770 /* for audit events */ 4757c478bd9Sstevel@tonic-gate } permcheck_t; 4767c478bd9Sstevel@tonic-gate 4775b7f77adStw21770 /* 4785b7f77adStw21770 * Structure for holding audit event data. Not all events use all members 4795b7f77adStw21770 * of the structure. 4805b7f77adStw21770 */ 4815b7f77adStw21770 typedef struct audit_event_data { 4825b7f77adStw21770 char *ed_auth; /* authorization string. */ 4835b7f77adStw21770 char *ed_fmri; /* affected FMRI. */ 4845b7f77adStw21770 char *ed_snapname; /* name of snapshot. */ 4855b7f77adStw21770 char *ed_old_fmri; /* old fmri in attach case. */ 4865b7f77adStw21770 char *ed_old_name; /* old snapshot in attach case. */ 4875b7f77adStw21770 char *ed_type; /* prop. group or prop. type. */ 4885b7f77adStw21770 char *ed_prop_value; /* property value. */ 4895b7f77adStw21770 } audit_event_data_t; 4905b7f77adStw21770 4915b7f77adStw21770 /* 4925b7f77adStw21770 * Pointer to function to do special processing to get audit event ID. 4935b7f77adStw21770 * Audit event IDs are defined in /usr/include/bsm/adt_event.h. Function 4945b7f77adStw21770 * returns 0 if ID successfully retrieved. Otherwise it returns -1. 4955b7f77adStw21770 */ 4965b7f77adStw21770 typedef int (*spc_getid_fn_t)(tx_commit_data_t *, size_t, const char *, 4975b7f77adStw21770 au_event_t *); 4985b7f77adStw21770 static int general_enable_id(tx_commit_data_t *, size_t, const char *, 4995b7f77adStw21770 au_event_t *); 5005b7f77adStw21770 5017c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_children_pool; 5027c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_pg_notify_pool; 5037c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_notify_pool; 5047c478bd9Sstevel@tonic-gate static uu_list_pool_t *rc_notify_info_pool; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate static rc_node_t *rc_scope; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate static pthread_mutex_t rc_pg_notify_lock = PTHREAD_MUTEX_INITIALIZER; 5097c478bd9Sstevel@tonic-gate static pthread_cond_t rc_pg_notify_cv = PTHREAD_COND_INITIALIZER; 5107c478bd9Sstevel@tonic-gate static uint_t rc_notify_in_use; /* blocks removals */ 5117c478bd9Sstevel@tonic-gate 5125b7f77adStw21770 /* 5135b7f77adStw21770 * Some combinations of property group/property name require a special 5145b7f77adStw21770 * audit event to be generated when there is a change. 5155b7f77adStw21770 * audit_special_prop_item_t is used to specify these special cases. The 5165b7f77adStw21770 * special_props_list array defines a list of these special properties. 5175b7f77adStw21770 */ 5185b7f77adStw21770 typedef struct audit_special_prop_item { 5195b7f77adStw21770 const char *api_pg_name; /* property group name. */ 5205b7f77adStw21770 const char *api_prop_name; /* property name. */ 5215b7f77adStw21770 au_event_t api_event_id; /* event id or 0. */ 5225b7f77adStw21770 spc_getid_fn_t api_event_func; /* function to get event id. */ 5235b7f77adStw21770 } audit_special_prop_item_t; 5245b7f77adStw21770 5255b7f77adStw21770 /* 5265b7f77adStw21770 * Native builds are done using the build machine's standard include 5275b7f77adStw21770 * files. These files may not yet have the definitions for the ADT_smf_* 5285b7f77adStw21770 * symbols. Thus, we do not compile this table when doing native builds. 5295b7f77adStw21770 */ 5305b7f77adStw21770 #ifndef NATIVE_BUILD 5315b7f77adStw21770 /* 5325b7f77adStw21770 * The following special_props_list array specifies property group/property 5335b7f77adStw21770 * name combinations that have specific meaning to startd. A special event 5345b7f77adStw21770 * is generated for these combinations in addition to the regular property 5355b7f77adStw21770 * event. 5365b7f77adStw21770 * 5375b7f77adStw21770 * At run time this array gets sorted. See the call to qsort(3C) in 5385b7f77adStw21770 * rc_node_init(). The array is sorted, so that bsearch(3C) can be used 5395b7f77adStw21770 * to do lookups. 5405b7f77adStw21770 */ 5415b7f77adStw21770 static audit_special_prop_item_t special_props_list[] = { 5425b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADED, ADT_smf_degrade, 5435b7f77adStw21770 NULL}, 5445b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADE_IMMEDIATE, 5455b7f77adStw21770 ADT_smf_immediate_degrade, NULL}, 5465b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_OFF, ADT_smf_clear, NULL}, 5475b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON, 5485b7f77adStw21770 ADT_smf_maintenance, NULL}, 5495b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMEDIATE, 5505b7f77adStw21770 ADT_smf_immediate_maintenance, NULL}, 5515b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMTEMP, 5525b7f77adStw21770 ADT_smf_immtmp_maintenance, NULL}, 5535b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_TEMPORARY, 5545b7f77adStw21770 ADT_smf_tmp_maintenance, NULL}, 5555b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_REFRESH, ADT_smf_refresh, NULL}, 5565b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTART, ADT_smf_restart, NULL}, 5575b7f77adStw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTORE, ADT_smf_clear, NULL}, 5585b7f77adStw21770 {SCF_PG_OPTIONS, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL}, 5595b7f77adStw21770 {SCF_PG_OPTIONS_OVR, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL}, 5605b7f77adStw21770 {SCF_PG_GENERAL, SCF_PROPERTY_ENABLED, 0, general_enable_id}, 5615b7f77adStw21770 {SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 0, general_enable_id} 5625b7f77adStw21770 }; 5635b7f77adStw21770 #define SPECIAL_PROP_COUNT (sizeof (special_props_list) /\ 5645b7f77adStw21770 sizeof (audit_special_prop_item_t)) 5655b7f77adStw21770 #endif /* NATIVE_BUILD */ 5665b7f77adStw21770 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * We support an arbitrary number of clients interested in events for certain 5697c478bd9Sstevel@tonic-gate * types of changes. Each client is represented by an rc_notify_info_t, and 5707c478bd9Sstevel@tonic-gate * all clients are chained onto the rc_notify_info_list. 5717c478bd9Sstevel@tonic-gate * 5727c478bd9Sstevel@tonic-gate * The rc_notify_list is the global notification list. Each entry is of 5737c478bd9Sstevel@tonic-gate * type rc_notify_t, which is embedded in one of three other structures: 5747c478bd9Sstevel@tonic-gate * 5757c478bd9Sstevel@tonic-gate * rc_node_t property group update notification 5767c478bd9Sstevel@tonic-gate * rc_notify_delete_t object deletion notification 5777c478bd9Sstevel@tonic-gate * rc_notify_info_t notification clients 5787c478bd9Sstevel@tonic-gate * 5797c478bd9Sstevel@tonic-gate * Which type of object is determined by which pointer in the rc_notify_t is 5807c478bd9Sstevel@tonic-gate * non-NULL. 5817c478bd9Sstevel@tonic-gate * 5827c478bd9Sstevel@tonic-gate * New notifications and clients are added to the end of the list. 5837c478bd9Sstevel@tonic-gate * Notifications no-one is interested in are never added to the list. 5847c478bd9Sstevel@tonic-gate * 5857c478bd9Sstevel@tonic-gate * Clients use their position in the list to track which notifications they 5867c478bd9Sstevel@tonic-gate * have not yet reported. As they process notifications, they move forward 5877c478bd9Sstevel@tonic-gate * in the list past them. There is always a client at the beginning of the 5887c478bd9Sstevel@tonic-gate * list -- as he moves past notifications, he removes them from the list and 5897c478bd9Sstevel@tonic-gate * cleans them up. 5907c478bd9Sstevel@tonic-gate * 5917c478bd9Sstevel@tonic-gate * The rc_pg_notify_lock protects all notification state. The rc_pg_notify_cv 5927c478bd9Sstevel@tonic-gate * is used for global signalling, and each client has a cv which he waits for 5937c478bd9Sstevel@tonic-gate * events of interest on. 594b5cbdab0STom Whitten * 595b5cbdab0STom Whitten * rc_notify_in_use is used to protect rc_notify_list from deletions when 596b5cbdab0STom Whitten * the rc_pg_notify_lock is dropped. Specifically, rc_notify_info_wait() 597b5cbdab0STom Whitten * must drop the lock to call rc_node_assign(), and then it reacquires the 598b5cbdab0STom Whitten * lock. Deletions from rc_notify_list during this period are not 599b5cbdab0STom Whitten * allowed. Insertions do not matter, because they are always done at the 600b5cbdab0STom Whitten * end of the list. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate static uu_list_t *rc_notify_info_list; 6037c478bd9Sstevel@tonic-gate static uu_list_t *rc_notify_list; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate #define HASH_SIZE 512 6067c478bd9Sstevel@tonic-gate #define HASH_MASK (HASH_SIZE - 1) 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate #pragma align 64(cache_hash) 6097c478bd9Sstevel@tonic-gate static cache_bucket_t cache_hash[HASH_SIZE]; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate #define CACHE_BUCKET(h) (&cache_hash[(h) & HASH_MASK]) 6127c478bd9Sstevel@tonic-gate 6136643e1ffSbustos 6146643e1ffSbustos static void rc_node_no_client_refs(rc_node_t *np); 6156643e1ffSbustos 6166643e1ffSbustos 6177c478bd9Sstevel@tonic-gate static uint32_t 6187c478bd9Sstevel@tonic-gate rc_node_hash(rc_node_lookup_t *lp) 6197c478bd9Sstevel@tonic-gate { 6207c478bd9Sstevel@tonic-gate uint32_t type = lp->rl_type; 6217c478bd9Sstevel@tonic-gate uint32_t backend = lp->rl_backend; 6220b5c9250Shg115875 uint32_t mainid = lp->rl_main_id; 6237c478bd9Sstevel@tonic-gate uint32_t *ids = lp->rl_ids; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate rc_type_info_t *tp = &rc_types[type]; 6267c478bd9Sstevel@tonic-gate uint32_t num_ids; 6277c478bd9Sstevel@tonic-gate uint32_t left; 6287c478bd9Sstevel@tonic-gate uint32_t hash; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate assert(backend == BACKEND_TYPE_NORMAL || 6317c478bd9Sstevel@tonic-gate backend == BACKEND_TYPE_NONPERSIST); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES); 6347c478bd9Sstevel@tonic-gate num_ids = tp->rt_num_ids; 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate left = MAX_IDS - num_ids; 6377c478bd9Sstevel@tonic-gate assert(num_ids <= MAX_IDS); 6387c478bd9Sstevel@tonic-gate 6390b5c9250Shg115875 hash = type * 7 + mainid * 5 + backend; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate while (num_ids-- > 0) 6427c478bd9Sstevel@tonic-gate hash = hash * 11 + *ids++ * 7; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * the rest should be zeroed 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate while (left-- > 0) 6487c478bd9Sstevel@tonic-gate assert(*ids++ == 0); 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate return (hash); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate static int 6547c478bd9Sstevel@tonic-gate rc_node_match(rc_node_t *np, rc_node_lookup_t *l) 6557c478bd9Sstevel@tonic-gate { 6567c478bd9Sstevel@tonic-gate rc_node_lookup_t *r = &np->rn_id; 6577c478bd9Sstevel@tonic-gate rc_type_info_t *tp; 6587c478bd9Sstevel@tonic-gate uint32_t type; 6597c478bd9Sstevel@tonic-gate uint32_t num_ids; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (r->rl_main_id != l->rl_main_id) 6627c478bd9Sstevel@tonic-gate return (0); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate type = r->rl_type; 6657c478bd9Sstevel@tonic-gate if (type != l->rl_type) 6667c478bd9Sstevel@tonic-gate return (0); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate tp = &rc_types[r->rl_type]; 6717c478bd9Sstevel@tonic-gate num_ids = tp->rt_num_ids; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate assert(num_ids <= MAX_IDS); 6747c478bd9Sstevel@tonic-gate while (num_ids-- > 0) 6757c478bd9Sstevel@tonic-gate if (r->rl_ids[num_ids] != l->rl_ids[num_ids]) 6767c478bd9Sstevel@tonic-gate return (0); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate return (1); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6826643e1ffSbustos * Register an ephemeral reference to np. This should be done while both 6836643e1ffSbustos * the persistent reference from which the np pointer was read is locked 6846643e1ffSbustos * and np itself is locked. This guarantees that another thread which 6856643e1ffSbustos * thinks it has the last reference will yield without destroying the 6866643e1ffSbustos * node. 6876643e1ffSbustos */ 6886643e1ffSbustos static void 6896643e1ffSbustos rc_node_hold_ephemeral_locked(rc_node_t *np) 6906643e1ffSbustos { 6916643e1ffSbustos assert(MUTEX_HELD(&np->rn_lock)); 6926643e1ffSbustos 6936643e1ffSbustos ++np->rn_erefs; 6946643e1ffSbustos } 6956643e1ffSbustos 6966643e1ffSbustos /* 6977c478bd9Sstevel@tonic-gate * the "other" references on a node are maintained in an atomically 6987c478bd9Sstevel@tonic-gate * updated refcount, rn_other_refs. This can be bumped from arbitrary 6997c478bd9Sstevel@tonic-gate * context, and tracks references to a possibly out-of-date node's children. 7007c478bd9Sstevel@tonic-gate * 7017c478bd9Sstevel@tonic-gate * To prevent the node from disappearing between the final drop of 7027c478bd9Sstevel@tonic-gate * rn_other_refs and the unref handling, rn_other_refs_held is bumped on 7037c478bd9Sstevel@tonic-gate * 0->1 transitions and decremented (with the node lock held) on 1->0 7047c478bd9Sstevel@tonic-gate * transitions. 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate static void 7077c478bd9Sstevel@tonic-gate rc_node_hold_other(rc_node_t *np) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, 1) == 1) { 7107c478bd9Sstevel@tonic-gate atomic_add_32(&np->rn_other_refs_held, 1); 7117c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held > 0); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate assert(np->rn_other_refs > 0); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * No node locks may be held 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate static void 7207c478bd9Sstevel@tonic-gate rc_node_rele_other(rc_node_t *np) 7217c478bd9Sstevel@tonic-gate { 7227c478bd9Sstevel@tonic-gate assert(np->rn_other_refs > 0); 7237c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, -1) == 0) { 7247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 7257c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held > 0); 7267c478bd9Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs_held, -1) == 0 && 7276643e1ffSbustos np->rn_refs == 0 && (np->rn_flags & RC_NODE_OLD)) { 7286643e1ffSbustos /* 7296643e1ffSbustos * This was the last client reference. Destroy 7306643e1ffSbustos * any other references and free() the node. 7316643e1ffSbustos */ 7326643e1ffSbustos rc_node_no_client_refs(np); 7336643e1ffSbustos } else { 7347c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate } 7376643e1ffSbustos } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate static void 7407c478bd9Sstevel@tonic-gate rc_node_hold_locked(rc_node_t *np) 7417c478bd9Sstevel@tonic-gate { 7427c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate if (np->rn_refs == 0 && (np->rn_flags & RC_NODE_PARENT_REF)) 7457c478bd9Sstevel@tonic-gate rc_node_hold_other(np->rn_parent_ref); 7467c478bd9Sstevel@tonic-gate np->rn_refs++; 7477c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate static void 7517c478bd9Sstevel@tonic-gate rc_node_hold(rc_node_t *np) 7527c478bd9Sstevel@tonic-gate { 7537c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 7547c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); 7557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate static void 7597c478bd9Sstevel@tonic-gate rc_node_rele_locked(rc_node_t *np) 7607c478bd9Sstevel@tonic-gate { 7617c478bd9Sstevel@tonic-gate int unref = 0; 7627c478bd9Sstevel@tonic-gate rc_node_t *par_ref = NULL; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 7657c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate if (--np->rn_refs == 0) { 7687c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_PARENT_REF) 7697c478bd9Sstevel@tonic-gate par_ref = np->rn_parent_ref; 7707c478bd9Sstevel@tonic-gate 771fda74dabSbustos /* 772fda74dabSbustos * Composed property groups are only as good as their 773fda74dabSbustos * references. 774fda74dabSbustos */ 775fda74dabSbustos if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) 776fda74dabSbustos np->rn_flags |= RC_NODE_DEAD; 777fda74dabSbustos 7787c478bd9Sstevel@tonic-gate if ((np->rn_flags & (RC_NODE_DEAD|RC_NODE_OLD)) && 7797c478bd9Sstevel@tonic-gate np->rn_other_refs == 0 && np->rn_other_refs_held == 0) 7807c478bd9Sstevel@tonic-gate unref = 1; 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7836643e1ffSbustos if (unref) { 7846643e1ffSbustos /* 7856643e1ffSbustos * This was the last client reference. Destroy any other 7866643e1ffSbustos * references and free() the node. 7876643e1ffSbustos */ 7886643e1ffSbustos rc_node_no_client_refs(np); 7896643e1ffSbustos } else { 7906643e1ffSbustos /* 7916643e1ffSbustos * rn_erefs can be 0 if we acquired the reference in 7926643e1ffSbustos * a path which hasn't been updated to increment rn_erefs. 7936643e1ffSbustos * When all paths which end here are updated, we should 7946643e1ffSbustos * assert rn_erefs > 0 and always decrement it. 7956643e1ffSbustos */ 7966643e1ffSbustos if (np->rn_erefs > 0) 7976643e1ffSbustos --np->rn_erefs; 7987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 7996643e1ffSbustos } 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate if (par_ref != NULL) 8027c478bd9Sstevel@tonic-gate rc_node_rele_other(par_ref); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate void 8067c478bd9Sstevel@tonic-gate rc_node_rele(rc_node_t *np) 8077c478bd9Sstevel@tonic-gate { 8087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 8097c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate static cache_bucket_t * 8137c478bd9Sstevel@tonic-gate cache_hold(uint32_t h) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate cache_bucket_t *bp = CACHE_BUCKET(h); 8167c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 8177c478bd9Sstevel@tonic-gate return (bp); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate static void 8217c478bd9Sstevel@tonic-gate cache_release(cache_bucket_t *bp) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate static rc_node_t * 8277c478bd9Sstevel@tonic-gate cache_lookup_unlocked(cache_bucket_t *bp, rc_node_lookup_t *lp) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(lp); 8307c478bd9Sstevel@tonic-gate rc_node_t *np; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock)); 8337c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(h)); 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate for (np = bp->cb_head; np != NULL; np = np->rn_hash_next) { 8367c478bd9Sstevel@tonic-gate if (np->rn_hash == h && rc_node_match(np, lp)) { 8377c478bd9Sstevel@tonic-gate rc_node_hold(np); 8387c478bd9Sstevel@tonic-gate return (np); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate return (NULL); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate static rc_node_t * 8467c478bd9Sstevel@tonic-gate cache_lookup(rc_node_lookup_t *lp) 8477c478bd9Sstevel@tonic-gate { 8487c478bd9Sstevel@tonic-gate uint32_t h; 8497c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 8507c478bd9Sstevel@tonic-gate rc_node_t *np; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate h = rc_node_hash(lp); 8537c478bd9Sstevel@tonic-gate bp = cache_hold(h); 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate np = cache_lookup_unlocked(bp, lp); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate cache_release(bp); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate return (np); 8607c478bd9Sstevel@tonic-gate } 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate static void 8637c478bd9Sstevel@tonic-gate cache_insert_unlocked(cache_bucket_t *bp, rc_node_t *np) 8647c478bd9Sstevel@tonic-gate { 8657c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock)); 8667c478bd9Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id)); 8677c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash)); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate assert(np->rn_hash_next == NULL); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate np->rn_hash_next = bp->cb_head; 8727c478bd9Sstevel@tonic-gate bp->cb_head = np; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate static void 8767c478bd9Sstevel@tonic-gate cache_remove_unlocked(cache_bucket_t *bp, rc_node_t *np) 8777c478bd9Sstevel@tonic-gate { 8787c478bd9Sstevel@tonic-gate rc_node_t **npp; 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock)); 8817c478bd9Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id)); 8827c478bd9Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash)); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate for (npp = &bp->cb_head; *npp != NULL; npp = &(*npp)->rn_hash_next) 8857c478bd9Sstevel@tonic-gate if (*npp == np) 8867c478bd9Sstevel@tonic-gate break; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate assert(*npp == np); 8897c478bd9Sstevel@tonic-gate *npp = np->rn_hash_next; 8907c478bd9Sstevel@tonic-gate np->rn_hash_next = NULL; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * verify that the 'parent' type can have a child typed 'child' 8957c478bd9Sstevel@tonic-gate * Fails with 8967c478bd9Sstevel@tonic-gate * _INVALID_TYPE - argument is invalid 8977c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent type cannot have children of type child 8987c478bd9Sstevel@tonic-gate */ 8997c478bd9Sstevel@tonic-gate static int 9007c478bd9Sstevel@tonic-gate rc_check_parent_child(uint32_t parent, uint32_t child) 9017c478bd9Sstevel@tonic-gate { 9027c478bd9Sstevel@tonic-gate int idx; 9037c478bd9Sstevel@tonic-gate uint32_t type; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate if (parent == 0 || parent >= NUM_TYPES || 9067c478bd9Sstevel@tonic-gate child == 0 || child >= NUM_TYPES) 9077c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */ 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate for (idx = 0; idx < MAX_VALID_CHILDREN; idx++) { 9107c478bd9Sstevel@tonic-gate type = rc_types[parent].rt_valid_children[idx]; 9117c478bd9Sstevel@tonic-gate if (type == child) 9127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * Fails with 9207c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 9217c478bd9Sstevel@tonic-gate * _BAD_REQUEST - name is an invalid name for a node of type type 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate int 9247c478bd9Sstevel@tonic-gate rc_check_type_name(uint32_t type, const char *name) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate if (type == 0 || type >= NUM_TYPES) 9277c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */ 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate if (uu_check_name(name, rc_types[type].rt_name_flags) == -1) 9307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate static int 9367c478bd9Sstevel@tonic-gate rc_check_pgtype_name(const char *name) 9377c478bd9Sstevel@tonic-gate { 9387c478bd9Sstevel@tonic-gate if (uu_check_name(name, UU_NAME_DOMAIN) == -1) 9397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate 9445b7f77adStw21770 /* 9455b7f77adStw21770 * rc_node_free_fmri should be called whenever a node loses its parent. 9465b7f77adStw21770 * The reason is that the node's fmri string is built up by concatenating 9475b7f77adStw21770 * its name to the parent's fmri. Thus, when the node no longer has a 9485b7f77adStw21770 * parent, its fmri is no longer valid. 9495b7f77adStw21770 */ 9505b7f77adStw21770 static void 9515b7f77adStw21770 rc_node_free_fmri(rc_node_t *np) 9525b7f77adStw21770 { 9535b7f77adStw21770 if (np->rn_fmri != NULL) { 9545b7f77adStw21770 free((void *)np->rn_fmri); 9555b7f77adStw21770 np->rn_fmri = NULL; 9565b7f77adStw21770 } 9575b7f77adStw21770 } 9585b7f77adStw21770 9595b7f77adStw21770 /* 9605b7f77adStw21770 * Concatenate the appropriate separator and the FMRI element to the base 9615b7f77adStw21770 * FMRI string at fmri. 9625b7f77adStw21770 * 9635b7f77adStw21770 * Fails with 9645b7f77adStw21770 * _TRUNCATED Not enough room in buffer at fmri. 9655b7f77adStw21770 */ 9665b7f77adStw21770 static int 9675b7f77adStw21770 rc_concat_fmri_element( 9685b7f77adStw21770 char *fmri, /* base fmri */ 9695b7f77adStw21770 size_t bufsize, /* size of buf at fmri */ 9705b7f77adStw21770 size_t *sz_out, /* receives result size. */ 9715b7f77adStw21770 const char *element, /* element name to concat */ 9725b7f77adStw21770 rep_protocol_entity_t type) /* type of element */ 9735b7f77adStw21770 { 9745b7f77adStw21770 size_t actual; 9755b7f77adStw21770 const char *name = element; 9765b7f77adStw21770 int rc; 9775b7f77adStw21770 const char *separator; 9785b7f77adStw21770 9795b7f77adStw21770 if (bufsize > 0) 9805b7f77adStw21770 *sz_out = strlen(fmri); 9815b7f77adStw21770 else 9825b7f77adStw21770 *sz_out = 0; 9835b7f77adStw21770 9845b7f77adStw21770 switch (type) { 9855b7f77adStw21770 case REP_PROTOCOL_ENTITY_SCOPE: 9865b7f77adStw21770 if (strcmp(element, SCF_FMRI_LOCAL_SCOPE) == 0) { 9875b7f77adStw21770 /* 9885b7f77adStw21770 * No need to display scope information if we are 9895b7f77adStw21770 * in the local scope. 9905b7f77adStw21770 */ 9915b7f77adStw21770 separator = SCF_FMRI_SVC_PREFIX; 9925b7f77adStw21770 name = NULL; 9935b7f77adStw21770 } else { 9945b7f77adStw21770 /* 9955b7f77adStw21770 * Need to display scope information, because it is 9965b7f77adStw21770 * not the local scope. 9975b7f77adStw21770 */ 9985b7f77adStw21770 separator = SCF_FMRI_SVC_PREFIX SCF_FMRI_SCOPE_PREFIX; 9995b7f77adStw21770 } 10005b7f77adStw21770 break; 10015b7f77adStw21770 case REP_PROTOCOL_ENTITY_SERVICE: 10025b7f77adStw21770 separator = SCF_FMRI_SERVICE_PREFIX; 10035b7f77adStw21770 break; 10045b7f77adStw21770 case REP_PROTOCOL_ENTITY_INSTANCE: 10055b7f77adStw21770 separator = SCF_FMRI_INSTANCE_PREFIX; 10065b7f77adStw21770 break; 10075b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP: 10085b7f77adStw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP: 10095b7f77adStw21770 separator = SCF_FMRI_PROPERTYGRP_PREFIX; 10105b7f77adStw21770 break; 10115b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTY: 10125b7f77adStw21770 separator = SCF_FMRI_PROPERTY_PREFIX; 10135b7f77adStw21770 break; 10145b7f77adStw21770 case REP_PROTOCOL_ENTITY_VALUE: 10155b7f77adStw21770 /* 10165b7f77adStw21770 * A value does not have a separate FMRI from its property, 10175b7f77adStw21770 * so there is nothing to concat. 10185b7f77adStw21770 */ 10195b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 10205b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT: 10215b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPLEVEL: 10225b7f77adStw21770 /* Snapshots do not have FMRIs, so there is nothing to do. */ 10235b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 10245b7f77adStw21770 default: 10255b7f77adStw21770 (void) fprintf(stderr, "%s:%d: Unknown protocol type %d.\n", 10265b7f77adStw21770 __FILE__, __LINE__, type); 10275b7f77adStw21770 abort(); /* Missing a case in switch if we get here. */ 10285b7f77adStw21770 } 10295b7f77adStw21770 10305b7f77adStw21770 /* Concatenate separator and element to the fmri buffer. */ 10315b7f77adStw21770 10325b7f77adStw21770 actual = strlcat(fmri, separator, bufsize); 10335b7f77adStw21770 if (name != NULL) { 10345b7f77adStw21770 if (actual < bufsize) { 10355b7f77adStw21770 actual = strlcat(fmri, name, bufsize); 10365b7f77adStw21770 } else { 10375b7f77adStw21770 actual += strlen(name); 10385b7f77adStw21770 } 10395b7f77adStw21770 } 10405b7f77adStw21770 if (actual < bufsize) { 10415b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 10425b7f77adStw21770 } else { 10435b7f77adStw21770 rc = REP_PROTOCOL_FAIL_TRUNCATED; 10445b7f77adStw21770 } 10455b7f77adStw21770 *sz_out = actual; 10465b7f77adStw21770 return (rc); 10475b7f77adStw21770 } 10485b7f77adStw21770 10495b7f77adStw21770 /* 10505b7f77adStw21770 * Get the FMRI for the node at np. The fmri will be placed in buf. On 10515b7f77adStw21770 * success sz_out will be set to the size of the fmri in buf. If 10525b7f77adStw21770 * REP_PROTOCOL_FAIL_TRUNCATED is returned, sz_out will be set to the size 10535b7f77adStw21770 * of the buffer that would be required to avoid truncation. 10545b7f77adStw21770 * 10555b7f77adStw21770 * Fails with 10565b7f77adStw21770 * _TRUNCATED not enough room in buf for the FMRI. 10575b7f77adStw21770 */ 10585b7f77adStw21770 static int 10595b7f77adStw21770 rc_node_get_fmri_or_fragment(rc_node_t *np, char *buf, size_t bufsize, 10605b7f77adStw21770 size_t *sz_out) 10615b7f77adStw21770 { 10625b7f77adStw21770 size_t fmri_len = 0; 10635b7f77adStw21770 int r; 10645b7f77adStw21770 10655b7f77adStw21770 if (bufsize > 0) 10665b7f77adStw21770 *buf = 0; 10675b7f77adStw21770 *sz_out = 0; 10685b7f77adStw21770 10695b7f77adStw21770 if (np->rn_fmri == NULL) { 10705b7f77adStw21770 /* 10715b7f77adStw21770 * A NULL rn_fmri implies that this is a top level scope. 10725b7f77adStw21770 * Child nodes will always have an rn_fmri established 10735b7f77adStw21770 * because both rc_node_link_child() and 10745b7f77adStw21770 * rc_node_relink_child() call rc_node_build_fmri(). In 10755b7f77adStw21770 * this case, we'll just return our name preceded by the 10765b7f77adStw21770 * appropriate FMRI decorations. 10775b7f77adStw21770 */ 10785b7f77adStw21770 assert(np->rn_parent == NULL); 10795b7f77adStw21770 r = rc_concat_fmri_element(buf, bufsize, &fmri_len, np->rn_name, 10805b7f77adStw21770 np->rn_id.rl_type); 10815b7f77adStw21770 if (r != REP_PROTOCOL_SUCCESS) 10825b7f77adStw21770 return (r); 10835b7f77adStw21770 } else { 10845b7f77adStw21770 /* We have an fmri, so return it. */ 10855b7f77adStw21770 fmri_len = strlcpy(buf, np->rn_fmri, bufsize); 10865b7f77adStw21770 } 10875b7f77adStw21770 10885b7f77adStw21770 *sz_out = fmri_len; 10895b7f77adStw21770 10905b7f77adStw21770 if (fmri_len >= bufsize) 10915b7f77adStw21770 return (REP_PROTOCOL_FAIL_TRUNCATED); 10925b7f77adStw21770 10935b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 10945b7f77adStw21770 } 10955b7f77adStw21770 10965b7f77adStw21770 /* 10975b7f77adStw21770 * Build an FMRI string for this node and save it in rn_fmri. 10985b7f77adStw21770 * 10995b7f77adStw21770 * The basic strategy here is to get the fmri of our parent and then 11005b7f77adStw21770 * concatenate the appropriate separator followed by our name. If our name 11015b7f77adStw21770 * is null, the resulting fmri will just be a copy of the parent fmri. 11025b7f77adStw21770 * rc_node_build_fmri() should be called with the RC_NODE_USING_PARENT flag 11035b7f77adStw21770 * set. Also the rn_lock for this node should be held. 11045b7f77adStw21770 * 11055b7f77adStw21770 * Fails with 11065b7f77adStw21770 * _NO_RESOURCES Could not allocate memory. 11075b7f77adStw21770 */ 11085b7f77adStw21770 static int 11095b7f77adStw21770 rc_node_build_fmri(rc_node_t *np) 11105b7f77adStw21770 { 11115b7f77adStw21770 size_t actual; 11125b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN]; 11135b7f77adStw21770 int rc; 11145b7f77adStw21770 size_t sz = REP_PROTOCOL_FMRI_LEN; 11155b7f77adStw21770 11165b7f77adStw21770 assert(MUTEX_HELD(&np->rn_lock)); 11175b7f77adStw21770 assert(np->rn_flags & RC_NODE_USING_PARENT); 11185b7f77adStw21770 11195b7f77adStw21770 rc_node_free_fmri(np); 11205b7f77adStw21770 11215b7f77adStw21770 rc = rc_node_get_fmri_or_fragment(np->rn_parent, fmri, sz, &actual); 11225b7f77adStw21770 assert(rc == REP_PROTOCOL_SUCCESS); 11235b7f77adStw21770 11245b7f77adStw21770 if (np->rn_name != NULL) { 11255b7f77adStw21770 rc = rc_concat_fmri_element(fmri, sz, &actual, np->rn_name, 11265b7f77adStw21770 np->rn_id.rl_type); 11275b7f77adStw21770 assert(rc == REP_PROTOCOL_SUCCESS); 11285b7f77adStw21770 np->rn_fmri = strdup(fmri); 11295b7f77adStw21770 } else { 11305b7f77adStw21770 np->rn_fmri = strdup(fmri); 11315b7f77adStw21770 } 11325b7f77adStw21770 if (np->rn_fmri == NULL) { 11335b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 11345b7f77adStw21770 } else { 11355b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 11365b7f77adStw21770 } 11375b7f77adStw21770 11385b7f77adStw21770 return (rc); 11395b7f77adStw21770 } 11405b7f77adStw21770 11415b7f77adStw21770 /* 11425b7f77adStw21770 * Get the FMRI of the node at np placing the result in fmri. Then 11435b7f77adStw21770 * concatenate the additional element to fmri. The type variable indicates 11445b7f77adStw21770 * the type of element, so that the appropriate separator can be 11455b7f77adStw21770 * generated. size is the number of bytes in the buffer at fmri, and 11465b7f77adStw21770 * sz_out receives the size of the generated string. If the result is 11475b7f77adStw21770 * truncated, sz_out will receive the size of the buffer that would be 11485b7f77adStw21770 * required to avoid truncation. 11495b7f77adStw21770 * 11505b7f77adStw21770 * Fails with 11515b7f77adStw21770 * _TRUNCATED Not enough room in buffer at fmri. 11525b7f77adStw21770 */ 11535b7f77adStw21770 static int 11545b7f77adStw21770 rc_get_fmri_and_concat(rc_node_t *np, char *fmri, size_t size, size_t *sz_out, 11555b7f77adStw21770 const char *element, rep_protocol_entity_t type) 11565b7f77adStw21770 { 11575b7f77adStw21770 int rc; 11585b7f77adStw21770 11595b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, size, sz_out)) != 11605b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 11615b7f77adStw21770 return (rc); 11625b7f77adStw21770 } 11635b7f77adStw21770 if ((rc = rc_concat_fmri_element(fmri, size, sz_out, element, type)) != 11645b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 11655b7f77adStw21770 return (rc); 11665b7f77adStw21770 } 11675b7f77adStw21770 11685b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 11695b7f77adStw21770 } 11705b7f77adStw21770 11717c478bd9Sstevel@tonic-gate static int 11727c478bd9Sstevel@tonic-gate rc_notify_info_interested(rc_notify_info_t *rnip, rc_notify_t *np) 11737c478bd9Sstevel@tonic-gate { 11747c478bd9Sstevel@tonic-gate rc_node_t *nnp = np->rcn_node; 11757c478bd9Sstevel@tonic-gate int i; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock)); 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate if (np->rcn_delete != NULL) { 11807c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL && np->rcn_node == NULL); 11817c478bd9Sstevel@tonic-gate return (1); /* everyone likes deletes */ 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate if (np->rcn_node == NULL) { 11847c478bd9Sstevel@tonic-gate assert(np->rcn_info != NULL || np->rcn_delete != NULL); 11857c478bd9Sstevel@tonic-gate return (0); 11867c478bd9Sstevel@tonic-gate } 11877c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL); 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) { 11907c478bd9Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) { 11917c478bd9Sstevel@tonic-gate if (strcmp(nnp->rn_name, rnip->rni_namelist[i]) == 0) 11927c478bd9Sstevel@tonic-gate return (1); 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) { 11957c478bd9Sstevel@tonic-gate if (strcmp(nnp->rn_type, rnip->rni_typelist[i]) == 0) 11967c478bd9Sstevel@tonic-gate return (1); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate return (0); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate static void 12037c478bd9Sstevel@tonic-gate rc_notify_insert_node(rc_node_t *nnp) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify; 12067c478bd9Sstevel@tonic-gate rc_notify_info_t *nip; 12077c478bd9Sstevel@tonic-gate int found = 0; 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL); 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (nnp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) 12127c478bd9Sstevel@tonic-gate return; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 12157c478bd9Sstevel@tonic-gate np->rcn_node = nnp; 12167c478bd9Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL; 12177c478bd9Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip)) { 12187c478bd9Sstevel@tonic-gate if (rc_notify_info_interested(nip, np)) { 12197c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv); 12207c478bd9Sstevel@tonic-gate found++; 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate if (found) 12247c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, np); 12257c478bd9Sstevel@tonic-gate else 12267c478bd9Sstevel@tonic-gate np->rcn_node = NULL; 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate static void 12327c478bd9Sstevel@tonic-gate rc_notify_deletion(rc_notify_delete_t *ndp, const char *service, 12337c478bd9Sstevel@tonic-gate const char *instance, const char *pg) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate rc_notify_info_t *nip; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate uu_list_node_init(&ndp->rnd_notify, &ndp->rnd_notify.rcn_list_node, 12387c478bd9Sstevel@tonic-gate rc_notify_pool); 12397c478bd9Sstevel@tonic-gate ndp->rnd_notify.rcn_delete = ndp; 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate (void) snprintf(ndp->rnd_fmri, sizeof (ndp->rnd_fmri), 12427c478bd9Sstevel@tonic-gate "svc:/%s%s%s%s%s", service, 12437c478bd9Sstevel@tonic-gate (instance != NULL)? ":" : "", (instance != NULL)? instance : "", 12447c478bd9Sstevel@tonic-gate (pg != NULL)? "/:properties/" : "", (pg != NULL)? pg : ""); 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate /* 12477c478bd9Sstevel@tonic-gate * add to notification list, notify watchers 12487c478bd9Sstevel@tonic-gate */ 12497c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 12507c478bd9Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL; 12517c478bd9Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip)) 12527c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv); 12537c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, ndp); 12547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate static void 12587c478bd9Sstevel@tonic-gate rc_notify_remove_node(rc_node_t *nnp) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate assert(np->rcn_info == NULL); 12637c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&nnp->rn_lock)); 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 12667c478bd9Sstevel@tonic-gate while (np->rcn_node != NULL) { 12677c478bd9Sstevel@tonic-gate if (rc_notify_in_use) { 12687c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv, 12697c478bd9Sstevel@tonic-gate &rc_pg_notify_lock); 12707c478bd9Sstevel@tonic-gate continue; 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np); 12737c478bd9Sstevel@tonic-gate np->rcn_node = NULL; 12747c478bd9Sstevel@tonic-gate break; 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate static void 12807c478bd9Sstevel@tonic-gate rc_notify_remove_locked(rc_notify_t *np) 12817c478bd9Sstevel@tonic-gate { 12827c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock)); 12837c478bd9Sstevel@tonic-gate assert(rc_notify_in_use == 0); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np); 12867c478bd9Sstevel@tonic-gate if (np->rcn_node) { 12877c478bd9Sstevel@tonic-gate np->rcn_node = NULL; 12887c478bd9Sstevel@tonic-gate } else if (np->rcn_delete) { 12897c478bd9Sstevel@tonic-gate uu_free(np->rcn_delete); 12907c478bd9Sstevel@tonic-gate } else { 12917c478bd9Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */ 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* 12967c478bd9Sstevel@tonic-gate * Permission checking functions. See comment atop this file. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate #ifndef NATIVE_BUILD 12997c478bd9Sstevel@tonic-gate static permcheck_t * 13007c478bd9Sstevel@tonic-gate pc_create() 13017c478bd9Sstevel@tonic-gate { 13027c478bd9Sstevel@tonic-gate permcheck_t *p; 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate p = uu_zalloc(sizeof (*p)); 13057c478bd9Sstevel@tonic-gate if (p == NULL) 13067c478bd9Sstevel@tonic-gate return (NULL); 13077c478bd9Sstevel@tonic-gate p->pc_bnum = 8; /* Normal case will only have 2 elts. */ 13087c478bd9Sstevel@tonic-gate p->pc_buckets = uu_zalloc(sizeof (*p->pc_buckets) * p->pc_bnum); 13097c478bd9Sstevel@tonic-gate if (p->pc_buckets == NULL) { 13107c478bd9Sstevel@tonic-gate uu_free(p); 13117c478bd9Sstevel@tonic-gate return (NULL); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate p->pc_enum = 0; 13157c478bd9Sstevel@tonic-gate return (p); 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate static void 13197c478bd9Sstevel@tonic-gate pc_free(permcheck_t *pcp) 13207c478bd9Sstevel@tonic-gate { 13217c478bd9Sstevel@tonic-gate uint_t i; 13227c478bd9Sstevel@tonic-gate struct pc_elt *ep, *next; 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) { 13257c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) { 13267c478bd9Sstevel@tonic-gate next = ep->pce_next; 13277c478bd9Sstevel@tonic-gate free(ep); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate free(pcp->pc_buckets); 13327c478bd9Sstevel@tonic-gate free(pcp); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate static uint32_t 13367c478bd9Sstevel@tonic-gate pc_hash(const char *auth) 13377c478bd9Sstevel@tonic-gate { 13387c478bd9Sstevel@tonic-gate uint32_t h = 0, g; 13397c478bd9Sstevel@tonic-gate const char *p; 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Generic hash function from uts/common/os/modhash.c. 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate for (p = auth; *p != '\0'; ++p) { 13457c478bd9Sstevel@tonic-gate h = (h << 4) + *p; 13467c478bd9Sstevel@tonic-gate g = (h & 0xf0000000); 13477c478bd9Sstevel@tonic-gate if (g != 0) { 13487c478bd9Sstevel@tonic-gate h ^= (g >> 24); 13497c478bd9Sstevel@tonic-gate h ^= g; 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate } 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate return (h); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 1356a4dc1477STom Whitten static perm_status_t 13575b7f77adStw21770 pc_exists(permcheck_t *pcp, const char *auth) 13587c478bd9Sstevel@tonic-gate { 13597c478bd9Sstevel@tonic-gate uint32_t h; 13607c478bd9Sstevel@tonic-gate struct pc_elt *ep; 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate h = pc_hash(auth); 13637c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[h & (pcp->pc_bnum - 1)]; 13647c478bd9Sstevel@tonic-gate ep != NULL; 13657c478bd9Sstevel@tonic-gate ep = ep->pce_next) { 13665b7f77adStw21770 if (strcmp(auth, ep->pce_auth) == 0) { 13675b7f77adStw21770 pcp->pc_auth_string = ep->pce_auth; 1368a4dc1477STom Whitten return (PERM_GRANTED); 13697c478bd9Sstevel@tonic-gate } 13705b7f77adStw21770 } 13717c478bd9Sstevel@tonic-gate 1372a4dc1477STom Whitten return (PERM_DENIED); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 1375a4dc1477STom Whitten static perm_status_t 13765b7f77adStw21770 pc_match(permcheck_t *pcp, const char *pattern) 13777c478bd9Sstevel@tonic-gate { 13787c478bd9Sstevel@tonic-gate uint_t i; 13797c478bd9Sstevel@tonic-gate struct pc_elt *ep; 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) { 13827c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = ep->pce_next) { 13835b7f77adStw21770 if (_auth_match(pattern, ep->pce_auth)) { 13845b7f77adStw21770 pcp->pc_auth_string = ep->pce_auth; 1385a4dc1477STom Whitten return (PERM_GRANTED); 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate } 13885b7f77adStw21770 } 13897c478bd9Sstevel@tonic-gate 1390a4dc1477STom Whitten return (PERM_DENIED); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate static int 13947c478bd9Sstevel@tonic-gate pc_grow(permcheck_t *pcp) 13957c478bd9Sstevel@tonic-gate { 13967c478bd9Sstevel@tonic-gate uint_t new_bnum, i, j; 13977c478bd9Sstevel@tonic-gate struct pc_elt **new_buckets; 13987c478bd9Sstevel@tonic-gate struct pc_elt *ep, *next; 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate new_bnum = pcp->pc_bnum * 2; 14017c478bd9Sstevel@tonic-gate if (new_bnum < pcp->pc_bnum) 14027c478bd9Sstevel@tonic-gate /* Homey don't play that. */ 14037c478bd9Sstevel@tonic-gate return (-1); 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate new_buckets = uu_zalloc(sizeof (*new_buckets) * new_bnum); 14067c478bd9Sstevel@tonic-gate if (new_buckets == NULL) 14077c478bd9Sstevel@tonic-gate return (-1); 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) { 14107c478bd9Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) { 14117c478bd9Sstevel@tonic-gate next = ep->pce_next; 14127c478bd9Sstevel@tonic-gate j = pc_hash(ep->pce_auth) & (new_bnum - 1); 14137c478bd9Sstevel@tonic-gate ep->pce_next = new_buckets[j]; 14147c478bd9Sstevel@tonic-gate new_buckets[j] = ep; 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate uu_free(pcp->pc_buckets); 14197c478bd9Sstevel@tonic-gate pcp->pc_buckets = new_buckets; 14207c478bd9Sstevel@tonic-gate pcp->pc_bnum = new_bnum; 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate return (0); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate static int 14265b7f77adStw21770 pc_add(permcheck_t *pcp, const char *auth, pc_auth_type_t auth_type) 14277c478bd9Sstevel@tonic-gate { 14287c478bd9Sstevel@tonic-gate struct pc_elt *ep; 14297c478bd9Sstevel@tonic-gate uint_t i; 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate ep = uu_zalloc(offsetof(struct pc_elt, pce_auth) + strlen(auth) + 1); 14327c478bd9Sstevel@tonic-gate if (ep == NULL) 14337c478bd9Sstevel@tonic-gate return (-1); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* Grow if pc_enum / pc_bnum > 3/4. */ 14367c478bd9Sstevel@tonic-gate if (pcp->pc_enum * 4 > 3 * pcp->pc_bnum) 14377c478bd9Sstevel@tonic-gate /* Failure is not a stopper; we'll try again next time. */ 14387c478bd9Sstevel@tonic-gate (void) pc_grow(pcp); 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate (void) strcpy(ep->pce_auth, auth); 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate i = pc_hash(auth) & (pcp->pc_bnum - 1); 14437c478bd9Sstevel@tonic-gate ep->pce_next = pcp->pc_buckets[i]; 14447c478bd9Sstevel@tonic-gate pcp->pc_buckets[i] = ep; 14457c478bd9Sstevel@tonic-gate 14465b7f77adStw21770 if (auth_type > pcp->pc_specific_type) { 14475b7f77adStw21770 pcp->pc_specific_type = auth_type; 14485b7f77adStw21770 pcp->pc_specific = ep; 14495b7f77adStw21770 } 14505b7f77adStw21770 14517c478bd9Sstevel@tonic-gate ++pcp->pc_enum; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate return (0); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* 14577c478bd9Sstevel@tonic-gate * For the type of a property group, return the authorization which may be 14587c478bd9Sstevel@tonic-gate * used to modify it. 14597c478bd9Sstevel@tonic-gate */ 14607c478bd9Sstevel@tonic-gate static const char * 14617c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(const char *pgtype) 14627c478bd9Sstevel@tonic-gate { 14637c478bd9Sstevel@tonic-gate if (strcmp(pgtype, SCF_GROUP_METHOD) == 0) 14647c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "method"); 14657c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_DEPENDENCY) == 0) 14667c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "dependency"); 14677c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_APPLICATION) == 0) 14687c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "application"); 14697c478bd9Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_FRAMEWORK) == 0) 14707c478bd9Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "framework"); 14717c478bd9Sstevel@tonic-gate else 14727c478bd9Sstevel@tonic-gate return (NULL); 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate /* 14767c478bd9Sstevel@tonic-gate * Fails with 14777c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate static int 14805b7f77adStw21770 perm_add_enabling_type(permcheck_t *pcp, const char *auth, 14815b7f77adStw21770 pc_auth_type_t auth_type) 14825b7f77adStw21770 { 14835b7f77adStw21770 return (pc_add(pcp, auth, auth_type) == 0 ? REP_PROTOCOL_SUCCESS : 14845b7f77adStw21770 REP_PROTOCOL_FAIL_NO_RESOURCES); 14855b7f77adStw21770 } 14865b7f77adStw21770 14875b7f77adStw21770 /* 14885b7f77adStw21770 * Fails with 14895b7f77adStw21770 * _NO_RESOURCES - out of memory 14905b7f77adStw21770 */ 14915b7f77adStw21770 static int 14927c478bd9Sstevel@tonic-gate perm_add_enabling(permcheck_t *pcp, const char *auth) 14937c478bd9Sstevel@tonic-gate { 14945b7f77adStw21770 return (perm_add_enabling_type(pcp, auth, PC_AUTH_SMF)); 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* Note that perm_add_enabling_values() is defined below. */ 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate /* 1500a4dc1477STom Whitten * perm_granted() returns PERM_GRANTED if the current door caller has one of 1501a4dc1477STom Whitten * the enabling authorizations in pcp, PERM_DENIED if it doesn't, PERM_GONE if 1502a4dc1477STom Whitten * the door client went away and PERM_FAIL if an error (usually lack of 1503134a1f4eSCasper H.S. Dik * memory) occurs. auth_cb() checks each and every authorizations as 1504134a1f4eSCasper H.S. Dik * enumerated by _enum_auths. When we find a result other than PERM_DENIED, 1505134a1f4eSCasper H.S. Dik * we short-cut the enumeration and return non-zero. 15067c478bd9Sstevel@tonic-gate */ 1507134a1f4eSCasper H.S. Dik 1508134a1f4eSCasper H.S. Dik static int 1509134a1f4eSCasper H.S. Dik auth_cb(const char *auth, void *ctxt, void *vres) 15107c478bd9Sstevel@tonic-gate { 1511134a1f4eSCasper H.S. Dik permcheck_t *pcp = ctxt; 1512134a1f4eSCasper H.S. Dik int *pret = vres; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate if (strchr(auth, KV_WILDCHAR) == NULL) 1515134a1f4eSCasper H.S. Dik *pret = pc_exists(pcp, auth); 15167c478bd9Sstevel@tonic-gate else 1517134a1f4eSCasper H.S. Dik *pret = pc_match(pcp, auth); 15187c478bd9Sstevel@tonic-gate 1519134a1f4eSCasper H.S. Dik if (*pret != PERM_DENIED) 1520134a1f4eSCasper H.S. Dik return (1); 15215b7f77adStw21770 /* 15225b7f77adStw21770 * If we failed, choose the most specific auth string for use in 15235b7f77adStw21770 * the audit event. 15245b7f77adStw21770 */ 15255b7f77adStw21770 assert(pcp->pc_specific != NULL); 15265b7f77adStw21770 pcp->pc_auth_string = pcp->pc_specific->pce_auth; 15275b7f77adStw21770 1528134a1f4eSCasper H.S. Dik return (0); /* Tells that we need to continue */ 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate 1531a4dc1477STom Whitten static perm_status_t 15325b7f77adStw21770 perm_granted(permcheck_t *pcp) 15337c478bd9Sstevel@tonic-gate { 15347c478bd9Sstevel@tonic-gate ucred_t *uc; 15357c478bd9Sstevel@tonic-gate 1536a4dc1477STom Whitten perm_status_t ret = PERM_DENIED; 15377c478bd9Sstevel@tonic-gate uid_t uid; 1538499fd601Sgww struct passwd pw; 1539499fd601Sgww char pwbuf[1024]; /* XXX should be NSS_BUFLEN_PASSWD */ 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* Get the uid */ 15427c478bd9Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) { 15437c478bd9Sstevel@tonic-gate if (errno == EINVAL) { 15447c478bd9Sstevel@tonic-gate /* 15457c478bd9Sstevel@tonic-gate * Client is no longer waiting for our response (e.g., 15467c478bd9Sstevel@tonic-gate * it received a signal & resumed with EINTR). 15477c478bd9Sstevel@tonic-gate * Punting with door_return() would be nice but we 15487c478bd9Sstevel@tonic-gate * need to release all of the locks & references we 15497c478bd9Sstevel@tonic-gate * hold. And we must report failure to the client 15507c478bd9Sstevel@tonic-gate * layer to keep it from ignoring retries as 15517c478bd9Sstevel@tonic-gate * already-done (idempotency & all that). None of the 15527c478bd9Sstevel@tonic-gate * error codes fit very well, so we might as well 15537c478bd9Sstevel@tonic-gate * force the return of _PERMISSION_DENIED since we 15547c478bd9Sstevel@tonic-gate * couldn't determine the user. 15557c478bd9Sstevel@tonic-gate */ 1556a4dc1477STom Whitten return (PERM_GONE); 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate assert(0); 15597c478bd9Sstevel@tonic-gate abort(); 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate uid = ucred_geteuid(uc); 1563f48205beScasper assert(uid != (uid_t)-1); 15647c478bd9Sstevel@tonic-gate 1565499fd601Sgww if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) { 1566a4dc1477STom Whitten return (PERM_FAIL); 1567499fd601Sgww } 1568499fd601Sgww 1569499fd601Sgww /* 1570134a1f4eSCasper H.S. Dik * Enumerate all the auths defined for the user and return the 1571134a1f4eSCasper H.S. Dik * result in ret. 1572499fd601Sgww */ 1573134a1f4eSCasper H.S. Dik if (_enum_auths(pw.pw_name, auth_cb, pcp, &ret) < 0) 1574a4dc1477STom Whitten return (PERM_FAIL); 1575499fd601Sgww 15767c478bd9Sstevel@tonic-gate return (ret); 15777c478bd9Sstevel@tonic-gate } 1578a4dc1477STom Whitten 1579a4dc1477STom Whitten static int 1580a4dc1477STom Whitten map_granted_status(perm_status_t status, permcheck_t *pcp, 1581a4dc1477STom Whitten char **match_auth) 1582a4dc1477STom Whitten { 1583a4dc1477STom Whitten int rc; 1584a4dc1477STom Whitten 1585a4dc1477STom Whitten *match_auth = NULL; 1586a4dc1477STom Whitten switch (status) { 1587a4dc1477STom Whitten case PERM_DENIED: 1588a4dc1477STom Whitten *match_auth = strdup(pcp->pc_auth_string); 1589a4dc1477STom Whitten if (*match_auth == NULL) 1590a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 1591a4dc1477STom Whitten else 1592a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 1593a4dc1477STom Whitten break; 1594a4dc1477STom Whitten case PERM_GRANTED: 1595a4dc1477STom Whitten *match_auth = strdup(pcp->pc_auth_string); 1596a4dc1477STom Whitten if (*match_auth == NULL) 1597a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 1598a4dc1477STom Whitten else 1599a4dc1477STom Whitten rc = REP_PROTOCOL_SUCCESS; 1600a4dc1477STom Whitten break; 1601a4dc1477STom Whitten case PERM_GONE: 1602a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 1603a4dc1477STom Whitten break; 1604a4dc1477STom Whitten case PERM_FAIL: 1605a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 1606a4dc1477STom Whitten break; 1607a4dc1477STom Whitten } 1608a4dc1477STom Whitten return (rc); 1609a4dc1477STom Whitten } 16107c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate /* 16137c478bd9Sstevel@tonic-gate * flags in RC_NODE_WAITING_FLAGS are broadcast when unset, and are used to 16147c478bd9Sstevel@tonic-gate * serialize certain actions, and to wait for certain operations to complete 16157c478bd9Sstevel@tonic-gate * 16167c478bd9Sstevel@tonic-gate * The waiting flags are: 16177c478bd9Sstevel@tonic-gate * RC_NODE_CHILDREN_CHANGING 16187c478bd9Sstevel@tonic-gate * The child list is being built or changed (due to creation 16197c478bd9Sstevel@tonic-gate * or deletion). All iterators pause. 16207c478bd9Sstevel@tonic-gate * 16217c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT 16227c478bd9Sstevel@tonic-gate * Someone is actively using the parent pointer, so we can't 16237c478bd9Sstevel@tonic-gate * be removed from the parent list. 16247c478bd9Sstevel@tonic-gate * 16257c478bd9Sstevel@tonic-gate * RC_NODE_CREATING_CHILD 16267c478bd9Sstevel@tonic-gate * A child is being created -- locks out other creations, to 16277c478bd9Sstevel@tonic-gate * prevent insert-insert races. 16287c478bd9Sstevel@tonic-gate * 16297c478bd9Sstevel@tonic-gate * RC_NODE_IN_TX 16307c478bd9Sstevel@tonic-gate * This object is running a transaction. 16317c478bd9Sstevel@tonic-gate * 16327c478bd9Sstevel@tonic-gate * RC_NODE_DYING 16337c478bd9Sstevel@tonic-gate * This node might be dying. Always set as a set, using 16347c478bd9Sstevel@tonic-gate * RC_NODE_DYING_FLAGS (which is everything but 16357c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT) 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate static int 16387c478bd9Sstevel@tonic-gate rc_node_hold_flag(rc_node_t *np, uint32_t flag) 16397c478bd9Sstevel@tonic-gate { 16407c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 16417c478bd9Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag)) { 16447c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD) 16477c478bd9Sstevel@tonic-gate return (0); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate np->rn_flags |= flag; 16507c478bd9Sstevel@tonic-gate return (1); 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate static void 16547c478bd9Sstevel@tonic-gate rc_node_rele_flag(rc_node_t *np, uint32_t flag) 16557c478bd9Sstevel@tonic-gate { 16567c478bd9Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0); 16577c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 16587c478bd9Sstevel@tonic-gate assert((np->rn_flags & flag) == flag); 16597c478bd9Sstevel@tonic-gate np->rn_flags &= ~flag; 16607c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&np->rn_cv); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * wait until a particular flag has cleared. Fails if the object dies. 16657c478bd9Sstevel@tonic-gate */ 16667c478bd9Sstevel@tonic-gate static int 16677c478bd9Sstevel@tonic-gate rc_node_wait_flag(rc_node_t *np, uint32_t flag) 16687c478bd9Sstevel@tonic-gate { 16697c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 16707c478bd9Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag)) 16717c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate return (!(np->rn_flags & RC_NODE_DEAD)); 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* 16777c478bd9Sstevel@tonic-gate * On entry, np's lock must be held, and this thread must be holding 16787c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT. On return, both of them are released. 16797c478bd9Sstevel@tonic-gate * 16807c478bd9Sstevel@tonic-gate * If the return value is NULL, np either does not have a parent, or 16817c478bd9Sstevel@tonic-gate * the parent has been marked DEAD. 16827c478bd9Sstevel@tonic-gate * 16837c478bd9Sstevel@tonic-gate * If the return value is non-NULL, it is the parent of np, and both 16847c478bd9Sstevel@tonic-gate * its lock and the requested flags are held. 16857c478bd9Sstevel@tonic-gate */ 16867c478bd9Sstevel@tonic-gate static rc_node_t * 16877c478bd9Sstevel@tonic-gate rc_node_hold_parent_flag(rc_node_t *np, uint32_t flag) 16887c478bd9Sstevel@tonic-gate { 16897c478bd9Sstevel@tonic-gate rc_node_t *pp; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 16927c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_USING_PARENT); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if ((pp = np->rn_parent) == NULL) { 16957c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 16967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 16977c478bd9Sstevel@tonic-gate return (NULL); 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 17027c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 17037c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 17047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(pp, flag)) { 17077c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 17087c478bd9Sstevel@tonic-gate return (NULL); 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate return (pp); 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate rc_node_t * 17147c478bd9Sstevel@tonic-gate rc_node_alloc(void) 17157c478bd9Sstevel@tonic-gate { 17167c478bd9Sstevel@tonic-gate rc_node_t *np = uu_zalloc(sizeof (*np)); 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate if (np == NULL) 17197c478bd9Sstevel@tonic-gate return (NULL); 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&np->rn_lock, NULL); 17227c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&np->rn_cv, NULL); 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate np->rn_children = uu_list_create(rc_children_pool, np, 0); 17257c478bd9Sstevel@tonic-gate np->rn_pg_notify_list = uu_list_create(rc_pg_notify_pool, np, 0); 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate uu_list_node_init(np, &np->rn_sibling_node, rc_children_pool); 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate uu_list_node_init(&np->rn_notify, &np->rn_notify.rcn_list_node, 17307c478bd9Sstevel@tonic-gate rc_notify_pool); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate return (np); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate void 17367c478bd9Sstevel@tonic-gate rc_node_destroy(rc_node_t *np) 17377c478bd9Sstevel@tonic-gate { 17387c478bd9Sstevel@tonic-gate int i; 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED) 17417c478bd9Sstevel@tonic-gate return; /* being handled elsewhere */ 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate assert(np->rn_refs == 0 && np->rn_other_refs == 0); 17447c478bd9Sstevel@tonic-gate assert(np->rn_former == NULL); 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 17477c478bd9Sstevel@tonic-gate /* Release the holds from rc_iter_next(). */ 17487c478bd9Sstevel@tonic-gate for (i = 0; i < COMPOSITION_DEPTH; ++i) { 17497c478bd9Sstevel@tonic-gate /* rn_cchain[i] may be NULL for empty snapshots. */ 17507c478bd9Sstevel@tonic-gate if (np->rn_cchain[i] != NULL) 17517c478bd9Sstevel@tonic-gate rc_node_rele(np->rn_cchain[i]); 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate if (np->rn_name != NULL) 17567c478bd9Sstevel@tonic-gate free((void *)np->rn_name); 17577c478bd9Sstevel@tonic-gate np->rn_name = NULL; 17587c478bd9Sstevel@tonic-gate if (np->rn_type != NULL) 17597c478bd9Sstevel@tonic-gate free((void *)np->rn_type); 17607c478bd9Sstevel@tonic-gate np->rn_type = NULL; 17617c478bd9Sstevel@tonic-gate if (np->rn_values != NULL) 17627c478bd9Sstevel@tonic-gate object_free_values(np->rn_values, np->rn_valtype, 17637c478bd9Sstevel@tonic-gate np->rn_values_count, np->rn_values_size); 17647c478bd9Sstevel@tonic-gate np->rn_values = NULL; 17655b7f77adStw21770 rc_node_free_fmri(np); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate if (np->rn_snaplevel != NULL) 17687c478bd9Sstevel@tonic-gate rc_snaplevel_rele(np->rn_snaplevel); 17697c478bd9Sstevel@tonic-gate np->rn_snaplevel = NULL; 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate uu_list_node_fini(np, &np->rn_sibling_node, rc_children_pool); 17727c478bd9Sstevel@tonic-gate 17737c478bd9Sstevel@tonic-gate uu_list_node_fini(&np->rn_notify, &np->rn_notify.rcn_list_node, 17747c478bd9Sstevel@tonic-gate rc_notify_pool); 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate assert(uu_list_first(np->rn_children) == NULL); 17777c478bd9Sstevel@tonic-gate uu_list_destroy(np->rn_children); 17787c478bd9Sstevel@tonic-gate uu_list_destroy(np->rn_pg_notify_list); 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&np->rn_lock); 17817c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&np->rn_cv); 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate uu_free(np); 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate /* 17877c478bd9Sstevel@tonic-gate * Link in a child node. 17887c478bd9Sstevel@tonic-gate * 17897c478bd9Sstevel@tonic-gate * Because of the lock ordering, cp has to already be in the hash table with 17907c478bd9Sstevel@tonic-gate * its lock dropped before we get it. To prevent anyone from noticing that 17917c478bd9Sstevel@tonic-gate * it is parentless, the creation code sets the RC_NODE_USING_PARENT. Once 17927c478bd9Sstevel@tonic-gate * we've linked it in, we release the flag. 17937c478bd9Sstevel@tonic-gate */ 17947c478bd9Sstevel@tonic-gate static void 17957c478bd9Sstevel@tonic-gate rc_node_link_child(rc_node_t *np, rc_node_t *cp) 17967c478bd9Sstevel@tonic-gate { 17977c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&np->rn_lock)); 17987c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&cp->rn_lock)); 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 18017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 18027c478bd9Sstevel@tonic-gate assert(!(cp->rn_flags & RC_NODE_IN_PARENT) && 18037c478bd9Sstevel@tonic-gate (cp->rn_flags & RC_NODE_USING_PARENT)); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate assert(rc_check_parent_child(np->rn_id.rl_type, cp->rn_id.rl_type) == 18067c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate cp->rn_parent = np; 18097c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_IN_PARENT; 18107c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(np->rn_children, NULL, cp); 18115b7f77adStw21770 (void) rc_node_build_fmri(cp); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate rc_node_rele_flag(cp, RC_NODE_USING_PARENT); 18167c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock); 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate /* 18207c478bd9Sstevel@tonic-gate * Sets the rn_parent_ref field of all the children of np to pp -- always 18217c478bd9Sstevel@tonic-gate * initially invoked as rc_node_setup_parent_ref(np, np), we then recurse. 18227c478bd9Sstevel@tonic-gate * 18237c478bd9Sstevel@tonic-gate * This is used when we mark a node RC_NODE_OLD, so that when the object and 18247c478bd9Sstevel@tonic-gate * its children are no longer referenced, they will all be deleted as a unit. 18257c478bd9Sstevel@tonic-gate */ 18267c478bd9Sstevel@tonic-gate static void 18277c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(rc_node_t *np, rc_node_t *pp) 18287c478bd9Sstevel@tonic-gate { 18297c478bd9Sstevel@tonic-gate rc_node_t *cp; 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL; 18347c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) { 18357c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 18367c478bd9Sstevel@tonic-gate if (cp->rn_flags & RC_NODE_PARENT_REF) { 18377c478bd9Sstevel@tonic-gate assert(cp->rn_parent_ref == pp); 18387c478bd9Sstevel@tonic-gate } else { 18397c478bd9Sstevel@tonic-gate assert(cp->rn_parent_ref == NULL); 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_PARENT_REF; 18427c478bd9Sstevel@tonic-gate cp->rn_parent_ref = pp; 18437c478bd9Sstevel@tonic-gate if (cp->rn_refs != 0) 18447c478bd9Sstevel@tonic-gate rc_node_hold_other(pp); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(cp, pp); /* recurse */ 18477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* 18527c478bd9Sstevel@tonic-gate * Atomically replace 'np' with 'newp', with a parent of 'pp'. 18537c478bd9Sstevel@tonic-gate * 18547c478bd9Sstevel@tonic-gate * Requirements: 18557c478bd9Sstevel@tonic-gate * *no* node locks may be held. 18567c478bd9Sstevel@tonic-gate * pp must be held with RC_NODE_CHILDREN_CHANGING 18577c478bd9Sstevel@tonic-gate * newp and np must be held with RC_NODE_IN_TX 18587c478bd9Sstevel@tonic-gate * np must be marked RC_NODE_IN_PARENT, newp must not be 18597c478bd9Sstevel@tonic-gate * np must be marked RC_NODE_OLD 18607c478bd9Sstevel@tonic-gate * 18617c478bd9Sstevel@tonic-gate * Afterwards: 18627c478bd9Sstevel@tonic-gate * pp's RC_NODE_CHILDREN_CHANGING is dropped 18637c478bd9Sstevel@tonic-gate * newp and np's RC_NODE_IN_TX is dropped 18647c478bd9Sstevel@tonic-gate * newp->rn_former = np; 18657c478bd9Sstevel@tonic-gate * newp is RC_NODE_IN_PARENT, np is not. 18667c478bd9Sstevel@tonic-gate * interested notify subscribers have been notified of newp's new status. 18677c478bd9Sstevel@tonic-gate */ 18687c478bd9Sstevel@tonic-gate static void 18697c478bd9Sstevel@tonic-gate rc_node_relink_child(rc_node_t *pp, rc_node_t *np, rc_node_t *newp) 18707c478bd9Sstevel@tonic-gate { 18717c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 18727c478bd9Sstevel@tonic-gate /* 18737c478bd9Sstevel@tonic-gate * First, swap np and nnp in the cache. newp's RC_NODE_IN_TX flag 18747c478bd9Sstevel@tonic-gate * keeps rc_node_update() from seeing it until we are done. 18757c478bd9Sstevel@tonic-gate */ 18767c478bd9Sstevel@tonic-gate bp = cache_hold(newp->rn_hash); 18777c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, np); 18787c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, newp); 18797c478bd9Sstevel@tonic-gate cache_release(bp); 18807c478bd9Sstevel@tonic-gate 18817c478bd9Sstevel@tonic-gate /* 18827c478bd9Sstevel@tonic-gate * replace np with newp in pp's list, and attach it to newp's rn_former 18837c478bd9Sstevel@tonic-gate * link. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 18867c478bd9Sstevel@tonic-gate assert(pp->rn_flags & RC_NODE_CHILDREN_CHANGING); 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&newp->rn_lock); 18897c478bd9Sstevel@tonic-gate assert(!(newp->rn_flags & RC_NODE_IN_PARENT)); 18907c478bd9Sstevel@tonic-gate assert(newp->rn_flags & RC_NODE_IN_TX); 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 18937c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 18947c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD); 18957c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_TX); 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate newp->rn_parent = pp; 18987c478bd9Sstevel@tonic-gate newp->rn_flags |= RC_NODE_IN_PARENT; 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate /* 19017c478bd9Sstevel@tonic-gate * Note that we carefully add newp before removing np -- this 19027c478bd9Sstevel@tonic-gate * keeps iterators on the list from missing us. 19037c478bd9Sstevel@tonic-gate */ 19047c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(pp->rn_children, np, newp); 19055b7f77adStw21770 (void) rc_node_build_fmri(newp); 19067c478bd9Sstevel@tonic-gate (void) uu_list_remove(pp->rn_children, np); 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate /* 19097c478bd9Sstevel@tonic-gate * re-set np 19107c478bd9Sstevel@tonic-gate */ 19117c478bd9Sstevel@tonic-gate newp->rn_former = np; 19127c478bd9Sstevel@tonic-gate np->rn_parent = NULL; 19137c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT; 19147c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_ON_FORMER; 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate rc_notify_insert_node(newp); 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 19197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 19207c478bd9Sstevel@tonic-gate rc_node_rele_flag(newp, RC_NODE_USING_PARENT | RC_NODE_IN_TX); 19217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&newp->rn_lock); 19227c478bd9Sstevel@tonic-gate rc_node_setup_parent_ref(np, np); 19237c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX); 19247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate 19277c478bd9Sstevel@tonic-gate /* 19287c478bd9Sstevel@tonic-gate * makes sure a node with lookup 'nip', name 'name', and parent 'pp' exists. 19297c478bd9Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does 19307c478bd9Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead. 19317c478bd9Sstevel@tonic-gate */ 19327c478bd9Sstevel@tonic-gate rc_node_t * 19337c478bd9Sstevel@tonic-gate rc_node_setup(rc_node_t *cp, rc_node_lookup_t *nip, const char *name, 19347c478bd9Sstevel@tonic-gate rc_node_t *pp) 19357c478bd9Sstevel@tonic-gate { 19367c478bd9Sstevel@tonic-gate rc_node_t *np; 19377c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 19387c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip); 19397c478bd9Sstevel@tonic-gate 19407c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0); 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate bp = cache_hold(h); 19437c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) { 19447c478bd9Sstevel@tonic-gate cache_release(bp); 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate /* 19477c478bd9Sstevel@tonic-gate * make sure it matches our expectations 19487c478bd9Sstevel@tonic-gate */ 1949cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock); 1950cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 19517c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp); 19527c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0); 19537c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0); 19547c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL); 19557c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 1956cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT); 1957cfae1de8Shg115875 } 1958cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock); 19597c478bd9Sstevel@tonic-gate 19607c478bd9Sstevel@tonic-gate rc_node_destroy(cp); 19617c478bd9Sstevel@tonic-gate return (np); 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate /* 19656643e1ffSbustos * No one is there -- setup & install the new node. 19667c478bd9Sstevel@tonic-gate */ 19677c478bd9Sstevel@tonic-gate np = cp; 19687c478bd9Sstevel@tonic-gate rc_node_hold(np); 19697c478bd9Sstevel@tonic-gate np->rn_id = *nip; 19707c478bd9Sstevel@tonic-gate np->rn_hash = h; 19717c478bd9Sstevel@tonic-gate np->rn_name = strdup(name); 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT; 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE) { 19767c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2 19777c478bd9Sstevel@tonic-gate np->rn_cchain[0] = np; 19787c478bd9Sstevel@tonic-gate np->rn_cchain[1] = pp; 19797c478bd9Sstevel@tonic-gate #else 19807c478bd9Sstevel@tonic-gate #error This code must be updated. 19817c478bd9Sstevel@tonic-gate #endif 19827c478bd9Sstevel@tonic-gate } 19837c478bd9Sstevel@tonic-gate 19847c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 19857c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */ 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np); 19887c478bd9Sstevel@tonic-gate 19897c478bd9Sstevel@tonic-gate return (np); 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate /* 19937c478bd9Sstevel@tonic-gate * makes sure a snapshot with lookup 'nip', name 'name', and parent 'pp' exists. 19947c478bd9Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does 19957c478bd9Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate rc_node_t * 19987c478bd9Sstevel@tonic-gate rc_node_setup_snapshot(rc_node_t *cp, rc_node_lookup_t *nip, const char *name, 19997c478bd9Sstevel@tonic-gate uint32_t snap_id, rc_node_t *pp) 20007c478bd9Sstevel@tonic-gate { 20017c478bd9Sstevel@tonic-gate rc_node_t *np; 20027c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 20037c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip); 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0); 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate bp = cache_hold(h); 20087c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) { 20097c478bd9Sstevel@tonic-gate cache_release(bp); 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate /* 20127c478bd9Sstevel@tonic-gate * make sure it matches our expectations 20137c478bd9Sstevel@tonic-gate */ 2014cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock); 2015cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 20167c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp); 20177c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0); 20187c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0); 20197c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL); 20207c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 2021cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT); 2022cfae1de8Shg115875 } 2023cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock); 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate rc_node_destroy(cp); 20267c478bd9Sstevel@tonic-gate return (np); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate /* 20307c478bd9Sstevel@tonic-gate * No one is there -- create a new node. 20317c478bd9Sstevel@tonic-gate */ 20327c478bd9Sstevel@tonic-gate np = cp; 20337c478bd9Sstevel@tonic-gate rc_node_hold(np); 20347c478bd9Sstevel@tonic-gate np->rn_id = *nip; 20357c478bd9Sstevel@tonic-gate np->rn_hash = h; 20367c478bd9Sstevel@tonic-gate np->rn_name = strdup(name); 20377c478bd9Sstevel@tonic-gate np->rn_snapshot_id = snap_id; 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT; 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 20427c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */ 20437c478bd9Sstevel@tonic-gate 20447c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np); 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate return (np); 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate /* 20507c478bd9Sstevel@tonic-gate * makes sure a snaplevel with lookup 'nip' and parent 'pp' exists. 'cp' is 20517c478bd9Sstevel@tonic-gate * used (and returned) if the node does not yet exist. If it does exist, 'cp' 20527c478bd9Sstevel@tonic-gate * is freed, and the existent node is returned instead. 20537c478bd9Sstevel@tonic-gate */ 20547c478bd9Sstevel@tonic-gate rc_node_t * 20557c478bd9Sstevel@tonic-gate rc_node_setup_snaplevel(rc_node_t *cp, rc_node_lookup_t *nip, 20567c478bd9Sstevel@tonic-gate rc_snaplevel_t *lvl, rc_node_t *pp) 20577c478bd9Sstevel@tonic-gate { 20587c478bd9Sstevel@tonic-gate rc_node_t *np; 20597c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 20607c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip); 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate assert(cp->rn_refs == 0); 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate bp = cache_hold(h); 20657c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) { 20667c478bd9Sstevel@tonic-gate cache_release(bp); 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate /* 20697c478bd9Sstevel@tonic-gate * make sure it matches our expectations 20707c478bd9Sstevel@tonic-gate */ 2071cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock); 2072cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 20737c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp); 20747c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0); 20757c478bd9Sstevel@tonic-gate assert(np->rn_name == NULL); 20767c478bd9Sstevel@tonic-gate assert(np->rn_type == NULL); 20777c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 2078cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT); 2079cfae1de8Shg115875 } 2080cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock); 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate rc_node_destroy(cp); 20837c478bd9Sstevel@tonic-gate return (np); 20847c478bd9Sstevel@tonic-gate } 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate /* 20877c478bd9Sstevel@tonic-gate * No one is there -- create a new node. 20887c478bd9Sstevel@tonic-gate */ 20897c478bd9Sstevel@tonic-gate np = cp; 20907c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released in snapshot_fill_children() */ 20917c478bd9Sstevel@tonic-gate np->rn_id = *nip; 20927c478bd9Sstevel@tonic-gate np->rn_hash = h; 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate rc_snaplevel_hold(lvl); 20957c478bd9Sstevel@tonic-gate np->rn_snaplevel = lvl; 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT; 20987c478bd9Sstevel@tonic-gate 20997c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 21007c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */ 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate /* Add this snaplevel to the snapshot's composition chain. */ 21037c478bd9Sstevel@tonic-gate assert(pp->rn_cchain[lvl->rsl_level_num - 1] == NULL); 21047c478bd9Sstevel@tonic-gate pp->rn_cchain[lvl->rsl_level_num - 1] = np; 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np); 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate return (np); 21097c478bd9Sstevel@tonic-gate } 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate /* 21127c478bd9Sstevel@tonic-gate * Returns NULL if strdup() fails. 21137c478bd9Sstevel@tonic-gate */ 21147c478bd9Sstevel@tonic-gate rc_node_t * 21157c478bd9Sstevel@tonic-gate rc_node_setup_pg(rc_node_t *cp, rc_node_lookup_t *nip, const char *name, 21167c478bd9Sstevel@tonic-gate const char *type, uint32_t flags, uint32_t gen_id, rc_node_t *pp) 21177c478bd9Sstevel@tonic-gate { 21187c478bd9Sstevel@tonic-gate rc_node_t *np; 21197c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip); 21227c478bd9Sstevel@tonic-gate bp = cache_hold(h); 21237c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) { 21247c478bd9Sstevel@tonic-gate cache_release(bp); 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* 21277c478bd9Sstevel@tonic-gate * make sure it matches our expectations (don't check 21287c478bd9Sstevel@tonic-gate * the generation number or parent, since someone could 21297c478bd9Sstevel@tonic-gate * have gotten a transaction through while we weren't 21307c478bd9Sstevel@tonic-gate * looking) 21317c478bd9Sstevel@tonic-gate */ 2132cfae1de8Shg115875 (void) pthread_mutex_lock(&np->rn_lock); 2133cfae1de8Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 21347c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0); 21357c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0); 21367c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_type, type) == 0); 21377c478bd9Sstevel@tonic-gate assert(np->rn_pgflags == flags); 21387c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 2139cfae1de8Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT); 2140cfae1de8Shg115875 } 2141cfae1de8Shg115875 (void) pthread_mutex_unlock(&np->rn_lock); 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate rc_node_destroy(cp); 21447c478bd9Sstevel@tonic-gate return (np); 21457c478bd9Sstevel@tonic-gate } 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate np = cp; 21487c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released in fill_pg_callback() */ 21497c478bd9Sstevel@tonic-gate np->rn_id = *nip; 21507c478bd9Sstevel@tonic-gate np->rn_hash = h; 21517c478bd9Sstevel@tonic-gate np->rn_name = strdup(name); 21527c478bd9Sstevel@tonic-gate if (np->rn_name == NULL) { 21537c478bd9Sstevel@tonic-gate rc_node_rele(np); 21547c478bd9Sstevel@tonic-gate return (NULL); 21557c478bd9Sstevel@tonic-gate } 21567c478bd9Sstevel@tonic-gate np->rn_type = strdup(type); 21577c478bd9Sstevel@tonic-gate if (np->rn_type == NULL) { 21587c478bd9Sstevel@tonic-gate free((void *)np->rn_name); 21597c478bd9Sstevel@tonic-gate rc_node_rele(np); 21607c478bd9Sstevel@tonic-gate return (NULL); 21617c478bd9Sstevel@tonic-gate } 21627c478bd9Sstevel@tonic-gate np->rn_pgflags = flags; 21637c478bd9Sstevel@tonic-gate np->rn_gen_id = gen_id; 21647c478bd9Sstevel@tonic-gate 21657c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT; 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 21687c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */ 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np); 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate return (np); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate 21757c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2 21767c478bd9Sstevel@tonic-gate /* 21777c478bd9Sstevel@tonic-gate * Initialize a "composed property group" which represents the composition of 21787c478bd9Sstevel@tonic-gate * property groups pg1 & pg2. It is ephemeral: once created & returned for an 21797c478bd9Sstevel@tonic-gate * ITER_READ request, keeping it out of cache_hash and any child lists 21807c478bd9Sstevel@tonic-gate * prevents it from being looked up. Operations besides iteration are passed 21817c478bd9Sstevel@tonic-gate * through to pg1. 21827c478bd9Sstevel@tonic-gate * 21837c478bd9Sstevel@tonic-gate * pg1 & pg2 should be held before entering this function. They will be 21847c478bd9Sstevel@tonic-gate * released in rc_node_destroy(). 21857c478bd9Sstevel@tonic-gate */ 21867c478bd9Sstevel@tonic-gate static int 21877c478bd9Sstevel@tonic-gate rc_node_setup_cpg(rc_node_t *cpg, rc_node_t *pg1, rc_node_t *pg2) 21887c478bd9Sstevel@tonic-gate { 21897c478bd9Sstevel@tonic-gate if (strcmp(pg1->rn_type, pg2->rn_type) != 0) 21907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 21917c478bd9Sstevel@tonic-gate 21927c478bd9Sstevel@tonic-gate cpg->rn_id.rl_type = REP_PROTOCOL_ENTITY_CPROPERTYGRP; 21937c478bd9Sstevel@tonic-gate cpg->rn_name = strdup(pg1->rn_name); 21947c478bd9Sstevel@tonic-gate if (cpg->rn_name == NULL) 21957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate cpg->rn_cchain[0] = pg1; 21987c478bd9Sstevel@tonic-gate cpg->rn_cchain[1] = pg2; 21997c478bd9Sstevel@tonic-gate 22007c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate #else 22037c478bd9Sstevel@tonic-gate #error This code must be updated. 22047c478bd9Sstevel@tonic-gate #endif 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate /* 22077c478bd9Sstevel@tonic-gate * Fails with _NO_RESOURCES. 22087c478bd9Sstevel@tonic-gate */ 22097c478bd9Sstevel@tonic-gate int 22107c478bd9Sstevel@tonic-gate rc_node_create_property(rc_node_t *pp, rc_node_lookup_t *nip, 22117c478bd9Sstevel@tonic-gate const char *name, rep_protocol_value_type_t type, 22127c478bd9Sstevel@tonic-gate const char *vals, size_t count, size_t size) 22137c478bd9Sstevel@tonic-gate { 22147c478bd9Sstevel@tonic-gate rc_node_t *np; 22157c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate uint32_t h = rc_node_hash(nip); 22187c478bd9Sstevel@tonic-gate bp = cache_hold(h); 22197c478bd9Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) { 22207c478bd9Sstevel@tonic-gate cache_release(bp); 22217c478bd9Sstevel@tonic-gate /* 22227c478bd9Sstevel@tonic-gate * make sure it matches our expectations 22237c478bd9Sstevel@tonic-gate */ 22247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 22257c478bd9Sstevel@tonic-gate if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 22267c478bd9Sstevel@tonic-gate assert(np->rn_parent == pp); 22277c478bd9Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0); 22287c478bd9Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0); 22297c478bd9Sstevel@tonic-gate assert(np->rn_valtype == type); 22307c478bd9Sstevel@tonic-gate assert(np->rn_values_count == count); 22317c478bd9Sstevel@tonic-gate assert(np->rn_values_size == size); 22327c478bd9Sstevel@tonic-gate assert(vals == NULL || 22337c478bd9Sstevel@tonic-gate memcmp(np->rn_values, vals, size) == 0); 22347c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT); 22357c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 22387c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size); 22397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate /* 22437c478bd9Sstevel@tonic-gate * No one is there -- create a new node. 22447c478bd9Sstevel@tonic-gate */ 22457c478bd9Sstevel@tonic-gate np = rc_node_alloc(); 22467c478bd9Sstevel@tonic-gate if (np == NULL) { 22477c478bd9Sstevel@tonic-gate cache_release(bp); 22487c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size); 22497c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate np->rn_id = *nip; 22527c478bd9Sstevel@tonic-gate np->rn_hash = h; 22537c478bd9Sstevel@tonic-gate np->rn_name = strdup(name); 22547c478bd9Sstevel@tonic-gate if (np->rn_name == NULL) { 22557c478bd9Sstevel@tonic-gate cache_release(bp); 22567c478bd9Sstevel@tonic-gate object_free_values(vals, type, count, size); 22577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate np->rn_valtype = type; 22617c478bd9Sstevel@tonic-gate np->rn_values = vals; 22627c478bd9Sstevel@tonic-gate np->rn_values_count = count; 22637c478bd9Sstevel@tonic-gate np->rn_values_size = size; 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT; 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 22687c478bd9Sstevel@tonic-gate cache_release(bp); /* we are now visible */ 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate rc_node_link_child(pp, np); 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate 22755b7f77adStw21770 /* 22765b7f77adStw21770 * This function implements a decision table to determine the event ID for 22775b7f77adStw21770 * changes to the enabled (SCF_PROPERTY_ENABLED) property. The event ID is 22785b7f77adStw21770 * determined by the value of the first property in the command specified 22795b7f77adStw21770 * by cmd_no and the name of the property group. Here is the decision 22805b7f77adStw21770 * table: 22815b7f77adStw21770 * 22825b7f77adStw21770 * Property Group Name 22835b7f77adStw21770 * Property ------------------------------------------ 22845b7f77adStw21770 * Value SCF_PG_GENERAL SCF_PG_GENERAL_OVR 22855b7f77adStw21770 * -------- -------------- ------------------ 22865b7f77adStw21770 * "0" ADT_smf_disable ADT_smf_tmp_disable 22875b7f77adStw21770 * "1" ADT_smf_enable ADT_smf_tmp_enable 22885b7f77adStw21770 * 22895b7f77adStw21770 * This function is called by special_property_event through a function 22905b7f77adStw21770 * pointer in the special_props_list array. 22915b7f77adStw21770 * 22925b7f77adStw21770 * Since the ADT_smf_* symbols may not be defined in the build machine's 22935b7f77adStw21770 * include files, this function is not compiled when doing native builds. 22945b7f77adStw21770 */ 22955b7f77adStw21770 #ifndef NATIVE_BUILD 22965b7f77adStw21770 static int 22975b7f77adStw21770 general_enable_id(tx_commit_data_t *tx_data, size_t cmd_no, const char *pg, 22985b7f77adStw21770 au_event_t *event_id) 22995b7f77adStw21770 { 23005b7f77adStw21770 const char *value; 23015b7f77adStw21770 uint32_t nvalues; 23025b7f77adStw21770 int enable; 23035b7f77adStw21770 23045b7f77adStw21770 /* 23055b7f77adStw21770 * First, check property value. 23065b7f77adStw21770 */ 23075b7f77adStw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS) 23085b7f77adStw21770 return (-1); 23095b7f77adStw21770 if (nvalues == 0) 23105b7f77adStw21770 return (-1); 23115b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, 0, &value) != REP_PROTOCOL_SUCCESS) 23125b7f77adStw21770 return (-1); 23135b7f77adStw21770 if (strcmp(value, "0") == 0) { 23145b7f77adStw21770 enable = 0; 23155b7f77adStw21770 } else if (strcmp(value, "1") == 0) { 23165b7f77adStw21770 enable = 1; 23175b7f77adStw21770 } else { 23185b7f77adStw21770 return (-1); 23195b7f77adStw21770 } 23205b7f77adStw21770 23215b7f77adStw21770 /* 23225b7f77adStw21770 * Now check property group name. 23235b7f77adStw21770 */ 23245b7f77adStw21770 if (strcmp(pg, SCF_PG_GENERAL) == 0) { 23255b7f77adStw21770 *event_id = enable ? ADT_smf_enable : ADT_smf_disable; 23265b7f77adStw21770 return (0); 23275b7f77adStw21770 } else if (strcmp(pg, SCF_PG_GENERAL_OVR) == 0) { 23285b7f77adStw21770 *event_id = enable ? ADT_smf_tmp_enable : ADT_smf_tmp_disable; 23295b7f77adStw21770 return (0); 23305b7f77adStw21770 } 23315b7f77adStw21770 return (-1); 23325b7f77adStw21770 } 23335b7f77adStw21770 #endif /* NATIVE_BUILD */ 23345b7f77adStw21770 23355b7f77adStw21770 /* 23365b7f77adStw21770 * This function compares two audit_special_prop_item_t structures 23375b7f77adStw21770 * represented by item1 and item2. It returns an integer greater than 0 if 23385b7f77adStw21770 * item1 is greater than item2. It returns 0 if they are equal and an 23395b7f77adStw21770 * integer less than 0 if item1 is less than item2. api_prop_name and 23405b7f77adStw21770 * api_pg_name are the key fields for sorting. 23415b7f77adStw21770 * 23425b7f77adStw21770 * This function is suitable for calls to bsearch(3C) and qsort(3C). 23435b7f77adStw21770 */ 23445b7f77adStw21770 static int 23455b7f77adStw21770 special_prop_compare(const void *item1, const void *item2) 23465b7f77adStw21770 { 23475b7f77adStw21770 const audit_special_prop_item_t *a = (audit_special_prop_item_t *)item1; 23485b7f77adStw21770 const audit_special_prop_item_t *b = (audit_special_prop_item_t *)item2; 23495b7f77adStw21770 int r; 23505b7f77adStw21770 23515b7f77adStw21770 r = strcmp(a->api_prop_name, b->api_prop_name); 23525b7f77adStw21770 if (r == 0) { 23535b7f77adStw21770 /* 23545b7f77adStw21770 * Primary keys are the same, so check the secondary key. 23555b7f77adStw21770 */ 23565b7f77adStw21770 r = strcmp(a->api_pg_name, b->api_pg_name); 23575b7f77adStw21770 } 23585b7f77adStw21770 return (r); 23595b7f77adStw21770 } 23605b7f77adStw21770 23617c478bd9Sstevel@tonic-gate int 23627c478bd9Sstevel@tonic-gate rc_node_init(void) 23637c478bd9Sstevel@tonic-gate { 23647c478bd9Sstevel@tonic-gate rc_node_t *np; 23657c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 23667c478bd9Sstevel@tonic-gate 23677c478bd9Sstevel@tonic-gate rc_children_pool = uu_list_pool_create("rc_children_pool", 23687c478bd9Sstevel@tonic-gate sizeof (rc_node_t), offsetof(rc_node_t, rn_sibling_node), 23697c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG); 23707c478bd9Sstevel@tonic-gate 23717c478bd9Sstevel@tonic-gate rc_pg_notify_pool = uu_list_pool_create("rc_pg_notify_pool", 23727c478bd9Sstevel@tonic-gate sizeof (rc_node_pg_notify_t), 23737c478bd9Sstevel@tonic-gate offsetof(rc_node_pg_notify_t, rnpn_node), 23747c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG); 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate rc_notify_pool = uu_list_pool_create("rc_notify_pool", 23777c478bd9Sstevel@tonic-gate sizeof (rc_notify_t), offsetof(rc_notify_t, rcn_list_node), 23787c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG); 23797c478bd9Sstevel@tonic-gate 23807c478bd9Sstevel@tonic-gate rc_notify_info_pool = uu_list_pool_create("rc_notify_info_pool", 23817c478bd9Sstevel@tonic-gate sizeof (rc_notify_info_t), 23827c478bd9Sstevel@tonic-gate offsetof(rc_notify_info_t, rni_list_node), 23837c478bd9Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG); 23847c478bd9Sstevel@tonic-gate 23857c478bd9Sstevel@tonic-gate if (rc_children_pool == NULL || rc_pg_notify_pool == NULL || 23867c478bd9Sstevel@tonic-gate rc_notify_pool == NULL || rc_notify_info_pool == NULL) 23877c478bd9Sstevel@tonic-gate uu_die("out of memory"); 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate rc_notify_list = uu_list_create(rc_notify_pool, 23907c478bd9Sstevel@tonic-gate &rc_notify_list, 0); 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate rc_notify_info_list = uu_list_create(rc_notify_info_pool, 23937c478bd9Sstevel@tonic-gate &rc_notify_info_list, 0); 23947c478bd9Sstevel@tonic-gate 23957c478bd9Sstevel@tonic-gate if (rc_notify_list == NULL || rc_notify_info_list == NULL) 23967c478bd9Sstevel@tonic-gate uu_die("out of memory"); 23977c478bd9Sstevel@tonic-gate 23985b7f77adStw21770 /* 23995b7f77adStw21770 * Sort the special_props_list array so that it can be searched 24005b7f77adStw21770 * with bsearch(3C). 24015b7f77adStw21770 * 24025b7f77adStw21770 * The special_props_list array is not compiled into the native 24035b7f77adStw21770 * build code, so there is no need to call qsort if NATIVE_BUILD is 24045b7f77adStw21770 * defined. 24055b7f77adStw21770 */ 24065b7f77adStw21770 #ifndef NATIVE_BUILD 24075b7f77adStw21770 qsort(special_props_list, SPECIAL_PROP_COUNT, 24085b7f77adStw21770 sizeof (special_props_list[0]), special_prop_compare); 24095b7f77adStw21770 #endif /* NATIVE_BUILD */ 24105b7f77adStw21770 24117c478bd9Sstevel@tonic-gate if ((np = rc_node_alloc()) == NULL) 24127c478bd9Sstevel@tonic-gate uu_die("out of memory"); 24137c478bd9Sstevel@tonic-gate 24147c478bd9Sstevel@tonic-gate rc_node_hold(np); 24157c478bd9Sstevel@tonic-gate np->rn_id.rl_type = REP_PROTOCOL_ENTITY_SCOPE; 24167c478bd9Sstevel@tonic-gate np->rn_id.rl_backend = BACKEND_TYPE_NORMAL; 24177c478bd9Sstevel@tonic-gate np->rn_hash = rc_node_hash(&np->rn_id); 24187c478bd9Sstevel@tonic-gate np->rn_name = "localhost"; 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash); 24217c478bd9Sstevel@tonic-gate cache_insert_unlocked(bp, np); 24227c478bd9Sstevel@tonic-gate cache_release(bp); 24237c478bd9Sstevel@tonic-gate 24247c478bd9Sstevel@tonic-gate rc_scope = np; 24257c478bd9Sstevel@tonic-gate return (1); 24267c478bd9Sstevel@tonic-gate } 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate /* 24297c478bd9Sstevel@tonic-gate * Fails with 24307c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 24317c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 24327c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted 24337c478bd9Sstevel@tonic-gate * _NO_RESOURCES 24347c478bd9Sstevel@tonic-gate */ 24357c478bd9Sstevel@tonic-gate static int 24367c478bd9Sstevel@tonic-gate rc_node_fill_children(rc_node_t *np, uint32_t type) 24377c478bd9Sstevel@tonic-gate { 24387c478bd9Sstevel@tonic-gate int rc; 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 24417c478bd9Sstevel@tonic-gate 24427c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) != 24437c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) 24447c478bd9Sstevel@tonic-gate return (rc); 24457c478bd9Sstevel@tonic-gate 24467c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_CHILDREN_CHANGING)) 24477c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_HAS_CHILDREN) { 24507c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING); 24517c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate 24547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 24557c478bd9Sstevel@tonic-gate rc = object_fill_children(np); 24567c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 24597c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_HAS_CHILDREN; 24607c478bd9Sstevel@tonic-gate } 24617c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING); 24627c478bd9Sstevel@tonic-gate 24637c478bd9Sstevel@tonic-gate return (rc); 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate 24667c478bd9Sstevel@tonic-gate /* 24677c478bd9Sstevel@tonic-gate * Returns 24687c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 24697c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 24707c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted 24717c478bd9Sstevel@tonic-gate * _NO_RESOURCES 24727c478bd9Sstevel@tonic-gate * _SUCCESS - if *cpp is not NULL, it is held 24737c478bd9Sstevel@tonic-gate */ 24747c478bd9Sstevel@tonic-gate static int 24757c478bd9Sstevel@tonic-gate rc_node_find_named_child(rc_node_t *np, const char *name, uint32_t type, 24767c478bd9Sstevel@tonic-gate rc_node_t **cpp) 24777c478bd9Sstevel@tonic-gate { 24787c478bd9Sstevel@tonic-gate int ret; 24797c478bd9Sstevel@tonic-gate rc_node_t *cp; 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 24827c478bd9Sstevel@tonic-gate assert(np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP); 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate ret = rc_node_fill_children(np, type); 24857c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) 24867c478bd9Sstevel@tonic-gate return (ret); 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); 24897c478bd9Sstevel@tonic-gate cp != NULL; 24907c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) { 24917c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type == type && strcmp(cp->rn_name, name) == 0) 24927c478bd9Sstevel@tonic-gate break; 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate 24957c478bd9Sstevel@tonic-gate if (cp != NULL) 24967c478bd9Sstevel@tonic-gate rc_node_hold(cp); 24977c478bd9Sstevel@tonic-gate *cpp = cp; 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate static int rc_node_parent(rc_node_t *, rc_node_t **); 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate /* 25053eae19d9Swesolows * Returns 25063eae19d9Swesolows * _INVALID_TYPE - type is invalid 25073eae19d9Swesolows * _DELETED - np or an ancestor has been deleted 25083eae19d9Swesolows * _NOT_FOUND - no ancestor of specified type exists 25093eae19d9Swesolows * _SUCCESS - *app is held 25103eae19d9Swesolows */ 25113eae19d9Swesolows static int 25123eae19d9Swesolows rc_node_find_ancestor(rc_node_t *np, uint32_t type, rc_node_t **app) 25133eae19d9Swesolows { 25143eae19d9Swesolows int ret; 25153eae19d9Swesolows rc_node_t *parent, *np_orig; 25163eae19d9Swesolows 25173eae19d9Swesolows if (type >= REP_PROTOCOL_ENTITY_MAX) 25183eae19d9Swesolows return (REP_PROTOCOL_FAIL_INVALID_TYPE); 25193eae19d9Swesolows 25203eae19d9Swesolows np_orig = np; 25213eae19d9Swesolows 25223eae19d9Swesolows while (np->rn_id.rl_type > type) { 25233eae19d9Swesolows ret = rc_node_parent(np, &parent); 25243eae19d9Swesolows if (np != np_orig) 25253eae19d9Swesolows rc_node_rele(np); 25263eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) 25273eae19d9Swesolows return (ret); 25283eae19d9Swesolows np = parent; 25293eae19d9Swesolows } 25303eae19d9Swesolows 25313eae19d9Swesolows if (np->rn_id.rl_type == type) { 25323eae19d9Swesolows *app = parent; 25333eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 25343eae19d9Swesolows } 25353eae19d9Swesolows 25363eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND); 25373eae19d9Swesolows } 25383eae19d9Swesolows 25393eae19d9Swesolows #ifndef NATIVE_BUILD 25403eae19d9Swesolows /* 25417c478bd9Sstevel@tonic-gate * If the propname property exists in pg, and it is of type string, add its 25427c478bd9Sstevel@tonic-gate * values as authorizations to pcp. pg must not be locked on entry, and it is 25437c478bd9Sstevel@tonic-gate * returned unlocked. Returns 25447c478bd9Sstevel@tonic-gate * _DELETED - pg was deleted 25457c478bd9Sstevel@tonic-gate * _NO_RESOURCES 25467c478bd9Sstevel@tonic-gate * _NOT_FOUND - pg has no property named propname 25477c478bd9Sstevel@tonic-gate * _SUCCESS 25487c478bd9Sstevel@tonic-gate */ 25497c478bd9Sstevel@tonic-gate static int 25507c478bd9Sstevel@tonic-gate perm_add_pg_prop_values(permcheck_t *pcp, rc_node_t *pg, const char *propname) 25517c478bd9Sstevel@tonic-gate { 25527c478bd9Sstevel@tonic-gate rc_node_t *prop; 25537c478bd9Sstevel@tonic-gate int result; 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate uint_t count; 25567c478bd9Sstevel@tonic-gate const char *cp; 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock)); 25597c478bd9Sstevel@tonic-gate assert(pg->rn_id.rl_type == REP_PROTOCOL_ENTITY_PROPERTYGRP); 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock); 25627c478bd9Sstevel@tonic-gate result = rc_node_find_named_child(pg, propname, 25637c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop); 25647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock); 25657c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) { 25667c478bd9Sstevel@tonic-gate switch (result) { 25677c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED: 25687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 25697c478bd9Sstevel@tonic-gate return (result); 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_INVALID_TYPE: 25727c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH: 25737c478bd9Sstevel@tonic-gate default: 25747c478bd9Sstevel@tonic-gate bad_error("rc_node_find_named_child", result); 25757c478bd9Sstevel@tonic-gate } 25767c478bd9Sstevel@tonic-gate } 25777c478bd9Sstevel@tonic-gate 25787c478bd9Sstevel@tonic-gate if (prop == NULL) 25797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate /* rn_valtype is immutable, so no locking. */ 25827c478bd9Sstevel@tonic-gate if (prop->rn_valtype != REP_PROTOCOL_TYPE_STRING) { 25837c478bd9Sstevel@tonic-gate rc_node_rele(prop); 25847c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 25857c478bd9Sstevel@tonic-gate } 25867c478bd9Sstevel@tonic-gate 25877c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&prop->rn_lock); 25887c478bd9Sstevel@tonic-gate for (count = prop->rn_values_count, cp = prop->rn_values; 25897c478bd9Sstevel@tonic-gate count > 0; 25907c478bd9Sstevel@tonic-gate --count) { 25915b7f77adStw21770 result = perm_add_enabling_type(pcp, cp, 25925b7f77adStw21770 (pg->rn_id.rl_ids[ID_INSTANCE]) ? PC_AUTH_INST : 25935b7f77adStw21770 PC_AUTH_SVC); 25947c478bd9Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 25957c478bd9Sstevel@tonic-gate break; 25967c478bd9Sstevel@tonic-gate 25977c478bd9Sstevel@tonic-gate cp = strchr(cp, '\0') + 1; 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate rc_node_rele_locked(prop); 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate return (result); 26037c478bd9Sstevel@tonic-gate } 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate /* 26067c478bd9Sstevel@tonic-gate * Assuming that ent is a service or instance node, if the pgname property 26077c478bd9Sstevel@tonic-gate * group has type pgtype, and it has a propname property with string type, add 26087c478bd9Sstevel@tonic-gate * its values as authorizations to pcp. If pgtype is NULL, it is not checked. 26097c478bd9Sstevel@tonic-gate * Returns 26107c478bd9Sstevel@tonic-gate * _SUCCESS 26117c478bd9Sstevel@tonic-gate * _DELETED - ent was deleted 26127c478bd9Sstevel@tonic-gate * _NO_RESOURCES - no resources 26137c478bd9Sstevel@tonic-gate * _NOT_FOUND - ent does not have pgname pg or propname property 26147c478bd9Sstevel@tonic-gate */ 26157c478bd9Sstevel@tonic-gate static int 26167c478bd9Sstevel@tonic-gate perm_add_ent_prop_values(permcheck_t *pcp, rc_node_t *ent, const char *pgname, 26177c478bd9Sstevel@tonic-gate const char *pgtype, const char *propname) 26187c478bd9Sstevel@tonic-gate { 26197c478bd9Sstevel@tonic-gate int r; 26207c478bd9Sstevel@tonic-gate rc_node_t *pg; 26217c478bd9Sstevel@tonic-gate 26227c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&ent->rn_lock)); 26237c478bd9Sstevel@tonic-gate 26247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock); 26257c478bd9Sstevel@tonic-gate r = rc_node_find_named_child(ent, pgname, 26267c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg); 26277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock); 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate switch (r) { 26307c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS: 26317c478bd9Sstevel@tonic-gate break; 26327c478bd9Sstevel@tonic-gate 26337c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED: 26347c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 26357c478bd9Sstevel@tonic-gate return (r); 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate default: 26387c478bd9Sstevel@tonic-gate bad_error("rc_node_find_named_child", r); 26397c478bd9Sstevel@tonic-gate } 26407c478bd9Sstevel@tonic-gate 26417c478bd9Sstevel@tonic-gate if (pg == NULL) 26427c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 26437c478bd9Sstevel@tonic-gate 26447c478bd9Sstevel@tonic-gate if (pgtype == NULL || strcmp(pg->rn_type, pgtype) == 0) { 26457c478bd9Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname); 26467c478bd9Sstevel@tonic-gate switch (r) { 26477c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED: 26487c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_FAIL_NOT_FOUND; 26497c478bd9Sstevel@tonic-gate break; 26507c478bd9Sstevel@tonic-gate 26517c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 26527c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS: 26537c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NOT_FOUND: 26547c478bd9Sstevel@tonic-gate break; 26557c478bd9Sstevel@tonic-gate 26567c478bd9Sstevel@tonic-gate default: 26577c478bd9Sstevel@tonic-gate bad_error("perm_add_pg_prop_values", r); 26587c478bd9Sstevel@tonic-gate } 26597c478bd9Sstevel@tonic-gate } 26607c478bd9Sstevel@tonic-gate 26617c478bd9Sstevel@tonic-gate rc_node_rele(pg); 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate return (r); 26647c478bd9Sstevel@tonic-gate } 26657c478bd9Sstevel@tonic-gate 26667c478bd9Sstevel@tonic-gate /* 26673eae19d9Swesolows * If pg has a property named propname, and is string typed, add its values as 26687c478bd9Sstevel@tonic-gate * authorizations to pcp. If pg has no such property, and its parent is an 26697c478bd9Sstevel@tonic-gate * instance, walk up to the service and try doing the same with the property 26707c478bd9Sstevel@tonic-gate * of the same name from the property group of the same name. Returns 26717c478bd9Sstevel@tonic-gate * _SUCCESS 26727c478bd9Sstevel@tonic-gate * _NO_RESOURCES 26737c478bd9Sstevel@tonic-gate * _DELETED - pg (or an ancestor) was deleted 26747c478bd9Sstevel@tonic-gate */ 26757c478bd9Sstevel@tonic-gate static int 26767c478bd9Sstevel@tonic-gate perm_add_enabling_values(permcheck_t *pcp, rc_node_t *pg, const char *propname) 26777c478bd9Sstevel@tonic-gate { 26787c478bd9Sstevel@tonic-gate int r; 26793eae19d9Swesolows char pgname[REP_PROTOCOL_NAME_LEN + 1]; 26803eae19d9Swesolows rc_node_t *svc; 26813eae19d9Swesolows size_t sz; 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname); 26847c478bd9Sstevel@tonic-gate 26853eae19d9Swesolows if (r != REP_PROTOCOL_FAIL_NOT_FOUND) 26863eae19d9Swesolows return (r); 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock)); 26897c478bd9Sstevel@tonic-gate 26903eae19d9Swesolows if (pg->rn_id.rl_ids[ID_INSTANCE] == 0) 26917c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate sz = strlcpy(pgname, pg->rn_name, sizeof (pgname)); 26947c478bd9Sstevel@tonic-gate assert(sz < sizeof (pgname)); 26957c478bd9Sstevel@tonic-gate 26963eae19d9Swesolows /* 26973eae19d9Swesolows * If pg is a child of an instance or snapshot, we want to compose the 26983eae19d9Swesolows * authorization property with the service's (if it exists). The 26993eae19d9Swesolows * snapshot case applies only to read_authorization. In all other 27003eae19d9Swesolows * cases, the pg's parent will be the instance. 27013eae19d9Swesolows */ 27023eae19d9Swesolows r = rc_node_find_ancestor(pg, REP_PROTOCOL_ENTITY_SERVICE, &svc); 27037c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) { 27047c478bd9Sstevel@tonic-gate assert(r == REP_PROTOCOL_FAIL_DELETED); 27057c478bd9Sstevel@tonic-gate return (r); 27067c478bd9Sstevel@tonic-gate } 27077c478bd9Sstevel@tonic-gate assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE); 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate rc_node_rele(svc); 27127c478bd9Sstevel@tonic-gate 27137c478bd9Sstevel@tonic-gate if (r == REP_PROTOCOL_FAIL_NOT_FOUND) 27147c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_SUCCESS; 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate return (r); 27177c478bd9Sstevel@tonic-gate } 27187c478bd9Sstevel@tonic-gate 27197c478bd9Sstevel@tonic-gate /* 27207c478bd9Sstevel@tonic-gate * Call perm_add_enabling_values() for the "action_authorization" property of 27217c478bd9Sstevel@tonic-gate * the "general" property group of inst. Returns 27227c478bd9Sstevel@tonic-gate * _DELETED - inst (or an ancestor) was deleted 27237c478bd9Sstevel@tonic-gate * _NO_RESOURCES 27247c478bd9Sstevel@tonic-gate * _SUCCESS 27257c478bd9Sstevel@tonic-gate */ 27267c478bd9Sstevel@tonic-gate static int 27277c478bd9Sstevel@tonic-gate perm_add_inst_action_auth(permcheck_t *pcp, rc_node_t *inst) 27287c478bd9Sstevel@tonic-gate { 27297c478bd9Sstevel@tonic-gate int r; 27307c478bd9Sstevel@tonic-gate rc_node_t *svc; 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate assert(inst->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE); 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, inst, AUTH_PG_GENERAL, 27357c478bd9Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION); 27367c478bd9Sstevel@tonic-gate 27377c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_FAIL_NOT_FOUND) 27387c478bd9Sstevel@tonic-gate return (r); 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate r = rc_node_parent(inst, &svc); 27417c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) { 27427c478bd9Sstevel@tonic-gate assert(r == REP_PROTOCOL_FAIL_DELETED); 27437c478bd9Sstevel@tonic-gate return (r); 27447c478bd9Sstevel@tonic-gate } 27457c478bd9Sstevel@tonic-gate 27467c478bd9Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, svc, AUTH_PG_GENERAL, 27477c478bd9Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION); 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate return (r == REP_PROTOCOL_FAIL_NOT_FOUND ? REP_PROTOCOL_SUCCESS : r); 27507c478bd9Sstevel@tonic-gate } 27517c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 27527c478bd9Sstevel@tonic-gate 27537c478bd9Sstevel@tonic-gate void 27547c478bd9Sstevel@tonic-gate rc_node_ptr_init(rc_node_ptr_t *out) 27557c478bd9Sstevel@tonic-gate { 27567c478bd9Sstevel@tonic-gate out->rnp_node = NULL; 27575b7f77adStw21770 out->rnp_auth_string = NULL; 27585b7f77adStw21770 out->rnp_authorized = RC_AUTH_UNKNOWN; 27597c478bd9Sstevel@tonic-gate out->rnp_deleted = 0; 27607c478bd9Sstevel@tonic-gate } 27617c478bd9Sstevel@tonic-gate 27625b7f77adStw21770 void 27635b7f77adStw21770 rc_node_ptr_free_mem(rc_node_ptr_t *npp) 27645b7f77adStw21770 { 27655b7f77adStw21770 if (npp->rnp_auth_string != NULL) { 27665b7f77adStw21770 free((void *)npp->rnp_auth_string); 27675b7f77adStw21770 npp->rnp_auth_string = NULL; 27685b7f77adStw21770 } 27695b7f77adStw21770 } 27705b7f77adStw21770 27717c478bd9Sstevel@tonic-gate static void 27727c478bd9Sstevel@tonic-gate rc_node_assign(rc_node_ptr_t *out, rc_node_t *val) 27737c478bd9Sstevel@tonic-gate { 27747c478bd9Sstevel@tonic-gate rc_node_t *cur = out->rnp_node; 27757c478bd9Sstevel@tonic-gate if (val != NULL) 27767c478bd9Sstevel@tonic-gate rc_node_hold(val); 27777c478bd9Sstevel@tonic-gate out->rnp_node = val; 27786643e1ffSbustos if (cur != NULL) { 27796643e1ffSbustos NODE_LOCK(cur); 27806643e1ffSbustos 27816643e1ffSbustos /* 27826643e1ffSbustos * Register the ephemeral reference created by reading 27836643e1ffSbustos * out->rnp_node into cur. Note that the persistent 27846643e1ffSbustos * reference we're destroying is locked by the client 27856643e1ffSbustos * layer. 27866643e1ffSbustos */ 27876643e1ffSbustos rc_node_hold_ephemeral_locked(cur); 27886643e1ffSbustos 27896643e1ffSbustos rc_node_rele_locked(cur); 27906643e1ffSbustos } 27915b7f77adStw21770 out->rnp_authorized = RC_AUTH_UNKNOWN; 27925b7f77adStw21770 rc_node_ptr_free_mem(out); 27937c478bd9Sstevel@tonic-gate out->rnp_deleted = 0; 27947c478bd9Sstevel@tonic-gate } 27957c478bd9Sstevel@tonic-gate 27967c478bd9Sstevel@tonic-gate void 27977c478bd9Sstevel@tonic-gate rc_node_clear(rc_node_ptr_t *out, int deleted) 27987c478bd9Sstevel@tonic-gate { 27997c478bd9Sstevel@tonic-gate rc_node_assign(out, NULL); 28007c478bd9Sstevel@tonic-gate out->rnp_deleted = deleted; 28017c478bd9Sstevel@tonic-gate } 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate void 28047c478bd9Sstevel@tonic-gate rc_node_ptr_assign(rc_node_ptr_t *out, const rc_node_ptr_t *val) 28057c478bd9Sstevel@tonic-gate { 28067c478bd9Sstevel@tonic-gate rc_node_assign(out, val->rnp_node); 28077c478bd9Sstevel@tonic-gate } 28087c478bd9Sstevel@tonic-gate 28097c478bd9Sstevel@tonic-gate /* 28107c478bd9Sstevel@tonic-gate * rc_node_check()/RC_NODE_CHECK() 28117c478bd9Sstevel@tonic-gate * generic "entry" checks, run before the use of an rc_node pointer. 28127c478bd9Sstevel@tonic-gate * 28137c478bd9Sstevel@tonic-gate * Fails with 28147c478bd9Sstevel@tonic-gate * _NOT_SET 28157c478bd9Sstevel@tonic-gate * _DELETED 28167c478bd9Sstevel@tonic-gate */ 28177c478bd9Sstevel@tonic-gate static int 28187c478bd9Sstevel@tonic-gate rc_node_check_and_lock(rc_node_t *np) 28197c478bd9Sstevel@tonic-gate { 28207c478bd9Sstevel@tonic-gate int result = REP_PROTOCOL_SUCCESS; 28217c478bd9Sstevel@tonic-gate if (np == NULL) 28227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET); 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 28257c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) { 28267c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_DELETED; 28277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 28287c478bd9Sstevel@tonic-gate } 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate return (result); 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate /* 28347c478bd9Sstevel@tonic-gate * Fails with 28357c478bd9Sstevel@tonic-gate * _NOT_SET - ptr is reset 28367c478bd9Sstevel@tonic-gate * _DELETED - node has been deleted 28377c478bd9Sstevel@tonic-gate */ 28387c478bd9Sstevel@tonic-gate static rc_node_t * 28397c478bd9Sstevel@tonic-gate rc_node_ptr_check_and_lock(rc_node_ptr_t *npp, int *res) 28407c478bd9Sstevel@tonic-gate { 28417c478bd9Sstevel@tonic-gate rc_node_t *np = npp->rnp_node; 28427c478bd9Sstevel@tonic-gate if (np == NULL) { 28437c478bd9Sstevel@tonic-gate if (npp->rnp_deleted) 28447c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED; 28457c478bd9Sstevel@tonic-gate else 28467c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_NOT_SET; 28477c478bd9Sstevel@tonic-gate return (NULL); 28487c478bd9Sstevel@tonic-gate } 28497c478bd9Sstevel@tonic-gate 28507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 28517c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) { 28527c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 28537c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 28547c478bd9Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED; 28557c478bd9Sstevel@tonic-gate return (NULL); 28567c478bd9Sstevel@tonic-gate } 28577c478bd9Sstevel@tonic-gate return (np); 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK_AND_LOCK(n) { \ 28617c478bd9Sstevel@tonic-gate int rc__res; \ 28627c478bd9Sstevel@tonic-gate if ((rc__res = rc_node_check_and_lock(n)) != REP_PROTOCOL_SUCCESS) \ 28637c478bd9Sstevel@tonic-gate return (rc__res); \ 28647c478bd9Sstevel@tonic-gate } 28657c478bd9Sstevel@tonic-gate 28667c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK(n) { \ 28677c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \ 28687c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \ 28697c478bd9Sstevel@tonic-gate } 28707c478bd9Sstevel@tonic-gate 28717c478bd9Sstevel@tonic-gate #define RC_NODE_CHECK_AND_HOLD(n) { \ 28727c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \ 28737c478bd9Sstevel@tonic-gate rc_node_hold_locked(n); \ 28747c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \ 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate 28777c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp) { \ 28787c478bd9Sstevel@tonic-gate int rc__res; \ 28797c478bd9Sstevel@tonic-gate if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == NULL) \ 28807c478bd9Sstevel@tonic-gate return (rc__res); \ 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 2883a4dc1477STom Whitten #define RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, mem) { \ 2884a4dc1477STom Whitten int rc__res; \ 2885a4dc1477STom Whitten if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == \ 2886a4dc1477STom Whitten NULL) { \ 2887a4dc1477STom Whitten if ((mem) != NULL) \ 2888a4dc1477STom Whitten free((mem)); \ 2889a4dc1477STom Whitten return (rc__res); \ 2890a4dc1477STom Whitten } \ 2891a4dc1477STom Whitten } 2892a4dc1477STom Whitten 28937c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK(np, npp) { \ 28947c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \ 28957c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \ 28967c478bd9Sstevel@tonic-gate } 28977c478bd9Sstevel@tonic-gate 28987c478bd9Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp) { \ 28997c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \ 29007c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); \ 29017c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \ 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate #define HOLD_FLAG_OR_RETURN(np, flag) { \ 29057c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&(np)->rn_lock)); \ 29067c478bd9Sstevel@tonic-gate assert(!((np)->rn_flags & RC_NODE_DEAD)); \ 29077c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag((np), flag)) { \ 29087c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \ 29097c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); \ 29107c478bd9Sstevel@tonic-gate } \ 29117c478bd9Sstevel@tonic-gate } 29127c478bd9Sstevel@tonic-gate 29135b7f77adStw21770 #define HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, flag, mem) { \ 29145b7f77adStw21770 assert(MUTEX_HELD(&(np)->rn_lock)); \ 29155b7f77adStw21770 if (!rc_node_hold_flag((np), flag)) { \ 29165b7f77adStw21770 (void) pthread_mutex_unlock(&(np)->rn_lock); \ 29175b7f77adStw21770 assert((np) == (npp)->rnp_node); \ 29185b7f77adStw21770 rc_node_clear(npp, 1); \ 29195b7f77adStw21770 if ((mem) != NULL) \ 29205b7f77adStw21770 free((mem)); \ 29215b7f77adStw21770 return (REP_PROTOCOL_FAIL_DELETED); \ 29225b7f77adStw21770 } \ 29235b7f77adStw21770 } 29245b7f77adStw21770 29257c478bd9Sstevel@tonic-gate int 29267c478bd9Sstevel@tonic-gate rc_local_scope(uint32_t type, rc_node_ptr_t *out) 29277c478bd9Sstevel@tonic-gate { 29287c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE) { 29297c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 29307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 29317c478bd9Sstevel@tonic-gate } 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate /* 29347c478bd9Sstevel@tonic-gate * the main scope never gets destroyed 29357c478bd9Sstevel@tonic-gate */ 29367c478bd9Sstevel@tonic-gate rc_node_assign(out, rc_scope); 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 29397c478bd9Sstevel@tonic-gate } 29407c478bd9Sstevel@tonic-gate 29417c478bd9Sstevel@tonic-gate /* 29427c478bd9Sstevel@tonic-gate * Fails with 29437c478bd9Sstevel@tonic-gate * _NOT_SET - npp is not set 29447c478bd9Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted 29457c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - type is not _SCOPE 29467c478bd9Sstevel@tonic-gate * _NOT_FOUND - scope has no parent 29477c478bd9Sstevel@tonic-gate */ 29487c478bd9Sstevel@tonic-gate static int 29497c478bd9Sstevel@tonic-gate rc_scope_parent_scope(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out) 29507c478bd9Sstevel@tonic-gate { 29517c478bd9Sstevel@tonic-gate rc_node_t *np; 29527c478bd9Sstevel@tonic-gate 29537c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 29547c478bd9Sstevel@tonic-gate 29557c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 29567c478bd9Sstevel@tonic-gate 29577c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE) 29587c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 29597c478bd9Sstevel@tonic-gate 29607c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 29617c478bd9Sstevel@tonic-gate } 29627c478bd9Sstevel@tonic-gate 29633eae19d9Swesolows static int rc_node_pg_check_read_protect(rc_node_t *); 29643eae19d9Swesolows 29657c478bd9Sstevel@tonic-gate /* 29667c478bd9Sstevel@tonic-gate * Fails with 29677c478bd9Sstevel@tonic-gate * _NOT_SET 29687c478bd9Sstevel@tonic-gate * _DELETED 29697c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE 29707c478bd9Sstevel@tonic-gate * _NOT_FOUND 29717c478bd9Sstevel@tonic-gate * _BAD_REQUEST 29727c478bd9Sstevel@tonic-gate * _TRUNCATED 29733eae19d9Swesolows * _NO_RESOURCES 29747c478bd9Sstevel@tonic-gate */ 29757c478bd9Sstevel@tonic-gate int 29767c478bd9Sstevel@tonic-gate rc_node_name(rc_node_ptr_t *npp, char *buf, size_t sz, uint32_t answertype, 29777c478bd9Sstevel@tonic-gate size_t *sz_out) 29787c478bd9Sstevel@tonic-gate { 29797c478bd9Sstevel@tonic-gate size_t actual; 29807c478bd9Sstevel@tonic-gate rc_node_t *np; 29817c478bd9Sstevel@tonic-gate 29827c478bd9Sstevel@tonic-gate assert(sz == *sz_out); 29837c478bd9Sstevel@tonic-gate 29847c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 29877c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 29887c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np); 29897c478bd9Sstevel@tonic-gate } 29907c478bd9Sstevel@tonic-gate 29917c478bd9Sstevel@tonic-gate switch (answertype) { 29927c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_NAME: 29937c478bd9Sstevel@tonic-gate if (np->rn_name == NULL) 29947c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 29957c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_name, sz); 29967c478bd9Sstevel@tonic-gate break; 29977c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_PGTYPE: 29987c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) 29997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30007c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_type, sz); 30017c478bd9Sstevel@tonic-gate break; 30027c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_PGFLAGS: 30037c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) 30047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30057c478bd9Sstevel@tonic-gate actual = snprintf(buf, sz, "%d", np->rn_pgflags); 30067c478bd9Sstevel@tonic-gate break; 30077c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SCOPE: 30087c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) 30097c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30107c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_scope, sz); 30117c478bd9Sstevel@tonic-gate break; 30127c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SERVICE: 30137c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) 30147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30157c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_service, sz); 30167c478bd9Sstevel@tonic-gate break; 30177c478bd9Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_INSTANCE: 30187c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) 30197c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30207c478bd9Sstevel@tonic-gate if (np->rn_snaplevel->rsl_instance == NULL) 30217c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 30227c478bd9Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_instance, sz); 30237c478bd9Sstevel@tonic-gate break; 30243eae19d9Swesolows case RP_ENTITY_NAME_PGREADPROT: 30253eae19d9Swesolows { 30263eae19d9Swesolows int ret; 30273eae19d9Swesolows 30283eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) 30293eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 30303eae19d9Swesolows ret = rc_node_pg_check_read_protect(np); 30313eae19d9Swesolows assert(ret != REP_PROTOCOL_FAIL_TYPE_MISMATCH); 30323eae19d9Swesolows switch (ret) { 30333eae19d9Swesolows case REP_PROTOCOL_FAIL_PERMISSION_DENIED: 30343eae19d9Swesolows actual = snprintf(buf, sz, "1"); 30353eae19d9Swesolows break; 30363eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 30373eae19d9Swesolows actual = snprintf(buf, sz, "0"); 30383eae19d9Swesolows break; 30393eae19d9Swesolows default: 30403eae19d9Swesolows return (ret); 30413eae19d9Swesolows } 30423eae19d9Swesolows break; 30433eae19d9Swesolows } 30447c478bd9Sstevel@tonic-gate default: 30457c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 30467c478bd9Sstevel@tonic-gate } 30477c478bd9Sstevel@tonic-gate if (actual >= sz) 30487c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TRUNCATED); 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate *sz_out = actual; 30517c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 30527c478bd9Sstevel@tonic-gate } 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate int 30557c478bd9Sstevel@tonic-gate rc_node_get_property_type(rc_node_ptr_t *npp, rep_protocol_value_type_t *out) 30567c478bd9Sstevel@tonic-gate { 30577c478bd9Sstevel@tonic-gate rc_node_t *np; 30587c478bd9Sstevel@tonic-gate 30597c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 30607c478bd9Sstevel@tonic-gate 30617c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) 30627c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate *out = np->rn_valtype; 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 30677c478bd9Sstevel@tonic-gate } 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate /* 30707c478bd9Sstevel@tonic-gate * Get np's parent. If np is deleted, returns _DELETED. Otherwise puts a hold 30717c478bd9Sstevel@tonic-gate * on the parent, returns a pointer to it in *out, and returns _SUCCESS. 30727c478bd9Sstevel@tonic-gate */ 30737c478bd9Sstevel@tonic-gate static int 30747c478bd9Sstevel@tonic-gate rc_node_parent(rc_node_t *np, rc_node_t **out) 30757c478bd9Sstevel@tonic-gate { 30767c478bd9Sstevel@tonic-gate rc_node_t *pnp; 30777c478bd9Sstevel@tonic-gate rc_node_t *np_orig; 30787c478bd9Sstevel@tonic-gate 30797c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 30807c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np); 30817c478bd9Sstevel@tonic-gate } else { 30827c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 30837c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np); 30847c478bd9Sstevel@tonic-gate } 30857c478bd9Sstevel@tonic-gate 30867c478bd9Sstevel@tonic-gate np_orig = np; 30877c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */ 30887c478bd9Sstevel@tonic-gate 30897c478bd9Sstevel@tonic-gate for (;;) { 30907c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, 30917c478bd9Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) { 30927c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 30937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 30947c478bd9Sstevel@tonic-gate } 30957c478bd9Sstevel@tonic-gate 30967c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD)) 30977c478bd9Sstevel@tonic-gate break; 30987c478bd9Sstevel@tonic-gate 30997c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 31007c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id); 31017c478bd9Sstevel@tonic-gate assert(np != np_orig); 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate if (np == NULL) 31047c478bd9Sstevel@tonic-gate goto deleted; 31057c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 31067c478bd9Sstevel@tonic-gate } 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate /* guaranteed to succeed without dropping the lock */ 31097c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 31107c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 31117c478bd9Sstevel@tonic-gate *out = NULL; 31127c478bd9Sstevel@tonic-gate rc_node_rele(np); 31137c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 31147c478bd9Sstevel@tonic-gate } 31157c478bd9Sstevel@tonic-gate 31167c478bd9Sstevel@tonic-gate assert(np->rn_parent != NULL); 31177c478bd9Sstevel@tonic-gate pnp = np->rn_parent; 31187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 31197c478bd9Sstevel@tonic-gate 31207c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pnp->rn_lock); 31217c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 31227c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 31237c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 31247c478bd9Sstevel@tonic-gate 31257c478bd9Sstevel@tonic-gate rc_node_hold_locked(pnp); 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pnp->rn_lock); 31287c478bd9Sstevel@tonic-gate 31297c478bd9Sstevel@tonic-gate rc_node_rele(np); 31307c478bd9Sstevel@tonic-gate *out = pnp; 31317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate deleted: 31347c478bd9Sstevel@tonic-gate rc_node_rele(np); 31357c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 31367c478bd9Sstevel@tonic-gate } 31377c478bd9Sstevel@tonic-gate 31387c478bd9Sstevel@tonic-gate /* 31397c478bd9Sstevel@tonic-gate * Fails with 31407c478bd9Sstevel@tonic-gate * _NOT_SET 31417c478bd9Sstevel@tonic-gate * _DELETED 31427c478bd9Sstevel@tonic-gate */ 31437c478bd9Sstevel@tonic-gate static int 31447c478bd9Sstevel@tonic-gate rc_node_ptr_parent(rc_node_ptr_t *npp, rc_node_t **out) 31457c478bd9Sstevel@tonic-gate { 31467c478bd9Sstevel@tonic-gate rc_node_t *np; 31477c478bd9Sstevel@tonic-gate 31487c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 31497c478bd9Sstevel@tonic-gate 31507c478bd9Sstevel@tonic-gate return (rc_node_parent(np, out)); 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate /* 31547c478bd9Sstevel@tonic-gate * Fails with 31557c478bd9Sstevel@tonic-gate * _NOT_SET - npp is not set 31567c478bd9Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted 31577c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node's parent is not of type type 31587c478bd9Sstevel@tonic-gate * 31597c478bd9Sstevel@tonic-gate * If npp points to a scope, can also fail with 31607c478bd9Sstevel@tonic-gate * _NOT_FOUND - scope has no parent 31617c478bd9Sstevel@tonic-gate */ 31627c478bd9Sstevel@tonic-gate int 31637c478bd9Sstevel@tonic-gate rc_node_get_parent(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out) 31647c478bd9Sstevel@tonic-gate { 31657c478bd9Sstevel@tonic-gate rc_node_t *pnp; 31667c478bd9Sstevel@tonic-gate int rc; 31677c478bd9Sstevel@tonic-gate 31687c478bd9Sstevel@tonic-gate if (npp->rnp_node != NULL && 31697c478bd9Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE) 31707c478bd9Sstevel@tonic-gate return (rc_scope_parent_scope(npp, type, out)); 31717c478bd9Sstevel@tonic-gate 31727c478bd9Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS) { 31737c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 31747c478bd9Sstevel@tonic-gate return (rc); 31757c478bd9Sstevel@tonic-gate } 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate if (type != pnp->rn_id.rl_type) { 31787c478bd9Sstevel@tonic-gate rc_node_rele(pnp); 31797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 31807c478bd9Sstevel@tonic-gate } 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate rc_node_assign(out, pnp); 31837c478bd9Sstevel@tonic-gate rc_node_rele(pnp); 31847c478bd9Sstevel@tonic-gate 31857c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 31867c478bd9Sstevel@tonic-gate } 31877c478bd9Sstevel@tonic-gate 31887c478bd9Sstevel@tonic-gate int 31897c478bd9Sstevel@tonic-gate rc_node_parent_type(rc_node_ptr_t *npp, uint32_t *type_out) 31907c478bd9Sstevel@tonic-gate { 31917c478bd9Sstevel@tonic-gate rc_node_t *pnp; 31927c478bd9Sstevel@tonic-gate int rc; 31937c478bd9Sstevel@tonic-gate 31947c478bd9Sstevel@tonic-gate if (npp->rnp_node != NULL && 31957c478bd9Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE) { 31967c478bd9Sstevel@tonic-gate *type_out = REP_PROTOCOL_ENTITY_SCOPE; 31977c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 31987c478bd9Sstevel@tonic-gate } 31997c478bd9Sstevel@tonic-gate 32007c478bd9Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS) 32017c478bd9Sstevel@tonic-gate return (rc); 32027c478bd9Sstevel@tonic-gate 32037c478bd9Sstevel@tonic-gate *type_out = pnp->rn_id.rl_type; 32047c478bd9Sstevel@tonic-gate 32057c478bd9Sstevel@tonic-gate rc_node_rele(pnp); 32067c478bd9Sstevel@tonic-gate 32077c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 32087c478bd9Sstevel@tonic-gate } 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate /* 32117c478bd9Sstevel@tonic-gate * Fails with 32127c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 32137c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 32147c478bd9Sstevel@tonic-gate * _DELETED - np has been deleted 32157c478bd9Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found 32167c478bd9Sstevel@tonic-gate * _NO_RESOURCES 32177c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 32187c478bd9Sstevel@tonic-gate */ 32197c478bd9Sstevel@tonic-gate int 32207c478bd9Sstevel@tonic-gate rc_node_get_child(rc_node_ptr_t *npp, const char *name, uint32_t type, 32217c478bd9Sstevel@tonic-gate rc_node_ptr_t *outp) 32227c478bd9Sstevel@tonic-gate { 32237c478bd9Sstevel@tonic-gate rc_node_t *np, *cp; 32247c478bd9Sstevel@tonic-gate rc_node_t *child = NULL; 32257c478bd9Sstevel@tonic-gate int ret, idx; 32267c478bd9Sstevel@tonic-gate 32277c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 32287c478bd9Sstevel@tonic-gate if ((ret = rc_check_type_name(type, name)) == REP_PROTOCOL_SUCCESS) { 32297c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 32307c478bd9Sstevel@tonic-gate ret = rc_node_find_named_child(np, name, type, &child); 32317c478bd9Sstevel@tonic-gate } else { 32327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 32337c478bd9Sstevel@tonic-gate ret = REP_PROTOCOL_SUCCESS; 32347c478bd9Sstevel@tonic-gate for (idx = 0; idx < COMPOSITION_DEPTH; idx++) { 32357c478bd9Sstevel@tonic-gate cp = np->rn_cchain[idx]; 32367c478bd9Sstevel@tonic-gate if (cp == NULL) 32377c478bd9Sstevel@tonic-gate break; 32387c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(cp); 32397c478bd9Sstevel@tonic-gate ret = rc_node_find_named_child(cp, name, type, 32407c478bd9Sstevel@tonic-gate &child); 32417c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock); 32427c478bd9Sstevel@tonic-gate /* 32437c478bd9Sstevel@tonic-gate * loop only if we succeeded, but no child of 32447c478bd9Sstevel@tonic-gate * the correct name was found. 32457c478bd9Sstevel@tonic-gate */ 32467c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS || 32477c478bd9Sstevel@tonic-gate child != NULL) 32487c478bd9Sstevel@tonic-gate break; 32497c478bd9Sstevel@tonic-gate } 32507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 32517c478bd9Sstevel@tonic-gate } 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 32547c478bd9Sstevel@tonic-gate 32557c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) { 32567c478bd9Sstevel@tonic-gate rc_node_assign(outp, child); 32577c478bd9Sstevel@tonic-gate if (child != NULL) 32587c478bd9Sstevel@tonic-gate rc_node_rele(child); 32597c478bd9Sstevel@tonic-gate else 32607c478bd9Sstevel@tonic-gate ret = REP_PROTOCOL_FAIL_NOT_FOUND; 32617c478bd9Sstevel@tonic-gate } else { 32627c478bd9Sstevel@tonic-gate rc_node_assign(outp, NULL); 32637c478bd9Sstevel@tonic-gate } 32647c478bd9Sstevel@tonic-gate return (ret); 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate int 32687c478bd9Sstevel@tonic-gate rc_node_update(rc_node_ptr_t *npp) 32697c478bd9Sstevel@tonic-gate { 32707c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 32717c478bd9Sstevel@tonic-gate rc_node_t *np = npp->rnp_node; 32727c478bd9Sstevel@tonic-gate rc_node_t *nnp; 32737c478bd9Sstevel@tonic-gate rc_node_t *cpg = NULL; 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate if (np != NULL && 32767c478bd9Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 32777c478bd9Sstevel@tonic-gate /* 32787c478bd9Sstevel@tonic-gate * If we're updating a composed property group, actually 32797c478bd9Sstevel@tonic-gate * update the top-level property group & return the 32807c478bd9Sstevel@tonic-gate * appropriate value. But leave *nnp pointing at us. 32817c478bd9Sstevel@tonic-gate */ 32827c478bd9Sstevel@tonic-gate cpg = np; 32837c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 32847c478bd9Sstevel@tonic-gate } 32857c478bd9Sstevel@tonic-gate 32867c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np); 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP && 32897c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) 32907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 32917c478bd9Sstevel@tonic-gate 32927c478bd9Sstevel@tonic-gate for (;;) { 32937c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash); 32947c478bd9Sstevel@tonic-gate nnp = cache_lookup_unlocked(bp, &np->rn_id); 32957c478bd9Sstevel@tonic-gate if (nnp == NULL) { 32967c478bd9Sstevel@tonic-gate cache_release(bp); 32977c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 32987c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 32997c478bd9Sstevel@tonic-gate } 33007c478bd9Sstevel@tonic-gate /* 33017c478bd9Sstevel@tonic-gate * grab the lock before dropping the cache bucket, so 33027c478bd9Sstevel@tonic-gate * that no one else can sneak in 33037c478bd9Sstevel@tonic-gate */ 33047c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock); 33057c478bd9Sstevel@tonic-gate cache_release(bp); 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate if (!(nnp->rn_flags & RC_NODE_IN_TX) || 33087c478bd9Sstevel@tonic-gate !rc_node_wait_flag(nnp, RC_NODE_IN_TX)) 33097c478bd9Sstevel@tonic-gate break; 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate rc_node_rele_locked(nnp); 33127c478bd9Sstevel@tonic-gate } 33137c478bd9Sstevel@tonic-gate 33147c478bd9Sstevel@tonic-gate /* 33157c478bd9Sstevel@tonic-gate * If it is dead, we want to update it so that it will continue to 33167c478bd9Sstevel@tonic-gate * report being dead. 33177c478bd9Sstevel@tonic-gate */ 33187c478bd9Sstevel@tonic-gate if (nnp->rn_flags & RC_NODE_DEAD) { 33197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock); 33207c478bd9Sstevel@tonic-gate if (nnp != np && cpg == NULL) 33217c478bd9Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */ 33227c478bd9Sstevel@tonic-gate rc_node_rele(nnp); 33237c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 33247c478bd9Sstevel@tonic-gate } 33257c478bd9Sstevel@tonic-gate 33267c478bd9Sstevel@tonic-gate assert(!(nnp->rn_flags & RC_NODE_OLD)); 33277c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock); 33287c478bd9Sstevel@tonic-gate 33297c478bd9Sstevel@tonic-gate if (nnp != np && cpg == NULL) 33307c478bd9Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */ 33317c478bd9Sstevel@tonic-gate 33327c478bd9Sstevel@tonic-gate rc_node_rele(nnp); 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate return ((nnp == np)? REP_PROTOCOL_SUCCESS : REP_PROTOCOL_DONE); 33357c478bd9Sstevel@tonic-gate } 33367c478bd9Sstevel@tonic-gate 33377c478bd9Sstevel@tonic-gate /* 33387c478bd9Sstevel@tonic-gate * does a generic modification check, for creation, deletion, and snapshot 33397c478bd9Sstevel@tonic-gate * management only. Property group transactions have different checks. 33405b7f77adStw21770 * 33415b7f77adStw21770 * The string returned to *match_auth must be freed. 33427c478bd9Sstevel@tonic-gate */ 3343a4dc1477STom Whitten static perm_status_t 33445b7f77adStw21770 rc_node_modify_permission_check(char **match_auth) 33457c478bd9Sstevel@tonic-gate { 33467c478bd9Sstevel@tonic-gate permcheck_t *pcp; 3347a4dc1477STom Whitten perm_status_t granted = PERM_GRANTED; 3348a4dc1477STom Whitten int rc; 33497c478bd9Sstevel@tonic-gate 33505b7f77adStw21770 *match_auth = NULL; 3351273264cdSdm120769 #ifdef NATIVE_BUILD 33525b7f77adStw21770 if (!client_is_privileged()) { 3353a4dc1477STom Whitten granted = PERM_DENIED; 33545b7f77adStw21770 } 3355a4dc1477STom Whitten return (granted); 33567c478bd9Sstevel@tonic-gate #else 33575b7f77adStw21770 if (is_main_repository == 0) 3358a4dc1477STom Whitten return (PERM_GRANTED); 33597c478bd9Sstevel@tonic-gate pcp = pc_create(); 33607c478bd9Sstevel@tonic-gate if (pcp != NULL) { 33617c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY); 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 33647c478bd9Sstevel@tonic-gate granted = perm_granted(pcp); 33657c478bd9Sstevel@tonic-gate 3366a4dc1477STom Whitten if ((granted == PERM_GRANTED) || 3367a4dc1477STom Whitten (granted == PERM_DENIED)) { 33685b7f77adStw21770 /* 33695b7f77adStw21770 * Copy off the authorization 33705b7f77adStw21770 * string before freeing pcp. 33715b7f77adStw21770 */ 33725b7f77adStw21770 *match_auth = 33735b7f77adStw21770 strdup(pcp->pc_auth_string); 33745b7f77adStw21770 if (*match_auth == NULL) 3375a4dc1477STom Whitten granted = PERM_FAIL; 33765b7f77adStw21770 } 3377a4dc1477STom Whitten } else { 3378a4dc1477STom Whitten granted = PERM_FAIL; 33797c478bd9Sstevel@tonic-gate } 33807c478bd9Sstevel@tonic-gate 33817c478bd9Sstevel@tonic-gate pc_free(pcp); 33827c478bd9Sstevel@tonic-gate } else { 3383a4dc1477STom Whitten granted = PERM_FAIL; 33847c478bd9Sstevel@tonic-gate } 33857c478bd9Sstevel@tonic-gate 3386a4dc1477STom Whitten return (granted); 3387273264cdSdm120769 #endif /* NATIVE_BUILD */ 3388273264cdSdm120769 } 33895b7f77adStw21770 33905b7f77adStw21770 /* 33915b7f77adStw21770 * Native builds are done to create svc.configd-native. This program runs 33925b7f77adStw21770 * only on the Solaris build machines to create the seed repository, and it 33935b7f77adStw21770 * is compiled against the build machine's header files. The ADT_smf_* 33945b7f77adStw21770 * symbols may not be defined in these header files. For this reason 33955b7f77adStw21770 * smf_annotation_event(), _smf_audit_event() and special_property_event() 33965b7f77adStw21770 * are not compiled for native builds. 33975b7f77adStw21770 */ 33985b7f77adStw21770 #ifndef NATIVE_BUILD 33995b7f77adStw21770 34005b7f77adStw21770 /* 34015b7f77adStw21770 * This function generates an annotation audit event if one has been setup. 34025b7f77adStw21770 * Annotation events should only be generated immediately before the audit 34035b7f77adStw21770 * record from the first attempt to modify the repository from a client 34045b7f77adStw21770 * which has requested an annotation. 34055b7f77adStw21770 */ 34065b7f77adStw21770 static void 34075b7f77adStw21770 smf_annotation_event(int status, int return_val) 34085b7f77adStw21770 { 34095b7f77adStw21770 adt_session_data_t *session; 34105b7f77adStw21770 adt_event_data_t *event = NULL; 34115b7f77adStw21770 char file[MAXPATHLEN]; 34125b7f77adStw21770 char operation[REP_PROTOCOL_NAME_LEN]; 34135b7f77adStw21770 34145b7f77adStw21770 /* Don't audit if we're using an alternate repository. */ 34155b7f77adStw21770 if (is_main_repository == 0) 34165b7f77adStw21770 return; 34175b7f77adStw21770 34185b7f77adStw21770 if (client_annotation_needed(operation, sizeof (operation), file, 34195b7f77adStw21770 sizeof (file)) == 0) { 34205b7f77adStw21770 return; 34215b7f77adStw21770 } 34225b7f77adStw21770 if (file[0] == 0) { 34235b7f77adStw21770 (void) strlcpy(file, "NO FILE", sizeof (file)); 34245b7f77adStw21770 } 34255b7f77adStw21770 if (operation[0] == 0) { 34265b7f77adStw21770 (void) strlcpy(operation, "NO OPERATION", 34275b7f77adStw21770 sizeof (operation)); 34285b7f77adStw21770 } 34295b7f77adStw21770 if ((session = get_audit_session()) == NULL) 34305b7f77adStw21770 return; 34315b7f77adStw21770 if ((event = adt_alloc_event(session, ADT_smf_annotation)) == NULL) { 34325b7f77adStw21770 uu_warn("smf_annotation_event cannot allocate event " 34335b7f77adStw21770 "data. %s\n", strerror(errno)); 34345b7f77adStw21770 return; 34355b7f77adStw21770 } 34365b7f77adStw21770 event->adt_smf_annotation.operation = operation; 34375b7f77adStw21770 event->adt_smf_annotation.file = file; 34385b7f77adStw21770 if (adt_put_event(event, status, return_val) == 0) { 34395b7f77adStw21770 client_annotation_finished(); 34405b7f77adStw21770 } else { 34415b7f77adStw21770 uu_warn("smf_annotation_event failed to put event. " 34425b7f77adStw21770 "%s\n", strerror(errno)); 34435b7f77adStw21770 } 34445b7f77adStw21770 adt_free_event(event); 34455b7f77adStw21770 } 34465b7f77adStw21770 34475b7f77adStw21770 /* 34485b7f77adStw21770 * _smf_audit_event interacts with the security auditing system to generate 34495b7f77adStw21770 * an audit event structure. It establishes an audit session and allocates 34505b7f77adStw21770 * an audit event. The event is filled in from the audit data, and 34515b7f77adStw21770 * adt_put_event is called to generate the event. 34525b7f77adStw21770 */ 34535b7f77adStw21770 static void 34545b7f77adStw21770 _smf_audit_event(au_event_t event_id, int status, int return_val, 34555b7f77adStw21770 audit_event_data_t *data) 34565b7f77adStw21770 { 34575b7f77adStw21770 char *auth_used; 34585b7f77adStw21770 char *fmri; 34595b7f77adStw21770 char *prop_value; 34605b7f77adStw21770 adt_session_data_t *session; 34615b7f77adStw21770 adt_event_data_t *event = NULL; 34625b7f77adStw21770 34635b7f77adStw21770 /* Don't audit if we're using an alternate repository */ 34645b7f77adStw21770 if (is_main_repository == 0) 34655b7f77adStw21770 return; 34665b7f77adStw21770 34675b7f77adStw21770 smf_annotation_event(status, return_val); 34685b7f77adStw21770 if ((session = get_audit_session()) == NULL) 34695b7f77adStw21770 return; 34705b7f77adStw21770 if ((event = adt_alloc_event(session, event_id)) == NULL) { 34715b7f77adStw21770 uu_warn("_smf_audit_event cannot allocate event " 34725b7f77adStw21770 "data. %s\n", strerror(errno)); 34735b7f77adStw21770 return; 34745b7f77adStw21770 } 34755b7f77adStw21770 34765b7f77adStw21770 /* 34775b7f77adStw21770 * Handle possibility of NULL authorization strings, FMRIs and 34785b7f77adStw21770 * property values. 34795b7f77adStw21770 */ 34805b7f77adStw21770 if (data->ed_auth == NULL) { 34815b7f77adStw21770 auth_used = "PRIVILEGED"; 34825b7f77adStw21770 } else { 34835b7f77adStw21770 auth_used = data->ed_auth; 34845b7f77adStw21770 } 34855b7f77adStw21770 if (data->ed_fmri == NULL) { 34865b7f77adStw21770 syslog(LOG_WARNING, "_smf_audit_event called with " 34875b7f77adStw21770 "empty FMRI string"); 34885b7f77adStw21770 fmri = "UNKNOWN FMRI"; 34895b7f77adStw21770 } else { 34905b7f77adStw21770 fmri = data->ed_fmri; 34915b7f77adStw21770 } 34925b7f77adStw21770 if (data->ed_prop_value == NULL) { 34935b7f77adStw21770 prop_value = ""; 34945b7f77adStw21770 } else { 34955b7f77adStw21770 prop_value = data->ed_prop_value; 34965b7f77adStw21770 } 34975b7f77adStw21770 34985b7f77adStw21770 /* Fill in the event data. */ 34995b7f77adStw21770 switch (event_id) { 35005b7f77adStw21770 case ADT_smf_attach_snap: 35015b7f77adStw21770 event->adt_smf_attach_snap.auth_used = auth_used; 35025b7f77adStw21770 event->adt_smf_attach_snap.old_fmri = data->ed_old_fmri; 35035b7f77adStw21770 event->adt_smf_attach_snap.old_name = data->ed_old_name; 35045b7f77adStw21770 event->adt_smf_attach_snap.new_fmri = fmri; 35055b7f77adStw21770 event->adt_smf_attach_snap.new_name = data->ed_snapname; 35065b7f77adStw21770 break; 35075b7f77adStw21770 case ADT_smf_change_prop: 35085b7f77adStw21770 event->adt_smf_change_prop.auth_used = auth_used; 35095b7f77adStw21770 event->adt_smf_change_prop.fmri = fmri; 35105b7f77adStw21770 event->adt_smf_change_prop.type = data->ed_type; 35115b7f77adStw21770 event->adt_smf_change_prop.value = prop_value; 35125b7f77adStw21770 break; 35135b7f77adStw21770 case ADT_smf_clear: 35145b7f77adStw21770 event->adt_smf_clear.auth_used = auth_used; 35155b7f77adStw21770 event->adt_smf_clear.fmri = fmri; 35165b7f77adStw21770 break; 35175b7f77adStw21770 case ADT_smf_create: 35185b7f77adStw21770 event->adt_smf_create.fmri = fmri; 35195b7f77adStw21770 event->adt_smf_create.auth_used = auth_used; 35205b7f77adStw21770 break; 35215b7f77adStw21770 case ADT_smf_create_npg: 35225b7f77adStw21770 event->adt_smf_create_npg.auth_used = auth_used; 35235b7f77adStw21770 event->adt_smf_create_npg.fmri = fmri; 35245b7f77adStw21770 event->adt_smf_create_npg.type = data->ed_type; 35255b7f77adStw21770 break; 35265b7f77adStw21770 case ADT_smf_create_pg: 35275b7f77adStw21770 event->adt_smf_create_pg.auth_used = auth_used; 35285b7f77adStw21770 event->adt_smf_create_pg.fmri = fmri; 35295b7f77adStw21770 event->adt_smf_create_pg.type = data->ed_type; 35305b7f77adStw21770 break; 35315b7f77adStw21770 case ADT_smf_create_prop: 35325b7f77adStw21770 event->adt_smf_create_prop.auth_used = auth_used; 35335b7f77adStw21770 event->adt_smf_create_prop.fmri = fmri; 35345b7f77adStw21770 event->adt_smf_create_prop.type = data->ed_type; 35355b7f77adStw21770 event->adt_smf_create_prop.value = prop_value; 35365b7f77adStw21770 break; 35375b7f77adStw21770 case ADT_smf_create_snap: 35385b7f77adStw21770 event->adt_smf_create_snap.auth_used = auth_used; 35395b7f77adStw21770 event->adt_smf_create_snap.fmri = fmri; 35405b7f77adStw21770 event->adt_smf_create_snap.name = data->ed_snapname; 35415b7f77adStw21770 break; 35425b7f77adStw21770 case ADT_smf_degrade: 35435b7f77adStw21770 event->adt_smf_degrade.auth_used = auth_used; 35445b7f77adStw21770 event->adt_smf_degrade.fmri = fmri; 35455b7f77adStw21770 break; 35465b7f77adStw21770 case ADT_smf_delete: 35475b7f77adStw21770 event->adt_smf_delete.fmri = fmri; 35485b7f77adStw21770 event->adt_smf_delete.auth_used = auth_used; 35495b7f77adStw21770 break; 35505b7f77adStw21770 case ADT_smf_delete_npg: 35515b7f77adStw21770 event->adt_smf_delete_npg.auth_used = auth_used; 35525b7f77adStw21770 event->adt_smf_delete_npg.fmri = fmri; 35535b7f77adStw21770 event->adt_smf_delete_npg.type = data->ed_type; 35545b7f77adStw21770 break; 35555b7f77adStw21770 case ADT_smf_delete_pg: 35565b7f77adStw21770 event->adt_smf_delete_pg.auth_used = auth_used; 35575b7f77adStw21770 event->adt_smf_delete_pg.fmri = fmri; 35585b7f77adStw21770 event->adt_smf_delete_pg.type = data->ed_type; 35595b7f77adStw21770 break; 35605b7f77adStw21770 case ADT_smf_delete_prop: 35615b7f77adStw21770 event->adt_smf_delete_prop.auth_used = auth_used; 35625b7f77adStw21770 event->adt_smf_delete_prop.fmri = fmri; 35635b7f77adStw21770 break; 35645b7f77adStw21770 case ADT_smf_delete_snap: 35655b7f77adStw21770 event->adt_smf_delete_snap.auth_used = auth_used; 35665b7f77adStw21770 event->adt_smf_delete_snap.fmri = fmri; 35675b7f77adStw21770 event->adt_smf_delete_snap.name = data->ed_snapname; 35685b7f77adStw21770 break; 35695b7f77adStw21770 case ADT_smf_disable: 35705b7f77adStw21770 event->adt_smf_disable.auth_used = auth_used; 35715b7f77adStw21770 event->adt_smf_disable.fmri = fmri; 35725b7f77adStw21770 break; 35735b7f77adStw21770 case ADT_smf_enable: 35745b7f77adStw21770 event->adt_smf_enable.auth_used = auth_used; 35755b7f77adStw21770 event->adt_smf_enable.fmri = fmri; 35765b7f77adStw21770 break; 35775b7f77adStw21770 case ADT_smf_immediate_degrade: 35785b7f77adStw21770 event->adt_smf_immediate_degrade.auth_used = auth_used; 35795b7f77adStw21770 event->adt_smf_immediate_degrade.fmri = fmri; 35805b7f77adStw21770 break; 35815b7f77adStw21770 case ADT_smf_immediate_maintenance: 35825b7f77adStw21770 event->adt_smf_immediate_maintenance.auth_used = auth_used; 35835b7f77adStw21770 event->adt_smf_immediate_maintenance.fmri = fmri; 35845b7f77adStw21770 break; 35855b7f77adStw21770 case ADT_smf_immtmp_maintenance: 35865b7f77adStw21770 event->adt_smf_immtmp_maintenance.auth_used = auth_used; 35875b7f77adStw21770 event->adt_smf_immtmp_maintenance.fmri = fmri; 35885b7f77adStw21770 break; 35895b7f77adStw21770 case ADT_smf_maintenance: 35905b7f77adStw21770 event->adt_smf_maintenance.auth_used = auth_used; 35915b7f77adStw21770 event->adt_smf_maintenance.fmri = fmri; 35925b7f77adStw21770 break; 35935b7f77adStw21770 case ADT_smf_milestone: 35945b7f77adStw21770 event->adt_smf_milestone.auth_used = auth_used; 35955b7f77adStw21770 event->adt_smf_milestone.fmri = fmri; 35965b7f77adStw21770 break; 35975b7f77adStw21770 case ADT_smf_read_prop: 35985b7f77adStw21770 event->adt_smf_read_prop.auth_used = auth_used; 35995b7f77adStw21770 event->adt_smf_read_prop.fmri = fmri; 36005b7f77adStw21770 break; 36015b7f77adStw21770 case ADT_smf_refresh: 36025b7f77adStw21770 event->adt_smf_refresh.auth_used = auth_used; 36035b7f77adStw21770 event->adt_smf_refresh.fmri = fmri; 36045b7f77adStw21770 break; 36055b7f77adStw21770 case ADT_smf_restart: 36065b7f77adStw21770 event->adt_smf_restart.auth_used = auth_used; 36075b7f77adStw21770 event->adt_smf_restart.fmri = fmri; 36085b7f77adStw21770 break; 36095b7f77adStw21770 case ADT_smf_tmp_disable: 36105b7f77adStw21770 event->adt_smf_tmp_disable.auth_used = auth_used; 36115b7f77adStw21770 event->adt_smf_tmp_disable.fmri = fmri; 36125b7f77adStw21770 break; 36135b7f77adStw21770 case ADT_smf_tmp_enable: 36145b7f77adStw21770 event->adt_smf_tmp_enable.auth_used = auth_used; 36155b7f77adStw21770 event->adt_smf_tmp_enable.fmri = fmri; 36165b7f77adStw21770 break; 36175b7f77adStw21770 case ADT_smf_tmp_maintenance: 36185b7f77adStw21770 event->adt_smf_tmp_maintenance.auth_used = auth_used; 36195b7f77adStw21770 event->adt_smf_tmp_maintenance.fmri = fmri; 36205b7f77adStw21770 break; 36215b7f77adStw21770 default: 36225b7f77adStw21770 abort(); /* Need to cover all SMF event IDs */ 36235b7f77adStw21770 } 36245b7f77adStw21770 36255b7f77adStw21770 if (adt_put_event(event, status, return_val) != 0) { 36265b7f77adStw21770 uu_warn("_smf_audit_event failed to put event. %s\n", 36275b7f77adStw21770 strerror(errno)); 36285b7f77adStw21770 } 36295b7f77adStw21770 adt_free_event(event); 36305b7f77adStw21770 } 36315b7f77adStw21770 36325b7f77adStw21770 /* 36335b7f77adStw21770 * Determine if the combination of the property group at pg_name and the 36345b7f77adStw21770 * property at prop_name are in the set of special startd properties. If 36355b7f77adStw21770 * they are, a special audit event will be generated. 36365b7f77adStw21770 */ 36375b7f77adStw21770 static void 36385b7f77adStw21770 special_property_event(audit_event_data_t *evdp, const char *prop_name, 36395b7f77adStw21770 char *pg_name, int status, int return_val, tx_commit_data_t *tx_data, 36405b7f77adStw21770 size_t cmd_no) 36415b7f77adStw21770 { 36425b7f77adStw21770 au_event_t event_id; 36435b7f77adStw21770 audit_special_prop_item_t search_key; 36445b7f77adStw21770 audit_special_prop_item_t *found; 36455b7f77adStw21770 36465b7f77adStw21770 /* Use bsearch to find the special property information. */ 36475b7f77adStw21770 search_key.api_prop_name = prop_name; 36485b7f77adStw21770 search_key.api_pg_name = pg_name; 36495b7f77adStw21770 found = (audit_special_prop_item_t *)bsearch(&search_key, 36505b7f77adStw21770 special_props_list, SPECIAL_PROP_COUNT, 36515b7f77adStw21770 sizeof (special_props_list[0]), special_prop_compare); 36525b7f77adStw21770 if (found == NULL) { 36535b7f77adStw21770 /* Not a special property. */ 36545b7f77adStw21770 return; 36555b7f77adStw21770 } 36565b7f77adStw21770 36575b7f77adStw21770 /* Get the event id */ 36585b7f77adStw21770 if (found->api_event_func == NULL) { 36595b7f77adStw21770 event_id = found->api_event_id; 36605b7f77adStw21770 } else { 36615b7f77adStw21770 if ((*found->api_event_func)(tx_data, cmd_no, 36625b7f77adStw21770 found->api_pg_name, &event_id) < 0) 36635b7f77adStw21770 return; 36645b7f77adStw21770 } 36655b7f77adStw21770 36665b7f77adStw21770 /* Generate the event. */ 36675b7f77adStw21770 smf_audit_event(event_id, status, return_val, evdp); 36685b7f77adStw21770 } 36695b7f77adStw21770 #endif /* NATIVE_BUILD */ 36705b7f77adStw21770 36715b7f77adStw21770 /* 36725b7f77adStw21770 * Return a pointer to a string containing all the values of the command 36735b7f77adStw21770 * specified by cmd_no with each value enclosed in quotes. It is up to the 36745b7f77adStw21770 * caller to free the memory at the returned pointer. 36755b7f77adStw21770 */ 36765b7f77adStw21770 static char * 36775b7f77adStw21770 generate_value_list(tx_commit_data_t *tx_data, size_t cmd_no) 36785b7f77adStw21770 { 36795b7f77adStw21770 const char *cp; 36805b7f77adStw21770 const char *cur_value; 36815b7f77adStw21770 size_t byte_count = 0; 36825b7f77adStw21770 uint32_t i; 36835b7f77adStw21770 uint32_t nvalues; 36845b7f77adStw21770 size_t str_size = 0; 36855b7f77adStw21770 char *values = NULL; 36865b7f77adStw21770 char *vp; 36875b7f77adStw21770 36885b7f77adStw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS) 36895b7f77adStw21770 return (NULL); 36905b7f77adStw21770 /* 36915b7f77adStw21770 * First determine the size of the buffer that we will need. We 36925b7f77adStw21770 * will represent each property value surrounded by quotes with a 36935b7f77adStw21770 * space separating the values. Thus, we need to find the total 36945b7f77adStw21770 * size of all the value strings and add 3 for each value. 36955b7f77adStw21770 * 36965b7f77adStw21770 * There is one catch, though. We need to escape any internal 36975b7f77adStw21770 * quote marks in the values. So for each quote in the value we 36985b7f77adStw21770 * need to add another byte to the buffer size. 36995b7f77adStw21770 */ 37005b7f77adStw21770 for (i = 0; i < nvalues; i++) { 37015b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) != 37025b7f77adStw21770 REP_PROTOCOL_SUCCESS) 37035b7f77adStw21770 return (NULL); 37045b7f77adStw21770 for (cp = cur_value; *cp != 0; cp++) { 37055b7f77adStw21770 byte_count += (*cp == '"') ? 2 : 1; 37065b7f77adStw21770 } 37075b7f77adStw21770 byte_count += 3; /* surrounding quotes & space */ 37085b7f77adStw21770 } 37095b7f77adStw21770 byte_count++; /* nul terminator */ 37105b7f77adStw21770 values = malloc(byte_count); 37115b7f77adStw21770 if (values == NULL) 37125b7f77adStw21770 return (NULL); 37135b7f77adStw21770 *values = 0; 37145b7f77adStw21770 37155b7f77adStw21770 /* Now build up the string of values. */ 37165b7f77adStw21770 for (i = 0; i < nvalues; i++) { 37175b7f77adStw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) != 37185b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 37195b7f77adStw21770 free(values); 37205b7f77adStw21770 return (NULL); 37215b7f77adStw21770 } 37225b7f77adStw21770 (void) strlcat(values, "\"", byte_count); 37235b7f77adStw21770 for (cp = cur_value, vp = values + strlen(values); 37245b7f77adStw21770 *cp != 0; cp++) { 37255b7f77adStw21770 if (*cp == '"') { 37265b7f77adStw21770 *vp++ = '\\'; 37275b7f77adStw21770 *vp++ = '"'; 37285b7f77adStw21770 } else { 37295b7f77adStw21770 *vp++ = *cp; 37305b7f77adStw21770 } 37315b7f77adStw21770 } 37325b7f77adStw21770 *vp = 0; 37335b7f77adStw21770 str_size = strlcat(values, "\" ", byte_count); 37345b7f77adStw21770 assert(str_size < byte_count); 37355b7f77adStw21770 } 37365b7f77adStw21770 if (str_size > 0) 37375b7f77adStw21770 values[str_size - 1] = 0; /* get rid of trailing space */ 37385b7f77adStw21770 return (values); 37395b7f77adStw21770 } 37405b7f77adStw21770 37415b7f77adStw21770 /* 37425b7f77adStw21770 * generate_property_events takes the transaction commit data at tx_data 37435b7f77adStw21770 * and generates an audit event for each command. 37445b7f77adStw21770 * 37455b7f77adStw21770 * Native builds are done to create svc.configd-native. This program runs 37465b7f77adStw21770 * only on the Solaris build machines to create the seed repository. Thus, 37475b7f77adStw21770 * no audit events should be generated when running svc.configd-native. 37485b7f77adStw21770 */ 37495b7f77adStw21770 static void 37505b7f77adStw21770 generate_property_events( 37515b7f77adStw21770 tx_commit_data_t *tx_data, 37525b7f77adStw21770 char *pg_fmri, /* FMRI of property group */ 37535b7f77adStw21770 char *auth_string, 37545b7f77adStw21770 int auth_status, 37555b7f77adStw21770 int auth_ret_value) 37565b7f77adStw21770 { 37575b7f77adStw21770 #ifndef NATIVE_BUILD 37585b7f77adStw21770 enum rep_protocol_transaction_action action; 37595b7f77adStw21770 audit_event_data_t audit_data; 37605b7f77adStw21770 size_t count; 37615b7f77adStw21770 size_t cmd_no; 37625b7f77adStw21770 char *cp; 37635b7f77adStw21770 au_event_t event_id; 37645b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN]; 37655b7f77adStw21770 char pg_name[REP_PROTOCOL_NAME_LEN]; 37665b7f77adStw21770 char *pg_end; /* End of prop. group fmri */ 37675b7f77adStw21770 const char *prop_name; 37685b7f77adStw21770 uint32_t ptype; 37695b7f77adStw21770 char prop_type[3]; 37705b7f77adStw21770 enum rep_protocol_responseid rc; 37715b7f77adStw21770 size_t sz_out; 37725b7f77adStw21770 37735b7f77adStw21770 /* Make sure we have something to do. */ 37745b7f77adStw21770 if (tx_data == NULL) 37755b7f77adStw21770 return; 37765b7f77adStw21770 if ((count = tx_cmd_count(tx_data)) == 0) 37775b7f77adStw21770 return; 37785b7f77adStw21770 37795b7f77adStw21770 /* Copy the property group fmri */ 37805b7f77adStw21770 pg_end = fmri; 37815b7f77adStw21770 pg_end += strlcpy(fmri, pg_fmri, sizeof (fmri)); 37825b7f77adStw21770 37835b7f77adStw21770 /* 37845b7f77adStw21770 * Get the property group name. It is the first component after 37855b7f77adStw21770 * the last occurance of SCF_FMRI_PROPERTYGRP_PREFIX in the fmri. 37865b7f77adStw21770 */ 37875b7f77adStw21770 cp = strstr(pg_fmri, SCF_FMRI_PROPERTYGRP_PREFIX); 37885b7f77adStw21770 if (cp == NULL) { 37895b7f77adStw21770 pg_name[0] = 0; 37905b7f77adStw21770 } else { 37915b7f77adStw21770 cp += strlen(SCF_FMRI_PROPERTYGRP_PREFIX); 37925b7f77adStw21770 (void) strlcpy(pg_name, cp, sizeof (pg_name)); 37935b7f77adStw21770 } 37945b7f77adStw21770 37955b7f77adStw21770 audit_data.ed_auth = auth_string; 37965b7f77adStw21770 audit_data.ed_fmri = fmri; 37975b7f77adStw21770 audit_data.ed_type = prop_type; 37985b7f77adStw21770 37995b7f77adStw21770 /* 38005b7f77adStw21770 * Property type is two characters (see 38015b7f77adStw21770 * rep_protocol_value_type_t), so terminate the string. 38025b7f77adStw21770 */ 38035b7f77adStw21770 prop_type[2] = 0; 38045b7f77adStw21770 38055b7f77adStw21770 for (cmd_no = 0; cmd_no < count; cmd_no++) { 38065b7f77adStw21770 /* Construct FMRI of the property */ 38075b7f77adStw21770 *pg_end = 0; 38085b7f77adStw21770 if (tx_cmd_prop(tx_data, cmd_no, &prop_name) != 38095b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 38105b7f77adStw21770 continue; 38115b7f77adStw21770 } 38125b7f77adStw21770 rc = rc_concat_fmri_element(fmri, sizeof (fmri), &sz_out, 38135b7f77adStw21770 prop_name, REP_PROTOCOL_ENTITY_PROPERTY); 38145b7f77adStw21770 if (rc != REP_PROTOCOL_SUCCESS) { 38155b7f77adStw21770 /* 38165b7f77adStw21770 * If we can't get the FMRI, we'll abandon this 38175b7f77adStw21770 * command 38185b7f77adStw21770 */ 38195b7f77adStw21770 continue; 38205b7f77adStw21770 } 38215b7f77adStw21770 38225b7f77adStw21770 /* Generate special property event if necessary. */ 38235b7f77adStw21770 special_property_event(&audit_data, prop_name, pg_name, 38245b7f77adStw21770 auth_status, auth_ret_value, tx_data, cmd_no); 38255b7f77adStw21770 38265b7f77adStw21770 /* Capture rest of audit data. */ 38275b7f77adStw21770 if (tx_cmd_prop_type(tx_data, cmd_no, &ptype) != 38285b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 38295b7f77adStw21770 continue; 38305b7f77adStw21770 } 38315b7f77adStw21770 prop_type[0] = REP_PROTOCOL_BASE_TYPE(ptype); 38325b7f77adStw21770 prop_type[1] = REP_PROTOCOL_SUBTYPE(ptype); 38335b7f77adStw21770 audit_data.ed_prop_value = generate_value_list(tx_data, cmd_no); 38345b7f77adStw21770 38355b7f77adStw21770 /* Determine the event type. */ 38365b7f77adStw21770 if (tx_cmd_action(tx_data, cmd_no, &action) != 38375b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 38385b7f77adStw21770 free(audit_data.ed_prop_value); 38395b7f77adStw21770 continue; 38405b7f77adStw21770 } 38415b7f77adStw21770 switch (action) { 38425b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_NEW: 38435b7f77adStw21770 event_id = ADT_smf_create_prop; 38445b7f77adStw21770 break; 38455b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_CLEAR: 38465b7f77adStw21770 event_id = ADT_smf_change_prop; 38475b7f77adStw21770 break; 38485b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_REPLACE: 38495b7f77adStw21770 event_id = ADT_smf_change_prop; 38505b7f77adStw21770 break; 38515b7f77adStw21770 case REP_PROTOCOL_TX_ENTRY_DELETE: 38525b7f77adStw21770 event_id = ADT_smf_delete_prop; 38535b7f77adStw21770 break; 38545b7f77adStw21770 default: 38555b7f77adStw21770 assert(0); /* Missing a case */ 38565b7f77adStw21770 free(audit_data.ed_prop_value); 38575b7f77adStw21770 continue; 38585b7f77adStw21770 } 38595b7f77adStw21770 38605b7f77adStw21770 /* Generate the event. */ 38615b7f77adStw21770 smf_audit_event(event_id, auth_status, auth_ret_value, 38625b7f77adStw21770 &audit_data); 38635b7f77adStw21770 free(audit_data.ed_prop_value); 38645b7f77adStw21770 } 38655b7f77adStw21770 #endif /* NATIVE_BUILD */ 38667c478bd9Sstevel@tonic-gate } 38677c478bd9Sstevel@tonic-gate 38687c478bd9Sstevel@tonic-gate /* 38697c478bd9Sstevel@tonic-gate * Fails with 38707c478bd9Sstevel@tonic-gate * _DELETED - node has been deleted 38717c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset 38727c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - type is _PROPERTYGRP 38737c478bd9Sstevel@tonic-gate * _INVALID_TYPE - node is corrupt or type is invalid 38747c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - node cannot have children of type type 38757c478bd9Sstevel@tonic-gate * _BAD_REQUEST - name is invalid 38767c478bd9Sstevel@tonic-gate * cannot create children for this type of node 38777c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory, or could not allocate new id 38787c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED 38797c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 38807c478bd9Sstevel@tonic-gate * _BACKEND_READONLY 38817c478bd9Sstevel@tonic-gate * _EXISTS - child already exists 38825b7f77adStw21770 * _TRUNCATED - truncated FMRI for the audit record 38837c478bd9Sstevel@tonic-gate */ 38847c478bd9Sstevel@tonic-gate int 38857c478bd9Sstevel@tonic-gate rc_node_create_child(rc_node_ptr_t *npp, uint32_t type, const char *name, 38867c478bd9Sstevel@tonic-gate rc_node_ptr_t *cpp) 38877c478bd9Sstevel@tonic-gate { 38887c478bd9Sstevel@tonic-gate rc_node_t *np; 38897c478bd9Sstevel@tonic-gate rc_node_t *cp = NULL; 3890a4dc1477STom Whitten int rc; 3891a4dc1477STom Whitten perm_status_t perm_rc; 38925b7f77adStw21770 size_t sz_out; 38935b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN]; 38945b7f77adStw21770 audit_event_data_t audit_data; 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0); 38977c478bd9Sstevel@tonic-gate 3898a4dc1477STom Whitten /* 3899a4dc1477STom Whitten * rc_node_modify_permission_check() must be called before the node 3900a4dc1477STom Whitten * is locked. This is because the library functions that check 3901a4dc1477STom Whitten * authorizations can trigger calls back into configd. 3902a4dc1477STom Whitten */ 39035b7f77adStw21770 perm_rc = rc_node_modify_permission_check(&audit_data.ed_auth); 3904a4dc1477STom Whitten switch (perm_rc) { 3905a4dc1477STom Whitten case PERM_DENIED: 3906a4dc1477STom Whitten /* 3907a4dc1477STom Whitten * We continue in this case, so that an audit event can be 3908a4dc1477STom Whitten * generated later in the function. 3909a4dc1477STom Whitten */ 3910a4dc1477STom Whitten break; 3911a4dc1477STom Whitten case PERM_GRANTED: 3912a4dc1477STom Whitten break; 3913a4dc1477STom Whitten case PERM_GONE: 3914a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 3915a4dc1477STom Whitten case PERM_FAIL: 3916a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_NO_RESOURCES); 3917a4dc1477STom Whitten default: 3918a4dc1477STom Whitten bad_error(rc_node_modify_permission_check, perm_rc); 3919a4dc1477STom Whitten } 39203eae19d9Swesolows 3921a4dc1477STom Whitten RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth); 39227c478bd9Sstevel@tonic-gate 39235b7f77adStw21770 audit_data.ed_fmri = fmri; 39245b7f77adStw21770 39257c478bd9Sstevel@tonic-gate /* 39267c478bd9Sstevel@tonic-gate * there is a separate interface for creating property groups 39277c478bd9Sstevel@tonic-gate */ 39287c478bd9Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 39297c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39305b7f77adStw21770 free(audit_data.ed_auth); 39317c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 39327c478bd9Sstevel@tonic-gate } 39337c478bd9Sstevel@tonic-gate 39347c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 39357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39367c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 3937a4dc1477STom Whitten if ((rc = rc_node_check_and_lock(np)) != REP_PROTOCOL_SUCCESS) { 3938a4dc1477STom Whitten free(audit_data.ed_auth); 3939a4dc1477STom Whitten return (rc); 3940a4dc1477STom Whitten } 39417c478bd9Sstevel@tonic-gate } 39427c478bd9Sstevel@tonic-gate 39437c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) != 39447c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 39457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39465b7f77adStw21770 free(audit_data.ed_auth); 39477c478bd9Sstevel@tonic-gate return (rc); 39487c478bd9Sstevel@tonic-gate } 39497c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS) { 39507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39515b7f77adStw21770 free(audit_data.ed_auth); 39527c478bd9Sstevel@tonic-gate return (rc); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate 39555b7f77adStw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out, 39565b7f77adStw21770 name, type)) != REP_PROTOCOL_SUCCESS) { 39575b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 39585b7f77adStw21770 free(audit_data.ed_auth); 39595b7f77adStw21770 return (rc); 39605b7f77adStw21770 } 3961a4dc1477STom Whitten if (perm_rc == PERM_DENIED) { 39627c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39635b7f77adStw21770 smf_audit_event(ADT_smf_create, ADT_FAILURE, 39645b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data); 39655b7f77adStw21770 free(audit_data.ed_auth); 3966a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 39677c478bd9Sstevel@tonic-gate } 39687c478bd9Sstevel@tonic-gate 39695b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD, 39705b7f77adStw21770 audit_data.ed_auth); 39717c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39727c478bd9Sstevel@tonic-gate 39737c478bd9Sstevel@tonic-gate rc = object_create(np, type, name, &cp); 39747c478bd9Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE); 39757c478bd9Sstevel@tonic-gate 39767c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 39777c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp); 39787c478bd9Sstevel@tonic-gate rc_node_rele(cp); 39797c478bd9Sstevel@tonic-gate } 39807c478bd9Sstevel@tonic-gate 39817c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 39827c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD); 39837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 39847c478bd9Sstevel@tonic-gate 39855b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) { 39865b7f77adStw21770 smf_audit_event(ADT_smf_create, ADT_SUCCESS, ADT_SUCCESS, 39875b7f77adStw21770 &audit_data); 39885b7f77adStw21770 } 39895b7f77adStw21770 39905b7f77adStw21770 free(audit_data.ed_auth); 39915b7f77adStw21770 39927c478bd9Sstevel@tonic-gate return (rc); 39937c478bd9Sstevel@tonic-gate } 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate int 39967c478bd9Sstevel@tonic-gate rc_node_create_child_pg(rc_node_ptr_t *npp, uint32_t type, const char *name, 39977c478bd9Sstevel@tonic-gate const char *pgtype, uint32_t flags, rc_node_ptr_t *cpp) 39987c478bd9Sstevel@tonic-gate { 39997c478bd9Sstevel@tonic-gate rc_node_t *np; 40007c478bd9Sstevel@tonic-gate rc_node_t *cp; 40017c478bd9Sstevel@tonic-gate int rc; 40027c478bd9Sstevel@tonic-gate permcheck_t *pcp; 4003a4dc1477STom Whitten perm_status_t granted; 40045b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN]; 40055b7f77adStw21770 audit_event_data_t audit_data; 40065b7f77adStw21770 au_event_t event_id; 40075b7f77adStw21770 size_t sz_out; 40085b7f77adStw21770 40095b7f77adStw21770 audit_data.ed_auth = NULL; 40105b7f77adStw21770 audit_data.ed_fmri = fmri; 40115b7f77adStw21770 audit_data.ed_type = (char *)pgtype; 40127c478bd9Sstevel@tonic-gate 40137c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0); 40147c478bd9Sstevel@tonic-gate 40157c478bd9Sstevel@tonic-gate /* verify flags is valid */ 40167c478bd9Sstevel@tonic-gate if (flags & ~SCF_PG_FLAG_NONPERSISTENT) 40177c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 40187c478bd9Sstevel@tonic-gate 40197c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp); 40207c478bd9Sstevel@tonic-gate 40217c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) { 40227c478bd9Sstevel@tonic-gate rc_node_rele(np); 40237c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 40247c478bd9Sstevel@tonic-gate } 40257c478bd9Sstevel@tonic-gate 40267c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) != 40277c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 40287c478bd9Sstevel@tonic-gate rc_node_rele(np); 40297c478bd9Sstevel@tonic-gate return (rc); 40307c478bd9Sstevel@tonic-gate } 40317c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS || 40327c478bd9Sstevel@tonic-gate (rc = rc_check_pgtype_name(pgtype)) != REP_PROTOCOL_SUCCESS) { 40337c478bd9Sstevel@tonic-gate rc_node_rele(np); 40347c478bd9Sstevel@tonic-gate return (rc); 40357c478bd9Sstevel@tonic-gate } 40367c478bd9Sstevel@tonic-gate 4037273264cdSdm120769 #ifdef NATIVE_BUILD 40385b7f77adStw21770 if (!client_is_privileged()) { 40397c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 40405b7f77adStw21770 } 40417c478bd9Sstevel@tonic-gate #else 40425b7f77adStw21770 if (flags & SCF_PG_FLAG_NONPERSISTENT) { 40435b7f77adStw21770 event_id = ADT_smf_create_npg; 40445b7f77adStw21770 } else { 40455b7f77adStw21770 event_id = ADT_smf_create_pg; 40465b7f77adStw21770 } 40475b7f77adStw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out, 40485b7f77adStw21770 name, REP_PROTOCOL_ENTITY_PROPERTYGRP)) != REP_PROTOCOL_SUCCESS) { 40495b7f77adStw21770 rc_node_rele(np); 40505b7f77adStw21770 return (rc); 40515b7f77adStw21770 } 40525b7f77adStw21770 40535b7f77adStw21770 if (is_main_repository) { 40547c478bd9Sstevel@tonic-gate /* Must have .smf.modify or smf.modify.<type> authorization */ 40557c478bd9Sstevel@tonic-gate pcp = pc_create(); 40567c478bd9Sstevel@tonic-gate if (pcp != NULL) { 40577c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY); 40587c478bd9Sstevel@tonic-gate 40597c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 40607c478bd9Sstevel@tonic-gate const char * const auth = 40617c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(pgtype); 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate if (auth != NULL) 40647c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth); 40657c478bd9Sstevel@tonic-gate } 40667c478bd9Sstevel@tonic-gate 40677c478bd9Sstevel@tonic-gate /* 40687c478bd9Sstevel@tonic-gate * .manage or $action_authorization can be used to 40697c478bd9Sstevel@tonic-gate * create the actions pg and the general_ovr pg. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && 40727c478bd9Sstevel@tonic-gate (flags & SCF_PG_FLAG_NONPERSISTENT) != 0 && 40737c478bd9Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE && 40747c478bd9Sstevel@tonic-gate ((strcmp(name, AUTH_PG_ACTIONS) == 0 && 40757c478bd9Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_ACTIONS_TYPE) == 0) || 40767c478bd9Sstevel@tonic-gate (strcmp(name, AUTH_PG_GENERAL_OVR) == 0 && 40777c478bd9Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_GENERAL_OVR_TYPE) == 0))) { 40787c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MANAGE); 40797c478bd9Sstevel@tonic-gate 40807c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) 40817c478bd9Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, np); 40827c478bd9Sstevel@tonic-gate } 40837c478bd9Sstevel@tonic-gate 40847c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 40857c478bd9Sstevel@tonic-gate granted = perm_granted(pcp); 40867c478bd9Sstevel@tonic-gate 4087a4dc1477STom Whitten rc = map_granted_status(granted, pcp, 4088a4dc1477STom Whitten &audit_data.ed_auth); 4089a4dc1477STom Whitten if (granted == PERM_GONE) { 4090a4dc1477STom Whitten /* No auditing if client gone. */ 4091a4dc1477STom Whitten pc_free(pcp); 4092a4dc1477STom Whitten rc_node_rele(np); 4093a4dc1477STom Whitten return (rc); 40945b7f77adStw21770 } 40957c478bd9Sstevel@tonic-gate } 40967c478bd9Sstevel@tonic-gate 40977c478bd9Sstevel@tonic-gate pc_free(pcp); 40987c478bd9Sstevel@tonic-gate } else { 40997c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 41007c478bd9Sstevel@tonic-gate } 41017c478bd9Sstevel@tonic-gate 41025b7f77adStw21770 } else { 41035b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 41045b7f77adStw21770 } 41057c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 41067c478bd9Sstevel@tonic-gate 4107a4dc1477STom Whitten 41087c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 41097c478bd9Sstevel@tonic-gate rc_node_rele(np); 4110a4dc1477STom Whitten if (rc != REP_PROTOCOL_FAIL_NO_RESOURCES) { 41115b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE, 41125b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data); 4113a4dc1477STom Whitten } 41145b7f77adStw21770 if (audit_data.ed_auth != NULL) 41155b7f77adStw21770 free(audit_data.ed_auth); 41167c478bd9Sstevel@tonic-gate return (rc); 41177c478bd9Sstevel@tonic-gate } 41187c478bd9Sstevel@tonic-gate 41197c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 41205b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD, 41215b7f77adStw21770 audit_data.ed_auth); 41227c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 41237c478bd9Sstevel@tonic-gate 41247c478bd9Sstevel@tonic-gate rc = object_create_pg(np, type, name, pgtype, flags, &cp); 41257c478bd9Sstevel@tonic-gate 41267c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 41277c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp); 41287c478bd9Sstevel@tonic-gate rc_node_rele(cp); 41297c478bd9Sstevel@tonic-gate } 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 41327c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD); 41337c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 41347c478bd9Sstevel@tonic-gate 41355b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) { 41365b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, 41375b7f77adStw21770 &audit_data); 41385b7f77adStw21770 } 41395b7f77adStw21770 if (audit_data.ed_auth != NULL) 41405b7f77adStw21770 free(audit_data.ed_auth); 41415b7f77adStw21770 41427c478bd9Sstevel@tonic-gate return (rc); 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate 41457c478bd9Sstevel@tonic-gate static void 41467c478bd9Sstevel@tonic-gate rc_pg_notify_fire(rc_node_pg_notify_t *pnp) 41477c478bd9Sstevel@tonic-gate { 41487c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock)); 41497c478bd9Sstevel@tonic-gate 41507c478bd9Sstevel@tonic-gate if (pnp->rnpn_pg != NULL) { 41517c478bd9Sstevel@tonic-gate uu_list_remove(pnp->rnpn_pg->rn_pg_notify_list, pnp); 41527c478bd9Sstevel@tonic-gate (void) close(pnp->rnpn_fd); 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate pnp->rnpn_pg = NULL; 41557c478bd9Sstevel@tonic-gate pnp->rnpn_fd = -1; 41567c478bd9Sstevel@tonic-gate } else { 41577c478bd9Sstevel@tonic-gate assert(pnp->rnpn_fd == -1); 41587c478bd9Sstevel@tonic-gate } 41597c478bd9Sstevel@tonic-gate } 41607c478bd9Sstevel@tonic-gate 41617c478bd9Sstevel@tonic-gate static void 41627c478bd9Sstevel@tonic-gate rc_notify_node_delete(rc_notify_delete_t *ndp, rc_node_t *np_arg) 41637c478bd9Sstevel@tonic-gate { 41647c478bd9Sstevel@tonic-gate rc_node_t *svc = NULL; 41657c478bd9Sstevel@tonic-gate rc_node_t *inst = NULL; 41667c478bd9Sstevel@tonic-gate rc_node_t *pg = NULL; 41677c478bd9Sstevel@tonic-gate rc_node_t *np = np_arg; 41687c478bd9Sstevel@tonic-gate rc_node_t *nnp; 41697c478bd9Sstevel@tonic-gate 41707c478bd9Sstevel@tonic-gate while (svc == NULL) { 41717c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 41727c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 41737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 41747c478bd9Sstevel@tonic-gate goto cleanup; 41757c478bd9Sstevel@tonic-gate } 41767c478bd9Sstevel@tonic-gate nnp = np->rn_parent; 41777c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* hold it in place */ 41787c478bd9Sstevel@tonic-gate 41797c478bd9Sstevel@tonic-gate switch (np->rn_id.rl_type) { 41807c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 41817c478bd9Sstevel@tonic-gate assert(pg == NULL); 41827c478bd9Sstevel@tonic-gate pg = np; 41837c478bd9Sstevel@tonic-gate break; 41847c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 41857c478bd9Sstevel@tonic-gate assert(inst == NULL); 41867c478bd9Sstevel@tonic-gate inst = np; 41877c478bd9Sstevel@tonic-gate break; 41887c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 41897c478bd9Sstevel@tonic-gate assert(svc == NULL); 41907c478bd9Sstevel@tonic-gate svc = np; 41917c478bd9Sstevel@tonic-gate break; 41927c478bd9Sstevel@tonic-gate default: 41937c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 41947c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 41957c478bd9Sstevel@tonic-gate goto cleanup; 41967c478bd9Sstevel@tonic-gate } 41977c478bd9Sstevel@tonic-gate 41987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 41997c478bd9Sstevel@tonic-gate 42007c478bd9Sstevel@tonic-gate np = nnp; 42017c478bd9Sstevel@tonic-gate if (np == NULL) 42027c478bd9Sstevel@tonic-gate goto cleanup; 42037c478bd9Sstevel@tonic-gate } 42047c478bd9Sstevel@tonic-gate 42057c478bd9Sstevel@tonic-gate rc_notify_deletion(ndp, 42067c478bd9Sstevel@tonic-gate svc->rn_name, 42077c478bd9Sstevel@tonic-gate inst != NULL ? inst->rn_name : NULL, 42087c478bd9Sstevel@tonic-gate pg != NULL ? pg->rn_name : NULL); 42097c478bd9Sstevel@tonic-gate 42107c478bd9Sstevel@tonic-gate ndp = NULL; 42117c478bd9Sstevel@tonic-gate 42127c478bd9Sstevel@tonic-gate cleanup: 42137c478bd9Sstevel@tonic-gate if (ndp != NULL) 42147c478bd9Sstevel@tonic-gate uu_free(ndp); 42157c478bd9Sstevel@tonic-gate 42167c478bd9Sstevel@tonic-gate for (;;) { 42177c478bd9Sstevel@tonic-gate if (svc != NULL) { 42187c478bd9Sstevel@tonic-gate np = svc; 42197c478bd9Sstevel@tonic-gate svc = NULL; 42207c478bd9Sstevel@tonic-gate } else if (inst != NULL) { 42217c478bd9Sstevel@tonic-gate np = inst; 42227c478bd9Sstevel@tonic-gate inst = NULL; 42237c478bd9Sstevel@tonic-gate } else if (pg != NULL) { 42247c478bd9Sstevel@tonic-gate np = pg; 42257c478bd9Sstevel@tonic-gate pg = NULL; 42267c478bd9Sstevel@tonic-gate } else 42277c478bd9Sstevel@tonic-gate break; 42287c478bd9Sstevel@tonic-gate 42297c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 42307c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 42317c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 42327c478bd9Sstevel@tonic-gate } 42337c478bd9Sstevel@tonic-gate } 42347c478bd9Sstevel@tonic-gate 42357c478bd9Sstevel@tonic-gate /* 42366643e1ffSbustos * Hold RC_NODE_DYING_FLAGS on np's descendents. If andformer is true, do 42376643e1ffSbustos * the same down the rn_former chain. 42387c478bd9Sstevel@tonic-gate */ 42397c478bd9Sstevel@tonic-gate static void 42407c478bd9Sstevel@tonic-gate rc_node_delete_hold(rc_node_t *np, int andformer) 42417c478bd9Sstevel@tonic-gate { 42427c478bd9Sstevel@tonic-gate rc_node_t *cp; 42437c478bd9Sstevel@tonic-gate 42447c478bd9Sstevel@tonic-gate again: 42457c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 42467c478bd9Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS); 42477c478bd9Sstevel@tonic-gate 42487c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL; 42497c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) { 42507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 42517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 42527c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS)) { 42537c478bd9Sstevel@tonic-gate /* 42547c478bd9Sstevel@tonic-gate * already marked as dead -- can't happen, since that 42557c478bd9Sstevel@tonic-gate * would require setting RC_NODE_CHILDREN_CHANGING 42567c478bd9Sstevel@tonic-gate * in np, and we're holding that... 42577c478bd9Sstevel@tonic-gate */ 42587c478bd9Sstevel@tonic-gate abort(); 42597c478bd9Sstevel@tonic-gate } 42607c478bd9Sstevel@tonic-gate rc_node_delete_hold(cp, andformer); /* recurse, drop lock */ 42617c478bd9Sstevel@tonic-gate 42627c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 42637c478bd9Sstevel@tonic-gate } 42647c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) { 42657c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 42667c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 42677c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS)) 42687c478bd9Sstevel@tonic-gate abort(); /* can't happen, see above */ 42697c478bd9Sstevel@tonic-gate np = cp; 42707c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */ 42717c478bd9Sstevel@tonic-gate } 42727c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 42737c478bd9Sstevel@tonic-gate } 42747c478bd9Sstevel@tonic-gate 42757c478bd9Sstevel@tonic-gate /* 42767c478bd9Sstevel@tonic-gate * N.B.: this function drops np->rn_lock on the way out. 42777c478bd9Sstevel@tonic-gate */ 42787c478bd9Sstevel@tonic-gate static void 42797c478bd9Sstevel@tonic-gate rc_node_delete_rele(rc_node_t *np, int andformer) 42807c478bd9Sstevel@tonic-gate { 42817c478bd9Sstevel@tonic-gate rc_node_t *cp; 42827c478bd9Sstevel@tonic-gate 42837c478bd9Sstevel@tonic-gate again: 42847c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 42857c478bd9Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS); 42867c478bd9Sstevel@tonic-gate 42877c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL; 42887c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) { 42897c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 42907c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 42917c478bd9Sstevel@tonic-gate rc_node_delete_rele(cp, andformer); /* recurse, drop lock */ 42927c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 42937c478bd9Sstevel@tonic-gate } 42947c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) { 42957c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 42967c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 42977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 42987c478bd9Sstevel@tonic-gate 42997c478bd9Sstevel@tonic-gate np = cp; 43007c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */ 43017c478bd9Sstevel@tonic-gate } 43027c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 43037c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 43047c478bd9Sstevel@tonic-gate } 43057c478bd9Sstevel@tonic-gate 43067c478bd9Sstevel@tonic-gate static void 43077c478bd9Sstevel@tonic-gate rc_node_finish_delete(rc_node_t *cp) 43087c478bd9Sstevel@tonic-gate { 43097c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 43107c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp; 43117c478bd9Sstevel@tonic-gate 43127c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&cp->rn_lock)); 43137c478bd9Sstevel@tonic-gate 43147c478bd9Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) { 43157c478bd9Sstevel@tonic-gate assert(cp->rn_flags & RC_NODE_IN_PARENT); 43167c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(cp, RC_NODE_USING_PARENT)) { 43177c478bd9Sstevel@tonic-gate abort(); /* can't happen, see above */ 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate cp->rn_flags &= ~RC_NODE_IN_PARENT; 43207c478bd9Sstevel@tonic-gate cp->rn_parent = NULL; 43215b7f77adStw21770 rc_node_free_fmri(cp); 43227c478bd9Sstevel@tonic-gate } 43237c478bd9Sstevel@tonic-gate 43247c478bd9Sstevel@tonic-gate cp->rn_flags |= RC_NODE_DEAD; 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate /* 43277c478bd9Sstevel@tonic-gate * If this node is not out-dated, we need to remove it from 43287c478bd9Sstevel@tonic-gate * the notify list and cache hash table. 43297c478bd9Sstevel@tonic-gate */ 43307c478bd9Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) { 43317c478bd9Sstevel@tonic-gate assert(cp->rn_refs > 0); /* can't go away yet */ 43327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock); 43337c478bd9Sstevel@tonic-gate 43347c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 43357c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(cp->rn_pg_notify_list)) != NULL) 43367c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp); 43377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 43387c478bd9Sstevel@tonic-gate rc_notify_remove_node(cp); 43397c478bd9Sstevel@tonic-gate 43407c478bd9Sstevel@tonic-gate bp = cache_hold(cp->rn_hash); 43417c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 43427c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, cp); 43437c478bd9Sstevel@tonic-gate cache_release(bp); 43447c478bd9Sstevel@tonic-gate } 43457c478bd9Sstevel@tonic-gate } 43467c478bd9Sstevel@tonic-gate 43477c478bd9Sstevel@tonic-gate /* 43486643e1ffSbustos * For each child, call rc_node_finish_delete() and recurse. If andformer 43496643e1ffSbustos * is set, also recurse down rn_former. Finally release np, which might 43506643e1ffSbustos * free it. 43517c478bd9Sstevel@tonic-gate */ 43527c478bd9Sstevel@tonic-gate static void 43537c478bd9Sstevel@tonic-gate rc_node_delete_children(rc_node_t *np, int andformer) 43547c478bd9Sstevel@tonic-gate { 43557c478bd9Sstevel@tonic-gate rc_node_t *cp; 43567c478bd9Sstevel@tonic-gate 43577c478bd9Sstevel@tonic-gate again: 43587c478bd9Sstevel@tonic-gate assert(np->rn_refs > 0); 43597c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 43607c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_DEAD); 43617c478bd9Sstevel@tonic-gate 43627c478bd9Sstevel@tonic-gate while ((cp = uu_list_first(np->rn_children)) != NULL) { 43637c478bd9Sstevel@tonic-gate uu_list_remove(np->rn_children, cp); 43647c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 43657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 43667c478bd9Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we recurse */ 43677c478bd9Sstevel@tonic-gate rc_node_finish_delete(cp); 43687c478bd9Sstevel@tonic-gate rc_node_delete_children(cp, andformer); /* drops lock + ref */ 43697c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 43707c478bd9Sstevel@tonic-gate } 43717c478bd9Sstevel@tonic-gate 43727c478bd9Sstevel@tonic-gate /* 4373addbbe95Srm88369 * When we drop cp's lock, all the children will be gone, so we 43747c478bd9Sstevel@tonic-gate * can release DYING_FLAGS. 43757c478bd9Sstevel@tonic-gate */ 43767c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 43777c478bd9Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) { 43787c478bd9Sstevel@tonic-gate np->rn_former = NULL; /* unlink */ 43797c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock); 43806643e1ffSbustos 43816643e1ffSbustos /* 43826643e1ffSbustos * Register the ephemeral reference created by reading 43836643e1ffSbustos * np->rn_former into cp. Note that the persistent 43846643e1ffSbustos * reference (np->rn_former) is locked because we haven't 43856643e1ffSbustos * dropped np's lock since we dropped its RC_NODE_IN_TX 43866643e1ffSbustos * (via RC_NODE_DYING_FLAGS). 43876643e1ffSbustos */ 43886643e1ffSbustos rc_node_hold_ephemeral_locked(cp); 43896643e1ffSbustos 43907c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 4391addbbe95Srm88369 cp->rn_flags &= ~RC_NODE_ON_FORMER; 43927c478bd9Sstevel@tonic-gate 43937c478bd9Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we loop */ 43947c478bd9Sstevel@tonic-gate 43957c478bd9Sstevel@tonic-gate rc_node_finish_delete(cp); 43967c478bd9Sstevel@tonic-gate 43977c478bd9Sstevel@tonic-gate rc_node_rele(np); /* drop the old reference */ 43987c478bd9Sstevel@tonic-gate 43997c478bd9Sstevel@tonic-gate np = cp; 44007c478bd9Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */ 44017c478bd9Sstevel@tonic-gate } 44027c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 44037c478bd9Sstevel@tonic-gate } 44047c478bd9Sstevel@tonic-gate 44056643e1ffSbustos /* 44066643e1ffSbustos * The last client or child reference to np, which must be either 44076643e1ffSbustos * RC_NODE_OLD or RC_NODE_DEAD, has been destroyed. We'll destroy any 44086643e1ffSbustos * remaining references (e.g., rn_former) and call rc_node_destroy() to 44096643e1ffSbustos * free np. 44106643e1ffSbustos */ 44117c478bd9Sstevel@tonic-gate static void 44126643e1ffSbustos rc_node_no_client_refs(rc_node_t *np) 44137c478bd9Sstevel@tonic-gate { 44147c478bd9Sstevel@tonic-gate int unrefed; 44156643e1ffSbustos rc_node_t *current, *cur; 44167c478bd9Sstevel@tonic-gate 44177c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 44187c478bd9Sstevel@tonic-gate assert(np->rn_refs == 0); 44197c478bd9Sstevel@tonic-gate assert(np->rn_other_refs == 0); 44207c478bd9Sstevel@tonic-gate assert(np->rn_other_refs_held == 0); 44217c478bd9Sstevel@tonic-gate 44227c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD) { 44236643e1ffSbustos /* 44246643e1ffSbustos * The node is DEAD, so the deletion code should have 44256643e1ffSbustos * destroyed all rn_children or rn_former references. 44266643e1ffSbustos * Since the last client or child reference has been 44276643e1ffSbustos * destroyed, we're free to destroy np. Unless another 44286643e1ffSbustos * thread has an ephemeral reference, in which case we'll 44296643e1ffSbustos * pass the buck. 44306643e1ffSbustos */ 44316643e1ffSbustos if (np->rn_erefs > 1) { 44326643e1ffSbustos --np->rn_erefs; 44336643e1ffSbustos NODE_UNLOCK(np); 44346643e1ffSbustos return; 44356643e1ffSbustos } 44366643e1ffSbustos 44377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 44387c478bd9Sstevel@tonic-gate rc_node_destroy(np); 44397c478bd9Sstevel@tonic-gate return; 44407c478bd9Sstevel@tonic-gate } 44417c478bd9Sstevel@tonic-gate 44426643e1ffSbustos /* We only collect DEAD and OLD nodes, thank you. */ 44437c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD); 44446643e1ffSbustos 44456643e1ffSbustos /* 44466643e1ffSbustos * RC_NODE_UNREFED keeps multiple threads from processing OLD 44476643e1ffSbustos * nodes. But it's vulnerable to unfriendly scheduling, so full 44486643e1ffSbustos * use of rn_erefs should supersede it someday. 44496643e1ffSbustos */ 44507c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED) { 44517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 44527c478bd9Sstevel@tonic-gate return; 44537c478bd9Sstevel@tonic-gate } 44547c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_UNREFED; 44557c478bd9Sstevel@tonic-gate 44566643e1ffSbustos /* 44576643e1ffSbustos * Now we'll remove the node from the rn_former chain and take its 44586643e1ffSbustos * DYING_FLAGS. 44596643e1ffSbustos */ 44607c478bd9Sstevel@tonic-gate 44617c478bd9Sstevel@tonic-gate /* 44626643e1ffSbustos * Since this node is OLD, it should be on an rn_former chain. To 44636643e1ffSbustos * remove it, we must find the current in-hash object and grab its 44646643e1ffSbustos * RC_NODE_IN_TX flag to protect the entire rn_former chain. 44657c478bd9Sstevel@tonic-gate */ 44666643e1ffSbustos 44676643e1ffSbustos (void) pthread_mutex_unlock(&np->rn_lock); 44686643e1ffSbustos 44697c478bd9Sstevel@tonic-gate for (;;) { 44706643e1ffSbustos current = cache_lookup(&np->rn_id); 44716643e1ffSbustos 44726643e1ffSbustos if (current == NULL) { 44737c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 44746643e1ffSbustos 44757c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD) 44767c478bd9Sstevel@tonic-gate goto died; 44776643e1ffSbustos 44787c478bd9Sstevel@tonic-gate /* 44797c478bd9Sstevel@tonic-gate * We are trying to unreference this node, but the 44807c478bd9Sstevel@tonic-gate * owner of the former list does not exist. It must 44817c478bd9Sstevel@tonic-gate * be the case that another thread is deleting this 44827c478bd9Sstevel@tonic-gate * entire sub-branch, but has not yet reached us. 44837c478bd9Sstevel@tonic-gate * We will in short order be deleted. 44847c478bd9Sstevel@tonic-gate */ 44857c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED; 44867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 44877c478bd9Sstevel@tonic-gate return; 44887c478bd9Sstevel@tonic-gate } 44896643e1ffSbustos 44906643e1ffSbustos if (current == np) { 44917c478bd9Sstevel@tonic-gate /* 44927c478bd9Sstevel@tonic-gate * no longer unreferenced 44937c478bd9Sstevel@tonic-gate */ 44947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 44957c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED; 44966643e1ffSbustos /* held in cache_lookup() */ 44977c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 44987c478bd9Sstevel@tonic-gate return; 44997c478bd9Sstevel@tonic-gate } 45006643e1ffSbustos 45016643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock); 45026643e1ffSbustos if (current->rn_flags & RC_NODE_OLD) { 45036643e1ffSbustos /* 45046643e1ffSbustos * current has been replaced since we looked it 45056643e1ffSbustos * up. Try again. 45066643e1ffSbustos */ 45076643e1ffSbustos /* held in cache_lookup() */ 45086643e1ffSbustos rc_node_rele_locked(current); 45097c478bd9Sstevel@tonic-gate continue; 45107c478bd9Sstevel@tonic-gate } 45116643e1ffSbustos 45126643e1ffSbustos if (!rc_node_hold_flag(current, RC_NODE_IN_TX)) { 45136643e1ffSbustos /* 45146643e1ffSbustos * current has been deleted since we looked it up. Try 45156643e1ffSbustos * again. 45166643e1ffSbustos */ 45176643e1ffSbustos /* held in cache_lookup() */ 45186643e1ffSbustos rc_node_rele_locked(current); 45196643e1ffSbustos continue; 45207c478bd9Sstevel@tonic-gate } 45217c478bd9Sstevel@tonic-gate 45226643e1ffSbustos /* 45236643e1ffSbustos * rc_node_hold_flag() might have dropped current's lock, so 45246643e1ffSbustos * check OLD again. 45256643e1ffSbustos */ 45266643e1ffSbustos if (!(current->rn_flags & RC_NODE_OLD)) { 45276643e1ffSbustos /* Not old. Stop looping. */ 45286643e1ffSbustos (void) pthread_mutex_unlock(¤t->rn_lock); 45296643e1ffSbustos break; 45306643e1ffSbustos } 45316643e1ffSbustos 45326643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX); 45336643e1ffSbustos rc_node_rele_locked(current); 45346643e1ffSbustos } 45356643e1ffSbustos 45366643e1ffSbustos /* To take np's RC_NODE_DYING_FLAGS, we need its lock. */ 45377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 45386643e1ffSbustos 45396643e1ffSbustos /* 45406643e1ffSbustos * While we didn't have the lock, a thread may have added 45416643e1ffSbustos * a reference or changed the flags. 45426643e1ffSbustos */ 45437c478bd9Sstevel@tonic-gate if (!(np->rn_flags & (RC_NODE_OLD | RC_NODE_DEAD)) || 45447c478bd9Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 || 45457c478bd9Sstevel@tonic-gate np->rn_other_refs_held != 0) { 45467c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED; 45477c478bd9Sstevel@tonic-gate 45486643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock); 45496643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX); 45506643e1ffSbustos /* held by cache_lookup() */ 45516643e1ffSbustos rc_node_rele_locked(current); 45527c478bd9Sstevel@tonic-gate return; 45537c478bd9Sstevel@tonic-gate } 45547c478bd9Sstevel@tonic-gate 45557c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) { 45566643e1ffSbustos /* 45576643e1ffSbustos * Someone deleted the node while we were waiting for 45586643e1ffSbustos * DYING_FLAGS. Undo the modifications to current. 45596643e1ffSbustos */ 45607c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 45617c478bd9Sstevel@tonic-gate 45626643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX); 45636643e1ffSbustos /* held by cache_lookup() */ 45646643e1ffSbustos rc_node_rele_locked(current); 45657c478bd9Sstevel@tonic-gate 45667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 45677c478bd9Sstevel@tonic-gate goto died; 45687c478bd9Sstevel@tonic-gate } 45697c478bd9Sstevel@tonic-gate 45706643e1ffSbustos /* Take RC_NODE_DYING_FLAGS on np's descendents. */ 45716643e1ffSbustos rc_node_delete_hold(np, 0); /* drops np->rn_lock */ 45727c478bd9Sstevel@tonic-gate 45736643e1ffSbustos /* Mark np DEAD. This requires the lock. */ 45747c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 45756643e1ffSbustos 45766643e1ffSbustos /* Recheck for new references. */ 45777c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD) || 45787c478bd9Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 || 45797c478bd9Sstevel@tonic-gate np->rn_other_refs_held != 0) { 45807c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED; 45816643e1ffSbustos rc_node_delete_rele(np, 0); /* drops np's lock */ 45827c478bd9Sstevel@tonic-gate 45836643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock); 45846643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX); 45856643e1ffSbustos /* held by cache_lookup() */ 45866643e1ffSbustos rc_node_rele_locked(current); 45877c478bd9Sstevel@tonic-gate return; 45887c478bd9Sstevel@tonic-gate } 45897c478bd9Sstevel@tonic-gate 45907c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD; 45917c478bd9Sstevel@tonic-gate 45927c478bd9Sstevel@tonic-gate /* 45936643e1ffSbustos * Delete the children. This calls rc_node_rele_locked() on np at 45946643e1ffSbustos * the end, so add a reference to keep the count from going 45956643e1ffSbustos * negative. It will recurse with RC_NODE_DEAD set, so we'll call 45966643e1ffSbustos * rc_node_destroy() above, but RC_NODE_UNREFED is also set, so it 45976643e1ffSbustos * shouldn't actually free() np. 45987c478bd9Sstevel@tonic-gate */ 45996643e1ffSbustos rc_node_hold_locked(np); 46006643e1ffSbustos rc_node_delete_children(np, 0); /* unlocks np */ 46016643e1ffSbustos 46026643e1ffSbustos /* Remove np from current's rn_former chain. */ 46036643e1ffSbustos (void) pthread_mutex_lock(¤t->rn_lock); 46046643e1ffSbustos for (cur = current; cur != NULL && cur->rn_former != np; 46057c478bd9Sstevel@tonic-gate cur = cur->rn_former) 46067c478bd9Sstevel@tonic-gate ; 46077c478bd9Sstevel@tonic-gate assert(cur != NULL && cur != np); 46087c478bd9Sstevel@tonic-gate 46097c478bd9Sstevel@tonic-gate cur->rn_former = np->rn_former; 46107c478bd9Sstevel@tonic-gate np->rn_former = NULL; 46117c478bd9Sstevel@tonic-gate 46126643e1ffSbustos rc_node_rele_flag(current, RC_NODE_IN_TX); 46136643e1ffSbustos /* held by cache_lookup() */ 46146643e1ffSbustos rc_node_rele_locked(current); 46157c478bd9Sstevel@tonic-gate 46166643e1ffSbustos /* Clear ON_FORMER and UNREFED, and destroy. */ 46177c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 46187c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_ON_FORMER); 46197c478bd9Sstevel@tonic-gate np->rn_flags &= ~(RC_NODE_UNREFED | RC_NODE_ON_FORMER); 46206643e1ffSbustos 46216643e1ffSbustos if (np->rn_erefs > 1) { 46226643e1ffSbustos /* Still referenced. Stay execution. */ 46236643e1ffSbustos --np->rn_erefs; 46246643e1ffSbustos NODE_UNLOCK(np); 46256643e1ffSbustos return; 46266643e1ffSbustos } 46276643e1ffSbustos 46287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 46297c478bd9Sstevel@tonic-gate rc_node_destroy(np); 46307c478bd9Sstevel@tonic-gate return; 46317c478bd9Sstevel@tonic-gate 46327c478bd9Sstevel@tonic-gate died: 46336643e1ffSbustos /* 46346643e1ffSbustos * Another thread marked np DEAD. If there still aren't any 46356643e1ffSbustos * persistent references, destroy the node. 46366643e1ffSbustos */ 46377c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED; 46386643e1ffSbustos 46397c478bd9Sstevel@tonic-gate unrefed = (np->rn_refs == 0 && np->rn_other_refs == 0 && 46407c478bd9Sstevel@tonic-gate np->rn_other_refs_held == 0); 46416643e1ffSbustos 46426643e1ffSbustos if (np->rn_erefs > 0) 46436643e1ffSbustos --np->rn_erefs; 46446643e1ffSbustos 46456643e1ffSbustos if (unrefed && np->rn_erefs > 0) { 46466643e1ffSbustos NODE_UNLOCK(np); 46476643e1ffSbustos return; 46486643e1ffSbustos } 46496643e1ffSbustos 46507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 46516643e1ffSbustos 46527c478bd9Sstevel@tonic-gate if (unrefed) 46537c478bd9Sstevel@tonic-gate rc_node_destroy(np); 46547c478bd9Sstevel@tonic-gate } 46557c478bd9Sstevel@tonic-gate 46565b7f77adStw21770 static au_event_t 46575b7f77adStw21770 get_delete_event_id(rep_protocol_entity_t entity, uint32_t pgflags) 46585b7f77adStw21770 { 46595b7f77adStw21770 au_event_t id = 0; 46605b7f77adStw21770 46615b7f77adStw21770 #ifndef NATIVE_BUILD 46625b7f77adStw21770 switch (entity) { 46635b7f77adStw21770 case REP_PROTOCOL_ENTITY_SERVICE: 46645b7f77adStw21770 case REP_PROTOCOL_ENTITY_INSTANCE: 46655b7f77adStw21770 id = ADT_smf_delete; 46665b7f77adStw21770 break; 46675b7f77adStw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT: 46685b7f77adStw21770 id = ADT_smf_delete_snap; 46695b7f77adStw21770 break; 46705b7f77adStw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP: 46715b7f77adStw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP: 46725b7f77adStw21770 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) { 46735b7f77adStw21770 id = ADT_smf_delete_npg; 46745b7f77adStw21770 } else { 46755b7f77adStw21770 id = ADT_smf_delete_pg; 46765b7f77adStw21770 } 46775b7f77adStw21770 break; 46785b7f77adStw21770 default: 46795b7f77adStw21770 abort(); 46805b7f77adStw21770 } 46815b7f77adStw21770 #endif /* NATIVE_BUILD */ 46825b7f77adStw21770 return (id); 46835b7f77adStw21770 } 46845b7f77adStw21770 46857c478bd9Sstevel@tonic-gate /* 46867c478bd9Sstevel@tonic-gate * Fails with 46877c478bd9Sstevel@tonic-gate * _NOT_SET 46887c478bd9Sstevel@tonic-gate * _DELETED 46897c478bd9Sstevel@tonic-gate * _BAD_REQUEST 46907c478bd9Sstevel@tonic-gate * _PERMISSION_DENIED 46917c478bd9Sstevel@tonic-gate * _NO_RESOURCES 46925b7f77adStw21770 * _TRUNCATED 46937c478bd9Sstevel@tonic-gate * and whatever object_delete() fails with. 46947c478bd9Sstevel@tonic-gate */ 46957c478bd9Sstevel@tonic-gate int 46967c478bd9Sstevel@tonic-gate rc_node_delete(rc_node_ptr_t *npp) 46977c478bd9Sstevel@tonic-gate { 46987c478bd9Sstevel@tonic-gate rc_node_t *np, *np_orig; 46997c478bd9Sstevel@tonic-gate rc_node_t *pp = NULL; 47007c478bd9Sstevel@tonic-gate int rc; 47017c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp; 47027c478bd9Sstevel@tonic-gate cache_bucket_t *bp; 47037c478bd9Sstevel@tonic-gate rc_notify_delete_t *ndp; 47047c478bd9Sstevel@tonic-gate permcheck_t *pcp; 47057c478bd9Sstevel@tonic-gate int granted; 47065b7f77adStw21770 au_event_t event_id = 0; 47075b7f77adStw21770 size_t sz_out; 47085b7f77adStw21770 audit_event_data_t audit_data; 47095b7f77adStw21770 int audit_failure = 0; 47107c478bd9Sstevel@tonic-gate 47117c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 47127c478bd9Sstevel@tonic-gate 47135b7f77adStw21770 audit_data.ed_fmri = NULL; 47145b7f77adStw21770 audit_data.ed_auth = NULL; 47155b7f77adStw21770 audit_data.ed_snapname = NULL; 47165b7f77adStw21770 audit_data.ed_type = NULL; 47175b7f77adStw21770 47187c478bd9Sstevel@tonic-gate switch (np->rn_id.rl_type) { 47197c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 47205b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SERVICE, 47215b7f77adStw21770 np->rn_pgflags); 47225b7f77adStw21770 break; 47237c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 47245b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_INSTANCE, 47255b7f77adStw21770 np->rn_pgflags); 47265b7f77adStw21770 break; 47277c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT: 47285b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SNAPSHOT, 47295b7f77adStw21770 np->rn_pgflags); 47305b7f77adStw21770 audit_data.ed_snapname = strdup(np->rn_name); 47315b7f77adStw21770 if (audit_data.ed_snapname == NULL) { 47325b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 47335b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 47345b7f77adStw21770 } 47357c478bd9Sstevel@tonic-gate break; /* deletable */ 47367c478bd9Sstevel@tonic-gate 47377c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE: 47387c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL: 47397c478bd9Sstevel@tonic-gate /* Scopes and snaplevels are indelible. */ 47407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 47417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 47427c478bd9Sstevel@tonic-gate 47437c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_CPROPERTYGRP: 47447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 47457c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 47467c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np); 47475b7f77adStw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_CPROPERTYGRP, 47485b7f77adStw21770 np->rn_pgflags); 47497c478bd9Sstevel@tonic-gate break; 47507c478bd9Sstevel@tonic-gate 47517c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 47525b7f77adStw21770 if (np->rn_id.rl_ids[ID_SNAPSHOT] == 0) { 47535b7f77adStw21770 event_id = 47545b7f77adStw21770 get_delete_event_id(REP_PROTOCOL_ENTITY_PROPERTYGRP, 47555b7f77adStw21770 np->rn_pgflags); 47565b7f77adStw21770 audit_data.ed_type = strdup(np->rn_type); 47575b7f77adStw21770 if (audit_data.ed_type == NULL) { 47585b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 47595b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 47605b7f77adStw21770 } 47617c478bd9Sstevel@tonic-gate break; 47625b7f77adStw21770 } 47637c478bd9Sstevel@tonic-gate 47647c478bd9Sstevel@tonic-gate /* Snapshot property groups are indelible. */ 47657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 47667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 47677c478bd9Sstevel@tonic-gate 47687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY: 47697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 47707c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 47717c478bd9Sstevel@tonic-gate 47727c478bd9Sstevel@tonic-gate default: 47737c478bd9Sstevel@tonic-gate assert(0); 47747c478bd9Sstevel@tonic-gate abort(); 47757c478bd9Sstevel@tonic-gate break; 47767c478bd9Sstevel@tonic-gate } 47777c478bd9Sstevel@tonic-gate 47785b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN); 47795b7f77adStw21770 if (audit_data.ed_fmri == NULL) { 47805b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 47815b7f77adStw21770 goto cleanout; 47825b7f77adStw21770 } 47837c478bd9Sstevel@tonic-gate np_orig = np; 47847c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies rest of the code */ 47857c478bd9Sstevel@tonic-gate 47867c478bd9Sstevel@tonic-gate again: 47877c478bd9Sstevel@tonic-gate /* 47887c478bd9Sstevel@tonic-gate * The following loop is to deal with the fact that snapshots and 47897c478bd9Sstevel@tonic-gate * property groups are moving targets -- changes to them result 47907c478bd9Sstevel@tonic-gate * in a new "child" node. Since we can only delete from the top node, 47917c478bd9Sstevel@tonic-gate * we have to loop until we have a non-RC_NODE_OLD version. 47927c478bd9Sstevel@tonic-gate */ 47937c478bd9Sstevel@tonic-gate for (;;) { 47947c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, 47957c478bd9Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) { 47967c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 47975b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 47985b7f77adStw21770 goto cleanout; 47997c478bd9Sstevel@tonic-gate } 48007c478bd9Sstevel@tonic-gate 48017c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) { 48027c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 48037c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id); 48047c478bd9Sstevel@tonic-gate assert(np != np_orig); 48057c478bd9Sstevel@tonic-gate 48067c478bd9Sstevel@tonic-gate if (np == NULL) { 48077c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED; 48087c478bd9Sstevel@tonic-gate goto fail; 48097c478bd9Sstevel@tonic-gate } 48107c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 48117c478bd9Sstevel@tonic-gate continue; 48127c478bd9Sstevel@tonic-gate } 48137c478bd9Sstevel@tonic-gate 48147c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 48157c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 48167c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 48175b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 48187c478bd9Sstevel@tonic-gate } 48197c478bd9Sstevel@tonic-gate 48207c478bd9Sstevel@tonic-gate /* 48217c478bd9Sstevel@tonic-gate * Mark our parent as children changing. this call drops our 48227c478bd9Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with 48237c478bd9Sstevel@tonic-gate * pp's lock held 48247c478bd9Sstevel@tonic-gate */ 48257c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING); 48267c478bd9Sstevel@tonic-gate if (pp == NULL) { 48277c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */ 48287c478bd9Sstevel@tonic-gate rc_node_rele(np); 48297c478bd9Sstevel@tonic-gate 48307c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 48315b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 48325b7f77adStw21770 goto cleanout; 48337c478bd9Sstevel@tonic-gate } 48347c478bd9Sstevel@tonic-gate 48357c478bd9Sstevel@tonic-gate rc_node_hold_locked(pp); /* hold for later */ 48367c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 48377c478bd9Sstevel@tonic-gate 48387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 48397c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD)) 48407c478bd9Sstevel@tonic-gate break; /* not old -- we're done */ 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 48437c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 48447c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 48457c478bd9Sstevel@tonic-gate rc_node_rele_locked(pp); 48467c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 48477c478bd9Sstevel@tonic-gate continue; /* loop around and try again */ 48487c478bd9Sstevel@tonic-gate } 48497c478bd9Sstevel@tonic-gate /* 48507c478bd9Sstevel@tonic-gate * Everyone out of the pool -- we grab everything but 48517c478bd9Sstevel@tonic-gate * RC_NODE_USING_PARENT (including RC_NODE_DYING) to keep 48527c478bd9Sstevel@tonic-gate * any changes from occurring while we are attempting to 48537c478bd9Sstevel@tonic-gate * delete the node. 48547c478bd9Sstevel@tonic-gate */ 48557c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) { 48567c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 48577c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED; 48587c478bd9Sstevel@tonic-gate goto fail; 48597c478bd9Sstevel@tonic-gate } 48607c478bd9Sstevel@tonic-gate 48617c478bd9Sstevel@tonic-gate assert(!(np->rn_flags & RC_NODE_OLD)); 48627c478bd9Sstevel@tonic-gate 48635b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri, 48645b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) { 48655b7f77adStw21770 rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 4866582271e8Stw21770 (void) pthread_mutex_unlock(&np->rn_lock); 48675b7f77adStw21770 goto fail; 48685b7f77adStw21770 } 4869273264cdSdm120769 4870273264cdSdm120769 #ifdef NATIVE_BUILD 48715b7f77adStw21770 if (!client_is_privileged()) { 4872273264cdSdm120769 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 48735b7f77adStw21770 } 4874273264cdSdm120769 #else 48755b7f77adStw21770 if (is_main_repository) { 48765b7f77adStw21770 /* permission check */ 48775b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 48787c478bd9Sstevel@tonic-gate pcp = pc_create(); 48797c478bd9Sstevel@tonic-gate if (pcp != NULL) { 48807c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY); 48817c478bd9Sstevel@tonic-gate 48827c478bd9Sstevel@tonic-gate /* add .smf.modify.<type> for pgs. */ 48837c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && np->rn_id.rl_type == 48847c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP) { 48857c478bd9Sstevel@tonic-gate const char * const auth = 48867c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type); 48877c478bd9Sstevel@tonic-gate 48887c478bd9Sstevel@tonic-gate if (auth != NULL) 48897c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth); 48907c478bd9Sstevel@tonic-gate } 48917c478bd9Sstevel@tonic-gate 48927c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 48937c478bd9Sstevel@tonic-gate granted = perm_granted(pcp); 48947c478bd9Sstevel@tonic-gate 4895a4dc1477STom Whitten rc = map_granted_status(granted, pcp, 4896a4dc1477STom Whitten &audit_data.ed_auth); 4897a4dc1477STom Whitten if (granted == PERM_GONE) { 4898a4dc1477STom Whitten /* No need to audit if client gone. */ 4899a4dc1477STom Whitten pc_free(pcp); 4900a4dc1477STom Whitten rc_node_rele_flag(np, 4901a4dc1477STom Whitten RC_NODE_DYING_FLAGS); 4902a4dc1477STom Whitten return (rc); 49035b7f77adStw21770 } 4904a4dc1477STom Whitten if (granted == PERM_DENIED) 4905a4dc1477STom Whitten audit_failure = 1; 49067c478bd9Sstevel@tonic-gate } 49077c478bd9Sstevel@tonic-gate 49087c478bd9Sstevel@tonic-gate pc_free(pcp); 49097c478bd9Sstevel@tonic-gate } else { 49107c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 49117c478bd9Sstevel@tonic-gate } 49127c478bd9Sstevel@tonic-gate 49135b7f77adStw21770 (void) pthread_mutex_lock(&np->rn_lock); 49145b7f77adStw21770 } else { 49155b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 49165b7f77adStw21770 } 49177c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 49187c478bd9Sstevel@tonic-gate 49197c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 49207c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 49217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 49227c478bd9Sstevel@tonic-gate goto fail; 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate ndp = uu_zalloc(sizeof (*ndp)); 49267c478bd9Sstevel@tonic-gate if (ndp == NULL) { 49277c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS); 49287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 49297c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 49307c478bd9Sstevel@tonic-gate goto fail; 49317c478bd9Sstevel@tonic-gate } 49327c478bd9Sstevel@tonic-gate 49337c478bd9Sstevel@tonic-gate rc_node_delete_hold(np, 1); /* hold entire subgraph, drop lock */ 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate rc = object_delete(np); 49367c478bd9Sstevel@tonic-gate 49377c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 49387c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 49397c478bd9Sstevel@tonic-gate rc_node_delete_rele(np, 1); /* drops lock */ 49407c478bd9Sstevel@tonic-gate uu_free(ndp); 49417c478bd9Sstevel@tonic-gate goto fail; 49427c478bd9Sstevel@tonic-gate } 49437c478bd9Sstevel@tonic-gate 49447c478bd9Sstevel@tonic-gate /* 49457c478bd9Sstevel@tonic-gate * Now, delicately unlink and delete the object. 49467c478bd9Sstevel@tonic-gate * 49477c478bd9Sstevel@tonic-gate * Create the delete notification, atomically remove 49487c478bd9Sstevel@tonic-gate * from the hash table and set the NODE_DEAD flag, and 49497c478bd9Sstevel@tonic-gate * remove from the parent's children list. 49507c478bd9Sstevel@tonic-gate */ 49517c478bd9Sstevel@tonic-gate rc_notify_node_delete(ndp, np); /* frees or uses ndp */ 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate bp = cache_hold(np->rn_hash); 49547c478bd9Sstevel@tonic-gate 49557c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 49567c478bd9Sstevel@tonic-gate cache_remove_unlocked(bp, np); 49577c478bd9Sstevel@tonic-gate cache_release(bp); 49587c478bd9Sstevel@tonic-gate 49597c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD; 49607c478bd9Sstevel@tonic-gate 49616643e1ffSbustos if (pp != NULL) { 49626643e1ffSbustos /* 49636643e1ffSbustos * Remove from pp's rn_children. This requires pp's lock, 49646643e1ffSbustos * so we must drop np's lock to respect lock order. 49656643e1ffSbustos */ 49666643e1ffSbustos (void) pthread_mutex_unlock(&np->rn_lock); 49677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 49687c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 49696643e1ffSbustos 49707c478bd9Sstevel@tonic-gate uu_list_remove(pp->rn_children, np); 49716643e1ffSbustos 49727c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 49736643e1ffSbustos 49747c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 49756643e1ffSbustos 49767c478bd9Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT; 49777c478bd9Sstevel@tonic-gate } 49786643e1ffSbustos 49797c478bd9Sstevel@tonic-gate /* 49806643e1ffSbustos * finally, propagate death to our children (including marking 49816643e1ffSbustos * them DEAD), handle notifications, and release our hold. 49827c478bd9Sstevel@tonic-gate */ 49837c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* hold for delete */ 49847c478bd9Sstevel@tonic-gate rc_node_delete_children(np, 1); /* drops DYING_FLAGS, lock, ref */ 49857c478bd9Sstevel@tonic-gate 49867c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 49897c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL) 49907c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp); 49917c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 49927c478bd9Sstevel@tonic-gate rc_notify_remove_node(np); 49937c478bd9Sstevel@tonic-gate 49947c478bd9Sstevel@tonic-gate rc_node_rele(np); 49957c478bd9Sstevel@tonic-gate 49965b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, 49975b7f77adStw21770 &audit_data); 49985b7f77adStw21770 free(audit_data.ed_auth); 49995b7f77adStw21770 free(audit_data.ed_snapname); 50005b7f77adStw21770 free(audit_data.ed_type); 50015b7f77adStw21770 free(audit_data.ed_fmri); 50027c478bd9Sstevel@tonic-gate return (rc); 50037c478bd9Sstevel@tonic-gate 50047c478bd9Sstevel@tonic-gate fail: 50057c478bd9Sstevel@tonic-gate rc_node_rele(np); 50067c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_FAIL_DELETED) 50077c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 50087c478bd9Sstevel@tonic-gate if (pp != NULL) { 50097c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 50107c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 50117c478bd9Sstevel@tonic-gate rc_node_rele_locked(pp); /* drop ref and lock */ 50127c478bd9Sstevel@tonic-gate } 50135b7f77adStw21770 if (audit_failure) { 50145b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE, 50155b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data); 50165b7f77adStw21770 } 50175b7f77adStw21770 cleanout: 50185b7f77adStw21770 free(audit_data.ed_auth); 50195b7f77adStw21770 free(audit_data.ed_snapname); 50205b7f77adStw21770 free(audit_data.ed_type); 50215b7f77adStw21770 free(audit_data.ed_fmri); 50227c478bd9Sstevel@tonic-gate return (rc); 50237c478bd9Sstevel@tonic-gate } 50247c478bd9Sstevel@tonic-gate 50257c478bd9Sstevel@tonic-gate int 50267c478bd9Sstevel@tonic-gate rc_node_next_snaplevel(rc_node_ptr_t *npp, rc_node_ptr_t *cpp) 50277c478bd9Sstevel@tonic-gate { 50287c478bd9Sstevel@tonic-gate rc_node_t *np; 50297c478bd9Sstevel@tonic-gate rc_node_t *cp, *pp; 50307c478bd9Sstevel@tonic-gate int res; 50317c478bd9Sstevel@tonic-gate 50327c478bd9Sstevel@tonic-gate rc_node_clear(cpp, 0); 50337c478bd9Sstevel@tonic-gate 50347c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 50357c478bd9Sstevel@tonic-gate 50367c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT && 50377c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) { 50387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 50397c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 50407c478bd9Sstevel@tonic-gate } 50417c478bd9Sstevel@tonic-gate 50427c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) { 50437c478bd9Sstevel@tonic-gate if ((res = rc_node_fill_children(np, 50447c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL)) != REP_PROTOCOL_SUCCESS) { 50457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 50467c478bd9Sstevel@tonic-gate return (res); 50477c478bd9Sstevel@tonic-gate } 50487c478bd9Sstevel@tonic-gate 50497c478bd9Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); 50507c478bd9Sstevel@tonic-gate cp != NULL; 50517c478bd9Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) { 50527c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) 50537c478bd9Sstevel@tonic-gate continue; 50547c478bd9Sstevel@tonic-gate rc_node_hold(cp); 50557c478bd9Sstevel@tonic-gate break; 50567c478bd9Sstevel@tonic-gate } 50577c478bd9Sstevel@tonic-gate 50587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 50597c478bd9Sstevel@tonic-gate } else { 5060a4dc1477STom Whitten if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 5061a4dc1477STom Whitten (void) pthread_mutex_unlock(&np->rn_lock); 5062a4dc1477STom Whitten rc_node_clear(npp, 1); 5063a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_DELETED); 5064a4dc1477STom Whitten } 5065a4dc1477STom Whitten 50667c478bd9Sstevel@tonic-gate /* 50677c478bd9Sstevel@tonic-gate * mark our parent as children changing. This call drops our 50687c478bd9Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with 50697c478bd9Sstevel@tonic-gate * pp's lock held 50707c478bd9Sstevel@tonic-gate */ 50717c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING); 50727c478bd9Sstevel@tonic-gate if (pp == NULL) { 50737c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */ 50747c478bd9Sstevel@tonic-gate 50757c478bd9Sstevel@tonic-gate rc_node_clear(npp, 1); 50767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 50777c478bd9Sstevel@tonic-gate } 50787c478bd9Sstevel@tonic-gate 50797c478bd9Sstevel@tonic-gate /* 50807c478bd9Sstevel@tonic-gate * find the next snaplevel 50817c478bd9Sstevel@tonic-gate */ 50827c478bd9Sstevel@tonic-gate cp = np; 50837c478bd9Sstevel@tonic-gate while ((cp = uu_list_next(pp->rn_children, cp)) != NULL && 50847c478bd9Sstevel@tonic-gate cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) 50857c478bd9Sstevel@tonic-gate ; 50867c478bd9Sstevel@tonic-gate 50877c478bd9Sstevel@tonic-gate /* it must match the snaplevel list */ 50887c478bd9Sstevel@tonic-gate assert((cp == NULL && np->rn_snaplevel->rsl_next == NULL) || 50897c478bd9Sstevel@tonic-gate (cp != NULL && np->rn_snaplevel->rsl_next == 50907c478bd9Sstevel@tonic-gate cp->rn_snaplevel)); 50917c478bd9Sstevel@tonic-gate 50927c478bd9Sstevel@tonic-gate if (cp != NULL) 50937c478bd9Sstevel@tonic-gate rc_node_hold(cp); 50947c478bd9Sstevel@tonic-gate 50957c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 50967c478bd9Sstevel@tonic-gate 50977c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 50987c478bd9Sstevel@tonic-gate } 50997c478bd9Sstevel@tonic-gate 51007c478bd9Sstevel@tonic-gate rc_node_assign(cpp, cp); 51017c478bd9Sstevel@tonic-gate if (cp != NULL) { 51027c478bd9Sstevel@tonic-gate rc_node_rele(cp); 51037c478bd9Sstevel@tonic-gate 51047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 51057c478bd9Sstevel@tonic-gate } 51067c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 51077c478bd9Sstevel@tonic-gate } 51087c478bd9Sstevel@tonic-gate 51097c478bd9Sstevel@tonic-gate /* 51107c478bd9Sstevel@tonic-gate * This call takes a snapshot (np) and either: 51117c478bd9Sstevel@tonic-gate * an existing snapid (to be associated with np), or 51127c478bd9Sstevel@tonic-gate * a non-NULL parentp (from which a new snapshot is taken, and associated 51137c478bd9Sstevel@tonic-gate * with np) 51147c478bd9Sstevel@tonic-gate * 51157c478bd9Sstevel@tonic-gate * To do the association, np is duplicated, the duplicate is made to 51167c478bd9Sstevel@tonic-gate * represent the new snapid, and np is replaced with the new rc_node_t on 51177c478bd9Sstevel@tonic-gate * np's parent's child list. np is placed on the new node's rn_former list, 51187c478bd9Sstevel@tonic-gate * and replaces np in cache_hash (so rc_node_update() will find the new one). 51195b7f77adStw21770 * 51205b7f77adStw21770 * old_fmri and old_name point to the original snap shot's FMRI and name. 51215b7f77adStw21770 * These values are used when generating audit events. 51225b7f77adStw21770 * 51235b7f77adStw21770 * Fails with 51245b7f77adStw21770 * _BAD_REQUEST 51255b7f77adStw21770 * _BACKEND_READONLY 51265b7f77adStw21770 * _DELETED 51275b7f77adStw21770 * _NO_RESOURCES 51285b7f77adStw21770 * _TRUNCATED 51295b7f77adStw21770 * _TYPE_MISMATCH 51307c478bd9Sstevel@tonic-gate */ 51317c478bd9Sstevel@tonic-gate static int 51325b7f77adStw21770 rc_attach_snapshot( 51335b7f77adStw21770 rc_node_t *np, 51345b7f77adStw21770 uint32_t snapid, 51355b7f77adStw21770 rc_node_t *parentp, 51365b7f77adStw21770 char *old_fmri, 51375b7f77adStw21770 char *old_name) 51387c478bd9Sstevel@tonic-gate { 51397c478bd9Sstevel@tonic-gate rc_node_t *np_orig; 51407c478bd9Sstevel@tonic-gate rc_node_t *nnp, *prev; 51417c478bd9Sstevel@tonic-gate rc_node_t *pp; 51427c478bd9Sstevel@tonic-gate int rc; 51435b7f77adStw21770 size_t sz_out; 5144a4dc1477STom Whitten perm_status_t granted; 51455b7f77adStw21770 au_event_t event_id; 51465b7f77adStw21770 audit_event_data_t audit_data; 51477c478bd9Sstevel@tonic-gate 51485b7f77adStw21770 if (parentp == NULL) { 51495b7f77adStw21770 assert(old_fmri != NULL); 51505b7f77adStw21770 } else { 51517c478bd9Sstevel@tonic-gate assert(snapid == 0); 51525b7f77adStw21770 } 51537c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 51547c478bd9Sstevel@tonic-gate 51555b7f77adStw21770 /* Gather the audit data. */ 51565b7f77adStw21770 /* 51575b7f77adStw21770 * ADT_smf_* symbols may not be defined in the /usr/include header 51585b7f77adStw21770 * files on the build machine. Thus, the following if-else will 51595b7f77adStw21770 * not be compiled when doing native builds. 51605b7f77adStw21770 */ 51615b7f77adStw21770 #ifndef NATIVE_BUILD 51625b7f77adStw21770 if (parentp == NULL) { 51635b7f77adStw21770 event_id = ADT_smf_attach_snap; 51645b7f77adStw21770 } else { 51655b7f77adStw21770 event_id = ADT_smf_create_snap; 51665b7f77adStw21770 } 51675b7f77adStw21770 #endif /* NATIVE_BUILD */ 51685b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN); 51695b7f77adStw21770 audit_data.ed_snapname = malloc(REP_PROTOCOL_NAME_LEN); 51705b7f77adStw21770 if ((audit_data.ed_fmri == NULL) || (audit_data.ed_snapname == NULL)) { 51715b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 51725b7f77adStw21770 free(audit_data.ed_fmri); 51735b7f77adStw21770 free(audit_data.ed_snapname); 51745b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 51755b7f77adStw21770 } 51765b7f77adStw21770 audit_data.ed_auth = NULL; 51775b7f77adStw21770 if (strlcpy(audit_data.ed_snapname, np->rn_name, 51785b7f77adStw21770 REP_PROTOCOL_NAME_LEN) >= REP_PROTOCOL_NAME_LEN) { 51795b7f77adStw21770 abort(); 51805b7f77adStw21770 } 51815b7f77adStw21770 audit_data.ed_old_fmri = old_fmri; 51825b7f77adStw21770 audit_data.ed_old_name = old_name ? old_name : "NO NAME"; 51835b7f77adStw21770 51845b7f77adStw21770 if (parentp == NULL) { 51855b7f77adStw21770 /* 51865b7f77adStw21770 * In the attach case, get the instance FMRIs of the 51875b7f77adStw21770 * snapshots. 51885b7f77adStw21770 */ 51895b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri, 51905b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) { 51915b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 51925b7f77adStw21770 free(audit_data.ed_fmri); 51935b7f77adStw21770 free(audit_data.ed_snapname); 51945b7f77adStw21770 return (rc); 51955b7f77adStw21770 } 51965b7f77adStw21770 } else { 51975b7f77adStw21770 /* 51985b7f77adStw21770 * Capture the FMRI of the parent if we're actually going 51995b7f77adStw21770 * to take the snapshot. 52005b7f77adStw21770 */ 52015b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(parentp, 52025b7f77adStw21770 audit_data.ed_fmri, REP_PROTOCOL_FMRI_LEN, &sz_out)) != 52035b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 52045b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 52055b7f77adStw21770 free(audit_data.ed_fmri); 52065b7f77adStw21770 free(audit_data.ed_snapname); 52075b7f77adStw21770 return (rc); 52085b7f77adStw21770 } 52095b7f77adStw21770 } 52105b7f77adStw21770 52117c478bd9Sstevel@tonic-gate np_orig = np; 52127c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */ 52137c478bd9Sstevel@tonic-gate 52143eae19d9Swesolows (void) pthread_mutex_unlock(&np->rn_lock); 5215a4dc1477STom Whitten granted = rc_node_modify_permission_check(&audit_data.ed_auth); 5216a4dc1477STom Whitten switch (granted) { 5217a4dc1477STom Whitten case PERM_DENIED: 52185b7f77adStw21770 smf_audit_event(event_id, ADT_FAILURE, ADT_FAIL_VALUE_AUTH, 52195b7f77adStw21770 &audit_data); 5220a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 5221a4dc1477STom Whitten rc_node_rele(np); 52225b7f77adStw21770 goto cleanout; 5223a4dc1477STom Whitten case PERM_GRANTED: 5224a4dc1477STom Whitten break; 5225a4dc1477STom Whitten case PERM_GONE: 5226a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 5227a4dc1477STom Whitten rc_node_rele(np); 5228a4dc1477STom Whitten goto cleanout; 5229a4dc1477STom Whitten case PERM_FAIL: 5230a4dc1477STom Whitten rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 5231a4dc1477STom Whitten rc_node_rele(np); 5232a4dc1477STom Whitten goto cleanout; 5233a4dc1477STom Whitten default: 5234a4dc1477STom Whitten bad_error(rc_node_modify_permission_check, granted); 52355b7f77adStw21770 } 52363eae19d9Swesolows (void) pthread_mutex_lock(&np->rn_lock); 52373eae19d9Swesolows 52387c478bd9Sstevel@tonic-gate /* 52397c478bd9Sstevel@tonic-gate * get the latest node, holding RC_NODE_IN_TX to keep the rn_former 52407c478bd9Sstevel@tonic-gate * list from changing. 52417c478bd9Sstevel@tonic-gate */ 52427c478bd9Sstevel@tonic-gate for (;;) { 52437c478bd9Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD)) { 52447c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 52457c478bd9Sstevel@tonic-gate goto again; 52467c478bd9Sstevel@tonic-gate } 52477c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, 52487c478bd9Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING); 52497c478bd9Sstevel@tonic-gate 52507c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 52517c478bd9Sstevel@tonic-gate if (pp == NULL) { 52527c478bd9Sstevel@tonic-gate goto again; 52537c478bd9Sstevel@tonic-gate } 52547c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) { 52557c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, 52567c478bd9Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING); 52577c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 52587c478bd9Sstevel@tonic-gate goto again; 52597c478bd9Sstevel@tonic-gate } 52607c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) { 52637c478bd9Sstevel@tonic-gate /* 52647c478bd9Sstevel@tonic-gate * Can't happen, since we're holding our 52657c478bd9Sstevel@tonic-gate * parent's CHILDREN_CHANGING flag... 52667c478bd9Sstevel@tonic-gate */ 52677c478bd9Sstevel@tonic-gate abort(); 52687c478bd9Sstevel@tonic-gate } 52697c478bd9Sstevel@tonic-gate break; /* everything's ready */ 52707c478bd9Sstevel@tonic-gate } 52717c478bd9Sstevel@tonic-gate again: 52727c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 52737c478bd9Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id); 52747c478bd9Sstevel@tonic-gate 52755b7f77adStw21770 if (np == NULL) { 52765b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 52775b7f77adStw21770 goto cleanout; 52785b7f77adStw21770 } 52797c478bd9Sstevel@tonic-gate 52807c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 52817c478bd9Sstevel@tonic-gate } 52827c478bd9Sstevel@tonic-gate 52837c478bd9Sstevel@tonic-gate if (parentp != NULL) { 52847c478bd9Sstevel@tonic-gate if (pp != parentp) { 52857c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST; 52867c478bd9Sstevel@tonic-gate goto fail; 52877c478bd9Sstevel@tonic-gate } 52887c478bd9Sstevel@tonic-gate nnp = NULL; 52897c478bd9Sstevel@tonic-gate } else { 52907c478bd9Sstevel@tonic-gate /* 52917c478bd9Sstevel@tonic-gate * look for a former node with the snapid we need. 52927c478bd9Sstevel@tonic-gate */ 52937c478bd9Sstevel@tonic-gate if (np->rn_snapshot_id == snapid) { 52947c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX); 52957c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 52967c478bd9Sstevel@tonic-gate 52977c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 52987c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 52997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 53005b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; /* nothing to do */ 53015b7f77adStw21770 goto cleanout; 53027c478bd9Sstevel@tonic-gate } 53037c478bd9Sstevel@tonic-gate 53047c478bd9Sstevel@tonic-gate prev = np; 53057c478bd9Sstevel@tonic-gate while ((nnp = prev->rn_former) != NULL) { 53067c478bd9Sstevel@tonic-gate if (nnp->rn_snapshot_id == snapid) { 53077c478bd9Sstevel@tonic-gate rc_node_hold(nnp); 53087c478bd9Sstevel@tonic-gate break; /* existing node with that id */ 53097c478bd9Sstevel@tonic-gate } 53107c478bd9Sstevel@tonic-gate prev = nnp; 53117c478bd9Sstevel@tonic-gate } 53127c478bd9Sstevel@tonic-gate } 53137c478bd9Sstevel@tonic-gate 53147c478bd9Sstevel@tonic-gate if (nnp == NULL) { 53157c478bd9Sstevel@tonic-gate prev = NULL; 53167c478bd9Sstevel@tonic-gate nnp = rc_node_alloc(); 53177c478bd9Sstevel@tonic-gate if (nnp == NULL) { 53187c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 53197c478bd9Sstevel@tonic-gate goto fail; 53207c478bd9Sstevel@tonic-gate } 53217c478bd9Sstevel@tonic-gate 53227c478bd9Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */ 53237c478bd9Sstevel@tonic-gate nnp->rn_hash = np->rn_hash; 53247c478bd9Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name); 53257c478bd9Sstevel@tonic-gate nnp->rn_snapshot_id = snapid; 53267c478bd9Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT; 53277c478bd9Sstevel@tonic-gate 53287c478bd9Sstevel@tonic-gate if (nnp->rn_name == NULL) { 53297c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 53307c478bd9Sstevel@tonic-gate goto fail; 53317c478bd9Sstevel@tonic-gate } 53327c478bd9Sstevel@tonic-gate } 53337c478bd9Sstevel@tonic-gate 53347c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate rc = object_snapshot_attach(&np->rn_id, &snapid, (parentp != NULL)); 53377c478bd9Sstevel@tonic-gate 53387c478bd9Sstevel@tonic-gate if (parentp != NULL) 53397c478bd9Sstevel@tonic-gate nnp->rn_snapshot_id = snapid; /* fill in new snapid */ 53407c478bd9Sstevel@tonic-gate else 53417c478bd9Sstevel@tonic-gate assert(nnp->rn_snapshot_id == snapid); 53427c478bd9Sstevel@tonic-gate 53437c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 53447c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) 53457c478bd9Sstevel@tonic-gate goto fail; 53467c478bd9Sstevel@tonic-gate 53477c478bd9Sstevel@tonic-gate /* 53487c478bd9Sstevel@tonic-gate * fix up the former chain 53497c478bd9Sstevel@tonic-gate */ 53507c478bd9Sstevel@tonic-gate if (prev != NULL) { 53517c478bd9Sstevel@tonic-gate prev->rn_former = nnp->rn_former; 53527c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock); 53537c478bd9Sstevel@tonic-gate nnp->rn_flags &= ~RC_NODE_ON_FORMER; 53547c478bd9Sstevel@tonic-gate nnp->rn_former = NULL; 53557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock); 53567c478bd9Sstevel@tonic-gate } 53577c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD; 53587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 53597c478bd9Sstevel@tonic-gate 53607c478bd9Sstevel@tonic-gate /* 53617c478bd9Sstevel@tonic-gate * replace np with nnp 53627c478bd9Sstevel@tonic-gate */ 53637c478bd9Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp); 53647c478bd9Sstevel@tonic-gate 53657c478bd9Sstevel@tonic-gate rc_node_rele(np); 53665b7f77adStw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, &audit_data); 53675b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 53687c478bd9Sstevel@tonic-gate 53695b7f77adStw21770 cleanout: 53705b7f77adStw21770 free(audit_data.ed_auth); 53715b7f77adStw21770 free(audit_data.ed_fmri); 53725b7f77adStw21770 free(audit_data.ed_snapname); 53735b7f77adStw21770 return (rc); 53747c478bd9Sstevel@tonic-gate 53757c478bd9Sstevel@tonic-gate fail: 53767c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX); 53777c478bd9Sstevel@tonic-gate rc_node_rele_locked(np); 53787c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 53797c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 53807c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 53817c478bd9Sstevel@tonic-gate 53827c478bd9Sstevel@tonic-gate if (nnp != NULL) { 53837c478bd9Sstevel@tonic-gate if (prev == NULL) 53847c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 53857c478bd9Sstevel@tonic-gate else 53867c478bd9Sstevel@tonic-gate rc_node_rele(nnp); 53877c478bd9Sstevel@tonic-gate } 53887c478bd9Sstevel@tonic-gate 53895b7f77adStw21770 free(audit_data.ed_auth); 53905b7f77adStw21770 free(audit_data.ed_fmri); 53915b7f77adStw21770 free(audit_data.ed_snapname); 53927c478bd9Sstevel@tonic-gate return (rc); 53937c478bd9Sstevel@tonic-gate } 53947c478bd9Sstevel@tonic-gate 53957c478bd9Sstevel@tonic-gate int 53967c478bd9Sstevel@tonic-gate rc_snapshot_take_new(rc_node_ptr_t *npp, const char *svcname, 53977c478bd9Sstevel@tonic-gate const char *instname, const char *name, rc_node_ptr_t *outpp) 53987c478bd9Sstevel@tonic-gate { 5399a4dc1477STom Whitten perm_status_t granted; 54007c478bd9Sstevel@tonic-gate rc_node_t *np; 54017c478bd9Sstevel@tonic-gate rc_node_t *outp = NULL; 54023eae19d9Swesolows int rc, perm_rc; 54035b7f77adStw21770 char fmri[REP_PROTOCOL_FMRI_LEN]; 54045b7f77adStw21770 audit_event_data_t audit_data; 54055b7f77adStw21770 size_t sz_out; 54067c478bd9Sstevel@tonic-gate 54077c478bd9Sstevel@tonic-gate rc_node_clear(outpp, 0); 54087c478bd9Sstevel@tonic-gate 5409a4dc1477STom Whitten /* 5410a4dc1477STom Whitten * rc_node_modify_permission_check() must be called before the node 5411a4dc1477STom Whitten * is locked. This is because the library functions that check 5412a4dc1477STom Whitten * authorizations can trigger calls back into configd. 5413a4dc1477STom Whitten */ 5414a4dc1477STom Whitten granted = rc_node_modify_permission_check(&audit_data.ed_auth); 5415a4dc1477STom Whitten switch (granted) { 5416a4dc1477STom Whitten case PERM_DENIED: 5417a4dc1477STom Whitten /* 5418a4dc1477STom Whitten * We continue in this case, so that we can generate an 5419a4dc1477STom Whitten * audit event later in this function. 5420a4dc1477STom Whitten */ 5421a4dc1477STom Whitten perm_rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 5422a4dc1477STom Whitten break; 5423a4dc1477STom Whitten case PERM_GRANTED: 5424a4dc1477STom Whitten perm_rc = REP_PROTOCOL_SUCCESS; 5425a4dc1477STom Whitten break; 5426a4dc1477STom Whitten case PERM_GONE: 5427a4dc1477STom Whitten /* No need to produce audit event if client is gone. */ 5428a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 5429a4dc1477STom Whitten case PERM_FAIL: 5430a4dc1477STom Whitten return (REP_PROTOCOL_FAIL_NO_RESOURCES); 5431a4dc1477STom Whitten default: 5432a4dc1477STom Whitten bad_error("rc_node_modify_permission_check", granted); 5433a4dc1477STom Whitten break; 5434a4dc1477STom Whitten } 54353eae19d9Swesolows 5436a4dc1477STom Whitten RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth); 54377c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) { 54387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54395b7f77adStw21770 free(audit_data.ed_auth); 54407c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 54417c478bd9Sstevel@tonic-gate } 54427c478bd9Sstevel@tonic-gate 54437c478bd9Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_SNAPSHOT, name); 54447c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 54457c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54465b7f77adStw21770 free(audit_data.ed_auth); 54477c478bd9Sstevel@tonic-gate return (rc); 54487c478bd9Sstevel@tonic-gate } 54497c478bd9Sstevel@tonic-gate 54507c478bd9Sstevel@tonic-gate if (svcname != NULL && (rc = 54517c478bd9Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_SERVICE, svcname)) != 54527c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 54537c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54545b7f77adStw21770 free(audit_data.ed_auth); 54557c478bd9Sstevel@tonic-gate return (rc); 54567c478bd9Sstevel@tonic-gate } 54577c478bd9Sstevel@tonic-gate 54587c478bd9Sstevel@tonic-gate if (instname != NULL && (rc = 54597c478bd9Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_INSTANCE, instname)) != 54607c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 54617c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54625b7f77adStw21770 free(audit_data.ed_auth); 54637c478bd9Sstevel@tonic-gate return (rc); 54647c478bd9Sstevel@tonic-gate } 54657c478bd9Sstevel@tonic-gate 54665b7f77adStw21770 audit_data.ed_fmri = fmri; 54675b7f77adStw21770 audit_data.ed_snapname = (char *)name; 54685b7f77adStw21770 54695b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, sizeof (fmri), 54705b7f77adStw21770 &sz_out)) != REP_PROTOCOL_SUCCESS) { 54715b7f77adStw21770 (void) pthread_mutex_unlock(&np->rn_lock); 54725b7f77adStw21770 free(audit_data.ed_auth); 54735b7f77adStw21770 return (rc); 54745b7f77adStw21770 } 54753eae19d9Swesolows if (perm_rc != REP_PROTOCOL_SUCCESS) { 54767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54775b7f77adStw21770 smf_audit_event(ADT_smf_create_snap, ADT_FAILURE, 54785b7f77adStw21770 ADT_FAIL_VALUE_AUTH, &audit_data); 54795b7f77adStw21770 free(audit_data.ed_auth); 54803eae19d9Swesolows return (perm_rc); 54817c478bd9Sstevel@tonic-gate } 54827c478bd9Sstevel@tonic-gate 54835b7f77adStw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD, 54845b7f77adStw21770 audit_data.ed_auth); 54857c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54867c478bd9Sstevel@tonic-gate 54877c478bd9Sstevel@tonic-gate rc = object_snapshot_take_new(np, svcname, instname, name, &outp); 54887c478bd9Sstevel@tonic-gate 54897c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 54907c478bd9Sstevel@tonic-gate rc_node_assign(outpp, outp); 54917c478bd9Sstevel@tonic-gate rc_node_rele(outp); 54927c478bd9Sstevel@tonic-gate } 54937c478bd9Sstevel@tonic-gate 54947c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 54957c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD); 54967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 54977c478bd9Sstevel@tonic-gate 54985b7f77adStw21770 if (rc == REP_PROTOCOL_SUCCESS) { 54995b7f77adStw21770 smf_audit_event(ADT_smf_create_snap, ADT_SUCCESS, ADT_SUCCESS, 55005b7f77adStw21770 &audit_data); 55015b7f77adStw21770 } 55025b7f77adStw21770 if (audit_data.ed_auth != NULL) 55035b7f77adStw21770 free(audit_data.ed_auth); 55047c478bd9Sstevel@tonic-gate return (rc); 55057c478bd9Sstevel@tonic-gate } 55067c478bd9Sstevel@tonic-gate 55077c478bd9Sstevel@tonic-gate int 55087c478bd9Sstevel@tonic-gate rc_snapshot_take_attach(rc_node_ptr_t *npp, rc_node_ptr_t *outpp) 55097c478bd9Sstevel@tonic-gate { 55107c478bd9Sstevel@tonic-gate rc_node_t *np, *outp; 55117c478bd9Sstevel@tonic-gate 55127c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 55137c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) { 55147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 55157c478bd9Sstevel@tonic-gate } 55167c478bd9Sstevel@tonic-gate 55177c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(outp, outpp); 55187c478bd9Sstevel@tonic-gate if (outp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 55197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&outp->rn_lock); 55207c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 55217c478bd9Sstevel@tonic-gate } 55227c478bd9Sstevel@tonic-gate 55235b7f77adStw21770 return (rc_attach_snapshot(outp, 0, np, NULL, 55245b7f77adStw21770 NULL)); /* drops outp's lock */ 55257c478bd9Sstevel@tonic-gate } 55267c478bd9Sstevel@tonic-gate 55277c478bd9Sstevel@tonic-gate int 55287c478bd9Sstevel@tonic-gate rc_snapshot_attach(rc_node_ptr_t *npp, rc_node_ptr_t *cpp) 55297c478bd9Sstevel@tonic-gate { 55307c478bd9Sstevel@tonic-gate rc_node_t *np; 55317c478bd9Sstevel@tonic-gate rc_node_t *cp; 55327c478bd9Sstevel@tonic-gate uint32_t snapid; 55335b7f77adStw21770 char old_name[REP_PROTOCOL_NAME_LEN]; 55345b7f77adStw21770 int rc; 55355b7f77adStw21770 size_t sz_out; 55365b7f77adStw21770 char old_fmri[REP_PROTOCOL_FMRI_LEN]; 55377c478bd9Sstevel@tonic-gate 55387c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 55397c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 55407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 55417c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 55427c478bd9Sstevel@tonic-gate } 55437c478bd9Sstevel@tonic-gate snapid = np->rn_snapshot_id; 55445b7f77adStw21770 rc = rc_node_get_fmri_or_fragment(np, old_fmri, sizeof (old_fmri), 55455b7f77adStw21770 &sz_out); 55467c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 55475b7f77adStw21770 if (rc != REP_PROTOCOL_SUCCESS) 55485b7f77adStw21770 return (rc); 55495b7f77adStw21770 if (np->rn_name != NULL) { 55505b7f77adStw21770 if (strlcpy(old_name, np->rn_name, sizeof (old_name)) >= 55515b7f77adStw21770 sizeof (old_name)) { 55525b7f77adStw21770 return (REP_PROTOCOL_FAIL_TRUNCATED); 55535b7f77adStw21770 } 55545b7f77adStw21770 } 55557c478bd9Sstevel@tonic-gate 55567c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(cp, cpp); 55577c478bd9Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 55587c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock); 55597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 55607c478bd9Sstevel@tonic-gate } 55617c478bd9Sstevel@tonic-gate 55625b7f77adStw21770 rc = rc_attach_snapshot(cp, snapid, NULL, 55635b7f77adStw21770 old_fmri, old_name); /* drops cp's lock */ 55645b7f77adStw21770 return (rc); 55657c478bd9Sstevel@tonic-gate } 55667c478bd9Sstevel@tonic-gate 55677c478bd9Sstevel@tonic-gate /* 55683eae19d9Swesolows * If the pgname property group under ent has type pgtype, and it has a 55693eae19d9Swesolows * propname property with type ptype, return _SUCCESS. If pgtype is NULL, 55703eae19d9Swesolows * it is not checked. If ent is not a service node, we will return _SUCCESS if 55713eae19d9Swesolows * a property meeting the requirements exists in either the instance or its 55723eae19d9Swesolows * parent. 55733eae19d9Swesolows * 55743eae19d9Swesolows * Returns 55753eae19d9Swesolows * _SUCCESS - see above 55763eae19d9Swesolows * _DELETED - ent or one of its ancestors was deleted 55773eae19d9Swesolows * _NO_RESOURCES - no resources 55783eae19d9Swesolows * _NOT_FOUND - no matching property was found 55793eae19d9Swesolows */ 55803eae19d9Swesolows static int 55813eae19d9Swesolows rc_svc_prop_exists(rc_node_t *ent, const char *pgname, const char *pgtype, 55823eae19d9Swesolows const char *propname, rep_protocol_value_type_t ptype) 55833eae19d9Swesolows { 55843eae19d9Swesolows int ret; 55853eae19d9Swesolows rc_node_t *pg = NULL, *spg = NULL, *svc, *prop; 55863eae19d9Swesolows 55873eae19d9Swesolows assert(!MUTEX_HELD(&ent->rn_lock)); 55883eae19d9Swesolows 55893eae19d9Swesolows (void) pthread_mutex_lock(&ent->rn_lock); 55903eae19d9Swesolows ret = rc_node_find_named_child(ent, pgname, 55913eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg); 55923eae19d9Swesolows (void) pthread_mutex_unlock(&ent->rn_lock); 55933eae19d9Swesolows 55943eae19d9Swesolows switch (ret) { 55953eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 55963eae19d9Swesolows break; 55973eae19d9Swesolows 55983eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED: 55993eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES: 56003eae19d9Swesolows return (ret); 56013eae19d9Swesolows 56023eae19d9Swesolows default: 56033eae19d9Swesolows bad_error("rc_node_find_named_child", ret); 56043eae19d9Swesolows } 56053eae19d9Swesolows 56063eae19d9Swesolows if (ent->rn_id.rl_type != REP_PROTOCOL_ENTITY_SERVICE) { 56073eae19d9Swesolows ret = rc_node_find_ancestor(ent, REP_PROTOCOL_ENTITY_SERVICE, 56083eae19d9Swesolows &svc); 56093eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) { 56103eae19d9Swesolows assert(ret == REP_PROTOCOL_FAIL_DELETED); 56113eae19d9Swesolows if (pg != NULL) 56123eae19d9Swesolows rc_node_rele(pg); 56133eae19d9Swesolows return (ret); 56143eae19d9Swesolows } 56153eae19d9Swesolows assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE); 56163eae19d9Swesolows 56173eae19d9Swesolows (void) pthread_mutex_lock(&svc->rn_lock); 56183eae19d9Swesolows ret = rc_node_find_named_child(svc, pgname, 56193eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &spg); 56203eae19d9Swesolows (void) pthread_mutex_unlock(&svc->rn_lock); 56213eae19d9Swesolows 56223eae19d9Swesolows rc_node_rele(svc); 56233eae19d9Swesolows 56243eae19d9Swesolows switch (ret) { 56253eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 56263eae19d9Swesolows break; 56273eae19d9Swesolows 56283eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED: 56293eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES: 56303eae19d9Swesolows if (pg != NULL) 56313eae19d9Swesolows rc_node_rele(pg); 56323eae19d9Swesolows return (ret); 56333eae19d9Swesolows 56343eae19d9Swesolows default: 56353eae19d9Swesolows bad_error("rc_node_find_named_child", ret); 56363eae19d9Swesolows } 56373eae19d9Swesolows } 56383eae19d9Swesolows 56393eae19d9Swesolows if (pg != NULL && 56403eae19d9Swesolows pgtype != NULL && strcmp(pg->rn_type, pgtype) != 0) { 56413eae19d9Swesolows rc_node_rele(pg); 56423eae19d9Swesolows pg = NULL; 56433eae19d9Swesolows } 56443eae19d9Swesolows 56453eae19d9Swesolows if (spg != NULL && 56463eae19d9Swesolows pgtype != NULL && strcmp(spg->rn_type, pgtype) != 0) { 56473eae19d9Swesolows rc_node_rele(spg); 56483eae19d9Swesolows spg = NULL; 56493eae19d9Swesolows } 56503eae19d9Swesolows 56513eae19d9Swesolows if (pg == NULL) { 56523eae19d9Swesolows if (spg == NULL) 56533eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND); 56543eae19d9Swesolows pg = spg; 56553eae19d9Swesolows spg = NULL; 56563eae19d9Swesolows } 56573eae19d9Swesolows 56583eae19d9Swesolows /* 56593eae19d9Swesolows * At this point, pg is non-NULL, and is a property group node of the 56603eae19d9Swesolows * correct type. spg, if non-NULL, is also a property group node of 56613eae19d9Swesolows * the correct type. Check for the property in pg first, then spg 56623eae19d9Swesolows * (if applicable). 56633eae19d9Swesolows */ 56643eae19d9Swesolows (void) pthread_mutex_lock(&pg->rn_lock); 56653eae19d9Swesolows ret = rc_node_find_named_child(pg, propname, 56663eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop); 56673eae19d9Swesolows (void) pthread_mutex_unlock(&pg->rn_lock); 56683eae19d9Swesolows rc_node_rele(pg); 56693eae19d9Swesolows switch (ret) { 56703eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 56713eae19d9Swesolows if (prop != NULL) { 56723eae19d9Swesolows if (prop->rn_valtype == ptype) { 56733eae19d9Swesolows rc_node_rele(prop); 56743eae19d9Swesolows if (spg != NULL) 56753eae19d9Swesolows rc_node_rele(spg); 56763eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 56773eae19d9Swesolows } 56783eae19d9Swesolows rc_node_rele(prop); 56793eae19d9Swesolows } 56803eae19d9Swesolows break; 56813eae19d9Swesolows 56823eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES: 56833eae19d9Swesolows if (spg != NULL) 56843eae19d9Swesolows rc_node_rele(spg); 56853eae19d9Swesolows return (ret); 56863eae19d9Swesolows 56873eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED: 56883eae19d9Swesolows break; 56893eae19d9Swesolows 56903eae19d9Swesolows default: 56913eae19d9Swesolows bad_error("rc_node_find_named_child", ret); 56923eae19d9Swesolows } 56933eae19d9Swesolows 56943eae19d9Swesolows if (spg == NULL) 56953eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND); 56963eae19d9Swesolows 56973eae19d9Swesolows pg = spg; 56983eae19d9Swesolows 56993eae19d9Swesolows (void) pthread_mutex_lock(&pg->rn_lock); 57003eae19d9Swesolows ret = rc_node_find_named_child(pg, propname, 57013eae19d9Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop); 57023eae19d9Swesolows (void) pthread_mutex_unlock(&pg->rn_lock); 57033eae19d9Swesolows rc_node_rele(pg); 57043eae19d9Swesolows switch (ret) { 57053eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 57063eae19d9Swesolows if (prop != NULL) { 57073eae19d9Swesolows if (prop->rn_valtype == ptype) { 57083eae19d9Swesolows rc_node_rele(prop); 57093eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 57103eae19d9Swesolows } 57113eae19d9Swesolows rc_node_rele(prop); 57123eae19d9Swesolows } 57133eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND); 57143eae19d9Swesolows 57153eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES: 57163eae19d9Swesolows return (ret); 57173eae19d9Swesolows 57183eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED: 57193eae19d9Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND); 57203eae19d9Swesolows 57213eae19d9Swesolows default: 57223eae19d9Swesolows bad_error("rc_node_find_named_child", ret); 57233eae19d9Swesolows } 57243eae19d9Swesolows 57253eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 57263eae19d9Swesolows } 57273eae19d9Swesolows 57283eae19d9Swesolows /* 57293eae19d9Swesolows * Given a property group node, returns _SUCCESS if the property group may 57303eae19d9Swesolows * be read without any special authorization. 57313eae19d9Swesolows * 57323eae19d9Swesolows * Fails with: 57333eae19d9Swesolows * _DELETED - np or an ancestor node was deleted 57343eae19d9Swesolows * _TYPE_MISMATCH - np does not refer to a property group 57353eae19d9Swesolows * _NO_RESOURCES - no resources 57363eae19d9Swesolows * _PERMISSION_DENIED - authorization is required 57373eae19d9Swesolows */ 57383eae19d9Swesolows static int 57393eae19d9Swesolows rc_node_pg_check_read_protect(rc_node_t *np) 57403eae19d9Swesolows { 57413eae19d9Swesolows int ret; 57423eae19d9Swesolows rc_node_t *ent; 57433eae19d9Swesolows 57443eae19d9Swesolows assert(!MUTEX_HELD(&np->rn_lock)); 57453eae19d9Swesolows 57463eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) 57473eae19d9Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 57483eae19d9Swesolows 57493eae19d9Swesolows if (strcmp(np->rn_type, SCF_GROUP_FRAMEWORK) == 0 || 57503eae19d9Swesolows strcmp(np->rn_type, SCF_GROUP_DEPENDENCY) == 0 || 57513eae19d9Swesolows strcmp(np->rn_type, SCF_GROUP_METHOD) == 0) 57523eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 57533eae19d9Swesolows 57543eae19d9Swesolows ret = rc_node_parent(np, &ent); 57553eae19d9Swesolows 57563eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) 57573eae19d9Swesolows return (ret); 57583eae19d9Swesolows 57593eae19d9Swesolows ret = rc_svc_prop_exists(ent, np->rn_name, np->rn_type, 57603eae19d9Swesolows AUTH_PROP_READ, REP_PROTOCOL_TYPE_STRING); 57613eae19d9Swesolows 57623eae19d9Swesolows rc_node_rele(ent); 57633eae19d9Swesolows 57643eae19d9Swesolows switch (ret) { 57653eae19d9Swesolows case REP_PROTOCOL_FAIL_NOT_FOUND: 57663eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 57673eae19d9Swesolows case REP_PROTOCOL_SUCCESS: 57683eae19d9Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 57693eae19d9Swesolows case REP_PROTOCOL_FAIL_DELETED: 57703eae19d9Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES: 57713eae19d9Swesolows return (ret); 57723eae19d9Swesolows default: 57733eae19d9Swesolows bad_error("rc_svc_prop_exists", ret); 57743eae19d9Swesolows } 57753eae19d9Swesolows 57763eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 57773eae19d9Swesolows } 57783eae19d9Swesolows 57793eae19d9Swesolows /* 57803eae19d9Swesolows * Fails with 57813eae19d9Swesolows * _DELETED - np's node or parent has been deleted 57823eae19d9Swesolows * _TYPE_MISMATCH - np's node is not a property 57833eae19d9Swesolows * _NO_RESOURCES - out of memory 57843eae19d9Swesolows * _PERMISSION_DENIED - no authorization to read this property's value(s) 57853eae19d9Swesolows * _BAD_REQUEST - np's parent is not a property group 57863eae19d9Swesolows */ 57873eae19d9Swesolows static int 57883eae19d9Swesolows rc_node_property_may_read(rc_node_t *np) 57893eae19d9Swesolows { 5790a4dc1477STom Whitten int ret; 5791a4dc1477STom Whitten perm_status_t granted = PERM_DENIED; 57923eae19d9Swesolows rc_node_t *pgp; 57933eae19d9Swesolows permcheck_t *pcp; 57945b7f77adStw21770 audit_event_data_t audit_data; 57955b7f77adStw21770 size_t sz_out; 57963eae19d9Swesolows 57973eae19d9Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) 57983eae19d9Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 57993eae19d9Swesolows 58003eae19d9Swesolows if (client_is_privileged()) 58013eae19d9Swesolows return (REP_PROTOCOL_SUCCESS); 58023eae19d9Swesolows 58033eae19d9Swesolows #ifdef NATIVE_BUILD 58043eae19d9Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 58053eae19d9Swesolows #else 58063eae19d9Swesolows ret = rc_node_parent(np, &pgp); 58073eae19d9Swesolows 58083eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) 58093eae19d9Swesolows return (ret); 58103eae19d9Swesolows 58113eae19d9Swesolows if (pgp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) { 58123eae19d9Swesolows rc_node_rele(pgp); 58133eae19d9Swesolows return (REP_PROTOCOL_FAIL_BAD_REQUEST); 58143eae19d9Swesolows } 58153eae19d9Swesolows 58163eae19d9Swesolows ret = rc_node_pg_check_read_protect(pgp); 58173eae19d9Swesolows 58183eae19d9Swesolows if (ret != REP_PROTOCOL_FAIL_PERMISSION_DENIED) { 58193eae19d9Swesolows rc_node_rele(pgp); 58203eae19d9Swesolows return (ret); 58213eae19d9Swesolows } 58223eae19d9Swesolows 58233eae19d9Swesolows pcp = pc_create(); 58243eae19d9Swesolows 58253eae19d9Swesolows if (pcp == NULL) { 58263eae19d9Swesolows rc_node_rele(pgp); 58273eae19d9Swesolows return (REP_PROTOCOL_FAIL_NO_RESOURCES); 58283eae19d9Swesolows } 58293eae19d9Swesolows 58303eae19d9Swesolows ret = perm_add_enabling(pcp, AUTH_MODIFY); 58313eae19d9Swesolows 58323eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) { 58333eae19d9Swesolows const char * const auth = 58343eae19d9Swesolows perm_auth_for_pgtype(pgp->rn_type); 58353eae19d9Swesolows 58363eae19d9Swesolows if (auth != NULL) 58373eae19d9Swesolows ret = perm_add_enabling(pcp, auth); 58383eae19d9Swesolows } 58393eae19d9Swesolows 58403eae19d9Swesolows /* 58413eae19d9Swesolows * If you are permitted to modify the value, you may also 58423eae19d9Swesolows * read it. This means that both the MODIFY and VALUE 58433eae19d9Swesolows * authorizations are acceptable. We don't allow requests 58443eae19d9Swesolows * for AUTH_PROP_MODIFY if all you have is $AUTH_PROP_VALUE, 58453eae19d9Swesolows * however, to avoid leaking possibly valuable information 58463eae19d9Swesolows * since such a user can't change the property anyway. 58473eae19d9Swesolows */ 58483eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) 58493eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp, 58503eae19d9Swesolows AUTH_PROP_MODIFY); 58513eae19d9Swesolows 58523eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS && 58533eae19d9Swesolows strcmp(np->rn_name, AUTH_PROP_MODIFY) != 0) 58543eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp, 58553eae19d9Swesolows AUTH_PROP_VALUE); 58563eae19d9Swesolows 58573eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) 58583eae19d9Swesolows ret = perm_add_enabling_values(pcp, pgp, 58593eae19d9Swesolows AUTH_PROP_READ); 58603eae19d9Swesolows 58613eae19d9Swesolows rc_node_rele(pgp); 58623eae19d9Swesolows 58633eae19d9Swesolows if (ret == REP_PROTOCOL_SUCCESS) { 58643eae19d9Swesolows granted = perm_granted(pcp); 5865a4dc1477STom Whitten if (granted == PERM_FAIL) 58663eae19d9Swesolows ret = REP_PROTOCOL_FAIL_NO_RESOURCES; 5867a4dc1477STom Whitten if (granted == PERM_GONE) 5868a4dc1477STom Whitten ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 58693eae19d9Swesolows } 5870a4dc1477STom Whitten 58715b7f77adStw21770 if (ret == REP_PROTOCOL_SUCCESS) { 58725b7f77adStw21770 /* Generate a read_prop audit event. */ 58735b7f77adStw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN); 58745b7f77adStw21770 if (audit_data.ed_fmri == NULL) 58755b7f77adStw21770 ret = REP_PROTOCOL_FAIL_NO_RESOURCES; 58765b7f77adStw21770 } 5877a4dc1477STom Whitten if (ret == REP_PROTOCOL_SUCCESS) { 58785b7f77adStw21770 ret = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri, 58795b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out); 5880a4dc1477STom Whitten } 58815b7f77adStw21770 if (ret == REP_PROTOCOL_SUCCESS) { 58825b7f77adStw21770 int status; 58835b7f77adStw21770 int ret_value; 58845b7f77adStw21770 5885a4dc1477STom Whitten if (granted == PERM_DENIED) { 58865b7f77adStw21770 status = ADT_FAILURE; 58875b7f77adStw21770 ret_value = ADT_FAIL_VALUE_AUTH; 58885b7f77adStw21770 } else { 58895b7f77adStw21770 status = ADT_SUCCESS; 58905b7f77adStw21770 ret_value = ADT_SUCCESS; 58915b7f77adStw21770 } 58925b7f77adStw21770 audit_data.ed_auth = pcp->pc_auth_string; 58935b7f77adStw21770 smf_audit_event(ADT_smf_read_prop, 58945b7f77adStw21770 status, ret_value, &audit_data); 58955b7f77adStw21770 } 58965b7f77adStw21770 free(audit_data.ed_fmri); 58973eae19d9Swesolows 58983eae19d9Swesolows pc_free(pcp); 58993eae19d9Swesolows 5900a4dc1477STom Whitten if ((ret == REP_PROTOCOL_SUCCESS) && (granted == PERM_DENIED)) 59013eae19d9Swesolows ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 59023eae19d9Swesolows 59033eae19d9Swesolows return (ret); 59043eae19d9Swesolows #endif /* NATIVE_BUILD */ 59053eae19d9Swesolows } 59063eae19d9Swesolows 59073eae19d9Swesolows /* 59087c478bd9Sstevel@tonic-gate * Iteration 59097c478bd9Sstevel@tonic-gate */ 59107c478bd9Sstevel@tonic-gate static int 59117c478bd9Sstevel@tonic-gate rc_iter_filter_name(rc_node_t *np, void *s) 59127c478bd9Sstevel@tonic-gate { 59137c478bd9Sstevel@tonic-gate const char *name = s; 59147c478bd9Sstevel@tonic-gate 59157c478bd9Sstevel@tonic-gate return (strcmp(np->rn_name, name) == 0); 59167c478bd9Sstevel@tonic-gate } 59177c478bd9Sstevel@tonic-gate 59187c478bd9Sstevel@tonic-gate static int 59197c478bd9Sstevel@tonic-gate rc_iter_filter_type(rc_node_t *np, void *s) 59207c478bd9Sstevel@tonic-gate { 59217c478bd9Sstevel@tonic-gate const char *type = s; 59227c478bd9Sstevel@tonic-gate 59237c478bd9Sstevel@tonic-gate return (np->rn_type != NULL && strcmp(np->rn_type, type) == 0); 59247c478bd9Sstevel@tonic-gate } 59257c478bd9Sstevel@tonic-gate 59267c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 59277c478bd9Sstevel@tonic-gate static int 59287c478bd9Sstevel@tonic-gate rc_iter_null_filter(rc_node_t *np, void *s) 59297c478bd9Sstevel@tonic-gate { 59307c478bd9Sstevel@tonic-gate return (1); 59317c478bd9Sstevel@tonic-gate } 59327c478bd9Sstevel@tonic-gate 59337c478bd9Sstevel@tonic-gate /* 59347c478bd9Sstevel@tonic-gate * Allocate & initialize an rc_node_iter_t structure. Essentially, ensure 59357c478bd9Sstevel@tonic-gate * np->rn_children is populated and call uu_list_walk_start(np->rn_children). 59367c478bd9Sstevel@tonic-gate * If successful, leaves a hold on np & increments np->rn_other_refs 59377c478bd9Sstevel@tonic-gate * 59387c478bd9Sstevel@tonic-gate * If composed is true, then set up for iteration across the top level of np's 59397c478bd9Sstevel@tonic-gate * composition chain. If successful, leaves a hold on np and increments 59407c478bd9Sstevel@tonic-gate * rn_other_refs for the top level of np's composition chain. 59417c478bd9Sstevel@tonic-gate * 59427c478bd9Sstevel@tonic-gate * Fails with 59437c478bd9Sstevel@tonic-gate * _NO_RESOURCES 59447c478bd9Sstevel@tonic-gate * _INVALID_TYPE 59457c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children 59467c478bd9Sstevel@tonic-gate * _DELETED 59477c478bd9Sstevel@tonic-gate */ 59487c478bd9Sstevel@tonic-gate static int 59497c478bd9Sstevel@tonic-gate rc_iter_create(rc_node_iter_t **resp, rc_node_t *np, uint32_t type, 59507c478bd9Sstevel@tonic-gate rc_iter_filter_func *filter, void *arg, boolean_t composed) 59517c478bd9Sstevel@tonic-gate { 59527c478bd9Sstevel@tonic-gate rc_node_iter_t *nip; 59537c478bd9Sstevel@tonic-gate int res; 59547c478bd9Sstevel@tonic-gate 59557c478bd9Sstevel@tonic-gate assert(*resp == NULL); 59567c478bd9Sstevel@tonic-gate 59577c478bd9Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip)); 59587c478bd9Sstevel@tonic-gate if (nip == NULL) 59597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 59607c478bd9Sstevel@tonic-gate 59617c478bd9Sstevel@tonic-gate /* np is held by the client's rc_node_ptr_t */ 59627c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) 59637c478bd9Sstevel@tonic-gate composed = 1; 59647c478bd9Sstevel@tonic-gate 59657c478bd9Sstevel@tonic-gate if (!composed) { 59667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 59677c478bd9Sstevel@tonic-gate 59687c478bd9Sstevel@tonic-gate if ((res = rc_node_fill_children(np, type)) != 59697c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 59707c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 59717c478bd9Sstevel@tonic-gate uu_free(nip); 59727c478bd9Sstevel@tonic-gate return (res); 59737c478bd9Sstevel@tonic-gate } 59747c478bd9Sstevel@tonic-gate 59757c478bd9Sstevel@tonic-gate nip->rni_clevel = -1; 59767c478bd9Sstevel@tonic-gate 59777c478bd9Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(np->rn_children, 59787c478bd9Sstevel@tonic-gate UU_WALK_ROBUST); 59797c478bd9Sstevel@tonic-gate if (nip->rni_iter != NULL) { 59807c478bd9Sstevel@tonic-gate nip->rni_iter_node = np; 59817c478bd9Sstevel@tonic-gate rc_node_hold_other(np); 59827c478bd9Sstevel@tonic-gate } else { 59837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 59847c478bd9Sstevel@tonic-gate uu_free(nip); 59857c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 59867c478bd9Sstevel@tonic-gate } 59877c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 59887c478bd9Sstevel@tonic-gate } else { 59897c478bd9Sstevel@tonic-gate rc_node_t *ent; 59907c478bd9Sstevel@tonic-gate 59917c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) { 59927c478bd9Sstevel@tonic-gate /* rn_cchain isn't valid until children are loaded. */ 59937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 59947c478bd9Sstevel@tonic-gate res = rc_node_fill_children(np, 59957c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL); 59967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 59977c478bd9Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) { 59987c478bd9Sstevel@tonic-gate uu_free(nip); 59997c478bd9Sstevel@tonic-gate return (res); 60007c478bd9Sstevel@tonic-gate } 60017c478bd9Sstevel@tonic-gate 60027c478bd9Sstevel@tonic-gate /* Check for an empty snapshot. */ 60037c478bd9Sstevel@tonic-gate if (np->rn_cchain[0] == NULL) 60047c478bd9Sstevel@tonic-gate goto empty; 60057c478bd9Sstevel@tonic-gate } 60067c478bd9Sstevel@tonic-gate 60077c478bd9Sstevel@tonic-gate /* Start at the top of the composition chain. */ 60087c478bd9Sstevel@tonic-gate for (nip->rni_clevel = 0; ; ++nip->rni_clevel) { 60097c478bd9Sstevel@tonic-gate if (nip->rni_clevel >= COMPOSITION_DEPTH) { 60107c478bd9Sstevel@tonic-gate /* Empty composition chain. */ 60117c478bd9Sstevel@tonic-gate empty: 60127c478bd9Sstevel@tonic-gate nip->rni_clevel = -1; 60137c478bd9Sstevel@tonic-gate nip->rni_iter = NULL; 60147c478bd9Sstevel@tonic-gate /* It's ok, iter_next() will return _DONE. */ 60157c478bd9Sstevel@tonic-gate goto out; 60167c478bd9Sstevel@tonic-gate } 60177c478bd9Sstevel@tonic-gate 60187c478bd9Sstevel@tonic-gate ent = np->rn_cchain[nip->rni_clevel]; 60197c478bd9Sstevel@tonic-gate assert(ent != NULL); 60207c478bd9Sstevel@tonic-gate 60217c478bd9Sstevel@tonic-gate if (rc_node_check_and_lock(ent) == REP_PROTOCOL_SUCCESS) 60227c478bd9Sstevel@tonic-gate break; 60237c478bd9Sstevel@tonic-gate 60247c478bd9Sstevel@tonic-gate /* Someone deleted it, so try the next one. */ 60257c478bd9Sstevel@tonic-gate } 60267c478bd9Sstevel@tonic-gate 60277c478bd9Sstevel@tonic-gate res = rc_node_fill_children(ent, type); 60287c478bd9Sstevel@tonic-gate 60297c478bd9Sstevel@tonic-gate if (res == REP_PROTOCOL_SUCCESS) { 60307c478bd9Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(ent->rn_children, 60317c478bd9Sstevel@tonic-gate UU_WALK_ROBUST); 60327c478bd9Sstevel@tonic-gate 60337c478bd9Sstevel@tonic-gate if (nip->rni_iter == NULL) 60347c478bd9Sstevel@tonic-gate res = REP_PROTOCOL_FAIL_NO_RESOURCES; 60357c478bd9Sstevel@tonic-gate else { 60367c478bd9Sstevel@tonic-gate nip->rni_iter_node = ent; 60377c478bd9Sstevel@tonic-gate rc_node_hold_other(ent); 60387c478bd9Sstevel@tonic-gate } 60397c478bd9Sstevel@tonic-gate } 60407c478bd9Sstevel@tonic-gate 60417c478bd9Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) { 60427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock); 60437c478bd9Sstevel@tonic-gate uu_free(nip); 60447c478bd9Sstevel@tonic-gate return (res); 60457c478bd9Sstevel@tonic-gate } 60467c478bd9Sstevel@tonic-gate 60477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock); 60487c478bd9Sstevel@tonic-gate } 60497c478bd9Sstevel@tonic-gate 60507c478bd9Sstevel@tonic-gate out: 60517c478bd9Sstevel@tonic-gate rc_node_hold(np); /* released by rc_iter_end() */ 60527c478bd9Sstevel@tonic-gate nip->rni_parent = np; 60537c478bd9Sstevel@tonic-gate nip->rni_type = type; 60547c478bd9Sstevel@tonic-gate nip->rni_filter = (filter != NULL)? filter : rc_iter_null_filter; 60557c478bd9Sstevel@tonic-gate nip->rni_filter_arg = arg; 60567c478bd9Sstevel@tonic-gate *resp = nip; 60577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 60587c478bd9Sstevel@tonic-gate } 60597c478bd9Sstevel@tonic-gate 60607c478bd9Sstevel@tonic-gate static void 60617c478bd9Sstevel@tonic-gate rc_iter_end(rc_node_iter_t *iter) 60627c478bd9Sstevel@tonic-gate { 60637c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent; 60647c478bd9Sstevel@tonic-gate 60657c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0) 60667c478bd9Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel]; 60677c478bd9Sstevel@tonic-gate 60687c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock)); 60697c478bd9Sstevel@tonic-gate if (iter->rni_iter != NULL) 60707c478bd9Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter); 60717c478bd9Sstevel@tonic-gate iter->rni_iter = NULL; 60727c478bd9Sstevel@tonic-gate 60737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 60747c478bd9Sstevel@tonic-gate rc_node_rele(iter->rni_parent); 60757c478bd9Sstevel@tonic-gate if (iter->rni_iter_node != NULL) 60767c478bd9Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node); 60777c478bd9Sstevel@tonic-gate } 60787c478bd9Sstevel@tonic-gate 60797c478bd9Sstevel@tonic-gate /* 60807c478bd9Sstevel@tonic-gate * Fails with 60817c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset 60827c478bd9Sstevel@tonic-gate * _DELETED - npp's node has been deleted 60837c478bd9Sstevel@tonic-gate * _NOT_APPLICABLE - npp's node is not a property 60847c478bd9Sstevel@tonic-gate * _NO_RESOURCES - out of memory 60857c478bd9Sstevel@tonic-gate */ 60867c478bd9Sstevel@tonic-gate static int 60877c478bd9Sstevel@tonic-gate rc_node_setup_value_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp) 60887c478bd9Sstevel@tonic-gate { 60897c478bd9Sstevel@tonic-gate rc_node_t *np; 60907c478bd9Sstevel@tonic-gate 60917c478bd9Sstevel@tonic-gate rc_node_iter_t *nip; 60927c478bd9Sstevel@tonic-gate 60937c478bd9Sstevel@tonic-gate assert(*iterp == NULL); 60947c478bd9Sstevel@tonic-gate 60957c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 60967c478bd9Sstevel@tonic-gate 60977c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) { 60987c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 60997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE); 61007c478bd9Sstevel@tonic-gate } 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip)); 61037c478bd9Sstevel@tonic-gate if (nip == NULL) { 61047c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 61057c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 61067c478bd9Sstevel@tonic-gate } 61077c478bd9Sstevel@tonic-gate 61087c478bd9Sstevel@tonic-gate nip->rni_parent = np; 61097c478bd9Sstevel@tonic-gate nip->rni_iter = NULL; 61107c478bd9Sstevel@tonic-gate nip->rni_clevel = -1; 61117c478bd9Sstevel@tonic-gate nip->rni_type = REP_PROTOCOL_ENTITY_VALUE; 61127c478bd9Sstevel@tonic-gate nip->rni_offset = 0; 61137c478bd9Sstevel@tonic-gate nip->rni_last_offset = 0; 61147c478bd9Sstevel@tonic-gate 61157c478bd9Sstevel@tonic-gate rc_node_hold_locked(np); 61167c478bd9Sstevel@tonic-gate 61177c478bd9Sstevel@tonic-gate *iterp = nip; 61187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 61197c478bd9Sstevel@tonic-gate 61207c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 61217c478bd9Sstevel@tonic-gate } 61227c478bd9Sstevel@tonic-gate 61237c478bd9Sstevel@tonic-gate /* 61247c478bd9Sstevel@tonic-gate * Returns: 61253eae19d9Swesolows * _NO_RESOURCES - out of memory 61267c478bd9Sstevel@tonic-gate * _NOT_SET - npp is reset 61277c478bd9Sstevel@tonic-gate * _DELETED - npp's node has been deleted 61287c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node is not a property 61297c478bd9Sstevel@tonic-gate * _NOT_FOUND - property has no values 61307c478bd9Sstevel@tonic-gate * _TRUNCATED - property has >1 values (first is written into out) 61317c478bd9Sstevel@tonic-gate * _SUCCESS - property has 1 value (which is written into out) 61323eae19d9Swesolows * _PERMISSION_DENIED - no authorization to read property value(s) 61337c478bd9Sstevel@tonic-gate * 61347c478bd9Sstevel@tonic-gate * We shorten *sz_out to not include anything after the final '\0'. 61357c478bd9Sstevel@tonic-gate */ 61367c478bd9Sstevel@tonic-gate int 61377c478bd9Sstevel@tonic-gate rc_node_get_property_value(rc_node_ptr_t *npp, 61387c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out) 61397c478bd9Sstevel@tonic-gate { 61407c478bd9Sstevel@tonic-gate rc_node_t *np; 61417c478bd9Sstevel@tonic-gate size_t w; 61427c478bd9Sstevel@tonic-gate int ret; 61437c478bd9Sstevel@tonic-gate 61447c478bd9Sstevel@tonic-gate assert(*sz_out == sizeof (*out)); 61457c478bd9Sstevel@tonic-gate 61463eae19d9Swesolows RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp); 61473eae19d9Swesolows ret = rc_node_property_may_read(np); 61483eae19d9Swesolows rc_node_rele(np); 61493eae19d9Swesolows 61503eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) 61513eae19d9Swesolows return (ret); 61523eae19d9Swesolows 61537c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 61547c478bd9Sstevel@tonic-gate 61557c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) { 61567c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 61577c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 61587c478bd9Sstevel@tonic-gate } 61597c478bd9Sstevel@tonic-gate 61607c478bd9Sstevel@tonic-gate if (np->rn_values_size == 0) { 61617c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 61627c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND); 61637c478bd9Sstevel@tonic-gate } 61647c478bd9Sstevel@tonic-gate out->rpr_type = np->rn_valtype; 61657c478bd9Sstevel@tonic-gate w = strlcpy(out->rpr_value, &np->rn_values[0], 61667c478bd9Sstevel@tonic-gate sizeof (out->rpr_value)); 61677c478bd9Sstevel@tonic-gate 61687c478bd9Sstevel@tonic-gate if (w >= sizeof (out->rpr_value)) 61697c478bd9Sstevel@tonic-gate backend_panic("value too large"); 61707c478bd9Sstevel@tonic-gate 61717c478bd9Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response, 61727c478bd9Sstevel@tonic-gate rpr_value[w + 1]); 61737c478bd9Sstevel@tonic-gate 61747c478bd9Sstevel@tonic-gate ret = (np->rn_values_count != 1)? REP_PROTOCOL_FAIL_TRUNCATED : 61757c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS; 61767c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 61777c478bd9Sstevel@tonic-gate return (ret); 61787c478bd9Sstevel@tonic-gate } 61797c478bd9Sstevel@tonic-gate 61807c478bd9Sstevel@tonic-gate int 61817c478bd9Sstevel@tonic-gate rc_iter_next_value(rc_node_iter_t *iter, 61827c478bd9Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out, int repeat) 61837c478bd9Sstevel@tonic-gate { 61847c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent; 61857c478bd9Sstevel@tonic-gate const char *vals; 61867c478bd9Sstevel@tonic-gate size_t len; 61877c478bd9Sstevel@tonic-gate 61887c478bd9Sstevel@tonic-gate size_t start; 61897c478bd9Sstevel@tonic-gate size_t w; 61903eae19d9Swesolows int ret; 61917c478bd9Sstevel@tonic-gate 61927c478bd9Sstevel@tonic-gate rep_protocol_responseid_t result; 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate assert(*sz_out == sizeof (*out)); 61957c478bd9Sstevel@tonic-gate 61967c478bd9Sstevel@tonic-gate (void) memset(out, '\0', *sz_out); 61977c478bd9Sstevel@tonic-gate 61987c478bd9Sstevel@tonic-gate if (iter->rni_type != REP_PROTOCOL_ENTITY_VALUE) 61997c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 62007c478bd9Sstevel@tonic-gate 62013eae19d9Swesolows RC_NODE_CHECK(np); 62023eae19d9Swesolows ret = rc_node_property_may_read(np); 62033eae19d9Swesolows 62043eae19d9Swesolows if (ret != REP_PROTOCOL_SUCCESS) 62053eae19d9Swesolows return (ret); 62063eae19d9Swesolows 62077c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np); 62087c478bd9Sstevel@tonic-gate 62097c478bd9Sstevel@tonic-gate vals = np->rn_values; 62107c478bd9Sstevel@tonic-gate len = np->rn_values_size; 62117c478bd9Sstevel@tonic-gate 62127c478bd9Sstevel@tonic-gate out->rpr_type = np->rn_valtype; 62137c478bd9Sstevel@tonic-gate 62147c478bd9Sstevel@tonic-gate start = (repeat)? iter->rni_last_offset : iter->rni_offset; 62157c478bd9Sstevel@tonic-gate 62167c478bd9Sstevel@tonic-gate if (len == 0 || start >= len) { 62177c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_DONE; 62187c478bd9Sstevel@tonic-gate *sz_out -= sizeof (out->rpr_value); 62197c478bd9Sstevel@tonic-gate } else { 62207c478bd9Sstevel@tonic-gate w = strlcpy(out->rpr_value, &vals[start], 62217c478bd9Sstevel@tonic-gate sizeof (out->rpr_value)); 62227c478bd9Sstevel@tonic-gate 62237c478bd9Sstevel@tonic-gate if (w >= sizeof (out->rpr_value)) 62247c478bd9Sstevel@tonic-gate backend_panic("value too large"); 62257c478bd9Sstevel@tonic-gate 62267c478bd9Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response, 62277c478bd9Sstevel@tonic-gate rpr_value[w + 1]); 62287c478bd9Sstevel@tonic-gate 62297c478bd9Sstevel@tonic-gate /* 62307c478bd9Sstevel@tonic-gate * update the offsets if we're not repeating 62317c478bd9Sstevel@tonic-gate */ 62327c478bd9Sstevel@tonic-gate if (!repeat) { 62337c478bd9Sstevel@tonic-gate iter->rni_last_offset = iter->rni_offset; 62347c478bd9Sstevel@tonic-gate iter->rni_offset += (w + 1); 62357c478bd9Sstevel@tonic-gate } 62367c478bd9Sstevel@tonic-gate 62377c478bd9Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 62387c478bd9Sstevel@tonic-gate } 62397c478bd9Sstevel@tonic-gate 62407c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 62417c478bd9Sstevel@tonic-gate return (result); 62427c478bd9Sstevel@tonic-gate } 62437c478bd9Sstevel@tonic-gate 62447c478bd9Sstevel@tonic-gate /* 62457c478bd9Sstevel@tonic-gate * Entry point for ITER_START from client.c. Validate the arguments & call 62467c478bd9Sstevel@tonic-gate * rc_iter_create(). 62477c478bd9Sstevel@tonic-gate * 62487c478bd9Sstevel@tonic-gate * Fails with 62497c478bd9Sstevel@tonic-gate * _NOT_SET 62507c478bd9Sstevel@tonic-gate * _DELETED 62517c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children 62527c478bd9Sstevel@tonic-gate * _BAD_REQUEST - flags is invalid 62537c478bd9Sstevel@tonic-gate * pattern is invalid 62547c478bd9Sstevel@tonic-gate * _NO_RESOURCES 62557c478bd9Sstevel@tonic-gate * _INVALID_TYPE 62567c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - *npp cannot have children of type 62577c478bd9Sstevel@tonic-gate * _BACKEND_ACCESS 62587c478bd9Sstevel@tonic-gate */ 62597c478bd9Sstevel@tonic-gate int 62607c478bd9Sstevel@tonic-gate rc_node_setup_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp, 62617c478bd9Sstevel@tonic-gate uint32_t type, uint32_t flags, const char *pattern) 62627c478bd9Sstevel@tonic-gate { 62637c478bd9Sstevel@tonic-gate rc_node_t *np; 62647c478bd9Sstevel@tonic-gate rc_iter_filter_func *f = NULL; 62657c478bd9Sstevel@tonic-gate int rc; 62667c478bd9Sstevel@tonic-gate 62677c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp); 62687c478bd9Sstevel@tonic-gate 62697c478bd9Sstevel@tonic-gate if (pattern != NULL && pattern[0] == '\0') 62707c478bd9Sstevel@tonic-gate pattern = NULL; 62717c478bd9Sstevel@tonic-gate 62727c478bd9Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_VALUE) { 62737c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) 62747c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 62757c478bd9Sstevel@tonic-gate if (flags != RP_ITER_START_ALL || pattern != NULL) 62767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 62777c478bd9Sstevel@tonic-gate 62787c478bd9Sstevel@tonic-gate rc = rc_node_setup_value_iter(npp, iterp); 62797c478bd9Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE); 62807c478bd9Sstevel@tonic-gate return (rc); 62817c478bd9Sstevel@tonic-gate } 62827c478bd9Sstevel@tonic-gate 62837c478bd9Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) != 62847c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) 62857c478bd9Sstevel@tonic-gate return (rc); 62867c478bd9Sstevel@tonic-gate 62877c478bd9Sstevel@tonic-gate if (((flags & RP_ITER_START_FILT_MASK) == RP_ITER_START_ALL) ^ 62887c478bd9Sstevel@tonic-gate (pattern == NULL)) 62897c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 62907c478bd9Sstevel@tonic-gate 62917c478bd9Sstevel@tonic-gate /* Composition only works for instances & snapshots. */ 62927c478bd9Sstevel@tonic-gate if ((flags & RP_ITER_START_COMPOSED) && 62937c478bd9Sstevel@tonic-gate (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE && 62947c478bd9Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)) 62957c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 62967c478bd9Sstevel@tonic-gate 62977c478bd9Sstevel@tonic-gate if (pattern != NULL) { 62987c478bd9Sstevel@tonic-gate if ((rc = rc_check_type_name(type, pattern)) != 62997c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) 63007c478bd9Sstevel@tonic-gate return (rc); 63017c478bd9Sstevel@tonic-gate pattern = strdup(pattern); 63027c478bd9Sstevel@tonic-gate if (pattern == NULL) 63037c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 63047c478bd9Sstevel@tonic-gate } 63057c478bd9Sstevel@tonic-gate 63067c478bd9Sstevel@tonic-gate switch (flags & RP_ITER_START_FILT_MASK) { 63077c478bd9Sstevel@tonic-gate case RP_ITER_START_ALL: 63087c478bd9Sstevel@tonic-gate f = NULL; 63097c478bd9Sstevel@tonic-gate break; 63107c478bd9Sstevel@tonic-gate case RP_ITER_START_EXACT: 63117c478bd9Sstevel@tonic-gate f = rc_iter_filter_name; 63127c478bd9Sstevel@tonic-gate break; 63137c478bd9Sstevel@tonic-gate case RP_ITER_START_PGTYPE: 63147c478bd9Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) { 63157c478bd9Sstevel@tonic-gate free((void *)pattern); 63167c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 63177c478bd9Sstevel@tonic-gate } 63187c478bd9Sstevel@tonic-gate f = rc_iter_filter_type; 63197c478bd9Sstevel@tonic-gate break; 63207c478bd9Sstevel@tonic-gate default: 63217c478bd9Sstevel@tonic-gate free((void *)pattern); 63227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 63237c478bd9Sstevel@tonic-gate } 63247c478bd9Sstevel@tonic-gate 63257c478bd9Sstevel@tonic-gate rc = rc_iter_create(iterp, np, type, f, (void *)pattern, 63267c478bd9Sstevel@tonic-gate flags & RP_ITER_START_COMPOSED); 63277c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS && pattern != NULL) 63287c478bd9Sstevel@tonic-gate free((void *)pattern); 63297c478bd9Sstevel@tonic-gate 63307c478bd9Sstevel@tonic-gate return (rc); 63317c478bd9Sstevel@tonic-gate } 63327c478bd9Sstevel@tonic-gate 63337c478bd9Sstevel@tonic-gate /* 63347c478bd9Sstevel@tonic-gate * Do uu_list_walk_next(iter->rni_iter) until we find a child which matches 63357c478bd9Sstevel@tonic-gate * the filter. 63367c478bd9Sstevel@tonic-gate * For composed iterators, then check to see if there's an overlapping entity 63377c478bd9Sstevel@tonic-gate * (see embedded comments). If we reach the end of the list, start over at 63387c478bd9Sstevel@tonic-gate * the next level. 63397c478bd9Sstevel@tonic-gate * 63407c478bd9Sstevel@tonic-gate * Returns 63417c478bd9Sstevel@tonic-gate * _BAD_REQUEST - iter walks values 63427c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities 63437c478bd9Sstevel@tonic-gate * _DELETED - parent was deleted 63447c478bd9Sstevel@tonic-gate * _NO_RESOURCES 63457c478bd9Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 63467c478bd9Sstevel@tonic-gate * _DONE 63477c478bd9Sstevel@tonic-gate * _SUCCESS 63487c478bd9Sstevel@tonic-gate * 63497c478bd9Sstevel@tonic-gate * For composed property group iterators, can also return 63507c478bd9Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children 63517c478bd9Sstevel@tonic-gate */ 63527c478bd9Sstevel@tonic-gate int 63537c478bd9Sstevel@tonic-gate rc_iter_next(rc_node_iter_t *iter, rc_node_ptr_t *out, uint32_t type) 63547c478bd9Sstevel@tonic-gate { 63557c478bd9Sstevel@tonic-gate rc_node_t *np = iter->rni_parent; 63567c478bd9Sstevel@tonic-gate rc_node_t *res; 63577c478bd9Sstevel@tonic-gate int rc; 63587c478bd9Sstevel@tonic-gate 63597c478bd9Sstevel@tonic-gate if (iter->rni_type == REP_PROTOCOL_ENTITY_VALUE) 63607c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 63617c478bd9Sstevel@tonic-gate 63627c478bd9Sstevel@tonic-gate if (iter->rni_iter == NULL) { 63637c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 63647c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE); 63657c478bd9Sstevel@tonic-gate } 63667c478bd9Sstevel@tonic-gate 63677c478bd9Sstevel@tonic-gate if (iter->rni_type != type) { 63687c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 63697c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 63707c478bd9Sstevel@tonic-gate } 63717c478bd9Sstevel@tonic-gate 63727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); /* held by _iter_create() */ 63737c478bd9Sstevel@tonic-gate 63747c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) { 63757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 63767c478bd9Sstevel@tonic-gate rc_node_clear(out, 1); 63777c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 63787c478bd9Sstevel@tonic-gate } 63797c478bd9Sstevel@tonic-gate 63807c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0) { 63817c478bd9Sstevel@tonic-gate /* Composed iterator. Iterate over appropriate level. */ 63827c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 63837c478bd9Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel]; 63847c478bd9Sstevel@tonic-gate /* 63857c478bd9Sstevel@tonic-gate * If iter->rni_parent is an instance or a snapshot, np must 63867c478bd9Sstevel@tonic-gate * be valid since iter holds iter->rni_parent & possible 63877c478bd9Sstevel@tonic-gate * levels (service, instance, snaplevel) cannot be destroyed 63887c478bd9Sstevel@tonic-gate * while rni_parent is held. If iter->rni_parent is 63897c478bd9Sstevel@tonic-gate * a composed property group then rc_node_setup_cpg() put 63907c478bd9Sstevel@tonic-gate * a hold on np. 63917c478bd9Sstevel@tonic-gate */ 63927c478bd9Sstevel@tonic-gate 63937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 63947c478bd9Sstevel@tonic-gate 63957c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) { 63967c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 63977c478bd9Sstevel@tonic-gate rc_node_clear(out, 1); 63987c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 63997c478bd9Sstevel@tonic-gate } 64007c478bd9Sstevel@tonic-gate } 64017c478bd9Sstevel@tonic-gate 64027c478bd9Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_HAS_CHILDREN); 64037c478bd9Sstevel@tonic-gate 64047c478bd9Sstevel@tonic-gate for (;;) { 64057c478bd9Sstevel@tonic-gate res = uu_list_walk_next(iter->rni_iter); 64067c478bd9Sstevel@tonic-gate if (res == NULL) { 64077c478bd9Sstevel@tonic-gate rc_node_t *parent = iter->rni_parent; 64087c478bd9Sstevel@tonic-gate 64097c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2 64107c478bd9Sstevel@tonic-gate if (iter->rni_clevel < 0 || iter->rni_clevel == 1) { 64117c478bd9Sstevel@tonic-gate /* release walker and lock */ 64127c478bd9Sstevel@tonic-gate rc_iter_end(iter); 64137c478bd9Sstevel@tonic-gate break; 64147c478bd9Sstevel@tonic-gate } 64157c478bd9Sstevel@tonic-gate 64167c478bd9Sstevel@tonic-gate /* Stop walking current level. */ 64177c478bd9Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter); 64187c478bd9Sstevel@tonic-gate iter->rni_iter = NULL; 64197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 64207c478bd9Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node); 64217c478bd9Sstevel@tonic-gate iter->rni_iter_node = NULL; 64227c478bd9Sstevel@tonic-gate 64237c478bd9Sstevel@tonic-gate /* Start walking next level. */ 64247c478bd9Sstevel@tonic-gate ++iter->rni_clevel; 64257c478bd9Sstevel@tonic-gate np = parent->rn_cchain[iter->rni_clevel]; 64267c478bd9Sstevel@tonic-gate assert(np != NULL); 64277c478bd9Sstevel@tonic-gate #else 64287c478bd9Sstevel@tonic-gate #error This code must be updated. 64297c478bd9Sstevel@tonic-gate #endif 64307c478bd9Sstevel@tonic-gate 64317c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 64327c478bd9Sstevel@tonic-gate 64337c478bd9Sstevel@tonic-gate rc = rc_node_fill_children(np, iter->rni_type); 64347c478bd9Sstevel@tonic-gate 64357c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 64367c478bd9Sstevel@tonic-gate iter->rni_iter = 64377c478bd9Sstevel@tonic-gate uu_list_walk_start(np->rn_children, 64387c478bd9Sstevel@tonic-gate UU_WALK_ROBUST); 64397c478bd9Sstevel@tonic-gate 64407c478bd9Sstevel@tonic-gate if (iter->rni_iter == NULL) 64417c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 64427c478bd9Sstevel@tonic-gate else { 64437c478bd9Sstevel@tonic-gate iter->rni_iter_node = np; 64447c478bd9Sstevel@tonic-gate rc_node_hold_other(np); 64457c478bd9Sstevel@tonic-gate } 64467c478bd9Sstevel@tonic-gate } 64477c478bd9Sstevel@tonic-gate 64487c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 64497c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 64507c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 64517c478bd9Sstevel@tonic-gate return (rc); 64527c478bd9Sstevel@tonic-gate } 64537c478bd9Sstevel@tonic-gate 64547c478bd9Sstevel@tonic-gate continue; 64557c478bd9Sstevel@tonic-gate } 64567c478bd9Sstevel@tonic-gate 64577c478bd9Sstevel@tonic-gate if (res->rn_id.rl_type != type || 64587c478bd9Sstevel@tonic-gate !iter->rni_filter(res, iter->rni_filter_arg)) 64597c478bd9Sstevel@tonic-gate continue; 64607c478bd9Sstevel@tonic-gate 64617c478bd9Sstevel@tonic-gate /* 64627c478bd9Sstevel@tonic-gate * If we're composed and not at the top level, check to see if 64637c478bd9Sstevel@tonic-gate * there's an entity at a higher level with the same name. If 64647c478bd9Sstevel@tonic-gate * so, skip this one. 64657c478bd9Sstevel@tonic-gate */ 64667c478bd9Sstevel@tonic-gate if (iter->rni_clevel > 0) { 64677c478bd9Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[0]; 64687c478bd9Sstevel@tonic-gate rc_node_t *pg; 64697c478bd9Sstevel@tonic-gate 64707c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2 64717c478bd9Sstevel@tonic-gate assert(iter->rni_clevel == 1); 64727c478bd9Sstevel@tonic-gate 64737c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 64747c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock); 64757c478bd9Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type, 64767c478bd9Sstevel@tonic-gate &pg); 64777c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && pg != NULL) 64787c478bd9Sstevel@tonic-gate rc_node_rele(pg); 64797c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock); 64807c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 64817c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 64827c478bd9Sstevel@tonic-gate return (rc); 64837c478bd9Sstevel@tonic-gate } 64847c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 64857c478bd9Sstevel@tonic-gate 64867c478bd9Sstevel@tonic-gate /* Make sure np isn't being deleted all of a sudden. */ 64877c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) { 64887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 64897c478bd9Sstevel@tonic-gate rc_node_clear(out, 1); 64907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 64917c478bd9Sstevel@tonic-gate } 64927c478bd9Sstevel@tonic-gate 64937c478bd9Sstevel@tonic-gate if (pg != NULL) 64947c478bd9Sstevel@tonic-gate /* Keep going. */ 64957c478bd9Sstevel@tonic-gate continue; 64967c478bd9Sstevel@tonic-gate #else 64977c478bd9Sstevel@tonic-gate #error This code must be updated. 64987c478bd9Sstevel@tonic-gate #endif 64997c478bd9Sstevel@tonic-gate } 65007c478bd9Sstevel@tonic-gate 65017c478bd9Sstevel@tonic-gate /* 65027c478bd9Sstevel@tonic-gate * If we're composed, iterating over property groups, and not 65037c478bd9Sstevel@tonic-gate * at the bottom level, check to see if there's a pg at lower 65047c478bd9Sstevel@tonic-gate * level with the same name. If so, return a cpg. 65057c478bd9Sstevel@tonic-gate */ 65067c478bd9Sstevel@tonic-gate if (iter->rni_clevel >= 0 && 65077c478bd9Sstevel@tonic-gate type == REP_PROTOCOL_ENTITY_PROPERTYGRP && 65087c478bd9Sstevel@tonic-gate iter->rni_clevel < COMPOSITION_DEPTH - 1) { 65097c478bd9Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2 65107c478bd9Sstevel@tonic-gate rc_node_t *pg; 65117c478bd9Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[1]; 65127c478bd9Sstevel@tonic-gate 65137c478bd9Sstevel@tonic-gate rc_node_hold(res); /* While we drop np->rn_lock */ 65147c478bd9Sstevel@tonic-gate 65157c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 65167c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock); 65177c478bd9Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type, 65187c478bd9Sstevel@tonic-gate &pg); 65197c478bd9Sstevel@tonic-gate /* holds pg if not NULL */ 65207c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock); 65217c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 65227c478bd9Sstevel@tonic-gate rc_node_rele(res); 65237c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 65247c478bd9Sstevel@tonic-gate return (rc); 65257c478bd9Sstevel@tonic-gate } 65267c478bd9Sstevel@tonic-gate 65277c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 65287c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) { 65297c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 65307c478bd9Sstevel@tonic-gate rc_node_rele(res); 65317c478bd9Sstevel@tonic-gate if (pg != NULL) 65327c478bd9Sstevel@tonic-gate rc_node_rele(pg); 65337c478bd9Sstevel@tonic-gate rc_node_clear(out, 1); 65347c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 65357c478bd9Sstevel@tonic-gate } 65367c478bd9Sstevel@tonic-gate 65377c478bd9Sstevel@tonic-gate if (pg == NULL) { 6538*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np->rn_lock); 65397c478bd9Sstevel@tonic-gate rc_node_rele(res); 6540*a29160b0SRobert Mustacchi (void) pthread_mutex_lock(&np->rn_lock); 6541*a29160b0SRobert Mustacchi if (!rc_node_wait_flag(np, RC_NODE_DYING)) { 6542*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np-> 6543*a29160b0SRobert Mustacchi rn_lock); 6544*a29160b0SRobert Mustacchi rc_node_clear(out, 1); 6545*a29160b0SRobert Mustacchi return (REP_PROTOCOL_FAIL_DELETED); 6546*a29160b0SRobert Mustacchi } 65477c478bd9Sstevel@tonic-gate } else { 65487c478bd9Sstevel@tonic-gate rc_node_t *cpg; 65497c478bd9Sstevel@tonic-gate 65507c478bd9Sstevel@tonic-gate /* Keep res held for rc_node_setup_cpg(). */ 65517c478bd9Sstevel@tonic-gate 65527c478bd9Sstevel@tonic-gate cpg = rc_node_alloc(); 65537c478bd9Sstevel@tonic-gate if (cpg == NULL) { 65547c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock( 65557c478bd9Sstevel@tonic-gate &np->rn_lock); 65567c478bd9Sstevel@tonic-gate rc_node_rele(res); 65577c478bd9Sstevel@tonic-gate rc_node_rele(pg); 65587c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 65597c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 65607c478bd9Sstevel@tonic-gate } 65617c478bd9Sstevel@tonic-gate 65627c478bd9Sstevel@tonic-gate switch (rc_node_setup_cpg(cpg, res, pg)) { 65637c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS: 65647c478bd9Sstevel@tonic-gate res = cpg; 65657c478bd9Sstevel@tonic-gate break; 65667c478bd9Sstevel@tonic-gate 65677c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH: 65687c478bd9Sstevel@tonic-gate /* Nevermind. */ 6569*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(&np-> 6570*a29160b0SRobert Mustacchi rn_lock); 65717c478bd9Sstevel@tonic-gate rc_node_destroy(cpg); 65727c478bd9Sstevel@tonic-gate rc_node_rele(pg); 65737c478bd9Sstevel@tonic-gate rc_node_rele(res); 6574*a29160b0SRobert Mustacchi (void) pthread_mutex_lock(&np-> 6575*a29160b0SRobert Mustacchi rn_lock); 6576*a29160b0SRobert Mustacchi if (!rc_node_wait_flag(np, 6577*a29160b0SRobert Mustacchi RC_NODE_DYING)) { 6578*a29160b0SRobert Mustacchi (void) pthread_mutex_unlock(& 6579*a29160b0SRobert Mustacchi np->rn_lock); 6580*a29160b0SRobert Mustacchi rc_node_clear(out, 1); 6581*a29160b0SRobert Mustacchi return 6582*a29160b0SRobert Mustacchi (REP_PROTOCOL_FAIL_DELETED); 6583*a29160b0SRobert Mustacchi } 65847c478bd9Sstevel@tonic-gate break; 65857c478bd9Sstevel@tonic-gate 65867c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 65877c478bd9Sstevel@tonic-gate rc_node_destroy(cpg); 65887c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock( 65897c478bd9Sstevel@tonic-gate &np->rn_lock); 65907c478bd9Sstevel@tonic-gate rc_node_rele(res); 65917c478bd9Sstevel@tonic-gate rc_node_rele(pg); 65927c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 65937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 65947c478bd9Sstevel@tonic-gate 65957c478bd9Sstevel@tonic-gate default: 65967c478bd9Sstevel@tonic-gate assert(0); 65977c478bd9Sstevel@tonic-gate abort(); 65987c478bd9Sstevel@tonic-gate } 65997c478bd9Sstevel@tonic-gate } 66007c478bd9Sstevel@tonic-gate #else 66017c478bd9Sstevel@tonic-gate #error This code must be updated. 66027c478bd9Sstevel@tonic-gate #endif 66037c478bd9Sstevel@tonic-gate } 66047c478bd9Sstevel@tonic-gate 66057c478bd9Sstevel@tonic-gate rc_node_hold(res); 66067c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 66077c478bd9Sstevel@tonic-gate break; 66087c478bd9Sstevel@tonic-gate } 66097c478bd9Sstevel@tonic-gate rc_node_assign(out, res); 66107c478bd9Sstevel@tonic-gate 66117c478bd9Sstevel@tonic-gate if (res == NULL) 66127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE); 66137c478bd9Sstevel@tonic-gate rc_node_rele(res); 66147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 66157c478bd9Sstevel@tonic-gate } 66167c478bd9Sstevel@tonic-gate 66177c478bd9Sstevel@tonic-gate void 66187c478bd9Sstevel@tonic-gate rc_iter_destroy(rc_node_iter_t **nipp) 66197c478bd9Sstevel@tonic-gate { 66207c478bd9Sstevel@tonic-gate rc_node_iter_t *nip = *nipp; 66217c478bd9Sstevel@tonic-gate rc_node_t *np; 66227c478bd9Sstevel@tonic-gate 66237c478bd9Sstevel@tonic-gate if (nip == NULL) 66247c478bd9Sstevel@tonic-gate return; /* already freed */ 66257c478bd9Sstevel@tonic-gate 66267c478bd9Sstevel@tonic-gate np = nip->rni_parent; 66277c478bd9Sstevel@tonic-gate 66287c478bd9Sstevel@tonic-gate if (nip->rni_filter_arg != NULL) 66297c478bd9Sstevel@tonic-gate free(nip->rni_filter_arg); 66307c478bd9Sstevel@tonic-gate nip->rni_filter_arg = NULL; 66317c478bd9Sstevel@tonic-gate 66327c478bd9Sstevel@tonic-gate if (nip->rni_type == REP_PROTOCOL_ENTITY_VALUE || 66337c478bd9Sstevel@tonic-gate nip->rni_iter != NULL) { 66347c478bd9Sstevel@tonic-gate if (nip->rni_clevel < 0) 66357c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 66367c478bd9Sstevel@tonic-gate else 66377c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock( 66387c478bd9Sstevel@tonic-gate &np->rn_cchain[nip->rni_clevel]->rn_lock); 66397c478bd9Sstevel@tonic-gate rc_iter_end(nip); /* release walker and lock */ 66407c478bd9Sstevel@tonic-gate } 66417c478bd9Sstevel@tonic-gate nip->rni_parent = NULL; 66427c478bd9Sstevel@tonic-gate 66437c478bd9Sstevel@tonic-gate uu_free(nip); 66447c478bd9Sstevel@tonic-gate *nipp = NULL; 66457c478bd9Sstevel@tonic-gate } 66467c478bd9Sstevel@tonic-gate 66477c478bd9Sstevel@tonic-gate int 66487c478bd9Sstevel@tonic-gate rc_node_setup_tx(rc_node_ptr_t *npp, rc_node_ptr_t *txp) 66497c478bd9Sstevel@tonic-gate { 66507c478bd9Sstevel@tonic-gate rc_node_t *np; 66517c478bd9Sstevel@tonic-gate permcheck_t *pcp; 66527c478bd9Sstevel@tonic-gate int ret; 6653a4dc1477STom Whitten perm_status_t granted; 66545b7f77adStw21770 rc_auth_state_t authorized = RC_AUTH_UNKNOWN; 66555b7f77adStw21770 char *auth_string = NULL; 66567c478bd9Sstevel@tonic-gate 66577c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp); 66587c478bd9Sstevel@tonic-gate 66597c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) { 66607c478bd9Sstevel@tonic-gate rc_node_rele(np); 66617c478bd9Sstevel@tonic-gate np = np->rn_cchain[0]; 66627c478bd9Sstevel@tonic-gate RC_NODE_CHECK_AND_HOLD(np); 66637c478bd9Sstevel@tonic-gate } 66647c478bd9Sstevel@tonic-gate 66657c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) { 66667c478bd9Sstevel@tonic-gate rc_node_rele(np); 66677c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 66687c478bd9Sstevel@tonic-gate } 66697c478bd9Sstevel@tonic-gate 66707c478bd9Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_SNAPSHOT] != 0) { 66717c478bd9Sstevel@tonic-gate rc_node_rele(np); 66727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 66737c478bd9Sstevel@tonic-gate } 66747c478bd9Sstevel@tonic-gate 66755b7f77adStw21770 #ifdef NATIVE_BUILD 66767c478bd9Sstevel@tonic-gate if (client_is_privileged()) 66777c478bd9Sstevel@tonic-gate goto skip_checks; 66787c478bd9Sstevel@tonic-gate rc_node_rele(np); 66797c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 66807c478bd9Sstevel@tonic-gate #else 66815b7f77adStw21770 if (is_main_repository == 0) 66825b7f77adStw21770 goto skip_checks; 66835b7f77adStw21770 66847c478bd9Sstevel@tonic-gate /* permission check */ 66857c478bd9Sstevel@tonic-gate pcp = pc_create(); 66867c478bd9Sstevel@tonic-gate if (pcp == NULL) { 66877c478bd9Sstevel@tonic-gate rc_node_rele(np); 66887c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 66897c478bd9Sstevel@tonic-gate } 66907c478bd9Sstevel@tonic-gate 66917c478bd9Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_INSTANCE] != 0 && /* instance pg */ 66927c478bd9Sstevel@tonic-gate ((strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0 && 66937c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_ACTIONS_TYPE) == 0) || 66947c478bd9Sstevel@tonic-gate (strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 && 66957c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0))) { 66967c478bd9Sstevel@tonic-gate rc_node_t *instn; 66977c478bd9Sstevel@tonic-gate 6698e8f5b3f5STruong Nguyen /* solaris.smf.modify can be used */ 6699e8f5b3f5STruong Nguyen ret = perm_add_enabling(pcp, AUTH_MODIFY); 6700e8f5b3f5STruong Nguyen if (ret != REP_PROTOCOL_SUCCESS) { 6701e8f5b3f5STruong Nguyen pc_free(pcp); 6702e8f5b3f5STruong Nguyen rc_node_rele(np); 6703e8f5b3f5STruong Nguyen return (ret); 6704e8f5b3f5STruong Nguyen } 6705e8f5b3f5STruong Nguyen 67067c478bd9Sstevel@tonic-gate /* solaris.smf.manage can be used. */ 67077c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE); 67087c478bd9Sstevel@tonic-gate 67097c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) { 67107c478bd9Sstevel@tonic-gate pc_free(pcp); 67117c478bd9Sstevel@tonic-gate rc_node_rele(np); 67127c478bd9Sstevel@tonic-gate return (ret); 67137c478bd9Sstevel@tonic-gate } 67147c478bd9Sstevel@tonic-gate 67157c478bd9Sstevel@tonic-gate /* general/action_authorization values can be used. */ 67167c478bd9Sstevel@tonic-gate ret = rc_node_parent(np, &instn); 67177c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) { 67187c478bd9Sstevel@tonic-gate assert(ret == REP_PROTOCOL_FAIL_DELETED); 67197c478bd9Sstevel@tonic-gate rc_node_rele(np); 67207c478bd9Sstevel@tonic-gate pc_free(pcp); 67217c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 67227c478bd9Sstevel@tonic-gate } 67237c478bd9Sstevel@tonic-gate 67247c478bd9Sstevel@tonic-gate assert(instn->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE); 67257c478bd9Sstevel@tonic-gate 67267c478bd9Sstevel@tonic-gate ret = perm_add_inst_action_auth(pcp, instn); 67277c478bd9Sstevel@tonic-gate rc_node_rele(instn); 67287c478bd9Sstevel@tonic-gate switch (ret) { 67297c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS: 67307c478bd9Sstevel@tonic-gate break; 67317c478bd9Sstevel@tonic-gate 67327c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED: 67337c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 67347c478bd9Sstevel@tonic-gate rc_node_rele(np); 67357c478bd9Sstevel@tonic-gate pc_free(pcp); 67367c478bd9Sstevel@tonic-gate return (ret); 67377c478bd9Sstevel@tonic-gate 67387c478bd9Sstevel@tonic-gate default: 67397c478bd9Sstevel@tonic-gate bad_error("perm_add_inst_action_auth", ret); 67407c478bd9Sstevel@tonic-gate } 67417c478bd9Sstevel@tonic-gate 67427c478bd9Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0) 67435b7f77adStw21770 authorized = RC_AUTH_PASSED; /* No check on commit. */ 67447c478bd9Sstevel@tonic-gate } else { 67457c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MODIFY); 67467c478bd9Sstevel@tonic-gate 67477c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) { 67487c478bd9Sstevel@tonic-gate /* propertygroup-type-specific authorization */ 67497c478bd9Sstevel@tonic-gate /* no locking because rn_type won't change anyway */ 67507c478bd9Sstevel@tonic-gate const char * const auth = 67517c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type); 67527c478bd9Sstevel@tonic-gate 67537c478bd9Sstevel@tonic-gate if (auth != NULL) 67547c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, auth); 67557c478bd9Sstevel@tonic-gate } 67567c478bd9Sstevel@tonic-gate 67577c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) 67587c478bd9Sstevel@tonic-gate /* propertygroup/transaction-type-specific auths */ 67597c478bd9Sstevel@tonic-gate ret = 67607c478bd9Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_VALUE); 67617c478bd9Sstevel@tonic-gate 67627c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) 67637c478bd9Sstevel@tonic-gate ret = 67647c478bd9Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_MODIFY); 67657c478bd9Sstevel@tonic-gate 67667c478bd9Sstevel@tonic-gate /* AUTH_MANAGE can manipulate general/AUTH_PROP_ACTION */ 67677c478bd9Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS && 67687c478bd9Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 && 67697c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0) 67707c478bd9Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE); 67717c478bd9Sstevel@tonic-gate 67727c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) { 67737c478bd9Sstevel@tonic-gate pc_free(pcp); 67747c478bd9Sstevel@tonic-gate rc_node_rele(np); 67757c478bd9Sstevel@tonic-gate return (ret); 67767c478bd9Sstevel@tonic-gate } 67777c478bd9Sstevel@tonic-gate } 67787c478bd9Sstevel@tonic-gate 6779a4dc1477STom Whitten granted = perm_granted(pcp); 6780a4dc1477STom Whitten ret = map_granted_status(granted, pcp, &auth_string); 67817c478bd9Sstevel@tonic-gate pc_free(pcp); 6782a4dc1477STom Whitten 6783a4dc1477STom Whitten if ((granted == PERM_GONE) || (granted == PERM_FAIL) || 6784a4dc1477STom Whitten (ret == REP_PROTOCOL_FAIL_NO_RESOURCES)) { 6785a4dc1477STom Whitten free(auth_string); 67867c478bd9Sstevel@tonic-gate rc_node_rele(np); 6787a4dc1477STom Whitten return (ret); 67887c478bd9Sstevel@tonic-gate } 67897c478bd9Sstevel@tonic-gate 6790a4dc1477STom Whitten if (granted == PERM_DENIED) { 67915b7f77adStw21770 /* 67925b7f77adStw21770 * If we get here, the authorization failed. 67935b7f77adStw21770 * Unfortunately, we don't have enough information at this 67945b7f77adStw21770 * point to generate the security audit events. We'll only 67955b7f77adStw21770 * get that information when the client tries to commit the 67965b7f77adStw21770 * event. Thus, we'll remember the failed authorization, 67975b7f77adStw21770 * so that we can generate the audit events later. 67985b7f77adStw21770 */ 67995b7f77adStw21770 authorized = RC_AUTH_FAILED; 68005b7f77adStw21770 } 68017c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 68027c478bd9Sstevel@tonic-gate 68037c478bd9Sstevel@tonic-gate skip_checks: 68047c478bd9Sstevel@tonic-gate rc_node_assign(txp, np); 68057c478bd9Sstevel@tonic-gate txp->rnp_authorized = authorized; 68065b7f77adStw21770 if (authorized != RC_AUTH_UNKNOWN) { 68075b7f77adStw21770 /* Save the authorization string. */ 68085b7f77adStw21770 if (txp->rnp_auth_string != NULL) 68095b7f77adStw21770 free((void *)txp->rnp_auth_string); 68105b7f77adStw21770 txp->rnp_auth_string = auth_string; 68115b7f77adStw21770 auth_string = NULL; /* Don't free until done with txp. */ 68125b7f77adStw21770 } 68137c478bd9Sstevel@tonic-gate 68147c478bd9Sstevel@tonic-gate rc_node_rele(np); 68155b7f77adStw21770 if (auth_string != NULL) 68165b7f77adStw21770 free(auth_string); 68177c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 68187c478bd9Sstevel@tonic-gate } 68197c478bd9Sstevel@tonic-gate 68207c478bd9Sstevel@tonic-gate /* 68217c478bd9Sstevel@tonic-gate * Return 1 if the given transaction commands only modify the values of 68227c478bd9Sstevel@tonic-gate * properties other than "modify_authorization". Return -1 if any of the 68237c478bd9Sstevel@tonic-gate * commands are invalid, and 0 otherwise. 68247c478bd9Sstevel@tonic-gate */ 68257c478bd9Sstevel@tonic-gate static int 68267c478bd9Sstevel@tonic-gate tx_allow_value(const void *cmds_arg, size_t cmds_sz, rc_node_t *pg) 68277c478bd9Sstevel@tonic-gate { 68287c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds; 68297c478bd9Sstevel@tonic-gate uintptr_t loc; 68307c478bd9Sstevel@tonic-gate uint32_t sz; 68317c478bd9Sstevel@tonic-gate rc_node_t *prop; 68327c478bd9Sstevel@tonic-gate boolean_t ok; 68337c478bd9Sstevel@tonic-gate 68347c478bd9Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock)); 68357c478bd9Sstevel@tonic-gate 68367c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg; 68377c478bd9Sstevel@tonic-gate 68387c478bd9Sstevel@tonic-gate while (cmds_sz > 0) { 68397c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc; 68407c478bd9Sstevel@tonic-gate 68417c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 68427c478bd9Sstevel@tonic-gate return (-1); 68437c478bd9Sstevel@tonic-gate 68447c478bd9Sstevel@tonic-gate sz = cmds->rptc_size; 68457c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 68467c478bd9Sstevel@tonic-gate return (-1); 68477c478bd9Sstevel@tonic-gate 68487c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz); 68497c478bd9Sstevel@tonic-gate if (sz > cmds_sz) 68507c478bd9Sstevel@tonic-gate return (-1); 68517c478bd9Sstevel@tonic-gate 68527c478bd9Sstevel@tonic-gate switch (cmds[0].rptc_action) { 68537c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_CLEAR: 68547c478bd9Sstevel@tonic-gate break; 68557c478bd9Sstevel@tonic-gate 68567c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_REPLACE: 68577c478bd9Sstevel@tonic-gate /* Check type */ 68587c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock); 68591ad2c453STom Whitten ok = B_FALSE; 68607c478bd9Sstevel@tonic-gate if (rc_node_find_named_child(pg, 68617c478bd9Sstevel@tonic-gate (const char *)cmds[0].rptc_data, 68627c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop) == 68637c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 68641ad2c453STom Whitten if (prop != NULL) { 68651ad2c453STom Whitten ok = prop->rn_valtype == 68661ad2c453STom Whitten cmds[0].rptc_type; 68671ad2c453STom Whitten /* 68681ad2c453STom Whitten * rc_node_find_named_child() 68691ad2c453STom Whitten * places a hold on prop which we 68701ad2c453STom Whitten * do not need to hang on to. 68711ad2c453STom Whitten */ 68721ad2c453STom Whitten rc_node_rele(prop); 68731ad2c453STom Whitten } 68747c478bd9Sstevel@tonic-gate } 68757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock); 68767c478bd9Sstevel@tonic-gate if (ok) 68777c478bd9Sstevel@tonic-gate break; 68787c478bd9Sstevel@tonic-gate return (0); 68797c478bd9Sstevel@tonic-gate 68807c478bd9Sstevel@tonic-gate default: 68817c478bd9Sstevel@tonic-gate return (0); 68827c478bd9Sstevel@tonic-gate } 68837c478bd9Sstevel@tonic-gate 68847c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_MODIFY) 68857c478bd9Sstevel@tonic-gate == 0) 68867c478bd9Sstevel@tonic-gate return (0); 68877c478bd9Sstevel@tonic-gate 68887c478bd9Sstevel@tonic-gate loc += sz; 68897c478bd9Sstevel@tonic-gate cmds_sz -= sz; 68907c478bd9Sstevel@tonic-gate } 68917c478bd9Sstevel@tonic-gate 68927c478bd9Sstevel@tonic-gate return (1); 68937c478bd9Sstevel@tonic-gate } 68947c478bd9Sstevel@tonic-gate 68957c478bd9Sstevel@tonic-gate /* 68967c478bd9Sstevel@tonic-gate * Return 1 if any of the given transaction commands affect 68977c478bd9Sstevel@tonic-gate * "action_authorization". Return -1 if any of the commands are invalid and 68987c478bd9Sstevel@tonic-gate * 0 in all other cases. 68997c478bd9Sstevel@tonic-gate */ 69007c478bd9Sstevel@tonic-gate static int 69017c478bd9Sstevel@tonic-gate tx_modifies_action(const void *cmds_arg, size_t cmds_sz) 69027c478bd9Sstevel@tonic-gate { 69037c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds; 69047c478bd9Sstevel@tonic-gate uintptr_t loc; 69057c478bd9Sstevel@tonic-gate uint32_t sz; 69067c478bd9Sstevel@tonic-gate 69077c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg; 69087c478bd9Sstevel@tonic-gate 69097c478bd9Sstevel@tonic-gate while (cmds_sz > 0) { 69107c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc; 69117c478bd9Sstevel@tonic-gate 69127c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 69137c478bd9Sstevel@tonic-gate return (-1); 69147c478bd9Sstevel@tonic-gate 69157c478bd9Sstevel@tonic-gate sz = cmds->rptc_size; 69167c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 69177c478bd9Sstevel@tonic-gate return (-1); 69187c478bd9Sstevel@tonic-gate 69197c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz); 69207c478bd9Sstevel@tonic-gate if (sz > cmds_sz) 69217c478bd9Sstevel@tonic-gate return (-1); 69227c478bd9Sstevel@tonic-gate 69237c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_ACTION) 69247c478bd9Sstevel@tonic-gate == 0) 69257c478bd9Sstevel@tonic-gate return (1); 69267c478bd9Sstevel@tonic-gate 69277c478bd9Sstevel@tonic-gate loc += sz; 69287c478bd9Sstevel@tonic-gate cmds_sz -= sz; 69297c478bd9Sstevel@tonic-gate } 69307c478bd9Sstevel@tonic-gate 69317c478bd9Sstevel@tonic-gate return (0); 69327c478bd9Sstevel@tonic-gate } 69337c478bd9Sstevel@tonic-gate 69347c478bd9Sstevel@tonic-gate /* 69357c478bd9Sstevel@tonic-gate * Returns 1 if the transaction commands only modify properties named 69367c478bd9Sstevel@tonic-gate * 'enabled'. 69377c478bd9Sstevel@tonic-gate */ 69387c478bd9Sstevel@tonic-gate static int 69397c478bd9Sstevel@tonic-gate tx_only_enabled(const void *cmds_arg, size_t cmds_sz) 69407c478bd9Sstevel@tonic-gate { 69417c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmd; 69427c478bd9Sstevel@tonic-gate uintptr_t loc; 69437c478bd9Sstevel@tonic-gate uint32_t sz; 69447c478bd9Sstevel@tonic-gate 69457c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg; 69467c478bd9Sstevel@tonic-gate 69477c478bd9Sstevel@tonic-gate while (cmds_sz > 0) { 69487c478bd9Sstevel@tonic-gate cmd = (struct rep_protocol_transaction_cmd *)loc; 69497c478bd9Sstevel@tonic-gate 69507c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 69517c478bd9Sstevel@tonic-gate return (-1); 69527c478bd9Sstevel@tonic-gate 69537c478bd9Sstevel@tonic-gate sz = cmd->rptc_size; 69547c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 69557c478bd9Sstevel@tonic-gate return (-1); 69567c478bd9Sstevel@tonic-gate 69577c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz); 69587c478bd9Sstevel@tonic-gate if (sz > cmds_sz) 69597c478bd9Sstevel@tonic-gate return (-1); 69607c478bd9Sstevel@tonic-gate 69617c478bd9Sstevel@tonic-gate if (strcmp((const char *)cmd->rptc_data, AUTH_PROP_ENABLED) 69627c478bd9Sstevel@tonic-gate != 0) 69637c478bd9Sstevel@tonic-gate return (0); 69647c478bd9Sstevel@tonic-gate 69657c478bd9Sstevel@tonic-gate loc += sz; 69667c478bd9Sstevel@tonic-gate cmds_sz -= sz; 69677c478bd9Sstevel@tonic-gate } 69687c478bd9Sstevel@tonic-gate 69697c478bd9Sstevel@tonic-gate return (1); 69707c478bd9Sstevel@tonic-gate } 69717c478bd9Sstevel@tonic-gate 69727c478bd9Sstevel@tonic-gate int 69737c478bd9Sstevel@tonic-gate rc_tx_commit(rc_node_ptr_t *txp, const void *cmds, size_t cmds_sz) 69747c478bd9Sstevel@tonic-gate { 69757c478bd9Sstevel@tonic-gate rc_node_t *np = txp->rnp_node; 69767c478bd9Sstevel@tonic-gate rc_node_t *pp; 69777c478bd9Sstevel@tonic-gate rc_node_t *nnp; 69787c478bd9Sstevel@tonic-gate rc_node_pg_notify_t *pnp; 69797c478bd9Sstevel@tonic-gate int rc; 69807c478bd9Sstevel@tonic-gate permcheck_t *pcp; 6981a4dc1477STom Whitten perm_status_t granted; 6982a4dc1477STom Whitten int normal; 69835b7f77adStw21770 char *pg_fmri = NULL; 69845b7f77adStw21770 char *auth_string = NULL; 69855b7f77adStw21770 int auth_status = ADT_SUCCESS; 69865b7f77adStw21770 int auth_ret_value = ADT_SUCCESS; 69875b7f77adStw21770 size_t sz_out; 69885b7f77adStw21770 int tx_flag = 1; 69895b7f77adStw21770 tx_commit_data_t *tx_data = NULL; 69907c478bd9Sstevel@tonic-gate 69917c478bd9Sstevel@tonic-gate RC_NODE_CHECK(np); 69927c478bd9Sstevel@tonic-gate 69935b7f77adStw21770 if ((txp->rnp_authorized != RC_AUTH_UNKNOWN) && 69945b7f77adStw21770 (txp->rnp_auth_string != NULL)) { 69955b7f77adStw21770 auth_string = strdup(txp->rnp_auth_string); 69965b7f77adStw21770 if (auth_string == NULL) 69975b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 69985b7f77adStw21770 } 69995b7f77adStw21770 70005b7f77adStw21770 if ((txp->rnp_authorized == RC_AUTH_UNKNOWN) && 70015b7f77adStw21770 is_main_repository) { 70027c478bd9Sstevel@tonic-gate #ifdef NATIVE_BUILD 70035b7f77adStw21770 if (!client_is_privileged()) { 70047c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 70055b7f77adStw21770 } 70067c478bd9Sstevel@tonic-gate #else 70077c478bd9Sstevel@tonic-gate /* permission check: depends on contents of transaction */ 70087c478bd9Sstevel@tonic-gate pcp = pc_create(); 70097c478bd9Sstevel@tonic-gate if (pcp == NULL) 70107c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 70117c478bd9Sstevel@tonic-gate 70127c478bd9Sstevel@tonic-gate /* If normal is cleared, we won't do the normal checks. */ 70137c478bd9Sstevel@tonic-gate normal = 1; 70147c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; 70157c478bd9Sstevel@tonic-gate 70167c478bd9Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 && 70177c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0) { 70187c478bd9Sstevel@tonic-gate /* Touching general[framework]/action_authorization? */ 70197c478bd9Sstevel@tonic-gate rc = tx_modifies_action(cmds, cmds_sz); 70207c478bd9Sstevel@tonic-gate if (rc == -1) { 70217c478bd9Sstevel@tonic-gate pc_free(pcp); 70227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 70237c478bd9Sstevel@tonic-gate } 70247c478bd9Sstevel@tonic-gate 70257c478bd9Sstevel@tonic-gate if (rc) { 7026e8f5b3f5STruong Nguyen /* 7027e8f5b3f5STruong Nguyen * Yes: only AUTH_MODIFY and AUTH_MANAGE 7028e8f5b3f5STruong Nguyen * can be used. 7029e8f5b3f5STruong Nguyen */ 7030e8f5b3f5STruong Nguyen rc = perm_add_enabling(pcp, AUTH_MODIFY); 7031e8f5b3f5STruong Nguyen 7032e8f5b3f5STruong Nguyen if (rc == REP_PROTOCOL_SUCCESS) 7033e8f5b3f5STruong Nguyen rc = perm_add_enabling(pcp, 7034e8f5b3f5STruong Nguyen AUTH_MANAGE); 7035e8f5b3f5STruong Nguyen 70367c478bd9Sstevel@tonic-gate normal = 0; 70377c478bd9Sstevel@tonic-gate } else { 70387c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; 70397c478bd9Sstevel@tonic-gate } 70407c478bd9Sstevel@tonic-gate } else if (np->rn_id.rl_ids[ID_INSTANCE] != 0 && 70417c478bd9Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 && 70427c478bd9Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0) { 70437c478bd9Sstevel@tonic-gate rc_node_t *instn; 70447c478bd9Sstevel@tonic-gate 70457c478bd9Sstevel@tonic-gate rc = tx_only_enabled(cmds, cmds_sz); 70467c478bd9Sstevel@tonic-gate if (rc == -1) { 70477c478bd9Sstevel@tonic-gate pc_free(pcp); 70487c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 70497c478bd9Sstevel@tonic-gate } 70507c478bd9Sstevel@tonic-gate 70517c478bd9Sstevel@tonic-gate if (rc) { 70527c478bd9Sstevel@tonic-gate rc = rc_node_parent(np, &instn); 70537c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 70547c478bd9Sstevel@tonic-gate assert(rc == REP_PROTOCOL_FAIL_DELETED); 70557c478bd9Sstevel@tonic-gate pc_free(pcp); 70567c478bd9Sstevel@tonic-gate return (rc); 70577c478bd9Sstevel@tonic-gate } 70587c478bd9Sstevel@tonic-gate 70597c478bd9Sstevel@tonic-gate assert(instn->rn_id.rl_type == 70607c478bd9Sstevel@tonic-gate REP_PROTOCOL_ENTITY_INSTANCE); 70617c478bd9Sstevel@tonic-gate 70627c478bd9Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, instn); 70637c478bd9Sstevel@tonic-gate rc_node_rele(instn); 70647c478bd9Sstevel@tonic-gate switch (rc) { 70657c478bd9Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS: 70667c478bd9Sstevel@tonic-gate break; 70677c478bd9Sstevel@tonic-gate 70687c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED: 70697c478bd9Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES: 70707c478bd9Sstevel@tonic-gate pc_free(pcp); 70717c478bd9Sstevel@tonic-gate return (rc); 70727c478bd9Sstevel@tonic-gate 70737c478bd9Sstevel@tonic-gate default: 70747c478bd9Sstevel@tonic-gate bad_error("perm_add_inst_action_auth", 70757c478bd9Sstevel@tonic-gate rc); 70767c478bd9Sstevel@tonic-gate } 70777c478bd9Sstevel@tonic-gate } else { 70787c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; 70797c478bd9Sstevel@tonic-gate } 70807c478bd9Sstevel@tonic-gate } 70817c478bd9Sstevel@tonic-gate 70827c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && normal) { 70837c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY); 70847c478bd9Sstevel@tonic-gate 70857c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 70867c478bd9Sstevel@tonic-gate /* Add pgtype-specific authorization. */ 70877c478bd9Sstevel@tonic-gate const char * const auth = 70887c478bd9Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type); 70897c478bd9Sstevel@tonic-gate 70907c478bd9Sstevel@tonic-gate if (auth != NULL) 70917c478bd9Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth); 70927c478bd9Sstevel@tonic-gate } 70937c478bd9Sstevel@tonic-gate 70947c478bd9Sstevel@tonic-gate /* Add pg-specific modify_authorization auths. */ 70957c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) 70967c478bd9Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np, 70977c478bd9Sstevel@tonic-gate AUTH_PROP_MODIFY); 70987c478bd9Sstevel@tonic-gate 70997c478bd9Sstevel@tonic-gate /* If value_authorization values are ok, add them. */ 71007c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 71017c478bd9Sstevel@tonic-gate rc = tx_allow_value(cmds, cmds_sz, np); 71027c478bd9Sstevel@tonic-gate if (rc == -1) 71037c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST; 71047c478bd9Sstevel@tonic-gate else if (rc) 71057c478bd9Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np, 71067c478bd9Sstevel@tonic-gate AUTH_PROP_VALUE); 71077c478bd9Sstevel@tonic-gate } 71087c478bd9Sstevel@tonic-gate } 71097c478bd9Sstevel@tonic-gate 71107c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) { 71117c478bd9Sstevel@tonic-gate granted = perm_granted(pcp); 7112a4dc1477STom Whitten rc = map_granted_status(granted, pcp, &auth_string); 7113a4dc1477STom Whitten if ((granted == PERM_DENIED) && auth_string) { 71145b7f77adStw21770 /* 7115a4dc1477STom Whitten * _PERMISSION_DENIED should not cause us 7116a4dc1477STom Whitten * to exit at this point, because we still 7117a4dc1477STom Whitten * want to generate an audit event. 71185b7f77adStw21770 */ 7119a4dc1477STom Whitten rc = REP_PROTOCOL_SUCCESS; 71205b7f77adStw21770 } 71217c478bd9Sstevel@tonic-gate } 71227c478bd9Sstevel@tonic-gate 71237c478bd9Sstevel@tonic-gate pc_free(pcp); 71247c478bd9Sstevel@tonic-gate 71257c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) 71265b7f77adStw21770 goto cleanout; 71277c478bd9Sstevel@tonic-gate 7128a4dc1477STom Whitten if (granted == PERM_DENIED) { 71295b7f77adStw21770 auth_status = ADT_FAILURE; 71305b7f77adStw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH; 71315b7f77adStw21770 tx_flag = 0; 71325b7f77adStw21770 } 71337c478bd9Sstevel@tonic-gate #endif /* NATIVE_BUILD */ 71345b7f77adStw21770 } else if (txp->rnp_authorized == RC_AUTH_FAILED) { 71355b7f77adStw21770 auth_status = ADT_FAILURE; 71365b7f77adStw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH; 71375b7f77adStw21770 tx_flag = 0; 71385b7f77adStw21770 } 71395b7f77adStw21770 71405b7f77adStw21770 pg_fmri = malloc(REP_PROTOCOL_FMRI_LEN); 71415b7f77adStw21770 if (pg_fmri == NULL) { 71425b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 71435b7f77adStw21770 goto cleanout; 71445b7f77adStw21770 } 71455b7f77adStw21770 if ((rc = rc_node_get_fmri_or_fragment(np, pg_fmri, 71465b7f77adStw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) { 71475b7f77adStw21770 goto cleanout; 71485b7f77adStw21770 } 71495b7f77adStw21770 71505b7f77adStw21770 /* 71515b7f77adStw21770 * Parse the transaction commands into a useful form. 71525b7f77adStw21770 */ 71535b7f77adStw21770 if ((rc = tx_commit_data_new(cmds, cmds_sz, &tx_data)) != 71545b7f77adStw21770 REP_PROTOCOL_SUCCESS) { 71555b7f77adStw21770 goto cleanout; 71565b7f77adStw21770 } 71575b7f77adStw21770 71585b7f77adStw21770 if (tx_flag == 0) { 71595b7f77adStw21770 /* Authorization failed. Generate audit events. */ 71605b7f77adStw21770 generate_property_events(tx_data, pg_fmri, auth_string, 71615b7f77adStw21770 auth_status, auth_ret_value); 71625b7f77adStw21770 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED; 71635b7f77adStw21770 goto cleanout; 71647c478bd9Sstevel@tonic-gate } 71657c478bd9Sstevel@tonic-gate 71667c478bd9Sstevel@tonic-gate nnp = rc_node_alloc(); 71675b7f77adStw21770 if (nnp == NULL) { 71685b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 71695b7f77adStw21770 goto cleanout; 71705b7f77adStw21770 } 71717c478bd9Sstevel@tonic-gate 71727c478bd9Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */ 71737c478bd9Sstevel@tonic-gate nnp->rn_hash = np->rn_hash; 71747c478bd9Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name); 71757c478bd9Sstevel@tonic-gate nnp->rn_type = strdup(np->rn_type); 71767c478bd9Sstevel@tonic-gate nnp->rn_pgflags = np->rn_pgflags; 71777c478bd9Sstevel@tonic-gate 71787c478bd9Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT; 71797c478bd9Sstevel@tonic-gate 71807c478bd9Sstevel@tonic-gate if (nnp->rn_name == NULL || nnp->rn_type == NULL) { 71817c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 71825b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 71835b7f77adStw21770 goto cleanout; 71847c478bd9Sstevel@tonic-gate } 71857c478bd9Sstevel@tonic-gate 71867c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 71875b7f77adStw21770 71887c478bd9Sstevel@tonic-gate /* 71897c478bd9Sstevel@tonic-gate * We must have all of the old properties in the cache, or the 71907c478bd9Sstevel@tonic-gate * database deletions could cause inconsistencies. 71917c478bd9Sstevel@tonic-gate */ 71927c478bd9Sstevel@tonic-gate if ((rc = rc_node_fill_children(np, REP_PROTOCOL_ENTITY_PROPERTY)) != 71937c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) { 71947c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 71957c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 71965b7f77adStw21770 goto cleanout; 71977c478bd9Sstevel@tonic-gate } 71987c478bd9Sstevel@tonic-gate 71997c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) { 72007c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72017c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 72025b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 72035b7f77adStw21770 goto cleanout; 72047c478bd9Sstevel@tonic-gate } 72057c478bd9Sstevel@tonic-gate 72067c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) { 72077c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT); 72087c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72097c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 72105b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST; 72115b7f77adStw21770 goto cleanout; 72127c478bd9Sstevel@tonic-gate } 72137c478bd9Sstevel@tonic-gate 72147c478bd9Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING); 72157c478bd9Sstevel@tonic-gate if (pp == NULL) { 72167c478bd9Sstevel@tonic-gate /* our parent is gone, we're going next... */ 72177c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 72187c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 72197c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) { 72207c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72215b7f77adStw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST; 72225b7f77adStw21770 goto cleanout; 72237c478bd9Sstevel@tonic-gate } 72247c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72255b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 72265b7f77adStw21770 goto cleanout; 72277c478bd9Sstevel@tonic-gate } 72287c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 72297c478bd9Sstevel@tonic-gate 72307c478bd9Sstevel@tonic-gate /* 72317c478bd9Sstevel@tonic-gate * prepare for the transaction 72327c478bd9Sstevel@tonic-gate */ 72337c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 72347c478bd9Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) { 72357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72367c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 72377c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 72387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 72397c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 72405b7f77adStw21770 rc = REP_PROTOCOL_FAIL_DELETED; 72415b7f77adStw21770 goto cleanout; 72427c478bd9Sstevel@tonic-gate } 72437c478bd9Sstevel@tonic-gate nnp->rn_gen_id = np->rn_gen_id; 72447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72457c478bd9Sstevel@tonic-gate 72467c478bd9Sstevel@tonic-gate /* Sets nnp->rn_gen_id on success. */ 72475b7f77adStw21770 rc = object_tx_commit(&np->rn_id, tx_data, &nnp->rn_gen_id); 72487c478bd9Sstevel@tonic-gate 72497c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); 72507c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) { 72517c478bd9Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX); 72527c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72537c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock); 72547c478bd9Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING); 72557c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock); 72567c478bd9Sstevel@tonic-gate rc_node_destroy(nnp); 72577c478bd9Sstevel@tonic-gate rc_node_clear(txp, 0); 72587c478bd9Sstevel@tonic-gate if (rc == REP_PROTOCOL_DONE) 72597c478bd9Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; /* successful empty tx */ 72605b7f77adStw21770 goto cleanout; 72617c478bd9Sstevel@tonic-gate } 72627c478bd9Sstevel@tonic-gate 72637c478bd9Sstevel@tonic-gate /* 72647c478bd9Sstevel@tonic-gate * Notify waiters 72657c478bd9Sstevel@tonic-gate */ 72667c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 72677c478bd9Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL) 72687c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp); 72697c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 72707c478bd9Sstevel@tonic-gate 72717c478bd9Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD; 72727c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 72737c478bd9Sstevel@tonic-gate 72747c478bd9Sstevel@tonic-gate rc_notify_remove_node(np); 72757c478bd9Sstevel@tonic-gate 72767c478bd9Sstevel@tonic-gate /* 72777c478bd9Sstevel@tonic-gate * replace np with nnp 72787c478bd9Sstevel@tonic-gate */ 72797c478bd9Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp); 72807c478bd9Sstevel@tonic-gate 72817c478bd9Sstevel@tonic-gate /* 72827c478bd9Sstevel@tonic-gate * all done -- clear the transaction. 72837c478bd9Sstevel@tonic-gate */ 72847c478bd9Sstevel@tonic-gate rc_node_clear(txp, 0); 72855b7f77adStw21770 generate_property_events(tx_data, pg_fmri, auth_string, 72865b7f77adStw21770 auth_status, auth_ret_value); 72877c478bd9Sstevel@tonic-gate 72885b7f77adStw21770 rc = REP_PROTOCOL_SUCCESS; 72895b7f77adStw21770 72905b7f77adStw21770 cleanout: 72915b7f77adStw21770 free(auth_string); 72925b7f77adStw21770 free(pg_fmri); 72935b7f77adStw21770 tx_commit_data_free(tx_data); 72945b7f77adStw21770 return (rc); 72957c478bd9Sstevel@tonic-gate } 72967c478bd9Sstevel@tonic-gate 72977c478bd9Sstevel@tonic-gate void 72987c478bd9Sstevel@tonic-gate rc_pg_notify_init(rc_node_pg_notify_t *pnp) 72997c478bd9Sstevel@tonic-gate { 73007c478bd9Sstevel@tonic-gate uu_list_node_init(pnp, &pnp->rnpn_node, rc_pg_notify_pool); 73017c478bd9Sstevel@tonic-gate pnp->rnpn_pg = NULL; 73027c478bd9Sstevel@tonic-gate pnp->rnpn_fd = -1; 73037c478bd9Sstevel@tonic-gate } 73047c478bd9Sstevel@tonic-gate 73057c478bd9Sstevel@tonic-gate int 73067c478bd9Sstevel@tonic-gate rc_pg_notify_setup(rc_node_pg_notify_t *pnp, rc_node_ptr_t *npp, int fd) 73077c478bd9Sstevel@tonic-gate { 73087c478bd9Sstevel@tonic-gate rc_node_t *np; 73097c478bd9Sstevel@tonic-gate 73107c478bd9Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); 73117c478bd9Sstevel@tonic-gate 73127c478bd9Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) { 73137c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 73147c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 73157c478bd9Sstevel@tonic-gate } 73167c478bd9Sstevel@tonic-gate 73177c478bd9Sstevel@tonic-gate /* 73187c478bd9Sstevel@tonic-gate * wait for any transaction in progress to complete 73197c478bd9Sstevel@tonic-gate */ 73207c478bd9Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_IN_TX)) { 73217c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 73227c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); 73237c478bd9Sstevel@tonic-gate } 73247c478bd9Sstevel@tonic-gate 73257c478bd9Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) { 73267c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 73277c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_LATEST); 73287c478bd9Sstevel@tonic-gate } 73297c478bd9Sstevel@tonic-gate 73307c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 73317c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp); 73327c478bd9Sstevel@tonic-gate pnp->rnpn_pg = np; 73337c478bd9Sstevel@tonic-gate pnp->rnpn_fd = fd; 73347c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(np->rn_pg_notify_list, NULL, pnp); 73357c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 73367c478bd9Sstevel@tonic-gate 73377c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock); 73387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 73397c478bd9Sstevel@tonic-gate } 73407c478bd9Sstevel@tonic-gate 73417c478bd9Sstevel@tonic-gate void 73427c478bd9Sstevel@tonic-gate rc_pg_notify_fini(rc_node_pg_notify_t *pnp) 73437c478bd9Sstevel@tonic-gate { 73447c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 73457c478bd9Sstevel@tonic-gate rc_pg_notify_fire(pnp); 73467c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 73477c478bd9Sstevel@tonic-gate 73487c478bd9Sstevel@tonic-gate uu_list_node_fini(pnp, &pnp->rnpn_node, rc_pg_notify_pool); 73497c478bd9Sstevel@tonic-gate } 73507c478bd9Sstevel@tonic-gate 73517c478bd9Sstevel@tonic-gate void 73527c478bd9Sstevel@tonic-gate rc_notify_info_init(rc_notify_info_t *rnip) 73537c478bd9Sstevel@tonic-gate { 73547c478bd9Sstevel@tonic-gate int i; 73557c478bd9Sstevel@tonic-gate 73567c478bd9Sstevel@tonic-gate uu_list_node_init(rnip, &rnip->rni_list_node, rc_notify_info_pool); 73577c478bd9Sstevel@tonic-gate uu_list_node_init(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node, 73587c478bd9Sstevel@tonic-gate rc_notify_pool); 73597c478bd9Sstevel@tonic-gate 73607c478bd9Sstevel@tonic-gate rnip->rni_notify.rcn_node = NULL; 73617c478bd9Sstevel@tonic-gate rnip->rni_notify.rcn_info = rnip; 73627c478bd9Sstevel@tonic-gate 73637c478bd9Sstevel@tonic-gate bzero(rnip->rni_namelist, sizeof (rnip->rni_namelist)); 73647c478bd9Sstevel@tonic-gate bzero(rnip->rni_typelist, sizeof (rnip->rni_typelist)); 73657c478bd9Sstevel@tonic-gate 73667c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&rnip->rni_cv, NULL); 73677c478bd9Sstevel@tonic-gate 73687c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) { 73697c478bd9Sstevel@tonic-gate rnip->rni_namelist[i] = NULL; 73707c478bd9Sstevel@tonic-gate rnip->rni_typelist[i] = NULL; 73717c478bd9Sstevel@tonic-gate } 73727c478bd9Sstevel@tonic-gate } 73737c478bd9Sstevel@tonic-gate 73747c478bd9Sstevel@tonic-gate static void 73757c478bd9Sstevel@tonic-gate rc_notify_info_insert_locked(rc_notify_info_t *rnip) 73767c478bd9Sstevel@tonic-gate { 73777c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock)); 73787c478bd9Sstevel@tonic-gate 73797c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_ACTIVE)); 73807c478bd9Sstevel@tonic-gate 73817c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_ACTIVE; 73827c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_info_list, NULL, rnip); 73837c478bd9Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, &rnip->rni_notify); 73847c478bd9Sstevel@tonic-gate } 73857c478bd9Sstevel@tonic-gate 73867c478bd9Sstevel@tonic-gate static void 73877c478bd9Sstevel@tonic-gate rc_notify_info_remove_locked(rc_notify_info_t *rnip) 73887c478bd9Sstevel@tonic-gate { 73897c478bd9Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify; 73907c478bd9Sstevel@tonic-gate rc_notify_t *np; 73917c478bd9Sstevel@tonic-gate 73927c478bd9Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock)); 73937c478bd9Sstevel@tonic-gate 73947c478bd9Sstevel@tonic-gate assert(rnip->rni_flags & RC_NOTIFY_ACTIVE); 73957c478bd9Sstevel@tonic-gate 73967c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_DRAIN)); 73977c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_DRAIN; 73987c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv); 73997c478bd9Sstevel@tonic-gate 74007c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_info_list, rnip); 74017c478bd9Sstevel@tonic-gate 74027c478bd9Sstevel@tonic-gate /* 74037c478bd9Sstevel@tonic-gate * clean up any notifications at the beginning of the list 74047c478bd9Sstevel@tonic-gate */ 74057c478bd9Sstevel@tonic-gate if (uu_list_first(rc_notify_list) == me) { 7406b5cbdab0STom Whitten /* 7407b5cbdab0STom Whitten * We can't call rc_notify_remove_locked() unless 7408b5cbdab0STom Whitten * rc_notify_in_use is 0. 7409b5cbdab0STom Whitten */ 7410b5cbdab0STom Whitten while (rc_notify_in_use) { 7411b5cbdab0STom Whitten (void) pthread_cond_wait(&rc_pg_notify_cv, 7412b5cbdab0STom Whitten &rc_pg_notify_lock); 7413b5cbdab0STom Whitten } 74147c478bd9Sstevel@tonic-gate while ((np = uu_list_next(rc_notify_list, me)) != NULL && 74157c478bd9Sstevel@tonic-gate np->rcn_info == NULL) 74167c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np); 74177c478bd9Sstevel@tonic-gate } 74187c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me); 74197c478bd9Sstevel@tonic-gate 74207c478bd9Sstevel@tonic-gate while (rnip->rni_waiters) { 74217c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv); 74227c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv); 74237c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock); 74247c478bd9Sstevel@tonic-gate } 74257c478bd9Sstevel@tonic-gate 74267c478bd9Sstevel@tonic-gate rnip->rni_flags &= ~(RC_NOTIFY_DRAIN | RC_NOTIFY_ACTIVE); 74277c478bd9Sstevel@tonic-gate } 74287c478bd9Sstevel@tonic-gate 74297c478bd9Sstevel@tonic-gate static int 74307c478bd9Sstevel@tonic-gate rc_notify_info_add_watch(rc_notify_info_t *rnip, const char **arr, 74317c478bd9Sstevel@tonic-gate const char *name) 74327c478bd9Sstevel@tonic-gate { 74337c478bd9Sstevel@tonic-gate int i; 74347c478bd9Sstevel@tonic-gate int rc; 74357c478bd9Sstevel@tonic-gate char *f; 74367c478bd9Sstevel@tonic-gate 74377c478bd9Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_PROPERTYGRP, name); 74387c478bd9Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) 74397c478bd9Sstevel@tonic-gate return (rc); 74407c478bd9Sstevel@tonic-gate 74417c478bd9Sstevel@tonic-gate f = strdup(name); 74427c478bd9Sstevel@tonic-gate if (f == NULL) 74437c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 74447c478bd9Sstevel@tonic-gate 74457c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 74467c478bd9Sstevel@tonic-gate 74477c478bd9Sstevel@tonic-gate while (rnip->rni_flags & RC_NOTIFY_EMPTYING) 74487c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock); 74497c478bd9Sstevel@tonic-gate 745042958ef4Stn143363 for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) { 74517c478bd9Sstevel@tonic-gate if (arr[i] == NULL) 74527c478bd9Sstevel@tonic-gate break; 74537c478bd9Sstevel@tonic-gate 745442958ef4Stn143363 /* 745542958ef4Stn143363 * Don't add name if it's already being tracked. 745642958ef4Stn143363 */ 745742958ef4Stn143363 if (strcmp(arr[i], f) == 0) { 745842958ef4Stn143363 free(f); 745942958ef4Stn143363 goto out; 746042958ef4Stn143363 } 746142958ef4Stn143363 } 746242958ef4Stn143363 74637c478bd9Sstevel@tonic-gate if (i == RC_NOTIFY_MAX_NAMES) { 74647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 74657c478bd9Sstevel@tonic-gate free(f); 74667c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 74677c478bd9Sstevel@tonic-gate } 74687c478bd9Sstevel@tonic-gate 74697c478bd9Sstevel@tonic-gate arr[i] = f; 747042958ef4Stn143363 747142958ef4Stn143363 out: 74727c478bd9Sstevel@tonic-gate if (!(rnip->rni_flags & RC_NOTIFY_ACTIVE)) 74737c478bd9Sstevel@tonic-gate rc_notify_info_insert_locked(rnip); 74747c478bd9Sstevel@tonic-gate 74757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 74767c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 74777c478bd9Sstevel@tonic-gate } 74787c478bd9Sstevel@tonic-gate 74797c478bd9Sstevel@tonic-gate int 74807c478bd9Sstevel@tonic-gate rc_notify_info_add_name(rc_notify_info_t *rnip, const char *name) 74817c478bd9Sstevel@tonic-gate { 74827c478bd9Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_namelist, name)); 74837c478bd9Sstevel@tonic-gate } 74847c478bd9Sstevel@tonic-gate 74857c478bd9Sstevel@tonic-gate int 74867c478bd9Sstevel@tonic-gate rc_notify_info_add_type(rc_notify_info_t *rnip, const char *type) 74877c478bd9Sstevel@tonic-gate { 74887c478bd9Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_typelist, type)); 74897c478bd9Sstevel@tonic-gate } 74907c478bd9Sstevel@tonic-gate 74917c478bd9Sstevel@tonic-gate /* 74927c478bd9Sstevel@tonic-gate * Wait for and report an event of interest to rnip, a notification client 74937c478bd9Sstevel@tonic-gate */ 74947c478bd9Sstevel@tonic-gate int 74957c478bd9Sstevel@tonic-gate rc_notify_info_wait(rc_notify_info_t *rnip, rc_node_ptr_t *out, 74967c478bd9Sstevel@tonic-gate char *outp, size_t sz) 74977c478bd9Sstevel@tonic-gate { 74987c478bd9Sstevel@tonic-gate rc_notify_t *np; 74997c478bd9Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify; 75007c478bd9Sstevel@tonic-gate rc_node_t *nnp; 75017c478bd9Sstevel@tonic-gate rc_notify_delete_t *ndp; 75027c478bd9Sstevel@tonic-gate 75037c478bd9Sstevel@tonic-gate int am_first_info; 75047c478bd9Sstevel@tonic-gate 75057c478bd9Sstevel@tonic-gate if (sz > 0) 75067c478bd9Sstevel@tonic-gate outp[0] = 0; 75077c478bd9Sstevel@tonic-gate 75087c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 75097c478bd9Sstevel@tonic-gate 75107c478bd9Sstevel@tonic-gate while ((rnip->rni_flags & (RC_NOTIFY_ACTIVE | RC_NOTIFY_DRAIN)) == 75117c478bd9Sstevel@tonic-gate RC_NOTIFY_ACTIVE) { 75127c478bd9Sstevel@tonic-gate /* 75137c478bd9Sstevel@tonic-gate * If I'm first on the notify list, it is my job to 75147c478bd9Sstevel@tonic-gate * clean up any notifications I pass by. I can't do that 75157c478bd9Sstevel@tonic-gate * if someone is blocking the list from removals, so I 75167c478bd9Sstevel@tonic-gate * have to wait until they have all drained. 75177c478bd9Sstevel@tonic-gate */ 75187c478bd9Sstevel@tonic-gate am_first_info = (uu_list_first(rc_notify_list) == me); 75197c478bd9Sstevel@tonic-gate if (am_first_info && rc_notify_in_use) { 75207c478bd9Sstevel@tonic-gate rnip->rni_waiters++; 75217c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv, 75227c478bd9Sstevel@tonic-gate &rc_pg_notify_lock); 75237c478bd9Sstevel@tonic-gate rnip->rni_waiters--; 75247c478bd9Sstevel@tonic-gate continue; 75257c478bd9Sstevel@tonic-gate } 75267c478bd9Sstevel@tonic-gate 75277c478bd9Sstevel@tonic-gate /* 75287c478bd9Sstevel@tonic-gate * Search the list for a node of interest. 75297c478bd9Sstevel@tonic-gate */ 75307c478bd9Sstevel@tonic-gate np = uu_list_next(rc_notify_list, me); 75317c478bd9Sstevel@tonic-gate while (np != NULL && !rc_notify_info_interested(rnip, np)) { 75327c478bd9Sstevel@tonic-gate rc_notify_t *next = uu_list_next(rc_notify_list, np); 75337c478bd9Sstevel@tonic-gate 75347c478bd9Sstevel@tonic-gate if (am_first_info) { 75357c478bd9Sstevel@tonic-gate if (np->rcn_info) { 75367c478bd9Sstevel@tonic-gate /* 75377c478bd9Sstevel@tonic-gate * Passing another client -- stop 75387c478bd9Sstevel@tonic-gate * cleaning up notifications 75397c478bd9Sstevel@tonic-gate */ 75407c478bd9Sstevel@tonic-gate am_first_info = 0; 75417c478bd9Sstevel@tonic-gate } else { 75427c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np); 75437c478bd9Sstevel@tonic-gate } 75447c478bd9Sstevel@tonic-gate } 75457c478bd9Sstevel@tonic-gate np = next; 75467c478bd9Sstevel@tonic-gate } 75477c478bd9Sstevel@tonic-gate 75487c478bd9Sstevel@tonic-gate /* 75497c478bd9Sstevel@tonic-gate * Nothing of interest -- wait for notification 75507c478bd9Sstevel@tonic-gate */ 75517c478bd9Sstevel@tonic-gate if (np == NULL) { 75527c478bd9Sstevel@tonic-gate rnip->rni_waiters++; 75537c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, 75547c478bd9Sstevel@tonic-gate &rc_pg_notify_lock); 75557c478bd9Sstevel@tonic-gate rnip->rni_waiters--; 75567c478bd9Sstevel@tonic-gate continue; 75577c478bd9Sstevel@tonic-gate } 75587c478bd9Sstevel@tonic-gate 75597c478bd9Sstevel@tonic-gate /* 75607c478bd9Sstevel@tonic-gate * found something to report -- move myself after the 75617c478bd9Sstevel@tonic-gate * notification and process it. 75627c478bd9Sstevel@tonic-gate */ 75637c478bd9Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me); 75647c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_list, np, me); 75657c478bd9Sstevel@tonic-gate 75667c478bd9Sstevel@tonic-gate if ((ndp = np->rcn_delete) != NULL) { 75677c478bd9Sstevel@tonic-gate (void) strlcpy(outp, ndp->rnd_fmri, sz); 75687c478bd9Sstevel@tonic-gate if (am_first_info) 75697c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np); 75707c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 75717c478bd9Sstevel@tonic-gate rc_node_clear(out, 0); 75727c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 75737c478bd9Sstevel@tonic-gate } 75747c478bd9Sstevel@tonic-gate 75757c478bd9Sstevel@tonic-gate nnp = np->rcn_node; 75767c478bd9Sstevel@tonic-gate assert(nnp != NULL); 75777c478bd9Sstevel@tonic-gate 75787c478bd9Sstevel@tonic-gate /* 75797c478bd9Sstevel@tonic-gate * We can't bump nnp's reference count without grabbing its 75807c478bd9Sstevel@tonic-gate * lock, and rc_pg_notify_lock is a leaf lock. So we 75817c478bd9Sstevel@tonic-gate * temporarily block all removals to keep nnp from 75827c478bd9Sstevel@tonic-gate * disappearing. 75837c478bd9Sstevel@tonic-gate */ 75847c478bd9Sstevel@tonic-gate rc_notify_in_use++; 75857c478bd9Sstevel@tonic-gate assert(rc_notify_in_use > 0); 75867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 75877c478bd9Sstevel@tonic-gate 75887c478bd9Sstevel@tonic-gate rc_node_assign(out, nnp); 75897c478bd9Sstevel@tonic-gate 75907c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 75917c478bd9Sstevel@tonic-gate assert(rc_notify_in_use > 0); 75927c478bd9Sstevel@tonic-gate rc_notify_in_use--; 7593b5cbdab0STom Whitten 7594b5cbdab0STom Whitten if (am_first_info) { 7595b5cbdab0STom Whitten /* 7596b5cbdab0STom Whitten * While we had the lock dropped, another thread 7597b5cbdab0STom Whitten * may have also incremented rc_notify_in_use. We 7598b5cbdab0STom Whitten * need to make sure that we're back to 0 before 7599b5cbdab0STom Whitten * removing the node. 7600b5cbdab0STom Whitten */ 7601b5cbdab0STom Whitten while (rc_notify_in_use) { 7602b5cbdab0STom Whitten (void) pthread_cond_wait(&rc_pg_notify_cv, 7603b5cbdab0STom Whitten &rc_pg_notify_lock); 7604b5cbdab0STom Whitten } 76057c478bd9Sstevel@tonic-gate rc_notify_remove_locked(np); 7606b5cbdab0STom Whitten } 76077c478bd9Sstevel@tonic-gate if (rc_notify_in_use == 0) 76087c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv); 76097c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 76107c478bd9Sstevel@tonic-gate 76117c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 76127c478bd9Sstevel@tonic-gate } 76137c478bd9Sstevel@tonic-gate /* 76147c478bd9Sstevel@tonic-gate * If we're the last one out, let people know it's clear. 76157c478bd9Sstevel@tonic-gate */ 76167c478bd9Sstevel@tonic-gate if (rnip->rni_waiters == 0) 76177c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv); 76187c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 76197c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_DONE); 76207c478bd9Sstevel@tonic-gate } 76217c478bd9Sstevel@tonic-gate 76227c478bd9Sstevel@tonic-gate static void 76237c478bd9Sstevel@tonic-gate rc_notify_info_reset(rc_notify_info_t *rnip) 76247c478bd9Sstevel@tonic-gate { 76257c478bd9Sstevel@tonic-gate int i; 76267c478bd9Sstevel@tonic-gate 76277c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 76287c478bd9Sstevel@tonic-gate if (rnip->rni_flags & RC_NOTIFY_ACTIVE) 76297c478bd9Sstevel@tonic-gate rc_notify_info_remove_locked(rnip); 76307c478bd9Sstevel@tonic-gate assert(!(rnip->rni_flags & (RC_NOTIFY_DRAIN | RC_NOTIFY_EMPTYING))); 76317c478bd9Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_EMPTYING; 76327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 76337c478bd9Sstevel@tonic-gate 76347c478bd9Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) { 76357c478bd9Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) { 76367c478bd9Sstevel@tonic-gate free((void *)rnip->rni_namelist[i]); 76377c478bd9Sstevel@tonic-gate rnip->rni_namelist[i] = NULL; 76387c478bd9Sstevel@tonic-gate } 76397c478bd9Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) { 76407c478bd9Sstevel@tonic-gate free((void *)rnip->rni_typelist[i]); 76417c478bd9Sstevel@tonic-gate rnip->rni_typelist[i] = NULL; 76427c478bd9Sstevel@tonic-gate } 76437c478bd9Sstevel@tonic-gate } 76447c478bd9Sstevel@tonic-gate 76457c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock); 76467c478bd9Sstevel@tonic-gate rnip->rni_flags &= ~RC_NOTIFY_EMPTYING; 76477c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock); 76487c478bd9Sstevel@tonic-gate } 76497c478bd9Sstevel@tonic-gate 76507c478bd9Sstevel@tonic-gate void 76517c478bd9Sstevel@tonic-gate rc_notify_info_fini(rc_notify_info_t *rnip) 76527c478bd9Sstevel@tonic-gate { 76537c478bd9Sstevel@tonic-gate rc_notify_info_reset(rnip); 76547c478bd9Sstevel@tonic-gate 76557c478bd9Sstevel@tonic-gate uu_list_node_fini(rnip, &rnip->rni_list_node, rc_notify_info_pool); 76567c478bd9Sstevel@tonic-gate uu_list_node_fini(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node, 76577c478bd9Sstevel@tonic-gate rc_notify_pool); 76587c478bd9Sstevel@tonic-gate } 7659