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
5158643e0Sps * Common Development and Distribution License (the "License").
6158643e0Sps * 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 */
21cf98b944SMarcel Telka
227c478bd9Sstevel@tonic-gate /*
23*02ac56e0SMatt Barden * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
240a4b0810SKaren Rochford * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25b97d6ca7SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
264a3b0527SAndy Fiddaman * Copyright 2012 Marcel Telka <marcel@telka.sk>
274a3b0527SAndy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
327c478bd9Sstevel@tonic-gate *
337c478bd9Sstevel@tonic-gate * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * Server side handling of RPCSEC_GSS flavor.
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include <sys/systm.h>
417c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
427c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
437c478bd9Sstevel@tonic-gate #include <sys/debug.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/time.h>
467c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
477c478bd9Sstevel@tonic-gate #include <gssapi/gssapi_ext.h>
487c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
497c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_defs.h>
50bfd8310aSGlenn Barry #include <sys/sunddi.h>
51bfd8310aSGlenn Barry #include <sys/atomic.h>
52*02ac56e0SMatt Barden #include <sys/disp.h>
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate #ifdef DEBUG
57b97d6ca7SMilan Jurik extern void prom_printf(const char *, ...);
587c478bd9Sstevel@tonic-gate #endif
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate #ifdef _KERNEL
617c478bd9Sstevel@tonic-gate #define memcmp(a, b, l) bcmp((a), (b), (l))
627c478bd9Sstevel@tonic-gate #endif
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate * Sequence window definitions.
677c478bd9Sstevel@tonic-gate */
687c478bd9Sstevel@tonic-gate #define SEQ_ARR_SIZE 4
697c478bd9Sstevel@tonic-gate #define SEQ_WIN (SEQ_ARR_SIZE*32)
707c478bd9Sstevel@tonic-gate #define SEQ_HI_BIT 0x80000000
717c478bd9Sstevel@tonic-gate #define SEQ_LO_BIT 1
727c478bd9Sstevel@tonic-gate #define DIV_BY_32 5
737c478bd9Sstevel@tonic-gate #define SEQ_MASK 0x1f
747c478bd9Sstevel@tonic-gate #define SEQ_MAX ((unsigned int)0x80000000)
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate /* cache retransmit data */
787c478bd9Sstevel@tonic-gate typedef struct _retrans_entry {
797c478bd9Sstevel@tonic-gate uint32_t xid;
807c478bd9Sstevel@tonic-gate rpc_gss_init_res result;
817c478bd9Sstevel@tonic-gate } retrans_entry;
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate * Server side RPCSEC_GSS context information.
857c478bd9Sstevel@tonic-gate */
867c478bd9Sstevel@tonic-gate typedef struct _svc_rpc_gss_data {
877c478bd9Sstevel@tonic-gate struct _svc_rpc_gss_data *next, *prev;
887c478bd9Sstevel@tonic-gate struct _svc_rpc_gss_data *lru_next, *lru_prev;
897c478bd9Sstevel@tonic-gate bool_t established;
907c478bd9Sstevel@tonic-gate gss_ctx_id_t context;
917c478bd9Sstevel@tonic-gate gss_buffer_desc client_name;
927c478bd9Sstevel@tonic-gate time_t expiration;
937c478bd9Sstevel@tonic-gate uint_t seq_num;
947c478bd9Sstevel@tonic-gate uint_t seq_bits[SEQ_ARR_SIZE];
957c478bd9Sstevel@tonic-gate uint_t key;
967c478bd9Sstevel@tonic-gate OM_uint32 qop;
977c478bd9Sstevel@tonic-gate bool_t done_docallback;
987c478bd9Sstevel@tonic-gate bool_t locked;
997c478bd9Sstevel@tonic-gate rpc_gss_rawcred_t raw_cred;
1007c478bd9Sstevel@tonic-gate rpc_gss_ucred_t u_cred;
1017c478bd9Sstevel@tonic-gate time_t u_cred_set;
1027c478bd9Sstevel@tonic-gate void *cookie;
1037c478bd9Sstevel@tonic-gate gss_cred_id_t deleg;
1047c478bd9Sstevel@tonic-gate kmutex_t clm;
1057c478bd9Sstevel@tonic-gate int ref_cnt;
1067c478bd9Sstevel@tonic-gate time_t last_ref_time;
1077c478bd9Sstevel@tonic-gate bool_t stale;
1087c478bd9Sstevel@tonic-gate retrans_entry *retrans_data;
1097c478bd9Sstevel@tonic-gate } svc_rpc_gss_data;
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate * Data structures used for LRU based context management.
1137c478bd9Sstevel@tonic-gate */
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate #define HASH(key) ((key) % svc_rpc_gss_hashmod)
1177c478bd9Sstevel@tonic-gate /* Size of hash table for svc_rpc_gss_data structures */
1187c478bd9Sstevel@tonic-gate #define GSS_DATA_HASH_SIZE 1024
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate * The following two defines specify a time delta that is used in
1227c478bd9Sstevel@tonic-gate * sweep_clients. When the last_ref_time of a context is older than
1237c478bd9Sstevel@tonic-gate * than the current time minus the delta, i.e, the context has not
1247c478bd9Sstevel@tonic-gate * been referenced in the last delta seconds, we will return the
1257c478bd9Sstevel@tonic-gate * context back to the cache if the ref_cnt is zero. The first delta
1267c478bd9Sstevel@tonic-gate * value will be used when sweep_clients is called from
1277c478bd9Sstevel@tonic-gate * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
1287c478bd9Sstevel@tonic-gate * all entries except those that are currently "active". By active we
1297c478bd9Sstevel@tonic-gate * mean those that have been referenced in the last ACTIVE_DELTA
1307c478bd9Sstevel@tonic-gate * seconds. If sweep_client is not being called from reclaim, then we
1317c478bd9Sstevel@tonic-gate * will reclaim all entries that are "inactive". By inactive we mean
1327c478bd9Sstevel@tonic-gate * those entries that have not been accessed in INACTIVE_DELTA
1337c478bd9Sstevel@tonic-gate * seconds. Note we always assume that ACTIVE_DELTA is less than
1347c478bd9Sstevel@tonic-gate * INACTIVE_DELTA, so that reaping entries from a reclaim operation
1357c478bd9Sstevel@tonic-gate * will necessarily imply reaping all "inactive" entries and then
1367c478bd9Sstevel@tonic-gate * some.
1377c478bd9Sstevel@tonic-gate */
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate * If low on memory reap cache entries that have not been active for
1417c478bd9Sstevel@tonic-gate * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
1427c478bd9Sstevel@tonic-gate */
1437c478bd9Sstevel@tonic-gate #define ACTIVE_DELTA 30*60 /* 30 minutes */
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate * If in sweeping contexts we find contexts with a ref_cnt equal to zero
1477c478bd9Sstevel@tonic-gate * and the context has not been referenced in INACTIVE_DELTA seconds, return
1487c478bd9Sstevel@tonic-gate * the entry to the cache.
1497c478bd9Sstevel@tonic-gate */
1507c478bd9Sstevel@tonic-gate #define INACTIVE_DELTA 8*60*60 /* 8 hours */
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate int svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
1537c478bd9Sstevel@tonic-gate static svc_rpc_gss_data **clients;
1547c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *lru_first, *lru_last;
1557c478bd9Sstevel@tonic-gate static time_t sweep_interval = 60*60;
1567c478bd9Sstevel@tonic-gate static time_t last_swept = 0;
1577c478bd9Sstevel@tonic-gate static int num_gss_contexts = 0;
1587c478bd9Sstevel@tonic-gate static time_t svc_rpcgss_gid_timeout = 60*60*12;
1597c478bd9Sstevel@tonic-gate static kmem_cache_t *svc_data_handle;
1607c478bd9Sstevel@tonic-gate static time_t svc_rpc_gss_active_delta = ACTIVE_DELTA;
1617c478bd9Sstevel@tonic-gate static time_t svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * lock used with context/lru variables
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate static kmutex_t ctx_mutex;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * Data structure to contain cache statistics
1707c478bd9Sstevel@tonic-gate */
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate static struct {
1737c478bd9Sstevel@tonic-gate int64_t total_entries_allocated;
1747c478bd9Sstevel@tonic-gate int64_t no_reclaims;
1757c478bd9Sstevel@tonic-gate int64_t no_returned_by_reclaim;
1767c478bd9Sstevel@tonic-gate } svc_rpc_gss_cache_stats;
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate * lock used with server credential variables list
1817c478bd9Sstevel@tonic-gate *
1827c478bd9Sstevel@tonic-gate * server cred list locking guidelines:
1837c478bd9Sstevel@tonic-gate * - Writer's lock holder has exclusive access to the list
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate static krwlock_t cred_lock;
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate /*
1887c478bd9Sstevel@tonic-gate * server callback list
1897c478bd9Sstevel@tonic-gate */
1907c478bd9Sstevel@tonic-gate typedef struct rpc_gss_cblist_s {
1917c478bd9Sstevel@tonic-gate struct rpc_gss_cblist_s *next;
1927c478bd9Sstevel@tonic-gate rpc_gss_callback_t cb;
1937c478bd9Sstevel@tonic-gate } rpc_gss_cblist_t;
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate static rpc_gss_cblist_t *rpc_gss_cblist = NULL;
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate * lock used with callback variables
1997c478bd9Sstevel@tonic-gate */
2007c478bd9Sstevel@tonic-gate static kmutex_t cb_mutex;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * forward declarations
2047c478bd9Sstevel@tonic-gate */
2057c478bd9Sstevel@tonic-gate static bool_t svc_rpc_gss_wrap();
2067c478bd9Sstevel@tonic-gate static bool_t svc_rpc_gss_unwrap();
2077c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *create_client();
2087c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *get_client();
2097c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *find_client();
2107c478bd9Sstevel@tonic-gate static void destroy_client();
2117c478bd9Sstevel@tonic-gate static void sweep_clients(bool_t);
2127c478bd9Sstevel@tonic-gate static void insert_client();
2137c478bd9Sstevel@tonic-gate static bool_t check_verf(struct rpc_msg *, gss_ctx_id_t,
2147c478bd9Sstevel@tonic-gate int *, uid_t);
2157c478bd9Sstevel@tonic-gate static bool_t set_response_verf();
2167c478bd9Sstevel@tonic-gate static void retrans_add(svc_rpc_gss_data *, uint32_t,
2177c478bd9Sstevel@tonic-gate rpc_gss_init_res *);
2187c478bd9Sstevel@tonic-gate static void retrans_del(svc_rpc_gss_data *);
2197c478bd9Sstevel@tonic-gate static bool_t transfer_sec_context(svc_rpc_gss_data *);
2207c478bd9Sstevel@tonic-gate static void common_client_data_free(svc_rpc_gss_data *);
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate * server side wrap/unwrap routines
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate struct svc_auth_ops svc_rpc_gss_ops = {
2267c478bd9Sstevel@tonic-gate svc_rpc_gss_wrap,
2277c478bd9Sstevel@tonic-gate svc_rpc_gss_unwrap,
2287c478bd9Sstevel@tonic-gate };
2297c478bd9Sstevel@tonic-gate
230bfd8310aSGlenn Barry /* taskq(9F) */
231bfd8310aSGlenn Barry typedef struct svcrpcsec_gss_taskq_arg {
232bfd8310aSGlenn Barry SVCXPRT *rq_xprt;
233bfd8310aSGlenn Barry rpc_gss_init_arg *rpc_call_arg;
234bfd8310aSGlenn Barry struct rpc_msg *msg;
235bfd8310aSGlenn Barry svc_rpc_gss_data *client_data;
236bfd8310aSGlenn Barry uint_t cr_version;
237bfd8310aSGlenn Barry rpc_gss_service_t cr_service;
238bfd8310aSGlenn Barry } svcrpcsec_gss_taskq_arg_t;
239bfd8310aSGlenn Barry
240bfd8310aSGlenn Barry /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
241bfd8310aSGlenn Barry int rpcsec_gss_init_taskq_nthreads = 1;
242bfd8310aSGlenn Barry
243bfd8310aSGlenn Barry extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
244bfd8310aSGlenn Barry extern void rpc_msg_free(struct rpc_msg **, int);
245bfd8310aSGlenn Barry
246bfd8310aSGlenn Barry /*
247bfd8310aSGlenn Barry * from svc_clts.c:
248bfd8310aSGlenn Barry * Transport private data.
249bfd8310aSGlenn Barry * Kept in xprt->xp_p2buf.
250bfd8310aSGlenn Barry */
251bfd8310aSGlenn Barry struct udp_data {
252bfd8310aSGlenn Barry mblk_t *ud_resp; /* buffer for response */
253bfd8310aSGlenn Barry mblk_t *ud_inmp; /* mblk chain of request */
254bfd8310aSGlenn Barry };
2557c478bd9Sstevel@tonic-gate
256*02ac56e0SMatt Barden static zone_key_t svc_gss_zone_key;
257*02ac56e0SMatt Barden static uint_t svc_gss_tsd_key;
258*02ac56e0SMatt Barden
259*02ac56e0SMatt Barden typedef struct svc_gss_zsd {
260*02ac56e0SMatt Barden zoneid_t sgz_zoneid;
261*02ac56e0SMatt Barden kmutex_t sgz_lock;
262*02ac56e0SMatt Barden taskq_t *sgz_init_taskq;
263*02ac56e0SMatt Barden } svc_gss_zsd_t;
264*02ac56e0SMatt Barden
265*02ac56e0SMatt Barden static taskq_t *
svc_gss_create_taskq(zone_t * zone)266*02ac56e0SMatt Barden svc_gss_create_taskq(zone_t *zone)
267*02ac56e0SMatt Barden {
268*02ac56e0SMatt Barden taskq_t *tq;
269*02ac56e0SMatt Barden
270*02ac56e0SMatt Barden if (zone == NULL) {
271*02ac56e0SMatt Barden cmn_err(CE_NOTE, "%s: couldn't find zone", __func__);
272*02ac56e0SMatt Barden return (NULL);
273*02ac56e0SMatt Barden }
274*02ac56e0SMatt Barden
275*02ac56e0SMatt Barden /* Like ddi_taskq_create(), but for zones, just for now */
276*02ac56e0SMatt Barden tq = taskq_create_proc("rpcsec_gss_init_taskq",
277*02ac56e0SMatt Barden rpcsec_gss_init_taskq_nthreads, minclsyspri,
278*02ac56e0SMatt Barden rpcsec_gss_init_taskq_nthreads, INT_MAX, zone->zone_zsched,
279*02ac56e0SMatt Barden TASKQ_PREPOPULATE);
280*02ac56e0SMatt Barden
281*02ac56e0SMatt Barden if (tq == NULL)
282*02ac56e0SMatt Barden cmn_err(CE_NOTE, "%s: taskq_create_proc failed", __func__);
283*02ac56e0SMatt Barden
284*02ac56e0SMatt Barden return (tq);
285*02ac56e0SMatt Barden }
286*02ac56e0SMatt Barden
287*02ac56e0SMatt Barden static void *
svc_gss_zone_init(zoneid_t zoneid)288*02ac56e0SMatt Barden svc_gss_zone_init(zoneid_t zoneid)
289*02ac56e0SMatt Barden {
290*02ac56e0SMatt Barden svc_gss_zsd_t *zsd;
291*02ac56e0SMatt Barden zone_t *zone = curzone;
292*02ac56e0SMatt Barden
293*02ac56e0SMatt Barden zsd = kmem_alloc(sizeof (*zsd), KM_SLEEP);
294*02ac56e0SMatt Barden mutex_init(&zsd->sgz_lock, NULL, MUTEX_DEFAULT, NULL);
295*02ac56e0SMatt Barden zsd->sgz_zoneid = zoneid;
296*02ac56e0SMatt Barden
297*02ac56e0SMatt Barden if (zone->zone_id != zoneid)
298*02ac56e0SMatt Barden zone = zone_find_by_id_nolock(zoneid);
299*02ac56e0SMatt Barden
300*02ac56e0SMatt Barden zsd->sgz_init_taskq = svc_gss_create_taskq(zone);
301*02ac56e0SMatt Barden return (zsd);
302*02ac56e0SMatt Barden }
303*02ac56e0SMatt Barden
304*02ac56e0SMatt Barden /*
305*02ac56e0SMatt Barden * taskq_destroy() wakes all taskq threads and tells them to exit.
306*02ac56e0SMatt Barden * It then cv_wait()'s for all of them to finish exiting.
307*02ac56e0SMatt Barden * cv_wait() calls resume(), which accesses the target's process.
308*02ac56e0SMatt Barden * That may be one of our taskq threads, which are attached to zone_zsched.
309*02ac56e0SMatt Barden *
310*02ac56e0SMatt Barden * If we do taskq_destroy() in the zsd_destroy callback, then zone_zsched
311*02ac56e0SMatt Barden * will have exited and been destroyed before it runs, and we can panic
312*02ac56e0SMatt Barden * in resume(). Our taskq threads are not accounted for in either
313*02ac56e0SMatt Barden * zone_ntasks or zone_kthreads, which means zsched does not wait for
314*02ac56e0SMatt Barden * taskq threads attached to it to complete before exiting.
315*02ac56e0SMatt Barden *
316*02ac56e0SMatt Barden * We therefore need to do this at shutdown time. At the point where
317*02ac56e0SMatt Barden * the zsd_shutdown callback is invoked, all other zone tasks (processes)
318*02ac56e0SMatt Barden * have exited, but zone_kthreads and other taskqs hanging off zsched have not.
319*02ac56e0SMatt Barden *
320*02ac56e0SMatt Barden * We need to be careful not to allow RPC services to be ran from
321*02ac56e0SMatt Barden * zsched-attached taskqs or zone_kthreads.
322*02ac56e0SMatt Barden */
323*02ac56e0SMatt Barden static void
svc_gss_zone_shutdown(zoneid_t zoneid,void * arg)324*02ac56e0SMatt Barden svc_gss_zone_shutdown(zoneid_t zoneid, void *arg)
325*02ac56e0SMatt Barden {
326*02ac56e0SMatt Barden svc_gss_zsd_t *zsd = arg;
327*02ac56e0SMatt Barden
328*02ac56e0SMatt Barden /* All non-zsched-hung threads should be finished. */
329*02ac56e0SMatt Barden mutex_enter(&zsd->sgz_lock);
330*02ac56e0SMatt Barden if (zsd->sgz_init_taskq != NULL) {
331*02ac56e0SMatt Barden taskq_destroy(zsd->sgz_init_taskq);
332*02ac56e0SMatt Barden zsd->sgz_init_taskq = NULL;
333*02ac56e0SMatt Barden }
334*02ac56e0SMatt Barden mutex_exit(&zsd->sgz_lock);
335*02ac56e0SMatt Barden }
336*02ac56e0SMatt Barden
337*02ac56e0SMatt Barden static void
svc_gss_zone_fini(zoneid_t zoneid,void * arg)338*02ac56e0SMatt Barden svc_gss_zone_fini(zoneid_t zoneid, void *arg)
339*02ac56e0SMatt Barden {
340*02ac56e0SMatt Barden svc_gss_zsd_t *zsd = arg;
341*02ac56e0SMatt Barden
342*02ac56e0SMatt Barden mutex_destroy(&zsd->sgz_lock);
343*02ac56e0SMatt Barden kmem_free(zsd, sizeof (*zsd));
344*02ac56e0SMatt Barden }
345*02ac56e0SMatt Barden
346*02ac56e0SMatt Barden static svc_gss_zsd_t *
svc_gss_get_zsd(void)347*02ac56e0SMatt Barden svc_gss_get_zsd(void)
348*02ac56e0SMatt Barden {
349*02ac56e0SMatt Barden svc_gss_zsd_t *zsd;
350*02ac56e0SMatt Barden
351*02ac56e0SMatt Barden zsd = tsd_get(svc_gss_tsd_key);
352*02ac56e0SMatt Barden if (zsd == NULL) {
353*02ac56e0SMatt Barden zsd = zone_getspecific(svc_gss_zone_key, curzone);
354*02ac56e0SMatt Barden (void) tsd_set(svc_gss_tsd_key, zsd);
355*02ac56e0SMatt Barden }
356*02ac56e0SMatt Barden
357*02ac56e0SMatt Barden return (zsd);
358*02ac56e0SMatt Barden }
359*02ac56e0SMatt Barden
3607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3617c478bd9Sstevel@tonic-gate static int
svc_gss_data_create(void * buf,void * pdata,int kmflag)3627c478bd9Sstevel@tonic-gate svc_gss_data_create(void *buf, void *pdata, int kmflag)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate return (0);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3727c478bd9Sstevel@tonic-gate static void
svc_gss_data_destroy(void * buf,void * pdata)3737c478bd9Sstevel@tonic-gate svc_gss_data_destroy(void *buf, void *pdata)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate mutex_destroy(&client_data->clm);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3827c478bd9Sstevel@tonic-gate static void
svc_gss_data_reclaim(void * pdata)3837c478bd9Sstevel@tonic-gate svc_gss_data_reclaim(void *pdata)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate mutex_enter(&ctx_mutex);
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate svc_rpc_gss_cache_stats.no_reclaims++;
3887c478bd9Sstevel@tonic-gate sweep_clients(TRUE);
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate mutex_exit(&ctx_mutex);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate * Init stuff on the server side.
3957c478bd9Sstevel@tonic-gate */
3967c478bd9Sstevel@tonic-gate void
svc_gss_init()3977c478bd9Sstevel@tonic-gate svc_gss_init()
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
4007c478bd9Sstevel@tonic-gate mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
4017c478bd9Sstevel@tonic-gate rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
4027c478bd9Sstevel@tonic-gate clients = (svc_rpc_gss_data **)
403bfd8310aSGlenn Barry kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
404bfd8310aSGlenn Barry KM_SLEEP);
4057c478bd9Sstevel@tonic-gate svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
406bfd8310aSGlenn Barry sizeof (svc_rpc_gss_data), 0,
407bfd8310aSGlenn Barry svc_gss_data_create,
408bfd8310aSGlenn Barry svc_gss_data_destroy,
409bfd8310aSGlenn Barry svc_gss_data_reclaim,
410bfd8310aSGlenn Barry NULL, NULL, 0);
411bfd8310aSGlenn Barry
412*02ac56e0SMatt Barden tsd_create(&svc_gss_tsd_key, NULL);
413*02ac56e0SMatt Barden zone_key_create(&svc_gss_zone_key, svc_gss_zone_init,
414*02ac56e0SMatt Barden svc_gss_zone_shutdown, svc_gss_zone_fini);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate * Destroy structures allocated in svc_gss_init().
4197c478bd9Sstevel@tonic-gate * This routine is called by _init() if mod_install() failed.
4207c478bd9Sstevel@tonic-gate */
4217c478bd9Sstevel@tonic-gate void
svc_gss_fini()4227c478bd9Sstevel@tonic-gate svc_gss_fini()
4237c478bd9Sstevel@tonic-gate {
424*02ac56e0SMatt Barden if (zone_key_delete(svc_gss_zone_key) != 0)
425*02ac56e0SMatt Barden cmn_err(CE_WARN, "%s: failed to delete zone key", __func__);
426*02ac56e0SMatt Barden tsd_destroy(&svc_gss_tsd_key);
4277c478bd9Sstevel@tonic-gate mutex_destroy(&cb_mutex);
4287c478bd9Sstevel@tonic-gate mutex_destroy(&ctx_mutex);
4297c478bd9Sstevel@tonic-gate rw_destroy(&cred_lock);
4307c478bd9Sstevel@tonic-gate kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
4317c478bd9Sstevel@tonic-gate kmem_cache_destroy(svc_data_handle);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate * Cleanup routine for destroying context, called after service
4367c478bd9Sstevel@tonic-gate * procedure is executed. Actually we just decrement the reference count
4377c478bd9Sstevel@tonic-gate * associated with this context. If the reference count is zero and the
4387c478bd9Sstevel@tonic-gate * context is marked as stale, we would then destroy the context. Additionally,
4397c478bd9Sstevel@tonic-gate * we check if its been longer than sweep_interval since the last sweep_clients
4407c478bd9Sstevel@tonic-gate * was run, and if so run sweep_clients to free all stale contexts with zero
4417c478bd9Sstevel@tonic-gate * reference counts or contexts that are old. (Haven't been access in
4427c478bd9Sstevel@tonic-gate * svc_rpc_inactive_delta seconds).
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate void
rpc_gss_cleanup(SVCXPRT * clone_xprt)4457c478bd9Sstevel@tonic-gate rpc_gss_cleanup(SVCXPRT *clone_xprt)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl;
4487c478bd9Sstevel@tonic-gate SVCAUTH *svcauth;
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate * First check if current context needs to be cleaned up.
4527c478bd9Sstevel@tonic-gate * There might be other threads stale this client data
4537c478bd9Sstevel@tonic-gate * in between.
4547c478bd9Sstevel@tonic-gate */
4557c478bd9Sstevel@tonic-gate svcauth = &clone_xprt->xp_auth;
4567c478bd9Sstevel@tonic-gate mutex_enter(&ctx_mutex);
4577c478bd9Sstevel@tonic-gate if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
4587c478bd9Sstevel@tonic-gate mutex_enter(&cl->clm);
4597c478bd9Sstevel@tonic-gate ASSERT(cl->ref_cnt > 0);
4607c478bd9Sstevel@tonic-gate if (--cl->ref_cnt == 0 && cl->stale) {
4617c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
4627c478bd9Sstevel@tonic-gate destroy_client(cl);
4637c478bd9Sstevel@tonic-gate svcauth->svc_ah_private = NULL;
4647c478bd9Sstevel@tonic-gate } else
4657c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate * Check for other expired contexts.
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate if ((gethrestime_sec() - last_swept) > sweep_interval)
4727c478bd9Sstevel@tonic-gate sweep_clients(FALSE);
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate mutex_exit(&ctx_mutex);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate * Shift the array arr of length arrlen right by nbits bits.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate static void
shift_bits(uint_t * arr,int arrlen,int nbits)4814a3b0527SAndy Fiddaman shift_bits(uint_t *arr, int arrlen, int nbits)
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate int i, j;
4847c478bd9Sstevel@tonic-gate uint_t lo, hi;
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /*
4877c478bd9Sstevel@tonic-gate * If the number of bits to be shifted exceeds SEQ_WIN, just
4887c478bd9Sstevel@tonic-gate * zero out the array.
4897c478bd9Sstevel@tonic-gate */
4907c478bd9Sstevel@tonic-gate if (nbits < SEQ_WIN) {
4917c478bd9Sstevel@tonic-gate for (i = 0; i < nbits; i++) {
4927c478bd9Sstevel@tonic-gate hi = 0;
4937c478bd9Sstevel@tonic-gate for (j = 0; j < arrlen; j++) {
4947c478bd9Sstevel@tonic-gate lo = arr[j] & SEQ_LO_BIT;
4957c478bd9Sstevel@tonic-gate arr[j] >>= 1;
4967c478bd9Sstevel@tonic-gate if (hi)
4977c478bd9Sstevel@tonic-gate arr[j] |= SEQ_HI_BIT;
4987c478bd9Sstevel@tonic-gate hi = lo;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate }
5017c478bd9Sstevel@tonic-gate } else {
5027c478bd9Sstevel@tonic-gate for (j = 0; j < arrlen; j++)
5037c478bd9Sstevel@tonic-gate arr[j] = 0;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate * Check that the received sequence number seq_num is valid.
5097c478bd9Sstevel@tonic-gate */
5107c478bd9Sstevel@tonic-gate static bool_t
check_seq(svc_rpc_gss_data * cl,uint_t seq_num,bool_t * kill_context)5114a3b0527SAndy Fiddaman check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate int i, j;
5147c478bd9Sstevel@tonic-gate uint_t bit;
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate * If it exceeds the maximum, kill context.
5187c478bd9Sstevel@tonic-gate */
5197c478bd9Sstevel@tonic-gate if (seq_num >= SEQ_MAX) {
5207c478bd9Sstevel@tonic-gate *kill_context = TRUE;
5217c478bd9Sstevel@tonic-gate RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
5227c478bd9Sstevel@tonic-gate return (FALSE);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * If greater than the last seen sequence number, just shift
5277c478bd9Sstevel@tonic-gate * the sequence window so that it starts at the new sequence
5287c478bd9Sstevel@tonic-gate * number and extends downwards by SEQ_WIN.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate if (seq_num > cl->seq_num) {
5317c478bd9Sstevel@tonic-gate (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
5324a3b0527SAndy Fiddaman (int)(seq_num - cl->seq_num));
5337c478bd9Sstevel@tonic-gate cl->seq_bits[0] |= SEQ_HI_BIT;
5347c478bd9Sstevel@tonic-gate cl->seq_num = seq_num;
5357c478bd9Sstevel@tonic-gate return (TRUE);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate * If it is outside the sequence window, return failure.
5407c478bd9Sstevel@tonic-gate */
5417c478bd9Sstevel@tonic-gate i = cl->seq_num - seq_num;
5427c478bd9Sstevel@tonic-gate if (i >= SEQ_WIN) {
5437c478bd9Sstevel@tonic-gate RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
5447c478bd9Sstevel@tonic-gate return (FALSE);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate * If within sequence window, set the bit corresponding to it
5497c478bd9Sstevel@tonic-gate * if not already seen; if already seen, return failure.
5507c478bd9Sstevel@tonic-gate */
5517c478bd9Sstevel@tonic-gate j = SEQ_MASK - (i & SEQ_MASK);
5527c478bd9Sstevel@tonic-gate bit = j > 0 ? (1 << j) : 1;
5537c478bd9Sstevel@tonic-gate i >>= DIV_BY_32;
5547c478bd9Sstevel@tonic-gate if (cl->seq_bits[i] & bit) {
5557c478bd9Sstevel@tonic-gate RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
5567c478bd9Sstevel@tonic-gate return (FALSE);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate cl->seq_bits[i] |= bit;
5597c478bd9Sstevel@tonic-gate return (TRUE);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate * Set server callback.
5647c478bd9Sstevel@tonic-gate */
5657c478bd9Sstevel@tonic-gate bool_t
rpc_gss_set_callback(rpc_gss_callback_t * cb)5664a3b0527SAndy Fiddaman rpc_gss_set_callback(rpc_gss_callback_t *cb)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate rpc_gss_cblist_t *cbl, *tmp;
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate if (cb->callback == NULL) {
5717c478bd9Sstevel@tonic-gate RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
5727c478bd9Sstevel@tonic-gate return (FALSE);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /* check if there is already an entry in the rpc_gss_cblist. */
5767c478bd9Sstevel@tonic-gate mutex_enter(&cb_mutex);
5777c478bd9Sstevel@tonic-gate if (rpc_gss_cblist) {
5787c478bd9Sstevel@tonic-gate for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
5797c478bd9Sstevel@tonic-gate if ((tmp->cb.callback == cb->callback) &&
5807c478bd9Sstevel@tonic-gate (tmp->cb.version == cb->version) &&
5817c478bd9Sstevel@tonic-gate (tmp->cb.program == cb->program)) {
5827c478bd9Sstevel@tonic-gate mutex_exit(&cb_mutex);
5837c478bd9Sstevel@tonic-gate return (TRUE);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate /* Not in rpc_gss_cblist. Create a new entry. */
5897c478bd9Sstevel@tonic-gate if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
5907c478bd9Sstevel@tonic-gate == NULL) {
5917c478bd9Sstevel@tonic-gate mutex_exit(&cb_mutex);
5927c478bd9Sstevel@tonic-gate return (FALSE);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate cbl->cb = *cb;
5957c478bd9Sstevel@tonic-gate cbl->next = rpc_gss_cblist;
5967c478bd9Sstevel@tonic-gate rpc_gss_cblist = cbl;
5977c478bd9Sstevel@tonic-gate mutex_exit(&cb_mutex);
5987c478bd9Sstevel@tonic-gate return (TRUE);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate * Locate callback (if specified) and call server. Release any
6037c478bd9Sstevel@tonic-gate * delegated credentials unless passed to server and the server
6047c478bd9Sstevel@tonic-gate * accepts the context. If a callback is not specified, accept
6057c478bd9Sstevel@tonic-gate * the incoming context.
6067c478bd9Sstevel@tonic-gate */
6077c478bd9Sstevel@tonic-gate static bool_t
do_callback(struct svc_req * req,svc_rpc_gss_data * client_data)6084a3b0527SAndy Fiddaman do_callback(struct svc_req *req, svc_rpc_gss_data *client_data)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate rpc_gss_cblist_t *cbl;
6117c478bd9Sstevel@tonic-gate bool_t ret = TRUE, found = FALSE;
6127c478bd9Sstevel@tonic-gate rpc_gss_lock_t lock;
6137c478bd9Sstevel@tonic-gate OM_uint32 minor;
6147c478bd9Sstevel@tonic-gate mutex_enter(&cb_mutex);
6157c478bd9Sstevel@tonic-gate for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
6167c478bd9Sstevel@tonic-gate if (req->rq_prog != cbl->cb.program ||
6174a3b0527SAndy Fiddaman req->rq_vers != cbl->cb.version)
6187c478bd9Sstevel@tonic-gate continue;
6197c478bd9Sstevel@tonic-gate found = TRUE;
6207c478bd9Sstevel@tonic-gate lock.locked = FALSE;
6217c478bd9Sstevel@tonic-gate lock.raw_cred = &client_data->raw_cred;
6227c478bd9Sstevel@tonic-gate ret = (*cbl->cb.callback)(req, client_data->deleg,
6234a3b0527SAndy Fiddaman client_data->context, &lock, &client_data->cookie);
6247c478bd9Sstevel@tonic-gate req->rq_xprt->xp_cookie = client_data->cookie;
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate if (ret) {
6277c478bd9Sstevel@tonic-gate client_data->locked = lock.locked;
6287c478bd9Sstevel@tonic-gate client_data->deleg = GSS_C_NO_CREDENTIAL;
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate break;
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate if (!found) {
6337c478bd9Sstevel@tonic-gate if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
6347c478bd9Sstevel@tonic-gate (void) kgss_release_cred(&minor, &client_data->deleg,
6354a3b0527SAndy Fiddaman crgetuid(CRED()));
6367c478bd9Sstevel@tonic-gate client_data->deleg = GSS_C_NO_CREDENTIAL;
6377c478bd9Sstevel@tonic-gate }
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate mutex_exit(&cb_mutex);
6407c478bd9Sstevel@tonic-gate return (ret);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * Get caller credentials.
6457c478bd9Sstevel@tonic-gate */
6467c478bd9Sstevel@tonic-gate bool_t
rpc_gss_getcred(struct svc_req * req,rpc_gss_rawcred_t ** rcred,rpc_gss_ucred_t ** ucred,void ** cookie)6474a3b0527SAndy Fiddaman rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
6484a3b0527SAndy Fiddaman rpc_gss_ucred_t **ucred, void **cookie)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate SVCAUTH *svcauth;
6517c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data;
6527c478bd9Sstevel@tonic-gate int gssstat, gidlen;
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate svcauth = &req->rq_xprt->xp_auth;
6557c478bd9Sstevel@tonic-gate client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate mutex_enter(&client_data->clm);
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate if (rcred != NULL) {
6607c478bd9Sstevel@tonic-gate svcauth->raw_cred = client_data->raw_cred;
6617c478bd9Sstevel@tonic-gate *rcred = &svcauth->raw_cred;
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate if (ucred != NULL) {
6647c478bd9Sstevel@tonic-gate *ucred = &client_data->u_cred;
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate if (client_data->u_cred_set == 0 ||
6677c478bd9Sstevel@tonic-gate client_data->u_cred_set < gethrestime_sec()) {
6684a3b0527SAndy Fiddaman if (client_data->u_cred_set == 0) {
6694a3b0527SAndy Fiddaman if ((gssstat = kgsscred_expname_to_unix_cred(
6704a3b0527SAndy Fiddaman &client_data->client_name,
6714a3b0527SAndy Fiddaman &client_data->u_cred.uid,
6724a3b0527SAndy Fiddaman &client_data->u_cred.gid,
6734a3b0527SAndy Fiddaman &client_data->u_cred.gidlist,
6744a3b0527SAndy Fiddaman &gidlen, crgetuid(CRED())))
6754a3b0527SAndy Fiddaman != GSS_S_COMPLETE) {
6764a3b0527SAndy Fiddaman RPCGSS_LOG(1, "rpc_gss_getcred: "
6774a3b0527SAndy Fiddaman "kgsscred_expname_to_unix_cred "
6784a3b0527SAndy Fiddaman "failed %x\n", gssstat);
6794a3b0527SAndy Fiddaman *ucred = NULL;
6804a3b0527SAndy Fiddaman } else {
6814a3b0527SAndy Fiddaman client_data->u_cred.gidlen =
6824a3b0527SAndy Fiddaman (short)gidlen;
6834a3b0527SAndy Fiddaman client_data->u_cred_set =
6844a3b0527SAndy Fiddaman gethrestime_sec() +
6854a3b0527SAndy Fiddaman svc_rpcgss_gid_timeout;
6864a3b0527SAndy Fiddaman }
6874a3b0527SAndy Fiddaman } else if (client_data->u_cred_set
6884a3b0527SAndy Fiddaman < gethrestime_sec()) {
6894a3b0527SAndy Fiddaman if ((gssstat = kgss_get_group_info(
6904a3b0527SAndy Fiddaman client_data->u_cred.uid,
6914a3b0527SAndy Fiddaman &client_data->u_cred.gid,
6924a3b0527SAndy Fiddaman &client_data->u_cred.gidlist,
6934a3b0527SAndy Fiddaman &gidlen, crgetuid(CRED())))
6944a3b0527SAndy Fiddaman != GSS_S_COMPLETE) {
6954a3b0527SAndy Fiddaman RPCGSS_LOG(1, "rpc_gss_getcred: "
6964a3b0527SAndy Fiddaman "kgss_get_group_info failed %x\n",
6974a3b0527SAndy Fiddaman gssstat);
6984a3b0527SAndy Fiddaman *ucred = NULL;
6994a3b0527SAndy Fiddaman } else {
7004a3b0527SAndy Fiddaman client_data->u_cred.gidlen =
7014a3b0527SAndy Fiddaman (short)gidlen;
7024a3b0527SAndy Fiddaman client_data->u_cred_set =
7034a3b0527SAndy Fiddaman gethrestime_sec() +
7044a3b0527SAndy Fiddaman svc_rpcgss_gid_timeout;
7054a3b0527SAndy Fiddaman }
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate if (cookie != NULL)
7117c478bd9Sstevel@tonic-gate *cookie = client_data->cookie;
7127c478bd9Sstevel@tonic-gate req->rq_xprt->xp_cookie = client_data->cookie;
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate mutex_exit(&client_data->clm);
7157c478bd9Sstevel@tonic-gate
7167c478bd9Sstevel@tonic-gate return (TRUE);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate * Transfer the context data from the user land to the kernel.
7217c478bd9Sstevel@tonic-gate */
transfer_sec_context(svc_rpc_gss_data * client_data)7227c478bd9Sstevel@tonic-gate bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate gss_buffer_desc process_token;
7257c478bd9Sstevel@tonic-gate OM_uint32 gssstat, minor;
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * Call kgss_export_sec_context
7297c478bd9Sstevel@tonic-gate * if an error is returned log a message
7307c478bd9Sstevel@tonic-gate * go to error handling
7317c478bd9Sstevel@tonic-gate * Otherwise call kgss_import_sec_context to
7327c478bd9Sstevel@tonic-gate * convert the token into a context
7337c478bd9Sstevel@tonic-gate */
7347c478bd9Sstevel@tonic-gate gssstat = kgss_export_sec_context(&minor, client_data->context,
7357c478bd9Sstevel@tonic-gate &process_token);
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate * if export_sec_context returns an error we delete the
7387c478bd9Sstevel@tonic-gate * context just to be safe.
7397c478bd9Sstevel@tonic-gate */
7407c478bd9Sstevel@tonic-gate if (gssstat == GSS_S_NAME_NOT_MN) {
7417c478bd9Sstevel@tonic-gate RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
7427c478bd9Sstevel@tonic-gate "Kernel mod unavailable\n");
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate } else if (gssstat != GSS_S_COMPLETE) {
7457c478bd9Sstevel@tonic-gate RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed "
7467c478bd9Sstevel@tonic-gate " gssstat = 0x%x\n", gssstat);
7477c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &process_token);
7487c478bd9Sstevel@tonic-gate (void) kgss_delete_sec_context(&minor, &client_data->context,
7497c478bd9Sstevel@tonic-gate NULL);
7507c478bd9Sstevel@tonic-gate return (FALSE);
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate } else if (process_token.length == 0) {
7537c478bd9Sstevel@tonic-gate RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
7547c478bd9Sstevel@tonic-gate "for export_sec_context, but "
7557c478bd9Sstevel@tonic-gate "gsstat == GSS_S_COMPLETE\n");
7567c478bd9Sstevel@tonic-gate (void) kgss_delete_sec_context(&minor, &client_data->context,
7577c478bd9Sstevel@tonic-gate NULL);
7587c478bd9Sstevel@tonic-gate return (FALSE);
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate } else {
7617c478bd9Sstevel@tonic-gate gssstat = kgss_import_sec_context(&minor, &process_token,
7627c478bd9Sstevel@tonic-gate client_data->context);
7637c478bd9Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) {
7647c478bd9Sstevel@tonic-gate RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
7657c478bd9Sstevel@tonic-gate " failed gssstat = 0x%x\n", gssstat);
7667c478bd9Sstevel@tonic-gate (void) kgss_delete_sec_context(&minor,
7677c478bd9Sstevel@tonic-gate &client_data->context, NULL);
7687c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &process_token);
7697c478bd9Sstevel@tonic-gate return (FALSE);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
7737c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &process_token);
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate return (TRUE);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate
7797c478bd9Sstevel@tonic-gate /*
780bfd8310aSGlenn Barry * do_gss_accept is called from a taskq and does all the work for a
781bfd8310aSGlenn Barry * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
7827c478bd9Sstevel@tonic-gate */
783bfd8310aSGlenn Barry static enum auth_stat
do_gss_accept(SVCXPRT * xprt,rpc_gss_init_arg * call_arg,struct rpc_msg * msg,svc_rpc_gss_data * client_data,uint_t cr_version,rpc_gss_service_t cr_service)784bfd8310aSGlenn Barry do_gss_accept(
785bfd8310aSGlenn Barry SVCXPRT *xprt,
786bfd8310aSGlenn Barry rpc_gss_init_arg *call_arg,
787bfd8310aSGlenn Barry struct rpc_msg *msg,
788bfd8310aSGlenn Barry svc_rpc_gss_data *client_data,
789bfd8310aSGlenn Barry uint_t cr_version,
790bfd8310aSGlenn Barry rpc_gss_service_t cr_service)
7917c478bd9Sstevel@tonic-gate {
792bfd8310aSGlenn Barry rpc_gss_init_res call_res;
7937c478bd9Sstevel@tonic-gate gss_buffer_desc output_token;
7947c478bd9Sstevel@tonic-gate OM_uint32 gssstat, minor, minor_stat, time_rec;
7957c478bd9Sstevel@tonic-gate int ret_flags, ret;
7964a3b0527SAndy Fiddaman gss_OID mech_type = GSS_C_NULL_OID;
7977c478bd9Sstevel@tonic-gate int free_mech_type = 1;
798bfd8310aSGlenn Barry struct svc_req r, *rqst;
7997c478bd9Sstevel@tonic-gate
800bfd8310aSGlenn Barry rqst = &r;
801bfd8310aSGlenn Barry rqst->rq_xprt = xprt;
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate /*
804bfd8310aSGlenn Barry * Initialize output_token.
8057c478bd9Sstevel@tonic-gate */
806bfd8310aSGlenn Barry output_token.length = 0;
807bfd8310aSGlenn Barry output_token.value = NULL;
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate bzero((char *)&call_res, sizeof (call_res));
8107c478bd9Sstevel@tonic-gate
811bfd8310aSGlenn Barry mutex_enter(&client_data->clm);
812bfd8310aSGlenn Barry if (client_data->stale) {
813bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
814bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
815bfd8310aSGlenn Barry goto error2;
816bfd8310aSGlenn Barry }
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate /*
819bfd8310aSGlenn Barry * Any response we send will use ctx_handle, so set it now;
820bfd8310aSGlenn Barry * also set seq_window since this won't change.
8217c478bd9Sstevel@tonic-gate */
822bfd8310aSGlenn Barry call_res.ctx_handle.length = sizeof (client_data->key);
823bfd8310aSGlenn Barry call_res.ctx_handle.value = (char *)&client_data->key;
824bfd8310aSGlenn Barry call_res.seq_window = SEQ_WIN;
8257c478bd9Sstevel@tonic-gate
826bfd8310aSGlenn Barry gssstat = GSS_S_FAILURE;
827bfd8310aSGlenn Barry minor = 0;
828bfd8310aSGlenn Barry minor_stat = 0;
829bfd8310aSGlenn Barry rw_enter(&cred_lock, RW_READER);
830bfd8310aSGlenn Barry
831bfd8310aSGlenn Barry if (client_data->client_name.length) {
832bfd8310aSGlenn Barry (void) gss_release_buffer(&minor,
833bfd8310aSGlenn Barry &client_data->client_name);
8347c478bd9Sstevel@tonic-gate }
835bfd8310aSGlenn Barry gssstat = kgss_accept_sec_context(&minor_stat,
836bfd8310aSGlenn Barry &client_data->context,
837bfd8310aSGlenn Barry GSS_C_NO_CREDENTIAL,
838bfd8310aSGlenn Barry call_arg,
839bfd8310aSGlenn Barry GSS_C_NO_CHANNEL_BINDINGS,
840bfd8310aSGlenn Barry &client_data->client_name,
841bfd8310aSGlenn Barry &mech_type,
842bfd8310aSGlenn Barry &output_token,
843bfd8310aSGlenn Barry &ret_flags,
844bfd8310aSGlenn Barry &time_rec,
845bfd8310aSGlenn Barry NULL, /* don't need a delegated cred back */
846bfd8310aSGlenn Barry crgetuid(CRED()));
847bfd8310aSGlenn Barry
848bfd8310aSGlenn Barry RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
849bfd8310aSGlenn Barry
850bfd8310aSGlenn Barry if (gssstat == GSS_S_COMPLETE) {
851bfd8310aSGlenn Barry /*
852bfd8310aSGlenn Barry * Set the raw and unix credentials at this
853bfd8310aSGlenn Barry * point. This saves a lot of computation
854bfd8310aSGlenn Barry * later when credentials are retrieved.
855bfd8310aSGlenn Barry */
856bfd8310aSGlenn Barry client_data->raw_cred.version = cr_version;
857bfd8310aSGlenn Barry client_data->raw_cred.service = cr_service;
8587c478bd9Sstevel@tonic-gate
859bfd8310aSGlenn Barry if (client_data->raw_cred.mechanism) {
860bfd8310aSGlenn Barry kgss_free_oid(client_data->raw_cred.mechanism);
861bfd8310aSGlenn Barry client_data->raw_cred.mechanism = NULL;
862bfd8310aSGlenn Barry }
863bfd8310aSGlenn Barry client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
864bfd8310aSGlenn Barry /*
865bfd8310aSGlenn Barry * client_data is now responsible for freeing
866bfd8310aSGlenn Barry * the data of 'mech_type'.
867bfd8310aSGlenn Barry */
868bfd8310aSGlenn Barry free_mech_type = 0;
869bfd8310aSGlenn Barry
870bfd8310aSGlenn Barry if (client_data->raw_cred.client_principal) {
871bfd8310aSGlenn Barry kmem_free((caddr_t)client_data->\
872bfd8310aSGlenn Barry raw_cred.client_principal,
873bfd8310aSGlenn Barry client_data->raw_cred.\
874bfd8310aSGlenn Barry client_principal->len + sizeof (int));
875bfd8310aSGlenn Barry client_data->raw_cred.client_principal = NULL;
876bfd8310aSGlenn Barry }
877bfd8310aSGlenn Barry
878bfd8310aSGlenn Barry /*
879bfd8310aSGlenn Barry * The client_name returned from
880bfd8310aSGlenn Barry * kgss_accept_sec_context() is in an
881bfd8310aSGlenn Barry * exported flat format.
882bfd8310aSGlenn Barry */
883bfd8310aSGlenn Barry if (! __rpc_gss_make_principal(
884bfd8310aSGlenn Barry &client_data->raw_cred.client_principal,
885bfd8310aSGlenn Barry &client_data->client_name)) {
886bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: "
887bfd8310aSGlenn Barry "make principal failed\n");
888bfd8310aSGlenn Barry gssstat = GSS_S_FAILURE;
889bfd8310aSGlenn Barry (void) gss_release_buffer(&minor_stat, &output_token);
890bfd8310aSGlenn Barry }
891bfd8310aSGlenn Barry }
892bfd8310aSGlenn Barry
893bfd8310aSGlenn Barry rw_exit(&cred_lock);
894bfd8310aSGlenn Barry
895bfd8310aSGlenn Barry call_res.gss_major = gssstat;
896bfd8310aSGlenn Barry call_res.gss_minor = minor_stat;
897bfd8310aSGlenn Barry
898bfd8310aSGlenn Barry if (gssstat != GSS_S_COMPLETE &&
899bfd8310aSGlenn Barry gssstat != GSS_S_CONTINUE_NEEDED) {
900bfd8310aSGlenn Barry call_res.ctx_handle.length = 0;
901bfd8310aSGlenn Barry call_res.ctx_handle.value = NULL;
902bfd8310aSGlenn Barry call_res.seq_window = 0;
903bfd8310aSGlenn Barry rpc_gss_display_status(gssstat, minor_stat, mech_type,
904bfd8310aSGlenn Barry crgetuid(CRED()),
905bfd8310aSGlenn Barry "_svc_rpcsec_gss gss_accept_sec_context");
906bfd8310aSGlenn Barry (void) svc_sendreply(rqst->rq_xprt,
907bfd8310aSGlenn Barry __xdr_rpc_gss_init_res, (caddr_t)&call_res);
908bfd8310aSGlenn Barry client_data->stale = TRUE;
909bfd8310aSGlenn Barry ret = AUTH_OK;
910bfd8310aSGlenn Barry goto error2;
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate /*
914bfd8310aSGlenn Barry * If appropriate, set established to TRUE *after* sending
915bfd8310aSGlenn Barry * response (otherwise, the client will receive the final
916bfd8310aSGlenn Barry * token encrypted)
9177c478bd9Sstevel@tonic-gate */
918bfd8310aSGlenn Barry if (gssstat == GSS_S_COMPLETE) {
9197c478bd9Sstevel@tonic-gate /*
920bfd8310aSGlenn Barry * Context is established. Set expiration time
921bfd8310aSGlenn Barry * for the context.
9227c478bd9Sstevel@tonic-gate */
923bfd8310aSGlenn Barry client_data->seq_num = 1;
924bfd8310aSGlenn Barry if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
925bfd8310aSGlenn Barry client_data->expiration = GSS_C_INDEFINITE;
926bfd8310aSGlenn Barry } else {
927bfd8310aSGlenn Barry client_data->expiration =
928bfd8310aSGlenn Barry time_rec + gethrestime_sec();
9297c478bd9Sstevel@tonic-gate }
930bfd8310aSGlenn Barry
931bfd8310aSGlenn Barry if (!transfer_sec_context(client_data)) {
932bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
933bfd8310aSGlenn Barry client_data->stale = TRUE;
934bfd8310aSGlenn Barry RPCGSS_LOG0(1,
935bfd8310aSGlenn Barry "_svc_rpcsec_gss: transfer sec context failed\n");
936bfd8310aSGlenn Barry goto error2;
9377c478bd9Sstevel@tonic-gate }
938bfd8310aSGlenn Barry
939bfd8310aSGlenn Barry client_data->established = TRUE;
940bfd8310aSGlenn Barry }
941bfd8310aSGlenn Barry
942bfd8310aSGlenn Barry /*
943bfd8310aSGlenn Barry * This step succeeded. Send a response, along with
944bfd8310aSGlenn Barry * a token if there's one. Don't dispatch.
945bfd8310aSGlenn Barry */
946bfd8310aSGlenn Barry
947bfd8310aSGlenn Barry if (output_token.length != 0)
948bfd8310aSGlenn Barry GSS_COPY_BUFFER(call_res.token, output_token);
949bfd8310aSGlenn Barry
950bfd8310aSGlenn Barry /*
951bfd8310aSGlenn Barry * If GSS_S_COMPLETE: set response verifier to
952bfd8310aSGlenn Barry * checksum of SEQ_WIN
953bfd8310aSGlenn Barry */
954bfd8310aSGlenn Barry if (gssstat == GSS_S_COMPLETE) {
955bfd8310aSGlenn Barry if (!set_response_verf(rqst, msg, client_data,
956bfd8310aSGlenn Barry (uint_t)SEQ_WIN)) {
957bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
958bfd8310aSGlenn Barry client_data->stale = TRUE;
959bfd8310aSGlenn Barry RPCGSS_LOG0(1,
960bfd8310aSGlenn Barry "_svc_rpcsec_gss:set response verifier failed\n");
961bfd8310aSGlenn Barry goto error2;
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate
965bfd8310aSGlenn Barry if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
966bfd8310aSGlenn Barry (caddr_t)&call_res)) {
967bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
968bfd8310aSGlenn Barry client_data->stale = TRUE;
969bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
970bfd8310aSGlenn Barry goto error2;
971bfd8310aSGlenn Barry }
972bfd8310aSGlenn Barry
973bfd8310aSGlenn Barry /*
974bfd8310aSGlenn Barry * Cache last response in case it is lost and the client
975bfd8310aSGlenn Barry * retries on an established context.
976bfd8310aSGlenn Barry */
977bfd8310aSGlenn Barry (void) retrans_add(client_data, msg->rm_xid, &call_res);
978bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
979bfd8310aSGlenn Barry client_data->ref_cnt--;
980bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
981bfd8310aSGlenn Barry
982bfd8310aSGlenn Barry (void) gss_release_buffer(&minor_stat, &output_token);
983bfd8310aSGlenn Barry
984bfd8310aSGlenn Barry return (AUTH_OK);
985bfd8310aSGlenn Barry
986bfd8310aSGlenn Barry error2:
987bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
988bfd8310aSGlenn Barry client_data->ref_cnt--;
989bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
990bfd8310aSGlenn Barry (void) gss_release_buffer(&minor_stat, &output_token);
991bfd8310aSGlenn Barry if (free_mech_type && mech_type)
992bfd8310aSGlenn Barry kgss_free_oid(mech_type);
993bfd8310aSGlenn Barry
994bfd8310aSGlenn Barry return (ret);
995bfd8310aSGlenn Barry }
996bfd8310aSGlenn Barry
997bfd8310aSGlenn Barry static void
svcrpcsec_gss_taskq_func(void * svcrpcsecgss_taskq_arg)998bfd8310aSGlenn Barry svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
999bfd8310aSGlenn Barry {
1000bfd8310aSGlenn Barry enum auth_stat retval;
1001bfd8310aSGlenn Barry svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
1002bfd8310aSGlenn Barry
1003bfd8310aSGlenn Barry retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
1004bfd8310aSGlenn Barry arg->client_data, arg->cr_version, arg->cr_service);
1005bfd8310aSGlenn Barry if (retval != AUTH_OK) {
1006bfd8310aSGlenn Barry cmn_err(CE_NOTE,
1007bfd8310aSGlenn Barry "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
1008bfd8310aSGlenn Barry retval);
1009bfd8310aSGlenn Barry }
1010bfd8310aSGlenn Barry rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
10114a3b0527SAndy Fiddaman SVC_RELE(arg->rq_xprt, NULL, FALSE);
1012bfd8310aSGlenn Barry svc_clone_unlink(arg->rq_xprt);
1013bfd8310aSGlenn Barry svc_clone_free(arg->rq_xprt);
1014bfd8310aSGlenn Barry xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
1015bfd8310aSGlenn Barry kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
1016bfd8310aSGlenn Barry
1017bfd8310aSGlenn Barry kmem_free(arg, sizeof (*arg));
1018bfd8310aSGlenn Barry }
1019bfd8310aSGlenn Barry
1020bfd8310aSGlenn Barry static enum auth_stat
rpcsec_gss_init(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch,svc_rpc_gss_data * c_d)1021bfd8310aSGlenn Barry rpcsec_gss_init(
1022bfd8310aSGlenn Barry struct svc_req *rqst,
1023bfd8310aSGlenn Barry struct rpc_msg *msg,
1024bfd8310aSGlenn Barry rpc_gss_creds creds,
1025bfd8310aSGlenn Barry bool_t *no_dispatch,
1026bfd8310aSGlenn Barry svc_rpc_gss_data *c_d) /* client data, can be NULL */
1027bfd8310aSGlenn Barry {
1028bfd8310aSGlenn Barry svc_rpc_gss_data *client_data;
1029bfd8310aSGlenn Barry int ret;
1030bfd8310aSGlenn Barry svcrpcsec_gss_taskq_arg_t *arg;
1031*02ac56e0SMatt Barden svc_gss_zsd_t *zsd = svc_gss_get_zsd();
1032*02ac56e0SMatt Barden taskq_t *tq = zsd->sgz_init_taskq;
1033*02ac56e0SMatt Barden
1034*02ac56e0SMatt Barden if (tq == NULL) {
1035*02ac56e0SMatt Barden mutex_enter(&zsd->sgz_lock);
1036*02ac56e0SMatt Barden if (zsd->sgz_init_taskq == NULL)
1037*02ac56e0SMatt Barden zsd->sgz_init_taskq = svc_gss_create_taskq(curzone);
1038*02ac56e0SMatt Barden tq = zsd->sgz_init_taskq;
1039*02ac56e0SMatt Barden mutex_exit(&zsd->sgz_lock);
1040*02ac56e0SMatt Barden if (tq == NULL) {
1041*02ac56e0SMatt Barden cmn_err(CE_NOTE, "%s: no taskq available", __func__);
1042*02ac56e0SMatt Barden return (RPCSEC_GSS_FAILED);
1043*02ac56e0SMatt Barden }
1044*02ac56e0SMatt Barden }
1045bfd8310aSGlenn Barry
1046bfd8310aSGlenn Barry if (creds.ctx_handle.length != 0) {
1047bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
1048bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1049bfd8310aSGlenn Barry return (ret);
1050bfd8310aSGlenn Barry }
1051bfd8310aSGlenn Barry
1052bfd8310aSGlenn Barry client_data = c_d ? c_d : create_client();
1053bfd8310aSGlenn Barry if (client_data == NULL) {
1054bfd8310aSGlenn Barry RPCGSS_LOG0(1,
1055bfd8310aSGlenn Barry "_svcrpcsec_gss: can't create a new cache entry\n");
1056bfd8310aSGlenn Barry ret = AUTH_FAILED;
1057bfd8310aSGlenn Barry return (ret);
1058bfd8310aSGlenn Barry }
1059bfd8310aSGlenn Barry
1060bfd8310aSGlenn Barry mutex_enter(&client_data->clm);
1061bfd8310aSGlenn Barry if (client_data->stale) {
1062bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1063bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1064bfd8310aSGlenn Barry goto error2;
1065bfd8310aSGlenn Barry }
1066bfd8310aSGlenn Barry
10677c478bd9Sstevel@tonic-gate /*
1068bbf21555SRichard Lowe * kgss_accept_sec_context()/gssd(8) can be overly time
1069bfd8310aSGlenn Barry * consuming so let's queue it and return asap.
1070bfd8310aSGlenn Barry *
1071bfd8310aSGlenn Barry * taskq func must free arg.
10727c478bd9Sstevel@tonic-gate */
1073bfd8310aSGlenn Barry arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
1074bfd8310aSGlenn Barry
1075bfd8310aSGlenn Barry /* taskq func must free rpc_call_arg & deserialized arguments */
1076a0f9c00cSJosef 'Jeff' Sipek arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
1077bfd8310aSGlenn Barry
1078bfd8310aSGlenn Barry /* deserialize arguments */
1079bfd8310aSGlenn Barry if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
1080bfd8310aSGlenn Barry (caddr_t)arg->rpc_call_arg)) {
1081bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
1082bfd8310aSGlenn Barry client_data->stale = TRUE;
1083bfd8310aSGlenn Barry goto error2;
1084bfd8310aSGlenn Barry }
1085bfd8310aSGlenn Barry
1086bfd8310aSGlenn Barry /* get a xprt clone for taskq thread, taskq func must free it */
1087bfd8310aSGlenn Barry arg->rq_xprt = svc_clone_init();
108860536ef9SKaren Rochford svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
1089bfd8310aSGlenn Barry arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
1090bfd8310aSGlenn Barry
10914a3b0527SAndy Fiddaman /*
10924a3b0527SAndy Fiddaman * Increment the reference count on the rpcmod slot so that is not
10934a3b0527SAndy Fiddaman * freed before the task has finished.
10944a3b0527SAndy Fiddaman */
10954a3b0527SAndy Fiddaman SVC_HOLD(arg->rq_xprt);
1096bfd8310aSGlenn Barry
1097bfd8310aSGlenn Barry /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
1098bfd8310aSGlenn Barry arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1099bfd8310aSGlenn Barry arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1100bfd8310aSGlenn Barry
1101bfd8310aSGlenn Barry /* get a dup of rpc msg for taskq thread */
1102bfd8310aSGlenn Barry arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */
1103bfd8310aSGlenn Barry
1104bfd8310aSGlenn Barry arg->client_data = client_data;
1105bfd8310aSGlenn Barry arg->cr_version = creds.version;
1106bfd8310aSGlenn Barry arg->cr_service = creds.service;
1107bfd8310aSGlenn Barry
1108bfd8310aSGlenn Barry /* should be ok to hold clm lock as taskq will have new thread(s) */
1109*02ac56e0SMatt Barden if (taskq_dispatch(tq, svcrpcsec_gss_taskq_func, arg, TQ_SLEEP)
1110*02ac56e0SMatt Barden == DDI_FAILURE) {
1111*02ac56e0SMatt Barden cmn_err(CE_NOTE, "%s: taskq dispatch fail", __func__);
1112bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
1113bfd8310aSGlenn Barry rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
11144a3b0527SAndy Fiddaman SVC_RELE(arg->rq_xprt, NULL, FALSE);
1115bfd8310aSGlenn Barry svc_clone_unlink(arg->rq_xprt);
1116bfd8310aSGlenn Barry svc_clone_free(arg->rq_xprt);
1117bfd8310aSGlenn Barry kmem_free(arg, sizeof (*arg));
1118bfd8310aSGlenn Barry goto error2;
1119bfd8310aSGlenn Barry }
1120bfd8310aSGlenn Barry
1121bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
1122bfd8310aSGlenn Barry *no_dispatch = TRUE;
1123bfd8310aSGlenn Barry return (AUTH_OK);
1124bfd8310aSGlenn Barry
1125bfd8310aSGlenn Barry error2:
1126bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
1127bfd8310aSGlenn Barry client_data->ref_cnt--;
1128bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
1129bfd8310aSGlenn Barry cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1130bfd8310aSGlenn Barry return (ret);
1131bfd8310aSGlenn Barry }
1132bfd8310aSGlenn Barry
1133bfd8310aSGlenn Barry static enum auth_stat
rpcsec_gss_continue_init(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch)1134bfd8310aSGlenn Barry rpcsec_gss_continue_init(
1135bfd8310aSGlenn Barry struct svc_req *rqst,
1136bfd8310aSGlenn Barry struct rpc_msg *msg,
1137bfd8310aSGlenn Barry rpc_gss_creds creds,
1138bfd8310aSGlenn Barry bool_t *no_dispatch)
1139bfd8310aSGlenn Barry {
1140bfd8310aSGlenn Barry int ret;
1141bfd8310aSGlenn Barry svc_rpc_gss_data *client_data;
1142bfd8310aSGlenn Barry svc_rpc_gss_parms_t *gss_parms;
1143bfd8310aSGlenn Barry rpc_gss_init_res *retrans_result;
1144bfd8310aSGlenn Barry
1145bfd8310aSGlenn Barry if (creds.ctx_handle.length == 0) {
1146bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1147bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1148bfd8310aSGlenn Barry return (ret);
1149bfd8310aSGlenn Barry }
1150bfd8310aSGlenn Barry if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1151bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1152bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1153bfd8310aSGlenn Barry return (ret);
1154bfd8310aSGlenn Barry }
1155bfd8310aSGlenn Barry
11567c478bd9Sstevel@tonic-gate mutex_enter(&client_data->clm);
11577c478bd9Sstevel@tonic-gate if (client_data->stale) {
11587c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_NOCRED;
11597c478bd9Sstevel@tonic-gate RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
11607c478bd9Sstevel@tonic-gate goto error2;
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate
11637c478bd9Sstevel@tonic-gate /*
1164bfd8310aSGlenn Barry * If context not established, go thru INIT code but with
1165bfd8310aSGlenn Barry * this client handle.
11667c478bd9Sstevel@tonic-gate */
1167bfd8310aSGlenn Barry if (!client_data->established) {
1168bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
1169bfd8310aSGlenn Barry return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1170bfd8310aSGlenn Barry client_data));
1171bfd8310aSGlenn Barry }
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate /*
11747c478bd9Sstevel@tonic-gate * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
11757c478bd9Sstevel@tonic-gate */
11767c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
11777c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate /*
11807c478bd9Sstevel@tonic-gate * Keep copy of parameters we'll need for response, for the
11817c478bd9Sstevel@tonic-gate * sake of reentrancy (we don't want to look in the context
11827c478bd9Sstevel@tonic-gate * data because when we are sending a response, another
11837c478bd9Sstevel@tonic-gate * request may have come in).
11847c478bd9Sstevel@tonic-gate */
11857c478bd9Sstevel@tonic-gate gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
11867c478bd9Sstevel@tonic-gate gss_parms->established = client_data->established;
11877c478bd9Sstevel@tonic-gate gss_parms->service = creds.service;
11887c478bd9Sstevel@tonic-gate gss_parms->qop_rcvd = (uint_t)client_data->qop;
11897c478bd9Sstevel@tonic-gate gss_parms->context = (void *)client_data->context;
11907c478bd9Sstevel@tonic-gate gss_parms->seq_num = creds.seq_num;
11917c478bd9Sstevel@tonic-gate
1192bfd8310aSGlenn Barry /*
1193bfd8310aSGlenn Barry * This is an established context. Continue to
1194bfd8310aSGlenn Barry * satisfy retried continue init requests out of
1195bfd8310aSGlenn Barry * the retransmit cache. Throw away any that don't
1196bfd8310aSGlenn Barry * have a matching xid or the cach is empty.
1197bfd8310aSGlenn Barry * Delete the retransmit cache once the client sends
1198bfd8310aSGlenn Barry * a data request.
1199bfd8310aSGlenn Barry */
1200bfd8310aSGlenn Barry if (client_data->retrans_data &&
1201bfd8310aSGlenn Barry (client_data->retrans_data->xid == msg->rm_xid)) {
1202bfd8310aSGlenn Barry retrans_result = &client_data->retrans_data->result;
1203bfd8310aSGlenn Barry if (set_response_verf(rqst, msg, client_data,
1204bfd8310aSGlenn Barry (uint_t)retrans_result->seq_window)) {
1205bfd8310aSGlenn Barry gss_parms->established = FALSE;
12067c478bd9Sstevel@tonic-gate (void) svc_sendreply(rqst->rq_xprt,
1207bfd8310aSGlenn Barry __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
12087c478bd9Sstevel@tonic-gate *no_dispatch = TRUE;
1209bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
1210bfd8310aSGlenn Barry client_data->ref_cnt--;
12117c478bd9Sstevel@tonic-gate }
1212bfd8310aSGlenn Barry }
1213bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
12147c478bd9Sstevel@tonic-gate
1215bfd8310aSGlenn Barry return (AUTH_OK);
12167c478bd9Sstevel@tonic-gate
1217bfd8310aSGlenn Barry error2:
1218bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
1219bfd8310aSGlenn Barry client_data->ref_cnt--;
1220bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
1221bfd8310aSGlenn Barry return (ret);
1222bfd8310aSGlenn Barry }
12237c478bd9Sstevel@tonic-gate
1224bfd8310aSGlenn Barry static enum auth_stat
rpcsec_gss_data(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch)1225bfd8310aSGlenn Barry rpcsec_gss_data(
1226bfd8310aSGlenn Barry struct svc_req *rqst,
1227bfd8310aSGlenn Barry struct rpc_msg *msg,
1228bfd8310aSGlenn Barry rpc_gss_creds creds,
1229bfd8310aSGlenn Barry bool_t *no_dispatch)
1230bfd8310aSGlenn Barry {
1231bfd8310aSGlenn Barry int ret;
1232bfd8310aSGlenn Barry svc_rpc_gss_parms_t *gss_parms;
1233bfd8310aSGlenn Barry svc_rpc_gss_data *client_data;
12347c478bd9Sstevel@tonic-gate
1235bfd8310aSGlenn Barry switch (creds.service) {
1236bfd8310aSGlenn Barry case rpc_gss_svc_none:
1237bfd8310aSGlenn Barry case rpc_gss_svc_integrity:
1238bfd8310aSGlenn Barry case rpc_gss_svc_privacy:
1239bfd8310aSGlenn Barry break;
1240bfd8310aSGlenn Barry default:
1241bfd8310aSGlenn Barry cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1242bfd8310aSGlenn Barry creds.service);
1243bfd8310aSGlenn Barry RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1244bfd8310aSGlenn Barry creds.service);
1245bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1246bfd8310aSGlenn Barry return (ret);
1247bfd8310aSGlenn Barry }
12487c478bd9Sstevel@tonic-gate
1249bfd8310aSGlenn Barry if (creds.ctx_handle.length == 0) {
1250bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1251bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1252bfd8310aSGlenn Barry return (ret);
1253bfd8310aSGlenn Barry }
1254bfd8310aSGlenn Barry if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1255bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1256bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1257bfd8310aSGlenn Barry return (ret);
1258bfd8310aSGlenn Barry }
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate
1261bfd8310aSGlenn Barry mutex_enter(&client_data->clm);
1262bfd8310aSGlenn Barry if (!client_data->established) {
1263bfd8310aSGlenn Barry ret = AUTH_FAILED;
1264bfd8310aSGlenn Barry goto error2;
1265bfd8310aSGlenn Barry }
1266bfd8310aSGlenn Barry if (client_data->stale) {
1267bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1268bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1269bfd8310aSGlenn Barry goto error2;
1270bfd8310aSGlenn Barry }
12717c478bd9Sstevel@tonic-gate
1272bfd8310aSGlenn Barry /*
1273bfd8310aSGlenn Barry * Once the context is established and there is no more
1274bfd8310aSGlenn Barry * retransmission of last continue init request, it is safe
1275bfd8310aSGlenn Barry * to delete the retransmit cache entry.
1276bfd8310aSGlenn Barry */
1277bfd8310aSGlenn Barry if (client_data->retrans_data)
1278bfd8310aSGlenn Barry retrans_del(client_data);
12797c478bd9Sstevel@tonic-gate
1280bfd8310aSGlenn Barry /*
1281bfd8310aSGlenn Barry * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1282bfd8310aSGlenn Barry */
1283bfd8310aSGlenn Barry rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1284bfd8310aSGlenn Barry rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
12857c478bd9Sstevel@tonic-gate
1286bfd8310aSGlenn Barry /*
1287bfd8310aSGlenn Barry * Keep copy of parameters we'll need for response, for the
1288bfd8310aSGlenn Barry * sake of reentrancy (we don't want to look in the context
1289bfd8310aSGlenn Barry * data because when we are sending a response, another
1290bfd8310aSGlenn Barry * request may have come in).
1291bfd8310aSGlenn Barry */
1292bfd8310aSGlenn Barry gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1293bfd8310aSGlenn Barry gss_parms->established = client_data->established;
1294bfd8310aSGlenn Barry gss_parms->service = creds.service;
1295bfd8310aSGlenn Barry gss_parms->qop_rcvd = (uint_t)client_data->qop;
1296bfd8310aSGlenn Barry gss_parms->context = (void *)client_data->context;
1297bfd8310aSGlenn Barry gss_parms->seq_num = creds.seq_num;
12987c478bd9Sstevel@tonic-gate
1299bfd8310aSGlenn Barry /*
1300bfd8310aSGlenn Barry * Context is already established. Check verifier, and
1301bfd8310aSGlenn Barry * note parameters we will need for response in gss_parms.
1302bfd8310aSGlenn Barry */
1303bfd8310aSGlenn Barry if (!check_verf(msg, client_data->context,
1304bfd8310aSGlenn Barry (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1305bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1306bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1307bfd8310aSGlenn Barry goto error2;
1308bfd8310aSGlenn Barry }
13097c478bd9Sstevel@tonic-gate
1310bfd8310aSGlenn Barry /*
1311bfd8310aSGlenn Barry * Check and invoke callback if necessary.
1312bfd8310aSGlenn Barry */
1313bfd8310aSGlenn Barry if (!client_data->done_docallback) {
1314bfd8310aSGlenn Barry client_data->done_docallback = TRUE;
1315bfd8310aSGlenn Barry client_data->qop = gss_parms->qop_rcvd;
1316bfd8310aSGlenn Barry client_data->raw_cred.qop = gss_parms->qop_rcvd;
1317bfd8310aSGlenn Barry client_data->raw_cred.service = creds.service;
1318bfd8310aSGlenn Barry if (!do_callback(rqst, client_data)) {
13197c478bd9Sstevel@tonic-gate ret = AUTH_FAILED;
1320bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
13217c478bd9Sstevel@tonic-gate goto error2;
13227c478bd9Sstevel@tonic-gate }
1323bfd8310aSGlenn Barry }
13247c478bd9Sstevel@tonic-gate
1325bfd8310aSGlenn Barry /*
1326bfd8310aSGlenn Barry * If the context was locked, make sure that the client
1327bfd8310aSGlenn Barry * has not changed QOP.
1328bfd8310aSGlenn Barry */
1329bfd8310aSGlenn Barry if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1330bfd8310aSGlenn Barry ret = AUTH_BADVERF;
1331bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1332bfd8310aSGlenn Barry goto error2;
1333bfd8310aSGlenn Barry }
13347c478bd9Sstevel@tonic-gate
1335bfd8310aSGlenn Barry /*
1336bfd8310aSGlenn Barry * Validate sequence number.
1337bfd8310aSGlenn Barry */
1338bfd8310aSGlenn Barry if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1339bfd8310aSGlenn Barry if (client_data->stale) {
13407c478bd9Sstevel@tonic-gate ret = RPCSEC_GSS_FAILED;
13417c478bd9Sstevel@tonic-gate RPCGSS_LOG0(1,
1342bfd8310aSGlenn Barry "_svc_rpcsec_gss:check seq failed\n");
1343bfd8310aSGlenn Barry } else {
1344bfd8310aSGlenn Barry RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1345bfd8310aSGlenn Barry "failed on good context. Ignoring "
1346bfd8310aSGlenn Barry "request\n");
13477c478bd9Sstevel@tonic-gate /*
1348bfd8310aSGlenn Barry * Operational error, drop packet silently.
1349bfd8310aSGlenn Barry * The client will recover after timing out,
1350bfd8310aSGlenn Barry * assuming this is a client error and not
1351bfd8310aSGlenn Barry * a relpay attack. Don't dispatch.
13527c478bd9Sstevel@tonic-gate */
1353bfd8310aSGlenn Barry ret = AUTH_OK;
13547c478bd9Sstevel@tonic-gate *no_dispatch = TRUE;
1355bfd8310aSGlenn Barry }
1356bfd8310aSGlenn Barry goto error2;
1357bfd8310aSGlenn Barry }
13587c478bd9Sstevel@tonic-gate
1359bfd8310aSGlenn Barry /*
1360bfd8310aSGlenn Barry * set response verifier
1361bfd8310aSGlenn Barry */
1362bfd8310aSGlenn Barry if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1363bfd8310aSGlenn Barry ret = RPCSEC_GSS_FAILED;
1364bfd8310aSGlenn Barry client_data->stale = TRUE;
1365bfd8310aSGlenn Barry RPCGSS_LOG0(1,
1366bfd8310aSGlenn Barry "_svc_rpcsec_gss:set response verifier failed\n");
1367bfd8310aSGlenn Barry goto error2;
1368bfd8310aSGlenn Barry }
13697c478bd9Sstevel@tonic-gate
1370bfd8310aSGlenn Barry /*
1371bfd8310aSGlenn Barry * If context is locked, make sure that the client
1372bfd8310aSGlenn Barry * has not changed the security service.
1373bfd8310aSGlenn Barry */
1374bfd8310aSGlenn Barry if (client_data->locked &&
1375bfd8310aSGlenn Barry client_data->raw_cred.service != creds.service) {
1376bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1377bfd8310aSGlenn Barry "security service changed.\n");
1378bfd8310aSGlenn Barry ret = AUTH_FAILED;
1379bfd8310aSGlenn Barry goto error2;
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate /*
1383bfd8310aSGlenn Barry * Set client credentials to raw credential
1384bfd8310aSGlenn Barry * structure in context. This is okay, since
1385bfd8310aSGlenn Barry * this will not change during the lifetime of
1386bfd8310aSGlenn Barry * the context (so it's MT safe).
13877c478bd9Sstevel@tonic-gate */
1388bfd8310aSGlenn Barry rqst->rq_clntcred = (char *)&client_data->raw_cred;
1389bfd8310aSGlenn Barry
1390bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
1391bfd8310aSGlenn Barry return (AUTH_OK);
1392bfd8310aSGlenn Barry
1393bfd8310aSGlenn Barry error2:
1394bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
1395bfd8310aSGlenn Barry client_data->ref_cnt--;
13967c478bd9Sstevel@tonic-gate mutex_exit(&client_data->clm);
1397bfd8310aSGlenn Barry return (ret);
1398bfd8310aSGlenn Barry }
1399bfd8310aSGlenn Barry
1400bfd8310aSGlenn Barry /*
1401bfd8310aSGlenn Barry * Note we don't have a client yet to use this routine and test it.
1402bfd8310aSGlenn Barry */
1403bfd8310aSGlenn Barry static enum auth_stat
rpcsec_gss_destroy(struct svc_req * rqst,rpc_gss_creds creds,bool_t * no_dispatch)1404bfd8310aSGlenn Barry rpcsec_gss_destroy(
1405bfd8310aSGlenn Barry struct svc_req *rqst,
1406bfd8310aSGlenn Barry rpc_gss_creds creds,
1407bfd8310aSGlenn Barry bool_t *no_dispatch)
1408bfd8310aSGlenn Barry {
1409bfd8310aSGlenn Barry svc_rpc_gss_data *client_data;
1410bfd8310aSGlenn Barry int ret;
1411bfd8310aSGlenn Barry
1412bfd8310aSGlenn Barry if (creds.ctx_handle.length == 0) {
1413bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1414bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1415bfd8310aSGlenn Barry return (ret);
1416bfd8310aSGlenn Barry }
1417bfd8310aSGlenn Barry if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1418bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1419bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1420bfd8310aSGlenn Barry return (ret);
1421bfd8310aSGlenn Barry }
1422bfd8310aSGlenn Barry
1423bfd8310aSGlenn Barry mutex_enter(&client_data->clm);
1424bfd8310aSGlenn Barry if (!client_data->established) {
1425bfd8310aSGlenn Barry ret = AUTH_FAILED;
1426bfd8310aSGlenn Barry goto error2;
1427bfd8310aSGlenn Barry }
1428bfd8310aSGlenn Barry if (client_data->stale) {
1429bfd8310aSGlenn Barry ret = RPCSEC_GSS_NOCRED;
1430bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1431bfd8310aSGlenn Barry goto error2;
1432bfd8310aSGlenn Barry }
14337c478bd9Sstevel@tonic-gate
1434bfd8310aSGlenn Barry (void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1435bfd8310aSGlenn Barry *no_dispatch = TRUE;
1436bfd8310aSGlenn Barry ASSERT(client_data->ref_cnt > 0);
1437bfd8310aSGlenn Barry client_data->ref_cnt--;
1438bfd8310aSGlenn Barry client_data->stale = TRUE;
1439bfd8310aSGlenn Barry mutex_exit(&client_data->clm);
14407c478bd9Sstevel@tonic-gate return (AUTH_OK);
1441bfd8310aSGlenn Barry
14427c478bd9Sstevel@tonic-gate error2:
14437c478bd9Sstevel@tonic-gate ASSERT(client_data->ref_cnt > 0);
14447c478bd9Sstevel@tonic-gate client_data->ref_cnt--;
1445bfd8310aSGlenn Barry client_data->stale = TRUE;
14467c478bd9Sstevel@tonic-gate mutex_exit(&client_data->clm);
1447bfd8310aSGlenn Barry return (ret);
1448bfd8310aSGlenn Barry }
1449bfd8310aSGlenn Barry
1450bfd8310aSGlenn Barry /*
1451bfd8310aSGlenn Barry * Server side authentication for RPCSEC_GSS.
1452bfd8310aSGlenn Barry */
1453bfd8310aSGlenn Barry enum auth_stat
__svcrpcsec_gss(struct svc_req * rqst,struct rpc_msg * msg,bool_t * no_dispatch)1454bfd8310aSGlenn Barry __svcrpcsec_gss(
1455bfd8310aSGlenn Barry struct svc_req *rqst,
1456bfd8310aSGlenn Barry struct rpc_msg *msg,
1457bfd8310aSGlenn Barry bool_t *no_dispatch)
1458bfd8310aSGlenn Barry {
1459bfd8310aSGlenn Barry XDR xdrs;
1460bfd8310aSGlenn Barry rpc_gss_creds creds;
1461bfd8310aSGlenn Barry struct opaque_auth *cred;
1462bfd8310aSGlenn Barry int ret;
1463bfd8310aSGlenn Barry
1464bfd8310aSGlenn Barry *no_dispatch = FALSE;
1465bfd8310aSGlenn Barry
1466bfd8310aSGlenn Barry /*
1467bfd8310aSGlenn Barry * Initialize response verifier to NULL verifier. If
1468bfd8310aSGlenn Barry * necessary, this will be changed later.
1469bfd8310aSGlenn Barry */
1470bfd8310aSGlenn Barry rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1471bfd8310aSGlenn Barry rqst->rq_xprt->xp_verf.oa_base = NULL;
1472bfd8310aSGlenn Barry rqst->rq_xprt->xp_verf.oa_length = 0;
1473bfd8310aSGlenn Barry
14747c478bd9Sstevel@tonic-gate /*
1475bfd8310aSGlenn Barry * Pull out and check credential and verifier.
14767c478bd9Sstevel@tonic-gate */
1477bfd8310aSGlenn Barry cred = &msg->rm_call.cb_cred;
1478bfd8310aSGlenn Barry
1479bfd8310aSGlenn Barry if (cred->oa_length == 0) {
1480bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1481bfd8310aSGlenn Barry return (AUTH_BADCRED);
1482bfd8310aSGlenn Barry }
1483bfd8310aSGlenn Barry
1484bfd8310aSGlenn Barry xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1485bfd8310aSGlenn Barry bzero((char *)&creds, sizeof (creds));
1486bfd8310aSGlenn Barry if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1487bfd8310aSGlenn Barry XDR_DESTROY(&xdrs);
1488bfd8310aSGlenn Barry RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1489bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1490bfd8310aSGlenn Barry return (AUTH_BADCRED);
1491bfd8310aSGlenn Barry }
1492bfd8310aSGlenn Barry XDR_DESTROY(&xdrs);
1493bfd8310aSGlenn Barry
1494bfd8310aSGlenn Barry switch (creds.gss_proc) {
1495bfd8310aSGlenn Barry case RPCSEC_GSS_INIT:
1496bfd8310aSGlenn Barry ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1497bfd8310aSGlenn Barry break;
1498bfd8310aSGlenn Barry case RPCSEC_GSS_CONTINUE_INIT:
1499bfd8310aSGlenn Barry ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1500bfd8310aSGlenn Barry break;
1501bfd8310aSGlenn Barry case RPCSEC_GSS_DATA:
1502bfd8310aSGlenn Barry ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1503bfd8310aSGlenn Barry break;
1504bfd8310aSGlenn Barry case RPCSEC_GSS_DESTROY:
1505bfd8310aSGlenn Barry ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1506bfd8310aSGlenn Barry break;
1507bfd8310aSGlenn Barry default:
1508bfd8310aSGlenn Barry cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1509bfd8310aSGlenn Barry creds.gss_proc);
1510bfd8310aSGlenn Barry ret = AUTH_BADCRED;
1511bfd8310aSGlenn Barry }
1512bfd8310aSGlenn Barry
15137c478bd9Sstevel@tonic-gate if (creds.ctx_handle.length != 0)
15147c478bd9Sstevel@tonic-gate xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
15157c478bd9Sstevel@tonic-gate return (ret);
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate * Check verifier. The verifier is the checksum of the RPC header
15207c478bd9Sstevel@tonic-gate * upto and including the credentials field.
15217c478bd9Sstevel@tonic-gate */
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate /* ARGSUSED */
15247c478bd9Sstevel@tonic-gate static bool_t
check_verf(struct rpc_msg * msg,gss_ctx_id_t context,int * qop_state,uid_t uid)15257c478bd9Sstevel@tonic-gate check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate int *buf, *tmp;
15287c478bd9Sstevel@tonic-gate char hdr[128];
15297c478bd9Sstevel@tonic-gate struct opaque_auth *oa;
15307c478bd9Sstevel@tonic-gate int len;
15317c478bd9Sstevel@tonic-gate gss_buffer_desc msg_buf;
15327c478bd9Sstevel@tonic-gate gss_buffer_desc tok_buf;
15337c478bd9Sstevel@tonic-gate OM_uint32 gssstat, minor_stat;
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate * We have to reconstruct the RPC header from the previously
15377c478bd9Sstevel@tonic-gate * parsed information, since we haven't kept the header intact.
15387c478bd9Sstevel@tonic-gate */
1539a38dd497Spk
1540a38dd497Spk oa = &msg->rm_call.cb_cred;
1541a38dd497Spk if (oa->oa_length > MAX_AUTH_BYTES)
1542a38dd497Spk return (FALSE);
1543a38dd497Spk
1544a38dd497Spk /* 8 XDR units from the IXDR macro calls. */
1545a38dd497Spk if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1546a38dd497Spk RNDUP(oa->oa_length)))
1547a38dd497Spk return (FALSE);
15487c478bd9Sstevel@tonic-gate buf = (int *)hdr;
15497c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_xid);
15507c478bd9Sstevel@tonic-gate IXDR_PUT_ENUM(buf, msg->rm_direction);
15517c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
15527c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
15537c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
15547c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
15557c478bd9Sstevel@tonic-gate IXDR_PUT_ENUM(buf, oa->oa_flavor);
15567c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(buf, oa->oa_length);
15577c478bd9Sstevel@tonic-gate if (oa->oa_length) {
15587c478bd9Sstevel@tonic-gate len = RNDUP(oa->oa_length);
15597c478bd9Sstevel@tonic-gate tmp = buf;
15607c478bd9Sstevel@tonic-gate buf += len / sizeof (int);
15617c478bd9Sstevel@tonic-gate *(buf - 1) = 0;
15627c478bd9Sstevel@tonic-gate (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate len = ((char *)buf) - hdr;
15657c478bd9Sstevel@tonic-gate msg_buf.length = len;
15667c478bd9Sstevel@tonic-gate msg_buf.value = hdr;
15677c478bd9Sstevel@tonic-gate oa = &msg->rm_call.cb_verf;
15687c478bd9Sstevel@tonic-gate tok_buf.length = oa->oa_length;
15697c478bd9Sstevel@tonic-gate tok_buf.value = oa->oa_base;
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1572bfd8310aSGlenn Barry qop_state);
15737c478bd9Sstevel@tonic-gate if (gssstat != GSS_S_COMPLETE) {
15747c478bd9Sstevel@tonic-gate RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
15777c478bd9Sstevel@tonic-gate RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
15787c478bd9Sstevel@tonic-gate RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1579bfd8310aSGlenn Barry tok_buf.length);
15807c478bd9Sstevel@tonic-gate RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1581bfd8310aSGlenn Barry (void *)oa->oa_base);
15827c478bd9Sstevel@tonic-gate RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
15837c478bd9Sstevel@tonic-gate
15847c478bd9Sstevel@tonic-gate return (FALSE);
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate return (TRUE);
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate
1589bfd8310aSGlenn Barry
15907c478bd9Sstevel@tonic-gate /*
15917c478bd9Sstevel@tonic-gate * Set response verifier. This is the checksum of the given number.
15927c478bd9Sstevel@tonic-gate * (e.g. sequence number or sequence window)
15937c478bd9Sstevel@tonic-gate */
15947c478bd9Sstevel@tonic-gate static bool_t
set_response_verf(struct svc_req * rqst,struct rpc_msg * msg,svc_rpc_gss_data * cl,uint_t num)15954a3b0527SAndy Fiddaman set_response_verf(struct svc_req *rqst, struct rpc_msg *msg,
15964a3b0527SAndy Fiddaman svc_rpc_gss_data *cl, uint_t num)
15977c478bd9Sstevel@tonic-gate {
15987c478bd9Sstevel@tonic-gate OM_uint32 minor;
15997c478bd9Sstevel@tonic-gate gss_buffer_desc in_buf, out_buf;
16007c478bd9Sstevel@tonic-gate uint_t num_net;
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate num_net = (uint_t)htonl(num);
16037c478bd9Sstevel@tonic-gate in_buf.length = sizeof (num);
16047c478bd9Sstevel@tonic-gate in_buf.value = (char *)&num_net;
16057c478bd9Sstevel@tonic-gate /* XXX uid ? */
1606bfd8310aSGlenn Barry
16074a3b0527SAndy Fiddaman if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, &out_buf))
16084a3b0527SAndy Fiddaman != GSS_S_COMPLETE)
16097c478bd9Sstevel@tonic-gate return (FALSE);
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
16127c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
16137c478bd9Sstevel@tonic-gate rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
16147c478bd9Sstevel@tonic-gate bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
16157c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor, &out_buf);
16167c478bd9Sstevel@tonic-gate return (TRUE);
16177c478bd9Sstevel@tonic-gate }
16187c478bd9Sstevel@tonic-gate
16197c478bd9Sstevel@tonic-gate /*
16207c478bd9Sstevel@tonic-gate * Create client context.
16217c478bd9Sstevel@tonic-gate */
16227c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *
create_client()16237c478bd9Sstevel@tonic-gate create_client()
16247c478bd9Sstevel@tonic-gate {
16257c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client_data;
16267c478bd9Sstevel@tonic-gate static uint_t key = 1;
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1629bfd8310aSGlenn Barry KM_SLEEP);
16307c478bd9Sstevel@tonic-gate if (client_data == NULL)
16317c478bd9Sstevel@tonic-gate return (NULL);
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate /*
16347c478bd9Sstevel@tonic-gate * set up client data structure
16357c478bd9Sstevel@tonic-gate */
16367c478bd9Sstevel@tonic-gate client_data->next = NULL;
16377c478bd9Sstevel@tonic-gate client_data->prev = NULL;
16387c478bd9Sstevel@tonic-gate client_data->lru_next = NULL;
16397c478bd9Sstevel@tonic-gate client_data->lru_prev = NULL;
16407c478bd9Sstevel@tonic-gate client_data->client_name.length = 0;
16417c478bd9Sstevel@tonic-gate client_data->client_name.value = NULL;
16427c478bd9Sstevel@tonic-gate client_data->seq_num = 0;
16437c478bd9Sstevel@tonic-gate bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
16447c478bd9Sstevel@tonic-gate client_data->key = 0;
16457c478bd9Sstevel@tonic-gate client_data->cookie = NULL;
16467c478bd9Sstevel@tonic-gate bzero(&client_data->u_cred, sizeof (client_data->u_cred));
16477c478bd9Sstevel@tonic-gate client_data->established = FALSE;
16487c478bd9Sstevel@tonic-gate client_data->locked = FALSE;
16497c478bd9Sstevel@tonic-gate client_data->u_cred_set = 0;
16507c478bd9Sstevel@tonic-gate client_data->context = GSS_C_NO_CONTEXT;
16517c478bd9Sstevel@tonic-gate client_data->expiration = GSS_C_INDEFINITE;
16527c478bd9Sstevel@tonic-gate client_data->deleg = GSS_C_NO_CREDENTIAL;
16537c478bd9Sstevel@tonic-gate client_data->ref_cnt = 1;
16547c478bd9Sstevel@tonic-gate client_data->last_ref_time = gethrestime_sec();
16557c478bd9Sstevel@tonic-gate client_data->qop = GSS_C_QOP_DEFAULT;
16567c478bd9Sstevel@tonic-gate client_data->done_docallback = FALSE;
16577c478bd9Sstevel@tonic-gate client_data->stale = FALSE;
16587c478bd9Sstevel@tonic-gate client_data->retrans_data = NULL;
16597c478bd9Sstevel@tonic-gate bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
16607c478bd9Sstevel@tonic-gate
16617c478bd9Sstevel@tonic-gate /*
16627c478bd9Sstevel@tonic-gate * The client context handle is a 32-bit key (unsigned int).
16637c478bd9Sstevel@tonic-gate * The key is incremented until there is no duplicate for it.
16647c478bd9Sstevel@tonic-gate */
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate svc_rpc_gss_cache_stats.total_entries_allocated++;
16677c478bd9Sstevel@tonic-gate mutex_enter(&ctx_mutex);
16687c478bd9Sstevel@tonic-gate for (;;) {
16697c478bd9Sstevel@tonic-gate client_data->key = key++;
16707c478bd9Sstevel@tonic-gate if (find_client(client_data->key) == NULL) {
16717c478bd9Sstevel@tonic-gate insert_client(client_data);
16727c478bd9Sstevel@tonic-gate mutex_exit(&ctx_mutex);
16737c478bd9Sstevel@tonic-gate return (client_data);
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate }
16767c478bd9Sstevel@tonic-gate /*NOTREACHED*/
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate /*
16807c478bd9Sstevel@tonic-gate * Insert client context into hash list and LRU list.
16817c478bd9Sstevel@tonic-gate */
16827c478bd9Sstevel@tonic-gate static void
insert_client(svc_rpc_gss_data * client_data)16834a3b0527SAndy Fiddaman insert_client(svc_rpc_gss_data *client_data)
16847c478bd9Sstevel@tonic-gate {
16857c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl;
16867c478bd9Sstevel@tonic-gate int index = HASH(client_data->key);
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ctx_mutex));
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate client_data->prev = NULL;
16917c478bd9Sstevel@tonic-gate cl = clients[index];
16927c478bd9Sstevel@tonic-gate if ((client_data->next = cl) != NULL)
16937c478bd9Sstevel@tonic-gate cl->prev = client_data;
16947c478bd9Sstevel@tonic-gate clients[index] = client_data;
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate client_data->lru_prev = NULL;
16977c478bd9Sstevel@tonic-gate if ((client_data->lru_next = lru_first) != NULL)
16987c478bd9Sstevel@tonic-gate lru_first->lru_prev = client_data;
16997c478bd9Sstevel@tonic-gate else
17007c478bd9Sstevel@tonic-gate lru_last = client_data;
17017c478bd9Sstevel@tonic-gate lru_first = client_data;
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate num_gss_contexts++;
17047c478bd9Sstevel@tonic-gate }
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate /*
17077c478bd9Sstevel@tonic-gate * Fetch a client, given the client context handle. Move it to the
17087c478bd9Sstevel@tonic-gate * top of the LRU list since this is the most recently used context.
17097c478bd9Sstevel@tonic-gate */
17107c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *
get_client(gss_buffer_t ctx_handle)17114a3b0527SAndy Fiddaman get_client(gss_buffer_t ctx_handle)
17127c478bd9Sstevel@tonic-gate {
17137c478bd9Sstevel@tonic-gate uint_t key = *(uint_t *)ctx_handle->value;
17147c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl;
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate mutex_enter(&ctx_mutex);
17177c478bd9Sstevel@tonic-gate if ((cl = find_client(key)) != NULL) {
17187c478bd9Sstevel@tonic-gate mutex_enter(&cl->clm);
17197c478bd9Sstevel@tonic-gate if (cl->stale) {
17207c478bd9Sstevel@tonic-gate if (cl->ref_cnt == 0) {
17217c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
17227c478bd9Sstevel@tonic-gate destroy_client(cl);
17237c478bd9Sstevel@tonic-gate } else {
17247c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate mutex_exit(&ctx_mutex);
17277c478bd9Sstevel@tonic-gate return (NULL);
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate cl->ref_cnt++;
17307c478bd9Sstevel@tonic-gate cl->last_ref_time = gethrestime_sec();
17317c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
17327c478bd9Sstevel@tonic-gate if (cl != lru_first) {
17337c478bd9Sstevel@tonic-gate cl->lru_prev->lru_next = cl->lru_next;
17347c478bd9Sstevel@tonic-gate if (cl->lru_next != NULL)
17357c478bd9Sstevel@tonic-gate cl->lru_next->lru_prev = cl->lru_prev;
17367c478bd9Sstevel@tonic-gate else
17377c478bd9Sstevel@tonic-gate lru_last = cl->lru_prev;
17387c478bd9Sstevel@tonic-gate cl->lru_prev = NULL;
17397c478bd9Sstevel@tonic-gate cl->lru_next = lru_first;
17407c478bd9Sstevel@tonic-gate lru_first->lru_prev = cl;
17417c478bd9Sstevel@tonic-gate lru_first = cl;
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate mutex_exit(&ctx_mutex);
17457c478bd9Sstevel@tonic-gate return (cl);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate /*
17497c478bd9Sstevel@tonic-gate * Given the client context handle, find the context corresponding to it.
17507c478bd9Sstevel@tonic-gate * Don't change its LRU state since it may not be used.
17517c478bd9Sstevel@tonic-gate */
17527c478bd9Sstevel@tonic-gate static svc_rpc_gss_data *
find_client(uint_t key)17534a3b0527SAndy Fiddaman find_client(uint_t key)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate int index = HASH(key);
17567c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl = NULL;
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ctx_mutex));
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate for (cl = clients[index]; cl != NULL; cl = cl->next) {
17617c478bd9Sstevel@tonic-gate if (cl->key == key)
17627c478bd9Sstevel@tonic-gate break;
17637c478bd9Sstevel@tonic-gate }
17647c478bd9Sstevel@tonic-gate return (cl);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate /*
17687c478bd9Sstevel@tonic-gate * Destroy a client context.
17697c478bd9Sstevel@tonic-gate */
17707c478bd9Sstevel@tonic-gate static void
destroy_client(svc_rpc_gss_data * client_data)17714a3b0527SAndy Fiddaman destroy_client(svc_rpc_gss_data *client_data)
17727c478bd9Sstevel@tonic-gate {
17737c478bd9Sstevel@tonic-gate OM_uint32 minor;
17747c478bd9Sstevel@tonic-gate int index = HASH(client_data->key);
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ctx_mutex));
17777c478bd9Sstevel@tonic-gate
17787c478bd9Sstevel@tonic-gate /*
17797c478bd9Sstevel@tonic-gate * remove from hash list
17807c478bd9Sstevel@tonic-gate */
17817c478bd9Sstevel@tonic-gate if (client_data->prev == NULL)
17827c478bd9Sstevel@tonic-gate clients[index] = client_data->next;
17837c478bd9Sstevel@tonic-gate else
17847c478bd9Sstevel@tonic-gate client_data->prev->next = client_data->next;
17857c478bd9Sstevel@tonic-gate if (client_data->next != NULL)
17867c478bd9Sstevel@tonic-gate client_data->next->prev = client_data->prev;
17877c478bd9Sstevel@tonic-gate
17887c478bd9Sstevel@tonic-gate /*
17897c478bd9Sstevel@tonic-gate * remove from LRU list
17907c478bd9Sstevel@tonic-gate */
17917c478bd9Sstevel@tonic-gate if (client_data->lru_prev == NULL)
17927c478bd9Sstevel@tonic-gate lru_first = client_data->lru_next;
17937c478bd9Sstevel@tonic-gate else
17947c478bd9Sstevel@tonic-gate client_data->lru_prev->lru_next = client_data->lru_next;
17957c478bd9Sstevel@tonic-gate if (client_data->lru_next != NULL)
17967c478bd9Sstevel@tonic-gate client_data->lru_next->lru_prev = client_data->lru_prev;
17977c478bd9Sstevel@tonic-gate else
17987c478bd9Sstevel@tonic-gate lru_last = client_data->lru_prev;
17997c478bd9Sstevel@tonic-gate
18007c478bd9Sstevel@tonic-gate /*
18017c478bd9Sstevel@tonic-gate * If there is a GSS context, clean up GSS state.
18027c478bd9Sstevel@tonic-gate */
18037c478bd9Sstevel@tonic-gate if (client_data->context != GSS_C_NO_CONTEXT) {
18047c478bd9Sstevel@tonic-gate (void) kgss_delete_sec_context(&minor, &client_data->context,
18054a3b0527SAndy Fiddaman NULL);
18067c478bd9Sstevel@tonic-gate
18077c478bd9Sstevel@tonic-gate common_client_data_free(client_data);
18087c478bd9Sstevel@tonic-gate
18097c478bd9Sstevel@tonic-gate if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
18104a3b0527SAndy Fiddaman (void) kgss_release_cred(&minor, &client_data->deleg,
18114a3b0527SAndy Fiddaman crgetuid(CRED()));
18127c478bd9Sstevel@tonic-gate }
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate if (client_data->u_cred.gidlist != NULL) {
18164a3b0527SAndy Fiddaman kmem_free((char *)client_data->u_cred.gidlist,
18174a3b0527SAndy Fiddaman client_data->u_cred.gidlen * sizeof (gid_t));
18184a3b0527SAndy Fiddaman client_data->u_cred.gidlist = NULL;
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate if (client_data->retrans_data != NULL)
18217c478bd9Sstevel@tonic-gate retrans_del(client_data);
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate kmem_cache_free(svc_data_handle, client_data);
18247c478bd9Sstevel@tonic-gate num_gss_contexts--;
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate /*
18287c478bd9Sstevel@tonic-gate * Check for expired and stale client contexts.
18297c478bd9Sstevel@tonic-gate */
18307c478bd9Sstevel@tonic-gate static void
sweep_clients(bool_t from_reclaim)18317c478bd9Sstevel@tonic-gate sweep_clients(bool_t from_reclaim)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate svc_rpc_gss_data *cl, *next;
18347c478bd9Sstevel@tonic-gate time_t last_reference_needed;
18357c478bd9Sstevel@tonic-gate time_t now = gethrestime_sec();
18367c478bd9Sstevel@tonic-gate
18377c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ctx_mutex));
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate last_reference_needed = now - (from_reclaim ?
1840bfd8310aSGlenn Barry svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate cl = lru_last;
18437c478bd9Sstevel@tonic-gate while (cl) {
18447c478bd9Sstevel@tonic-gate /*
18457c478bd9Sstevel@tonic-gate * We assume here that any manipulation of the LRU pointers
18467c478bd9Sstevel@tonic-gate * and hash bucket pointers are only done when holding the
18477c478bd9Sstevel@tonic-gate * ctx_mutex.
18487c478bd9Sstevel@tonic-gate */
18497c478bd9Sstevel@tonic-gate next = cl->lru_prev;
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate mutex_enter(&cl->clm);
18527c478bd9Sstevel@tonic-gate
18537c478bd9Sstevel@tonic-gate if ((cl->expiration != GSS_C_INDEFINITE &&
18547c478bd9Sstevel@tonic-gate cl->expiration <= now) || cl->stale ||
18557c478bd9Sstevel@tonic-gate cl->last_ref_time <= last_reference_needed) {
18567c478bd9Sstevel@tonic-gate
18577c478bd9Sstevel@tonic-gate if ((cl->expiration != GSS_C_INDEFINITE &&
18587c478bd9Sstevel@tonic-gate cl->expiration <= now) || cl->stale ||
18597c478bd9Sstevel@tonic-gate (cl->last_ref_time <= last_reference_needed &&
18607c478bd9Sstevel@tonic-gate cl->ref_cnt == 0)) {
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate cl->stale = TRUE;
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate if (cl->ref_cnt == 0) {
18657c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
18667c478bd9Sstevel@tonic-gate if (from_reclaim)
18677c478bd9Sstevel@tonic-gate svc_rpc_gss_cache_stats.
18687c478bd9Sstevel@tonic-gate no_returned_by_reclaim++;
18697c478bd9Sstevel@tonic-gate destroy_client(cl);
18707c478bd9Sstevel@tonic-gate } else
18717c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
18727c478bd9Sstevel@tonic-gate } else
18737c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
18747c478bd9Sstevel@tonic-gate } else
18757c478bd9Sstevel@tonic-gate mutex_exit(&cl->clm);
18767c478bd9Sstevel@tonic-gate
18777c478bd9Sstevel@tonic-gate cl = next;
18787c478bd9Sstevel@tonic-gate }
18797c478bd9Sstevel@tonic-gate
18807c478bd9Sstevel@tonic-gate last_swept = gethrestime_sec();
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate
18837c478bd9Sstevel@tonic-gate /*
18847c478bd9Sstevel@tonic-gate * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
18857c478bd9Sstevel@tonic-gate * and write the result to xdrs.
18867c478bd9Sstevel@tonic-gate */
18877c478bd9Sstevel@tonic-gate static bool_t
svc_rpc_gss_wrap(SVCAUTH * auth,XDR * out_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)18884a3b0527SAndy Fiddaman svc_rpc_gss_wrap(SVCAUTH *auth, XDR *out_xdrs, bool_t (*xdr_func)(),
18894a3b0527SAndy Fiddaman caddr_t xdr_ptr)
18907c478bd9Sstevel@tonic-gate {
18917c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1892bfd8310aSGlenn Barry bool_t ret;
18937c478bd9Sstevel@tonic-gate
18947c478bd9Sstevel@tonic-gate /*
18957c478bd9Sstevel@tonic-gate * If context is not established, or if neither integrity nor
18967c478bd9Sstevel@tonic-gate * privacy service is used, don't wrap - just XDR encode.
18977c478bd9Sstevel@tonic-gate * Otherwise, wrap data using service and QOP parameters.
18987c478bd9Sstevel@tonic-gate */
18994a3b0527SAndy Fiddaman if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
19007c478bd9Sstevel@tonic-gate return ((*xdr_func)(out_xdrs, xdr_ptr));
19017c478bd9Sstevel@tonic-gate
1902bfd8310aSGlenn Barry ret = __rpc_gss_wrap_data(gss_parms->service,
19034a3b0527SAndy Fiddaman (OM_uint32)gss_parms->qop_rcvd,
19044a3b0527SAndy Fiddaman (gss_ctx_id_t)gss_parms->context,
19054a3b0527SAndy Fiddaman gss_parms->seq_num,
19064a3b0527SAndy Fiddaman out_xdrs, xdr_func, xdr_ptr);
1907bfd8310aSGlenn Barry return (ret);
19087c478bd9Sstevel@tonic-gate }
19097c478bd9Sstevel@tonic-gate
19107c478bd9Sstevel@tonic-gate /*
19117c478bd9Sstevel@tonic-gate * Decrypt the serialized arguments and XDR decode them.
19127c478bd9Sstevel@tonic-gate */
19137c478bd9Sstevel@tonic-gate static bool_t
svc_rpc_gss_unwrap(SVCAUTH * auth,XDR * in_xdrs,bool_t (* xdr_func)(),caddr_t xdr_ptr)19144a3b0527SAndy Fiddaman svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(),
19154a3b0527SAndy Fiddaman caddr_t xdr_ptr)
19167c478bd9Sstevel@tonic-gate {
19177c478bd9Sstevel@tonic-gate svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
19187c478bd9Sstevel@tonic-gate
19197c478bd9Sstevel@tonic-gate /*
19207c478bd9Sstevel@tonic-gate * If context is not established, or if neither integrity nor
19217c478bd9Sstevel@tonic-gate * privacy service is used, don't unwrap - just XDR decode.
19227c478bd9Sstevel@tonic-gate * Otherwise, unwrap data.
19237c478bd9Sstevel@tonic-gate */
19244a3b0527SAndy Fiddaman if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
19257c478bd9Sstevel@tonic-gate return ((*xdr_func)(in_xdrs, xdr_ptr));
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate return (__rpc_gss_unwrap_data(gss_parms->service,
19284a3b0527SAndy Fiddaman (gss_ctx_id_t)gss_parms->context,
19294a3b0527SAndy Fiddaman gss_parms->seq_num,
19304a3b0527SAndy Fiddaman gss_parms->qop_rcvd,
19314a3b0527SAndy Fiddaman in_xdrs, xdr_func, xdr_ptr));
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate /* ARGSUSED */
19367c478bd9Sstevel@tonic-gate int
rpc_gss_svc_max_data_length(struct svc_req * req,int max_tp_unit_len)19377c478bd9Sstevel@tonic-gate rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate return (0);
19407c478bd9Sstevel@tonic-gate }
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate /*
19437c478bd9Sstevel@tonic-gate * Add retransmit entry to the context cache entry for a new xid.
19447c478bd9Sstevel@tonic-gate * If there is already an entry, delete it before adding the new one.
19457c478bd9Sstevel@tonic-gate */
retrans_add(client,xid,result)19467c478bd9Sstevel@tonic-gate static void retrans_add(client, xid, result)
19477c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client;
19487c478bd9Sstevel@tonic-gate uint32_t xid;
19497c478bd9Sstevel@tonic-gate rpc_gss_init_res *result;
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate retrans_entry *rdata;
19527c478bd9Sstevel@tonic-gate
19537c478bd9Sstevel@tonic-gate if (client->retrans_data && client->retrans_data->xid == xid)
19547c478bd9Sstevel@tonic-gate return;
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate if (rdata == NULL)
19597c478bd9Sstevel@tonic-gate return;
19607c478bd9Sstevel@tonic-gate
19617c478bd9Sstevel@tonic-gate rdata->xid = xid;
19627c478bd9Sstevel@tonic-gate rdata->result = *result;
19637c478bd9Sstevel@tonic-gate
19647c478bd9Sstevel@tonic-gate if (result->token.length != 0) {
19657c478bd9Sstevel@tonic-gate GSS_DUP_BUFFER(rdata->result.token, result->token);
19667c478bd9Sstevel@tonic-gate }
19677c478bd9Sstevel@tonic-gate
19687c478bd9Sstevel@tonic-gate if (client->retrans_data)
19697c478bd9Sstevel@tonic-gate retrans_del(client);
19707c478bd9Sstevel@tonic-gate
19717c478bd9Sstevel@tonic-gate client->retrans_data = rdata;
19727c478bd9Sstevel@tonic-gate }
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate /*
19757c478bd9Sstevel@tonic-gate * Delete the retransmit data from the context cache entry.
19767c478bd9Sstevel@tonic-gate */
retrans_del(client)19777c478bd9Sstevel@tonic-gate static void retrans_del(client)
19787c478bd9Sstevel@tonic-gate svc_rpc_gss_data *client;
19797c478bd9Sstevel@tonic-gate {
19807c478bd9Sstevel@tonic-gate retrans_entry *rdata;
19817c478bd9Sstevel@tonic-gate OM_uint32 minor_stat;
19827c478bd9Sstevel@tonic-gate
19837c478bd9Sstevel@tonic-gate if (client->retrans_data == NULL)
19847c478bd9Sstevel@tonic-gate return;
19857c478bd9Sstevel@tonic-gate
19867c478bd9Sstevel@tonic-gate rdata = client->retrans_data;
19877c478bd9Sstevel@tonic-gate if (rdata->result.token.length != 0) {
19887c478bd9Sstevel@tonic-gate (void) gss_release_buffer(&minor_stat, &rdata->result.token);
19897c478bd9Sstevel@tonic-gate }
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate kmem_free((caddr_t)rdata, sizeof (*rdata));
19927c478bd9Sstevel@tonic-gate client->retrans_data = NULL;
19937c478bd9Sstevel@tonic-gate }
19947c478bd9Sstevel@tonic-gate
19957c478bd9Sstevel@tonic-gate /*
19967c478bd9Sstevel@tonic-gate * This function frees the following fields of svc_rpc_gss_data:
19977c478bd9Sstevel@tonic-gate * client_name, raw_cred.client_principal, raw_cred.mechanism.
19987c478bd9Sstevel@tonic-gate */
19997c478bd9Sstevel@tonic-gate static void
common_client_data_free(svc_rpc_gss_data * client_data)20007c478bd9Sstevel@tonic-gate common_client_data_free(svc_rpc_gss_data *client_data)
20017c478bd9Sstevel@tonic-gate {
20027c478bd9Sstevel@tonic-gate if (client_data->client_name.length > 0) {
20037c478bd9Sstevel@tonic-gate (void) gss_release_buffer(NULL, &client_data->client_name);
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate
20067c478bd9Sstevel@tonic-gate if (client_data->raw_cred.client_principal) {
20077c478bd9Sstevel@tonic-gate kmem_free((caddr_t)client_data->raw_cred.client_principal,
2008bfd8310aSGlenn Barry client_data->raw_cred.client_principal->len +
2009bfd8310aSGlenn Barry sizeof (int));
20107c478bd9Sstevel@tonic-gate client_data->raw_cred.client_principal = NULL;
20117c478bd9Sstevel@tonic-gate }
20127c478bd9Sstevel@tonic-gate
20137c478bd9Sstevel@tonic-gate /*
20147c478bd9Sstevel@tonic-gate * In the user GSS-API library, mechanism (mech_type returned
20157c478bd9Sstevel@tonic-gate * by gss_accept_sec_context) is static storage, however
20167c478bd9Sstevel@tonic-gate * since all the work is done for gss_accept_sec_context under
20177c478bd9Sstevel@tonic-gate * gssd, what is returned in the kernel, is a copy from the oid
20187c478bd9Sstevel@tonic-gate * obtained under from gssd, so need to free it when destroying
20197c478bd9Sstevel@tonic-gate * the client data.
20207c478bd9Sstevel@tonic-gate */
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate if (client_data->raw_cred.mechanism) {
20237c478bd9Sstevel@tonic-gate kgss_free_oid(client_data->raw_cred.mechanism);
20247c478bd9Sstevel@tonic-gate client_data->raw_cred.mechanism = NULL;
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate }
2027