10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53179Sjeanm * Common Development and Distribution License (the "License").
63179Sjeanm * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
215040Swesolows
220Sstevel@tonic-gate /*
2312273SCasper.Dik@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
277266Sbustos * rc_node.c - In-memory SCF object management
287266Sbustos *
297266Sbustos * This layer manages the in-memory cache (the Repository Cache) of SCF
307266Sbustos * data. Read requests are usually satisfied from here, but may require
317266Sbustos * load calls to the "object" layer. Modify requests always write-through
327266Sbustos * to the object layer.
330Sstevel@tonic-gate *
347266Sbustos * SCF data comprises scopes, services, instances, snapshots, snaplevels,
357266Sbustos * property groups, properties, and property values. All but the last are
367266Sbustos * known here as "entities" and are represented by rc_node_t data
377266Sbustos * structures. (Property values are kept in the rn_values member of the
387266Sbustos * respective property, not as separate objects.) All entities besides
397266Sbustos * the "localhost" scope have some entity as a parent, and therefore form
407266Sbustos * a tree.
410Sstevel@tonic-gate *
420Sstevel@tonic-gate * The entity tree is rooted at rc_scope, which rc_node_init() initializes to
430Sstevel@tonic-gate * the "localhost" scope. The tree is filled in from the database on-demand
447266Sbustos * by rc_node_fill_children().
457266Sbustos *
467266Sbustos * rc_node_t's are also placed in the cache_hash[] hash table, for rapid
477266Sbustos * lookup.
480Sstevel@tonic-gate *
497266Sbustos * Multiple threads may service client requests, so access to each
507266Sbustos * rc_node_t is synchronized by its rn_lock member. Some fields are
517266Sbustos * protected by bits in the rn_flags field instead, to support operations
527266Sbustos * which need to drop rn_lock, for example to respect locking order. Such
537266Sbustos * flags should be manipulated with the rc_node_{hold,rele}_flag()
547266Sbustos * functions.
550Sstevel@tonic-gate *
567266Sbustos * We track references to nodes to tell when they can be free()d. rn_refs
577266Sbustos * should be incremented with rc_node_hold() on the creation of client
587266Sbustos * references (rc_node_ptr_t's and rc_iter_t's). rn_erefs ("ephemeral
597266Sbustos * references") should be incremented when a pointer is read into a local
607266Sbustos * variable of a thread, with rc_node_hold_ephemeral_locked(). This
617266Sbustos * hasn't been fully implemented, however, so rc_node_rele() tolerates
627266Sbustos * rn_erefs being 0. Some code which predates rn_erefs counts ephemeral
637266Sbustos * references in rn_refs. Other references are tracked by the
647266Sbustos * rn_other_refs field and the RC_NODE_DEAD, RC_NODE_IN_PARENT,
657266Sbustos * RC_NODE_OLD, and RC_NODE_ON_FORMER flags.
660Sstevel@tonic-gate *
670Sstevel@tonic-gate * Locking rules: To dereference an rc_node_t * (usually to lock it), you must
680Sstevel@tonic-gate * have a hold (rc_node_hold()) on it or otherwise be sure that it hasn't been
690Sstevel@tonic-gate * rc_node_destroy()ed (hold a lock on its parent or child, hold a flag,
700Sstevel@tonic-gate * etc.). Once you have locked an rc_node_t you must check its rn_flags for
710Sstevel@tonic-gate * RC_NODE_DEAD before you can use it. This is usually done with the
720Sstevel@tonic-gate * rc_node_{wait,hold}_flag() functions (often via the rc_node_check_*()
730Sstevel@tonic-gate * functions & RC_NODE_*() macros), which fail if the object has died.
740Sstevel@tonic-gate *
757266Sbustos * When a transactional node (property group or snapshot) is updated,
767266Sbustos * a new node takes the place of the old node in the global hash and the
777266Sbustos * old node is hung off of the rn_former list of the new node. At the
787266Sbustos * same time, all of its children have their rn_parent_ref pointer set,
797266Sbustos * and any holds they have are reflected in the old node's rn_other_refs
807266Sbustos * count. This is automatically kept up to date until the final reference
817266Sbustos * to the subgraph is dropped, at which point the node is unrefed and
827266Sbustos * destroyed, along with all of its children.
837266Sbustos *
845040Swesolows * Because name service lookups may take a long time and, more importantly
855040Swesolows * may trigger additional accesses to the repository, perm_granted() must be
865040Swesolows * called without holding any locks.
875040Swesolows *
880Sstevel@tonic-gate * An ITER_START for a non-ENTITY_VALUE induces an rc_node_fill_children()
890Sstevel@tonic-gate * call via rc_node_setup_iter() to populate the rn_children uu_list of the
900Sstevel@tonic-gate * rc_node_t * in question and a call to uu_list_walk_start() on that list. For
910Sstevel@tonic-gate * ITER_READ, rc_iter_next() uses uu_list_walk_next() to find the next
920Sstevel@tonic-gate * apropriate child.
930Sstevel@tonic-gate *
940Sstevel@tonic-gate * An ITER_START for an ENTITY_VALUE makes sure the node has its values
950Sstevel@tonic-gate * filled, and sets up the iterator. An ITER_READ_VALUE just copies out
960Sstevel@tonic-gate * the proper values and updates the offset information.
970Sstevel@tonic-gate *
980Sstevel@tonic-gate * To allow aliases, snapshots are implemented with a level of indirection.
990Sstevel@tonic-gate * A snapshot rc_node_t has a snapid which refers to an rc_snapshot_t in
1000Sstevel@tonic-gate * snapshot.c which contains the authoritative snaplevel information. The
1010Sstevel@tonic-gate * snapid is "assigned" by rc_attach_snapshot().
1020Sstevel@tonic-gate *
1030Sstevel@tonic-gate * We provide the client layer with rc_node_ptr_t's to reference objects.
1040Sstevel@tonic-gate * Objects referred to by them are automatically held & released by
1050Sstevel@tonic-gate * rc_node_assign() & rc_node_clear(). The RC_NODE_PTR_*() macros are used at
1060Sstevel@tonic-gate * client.c entry points to read the pointers. They fetch the pointer to the
1070Sstevel@tonic-gate * object, return (from the function) if it is dead, and lock, hold, or hold
1080Sstevel@tonic-gate * a flag of the object.
1090Sstevel@tonic-gate */
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate * Permission checking is authorization-based: some operations may only
1130Sstevel@tonic-gate * proceed if the user has been assigned at least one of a set of
1140Sstevel@tonic-gate * authorization strings. The set of enabling authorizations depends on the
1150Sstevel@tonic-gate * operation and the target object. The set of authorizations assigned to
11612273SCasper.Dik@Sun.COM * a user is determined by an algorithm defined in libsecdb.
1170Sstevel@tonic-gate *
1180Sstevel@tonic-gate * The fastest way to decide whether the two sets intersect is by entering the
1190Sstevel@tonic-gate * strings into a hash table and detecting collisions, which takes linear time
1200Sstevel@tonic-gate * in the total size of the sets. Except for the authorization patterns which
1210Sstevel@tonic-gate * may be assigned to users, which without advanced pattern-matching
1220Sstevel@tonic-gate * algorithms will take O(n) in the number of enabling authorizations, per
1230Sstevel@tonic-gate * pattern.
1240Sstevel@tonic-gate *
1250Sstevel@tonic-gate * We can achieve some practical speed-ups by noting that if we enter all of
1260Sstevel@tonic-gate * the authorizations from one of the sets into the hash table we can merely
1270Sstevel@tonic-gate * check the elements of the second set for existence without adding them.
1280Sstevel@tonic-gate * This reduces memory requirements and hash table clutter. The enabling set
1290Sstevel@tonic-gate * is well suited for this because it is internal to configd (for now, at
1300Sstevel@tonic-gate * least). Combine this with short-circuiting and we can even minimize the
1310Sstevel@tonic-gate * number of queries to the security databases (user_attr & prof_attr).
1320Sstevel@tonic-gate *
1330Sstevel@tonic-gate * To force this usage onto clients we provide functions for adding
1340Sstevel@tonic-gate * authorizations to the enabling set of a permission context structure
1350Sstevel@tonic-gate * (perm_add_*()) and one to decide whether the the user associated with the
1360Sstevel@tonic-gate * current door call client possesses any of them (perm_granted()).
1370Sstevel@tonic-gate *
1380Sstevel@tonic-gate * At some point, a generic version of this should move to libsecdb.
1395777Stw21770 *
1405777Stw21770 * While entering the enabling strings into the hash table, we keep track
1415777Stw21770 * of which is the most specific for use in generating auditing events.
1425777Stw21770 * See the "Collecting the Authorization String" section of the "SMF Audit
1435777Stw21770 * Events" block comment below.
1440Sstevel@tonic-gate */
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate * Composition is the combination of sets of properties. The sets are ordered
1480Sstevel@tonic-gate * and properties in higher sets obscure properties of the same name in lower
1490Sstevel@tonic-gate * sets. Here we present a composed view of an instance's properties as the
1500Sstevel@tonic-gate * union of its properties and its service's properties. Similarly the
1510Sstevel@tonic-gate * properties of snaplevels are combined to form a composed view of the
1520Sstevel@tonic-gate * properties of a snapshot (which should match the composed view of the
1530Sstevel@tonic-gate * properties of the instance when the snapshot was taken).
1540Sstevel@tonic-gate *
1550Sstevel@tonic-gate * In terms of the client interface, the client may request that a property
1560Sstevel@tonic-gate * group iterator for an instance or snapshot be composed. Property groups
1570Sstevel@tonic-gate * traversed by such an iterator may not have the target entity as a parent.
1580Sstevel@tonic-gate * Similarly, the properties traversed by a property iterator for those
1590Sstevel@tonic-gate * property groups may not have the property groups iterated as parents.
1600Sstevel@tonic-gate *
1610Sstevel@tonic-gate * Implementation requires that iterators for instances and snapshots be
1620Sstevel@tonic-gate * composition-savvy, and that we have a "composed property group" entity
1630Sstevel@tonic-gate * which represents the composition of a number of property groups. Iteration
1640Sstevel@tonic-gate * over "composed property groups" yields properties which may have different
1650Sstevel@tonic-gate * parents, but for all other operations a composed property group behaves
1660Sstevel@tonic-gate * like the top-most property group it represents.
1670Sstevel@tonic-gate *
1680Sstevel@tonic-gate * The implementation is based on the rn_cchain[] array of rc_node_t pointers
1690Sstevel@tonic-gate * in rc_node_t. For instances, the pointers point to the instance and its
1700Sstevel@tonic-gate * parent service. For snapshots they point to the child snaplevels, and for
1710Sstevel@tonic-gate * composed property groups they point to property groups. A composed
1720Sstevel@tonic-gate * iterator carries an index into rn_cchain[]. Thus most of the magic ends up
1730Sstevel@tonic-gate * int the rc_iter_*() code.
1740Sstevel@tonic-gate */
1755777Stw21770 /*
1765777Stw21770 * SMF Audit Events:
1775777Stw21770 * ================
1785777Stw21770 *
1795777Stw21770 * To maintain security, SMF generates audit events whenever
1805777Stw21770 * privileged operations are attempted. See the System Administration
1815777Stw21770 * Guide:Security Services answerbook for a discussion of the Solaris
1825777Stw21770 * audit system.
1835777Stw21770 *
1845777Stw21770 * The SMF audit event codes are defined in adt_event.h by symbols
1855777Stw21770 * starting with ADT_smf_ and are described in audit_event.txt. The
1865777Stw21770 * audit record structures are defined in the SMF section of adt.xml.
1875777Stw21770 * adt.xml is used to automatically generate adt_event.h which
1885777Stw21770 * contains the definitions that we code to in this file. For the
1895777Stw21770 * most part the audit events map closely to actions that you would
1905777Stw21770 * perform with svcadm or svccfg, but there are some special cases
1915777Stw21770 * which we'll discuss later.
1925777Stw21770 *
1935777Stw21770 * The software associated with SMF audit events falls into three
1945777Stw21770 * categories:
1955777Stw21770 * - collecting information to be written to the audit
1965777Stw21770 * records
1975777Stw21770 * - using the adt_* functions in
1985777Stw21770 * usr/src/lib/libbsm/common/adt.c to generate the audit
1995777Stw21770 * records.
2005777Stw21770 * - handling special cases
2015777Stw21770 *
2025777Stw21770 * Collecting Information:
2035777Stw21770 * ----------------------
2045777Stw21770 *
2055777Stw21770 * Most all of the audit events require the FMRI of the affected
2065777Stw21770 * object and the authorization string that was used. The one
2075777Stw21770 * exception is ADT_smf_annotation which we'll talk about later.
2085777Stw21770 *
2095777Stw21770 * Collecting the FMRI:
2105777Stw21770 *
2115777Stw21770 * The rc_node structure has a member called rn_fmri which points to
2125777Stw21770 * its FMRI. This is initialized by a call to rc_node_build_fmri()
2135777Stw21770 * when the node's parent is established. The reason for doing it
2145777Stw21770 * at this time is that a node's FMRI is basically the concatenation
2155777Stw21770 * of the parent's FMRI and the node's name with the appropriate
2165777Stw21770 * decoration. rc_node_build_fmri() does this concatenation and
2175777Stw21770 * decorating. It is called from rc_node_link_child() and
2185777Stw21770 * rc_node_relink_child() where a node is linked to its parent.
2195777Stw21770 *
2205777Stw21770 * rc_node_get_fmri_or_fragment() is called to retrieve a node's FMRI
2215777Stw21770 * when it is needed. It returns rn_fmri if it is set. If the node
2225777Stw21770 * is at the top level, however, rn_fmri won't be set because it was
2235777Stw21770 * never linked to a parent. In this case,
2245777Stw21770 * rc_node_get_fmri_or_fragment() constructs an FMRI fragment based on
2255777Stw21770 * its node type and its name, rn_name.
2265777Stw21770 *
2275777Stw21770 * Collecting the Authorization String:
2285777Stw21770 *
2295777Stw21770 * Naturally, the authorization string is captured during the
2305777Stw21770 * authorization checking process. Acceptable authorization strings
2315777Stw21770 * are added to a permcheck_t hash table as noted in the section on
2325777Stw21770 * permission checking above. Once all entries have been added to the
2335777Stw21770 * hash table, perm_granted() is called. If the client is authorized,
2345777Stw21770 * perm_granted() returns with pc_auth_string of the permcheck_t
2355777Stw21770 * structure pointing to the authorization string.
2365777Stw21770 *
2375777Stw21770 * This works fine if the client is authorized, but what happens if
2385777Stw21770 * the client is not authorized? We need to report the required
2395777Stw21770 * authorization string. This is the authorization that would have
2405777Stw21770 * been used if permission had been granted. perm_granted() will
2415777Stw21770 * find no match, so it needs to decide which string in the hash
2425777Stw21770 * table to use as the required authorization string. It needs to do
2435777Stw21770 * this, because configd is still going to generate an event. A
2445777Stw21770 * design decision was made to use the most specific authorization
2455777Stw21770 * in the hash table. The pc_auth_type enum designates the
2465777Stw21770 * specificity of an authorization string. For example, an
2475777Stw21770 * authorization string that is declared in an instance PG is more
2485777Stw21770 * specific than one that is declared in a service PG.
2495777Stw21770 *
2505777Stw21770 * The pc_add() function keeps track of the most specific
2515777Stw21770 * authorization in the hash table. It does this using the
2525777Stw21770 * pc_specific and pc_specific_type members of the permcheck
2535777Stw21770 * structure. pc_add() updates these members whenever a more
2545777Stw21770 * specific authorization string is added to the hash table. Thus, if
2555777Stw21770 * an authorization match is not found, perm_granted() will return
2565777Stw21770 * with pc_auth_string in the permcheck_t pointing to the string that
2575777Stw21770 * is referenced by pc_specific.
2585777Stw21770 *
2595777Stw21770 * Generating the Audit Events:
2605777Stw21770 * ===========================
2615777Stw21770 *
2625777Stw21770 * As the functions in this file process requests for clients of
2635777Stw21770 * configd, they gather the information that is required for an audit
2645777Stw21770 * event. Eventually, the request processing gets to the point where
2655777Stw21770 * the authorization is rejected or to the point where the requested
2665777Stw21770 * action was attempted. At these two points smf_audit_event() is
2675777Stw21770 * called.
2685777Stw21770 *
2695777Stw21770 * smf_audit_event() takes 4 parameters:
2705777Stw21770 * - the event ID which is one of the ADT_smf_* symbols from
2715777Stw21770 * adt_event.h.
2725777Stw21770 * - status to pass to adt_put_event()
2735777Stw21770 * - return value to pass to adt_put_event()
2745777Stw21770 * - the event data (see audit_event_data structure)
2755777Stw21770 *
2765777Stw21770 * All interactions with the auditing software require an audit
2775777Stw21770 * session. We use one audit session per configd client. We keep
2785777Stw21770 * track of the audit session in the repcache_client structure.
2795777Stw21770 * smf_audit_event() calls get_audit_session() to get the session
2805777Stw21770 * pointer.
2815777Stw21770 *
2825777Stw21770 * smf_audit_event() then calls adt_alloc_event() to allocate an
2835777Stw21770 * adt_event_data union which is defined in adt_event.h, copies the
2845777Stw21770 * data into the appropriate members of the union and calls
2855777Stw21770 * adt_put_event() to generate the event.
2865777Stw21770 *
2875777Stw21770 * Special Cases:
2885777Stw21770 * =============
2895777Stw21770 *
2905777Stw21770 * There are three major types of special cases:
2915777Stw21770 *
2925777Stw21770 * - gathering event information for each action in a
2935777Stw21770 * transaction
2945777Stw21770 * - Higher level events represented by special property
2955777Stw21770 * group/property name combinations. Many of these are
2965777Stw21770 * restarter actions.
2975777Stw21770 * - ADT_smf_annotation event
2985777Stw21770 *
2995777Stw21770 * Processing Transaction Actions:
3005777Stw21770 * ------------------------------
3015777Stw21770 *
3025777Stw21770 * A transaction can contain multiple actions to modify, create or
3035777Stw21770 * delete one or more properties. We need to capture information so
3045777Stw21770 * that we can generate an event for each property action. The
3055777Stw21770 * transaction information is stored in a tx_commmit_data_t, and
3065777Stw21770 * object.c provides accessor functions to retrieve data from this
3075777Stw21770 * structure. rc_tx_commit() obtains a tx_commit_data_t by calling
3085777Stw21770 * tx_commit_data_new() and passes this to object_tx_commit() to
3095777Stw21770 * commit the transaction. Then we call generate_property_events() to
3105777Stw21770 * generate an audit event for each property action.
3115777Stw21770 *
3125777Stw21770 * Special Properties:
3135777Stw21770 * ------------------
3145777Stw21770 *
3155777Stw21770 * There are combinations of property group/property name that are special.
3165777Stw21770 * They are special because they have specific meaning to startd. startd
3175777Stw21770 * interprets them in a service-independent fashion.
3185777Stw21770 * restarter_actions/refresh and general/enabled are two examples of these.
3195777Stw21770 * A special event is generated for these properties in addition to the
3205777Stw21770 * regular property event described in the previous section. The special
3215777Stw21770 * properties are declared as an array of audit_special_prop_item
3225777Stw21770 * structures at special_props_list in rc_node.c.
3235777Stw21770 *
3245777Stw21770 * In the previous section, we mentioned the
3255777Stw21770 * generate_property_event() function that generates an event for
3265777Stw21770 * every property action. Before generating the event,
3275777Stw21770 * generate_property_event() calls special_property_event().
3285777Stw21770 * special_property_event() checks to see if the action involves a
3295777Stw21770 * special property. If it does, it generates a special audit
3305777Stw21770 * event.
3315777Stw21770 *
3325777Stw21770 * ADT_smf_annotation event:
3335777Stw21770 * ------------------------
3345777Stw21770 *
3355777Stw21770 * This is a special event unlike any other. It allows the svccfg
3365777Stw21770 * program to store an annotation in the event log before a series
3375777Stw21770 * of transactions is processed. It is used with the import and
3385777Stw21770 * apply svccfg commands. svccfg uses the rep_protocol_annotation
3395777Stw21770 * message to pass the operation (import or apply) and the file name
3405777Stw21770 * to configd. The set_annotation() function in client.c stores
3415777Stw21770 * these away in the a repcache_client structure. The address of
3425777Stw21770 * this structure is saved in the thread_info structure.
3435777Stw21770 *
3445777Stw21770 * Before it generates any events, smf_audit_event() calls
3455777Stw21770 * smf_annotation_event(). smf_annotation_event() calls
3465777Stw21770 * client_annotation_needed() which is defined in client.c. If an
3475777Stw21770 * annotation is needed client_annotation_needed() returns the
3485777Stw21770 * operation and filename strings that were saved from the
3495777Stw21770 * rep_protocol_annotation message. smf_annotation_event() then
3505777Stw21770 * generates the ADT_smf_annotation event.
3515777Stw21770 */
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate #include <assert.h>
3540Sstevel@tonic-gate #include <atomic.h>
3555777Stw21770 #include <bsm/adt_event.h>
3560Sstevel@tonic-gate #include <errno.h>
3570Sstevel@tonic-gate #include <libuutil.h>
3580Sstevel@tonic-gate #include <libscf.h>
3590Sstevel@tonic-gate #include <libscf_priv.h>
3600Sstevel@tonic-gate #include <pthread.h>
3616059Sgww #include <pwd.h>
3620Sstevel@tonic-gate #include <stdio.h>
3630Sstevel@tonic-gate #include <stdlib.h>
3640Sstevel@tonic-gate #include <strings.h>
3650Sstevel@tonic-gate #include <sys/types.h>
3665777Stw21770 #include <syslog.h>
3670Sstevel@tonic-gate #include <unistd.h>
36812273SCasper.Dik@Sun.COM #include <secdb.h>
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate #include "configd.h"
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate #define AUTH_PREFIX "solaris.smf."
3730Sstevel@tonic-gate #define AUTH_MANAGE AUTH_PREFIX "manage"
3740Sstevel@tonic-gate #define AUTH_MODIFY AUTH_PREFIX "modify"
3750Sstevel@tonic-gate #define AUTH_MODIFY_PREFIX AUTH_MODIFY "."
3760Sstevel@tonic-gate #define AUTH_PG_ACTIONS SCF_PG_RESTARTER_ACTIONS
3770Sstevel@tonic-gate #define AUTH_PG_ACTIONS_TYPE SCF_PG_RESTARTER_ACTIONS_TYPE
3780Sstevel@tonic-gate #define AUTH_PG_GENERAL SCF_PG_GENERAL
3790Sstevel@tonic-gate #define AUTH_PG_GENERAL_TYPE SCF_PG_GENERAL_TYPE
3800Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR SCF_PG_GENERAL_OVR
3810Sstevel@tonic-gate #define AUTH_PG_GENERAL_OVR_TYPE SCF_PG_GENERAL_OVR_TYPE
3820Sstevel@tonic-gate #define AUTH_PROP_ACTION "action_authorization"
3830Sstevel@tonic-gate #define AUTH_PROP_ENABLED "enabled"
3840Sstevel@tonic-gate #define AUTH_PROP_MODIFY "modify_authorization"
3850Sstevel@tonic-gate #define AUTH_PROP_VALUE "value_authorization"
3865040Swesolows #define AUTH_PROP_READ "read_authorization"
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate #define MAX_VALID_CHILDREN 3
3890Sstevel@tonic-gate
3905777Stw21770 /*
3915777Stw21770 * The ADT_smf_* symbols may not be defined on the build machine. Because
3925777Stw21770 * of this, we do not want to compile the _smf_aud_event() function when
3935777Stw21770 * doing native builds.
3945777Stw21770 */
3955777Stw21770 #ifdef NATIVE_BUILD
3965777Stw21770 #define smf_audit_event(i, s, r, d)
3975777Stw21770 #else
3985777Stw21770 #define smf_audit_event(i, s, r, d) _smf_audit_event(i, s, r, d)
3995777Stw21770 #endif /* NATIVE_BUILD */
4005777Stw21770
4010Sstevel@tonic-gate typedef struct rc_type_info {
4020Sstevel@tonic-gate uint32_t rt_type; /* matches array index */
4030Sstevel@tonic-gate uint32_t rt_num_ids;
4040Sstevel@tonic-gate uint32_t rt_name_flags;
4050Sstevel@tonic-gate uint32_t rt_valid_children[MAX_VALID_CHILDREN];
4060Sstevel@tonic-gate } rc_type_info_t;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate #define RT_NO_NAME -1U
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate static rc_type_info_t rc_types[] = {
4110Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_NONE, 0, RT_NO_NAME},
4120Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SCOPE, 0, 0,
4130Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, REP_PROTOCOL_ENTITY_SCOPE}},
4140Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SERVICE, 0, UU_NAME_DOMAIN | UU_NAME_PATH,
4150Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4160Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_INSTANCE, 1, UU_NAME_DOMAIN,
4170Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4180Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPSHOT, 2, UU_NAME_DOMAIN,
4190Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4200Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_SNAPLEVEL, 4, RT_NO_NAME,
4210Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP}},
4220Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTYGRP, 5, UU_NAME_DOMAIN,
4230Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}},
4240Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_CPROPERTYGRP, 0, UU_NAME_DOMAIN,
4250Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY}},
4260Sstevel@tonic-gate {REP_PROTOCOL_ENTITY_PROPERTY, 7, UU_NAME_DOMAIN},
4270Sstevel@tonic-gate {-1UL}
4280Sstevel@tonic-gate };
4290Sstevel@tonic-gate #define NUM_TYPES ((sizeof (rc_types) / sizeof (*rc_types)))
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate /* Element of a permcheck_t hash table. */
4320Sstevel@tonic-gate struct pc_elt {
4330Sstevel@tonic-gate struct pc_elt *pce_next;
4340Sstevel@tonic-gate char pce_auth[1];
4350Sstevel@tonic-gate };
4360Sstevel@tonic-gate
4375777Stw21770 /*
4385777Stw21770 * If an authorization fails, we must decide which of the elements in the
4395777Stw21770 * permcheck hash table to use in the audit event. That is to say of all
4405777Stw21770 * the strings in the hash table, we must choose one and use it in the audit
4415777Stw21770 * event. It is desirable to use the most specific string in the audit
4425777Stw21770 * event.
4435777Stw21770 *
4445777Stw21770 * The pc_auth_type specifies the types (sources) of authorization
4455777Stw21770 * strings. The enum is ordered in increasing specificity.
4465777Stw21770 */
4475777Stw21770 typedef enum pc_auth_type {
4485777Stw21770 PC_AUTH_NONE = 0, /* no auth string available. */
4495777Stw21770 PC_AUTH_SMF, /* strings coded into SMF. */
4505777Stw21770 PC_AUTH_SVC, /* strings specified in PG of a service. */
4515777Stw21770 PC_AUTH_INST /* strings specified in PG of an instance. */
4525777Stw21770 } pc_auth_type_t;
4535777Stw21770
4548497SThomas.Whitten@Sun.COM /*
4558497SThomas.Whitten@Sun.COM * The following enum is used to represent the results of the checks to see
4568497SThomas.Whitten@Sun.COM * if the client has the appropriate permissions to perform an action.
4578497SThomas.Whitten@Sun.COM */
4588497SThomas.Whitten@Sun.COM typedef enum perm_status {
4598497SThomas.Whitten@Sun.COM PERM_DENIED = 0, /* Permission denied. */
4608497SThomas.Whitten@Sun.COM PERM_GRANTED, /* Client has authorizations. */
4618497SThomas.Whitten@Sun.COM PERM_GONE, /* Door client went away. */
4628497SThomas.Whitten@Sun.COM PERM_FAIL /* Generic failure. e.g. resources */
4638497SThomas.Whitten@Sun.COM } perm_status_t;
4648497SThomas.Whitten@Sun.COM
4650Sstevel@tonic-gate /* An authorization set hash table. */
4660Sstevel@tonic-gate typedef struct {
4670Sstevel@tonic-gate struct pc_elt **pc_buckets;
4680Sstevel@tonic-gate uint_t pc_bnum; /* number of buckets */
4690Sstevel@tonic-gate uint_t pc_enum; /* number of elements */
4705777Stw21770 struct pc_elt *pc_specific; /* most specific element */
4715777Stw21770 pc_auth_type_t pc_specific_type; /* type of pc_specific */
4725777Stw21770 char *pc_auth_string; /* authorization string */
4735777Stw21770 /* for audit events */
4740Sstevel@tonic-gate } permcheck_t;
4750Sstevel@tonic-gate
4765777Stw21770 /*
4775777Stw21770 * Structure for holding audit event data. Not all events use all members
4785777Stw21770 * of the structure.
4795777Stw21770 */
4805777Stw21770 typedef struct audit_event_data {
4815777Stw21770 char *ed_auth; /* authorization string. */
4825777Stw21770 char *ed_fmri; /* affected FMRI. */
4835777Stw21770 char *ed_snapname; /* name of snapshot. */
4845777Stw21770 char *ed_old_fmri; /* old fmri in attach case. */
4855777Stw21770 char *ed_old_name; /* old snapshot in attach case. */
4865777Stw21770 char *ed_type; /* prop. group or prop. type. */
4875777Stw21770 char *ed_prop_value; /* property value. */
4885777Stw21770 } audit_event_data_t;
4895777Stw21770
4905777Stw21770 /*
4915777Stw21770 * Pointer to function to do special processing to get audit event ID.
4925777Stw21770 * Audit event IDs are defined in /usr/include/bsm/adt_event.h. Function
4935777Stw21770 * returns 0 if ID successfully retrieved. Otherwise it returns -1.
4945777Stw21770 */
4955777Stw21770 typedef int (*spc_getid_fn_t)(tx_commit_data_t *, size_t, const char *,
4965777Stw21770 au_event_t *);
4975777Stw21770 static int general_enable_id(tx_commit_data_t *, size_t, const char *,
4985777Stw21770 au_event_t *);
4995777Stw21770
5000Sstevel@tonic-gate static uu_list_pool_t *rc_children_pool;
5010Sstevel@tonic-gate static uu_list_pool_t *rc_pg_notify_pool;
5020Sstevel@tonic-gate static uu_list_pool_t *rc_notify_pool;
5030Sstevel@tonic-gate static uu_list_pool_t *rc_notify_info_pool;
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate static rc_node_t *rc_scope;
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate static pthread_mutex_t rc_pg_notify_lock = PTHREAD_MUTEX_INITIALIZER;
5080Sstevel@tonic-gate static pthread_cond_t rc_pg_notify_cv = PTHREAD_COND_INITIALIZER;
5090Sstevel@tonic-gate static uint_t rc_notify_in_use; /* blocks removals */
5100Sstevel@tonic-gate
5115777Stw21770 /*
5125777Stw21770 * Some combinations of property group/property name require a special
5135777Stw21770 * audit event to be generated when there is a change.
5145777Stw21770 * audit_special_prop_item_t is used to specify these special cases. The
5155777Stw21770 * special_props_list array defines a list of these special properties.
5165777Stw21770 */
5175777Stw21770 typedef struct audit_special_prop_item {
5185777Stw21770 const char *api_pg_name; /* property group name. */
5195777Stw21770 const char *api_prop_name; /* property name. */
5205777Stw21770 au_event_t api_event_id; /* event id or 0. */
5215777Stw21770 spc_getid_fn_t api_event_func; /* function to get event id. */
5225777Stw21770 } audit_special_prop_item_t;
5235777Stw21770
5245777Stw21770 /*
5255777Stw21770 * Native builds are done using the build machine's standard include
5265777Stw21770 * files. These files may not yet have the definitions for the ADT_smf_*
5275777Stw21770 * symbols. Thus, we do not compile this table when doing native builds.
5285777Stw21770 */
5295777Stw21770 #ifndef NATIVE_BUILD
5305777Stw21770 /*
5315777Stw21770 * The following special_props_list array specifies property group/property
5325777Stw21770 * name combinations that have specific meaning to startd. A special event
5335777Stw21770 * is generated for these combinations in addition to the regular property
5345777Stw21770 * event.
5355777Stw21770 *
5365777Stw21770 * At run time this array gets sorted. See the call to qsort(3C) in
5375777Stw21770 * rc_node_init(). The array is sorted, so that bsearch(3C) can be used
5385777Stw21770 * to do lookups.
5395777Stw21770 */
5405777Stw21770 static audit_special_prop_item_t special_props_list[] = {
5415777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADED, ADT_smf_degrade,
5425777Stw21770 NULL},
5435777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_DEGRADE_IMMEDIATE,
5445777Stw21770 ADT_smf_immediate_degrade, NULL},
5455777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_OFF, ADT_smf_clear, NULL},
5465777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON,
5475777Stw21770 ADT_smf_maintenance, NULL},
5485777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMEDIATE,
5495777Stw21770 ADT_smf_immediate_maintenance, NULL},
5505777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_IMMTEMP,
5515777Stw21770 ADT_smf_immtmp_maintenance, NULL},
5525777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_MAINT_ON_TEMPORARY,
5535777Stw21770 ADT_smf_tmp_maintenance, NULL},
5545777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_REFRESH, ADT_smf_refresh, NULL},
5555777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTART, ADT_smf_restart, NULL},
5565777Stw21770 {SCF_PG_RESTARTER_ACTIONS, SCF_PROPERTY_RESTORE, ADT_smf_clear, NULL},
5575777Stw21770 {SCF_PG_OPTIONS, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
5585777Stw21770 {SCF_PG_OPTIONS_OVR, SCF_PROPERTY_MILESTONE, ADT_smf_milestone, NULL},
5595777Stw21770 {SCF_PG_GENERAL, SCF_PROPERTY_ENABLED, 0, general_enable_id},
5605777Stw21770 {SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 0, general_enable_id}
5615777Stw21770 };
5625777Stw21770 #define SPECIAL_PROP_COUNT (sizeof (special_props_list) /\
5635777Stw21770 sizeof (audit_special_prop_item_t))
5645777Stw21770 #endif /* NATIVE_BUILD */
5655777Stw21770
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * We support an arbitrary number of clients interested in events for certain
5680Sstevel@tonic-gate * types of changes. Each client is represented by an rc_notify_info_t, and
5690Sstevel@tonic-gate * all clients are chained onto the rc_notify_info_list.
5700Sstevel@tonic-gate *
5710Sstevel@tonic-gate * The rc_notify_list is the global notification list. Each entry is of
5720Sstevel@tonic-gate * type rc_notify_t, which is embedded in one of three other structures:
5730Sstevel@tonic-gate *
5740Sstevel@tonic-gate * rc_node_t property group update notification
5750Sstevel@tonic-gate * rc_notify_delete_t object deletion notification
5760Sstevel@tonic-gate * rc_notify_info_t notification clients
5770Sstevel@tonic-gate *
5780Sstevel@tonic-gate * Which type of object is determined by which pointer in the rc_notify_t is
5790Sstevel@tonic-gate * non-NULL.
5800Sstevel@tonic-gate *
5810Sstevel@tonic-gate * New notifications and clients are added to the end of the list.
5820Sstevel@tonic-gate * Notifications no-one is interested in are never added to the list.
5830Sstevel@tonic-gate *
5840Sstevel@tonic-gate * Clients use their position in the list to track which notifications they
5850Sstevel@tonic-gate * have not yet reported. As they process notifications, they move forward
5860Sstevel@tonic-gate * in the list past them. There is always a client at the beginning of the
5870Sstevel@tonic-gate * list -- as he moves past notifications, he removes them from the list and
5880Sstevel@tonic-gate * cleans them up.
5890Sstevel@tonic-gate *
5900Sstevel@tonic-gate * The rc_pg_notify_lock protects all notification state. The rc_pg_notify_cv
5910Sstevel@tonic-gate * is used for global signalling, and each client has a cv which he waits for
5920Sstevel@tonic-gate * events of interest on.
59312299Stom.whitten@oracle.com *
59412299Stom.whitten@oracle.com * rc_notify_in_use is used to protect rc_notify_list from deletions when
59512299Stom.whitten@oracle.com * the rc_pg_notify_lock is dropped. Specifically, rc_notify_info_wait()
59612299Stom.whitten@oracle.com * must drop the lock to call rc_node_assign(), and then it reacquires the
59712299Stom.whitten@oracle.com * lock. Deletions from rc_notify_list during this period are not
59812299Stom.whitten@oracle.com * allowed. Insertions do not matter, because they are always done at the
59912299Stom.whitten@oracle.com * end of the list.
6000Sstevel@tonic-gate */
6010Sstevel@tonic-gate static uu_list_t *rc_notify_info_list;
6020Sstevel@tonic-gate static uu_list_t *rc_notify_list;
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate #define HASH_SIZE 512
6050Sstevel@tonic-gate #define HASH_MASK (HASH_SIZE - 1)
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate #pragma align 64(cache_hash)
6080Sstevel@tonic-gate static cache_bucket_t cache_hash[HASH_SIZE];
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate #define CACHE_BUCKET(h) (&cache_hash[(h) & HASH_MASK])
6110Sstevel@tonic-gate
6127266Sbustos
6137266Sbustos static void rc_node_no_client_refs(rc_node_t *np);
6147266Sbustos
6157266Sbustos
6160Sstevel@tonic-gate static uint32_t
rc_node_hash(rc_node_lookup_t * lp)6170Sstevel@tonic-gate rc_node_hash(rc_node_lookup_t *lp)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate uint32_t type = lp->rl_type;
6200Sstevel@tonic-gate uint32_t backend = lp->rl_backend;
621471Shg115875 uint32_t mainid = lp->rl_main_id;
6220Sstevel@tonic-gate uint32_t *ids = lp->rl_ids;
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate rc_type_info_t *tp = &rc_types[type];
6250Sstevel@tonic-gate uint32_t num_ids;
6260Sstevel@tonic-gate uint32_t left;
6270Sstevel@tonic-gate uint32_t hash;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate assert(backend == BACKEND_TYPE_NORMAL ||
6300Sstevel@tonic-gate backend == BACKEND_TYPE_NONPERSIST);
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES);
6330Sstevel@tonic-gate num_ids = tp->rt_num_ids;
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate left = MAX_IDS - num_ids;
6360Sstevel@tonic-gate assert(num_ids <= MAX_IDS);
6370Sstevel@tonic-gate
638471Shg115875 hash = type * 7 + mainid * 5 + backend;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate while (num_ids-- > 0)
6410Sstevel@tonic-gate hash = hash * 11 + *ids++ * 7;
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate /*
6440Sstevel@tonic-gate * the rest should be zeroed
6450Sstevel@tonic-gate */
6460Sstevel@tonic-gate while (left-- > 0)
6470Sstevel@tonic-gate assert(*ids++ == 0);
6480Sstevel@tonic-gate
6490Sstevel@tonic-gate return (hash);
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate static int
rc_node_match(rc_node_t * np,rc_node_lookup_t * l)6530Sstevel@tonic-gate rc_node_match(rc_node_t *np, rc_node_lookup_t *l)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate rc_node_lookup_t *r = &np->rn_id;
6560Sstevel@tonic-gate rc_type_info_t *tp;
6570Sstevel@tonic-gate uint32_t type;
6580Sstevel@tonic-gate uint32_t num_ids;
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate if (r->rl_main_id != l->rl_main_id)
6610Sstevel@tonic-gate return (0);
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate type = r->rl_type;
6640Sstevel@tonic-gate if (type != l->rl_type)
6650Sstevel@tonic-gate return (0);
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate assert(type > 0 && type < NUM_TYPES);
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate tp = &rc_types[r->rl_type];
6700Sstevel@tonic-gate num_ids = tp->rt_num_ids;
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate assert(num_ids <= MAX_IDS);
6730Sstevel@tonic-gate while (num_ids-- > 0)
6740Sstevel@tonic-gate if (r->rl_ids[num_ids] != l->rl_ids[num_ids])
6750Sstevel@tonic-gate return (0);
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate return (1);
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate /*
6817266Sbustos * Register an ephemeral reference to np. This should be done while both
6827266Sbustos * the persistent reference from which the np pointer was read is locked
6837266Sbustos * and np itself is locked. This guarantees that another thread which
6847266Sbustos * thinks it has the last reference will yield without destroying the
6857266Sbustos * node.
6867266Sbustos */
6877266Sbustos static void
rc_node_hold_ephemeral_locked(rc_node_t * np)6887266Sbustos rc_node_hold_ephemeral_locked(rc_node_t *np)
6897266Sbustos {
6907266Sbustos assert(MUTEX_HELD(&np->rn_lock));
6917266Sbustos
6927266Sbustos ++np->rn_erefs;
6937266Sbustos }
6947266Sbustos
6957266Sbustos /*
6960Sstevel@tonic-gate * the "other" references on a node are maintained in an atomically
6970Sstevel@tonic-gate * updated refcount, rn_other_refs. This can be bumped from arbitrary
6980Sstevel@tonic-gate * context, and tracks references to a possibly out-of-date node's children.
6990Sstevel@tonic-gate *
7000Sstevel@tonic-gate * To prevent the node from disappearing between the final drop of
7010Sstevel@tonic-gate * rn_other_refs and the unref handling, rn_other_refs_held is bumped on
7020Sstevel@tonic-gate * 0->1 transitions and decremented (with the node lock held) on 1->0
7030Sstevel@tonic-gate * transitions.
7040Sstevel@tonic-gate */
7050Sstevel@tonic-gate static void
rc_node_hold_other(rc_node_t * np)7060Sstevel@tonic-gate rc_node_hold_other(rc_node_t *np)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, 1) == 1) {
7090Sstevel@tonic-gate atomic_add_32(&np->rn_other_refs_held, 1);
7100Sstevel@tonic-gate assert(np->rn_other_refs_held > 0);
7110Sstevel@tonic-gate }
7120Sstevel@tonic-gate assert(np->rn_other_refs > 0);
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate * No node locks may be held
7170Sstevel@tonic-gate */
7180Sstevel@tonic-gate static void
rc_node_rele_other(rc_node_t * np)7190Sstevel@tonic-gate rc_node_rele_other(rc_node_t *np)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate assert(np->rn_other_refs > 0);
7220Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs, -1) == 0) {
7230Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
7240Sstevel@tonic-gate assert(np->rn_other_refs_held > 0);
7250Sstevel@tonic-gate if (atomic_add_32_nv(&np->rn_other_refs_held, -1) == 0 &&
7267266Sbustos np->rn_refs == 0 && (np->rn_flags & RC_NODE_OLD)) {
7277266Sbustos /*
7287266Sbustos * This was the last client reference. Destroy
7297266Sbustos * any other references and free() the node.
7307266Sbustos */
7317266Sbustos rc_node_no_client_refs(np);
7327266Sbustos } else {
7330Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7347266Sbustos }
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate static void
rc_node_hold_locked(rc_node_t * np)7390Sstevel@tonic-gate rc_node_hold_locked(rc_node_t *np)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate if (np->rn_refs == 0 && (np->rn_flags & RC_NODE_PARENT_REF))
7440Sstevel@tonic-gate rc_node_hold_other(np->rn_parent_ref);
7450Sstevel@tonic-gate np->rn_refs++;
7460Sstevel@tonic-gate assert(np->rn_refs > 0);
7470Sstevel@tonic-gate }
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate static void
rc_node_hold(rc_node_t * np)7500Sstevel@tonic-gate rc_node_hold(rc_node_t *np)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
7530Sstevel@tonic-gate rc_node_hold_locked(np);
7540Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7550Sstevel@tonic-gate }
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate static void
rc_node_rele_locked(rc_node_t * np)7580Sstevel@tonic-gate rc_node_rele_locked(rc_node_t *np)
7590Sstevel@tonic-gate {
7600Sstevel@tonic-gate int unref = 0;
7610Sstevel@tonic-gate rc_node_t *par_ref = NULL;
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
7640Sstevel@tonic-gate assert(np->rn_refs > 0);
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate if (--np->rn_refs == 0) {
7670Sstevel@tonic-gate if (np->rn_flags & RC_NODE_PARENT_REF)
7680Sstevel@tonic-gate par_ref = np->rn_parent_ref;
7690Sstevel@tonic-gate
770294Sbustos /*
771294Sbustos * Composed property groups are only as good as their
772294Sbustos * references.
773294Sbustos */
774294Sbustos if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
775294Sbustos np->rn_flags |= RC_NODE_DEAD;
776294Sbustos
7770Sstevel@tonic-gate if ((np->rn_flags & (RC_NODE_DEAD|RC_NODE_OLD)) &&
7780Sstevel@tonic-gate np->rn_other_refs == 0 && np->rn_other_refs_held == 0)
7790Sstevel@tonic-gate unref = 1;
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7827266Sbustos if (unref) {
7837266Sbustos /*
7847266Sbustos * This was the last client reference. Destroy any other
7857266Sbustos * references and free() the node.
7867266Sbustos */
7877266Sbustos rc_node_no_client_refs(np);
7887266Sbustos } else {
7897266Sbustos /*
7907266Sbustos * rn_erefs can be 0 if we acquired the reference in
7917266Sbustos * a path which hasn't been updated to increment rn_erefs.
7927266Sbustos * When all paths which end here are updated, we should
7937266Sbustos * assert rn_erefs > 0 and always decrement it.
7947266Sbustos */
7957266Sbustos if (np->rn_erefs > 0)
7967266Sbustos --np->rn_erefs;
7970Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
7987266Sbustos }
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate if (par_ref != NULL)
8010Sstevel@tonic-gate rc_node_rele_other(par_ref);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate
8040Sstevel@tonic-gate void
rc_node_rele(rc_node_t * np)8050Sstevel@tonic-gate rc_node_rele(rc_node_t *np)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
8080Sstevel@tonic-gate rc_node_rele_locked(np);
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate static cache_bucket_t *
cache_hold(uint32_t h)8120Sstevel@tonic-gate cache_hold(uint32_t h)
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate cache_bucket_t *bp = CACHE_BUCKET(h);
8150Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock);
8160Sstevel@tonic-gate return (bp);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate static void
cache_release(cache_bucket_t * bp)8200Sstevel@tonic-gate cache_release(cache_bucket_t *bp)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate static rc_node_t *
cache_lookup_unlocked(cache_bucket_t * bp,rc_node_lookup_t * lp)8260Sstevel@tonic-gate cache_lookup_unlocked(cache_bucket_t *bp, rc_node_lookup_t *lp)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate uint32_t h = rc_node_hash(lp);
8290Sstevel@tonic-gate rc_node_t *np;
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8320Sstevel@tonic-gate assert(bp == CACHE_BUCKET(h));
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate for (np = bp->cb_head; np != NULL; np = np->rn_hash_next) {
8350Sstevel@tonic-gate if (np->rn_hash == h && rc_node_match(np, lp)) {
8360Sstevel@tonic-gate rc_node_hold(np);
8370Sstevel@tonic-gate return (np);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate
8410Sstevel@tonic-gate return (NULL);
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate static rc_node_t *
cache_lookup(rc_node_lookup_t * lp)8450Sstevel@tonic-gate cache_lookup(rc_node_lookup_t *lp)
8460Sstevel@tonic-gate {
8470Sstevel@tonic-gate uint32_t h;
8480Sstevel@tonic-gate cache_bucket_t *bp;
8490Sstevel@tonic-gate rc_node_t *np;
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate h = rc_node_hash(lp);
8520Sstevel@tonic-gate bp = cache_hold(h);
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate np = cache_lookup_unlocked(bp, lp);
8550Sstevel@tonic-gate
8560Sstevel@tonic-gate cache_release(bp);
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate return (np);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate static void
cache_insert_unlocked(cache_bucket_t * bp,rc_node_t * np)8620Sstevel@tonic-gate cache_insert_unlocked(cache_bucket_t *bp, rc_node_t *np)
8630Sstevel@tonic-gate {
8640Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8650Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id));
8660Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash));
8670Sstevel@tonic-gate
8680Sstevel@tonic-gate assert(np->rn_hash_next == NULL);
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate np->rn_hash_next = bp->cb_head;
8710Sstevel@tonic-gate bp->cb_head = np;
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate
8740Sstevel@tonic-gate static void
cache_remove_unlocked(cache_bucket_t * bp,rc_node_t * np)8750Sstevel@tonic-gate cache_remove_unlocked(cache_bucket_t *bp, rc_node_t *np)
8760Sstevel@tonic-gate {
8770Sstevel@tonic-gate rc_node_t **npp;
8780Sstevel@tonic-gate
8790Sstevel@tonic-gate assert(MUTEX_HELD(&bp->cb_lock));
8800Sstevel@tonic-gate assert(np->rn_hash == rc_node_hash(&np->rn_id));
8810Sstevel@tonic-gate assert(bp == CACHE_BUCKET(np->rn_hash));
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate for (npp = &bp->cb_head; *npp != NULL; npp = &(*npp)->rn_hash_next)
8840Sstevel@tonic-gate if (*npp == np)
8850Sstevel@tonic-gate break;
8860Sstevel@tonic-gate
8870Sstevel@tonic-gate assert(*npp == np);
8880Sstevel@tonic-gate *npp = np->rn_hash_next;
8890Sstevel@tonic-gate np->rn_hash_next = NULL;
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate * verify that the 'parent' type can have a child typed 'child'
8940Sstevel@tonic-gate * Fails with
8950Sstevel@tonic-gate * _INVALID_TYPE - argument is invalid
8960Sstevel@tonic-gate * _TYPE_MISMATCH - parent type cannot have children of type child
8970Sstevel@tonic-gate */
8980Sstevel@tonic-gate static int
rc_check_parent_child(uint32_t parent,uint32_t child)8990Sstevel@tonic-gate rc_check_parent_child(uint32_t parent, uint32_t child)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate int idx;
9020Sstevel@tonic-gate uint32_t type;
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate if (parent == 0 || parent >= NUM_TYPES ||
9050Sstevel@tonic-gate child == 0 || child >= NUM_TYPES)
9060Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate for (idx = 0; idx < MAX_VALID_CHILDREN; idx++) {
9090Sstevel@tonic-gate type = rc_types[parent].rt_valid_children[idx];
9100Sstevel@tonic-gate if (type == child)
9110Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate /*
9180Sstevel@tonic-gate * Fails with
9190Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
9200Sstevel@tonic-gate * _BAD_REQUEST - name is an invalid name for a node of type type
9210Sstevel@tonic-gate */
9220Sstevel@tonic-gate int
rc_check_type_name(uint32_t type,const char * name)9230Sstevel@tonic-gate rc_check_type_name(uint32_t type, const char *name)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate if (type == 0 || type >= NUM_TYPES)
9260Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_INVALID_TYPE); /* invalid types */
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate if (uu_check_name(name, rc_types[type].rt_name_flags) == -1)
9290Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9320Sstevel@tonic-gate }
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate static int
rc_check_pgtype_name(const char * name)9350Sstevel@tonic-gate rc_check_pgtype_name(const char *name)
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate if (uu_check_name(name, UU_NAME_DOMAIN) == -1)
9380Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9435777Stw21770 /*
9445777Stw21770 * rc_node_free_fmri should be called whenever a node loses its parent.
9455777Stw21770 * The reason is that the node's fmri string is built up by concatenating
9465777Stw21770 * its name to the parent's fmri. Thus, when the node no longer has a
9475777Stw21770 * parent, its fmri is no longer valid.
9485777Stw21770 */
9495777Stw21770 static void
rc_node_free_fmri(rc_node_t * np)9505777Stw21770 rc_node_free_fmri(rc_node_t *np)
9515777Stw21770 {
9525777Stw21770 if (np->rn_fmri != NULL) {
9535777Stw21770 free((void *)np->rn_fmri);
9545777Stw21770 np->rn_fmri = NULL;
9555777Stw21770 }
9565777Stw21770 }
9575777Stw21770
9585777Stw21770 /*
9595777Stw21770 * Concatenate the appropriate separator and the FMRI element to the base
9605777Stw21770 * FMRI string at fmri.
9615777Stw21770 *
9625777Stw21770 * Fails with
9635777Stw21770 * _TRUNCATED Not enough room in buffer at fmri.
9645777Stw21770 */
9655777Stw21770 static int
rc_concat_fmri_element(char * fmri,size_t bufsize,size_t * sz_out,const char * element,rep_protocol_entity_t type)9665777Stw21770 rc_concat_fmri_element(
9675777Stw21770 char *fmri, /* base fmri */
9685777Stw21770 size_t bufsize, /* size of buf at fmri */
9695777Stw21770 size_t *sz_out, /* receives result size. */
9705777Stw21770 const char *element, /* element name to concat */
9715777Stw21770 rep_protocol_entity_t type) /* type of element */
9725777Stw21770 {
9735777Stw21770 size_t actual;
9745777Stw21770 const char *name = element;
9755777Stw21770 int rc;
9765777Stw21770 const char *separator;
9775777Stw21770
9785777Stw21770 if (bufsize > 0)
9795777Stw21770 *sz_out = strlen(fmri);
9805777Stw21770 else
9815777Stw21770 *sz_out = 0;
9825777Stw21770
9835777Stw21770 switch (type) {
9845777Stw21770 case REP_PROTOCOL_ENTITY_SCOPE:
9855777Stw21770 if (strcmp(element, SCF_FMRI_LOCAL_SCOPE) == 0) {
9865777Stw21770 /*
9875777Stw21770 * No need to display scope information if we are
9885777Stw21770 * in the local scope.
9895777Stw21770 */
9905777Stw21770 separator = SCF_FMRI_SVC_PREFIX;
9915777Stw21770 name = NULL;
9925777Stw21770 } else {
9935777Stw21770 /*
9945777Stw21770 * Need to display scope information, because it is
9955777Stw21770 * not the local scope.
9965777Stw21770 */
9975777Stw21770 separator = SCF_FMRI_SVC_PREFIX SCF_FMRI_SCOPE_PREFIX;
9985777Stw21770 }
9995777Stw21770 break;
10005777Stw21770 case REP_PROTOCOL_ENTITY_SERVICE:
10015777Stw21770 separator = SCF_FMRI_SERVICE_PREFIX;
10025777Stw21770 break;
10035777Stw21770 case REP_PROTOCOL_ENTITY_INSTANCE:
10045777Stw21770 separator = SCF_FMRI_INSTANCE_PREFIX;
10055777Stw21770 break;
10065777Stw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
10075777Stw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
10085777Stw21770 separator = SCF_FMRI_PROPERTYGRP_PREFIX;
10095777Stw21770 break;
10105777Stw21770 case REP_PROTOCOL_ENTITY_PROPERTY:
10115777Stw21770 separator = SCF_FMRI_PROPERTY_PREFIX;
10125777Stw21770 break;
10135777Stw21770 case REP_PROTOCOL_ENTITY_VALUE:
10145777Stw21770 /*
10155777Stw21770 * A value does not have a separate FMRI from its property,
10165777Stw21770 * so there is nothing to concat.
10175777Stw21770 */
10185777Stw21770 return (REP_PROTOCOL_SUCCESS);
10195777Stw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT:
10205777Stw21770 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
10215777Stw21770 /* Snapshots do not have FMRIs, so there is nothing to do. */
10225777Stw21770 return (REP_PROTOCOL_SUCCESS);
10235777Stw21770 default:
10245777Stw21770 (void) fprintf(stderr, "%s:%d: Unknown protocol type %d.\n",
10255777Stw21770 __FILE__, __LINE__, type);
10265777Stw21770 abort(); /* Missing a case in switch if we get here. */
10275777Stw21770 }
10285777Stw21770
10295777Stw21770 /* Concatenate separator and element to the fmri buffer. */
10305777Stw21770
10315777Stw21770 actual = strlcat(fmri, separator, bufsize);
10325777Stw21770 if (name != NULL) {
10335777Stw21770 if (actual < bufsize) {
10345777Stw21770 actual = strlcat(fmri, name, bufsize);
10355777Stw21770 } else {
10365777Stw21770 actual += strlen(name);
10375777Stw21770 }
10385777Stw21770 }
10395777Stw21770 if (actual < bufsize) {
10405777Stw21770 rc = REP_PROTOCOL_SUCCESS;
10415777Stw21770 } else {
10425777Stw21770 rc = REP_PROTOCOL_FAIL_TRUNCATED;
10435777Stw21770 }
10445777Stw21770 *sz_out = actual;
10455777Stw21770 return (rc);
10465777Stw21770 }
10475777Stw21770
10485777Stw21770 /*
10495777Stw21770 * Get the FMRI for the node at np. The fmri will be placed in buf. On
10505777Stw21770 * success sz_out will be set to the size of the fmri in buf. If
10515777Stw21770 * REP_PROTOCOL_FAIL_TRUNCATED is returned, sz_out will be set to the size
10525777Stw21770 * of the buffer that would be required to avoid truncation.
10535777Stw21770 *
10545777Stw21770 * Fails with
10555777Stw21770 * _TRUNCATED not enough room in buf for the FMRI.
10565777Stw21770 */
10575777Stw21770 static int
rc_node_get_fmri_or_fragment(rc_node_t * np,char * buf,size_t bufsize,size_t * sz_out)10585777Stw21770 rc_node_get_fmri_or_fragment(rc_node_t *np, char *buf, size_t bufsize,
10595777Stw21770 size_t *sz_out)
10605777Stw21770 {
10615777Stw21770 size_t fmri_len = 0;
10625777Stw21770 int r;
10635777Stw21770
10645777Stw21770 if (bufsize > 0)
10655777Stw21770 *buf = 0;
10665777Stw21770 *sz_out = 0;
10675777Stw21770
10685777Stw21770 if (np->rn_fmri == NULL) {
10695777Stw21770 /*
10705777Stw21770 * A NULL rn_fmri implies that this is a top level scope.
10715777Stw21770 * Child nodes will always have an rn_fmri established
10725777Stw21770 * because both rc_node_link_child() and
10735777Stw21770 * rc_node_relink_child() call rc_node_build_fmri(). In
10745777Stw21770 * this case, we'll just return our name preceded by the
10755777Stw21770 * appropriate FMRI decorations.
10765777Stw21770 */
10775777Stw21770 assert(np->rn_parent == NULL);
10785777Stw21770 r = rc_concat_fmri_element(buf, bufsize, &fmri_len, np->rn_name,
10795777Stw21770 np->rn_id.rl_type);
10805777Stw21770 if (r != REP_PROTOCOL_SUCCESS)
10815777Stw21770 return (r);
10825777Stw21770 } else {
10835777Stw21770 /* We have an fmri, so return it. */
10845777Stw21770 fmri_len = strlcpy(buf, np->rn_fmri, bufsize);
10855777Stw21770 }
10865777Stw21770
10875777Stw21770 *sz_out = fmri_len;
10885777Stw21770
10895777Stw21770 if (fmri_len >= bufsize)
10905777Stw21770 return (REP_PROTOCOL_FAIL_TRUNCATED);
10915777Stw21770
10925777Stw21770 return (REP_PROTOCOL_SUCCESS);
10935777Stw21770 }
10945777Stw21770
10955777Stw21770 /*
10965777Stw21770 * Build an FMRI string for this node and save it in rn_fmri.
10975777Stw21770 *
10985777Stw21770 * The basic strategy here is to get the fmri of our parent and then
10995777Stw21770 * concatenate the appropriate separator followed by our name. If our name
11005777Stw21770 * is null, the resulting fmri will just be a copy of the parent fmri.
11015777Stw21770 * rc_node_build_fmri() should be called with the RC_NODE_USING_PARENT flag
11025777Stw21770 * set. Also the rn_lock for this node should be held.
11035777Stw21770 *
11045777Stw21770 * Fails with
11055777Stw21770 * _NO_RESOURCES Could not allocate memory.
11065777Stw21770 */
11075777Stw21770 static int
rc_node_build_fmri(rc_node_t * np)11085777Stw21770 rc_node_build_fmri(rc_node_t *np)
11095777Stw21770 {
11105777Stw21770 size_t actual;
11115777Stw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
11125777Stw21770 int rc;
11135777Stw21770 size_t sz = REP_PROTOCOL_FMRI_LEN;
11145777Stw21770
11155777Stw21770 assert(MUTEX_HELD(&np->rn_lock));
11165777Stw21770 assert(np->rn_flags & RC_NODE_USING_PARENT);
11175777Stw21770
11185777Stw21770 rc_node_free_fmri(np);
11195777Stw21770
11205777Stw21770 rc = rc_node_get_fmri_or_fragment(np->rn_parent, fmri, sz, &actual);
11215777Stw21770 assert(rc == REP_PROTOCOL_SUCCESS);
11225777Stw21770
11235777Stw21770 if (np->rn_name != NULL) {
11245777Stw21770 rc = rc_concat_fmri_element(fmri, sz, &actual, np->rn_name,
11255777Stw21770 np->rn_id.rl_type);
11265777Stw21770 assert(rc == REP_PROTOCOL_SUCCESS);
11275777Stw21770 np->rn_fmri = strdup(fmri);
11285777Stw21770 } else {
11295777Stw21770 np->rn_fmri = strdup(fmri);
11305777Stw21770 }
11315777Stw21770 if (np->rn_fmri == NULL) {
11325777Stw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
11335777Stw21770 } else {
11345777Stw21770 rc = REP_PROTOCOL_SUCCESS;
11355777Stw21770 }
11365777Stw21770
11375777Stw21770 return (rc);
11385777Stw21770 }
11395777Stw21770
11405777Stw21770 /*
11415777Stw21770 * Get the FMRI of the node at np placing the result in fmri. Then
11425777Stw21770 * concatenate the additional element to fmri. The type variable indicates
11435777Stw21770 * the type of element, so that the appropriate separator can be
11445777Stw21770 * generated. size is the number of bytes in the buffer at fmri, and
11455777Stw21770 * sz_out receives the size of the generated string. If the result is
11465777Stw21770 * truncated, sz_out will receive the size of the buffer that would be
11475777Stw21770 * required to avoid truncation.
11485777Stw21770 *
11495777Stw21770 * Fails with
11505777Stw21770 * _TRUNCATED Not enough room in buffer at fmri.
11515777Stw21770 */
11525777Stw21770 static int
rc_get_fmri_and_concat(rc_node_t * np,char * fmri,size_t size,size_t * sz_out,const char * element,rep_protocol_entity_t type)11535777Stw21770 rc_get_fmri_and_concat(rc_node_t *np, char *fmri, size_t size, size_t *sz_out,
11545777Stw21770 const char *element, rep_protocol_entity_t type)
11555777Stw21770 {
11565777Stw21770 int rc;
11575777Stw21770
11585777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, size, sz_out)) !=
11595777Stw21770 REP_PROTOCOL_SUCCESS) {
11605777Stw21770 return (rc);
11615777Stw21770 }
11625777Stw21770 if ((rc = rc_concat_fmri_element(fmri, size, sz_out, element, type)) !=
11635777Stw21770 REP_PROTOCOL_SUCCESS) {
11645777Stw21770 return (rc);
11655777Stw21770 }
11665777Stw21770
11675777Stw21770 return (REP_PROTOCOL_SUCCESS);
11685777Stw21770 }
11695777Stw21770
11700Sstevel@tonic-gate static int
rc_notify_info_interested(rc_notify_info_t * rnip,rc_notify_t * np)11710Sstevel@tonic-gate rc_notify_info_interested(rc_notify_info_t *rnip, rc_notify_t *np)
11720Sstevel@tonic-gate {
11730Sstevel@tonic-gate rc_node_t *nnp = np->rcn_node;
11740Sstevel@tonic-gate int i;
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate if (np->rcn_delete != NULL) {
11790Sstevel@tonic-gate assert(np->rcn_info == NULL && np->rcn_node == NULL);
11800Sstevel@tonic-gate return (1); /* everyone likes deletes */
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate if (np->rcn_node == NULL) {
11830Sstevel@tonic-gate assert(np->rcn_info != NULL || np->rcn_delete != NULL);
11840Sstevel@tonic-gate return (0);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate assert(np->rcn_info == NULL);
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
11890Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) {
11900Sstevel@tonic-gate if (strcmp(nnp->rn_name, rnip->rni_namelist[i]) == 0)
11910Sstevel@tonic-gate return (1);
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) {
11940Sstevel@tonic-gate if (strcmp(nnp->rn_type, rnip->rni_typelist[i]) == 0)
11950Sstevel@tonic-gate return (1);
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate return (0);
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate
12010Sstevel@tonic-gate static void
rc_notify_insert_node(rc_node_t * nnp)12020Sstevel@tonic-gate rc_notify_insert_node(rc_node_t *nnp)
12030Sstevel@tonic-gate {
12040Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify;
12050Sstevel@tonic-gate rc_notify_info_t *nip;
12060Sstevel@tonic-gate int found = 0;
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate assert(np->rcn_info == NULL);
12090Sstevel@tonic-gate
12100Sstevel@tonic-gate if (nnp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
12110Sstevel@tonic-gate return;
12120Sstevel@tonic-gate
12130Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12140Sstevel@tonic-gate np->rcn_node = nnp;
12150Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
12160Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip)) {
12170Sstevel@tonic-gate if (rc_notify_info_interested(nip, np)) {
12180Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv);
12190Sstevel@tonic-gate found++;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate if (found)
12230Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, np);
12240Sstevel@tonic-gate else
12250Sstevel@tonic-gate np->rcn_node = NULL;
12260Sstevel@tonic-gate
12270Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate static void
rc_notify_deletion(rc_notify_delete_t * ndp,const char * service,const char * instance,const char * pg)12310Sstevel@tonic-gate rc_notify_deletion(rc_notify_delete_t *ndp, const char *service,
12320Sstevel@tonic-gate const char *instance, const char *pg)
12330Sstevel@tonic-gate {
12340Sstevel@tonic-gate rc_notify_info_t *nip;
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate uu_list_node_init(&ndp->rnd_notify, &ndp->rnd_notify.rcn_list_node,
12370Sstevel@tonic-gate rc_notify_pool);
12380Sstevel@tonic-gate ndp->rnd_notify.rcn_delete = ndp;
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate (void) snprintf(ndp->rnd_fmri, sizeof (ndp->rnd_fmri),
12410Sstevel@tonic-gate "svc:/%s%s%s%s%s", service,
12420Sstevel@tonic-gate (instance != NULL)? ":" : "", (instance != NULL)? instance : "",
12430Sstevel@tonic-gate (pg != NULL)? "/:properties/" : "", (pg != NULL)? pg : "");
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate /*
12460Sstevel@tonic-gate * add to notification list, notify watchers
12470Sstevel@tonic-gate */
12480Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12490Sstevel@tonic-gate for (nip = uu_list_first(rc_notify_info_list); nip != NULL;
12500Sstevel@tonic-gate nip = uu_list_next(rc_notify_info_list, nip))
12510Sstevel@tonic-gate (void) pthread_cond_broadcast(&nip->rni_cv);
12520Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, ndp);
12530Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate static void
rc_notify_remove_node(rc_node_t * nnp)12570Sstevel@tonic-gate rc_notify_remove_node(rc_node_t *nnp)
12580Sstevel@tonic-gate {
12590Sstevel@tonic-gate rc_notify_t *np = &nnp->rn_notify;
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate assert(np->rcn_info == NULL);
12620Sstevel@tonic-gate assert(!MUTEX_HELD(&nnp->rn_lock));
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
12650Sstevel@tonic-gate while (np->rcn_node != NULL) {
12660Sstevel@tonic-gate if (rc_notify_in_use) {
12670Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv,
12680Sstevel@tonic-gate &rc_pg_notify_lock);
12690Sstevel@tonic-gate continue;
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np);
12720Sstevel@tonic-gate np->rcn_node = NULL;
12730Sstevel@tonic-gate break;
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate
12780Sstevel@tonic-gate static void
rc_notify_remove_locked(rc_notify_t * np)12790Sstevel@tonic-gate rc_notify_remove_locked(rc_notify_t *np)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
12820Sstevel@tonic-gate assert(rc_notify_in_use == 0);
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, np);
12850Sstevel@tonic-gate if (np->rcn_node) {
12860Sstevel@tonic-gate np->rcn_node = NULL;
12870Sstevel@tonic-gate } else if (np->rcn_delete) {
12880Sstevel@tonic-gate uu_free(np->rcn_delete);
12890Sstevel@tonic-gate } else {
12900Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate /*
12950Sstevel@tonic-gate * Permission checking functions. See comment atop this file.
12960Sstevel@tonic-gate */
12970Sstevel@tonic-gate #ifndef NATIVE_BUILD
12980Sstevel@tonic-gate static permcheck_t *
pc_create()12990Sstevel@tonic-gate pc_create()
13000Sstevel@tonic-gate {
13010Sstevel@tonic-gate permcheck_t *p;
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate p = uu_zalloc(sizeof (*p));
13040Sstevel@tonic-gate if (p == NULL)
13050Sstevel@tonic-gate return (NULL);
13060Sstevel@tonic-gate p->pc_bnum = 8; /* Normal case will only have 2 elts. */
13070Sstevel@tonic-gate p->pc_buckets = uu_zalloc(sizeof (*p->pc_buckets) * p->pc_bnum);
13080Sstevel@tonic-gate if (p->pc_buckets == NULL) {
13090Sstevel@tonic-gate uu_free(p);
13100Sstevel@tonic-gate return (NULL);
13110Sstevel@tonic-gate }
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate p->pc_enum = 0;
13140Sstevel@tonic-gate return (p);
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate static void
pc_free(permcheck_t * pcp)13180Sstevel@tonic-gate pc_free(permcheck_t *pcp)
13190Sstevel@tonic-gate {
13200Sstevel@tonic-gate uint_t i;
13210Sstevel@tonic-gate struct pc_elt *ep, *next;
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
13240Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
13250Sstevel@tonic-gate next = ep->pce_next;
13260Sstevel@tonic-gate free(ep);
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate }
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate free(pcp->pc_buckets);
13310Sstevel@tonic-gate free(pcp);
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate static uint32_t
pc_hash(const char * auth)13350Sstevel@tonic-gate pc_hash(const char *auth)
13360Sstevel@tonic-gate {
13370Sstevel@tonic-gate uint32_t h = 0, g;
13380Sstevel@tonic-gate const char *p;
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate /*
13410Sstevel@tonic-gate * Generic hash function from uts/common/os/modhash.c.
13420Sstevel@tonic-gate */
13430Sstevel@tonic-gate for (p = auth; *p != '\0'; ++p) {
13440Sstevel@tonic-gate h = (h << 4) + *p;
13450Sstevel@tonic-gate g = (h & 0xf0000000);
13460Sstevel@tonic-gate if (g != 0) {
13470Sstevel@tonic-gate h ^= (g >> 24);
13480Sstevel@tonic-gate h ^= g;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate return (h);
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate
13558497SThomas.Whitten@Sun.COM static perm_status_t
pc_exists(permcheck_t * pcp,const char * auth)13565777Stw21770 pc_exists(permcheck_t *pcp, const char *auth)
13570Sstevel@tonic-gate {
13580Sstevel@tonic-gate uint32_t h;
13590Sstevel@tonic-gate struct pc_elt *ep;
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate h = pc_hash(auth);
13620Sstevel@tonic-gate for (ep = pcp->pc_buckets[h & (pcp->pc_bnum - 1)];
13630Sstevel@tonic-gate ep != NULL;
13640Sstevel@tonic-gate ep = ep->pce_next) {
13655777Stw21770 if (strcmp(auth, ep->pce_auth) == 0) {
13665777Stw21770 pcp->pc_auth_string = ep->pce_auth;
13678497SThomas.Whitten@Sun.COM return (PERM_GRANTED);
13685777Stw21770 }
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate
13718497SThomas.Whitten@Sun.COM return (PERM_DENIED);
13728497SThomas.Whitten@Sun.COM }
13738497SThomas.Whitten@Sun.COM
13748497SThomas.Whitten@Sun.COM static perm_status_t
pc_match(permcheck_t * pcp,const char * pattern)13755777Stw21770 pc_match(permcheck_t *pcp, const char *pattern)
13760Sstevel@tonic-gate {
13770Sstevel@tonic-gate uint_t i;
13780Sstevel@tonic-gate struct pc_elt *ep;
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
13810Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = ep->pce_next) {
13825777Stw21770 if (_auth_match(pattern, ep->pce_auth)) {
13835777Stw21770 pcp->pc_auth_string = ep->pce_auth;
13848497SThomas.Whitten@Sun.COM return (PERM_GRANTED);
13855777Stw21770 }
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate
13898497SThomas.Whitten@Sun.COM return (PERM_DENIED);
13900Sstevel@tonic-gate }
13910Sstevel@tonic-gate
13920Sstevel@tonic-gate static int
pc_grow(permcheck_t * pcp)13930Sstevel@tonic-gate pc_grow(permcheck_t *pcp)
13940Sstevel@tonic-gate {
13950Sstevel@tonic-gate uint_t new_bnum, i, j;
13960Sstevel@tonic-gate struct pc_elt **new_buckets;
13970Sstevel@tonic-gate struct pc_elt *ep, *next;
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate new_bnum = pcp->pc_bnum * 2;
14000Sstevel@tonic-gate if (new_bnum < pcp->pc_bnum)
14010Sstevel@tonic-gate /* Homey don't play that. */
14020Sstevel@tonic-gate return (-1);
14030Sstevel@tonic-gate
14040Sstevel@tonic-gate new_buckets = uu_zalloc(sizeof (*new_buckets) * new_bnum);
14050Sstevel@tonic-gate if (new_buckets == NULL)
14060Sstevel@tonic-gate return (-1);
14070Sstevel@tonic-gate
14080Sstevel@tonic-gate for (i = 0; i < pcp->pc_bnum; ++i) {
14090Sstevel@tonic-gate for (ep = pcp->pc_buckets[i]; ep != NULL; ep = next) {
14100Sstevel@tonic-gate next = ep->pce_next;
14110Sstevel@tonic-gate j = pc_hash(ep->pce_auth) & (new_bnum - 1);
14120Sstevel@tonic-gate ep->pce_next = new_buckets[j];
14130Sstevel@tonic-gate new_buckets[j] = ep;
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate }
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate uu_free(pcp->pc_buckets);
14180Sstevel@tonic-gate pcp->pc_buckets = new_buckets;
14190Sstevel@tonic-gate pcp->pc_bnum = new_bnum;
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate return (0);
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate static int
pc_add(permcheck_t * pcp,const char * auth,pc_auth_type_t auth_type)14255777Stw21770 pc_add(permcheck_t *pcp, const char *auth, pc_auth_type_t auth_type)
14260Sstevel@tonic-gate {
14270Sstevel@tonic-gate struct pc_elt *ep;
14280Sstevel@tonic-gate uint_t i;
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate ep = uu_zalloc(offsetof(struct pc_elt, pce_auth) + strlen(auth) + 1);
14310Sstevel@tonic-gate if (ep == NULL)
14320Sstevel@tonic-gate return (-1);
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate /* Grow if pc_enum / pc_bnum > 3/4. */
14350Sstevel@tonic-gate if (pcp->pc_enum * 4 > 3 * pcp->pc_bnum)
14360Sstevel@tonic-gate /* Failure is not a stopper; we'll try again next time. */
14370Sstevel@tonic-gate (void) pc_grow(pcp);
14380Sstevel@tonic-gate
14390Sstevel@tonic-gate (void) strcpy(ep->pce_auth, auth);
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate i = pc_hash(auth) & (pcp->pc_bnum - 1);
14420Sstevel@tonic-gate ep->pce_next = pcp->pc_buckets[i];
14430Sstevel@tonic-gate pcp->pc_buckets[i] = ep;
14440Sstevel@tonic-gate
14455777Stw21770 if (auth_type > pcp->pc_specific_type) {
14465777Stw21770 pcp->pc_specific_type = auth_type;
14475777Stw21770 pcp->pc_specific = ep;
14485777Stw21770 }
14495777Stw21770
14500Sstevel@tonic-gate ++pcp->pc_enum;
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate return (0);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate
14550Sstevel@tonic-gate /*
14560Sstevel@tonic-gate * For the type of a property group, return the authorization which may be
14570Sstevel@tonic-gate * used to modify it.
14580Sstevel@tonic-gate */
14590Sstevel@tonic-gate static const char *
perm_auth_for_pgtype(const char * pgtype)14600Sstevel@tonic-gate perm_auth_for_pgtype(const char *pgtype)
14610Sstevel@tonic-gate {
14620Sstevel@tonic-gate if (strcmp(pgtype, SCF_GROUP_METHOD) == 0)
14630Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "method");
14640Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_DEPENDENCY) == 0)
14650Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "dependency");
14660Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_APPLICATION) == 0)
14670Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "application");
14680Sstevel@tonic-gate else if (strcmp(pgtype, SCF_GROUP_FRAMEWORK) == 0)
14690Sstevel@tonic-gate return (AUTH_MODIFY_PREFIX "framework");
14700Sstevel@tonic-gate else
14710Sstevel@tonic-gate return (NULL);
14720Sstevel@tonic-gate }
14730Sstevel@tonic-gate
14740Sstevel@tonic-gate /*
14750Sstevel@tonic-gate * Fails with
14760Sstevel@tonic-gate * _NO_RESOURCES - out of memory
14770Sstevel@tonic-gate */
14780Sstevel@tonic-gate static int
perm_add_enabling_type(permcheck_t * pcp,const char * auth,pc_auth_type_t auth_type)14795777Stw21770 perm_add_enabling_type(permcheck_t *pcp, const char *auth,
14805777Stw21770 pc_auth_type_t auth_type)
14815777Stw21770 {
14825777Stw21770 return (pc_add(pcp, auth, auth_type) == 0 ? REP_PROTOCOL_SUCCESS :
14835777Stw21770 REP_PROTOCOL_FAIL_NO_RESOURCES);
14845777Stw21770 }
14855777Stw21770
14865777Stw21770 /*
14875777Stw21770 * Fails with
14885777Stw21770 * _NO_RESOURCES - out of memory
14895777Stw21770 */
14905777Stw21770 static int
perm_add_enabling(permcheck_t * pcp,const char * auth)14910Sstevel@tonic-gate perm_add_enabling(permcheck_t *pcp, const char *auth)
14920Sstevel@tonic-gate {
14935777Stw21770 return (perm_add_enabling_type(pcp, auth, PC_AUTH_SMF));
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate /* Note that perm_add_enabling_values() is defined below. */
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate /*
14998497SThomas.Whitten@Sun.COM * perm_granted() returns PERM_GRANTED if the current door caller has one of
15008497SThomas.Whitten@Sun.COM * the enabling authorizations in pcp, PERM_DENIED if it doesn't, PERM_GONE if
15018497SThomas.Whitten@Sun.COM * the door client went away and PERM_FAIL if an error (usually lack of
150212273SCasper.Dik@Sun.COM * memory) occurs. auth_cb() checks each and every authorizations as
150312273SCasper.Dik@Sun.COM * enumerated by _enum_auths. When we find a result other than PERM_DENIED,
150412273SCasper.Dik@Sun.COM * we short-cut the enumeration and return non-zero.
15050Sstevel@tonic-gate */
150612273SCasper.Dik@Sun.COM
150712273SCasper.Dik@Sun.COM static int
auth_cb(const char * auth,void * ctxt,void * vres)150812273SCasper.Dik@Sun.COM auth_cb(const char *auth, void *ctxt, void *vres)
150912273SCasper.Dik@Sun.COM {
151012273SCasper.Dik@Sun.COM permcheck_t *pcp = ctxt;
151112273SCasper.Dik@Sun.COM int *pret = vres;
151212273SCasper.Dik@Sun.COM
151312273SCasper.Dik@Sun.COM if (strchr(auth, KV_WILDCHAR) == NULL)
151412273SCasper.Dik@Sun.COM *pret = pc_exists(pcp, auth);
151512273SCasper.Dik@Sun.COM else
151612273SCasper.Dik@Sun.COM *pret = pc_match(pcp, auth);
151712273SCasper.Dik@Sun.COM
151812273SCasper.Dik@Sun.COM if (*pret != PERM_DENIED)
151912273SCasper.Dik@Sun.COM return (1);
15205777Stw21770 /*
15215777Stw21770 * If we failed, choose the most specific auth string for use in
15225777Stw21770 * the audit event.
15235777Stw21770 */
15245777Stw21770 assert(pcp->pc_specific != NULL);
15255777Stw21770 pcp->pc_auth_string = pcp->pc_specific->pce_auth;
15265777Stw21770
152712273SCasper.Dik@Sun.COM return (0); /* Tells that we need to continue */
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate
15308497SThomas.Whitten@Sun.COM static perm_status_t
perm_granted(permcheck_t * pcp)15315777Stw21770 perm_granted(permcheck_t *pcp)
15320Sstevel@tonic-gate {
15330Sstevel@tonic-gate ucred_t *uc;
15340Sstevel@tonic-gate
15358497SThomas.Whitten@Sun.COM perm_status_t ret = PERM_DENIED;
15360Sstevel@tonic-gate uid_t uid;
15376059Sgww struct passwd pw;
15386059Sgww char pwbuf[1024]; /* XXX should be NSS_BUFLEN_PASSWD */
15390Sstevel@tonic-gate
15400Sstevel@tonic-gate /* Get the uid */
15410Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) {
15420Sstevel@tonic-gate if (errno == EINVAL) {
15430Sstevel@tonic-gate /*
15440Sstevel@tonic-gate * Client is no longer waiting for our response (e.g.,
15450Sstevel@tonic-gate * it received a signal & resumed with EINTR).
15460Sstevel@tonic-gate * Punting with door_return() would be nice but we
15470Sstevel@tonic-gate * need to release all of the locks & references we
15480Sstevel@tonic-gate * hold. And we must report failure to the client
15490Sstevel@tonic-gate * layer to keep it from ignoring retries as
15500Sstevel@tonic-gate * already-done (idempotency & all that). None of the
15510Sstevel@tonic-gate * error codes fit very well, so we might as well
15520Sstevel@tonic-gate * force the return of _PERMISSION_DENIED since we
15530Sstevel@tonic-gate * couldn't determine the user.
15540Sstevel@tonic-gate */
15558497SThomas.Whitten@Sun.COM return (PERM_GONE);
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate assert(0);
15580Sstevel@tonic-gate abort();
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate uid = ucred_geteuid(uc);
15624321Scasper assert(uid != (uid_t)-1);
15630Sstevel@tonic-gate
15646059Sgww if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) {
15658497SThomas.Whitten@Sun.COM return (PERM_FAIL);
15666059Sgww }
15676059Sgww
15686059Sgww /*
156912273SCasper.Dik@Sun.COM * Enumerate all the auths defined for the user and return the
157012273SCasper.Dik@Sun.COM * result in ret.
15716059Sgww */
157212273SCasper.Dik@Sun.COM if (_enum_auths(pw.pw_name, auth_cb, pcp, &ret) < 0)
157312273SCasper.Dik@Sun.COM return (PERM_FAIL);
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate return (ret);
15760Sstevel@tonic-gate }
15778497SThomas.Whitten@Sun.COM
15788497SThomas.Whitten@Sun.COM static int
map_granted_status(perm_status_t status,permcheck_t * pcp,char ** match_auth)15798497SThomas.Whitten@Sun.COM map_granted_status(perm_status_t status, permcheck_t *pcp,
15808497SThomas.Whitten@Sun.COM char **match_auth)
15818497SThomas.Whitten@Sun.COM {
15828497SThomas.Whitten@Sun.COM int rc;
15838497SThomas.Whitten@Sun.COM
15848497SThomas.Whitten@Sun.COM *match_auth = NULL;
15858497SThomas.Whitten@Sun.COM switch (status) {
15868497SThomas.Whitten@Sun.COM case PERM_DENIED:
15878497SThomas.Whitten@Sun.COM *match_auth = strdup(pcp->pc_auth_string);
15888497SThomas.Whitten@Sun.COM if (*match_auth == NULL)
15898497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
15908497SThomas.Whitten@Sun.COM else
15918497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
15928497SThomas.Whitten@Sun.COM break;
15938497SThomas.Whitten@Sun.COM case PERM_GRANTED:
15948497SThomas.Whitten@Sun.COM *match_auth = strdup(pcp->pc_auth_string);
15958497SThomas.Whitten@Sun.COM if (*match_auth == NULL)
15968497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
15978497SThomas.Whitten@Sun.COM else
15988497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_SUCCESS;
15998497SThomas.Whitten@Sun.COM break;
16008497SThomas.Whitten@Sun.COM case PERM_GONE:
16018497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
16028497SThomas.Whitten@Sun.COM break;
16038497SThomas.Whitten@Sun.COM case PERM_FAIL:
16048497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
16058497SThomas.Whitten@Sun.COM break;
16068497SThomas.Whitten@Sun.COM }
16078497SThomas.Whitten@Sun.COM return (rc);
16088497SThomas.Whitten@Sun.COM }
16090Sstevel@tonic-gate #endif /* NATIVE_BUILD */
16100Sstevel@tonic-gate
16110Sstevel@tonic-gate /*
16120Sstevel@tonic-gate * flags in RC_NODE_WAITING_FLAGS are broadcast when unset, and are used to
16130Sstevel@tonic-gate * serialize certain actions, and to wait for certain operations to complete
16140Sstevel@tonic-gate *
16150Sstevel@tonic-gate * The waiting flags are:
16160Sstevel@tonic-gate * RC_NODE_CHILDREN_CHANGING
16170Sstevel@tonic-gate * The child list is being built or changed (due to creation
16180Sstevel@tonic-gate * or deletion). All iterators pause.
16190Sstevel@tonic-gate *
16200Sstevel@tonic-gate * RC_NODE_USING_PARENT
16210Sstevel@tonic-gate * Someone is actively using the parent pointer, so we can't
16220Sstevel@tonic-gate * be removed from the parent list.
16230Sstevel@tonic-gate *
16240Sstevel@tonic-gate * RC_NODE_CREATING_CHILD
16250Sstevel@tonic-gate * A child is being created -- locks out other creations, to
16260Sstevel@tonic-gate * prevent insert-insert races.
16270Sstevel@tonic-gate *
16280Sstevel@tonic-gate * RC_NODE_IN_TX
16290Sstevel@tonic-gate * This object is running a transaction.
16300Sstevel@tonic-gate *
16310Sstevel@tonic-gate * RC_NODE_DYING
16320Sstevel@tonic-gate * This node might be dying. Always set as a set, using
16330Sstevel@tonic-gate * RC_NODE_DYING_FLAGS (which is everything but
16340Sstevel@tonic-gate * RC_NODE_USING_PARENT)
16350Sstevel@tonic-gate */
16360Sstevel@tonic-gate static int
rc_node_hold_flag(rc_node_t * np,uint32_t flag)16370Sstevel@tonic-gate rc_node_hold_flag(rc_node_t *np, uint32_t flag)
16380Sstevel@tonic-gate {
16390Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16400Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag)) {
16430Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD)
16460Sstevel@tonic-gate return (0);
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate np->rn_flags |= flag;
16490Sstevel@tonic-gate return (1);
16500Sstevel@tonic-gate }
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate static void
rc_node_rele_flag(rc_node_t * np,uint32_t flag)16530Sstevel@tonic-gate rc_node_rele_flag(rc_node_t *np, uint32_t flag)
16540Sstevel@tonic-gate {
16550Sstevel@tonic-gate assert((flag & ~RC_NODE_WAITING_FLAGS) == 0);
16560Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16570Sstevel@tonic-gate assert((np->rn_flags & flag) == flag);
16580Sstevel@tonic-gate np->rn_flags &= ~flag;
16590Sstevel@tonic-gate (void) pthread_cond_broadcast(&np->rn_cv);
16600Sstevel@tonic-gate }
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate /*
16630Sstevel@tonic-gate * wait until a particular flag has cleared. Fails if the object dies.
16640Sstevel@tonic-gate */
16650Sstevel@tonic-gate static int
rc_node_wait_flag(rc_node_t * np,uint32_t flag)16660Sstevel@tonic-gate rc_node_wait_flag(rc_node_t *np, uint32_t flag)
16670Sstevel@tonic-gate {
16680Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16690Sstevel@tonic-gate while (!(np->rn_flags & RC_NODE_DEAD) && (np->rn_flags & flag))
16700Sstevel@tonic-gate (void) pthread_cond_wait(&np->rn_cv, &np->rn_lock);
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate return (!(np->rn_flags & RC_NODE_DEAD));
16730Sstevel@tonic-gate }
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate /*
16760Sstevel@tonic-gate * On entry, np's lock must be held, and this thread must be holding
16770Sstevel@tonic-gate * RC_NODE_USING_PARENT. On return, both of them are released.
16780Sstevel@tonic-gate *
16790Sstevel@tonic-gate * If the return value is NULL, np either does not have a parent, or
16800Sstevel@tonic-gate * the parent has been marked DEAD.
16810Sstevel@tonic-gate *
16820Sstevel@tonic-gate * If the return value is non-NULL, it is the parent of np, and both
16830Sstevel@tonic-gate * its lock and the requested flags are held.
16840Sstevel@tonic-gate */
16850Sstevel@tonic-gate static rc_node_t *
rc_node_hold_parent_flag(rc_node_t * np,uint32_t flag)16860Sstevel@tonic-gate rc_node_hold_parent_flag(rc_node_t *np, uint32_t flag)
16870Sstevel@tonic-gate {
16880Sstevel@tonic-gate rc_node_t *pp;
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
16910Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_USING_PARENT);
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate if ((pp = np->rn_parent) == NULL) {
16940Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
16950Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
16960Sstevel@tonic-gate return (NULL);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
16990Sstevel@tonic-gate
17000Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
17010Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
17020Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
17030Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate if (!rc_node_hold_flag(pp, flag)) {
17060Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
17070Sstevel@tonic-gate return (NULL);
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate return (pp);
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate
17120Sstevel@tonic-gate rc_node_t *
rc_node_alloc(void)17130Sstevel@tonic-gate rc_node_alloc(void)
17140Sstevel@tonic-gate {
17150Sstevel@tonic-gate rc_node_t *np = uu_zalloc(sizeof (*np));
17160Sstevel@tonic-gate
17170Sstevel@tonic-gate if (np == NULL)
17180Sstevel@tonic-gate return (NULL);
17190Sstevel@tonic-gate
17200Sstevel@tonic-gate (void) pthread_mutex_init(&np->rn_lock, NULL);
17210Sstevel@tonic-gate (void) pthread_cond_init(&np->rn_cv, NULL);
17220Sstevel@tonic-gate
17230Sstevel@tonic-gate np->rn_children = uu_list_create(rc_children_pool, np, 0);
17240Sstevel@tonic-gate np->rn_pg_notify_list = uu_list_create(rc_pg_notify_pool, np, 0);
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate uu_list_node_init(np, &np->rn_sibling_node, rc_children_pool);
17270Sstevel@tonic-gate
17280Sstevel@tonic-gate uu_list_node_init(&np->rn_notify, &np->rn_notify.rcn_list_node,
17290Sstevel@tonic-gate rc_notify_pool);
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate return (np);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate void
rc_node_destroy(rc_node_t * np)17350Sstevel@tonic-gate rc_node_destroy(rc_node_t *np)
17360Sstevel@tonic-gate {
17370Sstevel@tonic-gate int i;
17380Sstevel@tonic-gate
17390Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED)
17400Sstevel@tonic-gate return; /* being handled elsewhere */
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate assert(np->rn_refs == 0 && np->rn_other_refs == 0);
17430Sstevel@tonic-gate assert(np->rn_former == NULL);
17440Sstevel@tonic-gate
17450Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
17460Sstevel@tonic-gate /* Release the holds from rc_iter_next(). */
17470Sstevel@tonic-gate for (i = 0; i < COMPOSITION_DEPTH; ++i) {
17480Sstevel@tonic-gate /* rn_cchain[i] may be NULL for empty snapshots. */
17490Sstevel@tonic-gate if (np->rn_cchain[i] != NULL)
17500Sstevel@tonic-gate rc_node_rele(np->rn_cchain[i]);
17510Sstevel@tonic-gate }
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate if (np->rn_name != NULL)
17550Sstevel@tonic-gate free((void *)np->rn_name);
17560Sstevel@tonic-gate np->rn_name = NULL;
17570Sstevel@tonic-gate if (np->rn_type != NULL)
17580Sstevel@tonic-gate free((void *)np->rn_type);
17590Sstevel@tonic-gate np->rn_type = NULL;
17600Sstevel@tonic-gate if (np->rn_values != NULL)
17610Sstevel@tonic-gate object_free_values(np->rn_values, np->rn_valtype,
17620Sstevel@tonic-gate np->rn_values_count, np->rn_values_size);
17630Sstevel@tonic-gate np->rn_values = NULL;
17645777Stw21770 rc_node_free_fmri(np);
17650Sstevel@tonic-gate
17660Sstevel@tonic-gate if (np->rn_snaplevel != NULL)
17670Sstevel@tonic-gate rc_snaplevel_rele(np->rn_snaplevel);
17680Sstevel@tonic-gate np->rn_snaplevel = NULL;
17690Sstevel@tonic-gate
17700Sstevel@tonic-gate uu_list_node_fini(np, &np->rn_sibling_node, rc_children_pool);
17710Sstevel@tonic-gate
17720Sstevel@tonic-gate uu_list_node_fini(&np->rn_notify, &np->rn_notify.rcn_list_node,
17730Sstevel@tonic-gate rc_notify_pool);
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate assert(uu_list_first(np->rn_children) == NULL);
17760Sstevel@tonic-gate uu_list_destroy(np->rn_children);
17770Sstevel@tonic-gate uu_list_destroy(np->rn_pg_notify_list);
17780Sstevel@tonic-gate
17790Sstevel@tonic-gate (void) pthread_mutex_destroy(&np->rn_lock);
17800Sstevel@tonic-gate (void) pthread_cond_destroy(&np->rn_cv);
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate uu_free(np);
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate /*
17860Sstevel@tonic-gate * Link in a child node.
17870Sstevel@tonic-gate *
17880Sstevel@tonic-gate * Because of the lock ordering, cp has to already be in the hash table with
17890Sstevel@tonic-gate * its lock dropped before we get it. To prevent anyone from noticing that
17900Sstevel@tonic-gate * it is parentless, the creation code sets the RC_NODE_USING_PARENT. Once
17910Sstevel@tonic-gate * we've linked it in, we release the flag.
17920Sstevel@tonic-gate */
17930Sstevel@tonic-gate static void
rc_node_link_child(rc_node_t * np,rc_node_t * cp)17940Sstevel@tonic-gate rc_node_link_child(rc_node_t *np, rc_node_t *cp)
17950Sstevel@tonic-gate {
17960Sstevel@tonic-gate assert(!MUTEX_HELD(&np->rn_lock));
17970Sstevel@tonic-gate assert(!MUTEX_HELD(&cp->rn_lock));
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
18000Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
18010Sstevel@tonic-gate assert(!(cp->rn_flags & RC_NODE_IN_PARENT) &&
18020Sstevel@tonic-gate (cp->rn_flags & RC_NODE_USING_PARENT));
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate assert(rc_check_parent_child(np->rn_id.rl_type, cp->rn_id.rl_type) ==
18050Sstevel@tonic-gate REP_PROTOCOL_SUCCESS);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate cp->rn_parent = np;
18080Sstevel@tonic-gate cp->rn_flags |= RC_NODE_IN_PARENT;
18090Sstevel@tonic-gate (void) uu_list_insert_before(np->rn_children, NULL, cp);
18105777Stw21770 (void) rc_node_build_fmri(cp);
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
18130Sstevel@tonic-gate
18140Sstevel@tonic-gate rc_node_rele_flag(cp, RC_NODE_USING_PARENT);
18150Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate /*
18190Sstevel@tonic-gate * Sets the rn_parent_ref field of all the children of np to pp -- always
18200Sstevel@tonic-gate * initially invoked as rc_node_setup_parent_ref(np, np), we then recurse.
18210Sstevel@tonic-gate *
18220Sstevel@tonic-gate * This is used when we mark a node RC_NODE_OLD, so that when the object and
18230Sstevel@tonic-gate * its children are no longer referenced, they will all be deleted as a unit.
18240Sstevel@tonic-gate */
18250Sstevel@tonic-gate static void
rc_node_setup_parent_ref(rc_node_t * np,rc_node_t * pp)18260Sstevel@tonic-gate rc_node_setup_parent_ref(rc_node_t *np, rc_node_t *pp)
18270Sstevel@tonic-gate {
18280Sstevel@tonic-gate rc_node_t *cp;
18290Sstevel@tonic-gate
18300Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
18330Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
18340Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
18350Sstevel@tonic-gate if (cp->rn_flags & RC_NODE_PARENT_REF) {
18360Sstevel@tonic-gate assert(cp->rn_parent_ref == pp);
18370Sstevel@tonic-gate } else {
18380Sstevel@tonic-gate assert(cp->rn_parent_ref == NULL);
18390Sstevel@tonic-gate
18400Sstevel@tonic-gate cp->rn_flags |= RC_NODE_PARENT_REF;
18410Sstevel@tonic-gate cp->rn_parent_ref = pp;
18420Sstevel@tonic-gate if (cp->rn_refs != 0)
18430Sstevel@tonic-gate rc_node_hold_other(pp);
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate rc_node_setup_parent_ref(cp, pp); /* recurse */
18460Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
18470Sstevel@tonic-gate }
18480Sstevel@tonic-gate }
18490Sstevel@tonic-gate
18500Sstevel@tonic-gate /*
18510Sstevel@tonic-gate * Atomically replace 'np' with 'newp', with a parent of 'pp'.
18520Sstevel@tonic-gate *
18530Sstevel@tonic-gate * Requirements:
18540Sstevel@tonic-gate * *no* node locks may be held.
18550Sstevel@tonic-gate * pp must be held with RC_NODE_CHILDREN_CHANGING
18560Sstevel@tonic-gate * newp and np must be held with RC_NODE_IN_TX
18570Sstevel@tonic-gate * np must be marked RC_NODE_IN_PARENT, newp must not be
18580Sstevel@tonic-gate * np must be marked RC_NODE_OLD
18590Sstevel@tonic-gate *
18600Sstevel@tonic-gate * Afterwards:
18610Sstevel@tonic-gate * pp's RC_NODE_CHILDREN_CHANGING is dropped
18620Sstevel@tonic-gate * newp and np's RC_NODE_IN_TX is dropped
18630Sstevel@tonic-gate * newp->rn_former = np;
18640Sstevel@tonic-gate * newp is RC_NODE_IN_PARENT, np is not.
18650Sstevel@tonic-gate * interested notify subscribers have been notified of newp's new status.
18660Sstevel@tonic-gate */
18670Sstevel@tonic-gate static void
rc_node_relink_child(rc_node_t * pp,rc_node_t * np,rc_node_t * newp)18680Sstevel@tonic-gate rc_node_relink_child(rc_node_t *pp, rc_node_t *np, rc_node_t *newp)
18690Sstevel@tonic-gate {
18700Sstevel@tonic-gate cache_bucket_t *bp;
18710Sstevel@tonic-gate /*
18720Sstevel@tonic-gate * First, swap np and nnp in the cache. newp's RC_NODE_IN_TX flag
18730Sstevel@tonic-gate * keeps rc_node_update() from seeing it until we are done.
18740Sstevel@tonic-gate */
18750Sstevel@tonic-gate bp = cache_hold(newp->rn_hash);
18760Sstevel@tonic-gate cache_remove_unlocked(bp, np);
18770Sstevel@tonic-gate cache_insert_unlocked(bp, newp);
18780Sstevel@tonic-gate cache_release(bp);
18790Sstevel@tonic-gate
18800Sstevel@tonic-gate /*
18810Sstevel@tonic-gate * replace np with newp in pp's list, and attach it to newp's rn_former
18820Sstevel@tonic-gate * link.
18830Sstevel@tonic-gate */
18840Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
18850Sstevel@tonic-gate assert(pp->rn_flags & RC_NODE_CHILDREN_CHANGING);
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate (void) pthread_mutex_lock(&newp->rn_lock);
18880Sstevel@tonic-gate assert(!(newp->rn_flags & RC_NODE_IN_PARENT));
18890Sstevel@tonic-gate assert(newp->rn_flags & RC_NODE_IN_TX);
18900Sstevel@tonic-gate
18910Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
18920Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
18930Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD);
18940Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_TX);
18950Sstevel@tonic-gate
18960Sstevel@tonic-gate newp->rn_parent = pp;
18970Sstevel@tonic-gate newp->rn_flags |= RC_NODE_IN_PARENT;
18980Sstevel@tonic-gate
18990Sstevel@tonic-gate /*
19000Sstevel@tonic-gate * Note that we carefully add newp before removing np -- this
19010Sstevel@tonic-gate * keeps iterators on the list from missing us.
19020Sstevel@tonic-gate */
19030Sstevel@tonic-gate (void) uu_list_insert_after(pp->rn_children, np, newp);
19045777Stw21770 (void) rc_node_build_fmri(newp);
19050Sstevel@tonic-gate (void) uu_list_remove(pp->rn_children, np);
19060Sstevel@tonic-gate
19070Sstevel@tonic-gate /*
19080Sstevel@tonic-gate * re-set np
19090Sstevel@tonic-gate */
19100Sstevel@tonic-gate newp->rn_former = np;
19110Sstevel@tonic-gate np->rn_parent = NULL;
19120Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT;
19130Sstevel@tonic-gate np->rn_flags |= RC_NODE_ON_FORMER;
19140Sstevel@tonic-gate
19150Sstevel@tonic-gate rc_notify_insert_node(newp);
19160Sstevel@tonic-gate
19170Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
19180Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
19190Sstevel@tonic-gate rc_node_rele_flag(newp, RC_NODE_USING_PARENT | RC_NODE_IN_TX);
19200Sstevel@tonic-gate (void) pthread_mutex_unlock(&newp->rn_lock);
19210Sstevel@tonic-gate rc_node_setup_parent_ref(np, np);
19220Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
19230Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
19240Sstevel@tonic-gate }
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate /*
19270Sstevel@tonic-gate * makes sure a node with lookup 'nip', name 'name', and parent 'pp' exists.
19280Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does
19290Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead.
19300Sstevel@tonic-gate */
19310Sstevel@tonic-gate rc_node_t *
rc_node_setup(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,rc_node_t * pp)19320Sstevel@tonic-gate rc_node_setup(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
19330Sstevel@tonic-gate rc_node_t *pp)
19340Sstevel@tonic-gate {
19350Sstevel@tonic-gate rc_node_t *np;
19360Sstevel@tonic-gate cache_bucket_t *bp;
19370Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate assert(cp->rn_refs == 0);
19400Sstevel@tonic-gate
19410Sstevel@tonic-gate bp = cache_hold(h);
19420Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
19430Sstevel@tonic-gate cache_release(bp);
19440Sstevel@tonic-gate
19450Sstevel@tonic-gate /*
19460Sstevel@tonic-gate * make sure it matches our expectations
19470Sstevel@tonic-gate */
1948887Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
1949887Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
1950887Shg115875 assert(np->rn_parent == pp);
1951887Shg115875 assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
1952887Shg115875 assert(strcmp(np->rn_name, name) == 0);
1953887Shg115875 assert(np->rn_type == NULL);
1954887Shg115875 assert(np->rn_flags & RC_NODE_IN_PARENT);
1955887Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
1956887Shg115875 }
1957887Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
19580Sstevel@tonic-gate
19590Sstevel@tonic-gate rc_node_destroy(cp);
19600Sstevel@tonic-gate return (np);
19610Sstevel@tonic-gate }
19620Sstevel@tonic-gate
19630Sstevel@tonic-gate /*
19647266Sbustos * No one is there -- setup & install the new node.
19650Sstevel@tonic-gate */
19660Sstevel@tonic-gate np = cp;
19670Sstevel@tonic-gate rc_node_hold(np);
19680Sstevel@tonic-gate np->rn_id = *nip;
19690Sstevel@tonic-gate np->rn_hash = h;
19700Sstevel@tonic-gate np->rn_name = strdup(name);
19710Sstevel@tonic-gate
19720Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE) {
19750Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
19760Sstevel@tonic-gate np->rn_cchain[0] = np;
19770Sstevel@tonic-gate np->rn_cchain[1] = pp;
19780Sstevel@tonic-gate #else
19790Sstevel@tonic-gate #error This code must be updated.
19800Sstevel@tonic-gate #endif
19810Sstevel@tonic-gate }
19820Sstevel@tonic-gate
19830Sstevel@tonic-gate cache_insert_unlocked(bp, np);
19840Sstevel@tonic-gate cache_release(bp); /* we are now visible */
19850Sstevel@tonic-gate
19860Sstevel@tonic-gate rc_node_link_child(pp, np);
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate return (np);
19890Sstevel@tonic-gate }
19900Sstevel@tonic-gate
19910Sstevel@tonic-gate /*
19920Sstevel@tonic-gate * makes sure a snapshot with lookup 'nip', name 'name', and parent 'pp' exists.
19930Sstevel@tonic-gate * 'cp' is used (and returned) if the node does not yet exist. If it does
19940Sstevel@tonic-gate * exist, 'cp' is freed, and the existent node is returned instead.
19950Sstevel@tonic-gate */
19960Sstevel@tonic-gate rc_node_t *
rc_node_setup_snapshot(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,uint32_t snap_id,rc_node_t * pp)19970Sstevel@tonic-gate rc_node_setup_snapshot(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
19980Sstevel@tonic-gate uint32_t snap_id, rc_node_t *pp)
19990Sstevel@tonic-gate {
20000Sstevel@tonic-gate rc_node_t *np;
20010Sstevel@tonic-gate cache_bucket_t *bp;
20020Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
20030Sstevel@tonic-gate
20040Sstevel@tonic-gate assert(cp->rn_refs == 0);
20050Sstevel@tonic-gate
20060Sstevel@tonic-gate bp = cache_hold(h);
20070Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
20080Sstevel@tonic-gate cache_release(bp);
20090Sstevel@tonic-gate
20100Sstevel@tonic-gate /*
20110Sstevel@tonic-gate * make sure it matches our expectations
20120Sstevel@tonic-gate */
2013887Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2014887Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
2015887Shg115875 assert(np->rn_parent == pp);
2016887Shg115875 assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
2017887Shg115875 assert(strcmp(np->rn_name, name) == 0);
2018887Shg115875 assert(np->rn_type == NULL);
2019887Shg115875 assert(np->rn_flags & RC_NODE_IN_PARENT);
2020887Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2021887Shg115875 }
2022887Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
20230Sstevel@tonic-gate
20240Sstevel@tonic-gate rc_node_destroy(cp);
20250Sstevel@tonic-gate return (np);
20260Sstevel@tonic-gate }
20270Sstevel@tonic-gate
20280Sstevel@tonic-gate /*
20290Sstevel@tonic-gate * No one is there -- create a new node.
20300Sstevel@tonic-gate */
20310Sstevel@tonic-gate np = cp;
20320Sstevel@tonic-gate rc_node_hold(np);
20330Sstevel@tonic-gate np->rn_id = *nip;
20340Sstevel@tonic-gate np->rn_hash = h;
20350Sstevel@tonic-gate np->rn_name = strdup(name);
20360Sstevel@tonic-gate np->rn_snapshot_id = snap_id;
20370Sstevel@tonic-gate
20380Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
20390Sstevel@tonic-gate
20400Sstevel@tonic-gate cache_insert_unlocked(bp, np);
20410Sstevel@tonic-gate cache_release(bp); /* we are now visible */
20420Sstevel@tonic-gate
20430Sstevel@tonic-gate rc_node_link_child(pp, np);
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate return (np);
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate /*
20490Sstevel@tonic-gate * makes sure a snaplevel with lookup 'nip' and parent 'pp' exists. 'cp' is
20500Sstevel@tonic-gate * used (and returned) if the node does not yet exist. If it does exist, 'cp'
20510Sstevel@tonic-gate * is freed, and the existent node is returned instead.
20520Sstevel@tonic-gate */
20530Sstevel@tonic-gate rc_node_t *
rc_node_setup_snaplevel(rc_node_t * cp,rc_node_lookup_t * nip,rc_snaplevel_t * lvl,rc_node_t * pp)20540Sstevel@tonic-gate rc_node_setup_snaplevel(rc_node_t *cp, rc_node_lookup_t *nip,
20550Sstevel@tonic-gate rc_snaplevel_t *lvl, rc_node_t *pp)
20560Sstevel@tonic-gate {
20570Sstevel@tonic-gate rc_node_t *np;
20580Sstevel@tonic-gate cache_bucket_t *bp;
20590Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
20600Sstevel@tonic-gate
20610Sstevel@tonic-gate assert(cp->rn_refs == 0);
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate bp = cache_hold(h);
20640Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
20650Sstevel@tonic-gate cache_release(bp);
20660Sstevel@tonic-gate
20670Sstevel@tonic-gate /*
20680Sstevel@tonic-gate * make sure it matches our expectations
20690Sstevel@tonic-gate */
2070887Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2071887Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
2072887Shg115875 assert(np->rn_parent == pp);
2073887Shg115875 assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
2074887Shg115875 assert(np->rn_name == NULL);
2075887Shg115875 assert(np->rn_type == NULL);
2076887Shg115875 assert(np->rn_flags & RC_NODE_IN_PARENT);
2077887Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2078887Shg115875 }
2079887Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
20800Sstevel@tonic-gate
20810Sstevel@tonic-gate rc_node_destroy(cp);
20820Sstevel@tonic-gate return (np);
20830Sstevel@tonic-gate }
20840Sstevel@tonic-gate
20850Sstevel@tonic-gate /*
20860Sstevel@tonic-gate * No one is there -- create a new node.
20870Sstevel@tonic-gate */
20880Sstevel@tonic-gate np = cp;
20890Sstevel@tonic-gate rc_node_hold(np); /* released in snapshot_fill_children() */
20900Sstevel@tonic-gate np->rn_id = *nip;
20910Sstevel@tonic-gate np->rn_hash = h;
20920Sstevel@tonic-gate
20930Sstevel@tonic-gate rc_snaplevel_hold(lvl);
20940Sstevel@tonic-gate np->rn_snaplevel = lvl;
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate cache_insert_unlocked(bp, np);
20990Sstevel@tonic-gate cache_release(bp); /* we are now visible */
21000Sstevel@tonic-gate
21010Sstevel@tonic-gate /* Add this snaplevel to the snapshot's composition chain. */
21020Sstevel@tonic-gate assert(pp->rn_cchain[lvl->rsl_level_num - 1] == NULL);
21030Sstevel@tonic-gate pp->rn_cchain[lvl->rsl_level_num - 1] = np;
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate rc_node_link_child(pp, np);
21060Sstevel@tonic-gate
21070Sstevel@tonic-gate return (np);
21080Sstevel@tonic-gate }
21090Sstevel@tonic-gate
21100Sstevel@tonic-gate /*
21110Sstevel@tonic-gate * Returns NULL if strdup() fails.
21120Sstevel@tonic-gate */
21130Sstevel@tonic-gate rc_node_t *
rc_node_setup_pg(rc_node_t * cp,rc_node_lookup_t * nip,const char * name,const char * type,uint32_t flags,uint32_t gen_id,rc_node_t * pp)21140Sstevel@tonic-gate rc_node_setup_pg(rc_node_t *cp, rc_node_lookup_t *nip, const char *name,
21150Sstevel@tonic-gate const char *type, uint32_t flags, uint32_t gen_id, rc_node_t *pp)
21160Sstevel@tonic-gate {
21170Sstevel@tonic-gate rc_node_t *np;
21180Sstevel@tonic-gate cache_bucket_t *bp;
21190Sstevel@tonic-gate
21200Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
21210Sstevel@tonic-gate bp = cache_hold(h);
21220Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
21230Sstevel@tonic-gate cache_release(bp);
21240Sstevel@tonic-gate
21250Sstevel@tonic-gate /*
21260Sstevel@tonic-gate * make sure it matches our expectations (don't check
21270Sstevel@tonic-gate * the generation number or parent, since someone could
21280Sstevel@tonic-gate * have gotten a transaction through while we weren't
21290Sstevel@tonic-gate * looking)
21300Sstevel@tonic-gate */
2131887Shg115875 (void) pthread_mutex_lock(&np->rn_lock);
2132887Shg115875 if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
2133887Shg115875 assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
2134887Shg115875 assert(strcmp(np->rn_name, name) == 0);
2135887Shg115875 assert(strcmp(np->rn_type, type) == 0);
2136887Shg115875 assert(np->rn_pgflags == flags);
2137887Shg115875 assert(np->rn_flags & RC_NODE_IN_PARENT);
2138887Shg115875 rc_node_rele_flag(np, RC_NODE_USING_PARENT);
2139887Shg115875 }
2140887Shg115875 (void) pthread_mutex_unlock(&np->rn_lock);
21410Sstevel@tonic-gate
21420Sstevel@tonic-gate rc_node_destroy(cp);
21430Sstevel@tonic-gate return (np);
21440Sstevel@tonic-gate }
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate np = cp;
21470Sstevel@tonic-gate rc_node_hold(np); /* released in fill_pg_callback() */
21480Sstevel@tonic-gate np->rn_id = *nip;
21490Sstevel@tonic-gate np->rn_hash = h;
21500Sstevel@tonic-gate np->rn_name = strdup(name);
21510Sstevel@tonic-gate if (np->rn_name == NULL) {
21520Sstevel@tonic-gate rc_node_rele(np);
21530Sstevel@tonic-gate return (NULL);
21540Sstevel@tonic-gate }
21550Sstevel@tonic-gate np->rn_type = strdup(type);
21560Sstevel@tonic-gate if (np->rn_type == NULL) {
21570Sstevel@tonic-gate free((void *)np->rn_name);
21580Sstevel@tonic-gate rc_node_rele(np);
21590Sstevel@tonic-gate return (NULL);
21600Sstevel@tonic-gate }
21610Sstevel@tonic-gate np->rn_pgflags = flags;
21620Sstevel@tonic-gate np->rn_gen_id = gen_id;
21630Sstevel@tonic-gate
21640Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
21650Sstevel@tonic-gate
21660Sstevel@tonic-gate cache_insert_unlocked(bp, np);
21670Sstevel@tonic-gate cache_release(bp); /* we are now visible */
21680Sstevel@tonic-gate
21690Sstevel@tonic-gate rc_node_link_child(pp, np);
21700Sstevel@tonic-gate
21710Sstevel@tonic-gate return (np);
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
21750Sstevel@tonic-gate /*
21760Sstevel@tonic-gate * Initialize a "composed property group" which represents the composition of
21770Sstevel@tonic-gate * property groups pg1 & pg2. It is ephemeral: once created & returned for an
21780Sstevel@tonic-gate * ITER_READ request, keeping it out of cache_hash and any child lists
21790Sstevel@tonic-gate * prevents it from being looked up. Operations besides iteration are passed
21800Sstevel@tonic-gate * through to pg1.
21810Sstevel@tonic-gate *
21820Sstevel@tonic-gate * pg1 & pg2 should be held before entering this function. They will be
21830Sstevel@tonic-gate * released in rc_node_destroy().
21840Sstevel@tonic-gate */
21850Sstevel@tonic-gate static int
rc_node_setup_cpg(rc_node_t * cpg,rc_node_t * pg1,rc_node_t * pg2)21860Sstevel@tonic-gate rc_node_setup_cpg(rc_node_t *cpg, rc_node_t *pg1, rc_node_t *pg2)
21870Sstevel@tonic-gate {
21880Sstevel@tonic-gate if (strcmp(pg1->rn_type, pg2->rn_type) != 0)
21890Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
21900Sstevel@tonic-gate
21910Sstevel@tonic-gate cpg->rn_id.rl_type = REP_PROTOCOL_ENTITY_CPROPERTYGRP;
21920Sstevel@tonic-gate cpg->rn_name = strdup(pg1->rn_name);
21930Sstevel@tonic-gate if (cpg->rn_name == NULL)
21940Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
21950Sstevel@tonic-gate
21960Sstevel@tonic-gate cpg->rn_cchain[0] = pg1;
21970Sstevel@tonic-gate cpg->rn_cchain[1] = pg2;
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22000Sstevel@tonic-gate }
22010Sstevel@tonic-gate #else
22020Sstevel@tonic-gate #error This code must be updated.
22030Sstevel@tonic-gate #endif
22040Sstevel@tonic-gate
22050Sstevel@tonic-gate /*
22060Sstevel@tonic-gate * Fails with _NO_RESOURCES.
22070Sstevel@tonic-gate */
22080Sstevel@tonic-gate int
rc_node_create_property(rc_node_t * pp,rc_node_lookup_t * nip,const char * name,rep_protocol_value_type_t type,const char * vals,size_t count,size_t size)22090Sstevel@tonic-gate rc_node_create_property(rc_node_t *pp, rc_node_lookup_t *nip,
22100Sstevel@tonic-gate const char *name, rep_protocol_value_type_t type,
22110Sstevel@tonic-gate const char *vals, size_t count, size_t size)
22120Sstevel@tonic-gate {
22130Sstevel@tonic-gate rc_node_t *np;
22140Sstevel@tonic-gate cache_bucket_t *bp;
22150Sstevel@tonic-gate
22160Sstevel@tonic-gate uint32_t h = rc_node_hash(nip);
22170Sstevel@tonic-gate bp = cache_hold(h);
22180Sstevel@tonic-gate if ((np = cache_lookup_unlocked(bp, nip)) != NULL) {
22190Sstevel@tonic-gate cache_release(bp);
22200Sstevel@tonic-gate /*
22210Sstevel@tonic-gate * make sure it matches our expectations
22220Sstevel@tonic-gate */
22230Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
22240Sstevel@tonic-gate if (rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
22250Sstevel@tonic-gate assert(np->rn_parent == pp);
22260Sstevel@tonic-gate assert(memcmp(&np->rn_id, nip, sizeof (*nip)) == 0);
22270Sstevel@tonic-gate assert(strcmp(np->rn_name, name) == 0);
22280Sstevel@tonic-gate assert(np->rn_valtype == type);
22290Sstevel@tonic-gate assert(np->rn_values_count == count);
22300Sstevel@tonic-gate assert(np->rn_values_size == size);
22310Sstevel@tonic-gate assert(vals == NULL ||
22320Sstevel@tonic-gate memcmp(np->rn_values, vals, size) == 0);
22330Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_IN_PARENT);
22340Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate rc_node_rele_locked(np);
22370Sstevel@tonic-gate object_free_values(vals, type, count, size);
22380Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22390Sstevel@tonic-gate }
22400Sstevel@tonic-gate
22410Sstevel@tonic-gate /*
22420Sstevel@tonic-gate * No one is there -- create a new node.
22430Sstevel@tonic-gate */
22440Sstevel@tonic-gate np = rc_node_alloc();
22450Sstevel@tonic-gate if (np == NULL) {
22460Sstevel@tonic-gate cache_release(bp);
22470Sstevel@tonic-gate object_free_values(vals, type, count, size);
22480Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
22490Sstevel@tonic-gate }
22500Sstevel@tonic-gate np->rn_id = *nip;
22510Sstevel@tonic-gate np->rn_hash = h;
22520Sstevel@tonic-gate np->rn_name = strdup(name);
22530Sstevel@tonic-gate if (np->rn_name == NULL) {
22540Sstevel@tonic-gate cache_release(bp);
22550Sstevel@tonic-gate object_free_values(vals, type, count, size);
22560Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
22570Sstevel@tonic-gate }
22580Sstevel@tonic-gate
22590Sstevel@tonic-gate np->rn_valtype = type;
22600Sstevel@tonic-gate np->rn_values = vals;
22610Sstevel@tonic-gate np->rn_values_count = count;
22620Sstevel@tonic-gate np->rn_values_size = size;
22630Sstevel@tonic-gate
22640Sstevel@tonic-gate np->rn_flags |= RC_NODE_USING_PARENT;
22650Sstevel@tonic-gate
22660Sstevel@tonic-gate cache_insert_unlocked(bp, np);
22670Sstevel@tonic-gate cache_release(bp); /* we are now visible */
22680Sstevel@tonic-gate
22690Sstevel@tonic-gate rc_node_link_child(pp, np);
22700Sstevel@tonic-gate
22710Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate
22745777Stw21770 /*
22755777Stw21770 * This function implements a decision table to determine the event ID for
22765777Stw21770 * changes to the enabled (SCF_PROPERTY_ENABLED) property. The event ID is
22775777Stw21770 * determined by the value of the first property in the command specified
22785777Stw21770 * by cmd_no and the name of the property group. Here is the decision
22795777Stw21770 * table:
22805777Stw21770 *
22815777Stw21770 * Property Group Name
22825777Stw21770 * Property ------------------------------------------
22835777Stw21770 * Value SCF_PG_GENERAL SCF_PG_GENERAL_OVR
22845777Stw21770 * -------- -------------- ------------------
22855777Stw21770 * "0" ADT_smf_disable ADT_smf_tmp_disable
22865777Stw21770 * "1" ADT_smf_enable ADT_smf_tmp_enable
22875777Stw21770 *
22885777Stw21770 * This function is called by special_property_event through a function
22895777Stw21770 * pointer in the special_props_list array.
22905777Stw21770 *
22915777Stw21770 * Since the ADT_smf_* symbols may not be defined in the build machine's
22925777Stw21770 * include files, this function is not compiled when doing native builds.
22935777Stw21770 */
22945777Stw21770 #ifndef NATIVE_BUILD
22955777Stw21770 static int
general_enable_id(tx_commit_data_t * tx_data,size_t cmd_no,const char * pg,au_event_t * event_id)22965777Stw21770 general_enable_id(tx_commit_data_t *tx_data, size_t cmd_no, const char *pg,
22975777Stw21770 au_event_t *event_id)
22985777Stw21770 {
22995777Stw21770 const char *value;
23005777Stw21770 uint32_t nvalues;
23015777Stw21770 int enable;
23025777Stw21770
23035777Stw21770 /*
23045777Stw21770 * First, check property value.
23055777Stw21770 */
23065777Stw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
23075777Stw21770 return (-1);
23085777Stw21770 if (nvalues == 0)
23095777Stw21770 return (-1);
23105777Stw21770 if (tx_cmd_value(tx_data, cmd_no, 0, &value) != REP_PROTOCOL_SUCCESS)
23115777Stw21770 return (-1);
23125777Stw21770 if (strcmp(value, "0") == 0) {
23135777Stw21770 enable = 0;
23145777Stw21770 } else if (strcmp(value, "1") == 0) {
23155777Stw21770 enable = 1;
23165777Stw21770 } else {
23175777Stw21770 return (-1);
23185777Stw21770 }
23195777Stw21770
23205777Stw21770 /*
23215777Stw21770 * Now check property group name.
23225777Stw21770 */
23235777Stw21770 if (strcmp(pg, SCF_PG_GENERAL) == 0) {
23245777Stw21770 *event_id = enable ? ADT_smf_enable : ADT_smf_disable;
23255777Stw21770 return (0);
23265777Stw21770 } else if (strcmp(pg, SCF_PG_GENERAL_OVR) == 0) {
23275777Stw21770 *event_id = enable ? ADT_smf_tmp_enable : ADT_smf_tmp_disable;
23285777Stw21770 return (0);
23295777Stw21770 }
23305777Stw21770 return (-1);
23315777Stw21770 }
23325777Stw21770 #endif /* NATIVE_BUILD */
23335777Stw21770
23345777Stw21770 /*
23355777Stw21770 * This function compares two audit_special_prop_item_t structures
23365777Stw21770 * represented by item1 and item2. It returns an integer greater than 0 if
23375777Stw21770 * item1 is greater than item2. It returns 0 if they are equal and an
23385777Stw21770 * integer less than 0 if item1 is less than item2. api_prop_name and
23395777Stw21770 * api_pg_name are the key fields for sorting.
23405777Stw21770 *
23415777Stw21770 * This function is suitable for calls to bsearch(3C) and qsort(3C).
23425777Stw21770 */
23435777Stw21770 static int
special_prop_compare(const void * item1,const void * item2)23445777Stw21770 special_prop_compare(const void *item1, const void *item2)
23455777Stw21770 {
23465777Stw21770 const audit_special_prop_item_t *a = (audit_special_prop_item_t *)item1;
23475777Stw21770 const audit_special_prop_item_t *b = (audit_special_prop_item_t *)item2;
23485777Stw21770 int r;
23495777Stw21770
23505777Stw21770 r = strcmp(a->api_prop_name, b->api_prop_name);
23515777Stw21770 if (r == 0) {
23525777Stw21770 /*
23535777Stw21770 * Primary keys are the same, so check the secondary key.
23545777Stw21770 */
23555777Stw21770 r = strcmp(a->api_pg_name, b->api_pg_name);
23565777Stw21770 }
23575777Stw21770 return (r);
23585777Stw21770 }
23595777Stw21770
23600Sstevel@tonic-gate int
rc_node_init(void)23610Sstevel@tonic-gate rc_node_init(void)
23620Sstevel@tonic-gate {
23630Sstevel@tonic-gate rc_node_t *np;
23640Sstevel@tonic-gate cache_bucket_t *bp;
23650Sstevel@tonic-gate
23660Sstevel@tonic-gate rc_children_pool = uu_list_pool_create("rc_children_pool",
23670Sstevel@tonic-gate sizeof (rc_node_t), offsetof(rc_node_t, rn_sibling_node),
23680Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23690Sstevel@tonic-gate
23700Sstevel@tonic-gate rc_pg_notify_pool = uu_list_pool_create("rc_pg_notify_pool",
23710Sstevel@tonic-gate sizeof (rc_node_pg_notify_t),
23720Sstevel@tonic-gate offsetof(rc_node_pg_notify_t, rnpn_node),
23730Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23740Sstevel@tonic-gate
23750Sstevel@tonic-gate rc_notify_pool = uu_list_pool_create("rc_notify_pool",
23760Sstevel@tonic-gate sizeof (rc_notify_t), offsetof(rc_notify_t, rcn_list_node),
23770Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23780Sstevel@tonic-gate
23790Sstevel@tonic-gate rc_notify_info_pool = uu_list_pool_create("rc_notify_info_pool",
23800Sstevel@tonic-gate sizeof (rc_notify_info_t),
23810Sstevel@tonic-gate offsetof(rc_notify_info_t, rni_list_node),
23820Sstevel@tonic-gate NULL, UU_LIST_POOL_DEBUG);
23830Sstevel@tonic-gate
23840Sstevel@tonic-gate if (rc_children_pool == NULL || rc_pg_notify_pool == NULL ||
23850Sstevel@tonic-gate rc_notify_pool == NULL || rc_notify_info_pool == NULL)
23860Sstevel@tonic-gate uu_die("out of memory");
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate rc_notify_list = uu_list_create(rc_notify_pool,
23890Sstevel@tonic-gate &rc_notify_list, 0);
23900Sstevel@tonic-gate
23910Sstevel@tonic-gate rc_notify_info_list = uu_list_create(rc_notify_info_pool,
23920Sstevel@tonic-gate &rc_notify_info_list, 0);
23930Sstevel@tonic-gate
23940Sstevel@tonic-gate if (rc_notify_list == NULL || rc_notify_info_list == NULL)
23950Sstevel@tonic-gate uu_die("out of memory");
23960Sstevel@tonic-gate
23975777Stw21770 /*
23985777Stw21770 * Sort the special_props_list array so that it can be searched
23995777Stw21770 * with bsearch(3C).
24005777Stw21770 *
24015777Stw21770 * The special_props_list array is not compiled into the native
24025777Stw21770 * build code, so there is no need to call qsort if NATIVE_BUILD is
24035777Stw21770 * defined.
24045777Stw21770 */
24055777Stw21770 #ifndef NATIVE_BUILD
24065777Stw21770 qsort(special_props_list, SPECIAL_PROP_COUNT,
24075777Stw21770 sizeof (special_props_list[0]), special_prop_compare);
24085777Stw21770 #endif /* NATIVE_BUILD */
24095777Stw21770
24100Sstevel@tonic-gate if ((np = rc_node_alloc()) == NULL)
24110Sstevel@tonic-gate uu_die("out of memory");
24120Sstevel@tonic-gate
24130Sstevel@tonic-gate rc_node_hold(np);
24140Sstevel@tonic-gate np->rn_id.rl_type = REP_PROTOCOL_ENTITY_SCOPE;
24150Sstevel@tonic-gate np->rn_id.rl_backend = BACKEND_TYPE_NORMAL;
24160Sstevel@tonic-gate np->rn_hash = rc_node_hash(&np->rn_id);
24170Sstevel@tonic-gate np->rn_name = "localhost";
24180Sstevel@tonic-gate
24190Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
24200Sstevel@tonic-gate cache_insert_unlocked(bp, np);
24210Sstevel@tonic-gate cache_release(bp);
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate rc_scope = np;
24240Sstevel@tonic-gate return (1);
24250Sstevel@tonic-gate }
24260Sstevel@tonic-gate
24270Sstevel@tonic-gate /*
24280Sstevel@tonic-gate * Fails with
24290Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
24300Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
24310Sstevel@tonic-gate * _DELETED - np has been deleted
24320Sstevel@tonic-gate * _NO_RESOURCES
24330Sstevel@tonic-gate */
24340Sstevel@tonic-gate static int
rc_node_fill_children(rc_node_t * np,uint32_t type)24350Sstevel@tonic-gate rc_node_fill_children(rc_node_t *np, uint32_t type)
24360Sstevel@tonic-gate {
24370Sstevel@tonic-gate int rc;
24380Sstevel@tonic-gate
24390Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
24400Sstevel@tonic-gate
24410Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
24420Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
24430Sstevel@tonic-gate return (rc);
24440Sstevel@tonic-gate
24450Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_CHILDREN_CHANGING))
24460Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
24470Sstevel@tonic-gate
24480Sstevel@tonic-gate if (np->rn_flags & RC_NODE_HAS_CHILDREN) {
24490Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
24500Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
24510Sstevel@tonic-gate }
24520Sstevel@tonic-gate
24530Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
24540Sstevel@tonic-gate rc = object_fill_children(np);
24550Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
24560Sstevel@tonic-gate
24570Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
24580Sstevel@tonic-gate np->rn_flags |= RC_NODE_HAS_CHILDREN;
24590Sstevel@tonic-gate }
24600Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CHILDREN_CHANGING);
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate return (rc);
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate /*
24660Sstevel@tonic-gate * Returns
24670Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
24680Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
24690Sstevel@tonic-gate * _DELETED - np has been deleted
24700Sstevel@tonic-gate * _NO_RESOURCES
24710Sstevel@tonic-gate * _SUCCESS - if *cpp is not NULL, it is held
24720Sstevel@tonic-gate */
24730Sstevel@tonic-gate static int
rc_node_find_named_child(rc_node_t * np,const char * name,uint32_t type,rc_node_t ** cpp)24740Sstevel@tonic-gate rc_node_find_named_child(rc_node_t *np, const char *name, uint32_t type,
24750Sstevel@tonic-gate rc_node_t **cpp)
24760Sstevel@tonic-gate {
24770Sstevel@tonic-gate int ret;
24780Sstevel@tonic-gate rc_node_t *cp;
24790Sstevel@tonic-gate
24800Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
24810Sstevel@tonic-gate assert(np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP);
24820Sstevel@tonic-gate
24830Sstevel@tonic-gate ret = rc_node_fill_children(np, type);
24840Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS)
24850Sstevel@tonic-gate return (ret);
24860Sstevel@tonic-gate
24870Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children);
24880Sstevel@tonic-gate cp != NULL;
24890Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
24900Sstevel@tonic-gate if (cp->rn_id.rl_type == type && strcmp(cp->rn_name, name) == 0)
24910Sstevel@tonic-gate break;
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate
24940Sstevel@tonic-gate if (cp != NULL)
24950Sstevel@tonic-gate rc_node_hold(cp);
24960Sstevel@tonic-gate *cpp = cp;
24970Sstevel@tonic-gate
24980Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
24990Sstevel@tonic-gate }
25000Sstevel@tonic-gate
25015040Swesolows static int rc_node_parent(rc_node_t *, rc_node_t **);
25025040Swesolows
25035040Swesolows /*
25045040Swesolows * Returns
25055040Swesolows * _INVALID_TYPE - type is invalid
25065040Swesolows * _DELETED - np or an ancestor has been deleted
25075040Swesolows * _NOT_FOUND - no ancestor of specified type exists
25085040Swesolows * _SUCCESS - *app is held
25095040Swesolows */
25105040Swesolows static int
rc_node_find_ancestor(rc_node_t * np,uint32_t type,rc_node_t ** app)25115040Swesolows rc_node_find_ancestor(rc_node_t *np, uint32_t type, rc_node_t **app)
25125040Swesolows {
25135040Swesolows int ret;
25145040Swesolows rc_node_t *parent, *np_orig;
25155040Swesolows
25165040Swesolows if (type >= REP_PROTOCOL_ENTITY_MAX)
25175040Swesolows return (REP_PROTOCOL_FAIL_INVALID_TYPE);
25185040Swesolows
25195040Swesolows np_orig = np;
25205040Swesolows
25215040Swesolows while (np->rn_id.rl_type > type) {
25225040Swesolows ret = rc_node_parent(np, &parent);
25235040Swesolows if (np != np_orig)
25245040Swesolows rc_node_rele(np);
25255040Swesolows if (ret != REP_PROTOCOL_SUCCESS)
25265040Swesolows return (ret);
25275040Swesolows np = parent;
25285040Swesolows }
25295040Swesolows
25305040Swesolows if (np->rn_id.rl_type == type) {
25315040Swesolows *app = parent;
25325040Swesolows return (REP_PROTOCOL_SUCCESS);
25335040Swesolows }
25345040Swesolows
25355040Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
25365040Swesolows }
25375040Swesolows
25380Sstevel@tonic-gate #ifndef NATIVE_BUILD
25390Sstevel@tonic-gate /*
25400Sstevel@tonic-gate * If the propname property exists in pg, and it is of type string, add its
25410Sstevel@tonic-gate * values as authorizations to pcp. pg must not be locked on entry, and it is
25420Sstevel@tonic-gate * returned unlocked. Returns
25430Sstevel@tonic-gate * _DELETED - pg was deleted
25440Sstevel@tonic-gate * _NO_RESOURCES
25450Sstevel@tonic-gate * _NOT_FOUND - pg has no property named propname
25460Sstevel@tonic-gate * _SUCCESS
25470Sstevel@tonic-gate */
25480Sstevel@tonic-gate static int
perm_add_pg_prop_values(permcheck_t * pcp,rc_node_t * pg,const char * propname)25490Sstevel@tonic-gate perm_add_pg_prop_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
25500Sstevel@tonic-gate {
25510Sstevel@tonic-gate rc_node_t *prop;
25520Sstevel@tonic-gate int result;
25530Sstevel@tonic-gate
25540Sstevel@tonic-gate uint_t count;
25550Sstevel@tonic-gate const char *cp;
25560Sstevel@tonic-gate
25570Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock));
25580Sstevel@tonic-gate assert(pg->rn_id.rl_type == REP_PROTOCOL_ENTITY_PROPERTYGRP);
25590Sstevel@tonic-gate
25600Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock);
25610Sstevel@tonic-gate result = rc_node_find_named_child(pg, propname,
25620Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop);
25630Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock);
25640Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) {
25650Sstevel@tonic-gate switch (result) {
25660Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
25670Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
25680Sstevel@tonic-gate return (result);
25690Sstevel@tonic-gate
25700Sstevel@tonic-gate case REP_PROTOCOL_FAIL_INVALID_TYPE:
25710Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
25720Sstevel@tonic-gate default:
25730Sstevel@tonic-gate bad_error("rc_node_find_named_child", result);
25740Sstevel@tonic-gate }
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate if (prop == NULL)
25780Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
25790Sstevel@tonic-gate
25800Sstevel@tonic-gate /* rn_valtype is immutable, so no locking. */
25810Sstevel@tonic-gate if (prop->rn_valtype != REP_PROTOCOL_TYPE_STRING) {
25820Sstevel@tonic-gate rc_node_rele(prop);
25830Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
25840Sstevel@tonic-gate }
25850Sstevel@tonic-gate
25860Sstevel@tonic-gate (void) pthread_mutex_lock(&prop->rn_lock);
25870Sstevel@tonic-gate for (count = prop->rn_values_count, cp = prop->rn_values;
25880Sstevel@tonic-gate count > 0;
25890Sstevel@tonic-gate --count) {
25905777Stw21770 result = perm_add_enabling_type(pcp, cp,
25915777Stw21770 (pg->rn_id.rl_ids[ID_INSTANCE]) ? PC_AUTH_INST :
25925777Stw21770 PC_AUTH_SVC);
25930Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS)
25940Sstevel@tonic-gate break;
25950Sstevel@tonic-gate
25960Sstevel@tonic-gate cp = strchr(cp, '\0') + 1;
25970Sstevel@tonic-gate }
25980Sstevel@tonic-gate
25990Sstevel@tonic-gate rc_node_rele_locked(prop);
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate return (result);
26020Sstevel@tonic-gate }
26030Sstevel@tonic-gate
26040Sstevel@tonic-gate /*
26050Sstevel@tonic-gate * Assuming that ent is a service or instance node, if the pgname property
26060Sstevel@tonic-gate * group has type pgtype, and it has a propname property with string type, add
26070Sstevel@tonic-gate * its values as authorizations to pcp. If pgtype is NULL, it is not checked.
26080Sstevel@tonic-gate * Returns
26090Sstevel@tonic-gate * _SUCCESS
26100Sstevel@tonic-gate * _DELETED - ent was deleted
26110Sstevel@tonic-gate * _NO_RESOURCES - no resources
26120Sstevel@tonic-gate * _NOT_FOUND - ent does not have pgname pg or propname property
26130Sstevel@tonic-gate */
26140Sstevel@tonic-gate static int
perm_add_ent_prop_values(permcheck_t * pcp,rc_node_t * ent,const char * pgname,const char * pgtype,const char * propname)26150Sstevel@tonic-gate perm_add_ent_prop_values(permcheck_t *pcp, rc_node_t *ent, const char *pgname,
26160Sstevel@tonic-gate const char *pgtype, const char *propname)
26170Sstevel@tonic-gate {
26180Sstevel@tonic-gate int r;
26190Sstevel@tonic-gate rc_node_t *pg;
26200Sstevel@tonic-gate
26210Sstevel@tonic-gate assert(!MUTEX_HELD(&ent->rn_lock));
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
26240Sstevel@tonic-gate r = rc_node_find_named_child(ent, pgname,
26250Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
26260Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
26270Sstevel@tonic-gate
26280Sstevel@tonic-gate switch (r) {
26290Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
26300Sstevel@tonic-gate break;
26310Sstevel@tonic-gate
26320Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
26330Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
26340Sstevel@tonic-gate return (r);
26350Sstevel@tonic-gate
26360Sstevel@tonic-gate default:
26370Sstevel@tonic-gate bad_error("rc_node_find_named_child", r);
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate if (pg == NULL)
26410Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
26420Sstevel@tonic-gate
26430Sstevel@tonic-gate if (pgtype == NULL || strcmp(pg->rn_type, pgtype) == 0) {
26440Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname);
26450Sstevel@tonic-gate switch (r) {
26460Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
26470Sstevel@tonic-gate r = REP_PROTOCOL_FAIL_NOT_FOUND;
26480Sstevel@tonic-gate break;
26490Sstevel@tonic-gate
26500Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
26510Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
26520Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NOT_FOUND:
26530Sstevel@tonic-gate break;
26540Sstevel@tonic-gate
26550Sstevel@tonic-gate default:
26560Sstevel@tonic-gate bad_error("perm_add_pg_prop_values", r);
26570Sstevel@tonic-gate }
26580Sstevel@tonic-gate }
26590Sstevel@tonic-gate
26600Sstevel@tonic-gate rc_node_rele(pg);
26610Sstevel@tonic-gate
26620Sstevel@tonic-gate return (r);
26630Sstevel@tonic-gate }
26640Sstevel@tonic-gate
26650Sstevel@tonic-gate /*
26665040Swesolows * If pg has a property named propname, and is string typed, add its values as
26670Sstevel@tonic-gate * authorizations to pcp. If pg has no such property, and its parent is an
26680Sstevel@tonic-gate * instance, walk up to the service and try doing the same with the property
26690Sstevel@tonic-gate * of the same name from the property group of the same name. Returns
26700Sstevel@tonic-gate * _SUCCESS
26710Sstevel@tonic-gate * _NO_RESOURCES
26720Sstevel@tonic-gate * _DELETED - pg (or an ancestor) was deleted
26730Sstevel@tonic-gate */
26740Sstevel@tonic-gate static int
perm_add_enabling_values(permcheck_t * pcp,rc_node_t * pg,const char * propname)26750Sstevel@tonic-gate perm_add_enabling_values(permcheck_t *pcp, rc_node_t *pg, const char *propname)
26760Sstevel@tonic-gate {
26770Sstevel@tonic-gate int r;
26785040Swesolows char pgname[REP_PROTOCOL_NAME_LEN + 1];
26795040Swesolows rc_node_t *svc;
26805040Swesolows size_t sz;
26810Sstevel@tonic-gate
26820Sstevel@tonic-gate r = perm_add_pg_prop_values(pcp, pg, propname);
26830Sstevel@tonic-gate
26845040Swesolows if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
26855040Swesolows return (r);
26865040Swesolows
26875040Swesolows assert(!MUTEX_HELD(&pg->rn_lock));
26885040Swesolows
26895040Swesolows if (pg->rn_id.rl_ids[ID_INSTANCE] == 0)
26905040Swesolows return (REP_PROTOCOL_SUCCESS);
26915040Swesolows
26925040Swesolows sz = strlcpy(pgname, pg->rn_name, sizeof (pgname));
26935040Swesolows assert(sz < sizeof (pgname));
26945040Swesolows
26955040Swesolows /*
26965040Swesolows * If pg is a child of an instance or snapshot, we want to compose the
26975040Swesolows * authorization property with the service's (if it exists). The
26985040Swesolows * snapshot case applies only to read_authorization. In all other
26995040Swesolows * cases, the pg's parent will be the instance.
27005040Swesolows */
27015040Swesolows r = rc_node_find_ancestor(pg, REP_PROTOCOL_ENTITY_SERVICE, &svc);
27025040Swesolows if (r != REP_PROTOCOL_SUCCESS) {
27035040Swesolows assert(r == REP_PROTOCOL_FAIL_DELETED);
27045040Swesolows return (r);
27055040Swesolows }
27065040Swesolows assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
27075040Swesolows
27085040Swesolows r = perm_add_ent_prop_values(pcp, svc, pgname, NULL, propname);
27095040Swesolows
27105040Swesolows rc_node_rele(svc);
27115040Swesolows
27125040Swesolows if (r == REP_PROTOCOL_FAIL_NOT_FOUND)
27135040Swesolows r = REP_PROTOCOL_SUCCESS;
27140Sstevel@tonic-gate
27150Sstevel@tonic-gate return (r);
27160Sstevel@tonic-gate }
27170Sstevel@tonic-gate
27180Sstevel@tonic-gate /*
27190Sstevel@tonic-gate * Call perm_add_enabling_values() for the "action_authorization" property of
27200Sstevel@tonic-gate * the "general" property group of inst. Returns
27210Sstevel@tonic-gate * _DELETED - inst (or an ancestor) was deleted
27220Sstevel@tonic-gate * _NO_RESOURCES
27230Sstevel@tonic-gate * _SUCCESS
27240Sstevel@tonic-gate */
27250Sstevel@tonic-gate static int
perm_add_inst_action_auth(permcheck_t * pcp,rc_node_t * inst)27260Sstevel@tonic-gate perm_add_inst_action_auth(permcheck_t *pcp, rc_node_t *inst)
27270Sstevel@tonic-gate {
27280Sstevel@tonic-gate int r;
27290Sstevel@tonic-gate rc_node_t *svc;
27300Sstevel@tonic-gate
27310Sstevel@tonic-gate assert(inst->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
27320Sstevel@tonic-gate
27330Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, inst, AUTH_PG_GENERAL,
27340Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
27350Sstevel@tonic-gate
27360Sstevel@tonic-gate if (r != REP_PROTOCOL_FAIL_NOT_FOUND)
27370Sstevel@tonic-gate return (r);
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate r = rc_node_parent(inst, &svc);
27400Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) {
27410Sstevel@tonic-gate assert(r == REP_PROTOCOL_FAIL_DELETED);
27420Sstevel@tonic-gate return (r);
27430Sstevel@tonic-gate }
27440Sstevel@tonic-gate
27450Sstevel@tonic-gate r = perm_add_ent_prop_values(pcp, svc, AUTH_PG_GENERAL,
27460Sstevel@tonic-gate AUTH_PG_GENERAL_TYPE, AUTH_PROP_ACTION);
27470Sstevel@tonic-gate
27480Sstevel@tonic-gate return (r == REP_PROTOCOL_FAIL_NOT_FOUND ? REP_PROTOCOL_SUCCESS : r);
27490Sstevel@tonic-gate }
27500Sstevel@tonic-gate #endif /* NATIVE_BUILD */
27510Sstevel@tonic-gate
27520Sstevel@tonic-gate void
rc_node_ptr_init(rc_node_ptr_t * out)27530Sstevel@tonic-gate rc_node_ptr_init(rc_node_ptr_t *out)
27540Sstevel@tonic-gate {
27550Sstevel@tonic-gate out->rnp_node = NULL;
27565777Stw21770 out->rnp_auth_string = NULL;
27575777Stw21770 out->rnp_authorized = RC_AUTH_UNKNOWN;
27580Sstevel@tonic-gate out->rnp_deleted = 0;
27590Sstevel@tonic-gate }
27600Sstevel@tonic-gate
27615777Stw21770 void
rc_node_ptr_free_mem(rc_node_ptr_t * npp)27625777Stw21770 rc_node_ptr_free_mem(rc_node_ptr_t *npp)
27635777Stw21770 {
27645777Stw21770 if (npp->rnp_auth_string != NULL) {
27655777Stw21770 free((void *)npp->rnp_auth_string);
27665777Stw21770 npp->rnp_auth_string = NULL;
27675777Stw21770 }
27685777Stw21770 }
27695777Stw21770
27700Sstevel@tonic-gate static void
rc_node_assign(rc_node_ptr_t * out,rc_node_t * val)27710Sstevel@tonic-gate rc_node_assign(rc_node_ptr_t *out, rc_node_t *val)
27720Sstevel@tonic-gate {
27730Sstevel@tonic-gate rc_node_t *cur = out->rnp_node;
27740Sstevel@tonic-gate if (val != NULL)
27750Sstevel@tonic-gate rc_node_hold(val);
27760Sstevel@tonic-gate out->rnp_node = val;
27777266Sbustos if (cur != NULL) {
27787266Sbustos NODE_LOCK(cur);
27797266Sbustos
27807266Sbustos /*
27817266Sbustos * Register the ephemeral reference created by reading
27827266Sbustos * out->rnp_node into cur. Note that the persistent
27837266Sbustos * reference we're destroying is locked by the client
27847266Sbustos * layer.
27857266Sbustos */
27867266Sbustos rc_node_hold_ephemeral_locked(cur);
27877266Sbustos
27887266Sbustos rc_node_rele_locked(cur);
27897266Sbustos }
27905777Stw21770 out->rnp_authorized = RC_AUTH_UNKNOWN;
27915777Stw21770 rc_node_ptr_free_mem(out);
27920Sstevel@tonic-gate out->rnp_deleted = 0;
27930Sstevel@tonic-gate }
27940Sstevel@tonic-gate
27950Sstevel@tonic-gate void
rc_node_clear(rc_node_ptr_t * out,int deleted)27960Sstevel@tonic-gate rc_node_clear(rc_node_ptr_t *out, int deleted)
27970Sstevel@tonic-gate {
27980Sstevel@tonic-gate rc_node_assign(out, NULL);
27990Sstevel@tonic-gate out->rnp_deleted = deleted;
28000Sstevel@tonic-gate }
28010Sstevel@tonic-gate
28020Sstevel@tonic-gate void
rc_node_ptr_assign(rc_node_ptr_t * out,const rc_node_ptr_t * val)28030Sstevel@tonic-gate rc_node_ptr_assign(rc_node_ptr_t *out, const rc_node_ptr_t *val)
28040Sstevel@tonic-gate {
28050Sstevel@tonic-gate rc_node_assign(out, val->rnp_node);
28060Sstevel@tonic-gate }
28070Sstevel@tonic-gate
28080Sstevel@tonic-gate /*
28090Sstevel@tonic-gate * rc_node_check()/RC_NODE_CHECK()
28100Sstevel@tonic-gate * generic "entry" checks, run before the use of an rc_node pointer.
28110Sstevel@tonic-gate *
28120Sstevel@tonic-gate * Fails with
28130Sstevel@tonic-gate * _NOT_SET
28140Sstevel@tonic-gate * _DELETED
28150Sstevel@tonic-gate */
28160Sstevel@tonic-gate static int
rc_node_check_and_lock(rc_node_t * np)28170Sstevel@tonic-gate rc_node_check_and_lock(rc_node_t *np)
28180Sstevel@tonic-gate {
28190Sstevel@tonic-gate int result = REP_PROTOCOL_SUCCESS;
28200Sstevel@tonic-gate if (np == NULL)
28210Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET);
28220Sstevel@tonic-gate
28230Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
28240Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
28250Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_DELETED;
28260Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
28270Sstevel@tonic-gate }
28280Sstevel@tonic-gate
28290Sstevel@tonic-gate return (result);
28300Sstevel@tonic-gate }
28310Sstevel@tonic-gate
28320Sstevel@tonic-gate /*
28330Sstevel@tonic-gate * Fails with
28340Sstevel@tonic-gate * _NOT_SET - ptr is reset
28350Sstevel@tonic-gate * _DELETED - node has been deleted
28360Sstevel@tonic-gate */
28370Sstevel@tonic-gate static rc_node_t *
rc_node_ptr_check_and_lock(rc_node_ptr_t * npp,int * res)28380Sstevel@tonic-gate rc_node_ptr_check_and_lock(rc_node_ptr_t *npp, int *res)
28390Sstevel@tonic-gate {
28400Sstevel@tonic-gate rc_node_t *np = npp->rnp_node;
28410Sstevel@tonic-gate if (np == NULL) {
28420Sstevel@tonic-gate if (npp->rnp_deleted)
28430Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED;
28440Sstevel@tonic-gate else
28450Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_NOT_SET;
28460Sstevel@tonic-gate return (NULL);
28470Sstevel@tonic-gate }
28480Sstevel@tonic-gate
28490Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
28500Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
28510Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
28520Sstevel@tonic-gate rc_node_clear(npp, 1);
28530Sstevel@tonic-gate *res = REP_PROTOCOL_FAIL_DELETED;
28540Sstevel@tonic-gate return (NULL);
28550Sstevel@tonic-gate }
28560Sstevel@tonic-gate return (np);
28570Sstevel@tonic-gate }
28580Sstevel@tonic-gate
28590Sstevel@tonic-gate #define RC_NODE_CHECK_AND_LOCK(n) { \
28600Sstevel@tonic-gate int rc__res; \
28610Sstevel@tonic-gate if ((rc__res = rc_node_check_and_lock(n)) != REP_PROTOCOL_SUCCESS) \
28620Sstevel@tonic-gate return (rc__res); \
28630Sstevel@tonic-gate }
28640Sstevel@tonic-gate
28650Sstevel@tonic-gate #define RC_NODE_CHECK(n) { \
28660Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \
28670Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \
28680Sstevel@tonic-gate }
28690Sstevel@tonic-gate
28700Sstevel@tonic-gate #define RC_NODE_CHECK_AND_HOLD(n) { \
28710Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(n); \
28720Sstevel@tonic-gate rc_node_hold_locked(n); \
28730Sstevel@tonic-gate (void) pthread_mutex_unlock(&(n)->rn_lock); \
28740Sstevel@tonic-gate }
28750Sstevel@tonic-gate
28760Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp) { \
28770Sstevel@tonic-gate int rc__res; \
28780Sstevel@tonic-gate if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == NULL) \
28790Sstevel@tonic-gate return (rc__res); \
28800Sstevel@tonic-gate }
28810Sstevel@tonic-gate
28828497SThomas.Whitten@Sun.COM #define RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, mem) { \
28838497SThomas.Whitten@Sun.COM int rc__res; \
28848497SThomas.Whitten@Sun.COM if (((np) = rc_node_ptr_check_and_lock(npp, &rc__res)) == \
28858497SThomas.Whitten@Sun.COM NULL) { \
28868497SThomas.Whitten@Sun.COM if ((mem) != NULL) \
28878497SThomas.Whitten@Sun.COM free((mem)); \
28888497SThomas.Whitten@Sun.COM return (rc__res); \
28898497SThomas.Whitten@Sun.COM } \
28908497SThomas.Whitten@Sun.COM }
28918497SThomas.Whitten@Sun.COM
28920Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK(np, npp) { \
28930Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \
28940Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
28950Sstevel@tonic-gate }
28960Sstevel@tonic-gate
28970Sstevel@tonic-gate #define RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp) { \
28980Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp); \
28990Sstevel@tonic-gate rc_node_hold_locked(np); \
29000Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
29010Sstevel@tonic-gate }
29020Sstevel@tonic-gate
29030Sstevel@tonic-gate #define HOLD_FLAG_OR_RETURN(np, flag) { \
29040Sstevel@tonic-gate assert(MUTEX_HELD(&(np)->rn_lock)); \
29050Sstevel@tonic-gate assert(!((np)->rn_flags & RC_NODE_DEAD)); \
29060Sstevel@tonic-gate if (!rc_node_hold_flag((np), flag)) { \
29070Sstevel@tonic-gate (void) pthread_mutex_unlock(&(np)->rn_lock); \
29080Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED); \
29090Sstevel@tonic-gate } \
29100Sstevel@tonic-gate }
29110Sstevel@tonic-gate
29125777Stw21770 #define HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, flag, mem) { \
29135777Stw21770 assert(MUTEX_HELD(&(np)->rn_lock)); \
29145777Stw21770 if (!rc_node_hold_flag((np), flag)) { \
29155777Stw21770 (void) pthread_mutex_unlock(&(np)->rn_lock); \
29165777Stw21770 assert((np) == (npp)->rnp_node); \
29175777Stw21770 rc_node_clear(npp, 1); \
29185777Stw21770 if ((mem) != NULL) \
29195777Stw21770 free((mem)); \
29205777Stw21770 return (REP_PROTOCOL_FAIL_DELETED); \
29215777Stw21770 } \
29225777Stw21770 }
29235777Stw21770
29240Sstevel@tonic-gate int
rc_local_scope(uint32_t type,rc_node_ptr_t * out)29250Sstevel@tonic-gate rc_local_scope(uint32_t type, rc_node_ptr_t *out)
29260Sstevel@tonic-gate {
29270Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE) {
29280Sstevel@tonic-gate rc_node_clear(out, 0);
29290Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
29300Sstevel@tonic-gate }
29310Sstevel@tonic-gate
29320Sstevel@tonic-gate /*
29330Sstevel@tonic-gate * the main scope never gets destroyed
29340Sstevel@tonic-gate */
29350Sstevel@tonic-gate rc_node_assign(out, rc_scope);
29360Sstevel@tonic-gate
29370Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
29380Sstevel@tonic-gate }
29390Sstevel@tonic-gate
29400Sstevel@tonic-gate /*
29410Sstevel@tonic-gate * Fails with
29420Sstevel@tonic-gate * _NOT_SET - npp is not set
29430Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted
29440Sstevel@tonic-gate * _TYPE_MISMATCH - type is not _SCOPE
29450Sstevel@tonic-gate * _NOT_FOUND - scope has no parent
29460Sstevel@tonic-gate */
29470Sstevel@tonic-gate static int
rc_scope_parent_scope(rc_node_ptr_t * npp,uint32_t type,rc_node_ptr_t * out)29480Sstevel@tonic-gate rc_scope_parent_scope(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
29490Sstevel@tonic-gate {
29500Sstevel@tonic-gate rc_node_t *np;
29510Sstevel@tonic-gate
29520Sstevel@tonic-gate rc_node_clear(out, 0);
29530Sstevel@tonic-gate
29540Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
29550Sstevel@tonic-gate
29560Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_SCOPE)
29570Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
29580Sstevel@tonic-gate
29590Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
29600Sstevel@tonic-gate }
29610Sstevel@tonic-gate
29625040Swesolows static int rc_node_pg_check_read_protect(rc_node_t *);
29635040Swesolows
29640Sstevel@tonic-gate /*
29650Sstevel@tonic-gate * Fails with
29660Sstevel@tonic-gate * _NOT_SET
29670Sstevel@tonic-gate * _DELETED
29680Sstevel@tonic-gate * _NOT_APPLICABLE
29690Sstevel@tonic-gate * _NOT_FOUND
29700Sstevel@tonic-gate * _BAD_REQUEST
29710Sstevel@tonic-gate * _TRUNCATED
29725040Swesolows * _NO_RESOURCES
29730Sstevel@tonic-gate */
29740Sstevel@tonic-gate int
rc_node_name(rc_node_ptr_t * npp,char * buf,size_t sz,uint32_t answertype,size_t * sz_out)29750Sstevel@tonic-gate rc_node_name(rc_node_ptr_t *npp, char *buf, size_t sz, uint32_t answertype,
29760Sstevel@tonic-gate size_t *sz_out)
29770Sstevel@tonic-gate {
29780Sstevel@tonic-gate size_t actual;
29790Sstevel@tonic-gate rc_node_t *np;
29800Sstevel@tonic-gate
29810Sstevel@tonic-gate assert(sz == *sz_out);
29820Sstevel@tonic-gate
29830Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
29840Sstevel@tonic-gate
29850Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
29860Sstevel@tonic-gate np = np->rn_cchain[0];
29870Sstevel@tonic-gate RC_NODE_CHECK(np);
29880Sstevel@tonic-gate }
29890Sstevel@tonic-gate
29900Sstevel@tonic-gate switch (answertype) {
29910Sstevel@tonic-gate case RP_ENTITY_NAME_NAME:
29920Sstevel@tonic-gate if (np->rn_name == NULL)
29930Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
29940Sstevel@tonic-gate actual = strlcpy(buf, np->rn_name, sz);
29950Sstevel@tonic-gate break;
29960Sstevel@tonic-gate case RP_ENTITY_NAME_PGTYPE:
29970Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
29980Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
29990Sstevel@tonic-gate actual = strlcpy(buf, np->rn_type, sz);
30000Sstevel@tonic-gate break;
30010Sstevel@tonic-gate case RP_ENTITY_NAME_PGFLAGS:
30020Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
30030Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30040Sstevel@tonic-gate actual = snprintf(buf, sz, "%d", np->rn_pgflags);
30050Sstevel@tonic-gate break;
30060Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SCOPE:
30070Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30080Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30090Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_scope, sz);
30100Sstevel@tonic-gate break;
30110Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_SERVICE:
30120Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30130Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30140Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_service, sz);
30150Sstevel@tonic-gate break;
30160Sstevel@tonic-gate case RP_ENTITY_NAME_SNAPLEVEL_INSTANCE:
30170Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
30180Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30190Sstevel@tonic-gate if (np->rn_snaplevel->rsl_instance == NULL)
30200Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
30210Sstevel@tonic-gate actual = strlcpy(buf, np->rn_snaplevel->rsl_instance, sz);
30220Sstevel@tonic-gate break;
30235040Swesolows case RP_ENTITY_NAME_PGREADPROT:
30245040Swesolows {
30255040Swesolows int ret;
30265040Swesolows
30275040Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
30285040Swesolows return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
30295040Swesolows ret = rc_node_pg_check_read_protect(np);
30305040Swesolows assert(ret != REP_PROTOCOL_FAIL_TYPE_MISMATCH);
30315040Swesolows switch (ret) {
30325040Swesolows case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
30335040Swesolows actual = snprintf(buf, sz, "1");
30345040Swesolows break;
30355040Swesolows case REP_PROTOCOL_SUCCESS:
30365040Swesolows actual = snprintf(buf, sz, "0");
30375040Swesolows break;
30385040Swesolows default:
30395040Swesolows return (ret);
30405040Swesolows }
30415040Swesolows break;
30425040Swesolows }
30430Sstevel@tonic-gate default:
30440Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
30450Sstevel@tonic-gate }
30460Sstevel@tonic-gate if (actual >= sz)
30470Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TRUNCATED);
30480Sstevel@tonic-gate
30490Sstevel@tonic-gate *sz_out = actual;
30500Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
30510Sstevel@tonic-gate }
30520Sstevel@tonic-gate
30530Sstevel@tonic-gate int
rc_node_get_property_type(rc_node_ptr_t * npp,rep_protocol_value_type_t * out)30540Sstevel@tonic-gate rc_node_get_property_type(rc_node_ptr_t *npp, rep_protocol_value_type_t *out)
30550Sstevel@tonic-gate {
30560Sstevel@tonic-gate rc_node_t *np;
30570Sstevel@tonic-gate
30580Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
30590Sstevel@tonic-gate
30600Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
30610Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
30620Sstevel@tonic-gate
30630Sstevel@tonic-gate *out = np->rn_valtype;
30640Sstevel@tonic-gate
30650Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
30660Sstevel@tonic-gate }
30670Sstevel@tonic-gate
30680Sstevel@tonic-gate /*
30690Sstevel@tonic-gate * Get np's parent. If np is deleted, returns _DELETED. Otherwise puts a hold
30700Sstevel@tonic-gate * on the parent, returns a pointer to it in *out, and returns _SUCCESS.
30710Sstevel@tonic-gate */
30720Sstevel@tonic-gate static int
rc_node_parent(rc_node_t * np,rc_node_t ** out)30730Sstevel@tonic-gate rc_node_parent(rc_node_t *np, rc_node_t **out)
30740Sstevel@tonic-gate {
30750Sstevel@tonic-gate rc_node_t *pnp;
30760Sstevel@tonic-gate rc_node_t *np_orig;
30770Sstevel@tonic-gate
30780Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
30790Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
30800Sstevel@tonic-gate } else {
30810Sstevel@tonic-gate np = np->rn_cchain[0];
30820Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
30830Sstevel@tonic-gate }
30840Sstevel@tonic-gate
30850Sstevel@tonic-gate np_orig = np;
30860Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */
30870Sstevel@tonic-gate
30880Sstevel@tonic-gate for (;;) {
30890Sstevel@tonic-gate if (!rc_node_wait_flag(np,
30900Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
30910Sstevel@tonic-gate rc_node_rele_locked(np);
30920Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
30930Sstevel@tonic-gate }
30940Sstevel@tonic-gate
30950Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD))
30960Sstevel@tonic-gate break;
30970Sstevel@tonic-gate
30980Sstevel@tonic-gate rc_node_rele_locked(np);
30990Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
31000Sstevel@tonic-gate assert(np != np_orig);
31010Sstevel@tonic-gate
31020Sstevel@tonic-gate if (np == NULL)
31030Sstevel@tonic-gate goto deleted;
31040Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
31050Sstevel@tonic-gate }
31060Sstevel@tonic-gate
31070Sstevel@tonic-gate /* guaranteed to succeed without dropping the lock */
31080Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
31090Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31100Sstevel@tonic-gate *out = NULL;
31110Sstevel@tonic-gate rc_node_rele(np);
31120Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
31130Sstevel@tonic-gate }
31140Sstevel@tonic-gate
31150Sstevel@tonic-gate assert(np->rn_parent != NULL);
31160Sstevel@tonic-gate pnp = np->rn_parent;
31170Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31180Sstevel@tonic-gate
31190Sstevel@tonic-gate (void) pthread_mutex_lock(&pnp->rn_lock);
31200Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
31210Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
31220Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
31230Sstevel@tonic-gate
31240Sstevel@tonic-gate rc_node_hold_locked(pnp);
31250Sstevel@tonic-gate
31260Sstevel@tonic-gate (void) pthread_mutex_unlock(&pnp->rn_lock);
31270Sstevel@tonic-gate
31280Sstevel@tonic-gate rc_node_rele(np);
31290Sstevel@tonic-gate *out = pnp;
31300Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31310Sstevel@tonic-gate
31320Sstevel@tonic-gate deleted:
31330Sstevel@tonic-gate rc_node_rele(np);
31340Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
31350Sstevel@tonic-gate }
31360Sstevel@tonic-gate
31370Sstevel@tonic-gate /*
31380Sstevel@tonic-gate * Fails with
31390Sstevel@tonic-gate * _NOT_SET
31400Sstevel@tonic-gate * _DELETED
31410Sstevel@tonic-gate */
31420Sstevel@tonic-gate static int
rc_node_ptr_parent(rc_node_ptr_t * npp,rc_node_t ** out)31430Sstevel@tonic-gate rc_node_ptr_parent(rc_node_ptr_t *npp, rc_node_t **out)
31440Sstevel@tonic-gate {
31450Sstevel@tonic-gate rc_node_t *np;
31460Sstevel@tonic-gate
31470Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
31480Sstevel@tonic-gate
31490Sstevel@tonic-gate return (rc_node_parent(np, out));
31500Sstevel@tonic-gate }
31510Sstevel@tonic-gate
31520Sstevel@tonic-gate /*
31530Sstevel@tonic-gate * Fails with
31540Sstevel@tonic-gate * _NOT_SET - npp is not set
31550Sstevel@tonic-gate * _DELETED - the node npp pointed at has been deleted
31560Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node's parent is not of type type
31570Sstevel@tonic-gate *
31580Sstevel@tonic-gate * If npp points to a scope, can also fail with
31590Sstevel@tonic-gate * _NOT_FOUND - scope has no parent
31600Sstevel@tonic-gate */
31610Sstevel@tonic-gate int
rc_node_get_parent(rc_node_ptr_t * npp,uint32_t type,rc_node_ptr_t * out)31620Sstevel@tonic-gate rc_node_get_parent(rc_node_ptr_t *npp, uint32_t type, rc_node_ptr_t *out)
31630Sstevel@tonic-gate {
31640Sstevel@tonic-gate rc_node_t *pnp;
31650Sstevel@tonic-gate int rc;
31660Sstevel@tonic-gate
31670Sstevel@tonic-gate if (npp->rnp_node != NULL &&
31680Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE)
31690Sstevel@tonic-gate return (rc_scope_parent_scope(npp, type, out));
31700Sstevel@tonic-gate
31710Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS) {
31720Sstevel@tonic-gate rc_node_clear(out, 0);
31730Sstevel@tonic-gate return (rc);
31740Sstevel@tonic-gate }
31750Sstevel@tonic-gate
31760Sstevel@tonic-gate if (type != pnp->rn_id.rl_type) {
31770Sstevel@tonic-gate rc_node_rele(pnp);
31780Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
31790Sstevel@tonic-gate }
31800Sstevel@tonic-gate
31810Sstevel@tonic-gate rc_node_assign(out, pnp);
31820Sstevel@tonic-gate rc_node_rele(pnp);
31830Sstevel@tonic-gate
31840Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31850Sstevel@tonic-gate }
31860Sstevel@tonic-gate
31870Sstevel@tonic-gate int
rc_node_parent_type(rc_node_ptr_t * npp,uint32_t * type_out)31880Sstevel@tonic-gate rc_node_parent_type(rc_node_ptr_t *npp, uint32_t *type_out)
31890Sstevel@tonic-gate {
31900Sstevel@tonic-gate rc_node_t *pnp;
31910Sstevel@tonic-gate int rc;
31920Sstevel@tonic-gate
31930Sstevel@tonic-gate if (npp->rnp_node != NULL &&
31940Sstevel@tonic-gate npp->rnp_node->rn_id.rl_type == REP_PROTOCOL_ENTITY_SCOPE) {
31950Sstevel@tonic-gate *type_out = REP_PROTOCOL_ENTITY_SCOPE;
31960Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
31970Sstevel@tonic-gate }
31980Sstevel@tonic-gate
31990Sstevel@tonic-gate if ((rc = rc_node_ptr_parent(npp, &pnp)) != REP_PROTOCOL_SUCCESS)
32000Sstevel@tonic-gate return (rc);
32010Sstevel@tonic-gate
32020Sstevel@tonic-gate *type_out = pnp->rn_id.rl_type;
32030Sstevel@tonic-gate
32040Sstevel@tonic-gate rc_node_rele(pnp);
32050Sstevel@tonic-gate
32060Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
32070Sstevel@tonic-gate }
32080Sstevel@tonic-gate
32090Sstevel@tonic-gate /*
32100Sstevel@tonic-gate * Fails with
32110Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
32120Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type
32130Sstevel@tonic-gate * _DELETED - np has been deleted
32140Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found
32150Sstevel@tonic-gate * _NO_RESOURCES
32160Sstevel@tonic-gate * _BACKEND_ACCESS
32170Sstevel@tonic-gate */
32180Sstevel@tonic-gate int
rc_node_get_child(rc_node_ptr_t * npp,const char * name,uint32_t type,rc_node_ptr_t * outp)32190Sstevel@tonic-gate rc_node_get_child(rc_node_ptr_t *npp, const char *name, uint32_t type,
32200Sstevel@tonic-gate rc_node_ptr_t *outp)
32210Sstevel@tonic-gate {
32220Sstevel@tonic-gate rc_node_t *np, *cp;
32230Sstevel@tonic-gate rc_node_t *child = NULL;
32240Sstevel@tonic-gate int ret, idx;
32250Sstevel@tonic-gate
32260Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
32270Sstevel@tonic-gate if ((ret = rc_check_type_name(type, name)) == REP_PROTOCOL_SUCCESS) {
32280Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
32290Sstevel@tonic-gate ret = rc_node_find_named_child(np, name, type, &child);
32300Sstevel@tonic-gate } else {
32310Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
32320Sstevel@tonic-gate ret = REP_PROTOCOL_SUCCESS;
32330Sstevel@tonic-gate for (idx = 0; idx < COMPOSITION_DEPTH; idx++) {
32340Sstevel@tonic-gate cp = np->rn_cchain[idx];
32350Sstevel@tonic-gate if (cp == NULL)
32360Sstevel@tonic-gate break;
32370Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(cp);
32380Sstevel@tonic-gate ret = rc_node_find_named_child(cp, name, type,
32390Sstevel@tonic-gate &child);
32400Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
32410Sstevel@tonic-gate /*
32420Sstevel@tonic-gate * loop only if we succeeded, but no child of
32430Sstevel@tonic-gate * the correct name was found.
32440Sstevel@tonic-gate */
32450Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS ||
32460Sstevel@tonic-gate child != NULL)
32470Sstevel@tonic-gate break;
32480Sstevel@tonic-gate }
32490Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
32500Sstevel@tonic-gate }
32510Sstevel@tonic-gate }
32520Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
32530Sstevel@tonic-gate
32540Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) {
32550Sstevel@tonic-gate rc_node_assign(outp, child);
32560Sstevel@tonic-gate if (child != NULL)
32570Sstevel@tonic-gate rc_node_rele(child);
32580Sstevel@tonic-gate else
32590Sstevel@tonic-gate ret = REP_PROTOCOL_FAIL_NOT_FOUND;
32600Sstevel@tonic-gate } else {
32610Sstevel@tonic-gate rc_node_assign(outp, NULL);
32620Sstevel@tonic-gate }
32630Sstevel@tonic-gate return (ret);
32640Sstevel@tonic-gate }
32650Sstevel@tonic-gate
32660Sstevel@tonic-gate int
rc_node_update(rc_node_ptr_t * npp)32670Sstevel@tonic-gate rc_node_update(rc_node_ptr_t *npp)
32680Sstevel@tonic-gate {
32690Sstevel@tonic-gate cache_bucket_t *bp;
32700Sstevel@tonic-gate rc_node_t *np = npp->rnp_node;
32710Sstevel@tonic-gate rc_node_t *nnp;
32720Sstevel@tonic-gate rc_node_t *cpg = NULL;
32730Sstevel@tonic-gate
32740Sstevel@tonic-gate if (np != NULL &&
32750Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
32760Sstevel@tonic-gate /*
32770Sstevel@tonic-gate * If we're updating a composed property group, actually
32780Sstevel@tonic-gate * update the top-level property group & return the
32790Sstevel@tonic-gate * appropriate value. But leave *nnp pointing at us.
32800Sstevel@tonic-gate */
32810Sstevel@tonic-gate cpg = np;
32820Sstevel@tonic-gate np = np->rn_cchain[0];
32830Sstevel@tonic-gate }
32840Sstevel@tonic-gate
32850Sstevel@tonic-gate RC_NODE_CHECK(np);
32860Sstevel@tonic-gate
32870Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP &&
32880Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)
32890Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
32900Sstevel@tonic-gate
32910Sstevel@tonic-gate for (;;) {
32920Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
32930Sstevel@tonic-gate nnp = cache_lookup_unlocked(bp, &np->rn_id);
32940Sstevel@tonic-gate if (nnp == NULL) {
32950Sstevel@tonic-gate cache_release(bp);
32960Sstevel@tonic-gate rc_node_clear(npp, 1);
32970Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
32980Sstevel@tonic-gate }
32990Sstevel@tonic-gate /*
33000Sstevel@tonic-gate * grab the lock before dropping the cache bucket, so
33010Sstevel@tonic-gate * that no one else can sneak in
33020Sstevel@tonic-gate */
33030Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock);
33040Sstevel@tonic-gate cache_release(bp);
33050Sstevel@tonic-gate
33060Sstevel@tonic-gate if (!(nnp->rn_flags & RC_NODE_IN_TX) ||
33070Sstevel@tonic-gate !rc_node_wait_flag(nnp, RC_NODE_IN_TX))
33080Sstevel@tonic-gate break;
33090Sstevel@tonic-gate
33100Sstevel@tonic-gate rc_node_rele_locked(nnp);
33110Sstevel@tonic-gate }
33120Sstevel@tonic-gate
33130Sstevel@tonic-gate /*
33140Sstevel@tonic-gate * If it is dead, we want to update it so that it will continue to
33150Sstevel@tonic-gate * report being dead.
33160Sstevel@tonic-gate */
33170Sstevel@tonic-gate if (nnp->rn_flags & RC_NODE_DEAD) {
33180Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
33190Sstevel@tonic-gate if (nnp != np && cpg == NULL)
33200Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */
33210Sstevel@tonic-gate rc_node_rele(nnp);
33220Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
33230Sstevel@tonic-gate }
33240Sstevel@tonic-gate
33250Sstevel@tonic-gate assert(!(nnp->rn_flags & RC_NODE_OLD));
33260Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
33270Sstevel@tonic-gate
33280Sstevel@tonic-gate if (nnp != np && cpg == NULL)
33290Sstevel@tonic-gate rc_node_assign(npp, nnp); /* updated */
33300Sstevel@tonic-gate
33310Sstevel@tonic-gate rc_node_rele(nnp);
33320Sstevel@tonic-gate
33330Sstevel@tonic-gate return ((nnp == np)? REP_PROTOCOL_SUCCESS : REP_PROTOCOL_DONE);
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate
33360Sstevel@tonic-gate /*
33370Sstevel@tonic-gate * does a generic modification check, for creation, deletion, and snapshot
33380Sstevel@tonic-gate * management only. Property group transactions have different checks.
33395777Stw21770 *
33405777Stw21770 * The string returned to *match_auth must be freed.
33410Sstevel@tonic-gate */
33428497SThomas.Whitten@Sun.COM static perm_status_t
rc_node_modify_permission_check(char ** match_auth)33435777Stw21770 rc_node_modify_permission_check(char **match_auth)
33440Sstevel@tonic-gate {
33450Sstevel@tonic-gate permcheck_t *pcp;
33468497SThomas.Whitten@Sun.COM perm_status_t granted = PERM_GRANTED;
33478497SThomas.Whitten@Sun.COM int rc;
33480Sstevel@tonic-gate
33495777Stw21770 *match_auth = NULL;
33500Sstevel@tonic-gate #ifdef NATIVE_BUILD
33515777Stw21770 if (!client_is_privileged()) {
33528497SThomas.Whitten@Sun.COM granted = PERM_DENIED;
33538497SThomas.Whitten@Sun.COM }
33548497SThomas.Whitten@Sun.COM return (granted);
33550Sstevel@tonic-gate #else
33565777Stw21770 if (is_main_repository == 0)
33578497SThomas.Whitten@Sun.COM return (PERM_GRANTED);
33585777Stw21770 pcp = pc_create();
33595777Stw21770 if (pcp != NULL) {
33605777Stw21770 rc = perm_add_enabling(pcp, AUTH_MODIFY);
33615777Stw21770
33625777Stw21770 if (rc == REP_PROTOCOL_SUCCESS) {
33635777Stw21770 granted = perm_granted(pcp);
33645777Stw21770
33658497SThomas.Whitten@Sun.COM if ((granted == PERM_GRANTED) ||
33668497SThomas.Whitten@Sun.COM (granted == PERM_DENIED)) {
33675777Stw21770 /*
33685777Stw21770 * Copy off the authorization
33695777Stw21770 * string before freeing pcp.
33705777Stw21770 */
33715777Stw21770 *match_auth =
33725777Stw21770 strdup(pcp->pc_auth_string);
33735777Stw21770 if (*match_auth == NULL)
33748497SThomas.Whitten@Sun.COM granted = PERM_FAIL;
33750Sstevel@tonic-gate }
33768497SThomas.Whitten@Sun.COM } else {
33778497SThomas.Whitten@Sun.COM granted = PERM_FAIL;
33780Sstevel@tonic-gate }
33790Sstevel@tonic-gate
33805777Stw21770 pc_free(pcp);
33815777Stw21770 } else {
33828497SThomas.Whitten@Sun.COM granted = PERM_FAIL;
33838497SThomas.Whitten@Sun.COM }
33848497SThomas.Whitten@Sun.COM
33858497SThomas.Whitten@Sun.COM return (granted);
33860Sstevel@tonic-gate #endif /* NATIVE_BUILD */
33875777Stw21770 }
33885777Stw21770
33895777Stw21770 /*
33905777Stw21770 * Native builds are done to create svc.configd-native. This program runs
33915777Stw21770 * only on the Solaris build machines to create the seed repository, and it
33925777Stw21770 * is compiled against the build machine's header files. The ADT_smf_*
33935777Stw21770 * symbols may not be defined in these header files. For this reason
33945777Stw21770 * smf_annotation_event(), _smf_audit_event() and special_property_event()
33955777Stw21770 * are not compiled for native builds.
33965777Stw21770 */
33975777Stw21770 #ifndef NATIVE_BUILD
33985777Stw21770
33995777Stw21770 /*
34005777Stw21770 * This function generates an annotation audit event if one has been setup.
34015777Stw21770 * Annotation events should only be generated immediately before the audit
34025777Stw21770 * record from the first attempt to modify the repository from a client
34035777Stw21770 * which has requested an annotation.
34045777Stw21770 */
34055777Stw21770 static void
smf_annotation_event(int status,int return_val)34065777Stw21770 smf_annotation_event(int status, int return_val)
34075777Stw21770 {
34085777Stw21770 adt_session_data_t *session;
34095777Stw21770 adt_event_data_t *event = NULL;
34105777Stw21770 char file[MAXPATHLEN];
34115777Stw21770 char operation[REP_PROTOCOL_NAME_LEN];
34125777Stw21770
34135777Stw21770 /* Don't audit if we're using an alternate repository. */
34145777Stw21770 if (is_main_repository == 0)
34155777Stw21770 return;
34165777Stw21770
34175777Stw21770 if (client_annotation_needed(operation, sizeof (operation), file,
34185777Stw21770 sizeof (file)) == 0) {
34195777Stw21770 return;
34205777Stw21770 }
34215777Stw21770 if (file[0] == 0) {
34225777Stw21770 (void) strlcpy(file, "NO FILE", sizeof (file));
34235777Stw21770 }
34245777Stw21770 if (operation[0] == 0) {
34255777Stw21770 (void) strlcpy(operation, "NO OPERATION",
34265777Stw21770 sizeof (operation));
34275777Stw21770 }
34285777Stw21770 if ((session = get_audit_session()) == NULL)
34295777Stw21770 return;
34305777Stw21770 if ((event = adt_alloc_event(session, ADT_smf_annotation)) == NULL) {
34315777Stw21770 uu_warn("smf_annotation_event cannot allocate event "
34325777Stw21770 "data. %s\n", strerror(errno));
34335777Stw21770 return;
34345777Stw21770 }
34355777Stw21770 event->adt_smf_annotation.operation = operation;
34365777Stw21770 event->adt_smf_annotation.file = file;
34375777Stw21770 if (adt_put_event(event, status, return_val) == 0) {
34385777Stw21770 client_annotation_finished();
34395777Stw21770 } else {
34405777Stw21770 uu_warn("smf_annotation_event failed to put event. "
34415777Stw21770 "%s\n", strerror(errno));
34425777Stw21770 }
34435777Stw21770 adt_free_event(event);
34445777Stw21770 }
34455777Stw21770
34465777Stw21770 /*
34475777Stw21770 * _smf_audit_event interacts with the security auditing system to generate
34485777Stw21770 * an audit event structure. It establishes an audit session and allocates
34495777Stw21770 * an audit event. The event is filled in from the audit data, and
34505777Stw21770 * adt_put_event is called to generate the event.
34515777Stw21770 */
34525777Stw21770 static void
_smf_audit_event(au_event_t event_id,int status,int return_val,audit_event_data_t * data)34535777Stw21770 _smf_audit_event(au_event_t event_id, int status, int return_val,
34545777Stw21770 audit_event_data_t *data)
34555777Stw21770 {
34565777Stw21770 char *auth_used;
34575777Stw21770 char *fmri;
34585777Stw21770 char *prop_value;
34595777Stw21770 adt_session_data_t *session;
34605777Stw21770 adt_event_data_t *event = NULL;
34615777Stw21770
34625777Stw21770 /* Don't audit if we're using an alternate repository */
34635777Stw21770 if (is_main_repository == 0)
34645777Stw21770 return;
34655777Stw21770
34665777Stw21770 smf_annotation_event(status, return_val);
34675777Stw21770 if ((session = get_audit_session()) == NULL)
34685777Stw21770 return;
34695777Stw21770 if ((event = adt_alloc_event(session, event_id)) == NULL) {
34705777Stw21770 uu_warn("_smf_audit_event cannot allocate event "
34715777Stw21770 "data. %s\n", strerror(errno));
34725777Stw21770 return;
34735777Stw21770 }
34745777Stw21770
34755777Stw21770 /*
34765777Stw21770 * Handle possibility of NULL authorization strings, FMRIs and
34775777Stw21770 * property values.
34785777Stw21770 */
34795777Stw21770 if (data->ed_auth == NULL) {
34805777Stw21770 auth_used = "PRIVILEGED";
34815777Stw21770 } else {
34825777Stw21770 auth_used = data->ed_auth;
34835777Stw21770 }
34845777Stw21770 if (data->ed_fmri == NULL) {
34855777Stw21770 syslog(LOG_WARNING, "_smf_audit_event called with "
34865777Stw21770 "empty FMRI string");
34875777Stw21770 fmri = "UNKNOWN FMRI";
34885777Stw21770 } else {
34895777Stw21770 fmri = data->ed_fmri;
34905777Stw21770 }
34915777Stw21770 if (data->ed_prop_value == NULL) {
34925777Stw21770 prop_value = "";
34935777Stw21770 } else {
34945777Stw21770 prop_value = data->ed_prop_value;
34955777Stw21770 }
34965777Stw21770
34975777Stw21770 /* Fill in the event data. */
34985777Stw21770 switch (event_id) {
34995777Stw21770 case ADT_smf_attach_snap:
35005777Stw21770 event->adt_smf_attach_snap.auth_used = auth_used;
35015777Stw21770 event->adt_smf_attach_snap.old_fmri = data->ed_old_fmri;
35025777Stw21770 event->adt_smf_attach_snap.old_name = data->ed_old_name;
35035777Stw21770 event->adt_smf_attach_snap.new_fmri = fmri;
35045777Stw21770 event->adt_smf_attach_snap.new_name = data->ed_snapname;
35055777Stw21770 break;
35065777Stw21770 case ADT_smf_change_prop:
35075777Stw21770 event->adt_smf_change_prop.auth_used = auth_used;
35085777Stw21770 event->adt_smf_change_prop.fmri = fmri;
35095777Stw21770 event->adt_smf_change_prop.type = data->ed_type;
35105777Stw21770 event->adt_smf_change_prop.value = prop_value;
35115777Stw21770 break;
35125777Stw21770 case ADT_smf_clear:
35135777Stw21770 event->adt_smf_clear.auth_used = auth_used;
35145777Stw21770 event->adt_smf_clear.fmri = fmri;
35155777Stw21770 break;
35165777Stw21770 case ADT_smf_create:
35175777Stw21770 event->adt_smf_create.fmri = fmri;
35185777Stw21770 event->adt_smf_create.auth_used = auth_used;
35195777Stw21770 break;
35205777Stw21770 case ADT_smf_create_npg:
35215777Stw21770 event->adt_smf_create_npg.auth_used = auth_used;
35225777Stw21770 event->adt_smf_create_npg.fmri = fmri;
35235777Stw21770 event->adt_smf_create_npg.type = data->ed_type;
35245777Stw21770 break;
35255777Stw21770 case ADT_smf_create_pg:
35265777Stw21770 event->adt_smf_create_pg.auth_used = auth_used;
35275777Stw21770 event->adt_smf_create_pg.fmri = fmri;
35285777Stw21770 event->adt_smf_create_pg.type = data->ed_type;
35295777Stw21770 break;
35305777Stw21770 case ADT_smf_create_prop:
35315777Stw21770 event->adt_smf_create_prop.auth_used = auth_used;
35325777Stw21770 event->adt_smf_create_prop.fmri = fmri;
35335777Stw21770 event->adt_smf_create_prop.type = data->ed_type;
35345777Stw21770 event->adt_smf_create_prop.value = prop_value;
35355777Stw21770 break;
35365777Stw21770 case ADT_smf_create_snap:
35375777Stw21770 event->adt_smf_create_snap.auth_used = auth_used;
35385777Stw21770 event->adt_smf_create_snap.fmri = fmri;
35395777Stw21770 event->adt_smf_create_snap.name = data->ed_snapname;
35405777Stw21770 break;
35415777Stw21770 case ADT_smf_degrade:
35425777Stw21770 event->adt_smf_degrade.auth_used = auth_used;
35435777Stw21770 event->adt_smf_degrade.fmri = fmri;
35445777Stw21770 break;
35455777Stw21770 case ADT_smf_delete:
35465777Stw21770 event->adt_smf_delete.fmri = fmri;
35475777Stw21770 event->adt_smf_delete.auth_used = auth_used;
35485777Stw21770 break;
35495777Stw21770 case ADT_smf_delete_npg:
35505777Stw21770 event->adt_smf_delete_npg.auth_used = auth_used;
35515777Stw21770 event->adt_smf_delete_npg.fmri = fmri;
35525777Stw21770 event->adt_smf_delete_npg.type = data->ed_type;
35535777Stw21770 break;
35545777Stw21770 case ADT_smf_delete_pg:
35555777Stw21770 event->adt_smf_delete_pg.auth_used = auth_used;
35565777Stw21770 event->adt_smf_delete_pg.fmri = fmri;
35575777Stw21770 event->adt_smf_delete_pg.type = data->ed_type;
35585777Stw21770 break;
35595777Stw21770 case ADT_smf_delete_prop:
35605777Stw21770 event->adt_smf_delete_prop.auth_used = auth_used;
35615777Stw21770 event->adt_smf_delete_prop.fmri = fmri;
35625777Stw21770 break;
35635777Stw21770 case ADT_smf_delete_snap:
35645777Stw21770 event->adt_smf_delete_snap.auth_used = auth_used;
35655777Stw21770 event->adt_smf_delete_snap.fmri = fmri;
35665777Stw21770 event->adt_smf_delete_snap.name = data->ed_snapname;
35675777Stw21770 break;
35685777Stw21770 case ADT_smf_disable:
35695777Stw21770 event->adt_smf_disable.auth_used = auth_used;
35705777Stw21770 event->adt_smf_disable.fmri = fmri;
35715777Stw21770 break;
35725777Stw21770 case ADT_smf_enable:
35735777Stw21770 event->adt_smf_enable.auth_used = auth_used;
35745777Stw21770 event->adt_smf_enable.fmri = fmri;
35755777Stw21770 break;
35765777Stw21770 case ADT_smf_immediate_degrade:
35775777Stw21770 event->adt_smf_immediate_degrade.auth_used = auth_used;
35785777Stw21770 event->adt_smf_immediate_degrade.fmri = fmri;
35795777Stw21770 break;
35805777Stw21770 case ADT_smf_immediate_maintenance:
35815777Stw21770 event->adt_smf_immediate_maintenance.auth_used = auth_used;
35825777Stw21770 event->adt_smf_immediate_maintenance.fmri = fmri;
35835777Stw21770 break;
35845777Stw21770 case ADT_smf_immtmp_maintenance:
35855777Stw21770 event->adt_smf_immtmp_maintenance.auth_used = auth_used;
35865777Stw21770 event->adt_smf_immtmp_maintenance.fmri = fmri;
35875777Stw21770 break;
35885777Stw21770 case ADT_smf_maintenance:
35895777Stw21770 event->adt_smf_maintenance.auth_used = auth_used;
35905777Stw21770 event->adt_smf_maintenance.fmri = fmri;
35915777Stw21770 break;
35925777Stw21770 case ADT_smf_milestone:
35935777Stw21770 event->adt_smf_milestone.auth_used = auth_used;
35945777Stw21770 event->adt_smf_milestone.fmri = fmri;
35955777Stw21770 break;
35965777Stw21770 case ADT_smf_read_prop:
35975777Stw21770 event->adt_smf_read_prop.auth_used = auth_used;
35985777Stw21770 event->adt_smf_read_prop.fmri = fmri;
35995777Stw21770 break;
36005777Stw21770 case ADT_smf_refresh:
36015777Stw21770 event->adt_smf_refresh.auth_used = auth_used;
36025777Stw21770 event->adt_smf_refresh.fmri = fmri;
36035777Stw21770 break;
36045777Stw21770 case ADT_smf_restart:
36055777Stw21770 event->adt_smf_restart.auth_used = auth_used;
36065777Stw21770 event->adt_smf_restart.fmri = fmri;
36075777Stw21770 break;
36085777Stw21770 case ADT_smf_tmp_disable:
36095777Stw21770 event->adt_smf_tmp_disable.auth_used = auth_used;
36105777Stw21770 event->adt_smf_tmp_disable.fmri = fmri;
36115777Stw21770 break;
36125777Stw21770 case ADT_smf_tmp_enable:
36135777Stw21770 event->adt_smf_tmp_enable.auth_used = auth_used;
36145777Stw21770 event->adt_smf_tmp_enable.fmri = fmri;
36155777Stw21770 break;
36165777Stw21770 case ADT_smf_tmp_maintenance:
36175777Stw21770 event->adt_smf_tmp_maintenance.auth_used = auth_used;
36185777Stw21770 event->adt_smf_tmp_maintenance.fmri = fmri;
36195777Stw21770 break;
36205777Stw21770 default:
36215777Stw21770 abort(); /* Need to cover all SMF event IDs */
36225777Stw21770 }
36235777Stw21770
36245777Stw21770 if (adt_put_event(event, status, return_val) != 0) {
36255777Stw21770 uu_warn("_smf_audit_event failed to put event. %s\n",
36265777Stw21770 strerror(errno));
36275777Stw21770 }
36285777Stw21770 adt_free_event(event);
36295777Stw21770 }
36305777Stw21770
36315777Stw21770 /*
36325777Stw21770 * Determine if the combination of the property group at pg_name and the
36335777Stw21770 * property at prop_name are in the set of special startd properties. If
36345777Stw21770 * they are, a special audit event will be generated.
36355777Stw21770 */
36365777Stw21770 static void
special_property_event(audit_event_data_t * evdp,const char * prop_name,char * pg_name,int status,int return_val,tx_commit_data_t * tx_data,size_t cmd_no)36375777Stw21770 special_property_event(audit_event_data_t *evdp, const char *prop_name,
36385777Stw21770 char *pg_name, int status, int return_val, tx_commit_data_t *tx_data,
36395777Stw21770 size_t cmd_no)
36405777Stw21770 {
36415777Stw21770 au_event_t event_id;
36425777Stw21770 audit_special_prop_item_t search_key;
36435777Stw21770 audit_special_prop_item_t *found;
36445777Stw21770
36455777Stw21770 /* Use bsearch to find the special property information. */
36465777Stw21770 search_key.api_prop_name = prop_name;
36475777Stw21770 search_key.api_pg_name = pg_name;
36485777Stw21770 found = (audit_special_prop_item_t *)bsearch(&search_key,
36495777Stw21770 special_props_list, SPECIAL_PROP_COUNT,
36505777Stw21770 sizeof (special_props_list[0]), special_prop_compare);
36515777Stw21770 if (found == NULL) {
36525777Stw21770 /* Not a special property. */
36535777Stw21770 return;
36545777Stw21770 }
36555777Stw21770
36565777Stw21770 /* Get the event id */
36575777Stw21770 if (found->api_event_func == NULL) {
36585777Stw21770 event_id = found->api_event_id;
36595777Stw21770 } else {
36605777Stw21770 if ((*found->api_event_func)(tx_data, cmd_no,
36615777Stw21770 found->api_pg_name, &event_id) < 0)
36625777Stw21770 return;
36635777Stw21770 }
36645777Stw21770
36655777Stw21770 /* Generate the event. */
36665777Stw21770 smf_audit_event(event_id, status, return_val, evdp);
36675777Stw21770 }
36685777Stw21770 #endif /* NATIVE_BUILD */
36695777Stw21770
36705777Stw21770 /*
36715777Stw21770 * Return a pointer to a string containing all the values of the command
36725777Stw21770 * specified by cmd_no with each value enclosed in quotes. It is up to the
36735777Stw21770 * caller to free the memory at the returned pointer.
36745777Stw21770 */
36755777Stw21770 static char *
generate_value_list(tx_commit_data_t * tx_data,size_t cmd_no)36765777Stw21770 generate_value_list(tx_commit_data_t *tx_data, size_t cmd_no)
36775777Stw21770 {
36785777Stw21770 const char *cp;
36795777Stw21770 const char *cur_value;
36805777Stw21770 size_t byte_count = 0;
36815777Stw21770 uint32_t i;
36825777Stw21770 uint32_t nvalues;
36835777Stw21770 size_t str_size = 0;
36845777Stw21770 char *values = NULL;
36855777Stw21770 char *vp;
36865777Stw21770
36875777Stw21770 if (tx_cmd_nvalues(tx_data, cmd_no, &nvalues) != REP_PROTOCOL_SUCCESS)
36885777Stw21770 return (NULL);
36895777Stw21770 /*
36905777Stw21770 * First determine the size of the buffer that we will need. We
36915777Stw21770 * will represent each property value surrounded by quotes with a
36925777Stw21770 * space separating the values. Thus, we need to find the total
36935777Stw21770 * size of all the value strings and add 3 for each value.
36945777Stw21770 *
36955777Stw21770 * There is one catch, though. We need to escape any internal
36965777Stw21770 * quote marks in the values. So for each quote in the value we
36975777Stw21770 * need to add another byte to the buffer size.
36985777Stw21770 */
36995777Stw21770 for (i = 0; i < nvalues; i++) {
37005777Stw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
37015777Stw21770 REP_PROTOCOL_SUCCESS)
37025777Stw21770 return (NULL);
37035777Stw21770 for (cp = cur_value; *cp != 0; cp++) {
37045777Stw21770 byte_count += (*cp == '"') ? 2 : 1;
37055777Stw21770 }
37065777Stw21770 byte_count += 3; /* surrounding quotes & space */
37075777Stw21770 }
37085777Stw21770 byte_count++; /* nul terminator */
37095777Stw21770 values = malloc(byte_count);
37105777Stw21770 if (values == NULL)
37115777Stw21770 return (NULL);
37125777Stw21770 *values = 0;
37135777Stw21770
37145777Stw21770 /* Now build up the string of values. */
37155777Stw21770 for (i = 0; i < nvalues; i++) {
37165777Stw21770 if (tx_cmd_value(tx_data, cmd_no, i, &cur_value) !=
37175777Stw21770 REP_PROTOCOL_SUCCESS) {
37185777Stw21770 free(values);
37195777Stw21770 return (NULL);
37205777Stw21770 }
37215777Stw21770 (void) strlcat(values, "\"", byte_count);
37225777Stw21770 for (cp = cur_value, vp = values + strlen(values);
37235777Stw21770 *cp != 0; cp++) {
37245777Stw21770 if (*cp == '"') {
37255777Stw21770 *vp++ = '\\';
37265777Stw21770 *vp++ = '"';
37275777Stw21770 } else {
37285777Stw21770 *vp++ = *cp;
37295777Stw21770 }
37305777Stw21770 }
37315777Stw21770 *vp = 0;
37325777Stw21770 str_size = strlcat(values, "\" ", byte_count);
37335777Stw21770 assert(str_size < byte_count);
37345777Stw21770 }
37355777Stw21770 if (str_size > 0)
37365777Stw21770 values[str_size - 1] = 0; /* get rid of trailing space */
37375777Stw21770 return (values);
37385777Stw21770 }
37395777Stw21770
37405777Stw21770 /*
37415777Stw21770 * generate_property_events takes the transaction commit data at tx_data
37425777Stw21770 * and generates an audit event for each command.
37435777Stw21770 *
37445777Stw21770 * Native builds are done to create svc.configd-native. This program runs
37455777Stw21770 * only on the Solaris build machines to create the seed repository. Thus,
37465777Stw21770 * no audit events should be generated when running svc.configd-native.
37475777Stw21770 */
37485777Stw21770 static void
generate_property_events(tx_commit_data_t * tx_data,char * pg_fmri,char * auth_string,int auth_status,int auth_ret_value)37495777Stw21770 generate_property_events(
37505777Stw21770 tx_commit_data_t *tx_data,
37515777Stw21770 char *pg_fmri, /* FMRI of property group */
37525777Stw21770 char *auth_string,
37535777Stw21770 int auth_status,
37545777Stw21770 int auth_ret_value)
37555777Stw21770 {
37565777Stw21770 #ifndef NATIVE_BUILD
37575777Stw21770 enum rep_protocol_transaction_action action;
37585777Stw21770 audit_event_data_t audit_data;
37595777Stw21770 size_t count;
37605777Stw21770 size_t cmd_no;
37615777Stw21770 char *cp;
37625777Stw21770 au_event_t event_id;
37635777Stw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
37645777Stw21770 char pg_name[REP_PROTOCOL_NAME_LEN];
37655777Stw21770 char *pg_end; /* End of prop. group fmri */
37665777Stw21770 const char *prop_name;
37675777Stw21770 uint32_t ptype;
37685777Stw21770 char prop_type[3];
37695777Stw21770 enum rep_protocol_responseid rc;
37705777Stw21770 size_t sz_out;
37715777Stw21770
37725777Stw21770 /* Make sure we have something to do. */
37735777Stw21770 if (tx_data == NULL)
37745777Stw21770 return;
37755777Stw21770 if ((count = tx_cmd_count(tx_data)) == 0)
37765777Stw21770 return;
37775777Stw21770
37785777Stw21770 /* Copy the property group fmri */
37795777Stw21770 pg_end = fmri;
37805777Stw21770 pg_end += strlcpy(fmri, pg_fmri, sizeof (fmri));
37815777Stw21770
37825777Stw21770 /*
37835777Stw21770 * Get the property group name. It is the first component after
37845777Stw21770 * the last occurance of SCF_FMRI_PROPERTYGRP_PREFIX in the fmri.
37855777Stw21770 */
37865777Stw21770 cp = strstr(pg_fmri, SCF_FMRI_PROPERTYGRP_PREFIX);
37875777Stw21770 if (cp == NULL) {
37885777Stw21770 pg_name[0] = 0;
37895777Stw21770 } else {
37905777Stw21770 cp += strlen(SCF_FMRI_PROPERTYGRP_PREFIX);
37915777Stw21770 (void) strlcpy(pg_name, cp, sizeof (pg_name));
37925777Stw21770 }
37935777Stw21770
37945777Stw21770 audit_data.ed_auth = auth_string;
37955777Stw21770 audit_data.ed_fmri = fmri;
37965777Stw21770 audit_data.ed_type = prop_type;
37975777Stw21770
37985777Stw21770 /*
37995777Stw21770 * Property type is two characters (see
38005777Stw21770 * rep_protocol_value_type_t), so terminate the string.
38015777Stw21770 */
38025777Stw21770 prop_type[2] = 0;
38035777Stw21770
38045777Stw21770 for (cmd_no = 0; cmd_no < count; cmd_no++) {
38055777Stw21770 /* Construct FMRI of the property */
38065777Stw21770 *pg_end = 0;
38075777Stw21770 if (tx_cmd_prop(tx_data, cmd_no, &prop_name) !=
38085777Stw21770 REP_PROTOCOL_SUCCESS) {
38095777Stw21770 continue;
38105777Stw21770 }
38115777Stw21770 rc = rc_concat_fmri_element(fmri, sizeof (fmri), &sz_out,
38125777Stw21770 prop_name, REP_PROTOCOL_ENTITY_PROPERTY);
38135777Stw21770 if (rc != REP_PROTOCOL_SUCCESS) {
38145777Stw21770 /*
38155777Stw21770 * If we can't get the FMRI, we'll abandon this
38165777Stw21770 * command
38175777Stw21770 */
38185777Stw21770 continue;
38195777Stw21770 }
38205777Stw21770
38215777Stw21770 /* Generate special property event if necessary. */
38225777Stw21770 special_property_event(&audit_data, prop_name, pg_name,
38235777Stw21770 auth_status, auth_ret_value, tx_data, cmd_no);
38245777Stw21770
38255777Stw21770 /* Capture rest of audit data. */
38265777Stw21770 if (tx_cmd_prop_type(tx_data, cmd_no, &ptype) !=
38275777Stw21770 REP_PROTOCOL_SUCCESS) {
38285777Stw21770 continue;
38295777Stw21770 }
38305777Stw21770 prop_type[0] = REP_PROTOCOL_BASE_TYPE(ptype);
38315777Stw21770 prop_type[1] = REP_PROTOCOL_SUBTYPE(ptype);
38325777Stw21770 audit_data.ed_prop_value = generate_value_list(tx_data, cmd_no);
38335777Stw21770
38345777Stw21770 /* Determine the event type. */
38355777Stw21770 if (tx_cmd_action(tx_data, cmd_no, &action) !=
38365777Stw21770 REP_PROTOCOL_SUCCESS) {
38375777Stw21770 free(audit_data.ed_prop_value);
38385777Stw21770 continue;
38395777Stw21770 }
38405777Stw21770 switch (action) {
38415777Stw21770 case REP_PROTOCOL_TX_ENTRY_NEW:
38425777Stw21770 event_id = ADT_smf_create_prop;
38435777Stw21770 break;
38445777Stw21770 case REP_PROTOCOL_TX_ENTRY_CLEAR:
38455777Stw21770 event_id = ADT_smf_change_prop;
38465777Stw21770 break;
38475777Stw21770 case REP_PROTOCOL_TX_ENTRY_REPLACE:
38485777Stw21770 event_id = ADT_smf_change_prop;
38495777Stw21770 break;
38505777Stw21770 case REP_PROTOCOL_TX_ENTRY_DELETE:
38515777Stw21770 event_id = ADT_smf_delete_prop;
38525777Stw21770 break;
38535777Stw21770 default:
38545777Stw21770 assert(0); /* Missing a case */
38555777Stw21770 free(audit_data.ed_prop_value);
38565777Stw21770 continue;
38575777Stw21770 }
38585777Stw21770
38595777Stw21770 /* Generate the event. */
38605777Stw21770 smf_audit_event(event_id, auth_status, auth_ret_value,
38615777Stw21770 &audit_data);
38625777Stw21770 free(audit_data.ed_prop_value);
38635777Stw21770 }
38645777Stw21770 #endif /* NATIVE_BUILD */
38650Sstevel@tonic-gate }
38660Sstevel@tonic-gate
38670Sstevel@tonic-gate /*
38680Sstevel@tonic-gate * Fails with
38690Sstevel@tonic-gate * _DELETED - node has been deleted
38700Sstevel@tonic-gate * _NOT_SET - npp is reset
38710Sstevel@tonic-gate * _NOT_APPLICABLE - type is _PROPERTYGRP
38720Sstevel@tonic-gate * _INVALID_TYPE - node is corrupt or type is invalid
38730Sstevel@tonic-gate * _TYPE_MISMATCH - node cannot have children of type type
38740Sstevel@tonic-gate * _BAD_REQUEST - name is invalid
38750Sstevel@tonic-gate * cannot create children for this type of node
38760Sstevel@tonic-gate * _NO_RESOURCES - out of memory, or could not allocate new id
38770Sstevel@tonic-gate * _PERMISSION_DENIED
38780Sstevel@tonic-gate * _BACKEND_ACCESS
38790Sstevel@tonic-gate * _BACKEND_READONLY
38800Sstevel@tonic-gate * _EXISTS - child already exists
38815777Stw21770 * _TRUNCATED - truncated FMRI for the audit record
38820Sstevel@tonic-gate */
38830Sstevel@tonic-gate int
rc_node_create_child(rc_node_ptr_t * npp,uint32_t type,const char * name,rc_node_ptr_t * cpp)38840Sstevel@tonic-gate rc_node_create_child(rc_node_ptr_t *npp, uint32_t type, const char *name,
38850Sstevel@tonic-gate rc_node_ptr_t *cpp)
38860Sstevel@tonic-gate {
38870Sstevel@tonic-gate rc_node_t *np;
38880Sstevel@tonic-gate rc_node_t *cp = NULL;
38898497SThomas.Whitten@Sun.COM int rc;
38908497SThomas.Whitten@Sun.COM perm_status_t perm_rc;
38915777Stw21770 size_t sz_out;
38925777Stw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
38935777Stw21770 audit_event_data_t audit_data;
38940Sstevel@tonic-gate
38950Sstevel@tonic-gate rc_node_clear(cpp, 0);
38960Sstevel@tonic-gate
38978497SThomas.Whitten@Sun.COM /*
38988497SThomas.Whitten@Sun.COM * rc_node_modify_permission_check() must be called before the node
38998497SThomas.Whitten@Sun.COM * is locked. This is because the library functions that check
39008497SThomas.Whitten@Sun.COM * authorizations can trigger calls back into configd.
39018497SThomas.Whitten@Sun.COM */
39025777Stw21770 perm_rc = rc_node_modify_permission_check(&audit_data.ed_auth);
39038497SThomas.Whitten@Sun.COM switch (perm_rc) {
39048497SThomas.Whitten@Sun.COM case PERM_DENIED:
39058497SThomas.Whitten@Sun.COM /*
39068497SThomas.Whitten@Sun.COM * We continue in this case, so that an audit event can be
39078497SThomas.Whitten@Sun.COM * generated later in the function.
39088497SThomas.Whitten@Sun.COM */
39098497SThomas.Whitten@Sun.COM break;
39108497SThomas.Whitten@Sun.COM case PERM_GRANTED:
39118497SThomas.Whitten@Sun.COM break;
39128497SThomas.Whitten@Sun.COM case PERM_GONE:
39138497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
39148497SThomas.Whitten@Sun.COM case PERM_FAIL:
39158497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_NO_RESOURCES);
39168497SThomas.Whitten@Sun.COM default:
39178497SThomas.Whitten@Sun.COM bad_error(rc_node_modify_permission_check, perm_rc);
39188497SThomas.Whitten@Sun.COM }
39198497SThomas.Whitten@Sun.COM
39208497SThomas.Whitten@Sun.COM RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
39210Sstevel@tonic-gate
39225777Stw21770 audit_data.ed_fmri = fmri;
39235777Stw21770
39240Sstevel@tonic-gate /*
39250Sstevel@tonic-gate * there is a separate interface for creating property groups
39260Sstevel@tonic-gate */
39270Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
39280Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39295777Stw21770 free(audit_data.ed_auth);
39300Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
39310Sstevel@tonic-gate }
39320Sstevel@tonic-gate
39330Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
39340Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39350Sstevel@tonic-gate np = np->rn_cchain[0];
39368497SThomas.Whitten@Sun.COM if ((rc = rc_node_check_and_lock(np)) != REP_PROTOCOL_SUCCESS) {
39378497SThomas.Whitten@Sun.COM free(audit_data.ed_auth);
39388497SThomas.Whitten@Sun.COM return (rc);
39398497SThomas.Whitten@Sun.COM }
39400Sstevel@tonic-gate }
39410Sstevel@tonic-gate
39420Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
39430Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
39440Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39455777Stw21770 free(audit_data.ed_auth);
39460Sstevel@tonic-gate return (rc);
39470Sstevel@tonic-gate }
39480Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS) {
39490Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39505777Stw21770 free(audit_data.ed_auth);
39510Sstevel@tonic-gate return (rc);
39520Sstevel@tonic-gate }
39530Sstevel@tonic-gate
39545777Stw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
39555777Stw21770 name, type)) != REP_PROTOCOL_SUCCESS) {
39565777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
39575777Stw21770 free(audit_data.ed_auth);
39585777Stw21770 return (rc);
39595777Stw21770 }
39608497SThomas.Whitten@Sun.COM if (perm_rc == PERM_DENIED) {
39610Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39625777Stw21770 smf_audit_event(ADT_smf_create, ADT_FAILURE,
39635777Stw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
39645777Stw21770 free(audit_data.ed_auth);
39658497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
39660Sstevel@tonic-gate }
39670Sstevel@tonic-gate
39685777Stw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
39695777Stw21770 audit_data.ed_auth);
39700Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39710Sstevel@tonic-gate
39720Sstevel@tonic-gate rc = object_create(np, type, name, &cp);
39730Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
39740Sstevel@tonic-gate
39750Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
39760Sstevel@tonic-gate rc_node_assign(cpp, cp);
39770Sstevel@tonic-gate rc_node_rele(cp);
39780Sstevel@tonic-gate }
39790Sstevel@tonic-gate
39800Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
39810Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
39820Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
39830Sstevel@tonic-gate
39845777Stw21770 if (rc == REP_PROTOCOL_SUCCESS) {
39855777Stw21770 smf_audit_event(ADT_smf_create, ADT_SUCCESS, ADT_SUCCESS,
39865777Stw21770 &audit_data);
39875777Stw21770 }
39885777Stw21770
39895777Stw21770 free(audit_data.ed_auth);
39905777Stw21770
39910Sstevel@tonic-gate return (rc);
39920Sstevel@tonic-gate }
39930Sstevel@tonic-gate
39940Sstevel@tonic-gate int
rc_node_create_child_pg(rc_node_ptr_t * npp,uint32_t type,const char * name,const char * pgtype,uint32_t flags,rc_node_ptr_t * cpp)39950Sstevel@tonic-gate rc_node_create_child_pg(rc_node_ptr_t *npp, uint32_t type, const char *name,
39960Sstevel@tonic-gate const char *pgtype, uint32_t flags, rc_node_ptr_t *cpp)
39970Sstevel@tonic-gate {
39980Sstevel@tonic-gate rc_node_t *np;
39990Sstevel@tonic-gate rc_node_t *cp;
40000Sstevel@tonic-gate int rc;
40010Sstevel@tonic-gate permcheck_t *pcp;
40028497SThomas.Whitten@Sun.COM perm_status_t granted;
40035777Stw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
40045777Stw21770 audit_event_data_t audit_data;
40055777Stw21770 au_event_t event_id;
40065777Stw21770 size_t sz_out;
40075777Stw21770
40085777Stw21770 audit_data.ed_auth = NULL;
40095777Stw21770 audit_data.ed_fmri = fmri;
40105777Stw21770 audit_data.ed_type = (char *)pgtype;
40110Sstevel@tonic-gate
40120Sstevel@tonic-gate rc_node_clear(cpp, 0);
40130Sstevel@tonic-gate
40140Sstevel@tonic-gate /* verify flags is valid */
40150Sstevel@tonic-gate if (flags & ~SCF_PG_FLAG_NONPERSISTENT)
40160Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
40170Sstevel@tonic-gate
40180Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
40190Sstevel@tonic-gate
40200Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
40210Sstevel@tonic-gate rc_node_rele(np);
40220Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
40230Sstevel@tonic-gate }
40240Sstevel@tonic-gate
40250Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
40260Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
40270Sstevel@tonic-gate rc_node_rele(np);
40280Sstevel@tonic-gate return (rc);
40290Sstevel@tonic-gate }
40300Sstevel@tonic-gate if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS ||
40310Sstevel@tonic-gate (rc = rc_check_pgtype_name(pgtype)) != REP_PROTOCOL_SUCCESS) {
40320Sstevel@tonic-gate rc_node_rele(np);
40330Sstevel@tonic-gate return (rc);
40340Sstevel@tonic-gate }
40350Sstevel@tonic-gate
40365777Stw21770 #ifdef NATIVE_BUILD
40375496Sdm120769 if (!client_is_privileged()) {
40380Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
40395777Stw21770 }
40400Sstevel@tonic-gate #else
40415777Stw21770 if (flags & SCF_PG_FLAG_NONPERSISTENT) {
40425777Stw21770 event_id = ADT_smf_create_npg;
40435777Stw21770 } else {
40445777Stw21770 event_id = ADT_smf_create_pg;
40455777Stw21770 }
40465777Stw21770 if ((rc = rc_get_fmri_and_concat(np, fmri, sizeof (fmri), &sz_out,
40475777Stw21770 name, REP_PROTOCOL_ENTITY_PROPERTYGRP)) != REP_PROTOCOL_SUCCESS) {
40485777Stw21770 rc_node_rele(np);
40495777Stw21770 return (rc);
40505777Stw21770 }
40515777Stw21770
40525777Stw21770 if (is_main_repository) {
40530Sstevel@tonic-gate /* Must have .smf.modify or smf.modify.<type> authorization */
40540Sstevel@tonic-gate pcp = pc_create();
40550Sstevel@tonic-gate if (pcp != NULL) {
40560Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
40570Sstevel@tonic-gate
40580Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
40590Sstevel@tonic-gate const char * const auth =
40600Sstevel@tonic-gate perm_auth_for_pgtype(pgtype);
40610Sstevel@tonic-gate
40620Sstevel@tonic-gate if (auth != NULL)
40630Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
40640Sstevel@tonic-gate }
40650Sstevel@tonic-gate
40660Sstevel@tonic-gate /*
40670Sstevel@tonic-gate * .manage or $action_authorization can be used to
40680Sstevel@tonic-gate * create the actions pg and the general_ovr pg.
40690Sstevel@tonic-gate */
40700Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS &&
40710Sstevel@tonic-gate (flags & SCF_PG_FLAG_NONPERSISTENT) != 0 &&
40720Sstevel@tonic-gate np->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE &&
40730Sstevel@tonic-gate ((strcmp(name, AUTH_PG_ACTIONS) == 0 &&
40740Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_ACTIONS_TYPE) == 0) ||
40750Sstevel@tonic-gate (strcmp(name, AUTH_PG_GENERAL_OVR) == 0 &&
40760Sstevel@tonic-gate strcmp(pgtype, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
40770Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MANAGE);
40780Sstevel@tonic-gate
40790Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS)
40800Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, np);
40810Sstevel@tonic-gate }
40820Sstevel@tonic-gate
40830Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
40840Sstevel@tonic-gate granted = perm_granted(pcp);
40850Sstevel@tonic-gate
40868497SThomas.Whitten@Sun.COM rc = map_granted_status(granted, pcp,
40878497SThomas.Whitten@Sun.COM &audit_data.ed_auth);
40888497SThomas.Whitten@Sun.COM if (granted == PERM_GONE) {
40898497SThomas.Whitten@Sun.COM /* No auditing if client gone. */
40908497SThomas.Whitten@Sun.COM pc_free(pcp);
40918497SThomas.Whitten@Sun.COM rc_node_rele(np);
40928497SThomas.Whitten@Sun.COM return (rc);
40935777Stw21770 }
40940Sstevel@tonic-gate }
40950Sstevel@tonic-gate
40960Sstevel@tonic-gate pc_free(pcp);
40970Sstevel@tonic-gate } else {
40980Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
40990Sstevel@tonic-gate }
41000Sstevel@tonic-gate
41015777Stw21770 } else {
41025777Stw21770 rc = REP_PROTOCOL_SUCCESS;
41035777Stw21770 }
41040Sstevel@tonic-gate #endif /* NATIVE_BUILD */
41050Sstevel@tonic-gate
41068497SThomas.Whitten@Sun.COM
41075777Stw21770 if (rc != REP_PROTOCOL_SUCCESS) {
41085777Stw21770 rc_node_rele(np);
41098497SThomas.Whitten@Sun.COM if (rc != REP_PROTOCOL_FAIL_NO_RESOURCES) {
41108497SThomas.Whitten@Sun.COM smf_audit_event(event_id, ADT_FAILURE,
41118497SThomas.Whitten@Sun.COM ADT_FAIL_VALUE_AUTH, &audit_data);
41128497SThomas.Whitten@Sun.COM }
41135777Stw21770 if (audit_data.ed_auth != NULL)
41145777Stw21770 free(audit_data.ed_auth);
41155777Stw21770 return (rc);
41160Sstevel@tonic-gate }
41170Sstevel@tonic-gate
41180Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41195777Stw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
41205777Stw21770 audit_data.ed_auth);
41210Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41220Sstevel@tonic-gate
41230Sstevel@tonic-gate rc = object_create_pg(np, type, name, pgtype, flags, &cp);
41240Sstevel@tonic-gate
41250Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
41260Sstevel@tonic-gate rc_node_assign(cpp, cp);
41270Sstevel@tonic-gate rc_node_rele(cp);
41280Sstevel@tonic-gate }
41290Sstevel@tonic-gate
41300Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41310Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
41320Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41330Sstevel@tonic-gate
41345777Stw21770 if (rc == REP_PROTOCOL_SUCCESS) {
41355777Stw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
41365777Stw21770 &audit_data);
41375777Stw21770 }
41385777Stw21770 if (audit_data.ed_auth != NULL)
41395777Stw21770 free(audit_data.ed_auth);
41405777Stw21770
41410Sstevel@tonic-gate return (rc);
41420Sstevel@tonic-gate }
41430Sstevel@tonic-gate
41440Sstevel@tonic-gate static void
rc_pg_notify_fire(rc_node_pg_notify_t * pnp)41450Sstevel@tonic-gate rc_pg_notify_fire(rc_node_pg_notify_t *pnp)
41460Sstevel@tonic-gate {
41470Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
41480Sstevel@tonic-gate
41490Sstevel@tonic-gate if (pnp->rnpn_pg != NULL) {
41500Sstevel@tonic-gate uu_list_remove(pnp->rnpn_pg->rn_pg_notify_list, pnp);
41510Sstevel@tonic-gate (void) close(pnp->rnpn_fd);
41520Sstevel@tonic-gate
41530Sstevel@tonic-gate pnp->rnpn_pg = NULL;
41540Sstevel@tonic-gate pnp->rnpn_fd = -1;
41550Sstevel@tonic-gate } else {
41560Sstevel@tonic-gate assert(pnp->rnpn_fd == -1);
41570Sstevel@tonic-gate }
41580Sstevel@tonic-gate }
41590Sstevel@tonic-gate
41600Sstevel@tonic-gate static void
rc_notify_node_delete(rc_notify_delete_t * ndp,rc_node_t * np_arg)41610Sstevel@tonic-gate rc_notify_node_delete(rc_notify_delete_t *ndp, rc_node_t *np_arg)
41620Sstevel@tonic-gate {
41630Sstevel@tonic-gate rc_node_t *svc = NULL;
41640Sstevel@tonic-gate rc_node_t *inst = NULL;
41650Sstevel@tonic-gate rc_node_t *pg = NULL;
41660Sstevel@tonic-gate rc_node_t *np = np_arg;
41670Sstevel@tonic-gate rc_node_t *nnp;
41680Sstevel@tonic-gate
41690Sstevel@tonic-gate while (svc == NULL) {
41700Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
41710Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
41720Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41730Sstevel@tonic-gate goto cleanup;
41740Sstevel@tonic-gate }
41750Sstevel@tonic-gate nnp = np->rn_parent;
41760Sstevel@tonic-gate rc_node_hold_locked(np); /* hold it in place */
41770Sstevel@tonic-gate
41780Sstevel@tonic-gate switch (np->rn_id.rl_type) {
41790Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP:
41800Sstevel@tonic-gate assert(pg == NULL);
41810Sstevel@tonic-gate pg = np;
41820Sstevel@tonic-gate break;
41830Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE:
41840Sstevel@tonic-gate assert(inst == NULL);
41850Sstevel@tonic-gate inst = np;
41860Sstevel@tonic-gate break;
41870Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE:
41880Sstevel@tonic-gate assert(svc == NULL);
41890Sstevel@tonic-gate svc = np;
41900Sstevel@tonic-gate break;
41910Sstevel@tonic-gate default:
41920Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
41930Sstevel@tonic-gate rc_node_rele_locked(np);
41940Sstevel@tonic-gate goto cleanup;
41950Sstevel@tonic-gate }
41960Sstevel@tonic-gate
41970Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
41980Sstevel@tonic-gate
41990Sstevel@tonic-gate np = nnp;
42000Sstevel@tonic-gate if (np == NULL)
42010Sstevel@tonic-gate goto cleanup;
42020Sstevel@tonic-gate }
42030Sstevel@tonic-gate
42040Sstevel@tonic-gate rc_notify_deletion(ndp,
42050Sstevel@tonic-gate svc->rn_name,
42060Sstevel@tonic-gate inst != NULL ? inst->rn_name : NULL,
42070Sstevel@tonic-gate pg != NULL ? pg->rn_name : NULL);
42080Sstevel@tonic-gate
42090Sstevel@tonic-gate ndp = NULL;
42100Sstevel@tonic-gate
42110Sstevel@tonic-gate cleanup:
42120Sstevel@tonic-gate if (ndp != NULL)
42130Sstevel@tonic-gate uu_free(ndp);
42140Sstevel@tonic-gate
42150Sstevel@tonic-gate for (;;) {
42160Sstevel@tonic-gate if (svc != NULL) {
42170Sstevel@tonic-gate np = svc;
42180Sstevel@tonic-gate svc = NULL;
42190Sstevel@tonic-gate } else if (inst != NULL) {
42200Sstevel@tonic-gate np = inst;
42210Sstevel@tonic-gate inst = NULL;
42220Sstevel@tonic-gate } else if (pg != NULL) {
42230Sstevel@tonic-gate np = pg;
42240Sstevel@tonic-gate pg = NULL;
42250Sstevel@tonic-gate } else
42260Sstevel@tonic-gate break;
42270Sstevel@tonic-gate
42280Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42290Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
42300Sstevel@tonic-gate rc_node_rele_locked(np);
42310Sstevel@tonic-gate }
42320Sstevel@tonic-gate }
42330Sstevel@tonic-gate
42340Sstevel@tonic-gate /*
42357266Sbustos * Hold RC_NODE_DYING_FLAGS on np's descendents. If andformer is true, do
42367266Sbustos * the same down the rn_former chain.
42370Sstevel@tonic-gate */
42380Sstevel@tonic-gate static void
rc_node_delete_hold(rc_node_t * np,int andformer)42390Sstevel@tonic-gate rc_node_delete_hold(rc_node_t *np, int andformer)
42400Sstevel@tonic-gate {
42410Sstevel@tonic-gate rc_node_t *cp;
42420Sstevel@tonic-gate
42430Sstevel@tonic-gate again:
42440Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
42450Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
42460Sstevel@tonic-gate
42470Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
42480Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
42490Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42500Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42510Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS)) {
42520Sstevel@tonic-gate /*
42530Sstevel@tonic-gate * already marked as dead -- can't happen, since that
42540Sstevel@tonic-gate * would require setting RC_NODE_CHILDREN_CHANGING
42550Sstevel@tonic-gate * in np, and we're holding that...
42560Sstevel@tonic-gate */
42570Sstevel@tonic-gate abort();
42580Sstevel@tonic-gate }
42590Sstevel@tonic-gate rc_node_delete_hold(cp, andformer); /* recurse, drop lock */
42600Sstevel@tonic-gate
42610Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42620Sstevel@tonic-gate }
42630Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
42640Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42650Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42660Sstevel@tonic-gate if (!rc_node_hold_flag(cp, RC_NODE_DYING_FLAGS))
42670Sstevel@tonic-gate abort(); /* can't happen, see above */
42680Sstevel@tonic-gate np = cp;
42690Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
42700Sstevel@tonic-gate }
42710Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42720Sstevel@tonic-gate }
42730Sstevel@tonic-gate
42740Sstevel@tonic-gate /*
42750Sstevel@tonic-gate * N.B.: this function drops np->rn_lock on the way out.
42760Sstevel@tonic-gate */
42770Sstevel@tonic-gate static void
rc_node_delete_rele(rc_node_t * np,int andformer)42780Sstevel@tonic-gate rc_node_delete_rele(rc_node_t *np, int andformer)
42790Sstevel@tonic-gate {
42800Sstevel@tonic-gate rc_node_t *cp;
42810Sstevel@tonic-gate
42820Sstevel@tonic-gate again:
42830Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
42840Sstevel@tonic-gate assert((np->rn_flags & RC_NODE_DYING_FLAGS) == RC_NODE_DYING_FLAGS);
42850Sstevel@tonic-gate
42860Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children); cp != NULL;
42870Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
42880Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42890Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42900Sstevel@tonic-gate rc_node_delete_rele(cp, andformer); /* recurse, drop lock */
42910Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
42920Sstevel@tonic-gate }
42930Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
42940Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
42950Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
42960Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
42970Sstevel@tonic-gate
42980Sstevel@tonic-gate np = cp;
42990Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
43000Sstevel@tonic-gate }
43010Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
43020Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
43030Sstevel@tonic-gate }
43040Sstevel@tonic-gate
43050Sstevel@tonic-gate static void
rc_node_finish_delete(rc_node_t * cp)43060Sstevel@tonic-gate rc_node_finish_delete(rc_node_t *cp)
43070Sstevel@tonic-gate {
43080Sstevel@tonic-gate cache_bucket_t *bp;
43090Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
43100Sstevel@tonic-gate
43110Sstevel@tonic-gate assert(MUTEX_HELD(&cp->rn_lock));
43120Sstevel@tonic-gate
43130Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) {
43140Sstevel@tonic-gate assert(cp->rn_flags & RC_NODE_IN_PARENT);
43150Sstevel@tonic-gate if (!rc_node_wait_flag(cp, RC_NODE_USING_PARENT)) {
43160Sstevel@tonic-gate abort(); /* can't happen, see above */
43170Sstevel@tonic-gate }
43180Sstevel@tonic-gate cp->rn_flags &= ~RC_NODE_IN_PARENT;
43190Sstevel@tonic-gate cp->rn_parent = NULL;
43205777Stw21770 rc_node_free_fmri(cp);
43210Sstevel@tonic-gate }
43220Sstevel@tonic-gate
43230Sstevel@tonic-gate cp->rn_flags |= RC_NODE_DEAD;
43240Sstevel@tonic-gate
43250Sstevel@tonic-gate /*
43260Sstevel@tonic-gate * If this node is not out-dated, we need to remove it from
43270Sstevel@tonic-gate * the notify list and cache hash table.
43280Sstevel@tonic-gate */
43290Sstevel@tonic-gate if (!(cp->rn_flags & RC_NODE_OLD)) {
43300Sstevel@tonic-gate assert(cp->rn_refs > 0); /* can't go away yet */
43310Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
43320Sstevel@tonic-gate
43330Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
43340Sstevel@tonic-gate while ((pnp = uu_list_first(cp->rn_pg_notify_list)) != NULL)
43350Sstevel@tonic-gate rc_pg_notify_fire(pnp);
43360Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
43370Sstevel@tonic-gate rc_notify_remove_node(cp);
43380Sstevel@tonic-gate
43390Sstevel@tonic-gate bp = cache_hold(cp->rn_hash);
43400Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43410Sstevel@tonic-gate cache_remove_unlocked(bp, cp);
43420Sstevel@tonic-gate cache_release(bp);
43430Sstevel@tonic-gate }
43440Sstevel@tonic-gate }
43450Sstevel@tonic-gate
43460Sstevel@tonic-gate /*
43477266Sbustos * For each child, call rc_node_finish_delete() and recurse. If andformer
43487266Sbustos * is set, also recurse down rn_former. Finally release np, which might
43497266Sbustos * free it.
43500Sstevel@tonic-gate */
43510Sstevel@tonic-gate static void
rc_node_delete_children(rc_node_t * np,int andformer)43520Sstevel@tonic-gate rc_node_delete_children(rc_node_t *np, int andformer)
43530Sstevel@tonic-gate {
43540Sstevel@tonic-gate rc_node_t *cp;
43550Sstevel@tonic-gate
43560Sstevel@tonic-gate again:
43570Sstevel@tonic-gate assert(np->rn_refs > 0);
43580Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
43590Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_DEAD);
43600Sstevel@tonic-gate
43610Sstevel@tonic-gate while ((cp = uu_list_first(np->rn_children)) != NULL) {
43620Sstevel@tonic-gate uu_list_remove(np->rn_children, cp);
43630Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43640Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
43650Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we recurse */
43660Sstevel@tonic-gate rc_node_finish_delete(cp);
43670Sstevel@tonic-gate rc_node_delete_children(cp, andformer); /* drops lock + ref */
43680Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
43690Sstevel@tonic-gate }
43700Sstevel@tonic-gate
43710Sstevel@tonic-gate /*
43726748Srm88369 * When we drop cp's lock, all the children will be gone, so we
43730Sstevel@tonic-gate * can release DYING_FLAGS.
43740Sstevel@tonic-gate */
43750Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
43760Sstevel@tonic-gate if (andformer && (cp = np->rn_former) != NULL) {
43770Sstevel@tonic-gate np->rn_former = NULL; /* unlink */
43780Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rn_lock);
43797266Sbustos
43807266Sbustos /*
43817266Sbustos * Register the ephemeral reference created by reading
43827266Sbustos * np->rn_former into cp. Note that the persistent
43837266Sbustos * reference (np->rn_former) is locked because we haven't
43847266Sbustos * dropped np's lock since we dropped its RC_NODE_IN_TX
43857266Sbustos * (via RC_NODE_DYING_FLAGS).
43867266Sbustos */
43877266Sbustos rc_node_hold_ephemeral_locked(cp);
43887266Sbustos
43890Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
43906748Srm88369 cp->rn_flags &= ~RC_NODE_ON_FORMER;
43910Sstevel@tonic-gate
43920Sstevel@tonic-gate rc_node_hold_locked(cp); /* hold while we loop */
43930Sstevel@tonic-gate
43940Sstevel@tonic-gate rc_node_finish_delete(cp);
43950Sstevel@tonic-gate
43960Sstevel@tonic-gate rc_node_rele(np); /* drop the old reference */
43970Sstevel@tonic-gate
43980Sstevel@tonic-gate np = cp;
43990Sstevel@tonic-gate goto again; /* tail-recurse down rn_former */
44000Sstevel@tonic-gate }
44010Sstevel@tonic-gate rc_node_rele_locked(np);
44020Sstevel@tonic-gate }
44030Sstevel@tonic-gate
44047266Sbustos /*
44057266Sbustos * The last client or child reference to np, which must be either
44067266Sbustos * RC_NODE_OLD or RC_NODE_DEAD, has been destroyed. We'll destroy any
44077266Sbustos * remaining references (e.g., rn_former) and call rc_node_destroy() to
44087266Sbustos * free np.
44097266Sbustos */
44100Sstevel@tonic-gate static void
rc_node_no_client_refs(rc_node_t * np)44117266Sbustos rc_node_no_client_refs(rc_node_t *np)
44120Sstevel@tonic-gate {
44130Sstevel@tonic-gate int unrefed;
44147266Sbustos rc_node_t *current, *cur;
44150Sstevel@tonic-gate
44160Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
44170Sstevel@tonic-gate assert(np->rn_refs == 0);
44180Sstevel@tonic-gate assert(np->rn_other_refs == 0);
44190Sstevel@tonic-gate assert(np->rn_other_refs_held == 0);
44200Sstevel@tonic-gate
44210Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD) {
44227266Sbustos /*
44237266Sbustos * The node is DEAD, so the deletion code should have
44247266Sbustos * destroyed all rn_children or rn_former references.
44257266Sbustos * Since the last client or child reference has been
44267266Sbustos * destroyed, we're free to destroy np. Unless another
44277266Sbustos * thread has an ephemeral reference, in which case we'll
44287266Sbustos * pass the buck.
44297266Sbustos */
44307266Sbustos if (np->rn_erefs > 1) {
44317266Sbustos --np->rn_erefs;
44327266Sbustos NODE_UNLOCK(np);
44337266Sbustos return;
44347266Sbustos }
44357266Sbustos
44360Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44370Sstevel@tonic-gate rc_node_destroy(np);
44380Sstevel@tonic-gate return;
44390Sstevel@tonic-gate }
44400Sstevel@tonic-gate
44417266Sbustos /* We only collect DEAD and OLD nodes, thank you. */
44420Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_OLD);
44437266Sbustos
44447266Sbustos /*
44457266Sbustos * RC_NODE_UNREFED keeps multiple threads from processing OLD
44467266Sbustos * nodes. But it's vulnerable to unfriendly scheduling, so full
44477266Sbustos * use of rn_erefs should supersede it someday.
44487266Sbustos */
44490Sstevel@tonic-gate if (np->rn_flags & RC_NODE_UNREFED) {
44500Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44510Sstevel@tonic-gate return;
44520Sstevel@tonic-gate }
44530Sstevel@tonic-gate np->rn_flags |= RC_NODE_UNREFED;
44540Sstevel@tonic-gate
44557266Sbustos /*
44567266Sbustos * Now we'll remove the node from the rn_former chain and take its
44577266Sbustos * DYING_FLAGS.
44587266Sbustos */
44590Sstevel@tonic-gate
44600Sstevel@tonic-gate /*
44617266Sbustos * Since this node is OLD, it should be on an rn_former chain. To
44627266Sbustos * remove it, we must find the current in-hash object and grab its
44637266Sbustos * RC_NODE_IN_TX flag to protect the entire rn_former chain.
44640Sstevel@tonic-gate */
44657266Sbustos
44667266Sbustos (void) pthread_mutex_unlock(&np->rn_lock);
44677266Sbustos
44680Sstevel@tonic-gate for (;;) {
44697266Sbustos current = cache_lookup(&np->rn_id);
44707266Sbustos
44717266Sbustos if (current == NULL) {
44720Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
44737266Sbustos
44740Sstevel@tonic-gate if (np->rn_flags & RC_NODE_DEAD)
44750Sstevel@tonic-gate goto died;
44767266Sbustos
44770Sstevel@tonic-gate /*
44780Sstevel@tonic-gate * We are trying to unreference this node, but the
44790Sstevel@tonic-gate * owner of the former list does not exist. It must
44800Sstevel@tonic-gate * be the case that another thread is deleting this
44810Sstevel@tonic-gate * entire sub-branch, but has not yet reached us.
44820Sstevel@tonic-gate * We will in short order be deleted.
44830Sstevel@tonic-gate */
44840Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
44850Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
44860Sstevel@tonic-gate return;
44870Sstevel@tonic-gate }
44887266Sbustos
44897266Sbustos if (current == np) {
44900Sstevel@tonic-gate /*
44910Sstevel@tonic-gate * no longer unreferenced
44920Sstevel@tonic-gate */
44930Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
44940Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
44957266Sbustos /* held in cache_lookup() */
44960Sstevel@tonic-gate rc_node_rele_locked(np);
44970Sstevel@tonic-gate return;
44980Sstevel@tonic-gate }
44997266Sbustos
45007266Sbustos (void) pthread_mutex_lock(¤t->rn_lock);
45017266Sbustos if (current->rn_flags & RC_NODE_OLD) {
45027266Sbustos /*
45037266Sbustos * current has been replaced since we looked it
45047266Sbustos * up. Try again.
45057266Sbustos */
45067266Sbustos /* held in cache_lookup() */
45077266Sbustos rc_node_rele_locked(current);
45087266Sbustos continue;
45097266Sbustos }
45107266Sbustos
45117266Sbustos if (!rc_node_hold_flag(current, RC_NODE_IN_TX)) {
45127266Sbustos /*
45137266Sbustos * current has been deleted since we looked it up. Try
45147266Sbustos * again.
45157266Sbustos */
45167266Sbustos /* held in cache_lookup() */
45177266Sbustos rc_node_rele_locked(current);
45180Sstevel@tonic-gate continue;
45190Sstevel@tonic-gate }
45207266Sbustos
45217266Sbustos /*
45227266Sbustos * rc_node_hold_flag() might have dropped current's lock, so
45237266Sbustos * check OLD again.
45247266Sbustos */
45257266Sbustos if (!(current->rn_flags & RC_NODE_OLD)) {
45267266Sbustos /* Not old. Stop looping. */
45277266Sbustos (void) pthread_mutex_unlock(¤t->rn_lock);
45280Sstevel@tonic-gate break;
45290Sstevel@tonic-gate }
45307266Sbustos
45317266Sbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45327266Sbustos rc_node_rele_locked(current);
45337266Sbustos }
45347266Sbustos
45357266Sbustos /* To take np's RC_NODE_DYING_FLAGS, we need its lock. */
45360Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45377266Sbustos
45387266Sbustos /*
45397266Sbustos * While we didn't have the lock, a thread may have added
45407266Sbustos * a reference or changed the flags.
45417266Sbustos */
45420Sstevel@tonic-gate if (!(np->rn_flags & (RC_NODE_OLD | RC_NODE_DEAD)) ||
45430Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 ||
45440Sstevel@tonic-gate np->rn_other_refs_held != 0) {
45450Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
45467266Sbustos
45477266Sbustos (void) pthread_mutex_lock(¤t->rn_lock);
45487266Sbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45497266Sbustos /* held by cache_lookup() */
45507266Sbustos rc_node_rele_locked(current);
45510Sstevel@tonic-gate return;
45520Sstevel@tonic-gate }
45530Sstevel@tonic-gate
45540Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
45557266Sbustos /*
45567266Sbustos * Someone deleted the node while we were waiting for
45577266Sbustos * DYING_FLAGS. Undo the modifications to current.
45587266Sbustos */
45590Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
45600Sstevel@tonic-gate
45617266Sbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45627266Sbustos /* held by cache_lookup() */
45637266Sbustos rc_node_rele_locked(current);
45640Sstevel@tonic-gate
45650Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45660Sstevel@tonic-gate goto died;
45670Sstevel@tonic-gate }
45680Sstevel@tonic-gate
45697266Sbustos /* Take RC_NODE_DYING_FLAGS on np's descendents. */
45707266Sbustos rc_node_delete_hold(np, 0); /* drops np->rn_lock */
45717266Sbustos
45727266Sbustos /* Mark np DEAD. This requires the lock. */
45730Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
45747266Sbustos
45757266Sbustos /* Recheck for new references. */
45760Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD) ||
45770Sstevel@tonic-gate np->rn_refs != 0 || np->rn_other_refs != 0 ||
45780Sstevel@tonic-gate np->rn_other_refs_held != 0) {
45790Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
45807266Sbustos rc_node_delete_rele(np, 0); /* drops np's lock */
45817266Sbustos
45827266Sbustos (void) pthread_mutex_lock(¤t->rn_lock);
45837266Sbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
45847266Sbustos /* held by cache_lookup() */
45857266Sbustos rc_node_rele_locked(current);
45860Sstevel@tonic-gate return;
45870Sstevel@tonic-gate }
45880Sstevel@tonic-gate
45890Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD;
45900Sstevel@tonic-gate
45910Sstevel@tonic-gate /*
45927266Sbustos * Delete the children. This calls rc_node_rele_locked() on np at
45937266Sbustos * the end, so add a reference to keep the count from going
45947266Sbustos * negative. It will recurse with RC_NODE_DEAD set, so we'll call
45957266Sbustos * rc_node_destroy() above, but RC_NODE_UNREFED is also set, so it
45967266Sbustos * shouldn't actually free() np.
45970Sstevel@tonic-gate */
45987266Sbustos rc_node_hold_locked(np);
45997266Sbustos rc_node_delete_children(np, 0); /* unlocks np */
46007266Sbustos
46017266Sbustos /* Remove np from current's rn_former chain. */
46027266Sbustos (void) pthread_mutex_lock(¤t->rn_lock);
46037266Sbustos for (cur = current; cur != NULL && cur->rn_former != np;
46040Sstevel@tonic-gate cur = cur->rn_former)
46050Sstevel@tonic-gate ;
46060Sstevel@tonic-gate assert(cur != NULL && cur != np);
46070Sstevel@tonic-gate
46080Sstevel@tonic-gate cur->rn_former = np->rn_former;
46090Sstevel@tonic-gate np->rn_former = NULL;
46100Sstevel@tonic-gate
46117266Sbustos rc_node_rele_flag(current, RC_NODE_IN_TX);
46127266Sbustos /* held by cache_lookup() */
46137266Sbustos rc_node_rele_locked(current);
46147266Sbustos
46157266Sbustos /* Clear ON_FORMER and UNREFED, and destroy. */
46160Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
46170Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_ON_FORMER);
46180Sstevel@tonic-gate np->rn_flags &= ~(RC_NODE_UNREFED | RC_NODE_ON_FORMER);
46197266Sbustos
46207266Sbustos if (np->rn_erefs > 1) {
46217266Sbustos /* Still referenced. Stay execution. */
46227266Sbustos --np->rn_erefs;
46237266Sbustos NODE_UNLOCK(np);
46247266Sbustos return;
46257266Sbustos }
46267266Sbustos
46270Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
46280Sstevel@tonic-gate rc_node_destroy(np);
46290Sstevel@tonic-gate return;
46300Sstevel@tonic-gate
46310Sstevel@tonic-gate died:
46327266Sbustos /*
46337266Sbustos * Another thread marked np DEAD. If there still aren't any
46347266Sbustos * persistent references, destroy the node.
46357266Sbustos */
46360Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_UNREFED;
46377266Sbustos
46380Sstevel@tonic-gate unrefed = (np->rn_refs == 0 && np->rn_other_refs == 0 &&
46390Sstevel@tonic-gate np->rn_other_refs_held == 0);
46407266Sbustos
46417266Sbustos if (np->rn_erefs > 0)
46427266Sbustos --np->rn_erefs;
46437266Sbustos
46447266Sbustos if (unrefed && np->rn_erefs > 0) {
46457266Sbustos NODE_UNLOCK(np);
46467266Sbustos return;
46477266Sbustos }
46487266Sbustos
46490Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
46507266Sbustos
46510Sstevel@tonic-gate if (unrefed)
46520Sstevel@tonic-gate rc_node_destroy(np);
46530Sstevel@tonic-gate }
46540Sstevel@tonic-gate
46555777Stw21770 static au_event_t
get_delete_event_id(rep_protocol_entity_t entity,uint32_t pgflags)46565777Stw21770 get_delete_event_id(rep_protocol_entity_t entity, uint32_t pgflags)
46575777Stw21770 {
46585777Stw21770 au_event_t id = 0;
46595777Stw21770
46605777Stw21770 #ifndef NATIVE_BUILD
46615777Stw21770 switch (entity) {
46625777Stw21770 case REP_PROTOCOL_ENTITY_SERVICE:
46635777Stw21770 case REP_PROTOCOL_ENTITY_INSTANCE:
46645777Stw21770 id = ADT_smf_delete;
46655777Stw21770 break;
46665777Stw21770 case REP_PROTOCOL_ENTITY_SNAPSHOT:
46675777Stw21770 id = ADT_smf_delete_snap;
46685777Stw21770 break;
46695777Stw21770 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
46705777Stw21770 case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
46715777Stw21770 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) {
46725777Stw21770 id = ADT_smf_delete_npg;
46735777Stw21770 } else {
46745777Stw21770 id = ADT_smf_delete_pg;
46755777Stw21770 }
46765777Stw21770 break;
46775777Stw21770 default:
46785777Stw21770 abort();
46795777Stw21770 }
46805777Stw21770 #endif /* NATIVE_BUILD */
46815777Stw21770 return (id);
46825777Stw21770 }
46835777Stw21770
46840Sstevel@tonic-gate /*
46850Sstevel@tonic-gate * Fails with
46860Sstevel@tonic-gate * _NOT_SET
46870Sstevel@tonic-gate * _DELETED
46880Sstevel@tonic-gate * _BAD_REQUEST
46890Sstevel@tonic-gate * _PERMISSION_DENIED
46900Sstevel@tonic-gate * _NO_RESOURCES
46915777Stw21770 * _TRUNCATED
46920Sstevel@tonic-gate * and whatever object_delete() fails with.
46930Sstevel@tonic-gate */
46940Sstevel@tonic-gate int
rc_node_delete(rc_node_ptr_t * npp)46950Sstevel@tonic-gate rc_node_delete(rc_node_ptr_t *npp)
46960Sstevel@tonic-gate {
46970Sstevel@tonic-gate rc_node_t *np, *np_orig;
46980Sstevel@tonic-gate rc_node_t *pp = NULL;
46990Sstevel@tonic-gate int rc;
47000Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
47010Sstevel@tonic-gate cache_bucket_t *bp;
47020Sstevel@tonic-gate rc_notify_delete_t *ndp;
47030Sstevel@tonic-gate permcheck_t *pcp;
47040Sstevel@tonic-gate int granted;
47055777Stw21770 au_event_t event_id = 0;
47065777Stw21770 size_t sz_out;
47075777Stw21770 audit_event_data_t audit_data;
47085777Stw21770 int audit_failure = 0;
47090Sstevel@tonic-gate
47100Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
47110Sstevel@tonic-gate
47125777Stw21770 audit_data.ed_fmri = NULL;
47135777Stw21770 audit_data.ed_auth = NULL;
47145777Stw21770 audit_data.ed_snapname = NULL;
47155777Stw21770 audit_data.ed_type = NULL;
47165777Stw21770
47170Sstevel@tonic-gate switch (np->rn_id.rl_type) {
47180Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE:
47195777Stw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SERVICE,
47205777Stw21770 np->rn_pgflags);
47215777Stw21770 break;
47220Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE:
47235777Stw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_INSTANCE,
47245777Stw21770 np->rn_pgflags);
47255777Stw21770 break;
47260Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT:
47275777Stw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_SNAPSHOT,
47285777Stw21770 np->rn_pgflags);
47295777Stw21770 audit_data.ed_snapname = strdup(np->rn_name);
47305777Stw21770 if (audit_data.ed_snapname == NULL) {
47315777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
47325777Stw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
47335777Stw21770 }
47340Sstevel@tonic-gate break; /* deletable */
47350Sstevel@tonic-gate
47360Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE:
47370Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL:
47380Sstevel@tonic-gate /* Scopes and snaplevels are indelible. */
47390Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47400Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
47410Sstevel@tonic-gate
47420Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_CPROPERTYGRP:
47430Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47440Sstevel@tonic-gate np = np->rn_cchain[0];
47450Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
47465777Stw21770 event_id = get_delete_event_id(REP_PROTOCOL_ENTITY_CPROPERTYGRP,
47475777Stw21770 np->rn_pgflags);
47480Sstevel@tonic-gate break;
47490Sstevel@tonic-gate
47500Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP:
47515777Stw21770 if (np->rn_id.rl_ids[ID_SNAPSHOT] == 0) {
47525777Stw21770 event_id =
47535777Stw21770 get_delete_event_id(REP_PROTOCOL_ENTITY_PROPERTYGRP,
47545777Stw21770 np->rn_pgflags);
47555777Stw21770 audit_data.ed_type = strdup(np->rn_type);
47565777Stw21770 if (audit_data.ed_type == NULL) {
47575777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
47585777Stw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
47595777Stw21770 }
47600Sstevel@tonic-gate break;
47615777Stw21770 }
47620Sstevel@tonic-gate
47630Sstevel@tonic-gate /* Snapshot property groups are indelible. */
47640Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47650Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
47660Sstevel@tonic-gate
47670Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY:
47680Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
47690Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
47700Sstevel@tonic-gate
47710Sstevel@tonic-gate default:
47720Sstevel@tonic-gate assert(0);
47730Sstevel@tonic-gate abort();
47740Sstevel@tonic-gate break;
47750Sstevel@tonic-gate }
47760Sstevel@tonic-gate
47775777Stw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
47785777Stw21770 if (audit_data.ed_fmri == NULL) {
47795777Stw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
47805777Stw21770 goto cleanout;
47815777Stw21770 }
47820Sstevel@tonic-gate np_orig = np;
47830Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies rest of the code */
47840Sstevel@tonic-gate
47850Sstevel@tonic-gate again:
47860Sstevel@tonic-gate /*
47870Sstevel@tonic-gate * The following loop is to deal with the fact that snapshots and
47880Sstevel@tonic-gate * property groups are moving targets -- changes to them result
47890Sstevel@tonic-gate * in a new "child" node. Since we can only delete from the top node,
47900Sstevel@tonic-gate * we have to loop until we have a non-RC_NODE_OLD version.
47910Sstevel@tonic-gate */
47920Sstevel@tonic-gate for (;;) {
47930Sstevel@tonic-gate if (!rc_node_wait_flag(np,
47940Sstevel@tonic-gate RC_NODE_IN_TX | RC_NODE_USING_PARENT)) {
47950Sstevel@tonic-gate rc_node_rele_locked(np);
47965777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
47975777Stw21770 goto cleanout;
47980Sstevel@tonic-gate }
47990Sstevel@tonic-gate
48000Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
48010Sstevel@tonic-gate rc_node_rele_locked(np);
48020Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
48030Sstevel@tonic-gate assert(np != np_orig);
48040Sstevel@tonic-gate
48050Sstevel@tonic-gate if (np == NULL) {
48060Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED;
48070Sstevel@tonic-gate goto fail;
48080Sstevel@tonic-gate }
48090Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48100Sstevel@tonic-gate continue;
48110Sstevel@tonic-gate }
48120Sstevel@tonic-gate
48130Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
48140Sstevel@tonic-gate rc_node_rele_locked(np);
48150Sstevel@tonic-gate rc_node_clear(npp, 1);
48165777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
48170Sstevel@tonic-gate }
48180Sstevel@tonic-gate
48190Sstevel@tonic-gate /*
48200Sstevel@tonic-gate * Mark our parent as children changing. this call drops our
48210Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with
48220Sstevel@tonic-gate * pp's lock held
48230Sstevel@tonic-gate */
48240Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
48250Sstevel@tonic-gate if (pp == NULL) {
48260Sstevel@tonic-gate /* our parent is gone, we're going next... */
48270Sstevel@tonic-gate rc_node_rele(np);
48280Sstevel@tonic-gate
48290Sstevel@tonic-gate rc_node_clear(npp, 1);
48305777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
48315777Stw21770 goto cleanout;
48320Sstevel@tonic-gate }
48330Sstevel@tonic-gate
48340Sstevel@tonic-gate rc_node_hold_locked(pp); /* hold for later */
48350Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
48360Sstevel@tonic-gate
48370Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48380Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD))
48390Sstevel@tonic-gate break; /* not old -- we're done */
48400Sstevel@tonic-gate
48410Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
48420Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
48430Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
48440Sstevel@tonic-gate rc_node_rele_locked(pp);
48450Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
48460Sstevel@tonic-gate continue; /* loop around and try again */
48470Sstevel@tonic-gate }
48480Sstevel@tonic-gate /*
48490Sstevel@tonic-gate * Everyone out of the pool -- we grab everything but
48500Sstevel@tonic-gate * RC_NODE_USING_PARENT (including RC_NODE_DYING) to keep
48510Sstevel@tonic-gate * any changes from occurring while we are attempting to
48520Sstevel@tonic-gate * delete the node.
48530Sstevel@tonic-gate */
48540Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_DYING_FLAGS)) {
48550Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
48560Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_DELETED;
48570Sstevel@tonic-gate goto fail;
48580Sstevel@tonic-gate }
48590Sstevel@tonic-gate
48600Sstevel@tonic-gate assert(!(np->rn_flags & RC_NODE_OLD));
48610Sstevel@tonic-gate
48625777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
48635777Stw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
48645777Stw21770 rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
48655777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
48665777Stw21770 goto fail;
48675777Stw21770 }
48685777Stw21770
48695777Stw21770 #ifdef NATIVE_BUILD
48705496Sdm120769 if (!client_is_privileged()) {
48715777Stw21770 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
48725777Stw21770 }
48735777Stw21770 #else
48745777Stw21770 if (is_main_repository) {
48755496Sdm120769 /* permission check */
48765405Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
48770Sstevel@tonic-gate pcp = pc_create();
48780Sstevel@tonic-gate if (pcp != NULL) {
48790Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
48800Sstevel@tonic-gate
48810Sstevel@tonic-gate /* add .smf.modify.<type> for pgs. */
48820Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && np->rn_id.rl_type ==
48830Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTYGRP) {
48840Sstevel@tonic-gate const char * const auth =
48850Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
48860Sstevel@tonic-gate
48870Sstevel@tonic-gate if (auth != NULL)
48880Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
48890Sstevel@tonic-gate }
48900Sstevel@tonic-gate
48910Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
48920Sstevel@tonic-gate granted = perm_granted(pcp);
48930Sstevel@tonic-gate
48948497SThomas.Whitten@Sun.COM rc = map_granted_status(granted, pcp,
48958497SThomas.Whitten@Sun.COM &audit_data.ed_auth);
48968497SThomas.Whitten@Sun.COM if (granted == PERM_GONE) {
48978497SThomas.Whitten@Sun.COM /* No need to audit if client gone. */
48988497SThomas.Whitten@Sun.COM pc_free(pcp);
48998497SThomas.Whitten@Sun.COM rc_node_rele_flag(np,
49008497SThomas.Whitten@Sun.COM RC_NODE_DYING_FLAGS);
49018497SThomas.Whitten@Sun.COM return (rc);
49025777Stw21770 }
49038497SThomas.Whitten@Sun.COM if (granted == PERM_DENIED)
49048497SThomas.Whitten@Sun.COM audit_failure = 1;
49050Sstevel@tonic-gate }
49060Sstevel@tonic-gate
49070Sstevel@tonic-gate pc_free(pcp);
49080Sstevel@tonic-gate } else {
49090Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
49100Sstevel@tonic-gate }
49110Sstevel@tonic-gate
49125777Stw21770 (void) pthread_mutex_lock(&np->rn_lock);
49135777Stw21770 } else {
49145777Stw21770 rc = REP_PROTOCOL_SUCCESS;
49155777Stw21770 }
49165496Sdm120769 #endif /* NATIVE_BUILD */
49175496Sdm120769
49185777Stw21770 if (rc != REP_PROTOCOL_SUCCESS) {
49195777Stw21770 rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
49205777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
49215777Stw21770 goto fail;
49220Sstevel@tonic-gate }
49230Sstevel@tonic-gate
49240Sstevel@tonic-gate ndp = uu_zalloc(sizeof (*ndp));
49250Sstevel@tonic-gate if (ndp == NULL) {
49260Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_DYING_FLAGS);
49270Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
49280Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
49290Sstevel@tonic-gate goto fail;
49300Sstevel@tonic-gate }
49310Sstevel@tonic-gate
49320Sstevel@tonic-gate rc_node_delete_hold(np, 1); /* hold entire subgraph, drop lock */
49330Sstevel@tonic-gate
49340Sstevel@tonic-gate rc = object_delete(np);
49350Sstevel@tonic-gate
49360Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
49370Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49380Sstevel@tonic-gate rc_node_delete_rele(np, 1); /* drops lock */
49390Sstevel@tonic-gate uu_free(ndp);
49400Sstevel@tonic-gate goto fail;
49410Sstevel@tonic-gate }
49420Sstevel@tonic-gate
49430Sstevel@tonic-gate /*
49440Sstevel@tonic-gate * Now, delicately unlink and delete the object.
49450Sstevel@tonic-gate *
49460Sstevel@tonic-gate * Create the delete notification, atomically remove
49470Sstevel@tonic-gate * from the hash table and set the NODE_DEAD flag, and
49480Sstevel@tonic-gate * remove from the parent's children list.
49490Sstevel@tonic-gate */
49500Sstevel@tonic-gate rc_notify_node_delete(ndp, np); /* frees or uses ndp */
49510Sstevel@tonic-gate
49520Sstevel@tonic-gate bp = cache_hold(np->rn_hash);
49530Sstevel@tonic-gate
49540Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49550Sstevel@tonic-gate cache_remove_unlocked(bp, np);
49560Sstevel@tonic-gate cache_release(bp);
49570Sstevel@tonic-gate
49580Sstevel@tonic-gate np->rn_flags |= RC_NODE_DEAD;
49597266Sbustos
49600Sstevel@tonic-gate if (pp != NULL) {
49617266Sbustos /*
49627266Sbustos * Remove from pp's rn_children. This requires pp's lock,
49637266Sbustos * so we must drop np's lock to respect lock order.
49647266Sbustos */
49650Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
49660Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
49670Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
49687266Sbustos
49690Sstevel@tonic-gate uu_list_remove(pp->rn_children, np);
49707266Sbustos
49710Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
49727266Sbustos
49730Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
49747266Sbustos
49750Sstevel@tonic-gate np->rn_flags &= ~RC_NODE_IN_PARENT;
49760Sstevel@tonic-gate }
49777266Sbustos
49780Sstevel@tonic-gate /*
49797266Sbustos * finally, propagate death to our children (including marking
49807266Sbustos * them DEAD), handle notifications, and release our hold.
49810Sstevel@tonic-gate */
49820Sstevel@tonic-gate rc_node_hold_locked(np); /* hold for delete */
49830Sstevel@tonic-gate rc_node_delete_children(np, 1); /* drops DYING_FLAGS, lock, ref */
49840Sstevel@tonic-gate
49850Sstevel@tonic-gate rc_node_clear(npp, 1);
49860Sstevel@tonic-gate
49870Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
49880Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
49890Sstevel@tonic-gate rc_pg_notify_fire(pnp);
49900Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
49910Sstevel@tonic-gate rc_notify_remove_node(np);
49920Sstevel@tonic-gate
49930Sstevel@tonic-gate rc_node_rele(np);
49940Sstevel@tonic-gate
49955777Stw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS,
49965777Stw21770 &audit_data);
49975777Stw21770 free(audit_data.ed_auth);
49985777Stw21770 free(audit_data.ed_snapname);
49995777Stw21770 free(audit_data.ed_type);
50005777Stw21770 free(audit_data.ed_fmri);
50010Sstevel@tonic-gate return (rc);
50020Sstevel@tonic-gate
50030Sstevel@tonic-gate fail:
50040Sstevel@tonic-gate rc_node_rele(np);
50050Sstevel@tonic-gate if (rc == REP_PROTOCOL_FAIL_DELETED)
50060Sstevel@tonic-gate rc_node_clear(npp, 1);
50070Sstevel@tonic-gate if (pp != NULL) {
50080Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
50090Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
50100Sstevel@tonic-gate rc_node_rele_locked(pp); /* drop ref and lock */
50110Sstevel@tonic-gate }
50125777Stw21770 if (audit_failure) {
50135777Stw21770 smf_audit_event(event_id, ADT_FAILURE,
50145777Stw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
50155777Stw21770 }
50165777Stw21770 cleanout:
50175777Stw21770 free(audit_data.ed_auth);
50185777Stw21770 free(audit_data.ed_snapname);
50195777Stw21770 free(audit_data.ed_type);
50205777Stw21770 free(audit_data.ed_fmri);
50210Sstevel@tonic-gate return (rc);
50220Sstevel@tonic-gate }
50230Sstevel@tonic-gate
50240Sstevel@tonic-gate int
rc_node_next_snaplevel(rc_node_ptr_t * npp,rc_node_ptr_t * cpp)50250Sstevel@tonic-gate rc_node_next_snaplevel(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
50260Sstevel@tonic-gate {
50270Sstevel@tonic-gate rc_node_t *np;
50280Sstevel@tonic-gate rc_node_t *cp, *pp;
50290Sstevel@tonic-gate int res;
50300Sstevel@tonic-gate
50310Sstevel@tonic-gate rc_node_clear(cpp, 0);
50320Sstevel@tonic-gate
50330Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
50340Sstevel@tonic-gate
50350Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT &&
50360Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL) {
50370Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50380Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
50390Sstevel@tonic-gate }
50400Sstevel@tonic-gate
50410Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
50420Sstevel@tonic-gate if ((res = rc_node_fill_children(np,
50430Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL)) != REP_PROTOCOL_SUCCESS) {
50440Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50450Sstevel@tonic-gate return (res);
50460Sstevel@tonic-gate }
50470Sstevel@tonic-gate
50480Sstevel@tonic-gate for (cp = uu_list_first(np->rn_children);
50490Sstevel@tonic-gate cp != NULL;
50500Sstevel@tonic-gate cp = uu_list_next(np->rn_children, cp)) {
50510Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
50520Sstevel@tonic-gate continue;
50530Sstevel@tonic-gate rc_node_hold(cp);
50540Sstevel@tonic-gate break;
50550Sstevel@tonic-gate }
50560Sstevel@tonic-gate
50570Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
50580Sstevel@tonic-gate } else {
50598497SThomas.Whitten@Sun.COM if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
50608497SThomas.Whitten@Sun.COM (void) pthread_mutex_unlock(&np->rn_lock);
50618497SThomas.Whitten@Sun.COM rc_node_clear(npp, 1);
50628497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_DELETED);
50638497SThomas.Whitten@Sun.COM }
50648497SThomas.Whitten@Sun.COM
50650Sstevel@tonic-gate /*
50660Sstevel@tonic-gate * mark our parent as children changing. This call drops our
50670Sstevel@tonic-gate * lock and the RC_NODE_USING_PARENT flag, and returns with
50680Sstevel@tonic-gate * pp's lock held
50690Sstevel@tonic-gate */
50700Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
50710Sstevel@tonic-gate if (pp == NULL) {
50720Sstevel@tonic-gate /* our parent is gone, we're going next... */
50730Sstevel@tonic-gate
50740Sstevel@tonic-gate rc_node_clear(npp, 1);
50750Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
50760Sstevel@tonic-gate }
50770Sstevel@tonic-gate
50780Sstevel@tonic-gate /*
50790Sstevel@tonic-gate * find the next snaplevel
50800Sstevel@tonic-gate */
50810Sstevel@tonic-gate cp = np;
50820Sstevel@tonic-gate while ((cp = uu_list_next(pp->rn_children, cp)) != NULL &&
50830Sstevel@tonic-gate cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPLEVEL)
50840Sstevel@tonic-gate ;
50850Sstevel@tonic-gate
50860Sstevel@tonic-gate /* it must match the snaplevel list */
50870Sstevel@tonic-gate assert((cp == NULL && np->rn_snaplevel->rsl_next == NULL) ||
50880Sstevel@tonic-gate (cp != NULL && np->rn_snaplevel->rsl_next ==
50890Sstevel@tonic-gate cp->rn_snaplevel));
50900Sstevel@tonic-gate
50910Sstevel@tonic-gate if (cp != NULL)
50920Sstevel@tonic-gate rc_node_hold(cp);
50930Sstevel@tonic-gate
50940Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
50950Sstevel@tonic-gate
50960Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
50970Sstevel@tonic-gate }
50980Sstevel@tonic-gate
50990Sstevel@tonic-gate rc_node_assign(cpp, cp);
51000Sstevel@tonic-gate if (cp != NULL) {
51010Sstevel@tonic-gate rc_node_rele(cp);
51020Sstevel@tonic-gate
51030Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
51040Sstevel@tonic-gate }
51050Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
51060Sstevel@tonic-gate }
51070Sstevel@tonic-gate
51080Sstevel@tonic-gate /*
51090Sstevel@tonic-gate * This call takes a snapshot (np) and either:
51100Sstevel@tonic-gate * an existing snapid (to be associated with np), or
51110Sstevel@tonic-gate * a non-NULL parentp (from which a new snapshot is taken, and associated
51120Sstevel@tonic-gate * with np)
51130Sstevel@tonic-gate *
51140Sstevel@tonic-gate * To do the association, np is duplicated, the duplicate is made to
51150Sstevel@tonic-gate * represent the new snapid, and np is replaced with the new rc_node_t on
51160Sstevel@tonic-gate * np's parent's child list. np is placed on the new node's rn_former list,
51170Sstevel@tonic-gate * and replaces np in cache_hash (so rc_node_update() will find the new one).
51185777Stw21770 *
51195777Stw21770 * old_fmri and old_name point to the original snap shot's FMRI and name.
51205777Stw21770 * These values are used when generating audit events.
51215777Stw21770 *
51225777Stw21770 * Fails with
51235777Stw21770 * _BAD_REQUEST
51245777Stw21770 * _BACKEND_READONLY
51255777Stw21770 * _DELETED
51265777Stw21770 * _NO_RESOURCES
51275777Stw21770 * _TRUNCATED
51285777Stw21770 * _TYPE_MISMATCH
51290Sstevel@tonic-gate */
51300Sstevel@tonic-gate static int
rc_attach_snapshot(rc_node_t * np,uint32_t snapid,rc_node_t * parentp,char * old_fmri,char * old_name)51315777Stw21770 rc_attach_snapshot(
51325777Stw21770 rc_node_t *np,
51335777Stw21770 uint32_t snapid,
51345777Stw21770 rc_node_t *parentp,
51355777Stw21770 char *old_fmri,
51365777Stw21770 char *old_name)
51370Sstevel@tonic-gate {
51380Sstevel@tonic-gate rc_node_t *np_orig;
51390Sstevel@tonic-gate rc_node_t *nnp, *prev;
51400Sstevel@tonic-gate rc_node_t *pp;
51410Sstevel@tonic-gate int rc;
51425777Stw21770 size_t sz_out;
51438497SThomas.Whitten@Sun.COM perm_status_t granted;
51445777Stw21770 au_event_t event_id;
51455777Stw21770 audit_event_data_t audit_data;
51465777Stw21770
51475777Stw21770 if (parentp == NULL) {
51485777Stw21770 assert(old_fmri != NULL);
51495777Stw21770 } else {
51500Sstevel@tonic-gate assert(snapid == 0);
51515777Stw21770 }
51520Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
51530Sstevel@tonic-gate
51545777Stw21770 /* Gather the audit data. */
51555777Stw21770 /*
51565777Stw21770 * ADT_smf_* symbols may not be defined in the /usr/include header
51575777Stw21770 * files on the build machine. Thus, the following if-else will
51585777Stw21770 * not be compiled when doing native builds.
51595777Stw21770 */
51605777Stw21770 #ifndef NATIVE_BUILD
51615777Stw21770 if (parentp == NULL) {
51625777Stw21770 event_id = ADT_smf_attach_snap;
51635777Stw21770 } else {
51645777Stw21770 event_id = ADT_smf_create_snap;
51655777Stw21770 }
51665777Stw21770 #endif /* NATIVE_BUILD */
51675777Stw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
51685777Stw21770 audit_data.ed_snapname = malloc(REP_PROTOCOL_NAME_LEN);
51695777Stw21770 if ((audit_data.ed_fmri == NULL) || (audit_data.ed_snapname == NULL)) {
51705777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
51715777Stw21770 free(audit_data.ed_fmri);
51725777Stw21770 free(audit_data.ed_snapname);
51735777Stw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
51745777Stw21770 }
51755777Stw21770 audit_data.ed_auth = NULL;
51765777Stw21770 if (strlcpy(audit_data.ed_snapname, np->rn_name,
51775777Stw21770 REP_PROTOCOL_NAME_LEN) >= REP_PROTOCOL_NAME_LEN) {
51785777Stw21770 abort();
51795777Stw21770 }
51805777Stw21770 audit_data.ed_old_fmri = old_fmri;
51815777Stw21770 audit_data.ed_old_name = old_name ? old_name : "NO NAME";
51825777Stw21770
51835777Stw21770 if (parentp == NULL) {
51845777Stw21770 /*
51855777Stw21770 * In the attach case, get the instance FMRIs of the
51865777Stw21770 * snapshots.
51875777Stw21770 */
51885777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
51895777Stw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
51905777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
51915777Stw21770 free(audit_data.ed_fmri);
51925777Stw21770 free(audit_data.ed_snapname);
51935777Stw21770 return (rc);
51945777Stw21770 }
51955777Stw21770 } else {
51965777Stw21770 /*
51975777Stw21770 * Capture the FMRI of the parent if we're actually going
51985777Stw21770 * to take the snapshot.
51995777Stw21770 */
52005777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(parentp,
52015777Stw21770 audit_data.ed_fmri, REP_PROTOCOL_FMRI_LEN, &sz_out)) !=
52025777Stw21770 REP_PROTOCOL_SUCCESS) {
52035777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
52045777Stw21770 free(audit_data.ed_fmri);
52055777Stw21770 free(audit_data.ed_snapname);
52065777Stw21770 return (rc);
52075777Stw21770 }
52085777Stw21770 }
52095777Stw21770
52100Sstevel@tonic-gate np_orig = np;
52110Sstevel@tonic-gate rc_node_hold_locked(np); /* simplifies the remainder */
52120Sstevel@tonic-gate
52135040Swesolows (void) pthread_mutex_unlock(&np->rn_lock);
52148497SThomas.Whitten@Sun.COM granted = rc_node_modify_permission_check(&audit_data.ed_auth);
52158497SThomas.Whitten@Sun.COM switch (granted) {
52168497SThomas.Whitten@Sun.COM case PERM_DENIED:
52175777Stw21770 smf_audit_event(event_id, ADT_FAILURE, ADT_FAIL_VALUE_AUTH,
52185777Stw21770 &audit_data);
52198497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
52208497SThomas.Whitten@Sun.COM rc_node_rele(np);
52215777Stw21770 goto cleanout;
52228497SThomas.Whitten@Sun.COM case PERM_GRANTED:
52238497SThomas.Whitten@Sun.COM break;
52248497SThomas.Whitten@Sun.COM case PERM_GONE:
52258497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
52268497SThomas.Whitten@Sun.COM rc_node_rele(np);
52278497SThomas.Whitten@Sun.COM goto cleanout;
52288497SThomas.Whitten@Sun.COM case PERM_FAIL:
52298497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
52308497SThomas.Whitten@Sun.COM rc_node_rele(np);
52318497SThomas.Whitten@Sun.COM goto cleanout;
52328497SThomas.Whitten@Sun.COM default:
52338497SThomas.Whitten@Sun.COM bad_error(rc_node_modify_permission_check, granted);
52345777Stw21770 }
52355040Swesolows (void) pthread_mutex_lock(&np->rn_lock);
52365040Swesolows
52370Sstevel@tonic-gate /*
52380Sstevel@tonic-gate * get the latest node, holding RC_NODE_IN_TX to keep the rn_former
52390Sstevel@tonic-gate * list from changing.
52400Sstevel@tonic-gate */
52410Sstevel@tonic-gate for (;;) {
52420Sstevel@tonic-gate if (!(np->rn_flags & RC_NODE_OLD)) {
52430Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
52440Sstevel@tonic-gate goto again;
52450Sstevel@tonic-gate }
52460Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np,
52470Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING);
52480Sstevel@tonic-gate
52490Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
52500Sstevel@tonic-gate if (pp == NULL) {
52510Sstevel@tonic-gate goto again;
52520Sstevel@tonic-gate }
52530Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
52540Sstevel@tonic-gate rc_node_rele_flag(pp,
52550Sstevel@tonic-gate RC_NODE_CHILDREN_CHANGING);
52560Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
52570Sstevel@tonic-gate goto again;
52580Sstevel@tonic-gate }
52590Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
52600Sstevel@tonic-gate
52610Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
52620Sstevel@tonic-gate /*
52630Sstevel@tonic-gate * Can't happen, since we're holding our
52640Sstevel@tonic-gate * parent's CHILDREN_CHANGING flag...
52650Sstevel@tonic-gate */
52660Sstevel@tonic-gate abort();
52670Sstevel@tonic-gate }
52680Sstevel@tonic-gate break; /* everything's ready */
52690Sstevel@tonic-gate }
52700Sstevel@tonic-gate again:
52710Sstevel@tonic-gate rc_node_rele_locked(np);
52720Sstevel@tonic-gate np = cache_lookup(&np_orig->rn_id);
52730Sstevel@tonic-gate
52745777Stw21770 if (np == NULL) {
52755777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
52765777Stw21770 goto cleanout;
52775777Stw21770 }
52780Sstevel@tonic-gate
52790Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
52800Sstevel@tonic-gate }
52810Sstevel@tonic-gate
52820Sstevel@tonic-gate if (parentp != NULL) {
52830Sstevel@tonic-gate if (pp != parentp) {
52840Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
52850Sstevel@tonic-gate goto fail;
52860Sstevel@tonic-gate }
52870Sstevel@tonic-gate nnp = NULL;
52880Sstevel@tonic-gate } else {
52890Sstevel@tonic-gate /*
52900Sstevel@tonic-gate * look for a former node with the snapid we need.
52910Sstevel@tonic-gate */
52920Sstevel@tonic-gate if (np->rn_snapshot_id == snapid) {
52930Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
52940Sstevel@tonic-gate rc_node_rele_locked(np);
52950Sstevel@tonic-gate
52960Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
52970Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
52980Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
52995777Stw21770 rc = REP_PROTOCOL_SUCCESS; /* nothing to do */
53005777Stw21770 goto cleanout;
53010Sstevel@tonic-gate }
53020Sstevel@tonic-gate
53030Sstevel@tonic-gate prev = np;
53040Sstevel@tonic-gate while ((nnp = prev->rn_former) != NULL) {
53050Sstevel@tonic-gate if (nnp->rn_snapshot_id == snapid) {
53060Sstevel@tonic-gate rc_node_hold(nnp);
53070Sstevel@tonic-gate break; /* existing node with that id */
53080Sstevel@tonic-gate }
53090Sstevel@tonic-gate prev = nnp;
53100Sstevel@tonic-gate }
53110Sstevel@tonic-gate }
53120Sstevel@tonic-gate
53130Sstevel@tonic-gate if (nnp == NULL) {
53140Sstevel@tonic-gate prev = NULL;
53150Sstevel@tonic-gate nnp = rc_node_alloc();
53160Sstevel@tonic-gate if (nnp == NULL) {
53170Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
53180Sstevel@tonic-gate goto fail;
53190Sstevel@tonic-gate }
53200Sstevel@tonic-gate
53210Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */
53220Sstevel@tonic-gate nnp->rn_hash = np->rn_hash;
53230Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name);
53240Sstevel@tonic-gate nnp->rn_snapshot_id = snapid;
53250Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
53260Sstevel@tonic-gate
53270Sstevel@tonic-gate if (nnp->rn_name == NULL) {
53280Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
53290Sstevel@tonic-gate goto fail;
53300Sstevel@tonic-gate }
53310Sstevel@tonic-gate }
53320Sstevel@tonic-gate
53330Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
53340Sstevel@tonic-gate
53350Sstevel@tonic-gate rc = object_snapshot_attach(&np->rn_id, &snapid, (parentp != NULL));
53360Sstevel@tonic-gate
53370Sstevel@tonic-gate if (parentp != NULL)
53380Sstevel@tonic-gate nnp->rn_snapshot_id = snapid; /* fill in new snapid */
53390Sstevel@tonic-gate else
53400Sstevel@tonic-gate assert(nnp->rn_snapshot_id == snapid);
53410Sstevel@tonic-gate
53420Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
53430Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
53440Sstevel@tonic-gate goto fail;
53450Sstevel@tonic-gate
53460Sstevel@tonic-gate /*
53470Sstevel@tonic-gate * fix up the former chain
53480Sstevel@tonic-gate */
53490Sstevel@tonic-gate if (prev != NULL) {
53500Sstevel@tonic-gate prev->rn_former = nnp->rn_former;
53510Sstevel@tonic-gate (void) pthread_mutex_lock(&nnp->rn_lock);
53520Sstevel@tonic-gate nnp->rn_flags &= ~RC_NODE_ON_FORMER;
53530Sstevel@tonic-gate nnp->rn_former = NULL;
53540Sstevel@tonic-gate (void) pthread_mutex_unlock(&nnp->rn_lock);
53550Sstevel@tonic-gate }
53560Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD;
53570Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
53580Sstevel@tonic-gate
53590Sstevel@tonic-gate /*
53600Sstevel@tonic-gate * replace np with nnp
53610Sstevel@tonic-gate */
53620Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp);
53630Sstevel@tonic-gate
53640Sstevel@tonic-gate rc_node_rele(np);
53655777Stw21770 smf_audit_event(event_id, ADT_SUCCESS, ADT_SUCCESS, &audit_data);
53665777Stw21770 rc = REP_PROTOCOL_SUCCESS;
53675777Stw21770
53685777Stw21770 cleanout:
53695777Stw21770 free(audit_data.ed_auth);
53705777Stw21770 free(audit_data.ed_fmri);
53715777Stw21770 free(audit_data.ed_snapname);
53725777Stw21770 return (rc);
53730Sstevel@tonic-gate
53740Sstevel@tonic-gate fail:
53750Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
53760Sstevel@tonic-gate rc_node_rele_locked(np);
53770Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
53780Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
53790Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
53800Sstevel@tonic-gate
53810Sstevel@tonic-gate if (nnp != NULL) {
53820Sstevel@tonic-gate if (prev == NULL)
53830Sstevel@tonic-gate rc_node_destroy(nnp);
53840Sstevel@tonic-gate else
53850Sstevel@tonic-gate rc_node_rele(nnp);
53860Sstevel@tonic-gate }
53870Sstevel@tonic-gate
53885777Stw21770 free(audit_data.ed_auth);
53895777Stw21770 free(audit_data.ed_fmri);
53905777Stw21770 free(audit_data.ed_snapname);
53910Sstevel@tonic-gate return (rc);
53920Sstevel@tonic-gate }
53930Sstevel@tonic-gate
53940Sstevel@tonic-gate int
rc_snapshot_take_new(rc_node_ptr_t * npp,const char * svcname,const char * instname,const char * name,rc_node_ptr_t * outpp)53950Sstevel@tonic-gate rc_snapshot_take_new(rc_node_ptr_t *npp, const char *svcname,
53960Sstevel@tonic-gate const char *instname, const char *name, rc_node_ptr_t *outpp)
53970Sstevel@tonic-gate {
53988497SThomas.Whitten@Sun.COM perm_status_t granted;
53990Sstevel@tonic-gate rc_node_t *np;
54000Sstevel@tonic-gate rc_node_t *outp = NULL;
54015040Swesolows int rc, perm_rc;
54025777Stw21770 char fmri[REP_PROTOCOL_FMRI_LEN];
54035777Stw21770 audit_event_data_t audit_data;
54045777Stw21770 size_t sz_out;
54050Sstevel@tonic-gate
54060Sstevel@tonic-gate rc_node_clear(outpp, 0);
54070Sstevel@tonic-gate
54088497SThomas.Whitten@Sun.COM /*
54098497SThomas.Whitten@Sun.COM * rc_node_modify_permission_check() must be called before the node
54108497SThomas.Whitten@Sun.COM * is locked. This is because the library functions that check
54118497SThomas.Whitten@Sun.COM * authorizations can trigger calls back into configd.
54128497SThomas.Whitten@Sun.COM */
54138497SThomas.Whitten@Sun.COM granted = rc_node_modify_permission_check(&audit_data.ed_auth);
54148497SThomas.Whitten@Sun.COM switch (granted) {
54158497SThomas.Whitten@Sun.COM case PERM_DENIED:
54168497SThomas.Whitten@Sun.COM /*
54178497SThomas.Whitten@Sun.COM * We continue in this case, so that we can generate an
54188497SThomas.Whitten@Sun.COM * audit event later in this function.
54198497SThomas.Whitten@Sun.COM */
54208497SThomas.Whitten@Sun.COM perm_rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
54218497SThomas.Whitten@Sun.COM break;
54228497SThomas.Whitten@Sun.COM case PERM_GRANTED:
54238497SThomas.Whitten@Sun.COM perm_rc = REP_PROTOCOL_SUCCESS;
54248497SThomas.Whitten@Sun.COM break;
54258497SThomas.Whitten@Sun.COM case PERM_GONE:
54268497SThomas.Whitten@Sun.COM /* No need to produce audit event if client is gone. */
54278497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
54288497SThomas.Whitten@Sun.COM case PERM_FAIL:
54298497SThomas.Whitten@Sun.COM return (REP_PROTOCOL_FAIL_NO_RESOURCES);
54308497SThomas.Whitten@Sun.COM default:
54318497SThomas.Whitten@Sun.COM bad_error("rc_node_modify_permission_check", granted);
54328497SThomas.Whitten@Sun.COM break;
54338497SThomas.Whitten@Sun.COM }
54348497SThomas.Whitten@Sun.COM
54358497SThomas.Whitten@Sun.COM RC_NODE_PTR_CHECK_LOCK_OR_FREE_RETURN(np, npp, audit_data.ed_auth);
54360Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
54370Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54385777Stw21770 free(audit_data.ed_auth);
54390Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
54400Sstevel@tonic-gate }
54410Sstevel@tonic-gate
54420Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_SNAPSHOT, name);
54430Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
54440Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54455777Stw21770 free(audit_data.ed_auth);
54460Sstevel@tonic-gate return (rc);
54470Sstevel@tonic-gate }
54480Sstevel@tonic-gate
54490Sstevel@tonic-gate if (svcname != NULL && (rc =
54500Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_SERVICE, svcname)) !=
54510Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
54520Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54535777Stw21770 free(audit_data.ed_auth);
54540Sstevel@tonic-gate return (rc);
54550Sstevel@tonic-gate }
54560Sstevel@tonic-gate
54570Sstevel@tonic-gate if (instname != NULL && (rc =
54580Sstevel@tonic-gate rc_check_type_name(REP_PROTOCOL_ENTITY_INSTANCE, instname)) !=
54590Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
54600Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54615777Stw21770 free(audit_data.ed_auth);
54620Sstevel@tonic-gate return (rc);
54630Sstevel@tonic-gate }
54640Sstevel@tonic-gate
54655777Stw21770 audit_data.ed_fmri = fmri;
54665777Stw21770 audit_data.ed_snapname = (char *)name;
54675777Stw21770
54685777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(np, fmri, sizeof (fmri),
54695777Stw21770 &sz_out)) != REP_PROTOCOL_SUCCESS) {
54705777Stw21770 (void) pthread_mutex_unlock(&np->rn_lock);
54715777Stw21770 free(audit_data.ed_auth);
54725777Stw21770 return (rc);
54735777Stw21770 }
54745040Swesolows if (perm_rc != REP_PROTOCOL_SUCCESS) {
54750Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54765777Stw21770 smf_audit_event(ADT_smf_create_snap, ADT_FAILURE,
54775777Stw21770 ADT_FAIL_VALUE_AUTH, &audit_data);
54785777Stw21770 free(audit_data.ed_auth);
54795040Swesolows return (perm_rc);
54800Sstevel@tonic-gate }
54810Sstevel@tonic-gate
54825777Stw21770 HOLD_PTR_FLAG_OR_FREE_AND_RETURN(np, npp, RC_NODE_CREATING_CHILD,
54835777Stw21770 audit_data.ed_auth);
54840Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54850Sstevel@tonic-gate
54860Sstevel@tonic-gate rc = object_snapshot_take_new(np, svcname, instname, name, &outp);
54870Sstevel@tonic-gate
54880Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
54890Sstevel@tonic-gate rc_node_assign(outpp, outp);
54900Sstevel@tonic-gate rc_node_rele(outp);
54910Sstevel@tonic-gate }
54920Sstevel@tonic-gate
54930Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
54940Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_CREATING_CHILD);
54950Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
54960Sstevel@tonic-gate
54975777Stw21770 if (rc == REP_PROTOCOL_SUCCESS) {
54985777Stw21770 smf_audit_event(ADT_smf_create_snap, ADT_SUCCESS, ADT_SUCCESS,
54995777Stw21770 &audit_data);
55005777Stw21770 }
55015777Stw21770 if (audit_data.ed_auth != NULL)
55025777Stw21770 free(audit_data.ed_auth);
55030Sstevel@tonic-gate return (rc);
55040Sstevel@tonic-gate }
55050Sstevel@tonic-gate
55060Sstevel@tonic-gate int
rc_snapshot_take_attach(rc_node_ptr_t * npp,rc_node_ptr_t * outpp)55070Sstevel@tonic-gate rc_snapshot_take_attach(rc_node_ptr_t *npp, rc_node_ptr_t *outpp)
55080Sstevel@tonic-gate {
55090Sstevel@tonic-gate rc_node_t *np, *outp;
55100Sstevel@tonic-gate
55110Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
55120Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE) {
55130Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
55140Sstevel@tonic-gate }
55150Sstevel@tonic-gate
55160Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(outp, outpp);
55170Sstevel@tonic-gate if (outp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55180Sstevel@tonic-gate (void) pthread_mutex_unlock(&outp->rn_lock);
55190Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55200Sstevel@tonic-gate }
55210Sstevel@tonic-gate
55225777Stw21770 return (rc_attach_snapshot(outp, 0, np, NULL,
55235777Stw21770 NULL)); /* drops outp's lock */
55240Sstevel@tonic-gate }
55250Sstevel@tonic-gate
55260Sstevel@tonic-gate int
rc_snapshot_attach(rc_node_ptr_t * npp,rc_node_ptr_t * cpp)55270Sstevel@tonic-gate rc_snapshot_attach(rc_node_ptr_t *npp, rc_node_ptr_t *cpp)
55280Sstevel@tonic-gate {
55290Sstevel@tonic-gate rc_node_t *np;
55300Sstevel@tonic-gate rc_node_t *cp;
55310Sstevel@tonic-gate uint32_t snapid;
55325777Stw21770 char old_name[REP_PROTOCOL_NAME_LEN];
55335777Stw21770 int rc;
55345777Stw21770 size_t sz_out;
55355777Stw21770 char old_fmri[REP_PROTOCOL_FMRI_LEN];
55360Sstevel@tonic-gate
55370Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
55380Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55390Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
55400Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55410Sstevel@tonic-gate }
55420Sstevel@tonic-gate snapid = np->rn_snapshot_id;
55435777Stw21770 rc = rc_node_get_fmri_or_fragment(np, old_fmri, sizeof (old_fmri),
55445777Stw21770 &sz_out);
55450Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
55465777Stw21770 if (rc != REP_PROTOCOL_SUCCESS)
55475777Stw21770 return (rc);
55485777Stw21770 if (np->rn_name != NULL) {
55495777Stw21770 if (strlcpy(old_name, np->rn_name, sizeof (old_name)) >=
55505777Stw21770 sizeof (old_name)) {
55515777Stw21770 return (REP_PROTOCOL_FAIL_TRUNCATED);
55525777Stw21770 }
55535777Stw21770 }
55540Sstevel@tonic-gate
55550Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(cp, cpp);
55560Sstevel@tonic-gate if (cp->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
55570Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rn_lock);
55580Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
55590Sstevel@tonic-gate }
55600Sstevel@tonic-gate
55615777Stw21770 rc = rc_attach_snapshot(cp, snapid, NULL,
55625777Stw21770 old_fmri, old_name); /* drops cp's lock */
55635777Stw21770 return (rc);
55640Sstevel@tonic-gate }
55650Sstevel@tonic-gate
55660Sstevel@tonic-gate /*
55675040Swesolows * If the pgname property group under ent has type pgtype, and it has a
55685040Swesolows * propname property with type ptype, return _SUCCESS. If pgtype is NULL,
55695040Swesolows * it is not checked. If ent is not a service node, we will return _SUCCESS if
55705040Swesolows * a property meeting the requirements exists in either the instance or its
55715040Swesolows * parent.
55725040Swesolows *
55735040Swesolows * Returns
55745040Swesolows * _SUCCESS - see above
55755040Swesolows * _DELETED - ent or one of its ancestors was deleted
55765040Swesolows * _NO_RESOURCES - no resources
55775040Swesolows * _NOT_FOUND - no matching property was found
55785040Swesolows */
55795040Swesolows static int
rc_svc_prop_exists(rc_node_t * ent,const char * pgname,const char * pgtype,const char * propname,rep_protocol_value_type_t ptype)55805040Swesolows rc_svc_prop_exists(rc_node_t *ent, const char *pgname, const char *pgtype,
55815040Swesolows const char *propname, rep_protocol_value_type_t ptype)
55825040Swesolows {
55835040Swesolows int ret;
55845040Swesolows rc_node_t *pg = NULL, *spg = NULL, *svc, *prop;
55855040Swesolows
55865040Swesolows assert(!MUTEX_HELD(&ent->rn_lock));
55875040Swesolows
55885040Swesolows (void) pthread_mutex_lock(&ent->rn_lock);
55895040Swesolows ret = rc_node_find_named_child(ent, pgname,
55905040Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &pg);
55915040Swesolows (void) pthread_mutex_unlock(&ent->rn_lock);
55925040Swesolows
55935040Swesolows switch (ret) {
55945040Swesolows case REP_PROTOCOL_SUCCESS:
55955040Swesolows break;
55965040Swesolows
55975040Swesolows case REP_PROTOCOL_FAIL_DELETED:
55985040Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
55995040Swesolows return (ret);
56005040Swesolows
56015040Swesolows default:
56025040Swesolows bad_error("rc_node_find_named_child", ret);
56035040Swesolows }
56045040Swesolows
56055040Swesolows if (ent->rn_id.rl_type != REP_PROTOCOL_ENTITY_SERVICE) {
56065040Swesolows ret = rc_node_find_ancestor(ent, REP_PROTOCOL_ENTITY_SERVICE,
56075040Swesolows &svc);
56085040Swesolows if (ret != REP_PROTOCOL_SUCCESS) {
56095040Swesolows assert(ret == REP_PROTOCOL_FAIL_DELETED);
56105040Swesolows if (pg != NULL)
56115040Swesolows rc_node_rele(pg);
56125040Swesolows return (ret);
56135040Swesolows }
56145040Swesolows assert(svc->rn_id.rl_type == REP_PROTOCOL_ENTITY_SERVICE);
56155040Swesolows
56165040Swesolows (void) pthread_mutex_lock(&svc->rn_lock);
56175040Swesolows ret = rc_node_find_named_child(svc, pgname,
56185040Swesolows REP_PROTOCOL_ENTITY_PROPERTYGRP, &spg);
56195040Swesolows (void) pthread_mutex_unlock(&svc->rn_lock);
56205040Swesolows
56215040Swesolows rc_node_rele(svc);
56225040Swesolows
56235040Swesolows switch (ret) {
56245040Swesolows case REP_PROTOCOL_SUCCESS:
56255040Swesolows break;
56265040Swesolows
56275040Swesolows case REP_PROTOCOL_FAIL_DELETED:
56285040Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
56295040Swesolows if (pg != NULL)
56305040Swesolows rc_node_rele(pg);
56315040Swesolows return (ret);
56325040Swesolows
56335040Swesolows default:
56345040Swesolows bad_error("rc_node_find_named_child", ret);
56355040Swesolows }
56365040Swesolows }
56375040Swesolows
56385040Swesolows if (pg != NULL &&
56395040Swesolows pgtype != NULL && strcmp(pg->rn_type, pgtype) != 0) {
56405040Swesolows rc_node_rele(pg);
56415040Swesolows pg = NULL;
56425040Swesolows }
56435040Swesolows
56445040Swesolows if (spg != NULL &&
56455040Swesolows pgtype != NULL && strcmp(spg->rn_type, pgtype) != 0) {
56465040Swesolows rc_node_rele(spg);
56475040Swesolows spg = NULL;
56485040Swesolows }
56495040Swesolows
56505040Swesolows if (pg == NULL) {
56515040Swesolows if (spg == NULL)
56525040Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
56535040Swesolows pg = spg;
56545040Swesolows spg = NULL;
56555040Swesolows }
56565040Swesolows
56575040Swesolows /*
56585040Swesolows * At this point, pg is non-NULL, and is a property group node of the
56595040Swesolows * correct type. spg, if non-NULL, is also a property group node of
56605040Swesolows * the correct type. Check for the property in pg first, then spg
56615040Swesolows * (if applicable).
56625040Swesolows */
56635040Swesolows (void) pthread_mutex_lock(&pg->rn_lock);
56645040Swesolows ret = rc_node_find_named_child(pg, propname,
56655040Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop);
56665040Swesolows (void) pthread_mutex_unlock(&pg->rn_lock);
56675040Swesolows rc_node_rele(pg);
56685040Swesolows switch (ret) {
56695040Swesolows case REP_PROTOCOL_SUCCESS:
56705040Swesolows if (prop != NULL) {
56715040Swesolows if (prop->rn_valtype == ptype) {
56725040Swesolows rc_node_rele(prop);
56735040Swesolows if (spg != NULL)
56745040Swesolows rc_node_rele(spg);
56755040Swesolows return (REP_PROTOCOL_SUCCESS);
56765040Swesolows }
56775040Swesolows rc_node_rele(prop);
56785040Swesolows }
56795040Swesolows break;
56805040Swesolows
56815040Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
56825040Swesolows if (spg != NULL)
56835040Swesolows rc_node_rele(spg);
56845040Swesolows return (ret);
56855040Swesolows
56865040Swesolows case REP_PROTOCOL_FAIL_DELETED:
56875040Swesolows break;
56885040Swesolows
56895040Swesolows default:
56905040Swesolows bad_error("rc_node_find_named_child", ret);
56915040Swesolows }
56925040Swesolows
56935040Swesolows if (spg == NULL)
56945040Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
56955040Swesolows
56965040Swesolows pg = spg;
56975040Swesolows
56985040Swesolows (void) pthread_mutex_lock(&pg->rn_lock);
56995040Swesolows ret = rc_node_find_named_child(pg, propname,
57005040Swesolows REP_PROTOCOL_ENTITY_PROPERTY, &prop);
57015040Swesolows (void) pthread_mutex_unlock(&pg->rn_lock);
57025040Swesolows rc_node_rele(pg);
57035040Swesolows switch (ret) {
57045040Swesolows case REP_PROTOCOL_SUCCESS:
57055040Swesolows if (prop != NULL) {
57065040Swesolows if (prop->rn_valtype == ptype) {
57075040Swesolows rc_node_rele(prop);
57085040Swesolows return (REP_PROTOCOL_SUCCESS);
57095040Swesolows }
57105040Swesolows rc_node_rele(prop);
57115040Swesolows }
57125040Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
57135040Swesolows
57145040Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
57155040Swesolows return (ret);
57165040Swesolows
57175040Swesolows case REP_PROTOCOL_FAIL_DELETED:
57185040Swesolows return (REP_PROTOCOL_FAIL_NOT_FOUND);
57195040Swesolows
57205040Swesolows default:
57215040Swesolows bad_error("rc_node_find_named_child", ret);
57225040Swesolows }
57235040Swesolows
57245040Swesolows return (REP_PROTOCOL_SUCCESS);
57255040Swesolows }
57265040Swesolows
57275040Swesolows /*
57285040Swesolows * Given a property group node, returns _SUCCESS if the property group may
57295040Swesolows * be read without any special authorization.
57305040Swesolows *
57315040Swesolows * Fails with:
57325040Swesolows * _DELETED - np or an ancestor node was deleted
57335040Swesolows * _TYPE_MISMATCH - np does not refer to a property group
57345040Swesolows * _NO_RESOURCES - no resources
57355040Swesolows * _PERMISSION_DENIED - authorization is required
57365040Swesolows */
57375040Swesolows static int
rc_node_pg_check_read_protect(rc_node_t * np)57385040Swesolows rc_node_pg_check_read_protect(rc_node_t *np)
57395040Swesolows {
57405040Swesolows int ret;
57415040Swesolows rc_node_t *ent;
57425040Swesolows
57435040Swesolows assert(!MUTEX_HELD(&np->rn_lock));
57445040Swesolows
57455040Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
57465040Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
57475040Swesolows
57485040Swesolows if (strcmp(np->rn_type, SCF_GROUP_FRAMEWORK) == 0 ||
57495040Swesolows strcmp(np->rn_type, SCF_GROUP_DEPENDENCY) == 0 ||
57505040Swesolows strcmp(np->rn_type, SCF_GROUP_METHOD) == 0)
57515040Swesolows return (REP_PROTOCOL_SUCCESS);
57525040Swesolows
57535040Swesolows ret = rc_node_parent(np, &ent);
57545040Swesolows
57555040Swesolows if (ret != REP_PROTOCOL_SUCCESS)
57565040Swesolows return (ret);
57575040Swesolows
57585040Swesolows ret = rc_svc_prop_exists(ent, np->rn_name, np->rn_type,
57595040Swesolows AUTH_PROP_READ, REP_PROTOCOL_TYPE_STRING);
57605040Swesolows
57615040Swesolows rc_node_rele(ent);
57625040Swesolows
57635040Swesolows switch (ret) {
57645040Swesolows case REP_PROTOCOL_FAIL_NOT_FOUND:
57655040Swesolows return (REP_PROTOCOL_SUCCESS);
57665040Swesolows case REP_PROTOCOL_SUCCESS:
57675040Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
57685040Swesolows case REP_PROTOCOL_FAIL_DELETED:
57695040Swesolows case REP_PROTOCOL_FAIL_NO_RESOURCES:
57705040Swesolows return (ret);
57715040Swesolows default:
57725040Swesolows bad_error("rc_svc_prop_exists", ret);
57735040Swesolows }
57745040Swesolows
57755040Swesolows return (REP_PROTOCOL_SUCCESS);
57765040Swesolows }
57775040Swesolows
57785040Swesolows /*
57795040Swesolows * Fails with
57805040Swesolows * _DELETED - np's node or parent has been deleted
57815040Swesolows * _TYPE_MISMATCH - np's node is not a property
57825040Swesolows * _NO_RESOURCES - out of memory
57835040Swesolows * _PERMISSION_DENIED - no authorization to read this property's value(s)
57845040Swesolows * _BAD_REQUEST - np's parent is not a property group
57855040Swesolows */
57865040Swesolows static int
rc_node_property_may_read(rc_node_t * np)57875040Swesolows rc_node_property_may_read(rc_node_t *np)
57885040Swesolows {
57898497SThomas.Whitten@Sun.COM int ret;
57908497SThomas.Whitten@Sun.COM perm_status_t granted = PERM_DENIED;
57915040Swesolows rc_node_t *pgp;
57925040Swesolows permcheck_t *pcp;
57935777Stw21770 audit_event_data_t audit_data;
57945777Stw21770 size_t sz_out;
57955040Swesolows
57965040Swesolows if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
57975040Swesolows return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
57985040Swesolows
57995040Swesolows if (client_is_privileged())
58005040Swesolows return (REP_PROTOCOL_SUCCESS);
58015040Swesolows
58025040Swesolows #ifdef NATIVE_BUILD
58035040Swesolows return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
58045040Swesolows #else
58055040Swesolows ret = rc_node_parent(np, &pgp);
58065040Swesolows
58075040Swesolows if (ret != REP_PROTOCOL_SUCCESS)
58085040Swesolows return (ret);
58095040Swesolows
58105040Swesolows if (pgp->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
58115040Swesolows rc_node_rele(pgp);
58125040Swesolows return (REP_PROTOCOL_FAIL_BAD_REQUEST);
58135040Swesolows }
58145040Swesolows
58155040Swesolows ret = rc_node_pg_check_read_protect(pgp);
58165040Swesolows
58175040Swesolows if (ret != REP_PROTOCOL_FAIL_PERMISSION_DENIED) {
58185040Swesolows rc_node_rele(pgp);
58195040Swesolows return (ret);
58205040Swesolows }
58215040Swesolows
58225040Swesolows pcp = pc_create();
58235040Swesolows
58245040Swesolows if (pcp == NULL) {
58255040Swesolows rc_node_rele(pgp);
58265040Swesolows return (REP_PROTOCOL_FAIL_NO_RESOURCES);
58275040Swesolows }
58285040Swesolows
58295040Swesolows ret = perm_add_enabling(pcp, AUTH_MODIFY);
58305040Swesolows
58315040Swesolows if (ret == REP_PROTOCOL_SUCCESS) {
58325040Swesolows const char * const auth =
58335040Swesolows perm_auth_for_pgtype(pgp->rn_type);
58345040Swesolows
58355040Swesolows if (auth != NULL)
58365040Swesolows ret = perm_add_enabling(pcp, auth);
58375040Swesolows }
58385040Swesolows
58395040Swesolows /*
58405040Swesolows * If you are permitted to modify the value, you may also
58415040Swesolows * read it. This means that both the MODIFY and VALUE
58425040Swesolows * authorizations are acceptable. We don't allow requests
58435040Swesolows * for AUTH_PROP_MODIFY if all you have is $AUTH_PROP_VALUE,
58445040Swesolows * however, to avoid leaking possibly valuable information
58455040Swesolows * since such a user can't change the property anyway.
58465040Swesolows */
58475040Swesolows if (ret == REP_PROTOCOL_SUCCESS)
58485040Swesolows ret = perm_add_enabling_values(pcp, pgp,
58495040Swesolows AUTH_PROP_MODIFY);
58505040Swesolows
58515040Swesolows if (ret == REP_PROTOCOL_SUCCESS &&
58525040Swesolows strcmp(np->rn_name, AUTH_PROP_MODIFY) != 0)
58535040Swesolows ret = perm_add_enabling_values(pcp, pgp,
58545040Swesolows AUTH_PROP_VALUE);
58555040Swesolows
58565040Swesolows if (ret == REP_PROTOCOL_SUCCESS)
58575040Swesolows ret = perm_add_enabling_values(pcp, pgp,
58585040Swesolows AUTH_PROP_READ);
58595040Swesolows
58605040Swesolows rc_node_rele(pgp);
58615040Swesolows
58625040Swesolows if (ret == REP_PROTOCOL_SUCCESS) {
58635040Swesolows granted = perm_granted(pcp);
58648497SThomas.Whitten@Sun.COM if (granted == PERM_FAIL)
58655040Swesolows ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
58668497SThomas.Whitten@Sun.COM if (granted == PERM_GONE)
58678497SThomas.Whitten@Sun.COM ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
58688497SThomas.Whitten@Sun.COM }
58698497SThomas.Whitten@Sun.COM
58705777Stw21770 if (ret == REP_PROTOCOL_SUCCESS) {
58715777Stw21770 /* Generate a read_prop audit event. */
58725777Stw21770 audit_data.ed_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
58735777Stw21770 if (audit_data.ed_fmri == NULL)
58745777Stw21770 ret = REP_PROTOCOL_FAIL_NO_RESOURCES;
58755777Stw21770 }
58768497SThomas.Whitten@Sun.COM if (ret == REP_PROTOCOL_SUCCESS) {
58778497SThomas.Whitten@Sun.COM ret = rc_node_get_fmri_or_fragment(np, audit_data.ed_fmri,
58788497SThomas.Whitten@Sun.COM REP_PROTOCOL_FMRI_LEN, &sz_out);
58798497SThomas.Whitten@Sun.COM }
58805777Stw21770 if (ret == REP_PROTOCOL_SUCCESS) {
58815777Stw21770 int status;
58825777Stw21770 int ret_value;
58835777Stw21770
58848497SThomas.Whitten@Sun.COM if (granted == PERM_DENIED) {
58855777Stw21770 status = ADT_FAILURE;
58865777Stw21770 ret_value = ADT_FAIL_VALUE_AUTH;
58875777Stw21770 } else {
58885777Stw21770 status = ADT_SUCCESS;
58895777Stw21770 ret_value = ADT_SUCCESS;
58905777Stw21770 }
58915777Stw21770 audit_data.ed_auth = pcp->pc_auth_string;
58925777Stw21770 smf_audit_event(ADT_smf_read_prop,
58935777Stw21770 status, ret_value, &audit_data);
58945777Stw21770 }
58955777Stw21770 free(audit_data.ed_fmri);
58965040Swesolows
58975040Swesolows pc_free(pcp);
58985040Swesolows
58998497SThomas.Whitten@Sun.COM if ((ret == REP_PROTOCOL_SUCCESS) && (granted == PERM_DENIED))
59005040Swesolows ret = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
59015040Swesolows
59025040Swesolows return (ret);
59035040Swesolows #endif /* NATIVE_BUILD */
59045040Swesolows }
59055040Swesolows
59065040Swesolows /*
59070Sstevel@tonic-gate * Iteration
59080Sstevel@tonic-gate */
59090Sstevel@tonic-gate static int
rc_iter_filter_name(rc_node_t * np,void * s)59100Sstevel@tonic-gate rc_iter_filter_name(rc_node_t *np, void *s)
59110Sstevel@tonic-gate {
59120Sstevel@tonic-gate const char *name = s;
59130Sstevel@tonic-gate
59140Sstevel@tonic-gate return (strcmp(np->rn_name, name) == 0);
59150Sstevel@tonic-gate }
59160Sstevel@tonic-gate
59170Sstevel@tonic-gate static int
rc_iter_filter_type(rc_node_t * np,void * s)59180Sstevel@tonic-gate rc_iter_filter_type(rc_node_t *np, void *s)
59190Sstevel@tonic-gate {
59200Sstevel@tonic-gate const char *type = s;
59210Sstevel@tonic-gate
59220Sstevel@tonic-gate return (np->rn_type != NULL && strcmp(np->rn_type, type) == 0);
59230Sstevel@tonic-gate }
59240Sstevel@tonic-gate
59250Sstevel@tonic-gate /*ARGSUSED*/
59260Sstevel@tonic-gate static int
rc_iter_null_filter(rc_node_t * np,void * s)59270Sstevel@tonic-gate rc_iter_null_filter(rc_node_t *np, void *s)
59280Sstevel@tonic-gate {
59290Sstevel@tonic-gate return (1);
59300Sstevel@tonic-gate }
59310Sstevel@tonic-gate
59320Sstevel@tonic-gate /*
59330Sstevel@tonic-gate * Allocate & initialize an rc_node_iter_t structure. Essentially, ensure
59340Sstevel@tonic-gate * np->rn_children is populated and call uu_list_walk_start(np->rn_children).
59350Sstevel@tonic-gate * If successful, leaves a hold on np & increments np->rn_other_refs
59360Sstevel@tonic-gate *
59370Sstevel@tonic-gate * If composed is true, then set up for iteration across the top level of np's
59380Sstevel@tonic-gate * composition chain. If successful, leaves a hold on np and increments
59390Sstevel@tonic-gate * rn_other_refs for the top level of np's composition chain.
59400Sstevel@tonic-gate *
59410Sstevel@tonic-gate * Fails with
59420Sstevel@tonic-gate * _NO_RESOURCES
59430Sstevel@tonic-gate * _INVALID_TYPE
59440Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children
59450Sstevel@tonic-gate * _DELETED
59460Sstevel@tonic-gate */
59470Sstevel@tonic-gate static int
rc_iter_create(rc_node_iter_t ** resp,rc_node_t * np,uint32_t type,rc_iter_filter_func * filter,void * arg,boolean_t composed)59480Sstevel@tonic-gate rc_iter_create(rc_node_iter_t **resp, rc_node_t *np, uint32_t type,
59490Sstevel@tonic-gate rc_iter_filter_func *filter, void *arg, boolean_t composed)
59500Sstevel@tonic-gate {
59510Sstevel@tonic-gate rc_node_iter_t *nip;
59520Sstevel@tonic-gate int res;
59530Sstevel@tonic-gate
59540Sstevel@tonic-gate assert(*resp == NULL);
59550Sstevel@tonic-gate
59560Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip));
59570Sstevel@tonic-gate if (nip == NULL)
59580Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
59590Sstevel@tonic-gate
59600Sstevel@tonic-gate /* np is held by the client's rc_node_ptr_t */
59610Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP)
59620Sstevel@tonic-gate composed = 1;
59630Sstevel@tonic-gate
59640Sstevel@tonic-gate if (!composed) {
59650Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
59660Sstevel@tonic-gate
59670Sstevel@tonic-gate if ((res = rc_node_fill_children(np, type)) !=
59680Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
59690Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59700Sstevel@tonic-gate uu_free(nip);
59710Sstevel@tonic-gate return (res);
59720Sstevel@tonic-gate }
59730Sstevel@tonic-gate
59740Sstevel@tonic-gate nip->rni_clevel = -1;
59750Sstevel@tonic-gate
59760Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(np->rn_children,
59770Sstevel@tonic-gate UU_WALK_ROBUST);
59780Sstevel@tonic-gate if (nip->rni_iter != NULL) {
59790Sstevel@tonic-gate nip->rni_iter_node = np;
59800Sstevel@tonic-gate rc_node_hold_other(np);
59810Sstevel@tonic-gate } else {
59820Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59830Sstevel@tonic-gate uu_free(nip);
59840Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
59850Sstevel@tonic-gate }
59860Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59870Sstevel@tonic-gate } else {
59880Sstevel@tonic-gate rc_node_t *ent;
59890Sstevel@tonic-gate
59900Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_SNAPSHOT) {
59910Sstevel@tonic-gate /* rn_cchain isn't valid until children are loaded. */
59920Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
59930Sstevel@tonic-gate res = rc_node_fill_children(np,
59940Sstevel@tonic-gate REP_PROTOCOL_ENTITY_SNAPLEVEL);
59950Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
59960Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) {
59970Sstevel@tonic-gate uu_free(nip);
59980Sstevel@tonic-gate return (res);
59990Sstevel@tonic-gate }
60000Sstevel@tonic-gate
60010Sstevel@tonic-gate /* Check for an empty snapshot. */
60020Sstevel@tonic-gate if (np->rn_cchain[0] == NULL)
60030Sstevel@tonic-gate goto empty;
60040Sstevel@tonic-gate }
60050Sstevel@tonic-gate
60060Sstevel@tonic-gate /* Start at the top of the composition chain. */
60070Sstevel@tonic-gate for (nip->rni_clevel = 0; ; ++nip->rni_clevel) {
60080Sstevel@tonic-gate if (nip->rni_clevel >= COMPOSITION_DEPTH) {
60090Sstevel@tonic-gate /* Empty composition chain. */
60100Sstevel@tonic-gate empty:
60110Sstevel@tonic-gate nip->rni_clevel = -1;
60120Sstevel@tonic-gate nip->rni_iter = NULL;
60130Sstevel@tonic-gate /* It's ok, iter_next() will return _DONE. */
60140Sstevel@tonic-gate goto out;
60150Sstevel@tonic-gate }
60160Sstevel@tonic-gate
60170Sstevel@tonic-gate ent = np->rn_cchain[nip->rni_clevel];
60180Sstevel@tonic-gate assert(ent != NULL);
60190Sstevel@tonic-gate
60200Sstevel@tonic-gate if (rc_node_check_and_lock(ent) == REP_PROTOCOL_SUCCESS)
60210Sstevel@tonic-gate break;
60220Sstevel@tonic-gate
60230Sstevel@tonic-gate /* Someone deleted it, so try the next one. */
60240Sstevel@tonic-gate }
60250Sstevel@tonic-gate
60260Sstevel@tonic-gate res = rc_node_fill_children(ent, type);
60270Sstevel@tonic-gate
60280Sstevel@tonic-gate if (res == REP_PROTOCOL_SUCCESS) {
60290Sstevel@tonic-gate nip->rni_iter = uu_list_walk_start(ent->rn_children,
60300Sstevel@tonic-gate UU_WALK_ROBUST);
60310Sstevel@tonic-gate
60320Sstevel@tonic-gate if (nip->rni_iter == NULL)
60330Sstevel@tonic-gate res = REP_PROTOCOL_FAIL_NO_RESOURCES;
60340Sstevel@tonic-gate else {
60350Sstevel@tonic-gate nip->rni_iter_node = ent;
60360Sstevel@tonic-gate rc_node_hold_other(ent);
60370Sstevel@tonic-gate }
60380Sstevel@tonic-gate }
60390Sstevel@tonic-gate
60400Sstevel@tonic-gate if (res != REP_PROTOCOL_SUCCESS) {
60410Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
60420Sstevel@tonic-gate uu_free(nip);
60430Sstevel@tonic-gate return (res);
60440Sstevel@tonic-gate }
60450Sstevel@tonic-gate
60460Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
60470Sstevel@tonic-gate }
60480Sstevel@tonic-gate
60490Sstevel@tonic-gate out:
60500Sstevel@tonic-gate rc_node_hold(np); /* released by rc_iter_end() */
60510Sstevel@tonic-gate nip->rni_parent = np;
60520Sstevel@tonic-gate nip->rni_type = type;
60530Sstevel@tonic-gate nip->rni_filter = (filter != NULL)? filter : rc_iter_null_filter;
60540Sstevel@tonic-gate nip->rni_filter_arg = arg;
60550Sstevel@tonic-gate *resp = nip;
60560Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
60570Sstevel@tonic-gate }
60580Sstevel@tonic-gate
60590Sstevel@tonic-gate static void
rc_iter_end(rc_node_iter_t * iter)60600Sstevel@tonic-gate rc_iter_end(rc_node_iter_t *iter)
60610Sstevel@tonic-gate {
60620Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
60630Sstevel@tonic-gate
60640Sstevel@tonic-gate if (iter->rni_clevel >= 0)
60650Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel];
60660Sstevel@tonic-gate
60670Sstevel@tonic-gate assert(MUTEX_HELD(&np->rn_lock));
60680Sstevel@tonic-gate if (iter->rni_iter != NULL)
60690Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter);
60700Sstevel@tonic-gate iter->rni_iter = NULL;
60710Sstevel@tonic-gate
60720Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
60730Sstevel@tonic-gate rc_node_rele(iter->rni_parent);
60740Sstevel@tonic-gate if (iter->rni_iter_node != NULL)
60750Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node);
60760Sstevel@tonic-gate }
60770Sstevel@tonic-gate
60780Sstevel@tonic-gate /*
60790Sstevel@tonic-gate * Fails with
60800Sstevel@tonic-gate * _NOT_SET - npp is reset
60810Sstevel@tonic-gate * _DELETED - npp's node has been deleted
60820Sstevel@tonic-gate * _NOT_APPLICABLE - npp's node is not a property
60830Sstevel@tonic-gate * _NO_RESOURCES - out of memory
60840Sstevel@tonic-gate */
60850Sstevel@tonic-gate static int
rc_node_setup_value_iter(rc_node_ptr_t * npp,rc_node_iter_t ** iterp)60860Sstevel@tonic-gate rc_node_setup_value_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp)
60870Sstevel@tonic-gate {
60880Sstevel@tonic-gate rc_node_t *np;
60890Sstevel@tonic-gate
60900Sstevel@tonic-gate rc_node_iter_t *nip;
60910Sstevel@tonic-gate
60920Sstevel@tonic-gate assert(*iterp == NULL);
60930Sstevel@tonic-gate
60940Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
60950Sstevel@tonic-gate
60960Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
60970Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
60980Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
60990Sstevel@tonic-gate }
61000Sstevel@tonic-gate
61010Sstevel@tonic-gate nip = uu_zalloc(sizeof (*nip));
61020Sstevel@tonic-gate if (nip == NULL) {
61030Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61040Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
61050Sstevel@tonic-gate }
61060Sstevel@tonic-gate
61070Sstevel@tonic-gate nip->rni_parent = np;
61080Sstevel@tonic-gate nip->rni_iter = NULL;
61090Sstevel@tonic-gate nip->rni_clevel = -1;
61100Sstevel@tonic-gate nip->rni_type = REP_PROTOCOL_ENTITY_VALUE;
61110Sstevel@tonic-gate nip->rni_offset = 0;
61120Sstevel@tonic-gate nip->rni_last_offset = 0;
61130Sstevel@tonic-gate
61140Sstevel@tonic-gate rc_node_hold_locked(np);
61150Sstevel@tonic-gate
61160Sstevel@tonic-gate *iterp = nip;
61170Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61180Sstevel@tonic-gate
61190Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
61200Sstevel@tonic-gate }
61210Sstevel@tonic-gate
61220Sstevel@tonic-gate /*
61230Sstevel@tonic-gate * Returns:
61245040Swesolows * _NO_RESOURCES - out of memory
61250Sstevel@tonic-gate * _NOT_SET - npp is reset
61260Sstevel@tonic-gate * _DELETED - npp's node has been deleted
61270Sstevel@tonic-gate * _TYPE_MISMATCH - npp's node is not a property
61280Sstevel@tonic-gate * _NOT_FOUND - property has no values
61290Sstevel@tonic-gate * _TRUNCATED - property has >1 values (first is written into out)
61300Sstevel@tonic-gate * _SUCCESS - property has 1 value (which is written into out)
61315040Swesolows * _PERMISSION_DENIED - no authorization to read property value(s)
61320Sstevel@tonic-gate *
61330Sstevel@tonic-gate * We shorten *sz_out to not include anything after the final '\0'.
61340Sstevel@tonic-gate */
61350Sstevel@tonic-gate int
rc_node_get_property_value(rc_node_ptr_t * npp,struct rep_protocol_value_response * out,size_t * sz_out)61360Sstevel@tonic-gate rc_node_get_property_value(rc_node_ptr_t *npp,
61370Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out)
61380Sstevel@tonic-gate {
61390Sstevel@tonic-gate rc_node_t *np;
61400Sstevel@tonic-gate size_t w;
61410Sstevel@tonic-gate int ret;
61420Sstevel@tonic-gate
61430Sstevel@tonic-gate assert(*sz_out == sizeof (*out));
61440Sstevel@tonic-gate
61455040Swesolows RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
61465040Swesolows ret = rc_node_property_may_read(np);
61475040Swesolows rc_node_rele(np);
61485040Swesolows
61495040Swesolows if (ret != REP_PROTOCOL_SUCCESS)
61505040Swesolows return (ret);
61515040Swesolows
61520Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
61530Sstevel@tonic-gate
61540Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY) {
61550Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61560Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
61570Sstevel@tonic-gate }
61580Sstevel@tonic-gate
61590Sstevel@tonic-gate if (np->rn_values_size == 0) {
61600Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61610Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_FOUND);
61620Sstevel@tonic-gate }
61630Sstevel@tonic-gate out->rpr_type = np->rn_valtype;
61640Sstevel@tonic-gate w = strlcpy(out->rpr_value, &np->rn_values[0],
61650Sstevel@tonic-gate sizeof (out->rpr_value));
61660Sstevel@tonic-gate
61670Sstevel@tonic-gate if (w >= sizeof (out->rpr_value))
61680Sstevel@tonic-gate backend_panic("value too large");
61690Sstevel@tonic-gate
61700Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response,
61710Sstevel@tonic-gate rpr_value[w + 1]);
61720Sstevel@tonic-gate
61730Sstevel@tonic-gate ret = (np->rn_values_count != 1)? REP_PROTOCOL_FAIL_TRUNCATED :
61740Sstevel@tonic-gate REP_PROTOCOL_SUCCESS;
61750Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
61760Sstevel@tonic-gate return (ret);
61770Sstevel@tonic-gate }
61780Sstevel@tonic-gate
61790Sstevel@tonic-gate int
rc_iter_next_value(rc_node_iter_t * iter,struct rep_protocol_value_response * out,size_t * sz_out,int repeat)61800Sstevel@tonic-gate rc_iter_next_value(rc_node_iter_t *iter,
61810Sstevel@tonic-gate struct rep_protocol_value_response *out, size_t *sz_out, int repeat)
61820Sstevel@tonic-gate {
61830Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
61840Sstevel@tonic-gate const char *vals;
61850Sstevel@tonic-gate size_t len;
61860Sstevel@tonic-gate
61870Sstevel@tonic-gate size_t start;
61880Sstevel@tonic-gate size_t w;
61895040Swesolows int ret;
61900Sstevel@tonic-gate
61910Sstevel@tonic-gate rep_protocol_responseid_t result;
61920Sstevel@tonic-gate
61930Sstevel@tonic-gate assert(*sz_out == sizeof (*out));
61940Sstevel@tonic-gate
61950Sstevel@tonic-gate (void) memset(out, '\0', *sz_out);
61960Sstevel@tonic-gate
61970Sstevel@tonic-gate if (iter->rni_type != REP_PROTOCOL_ENTITY_VALUE)
61980Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
61990Sstevel@tonic-gate
62005040Swesolows RC_NODE_CHECK(np);
62015040Swesolows ret = rc_node_property_may_read(np);
62025040Swesolows
62035040Swesolows if (ret != REP_PROTOCOL_SUCCESS)
62045040Swesolows return (ret);
62055040Swesolows
62060Sstevel@tonic-gate RC_NODE_CHECK_AND_LOCK(np);
62070Sstevel@tonic-gate
62080Sstevel@tonic-gate vals = np->rn_values;
62090Sstevel@tonic-gate len = np->rn_values_size;
62100Sstevel@tonic-gate
62110Sstevel@tonic-gate out->rpr_type = np->rn_valtype;
62120Sstevel@tonic-gate
62130Sstevel@tonic-gate start = (repeat)? iter->rni_last_offset : iter->rni_offset;
62140Sstevel@tonic-gate
62150Sstevel@tonic-gate if (len == 0 || start >= len) {
62160Sstevel@tonic-gate result = REP_PROTOCOL_DONE;
62170Sstevel@tonic-gate *sz_out -= sizeof (out->rpr_value);
62180Sstevel@tonic-gate } else {
62190Sstevel@tonic-gate w = strlcpy(out->rpr_value, &vals[start],
62200Sstevel@tonic-gate sizeof (out->rpr_value));
62210Sstevel@tonic-gate
62220Sstevel@tonic-gate if (w >= sizeof (out->rpr_value))
62230Sstevel@tonic-gate backend_panic("value too large");
62240Sstevel@tonic-gate
62250Sstevel@tonic-gate *sz_out = offsetof(struct rep_protocol_value_response,
62260Sstevel@tonic-gate rpr_value[w + 1]);
62270Sstevel@tonic-gate
62280Sstevel@tonic-gate /*
62290Sstevel@tonic-gate * update the offsets if we're not repeating
62300Sstevel@tonic-gate */
62310Sstevel@tonic-gate if (!repeat) {
62320Sstevel@tonic-gate iter->rni_last_offset = iter->rni_offset;
62330Sstevel@tonic-gate iter->rni_offset += (w + 1);
62340Sstevel@tonic-gate }
62350Sstevel@tonic-gate
62360Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS;
62370Sstevel@tonic-gate }
62380Sstevel@tonic-gate
62390Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
62400Sstevel@tonic-gate return (result);
62410Sstevel@tonic-gate }
62420Sstevel@tonic-gate
62430Sstevel@tonic-gate /*
62440Sstevel@tonic-gate * Entry point for ITER_START from client.c. Validate the arguments & call
62450Sstevel@tonic-gate * rc_iter_create().
62460Sstevel@tonic-gate *
62470Sstevel@tonic-gate * Fails with
62480Sstevel@tonic-gate * _NOT_SET
62490Sstevel@tonic-gate * _DELETED
62500Sstevel@tonic-gate * _TYPE_MISMATCH - np cannot carry type children
62510Sstevel@tonic-gate * _BAD_REQUEST - flags is invalid
62520Sstevel@tonic-gate * pattern is invalid
62530Sstevel@tonic-gate * _NO_RESOURCES
62540Sstevel@tonic-gate * _INVALID_TYPE
62550Sstevel@tonic-gate * _TYPE_MISMATCH - *npp cannot have children of type
62560Sstevel@tonic-gate * _BACKEND_ACCESS
62570Sstevel@tonic-gate */
62580Sstevel@tonic-gate int
rc_node_setup_iter(rc_node_ptr_t * npp,rc_node_iter_t ** iterp,uint32_t type,uint32_t flags,const char * pattern)62590Sstevel@tonic-gate rc_node_setup_iter(rc_node_ptr_t *npp, rc_node_iter_t **iterp,
62600Sstevel@tonic-gate uint32_t type, uint32_t flags, const char *pattern)
62610Sstevel@tonic-gate {
62620Sstevel@tonic-gate rc_node_t *np;
62630Sstevel@tonic-gate rc_iter_filter_func *f = NULL;
62640Sstevel@tonic-gate int rc;
62650Sstevel@tonic-gate
62660Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK(np, npp);
62670Sstevel@tonic-gate
62680Sstevel@tonic-gate if (pattern != NULL && pattern[0] == '\0')
62690Sstevel@tonic-gate pattern = NULL;
62700Sstevel@tonic-gate
62710Sstevel@tonic-gate if (type == REP_PROTOCOL_ENTITY_VALUE) {
62720Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTY)
62730Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
62740Sstevel@tonic-gate if (flags != RP_ITER_START_ALL || pattern != NULL)
62750Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62760Sstevel@tonic-gate
62770Sstevel@tonic-gate rc = rc_node_setup_value_iter(npp, iterp);
62780Sstevel@tonic-gate assert(rc != REP_PROTOCOL_FAIL_NOT_APPLICABLE);
62790Sstevel@tonic-gate return (rc);
62800Sstevel@tonic-gate }
62810Sstevel@tonic-gate
62820Sstevel@tonic-gate if ((rc = rc_check_parent_child(np->rn_id.rl_type, type)) !=
62830Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
62840Sstevel@tonic-gate return (rc);
62850Sstevel@tonic-gate
62860Sstevel@tonic-gate if (((flags & RP_ITER_START_FILT_MASK) == RP_ITER_START_ALL) ^
62870Sstevel@tonic-gate (pattern == NULL))
62880Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62890Sstevel@tonic-gate
62900Sstevel@tonic-gate /* Composition only works for instances & snapshots. */
62910Sstevel@tonic-gate if ((flags & RP_ITER_START_COMPOSED) &&
62920Sstevel@tonic-gate (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_INSTANCE &&
62930Sstevel@tonic-gate np->rn_id.rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT))
62940Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
62950Sstevel@tonic-gate
62960Sstevel@tonic-gate if (pattern != NULL) {
62970Sstevel@tonic-gate if ((rc = rc_check_type_name(type, pattern)) !=
62980Sstevel@tonic-gate REP_PROTOCOL_SUCCESS)
62990Sstevel@tonic-gate return (rc);
63000Sstevel@tonic-gate pattern = strdup(pattern);
63010Sstevel@tonic-gate if (pattern == NULL)
63020Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
63030Sstevel@tonic-gate }
63040Sstevel@tonic-gate
63050Sstevel@tonic-gate switch (flags & RP_ITER_START_FILT_MASK) {
63060Sstevel@tonic-gate case RP_ITER_START_ALL:
63070Sstevel@tonic-gate f = NULL;
63080Sstevel@tonic-gate break;
63090Sstevel@tonic-gate case RP_ITER_START_EXACT:
63100Sstevel@tonic-gate f = rc_iter_filter_name;
63110Sstevel@tonic-gate break;
63120Sstevel@tonic-gate case RP_ITER_START_PGTYPE:
63130Sstevel@tonic-gate if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
63140Sstevel@tonic-gate free((void *)pattern);
63150Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63160Sstevel@tonic-gate }
63170Sstevel@tonic-gate f = rc_iter_filter_type;
63180Sstevel@tonic-gate break;
63190Sstevel@tonic-gate default:
63200Sstevel@tonic-gate free((void *)pattern);
63210Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63220Sstevel@tonic-gate }
63230Sstevel@tonic-gate
63240Sstevel@tonic-gate rc = rc_iter_create(iterp, np, type, f, (void *)pattern,
63250Sstevel@tonic-gate flags & RP_ITER_START_COMPOSED);
63260Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS && pattern != NULL)
63270Sstevel@tonic-gate free((void *)pattern);
63280Sstevel@tonic-gate
63290Sstevel@tonic-gate return (rc);
63300Sstevel@tonic-gate }
63310Sstevel@tonic-gate
63320Sstevel@tonic-gate /*
63330Sstevel@tonic-gate * Do uu_list_walk_next(iter->rni_iter) until we find a child which matches
63340Sstevel@tonic-gate * the filter.
63350Sstevel@tonic-gate * For composed iterators, then check to see if there's an overlapping entity
63360Sstevel@tonic-gate * (see embedded comments). If we reach the end of the list, start over at
63370Sstevel@tonic-gate * the next level.
63380Sstevel@tonic-gate *
63390Sstevel@tonic-gate * Returns
63400Sstevel@tonic-gate * _BAD_REQUEST - iter walks values
63410Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities
63420Sstevel@tonic-gate * _DELETED - parent was deleted
63430Sstevel@tonic-gate * _NO_RESOURCES
63440Sstevel@tonic-gate * _INVALID_TYPE - type is invalid
63450Sstevel@tonic-gate * _DONE
63460Sstevel@tonic-gate * _SUCCESS
63470Sstevel@tonic-gate *
63480Sstevel@tonic-gate * For composed property group iterators, can also return
63490Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children
63500Sstevel@tonic-gate */
63510Sstevel@tonic-gate int
rc_iter_next(rc_node_iter_t * iter,rc_node_ptr_t * out,uint32_t type)63520Sstevel@tonic-gate rc_iter_next(rc_node_iter_t *iter, rc_node_ptr_t *out, uint32_t type)
63530Sstevel@tonic-gate {
63540Sstevel@tonic-gate rc_node_t *np = iter->rni_parent;
63550Sstevel@tonic-gate rc_node_t *res;
63560Sstevel@tonic-gate int rc;
63570Sstevel@tonic-gate
63580Sstevel@tonic-gate if (iter->rni_type == REP_PROTOCOL_ENTITY_VALUE)
63590Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
63600Sstevel@tonic-gate
63610Sstevel@tonic-gate if (iter->rni_iter == NULL) {
63620Sstevel@tonic-gate rc_node_clear(out, 0);
63630Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
63640Sstevel@tonic-gate }
63650Sstevel@tonic-gate
63660Sstevel@tonic-gate if (iter->rni_type != type) {
63670Sstevel@tonic-gate rc_node_clear(out, 0);
63680Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
63690Sstevel@tonic-gate }
63700Sstevel@tonic-gate
63710Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock); /* held by _iter_create() */
63720Sstevel@tonic-gate
63730Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
63740Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63750Sstevel@tonic-gate rc_node_clear(out, 1);
63760Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
63770Sstevel@tonic-gate }
63780Sstevel@tonic-gate
63790Sstevel@tonic-gate if (iter->rni_clevel >= 0) {
63800Sstevel@tonic-gate /* Composed iterator. Iterate over appropriate level. */
63810Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63820Sstevel@tonic-gate np = np->rn_cchain[iter->rni_clevel];
63830Sstevel@tonic-gate /*
63840Sstevel@tonic-gate * If iter->rni_parent is an instance or a snapshot, np must
63850Sstevel@tonic-gate * be valid since iter holds iter->rni_parent & possible
63860Sstevel@tonic-gate * levels (service, instance, snaplevel) cannot be destroyed
63870Sstevel@tonic-gate * while rni_parent is held. If iter->rni_parent is
63880Sstevel@tonic-gate * a composed property group then rc_node_setup_cpg() put
63890Sstevel@tonic-gate * a hold on np.
63900Sstevel@tonic-gate */
63910Sstevel@tonic-gate
63920Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
63930Sstevel@tonic-gate
63940Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_CHILDREN_CHANGING)) {
63950Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
63960Sstevel@tonic-gate rc_node_clear(out, 1);
63970Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
63980Sstevel@tonic-gate }
63990Sstevel@tonic-gate }
64000Sstevel@tonic-gate
64010Sstevel@tonic-gate assert(np->rn_flags & RC_NODE_HAS_CHILDREN);
64020Sstevel@tonic-gate
64030Sstevel@tonic-gate for (;;) {
64040Sstevel@tonic-gate res = uu_list_walk_next(iter->rni_iter);
64050Sstevel@tonic-gate if (res == NULL) {
64060Sstevel@tonic-gate rc_node_t *parent = iter->rni_parent;
64070Sstevel@tonic-gate
64080Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
64090Sstevel@tonic-gate if (iter->rni_clevel < 0 || iter->rni_clevel == 1) {
64100Sstevel@tonic-gate /* release walker and lock */
64110Sstevel@tonic-gate rc_iter_end(iter);
64120Sstevel@tonic-gate break;
64130Sstevel@tonic-gate }
64140Sstevel@tonic-gate
64150Sstevel@tonic-gate /* Stop walking current level. */
64160Sstevel@tonic-gate uu_list_walk_end(iter->rni_iter);
64170Sstevel@tonic-gate iter->rni_iter = NULL;
64180Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64190Sstevel@tonic-gate rc_node_rele_other(iter->rni_iter_node);
64200Sstevel@tonic-gate iter->rni_iter_node = NULL;
64210Sstevel@tonic-gate
64220Sstevel@tonic-gate /* Start walking next level. */
64230Sstevel@tonic-gate ++iter->rni_clevel;
64240Sstevel@tonic-gate np = parent->rn_cchain[iter->rni_clevel];
64250Sstevel@tonic-gate assert(np != NULL);
64260Sstevel@tonic-gate #else
64270Sstevel@tonic-gate #error This code must be updated.
64280Sstevel@tonic-gate #endif
64290Sstevel@tonic-gate
64300Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
64310Sstevel@tonic-gate
64320Sstevel@tonic-gate rc = rc_node_fill_children(np, iter->rni_type);
64330Sstevel@tonic-gate
64340Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
64350Sstevel@tonic-gate iter->rni_iter =
64360Sstevel@tonic-gate uu_list_walk_start(np->rn_children,
64375040Swesolows UU_WALK_ROBUST);
64380Sstevel@tonic-gate
64390Sstevel@tonic-gate if (iter->rni_iter == NULL)
64400Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
64410Sstevel@tonic-gate else {
64420Sstevel@tonic-gate iter->rni_iter_node = np;
64430Sstevel@tonic-gate rc_node_hold_other(np);
64440Sstevel@tonic-gate }
64450Sstevel@tonic-gate }
64460Sstevel@tonic-gate
64470Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
64480Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64490Sstevel@tonic-gate rc_node_clear(out, 0);
64500Sstevel@tonic-gate return (rc);
64510Sstevel@tonic-gate }
64520Sstevel@tonic-gate
64530Sstevel@tonic-gate continue;
64540Sstevel@tonic-gate }
64550Sstevel@tonic-gate
64560Sstevel@tonic-gate if (res->rn_id.rl_type != type ||
64570Sstevel@tonic-gate !iter->rni_filter(res, iter->rni_filter_arg))
64580Sstevel@tonic-gate continue;
64590Sstevel@tonic-gate
64600Sstevel@tonic-gate /*
64610Sstevel@tonic-gate * If we're composed and not at the top level, check to see if
64620Sstevel@tonic-gate * there's an entity at a higher level with the same name. If
64630Sstevel@tonic-gate * so, skip this one.
64640Sstevel@tonic-gate */
64650Sstevel@tonic-gate if (iter->rni_clevel > 0) {
64660Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[0];
64670Sstevel@tonic-gate rc_node_t *pg;
64680Sstevel@tonic-gate
64690Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
64700Sstevel@tonic-gate assert(iter->rni_clevel == 1);
64710Sstevel@tonic-gate
64720Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64730Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
64740Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type,
64750Sstevel@tonic-gate &pg);
64760Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && pg != NULL)
64770Sstevel@tonic-gate rc_node_rele(pg);
64780Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
64790Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
64800Sstevel@tonic-gate rc_node_clear(out, 0);
64810Sstevel@tonic-gate return (rc);
64820Sstevel@tonic-gate }
64830Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
64840Sstevel@tonic-gate
64850Sstevel@tonic-gate /* Make sure np isn't being deleted all of a sudden. */
64860Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
64870Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
64880Sstevel@tonic-gate rc_node_clear(out, 1);
64890Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
64900Sstevel@tonic-gate }
64910Sstevel@tonic-gate
64920Sstevel@tonic-gate if (pg != NULL)
64930Sstevel@tonic-gate /* Keep going. */
64940Sstevel@tonic-gate continue;
64950Sstevel@tonic-gate #else
64960Sstevel@tonic-gate #error This code must be updated.
64970Sstevel@tonic-gate #endif
64980Sstevel@tonic-gate }
64990Sstevel@tonic-gate
65000Sstevel@tonic-gate /*
65010Sstevel@tonic-gate * If we're composed, iterating over property groups, and not
65020Sstevel@tonic-gate * at the bottom level, check to see if there's a pg at lower
65030Sstevel@tonic-gate * level with the same name. If so, return a cpg.
65040Sstevel@tonic-gate */
65050Sstevel@tonic-gate if (iter->rni_clevel >= 0 &&
65060Sstevel@tonic-gate type == REP_PROTOCOL_ENTITY_PROPERTYGRP &&
65070Sstevel@tonic-gate iter->rni_clevel < COMPOSITION_DEPTH - 1) {
65080Sstevel@tonic-gate #if COMPOSITION_DEPTH == 2
65090Sstevel@tonic-gate rc_node_t *pg;
65100Sstevel@tonic-gate rc_node_t *ent = iter->rni_parent->rn_cchain[1];
65110Sstevel@tonic-gate
65120Sstevel@tonic-gate rc_node_hold(res); /* While we drop np->rn_lock */
65130Sstevel@tonic-gate
65140Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
65150Sstevel@tonic-gate (void) pthread_mutex_lock(&ent->rn_lock);
65160Sstevel@tonic-gate rc = rc_node_find_named_child(ent, res->rn_name, type,
65170Sstevel@tonic-gate &pg);
65180Sstevel@tonic-gate /* holds pg if not NULL */
65190Sstevel@tonic-gate (void) pthread_mutex_unlock(&ent->rn_lock);
65200Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
65210Sstevel@tonic-gate rc_node_rele(res);
65220Sstevel@tonic-gate rc_node_clear(out, 0);
65230Sstevel@tonic-gate return (rc);
65240Sstevel@tonic-gate }
65250Sstevel@tonic-gate
65260Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
65270Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_DYING)) {
65280Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
65290Sstevel@tonic-gate rc_node_rele(res);
65300Sstevel@tonic-gate if (pg != NULL)
65310Sstevel@tonic-gate rc_node_rele(pg);
65320Sstevel@tonic-gate rc_node_clear(out, 1);
65330Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
65340Sstevel@tonic-gate }
65350Sstevel@tonic-gate
65360Sstevel@tonic-gate if (pg == NULL) {
65370Sstevel@tonic-gate rc_node_rele(res);
65380Sstevel@tonic-gate } else {
65390Sstevel@tonic-gate rc_node_t *cpg;
65400Sstevel@tonic-gate
65410Sstevel@tonic-gate /* Keep res held for rc_node_setup_cpg(). */
65420Sstevel@tonic-gate
65430Sstevel@tonic-gate cpg = rc_node_alloc();
65440Sstevel@tonic-gate if (cpg == NULL) {
65450Sstevel@tonic-gate (void) pthread_mutex_unlock(
65460Sstevel@tonic-gate &np->rn_lock);
65470Sstevel@tonic-gate rc_node_rele(res);
65480Sstevel@tonic-gate rc_node_rele(pg);
65490Sstevel@tonic-gate rc_node_clear(out, 0);
65500Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
65510Sstevel@tonic-gate }
65520Sstevel@tonic-gate
65530Sstevel@tonic-gate switch (rc_node_setup_cpg(cpg, res, pg)) {
65540Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
65550Sstevel@tonic-gate res = cpg;
65560Sstevel@tonic-gate break;
65570Sstevel@tonic-gate
65580Sstevel@tonic-gate case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
65590Sstevel@tonic-gate /* Nevermind. */
65600Sstevel@tonic-gate rc_node_destroy(cpg);
65610Sstevel@tonic-gate rc_node_rele(pg);
65620Sstevel@tonic-gate rc_node_rele(res);
65630Sstevel@tonic-gate break;
65640Sstevel@tonic-gate
65650Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
65660Sstevel@tonic-gate rc_node_destroy(cpg);
65670Sstevel@tonic-gate (void) pthread_mutex_unlock(
65680Sstevel@tonic-gate &np->rn_lock);
65690Sstevel@tonic-gate rc_node_rele(res);
65700Sstevel@tonic-gate rc_node_rele(pg);
65710Sstevel@tonic-gate rc_node_clear(out, 0);
65720Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
65730Sstevel@tonic-gate
65740Sstevel@tonic-gate default:
65750Sstevel@tonic-gate assert(0);
65760Sstevel@tonic-gate abort();
65770Sstevel@tonic-gate }
65780Sstevel@tonic-gate }
65790Sstevel@tonic-gate #else
65800Sstevel@tonic-gate #error This code must be updated.
65810Sstevel@tonic-gate #endif
65820Sstevel@tonic-gate }
65830Sstevel@tonic-gate
65840Sstevel@tonic-gate rc_node_hold(res);
65850Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
65860Sstevel@tonic-gate break;
65870Sstevel@tonic-gate }
65880Sstevel@tonic-gate rc_node_assign(out, res);
65890Sstevel@tonic-gate
65900Sstevel@tonic-gate if (res == NULL)
65910Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
65920Sstevel@tonic-gate rc_node_rele(res);
65930Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
65940Sstevel@tonic-gate }
65950Sstevel@tonic-gate
65960Sstevel@tonic-gate void
rc_iter_destroy(rc_node_iter_t ** nipp)65970Sstevel@tonic-gate rc_iter_destroy(rc_node_iter_t **nipp)
65980Sstevel@tonic-gate {
65990Sstevel@tonic-gate rc_node_iter_t *nip = *nipp;
66000Sstevel@tonic-gate rc_node_t *np;
66010Sstevel@tonic-gate
66020Sstevel@tonic-gate if (nip == NULL)
66030Sstevel@tonic-gate return; /* already freed */
66040Sstevel@tonic-gate
66050Sstevel@tonic-gate np = nip->rni_parent;
66060Sstevel@tonic-gate
66070Sstevel@tonic-gate if (nip->rni_filter_arg != NULL)
66080Sstevel@tonic-gate free(nip->rni_filter_arg);
66090Sstevel@tonic-gate nip->rni_filter_arg = NULL;
66100Sstevel@tonic-gate
66110Sstevel@tonic-gate if (nip->rni_type == REP_PROTOCOL_ENTITY_VALUE ||
66120Sstevel@tonic-gate nip->rni_iter != NULL) {
66130Sstevel@tonic-gate if (nip->rni_clevel < 0)
66140Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
66150Sstevel@tonic-gate else
66160Sstevel@tonic-gate (void) pthread_mutex_lock(
66170Sstevel@tonic-gate &np->rn_cchain[nip->rni_clevel]->rn_lock);
66180Sstevel@tonic-gate rc_iter_end(nip); /* release walker and lock */
66190Sstevel@tonic-gate }
66200Sstevel@tonic-gate nip->rni_parent = NULL;
66210Sstevel@tonic-gate
66220Sstevel@tonic-gate uu_free(nip);
66230Sstevel@tonic-gate *nipp = NULL;
66240Sstevel@tonic-gate }
66250Sstevel@tonic-gate
66260Sstevel@tonic-gate int
rc_node_setup_tx(rc_node_ptr_t * npp,rc_node_ptr_t * txp)66270Sstevel@tonic-gate rc_node_setup_tx(rc_node_ptr_t *npp, rc_node_ptr_t *txp)
66280Sstevel@tonic-gate {
66290Sstevel@tonic-gate rc_node_t *np;
66300Sstevel@tonic-gate permcheck_t *pcp;
66310Sstevel@tonic-gate int ret;
66328497SThomas.Whitten@Sun.COM perm_status_t granted;
66335777Stw21770 rc_auth_state_t authorized = RC_AUTH_UNKNOWN;
66345777Stw21770 char *auth_string = NULL;
66350Sstevel@tonic-gate
66360Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_HOLD(np, npp);
66370Sstevel@tonic-gate
66380Sstevel@tonic-gate if (np->rn_id.rl_type == REP_PROTOCOL_ENTITY_CPROPERTYGRP) {
66390Sstevel@tonic-gate rc_node_rele(np);
66400Sstevel@tonic-gate np = np->rn_cchain[0];
66410Sstevel@tonic-gate RC_NODE_CHECK_AND_HOLD(np);
66420Sstevel@tonic-gate }
66430Sstevel@tonic-gate
66440Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
66450Sstevel@tonic-gate rc_node_rele(np);
66460Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
66470Sstevel@tonic-gate }
66480Sstevel@tonic-gate
66490Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_SNAPSHOT] != 0) {
66500Sstevel@tonic-gate rc_node_rele(np);
66510Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
66520Sstevel@tonic-gate }
66530Sstevel@tonic-gate
66545777Stw21770 #ifdef NATIVE_BUILD
66550Sstevel@tonic-gate if (client_is_privileged())
66560Sstevel@tonic-gate goto skip_checks;
66570Sstevel@tonic-gate rc_node_rele(np);
66580Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
66590Sstevel@tonic-gate #else
66605777Stw21770 if (is_main_repository == 0)
66615777Stw21770 goto skip_checks;
66625777Stw21770
66630Sstevel@tonic-gate /* permission check */
66640Sstevel@tonic-gate pcp = pc_create();
66650Sstevel@tonic-gate if (pcp == NULL) {
66660Sstevel@tonic-gate rc_node_rele(np);
66670Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
66680Sstevel@tonic-gate }
66690Sstevel@tonic-gate
66700Sstevel@tonic-gate if (np->rn_id.rl_ids[ID_INSTANCE] != 0 && /* instance pg */
66710Sstevel@tonic-gate ((strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0 &&
66720Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_ACTIONS_TYPE) == 0) ||
66730Sstevel@tonic-gate (strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
66740Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0))) {
66750Sstevel@tonic-gate rc_node_t *instn;
66760Sstevel@tonic-gate
667711223STruong.Q.Nguyen@Sun.COM /* solaris.smf.modify can be used */
667811223STruong.Q.Nguyen@Sun.COM ret = perm_add_enabling(pcp, AUTH_MODIFY);
667911223STruong.Q.Nguyen@Sun.COM if (ret != REP_PROTOCOL_SUCCESS) {
668011223STruong.Q.Nguyen@Sun.COM pc_free(pcp);
668111223STruong.Q.Nguyen@Sun.COM rc_node_rele(np);
668211223STruong.Q.Nguyen@Sun.COM return (ret);
668311223STruong.Q.Nguyen@Sun.COM }
668411223STruong.Q.Nguyen@Sun.COM
66850Sstevel@tonic-gate /* solaris.smf.manage can be used. */
66860Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE);
66870Sstevel@tonic-gate
66880Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
66890Sstevel@tonic-gate pc_free(pcp);
66900Sstevel@tonic-gate rc_node_rele(np);
66910Sstevel@tonic-gate return (ret);
66920Sstevel@tonic-gate }
66930Sstevel@tonic-gate
66940Sstevel@tonic-gate /* general/action_authorization values can be used. */
66950Sstevel@tonic-gate ret = rc_node_parent(np, &instn);
66960Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
66970Sstevel@tonic-gate assert(ret == REP_PROTOCOL_FAIL_DELETED);
66980Sstevel@tonic-gate rc_node_rele(np);
66990Sstevel@tonic-gate pc_free(pcp);
67000Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
67010Sstevel@tonic-gate }
67020Sstevel@tonic-gate
67030Sstevel@tonic-gate assert(instn->rn_id.rl_type == REP_PROTOCOL_ENTITY_INSTANCE);
67040Sstevel@tonic-gate
67050Sstevel@tonic-gate ret = perm_add_inst_action_auth(pcp, instn);
67060Sstevel@tonic-gate rc_node_rele(instn);
67070Sstevel@tonic-gate switch (ret) {
67080Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
67090Sstevel@tonic-gate break;
67100Sstevel@tonic-gate
67110Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
67120Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
67130Sstevel@tonic-gate rc_node_rele(np);
67140Sstevel@tonic-gate pc_free(pcp);
67150Sstevel@tonic-gate return (ret);
67160Sstevel@tonic-gate
67170Sstevel@tonic-gate default:
67180Sstevel@tonic-gate bad_error("perm_add_inst_action_auth", ret);
67190Sstevel@tonic-gate }
67200Sstevel@tonic-gate
67210Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_ACTIONS) == 0)
67225777Stw21770 authorized = RC_AUTH_PASSED; /* No check on commit. */
67230Sstevel@tonic-gate } else {
67240Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MODIFY);
67250Sstevel@tonic-gate
67260Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS) {
67270Sstevel@tonic-gate /* propertygroup-type-specific authorization */
67280Sstevel@tonic-gate /* no locking because rn_type won't change anyway */
67290Sstevel@tonic-gate const char * const auth =
67300Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
67310Sstevel@tonic-gate
67320Sstevel@tonic-gate if (auth != NULL)
67330Sstevel@tonic-gate ret = perm_add_enabling(pcp, auth);
67340Sstevel@tonic-gate }
67350Sstevel@tonic-gate
67360Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS)
67370Sstevel@tonic-gate /* propertygroup/transaction-type-specific auths */
67380Sstevel@tonic-gate ret =
67390Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_VALUE);
67400Sstevel@tonic-gate
67410Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS)
67420Sstevel@tonic-gate ret =
67430Sstevel@tonic-gate perm_add_enabling_values(pcp, np, AUTH_PROP_MODIFY);
67440Sstevel@tonic-gate
67450Sstevel@tonic-gate /* AUTH_MANAGE can manipulate general/AUTH_PROP_ACTION */
67460Sstevel@tonic-gate if (ret == REP_PROTOCOL_SUCCESS &&
67470Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
67480Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0)
67490Sstevel@tonic-gate ret = perm_add_enabling(pcp, AUTH_MANAGE);
67500Sstevel@tonic-gate
67510Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) {
67520Sstevel@tonic-gate pc_free(pcp);
67530Sstevel@tonic-gate rc_node_rele(np);
67540Sstevel@tonic-gate return (ret);
67550Sstevel@tonic-gate }
67560Sstevel@tonic-gate }
67570Sstevel@tonic-gate
67588497SThomas.Whitten@Sun.COM granted = perm_granted(pcp);
67598497SThomas.Whitten@Sun.COM ret = map_granted_status(granted, pcp, &auth_string);
67605777Stw21770 pc_free(pcp);
67618497SThomas.Whitten@Sun.COM
67628497SThomas.Whitten@Sun.COM if ((granted == PERM_GONE) || (granted == PERM_FAIL) ||
67638497SThomas.Whitten@Sun.COM (ret == REP_PROTOCOL_FAIL_NO_RESOURCES)) {
67648497SThomas.Whitten@Sun.COM free(auth_string);
67650Sstevel@tonic-gate rc_node_rele(np);
67668497SThomas.Whitten@Sun.COM return (ret);
67678497SThomas.Whitten@Sun.COM }
67688497SThomas.Whitten@Sun.COM
67698497SThomas.Whitten@Sun.COM if (granted == PERM_DENIED) {
67705777Stw21770 /*
67715777Stw21770 * If we get here, the authorization failed.
67725777Stw21770 * Unfortunately, we don't have enough information at this
67735777Stw21770 * point to generate the security audit events. We'll only
67745777Stw21770 * get that information when the client tries to commit the
67755777Stw21770 * event. Thus, we'll remember the failed authorization,
67765777Stw21770 * so that we can generate the audit events later.
67775777Stw21770 */
67785777Stw21770 authorized = RC_AUTH_FAILED;
67795777Stw21770 }
67800Sstevel@tonic-gate #endif /* NATIVE_BUILD */
67810Sstevel@tonic-gate
67820Sstevel@tonic-gate skip_checks:
67830Sstevel@tonic-gate rc_node_assign(txp, np);
67840Sstevel@tonic-gate txp->rnp_authorized = authorized;
67855777Stw21770 if (authorized != RC_AUTH_UNKNOWN) {
67865777Stw21770 /* Save the authorization string. */
67875777Stw21770 if (txp->rnp_auth_string != NULL)
67885777Stw21770 free((void *)txp->rnp_auth_string);
67895777Stw21770 txp->rnp_auth_string = auth_string;
67905777Stw21770 auth_string = NULL; /* Don't free until done with txp. */
67915777Stw21770 }
67920Sstevel@tonic-gate
67930Sstevel@tonic-gate rc_node_rele(np);
67945777Stw21770 if (auth_string != NULL)
67955777Stw21770 free(auth_string);
67960Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
67970Sstevel@tonic-gate }
67980Sstevel@tonic-gate
67990Sstevel@tonic-gate /*
68000Sstevel@tonic-gate * Return 1 if the given transaction commands only modify the values of
68010Sstevel@tonic-gate * properties other than "modify_authorization". Return -1 if any of the
68020Sstevel@tonic-gate * commands are invalid, and 0 otherwise.
68030Sstevel@tonic-gate */
68040Sstevel@tonic-gate static int
tx_allow_value(const void * cmds_arg,size_t cmds_sz,rc_node_t * pg)68050Sstevel@tonic-gate tx_allow_value(const void *cmds_arg, size_t cmds_sz, rc_node_t *pg)
68060Sstevel@tonic-gate {
68070Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds;
68080Sstevel@tonic-gate uintptr_t loc;
68090Sstevel@tonic-gate uint32_t sz;
68100Sstevel@tonic-gate rc_node_t *prop;
68110Sstevel@tonic-gate boolean_t ok;
68120Sstevel@tonic-gate
68130Sstevel@tonic-gate assert(!MUTEX_HELD(&pg->rn_lock));
68140Sstevel@tonic-gate
68150Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
68160Sstevel@tonic-gate
68170Sstevel@tonic-gate while (cmds_sz > 0) {
68180Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc;
68190Sstevel@tonic-gate
68200Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68210Sstevel@tonic-gate return (-1);
68220Sstevel@tonic-gate
68230Sstevel@tonic-gate sz = cmds->rptc_size;
68240Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68250Sstevel@tonic-gate return (-1);
68260Sstevel@tonic-gate
68270Sstevel@tonic-gate sz = TX_SIZE(sz);
68280Sstevel@tonic-gate if (sz > cmds_sz)
68290Sstevel@tonic-gate return (-1);
68300Sstevel@tonic-gate
68310Sstevel@tonic-gate switch (cmds[0].rptc_action) {
68320Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_CLEAR:
68330Sstevel@tonic-gate break;
68340Sstevel@tonic-gate
68350Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_REPLACE:
68360Sstevel@tonic-gate /* Check type */
68370Sstevel@tonic-gate (void) pthread_mutex_lock(&pg->rn_lock);
6838*12430Stom.whitten@oracle.com ok = B_FALSE;
68390Sstevel@tonic-gate if (rc_node_find_named_child(pg,
68400Sstevel@tonic-gate (const char *)cmds[0].rptc_data,
68410Sstevel@tonic-gate REP_PROTOCOL_ENTITY_PROPERTY, &prop) ==
68420Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
6843*12430Stom.whitten@oracle.com if (prop != NULL) {
6844*12430Stom.whitten@oracle.com ok = prop->rn_valtype ==
6845*12430Stom.whitten@oracle.com cmds[0].rptc_type;
6846*12430Stom.whitten@oracle.com /*
6847*12430Stom.whitten@oracle.com * rc_node_find_named_child()
6848*12430Stom.whitten@oracle.com * places a hold on prop which we
6849*12430Stom.whitten@oracle.com * do not need to hang on to.
6850*12430Stom.whitten@oracle.com */
6851*12430Stom.whitten@oracle.com rc_node_rele(prop);
6852*12430Stom.whitten@oracle.com }
68530Sstevel@tonic-gate }
68540Sstevel@tonic-gate (void) pthread_mutex_unlock(&pg->rn_lock);
68550Sstevel@tonic-gate if (ok)
68560Sstevel@tonic-gate break;
68570Sstevel@tonic-gate return (0);
68580Sstevel@tonic-gate
68590Sstevel@tonic-gate default:
68600Sstevel@tonic-gate return (0);
68610Sstevel@tonic-gate }
68620Sstevel@tonic-gate
68630Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_MODIFY)
68640Sstevel@tonic-gate == 0)
68650Sstevel@tonic-gate return (0);
68660Sstevel@tonic-gate
68670Sstevel@tonic-gate loc += sz;
68680Sstevel@tonic-gate cmds_sz -= sz;
68690Sstevel@tonic-gate }
68700Sstevel@tonic-gate
68710Sstevel@tonic-gate return (1);
68720Sstevel@tonic-gate }
68730Sstevel@tonic-gate
68740Sstevel@tonic-gate /*
68750Sstevel@tonic-gate * Return 1 if any of the given transaction commands affect
68760Sstevel@tonic-gate * "action_authorization". Return -1 if any of the commands are invalid and
68770Sstevel@tonic-gate * 0 in all other cases.
68780Sstevel@tonic-gate */
68790Sstevel@tonic-gate static int
tx_modifies_action(const void * cmds_arg,size_t cmds_sz)68800Sstevel@tonic-gate tx_modifies_action(const void *cmds_arg, size_t cmds_sz)
68810Sstevel@tonic-gate {
68820Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds;
68830Sstevel@tonic-gate uintptr_t loc;
68840Sstevel@tonic-gate uint32_t sz;
68850Sstevel@tonic-gate
68860Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
68870Sstevel@tonic-gate
68880Sstevel@tonic-gate while (cmds_sz > 0) {
68890Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc;
68900Sstevel@tonic-gate
68910Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68920Sstevel@tonic-gate return (-1);
68930Sstevel@tonic-gate
68940Sstevel@tonic-gate sz = cmds->rptc_size;
68950Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
68960Sstevel@tonic-gate return (-1);
68970Sstevel@tonic-gate
68980Sstevel@tonic-gate sz = TX_SIZE(sz);
68990Sstevel@tonic-gate if (sz > cmds_sz)
69000Sstevel@tonic-gate return (-1);
69010Sstevel@tonic-gate
69020Sstevel@tonic-gate if (strcmp((const char *)cmds[0].rptc_data, AUTH_PROP_ACTION)
69030Sstevel@tonic-gate == 0)
69040Sstevel@tonic-gate return (1);
69050Sstevel@tonic-gate
69060Sstevel@tonic-gate loc += sz;
69070Sstevel@tonic-gate cmds_sz -= sz;
69080Sstevel@tonic-gate }
69090Sstevel@tonic-gate
69100Sstevel@tonic-gate return (0);
69110Sstevel@tonic-gate }
69120Sstevel@tonic-gate
69130Sstevel@tonic-gate /*
69140Sstevel@tonic-gate * Returns 1 if the transaction commands only modify properties named
69150Sstevel@tonic-gate * 'enabled'.
69160Sstevel@tonic-gate */
69170Sstevel@tonic-gate static int
tx_only_enabled(const void * cmds_arg,size_t cmds_sz)69180Sstevel@tonic-gate tx_only_enabled(const void *cmds_arg, size_t cmds_sz)
69190Sstevel@tonic-gate {
69200Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmd;
69210Sstevel@tonic-gate uintptr_t loc;
69220Sstevel@tonic-gate uint32_t sz;
69230Sstevel@tonic-gate
69240Sstevel@tonic-gate loc = (uintptr_t)cmds_arg;
69250Sstevel@tonic-gate
69260Sstevel@tonic-gate while (cmds_sz > 0) {
69270Sstevel@tonic-gate cmd = (struct rep_protocol_transaction_cmd *)loc;
69280Sstevel@tonic-gate
69290Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69300Sstevel@tonic-gate return (-1);
69310Sstevel@tonic-gate
69320Sstevel@tonic-gate sz = cmd->rptc_size;
69330Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE)
69340Sstevel@tonic-gate return (-1);
69350Sstevel@tonic-gate
69360Sstevel@tonic-gate sz = TX_SIZE(sz);
69370Sstevel@tonic-gate if (sz > cmds_sz)
69380Sstevel@tonic-gate return (-1);
69390Sstevel@tonic-gate
69400Sstevel@tonic-gate if (strcmp((const char *)cmd->rptc_data, AUTH_PROP_ENABLED)
69410Sstevel@tonic-gate != 0)
69420Sstevel@tonic-gate return (0);
69430Sstevel@tonic-gate
69440Sstevel@tonic-gate loc += sz;
69450Sstevel@tonic-gate cmds_sz -= sz;
69460Sstevel@tonic-gate }
69470Sstevel@tonic-gate
69480Sstevel@tonic-gate return (1);
69490Sstevel@tonic-gate }
69500Sstevel@tonic-gate
69510Sstevel@tonic-gate int
rc_tx_commit(rc_node_ptr_t * txp,const void * cmds,size_t cmds_sz)69520Sstevel@tonic-gate rc_tx_commit(rc_node_ptr_t *txp, const void *cmds, size_t cmds_sz)
69530Sstevel@tonic-gate {
69540Sstevel@tonic-gate rc_node_t *np = txp->rnp_node;
69550Sstevel@tonic-gate rc_node_t *pp;
69560Sstevel@tonic-gate rc_node_t *nnp;
69570Sstevel@tonic-gate rc_node_pg_notify_t *pnp;
69580Sstevel@tonic-gate int rc;
69590Sstevel@tonic-gate permcheck_t *pcp;
69608497SThomas.Whitten@Sun.COM perm_status_t granted;
69618497SThomas.Whitten@Sun.COM int normal;
69625777Stw21770 char *pg_fmri = NULL;
69635777Stw21770 char *auth_string = NULL;
69645777Stw21770 int auth_status = ADT_SUCCESS;
69655777Stw21770 int auth_ret_value = ADT_SUCCESS;
69665777Stw21770 size_t sz_out;
69675777Stw21770 int tx_flag = 1;
69685777Stw21770 tx_commit_data_t *tx_data = NULL;
69690Sstevel@tonic-gate
69700Sstevel@tonic-gate RC_NODE_CHECK(np);
69710Sstevel@tonic-gate
69725777Stw21770 if ((txp->rnp_authorized != RC_AUTH_UNKNOWN) &&
69735777Stw21770 (txp->rnp_auth_string != NULL)) {
69745777Stw21770 auth_string = strdup(txp->rnp_auth_string);
69755777Stw21770 if (auth_string == NULL)
69765777Stw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
69775777Stw21770 }
69785777Stw21770
69795777Stw21770 if ((txp->rnp_authorized == RC_AUTH_UNKNOWN) &&
69805777Stw21770 is_main_repository) {
69810Sstevel@tonic-gate #ifdef NATIVE_BUILD
69825777Stw21770 if (!client_is_privileged()) {
69835777Stw21770 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
69845777Stw21770 }
69850Sstevel@tonic-gate #else
69860Sstevel@tonic-gate /* permission check: depends on contents of transaction */
69870Sstevel@tonic-gate pcp = pc_create();
69880Sstevel@tonic-gate if (pcp == NULL)
69890Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
69900Sstevel@tonic-gate
69910Sstevel@tonic-gate /* If normal is cleared, we won't do the normal checks. */
69920Sstevel@tonic-gate normal = 1;
69930Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
69940Sstevel@tonic-gate
69950Sstevel@tonic-gate if (strcmp(np->rn_name, AUTH_PG_GENERAL) == 0 &&
69960Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_TYPE) == 0) {
69970Sstevel@tonic-gate /* Touching general[framework]/action_authorization? */
69980Sstevel@tonic-gate rc = tx_modifies_action(cmds, cmds_sz);
69990Sstevel@tonic-gate if (rc == -1) {
70000Sstevel@tonic-gate pc_free(pcp);
70010Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
70020Sstevel@tonic-gate }
70030Sstevel@tonic-gate
70040Sstevel@tonic-gate if (rc) {
700511223STruong.Q.Nguyen@Sun.COM /*
700611223STruong.Q.Nguyen@Sun.COM * Yes: only AUTH_MODIFY and AUTH_MANAGE
700711223STruong.Q.Nguyen@Sun.COM * can be used.
700811223STruong.Q.Nguyen@Sun.COM */
700911223STruong.Q.Nguyen@Sun.COM rc = perm_add_enabling(pcp, AUTH_MODIFY);
701011223STruong.Q.Nguyen@Sun.COM
701111223STruong.Q.Nguyen@Sun.COM if (rc == REP_PROTOCOL_SUCCESS)
701211223STruong.Q.Nguyen@Sun.COM rc = perm_add_enabling(pcp,
701311223STruong.Q.Nguyen@Sun.COM AUTH_MANAGE);
701411223STruong.Q.Nguyen@Sun.COM
70150Sstevel@tonic-gate normal = 0;
70160Sstevel@tonic-gate } else {
70170Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
70180Sstevel@tonic-gate }
70190Sstevel@tonic-gate } else if (np->rn_id.rl_ids[ID_INSTANCE] != 0 &&
70200Sstevel@tonic-gate strcmp(np->rn_name, AUTH_PG_GENERAL_OVR) == 0 &&
70210Sstevel@tonic-gate strcmp(np->rn_type, AUTH_PG_GENERAL_OVR_TYPE) == 0) {
70220Sstevel@tonic-gate rc_node_t *instn;
70230Sstevel@tonic-gate
70240Sstevel@tonic-gate rc = tx_only_enabled(cmds, cmds_sz);
70250Sstevel@tonic-gate if (rc == -1) {
70260Sstevel@tonic-gate pc_free(pcp);
70270Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
70280Sstevel@tonic-gate }
70290Sstevel@tonic-gate
70300Sstevel@tonic-gate if (rc) {
70310Sstevel@tonic-gate rc = rc_node_parent(np, &instn);
70320Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
70330Sstevel@tonic-gate assert(rc == REP_PROTOCOL_FAIL_DELETED);
70340Sstevel@tonic-gate pc_free(pcp);
70350Sstevel@tonic-gate return (rc);
70360Sstevel@tonic-gate }
70370Sstevel@tonic-gate
70380Sstevel@tonic-gate assert(instn->rn_id.rl_type ==
70390Sstevel@tonic-gate REP_PROTOCOL_ENTITY_INSTANCE);
70400Sstevel@tonic-gate
70410Sstevel@tonic-gate rc = perm_add_inst_action_auth(pcp, instn);
70420Sstevel@tonic-gate rc_node_rele(instn);
70430Sstevel@tonic-gate switch (rc) {
70440Sstevel@tonic-gate case REP_PROTOCOL_SUCCESS:
70450Sstevel@tonic-gate break;
70460Sstevel@tonic-gate
70470Sstevel@tonic-gate case REP_PROTOCOL_FAIL_DELETED:
70480Sstevel@tonic-gate case REP_PROTOCOL_FAIL_NO_RESOURCES:
70490Sstevel@tonic-gate pc_free(pcp);
70500Sstevel@tonic-gate return (rc);
70510Sstevel@tonic-gate
70520Sstevel@tonic-gate default:
70530Sstevel@tonic-gate bad_error("perm_add_inst_action_auth",
70540Sstevel@tonic-gate rc);
70550Sstevel@tonic-gate }
70560Sstevel@tonic-gate } else {
70570Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS;
70580Sstevel@tonic-gate }
70590Sstevel@tonic-gate }
70600Sstevel@tonic-gate
70610Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS && normal) {
70620Sstevel@tonic-gate rc = perm_add_enabling(pcp, AUTH_MODIFY);
70630Sstevel@tonic-gate
70640Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
70650Sstevel@tonic-gate /* Add pgtype-specific authorization. */
70660Sstevel@tonic-gate const char * const auth =
70670Sstevel@tonic-gate perm_auth_for_pgtype(np->rn_type);
70680Sstevel@tonic-gate
70690Sstevel@tonic-gate if (auth != NULL)
70700Sstevel@tonic-gate rc = perm_add_enabling(pcp, auth);
70710Sstevel@tonic-gate }
70720Sstevel@tonic-gate
70730Sstevel@tonic-gate /* Add pg-specific modify_authorization auths. */
70740Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS)
70750Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np,
70760Sstevel@tonic-gate AUTH_PROP_MODIFY);
70770Sstevel@tonic-gate
70780Sstevel@tonic-gate /* If value_authorization values are ok, add them. */
70790Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
70800Sstevel@tonic-gate rc = tx_allow_value(cmds, cmds_sz, np);
70810Sstevel@tonic-gate if (rc == -1)
70820Sstevel@tonic-gate rc = REP_PROTOCOL_FAIL_BAD_REQUEST;
70830Sstevel@tonic-gate else if (rc)
70840Sstevel@tonic-gate rc = perm_add_enabling_values(pcp, np,
70850Sstevel@tonic-gate AUTH_PROP_VALUE);
70860Sstevel@tonic-gate }
70870Sstevel@tonic-gate }
70880Sstevel@tonic-gate
70890Sstevel@tonic-gate if (rc == REP_PROTOCOL_SUCCESS) {
70900Sstevel@tonic-gate granted = perm_granted(pcp);
70918497SThomas.Whitten@Sun.COM rc = map_granted_status(granted, pcp, &auth_string);
70928497SThomas.Whitten@Sun.COM if ((granted == PERM_DENIED) && auth_string) {
70935777Stw21770 /*
70948497SThomas.Whitten@Sun.COM * _PERMISSION_DENIED should not cause us
70958497SThomas.Whitten@Sun.COM * to exit at this point, because we still
70968497SThomas.Whitten@Sun.COM * want to generate an audit event.
70975777Stw21770 */
70988497SThomas.Whitten@Sun.COM rc = REP_PROTOCOL_SUCCESS;
70995777Stw21770 }
71000Sstevel@tonic-gate }
71010Sstevel@tonic-gate
71020Sstevel@tonic-gate pc_free(pcp);
71030Sstevel@tonic-gate
71040Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
71055777Stw21770 goto cleanout;
71065777Stw21770
71078497SThomas.Whitten@Sun.COM if (granted == PERM_DENIED) {
71085777Stw21770 auth_status = ADT_FAILURE;
71095777Stw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH;
71105777Stw21770 tx_flag = 0;
71115777Stw21770 }
71120Sstevel@tonic-gate #endif /* NATIVE_BUILD */
71135777Stw21770 } else if (txp->rnp_authorized == RC_AUTH_FAILED) {
71145777Stw21770 auth_status = ADT_FAILURE;
71155777Stw21770 auth_ret_value = ADT_FAIL_VALUE_AUTH;
71165777Stw21770 tx_flag = 0;
71175777Stw21770 }
71185777Stw21770
71195777Stw21770 pg_fmri = malloc(REP_PROTOCOL_FMRI_LEN);
71205777Stw21770 if (pg_fmri == NULL) {
71215777Stw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71225777Stw21770 goto cleanout;
71235777Stw21770 }
71245777Stw21770 if ((rc = rc_node_get_fmri_or_fragment(np, pg_fmri,
71255777Stw21770 REP_PROTOCOL_FMRI_LEN, &sz_out)) != REP_PROTOCOL_SUCCESS) {
71265777Stw21770 goto cleanout;
71275777Stw21770 }
71285777Stw21770
71295777Stw21770 /*
71305777Stw21770 * Parse the transaction commands into a useful form.
71315777Stw21770 */
71325777Stw21770 if ((rc = tx_commit_data_new(cmds, cmds_sz, &tx_data)) !=
71335777Stw21770 REP_PROTOCOL_SUCCESS) {
71345777Stw21770 goto cleanout;
71355777Stw21770 }
71365777Stw21770
71375777Stw21770 if (tx_flag == 0) {
71385777Stw21770 /* Authorization failed. Generate audit events. */
71395777Stw21770 generate_property_events(tx_data, pg_fmri, auth_string,
71405777Stw21770 auth_status, auth_ret_value);
71415777Stw21770 rc = REP_PROTOCOL_FAIL_PERMISSION_DENIED;
71425777Stw21770 goto cleanout;
71430Sstevel@tonic-gate }
71440Sstevel@tonic-gate
71450Sstevel@tonic-gate nnp = rc_node_alloc();
71465777Stw21770 if (nnp == NULL) {
71475777Stw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71485777Stw21770 goto cleanout;
71495777Stw21770 }
71500Sstevel@tonic-gate
71510Sstevel@tonic-gate nnp->rn_id = np->rn_id; /* structure assignment */
71520Sstevel@tonic-gate nnp->rn_hash = np->rn_hash;
71530Sstevel@tonic-gate nnp->rn_name = strdup(np->rn_name);
71540Sstevel@tonic-gate nnp->rn_type = strdup(np->rn_type);
71550Sstevel@tonic-gate nnp->rn_pgflags = np->rn_pgflags;
71560Sstevel@tonic-gate
71570Sstevel@tonic-gate nnp->rn_flags = RC_NODE_IN_TX | RC_NODE_USING_PARENT;
71580Sstevel@tonic-gate
71590Sstevel@tonic-gate if (nnp->rn_name == NULL || nnp->rn_type == NULL) {
71600Sstevel@tonic-gate rc_node_destroy(nnp);
71615777Stw21770 rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
71625777Stw21770 goto cleanout;
71630Sstevel@tonic-gate }
71640Sstevel@tonic-gate
71650Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
71665777Stw21770
71670Sstevel@tonic-gate /*
71680Sstevel@tonic-gate * We must have all of the old properties in the cache, or the
71690Sstevel@tonic-gate * database deletions could cause inconsistencies.
71700Sstevel@tonic-gate */
71710Sstevel@tonic-gate if ((rc = rc_node_fill_children(np, REP_PROTOCOL_ENTITY_PROPERTY)) !=
71720Sstevel@tonic-gate REP_PROTOCOL_SUCCESS) {
71730Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
71740Sstevel@tonic-gate rc_node_destroy(nnp);
71755777Stw21770 goto cleanout;
71760Sstevel@tonic-gate }
71770Sstevel@tonic-gate
71780Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_USING_PARENT)) {
71790Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
71800Sstevel@tonic-gate rc_node_destroy(nnp);
71815777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
71825777Stw21770 goto cleanout;
71830Sstevel@tonic-gate }
71840Sstevel@tonic-gate
71850Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
71860Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_USING_PARENT);
71870Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
71880Sstevel@tonic-gate rc_node_destroy(nnp);
71895777Stw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST;
71905777Stw21770 goto cleanout;
71910Sstevel@tonic-gate }
71920Sstevel@tonic-gate
71930Sstevel@tonic-gate pp = rc_node_hold_parent_flag(np, RC_NODE_CHILDREN_CHANGING);
71940Sstevel@tonic-gate if (pp == NULL) {
71950Sstevel@tonic-gate /* our parent is gone, we're going next... */
71960Sstevel@tonic-gate rc_node_destroy(nnp);
71970Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
71980Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
71990Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72005777Stw21770 rc = REP_PROTOCOL_FAIL_NOT_LATEST;
72015777Stw21770 goto cleanout;
72020Sstevel@tonic-gate }
72030Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72045777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
72055777Stw21770 goto cleanout;
72060Sstevel@tonic-gate }
72070Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72080Sstevel@tonic-gate
72090Sstevel@tonic-gate /*
72100Sstevel@tonic-gate * prepare for the transaction
72110Sstevel@tonic-gate */
72120Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
72130Sstevel@tonic-gate if (!rc_node_hold_flag(np, RC_NODE_IN_TX)) {
72140Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72150Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
72160Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
72170Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72180Sstevel@tonic-gate rc_node_destroy(nnp);
72195777Stw21770 rc = REP_PROTOCOL_FAIL_DELETED;
72205777Stw21770 goto cleanout;
72210Sstevel@tonic-gate }
72220Sstevel@tonic-gate nnp->rn_gen_id = np->rn_gen_id;
72230Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72240Sstevel@tonic-gate
72250Sstevel@tonic-gate /* Sets nnp->rn_gen_id on success. */
72265777Stw21770 rc = object_tx_commit(&np->rn_id, tx_data, &nnp->rn_gen_id);
72270Sstevel@tonic-gate
72280Sstevel@tonic-gate (void) pthread_mutex_lock(&np->rn_lock);
72290Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS) {
72300Sstevel@tonic-gate rc_node_rele_flag(np, RC_NODE_IN_TX);
72310Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72320Sstevel@tonic-gate (void) pthread_mutex_lock(&pp->rn_lock);
72330Sstevel@tonic-gate rc_node_rele_flag(pp, RC_NODE_CHILDREN_CHANGING);
72340Sstevel@tonic-gate (void) pthread_mutex_unlock(&pp->rn_lock);
72350Sstevel@tonic-gate rc_node_destroy(nnp);
72360Sstevel@tonic-gate rc_node_clear(txp, 0);
72370Sstevel@tonic-gate if (rc == REP_PROTOCOL_DONE)
72380Sstevel@tonic-gate rc = REP_PROTOCOL_SUCCESS; /* successful empty tx */
72395777Stw21770 goto cleanout;
72400Sstevel@tonic-gate }
72410Sstevel@tonic-gate
72420Sstevel@tonic-gate /*
72430Sstevel@tonic-gate * Notify waiters
72440Sstevel@tonic-gate */
72450Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
72460Sstevel@tonic-gate while ((pnp = uu_list_first(np->rn_pg_notify_list)) != NULL)
72470Sstevel@tonic-gate rc_pg_notify_fire(pnp);
72480Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
72490Sstevel@tonic-gate
72500Sstevel@tonic-gate np->rn_flags |= RC_NODE_OLD;
72510Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72520Sstevel@tonic-gate
72530Sstevel@tonic-gate rc_notify_remove_node(np);
72540Sstevel@tonic-gate
72550Sstevel@tonic-gate /*
72560Sstevel@tonic-gate * replace np with nnp
72570Sstevel@tonic-gate */
72580Sstevel@tonic-gate rc_node_relink_child(pp, np, nnp);
72590Sstevel@tonic-gate
72600Sstevel@tonic-gate /*
72610Sstevel@tonic-gate * all done -- clear the transaction.
72620Sstevel@tonic-gate */
72630Sstevel@tonic-gate rc_node_clear(txp, 0);
72645777Stw21770 generate_property_events(tx_data, pg_fmri, auth_string,
72655777Stw21770 auth_status, auth_ret_value);
72665777Stw21770
72675777Stw21770 rc = REP_PROTOCOL_SUCCESS;
72685777Stw21770
72695777Stw21770 cleanout:
72705777Stw21770 free(auth_string);
72715777Stw21770 free(pg_fmri);
72725777Stw21770 tx_commit_data_free(tx_data);
72735777Stw21770 return (rc);
72740Sstevel@tonic-gate }
72750Sstevel@tonic-gate
72760Sstevel@tonic-gate void
rc_pg_notify_init(rc_node_pg_notify_t * pnp)72770Sstevel@tonic-gate rc_pg_notify_init(rc_node_pg_notify_t *pnp)
72780Sstevel@tonic-gate {
72790Sstevel@tonic-gate uu_list_node_init(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
72800Sstevel@tonic-gate pnp->rnpn_pg = NULL;
72810Sstevel@tonic-gate pnp->rnpn_fd = -1;
72820Sstevel@tonic-gate }
72830Sstevel@tonic-gate
72840Sstevel@tonic-gate int
rc_pg_notify_setup(rc_node_pg_notify_t * pnp,rc_node_ptr_t * npp,int fd)72850Sstevel@tonic-gate rc_pg_notify_setup(rc_node_pg_notify_t *pnp, rc_node_ptr_t *npp, int fd)
72860Sstevel@tonic-gate {
72870Sstevel@tonic-gate rc_node_t *np;
72880Sstevel@tonic-gate
72890Sstevel@tonic-gate RC_NODE_PTR_GET_CHECK_AND_LOCK(np, npp);
72900Sstevel@tonic-gate
72910Sstevel@tonic-gate if (np->rn_id.rl_type != REP_PROTOCOL_ENTITY_PROPERTYGRP) {
72920Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
72930Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST);
72940Sstevel@tonic-gate }
72950Sstevel@tonic-gate
72960Sstevel@tonic-gate /*
72970Sstevel@tonic-gate * wait for any transaction in progress to complete
72980Sstevel@tonic-gate */
72990Sstevel@tonic-gate if (!rc_node_wait_flag(np, RC_NODE_IN_TX)) {
73000Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73010Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DELETED);
73020Sstevel@tonic-gate }
73030Sstevel@tonic-gate
73040Sstevel@tonic-gate if (np->rn_flags & RC_NODE_OLD) {
73050Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73060Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_LATEST);
73070Sstevel@tonic-gate }
73080Sstevel@tonic-gate
73090Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
73100Sstevel@tonic-gate rc_pg_notify_fire(pnp);
73110Sstevel@tonic-gate pnp->rnpn_pg = np;
73120Sstevel@tonic-gate pnp->rnpn_fd = fd;
73130Sstevel@tonic-gate (void) uu_list_insert_after(np->rn_pg_notify_list, NULL, pnp);
73140Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
73150Sstevel@tonic-gate
73160Sstevel@tonic-gate (void) pthread_mutex_unlock(&np->rn_lock);
73170Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
73180Sstevel@tonic-gate }
73190Sstevel@tonic-gate
73200Sstevel@tonic-gate void
rc_pg_notify_fini(rc_node_pg_notify_t * pnp)73210Sstevel@tonic-gate rc_pg_notify_fini(rc_node_pg_notify_t *pnp)
73220Sstevel@tonic-gate {
73230Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
73240Sstevel@tonic-gate rc_pg_notify_fire(pnp);
73250Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
73260Sstevel@tonic-gate
73270Sstevel@tonic-gate uu_list_node_fini(pnp, &pnp->rnpn_node, rc_pg_notify_pool);
73280Sstevel@tonic-gate }
73290Sstevel@tonic-gate
73300Sstevel@tonic-gate void
rc_notify_info_init(rc_notify_info_t * rnip)73310Sstevel@tonic-gate rc_notify_info_init(rc_notify_info_t *rnip)
73320Sstevel@tonic-gate {
73330Sstevel@tonic-gate int i;
73340Sstevel@tonic-gate
73350Sstevel@tonic-gate uu_list_node_init(rnip, &rnip->rni_list_node, rc_notify_info_pool);
73360Sstevel@tonic-gate uu_list_node_init(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
73370Sstevel@tonic-gate rc_notify_pool);
73380Sstevel@tonic-gate
73390Sstevel@tonic-gate rnip->rni_notify.rcn_node = NULL;
73400Sstevel@tonic-gate rnip->rni_notify.rcn_info = rnip;
73410Sstevel@tonic-gate
73420Sstevel@tonic-gate bzero(rnip->rni_namelist, sizeof (rnip->rni_namelist));
73430Sstevel@tonic-gate bzero(rnip->rni_typelist, sizeof (rnip->rni_typelist));
73440Sstevel@tonic-gate
73450Sstevel@tonic-gate (void) pthread_cond_init(&rnip->rni_cv, NULL);
73460Sstevel@tonic-gate
73470Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
73480Sstevel@tonic-gate rnip->rni_namelist[i] = NULL;
73490Sstevel@tonic-gate rnip->rni_typelist[i] = NULL;
73500Sstevel@tonic-gate }
73510Sstevel@tonic-gate }
73520Sstevel@tonic-gate
73530Sstevel@tonic-gate static void
rc_notify_info_insert_locked(rc_notify_info_t * rnip)73540Sstevel@tonic-gate rc_notify_info_insert_locked(rc_notify_info_t *rnip)
73550Sstevel@tonic-gate {
73560Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
73570Sstevel@tonic-gate
73580Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_ACTIVE));
73590Sstevel@tonic-gate
73600Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_ACTIVE;
73610Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_info_list, NULL, rnip);
73620Sstevel@tonic-gate (void) uu_list_insert_before(rc_notify_list, NULL, &rnip->rni_notify);
73630Sstevel@tonic-gate }
73640Sstevel@tonic-gate
73650Sstevel@tonic-gate static void
rc_notify_info_remove_locked(rc_notify_info_t * rnip)73660Sstevel@tonic-gate rc_notify_info_remove_locked(rc_notify_info_t *rnip)
73670Sstevel@tonic-gate {
73680Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify;
73690Sstevel@tonic-gate rc_notify_t *np;
73700Sstevel@tonic-gate
73710Sstevel@tonic-gate assert(MUTEX_HELD(&rc_pg_notify_lock));
73720Sstevel@tonic-gate
73730Sstevel@tonic-gate assert(rnip->rni_flags & RC_NOTIFY_ACTIVE);
73740Sstevel@tonic-gate
73750Sstevel@tonic-gate assert(!(rnip->rni_flags & RC_NOTIFY_DRAIN));
73760Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_DRAIN;
73770Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
73780Sstevel@tonic-gate
73790Sstevel@tonic-gate (void) uu_list_remove(rc_notify_info_list, rnip);
73800Sstevel@tonic-gate
73810Sstevel@tonic-gate /*
73820Sstevel@tonic-gate * clean up any notifications at the beginning of the list
73830Sstevel@tonic-gate */
73840Sstevel@tonic-gate if (uu_list_first(rc_notify_list) == me) {
738512299Stom.whitten@oracle.com /*
738612299Stom.whitten@oracle.com * We can't call rc_notify_remove_locked() unless
738712299Stom.whitten@oracle.com * rc_notify_in_use is 0.
738812299Stom.whitten@oracle.com */
738912299Stom.whitten@oracle.com while (rc_notify_in_use) {
739012299Stom.whitten@oracle.com (void) pthread_cond_wait(&rc_pg_notify_cv,
739112299Stom.whitten@oracle.com &rc_pg_notify_lock);
739212299Stom.whitten@oracle.com }
73930Sstevel@tonic-gate while ((np = uu_list_next(rc_notify_list, me)) != NULL &&
73940Sstevel@tonic-gate np->rcn_info == NULL)
73950Sstevel@tonic-gate rc_notify_remove_locked(np);
73960Sstevel@tonic-gate }
73970Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me);
73980Sstevel@tonic-gate
73990Sstevel@tonic-gate while (rnip->rni_waiters) {
74000Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv);
74010Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
74020Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
74030Sstevel@tonic-gate }
74040Sstevel@tonic-gate
74050Sstevel@tonic-gate rnip->rni_flags &= ~(RC_NOTIFY_DRAIN | RC_NOTIFY_ACTIVE);
74060Sstevel@tonic-gate }
74070Sstevel@tonic-gate
74080Sstevel@tonic-gate static int
rc_notify_info_add_watch(rc_notify_info_t * rnip,const char ** arr,const char * name)74090Sstevel@tonic-gate rc_notify_info_add_watch(rc_notify_info_t *rnip, const char **arr,
74100Sstevel@tonic-gate const char *name)
74110Sstevel@tonic-gate {
74120Sstevel@tonic-gate int i;
74130Sstevel@tonic-gate int rc;
74140Sstevel@tonic-gate char *f;
74150Sstevel@tonic-gate
74160Sstevel@tonic-gate rc = rc_check_type_name(REP_PROTOCOL_ENTITY_PROPERTYGRP, name);
74170Sstevel@tonic-gate if (rc != REP_PROTOCOL_SUCCESS)
74180Sstevel@tonic-gate return (rc);
74190Sstevel@tonic-gate
74200Sstevel@tonic-gate f = strdup(name);
74210Sstevel@tonic-gate if (f == NULL)
74220Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
74230Sstevel@tonic-gate
74240Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
74250Sstevel@tonic-gate
74260Sstevel@tonic-gate while (rnip->rni_flags & RC_NOTIFY_EMPTYING)
74270Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv, &rc_pg_notify_lock);
74280Sstevel@tonic-gate
74296961Stn143363 for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
74300Sstevel@tonic-gate if (arr[i] == NULL)
74310Sstevel@tonic-gate break;
74320Sstevel@tonic-gate
74336961Stn143363 /*
74346961Stn143363 * Don't add name if it's already being tracked.
74356961Stn143363 */
74366961Stn143363 if (strcmp(arr[i], f) == 0) {
74376961Stn143363 free(f);
74386961Stn143363 goto out;
74396961Stn143363 }
74406961Stn143363 }
74416961Stn143363
74420Sstevel@tonic-gate if (i == RC_NOTIFY_MAX_NAMES) {
74430Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
74440Sstevel@tonic-gate free(f);
74450Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES);
74460Sstevel@tonic-gate }
74470Sstevel@tonic-gate
74480Sstevel@tonic-gate arr[i] = f;
74496961Stn143363
74506961Stn143363 out:
74510Sstevel@tonic-gate if (!(rnip->rni_flags & RC_NOTIFY_ACTIVE))
74520Sstevel@tonic-gate rc_notify_info_insert_locked(rnip);
74530Sstevel@tonic-gate
74540Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
74550Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
74560Sstevel@tonic-gate }
74570Sstevel@tonic-gate
74580Sstevel@tonic-gate int
rc_notify_info_add_name(rc_notify_info_t * rnip,const char * name)74590Sstevel@tonic-gate rc_notify_info_add_name(rc_notify_info_t *rnip, const char *name)
74600Sstevel@tonic-gate {
74610Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_namelist, name));
74620Sstevel@tonic-gate }
74630Sstevel@tonic-gate
74640Sstevel@tonic-gate int
rc_notify_info_add_type(rc_notify_info_t * rnip,const char * type)74650Sstevel@tonic-gate rc_notify_info_add_type(rc_notify_info_t *rnip, const char *type)
74660Sstevel@tonic-gate {
74670Sstevel@tonic-gate return (rc_notify_info_add_watch(rnip, rnip->rni_typelist, type));
74680Sstevel@tonic-gate }
74690Sstevel@tonic-gate
74700Sstevel@tonic-gate /*
74710Sstevel@tonic-gate * Wait for and report an event of interest to rnip, a notification client
74720Sstevel@tonic-gate */
74730Sstevel@tonic-gate int
rc_notify_info_wait(rc_notify_info_t * rnip,rc_node_ptr_t * out,char * outp,size_t sz)74740Sstevel@tonic-gate rc_notify_info_wait(rc_notify_info_t *rnip, rc_node_ptr_t *out,
74750Sstevel@tonic-gate char *outp, size_t sz)
74760Sstevel@tonic-gate {
74770Sstevel@tonic-gate rc_notify_t *np;
74780Sstevel@tonic-gate rc_notify_t *me = &rnip->rni_notify;
74790Sstevel@tonic-gate rc_node_t *nnp;
74800Sstevel@tonic-gate rc_notify_delete_t *ndp;
74810Sstevel@tonic-gate
74820Sstevel@tonic-gate int am_first_info;
74830Sstevel@tonic-gate
74840Sstevel@tonic-gate if (sz > 0)
74850Sstevel@tonic-gate outp[0] = 0;
74860Sstevel@tonic-gate
74870Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
74880Sstevel@tonic-gate
74890Sstevel@tonic-gate while ((rnip->rni_flags & (RC_NOTIFY_ACTIVE | RC_NOTIFY_DRAIN)) ==
74900Sstevel@tonic-gate RC_NOTIFY_ACTIVE) {
74910Sstevel@tonic-gate /*
74920Sstevel@tonic-gate * If I'm first on the notify list, it is my job to
74930Sstevel@tonic-gate * clean up any notifications I pass by. I can't do that
74940Sstevel@tonic-gate * if someone is blocking the list from removals, so I
74950Sstevel@tonic-gate * have to wait until they have all drained.
74960Sstevel@tonic-gate */
74970Sstevel@tonic-gate am_first_info = (uu_list_first(rc_notify_list) == me);
74980Sstevel@tonic-gate if (am_first_info && rc_notify_in_use) {
74990Sstevel@tonic-gate rnip->rni_waiters++;
75000Sstevel@tonic-gate (void) pthread_cond_wait(&rc_pg_notify_cv,
75010Sstevel@tonic-gate &rc_pg_notify_lock);
75020Sstevel@tonic-gate rnip->rni_waiters--;
75030Sstevel@tonic-gate continue;
75040Sstevel@tonic-gate }
75050Sstevel@tonic-gate
75060Sstevel@tonic-gate /*
75070Sstevel@tonic-gate * Search the list for a node of interest.
75080Sstevel@tonic-gate */
75090Sstevel@tonic-gate np = uu_list_next(rc_notify_list, me);
75100Sstevel@tonic-gate while (np != NULL && !rc_notify_info_interested(rnip, np)) {
75110Sstevel@tonic-gate rc_notify_t *next = uu_list_next(rc_notify_list, np);
75120Sstevel@tonic-gate
75130Sstevel@tonic-gate if (am_first_info) {
75140Sstevel@tonic-gate if (np->rcn_info) {
75150Sstevel@tonic-gate /*
75160Sstevel@tonic-gate * Passing another client -- stop
75170Sstevel@tonic-gate * cleaning up notifications
75180Sstevel@tonic-gate */
75190Sstevel@tonic-gate am_first_info = 0;
75200Sstevel@tonic-gate } else {
75210Sstevel@tonic-gate rc_notify_remove_locked(np);
75220Sstevel@tonic-gate }
75230Sstevel@tonic-gate }
75240Sstevel@tonic-gate np = next;
75250Sstevel@tonic-gate }
75260Sstevel@tonic-gate
75270Sstevel@tonic-gate /*
75280Sstevel@tonic-gate * Nothing of interest -- wait for notification
75290Sstevel@tonic-gate */
75300Sstevel@tonic-gate if (np == NULL) {
75310Sstevel@tonic-gate rnip->rni_waiters++;
75320Sstevel@tonic-gate (void) pthread_cond_wait(&rnip->rni_cv,
75330Sstevel@tonic-gate &rc_pg_notify_lock);
75340Sstevel@tonic-gate rnip->rni_waiters--;
75350Sstevel@tonic-gate continue;
75360Sstevel@tonic-gate }
75370Sstevel@tonic-gate
75380Sstevel@tonic-gate /*
75390Sstevel@tonic-gate * found something to report -- move myself after the
75400Sstevel@tonic-gate * notification and process it.
75410Sstevel@tonic-gate */
75420Sstevel@tonic-gate (void) uu_list_remove(rc_notify_list, me);
75430Sstevel@tonic-gate (void) uu_list_insert_after(rc_notify_list, np, me);
75440Sstevel@tonic-gate
75450Sstevel@tonic-gate if ((ndp = np->rcn_delete) != NULL) {
75460Sstevel@tonic-gate (void) strlcpy(outp, ndp->rnd_fmri, sz);
75470Sstevel@tonic-gate if (am_first_info)
75480Sstevel@tonic-gate rc_notify_remove_locked(np);
75490Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75500Sstevel@tonic-gate rc_node_clear(out, 0);
75510Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
75520Sstevel@tonic-gate }
75530Sstevel@tonic-gate
75540Sstevel@tonic-gate nnp = np->rcn_node;
75550Sstevel@tonic-gate assert(nnp != NULL);
75560Sstevel@tonic-gate
75570Sstevel@tonic-gate /*
75580Sstevel@tonic-gate * We can't bump nnp's reference count without grabbing its
75590Sstevel@tonic-gate * lock, and rc_pg_notify_lock is a leaf lock. So we
75600Sstevel@tonic-gate * temporarily block all removals to keep nnp from
75610Sstevel@tonic-gate * disappearing.
75620Sstevel@tonic-gate */
75630Sstevel@tonic-gate rc_notify_in_use++;
75640Sstevel@tonic-gate assert(rc_notify_in_use > 0);
75650Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75660Sstevel@tonic-gate
75670Sstevel@tonic-gate rc_node_assign(out, nnp);
75680Sstevel@tonic-gate
75690Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
75700Sstevel@tonic-gate assert(rc_notify_in_use > 0);
75710Sstevel@tonic-gate rc_notify_in_use--;
757212299Stom.whitten@oracle.com
757312299Stom.whitten@oracle.com if (am_first_info) {
757412299Stom.whitten@oracle.com /*
757512299Stom.whitten@oracle.com * While we had the lock dropped, another thread
757612299Stom.whitten@oracle.com * may have also incremented rc_notify_in_use. We
757712299Stom.whitten@oracle.com * need to make sure that we're back to 0 before
757812299Stom.whitten@oracle.com * removing the node.
757912299Stom.whitten@oracle.com */
758012299Stom.whitten@oracle.com while (rc_notify_in_use) {
758112299Stom.whitten@oracle.com (void) pthread_cond_wait(&rc_pg_notify_cv,
758212299Stom.whitten@oracle.com &rc_pg_notify_lock);
758312299Stom.whitten@oracle.com }
75840Sstevel@tonic-gate rc_notify_remove_locked(np);
758512299Stom.whitten@oracle.com }
75860Sstevel@tonic-gate if (rc_notify_in_use == 0)
75870Sstevel@tonic-gate (void) pthread_cond_broadcast(&rc_pg_notify_cv);
75880Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75890Sstevel@tonic-gate
75900Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS);
75910Sstevel@tonic-gate }
75920Sstevel@tonic-gate /*
75930Sstevel@tonic-gate * If we're the last one out, let people know it's clear.
75940Sstevel@tonic-gate */
75950Sstevel@tonic-gate if (rnip->rni_waiters == 0)
75960Sstevel@tonic-gate (void) pthread_cond_broadcast(&rnip->rni_cv);
75970Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
75980Sstevel@tonic-gate return (REP_PROTOCOL_DONE);
75990Sstevel@tonic-gate }
76000Sstevel@tonic-gate
76010Sstevel@tonic-gate static void
rc_notify_info_reset(rc_notify_info_t * rnip)76020Sstevel@tonic-gate rc_notify_info_reset(rc_notify_info_t *rnip)
76030Sstevel@tonic-gate {
76040Sstevel@tonic-gate int i;
76050Sstevel@tonic-gate
76060Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
76070Sstevel@tonic-gate if (rnip->rni_flags & RC_NOTIFY_ACTIVE)
76080Sstevel@tonic-gate rc_notify_info_remove_locked(rnip);
76090Sstevel@tonic-gate assert(!(rnip->rni_flags & (RC_NOTIFY_DRAIN | RC_NOTIFY_EMPTYING)));
76100Sstevel@tonic-gate rnip->rni_flags |= RC_NOTIFY_EMPTYING;
76110Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76120Sstevel@tonic-gate
76130Sstevel@tonic-gate for (i = 0; i < RC_NOTIFY_MAX_NAMES; i++) {
76140Sstevel@tonic-gate if (rnip->rni_namelist[i] != NULL) {
76150Sstevel@tonic-gate free((void *)rnip->rni_namelist[i]);
76160Sstevel@tonic-gate rnip->rni_namelist[i] = NULL;
76170Sstevel@tonic-gate }
76180Sstevel@tonic-gate if (rnip->rni_typelist[i] != NULL) {
76190Sstevel@tonic-gate free((void *)rnip->rni_typelist[i]);
76200Sstevel@tonic-gate rnip->rni_typelist[i] = NULL;
76210Sstevel@tonic-gate }
76220Sstevel@tonic-gate }
76230Sstevel@tonic-gate
76240Sstevel@tonic-gate (void) pthread_mutex_lock(&rc_pg_notify_lock);
76250Sstevel@tonic-gate rnip->rni_flags &= ~RC_NOTIFY_EMPTYING;
76260Sstevel@tonic-gate (void) pthread_mutex_unlock(&rc_pg_notify_lock);
76270Sstevel@tonic-gate }
76280Sstevel@tonic-gate
76290Sstevel@tonic-gate void
rc_notify_info_fini(rc_notify_info_t * rnip)76300Sstevel@tonic-gate rc_notify_info_fini(rc_notify_info_t *rnip)
76310Sstevel@tonic-gate {
76320Sstevel@tonic-gate rc_notify_info_reset(rnip);
76330Sstevel@tonic-gate
76340Sstevel@tonic-gate uu_list_node_fini(rnip, &rnip->rni_list_node, rc_notify_info_pool);
76350Sstevel@tonic-gate uu_list_node_fini(&rnip->rni_notify, &rnip->rni_notify.rcn_list_node,
76360Sstevel@tonic-gate rc_notify_pool);
76370Sstevel@tonic-gate }
7638