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 52832Sjeanm * Common Development and Distribution License (the "License"). 62832Sjeanm * 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 */ 215777Stw21770 220Sstevel@tonic-gate /* 23*8497SThomas.Whitten@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * This is the client layer for svc.configd. All direct protocol interactions 290Sstevel@tonic-gate * are handled here. 300Sstevel@tonic-gate * 310Sstevel@tonic-gate * Essentially, the job of this layer is to turn the idempotent protocol 320Sstevel@tonic-gate * into a series of non-idempotent calls into the object layer, while 330Sstevel@tonic-gate * also handling the necessary locking. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include <alloca.h> 370Sstevel@tonic-gate #include <assert.h> 385777Stw21770 #include <bsm/adt_event.h> 390Sstevel@tonic-gate #include <door.h> 400Sstevel@tonic-gate #include <errno.h> 415777Stw21770 #include <libintl.h> 420Sstevel@tonic-gate #include <limits.h> 430Sstevel@tonic-gate #include <pthread.h> 440Sstevel@tonic-gate #include <stdio.h> 450Sstevel@tonic-gate #include <stdlib.h> 460Sstevel@tonic-gate #include <string.h> 475777Stw21770 #include <syslog.h> 485777Stw21770 #include <ucred.h> 490Sstevel@tonic-gate #include <unistd.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <libuutil.h> 520Sstevel@tonic-gate 530Sstevel@tonic-gate #include "configd.h" 540Sstevel@tonic-gate #include "repcache_protocol.h" 550Sstevel@tonic-gate 560Sstevel@tonic-gate #define INVALID_CHANGEID (0) 570Sstevel@tonic-gate #define INVALID_DOORID ((door_id_t)-1) 580Sstevel@tonic-gate #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN) 590Sstevel@tonic-gate 600Sstevel@tonic-gate /* 610Sstevel@tonic-gate * lint doesn't like constant assertions 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate #ifdef lint 640Sstevel@tonic-gate #define assert_nolint(x) (void)0 650Sstevel@tonic-gate #else 660Sstevel@tonic-gate #define assert_nolint(x) assert(x) 670Sstevel@tonic-gate #endif 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * Protects client linkage and the freelist 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate #define CLIENT_HASH_SIZE 64 730Sstevel@tonic-gate 740Sstevel@tonic-gate #pragma align 64(client_hash) 750Sstevel@tonic-gate static client_bucket_t client_hash[CLIENT_HASH_SIZE]; 760Sstevel@tonic-gate 77407Sjwadams static uu_avl_pool_t *entity_pool; 78407Sjwadams static uu_avl_pool_t *iter_pool; 790Sstevel@tonic-gate static uu_list_pool_t *client_pool; 800Sstevel@tonic-gate 810Sstevel@tonic-gate #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))]) 820Sstevel@tonic-gate 830Sstevel@tonic-gate uint_t request_log_size = 1024; /* tunable, before we start */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER; 860Sstevel@tonic-gate static uint_t request_log_cur; 870Sstevel@tonic-gate request_log_entry_t *request_log; 880Sstevel@tonic-gate 890Sstevel@tonic-gate static uint32_t client_maxid; 900Sstevel@tonic-gate static pthread_mutex_t client_lock; /* protects client_maxid */ 910Sstevel@tonic-gate 920Sstevel@tonic-gate static request_log_entry_t * 930Sstevel@tonic-gate get_log(void) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate thread_info_t *ti = thread_self(); 960Sstevel@tonic-gate return (&ti->ti_log); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 990Sstevel@tonic-gate void 1000Sstevel@tonic-gate log_enter(request_log_entry_t *rlp) 1010Sstevel@tonic-gate { 1020Sstevel@tonic-gate if (rlp->rl_start != 0 && request_log != NULL) { 1030Sstevel@tonic-gate request_log_entry_t *logrlp; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate (void) pthread_mutex_lock(&request_log_lock); 1060Sstevel@tonic-gate assert(request_log_cur < request_log_size); 1070Sstevel@tonic-gate logrlp = &request_log[request_log_cur++]; 1080Sstevel@tonic-gate if (request_log_cur == request_log_size) 1090Sstevel@tonic-gate request_log_cur = 0; 1100Sstevel@tonic-gate (void) memcpy(logrlp, rlp, sizeof (*rlp)); 1110Sstevel@tonic-gate (void) pthread_mutex_unlock(&request_log_lock); 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Note that the svc.configd dmod will join all of the per-thread log entries 1170Sstevel@tonic-gate * with the main log, so that even if the log is disabled, there is some 1180Sstevel@tonic-gate * information available. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate static request_log_entry_t * 1210Sstevel@tonic-gate start_log(uint32_t clientid) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate log_enter(rlp); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate (void) memset(rlp, 0, sizeof (*rlp)); 1280Sstevel@tonic-gate rlp->rl_start = gethrtime(); 1290Sstevel@tonic-gate rlp->rl_tid = pthread_self(); 1300Sstevel@tonic-gate rlp->rl_clientid = clientid; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate return (rlp); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate void 1360Sstevel@tonic-gate end_log(void) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate request_log_entry_t *rlp = get_log(); 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate rlp->rl_end = gethrtime(); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate static void 1440Sstevel@tonic-gate add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id, 1450Sstevel@tonic-gate void *ptr) 1460Sstevel@tonic-gate { 1470Sstevel@tonic-gate request_log_ptr_t *rpp; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate if (rlp == NULL) 1500Sstevel@tonic-gate return; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate if (rlp->rl_num_ptrs >= MAX_PTRS) 1530Sstevel@tonic-gate return; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++]; 1560Sstevel@tonic-gate rpp->rlp_type = type; 1570Sstevel@tonic-gate rpp->rlp_id = id; 1580Sstevel@tonic-gate rpp->rlp_ptr = ptr; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * For entities, it's useful to have the node pointer at the start 1620Sstevel@tonic-gate * of the request. 1630Sstevel@tonic-gate */ 1640Sstevel@tonic-gate if (type == RC_PTR_TYPE_ENTITY && ptr != NULL) 1650Sstevel@tonic-gate rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node; 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate int 1690Sstevel@tonic-gate client_is_privileged(void) 1700Sstevel@tonic-gate { 1710Sstevel@tonic-gate thread_info_t *ti = thread_self(); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate ucred_t *uc; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate if (ti->ti_active_client != NULL && 1760Sstevel@tonic-gate ti->ti_active_client->rc_all_auths) 1770Sstevel@tonic-gate return (1); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate if ((uc = get_ucred()) == NULL) 1800Sstevel@tonic-gate return (0); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate return (ucred_is_privileged(uc)); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /*ARGSUSED*/ 1860Sstevel@tonic-gate static int 1870Sstevel@tonic-gate client_compare(const void *lc_arg, const void *rc_arg, void *private) 1880Sstevel@tonic-gate { 1890Sstevel@tonic-gate uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id; 1900Sstevel@tonic-gate uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate if (l_id > r_id) 1930Sstevel@tonic-gate return (1); 1940Sstevel@tonic-gate if (l_id < r_id) 1950Sstevel@tonic-gate return (-1); 1960Sstevel@tonic-gate return (0); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /*ARGSUSED*/ 2000Sstevel@tonic-gate static int 2010Sstevel@tonic-gate entity_compare(const void *lc_arg, const void *rc_arg, void *private) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id; 2040Sstevel@tonic-gate uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate if (l_id > r_id) 2070Sstevel@tonic-gate return (1); 2080Sstevel@tonic-gate if (l_id < r_id) 2090Sstevel@tonic-gate return (-1); 2100Sstevel@tonic-gate return (0); 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /*ARGSUSED*/ 2140Sstevel@tonic-gate static int 2150Sstevel@tonic-gate iter_compare(const void *lc_arg, const void *rc_arg, void *private) 2160Sstevel@tonic-gate { 2170Sstevel@tonic-gate uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id; 2180Sstevel@tonic-gate uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate if (l_id > r_id) 2210Sstevel@tonic-gate return (1); 2220Sstevel@tonic-gate if (l_id < r_id) 2230Sstevel@tonic-gate return (-1); 2240Sstevel@tonic-gate return (0); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate static int 2280Sstevel@tonic-gate client_hash_init(void) 2290Sstevel@tonic-gate { 2300Sstevel@tonic-gate int x; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate assert_nolint(offsetof(repcache_entity_t, re_id) == 0); 233407Sjwadams entity_pool = uu_avl_pool_create("repcache_entitys", 2340Sstevel@tonic-gate sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link), 235407Sjwadams entity_compare, UU_AVL_POOL_DEBUG); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate assert_nolint(offsetof(repcache_iter_t, ri_id) == 0); 238407Sjwadams iter_pool = uu_avl_pool_create("repcache_iters", 2390Sstevel@tonic-gate sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link), 240407Sjwadams iter_compare, UU_AVL_POOL_DEBUG); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate assert_nolint(offsetof(repcache_client_t, rc_id) == 0); 2430Sstevel@tonic-gate client_pool = uu_list_pool_create("repcache_clients", 2440Sstevel@tonic-gate sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link), 2450Sstevel@tonic-gate client_compare, UU_LIST_POOL_DEBUG); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL) 2480Sstevel@tonic-gate return (0); 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate for (x = 0; x < CLIENT_HASH_SIZE; x++) { 2510Sstevel@tonic-gate uu_list_t *lp = uu_list_create(client_pool, &client_hash[x], 2520Sstevel@tonic-gate UU_LIST_SORTED); 2530Sstevel@tonic-gate if (lp == NULL) 2540Sstevel@tonic-gate return (0); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate (void) pthread_mutex_init(&client_hash[x].cb_lock, NULL); 2570Sstevel@tonic-gate client_hash[x].cb_list = lp; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate return (1); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate static repcache_client_t * 2640Sstevel@tonic-gate client_alloc(void) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate repcache_client_t *cp; 2670Sstevel@tonic-gate cp = uu_zalloc(sizeof (*cp)); 2680Sstevel@tonic-gate if (cp == NULL) 2690Sstevel@tonic-gate return (NULL); 2700Sstevel@tonic-gate 271407Sjwadams cp->rc_entities = uu_avl_create(entity_pool, cp, 0); 272407Sjwadams if (cp->rc_entities == NULL) 2730Sstevel@tonic-gate goto fail; 2740Sstevel@tonic-gate 275407Sjwadams cp->rc_iters = uu_avl_create(iter_pool, cp, 0); 276407Sjwadams if (cp->rc_iters == NULL) 2770Sstevel@tonic-gate goto fail; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate uu_list_node_init(cp, &cp->rc_link, client_pool); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate cp->rc_doorfd = -1; 2820Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate (void) pthread_mutex_init(&cp->rc_lock, NULL); 2855777Stw21770 (void) pthread_mutex_init(&cp->rc_annotate_lock, NULL); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate rc_node_ptr_init(&cp->rc_notify_ptr); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate return (cp); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate fail: 292407Sjwadams if (cp->rc_iters != NULL) 293407Sjwadams uu_avl_destroy(cp->rc_iters); 294407Sjwadams if (cp->rc_entities != NULL) 295407Sjwadams uu_avl_destroy(cp->rc_entities); 2960Sstevel@tonic-gate uu_free(cp); 2970Sstevel@tonic-gate return (NULL); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate static void 3010Sstevel@tonic-gate client_free(repcache_client_t *cp) 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate assert(cp->rc_insert_thr == 0); 3040Sstevel@tonic-gate assert(cp->rc_refcnt == 0); 3050Sstevel@tonic-gate assert(cp->rc_doorfd == -1); 3060Sstevel@tonic-gate assert(cp->rc_doorid == INVALID_DOORID); 307407Sjwadams assert(uu_avl_first(cp->rc_entities) == NULL); 308407Sjwadams assert(uu_avl_first(cp->rc_iters) == NULL); 309407Sjwadams uu_avl_destroy(cp->rc_entities); 310407Sjwadams uu_avl_destroy(cp->rc_iters); 3110Sstevel@tonic-gate uu_list_node_fini(cp, &cp->rc_link, client_pool); 3120Sstevel@tonic-gate (void) pthread_mutex_destroy(&cp->rc_lock); 3135777Stw21770 (void) pthread_mutex_destroy(&cp->rc_annotate_lock); 3145777Stw21770 rc_node_ptr_free_mem(&cp->rc_notify_ptr); 3150Sstevel@tonic-gate uu_free(cp); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate static void 3190Sstevel@tonic-gate client_insert(repcache_client_t *cp) 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(cp->rc_id); 3220Sstevel@tonic-gate uu_list_index_t idx; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate assert(cp->rc_id > 0); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * We assume it does not already exist 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate (void) uu_list_find(bp->cb_list, cp, NULL, &idx); 3310Sstevel@tonic-gate uu_list_insert(bp->cb_list, cp, idx); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate static repcache_client_t * 3370Sstevel@tonic-gate client_lookup(uint32_t id) 3380Sstevel@tonic-gate { 3390Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 3400Sstevel@tonic-gate repcache_client_t *cp; 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * Bump the reference count 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate if (cp != NULL) { 3500Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3510Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 3520Sstevel@tonic-gate cp->rc_refcnt++; 3530Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate return (cp); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate static void 3610Sstevel@tonic-gate client_release(repcache_client_t *cp) 3620Sstevel@tonic-gate { 3630Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3640Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3650Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate --cp->rc_refcnt; 3680Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3690Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * We only allow one thread to be inserting at a time, to prevent 3740Sstevel@tonic-gate * insert/insert races. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate static void 3770Sstevel@tonic-gate client_start_insert(repcache_client_t *cp) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3800Sstevel@tonic-gate assert(cp->rc_refcnt > 0); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate while (cp->rc_insert_thr != 0) { 3830Sstevel@tonic-gate assert(cp->rc_insert_thr != pthread_self()); 3840Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 3850Sstevel@tonic-gate } 3860Sstevel@tonic-gate cp->rc_insert_thr = pthread_self(); 3870Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate static void 3910Sstevel@tonic-gate client_end_insert(repcache_client_t *cp) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 3940Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 3950Sstevel@tonic-gate cp->rc_insert_thr = 0; 3960Sstevel@tonic-gate (void) pthread_cond_broadcast(&cp->rc_cv); 3970Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /*ARGSUSED*/ 4010Sstevel@tonic-gate static repcache_entity_t * 4020Sstevel@tonic-gate entity_alloc(repcache_client_t *cp) 4030Sstevel@tonic-gate { 4040Sstevel@tonic-gate repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t)); 4050Sstevel@tonic-gate if (ep != NULL) { 406407Sjwadams uu_avl_node_init(ep, &ep->re_link, entity_pool); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate return (ep); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate static void 4120Sstevel@tonic-gate entity_add(repcache_client_t *cp, repcache_entity_t *ep) 4130Sstevel@tonic-gate { 414407Sjwadams uu_avl_index_t idx; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 4170Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 4180Sstevel@tonic-gate 419407Sjwadams (void) uu_avl_find(cp->rc_entities, ep, NULL, &idx); 420407Sjwadams uu_avl_insert(cp->rc_entities, ep, idx); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate static repcache_entity_t * 4260Sstevel@tonic-gate entity_find(repcache_client_t *cp, uint32_t id) 4270Sstevel@tonic-gate { 4280Sstevel@tonic-gate repcache_entity_t *ep; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 431407Sjwadams ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 4320Sstevel@tonic-gate if (ep != NULL) { 4330Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep); 4340Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate return (ep); 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate /* 4420Sstevel@tonic-gate * Fails with 4430Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 4440Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate static int 4470Sstevel@tonic-gate entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1, 4480Sstevel@tonic-gate uint32_t id2, repcache_entity_t **out2) 4490Sstevel@tonic-gate { 4500Sstevel@tonic-gate repcache_entity_t *e1, *e2; 4510Sstevel@tonic-gate request_log_entry_t *rlp; 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate if (id1 == id2) 4540Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_DUPLICATE_ID); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 457407Sjwadams e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL); 458407Sjwadams e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL); 4590Sstevel@tonic-gate if (e1 == NULL || e2 == NULL) { 4600Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4610Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate assert(e1 != e2); 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * locks are ordered by id number 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate if (id1 < id2) { 4700Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4710Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4720Sstevel@tonic-gate } else { 4730Sstevel@tonic-gate (void) pthread_mutex_lock(&e2->re_lock); 4740Sstevel@tonic-gate (void) pthread_mutex_lock(&e1->re_lock); 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate *out1 = e1; 4770Sstevel@tonic-gate *out2 = e2; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 4820Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1); 4830Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate static void 4900Sstevel@tonic-gate entity_release(repcache_entity_t *ep) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate assert(ep->re_node.rnp_node == NULL || 4930Sstevel@tonic-gate !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock)); 4940Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->re_lock); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate static void 4980Sstevel@tonic-gate entity_destroy(repcache_entity_t *entity) 4990Sstevel@tonic-gate { 5000Sstevel@tonic-gate (void) pthread_mutex_lock(&entity->re_lock); 5010Sstevel@tonic-gate rc_node_clear(&entity->re_node, 0); 5020Sstevel@tonic-gate (void) pthread_mutex_unlock(&entity->re_lock); 5030Sstevel@tonic-gate 504407Sjwadams uu_avl_node_fini(entity, &entity->re_link, entity_pool); 5050Sstevel@tonic-gate (void) pthread_mutex_destroy(&entity->re_lock); 5065777Stw21770 rc_node_ptr_free_mem(&entity->re_node); 5070Sstevel@tonic-gate uu_free(entity); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate static void 5110Sstevel@tonic-gate entity_remove(repcache_client_t *cp, uint32_t id) 5120Sstevel@tonic-gate { 5130Sstevel@tonic-gate repcache_entity_t *entity; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 516407Sjwadams entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL); 5177266Sbustos if (entity != NULL) { 5187266Sbustos add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, entity); 5197266Sbustos 520407Sjwadams uu_avl_remove(cp->rc_entities, entity); 5217266Sbustos } 5220Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate if (entity != NULL) 5250Sstevel@tonic-gate entity_destroy(entity); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate static void 5290Sstevel@tonic-gate entity_cleanup(repcache_client_t *cp) 5300Sstevel@tonic-gate { 5310Sstevel@tonic-gate repcache_entity_t *ep; 5320Sstevel@tonic-gate void *cookie = NULL; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 535407Sjwadams while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) { 5360Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5370Sstevel@tonic-gate entity_destroy(ep); 5380Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /*ARGSUSED*/ 5440Sstevel@tonic-gate static repcache_iter_t * 5450Sstevel@tonic-gate iter_alloc(repcache_client_t *cp) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate repcache_iter_t *iter; 5480Sstevel@tonic-gate iter = uu_zalloc(sizeof (repcache_iter_t)); 5490Sstevel@tonic-gate if (iter != NULL) 550407Sjwadams uu_avl_node_init(iter, &iter->ri_link, iter_pool); 5510Sstevel@tonic-gate return (iter); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate static void 5550Sstevel@tonic-gate iter_add(repcache_client_t *cp, repcache_iter_t *iter) 5560Sstevel@tonic-gate { 5570Sstevel@tonic-gate uu_list_index_t idx; 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5600Sstevel@tonic-gate assert(cp->rc_insert_thr == pthread_self()); 5610Sstevel@tonic-gate 562407Sjwadams (void) uu_avl_find(cp->rc_iters, iter, NULL, &idx); 563407Sjwadams uu_avl_insert(cp->rc_iters, iter, idx); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate static repcache_iter_t * 5690Sstevel@tonic-gate iter_find(repcache_client_t *cp, uint32_t id) 5700Sstevel@tonic-gate { 5710Sstevel@tonic-gate repcache_iter_t *iter; 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 5740Sstevel@tonic-gate 575407Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 5760Sstevel@tonic-gate if (iter != NULL) { 5770Sstevel@tonic-gate add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter); 5780Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate return (iter); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* 5860Sstevel@tonic-gate * Fails with 5870Sstevel@tonic-gate * _UNKNOWN_ID - iter_id or entity_id does not designate an active register 5880Sstevel@tonic-gate */ 5890Sstevel@tonic-gate static int 5900Sstevel@tonic-gate iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id, 5910Sstevel@tonic-gate repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp) 5920Sstevel@tonic-gate { 5930Sstevel@tonic-gate repcache_iter_t *iter; 5940Sstevel@tonic-gate repcache_entity_t *ep; 5950Sstevel@tonic-gate request_log_entry_t *rlp; 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 598407Sjwadams iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL); 599407Sjwadams ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock)); 6020Sstevel@tonic-gate assert(ep == NULL || !MUTEX_HELD(&ep->re_lock)); 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (iter == NULL || ep == NULL) { 6050Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6060Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6100Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->re_lock); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate *iterp = iter; 6150Sstevel@tonic-gate *epp = ep; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate if ((rlp = get_log()) != NULL) { 6180Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep); 6190Sstevel@tonic-gate add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate static void 6260Sstevel@tonic-gate iter_release(repcache_iter_t *iter) 6270Sstevel@tonic-gate { 6280Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate static void 6320Sstevel@tonic-gate iter_destroy(repcache_iter_t *iter) 6330Sstevel@tonic-gate { 6340Sstevel@tonic-gate (void) pthread_mutex_lock(&iter->ri_lock); 6350Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 6360Sstevel@tonic-gate (void) pthread_mutex_unlock(&iter->ri_lock); 6370Sstevel@tonic-gate 638407Sjwadams uu_avl_node_fini(iter, &iter->ri_link, iter_pool); 6390Sstevel@tonic-gate (void) pthread_mutex_destroy(&iter->ri_lock); 6400Sstevel@tonic-gate uu_free(iter); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate static void 6440Sstevel@tonic-gate iter_remove(repcache_client_t *cp, uint32_t id) 6450Sstevel@tonic-gate { 6460Sstevel@tonic-gate repcache_iter_t *iter; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 649407Sjwadams iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL); 6500Sstevel@tonic-gate if (iter != NULL) 651407Sjwadams uu_avl_remove(cp->rc_iters, iter); 6520Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate if (iter != NULL) 6550Sstevel@tonic-gate iter_destroy(iter); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate static void 6590Sstevel@tonic-gate iter_cleanup(repcache_client_t *cp) 6600Sstevel@tonic-gate { 6610Sstevel@tonic-gate repcache_iter_t *iter; 6620Sstevel@tonic-gate void *cookie = NULL; 6630Sstevel@tonic-gate 6640Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 665407Sjwadams while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) { 6660Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6670Sstevel@tonic-gate iter_destroy(iter); 6680Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * Ensure that the passed client id is no longer usable, wait for any 6750Sstevel@tonic-gate * outstanding invocations to complete, then destroy the client 6760Sstevel@tonic-gate * structure. 6770Sstevel@tonic-gate */ 6780Sstevel@tonic-gate static void 6790Sstevel@tonic-gate client_destroy(uint32_t id) 6800Sstevel@tonic-gate { 6810Sstevel@tonic-gate client_bucket_t *bp = CLIENT_HASH(id); 6820Sstevel@tonic-gate repcache_client_t *cp; 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate (void) pthread_mutex_lock(&bp->cb_lock); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate cp = uu_list_find(bp->cb_list, &id, NULL, NULL); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate if (cp == NULL) { 6890Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6900Sstevel@tonic-gate return; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate uu_list_remove(bp->cb_list, cp); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate (void) pthread_mutex_unlock(&bp->cb_lock); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate /* kick the waiters out */ 6980Sstevel@tonic-gate rc_notify_info_fini(&cp->rc_notify_info); 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 7010Sstevel@tonic-gate assert(!(cp->rc_flags & RC_CLIENT_DEAD)); 7020Sstevel@tonic-gate cp->rc_flags |= RC_CLIENT_DEAD; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if (cp->rc_doorfd != -1) { 7050Sstevel@tonic-gate if (door_revoke(cp->rc_doorfd) < 0) 7060Sstevel@tonic-gate perror("door_revoke"); 7070Sstevel@tonic-gate cp->rc_doorfd = -1; 7080Sstevel@tonic-gate cp->rc_doorid = INVALID_DOORID; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate while (cp->rc_refcnt > 0) 7120Sstevel@tonic-gate (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0); 7150Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* 7180Sstevel@tonic-gate * destroy outstanding objects 7190Sstevel@tonic-gate */ 7200Sstevel@tonic-gate entity_cleanup(cp); 7210Sstevel@tonic-gate iter_cleanup(cp); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate /* 7240Sstevel@tonic-gate * clean up notifications 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate rc_pg_notify_fini(&cp->rc_pg_notify); 7270Sstevel@tonic-gate 7285777Stw21770 /* 7295777Stw21770 * clean up annotations 7305777Stw21770 */ 7315777Stw21770 if (cp->rc_operation != NULL) 7325777Stw21770 free((void *)cp->rc_operation); 7335777Stw21770 if (cp->rc_file != NULL) 7345777Stw21770 free((void *)cp->rc_file); 7355777Stw21770 7365777Stw21770 /* 7375777Stw21770 * End audit session. 7385777Stw21770 */ 7395777Stw21770 (void) adt_end_session(cp->rc_adt_session); 7405777Stw21770 7410Sstevel@tonic-gate client_free(cp); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * Fails with 7460Sstevel@tonic-gate * _TYPE_MISMATCH - the entity is already set up with a different type 7470Sstevel@tonic-gate * _NO_RESOURCES - out of memory 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate static int 7500Sstevel@tonic-gate entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr) 7510Sstevel@tonic-gate { 7520Sstevel@tonic-gate repcache_entity_t *ep; 7530Sstevel@tonic-gate uint32_t type; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate client_start_insert(cp); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 7580Sstevel@tonic-gate type = ep->re_type; 7590Sstevel@tonic-gate entity_release(ep); 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate client_end_insert(cp); 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate if (type != rpr->rpr_entitytype) 7640Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_TYPE_MISMATCH); 7650Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate switch (type = rpr->rpr_entitytype) { 7690Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SCOPE: 7700Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SERVICE: 7710Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_INSTANCE: 7720Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPSHOT: 7730Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_SNAPLEVEL: 7740Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTYGRP: 7750Sstevel@tonic-gate case REP_PROTOCOL_ENTITY_PROPERTY: 7760Sstevel@tonic-gate break; 7770Sstevel@tonic-gate default: 7780Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate ep = entity_alloc(cp); 7820Sstevel@tonic-gate if (ep == NULL) { 7830Sstevel@tonic-gate client_end_insert(cp); 7840Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate ep->re_id = rpr->rpr_entityid; 7880Sstevel@tonic-gate ep->re_changeid = INVALID_CHANGEID; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate ep->re_type = type; 7910Sstevel@tonic-gate rc_node_ptr_init(&ep->re_node); 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate entity_add(cp, ep); 7940Sstevel@tonic-gate client_end_insert(cp); 7950Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /*ARGSUSED*/ 7990Sstevel@tonic-gate static void 8000Sstevel@tonic-gate entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg, 8010Sstevel@tonic-gate size_t *outsz, void *arg) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 8040Sstevel@tonic-gate struct rep_protocol_name_response *out = out_arg; 8050Sstevel@tonic-gate repcache_entity_t *ep; 8060Sstevel@tonic-gate size_t sz = sizeof (out->rpr_name); 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if (ep == NULL) { 8130Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 8140Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8150Sstevel@tonic-gate return; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name, 8180Sstevel@tonic-gate sz, rpr->rpr_answertype, &sz); 8190Sstevel@tonic-gate entity_release(ep); 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* 8220Sstevel@tonic-gate * If we fail, we only return the response code. 8230Sstevel@tonic-gate * If we succeed, we don't return anything after the '\0' in rpr_name. 8240Sstevel@tonic-gate */ 8250Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8260Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8270Sstevel@tonic-gate else 8280Sstevel@tonic-gate *outsz = offsetof(struct rep_protocol_name_response, 8290Sstevel@tonic-gate rpr_name[sz + 1]); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate /*ARGSUSED*/ 8330Sstevel@tonic-gate static void 8340Sstevel@tonic-gate entity_parent_type(repcache_client_t *cp, const void *in, size_t insz, 8350Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate const struct rep_protocol_entity_name *rpr = in; 8380Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 8390Sstevel@tonic-gate repcache_entity_t *ep; 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate if (ep == NULL) { 8460Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 8470Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8480Sstevel@tonic-gate return; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value); 8520Sstevel@tonic-gate entity_release(ep); 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 8550Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate /* 8590Sstevel@tonic-gate * Fails with 8600Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8610Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 8620Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 8630Sstevel@tonic-gate * _TYPE_MISMATCH - np doesn't carry children of type type 8640Sstevel@tonic-gate * _DELETED - np has been deleted 8650Sstevel@tonic-gate * _NOT_FOUND - no child with that name/type combo found 8660Sstevel@tonic-gate * _NO_RESOURCES 8670Sstevel@tonic-gate * _BACKEND_ACCESS 8680Sstevel@tonic-gate */ 8690Sstevel@tonic-gate static int 8700Sstevel@tonic-gate entity_get_child(repcache_client_t *cp, 8710Sstevel@tonic-gate struct rep_protocol_entity_get_child *rpr) 8720Sstevel@tonic-gate { 8730Sstevel@tonic-gate repcache_entity_t *parent, *child; 8740Sstevel@tonic-gate int result; 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 8770Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate result = entity_find2(cp, childid, &child, parentid, &parent); 8800Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 8810Sstevel@tonic-gate return (result); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate result = rc_node_get_child(&parent->re_node, rpr->rpr_name, 8860Sstevel@tonic-gate child->re_type, &child->re_node); 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate entity_release(child); 8890Sstevel@tonic-gate entity_release(parent); 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate return (result); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED, 8960Sstevel@tonic-gate * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS. 8970Sstevel@tonic-gate * Fails with 8980Sstevel@tonic-gate * _DUPLICATE_ID - the ids are equal 8990Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 9000Sstevel@tonic-gate * _NOT_SET - child is not set 9010Sstevel@tonic-gate * _DELETED - child has been deleted 9020Sstevel@tonic-gate * _TYPE_MISMATCH - child's parent does not match that of the parent register 9030Sstevel@tonic-gate * _NOT_FOUND - child has no parent (and is a scope) 9040Sstevel@tonic-gate */ 9050Sstevel@tonic-gate static int 9060Sstevel@tonic-gate entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr) 9070Sstevel@tonic-gate { 9080Sstevel@tonic-gate repcache_entity_t *child, *parent; 9090Sstevel@tonic-gate int result; 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate uint32_t childid = rpr->rpr_entityid; 9120Sstevel@tonic-gate uint32_t outid = rpr->rpr_outid; 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate result = entity_find2(cp, childid, &child, outid, &parent); 9150Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 9160Sstevel@tonic-gate return (result); 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate result = rc_node_get_parent(&child->re_node, parent->re_type, 9190Sstevel@tonic-gate &parent->re_node); 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate entity_release(child); 9220Sstevel@tonic-gate entity_release(parent); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate return (result); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate static int 9280Sstevel@tonic-gate entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr) 9290Sstevel@tonic-gate { 9300Sstevel@tonic-gate repcache_entity_t *ep; 9310Sstevel@tonic-gate int result; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate if (ep == NULL) 9360Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate switch (rpr->rpr_object) { 9390Sstevel@tonic-gate case RP_ENTITY_GET_INVALIDATE: 9400Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9410Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 9420Sstevel@tonic-gate break; 9430Sstevel@tonic-gate case RP_ENTITY_GET_MOST_LOCAL_SCOPE: 9440Sstevel@tonic-gate result = rc_local_scope(ep->re_type, &ep->re_node); 9450Sstevel@tonic-gate break; 9460Sstevel@tonic-gate default: 9470Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 9480Sstevel@tonic-gate break; 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate entity_release(ep); 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate return (result); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate static int 9570Sstevel@tonic-gate entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr) 9580Sstevel@tonic-gate { 9590Sstevel@tonic-gate repcache_entity_t *ep; 9600Sstevel@tonic-gate int result; 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 9630Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if (ep == NULL) 9680Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate if (ep->re_changeid == rpr->rpr_changeid) { 9710Sstevel@tonic-gate result = REP_PROTOCOL_DONE; 9720Sstevel@tonic-gate } else { 9730Sstevel@tonic-gate result = rc_node_update(&ep->re_node); 9740Sstevel@tonic-gate if (result == REP_PROTOCOL_DONE) 9750Sstevel@tonic-gate ep->re_changeid = rpr->rpr_changeid; 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate entity_release(ep); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate return (result); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate static int 9840Sstevel@tonic-gate entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr) 9850Sstevel@tonic-gate { 9860Sstevel@tonic-gate repcache_entity_t *ep; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 9890Sstevel@tonic-gate if (ep == NULL) 9900Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate rc_node_clear(&ep->re_node, 0); 9930Sstevel@tonic-gate ep->re_txstate = REPCACHE_TX_INIT; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate entity_release(ep); 9960Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate /* 10000Sstevel@tonic-gate * Fails with 10010Sstevel@tonic-gate * _BAD_REQUEST - request has invalid changeid 10020Sstevel@tonic-gate * rpr_name is invalid 10030Sstevel@tonic-gate * cannot create children for parent's type of node 10040Sstevel@tonic-gate * _DUPLICATE_ID - request has duplicate ids 10050Sstevel@tonic-gate * _UNKNOWN_ID - request has unknown id 10060Sstevel@tonic-gate * _DELETED - parent has been deleted 10070Sstevel@tonic-gate * _NOT_SET - parent is reset 10080Sstevel@tonic-gate * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP 10090Sstevel@tonic-gate * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid 10100Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype 10110Sstevel@tonic-gate * _NO_RESOURCES 10120Sstevel@tonic-gate * _PERMISSION_DENIED 10130Sstevel@tonic-gate * _BACKEND_ACCESS 10140Sstevel@tonic-gate * _BACKEND_READONLY 10150Sstevel@tonic-gate * _EXISTS - child already exists 10160Sstevel@tonic-gate */ 10170Sstevel@tonic-gate static int 10180Sstevel@tonic-gate entity_create_child(repcache_client_t *cp, 10190Sstevel@tonic-gate struct rep_protocol_entity_create_child *rpr) 10200Sstevel@tonic-gate { 10210Sstevel@tonic-gate repcache_entity_t *parent; 10220Sstevel@tonic-gate repcache_entity_t *child; 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10250Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate int result; 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10300Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10330Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10340Sstevel@tonic-gate return (result); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10390Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10400Sstevel@tonic-gate } else { 10410Sstevel@tonic-gate result = rc_node_create_child(&parent->re_node, 10420Sstevel@tonic-gate rpr->rpr_childtype, rpr->rpr_name, &child->re_node); 10430Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10440Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate entity_release(parent); 10480Sstevel@tonic-gate entity_release(child); 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate return (result); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate static int 10540Sstevel@tonic-gate entity_create_pg(repcache_client_t *cp, 10550Sstevel@tonic-gate struct rep_protocol_entity_create_pg *rpr) 10560Sstevel@tonic-gate { 10570Sstevel@tonic-gate repcache_entity_t *parent; 10580Sstevel@tonic-gate repcache_entity_t *child; 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate uint32_t parentid = rpr->rpr_entityid; 10610Sstevel@tonic-gate uint32_t childid = rpr->rpr_childid; 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate int result; 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 10660Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate result = entity_find2(cp, parentid, &parent, childid, &child); 10690Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 10700Sstevel@tonic-gate return (result); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 10730Sstevel@tonic-gate rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0; 10740Sstevel@tonic-gate 10750Sstevel@tonic-gate if (child->re_changeid == rpr->rpr_changeid) { 10760Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 10770Sstevel@tonic-gate } else { 10780Sstevel@tonic-gate result = rc_node_create_child_pg(&parent->re_node, 10790Sstevel@tonic-gate child->re_type, rpr->rpr_name, rpr->rpr_type, 10800Sstevel@tonic-gate rpr->rpr_flags, &child->re_node); 10810Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 10820Sstevel@tonic-gate child->re_changeid = rpr->rpr_changeid; 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate entity_release(parent); 10860Sstevel@tonic-gate entity_release(child); 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate return (result); 10890Sstevel@tonic-gate } 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate static int 10920Sstevel@tonic-gate entity_delete(repcache_client_t *cp, 10930Sstevel@tonic-gate struct rep_protocol_entity_delete *rpr) 10940Sstevel@tonic-gate { 10950Sstevel@tonic-gate repcache_entity_t *entity; 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate uint32_t entityid = rpr->rpr_entityid; 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate int result; 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate if (rpr->rpr_changeid == INVALID_CHANGEID) 11020Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate entity = entity_find(cp, entityid); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate if (entity == NULL) 11070Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (entity->re_changeid == rpr->rpr_changeid) { 11100Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 11110Sstevel@tonic-gate } else { 11120Sstevel@tonic-gate result = rc_node_delete(&entity->re_node); 11130Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 11140Sstevel@tonic-gate entity->re_changeid = rpr->rpr_changeid; 11150Sstevel@tonic-gate } 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate entity_release(entity); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate return (result); 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate static rep_protocol_responseid_t 11230Sstevel@tonic-gate entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr) 11240Sstevel@tonic-gate { 11250Sstevel@tonic-gate entity_remove(cp, rpr->rpr_entityid); 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate /* 11310Sstevel@tonic-gate * Fails with 11320Sstevel@tonic-gate * _MISORDERED - the iterator exists and is not reset 11330Sstevel@tonic-gate * _NO_RESOURCES - out of memory 11340Sstevel@tonic-gate */ 11350Sstevel@tonic-gate static int 11360Sstevel@tonic-gate iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 11370Sstevel@tonic-gate { 11380Sstevel@tonic-gate repcache_iter_t *iter; 11390Sstevel@tonic-gate uint32_t sequence; 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate client_start_insert(cp); 11420Sstevel@tonic-gate /* 11430Sstevel@tonic-gate * If the iter already exists, and hasn't been read from, 11440Sstevel@tonic-gate * we assume the previous call succeeded. 11450Sstevel@tonic-gate */ 11460Sstevel@tonic-gate if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) { 11470Sstevel@tonic-gate sequence = iter->ri_sequence; 11480Sstevel@tonic-gate iter_release(iter); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate client_end_insert(cp); 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate if (sequence != 0) 11530Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 11540Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate iter = iter_alloc(cp); 11580Sstevel@tonic-gate if (iter == NULL) { 11590Sstevel@tonic-gate client_end_insert(cp); 11600Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate iter->ri_id = rpr->rpr_iterid; 11640Sstevel@tonic-gate iter->ri_type = REP_PROTOCOL_TYPE_INVALID; 11650Sstevel@tonic-gate iter->ri_sequence = 0; 11660Sstevel@tonic-gate iter_add(cp, iter); 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate client_end_insert(cp); 11690Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate /* 11730Sstevel@tonic-gate * Fails with 11740Sstevel@tonic-gate * _UNKNOWN_ID 11750Sstevel@tonic-gate * _MISORDERED - iterator has already been started 11760Sstevel@tonic-gate * _NOT_SET 11770Sstevel@tonic-gate * _DELETED 11780Sstevel@tonic-gate * _TYPE_MISMATCH - entity cannot have type children 11790Sstevel@tonic-gate * _BAD_REQUEST - rpr_flags is invalid 11800Sstevel@tonic-gate * rpr_pattern is invalid 11810Sstevel@tonic-gate * _NO_RESOURCES 11820Sstevel@tonic-gate * _INVALID_TYPE 11830Sstevel@tonic-gate * _BACKEND_ACCESS 11840Sstevel@tonic-gate */ 11850Sstevel@tonic-gate static int 11860Sstevel@tonic-gate iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr) 11870Sstevel@tonic-gate { 11880Sstevel@tonic-gate int result; 11890Sstevel@tonic-gate repcache_iter_t *iter; 11900Sstevel@tonic-gate repcache_entity_t *ep; 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 11930Sstevel@tonic-gate rpr->rpr_entity, &ep); 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 11960Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate if (iter->ri_sequence > 1) { 11990Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 12000Sstevel@tonic-gate goto end; 12010Sstevel@tonic-gate } 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate if (iter->ri_sequence == 1) { 12040Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 12050Sstevel@tonic-gate goto end; 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter, 12110Sstevel@tonic-gate rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern); 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 12140Sstevel@tonic-gate iter->ri_sequence++; 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate end: 12170Sstevel@tonic-gate iter_release(iter); 12180Sstevel@tonic-gate entity_release(ep); 12190Sstevel@tonic-gate return (result); 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate /* 12230Sstevel@tonic-gate * Returns 12240Sstevel@tonic-gate * _UNKNOWN_ID 12250Sstevel@tonic-gate * _NOT_SET - iter has not been started 12260Sstevel@tonic-gate * _MISORDERED 12270Sstevel@tonic-gate * _BAD_REQUEST - iter walks values 12280Sstevel@tonic-gate * _TYPE_MISMATCH - iter does not walk type entities 12290Sstevel@tonic-gate * _DELETED - parent was deleted 12300Sstevel@tonic-gate * _NO_RESOURCES 12310Sstevel@tonic-gate * _INVALID_TYPE - type is invalid 12320Sstevel@tonic-gate * _DONE 12330Sstevel@tonic-gate * _SUCCESS 12340Sstevel@tonic-gate * 12350Sstevel@tonic-gate * For composed property group iterators, can also return 12360Sstevel@tonic-gate * _TYPE_MISMATCH - parent cannot have type children 12370Sstevel@tonic-gate * _BACKEND_ACCESS 12380Sstevel@tonic-gate */ 12390Sstevel@tonic-gate static rep_protocol_responseid_t 12400Sstevel@tonic-gate iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr) 12410Sstevel@tonic-gate { 12420Sstevel@tonic-gate rep_protocol_responseid_t result; 12430Sstevel@tonic-gate repcache_iter_t *iter; 12440Sstevel@tonic-gate repcache_entity_t *ep; 12450Sstevel@tonic-gate uint32_t sequence; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter, 12480Sstevel@tonic-gate rpr->rpr_entityid, &ep); 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 12510Sstevel@tonic-gate return (result); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate sequence = rpr->rpr_sequence; 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate if (iter->ri_sequence == 0) { 12560Sstevel@tonic-gate iter_release(iter); 12570Sstevel@tonic-gate entity_release(ep); 12580Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NOT_SET); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate if (sequence == 1) { 12620Sstevel@tonic-gate iter_release(iter); 12630Sstevel@tonic-gate entity_release(ep); 12640Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate if (sequence == iter->ri_sequence) { 12680Sstevel@tonic-gate iter_release(iter); 12690Sstevel@tonic-gate entity_release(ep); 12700Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate if (sequence == iter->ri_sequence + 1) { 12740Sstevel@tonic-gate result = rc_iter_next(iter->ri_iter, &ep->re_node, 12750Sstevel@tonic-gate ep->re_type); 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 12780Sstevel@tonic-gate iter->ri_sequence++; 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate iter_release(iter); 12810Sstevel@tonic-gate entity_release(ep); 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate return (result); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate iter_release(iter); 12870Sstevel@tonic-gate entity_release(ep); 12880Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_MISORDERED); 12890Sstevel@tonic-gate } 12900Sstevel@tonic-gate 12910Sstevel@tonic-gate /*ARGSUSED*/ 12920Sstevel@tonic-gate static void 12930Sstevel@tonic-gate iter_read_value(repcache_client_t *cp, const void *in, size_t insz, 12940Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 12950Sstevel@tonic-gate { 12960Sstevel@tonic-gate const struct rep_protocol_iter_read_value *rpr = in; 12970Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 12980Sstevel@tonic-gate rep_protocol_responseid_t result; 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate repcache_iter_t *iter; 13010Sstevel@tonic-gate uint32_t sequence; 13020Sstevel@tonic-gate int repeat; 13030Sstevel@tonic-gate 13040Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate iter = iter_find(cp, rpr->rpr_iterid); 13070Sstevel@tonic-gate 13080Sstevel@tonic-gate if (iter == NULL) { 13090Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 13100Sstevel@tonic-gate goto out; 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate sequence = rpr->rpr_sequence; 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate if (iter->ri_sequence == 0) { 13160Sstevel@tonic-gate iter_release(iter); 13170Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_NOT_SET; 13180Sstevel@tonic-gate goto out; 13190Sstevel@tonic-gate } 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate repeat = (sequence == iter->ri_sequence); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) { 13240Sstevel@tonic-gate iter_release(iter); 13250Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13260Sstevel@tonic-gate goto out; 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat); 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate if (!repeat && result == REP_PROTOCOL_SUCCESS) 13320Sstevel@tonic-gate iter->ri_sequence++; 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate iter_release(iter); 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate out: 13370Sstevel@tonic-gate /* 13380Sstevel@tonic-gate * If we fail, we only return the response code. 13390Sstevel@tonic-gate * If we succeed, rc_iter_next_value has shortened *outsz 13400Sstevel@tonic-gate * to only include the value bytes needed. 13410Sstevel@tonic-gate */ 13420Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE) 13430Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate out->rpr_response = result; 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13480Sstevel@tonic-gate static int 13490Sstevel@tonic-gate iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13500Sstevel@tonic-gate { 13510Sstevel@tonic-gate repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid); 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate if (iter == NULL) 13540Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN_ID); 13550Sstevel@tonic-gate 13560Sstevel@tonic-gate if (iter->ri_sequence != 0) { 13570Sstevel@tonic-gate iter->ri_sequence = 0; 13580Sstevel@tonic-gate rc_iter_destroy(&iter->ri_iter); 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate iter_release(iter); 13610Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13620Sstevel@tonic-gate } 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate static rep_protocol_responseid_t 13650Sstevel@tonic-gate iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr) 13660Sstevel@tonic-gate { 13670Sstevel@tonic-gate iter_remove(cp, rpr->rpr_iterid); 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate 13720Sstevel@tonic-gate static rep_protocol_responseid_t 13730Sstevel@tonic-gate tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr) 13740Sstevel@tonic-gate { 13750Sstevel@tonic-gate repcache_entity_t *tx; 13760Sstevel@tonic-gate repcache_entity_t *ep; 13770Sstevel@tonic-gate rep_protocol_responseid_t result; 13780Sstevel@tonic-gate 13790Sstevel@tonic-gate uint32_t txid = rpr->rpr_entityid_tx; 13800Sstevel@tonic-gate uint32_t epid = rpr->rpr_entityid; 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate result = entity_find2(cp, txid, &tx, epid, &ep); 13830Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 13840Sstevel@tonic-gate return (result); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate if (tx->re_txstate == REPCACHE_TX_SETUP) { 13870Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 13880Sstevel@tonic-gate goto end; 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate if (tx->re_txstate != REPCACHE_TX_INIT) { 13910Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_MISORDERED; 13920Sstevel@tonic-gate goto end; 13930Sstevel@tonic-gate } 13940Sstevel@tonic-gate 13950Sstevel@tonic-gate result = rc_node_setup_tx(&ep->re_node, &tx->re_node); 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate end: 13980Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 13990Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_SETUP; 14000Sstevel@tonic-gate else 14010Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 14020Sstevel@tonic-gate 14030Sstevel@tonic-gate entity_release(ep); 14040Sstevel@tonic-gate entity_release(tx); 14050Sstevel@tonic-gate return (result); 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate /*ARGSUSED*/ 14090Sstevel@tonic-gate static void 14100Sstevel@tonic-gate tx_commit(repcache_client_t *cp, const void *in, size_t insz, 14110Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 14120Sstevel@tonic-gate { 14130Sstevel@tonic-gate struct rep_protocol_response *out = out_arg; 14140Sstevel@tonic-gate const struct rep_protocol_transaction_commit *rpr = in; 14150Sstevel@tonic-gate repcache_entity_t *tx; 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 14180Sstevel@tonic-gate assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate if (rpr->rpr_size != insz) { 14210Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST; 14220Sstevel@tonic-gate return; 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate 14250Sstevel@tonic-gate tx = entity_find(cp, rpr->rpr_entityid); 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate if (tx == NULL) { 14280Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 14290Sstevel@tonic-gate return; 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate switch (tx->re_txstate) { 14330Sstevel@tonic-gate case REPCACHE_TX_INIT: 14340Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED; 14350Sstevel@tonic-gate break; 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate case REPCACHE_TX_SETUP: 14380Sstevel@tonic-gate out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd, 14390Sstevel@tonic-gate insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE); 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate if (out->rpr_response == REP_PROTOCOL_SUCCESS) { 14420Sstevel@tonic-gate tx->re_txstate = REPCACHE_TX_COMMITTED; 14430Sstevel@tonic-gate rc_node_clear(&tx->re_node, 0); 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate break; 14470Sstevel@tonic-gate case REPCACHE_TX_COMMITTED: 14480Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_SUCCESS; 14490Sstevel@tonic-gate break; 14500Sstevel@tonic-gate default: 14510Sstevel@tonic-gate assert(0); /* CAN'T HAPPEN */ 14520Sstevel@tonic-gate break; 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate entity_release(tx); 14560Sstevel@tonic-gate } 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate static rep_protocol_responseid_t 14590Sstevel@tonic-gate next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr) 14600Sstevel@tonic-gate { 14610Sstevel@tonic-gate repcache_entity_t *src; 14620Sstevel@tonic-gate repcache_entity_t *dest; 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entity_src; 14650Sstevel@tonic-gate uint32_t destid = rpr->rpr_entity_dst; 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate int result; 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 14700Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 14710Sstevel@tonic-gate return (result); 14720Sstevel@tonic-gate 14730Sstevel@tonic-gate result = rc_node_next_snaplevel(&src->re_node, &dest->re_node); 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate entity_release(src); 14760Sstevel@tonic-gate entity_release(dest); 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate return (result); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate static rep_protocol_responseid_t 14820Sstevel@tonic-gate snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr) 14830Sstevel@tonic-gate { 14840Sstevel@tonic-gate repcache_entity_t *src; 14850Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 14860Sstevel@tonic-gate repcache_entity_t *dest; 14870Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate int result; 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 14920Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 14930Sstevel@tonic-gate return (result); 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 14960Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 14970Sstevel@tonic-gate } else { 14980Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate if (rpr->rpr_flags == REP_SNAPSHOT_NEW) 15010Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, NULL, 15020Sstevel@tonic-gate NULL, rpr->rpr_name, &dest->re_node); 15030Sstevel@tonic-gate else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH && 15040Sstevel@tonic-gate rpr->rpr_name[0] == 0) 15050Sstevel@tonic-gate result = rc_snapshot_take_attach(&src->re_node, 15060Sstevel@tonic-gate &dest->re_node); 15070Sstevel@tonic-gate else 15080Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 15090Sstevel@tonic-gate } 15100Sstevel@tonic-gate entity_release(src); 15110Sstevel@tonic-gate entity_release(dest); 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate return (result); 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate 15160Sstevel@tonic-gate static rep_protocol_responseid_t 15170Sstevel@tonic-gate snapshot_take_named(repcache_client_t *cp, 15180Sstevel@tonic-gate struct rep_protocol_snapshot_take_named *rpr) 15190Sstevel@tonic-gate { 15200Sstevel@tonic-gate repcache_entity_t *src; 15210Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 15220Sstevel@tonic-gate repcache_entity_t *dest; 15230Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15240Sstevel@tonic-gate 15250Sstevel@tonic-gate int result; 15260Sstevel@tonic-gate 15270Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15280Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15290Sstevel@tonic-gate return (result); 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) { 15320Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 15330Sstevel@tonic-gate } else { 15340Sstevel@tonic-gate rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0; 15350Sstevel@tonic-gate rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0; 15360Sstevel@tonic-gate rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0; 15370Sstevel@tonic-gate 15380Sstevel@tonic-gate result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname, 15390Sstevel@tonic-gate rpr->rpr_instname, rpr->rpr_name, &dest->re_node); 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate entity_release(src); 15420Sstevel@tonic-gate entity_release(dest); 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate return (result); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate static rep_protocol_responseid_t 15480Sstevel@tonic-gate snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr) 15490Sstevel@tonic-gate { 15500Sstevel@tonic-gate repcache_entity_t *src; 15510Sstevel@tonic-gate uint32_t srcid = rpr->rpr_entityid_src; 15520Sstevel@tonic-gate repcache_entity_t *dest; 15530Sstevel@tonic-gate uint32_t destid = rpr->rpr_entityid_dest; 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate int result; 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate result = entity_find2(cp, srcid, &src, destid, &dest); 15580Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 15590Sstevel@tonic-gate return (result); 15600Sstevel@tonic-gate 15610Sstevel@tonic-gate result = rc_snapshot_attach(&src->re_node, &dest->re_node); 15620Sstevel@tonic-gate 15630Sstevel@tonic-gate entity_release(src); 15640Sstevel@tonic-gate entity_release(dest); 15650Sstevel@tonic-gate 15660Sstevel@tonic-gate return (result); 15670Sstevel@tonic-gate } 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate /*ARGSUSED*/ 15700Sstevel@tonic-gate static void 15710Sstevel@tonic-gate property_get_type(repcache_client_t *cp, const void *in, size_t insz, 15720Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 15730Sstevel@tonic-gate { 15740Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 15750Sstevel@tonic-gate struct rep_protocol_integer_response *out = out_arg; 15760Sstevel@tonic-gate repcache_entity_t *ep; 15770Sstevel@tonic-gate rep_protocol_value_type_t t = 0; 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate if (ep == NULL) { 15840Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 15850Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15860Sstevel@tonic-gate return; 15870Sstevel@tonic-gate } 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate out->rpr_response = rc_node_get_property_type(&ep->re_node, &t); 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate entity_release(ep); 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS) 15940Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 15950Sstevel@tonic-gate else 15960Sstevel@tonic-gate out->rpr_value = t; 15970Sstevel@tonic-gate } 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate /* 16000Sstevel@tonic-gate * Fails with: 16010Sstevel@tonic-gate * _UNKNOWN_ID - an id does not designate an active register 16020Sstevel@tonic-gate * _NOT_SET - The property is not set 16030Sstevel@tonic-gate * _DELETED - The property has been deleted 16040Sstevel@tonic-gate * _TYPE_MISMATCH - The object is not a property 16050Sstevel@tonic-gate * _NOT_FOUND - The property has no values. 16060Sstevel@tonic-gate * 16070Sstevel@tonic-gate * Succeeds with: 16080Sstevel@tonic-gate * _SUCCESS - The property has 1 value. 16090Sstevel@tonic-gate * _TRUNCATED - The property has >1 value. 16100Sstevel@tonic-gate */ 16110Sstevel@tonic-gate /*ARGSUSED*/ 16120Sstevel@tonic-gate static void 16130Sstevel@tonic-gate property_get_value(repcache_client_t *cp, const void *in, size_t insz, 16140Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 16150Sstevel@tonic-gate { 16160Sstevel@tonic-gate const struct rep_protocol_property_request *rpr = in; 16170Sstevel@tonic-gate struct rep_protocol_value_response *out = out_arg; 16180Sstevel@tonic-gate repcache_entity_t *ep; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate ep = entity_find(cp, rpr->rpr_entityid); 16230Sstevel@tonic-gate if (ep == NULL) { 16240Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16250Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16260Sstevel@tonic-gate return; 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate out->rpr_response = rc_node_get_property_value(&ep->re_node, out, 16300Sstevel@tonic-gate outsz); 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate entity_release(ep); 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate /* 16350Sstevel@tonic-gate * If we fail, we only return the response code. 16360Sstevel@tonic-gate * If we succeed, rc_node_get_property_value has shortened *outsz 16370Sstevel@tonic-gate * to only include the value bytes needed. 16380Sstevel@tonic-gate */ 16390Sstevel@tonic-gate if (out->rpr_response != REP_PROTOCOL_SUCCESS && 16400Sstevel@tonic-gate out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) 16410Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 16420Sstevel@tonic-gate } 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate static rep_protocol_responseid_t 16450Sstevel@tonic-gate propertygrp_notify(repcache_client_t *cp, 16460Sstevel@tonic-gate struct rep_protocol_propertygrp_request *rpr, int *out_fd) 16470Sstevel@tonic-gate { 16480Sstevel@tonic-gate int fds[2]; 16490Sstevel@tonic-gate int ours, theirs; 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate rep_protocol_responseid_t result; 16520Sstevel@tonic-gate repcache_entity_t *ep; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate if (pipe(fds) < 0) 16550Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate ours = fds[0]; 16580Sstevel@tonic-gate theirs = fds[1]; 16590Sstevel@tonic-gate 16600Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) { 16610Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 16620Sstevel@tonic-gate goto fail; 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate /* 16660Sstevel@tonic-gate * While the following can race with other threads setting up a 16670Sstevel@tonic-gate * notification, the worst that can happen is that our fd has 16680Sstevel@tonic-gate * already been closed before we return. 16690Sstevel@tonic-gate */ 16700Sstevel@tonic-gate result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node, 16710Sstevel@tonic-gate ours); 16720Sstevel@tonic-gate 16730Sstevel@tonic-gate entity_release(ep); 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 16760Sstevel@tonic-gate goto fail; 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate *out_fd = theirs; 16790Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 16800Sstevel@tonic-gate 16810Sstevel@tonic-gate fail: 16820Sstevel@tonic-gate (void) close(ours); 16830Sstevel@tonic-gate (void) close(theirs); 16840Sstevel@tonic-gate 16850Sstevel@tonic-gate return (result); 16860Sstevel@tonic-gate } 16870Sstevel@tonic-gate 16880Sstevel@tonic-gate static rep_protocol_responseid_t 16890Sstevel@tonic-gate client_add_notify(repcache_client_t *cp, 16900Sstevel@tonic-gate struct rep_protocol_notify_request *rpr) 16910Sstevel@tonic-gate { 16920Sstevel@tonic-gate rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0; 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate switch (rpr->rpr_type) { 16950Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGNAME: 16960Sstevel@tonic-gate return (rc_notify_info_add_name(&cp->rc_notify_info, 16970Sstevel@tonic-gate rpr->rpr_pattern)); 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate case REP_PROTOCOL_NOTIFY_PGTYPE: 17000Sstevel@tonic-gate return (rc_notify_info_add_type(&cp->rc_notify_info, 17010Sstevel@tonic-gate rpr->rpr_pattern)); 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate default: 17040Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate } 17070Sstevel@tonic-gate 17080Sstevel@tonic-gate /*ARGSUSED*/ 17090Sstevel@tonic-gate static void 17100Sstevel@tonic-gate client_wait(repcache_client_t *cp, const void *in, size_t insz, 17110Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 17120Sstevel@tonic-gate { 17130Sstevel@tonic-gate int result; 17140Sstevel@tonic-gate repcache_entity_t *ep; 17150Sstevel@tonic-gate const struct rep_protocol_wait_request *rpr = in; 17160Sstevel@tonic-gate struct rep_protocol_fmri_response *out = out_arg; 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17210Sstevel@tonic-gate if (cp->rc_notify_thr != 0) { 17220Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17230Sstevel@tonic-gate out->rpr_response = REP_PROTOCOL_FAIL_EXISTS; 17240Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17250Sstevel@tonic-gate return; 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate cp->rc_notify_thr = pthread_self(); 17280Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr, 17310Sstevel@tonic-gate out->rpr_fmri, sizeof (out->rpr_fmri)); 17320Sstevel@tonic-gate 17330Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) { 17340Sstevel@tonic-gate if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) { 17350Sstevel@tonic-gate if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) { 17360Sstevel@tonic-gate rc_node_ptr_assign(&ep->re_node, 17370Sstevel@tonic-gate &cp->rc_notify_ptr); 17380Sstevel@tonic-gate } else { 17390Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_TYPE_MISMATCH; 17400Sstevel@tonic-gate } 17410Sstevel@tonic-gate entity_release(ep); 17420Sstevel@tonic-gate } else { 17430Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_UNKNOWN_ID; 17440Sstevel@tonic-gate } 17450Sstevel@tonic-gate rc_node_clear(&cp->rc_notify_ptr, 0); 17460Sstevel@tonic-gate } 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17490Sstevel@tonic-gate assert(cp->rc_notify_thr == pthread_self()); 17500Sstevel@tonic-gate cp->rc_notify_thr = 0; 17510Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate out->rpr_response = result; 17540Sstevel@tonic-gate if (result != REP_PROTOCOL_SUCCESS) 17550Sstevel@tonic-gate *outsz = sizeof (out->rpr_response); 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate /* 17590Sstevel@tonic-gate * Can return: 17600Sstevel@tonic-gate * _PERMISSION_DENIED not enough privileges to do request. 17610Sstevel@tonic-gate * _BAD_REQUEST name is not valid or reserved 17620Sstevel@tonic-gate * _TRUNCATED name is too long for current repository path 17630Sstevel@tonic-gate * _UNKNOWN failed for unknown reason (details written to 17640Sstevel@tonic-gate * console) 17650Sstevel@tonic-gate * _BACKEND_READONLY backend is not writable 17666035Sstevep * _NO_RESOURCES out of memory 17670Sstevel@tonic-gate * _SUCCESS Backup completed successfully. 17680Sstevel@tonic-gate */ 17690Sstevel@tonic-gate static rep_protocol_responseid_t 17700Sstevel@tonic-gate backup_repository(repcache_client_t *cp, 17710Sstevel@tonic-gate struct rep_protocol_backup_request *rpr) 17720Sstevel@tonic-gate { 17730Sstevel@tonic-gate rep_protocol_responseid_t result; 17740Sstevel@tonic-gate ucred_t *uc = get_ucred(); 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0)) 17770Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 17780Sstevel@tonic-gate 17790Sstevel@tonic-gate rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0; 17800Sstevel@tonic-gate if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0) 17810Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate (void) pthread_mutex_lock(&cp->rc_lock); 17840Sstevel@tonic-gate if (rpr->rpr_changeid != cp->rc_changeid) { 17850Sstevel@tonic-gate result = backend_create_backup(rpr->rpr_name); 17860Sstevel@tonic-gate if (result == REP_PROTOCOL_SUCCESS) 17870Sstevel@tonic-gate cp->rc_changeid = rpr->rpr_changeid; 17880Sstevel@tonic-gate } else { 17890Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 17900Sstevel@tonic-gate } 17910Sstevel@tonic-gate (void) pthread_mutex_unlock(&cp->rc_lock); 17920Sstevel@tonic-gate 17930Sstevel@tonic-gate return (result); 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate 17965777Stw21770 /* 17975777Stw21770 * This function captures the information that will be used for an 17985777Stw21770 * annotation audit event. Specifically, it captures the operation to be 17995777Stw21770 * performed and the name of the file that is being used. These values are 18005777Stw21770 * copied from the rep_protocol_annotation request at rpr to the client 18015777Stw21770 * structure. If both these values are null, the client is turning 18025777Stw21770 * annotation off. 18035777Stw21770 * 18045777Stw21770 * Fails with 18055777Stw21770 * _NO_RESOURCES - unable to allocate memory 18065777Stw21770 */ 18075777Stw21770 static rep_protocol_responseid_t 18085777Stw21770 set_annotation(repcache_client_t *cp, struct rep_protocol_annotation *rpr) 18095777Stw21770 { 18105777Stw21770 au_id_t audit_uid; 18115777Stw21770 const char *file = NULL; 18125777Stw21770 const char *old_ptrs[2]; 18135777Stw21770 const char *operation = NULL; 18145777Stw21770 rep_protocol_responseid_t rc = REP_PROTOCOL_FAIL_NO_RESOURCES; 18155777Stw21770 au_asid_t sessionid; 18165777Stw21770 18175777Stw21770 (void) memset((void *)old_ptrs, 0, sizeof (old_ptrs)); 18185777Stw21770 18195777Stw21770 /* Copy rpr_operation and rpr_file if they are not empty strings. */ 18205777Stw21770 if (rpr->rpr_operation[0] != 0) { 18215777Stw21770 /* 18225777Stw21770 * Make sure that client did not send us an unterminated buffer. 18235777Stw21770 */ 18245777Stw21770 rpr->rpr_operation[sizeof (rpr->rpr_operation) - 1] = 0; 18255777Stw21770 if ((operation = strdup(rpr->rpr_operation)) == NULL) 18265777Stw21770 goto out; 18275777Stw21770 } 18285777Stw21770 if (rpr->rpr_file[0] != 0) { 18295777Stw21770 /* 18305777Stw21770 * Make sure that client did not send us an unterminated buffer. 18315777Stw21770 */ 18325777Stw21770 rpr->rpr_file[sizeof (rpr->rpr_file) - 1] = 0; 18335777Stw21770 if ((file = strdup(rpr->rpr_file)) == NULL) 18345777Stw21770 goto out; 18355777Stw21770 } 18365777Stw21770 18375777Stw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 18385777Stw21770 /* Save addresses of memory to free when not locked */ 18395777Stw21770 old_ptrs[0] = cp->rc_operation; 18405777Stw21770 old_ptrs[1] = cp->rc_file; 18415777Stw21770 18425777Stw21770 /* Save pointers to annotation strings. */ 18435777Stw21770 cp->rc_operation = operation; 18445777Stw21770 cp->rc_file = file; 18455777Stw21770 18465777Stw21770 /* 18475777Stw21770 * Set annotation flag. Annotations should be turned on if either 18485777Stw21770 * operation or file are not NULL. 18495777Stw21770 */ 18505777Stw21770 cp->rc_annotate = (operation != NULL) || (file != NULL); 18515777Stw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 18525777Stw21770 18535777Stw21770 /* 18545777Stw21770 * operation and file pointers are saved in cp, so don't free them 18555777Stw21770 * during cleanup. 18565777Stw21770 */ 18575777Stw21770 operation = NULL; 18585777Stw21770 file = NULL; 18595777Stw21770 rc = REP_PROTOCOL_SUCCESS; 18605777Stw21770 18615777Stw21770 /* 18625777Stw21770 * Native builds are done to create svc.configd-native. This 18635777Stw21770 * program runs only on the Open Solaris build machines to create 18645777Stw21770 * the seed repository. Until the SMF auditing code is distributed 18655777Stw21770 * to the Open Solaris build machines, adt_get_unique_id() in the 18665777Stw21770 * following code is not a global function in libbsm. Hence the 18675777Stw21770 * following conditional compilation. 18685777Stw21770 */ 18695777Stw21770 #ifndef NATIVE_BUILD 18705777Stw21770 /* 18715777Stw21770 * Set the appropriate audit session id. 18725777Stw21770 */ 18735777Stw21770 if (cp->rc_annotate) { 18745777Stw21770 /* 18755777Stw21770 * We're starting a group of annotated audit events, so 18765777Stw21770 * create and set an audit session ID for this annotation. 18775777Stw21770 */ 18785777Stw21770 adt_get_auid(cp->rc_adt_session, &audit_uid); 18795777Stw21770 sessionid = adt_get_unique_id(audit_uid); 18805777Stw21770 } else { 18815777Stw21770 /* 18825777Stw21770 * Annotation is done so restore our client audit session 18835777Stw21770 * id. 18845777Stw21770 */ 18855777Stw21770 sessionid = cp->rc_adt_sessionid; 18865777Stw21770 } 18875777Stw21770 adt_set_asid(cp->rc_adt_session, sessionid); 18885777Stw21770 #endif /* NATIVE_BUILD */ 18895777Stw21770 18905777Stw21770 out: 18915777Stw21770 if (operation != NULL) 18925777Stw21770 free((void *)operation); 18935777Stw21770 if (file != NULL) 18945777Stw21770 free((void *)file); 18955777Stw21770 free((void *)old_ptrs[0]); 18965777Stw21770 free((void *)old_ptrs[1]); 18975777Stw21770 return (rc); 18985777Stw21770 } 18995777Stw21770 19005777Stw21770 /* 19015777Stw21770 * Determine if an annotation event needs to be generated. If it does 19025777Stw21770 * provide the operation and file name that should be used in the event. 19035777Stw21770 * 19045777Stw21770 * Can return: 19055777Stw21770 * 0 No annotation event needed or buffers are not large 19065777Stw21770 * enough. Either way an event should not be 19075777Stw21770 * generated. 19085777Stw21770 * 1 Generate annotation event. 19095777Stw21770 */ 19105777Stw21770 int 19115777Stw21770 client_annotation_needed(char *operation, size_t oper_sz, 19125777Stw21770 char *file, size_t file_sz) 19135777Stw21770 { 19145777Stw21770 thread_info_t *ti = thread_self(); 19155777Stw21770 repcache_client_t *cp = ti->ti_active_client; 19165777Stw21770 int rc = 0; 19175777Stw21770 19185777Stw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 19195777Stw21770 if (cp->rc_annotate) { 19205777Stw21770 rc = 1; 19215777Stw21770 if (cp->rc_operation == NULL) { 19225777Stw21770 if (oper_sz > 0) 19235777Stw21770 operation[0] = 0; 19245777Stw21770 } else { 19255777Stw21770 if (strlcpy(operation, cp->rc_operation, oper_sz) >= 19265777Stw21770 oper_sz) { 19275777Stw21770 /* Buffer overflow, so do not generate event */ 19285777Stw21770 rc = 0; 19295777Stw21770 } 19305777Stw21770 } 19315777Stw21770 if (cp->rc_file == NULL) { 19325777Stw21770 if (file_sz > 0) 19335777Stw21770 file[0] = 0; 19345777Stw21770 } else if (rc == 1) { 19355777Stw21770 if (strlcpy(file, cp->rc_file, file_sz) >= file_sz) { 19365777Stw21770 /* Buffer overflow, so do not generate event */ 19375777Stw21770 rc = 0; 19385777Stw21770 } 19395777Stw21770 } 19405777Stw21770 } 19415777Stw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 19425777Stw21770 return (rc); 19435777Stw21770 } 19445777Stw21770 19455777Stw21770 void 19465777Stw21770 client_annotation_finished() 19475777Stw21770 { 19485777Stw21770 thread_info_t *ti = thread_self(); 19495777Stw21770 repcache_client_t *cp = ti->ti_active_client; 19505777Stw21770 19515777Stw21770 (void) pthread_mutex_lock(&cp->rc_annotate_lock); 19525777Stw21770 cp->rc_annotate = 0; 19535777Stw21770 (void) pthread_mutex_unlock(&cp->rc_annotate_lock); 19545777Stw21770 } 19555777Stw21770 19565777Stw21770 static void 19575777Stw21770 start_audit_session(repcache_client_t *cp) 19585777Stw21770 { 19595777Stw21770 ucred_t *cred = NULL; 19605777Stw21770 adt_session_data_t *session; 19615777Stw21770 1962*8497SThomas.Whitten@Sun.COM /* 1963*8497SThomas.Whitten@Sun.COM * A NULL session pointer value can legally be used in all 1964*8497SThomas.Whitten@Sun.COM * subsequent calls to adt_* functions. 1965*8497SThomas.Whitten@Sun.COM */ 1966*8497SThomas.Whitten@Sun.COM cp->rc_adt_session = NULL; 1967*8497SThomas.Whitten@Sun.COM 1968*8497SThomas.Whitten@Sun.COM if (door_ucred(&cred) != 0) { 1969*8497SThomas.Whitten@Sun.COM switch (errno) { 1970*8497SThomas.Whitten@Sun.COM case EAGAIN: 1971*8497SThomas.Whitten@Sun.COM case ENOMEM: 1972*8497SThomas.Whitten@Sun.COM syslog(LOG_ERR, gettext("start_audit_session(): cannot " 1973*8497SThomas.Whitten@Sun.COM "get ucred. %m\n")); 1974*8497SThomas.Whitten@Sun.COM return; 1975*8497SThomas.Whitten@Sun.COM case EINVAL: 1976*8497SThomas.Whitten@Sun.COM /* 1977*8497SThomas.Whitten@Sun.COM * Door client went away. This is a normal, 1978*8497SThomas.Whitten@Sun.COM * although infrequent event, so there is no need 1979*8497SThomas.Whitten@Sun.COM * to create a syslog message. 1980*8497SThomas.Whitten@Sun.COM */ 1981*8497SThomas.Whitten@Sun.COM return; 1982*8497SThomas.Whitten@Sun.COM case EFAULT: 1983*8497SThomas.Whitten@Sun.COM default: 1984*8497SThomas.Whitten@Sun.COM bad_error("door_ucred", errno); 1985*8497SThomas.Whitten@Sun.COM return; 1986*8497SThomas.Whitten@Sun.COM } 19875777Stw21770 } 1988*8497SThomas.Whitten@Sun.COM if (adt_start_session(&session, NULL, 0) != 0) { 19895777Stw21770 syslog(LOG_ERR, gettext("start_audit_session(): could not " 19905777Stw21770 "start audit session.\n")); 1991*8497SThomas.Whitten@Sun.COM ucred_free(cred); 1992*8497SThomas.Whitten@Sun.COM return; 19935777Stw21770 } 1994*8497SThomas.Whitten@Sun.COM if (adt_set_from_ucred(session, cred, ADT_NEW) != 0) { 19955777Stw21770 syslog(LOG_ERR, gettext("start_audit_session(): cannot set " 19965777Stw21770 "audit session data from ucred\n")); 1997*8497SThomas.Whitten@Sun.COM /* Something went wrong. End the session. */ 1998*8497SThomas.Whitten@Sun.COM (void) adt_end_session(session); 1999*8497SThomas.Whitten@Sun.COM ucred_free(cred); 2000*8497SThomas.Whitten@Sun.COM return; 20015777Stw21770 } 2002*8497SThomas.Whitten@Sun.COM 2003*8497SThomas.Whitten@Sun.COM /* All went well. Save the session data and session ID */ 2004*8497SThomas.Whitten@Sun.COM cp->rc_adt_session = session; 2005*8497SThomas.Whitten@Sun.COM adt_get_asid(session, &cp->rc_adt_sessionid); 20065777Stw21770 20075777Stw21770 ucred_free(cred); 20085777Stw21770 } 20090Sstevel@tonic-gate 20106035Sstevep /* 20116035Sstevep * Handle switch client request 20126035Sstevep * 20136035Sstevep * This routine can return: 20146035Sstevep * 20156035Sstevep * _PERMISSION_DENIED not enough privileges to do request. 20166035Sstevep * _UNKNOWN file operation error (details written to 20176035Sstevep * the console). 20186035Sstevep * _SUCCESS switch operation is completed. 20196035Sstevep * _BACKEND_ACCESS backend access fails. 20206035Sstevep * _NO_RESOURCES out of memory. 20216035Sstevep * _BACKEND_READONLY backend is not writable. 20226035Sstevep */ 20236035Sstevep static rep_protocol_responseid_t 20246035Sstevep repository_switch(repcache_client_t *cp, 20256035Sstevep struct rep_protocol_switch_request *rpr) 20266035Sstevep { 20276035Sstevep rep_protocol_responseid_t result; 20286035Sstevep ucred_t *uc = get_ucred(); 20296035Sstevep 20306035Sstevep if (!client_is_privileged() && (uc == NULL || 20316035Sstevep ucred_geteuid(uc) != 0)) { 20326035Sstevep return (REP_PROTOCOL_FAIL_PERMISSION_DENIED); 20336035Sstevep } 20346035Sstevep 20356035Sstevep (void) pthread_mutex_lock(&cp->rc_lock); 20366035Sstevep if (rpr->rpr_changeid != cp->rc_changeid) { 20376035Sstevep if ((result = backend_switch(rpr->rpr_flag)) == 20386035Sstevep REP_PROTOCOL_SUCCESS) 20396035Sstevep cp->rc_changeid = rpr->rpr_changeid; 20406035Sstevep } else { 20416035Sstevep result = REP_PROTOCOL_SUCCESS; 20426035Sstevep } 20436035Sstevep (void) pthread_mutex_unlock(&cp->rc_lock); 20446035Sstevep 20456035Sstevep return (result); 20466035Sstevep } 20476035Sstevep 20480Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp, 20490Sstevel@tonic-gate const void *rpr); 20500Sstevel@tonic-gate 20510Sstevel@tonic-gate /*ARGSUSED*/ 20520Sstevel@tonic-gate static void 20530Sstevel@tonic-gate simple_handler(repcache_client_t *cp, const void *in, size_t insz, 20540Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg) 20550Sstevel@tonic-gate { 20560Sstevel@tonic-gate protocol_simple_f *f = (protocol_simple_f *)arg; 20570Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 20580Sstevel@tonic-gate 20590Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 20600Sstevel@tonic-gate assert(f != NULL); 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate out->rpr_response = (*f)(cp, in); 20630Sstevel@tonic-gate } 20640Sstevel@tonic-gate 20650Sstevel@tonic-gate typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp, 20660Sstevel@tonic-gate const void *rpr, int *out_fd); 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate /*ARGSUSED*/ 20690Sstevel@tonic-gate static void 20700Sstevel@tonic-gate simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz, 20710Sstevel@tonic-gate void *out_arg, size_t *outsz, void *arg, int *out_fd) 20720Sstevel@tonic-gate { 20730Sstevel@tonic-gate protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg; 20740Sstevel@tonic-gate rep_protocol_response_t *out = out_arg; 20750Sstevel@tonic-gate 20760Sstevel@tonic-gate assert(*outsz == sizeof (*out)); 20770Sstevel@tonic-gate assert(f != NULL); 20780Sstevel@tonic-gate 20790Sstevel@tonic-gate out->rpr_response = (*f)(cp, in, out_fd); 20800Sstevel@tonic-gate } 20810Sstevel@tonic-gate 20820Sstevel@tonic-gate typedef void protocol_handler_f(repcache_client_t *, const void *in, 20830Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg); 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in, 20860Sstevel@tonic-gate size_t insz, void *out, size_t *outsz, void *arg, int *fd_out); 20870Sstevel@tonic-gate 20880Sstevel@tonic-gate #define PROTO(p, f, in) { \ 20890Sstevel@tonic-gate p, #p, simple_handler, (void *)(&f), NULL, \ 20900Sstevel@tonic-gate sizeof (in), sizeof (rep_protocol_response_t), 0 \ 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate 20930Sstevel@tonic-gate #define PROTO_FD_OUT(p, f, in) { \ 20940Sstevel@tonic-gate p, #p, NULL, (void *)(&f), simple_fd_handler, \ 20950Sstevel@tonic-gate sizeof (in), \ 20960Sstevel@tonic-gate sizeof (rep_protocol_response_t), \ 20970Sstevel@tonic-gate PROTO_FLAG_RETFD \ 20980Sstevel@tonic-gate } 20990Sstevel@tonic-gate 21000Sstevel@tonic-gate #define PROTO_VARIN(p, f, insz) { \ 21010Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 21020Sstevel@tonic-gate insz, sizeof (rep_protocol_response_t), \ 21030Sstevel@tonic-gate PROTO_FLAG_VARINPUT \ 21040Sstevel@tonic-gate } 21050Sstevel@tonic-gate 21060Sstevel@tonic-gate #define PROTO_UINT_OUT(p, f, in) { \ 21070Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 21080Sstevel@tonic-gate sizeof (in), \ 21090Sstevel@tonic-gate sizeof (struct rep_protocol_integer_response), 0 \ 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate #define PROTO_NAME_OUT(p, f, in) { \ 21130Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 21140Sstevel@tonic-gate sizeof (in), \ 21150Sstevel@tonic-gate sizeof (struct rep_protocol_name_response), 0 \ 21160Sstevel@tonic-gate } 21170Sstevel@tonic-gate 21180Sstevel@tonic-gate #define PROTO_FMRI_OUT(p, f, in) { \ 21190Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 21200Sstevel@tonic-gate sizeof (in), \ 21210Sstevel@tonic-gate sizeof (struct rep_protocol_fmri_response), 0 \ 21220Sstevel@tonic-gate } 21230Sstevel@tonic-gate 21240Sstevel@tonic-gate #define PROTO_VALUE_OUT(p, f, in) { \ 21250Sstevel@tonic-gate p, #p, &(f), NULL, NULL, \ 21260Sstevel@tonic-gate sizeof (in), \ 21270Sstevel@tonic-gate sizeof (struct rep_protocol_value_response), 0 \ 21280Sstevel@tonic-gate } 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 21310Sstevel@tonic-gate #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC } 21320Sstevel@tonic-gate 21330Sstevel@tonic-gate #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */ 21340Sstevel@tonic-gate #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */ 21350Sstevel@tonic-gate #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */ 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate #define PROTO_ALL_FLAGS 0x0000000f /* all flags */ 21380Sstevel@tonic-gate 21390Sstevel@tonic-gate static struct protocol_entry { 21400Sstevel@tonic-gate enum rep_protocol_requestid pt_request; 21410Sstevel@tonic-gate const char *pt_name; 21420Sstevel@tonic-gate protocol_handler_f *pt_handler; 21430Sstevel@tonic-gate void *pt_arg; 21440Sstevel@tonic-gate protocol_handler_fdret_f *pt_fd_handler; 21450Sstevel@tonic-gate size_t pt_in_size; 21460Sstevel@tonic-gate size_t pt_out_max; 21470Sstevel@tonic-gate uint32_t pt_flags; 21480Sstevel@tonic-gate } protocol_table[] = { 21490Sstevel@tonic-gate PROTO_PANIC(REP_PROTOCOL_CLOSE), /* special case */ 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_SETUP, entity_setup, 21520Sstevel@tonic-gate struct rep_protocol_entity_setup), 21530Sstevel@tonic-gate PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME, entity_name, 21540Sstevel@tonic-gate struct rep_protocol_entity_name), 21550Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE, entity_parent_type, 21560Sstevel@tonic-gate struct rep_protocol_entity_parent_type), 21570Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_CHILD, entity_get_child, 21580Sstevel@tonic-gate struct rep_protocol_entity_get_child), 21590Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET_PARENT, entity_get_parent, 21600Sstevel@tonic-gate struct rep_protocol_entity_parent), 21610Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_GET, entity_get, 21620Sstevel@tonic-gate struct rep_protocol_entity_get), 21630Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_UPDATE, entity_update, 21640Sstevel@tonic-gate struct rep_protocol_entity_update), 21650Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD, entity_create_child, 21660Sstevel@tonic-gate struct rep_protocol_entity_create_child), 21670Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_CREATE_PG, entity_create_pg, 21680Sstevel@tonic-gate struct rep_protocol_entity_create_pg), 21690Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_DELETE, entity_delete, 21700Sstevel@tonic-gate struct rep_protocol_entity_delete), 21710Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_RESET, entity_reset, 21720Sstevel@tonic-gate struct rep_protocol_entity_reset), 21730Sstevel@tonic-gate PROTO(REP_PROTOCOL_ENTITY_TEARDOWN, entity_teardown, 21740Sstevel@tonic-gate struct rep_protocol_entity_teardown), 21750Sstevel@tonic-gate 21760Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_SETUP, iter_setup, 21770Sstevel@tonic-gate struct rep_protocol_iter_request), 21780Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_START, iter_start, 21790Sstevel@tonic-gate struct rep_protocol_iter_start), 21800Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_READ, iter_read, 21810Sstevel@tonic-gate struct rep_protocol_iter_read), 21820Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE, iter_read_value, 21830Sstevel@tonic-gate struct rep_protocol_iter_read_value), 21840Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_RESET, iter_reset, 21850Sstevel@tonic-gate struct rep_protocol_iter_request), 21860Sstevel@tonic-gate PROTO(REP_PROTOCOL_ITER_TEARDOWN, iter_teardown, 21870Sstevel@tonic-gate struct rep_protocol_iter_request), 21880Sstevel@tonic-gate 21890Sstevel@tonic-gate PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL, next_snaplevel, 21900Sstevel@tonic-gate struct rep_protocol_entity_pair), 21910Sstevel@tonic-gate 21920Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE, snapshot_take, 21930Sstevel@tonic-gate struct rep_protocol_snapshot_take), 21940Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED, snapshot_take_named, 21950Sstevel@tonic-gate struct rep_protocol_snapshot_take_named), 21960Sstevel@tonic-gate PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH, snapshot_attach, 21970Sstevel@tonic-gate struct rep_protocol_snapshot_attach), 21980Sstevel@tonic-gate 21990Sstevel@tonic-gate PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE, property_get_type, 22000Sstevel@tonic-gate struct rep_protocol_property_request), 22010Sstevel@tonic-gate PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value, 22020Sstevel@tonic-gate struct rep_protocol_property_request), 22030Sstevel@tonic-gate 22040Sstevel@tonic-gate PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify, 22050Sstevel@tonic-gate struct rep_protocol_propertygrp_request), 22060Sstevel@tonic-gate PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START, tx_start, 22070Sstevel@tonic-gate struct rep_protocol_transaction_start), 22080Sstevel@tonic-gate PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT, tx_commit, 22090Sstevel@tonic-gate REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE), 22100Sstevel@tonic-gate 22110Sstevel@tonic-gate PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY, client_add_notify, 22120Sstevel@tonic-gate struct rep_protocol_notify_request), 22130Sstevel@tonic-gate PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT, client_wait, 22140Sstevel@tonic-gate struct rep_protocol_wait_request), 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate PROTO(REP_PROTOCOL_BACKUP, backup_repository, 22170Sstevel@tonic-gate struct rep_protocol_backup_request), 22180Sstevel@tonic-gate 22195777Stw21770 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION, set_annotation, 22205777Stw21770 struct rep_protocol_annotation), 22215777Stw21770 22226035Sstevep PROTO(REP_PROTOCOL_SWITCH, repository_switch, 22236035Sstevep struct rep_protocol_switch_request), 22246035Sstevep 22250Sstevel@tonic-gate PROTO_END() 22260Sstevel@tonic-gate }; 22270Sstevel@tonic-gate #undef PROTO 22280Sstevel@tonic-gate #undef PROTO_FMRI_OUT 22290Sstevel@tonic-gate #undef PROTO_NAME_OUT 22300Sstevel@tonic-gate #undef PROTO_UINT_OUT 22310Sstevel@tonic-gate #undef PROTO_PANIC 22320Sstevel@tonic-gate #undef PROTO_END 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate /* 22350Sstevel@tonic-gate * The number of entries, sans PROTO_END() 22360Sstevel@tonic-gate */ 22370Sstevel@tonic-gate #define PROTOCOL_ENTRIES \ 22380Sstevel@tonic-gate (sizeof (protocol_table) / sizeof (*protocol_table) - 1) 22390Sstevel@tonic-gate 22400Sstevel@tonic-gate #define PROTOCOL_PREFIX "REP_PROTOCOL_" 22410Sstevel@tonic-gate 22420Sstevel@tonic-gate int 22430Sstevel@tonic-gate client_init(void) 22440Sstevel@tonic-gate { 22450Sstevel@tonic-gate int i; 22460Sstevel@tonic-gate struct protocol_entry *e; 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate if (!client_hash_init()) 22490Sstevel@tonic-gate return (0); 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate if (request_log_size > 0) { 22520Sstevel@tonic-gate request_log = uu_zalloc(request_log_size * 22530Sstevel@tonic-gate sizeof (request_log_entry_t)); 22540Sstevel@tonic-gate } 22550Sstevel@tonic-gate 22560Sstevel@tonic-gate /* 22570Sstevel@tonic-gate * update the names to not include REP_PROTOCOL_ 22580Sstevel@tonic-gate */ 22590Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 22600Sstevel@tonic-gate e = &protocol_table[i]; 22610Sstevel@tonic-gate assert(strncmp(e->pt_name, PROTOCOL_PREFIX, 22620Sstevel@tonic-gate strlen(PROTOCOL_PREFIX)) == 0); 22630Sstevel@tonic-gate e->pt_name += strlen(PROTOCOL_PREFIX); 22640Sstevel@tonic-gate } 22650Sstevel@tonic-gate /* 22660Sstevel@tonic-gate * verify the protocol table is consistent 22670Sstevel@tonic-gate */ 22680Sstevel@tonic-gate for (i = 0; i < PROTOCOL_ENTRIES; i++) { 22690Sstevel@tonic-gate e = &protocol_table[i]; 22700Sstevel@tonic-gate assert(e->pt_request == (REP_PROTOCOL_BASE + i)); 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0); 22730Sstevel@tonic-gate 22740Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_PANIC) 22750Sstevel@tonic-gate assert(e->pt_in_size == 0 && e->pt_out_max == 0 && 22760Sstevel@tonic-gate e->pt_handler == NULL); 22770Sstevel@tonic-gate else 22780Sstevel@tonic-gate assert(e->pt_in_size != 0 && e->pt_out_max != 0 && 22790Sstevel@tonic-gate (e->pt_handler != NULL || 22800Sstevel@tonic-gate e->pt_fd_handler != NULL)); 22810Sstevel@tonic-gate } 22820Sstevel@tonic-gate assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST); 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate assert(protocol_table[i].pt_request == 0); 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate return (1); 22870Sstevel@tonic-gate } 22880Sstevel@tonic-gate 22890Sstevel@tonic-gate static void 22900Sstevel@tonic-gate client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in, 22910Sstevel@tonic-gate uint_t n_desc) 22920Sstevel@tonic-gate { 22930Sstevel@tonic-gate thread_info_t *ti = thread_self(); 22940Sstevel@tonic-gate 22950Sstevel@tonic-gate repcache_client_t *cp; 22960Sstevel@tonic-gate uint32_t id = (uint32_t)cookie; 22970Sstevel@tonic-gate enum rep_protocol_requestid request_code; 22980Sstevel@tonic-gate 22990Sstevel@tonic-gate rep_protocol_responseid_t result = INVALID_RESULT; 23000Sstevel@tonic-gate 23010Sstevel@tonic-gate struct protocol_entry *e; 23020Sstevel@tonic-gate 23030Sstevel@tonic-gate char *retval = NULL; 23040Sstevel@tonic-gate size_t retsize = 0; 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate int retfd = -1; 23070Sstevel@tonic-gate door_desc_t desc; 23080Sstevel@tonic-gate request_log_entry_t *rlp; 23090Sstevel@tonic-gate 23100Sstevel@tonic-gate rlp = start_log(id); 23110Sstevel@tonic-gate 23120Sstevel@tonic-gate if (n_desc != 0) 23130Sstevel@tonic-gate uu_die("can't happen: %d descriptors @%p (cookie %p)", 23140Sstevel@tonic-gate n_desc, desc_in, cookie); 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate if (argp == DOOR_UNREF_DATA) { 23170Sstevel@tonic-gate client_destroy(id); 23180Sstevel@tonic-gate goto bad_end; 23190Sstevel@tonic-gate } 23200Sstevel@tonic-gate 23210Sstevel@tonic-gate thread_newstate(ti, TI_CLIENT_CALL); 23220Sstevel@tonic-gate 23230Sstevel@tonic-gate /* 23240Sstevel@tonic-gate * To simplify returning just a result code, we set up for 23250Sstevel@tonic-gate * that case here. 23260Sstevel@tonic-gate */ 23270Sstevel@tonic-gate retval = (char *)&result; 23280Sstevel@tonic-gate retsize = sizeof (result); 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate if (arg_size < sizeof (request_code)) { 23310Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23320Sstevel@tonic-gate goto end_unheld; 23330Sstevel@tonic-gate } 23340Sstevel@tonic-gate 23350Sstevel@tonic-gate ti->ti_client_request = (void *)argp; 23360Sstevel@tonic-gate 23370Sstevel@tonic-gate /* LINTED alignment */ 23380Sstevel@tonic-gate request_code = *(uint32_t *)argp; 23390Sstevel@tonic-gate 23400Sstevel@tonic-gate if (rlp != NULL) { 23410Sstevel@tonic-gate rlp->rl_request = request_code; 23420Sstevel@tonic-gate } 23430Sstevel@tonic-gate /* 23440Sstevel@tonic-gate * In order to avoid locking problems on removal, we handle the 23450Sstevel@tonic-gate * "close" case before doing a lookup. 23460Sstevel@tonic-gate */ 23470Sstevel@tonic-gate if (request_code == REP_PROTOCOL_CLOSE) { 23480Sstevel@tonic-gate client_destroy(id); 23490Sstevel@tonic-gate result = REP_PROTOCOL_SUCCESS; 23500Sstevel@tonic-gate goto end_unheld; 23510Sstevel@tonic-gate } 23520Sstevel@tonic-gate 23530Sstevel@tonic-gate cp = client_lookup(id); 23540Sstevel@tonic-gate /* 23550Sstevel@tonic-gate * cp is held 23560Sstevel@tonic-gate */ 23570Sstevel@tonic-gate 23580Sstevel@tonic-gate if (cp == NULL) 23590Sstevel@tonic-gate goto bad_end; 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate if (rlp != NULL) 23620Sstevel@tonic-gate rlp->rl_client = cp; 23630Sstevel@tonic-gate 23640Sstevel@tonic-gate ti->ti_active_client = cp; 23650Sstevel@tonic-gate 23660Sstevel@tonic-gate if (request_code < REP_PROTOCOL_BASE || 23670Sstevel@tonic-gate request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) { 23680Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23690Sstevel@tonic-gate goto end; 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate e = &protocol_table[request_code - REP_PROTOCOL_BASE]; 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate assert(!(e->pt_flags & PROTO_FLAG_PANIC)); 23750Sstevel@tonic-gate 23760Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_VARINPUT) { 23770Sstevel@tonic-gate if (arg_size < e->pt_in_size) { 23780Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23790Sstevel@tonic-gate goto end; 23800Sstevel@tonic-gate } 23810Sstevel@tonic-gate } else if (arg_size != e->pt_in_size) { 23820Sstevel@tonic-gate result = REP_PROTOCOL_FAIL_BAD_REQUEST; 23830Sstevel@tonic-gate goto end; 23840Sstevel@tonic-gate } 23850Sstevel@tonic-gate 23860Sstevel@tonic-gate if (retsize != e->pt_out_max) { 23870Sstevel@tonic-gate retsize = e->pt_out_max; 23880Sstevel@tonic-gate retval = alloca(retsize); 23890Sstevel@tonic-gate } 23900Sstevel@tonic-gate 23910Sstevel@tonic-gate if (e->pt_flags & PROTO_FLAG_RETFD) 23920Sstevel@tonic-gate e->pt_fd_handler(cp, argp, arg_size, retval, &retsize, 23930Sstevel@tonic-gate e->pt_arg, &retfd); 23940Sstevel@tonic-gate else 23950Sstevel@tonic-gate e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg); 23960Sstevel@tonic-gate 23970Sstevel@tonic-gate end: 23980Sstevel@tonic-gate ti->ti_active_client = NULL; 23990Sstevel@tonic-gate client_release(cp); 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate end_unheld: 24020Sstevel@tonic-gate if (rlp != NULL) { 24030Sstevel@tonic-gate /* LINTED alignment */ 24040Sstevel@tonic-gate rlp->rl_response = *(uint32_t *)retval; 24050Sstevel@tonic-gate end_log(); 24060Sstevel@tonic-gate rlp = NULL; 24070Sstevel@tonic-gate } 24080Sstevel@tonic-gate ti->ti_client_request = NULL; 24090Sstevel@tonic-gate thread_newstate(ti, TI_DOOR_RETURN); 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate if (retval == (char *)&result) { 24120Sstevel@tonic-gate assert(result != INVALID_RESULT && retsize == sizeof (result)); 24130Sstevel@tonic-gate } else { 24140Sstevel@tonic-gate /* LINTED alignment */ 24150Sstevel@tonic-gate result = *(uint32_t *)retval; 24160Sstevel@tonic-gate } 24170Sstevel@tonic-gate if (retfd != -1) { 24180Sstevel@tonic-gate desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; 24190Sstevel@tonic-gate desc.d_data.d_desc.d_descriptor = retfd; 24200Sstevel@tonic-gate (void) door_return(retval, retsize, &desc, 1); 24210Sstevel@tonic-gate } else { 24220Sstevel@tonic-gate (void) door_return(retval, retsize, NULL, 0); 24230Sstevel@tonic-gate } 24240Sstevel@tonic-gate bad_end: 24250Sstevel@tonic-gate if (rlp != NULL) { 24260Sstevel@tonic-gate rlp->rl_response = -1; 24270Sstevel@tonic-gate end_log(); 24280Sstevel@tonic-gate rlp = NULL; 24290Sstevel@tonic-gate } 24300Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 24310Sstevel@tonic-gate } 24320Sstevel@tonic-gate 24330Sstevel@tonic-gate int 24340Sstevel@tonic-gate create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd) 24350Sstevel@tonic-gate { 24360Sstevel@tonic-gate int fd; 24370Sstevel@tonic-gate 24380Sstevel@tonic-gate repcache_client_t *cp; 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate struct door_info info; 24410Sstevel@tonic-gate 24420Sstevel@tonic-gate int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC; 24430Sstevel@tonic-gate #ifdef DOOR_NO_CANCEL 24440Sstevel@tonic-gate door_flags |= DOOR_NO_CANCEL; 24450Sstevel@tonic-gate #endif 24460Sstevel@tonic-gate 24470Sstevel@tonic-gate cp = client_alloc(); 24480Sstevel@tonic-gate if (cp == NULL) 24490Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 24500Sstevel@tonic-gate 24510Sstevel@tonic-gate (void) pthread_mutex_lock(&client_lock); 24520Sstevel@tonic-gate cp->rc_id = ++client_maxid; 24530Sstevel@tonic-gate (void) pthread_mutex_unlock(&client_lock); 24540Sstevel@tonic-gate 24550Sstevel@tonic-gate cp->rc_all_auths = privileged; 24560Sstevel@tonic-gate cp->rc_pid = pid; 24570Sstevel@tonic-gate cp->rc_debug = debugflags; 24580Sstevel@tonic-gate 24595777Stw21770 start_audit_session(cp); 24605777Stw21770 24610Sstevel@tonic-gate cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id, 24620Sstevel@tonic-gate door_flags); 24630Sstevel@tonic-gate 24640Sstevel@tonic-gate if (cp->rc_doorfd < 0) { 24650Sstevel@tonic-gate client_free(cp); 24660Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 24670Sstevel@tonic-gate } 24680Sstevel@tonic-gate #ifdef DOOR_PARAM_DATA_MIN 24690Sstevel@tonic-gate (void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN, 24700Sstevel@tonic-gate sizeof (enum rep_protocol_requestid)); 24710Sstevel@tonic-gate #endif 24720Sstevel@tonic-gate 24730Sstevel@tonic-gate if ((fd = dup(cp->rc_doorfd)) < 0 || 24740Sstevel@tonic-gate door_info(cp->rc_doorfd, &info) < 0) { 24750Sstevel@tonic-gate if (fd >= 0) 24760Sstevel@tonic-gate (void) close(fd); 24770Sstevel@tonic-gate (void) door_revoke(cp->rc_doorfd); 24780Sstevel@tonic-gate cp->rc_doorfd = -1; 24790Sstevel@tonic-gate client_free(cp); 24800Sstevel@tonic-gate return (REPOSITORY_DOOR_FAIL_NO_RESOURCES); 24810Sstevel@tonic-gate } 24820Sstevel@tonic-gate 24830Sstevel@tonic-gate rc_pg_notify_init(&cp->rc_pg_notify); 24840Sstevel@tonic-gate rc_notify_info_init(&cp->rc_notify_info); 24850Sstevel@tonic-gate 24860Sstevel@tonic-gate client_insert(cp); 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate cp->rc_doorid = info.di_uniquifier; 24890Sstevel@tonic-gate *out_fd = fd; 24900Sstevel@tonic-gate 24910Sstevel@tonic-gate return (REPOSITORY_DOOR_SUCCESS); 24920Sstevel@tonic-gate } 2493