1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25/*
26 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
27 *
28 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
29 */
30
31/*
32 * Server side handling of RPCSEC_GSS flavor.
33 */
34
35#include <sys/systm.h>
36#include <sys/kstat.h>
37#include <sys/cmn_err.h>
38#include <sys/debug.h>
39#include <sys/types.h>
40#include <sys/time.h>
41#include <gssapi/gssapi.h>
42#include <gssapi/gssapi_ext.h>
43#include <rpc/rpc.h>
44#include <rpc/rpcsec_defs.h>
45#include <sys/sunddi.h>
46#include <sys/atomic.h>
47
48extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
49
50#ifdef	DEBUG
51extern void prom_printf();
52#endif
53
54#ifdef  _KERNEL
55#define	memcmp(a, b, l) bcmp((a), (b), (l))
56#endif
57
58
59/*
60 * Sequence window definitions.
61 */
62#define	SEQ_ARR_SIZE	4
63#define	SEQ_WIN		(SEQ_ARR_SIZE*32)
64#define	SEQ_HI_BIT	0x80000000
65#define	SEQ_LO_BIT	1
66#define	DIV_BY_32	5
67#define	SEQ_MASK	0x1f
68#define	SEQ_MAX		((unsigned int)0x80000000)
69
70
71/* cache retransmit data */
72typedef struct _retrans_entry {
73	uint32_t	xid;
74	rpc_gss_init_res result;
75} retrans_entry;
76
77/*
78 * Server side RPCSEC_GSS context information.
79 */
80typedef struct _svc_rpc_gss_data {
81	struct _svc_rpc_gss_data	*next, *prev;
82	struct _svc_rpc_gss_data	*lru_next, *lru_prev;
83	bool_t				established;
84	gss_ctx_id_t			context;
85	gss_buffer_desc			client_name;
86	time_t				expiration;
87	uint_t				seq_num;
88	uint_t				seq_bits[SEQ_ARR_SIZE];
89	uint_t				key;
90	OM_uint32			qop;
91	bool_t				done_docallback;
92	bool_t				locked;
93	rpc_gss_rawcred_t		raw_cred;
94	rpc_gss_ucred_t			u_cred;
95	time_t				u_cred_set;
96	void				*cookie;
97	gss_cred_id_t			deleg;
98	kmutex_t			clm;
99	int				ref_cnt;
100	time_t				last_ref_time;
101	bool_t				stale;
102	retrans_entry			*retrans_data;
103} svc_rpc_gss_data;
104
105/*
106 * Data structures used for LRU based context management.
107 */
108
109
110#define	HASH(key) ((key) % svc_rpc_gss_hashmod)
111/* Size of hash table for svc_rpc_gss_data structures */
112#define	GSS_DATA_HASH_SIZE	1024
113
114/*
115 * The following two defines specify a time delta that is used in
116 * sweep_clients. When the last_ref_time of a context is older than
117 * than the current time minus the delta, i.e, the context has not
118 * been referenced in the last delta seconds, we will return the
119 * context back to the cache if the ref_cnt is zero. The first delta
120 * value will be used when sweep_clients is called from
121 * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
122 * all entries except those that are currently "active". By active we
123 * mean those that have been referenced in the last ACTIVE_DELTA
124 * seconds. If sweep_client is not being called from reclaim, then we
125 * will reclaim all entries that are "inactive". By inactive we mean
126 * those entries that have not been accessed in INACTIVE_DELTA
127 * seconds.  Note we always assume that ACTIVE_DELTA is less than
128 * INACTIVE_DELTA, so that reaping entries from a reclaim operation
129 * will necessarily imply reaping all "inactive" entries and then
130 * some.
131 */
132
133/*
134 * If low on memory reap cache entries that have not been active for
135 * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
136 */
137#define	ACTIVE_DELTA		30*60		/* 30 minutes */
138
139/*
140 * If in sweeping contexts we find contexts with a ref_cnt equal to zero
141 * and the context has not been referenced in INACTIVE_DELTA seconds, return
142 * the entry to the cache.
143 */
144#define	INACTIVE_DELTA		8*60*60		/* 8 hours */
145
146int				svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
147static svc_rpc_gss_data		**clients;
148static svc_rpc_gss_data		*lru_first, *lru_last;
149static time_t			sweep_interval = 60*60;
150static time_t			last_swept = 0;
151static int			num_gss_contexts = 0;
152static time_t			svc_rpcgss_gid_timeout = 60*60*12;
153static kmem_cache_t		*svc_data_handle;
154static time_t			svc_rpc_gss_active_delta = ACTIVE_DELTA;
155static time_t			svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
156
157/*
158 * lock used with context/lru variables
159 */
160static kmutex_t			ctx_mutex;
161
162/*
163 * Data structure to contain cache statistics
164 */
165
166static struct {
167	int64_t total_entries_allocated;
168	int64_t no_reclaims;
169	int64_t no_returned_by_reclaim;
170} svc_rpc_gss_cache_stats;
171
172
173/*
174 * lock used with server credential variables list
175 *
176 * server cred list locking guidelines:
177 * - Writer's lock holder has exclusive access to the list
178 */
179static krwlock_t		cred_lock;
180
181/*
182 * server callback list
183 */
184typedef struct rpc_gss_cblist_s {
185	struct rpc_gss_cblist_s		*next;
186	rpc_gss_callback_t	cb;
187} rpc_gss_cblist_t;
188
189static rpc_gss_cblist_t			*rpc_gss_cblist = NULL;
190
191/*
192 * lock used with callback variables
193 */
194static kmutex_t			cb_mutex;
195
196/*
197 * forward declarations
198 */
199static bool_t			svc_rpc_gss_wrap();
200static bool_t			svc_rpc_gss_unwrap();
201static svc_rpc_gss_data		*create_client();
202static svc_rpc_gss_data		*get_client();
203static svc_rpc_gss_data		*find_client();
204static void			destroy_client();
205static void			sweep_clients(bool_t);
206static void			insert_client();
207static bool_t			check_verf(struct rpc_msg *, gss_ctx_id_t,
208					int *, uid_t);
209static bool_t			set_response_verf();
210static void			retrans_add(svc_rpc_gss_data *, uint32_t,
211					rpc_gss_init_res *);
212static void			retrans_del(svc_rpc_gss_data *);
213static bool_t			transfer_sec_context(svc_rpc_gss_data *);
214static void			common_client_data_free(svc_rpc_gss_data *);
215
216/*
217 * server side wrap/unwrap routines
218 */
219struct svc_auth_ops svc_rpc_gss_ops = {
220	svc_rpc_gss_wrap,
221	svc_rpc_gss_unwrap,
222};
223
224/* taskq(9F) */
225typedef struct svcrpcsec_gss_taskq_arg {
226	SVCXPRT			*rq_xprt;
227	rpc_gss_init_arg	*rpc_call_arg;
228	struct rpc_msg		*msg;
229	svc_rpc_gss_data	*client_data;
230	uint_t			cr_version;
231	rpc_gss_service_t	cr_service;
232} svcrpcsec_gss_taskq_arg_t;
233
234/* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
235int rpcsec_gss_init_taskq_nthreads = 1;
236static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL;
237
238extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
239extern void rpc_msg_free(struct rpc_msg **, int);
240
241/*
242 * from svc_clts.c:
243 * Transport private data.
244 * Kept in xprt->xp_p2buf.
245 */
246struct udp_data {
247	mblk_t	*ud_resp;			/* buffer for response */
248	mblk_t	*ud_inmp;			/* mblk chain of request */
249};
250
251/*ARGSUSED*/
252static int
253svc_gss_data_create(void *buf, void *pdata, int kmflag)
254{
255	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
256
257	mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
258
259	return (0);
260}
261
262/*ARGSUSED*/
263static void
264svc_gss_data_destroy(void *buf, void *pdata)
265{
266	svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
267
268	mutex_destroy(&client_data->clm);
269}
270
271
272/*ARGSUSED*/
273static void
274svc_gss_data_reclaim(void *pdata)
275{
276	mutex_enter(&ctx_mutex);
277
278	svc_rpc_gss_cache_stats.no_reclaims++;
279	sweep_clients(TRUE);
280
281	mutex_exit(&ctx_mutex);
282}
283
284/*
285 *  Init stuff on the server side.
286 */
287void
288svc_gss_init()
289{
290	mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
291	mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
292	rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
293	clients = (svc_rpc_gss_data **)
294	    kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
295	    KM_SLEEP);
296	svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
297	    sizeof (svc_rpc_gss_data), 0,
298	    svc_gss_data_create,
299	    svc_gss_data_destroy,
300	    svc_gss_data_reclaim,
301	    NULL, NULL, 0);
302
303	if (svcrpcsec_gss_init_taskq == NULL) {
304		svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL,
305		    "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads,
306		    TASKQ_DEFAULTPRI, 0);
307		if (svcrpcsec_gss_init_taskq == NULL)
308			cmn_err(CE_NOTE,
309			    "svc_gss_init: ddi_taskq_create failed");
310	}
311}
312
313/*
314 * Destroy structures allocated in svc_gss_init().
315 * This routine is called by _init() if mod_install() failed.
316 */
317void
318svc_gss_fini()
319{
320	mutex_destroy(&cb_mutex);
321	mutex_destroy(&ctx_mutex);
322	rw_destroy(&cred_lock);
323	kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
324	kmem_cache_destroy(svc_data_handle);
325}
326
327/*
328 * Cleanup routine for destroying context, called after service
329 * procedure is executed. Actually we just decrement the reference count
330 * associated with this context. If the reference count is zero and the
331 * context is marked as stale, we would then destroy the context. Additionally,
332 * we check if its been longer than sweep_interval since the last sweep_clients
333 * was run, and if so run sweep_clients to free all stale contexts with zero
334 * reference counts or contexts that are old. (Haven't been access in
335 * svc_rpc_inactive_delta seconds).
336 */
337void
338rpc_gss_cleanup(SVCXPRT *clone_xprt)
339{
340	svc_rpc_gss_data	*cl;
341	SVCAUTH			*svcauth;
342
343	/*
344	 * First check if current context needs to be cleaned up.
345	 * There might be other threads stale this client data
346	 * in between.
347	 */
348	svcauth = &clone_xprt->xp_auth;
349	mutex_enter(&ctx_mutex);
350	if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
351		mutex_enter(&cl->clm);
352		ASSERT(cl->ref_cnt > 0);
353		if (--cl->ref_cnt == 0 && cl->stale) {
354			mutex_exit(&cl->clm);
355			destroy_client(cl);
356			svcauth->svc_ah_private = NULL;
357		} else
358			mutex_exit(&cl->clm);
359	}
360
361	/*
362	 * Check for other expired contexts.
363	 */
364	if ((gethrestime_sec() - last_swept) > sweep_interval)
365		sweep_clients(FALSE);
366
367	mutex_exit(&ctx_mutex);
368}
369
370/*
371 * Shift the array arr of length arrlen right by nbits bits.
372 */
373static void
374shift_bits(arr, arrlen, nbits)
375	uint_t	*arr;
376	int	arrlen;
377	int	nbits;
378{
379	int	i, j;
380	uint_t	lo, hi;
381
382	/*
383	 * If the number of bits to be shifted exceeds SEQ_WIN, just
384	 * zero out the array.
385	 */
386	if (nbits < SEQ_WIN) {
387		for (i = 0; i < nbits; i++) {
388			hi = 0;
389			for (j = 0; j < arrlen; j++) {
390				lo = arr[j] & SEQ_LO_BIT;
391				arr[j] >>= 1;
392				if (hi)
393					arr[j] |= SEQ_HI_BIT;
394				hi = lo;
395			}
396		}
397	} else {
398		for (j = 0; j < arrlen; j++)
399			arr[j] = 0;
400	}
401}
402
403/*
404 * Check that the received sequence number seq_num is valid.
405 */
406static bool_t
407check_seq(cl, seq_num, kill_context)
408	svc_rpc_gss_data	*cl;
409	uint_t			seq_num;
410	bool_t			*kill_context;
411{
412	int			i, j;
413	uint_t			bit;
414
415	/*
416	 * If it exceeds the maximum, kill context.
417	 */
418	if (seq_num >= SEQ_MAX) {
419		*kill_context = TRUE;
420		RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
421		return (FALSE);
422	}
423
424	/*
425	 * If greater than the last seen sequence number, just shift
426	 * the sequence window so that it starts at the new sequence
427	 * number and extends downwards by SEQ_WIN.
428	 */
429	if (seq_num > cl->seq_num) {
430		(void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
431				(int)(seq_num - cl->seq_num));
432		cl->seq_bits[0] |= SEQ_HI_BIT;
433		cl->seq_num = seq_num;
434		return (TRUE);
435	}
436
437	/*
438	 * If it is outside the sequence window, return failure.
439	 */
440	i = cl->seq_num - seq_num;
441	if (i >= SEQ_WIN) {
442		RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
443		return (FALSE);
444	}
445
446	/*
447	 * If within sequence window, set the bit corresponding to it
448	 * if not already seen;  if already seen, return failure.
449	 */
450	j = SEQ_MASK - (i & SEQ_MASK);
451	bit = j > 0 ? (1 << j) : 1;
452	i >>= DIV_BY_32;
453	if (cl->seq_bits[i] & bit) {
454		RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
455		return (FALSE);
456	}
457	cl->seq_bits[i] |= bit;
458	return (TRUE);
459}
460
461/*
462 * Set server callback.
463 */
464bool_t
465rpc_gss_set_callback(cb)
466	rpc_gss_callback_t	*cb;
467{
468	rpc_gss_cblist_t		*cbl, *tmp;
469
470	if (cb->callback == NULL) {
471		RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
472		return (FALSE);
473	}
474
475	/* check if there is already an entry in the rpc_gss_cblist. */
476	mutex_enter(&cb_mutex);
477	if (rpc_gss_cblist) {
478		for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
479			if ((tmp->cb.callback == cb->callback) &&
480			    (tmp->cb.version == cb->version) &&
481			    (tmp->cb.program == cb->program)) {
482				mutex_exit(&cb_mutex);
483				return (TRUE);
484			}
485		}
486	}
487
488	/* Not in rpc_gss_cblist.  Create a new entry. */
489	if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
490	    == NULL) {
491		mutex_exit(&cb_mutex);
492		return (FALSE);
493	}
494	cbl->cb = *cb;
495	cbl->next = rpc_gss_cblist;
496	rpc_gss_cblist = cbl;
497	mutex_exit(&cb_mutex);
498	return (TRUE);
499}
500
501/*
502 * Locate callback (if specified) and call server.  Release any
503 * delegated credentials unless passed to server and the server
504 * accepts the context.  If a callback is not specified, accept
505 * the incoming context.
506 */
507static bool_t
508do_callback(req, client_data)
509	struct svc_req		*req;
510	svc_rpc_gss_data	*client_data;
511{
512	rpc_gss_cblist_t		*cbl;
513	bool_t			ret = TRUE, found = FALSE;
514	rpc_gss_lock_t		lock;
515	OM_uint32		minor;
516	mutex_enter(&cb_mutex);
517	for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
518		if (req->rq_prog != cbl->cb.program ||
519					req->rq_vers != cbl->cb.version)
520			continue;
521		found = TRUE;
522		lock.locked = FALSE;
523		lock.raw_cred = &client_data->raw_cred;
524		ret = (*cbl->cb.callback)(req, client_data->deleg,
525			client_data->context, &lock, &client_data->cookie);
526		req->rq_xprt->xp_cookie = client_data->cookie;
527
528		if (ret) {
529			client_data->locked = lock.locked;
530			client_data->deleg = GSS_C_NO_CREDENTIAL;
531		}
532		break;
533	}
534	if (!found) {
535		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
536			(void) kgss_release_cred(&minor, &client_data->deleg,
537					crgetuid(CRED()));
538			client_data->deleg = GSS_C_NO_CREDENTIAL;
539		}
540	}
541	mutex_exit(&cb_mutex);
542	return (ret);
543}
544
545/*
546 * Get caller credentials.
547 */
548bool_t
549rpc_gss_getcred(req, rcred, ucred, cookie)
550	struct svc_req		*req;
551	rpc_gss_rawcred_t	**rcred;
552	rpc_gss_ucred_t		**ucred;
553	void			**cookie;
554{
555	SVCAUTH			*svcauth;
556	svc_rpc_gss_data	*client_data;
557	int			gssstat, gidlen;
558
559	svcauth = &req->rq_xprt->xp_auth;
560	client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
561
562	mutex_enter(&client_data->clm);
563
564	if (rcred != NULL) {
565		svcauth->raw_cred = client_data->raw_cred;
566		*rcred = &svcauth->raw_cred;
567	}
568	if (ucred != NULL) {
569		*ucred = &client_data->u_cred;
570
571		if (client_data->u_cred_set == 0 ||
572		    client_data->u_cred_set < gethrestime_sec()) {
573		    if (client_data->u_cred_set == 0) {
574			if ((gssstat = kgsscred_expname_to_unix_cred(
575			    &client_data->client_name,
576			    &client_data->u_cred.uid,
577			    &client_data->u_cred.gid,
578			    &client_data->u_cred.gidlist,
579			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
580				RPCGSS_LOG(1, "rpc_gss_getcred: "
581				    "kgsscred_expname_to_unix_cred failed %x\n",
582				    gssstat);
583				*ucred = NULL;
584			} else {
585				client_data->u_cred.gidlen = (short)gidlen;
586				client_data->u_cred_set =
587				    gethrestime_sec() + svc_rpcgss_gid_timeout;
588			}
589		    } else if (client_data->u_cred_set < gethrestime_sec()) {
590			if ((gssstat = kgss_get_group_info(
591			    client_data->u_cred.uid,
592			    &client_data->u_cred.gid,
593			    &client_data->u_cred.gidlist,
594			    &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
595				RPCGSS_LOG(1, "rpc_gss_getcred: "
596				    "kgss_get_group_info failed %x\n",
597				    gssstat);
598				*ucred = NULL;
599			} else {
600				client_data->u_cred.gidlen = (short)gidlen;
601				client_data->u_cred_set =
602				    gethrestime_sec() + svc_rpcgss_gid_timeout;
603			}
604		    }
605		}
606	}
607
608	if (cookie != NULL)
609		*cookie = client_data->cookie;
610	req->rq_xprt->xp_cookie = client_data->cookie;
611
612	mutex_exit(&client_data->clm);
613
614	return (TRUE);
615}
616
617/*
618 * Transfer the context data from the user land to the kernel.
619 */
620bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
621
622	gss_buffer_desc process_token;
623	OM_uint32 gssstat, minor;
624
625	/*
626	 * Call kgss_export_sec_context
627	 * if an error is returned log a message
628	 * go to error handling
629	 * Otherwise call kgss_import_sec_context to
630	 * convert the token into a context
631	 */
632	gssstat  = kgss_export_sec_context(&minor, client_data->context,
633				&process_token);
634	/*
635	 * if export_sec_context returns an error we delete the
636	 * context just to be safe.
637	 */
638	if (gssstat == GSS_S_NAME_NOT_MN) {
639		RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
640				"Kernel mod unavailable\n");
641
642	} else if (gssstat != GSS_S_COMPLETE) {
643		RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed  "
644				" gssstat = 0x%x\n", gssstat);
645		(void) gss_release_buffer(&minor, &process_token);
646		(void) kgss_delete_sec_context(&minor, &client_data->context,
647				NULL);
648		return (FALSE);
649
650	} else if (process_token.length == 0) {
651		RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
652				"for export_sec_context, but "
653				"gsstat == GSS_S_COMPLETE\n");
654		(void) kgss_delete_sec_context(&minor, &client_data->context,
655				NULL);
656		return (FALSE);
657
658	} else {
659		gssstat = kgss_import_sec_context(&minor, &process_token,
660					client_data->context);
661		if (gssstat != GSS_S_COMPLETE) {
662			RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
663				" failed gssstat = 0x%x\n", gssstat);
664			(void) kgss_delete_sec_context(&minor,
665				&client_data->context, NULL);
666			(void) gss_release_buffer(&minor, &process_token);
667			return (FALSE);
668		}
669
670		RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
671		(void) gss_release_buffer(&minor, &process_token);
672	}
673
674	return (TRUE);
675}
676
677/*
678 * do_gss_accept is called from a taskq and does all the work for a
679 * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
680 */
681static enum auth_stat
682do_gss_accept(
683	SVCXPRT *xprt,
684	rpc_gss_init_arg *call_arg,
685	struct rpc_msg *msg,
686	svc_rpc_gss_data *client_data,
687	uint_t cr_version,
688	rpc_gss_service_t cr_service)
689{
690	rpc_gss_init_res	call_res;
691	gss_buffer_desc		output_token;
692	OM_uint32		gssstat, minor, minor_stat, time_rec;
693	int			ret_flags, ret;
694	gss_OID 		mech_type = GSS_C_NULL_OID;
695	int			free_mech_type = 1;
696	struct svc_req		r, *rqst;
697
698	rqst = &r;
699	rqst->rq_xprt = xprt;
700
701	/*
702	 * Initialize output_token.
703	 */
704	output_token.length = 0;
705	output_token.value = NULL;
706
707	bzero((char *)&call_res, sizeof (call_res));
708
709	mutex_enter(&client_data->clm);
710	if (client_data->stale) {
711		ret = RPCSEC_GSS_NOCRED;
712		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
713		goto error2;
714	}
715
716	/*
717	 * Any response we send will use ctx_handle, so set it now;
718	 * also set seq_window since this won't change.
719	 */
720	call_res.ctx_handle.length = sizeof (client_data->key);
721	call_res.ctx_handle.value = (char *)&client_data->key;
722	call_res.seq_window = SEQ_WIN;
723
724	gssstat = GSS_S_FAILURE;
725	minor = 0;
726	minor_stat = 0;
727	rw_enter(&cred_lock, RW_READER);
728
729	if (client_data->client_name.length) {
730		(void) gss_release_buffer(&minor,
731		    &client_data->client_name);
732	}
733	gssstat = kgss_accept_sec_context(&minor_stat,
734	    &client_data->context,
735	    GSS_C_NO_CREDENTIAL,
736	    call_arg,
737	    GSS_C_NO_CHANNEL_BINDINGS,
738	    &client_data->client_name,
739	    &mech_type,
740	    &output_token,
741	    &ret_flags,
742	    &time_rec,
743	    NULL,		/* don't need a delegated cred back */
744	    crgetuid(CRED()));
745
746	RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
747
748	if (gssstat == GSS_S_COMPLETE) {
749		/*
750		 * Set the raw and unix credentials at this
751		 * point.  This saves a lot of computation
752		 * later when credentials are retrieved.
753		 */
754		client_data->raw_cred.version = cr_version;
755		client_data->raw_cred.service = cr_service;
756
757		if (client_data->raw_cred.mechanism) {
758			kgss_free_oid(client_data->raw_cred.mechanism);
759			client_data->raw_cred.mechanism = NULL;
760		}
761		client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
762		/*
763		 * client_data is now responsible for freeing
764		 * the data of 'mech_type'.
765		 */
766		free_mech_type = 0;
767
768		if (client_data->raw_cred.client_principal) {
769			kmem_free((caddr_t)client_data->\
770			    raw_cred.client_principal,
771			    client_data->raw_cred.\
772			    client_principal->len + sizeof (int));
773			client_data->raw_cred.client_principal = NULL;
774		}
775
776		/*
777		 *  The client_name returned from
778		 *  kgss_accept_sec_context() is in an
779		 *  exported flat format.
780		 */
781		if (! __rpc_gss_make_principal(
782		    &client_data->raw_cred.client_principal,
783		    &client_data->client_name)) {
784			RPCGSS_LOG0(1, "_svcrpcsec_gss: "
785			    "make principal failed\n");
786			gssstat = GSS_S_FAILURE;
787			(void) gss_release_buffer(&minor_stat, &output_token);
788		}
789	}
790
791	rw_exit(&cred_lock);
792
793	call_res.gss_major = gssstat;
794	call_res.gss_minor = minor_stat;
795
796	if (gssstat != GSS_S_COMPLETE &&
797	    gssstat != GSS_S_CONTINUE_NEEDED) {
798		call_res.ctx_handle.length = 0;
799		call_res.ctx_handle.value = NULL;
800		call_res.seq_window = 0;
801		rpc_gss_display_status(gssstat, minor_stat, mech_type,
802		    crgetuid(CRED()),
803		    "_svc_rpcsec_gss gss_accept_sec_context");
804		(void) svc_sendreply(rqst->rq_xprt,
805		    __xdr_rpc_gss_init_res, (caddr_t)&call_res);
806		client_data->stale = TRUE;
807		ret = AUTH_OK;
808		goto error2;
809	}
810
811	/*
812	 * If appropriate, set established to TRUE *after* sending
813	 * response (otherwise, the client will receive the final
814	 * token encrypted)
815	 */
816	if (gssstat == GSS_S_COMPLETE) {
817		/*
818		 * Context is established.  Set expiration time
819		 * for the context.
820		 */
821		client_data->seq_num = 1;
822		if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
823			client_data->expiration = GSS_C_INDEFINITE;
824		} else {
825			client_data->expiration =
826			    time_rec + gethrestime_sec();
827		}
828
829		if (!transfer_sec_context(client_data)) {
830			ret = RPCSEC_GSS_FAILED;
831			client_data->stale = TRUE;
832			RPCGSS_LOG0(1,
833			    "_svc_rpcsec_gss: transfer sec context failed\n");
834			goto error2;
835		}
836
837		client_data->established = TRUE;
838	}
839
840	/*
841	 * This step succeeded.  Send a response, along with
842	 * a token if there's one.  Don't dispatch.
843	 */
844
845	if (output_token.length != 0)
846		GSS_COPY_BUFFER(call_res.token, output_token);
847
848	/*
849	 * If GSS_S_COMPLETE: set response verifier to
850	 * checksum of SEQ_WIN
851	 */
852	if (gssstat == GSS_S_COMPLETE) {
853		if (!set_response_verf(rqst, msg, client_data,
854		    (uint_t)SEQ_WIN)) {
855			ret = RPCSEC_GSS_FAILED;
856			client_data->stale = TRUE;
857			RPCGSS_LOG0(1,
858			    "_svc_rpcsec_gss:set response verifier failed\n");
859			goto error2;
860		}
861	}
862
863	if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
864	    (caddr_t)&call_res)) {
865		ret = RPCSEC_GSS_FAILED;
866		client_data->stale = TRUE;
867		RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
868		goto error2;
869	}
870
871	/*
872	 * Cache last response in case it is lost and the client
873	 * retries on an established context.
874	 */
875	(void) retrans_add(client_data, msg->rm_xid, &call_res);
876	ASSERT(client_data->ref_cnt > 0);
877	client_data->ref_cnt--;
878	mutex_exit(&client_data->clm);
879
880	(void) gss_release_buffer(&minor_stat, &output_token);
881
882	return (AUTH_OK);
883
884error2:
885	ASSERT(client_data->ref_cnt > 0);
886	client_data->ref_cnt--;
887	mutex_exit(&client_data->clm);
888	(void) gss_release_buffer(&minor_stat, &output_token);
889	if (free_mech_type && mech_type)
890		kgss_free_oid(mech_type);
891
892	return (ret);
893}
894
895static void
896svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
897{
898	enum auth_stat retval;
899	svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
900
901	retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
902	    arg->client_data, arg->cr_version, arg->cr_service);
903	if (retval != AUTH_OK) {
904		cmn_err(CE_NOTE,
905		    "svcrpcsec_gss_taskq_func:  do_gss_accept fail 0x%x",
906		    retval);
907	}
908	rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
909	svc_clone_unlink(arg->rq_xprt);
910	svc_clone_free(arg->rq_xprt);
911	xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
912	kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
913
914	kmem_free(arg, sizeof (*arg));
915}
916
917static enum auth_stat
918rpcsec_gss_init(
919	struct svc_req		*rqst,
920	struct rpc_msg		*msg,
921	rpc_gss_creds		creds,
922	bool_t			*no_dispatch,
923	svc_rpc_gss_data	*c_d) /* client data, can be NULL */
924{
925	svc_rpc_gss_data	*client_data;
926	int ret;
927	svcrpcsec_gss_taskq_arg_t *arg;
928
929	if (creds.ctx_handle.length != 0) {
930		RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
931		ret = AUTH_BADCRED;
932		return (ret);
933	}
934
935	client_data = c_d ? c_d : create_client();
936	if (client_data == NULL) {
937		RPCGSS_LOG0(1,
938		    "_svcrpcsec_gss: can't create a new cache entry\n");
939		ret = AUTH_FAILED;
940		return (ret);
941	}
942
943	mutex_enter(&client_data->clm);
944	if (client_data->stale) {
945		ret = RPCSEC_GSS_NOCRED;
946		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
947		goto error2;
948	}
949
950	/*
951	 * kgss_accept_sec_context()/gssd(1M) can be overly time
952	 * consuming so let's queue it and return asap.
953	 *
954	 * taskq func must free arg.
955	 */
956	arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
957
958	/* taskq func must free rpc_call_arg & deserialized arguments */
959	arg->rpc_call_arg = kmem_alloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
960
961	/* deserialize arguments */
962	bzero(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
963	if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
964	    (caddr_t)arg->rpc_call_arg)) {
965		ret = RPCSEC_GSS_FAILED;
966		client_data->stale = TRUE;
967		goto error2;
968	}
969
970	/* get a xprt clone for taskq thread, taskq func must free it */
971	arg->rq_xprt = svc_clone_init();
972	svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
973	arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
974
975
976	/* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
977	arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
978	arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
979
980	/* get a dup of rpc msg for taskq thread */
981	arg->msg = rpc_msg_dup(msg);  /* taskq func must free msg dup */
982
983	arg->client_data = client_data;
984	arg->cr_version = creds.version;
985	arg->cr_service = creds.service;
986
987	/* We no longer need the xp_xdrin, destroy it all here. */
988	XDR_DESTROY(&(rqst->rq_xprt->xp_xdrin));
989
990	/* should be ok to hold clm lock as taskq will have new thread(s) */
991	ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
992	    svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
993	if (ret == DDI_FAILURE) {
994		cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
995		ret = RPCSEC_GSS_FAILED;
996		rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
997		svc_clone_unlink(arg->rq_xprt);
998		svc_clone_free(arg->rq_xprt);
999		kmem_free(arg, sizeof (*arg));
1000		goto error2;
1001	}
1002
1003	mutex_exit(&client_data->clm);
1004	*no_dispatch = TRUE;
1005	return (AUTH_OK);
1006
1007error2:
1008	ASSERT(client_data->ref_cnt > 0);
1009	client_data->ref_cnt--;
1010	mutex_exit(&client_data->clm);
1011	cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1012	return (ret);
1013}
1014
1015static enum auth_stat
1016rpcsec_gss_continue_init(
1017	struct svc_req		*rqst,
1018	struct rpc_msg		*msg,
1019	rpc_gss_creds		creds,
1020	bool_t			*no_dispatch)
1021{
1022	int ret;
1023	svc_rpc_gss_data	*client_data;
1024	svc_rpc_gss_parms_t	*gss_parms;
1025	rpc_gss_init_res	*retrans_result;
1026
1027	if (creds.ctx_handle.length == 0) {
1028		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1029		ret = AUTH_BADCRED;
1030		return (ret);
1031	}
1032	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1033		ret = RPCSEC_GSS_NOCRED;
1034		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1035		return (ret);
1036	}
1037
1038	mutex_enter(&client_data->clm);
1039	if (client_data->stale) {
1040		ret = RPCSEC_GSS_NOCRED;
1041		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1042		goto error2;
1043	}
1044
1045	/*
1046	 * If context not established, go thru INIT code but with
1047	 * this client handle.
1048	 */
1049	if (!client_data->established) {
1050		mutex_exit(&client_data->clm);
1051		return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1052		    client_data));
1053	}
1054
1055	/*
1056	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1057	 */
1058	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1059	rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1060
1061	/*
1062	 * Keep copy of parameters we'll need for response, for the
1063	 * sake of reentrancy (we don't want to look in the context
1064	 * data because when we are sending a response, another
1065	 * request may have come in).
1066	 */
1067	gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1068	gss_parms->established = client_data->established;
1069	gss_parms->service = creds.service;
1070	gss_parms->qop_rcvd = (uint_t)client_data->qop;
1071	gss_parms->context = (void *)client_data->context;
1072	gss_parms->seq_num = creds.seq_num;
1073
1074	/*
1075	 * This is an established context. Continue to
1076	 * satisfy retried continue init requests out of
1077	 * the retransmit cache.  Throw away any that don't
1078	 * have a matching xid or the cach is empty.
1079	 * Delete the retransmit cache once the client sends
1080	 * a data request.
1081	 */
1082	if (client_data->retrans_data &&
1083	    (client_data->retrans_data->xid == msg->rm_xid)) {
1084		retrans_result = &client_data->retrans_data->result;
1085		if (set_response_verf(rqst, msg, client_data,
1086		    (uint_t)retrans_result->seq_window)) {
1087			gss_parms->established = FALSE;
1088			(void) svc_sendreply(rqst->rq_xprt,
1089			    __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
1090			*no_dispatch = TRUE;
1091			ASSERT(client_data->ref_cnt > 0);
1092			client_data->ref_cnt--;
1093		}
1094	}
1095	mutex_exit(&client_data->clm);
1096
1097	return (AUTH_OK);
1098
1099error2:
1100	ASSERT(client_data->ref_cnt > 0);
1101	client_data->ref_cnt--;
1102	mutex_exit(&client_data->clm);
1103	return (ret);
1104}
1105
1106static enum auth_stat
1107rpcsec_gss_data(
1108	struct svc_req		*rqst,
1109	struct rpc_msg		*msg,
1110	rpc_gss_creds		creds,
1111	bool_t			*no_dispatch)
1112{
1113	int ret;
1114	svc_rpc_gss_parms_t	*gss_parms;
1115	svc_rpc_gss_data	*client_data;
1116
1117	switch (creds.service) {
1118	case rpc_gss_svc_none:
1119	case rpc_gss_svc_integrity:
1120	case rpc_gss_svc_privacy:
1121		break;
1122	default:
1123		cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1124		    creds.service);
1125		RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1126		    creds.service);
1127		ret = AUTH_BADCRED;
1128		return (ret);
1129	}
1130
1131	if (creds.ctx_handle.length == 0) {
1132		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1133		ret = AUTH_BADCRED;
1134		return (ret);
1135	}
1136	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1137		ret = RPCSEC_GSS_NOCRED;
1138		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1139		return (ret);
1140	}
1141
1142
1143	mutex_enter(&client_data->clm);
1144	if (!client_data->established) {
1145		ret = AUTH_FAILED;
1146		goto error2;
1147	}
1148	if (client_data->stale) {
1149		ret = RPCSEC_GSS_NOCRED;
1150		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1151		goto error2;
1152	}
1153
1154	/*
1155	 * Once the context is established and there is no more
1156	 * retransmission of last continue init request, it is safe
1157	 * to delete the retransmit cache entry.
1158	 */
1159	if (client_data->retrans_data)
1160		retrans_del(client_data);
1161
1162	/*
1163	 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1164	 */
1165	rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1166	rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1167
1168	/*
1169	 * Keep copy of parameters we'll need for response, for the
1170	 * sake of reentrancy (we don't want to look in the context
1171	 * data because when we are sending a response, another
1172	 * request may have come in).
1173	 */
1174	gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1175	gss_parms->established = client_data->established;
1176	gss_parms->service = creds.service;
1177	gss_parms->qop_rcvd = (uint_t)client_data->qop;
1178	gss_parms->context = (void *)client_data->context;
1179	gss_parms->seq_num = creds.seq_num;
1180
1181	/*
1182	 * Context is already established.  Check verifier, and
1183	 * note parameters we will need for response in gss_parms.
1184	 */
1185	if (!check_verf(msg, client_data->context,
1186	    (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1187		ret = RPCSEC_GSS_NOCRED;
1188		RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1189		goto error2;
1190	}
1191
1192	/*
1193	 *  Check and invoke callback if necessary.
1194	 */
1195	if (!client_data->done_docallback) {
1196		client_data->done_docallback = TRUE;
1197		client_data->qop = gss_parms->qop_rcvd;
1198		client_data->raw_cred.qop = gss_parms->qop_rcvd;
1199		client_data->raw_cred.service = creds.service;
1200		if (!do_callback(rqst, client_data)) {
1201			ret = AUTH_FAILED;
1202			RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1203			goto error2;
1204		}
1205	}
1206
1207	/*
1208	 * If the context was locked, make sure that the client
1209	 * has not changed QOP.
1210	 */
1211	if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1212		ret = AUTH_BADVERF;
1213		RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1214		goto error2;
1215	}
1216
1217	/*
1218	 * Validate sequence number.
1219	 */
1220	if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1221		if (client_data->stale) {
1222			ret = RPCSEC_GSS_FAILED;
1223			RPCGSS_LOG0(1,
1224			    "_svc_rpcsec_gss:check seq failed\n");
1225		} else {
1226			RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1227			    "failed on good context. Ignoring "
1228			    "request\n");
1229			/*
1230			 * Operational error, drop packet silently.
1231			 * The client will recover after timing out,
1232			 * assuming this is a client error and not
1233			 * a relpay attack.  Don't dispatch.
1234			 */
1235			ret = AUTH_OK;
1236			*no_dispatch = TRUE;
1237		}
1238		goto error2;
1239	}
1240
1241	/*
1242	 * set response verifier
1243	 */
1244	if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1245		ret = RPCSEC_GSS_FAILED;
1246		client_data->stale = TRUE;
1247		RPCGSS_LOG0(1,
1248		    "_svc_rpcsec_gss:set response verifier failed\n");
1249		goto error2;
1250	}
1251
1252	/*
1253	 * If context is locked, make sure that the client
1254	 * has not changed the security service.
1255	 */
1256	if (client_data->locked &&
1257	    client_data->raw_cred.service != creds.service) {
1258		RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1259		    "security service changed.\n");
1260		ret = AUTH_FAILED;
1261		goto error2;
1262	}
1263
1264	/*
1265	 * Set client credentials to raw credential
1266	 * structure in context.  This is okay, since
1267	 * this will not change during the lifetime of
1268	 * the context (so it's MT safe).
1269	 */
1270	rqst->rq_clntcred = (char *)&client_data->raw_cred;
1271
1272	mutex_exit(&client_data->clm);
1273	return (AUTH_OK);
1274
1275error2:
1276	ASSERT(client_data->ref_cnt > 0);
1277	client_data->ref_cnt--;
1278	mutex_exit(&client_data->clm);
1279	return (ret);
1280}
1281
1282/*
1283 * Note we don't have a client yet to use this routine and test it.
1284 */
1285static enum auth_stat
1286rpcsec_gss_destroy(
1287	struct svc_req		*rqst,
1288	rpc_gss_creds		creds,
1289	bool_t			*no_dispatch)
1290{
1291	svc_rpc_gss_data	*client_data;
1292	int ret;
1293
1294	if (creds.ctx_handle.length == 0) {
1295		RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1296		ret = AUTH_BADCRED;
1297		return (ret);
1298	}
1299	if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1300		ret = RPCSEC_GSS_NOCRED;
1301		RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1302		return (ret);
1303	}
1304
1305	mutex_enter(&client_data->clm);
1306	if (!client_data->established) {
1307		ret = AUTH_FAILED;
1308		goto error2;
1309	}
1310	if (client_data->stale) {
1311		ret = RPCSEC_GSS_NOCRED;
1312		RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1313		goto error2;
1314	}
1315
1316	(void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1317	*no_dispatch = TRUE;
1318	ASSERT(client_data->ref_cnt > 0);
1319	client_data->ref_cnt--;
1320	client_data->stale = TRUE;
1321	mutex_exit(&client_data->clm);
1322	return (AUTH_OK);
1323
1324error2:
1325	ASSERT(client_data->ref_cnt > 0);
1326	client_data->ref_cnt--;
1327	client_data->stale = TRUE;
1328	mutex_exit(&client_data->clm);
1329	return (ret);
1330}
1331
1332/*
1333 * Server side authentication for RPCSEC_GSS.
1334 */
1335enum auth_stat
1336__svcrpcsec_gss(
1337	struct svc_req		*rqst,
1338	struct rpc_msg		*msg,
1339	bool_t			*no_dispatch)
1340{
1341	XDR			xdrs;
1342	rpc_gss_creds		creds;
1343	struct opaque_auth	*cred;
1344	int			ret;
1345
1346	*no_dispatch = FALSE;
1347
1348	/*
1349	 * Initialize response verifier to NULL verifier.  If
1350	 * necessary, this will be changed later.
1351	 */
1352	rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1353	rqst->rq_xprt->xp_verf.oa_base = NULL;
1354	rqst->rq_xprt->xp_verf.oa_length = 0;
1355
1356	/*
1357	 * Pull out and check credential and verifier.
1358	 */
1359	cred = &msg->rm_call.cb_cred;
1360
1361	if (cred->oa_length == 0) {
1362		RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1363		return (AUTH_BADCRED);
1364	}
1365
1366	xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1367	bzero((char *)&creds, sizeof (creds));
1368	if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1369		XDR_DESTROY(&xdrs);
1370		RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1371		ret = AUTH_BADCRED;
1372		return (AUTH_BADCRED);
1373	}
1374	XDR_DESTROY(&xdrs);
1375
1376	switch (creds.gss_proc) {
1377	case RPCSEC_GSS_INIT:
1378		ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1379		break;
1380	case RPCSEC_GSS_CONTINUE_INIT:
1381		ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1382		break;
1383	case RPCSEC_GSS_DATA:
1384		ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1385		break;
1386	case RPCSEC_GSS_DESTROY:
1387		ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1388		break;
1389	default:
1390		cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1391		    creds.gss_proc);
1392		ret = AUTH_BADCRED;
1393	}
1394
1395	if (creds.ctx_handle.length != 0)
1396		xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1397	return (ret);
1398}
1399
1400/*
1401 * Check verifier.  The verifier is the checksum of the RPC header
1402 * upto and including the credentials field.
1403 */
1404
1405/* ARGSUSED */
1406static bool_t
1407check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1408{
1409	int			*buf, *tmp;
1410	char			hdr[128];
1411	struct opaque_auth	*oa;
1412	int			len;
1413	gss_buffer_desc		msg_buf;
1414	gss_buffer_desc		tok_buf;
1415	OM_uint32		gssstat, minor_stat;
1416
1417	/*
1418	 * We have to reconstruct the RPC header from the previously
1419	 * parsed information, since we haven't kept the header intact.
1420	 */
1421
1422	oa = &msg->rm_call.cb_cred;
1423	if (oa->oa_length > MAX_AUTH_BYTES)
1424		return (FALSE);
1425
1426	/* 8 XDR units from the IXDR macro calls. */
1427	if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1428	    RNDUP(oa->oa_length)))
1429		return (FALSE);
1430	buf = (int *)hdr;
1431	IXDR_PUT_U_INT32(buf, msg->rm_xid);
1432	IXDR_PUT_ENUM(buf, msg->rm_direction);
1433	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1434	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1435	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1436	IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1437	IXDR_PUT_ENUM(buf, oa->oa_flavor);
1438	IXDR_PUT_U_INT32(buf, oa->oa_length);
1439	if (oa->oa_length) {
1440		len = RNDUP(oa->oa_length);
1441		tmp = buf;
1442		buf += len / sizeof (int);
1443		*(buf - 1) = 0;
1444		(void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1445	}
1446	len = ((char *)buf) - hdr;
1447	msg_buf.length = len;
1448	msg_buf.value = hdr;
1449	oa = &msg->rm_call.cb_verf;
1450	tok_buf.length = oa->oa_length;
1451	tok_buf.value = oa->oa_base;
1452
1453	gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1454	    qop_state);
1455	if (gssstat != GSS_S_COMPLETE) {
1456		RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1457
1458		RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1459		RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1460		RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1461		    tok_buf.length);
1462		RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1463		    (void *)oa->oa_base);
1464		RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1465
1466		return (FALSE);
1467	}
1468	return (TRUE);
1469}
1470
1471
1472/*
1473 * Set response verifier.  This is the checksum of the given number.
1474 * (e.g. sequence number or sequence window)
1475 */
1476static bool_t
1477set_response_verf(rqst, msg, cl, num)
1478	struct svc_req		*rqst;
1479	struct rpc_msg		*msg;
1480	svc_rpc_gss_data	*cl;
1481	uint_t			num;
1482{
1483	OM_uint32		minor;
1484	gss_buffer_desc		in_buf, out_buf;
1485	uint_t			num_net;
1486
1487	num_net = (uint_t)htonl(num);
1488	in_buf.length = sizeof (num);
1489	in_buf.value = (char *)&num_net;
1490/* XXX uid ? */
1491
1492	if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf,
1493				&out_buf)) != GSS_S_COMPLETE)
1494		return (FALSE);
1495
1496	rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1497	rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1498	rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1499	bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1500	(void) gss_release_buffer(&minor, &out_buf);
1501	return (TRUE);
1502}
1503
1504/*
1505 * Create client context.
1506 */
1507static svc_rpc_gss_data *
1508create_client()
1509{
1510	svc_rpc_gss_data	*client_data;
1511	static uint_t		key = 1;
1512
1513	client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1514	    KM_SLEEP);
1515	if (client_data == NULL)
1516		return (NULL);
1517
1518	/*
1519	 * set up client data structure
1520	 */
1521	client_data->next = NULL;
1522	client_data->prev = NULL;
1523	client_data->lru_next = NULL;
1524	client_data->lru_prev = NULL;
1525	client_data->client_name.length = 0;
1526	client_data->client_name.value = NULL;
1527	client_data->seq_num = 0;
1528	bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1529	client_data->key = 0;
1530	client_data->cookie = NULL;
1531	bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1532	client_data->established = FALSE;
1533	client_data->locked = FALSE;
1534	client_data->u_cred_set = 0;
1535	client_data->context = GSS_C_NO_CONTEXT;
1536	client_data->expiration = GSS_C_INDEFINITE;
1537	client_data->deleg = GSS_C_NO_CREDENTIAL;
1538	client_data->ref_cnt = 1;
1539	client_data->last_ref_time = gethrestime_sec();
1540	client_data->qop = GSS_C_QOP_DEFAULT;
1541	client_data->done_docallback = FALSE;
1542	client_data->stale = FALSE;
1543	client_data->retrans_data = NULL;
1544	bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1545
1546	/*
1547	 * The client context handle is a 32-bit key (unsigned int).
1548	 * The key is incremented until there is no duplicate for it.
1549	 */
1550
1551	svc_rpc_gss_cache_stats.total_entries_allocated++;
1552	mutex_enter(&ctx_mutex);
1553	for (;;) {
1554		client_data->key = key++;
1555		if (find_client(client_data->key) == NULL) {
1556			insert_client(client_data);
1557			mutex_exit(&ctx_mutex);
1558			return (client_data);
1559		}
1560	}
1561	/*NOTREACHED*/
1562}
1563
1564/*
1565 * Insert client context into hash list and LRU list.
1566 */
1567static void
1568insert_client(client_data)
1569	svc_rpc_gss_data	*client_data;
1570{
1571	svc_rpc_gss_data	*cl;
1572	int			index = HASH(client_data->key);
1573
1574	ASSERT(mutex_owned(&ctx_mutex));
1575
1576	client_data->prev = NULL;
1577	cl = clients[index];
1578	if ((client_data->next = cl) != NULL)
1579		cl->prev = client_data;
1580	clients[index] = client_data;
1581
1582	client_data->lru_prev = NULL;
1583	if ((client_data->lru_next = lru_first) != NULL)
1584		lru_first->lru_prev = client_data;
1585	else
1586		lru_last = client_data;
1587	lru_first = client_data;
1588
1589	num_gss_contexts++;
1590}
1591
1592/*
1593 * Fetch a client, given the client context handle.  Move it to the
1594 * top of the LRU list since this is the most recently used context.
1595 */
1596static svc_rpc_gss_data *
1597get_client(ctx_handle)
1598	gss_buffer_t		ctx_handle;
1599{
1600	uint_t			key = *(uint_t *)ctx_handle->value;
1601	svc_rpc_gss_data	*cl;
1602
1603	mutex_enter(&ctx_mutex);
1604	if ((cl = find_client(key)) != NULL) {
1605		mutex_enter(&cl->clm);
1606		if (cl->stale) {
1607			if (cl->ref_cnt == 0) {
1608				mutex_exit(&cl->clm);
1609				destroy_client(cl);
1610			} else {
1611				mutex_exit(&cl->clm);
1612			}
1613			mutex_exit(&ctx_mutex);
1614			return (NULL);
1615		}
1616		cl->ref_cnt++;
1617		cl->last_ref_time = gethrestime_sec();
1618		mutex_exit(&cl->clm);
1619		if (cl != lru_first) {
1620			cl->lru_prev->lru_next = cl->lru_next;
1621			if (cl->lru_next != NULL)
1622				cl->lru_next->lru_prev = cl->lru_prev;
1623			else
1624				lru_last = cl->lru_prev;
1625			cl->lru_prev = NULL;
1626			cl->lru_next = lru_first;
1627			lru_first->lru_prev = cl;
1628			lru_first = cl;
1629		}
1630	}
1631	mutex_exit(&ctx_mutex);
1632	return (cl);
1633}
1634
1635/*
1636 * Given the client context handle, find the context corresponding to it.
1637 * Don't change its LRU state since it may not be used.
1638 */
1639static svc_rpc_gss_data *
1640find_client(key)
1641	uint_t			key;
1642{
1643	int			index = HASH(key);
1644	svc_rpc_gss_data	*cl = NULL;
1645
1646	ASSERT(mutex_owned(&ctx_mutex));
1647
1648	for (cl = clients[index]; cl != NULL; cl = cl->next) {
1649		if (cl->key == key)
1650			break;
1651	}
1652	return (cl);
1653}
1654
1655/*
1656 * Destroy a client context.
1657 */
1658static void
1659destroy_client(client_data)
1660	svc_rpc_gss_data	*client_data;
1661{
1662	OM_uint32		minor;
1663	int			index = HASH(client_data->key);
1664
1665	ASSERT(mutex_owned(&ctx_mutex));
1666
1667	/*
1668	 * remove from hash list
1669	 */
1670	if (client_data->prev == NULL)
1671		clients[index] = client_data->next;
1672	else
1673		client_data->prev->next = client_data->next;
1674	if (client_data->next != NULL)
1675		client_data->next->prev = client_data->prev;
1676
1677	/*
1678	 * remove from LRU list
1679	 */
1680	if (client_data->lru_prev == NULL)
1681		lru_first = client_data->lru_next;
1682	else
1683		client_data->lru_prev->lru_next = client_data->lru_next;
1684	if (client_data->lru_next != NULL)
1685		client_data->lru_next->lru_prev = client_data->lru_prev;
1686	else
1687		lru_last = client_data->lru_prev;
1688
1689	/*
1690	 * If there is a GSS context, clean up GSS state.
1691	 */
1692	if (client_data->context != GSS_C_NO_CONTEXT) {
1693		(void) kgss_delete_sec_context(&minor, &client_data->context,
1694					NULL);
1695
1696		common_client_data_free(client_data);
1697
1698		if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1699		    (void) kgss_release_cred(&minor, &client_data->deleg,
1700				crgetuid(CRED()));
1701		}
1702	}
1703
1704	if (client_data->u_cred.gidlist != NULL) {
1705	    kmem_free((char *)client_data->u_cred.gidlist,
1706			client_data->u_cred.gidlen * sizeof (gid_t));
1707	    client_data->u_cred.gidlist = NULL;
1708	}
1709	if (client_data->retrans_data != NULL)
1710		retrans_del(client_data);
1711
1712	kmem_cache_free(svc_data_handle, client_data);
1713	num_gss_contexts--;
1714}
1715
1716/*
1717 * Check for expired and stale client contexts.
1718 */
1719static void
1720sweep_clients(bool_t from_reclaim)
1721{
1722	svc_rpc_gss_data	*cl, *next;
1723	time_t			last_reference_needed;
1724	time_t			now = gethrestime_sec();
1725
1726	ASSERT(mutex_owned(&ctx_mutex));
1727
1728	last_reference_needed = now - (from_reclaim ?
1729	    svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
1730
1731	cl = lru_last;
1732	while (cl) {
1733		/*
1734		 * We assume here that any manipulation of the LRU pointers
1735		 * and hash bucket pointers are only done when holding the
1736		 * ctx_mutex.
1737		 */
1738		next = cl->lru_prev;
1739
1740		mutex_enter(&cl->clm);
1741
1742		if ((cl->expiration != GSS_C_INDEFINITE &&
1743		    cl->expiration <= now) || cl->stale ||
1744		    cl->last_ref_time <= last_reference_needed) {
1745
1746			if ((cl->expiration != GSS_C_INDEFINITE &&
1747			    cl->expiration <= now) || cl->stale ||
1748			    (cl->last_ref_time <= last_reference_needed &&
1749			    cl->ref_cnt == 0)) {
1750
1751				cl->stale = TRUE;
1752
1753				if (cl->ref_cnt == 0) {
1754					mutex_exit(&cl->clm);
1755					if (from_reclaim)
1756						svc_rpc_gss_cache_stats.
1757						    no_returned_by_reclaim++;
1758					destroy_client(cl);
1759				} else
1760					mutex_exit(&cl->clm);
1761			} else
1762				mutex_exit(&cl->clm);
1763		} else
1764			mutex_exit(&cl->clm);
1765
1766		cl = next;
1767	}
1768
1769	last_swept = gethrestime_sec();
1770}
1771
1772/*
1773 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1774 * and write the result to xdrs.
1775 */
1776static bool_t
1777svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1778	SVCAUTH			*auth;
1779	XDR			*out_xdrs;
1780	bool_t			(*xdr_func)();
1781	caddr_t			xdr_ptr;
1782{
1783	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1784	bool_t ret;
1785
1786	/*
1787	 * If context is not established, or if neither integrity nor
1788	 * privacy service is used, don't wrap - just XDR encode.
1789	 * Otherwise, wrap data using service and QOP parameters.
1790	 */
1791	if (!gss_parms->established ||
1792				gss_parms->service == rpc_gss_svc_none)
1793		return ((*xdr_func)(out_xdrs, xdr_ptr));
1794
1795	ret = __rpc_gss_wrap_data(gss_parms->service,
1796				(OM_uint32)gss_parms->qop_rcvd,
1797				(gss_ctx_id_t)gss_parms->context,
1798				gss_parms->seq_num,
1799				out_xdrs, xdr_func, xdr_ptr);
1800	return (ret);
1801}
1802
1803/*
1804 * Decrypt the serialized arguments and XDR decode them.
1805 */
1806static bool_t
1807svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1808	SVCAUTH			*auth;
1809	XDR			*in_xdrs;
1810	bool_t			(*xdr_func)();
1811	caddr_t			xdr_ptr;
1812{
1813	svc_rpc_gss_parms_t	*gss_parms = SVCAUTH_GSSPARMS(auth);
1814
1815	/*
1816	 * If context is not established, or if neither integrity nor
1817	 * privacy service is used, don't unwrap - just XDR decode.
1818	 * Otherwise, unwrap data.
1819	 */
1820	if (!gss_parms->established ||
1821				gss_parms->service == rpc_gss_svc_none)
1822		return ((*xdr_func)(in_xdrs, xdr_ptr));
1823
1824	return (__rpc_gss_unwrap_data(gss_parms->service,
1825				(gss_ctx_id_t)gss_parms->context,
1826				gss_parms->seq_num,
1827				gss_parms->qop_rcvd,
1828				in_xdrs, xdr_func, xdr_ptr));
1829}
1830
1831
1832/* ARGSUSED */
1833int
1834rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1835{
1836	return (0);
1837}
1838
1839/*
1840 * Add retransmit entry to the context cache entry for a new xid.
1841 * If there is already an entry, delete it before adding the new one.
1842 */
1843static void retrans_add(client, xid, result)
1844	svc_rpc_gss_data *client;
1845	uint32_t	xid;
1846	rpc_gss_init_res *result;
1847{
1848	retrans_entry	*rdata;
1849
1850	if (client->retrans_data && client->retrans_data->xid == xid)
1851		return;
1852
1853	rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1854
1855	if (rdata == NULL)
1856		return;
1857
1858	rdata->xid = xid;
1859	rdata->result = *result;
1860
1861	if (result->token.length != 0) {
1862		GSS_DUP_BUFFER(rdata->result.token, result->token);
1863	}
1864
1865	if (client->retrans_data)
1866		retrans_del(client);
1867
1868	client->retrans_data = rdata;
1869}
1870
1871/*
1872 * Delete the retransmit data from the context cache entry.
1873 */
1874static void retrans_del(client)
1875	svc_rpc_gss_data *client;
1876{
1877	retrans_entry *rdata;
1878	OM_uint32 minor_stat;
1879
1880	if (client->retrans_data == NULL)
1881		return;
1882
1883	rdata = client->retrans_data;
1884	if (rdata->result.token.length != 0) {
1885	    (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1886	}
1887
1888	kmem_free((caddr_t)rdata, sizeof (*rdata));
1889	client->retrans_data = NULL;
1890}
1891
1892/*
1893 * This function frees the following fields of svc_rpc_gss_data:
1894 *	client_name, raw_cred.client_principal, raw_cred.mechanism.
1895 */
1896static void
1897common_client_data_free(svc_rpc_gss_data *client_data)
1898{
1899	if (client_data->client_name.length > 0) {
1900		(void) gss_release_buffer(NULL, &client_data->client_name);
1901	}
1902
1903	if (client_data->raw_cred.client_principal) {
1904		kmem_free((caddr_t)client_data->raw_cred.client_principal,
1905		    client_data->raw_cred.client_principal->len +
1906		    sizeof (int));
1907		client_data->raw_cred.client_principal = NULL;
1908	}
1909
1910	/*
1911	 * In the user GSS-API library, mechanism (mech_type returned
1912	 * by gss_accept_sec_context) is static storage, however
1913	 * since all the work is done for gss_accept_sec_context under
1914	 * gssd, what is returned in the kernel, is a copy from the oid
1915	 * obtained under from gssd, so need to free it when destroying
1916	 * the client data.
1917	 */
1918
1919	if (client_data->raw_cred.mechanism) {
1920		kgss_free_oid(client_data->raw_cred.mechanism);
1921		client_data->raw_cred.mechanism = NULL;
1922	}
1923}
1924