17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5158643e0Sps57422 * Common Development and Distribution License (the "License"). 6158643e0Sps57422 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21158643e0Sps57422 227c478bd9Sstevel@tonic-gate /* 23*dda0f8f7Sgtb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24158643e0Sps57422 * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $ 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * Server side handling of RPCSEC_GSS flavor. 377c478bd9Sstevel@tonic-gate */ 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include <stdio.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <strings.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/time.h> 447c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h> 457c478bd9Sstevel@tonic-gate #include <gssapi/gssapi_ext.h> 467c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 477c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_defs.h> 487c478bd9Sstevel@tonic-gate #include <sys/file.h> 497c478bd9Sstevel@tonic-gate #include <fcntl.h> 507c478bd9Sstevel@tonic-gate #include <pwd.h> 517c478bd9Sstevel@tonic-gate #include <stdio.h> 527c478bd9Sstevel@tonic-gate #include <syslog.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Sequence window definitions. 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate #define SEQ_ARR_SIZE 4 587c478bd9Sstevel@tonic-gate #define SEQ_WIN (SEQ_ARR_SIZE*32) 597c478bd9Sstevel@tonic-gate #define SEQ_HI_BIT 0x80000000 607c478bd9Sstevel@tonic-gate #define SEQ_LO_BIT 1 617c478bd9Sstevel@tonic-gate #define DIV_BY_32 5 627c478bd9Sstevel@tonic-gate #define SEQ_MASK 0x1f 637c478bd9Sstevel@tonic-gate #define SEQ_MAX 0x80000000 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* cache retransmit data */ 677c478bd9Sstevel@tonic-gate typedef struct _retrans_entry { 687c478bd9Sstevel@tonic-gate uint32_t xid; 697c478bd9Sstevel@tonic-gate rpc_gss_init_res result; 707c478bd9Sstevel@tonic-gate struct _retrans_entry *next, *prev; 717c478bd9Sstevel@tonic-gate } retrans_entry; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Server side RPCSEC_GSS context information. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate typedef struct _svc_rpc_gss_data { 777c478bd9Sstevel@tonic-gate struct _svc_rpc_gss_data *next, *prev; 787c478bd9Sstevel@tonic-gate struct _svc_rpc_gss_data *lru_next, *lru_prev; 797c478bd9Sstevel@tonic-gate bool_t established; 807c478bd9Sstevel@tonic-gate gss_ctx_id_t context; 817c478bd9Sstevel@tonic-gate gss_name_t client_name; 827c478bd9Sstevel@tonic-gate gss_cred_id_t server_creds; 837c478bd9Sstevel@tonic-gate uint_t expiration; 847c478bd9Sstevel@tonic-gate uint_t seq_num; 857c478bd9Sstevel@tonic-gate uint_t seq_bits[SEQ_ARR_SIZE]; 867c478bd9Sstevel@tonic-gate uint_t key; 877c478bd9Sstevel@tonic-gate OM_uint32 qop; 887c478bd9Sstevel@tonic-gate bool_t done_docallback; 897c478bd9Sstevel@tonic-gate bool_t locked; 907c478bd9Sstevel@tonic-gate rpc_gss_rawcred_t raw_cred; 917c478bd9Sstevel@tonic-gate rpc_gss_ucred_t u_cred; 927c478bd9Sstevel@tonic-gate bool_t u_cred_set; 937c478bd9Sstevel@tonic-gate void *cookie; 947c478bd9Sstevel@tonic-gate gss_cred_id_t deleg; 957c478bd9Sstevel@tonic-gate mutex_t clm; 967c478bd9Sstevel@tonic-gate int ref_cnt; 977c478bd9Sstevel@tonic-gate bool_t stale; 987c478bd9Sstevel@tonic-gate time_t time_secs_set; 997c478bd9Sstevel@tonic-gate retrans_entry *retrans_data; 1007c478bd9Sstevel@tonic-gate } svc_rpc_gss_data; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Data structures used for LRU based context management. 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate #define HASHMOD 256 1067c478bd9Sstevel@tonic-gate #define HASHMASK 255 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *clients[HASHMOD]; 1097c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *lru_first, *lru_last; 1107c478bd9Sstevel@tonic-gate static int num_gss_contexts = 0; 1117c478bd9Sstevel@tonic-gate static int max_gss_contexts = 128; 1127c478bd9Sstevel@tonic-gate static int sweep_interval = 10; 1137c478bd9Sstevel@tonic-gate static int last_swept = 0; 1147c478bd9Sstevel@tonic-gate static uint_t max_lifetime = GSS_C_INDEFINITE; 115*dda0f8f7Sgtb static int init_lifetime = 0; 1167c478bd9Sstevel@tonic-gate static uint_t gid_timeout = 43200; /* 43200 secs = 12 hours */ 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * lock used with context/lru variables 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate static mutex_t ctx_mutex = DEFAULTMUTEX; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * server credential management data and structures 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate typedef struct svc_creds_list_s { 1277c478bd9Sstevel@tonic-gate struct svc_creds_list_s *next; 1287c478bd9Sstevel@tonic-gate gss_cred_id_t cred; 1297c478bd9Sstevel@tonic-gate gss_name_t name; 1307c478bd9Sstevel@tonic-gate rpcprog_t program; 1317c478bd9Sstevel@tonic-gate rpcvers_t version; 1327c478bd9Sstevel@tonic-gate gss_OID_set oid_set; 1337c478bd9Sstevel@tonic-gate OM_uint32 req_time; 1347c478bd9Sstevel@tonic-gate char *server_name; 1357c478bd9Sstevel@tonic-gate mutex_t refresh_mutex; 1367c478bd9Sstevel@tonic-gate } svc_creds_list_t; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static svc_creds_list_t *svc_creds_list; 1407c478bd9Sstevel@tonic-gate static int svc_creds_count = 0; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * lock used with server credential variables list 1447c478bd9Sstevel@tonic-gate * 1457c478bd9Sstevel@tonic-gate * server cred list locking guidelines: 1467c478bd9Sstevel@tonic-gate * - Writer's lock holder has exclusive access to the list 1477c478bd9Sstevel@tonic-gate * - Reader's lock holder(s) must also lock (refresh_mutex) each node 1487c478bd9Sstevel@tonic-gate * before accessing that node's elements (ie. cred) 1497c478bd9Sstevel@tonic-gate */ 1507c478bd9Sstevel@tonic-gate static rwlock_t cred_lock = DEFAULTRWLOCK; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* 1537c478bd9Sstevel@tonic-gate * server callback list 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate typedef struct cblist_s { 1567c478bd9Sstevel@tonic-gate struct cblist_s *next; 1577c478bd9Sstevel@tonic-gate rpc_gss_callback_t cb; 1587c478bd9Sstevel@tonic-gate } cblist_t; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate cblist_t *cblist = NULL; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * lock used with callback variables 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate static mutex_t cb_mutex = DEFAULTMUTEX; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * forward declarations 1697c478bd9Sstevel@tonic-gate */ 1707c478bd9Sstevel@tonic-gate static bool_t svc_rpc_gss_wrap(); 1717c478bd9Sstevel@tonic-gate static bool_t svc_rpc_gss_unwrap(); 1727c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *create_client(); 1737c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *get_client(); 1747c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *find_client(); 1757c478bd9Sstevel@tonic-gate static void destroy_client(); 1767c478bd9Sstevel@tonic-gate static void sweep_clients(); 1777c478bd9Sstevel@tonic-gate static void drop_lru_client(); 1787c478bd9Sstevel@tonic-gate static void insert_client(); 1797c478bd9Sstevel@tonic-gate static bool_t check_verf(); 1807c478bd9Sstevel@tonic-gate static bool_t rpc_gss_refresh_svc_cred(); 1817c478bd9Sstevel@tonic-gate static bool_t set_response_verf(); 1827c478bd9Sstevel@tonic-gate static void retrans_add(svc_rpc_gss_data *, uint32_t, 1837c478bd9Sstevel@tonic-gate rpc_gss_init_res *); 1847c478bd9Sstevel@tonic-gate static void retrans_del(struct _svc_rpc_gss_data *); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * server side wrap/unwrap routines 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate struct svc_auth_ops svc_rpc_gss_ops = { 1917c478bd9Sstevel@tonic-gate svc_rpc_gss_wrap, 1927c478bd9Sstevel@tonic-gate svc_rpc_gss_unwrap, 1937c478bd9Sstevel@tonic-gate }; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * Fetch server side authentication structure. 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate extern SVCAUTH *__svc_get_svcauth(); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * Cleanup routine for destroying context, called after service 2027c478bd9Sstevel@tonic-gate * procedure is executed, for MT safeness. 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate extern void *__svc_set_proc_cleanup_cb(); 2057c478bd9Sstevel@tonic-gate static void (*old_cleanup_cb)() = NULL; 2067c478bd9Sstevel@tonic-gate static bool_t cleanup_cb_set = FALSE; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static void 2097c478bd9Sstevel@tonic-gate ctx_cleanup(xprt) 2107c478bd9Sstevel@tonic-gate SVCXPRT *xprt; 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 2137c478bd9Sstevel@tonic-gate SVCAUTH *svcauth; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate if (old_cleanup_cb != NULL) 2167c478bd9Sstevel@tonic-gate (*old_cleanup_cb)(xprt); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * First check if current context needs to be cleaned up. 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate svcauth = __svc_get_svcauth(xprt); 2227c478bd9Sstevel@tonic-gate /*LINTED*/ 2237c478bd9Sstevel@tonic-gate if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) { 2247c478bd9Sstevel@tonic-gate mutex_lock(&cl->clm); 2257c478bd9Sstevel@tonic-gate if (--cl->ref_cnt == 0 && cl->stale) { 2267c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 2277c478bd9Sstevel@tonic-gate mutex_lock(&ctx_mutex); 2287c478bd9Sstevel@tonic-gate destroy_client(cl); 2297c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 2307c478bd9Sstevel@tonic-gate } else 2317c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * Check for other expired contexts. 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate if ((time(0) - last_swept) > sweep_interval) { 2387c478bd9Sstevel@tonic-gate mutex_lock(&ctx_mutex); 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Check again, in case some other thread got in. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate if ((time(0) - last_swept) > sweep_interval) 2437c478bd9Sstevel@tonic-gate sweep_clients(); 2447c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * Set server parameters. 2507c478bd9Sstevel@tonic-gate */ 2517c478bd9Sstevel@tonic-gate void 2527c478bd9Sstevel@tonic-gate __rpc_gss_set_server_parms(init_cred_lifetime, max_cred_lifetime, cache_size) 2537c478bd9Sstevel@tonic-gate int init_cred_lifetime; 2547c478bd9Sstevel@tonic-gate int max_cred_lifetime; 2557c478bd9Sstevel@tonic-gate int cache_size; 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * Ignore parameters unless greater than zero. 2597c478bd9Sstevel@tonic-gate */ 2607c478bd9Sstevel@tonic-gate mutex_lock(&ctx_mutex); 2617c478bd9Sstevel@tonic-gate if (cache_size > 0) 2627c478bd9Sstevel@tonic-gate max_gss_contexts = cache_size; 2637c478bd9Sstevel@tonic-gate if (max_cred_lifetime > 0) 2647c478bd9Sstevel@tonic-gate max_lifetime = (uint_t)max_cred_lifetime; 2657c478bd9Sstevel@tonic-gate if (init_cred_lifetime > 0) 2667c478bd9Sstevel@tonic-gate init_lifetime = init_cred_lifetime; 2677c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * Shift the array arr of length arrlen right by nbits bits. 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate static void 2747c478bd9Sstevel@tonic-gate shift_bits(arr, arrlen, nbits) 2757c478bd9Sstevel@tonic-gate uint_t *arr; 2767c478bd9Sstevel@tonic-gate int arrlen; 2777c478bd9Sstevel@tonic-gate int nbits; 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate int i, j; 2807c478bd9Sstevel@tonic-gate uint_t lo, hi; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * If the number of bits to be shifted exceeds SEQ_WIN, just 2847c478bd9Sstevel@tonic-gate * zero out the array. 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate if (nbits < SEQ_WIN) { 2877c478bd9Sstevel@tonic-gate for (i = 0; i < nbits; i++) { 2887c478bd9Sstevel@tonic-gate hi = 0; 2897c478bd9Sstevel@tonic-gate for (j = 0; j < arrlen; j++) { 2907c478bd9Sstevel@tonic-gate lo = arr[j] & SEQ_LO_BIT; 2917c478bd9Sstevel@tonic-gate arr[j] >>= 1; 2927c478bd9Sstevel@tonic-gate if (hi) 2937c478bd9Sstevel@tonic-gate arr[j] |= SEQ_HI_BIT; 2947c478bd9Sstevel@tonic-gate hi = lo; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate } else { 2987c478bd9Sstevel@tonic-gate for (j = 0; j < arrlen; j++) 2997c478bd9Sstevel@tonic-gate arr[j] = 0; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /* 3047c478bd9Sstevel@tonic-gate * Check that the received sequence number seq_num is valid. 3057c478bd9Sstevel@tonic-gate */ 3067c478bd9Sstevel@tonic-gate static bool_t 3077c478bd9Sstevel@tonic-gate check_seq(cl, seq_num, kill_context) 3087c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 3097c478bd9Sstevel@tonic-gate uint_t seq_num; 3107c478bd9Sstevel@tonic-gate bool_t *kill_context; 3117c478bd9Sstevel@tonic-gate { 3127c478bd9Sstevel@tonic-gate int i, j; 3137c478bd9Sstevel@tonic-gate uint_t bit; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * If it exceeds the maximum, kill context. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate if (seq_num >= SEQ_MAX) { 3197c478bd9Sstevel@tonic-gate *kill_context = TRUE; 3207c478bd9Sstevel@tonic-gate return (FALSE); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * If greater than the last seen sequence number, just shift 3257c478bd9Sstevel@tonic-gate * the sequence window so that it starts at the new sequence 3267c478bd9Sstevel@tonic-gate * number and extends downwards by SEQ_WIN. 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate if (seq_num > cl->seq_num) { 3297c478bd9Sstevel@tonic-gate shift_bits(cl->seq_bits, SEQ_ARR_SIZE, seq_num - cl->seq_num); 3307c478bd9Sstevel@tonic-gate cl->seq_bits[0] |= SEQ_HI_BIT; 3317c478bd9Sstevel@tonic-gate cl->seq_num = seq_num; 3327c478bd9Sstevel@tonic-gate return (TRUE); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * If it is outside the sequence window, return failure. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate i = cl->seq_num - seq_num; 3397c478bd9Sstevel@tonic-gate if (i >= SEQ_WIN) 3407c478bd9Sstevel@tonic-gate return (FALSE); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * If within sequence window, set the bit corresponding to it 3447c478bd9Sstevel@tonic-gate * if not already seen; if already seen, return failure. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate j = SEQ_MASK - (i & SEQ_MASK); 3477c478bd9Sstevel@tonic-gate bit = j > 0 ? (1 << j) : 1; 3487c478bd9Sstevel@tonic-gate i >>= DIV_BY_32; 3497c478bd9Sstevel@tonic-gate if (cl->seq_bits[i] & bit) 3507c478bd9Sstevel@tonic-gate return (FALSE); 3517c478bd9Sstevel@tonic-gate cl->seq_bits[i] |= bit; 3527c478bd9Sstevel@tonic-gate return (TRUE); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * Convert a name in gss exported type to rpc_gss_principal_t type. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate static bool_t 3597c478bd9Sstevel@tonic-gate __rpc_gss_make_principal(principal, name) 3607c478bd9Sstevel@tonic-gate rpc_gss_principal_t *principal; 3617c478bd9Sstevel@tonic-gate gss_buffer_desc *name; 3627c478bd9Sstevel@tonic-gate { 3637c478bd9Sstevel@tonic-gate int plen; 3647c478bd9Sstevel@tonic-gate char *s; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate plen = RNDUP(name->length) + sizeof (int); 3677c478bd9Sstevel@tonic-gate (*principal) = (rpc_gss_principal_t)malloc(plen); 3687c478bd9Sstevel@tonic-gate if ((*principal) == NULL) 3697c478bd9Sstevel@tonic-gate return (FALSE); 3707c478bd9Sstevel@tonic-gate bzero((caddr_t)(*principal), plen); 3717c478bd9Sstevel@tonic-gate (*principal)->len = RNDUP(name->length); 3727c478bd9Sstevel@tonic-gate s = (*principal)->name; 3737c478bd9Sstevel@tonic-gate memcpy(s, name->value, name->length); 3747c478bd9Sstevel@tonic-gate return (TRUE); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate /* 3787c478bd9Sstevel@tonic-gate * Convert a name in internal form to the exported type. 3797c478bd9Sstevel@tonic-gate */ 3807c478bd9Sstevel@tonic-gate static bool_t 3817c478bd9Sstevel@tonic-gate set_client_principal(g_name, r_name) 3827c478bd9Sstevel@tonic-gate gss_name_t g_name; 3837c478bd9Sstevel@tonic-gate rpc_gss_principal_t *r_name; 3847c478bd9Sstevel@tonic-gate { 3857c478bd9Sstevel@tonic-gate gss_buffer_desc name; 3867c478bd9Sstevel@tonic-gate OM_uint32 major, minor; 3877c478bd9Sstevel@tonic-gate bool_t ret = FALSE; 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate major = gss_export_name(&minor, g_name, &name); 3907c478bd9Sstevel@tonic-gate if (major != GSS_S_COMPLETE) 3917c478bd9Sstevel@tonic-gate return (FALSE); 3927c478bd9Sstevel@tonic-gate ret = __rpc_gss_make_principal(r_name, &name); 3937c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &name); 3947c478bd9Sstevel@tonic-gate return (ret); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Set server callback. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate bool_t 4017c478bd9Sstevel@tonic-gate __rpc_gss_set_callback(cb) 4027c478bd9Sstevel@tonic-gate rpc_gss_callback_t *cb; 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate cblist_t *cbl; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate if (cb->callback == NULL) 4077c478bd9Sstevel@tonic-gate return (FALSE); 4087c478bd9Sstevel@tonic-gate if ((cbl = (cblist_t *)malloc(sizeof (*cbl))) == NULL) 4097c478bd9Sstevel@tonic-gate return (FALSE); 4107c478bd9Sstevel@tonic-gate cbl->cb = *cb; 4117c478bd9Sstevel@tonic-gate mutex_lock(&cb_mutex); 4127c478bd9Sstevel@tonic-gate cbl->next = cblist; 4137c478bd9Sstevel@tonic-gate cblist = cbl; 4147c478bd9Sstevel@tonic-gate mutex_unlock(&cb_mutex); 4157c478bd9Sstevel@tonic-gate return (TRUE); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Locate callback (if specified) and call server. Release any 4207c478bd9Sstevel@tonic-gate * delegated credentials unless passed to server and the server 4217c478bd9Sstevel@tonic-gate * accepts the context. If a callback is not specified, accept 4227c478bd9Sstevel@tonic-gate * the incoming context. 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate static bool_t 4257c478bd9Sstevel@tonic-gate do_callback(req, client_data) 4267c478bd9Sstevel@tonic-gate struct svc_req *req; 4277c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate cblist_t *cbl; 4307c478bd9Sstevel@tonic-gate bool_t ret = TRUE, found = FALSE; 4317c478bd9Sstevel@tonic-gate rpc_gss_lock_t lock; 4327c478bd9Sstevel@tonic-gate OM_uint32 minor; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate mutex_lock(&cb_mutex); 4357c478bd9Sstevel@tonic-gate for (cbl = cblist; cbl != NULL; cbl = cbl->next) { 4367c478bd9Sstevel@tonic-gate if (req->rq_prog != cbl->cb.program || 4377c478bd9Sstevel@tonic-gate req->rq_vers != cbl->cb.version) 4387c478bd9Sstevel@tonic-gate continue; 4397c478bd9Sstevel@tonic-gate found = TRUE; 4407c478bd9Sstevel@tonic-gate lock.locked = FALSE; 4417c478bd9Sstevel@tonic-gate lock.raw_cred = &client_data->raw_cred; 4427c478bd9Sstevel@tonic-gate ret = (*cbl->cb.callback)(req, client_data->deleg, 4437c478bd9Sstevel@tonic-gate client_data->context, &lock, &client_data->cookie); 4447c478bd9Sstevel@tonic-gate if (ret) { 4457c478bd9Sstevel@tonic-gate client_data->locked = lock.locked; 4467c478bd9Sstevel@tonic-gate client_data->deleg = GSS_C_NO_CREDENTIAL; 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate if (!found) { 4517c478bd9Sstevel@tonic-gate if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 4527c478bd9Sstevel@tonic-gate (void) gss_release_cred(&minor, &client_data->deleg); 4537c478bd9Sstevel@tonic-gate client_data->deleg = GSS_C_NO_CREDENTIAL; 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate mutex_unlock(&cb_mutex); 4577c478bd9Sstevel@tonic-gate return (ret); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Return caller credentials. 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate bool_t 4647c478bd9Sstevel@tonic-gate __rpc_gss_getcred(req, rcred, ucred, cookie) 4657c478bd9Sstevel@tonic-gate struct svc_req *req; 4667c478bd9Sstevel@tonic-gate rpc_gss_rawcred_t **rcred; 4677c478bd9Sstevel@tonic-gate rpc_gss_ucred_t **ucred; 4687c478bd9Sstevel@tonic-gate void **cookie; 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate SVCAUTH *svcauth; 4717c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 4727c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms; 4737c478bd9Sstevel@tonic-gate gss_OID oid; 4747c478bd9Sstevel@tonic-gate OM_uint32 status; 4757c478bd9Sstevel@tonic-gate int len = 0; 4767c478bd9Sstevel@tonic-gate struct timeval now; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate svcauth = __svc_get_svcauth(req->rq_xprt); 4797c478bd9Sstevel@tonic-gate /*LINTED*/ 4807c478bd9Sstevel@tonic-gate client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private; 4817c478bd9Sstevel@tonic-gate gss_parms = &svcauth->svc_gss_parms; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate mutex_lock(&client_data->clm); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (rcred != NULL) { 4867c478bd9Sstevel@tonic-gate svcauth->raw_cred = client_data->raw_cred; 4877c478bd9Sstevel@tonic-gate svcauth->raw_cred.service = gss_parms->service; 4887c478bd9Sstevel@tonic-gate svcauth->raw_cred.qop = __rpc_gss_num_to_qop( 4897c478bd9Sstevel@tonic-gate svcauth->raw_cred.mechanism, gss_parms->qop_rcvd); 4907c478bd9Sstevel@tonic-gate *rcred = &svcauth->raw_cred; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate if (ucred != NULL) { 4937c478bd9Sstevel@tonic-gate if (!client_data->u_cred_set) { 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Double check making sure ucred is not set 4967c478bd9Sstevel@tonic-gate * after acquiring the lock. 4977c478bd9Sstevel@tonic-gate */ 4987c478bd9Sstevel@tonic-gate if (!client_data->u_cred_set) { 4997c478bd9Sstevel@tonic-gate if (!__rpc_gss_mech_to_oid( 5007c478bd9Sstevel@tonic-gate (*rcred)->mechanism, &oid)) { 5017c478bd9Sstevel@tonic-gate fprintf(stderr, dgettext(TEXT_DOMAIN, 5027c478bd9Sstevel@tonic-gate "mech_to_oid failed in getcred.\n")); 5037c478bd9Sstevel@tonic-gate *ucred = NULL; 5047c478bd9Sstevel@tonic-gate } else { 5057c478bd9Sstevel@tonic-gate status = gsscred_name_to_unix_cred( 5067c478bd9Sstevel@tonic-gate client_data->client_name, oid, 5077c478bd9Sstevel@tonic-gate &client_data->u_cred.uid, 5087c478bd9Sstevel@tonic-gate &client_data->u_cred.gid, 5097c478bd9Sstevel@tonic-gate &client_data->u_cred.gidlist, 5107c478bd9Sstevel@tonic-gate &len); 5117c478bd9Sstevel@tonic-gate if (status == GSS_S_COMPLETE) { 5127c478bd9Sstevel@tonic-gate client_data->u_cred_set = TRUE; 5137c478bd9Sstevel@tonic-gate client_data->u_cred.gidlen = 5147c478bd9Sstevel@tonic-gate (short)len; 5157c478bd9Sstevel@tonic-gate gettimeofday(&now, 5167c478bd9Sstevel@tonic-gate (struct timezone *)NULL); 5177c478bd9Sstevel@tonic-gate client_data->time_secs_set = 5187c478bd9Sstevel@tonic-gate now.tv_sec; 5197c478bd9Sstevel@tonic-gate *ucred = &client_data->u_cred; 5207c478bd9Sstevel@tonic-gate } else 5217c478bd9Sstevel@tonic-gate *ucred = NULL; 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate } else { 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * gid's already set; 5277c478bd9Sstevel@tonic-gate * check if they have expired. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate gettimeofday(&now, (struct timezone *)NULL); 5307c478bd9Sstevel@tonic-gate if ((now.tv_sec - client_data->time_secs_set) 5317c478bd9Sstevel@tonic-gate > gid_timeout) { 5327c478bd9Sstevel@tonic-gate /* Refresh gid's */ 5337c478bd9Sstevel@tonic-gate status = gss_get_group_info( 5347c478bd9Sstevel@tonic-gate client_data->u_cred.uid, 5357c478bd9Sstevel@tonic-gate &client_data->u_cred.gid, 5367c478bd9Sstevel@tonic-gate &client_data->u_cred.gidlist, 5377c478bd9Sstevel@tonic-gate &len); 5387c478bd9Sstevel@tonic-gate if (status == GSS_S_COMPLETE) { 5397c478bd9Sstevel@tonic-gate client_data->u_cred.gidlen = 5407c478bd9Sstevel@tonic-gate (short)len; 5417c478bd9Sstevel@tonic-gate gettimeofday(&now, 5427c478bd9Sstevel@tonic-gate (struct timezone *)NULL); 5437c478bd9Sstevel@tonic-gate client_data->time_secs_set = now.tv_sec; 5447c478bd9Sstevel@tonic-gate *ucred = &client_data->u_cred; 5457c478bd9Sstevel@tonic-gate } else { 5467c478bd9Sstevel@tonic-gate client_data->u_cred_set = FALSE; 5477c478bd9Sstevel@tonic-gate *ucred = NULL; 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate else 5517c478bd9Sstevel@tonic-gate *ucred = &client_data->u_cred; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate if (cookie != NULL) 5557c478bd9Sstevel@tonic-gate *cookie = client_data->cookie; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate mutex_unlock(&client_data->clm); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate return (TRUE); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * Server side authentication for RPCSEC_GSS. 5647c478bd9Sstevel@tonic-gate */ 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate enum auth_stat 5677c478bd9Sstevel@tonic-gate __svcrpcsec_gss(rqst, msg, no_dispatch) 5687c478bd9Sstevel@tonic-gate struct svc_req *rqst; 5697c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 5707c478bd9Sstevel@tonic-gate bool_t *no_dispatch; 5717c478bd9Sstevel@tonic-gate { 5727c478bd9Sstevel@tonic-gate XDR xdrs; 5737c478bd9Sstevel@tonic-gate rpc_gss_creds creds; 5747c478bd9Sstevel@tonic-gate rpc_gss_init_arg call_arg; 5757c478bd9Sstevel@tonic-gate rpc_gss_init_res call_res, *retrans_result; 5767c478bd9Sstevel@tonic-gate gss_buffer_desc output_token; 5777c478bd9Sstevel@tonic-gate OM_uint32 gssstat, minor_stat, time_rec, ret_flags; 5787c478bd9Sstevel@tonic-gate struct opaque_auth *cred; 5797c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 5807c478bd9Sstevel@tonic-gate int ret; 5817c478bd9Sstevel@tonic-gate svc_creds_list_t *sc; 5827c478bd9Sstevel@tonic-gate SVCAUTH *svcauth; 5837c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms; 5847c478bd9Sstevel@tonic-gate gss_OID mech_type = GSS_C_NULL_OID; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate /* 5877c478bd9Sstevel@tonic-gate * Initialize response verifier to NULL verifier. If 5887c478bd9Sstevel@tonic-gate * necessary, this will be changed later. 5897c478bd9Sstevel@tonic-gate */ 5907c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE; 5917c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = NULL; 5927c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length = 0; 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * Need to null out results to start with. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate memset((char *)&call_res, 0, sizeof (call_res)); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * Pull out and check credential and verifier. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate cred = &msg->rm_call.cb_cred; 6027c478bd9Sstevel@tonic-gate if (cred->oa_length == 0) { 603158643e0Sps57422 return (AUTH_BADCRED); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate memset((char *)&creds, 0, sizeof (creds)); 6097c478bd9Sstevel@tonic-gate if (!__xdr_rpc_gss_creds(&xdrs, &creds)) { 6107c478bd9Sstevel@tonic-gate XDR_DESTROY(&xdrs); 6117c478bd9Sstevel@tonic-gate ret = AUTH_BADCRED; 6127c478bd9Sstevel@tonic-gate goto error; 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate XDR_DESTROY(&xdrs); 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * If this is a control message and proc is GSSAPI_INIT, then 6187c478bd9Sstevel@tonic-gate * create a client handle for this client. Otherwise, look up 6197c478bd9Sstevel@tonic-gate * the existing handle. 6207c478bd9Sstevel@tonic-gate */ 6217c478bd9Sstevel@tonic-gate if (creds.gss_proc == RPCSEC_GSS_INIT) { 6227c478bd9Sstevel@tonic-gate if (creds.ctx_handle.length != 0) { 6237c478bd9Sstevel@tonic-gate ret = AUTH_BADCRED; 6247c478bd9Sstevel@tonic-gate goto error; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate if ((client_data = create_client()) == NULL) { 6277c478bd9Sstevel@tonic-gate ret = AUTH_FAILED; 6287c478bd9Sstevel@tonic-gate goto error; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate } else { 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * Only verify values for service parameter when proc 6337c478bd9Sstevel@tonic-gate * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT. 6347c478bd9Sstevel@tonic-gate * RFC2203 says contents for sequence and service args 6357c478bd9Sstevel@tonic-gate * are undefined for creation procs. 6367c478bd9Sstevel@tonic-gate * 6377c478bd9Sstevel@tonic-gate * Note: only need to check for *CONTINUE_INIT here because 6387c478bd9Sstevel@tonic-gate * if() clause already checked for RPCSEC_GSS_INIT 6397c478bd9Sstevel@tonic-gate */ 6407c478bd9Sstevel@tonic-gate if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) { 6417c478bd9Sstevel@tonic-gate switch (creds.service) { 6427c478bd9Sstevel@tonic-gate case rpc_gss_svc_none: 6437c478bd9Sstevel@tonic-gate case rpc_gss_svc_integrity: 6447c478bd9Sstevel@tonic-gate case rpc_gss_svc_privacy: 6457c478bd9Sstevel@tonic-gate break; 6467c478bd9Sstevel@tonic-gate default: 6477c478bd9Sstevel@tonic-gate ret = AUTH_BADCRED; 6487c478bd9Sstevel@tonic-gate goto error; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate if (creds.ctx_handle.length == 0) { 6527c478bd9Sstevel@tonic-gate ret = AUTH_BADCRED; 6537c478bd9Sstevel@tonic-gate goto error; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 6567c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_NOCRED; 6577c478bd9Sstevel@tonic-gate goto error; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * lock the client data until it's safe; if it's already stale, 6637c478bd9Sstevel@tonic-gate * no more processing is possible 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate mutex_lock(&client_data->clm); 6667c478bd9Sstevel@tonic-gate if (client_data->stale) { 6677c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_NOCRED; 6687c478bd9Sstevel@tonic-gate goto error2; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * Any response we send will use ctx_handle, so set it now; 6737c478bd9Sstevel@tonic-gate * also set seq_window since this won't change. 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate call_res.ctx_handle.length = sizeof (client_data->key); 6767c478bd9Sstevel@tonic-gate call_res.ctx_handle.value = (char *)&client_data->key; 6777c478bd9Sstevel@tonic-gate call_res.seq_window = SEQ_WIN; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate svcauth = __svc_get_svcauth(rqst->rq_xprt); 6837c478bd9Sstevel@tonic-gate svcauth->svc_ah_ops = svc_rpc_gss_ops; 6847c478bd9Sstevel@tonic-gate svcauth->svc_ah_private = (caddr_t)client_data; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate /* 6877c478bd9Sstevel@tonic-gate * Keep copy of parameters we'll need for response, for the 6887c478bd9Sstevel@tonic-gate * sake of reentrancy (we don't want to look in the context 6897c478bd9Sstevel@tonic-gate * data because when we are sending a response, another 6907c478bd9Sstevel@tonic-gate * request may have come in. 6917c478bd9Sstevel@tonic-gate */ 6927c478bd9Sstevel@tonic-gate gss_parms = &svcauth->svc_gss_parms; 6937c478bd9Sstevel@tonic-gate gss_parms->established = client_data->established; 6947c478bd9Sstevel@tonic-gate gss_parms->service = creds.service; 6957c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd = (uint_t)client_data->qop; 6967c478bd9Sstevel@tonic-gate gss_parms->context = (void *)client_data->context; 6977c478bd9Sstevel@tonic-gate gss_parms->seq_num = creds.seq_num; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate if (!client_data->established) { 7007c478bd9Sstevel@tonic-gate if (creds.gss_proc == RPCSEC_GSS_DATA) { 7017c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 7027c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 7037c478bd9Sstevel@tonic-gate goto error2; 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * If the context is not established, then only GSSAPI_INIT 7087c478bd9Sstevel@tonic-gate * and _CONTINUE requests are valid. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc != 7117c478bd9Sstevel@tonic-gate RPCSEC_GSS_CONTINUE_INIT) { 7127c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 7137c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 7147c478bd9Sstevel@tonic-gate goto error2; 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* 7187c478bd9Sstevel@tonic-gate * call is for us, deserialize arguments 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate memset(&call_arg, 0, sizeof (call_arg)); 7217c478bd9Sstevel@tonic-gate if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg, 7227c478bd9Sstevel@tonic-gate (caddr_t)&call_arg)) { 7237c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 7247c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 7257c478bd9Sstevel@tonic-gate goto error2; 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate gssstat = GSS_S_FAILURE; 7297c478bd9Sstevel@tonic-gate minor_stat = 0; 7307c478bd9Sstevel@tonic-gate rw_rdlock(&cred_lock); 7317c478bd9Sstevel@tonic-gate /* 7327c478bd9Sstevel@tonic-gate * set next sc to point to the server cred 7337c478bd9Sstevel@tonic-gate * if the client_data contains server_creds 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 7367c478bd9Sstevel@tonic-gate if (rqst->rq_prog != sc->program || 7377c478bd9Sstevel@tonic-gate rqst->rq_vers != sc->version) 7387c478bd9Sstevel@tonic-gate continue; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate mutex_lock(&sc->refresh_mutex); 7417c478bd9Sstevel@tonic-gate gssstat = gss_accept_sec_context(&minor_stat, 7427c478bd9Sstevel@tonic-gate &client_data->context, 7437c478bd9Sstevel@tonic-gate sc->cred, 7447c478bd9Sstevel@tonic-gate &call_arg, 7457c478bd9Sstevel@tonic-gate GSS_C_NO_CHANNEL_BINDINGS, 7467c478bd9Sstevel@tonic-gate &client_data->client_name, 7477c478bd9Sstevel@tonic-gate &mech_type, 7487c478bd9Sstevel@tonic-gate &output_token, 7497c478bd9Sstevel@tonic-gate &ret_flags, 7507c478bd9Sstevel@tonic-gate &time_rec, 7517c478bd9Sstevel@tonic-gate NULL); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_CREDENTIALS_EXPIRED) { 7547c478bd9Sstevel@tonic-gate if (rpc_gss_refresh_svc_cred(sc)) { 7557c478bd9Sstevel@tonic-gate gssstat = gss_accept_sec_context( 7567c478bd9Sstevel@tonic-gate &minor_stat, 7577c478bd9Sstevel@tonic-gate &client_data->context, 7587c478bd9Sstevel@tonic-gate sc->cred, 7597c478bd9Sstevel@tonic-gate &call_arg, 7607c478bd9Sstevel@tonic-gate GSS_C_NO_CHANNEL_BINDINGS, 7617c478bd9Sstevel@tonic-gate &client_data->client_name, 7627c478bd9Sstevel@tonic-gate &mech_type, 7637c478bd9Sstevel@tonic-gate &output_token, 7647c478bd9Sstevel@tonic-gate &ret_flags, 7657c478bd9Sstevel@tonic-gate &time_rec, 7667c478bd9Sstevel@tonic-gate NULL); 7677c478bd9Sstevel@tonic-gate mutex_unlock(&sc->refresh_mutex); 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate } else { 7707c478bd9Sstevel@tonic-gate mutex_unlock(&sc->refresh_mutex); 7717c478bd9Sstevel@tonic-gate gssstat = GSS_S_NO_CRED; 7727c478bd9Sstevel@tonic-gate break; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate } else 7767c478bd9Sstevel@tonic-gate mutex_unlock(&sc->refresh_mutex); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_COMPLETE) { 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * Server_creds was right - set it. Also 7817c478bd9Sstevel@tonic-gate * set the raw and unix credentials at this 7827c478bd9Sstevel@tonic-gate * point. This saves a lot of computation 7837c478bd9Sstevel@tonic-gate * later when credentials are retrieved. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * XXX server_creds will prob be stale 7877c478bd9Sstevel@tonic-gate * after rpc_gss_refresh_svc_cred(), but 7887c478bd9Sstevel@tonic-gate * it appears not to ever be referenced 7897c478bd9Sstevel@tonic-gate * anyways. 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate mutex_lock(&sc->refresh_mutex); 7927c478bd9Sstevel@tonic-gate client_data->server_creds = sc->cred; 7937c478bd9Sstevel@tonic-gate client_data->raw_cred.version = creds.version; 7947c478bd9Sstevel@tonic-gate client_data->raw_cred.service = creds.service; 7957c478bd9Sstevel@tonic-gate client_data->raw_cred.svc_principal = 7967c478bd9Sstevel@tonic-gate sc->server_name; 7977c478bd9Sstevel@tonic-gate mutex_unlock(&sc->refresh_mutex); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate if ((client_data->raw_cred.mechanism 8007c478bd9Sstevel@tonic-gate = __rpc_gss_oid_to_mech(mech_type)) 8017c478bd9Sstevel@tonic-gate == NULL) { 8027c478bd9Sstevel@tonic-gate gssstat = GSS_S_FAILURE; 8037c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, 8047c478bd9Sstevel@tonic-gate &output_token); 8057c478bd9Sstevel@tonic-gate } else if (!set_client_principal(client_data-> 8067c478bd9Sstevel@tonic-gate client_name, &client_data-> 8077c478bd9Sstevel@tonic-gate raw_cred.client_principal)) { 8087c478bd9Sstevel@tonic-gate gssstat = GSS_S_FAILURE; 8097c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, 8107c478bd9Sstevel@tonic-gate &output_token); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate break; 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_CONTINUE_NEEDED) { 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate * XXX server_creds will prob be stale 8187c478bd9Sstevel@tonic-gate * after rpc_gss_refresh_svc_cred(), but 8197c478bd9Sstevel@tonic-gate * it appears not to ever be referenced 8207c478bd9Sstevel@tonic-gate * anyways. 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate mutex_lock(&sc->refresh_mutex); 8237c478bd9Sstevel@tonic-gate client_data->server_creds = sc->cred; 8247c478bd9Sstevel@tonic-gate mutex_unlock(&sc->refresh_mutex); 8257c478bd9Sstevel@tonic-gate break; 8267c478bd9Sstevel@tonic-gate } 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate call_res.gss_major = gssstat; 8327c478bd9Sstevel@tonic-gate call_res.gss_minor = minor_stat; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE && 8377c478bd9Sstevel@tonic-gate gssstat != GSS_S_CONTINUE_NEEDED) { 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * We have a failure - send response and delete 8407c478bd9Sstevel@tonic-gate * the context. Don't dispatch. Set ctx_handle 8417c478bd9Sstevel@tonic-gate * to NULL and seq_window to 0. 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate call_res.ctx_handle.length = 0; 8447c478bd9Sstevel@tonic-gate call_res.ctx_handle.value = NULL; 8457c478bd9Sstevel@tonic-gate call_res.seq_window = 0; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 8487c478bd9Sstevel@tonic-gate (caddr_t)&call_res); 8497c478bd9Sstevel@tonic-gate *no_dispatch = TRUE; 8507c478bd9Sstevel@tonic-gate ret = AUTH_OK; 8517c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 8527c478bd9Sstevel@tonic-gate goto error2; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate * This step succeeded. Send a response, along with 8577c478bd9Sstevel@tonic-gate * a token if there's one. Don't dispatch. 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate if (output_token.length != 0) { 8607c478bd9Sstevel@tonic-gate GSS_COPY_BUFFER(call_res.token, output_token); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * set response verifier: checksum of SEQ_WIN 8657c478bd9Sstevel@tonic-gate */ 8667c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_COMPLETE) { 8677c478bd9Sstevel@tonic-gate if (!set_response_verf(rqst, msg, client_data, 8687c478bd9Sstevel@tonic-gate (uint_t)SEQ_WIN)) { 8697c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 8707c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 8717c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, 8727c478bd9Sstevel@tonic-gate &output_token); 8737c478bd9Sstevel@tonic-gate goto error2; 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 8787c478bd9Sstevel@tonic-gate (caddr_t)&call_res); 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * Cache last response in case it is lost and the client 8817c478bd9Sstevel@tonic-gate * retries on an established context. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate (void) retrans_add(client_data, msg->rm_xid, &call_res); 8847c478bd9Sstevel@tonic-gate *no_dispatch = TRUE; 8857c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, &output_token); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate /* 8887c478bd9Sstevel@tonic-gate * If appropriate, set established to TRUE *after* sending 8897c478bd9Sstevel@tonic-gate * response (otherwise, the client will receive the final 8907c478bd9Sstevel@tonic-gate * token encrypted) 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_COMPLETE) { 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * Context is established. Set expiry time for 8957c478bd9Sstevel@tonic-gate * context (the minimum of time_rec and max_lifetime). 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate client_data->seq_num = 1; 8987c478bd9Sstevel@tonic-gate if (time_rec == GSS_C_INDEFINITE) { 8997c478bd9Sstevel@tonic-gate if (max_lifetime != GSS_C_INDEFINITE) 9007c478bd9Sstevel@tonic-gate client_data->expiration = 9017c478bd9Sstevel@tonic-gate max_lifetime + time(0); 9027c478bd9Sstevel@tonic-gate else 9037c478bd9Sstevel@tonic-gate client_data->expiration = 9047c478bd9Sstevel@tonic-gate GSS_C_INDEFINITE; 9057c478bd9Sstevel@tonic-gate } else if (max_lifetime == GSS_C_INDEFINITE || 9067c478bd9Sstevel@tonic-gate max_lifetime > time_rec) 9077c478bd9Sstevel@tonic-gate client_data->expiration = time_rec + time(0); 9087c478bd9Sstevel@tonic-gate else 9097c478bd9Sstevel@tonic-gate client_data->expiration = max_lifetime + 9107c478bd9Sstevel@tonic-gate time(0); 9117c478bd9Sstevel@tonic-gate client_data->established = TRUE; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate } else { 9157c478bd9Sstevel@tonic-gate if ((creds.gss_proc != RPCSEC_GSS_DATA) && 9167c478bd9Sstevel@tonic-gate (creds.gss_proc != RPCSEC_GSS_DESTROY)) { 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate switch (creds.gss_proc) { 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate case RPCSEC_GSS_CONTINUE_INIT: 9217c478bd9Sstevel@tonic-gate /* 9227c478bd9Sstevel@tonic-gate * This is an established context. Continue to 9237c478bd9Sstevel@tonic-gate * satisfy retried continue init requests out of 9247c478bd9Sstevel@tonic-gate * the retransmit cache. Throw away any that don't 9257c478bd9Sstevel@tonic-gate * have a matching xid or the cach is empty. 9267c478bd9Sstevel@tonic-gate * Delete the retransmit cache once the client sends 9277c478bd9Sstevel@tonic-gate * a data request. 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate if (client_data->retrans_data && 9307c478bd9Sstevel@tonic-gate (client_data->retrans_data->xid == msg->rm_xid)) { 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate retrans_result = &client_data->retrans_data->result; 9337c478bd9Sstevel@tonic-gate if (set_response_verf(rqst, msg, client_data, 9347c478bd9Sstevel@tonic-gate (uint_t)retrans_result->seq_window)) { 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate gss_parms->established = FALSE; 9377c478bd9Sstevel@tonic-gate svc_sendreply(rqst->rq_xprt, 9387c478bd9Sstevel@tonic-gate __xdr_rpc_gss_init_res, 9397c478bd9Sstevel@tonic-gate (caddr_t)retrans_result); 9407c478bd9Sstevel@tonic-gate *no_dispatch = TRUE; 9417c478bd9Sstevel@tonic-gate goto success; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate /* fall thru to default */ 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate default: 9477c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "_svcrpcsec_gss: non-data request " 9487c478bd9Sstevel@tonic-gate "on an established context"); 9497c478bd9Sstevel@tonic-gate ret = AUTH_FAILED; 9507c478bd9Sstevel@tonic-gate goto error2; 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Once the context is established and there is no more 9567c478bd9Sstevel@tonic-gate * retransmission of last continue init request, it is safe 9577c478bd9Sstevel@tonic-gate * to delete the retransmit cache entry. 9587c478bd9Sstevel@tonic-gate */ 9597c478bd9Sstevel@tonic-gate if (client_data->retrans_data) 9607c478bd9Sstevel@tonic-gate retrans_del(client_data); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Context is already established. Check verifier, and 9647c478bd9Sstevel@tonic-gate * note parameters we will need for response in gss_parms. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate if (!check_verf(msg, client_data->context, 9677c478bd9Sstevel@tonic-gate &gss_parms->qop_rcvd)) { 9687c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_NOCRED; 9697c478bd9Sstevel@tonic-gate goto error2; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * Check and invoke callback if necessary. 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate if (!client_data->done_docallback) { 9757c478bd9Sstevel@tonic-gate client_data->done_docallback = TRUE; 9767c478bd9Sstevel@tonic-gate client_data->qop = gss_parms->qop_rcvd; 9777c478bd9Sstevel@tonic-gate client_data->raw_cred.qop = __rpc_gss_num_to_qop( 9787c478bd9Sstevel@tonic-gate client_data->raw_cred.mechanism, 9797c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd); 9807c478bd9Sstevel@tonic-gate client_data->raw_cred.service = creds.service; 9817c478bd9Sstevel@tonic-gate if (!do_callback(rqst, client_data)) { 9827c478bd9Sstevel@tonic-gate ret = AUTH_FAILED; 9837c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 9847c478bd9Sstevel@tonic-gate goto error2; 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * If the context was locked, make sure that the client 9907c478bd9Sstevel@tonic-gate * has not changed QOP. 9917c478bd9Sstevel@tonic-gate */ 9927c478bd9Sstevel@tonic-gate if (client_data->locked && 9937c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd != client_data->qop) { 9947c478bd9Sstevel@tonic-gate ret = AUTH_BADVERF; 9957c478bd9Sstevel@tonic-gate goto error2; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate /* 9997c478bd9Sstevel@tonic-gate * Validate sequence number. 10007c478bd9Sstevel@tonic-gate */ 10017c478bd9Sstevel@tonic-gate if (!check_seq(client_data, creds.seq_num, 10027c478bd9Sstevel@tonic-gate &client_data->stale)) { 10037c478bd9Sstevel@tonic-gate if (client_data->stale) 10047c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 10057c478bd9Sstevel@tonic-gate else { 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * Operational error, drop packet silently. 10087c478bd9Sstevel@tonic-gate * The client will recover after timing out, 10097c478bd9Sstevel@tonic-gate * assuming this is a client error and not 10107c478bd9Sstevel@tonic-gate * a relpay attack. Don't dispatch. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate ret = AUTH_OK; 10137c478bd9Sstevel@tonic-gate *no_dispatch = TRUE; 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate goto error2; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * set response verifier 10207c478bd9Sstevel@tonic-gate */ 10217c478bd9Sstevel@tonic-gate if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) { 10227c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED; 10237c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 10247c478bd9Sstevel@tonic-gate goto error2; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * If this is a control message RPCSEC_GSS_DESTROY, process 10297c478bd9Sstevel@tonic-gate * the call; otherwise, return AUTH_OK so it will be 10307c478bd9Sstevel@tonic-gate * dispatched to the application server. 10317c478bd9Sstevel@tonic-gate */ 10327c478bd9Sstevel@tonic-gate if (creds.gss_proc == RPCSEC_GSS_DESTROY) { 10337c478bd9Sstevel@tonic-gate svc_sendreply(rqst->rq_xprt, xdr_void, NULL); 10347c478bd9Sstevel@tonic-gate *no_dispatch = TRUE; 10357c478bd9Sstevel@tonic-gate client_data->stale = TRUE; 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate } else { 10387c478bd9Sstevel@tonic-gate /* 10397c478bd9Sstevel@tonic-gate * This should be an RPCSEC_GSS_DATA request. 10407c478bd9Sstevel@tonic-gate * If context is locked, make sure that the client 10417c478bd9Sstevel@tonic-gate * has not changed the security service. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate if (client_data->locked && 10447c478bd9Sstevel@tonic-gate client_data->raw_cred.service != creds.service) { 10457c478bd9Sstevel@tonic-gate ret = AUTH_FAILED; 10467c478bd9Sstevel@tonic-gate goto error2; 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate /* 10507c478bd9Sstevel@tonic-gate * Set client credentials to raw credential 10517c478bd9Sstevel@tonic-gate * structure in context. This is okay, since 10527c478bd9Sstevel@tonic-gate * this will not change during the lifetime of 10537c478bd9Sstevel@tonic-gate * the context (so it's MT safe). 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate rqst->rq_clntcred = (char *)&client_data->raw_cred; 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate success: 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * Success. 10627c478bd9Sstevel@tonic-gate */ 10637c478bd9Sstevel@tonic-gate if (creds.ctx_handle.length != 0) 10647c478bd9Sstevel@tonic-gate xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 10657c478bd9Sstevel@tonic-gate mutex_unlock(&client_data->clm); 10667c478bd9Sstevel@tonic-gate return (AUTH_OK); 10677c478bd9Sstevel@tonic-gate error2: 10687c478bd9Sstevel@tonic-gate mutex_unlock(&client_data->clm); 10697c478bd9Sstevel@tonic-gate error: 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Failure. 10727c478bd9Sstevel@tonic-gate */ 10737c478bd9Sstevel@tonic-gate if (creds.ctx_handle.length != 0) 10747c478bd9Sstevel@tonic-gate xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 10757c478bd9Sstevel@tonic-gate return (ret); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * Check verifier. The verifier is the checksum of the RPC header 10807c478bd9Sstevel@tonic-gate * upto and including the credentials field. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate static bool_t 10837c478bd9Sstevel@tonic-gate check_verf(msg, context, qop_state) 10847c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 10857c478bd9Sstevel@tonic-gate gss_ctx_id_t context; 10867c478bd9Sstevel@tonic-gate int *qop_state; 10877c478bd9Sstevel@tonic-gate { 10887c478bd9Sstevel@tonic-gate int *buf, *tmp; 10897c478bd9Sstevel@tonic-gate int hdr[32]; 10907c478bd9Sstevel@tonic-gate struct opaque_auth *oa; 10917c478bd9Sstevel@tonic-gate int len; 10927c478bd9Sstevel@tonic-gate gss_buffer_desc msg_buf; 10937c478bd9Sstevel@tonic-gate gss_buffer_desc tok_buf; 10947c478bd9Sstevel@tonic-gate OM_uint32 gssstat, minor_stat; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * We have to reconstruct the RPC header from the previously 10987c478bd9Sstevel@tonic-gate * parsed information, since we haven't kept the header intact. 10997c478bd9Sstevel@tonic-gate */ 1100a38dd497Spk193450 1101a38dd497Spk193450 oa = &msg->rm_call.cb_cred; 1102a38dd497Spk193450 if (oa->oa_length > MAX_AUTH_BYTES) 1103a38dd497Spk193450 return (FALSE); 1104a38dd497Spk193450 1105a38dd497Spk193450 /* 8 XDR units from the IXDR macro calls. */ 1106a38dd497Spk193450 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT + 1107a38dd497Spk193450 RNDUP(oa->oa_length))) 1108a38dd497Spk193450 return (FALSE); 11097c478bd9Sstevel@tonic-gate buf = hdr; 1110a38dd497Spk193450 11117c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_xid); 11127c478bd9Sstevel@tonic-gate IXDR_PUT_ENUM(buf, msg->rm_direction); 11137c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 11147c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 11157c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 11167c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 11177c478bd9Sstevel@tonic-gate IXDR_PUT_ENUM(buf, oa->oa_flavor); 11187c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, oa->oa_length); 11197c478bd9Sstevel@tonic-gate if (oa->oa_length) { 11207c478bd9Sstevel@tonic-gate len = RNDUP(oa->oa_length); 11217c478bd9Sstevel@tonic-gate tmp = buf; 11227c478bd9Sstevel@tonic-gate buf += len / sizeof (int); 11237c478bd9Sstevel@tonic-gate *(buf - 1) = 0; 11247c478bd9Sstevel@tonic-gate (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate len = ((char *)buf) - (char *)hdr; 11277c478bd9Sstevel@tonic-gate msg_buf.length = len; 11287c478bd9Sstevel@tonic-gate msg_buf.value = (char *)hdr; 11297c478bd9Sstevel@tonic-gate oa = &msg->rm_call.cb_verf; 11307c478bd9Sstevel@tonic-gate tok_buf.length = oa->oa_length; 11317c478bd9Sstevel@tonic-gate tok_buf.value = oa->oa_base; 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf, 11347c478bd9Sstevel@tonic-gate qop_state); 11357c478bd9Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) 11367c478bd9Sstevel@tonic-gate return (FALSE); 11377c478bd9Sstevel@tonic-gate return (TRUE); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate /* 11417c478bd9Sstevel@tonic-gate * Set response verifier. This is the checksum of the given number. 11427c478bd9Sstevel@tonic-gate * (e.g. sequence number or sequence window) 11437c478bd9Sstevel@tonic-gate */ 11447c478bd9Sstevel@tonic-gate static bool_t 11457c478bd9Sstevel@tonic-gate set_response_verf(rqst, msg, cl, num) 11467c478bd9Sstevel@tonic-gate struct svc_req *rqst; 11477c478bd9Sstevel@tonic-gate struct rpc_msg *msg; 11487c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 11497c478bd9Sstevel@tonic-gate uint_t num; 11507c478bd9Sstevel@tonic-gate { 11517c478bd9Sstevel@tonic-gate OM_uint32 minor; 11527c478bd9Sstevel@tonic-gate gss_buffer_desc in_buf, out_buf; 11537c478bd9Sstevel@tonic-gate uint_t num_net; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate num_net = (uint_t)htonl(num); 11567c478bd9Sstevel@tonic-gate in_buf.length = sizeof (num); 11577c478bd9Sstevel@tonic-gate in_buf.value = (char *)&num_net; 11587c478bd9Sstevel@tonic-gate if (gss_sign(&minor, cl->context, cl->qop, &in_buf, 11597c478bd9Sstevel@tonic-gate &out_buf) != GSS_S_COMPLETE) 11607c478bd9Sstevel@tonic-gate return (FALSE); 11617c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 11627c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 11637c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 11647c478bd9Sstevel@tonic-gate memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value, 11657c478bd9Sstevel@tonic-gate out_buf.length); 11667c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &out_buf); 11677c478bd9Sstevel@tonic-gate return (TRUE); 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate /* 11717c478bd9Sstevel@tonic-gate * Create client context. 11727c478bd9Sstevel@tonic-gate */ 11737c478bd9Sstevel@tonic-gate static svc_rpc_gss_data * 11747c478bd9Sstevel@tonic-gate create_client() 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 11777c478bd9Sstevel@tonic-gate static uint_t key = 1; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data)); 11807c478bd9Sstevel@tonic-gate if (client_data == NULL) 11817c478bd9Sstevel@tonic-gate return (NULL); 11827c478bd9Sstevel@tonic-gate memset((char *)client_data, 0, sizeof (*client_data)); 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * set up client data structure 11867c478bd9Sstevel@tonic-gate */ 11877c478bd9Sstevel@tonic-gate client_data->established = FALSE; 11887c478bd9Sstevel@tonic-gate client_data->locked = FALSE; 11897c478bd9Sstevel@tonic-gate client_data->u_cred_set = FALSE; 11907c478bd9Sstevel@tonic-gate client_data->context = GSS_C_NO_CONTEXT; 11917c478bd9Sstevel@tonic-gate client_data->expiration = init_lifetime + time(0); 11927c478bd9Sstevel@tonic-gate client_data->ref_cnt = 1; 11937c478bd9Sstevel@tonic-gate client_data->qop = GSS_C_QOP_DEFAULT; 11947c478bd9Sstevel@tonic-gate client_data->done_docallback = FALSE; 11957c478bd9Sstevel@tonic-gate client_data->stale = FALSE; 11967c478bd9Sstevel@tonic-gate client_data->time_secs_set = 0; 11977c478bd9Sstevel@tonic-gate client_data->retrans_data = NULL; 11987c478bd9Sstevel@tonic-gate mutex_init(&client_data->clm, USYNC_THREAD, NULL); 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * Check totals. If we've hit the limit, we destroy a context 12017c478bd9Sstevel@tonic-gate * based on LRU method. 12027c478bd9Sstevel@tonic-gate */ 12037c478bd9Sstevel@tonic-gate mutex_lock(&ctx_mutex); 12047c478bd9Sstevel@tonic-gate if (num_gss_contexts >= max_gss_contexts) { 12057c478bd9Sstevel@tonic-gate /* 12067c478bd9Sstevel@tonic-gate * now try on LRU basis 12077c478bd9Sstevel@tonic-gate */ 12087c478bd9Sstevel@tonic-gate drop_lru_client(); 12097c478bd9Sstevel@tonic-gate if (num_gss_contexts >= max_gss_contexts) { 12107c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 12117c478bd9Sstevel@tonic-gate free((char *)client_data); 12127c478bd9Sstevel@tonic-gate return (NULL); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate /* 12177c478bd9Sstevel@tonic-gate * The client context handle is a 32-bit key (unsigned int). 12187c478bd9Sstevel@tonic-gate * The key is incremented until there is no duplicate for it. 12197c478bd9Sstevel@tonic-gate */ 12207c478bd9Sstevel@tonic-gate for (;;) { 12217c478bd9Sstevel@tonic-gate client_data->key = key++; 12227c478bd9Sstevel@tonic-gate if (find_client(client_data->key) == NULL) { 12237c478bd9Sstevel@tonic-gate insert_client(client_data); 12247c478bd9Sstevel@tonic-gate /* 12257c478bd9Sstevel@tonic-gate * Set cleanup callback if we haven't. 12267c478bd9Sstevel@tonic-gate */ 12277c478bd9Sstevel@tonic-gate if (!cleanup_cb_set) { 12287c478bd9Sstevel@tonic-gate old_cleanup_cb = 12297c478bd9Sstevel@tonic-gate (void (*)()) __svc_set_proc_cleanup_cb( 12307c478bd9Sstevel@tonic-gate (void *)ctx_cleanup); 12317c478bd9Sstevel@tonic-gate cleanup_cb_set = TRUE; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 12347c478bd9Sstevel@tonic-gate return (client_data); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate /* 12417c478bd9Sstevel@tonic-gate * Insert client context into hash list and LRU list. 12427c478bd9Sstevel@tonic-gate */ 12437c478bd9Sstevel@tonic-gate static void 12447c478bd9Sstevel@tonic-gate insert_client(client_data) 12457c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 12467c478bd9Sstevel@tonic-gate { 12477c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 12487c478bd9Sstevel@tonic-gate int index = (client_data->key & HASHMASK); 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate client_data->prev = NULL; 12517c478bd9Sstevel@tonic-gate cl = clients[index]; 12527c478bd9Sstevel@tonic-gate if ((client_data->next = cl) != NULL) 12537c478bd9Sstevel@tonic-gate cl->prev = client_data; 12547c478bd9Sstevel@tonic-gate clients[index] = client_data; 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate client_data->lru_prev = NULL; 12577c478bd9Sstevel@tonic-gate if ((client_data->lru_next = lru_first) != NULL) 12587c478bd9Sstevel@tonic-gate lru_first->lru_prev = client_data; 12597c478bd9Sstevel@tonic-gate else 12607c478bd9Sstevel@tonic-gate lru_last = client_data; 12617c478bd9Sstevel@tonic-gate lru_first = client_data; 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate num_gss_contexts++; 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Fetch a client, given the client context handle. Move it to the 12687c478bd9Sstevel@tonic-gate * top of the LRU list since this is the most recently used context. 12697c478bd9Sstevel@tonic-gate */ 12707c478bd9Sstevel@tonic-gate static svc_rpc_gss_data * 12717c478bd9Sstevel@tonic-gate get_client(ctx_handle) 12727c478bd9Sstevel@tonic-gate gss_buffer_t ctx_handle; 12737c478bd9Sstevel@tonic-gate { 12747c478bd9Sstevel@tonic-gate uint_t key = *(uint_t *)ctx_handle->value; 12757c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate mutex_lock(&ctx_mutex); 12787c478bd9Sstevel@tonic-gate if ((cl = find_client(key)) != NULL) { 12797c478bd9Sstevel@tonic-gate mutex_lock(&cl->clm); 12807c478bd9Sstevel@tonic-gate if (cl->stale) { 12817c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 12827c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 12837c478bd9Sstevel@tonic-gate return (NULL); 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate cl->ref_cnt++; 12867c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 12877c478bd9Sstevel@tonic-gate if (cl != lru_first) { 12887c478bd9Sstevel@tonic-gate cl->lru_prev->lru_next = cl->lru_next; 12897c478bd9Sstevel@tonic-gate if (cl->lru_next != NULL) 12907c478bd9Sstevel@tonic-gate cl->lru_next->lru_prev = cl->lru_prev; 12917c478bd9Sstevel@tonic-gate else 12927c478bd9Sstevel@tonic-gate lru_last = cl->lru_prev; 12937c478bd9Sstevel@tonic-gate cl->lru_prev = NULL; 12947c478bd9Sstevel@tonic-gate cl->lru_next = lru_first; 12957c478bd9Sstevel@tonic-gate lru_first->lru_prev = cl; 12967c478bd9Sstevel@tonic-gate lru_first = cl; 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate mutex_unlock(&ctx_mutex); 13007c478bd9Sstevel@tonic-gate return (cl); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * Given the client context handle, find the context corresponding to it. 13057c478bd9Sstevel@tonic-gate * Don't change its LRU state since it may not be used. 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate static svc_rpc_gss_data * 13087c478bd9Sstevel@tonic-gate find_client(key) 13097c478bd9Sstevel@tonic-gate uint_t key; 13107c478bd9Sstevel@tonic-gate { 13117c478bd9Sstevel@tonic-gate int index = (key & HASHMASK); 13127c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate for (cl = clients[index]; cl != NULL; cl = cl->next) { 13157c478bd9Sstevel@tonic-gate if (cl->key == key) 13167c478bd9Sstevel@tonic-gate break; 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate return (cl); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate /* 13227c478bd9Sstevel@tonic-gate * Destroy a client context. 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate static void 13257c478bd9Sstevel@tonic-gate destroy_client(client_data) 13267c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data; 13277c478bd9Sstevel@tonic-gate { 13287c478bd9Sstevel@tonic-gate OM_uint32 minor; 13297c478bd9Sstevel@tonic-gate int index = (client_data->key & HASHMASK); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* 13327c478bd9Sstevel@tonic-gate * remove from hash list 13337c478bd9Sstevel@tonic-gate */ 13347c478bd9Sstevel@tonic-gate if (client_data->prev == NULL) 13357c478bd9Sstevel@tonic-gate clients[index] = client_data->next; 13367c478bd9Sstevel@tonic-gate else 13377c478bd9Sstevel@tonic-gate client_data->prev->next = client_data->next; 13387c478bd9Sstevel@tonic-gate if (client_data->next != NULL) 13397c478bd9Sstevel@tonic-gate client_data->next->prev = client_data->prev; 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * remove from LRU list 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate if (client_data->lru_prev == NULL) 13457c478bd9Sstevel@tonic-gate lru_first = client_data->lru_next; 13467c478bd9Sstevel@tonic-gate else 13477c478bd9Sstevel@tonic-gate client_data->lru_prev->lru_next = client_data->lru_next; 13487c478bd9Sstevel@tonic-gate if (client_data->lru_next != NULL) 13497c478bd9Sstevel@tonic-gate client_data->lru_next->lru_prev = client_data->lru_prev; 13507c478bd9Sstevel@tonic-gate else 13517c478bd9Sstevel@tonic-gate lru_last = client_data->lru_prev; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * If there is a GSS context, clean up GSS state. 13557c478bd9Sstevel@tonic-gate */ 13567c478bd9Sstevel@tonic-gate if (client_data->context != GSS_C_NO_CONTEXT) { 13577c478bd9Sstevel@tonic-gate (void) gss_delete_sec_context(&minor, &client_data->context, 13587c478bd9Sstevel@tonic-gate NULL); 13597c478bd9Sstevel@tonic-gate if (client_data->client_name) 13607c478bd9Sstevel@tonic-gate (void) gss_release_name(&minor, &client_data->client_name); 13617c478bd9Sstevel@tonic-gate if (client_data->raw_cred.client_principal) 13627c478bd9Sstevel@tonic-gate free((char *)client_data->raw_cred.client_principal); 13637c478bd9Sstevel@tonic-gate if (client_data->u_cred.gidlist != NULL) 13647c478bd9Sstevel@tonic-gate free((char *)client_data->u_cred.gidlist); 13657c478bd9Sstevel@tonic-gate if (client_data->deleg != GSS_C_NO_CREDENTIAL) 13667c478bd9Sstevel@tonic-gate (void) gss_release_cred(&minor, &client_data->deleg); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if (client_data->retrans_data != NULL) 13707c478bd9Sstevel@tonic-gate retrans_del(client_data); 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate free(client_data); 13737c478bd9Sstevel@tonic-gate num_gss_contexts--; 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* 13777c478bd9Sstevel@tonic-gate * Check for expired client contexts. 13787c478bd9Sstevel@tonic-gate */ 13797c478bd9Sstevel@tonic-gate static void 13807c478bd9Sstevel@tonic-gate sweep_clients() 13817c478bd9Sstevel@tonic-gate { 13827c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl, *next; 13837c478bd9Sstevel@tonic-gate int index; 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate for (index = 0; index < HASHMOD; index++) { 13867c478bd9Sstevel@tonic-gate cl = clients[index]; 13877c478bd9Sstevel@tonic-gate while (cl) { 13887c478bd9Sstevel@tonic-gate next = cl->next; 13897c478bd9Sstevel@tonic-gate mutex_lock(&cl->clm); 13907c478bd9Sstevel@tonic-gate if ((cl->expiration != GSS_C_INDEFINITE && 13917c478bd9Sstevel@tonic-gate cl->expiration <= time(0)) || cl->stale) { 13927c478bd9Sstevel@tonic-gate cl->stale = TRUE; 13937c478bd9Sstevel@tonic-gate if (cl->ref_cnt == 0) { 13947c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 13957c478bd9Sstevel@tonic-gate destroy_client(cl); 13967c478bd9Sstevel@tonic-gate } else 13977c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 13987c478bd9Sstevel@tonic-gate } else 13997c478bd9Sstevel@tonic-gate mutex_unlock(&cl->clm); 14007c478bd9Sstevel@tonic-gate cl = next; 14017c478bd9Sstevel@tonic-gate } 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate last_swept = time(0); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate /* 14077c478bd9Sstevel@tonic-gate * Drop the least recently used client context, if possible. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate static void 14107c478bd9Sstevel@tonic-gate drop_lru_client() 14117c478bd9Sstevel@tonic-gate { 14127c478bd9Sstevel@tonic-gate mutex_lock(&lru_last->clm); 14137c478bd9Sstevel@tonic-gate lru_last->stale = TRUE; 14147c478bd9Sstevel@tonic-gate mutex_unlock(&lru_last->clm); 14157c478bd9Sstevel@tonic-gate if (lru_last->ref_cnt == 0) 14167c478bd9Sstevel@tonic-gate destroy_client(lru_last); 14177c478bd9Sstevel@tonic-gate else 14187c478bd9Sstevel@tonic-gate sweep_clients(); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate 14217c478bd9Sstevel@tonic-gate /* 14227c478bd9Sstevel@tonic-gate * find service credentials 14237c478bd9Sstevel@tonic-gate * return cred if found, 14247c478bd9Sstevel@tonic-gate * other wise, NULL 14257c478bd9Sstevel@tonic-gate */ 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate svc_creds_list_t * 14287c478bd9Sstevel@tonic-gate find_svc_cred(char *service_name, uint_t program, uint_t version) { 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate svc_creds_list_t *sc; 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate if (!svc_creds_list) 14337c478bd9Sstevel@tonic-gate return (NULL); 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 14367c478bd9Sstevel@tonic-gate if (program != sc->program || version != sc->version) 14377c478bd9Sstevel@tonic-gate continue; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate if (strcmp(service_name, sc->server_name) != 0) 14407c478bd9Sstevel@tonic-gate continue; 14417c478bd9Sstevel@tonic-gate return (sc); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate return (NULL); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * Set the server principal name. 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate bool_t 14507c478bd9Sstevel@tonic-gate __rpc_gss_set_svc_name(server_name, mech, req_time, program, version) 14517c478bd9Sstevel@tonic-gate char *server_name; 14527c478bd9Sstevel@tonic-gate char *mech; 14537c478bd9Sstevel@tonic-gate OM_uint32 req_time; 14547c478bd9Sstevel@tonic-gate uint_t program; 14557c478bd9Sstevel@tonic-gate uint_t version; 14567c478bd9Sstevel@tonic-gate { 14577c478bd9Sstevel@tonic-gate gss_name_t name; 14587c478bd9Sstevel@tonic-gate svc_creds_list_t *svc_cred; 14597c478bd9Sstevel@tonic-gate gss_OID mechanism; 14607c478bd9Sstevel@tonic-gate gss_OID_set_desc oid_set_desc; 14617c478bd9Sstevel@tonic-gate gss_OID_set oid_set; 14627c478bd9Sstevel@tonic-gate OM_uint32 ret_time; 14637c478bd9Sstevel@tonic-gate OM_uint32 major, minor; 14647c478bd9Sstevel@tonic-gate gss_buffer_desc name_buf; 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate if (!__rpc_gss_mech_to_oid(mech, &mechanism)) { 14677c478bd9Sstevel@tonic-gate return (FALSE); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate name_buf.value = server_name; 14717c478bd9Sstevel@tonic-gate name_buf.length = strlen(server_name); 14727c478bd9Sstevel@tonic-gate major = gss_import_name(&minor, &name_buf, 14737c478bd9Sstevel@tonic-gate (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name); 14747c478bd9Sstevel@tonic-gate if (major != GSS_S_COMPLETE) { 14757c478bd9Sstevel@tonic-gate return (FALSE); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate /* Check if there is already an entry in the svc_creds_list. */ 14797c478bd9Sstevel@tonic-gate rw_wrlock(&cred_lock); 14807c478bd9Sstevel@tonic-gate if (svc_cred = find_svc_cred(server_name, program, version)) { 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate major = gss_add_cred(&minor, svc_cred->cred, name, 14837c478bd9Sstevel@tonic-gate mechanism, GSS_C_ACCEPT, 14847c478bd9Sstevel@tonic-gate 0, req_time, NULL, 14857c478bd9Sstevel@tonic-gate &oid_set, NULL, 14867c478bd9Sstevel@tonic-gate &ret_time); 14877c478bd9Sstevel@tonic-gate (void) gss_release_name(&minor, &name); 14887c478bd9Sstevel@tonic-gate if (major == GSS_S_COMPLETE) { 14897c478bd9Sstevel@tonic-gate /* 14907c478bd9Sstevel@tonic-gate * Successfully added the mech to the cred handle 14917c478bd9Sstevel@tonic-gate * free the existing oid_set in svc_cred 14927c478bd9Sstevel@tonic-gate */ 14937c478bd9Sstevel@tonic-gate gss_release_oid_set(&minor, &svc_cred->oid_set); 14947c478bd9Sstevel@tonic-gate svc_cred->oid_set = oid_set; 14957c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 14967c478bd9Sstevel@tonic-gate return (TRUE); 14977c478bd9Sstevel@tonic-gate } else if (major == GSS_S_DUPLICATE_ELEMENT) { 14987c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 14997c478bd9Sstevel@tonic-gate return (TRUE); 15007c478bd9Sstevel@tonic-gate } else if (major == GSS_S_CREDENTIALS_EXPIRED) { 15017c478bd9Sstevel@tonic-gate if (rpc_gss_refresh_svc_cred(svc_cred)) { 15027c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15037c478bd9Sstevel@tonic-gate return (TRUE); 15047c478bd9Sstevel@tonic-gate } else { 15057c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15067c478bd9Sstevel@tonic-gate return (FALSE); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate } else { 15097c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15107c478bd9Sstevel@tonic-gate return (FALSE); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate } else { 15137c478bd9Sstevel@tonic-gate svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred)); 15147c478bd9Sstevel@tonic-gate if (svc_cred == NULL) { 15157c478bd9Sstevel@tonic-gate (void) gss_release_name(&minor, &name); 15167c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15177c478bd9Sstevel@tonic-gate return (FALSE); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate oid_set_desc.count = 1; 15207c478bd9Sstevel@tonic-gate oid_set_desc.elements = mechanism; 15217c478bd9Sstevel@tonic-gate major = gss_acquire_cred(&minor, name, req_time, 15227c478bd9Sstevel@tonic-gate &oid_set_desc, 15237c478bd9Sstevel@tonic-gate GSS_C_ACCEPT, 15247c478bd9Sstevel@tonic-gate &svc_cred->cred, 15257c478bd9Sstevel@tonic-gate &oid_set, &ret_time); 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate if (major != GSS_S_COMPLETE) { 15287c478bd9Sstevel@tonic-gate (void) gss_release_name(&minor, &name); 15297c478bd9Sstevel@tonic-gate free(svc_cred); 15307c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15317c478bd9Sstevel@tonic-gate return (FALSE); 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate svc_cred->name = name; 15357c478bd9Sstevel@tonic-gate svc_cred->program = program; 15367c478bd9Sstevel@tonic-gate svc_cred->version = version; 15377c478bd9Sstevel@tonic-gate svc_cred->req_time = req_time; 15387c478bd9Sstevel@tonic-gate svc_cred->oid_set = oid_set; 15397c478bd9Sstevel@tonic-gate svc_cred->server_name = strdup(server_name); 15407c478bd9Sstevel@tonic-gate if (svc_cred->server_name == NULL) { 15417c478bd9Sstevel@tonic-gate (void) gss_release_name(&minor, &name); 15427c478bd9Sstevel@tonic-gate free((char *)svc_cred); 15437c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15447c478bd9Sstevel@tonic-gate return (FALSE); 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL); 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate svc_cred->next = svc_creds_list; 15497c478bd9Sstevel@tonic-gate svc_creds_list = svc_cred; 15507c478bd9Sstevel@tonic-gate svc_creds_count++; 15517c478bd9Sstevel@tonic-gate rw_unlock(&cred_lock); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate return (TRUE); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate /* 15577c478bd9Sstevel@tonic-gate * Refresh server credentials. 15587c478bd9Sstevel@tonic-gate */ 15597c478bd9Sstevel@tonic-gate static bool_t 15607c478bd9Sstevel@tonic-gate rpc_gss_refresh_svc_cred(svc_cred) 15617c478bd9Sstevel@tonic-gate svc_creds_list_t *svc_cred; 15627c478bd9Sstevel@tonic-gate { 15637c478bd9Sstevel@tonic-gate OM_uint32 major, minor; 15647c478bd9Sstevel@tonic-gate gss_OID_set oid_set; 15657c478bd9Sstevel@tonic-gate OM_uint32 ret_time; 15667c478bd9Sstevel@tonic-gate 15677c478bd9Sstevel@tonic-gate (void) gss_release_cred(&minor, &svc_cred->cred); 15687c478bd9Sstevel@tonic-gate svc_cred->cred = GSS_C_NO_CREDENTIAL; 15697c478bd9Sstevel@tonic-gate major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time, 15707c478bd9Sstevel@tonic-gate svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set, 15717c478bd9Sstevel@tonic-gate &ret_time); 15727c478bd9Sstevel@tonic-gate if (major != GSS_S_COMPLETE) { 15737c478bd9Sstevel@tonic-gate return (FALSE); 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate gss_release_oid_set(&minor, &svc_cred->oid_set); 15767c478bd9Sstevel@tonic-gate svc_cred->oid_set = oid_set; 15777c478bd9Sstevel@tonic-gate return (TRUE); 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 15827c478bd9Sstevel@tonic-gate * and write the result to xdrs. 15837c478bd9Sstevel@tonic-gate */ 15847c478bd9Sstevel@tonic-gate static bool_t 15857c478bd9Sstevel@tonic-gate svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 15867c478bd9Sstevel@tonic-gate SVCAUTH *auth; 15877c478bd9Sstevel@tonic-gate XDR *out_xdrs; 15887c478bd9Sstevel@tonic-gate bool_t (*xdr_func)(); 15897c478bd9Sstevel@tonic-gate caddr_t xdr_ptr; 15907c478bd9Sstevel@tonic-gate { 15917c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate /* 15947c478bd9Sstevel@tonic-gate * If context is not established, or if neither integrity nor 15957c478bd9Sstevel@tonic-gate * privacy service is used, don't wrap - just XDR encode. 15967c478bd9Sstevel@tonic-gate * Otherwise, wrap data using service and QOP parameters. 15977c478bd9Sstevel@tonic-gate */ 15987c478bd9Sstevel@tonic-gate if (!gss_parms->established || 15997c478bd9Sstevel@tonic-gate gss_parms->service == rpc_gss_svc_none) 16007c478bd9Sstevel@tonic-gate return ((*xdr_func)(out_xdrs, xdr_ptr)); 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate return (__rpc_gss_wrap_data(gss_parms->service, 16037c478bd9Sstevel@tonic-gate (OM_uint32)gss_parms->qop_rcvd, 16047c478bd9Sstevel@tonic-gate (gss_ctx_id_t)gss_parms->context, 16057c478bd9Sstevel@tonic-gate gss_parms->seq_num, 16067c478bd9Sstevel@tonic-gate out_xdrs, xdr_func, xdr_ptr)); 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * Decrypt the serialized arguments and XDR decode them. 16117c478bd9Sstevel@tonic-gate */ 16127c478bd9Sstevel@tonic-gate static bool_t 16137c478bd9Sstevel@tonic-gate svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 16147c478bd9Sstevel@tonic-gate SVCAUTH *auth; 16157c478bd9Sstevel@tonic-gate XDR *in_xdrs; 16167c478bd9Sstevel@tonic-gate bool_t (*xdr_func)(); 16177c478bd9Sstevel@tonic-gate caddr_t xdr_ptr; 16187c478bd9Sstevel@tonic-gate { 16197c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * If context is not established, or if neither integrity nor 16237c478bd9Sstevel@tonic-gate * privacy service is used, don't unwrap - just XDR decode. 16247c478bd9Sstevel@tonic-gate * Otherwise, unwrap data. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate if (!gss_parms->established || 16277c478bd9Sstevel@tonic-gate gss_parms->service == rpc_gss_svc_none) 16287c478bd9Sstevel@tonic-gate return ((*xdr_func)(in_xdrs, xdr_ptr)); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate return (__rpc_gss_unwrap_data(gss_parms->service, 16317c478bd9Sstevel@tonic-gate (gss_ctx_id_t)gss_parms->context, 16327c478bd9Sstevel@tonic-gate gss_parms->seq_num, 16337c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd, 16347c478bd9Sstevel@tonic-gate in_xdrs, xdr_func, xdr_ptr)); 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate int 16387c478bd9Sstevel@tonic-gate __rpc_gss_svc_max_data_length(req, max_tp_unit_len) 16397c478bd9Sstevel@tonic-gate struct svc_req *req; 16407c478bd9Sstevel@tonic-gate int max_tp_unit_len; 16417c478bd9Sstevel@tonic-gate { 16427c478bd9Sstevel@tonic-gate SVCAUTH *svcauth; 16437c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms; 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate svcauth = __svc_get_svcauth(req->rq_xprt); 16467c478bd9Sstevel@tonic-gate gss_parms = &svcauth->svc_gss_parms; 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate if (!gss_parms->established || max_tp_unit_len <= 0) 16497c478bd9Sstevel@tonic-gate return (0); 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate return (__find_max_data_length(gss_parms->service, 16527c478bd9Sstevel@tonic-gate (gss_ctx_id_t)gss_parms->context, 16537c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd, max_tp_unit_len)); 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate /* 16577c478bd9Sstevel@tonic-gate * Add retransmit entry to the context cache entry for a new xid. 16587c478bd9Sstevel@tonic-gate * If there is already an entry, delete it before adding the new one. 16597c478bd9Sstevel@tonic-gate */ 16607c478bd9Sstevel@tonic-gate static void retrans_add(client, xid, result) 16617c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client; 16627c478bd9Sstevel@tonic-gate uint32_t xid; 16637c478bd9Sstevel@tonic-gate rpc_gss_init_res *result; 16647c478bd9Sstevel@tonic-gate { 16657c478bd9Sstevel@tonic-gate retrans_entry *rdata; 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate if (client->retrans_data && client->retrans_data->xid == xid) 16687c478bd9Sstevel@tonic-gate return; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate rdata = (retrans_entry *) malloc(sizeof (*rdata)); 16717c478bd9Sstevel@tonic-gate if (rdata == NULL) 16727c478bd9Sstevel@tonic-gate return; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate rdata->xid = xid; 16757c478bd9Sstevel@tonic-gate rdata->result = *result; 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate if (result->token.length != 0) { 16787c478bd9Sstevel@tonic-gate GSS_DUP_BUFFER(rdata->result.token, result->token); 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate if (client->retrans_data) 16827c478bd9Sstevel@tonic-gate retrans_del(client); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate client->retrans_data = rdata; 16857c478bd9Sstevel@tonic-gate } 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate /* 16887c478bd9Sstevel@tonic-gate * Delete the retransmit data from the context cache entry. 16897c478bd9Sstevel@tonic-gate */ 16907c478bd9Sstevel@tonic-gate static void retrans_del(client) 16917c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client; 16927c478bd9Sstevel@tonic-gate { 16937c478bd9Sstevel@tonic-gate retrans_entry *rdata; 16947c478bd9Sstevel@tonic-gate OM_uint32 minor_stat; 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate if (client->retrans_data == NULL) 16977c478bd9Sstevel@tonic-gate return; 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate rdata = client->retrans_data; 17007c478bd9Sstevel@tonic-gate if (rdata->result.token.length != 0) { 17017c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, &rdata->result.token); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate free((caddr_t)rdata); 17057c478bd9Sstevel@tonic-gate client->retrans_data = NULL; 17067c478bd9Sstevel@tonic-gate } 1707