xref: /freebsd/sys/rpc/rpcsec_gss/rpcsec_gss.c (revision 7aa383846770374466b1dcb2cefd71bde9acf463)
1 /*-
2  * Copyright (c) 2008 Doug Rabson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27   auth_gss.c
28 
29   RPCSEC_GSS client routines.
30 
31   Copyright (c) 2000 The Regents of the University of Michigan.
32   All rights reserved.
33 
34   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
35   All rights reserved, all wrongs reversed.
36 
37   Redistribution and use in source and binary forms, with or without
38   modification, are permitted provided that the following conditions
39   are met:
40 
41   1. Redistributions of source code must retain the above copyright
42      notice, this list of conditions and the following disclaimer.
43   2. Redistributions in binary form must reproduce the above copyright
44      notice, this list of conditions and the following disclaimer in the
45      documentation and/or other materials provided with the distribution.
46   3. Neither the name of the University nor the names of its
47      contributors may be used to endorse or promote products derived
48      from this software without specific prior written permission.
49 
50   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
51   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
57   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 
62   $Id: auth_gss.c,v 1.32 2002/01/15 15:43:00 andros Exp $
63 */
64 
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
67 
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/hash.h>
71 #include <sys/kernel.h>
72 #include <sys/kobj.h>
73 #include <sys/lock.h>
74 #include <sys/malloc.h>
75 #include <sys/mbuf.h>
76 #include <sys/mutex.h>
77 #include <sys/proc.h>
78 #include <sys/refcount.h>
79 #include <sys/sx.h>
80 #include <sys/ucred.h>
81 
82 #include <rpc/rpc.h>
83 #include <rpc/rpcsec_gss.h>
84 
85 #include "rpcsec_gss_int.h"
86 
87 static void	rpc_gss_nextverf(AUTH*);
88 static bool_t	rpc_gss_marshal(AUTH *, uint32_t, XDR *, struct mbuf *);
89 static bool_t	rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret);
90 static bool_t	rpc_gss_refresh(AUTH *, void *);
91 static bool_t	rpc_gss_validate(AUTH *, uint32_t, struct opaque_auth *,
92     struct mbuf **);
93 static void	rpc_gss_destroy(AUTH *);
94 static void	rpc_gss_destroy_context(AUTH *, bool_t);
95 
96 static struct auth_ops rpc_gss_ops = {
97 	rpc_gss_nextverf,
98 	rpc_gss_marshal,
99 	rpc_gss_validate,
100 	rpc_gss_refresh,
101 	rpc_gss_destroy,
102 };
103 
104 enum rpcsec_gss_state {
105 	RPCSEC_GSS_START,
106 	RPCSEC_GSS_CONTEXT,
107 	RPCSEC_GSS_ESTABLISHED,
108 	RPCSEC_GSS_DESTROYING
109 };
110 
111 struct rpc_pending_request {
112 	uint32_t		pr_xid;		/* XID of rpc */
113 	uint32_t		pr_seq;		/* matching GSS seq */
114 	LIST_ENTRY(rpc_pending_request) pr_link;
115 };
116 LIST_HEAD(rpc_pending_request_list, rpc_pending_request);
117 
118 struct rpc_gss_data {
119 	volatile u_int		gd_refs;	/* number of current users */
120 	struct mtx		gd_lock;
121 	uint32_t		gd_hash;
122 	AUTH			*gd_auth;	/* link back to AUTH */
123 	struct ucred		*gd_ucred;	/* matching local cred */
124 	char			*gd_principal;	/* server principal name */
125 	rpc_gss_options_req_t	gd_options;	/* GSS context options */
126 	enum rpcsec_gss_state	gd_state;	/* connection state */
127 	gss_buffer_desc		gd_verf;	/* save GSS_S_COMPLETE
128 						 * NULL RPC verfier to
129 						 * process at end of
130 						 * context negotiation */
131 	CLIENT			*gd_clnt;	/* client handle */
132 	gss_OID			gd_mech;	/* mechanism to use */
133 	gss_qop_t		gd_qop;		/* quality of protection */
134 	gss_ctx_id_t		gd_ctx;		/* context id */
135 	struct rpc_gss_cred	gd_cred;	/* client credentials */
136 	uint32_t		gd_seq;		/* next sequence number */
137 	u_int			gd_win;		/* sequence window */
138 	struct rpc_pending_request_list gd_reqs;
139 	TAILQ_ENTRY(rpc_gss_data) gd_link;
140 	TAILQ_ENTRY(rpc_gss_data) gd_alllink;
141 };
142 TAILQ_HEAD(rpc_gss_data_list, rpc_gss_data);
143 
144 #define	AUTH_PRIVATE(auth)	((struct rpc_gss_data *)auth->ah_private)
145 
146 static struct timeval AUTH_TIMEOUT = { 25, 0 };
147 
148 #define RPC_GSS_HASH_SIZE	11
149 #define RPC_GSS_MAX		256
150 static struct rpc_gss_data_list rpc_gss_cache[RPC_GSS_HASH_SIZE];
151 static struct rpc_gss_data_list rpc_gss_all;
152 static struct sx rpc_gss_lock;
153 static int rpc_gss_count;
154 
155 static AUTH *rpc_gss_seccreate_int(CLIENT *, struct ucred *, const char *,
156     gss_OID, rpc_gss_service_t, u_int, rpc_gss_options_req_t *,
157     rpc_gss_options_ret_t *);
158 
159 static void
160 rpc_gss_hashinit(void *dummy)
161 {
162 	int i;
163 
164 	for (i = 0; i < RPC_GSS_HASH_SIZE; i++)
165 		TAILQ_INIT(&rpc_gss_cache[i]);
166 	TAILQ_INIT(&rpc_gss_all);
167 	sx_init(&rpc_gss_lock, "rpc_gss_lock");
168 }
169 SYSINIT(rpc_gss_hashinit, SI_SUB_KMEM, SI_ORDER_ANY, rpc_gss_hashinit, NULL);
170 
171 static uint32_t
172 rpc_gss_hash(const char *principal, gss_OID mech,
173     struct ucred *cred, rpc_gss_service_t service)
174 {
175 	uint32_t h;
176 
177 	h = HASHSTEP(HASHINIT, cred->cr_uid);
178 	h = hash32_str(principal, h);
179 	h = hash32_buf(mech->elements, mech->length, h);
180 	h = HASHSTEP(h, (int) service);
181 
182 	return (h % RPC_GSS_HASH_SIZE);
183 }
184 
185 /*
186  * Simplified interface to create a security association for the
187  * current thread's * ucred.
188  */
189 AUTH *
190 rpc_gss_secfind(CLIENT *clnt, struct ucred *cred, const char *principal,
191     gss_OID mech_oid, rpc_gss_service_t service)
192 {
193 	uint32_t		h, th;
194 	AUTH			*auth;
195 	struct rpc_gss_data	*gd, *tgd;
196 	rpc_gss_options_ret_t	options;
197 
198 	if (rpc_gss_count > RPC_GSS_MAX) {
199 		while (rpc_gss_count > RPC_GSS_MAX) {
200 			sx_xlock(&rpc_gss_lock);
201 			tgd = TAILQ_FIRST(&rpc_gss_all);
202 			th = tgd->gd_hash;
203 			TAILQ_REMOVE(&rpc_gss_cache[th], tgd, gd_link);
204 			TAILQ_REMOVE(&rpc_gss_all, tgd, gd_alllink);
205 			rpc_gss_count--;
206 			sx_xunlock(&rpc_gss_lock);
207 			AUTH_DESTROY(tgd->gd_auth);
208 		}
209 	}
210 
211 	/*
212 	 * See if we already have an AUTH which matches.
213 	 */
214 	h = rpc_gss_hash(principal, mech_oid, cred, service);
215 
216 again:
217 	sx_slock(&rpc_gss_lock);
218 	TAILQ_FOREACH(gd, &rpc_gss_cache[h], gd_link) {
219 		if (gd->gd_ucred->cr_uid == cred->cr_uid
220 		    && !strcmp(gd->gd_principal, principal)
221 		    && gd->gd_mech == mech_oid
222 		    && gd->gd_cred.gc_svc == service) {
223 			refcount_acquire(&gd->gd_refs);
224 			if (sx_try_upgrade(&rpc_gss_lock)) {
225 				/*
226 				 * Keep rpc_gss_all LRU sorted.
227 				 */
228 				TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink);
229 				TAILQ_INSERT_TAIL(&rpc_gss_all, gd,
230 				    gd_alllink);
231 				sx_xunlock(&rpc_gss_lock);
232 			} else {
233 				sx_sunlock(&rpc_gss_lock);
234 			}
235 
236 			/*
237 			 * If the state != ESTABLISHED, try and initialize
238 			 * the authenticator again. This will happen if the
239 			 * user's credentials have expired. It may succeed now,
240 			 * if they have done a kinit or similar.
241 			 */
242 			if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
243 				memset(&options, 0, sizeof (options));
244 				(void) rpc_gss_init(gd->gd_auth, &options);
245 			}
246 			return (gd->gd_auth);
247 		}
248 	}
249 	sx_sunlock(&rpc_gss_lock);
250 
251 	/*
252 	 * We missed in the cache - create a new association.
253 	 */
254 	auth = rpc_gss_seccreate_int(clnt, cred, principal, mech_oid, service,
255 	    GSS_C_QOP_DEFAULT, NULL, NULL);
256 	if (!auth)
257 		return (NULL);
258 
259 	gd = AUTH_PRIVATE(auth);
260 	gd->gd_hash = h;
261 
262 	sx_xlock(&rpc_gss_lock);
263 	TAILQ_FOREACH(tgd, &rpc_gss_cache[h], gd_link) {
264 		if (tgd->gd_ucred->cr_uid == cred->cr_uid
265 		    && !strcmp(tgd->gd_principal, principal)
266 		    && tgd->gd_mech == mech_oid
267 		    && tgd->gd_cred.gc_svc == service) {
268 			/*
269 			 * We lost a race to create the AUTH that
270 			 * matches this cred.
271 			 */
272 			sx_xunlock(&rpc_gss_lock);
273 			AUTH_DESTROY(auth);
274 			goto again;
275 		}
276 	}
277 
278 	rpc_gss_count++;
279 	TAILQ_INSERT_TAIL(&rpc_gss_cache[h], gd, gd_link);
280 	TAILQ_INSERT_TAIL(&rpc_gss_all, gd, gd_alllink);
281 	refcount_acquire(&gd->gd_refs);	/* one for the cache, one for user */
282 	sx_xunlock(&rpc_gss_lock);
283 
284 	return (auth);
285 }
286 
287 void
288 rpc_gss_secpurge(CLIENT *clnt)
289 {
290 	uint32_t		h;
291 	struct rpc_gss_data	*gd, *tgd;
292 
293 	TAILQ_FOREACH_SAFE(gd, &rpc_gss_all, gd_alllink, tgd) {
294 		if (gd->gd_clnt == clnt) {
295 			sx_xlock(&rpc_gss_lock);
296 			h = gd->gd_hash;
297 			TAILQ_REMOVE(&rpc_gss_cache[h], gd, gd_link);
298 			TAILQ_REMOVE(&rpc_gss_all, gd, gd_alllink);
299 			rpc_gss_count--;
300 			sx_xunlock(&rpc_gss_lock);
301 			AUTH_DESTROY(gd->gd_auth);
302 		}
303 	}
304 }
305 
306 AUTH *
307 rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred, const char *principal,
308     const char *mechanism, rpc_gss_service_t service, const char *qop,
309     rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
310 {
311 	gss_OID			oid;
312 	u_int			qop_num;
313 
314 	/*
315 	 * Bail out now if we don't know this mechanism.
316 	 */
317 	if (!rpc_gss_mech_to_oid(mechanism, &oid))
318 		return (NULL);
319 
320 	if (qop) {
321 		if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num))
322 			return (NULL);
323 	} else {
324 		qop_num = GSS_C_QOP_DEFAULT;
325 	}
326 
327 	return (rpc_gss_seccreate_int(clnt, cred, principal, oid, service,
328 		qop_num, options_req, options_ret));
329 }
330 
331 static AUTH *
332 rpc_gss_seccreate_int(CLIENT *clnt, struct ucred *cred, const char *principal,
333     gss_OID mech_oid, rpc_gss_service_t service, u_int qop_num,
334     rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
335 {
336 	AUTH			*auth;
337 	rpc_gss_options_ret_t	options;
338 	struct rpc_gss_data	*gd;
339 
340 	/*
341 	 * If the caller doesn't want the options, point at local
342 	 * storage to simplify the code below.
343 	 */
344 	if (!options_ret)
345 		options_ret = &options;
346 
347 	/*
348 	 * Default service is integrity.
349 	 */
350 	if (service == rpc_gss_svc_default)
351 		service = rpc_gss_svc_integrity;
352 
353 	memset(options_ret, 0, sizeof(*options_ret));
354 
355 	rpc_gss_log_debug("in rpc_gss_seccreate()");
356 
357 	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
358 
359 	auth = mem_alloc(sizeof(*auth));
360 	if (auth == NULL) {
361 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
362 		rpc_createerr.cf_error.re_errno = ENOMEM;
363 		return (NULL);
364 	}
365 	gd = mem_alloc(sizeof(*gd));
366 	if (gd == NULL) {
367 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
368 		rpc_createerr.cf_error.re_errno = ENOMEM;
369 		mem_free(auth, sizeof(*auth));
370 		return (NULL);
371 	}
372 
373 	auth->ah_ops = &rpc_gss_ops;
374 	auth->ah_private = (caddr_t) gd;
375 	auth->ah_cred.oa_flavor = RPCSEC_GSS;
376 
377 	refcount_init(&gd->gd_refs, 1);
378 	mtx_init(&gd->gd_lock, "gd->gd_lock", NULL, MTX_DEF);
379 	gd->gd_auth = auth;
380 	gd->gd_ucred = crdup(cred);
381 	gd->gd_principal = strdup(principal, M_RPC);
382 
383 
384 	if (options_req) {
385 		gd->gd_options = *options_req;
386 	} else {
387 		gd->gd_options.req_flags = GSS_C_MUTUAL_FLAG;
388 		gd->gd_options.time_req = 0;
389 		gd->gd_options.my_cred = GSS_C_NO_CREDENTIAL;
390 		gd->gd_options.input_channel_bindings = NULL;
391 	}
392 	CLNT_ACQUIRE(clnt);
393 	gd->gd_clnt = clnt;
394 	gd->gd_ctx = GSS_C_NO_CONTEXT;
395 	gd->gd_mech = mech_oid;
396 	gd->gd_qop = qop_num;
397 
398 	gd->gd_cred.gc_version = RPCSEC_GSS_VERSION;
399 	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
400 	gd->gd_cred.gc_seq = 0;
401 	gd->gd_cred.gc_svc = service;
402 	LIST_INIT(&gd->gd_reqs);
403 
404 	if (!rpc_gss_init(auth, options_ret)) {
405 		goto bad;
406 	}
407 
408 	return (auth);
409 
410  bad:
411 	AUTH_DESTROY(auth);
412 	return (NULL);
413 }
414 
415 bool_t
416 rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service, const char *qop)
417 {
418 	struct rpc_gss_data	*gd;
419 	u_int			qop_num;
420 	const char		*mechanism;
421 
422 	gd = AUTH_PRIVATE(auth);
423 	if (!rpc_gss_oid_to_mech(gd->gd_mech, &mechanism)) {
424 		return (FALSE);
425 	}
426 
427 	if (qop) {
428 		if (!rpc_gss_qop_to_num(qop, mechanism, &qop_num)) {
429 			return (FALSE);
430 		}
431 	} else {
432 		qop_num = GSS_C_QOP_DEFAULT;
433 	}
434 
435 	gd->gd_cred.gc_svc = service;
436 	gd->gd_qop = qop_num;
437 	return (TRUE);
438 }
439 
440 static void
441 rpc_gss_purge_xid(struct rpc_gss_data *gd, uint32_t xid)
442 {
443 	struct rpc_pending_request *pr, *npr;
444 	struct rpc_pending_request_list reqs;
445 
446 	LIST_INIT(&reqs);
447 	mtx_lock(&gd->gd_lock);
448 	LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) {
449 		if (pr->pr_xid == xid) {
450 			LIST_REMOVE(pr, pr_link);
451 			LIST_INSERT_HEAD(&reqs, pr, pr_link);
452 		}
453 	}
454 
455 	mtx_unlock(&gd->gd_lock);
456 
457 	LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) {
458 		mem_free(pr, sizeof(*pr));
459 	}
460 }
461 
462 static uint32_t
463 rpc_gss_alloc_seq(struct rpc_gss_data *gd)
464 {
465 	uint32_t seq;
466 
467 	mtx_lock(&gd->gd_lock);
468 	seq = gd->gd_seq;
469 	gd->gd_seq++;
470 	mtx_unlock(&gd->gd_lock);
471 
472 	return (seq);
473 }
474 
475 static void
476 rpc_gss_nextverf(__unused AUTH *auth)
477 {
478 
479 	/* not used */
480 }
481 
482 static bool_t
483 rpc_gss_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args)
484 {
485 	struct rpc_gss_data	*gd;
486 	struct rpc_pending_request *pr;
487 	uint32_t		 seq;
488 	XDR			 tmpxdrs;
489 	struct rpc_gss_cred	 gsscred;
490 	char			 credbuf[MAX_AUTH_BYTES];
491 	struct opaque_auth	 creds, verf;
492 	gss_buffer_desc		 rpcbuf, checksum;
493 	OM_uint32		 maj_stat, min_stat;
494 	bool_t			 xdr_stat;
495 
496 	rpc_gss_log_debug("in rpc_gss_marshal()");
497 
498 	gd = AUTH_PRIVATE(auth);
499 
500 	gsscred = gd->gd_cred;
501 	seq = rpc_gss_alloc_seq(gd);
502 	gsscred.gc_seq = seq;
503 
504 	xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE);
505 	if (!xdr_rpc_gss_cred(&tmpxdrs, &gsscred)) {
506 		XDR_DESTROY(&tmpxdrs);
507 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
508 		return (FALSE);
509 	}
510 	creds.oa_flavor = RPCSEC_GSS;
511 	creds.oa_base = credbuf;
512 	creds.oa_length = XDR_GETPOS(&tmpxdrs);
513 	XDR_DESTROY(&tmpxdrs);
514 
515 	xdr_opaque_auth(xdrs, &creds);
516 
517 	if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT ||
518 	    gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) {
519 		if (!xdr_opaque_auth(xdrs, &_null_auth)) {
520 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
521 			return (FALSE);
522 		}
523 		xdrmbuf_append(xdrs, args);
524 		return (TRUE);
525 	} else {
526 		/*
527 		 * Keep track of this XID + seq pair so that we can do
528 		 * the matching gss_verify_mic in AUTH_VALIDATE.
529 		 */
530 		pr = mem_alloc(sizeof(struct rpc_pending_request));
531 		mtx_lock(&gd->gd_lock);
532 		pr->pr_xid = xid;
533 		pr->pr_seq = seq;
534 		LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link);
535 		mtx_unlock(&gd->gd_lock);
536 
537 		/*
538 		 * Checksum serialized RPC header, up to and including
539 		 * credential. For the in-kernel environment, we
540 		 * assume that our XDR stream is on a contiguous
541 		 * memory buffer (e.g. an mbuf).
542 		 */
543 		rpcbuf.length = XDR_GETPOS(xdrs);
544 		XDR_SETPOS(xdrs, 0);
545 		rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length);
546 
547 		maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop,
548 		    &rpcbuf, &checksum);
549 
550 		if (maj_stat != GSS_S_COMPLETE) {
551 			rpc_gss_log_status("gss_get_mic", gd->gd_mech,
552 			    maj_stat, min_stat);
553 			if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
554 				rpc_gss_destroy_context(auth, TRUE);
555 			}
556 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
557 			return (FALSE);
558 		}
559 
560 		verf.oa_flavor = RPCSEC_GSS;
561 		verf.oa_base = checksum.value;
562 		verf.oa_length = checksum.length;
563 
564 		xdr_stat = xdr_opaque_auth(xdrs, &verf);
565 		gss_release_buffer(&min_stat, &checksum);
566 		if (!xdr_stat) {
567 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
568 			return (FALSE);
569 		}
570 		if (gd->gd_state != RPCSEC_GSS_ESTABLISHED ||
571 		    gd->gd_cred.gc_svc == rpc_gss_svc_none) {
572 			xdrmbuf_append(xdrs, args);
573 			return (TRUE);
574 		} else {
575 			if (!xdr_rpc_gss_wrap_data(&args,
576 				gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc,
577 				seq))
578 				return (FALSE);
579 			xdrmbuf_append(xdrs, args);
580 			return (TRUE);
581 		}
582 	}
583 
584 	return (TRUE);
585 }
586 
587 static bool_t
588 rpc_gss_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf,
589     struct mbuf **resultsp)
590 {
591 	struct rpc_gss_data	*gd;
592 	struct rpc_pending_request *pr, *npr;
593 	struct rpc_pending_request_list reqs;
594 	gss_qop_t		qop_state;
595 	uint32_t		num, seq;
596 	gss_buffer_desc		signbuf, checksum;
597 	OM_uint32		maj_stat, min_stat;
598 
599 	rpc_gss_log_debug("in rpc_gss_validate()");
600 
601 	gd = AUTH_PRIVATE(auth);
602 
603 	/*
604 	 * The client will call us with a NULL verf when it gives up
605 	 * on an XID.
606 	 */
607 	if (!verf) {
608 		rpc_gss_purge_xid(gd, xid);
609 		return (TRUE);
610 	}
611 
612 	if (gd->gd_state == RPCSEC_GSS_CONTEXT) {
613 		/*
614 		 * Save the on the wire verifier to validate last INIT
615 		 * phase packet after decode if the major status is
616 		 * GSS_S_COMPLETE.
617 		 */
618 		if (gd->gd_verf.value)
619 			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
620 			    (char *) &gd->gd_verf);
621 		gd->gd_verf.value = mem_alloc(verf->oa_length);
622 		if (gd->gd_verf.value == NULL) {
623 			printf("gss_validate: out of memory\n");
624 			_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM);
625 			m_freem(*resultsp);
626 			*resultsp = NULL;
627 			return (FALSE);
628 		}
629 		memcpy(gd->gd_verf.value, verf->oa_base, verf->oa_length);
630 		gd->gd_verf.length = verf->oa_length;
631 
632 		return (TRUE);
633 	}
634 
635 	/*
636 	 * We need to check the verifier against all the requests
637 	 * we've send for this XID - for unreliable protocols, we
638 	 * retransmit with the same XID but different sequence
639 	 * number. We temporarily take this set of requests out of the
640 	 * list so that we can work through the list without having to
641 	 * hold the lock.
642 	 */
643 	mtx_lock(&gd->gd_lock);
644 	LIST_INIT(&reqs);
645 	LIST_FOREACH_SAFE(pr, &gd->gd_reqs, pr_link, npr) {
646 		if (pr->pr_xid == xid) {
647 			LIST_REMOVE(pr, pr_link);
648 			LIST_INSERT_HEAD(&reqs, pr, pr_link);
649 		}
650 	}
651 	mtx_unlock(&gd->gd_lock);
652 	LIST_FOREACH(pr, &reqs, pr_link) {
653 		if (pr->pr_xid == xid) {
654 			seq = pr->pr_seq;
655 			num = htonl(seq);
656 			signbuf.value = &num;
657 			signbuf.length = sizeof(num);
658 
659 			checksum.value = verf->oa_base;
660 			checksum.length = verf->oa_length;
661 
662 			maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
663 			    &signbuf, &checksum, &qop_state);
664 			if (maj_stat != GSS_S_COMPLETE
665 			    || qop_state != gd->gd_qop) {
666 				continue;
667 			}
668 			if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
669 				rpc_gss_destroy_context(auth, TRUE);
670 				break;
671 			}
672 			//rpc_gss_purge_reqs(gd, seq);
673 			LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr)
674 				mem_free(pr, sizeof(*pr));
675 
676 			if (gd->gd_cred.gc_svc == rpc_gss_svc_none) {
677 				return (TRUE);
678 			} else {
679 				if (!xdr_rpc_gss_unwrap_data(resultsp,
680 					gd->gd_ctx, gd->gd_qop,
681 					gd->gd_cred.gc_svc, seq)) {
682 					return (FALSE);
683 				}
684 			}
685 			return (TRUE);
686 		}
687 	}
688 
689 	/*
690 	 * We didn't match - put back any entries for this XID so that
691 	 * a future call to validate can retry.
692 	 */
693 	mtx_lock(&gd->gd_lock);
694 	LIST_FOREACH_SAFE(pr, &reqs, pr_link, npr) {
695 		LIST_REMOVE(pr, pr_link);
696 		LIST_INSERT_HEAD(&gd->gd_reqs, pr, pr_link);
697 	}
698 	mtx_unlock(&gd->gd_lock);
699 
700 	/*
701 	 * Nothing matches - give up.
702 	 */
703 	_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
704 	m_freem(*resultsp);
705 	*resultsp = NULL;
706 	return (FALSE);
707 }
708 
709 static bool_t
710 rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
711 {
712 	struct thread		*td = curthread;
713 	struct ucred		*crsave;
714 	struct rpc_gss_data	*gd;
715 	struct rpc_gss_init_res	 gr;
716 	gss_buffer_desc		principal_desc;
717 	gss_buffer_desc		*recv_tokenp, recv_token, send_token;
718 	gss_name_t		name;
719 	OM_uint32		 maj_stat, min_stat, call_stat;
720 	const char		*mech;
721 	struct rpc_callextra	 ext;
722 
723 	rpc_gss_log_debug("in rpc_gss_refresh()");
724 
725 	gd = AUTH_PRIVATE(auth);
726 
727 	mtx_lock(&gd->gd_lock);
728 	/*
729 	 * If the context isn't in START state, someone else is
730 	 * refreshing - we wait till they are done. If they fail, they
731 	 * will put the state back to START and we can try (most
732 	 * likely to also fail).
733 	 */
734 	while (gd->gd_state != RPCSEC_GSS_START
735 	    && gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
736 		msleep(gd, &gd->gd_lock, 0, "gssstate", 0);
737 	}
738 	if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) {
739 		mtx_unlock(&gd->gd_lock);
740 		return (TRUE);
741 	}
742 	gd->gd_state = RPCSEC_GSS_CONTEXT;
743 	mtx_unlock(&gd->gd_lock);
744 
745 	gd->gd_cred.gc_proc = RPCSEC_GSS_INIT;
746 	gd->gd_cred.gc_seq = 0;
747 
748 	principal_desc.value = (void *)gd->gd_principal;
749 	principal_desc.length = strlen(gd->gd_principal);
750 	maj_stat = gss_import_name(&min_stat, &principal_desc,
751 	    GSS_C_NT_HOSTBASED_SERVICE, &name);
752 	if (maj_stat != GSS_S_COMPLETE) {
753 		options_ret->major_status = maj_stat;
754 		options_ret->minor_status = min_stat;
755 		goto out;
756 	}
757 
758 	/* GSS context establishment loop. */
759 	memset(&recv_token, 0, sizeof(recv_token));
760 	memset(&gr, 0, sizeof(gr));
761 	memset(options_ret, 0, sizeof(*options_ret));
762 	options_ret->major_status = GSS_S_FAILURE;
763 	recv_tokenp = GSS_C_NO_BUFFER;
764 
765 	for (;;) {
766 		crsave = td->td_ucred;
767 		td->td_ucred = gd->gd_ucred;
768 		maj_stat = gss_init_sec_context(&min_stat,
769 		    gd->gd_options.my_cred,
770 		    &gd->gd_ctx,
771 		    name,
772 		    gd->gd_mech,
773 		    gd->gd_options.req_flags,
774 		    gd->gd_options.time_req,
775 		    gd->gd_options.input_channel_bindings,
776 		    recv_tokenp,
777 		    &gd->gd_mech,	/* used mech */
778 		    &send_token,
779 		    &options_ret->ret_flags,
780 		    &options_ret->time_req);
781 		td->td_ucred = crsave;
782 
783 		/*
784 		 * Free the token which we got from the server (if
785 		 * any).  Remember that this was allocated by XDR, not
786 		 * GSS-API.
787 		 */
788 		if (recv_tokenp != GSS_C_NO_BUFFER) {
789 			xdr_free((xdrproc_t) xdr_gss_buffer_desc,
790 			    (char *) &recv_token);
791 			recv_tokenp = GSS_C_NO_BUFFER;
792 		}
793 		if (gd->gd_mech && rpc_gss_oid_to_mech(gd->gd_mech, &mech)) {
794 			strlcpy(options_ret->actual_mechanism,
795 			    mech,
796 			    sizeof(options_ret->actual_mechanism));
797 		}
798 		if (maj_stat != GSS_S_COMPLETE &&
799 		    maj_stat != GSS_S_CONTINUE_NEEDED) {
800 			rpc_gss_log_status("gss_init_sec_context", gd->gd_mech,
801 			    maj_stat, min_stat);
802 			options_ret->major_status = maj_stat;
803 			options_ret->minor_status = min_stat;
804 			break;
805 		}
806 		if (send_token.length != 0) {
807 			memset(&gr, 0, sizeof(gr));
808 
809 			bzero(&ext, sizeof(ext));
810 			ext.rc_auth = auth;
811 			call_stat = CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC,
812 			    (xdrproc_t)xdr_gss_buffer_desc,
813 			    &send_token,
814 			    (xdrproc_t)xdr_rpc_gss_init_res,
815 			    (caddr_t)&gr, AUTH_TIMEOUT);
816 
817 			gss_release_buffer(&min_stat, &send_token);
818 
819 			if (call_stat != RPC_SUCCESS)
820 				break;
821 
822 			if (gr.gr_major != GSS_S_COMPLETE &&
823 			    gr.gr_major != GSS_S_CONTINUE_NEEDED) {
824 				rpc_gss_log_status("server reply", gd->gd_mech,
825 				    gr.gr_major, gr.gr_minor);
826 				options_ret->major_status = gr.gr_major;
827 				options_ret->minor_status = gr.gr_minor;
828 				break;
829 			}
830 
831 			/*
832 			 * Save the server's gr_handle value, freeing
833 			 * what we have already (remember that this
834 			 * was allocated by XDR, not GSS-API).
835 			 */
836 			if (gr.gr_handle.length != 0) {
837 				xdr_free((xdrproc_t) xdr_gss_buffer_desc,
838 				    (char *) &gd->gd_cred.gc_handle);
839 				gd->gd_cred.gc_handle = gr.gr_handle;
840 			}
841 
842 			/*
843 			 * Save the server's token as well.
844 			 */
845 			if (gr.gr_token.length != 0) {
846 				recv_token = gr.gr_token;
847 				recv_tokenp = &recv_token;
848 			}
849 
850 			/*
851 			 * Since we have copied out all the bits of gr
852 			 * which XDR allocated for us, we don't need
853 			 * to free it.
854 			 */
855 			gd->gd_cred.gc_proc = RPCSEC_GSS_CONTINUE_INIT;
856 		}
857 
858 		if (maj_stat == GSS_S_COMPLETE) {
859 			gss_buffer_desc   bufin;
860 			u_int seq, qop_state = 0;
861 
862 			/*
863 			 * gss header verifier,
864 			 * usually checked in gss_validate
865 			 */
866 			seq = htonl(gr.gr_win);
867 			bufin.value = (unsigned char *)&seq;
868 			bufin.length = sizeof(seq);
869 
870 			maj_stat = gss_verify_mic(&min_stat, gd->gd_ctx,
871 			    &bufin, &gd->gd_verf, &qop_state);
872 
873 			if (maj_stat != GSS_S_COMPLETE ||
874 			    qop_state != gd->gd_qop) {
875 				rpc_gss_log_status("gss_verify_mic", gd->gd_mech,
876 				    maj_stat, min_stat);
877 				if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
878 					rpc_gss_destroy_context(auth, TRUE);
879 				}
880 				_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR,
881 				    EPERM);
882 				options_ret->major_status = maj_stat;
883 				options_ret->minor_status = min_stat;
884 				break;
885 			}
886 
887 			options_ret->major_status = GSS_S_COMPLETE;
888 			options_ret->minor_status = 0;
889 			options_ret->rpcsec_version = gd->gd_cred.gc_version;
890 			options_ret->gss_context = gd->gd_ctx;
891 
892 			gd->gd_cred.gc_proc = RPCSEC_GSS_DATA;
893 			gd->gd_seq = 1;
894 			gd->gd_win = gr.gr_win;
895 			break;
896 		}
897 	}
898 
899 	gss_release_name(&min_stat, &name);
900 	xdr_free((xdrproc_t) xdr_gss_buffer_desc,
901 	    (char *) &gd->gd_verf);
902 
903 out:
904 	/* End context negotiation loop. */
905 	if (gd->gd_cred.gc_proc != RPCSEC_GSS_DATA) {
906 		rpc_createerr.cf_stat = RPC_AUTHERROR;
907 		_rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM);
908 		if (gd->gd_ctx) {
909 			gss_delete_sec_context(&min_stat, &gd->gd_ctx,
910 				GSS_C_NO_BUFFER);
911 		}
912 		mtx_lock(&gd->gd_lock);
913 		gd->gd_state = RPCSEC_GSS_START;
914 		wakeup(gd);
915 		mtx_unlock(&gd->gd_lock);
916 		return (FALSE);
917 	}
918 
919 	mtx_lock(&gd->gd_lock);
920 	gd->gd_state = RPCSEC_GSS_ESTABLISHED;
921 	wakeup(gd);
922 	mtx_unlock(&gd->gd_lock);
923 
924 	return (TRUE);
925 }
926 
927 static bool_t
928 rpc_gss_refresh(AUTH *auth, void *msg)
929 {
930 	struct rpc_msg *reply = (struct rpc_msg *) msg;
931 	rpc_gss_options_ret_t options;
932 	struct rpc_gss_data *gd;
933 
934 	gd = AUTH_PRIVATE(auth);
935 
936 	/*
937 	 * If the context is in DESTROYING state, then just return, since
938 	 * there is no point in refreshing the credentials.
939 	 */
940 	mtx_lock(&gd->gd_lock);
941 	if (gd->gd_state == RPCSEC_GSS_DESTROYING) {
942 		mtx_unlock(&gd->gd_lock);
943 		return (FALSE);
944 	}
945 	mtx_unlock(&gd->gd_lock);
946 
947 	/*
948 	 * If the error was RPCSEC_GSS_CREDPROBLEM of
949 	 * RPCSEC_GSS_CTXPROBLEM we start again from scratch. All
950 	 * other errors are fatal.
951 	 */
952 	if (reply->rm_reply.rp_stat == MSG_DENIED
953 	    && reply->rm_reply.rp_rjct.rj_stat == AUTH_ERROR
954 	    && (reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CREDPROBLEM
955 		|| reply->rm_reply.rp_rjct.rj_why == RPCSEC_GSS_CTXPROBLEM)) {
956 		rpc_gss_destroy_context(auth, FALSE);
957 		memset(&options, 0, sizeof(options));
958 		return (rpc_gss_init(auth, &options));
959 	}
960 
961 	return (FALSE);
962 }
963 
964 static void
965 rpc_gss_destroy_context(AUTH *auth, bool_t send_destroy)
966 {
967 	struct rpc_gss_data	*gd;
968 	struct rpc_pending_request *pr;
969 	OM_uint32		 min_stat;
970 	struct rpc_callextra	 ext;
971 
972 	rpc_gss_log_debug("in rpc_gss_destroy_context()");
973 
974 	gd = AUTH_PRIVATE(auth);
975 
976 	mtx_lock(&gd->gd_lock);
977 	/*
978 	 * If the context isn't in ESTABISHED state, someone else is
979 	 * destroying/refreshing - we wait till they are done.
980 	 */
981 	if (gd->gd_state != RPCSEC_GSS_ESTABLISHED) {
982 		while (gd->gd_state != RPCSEC_GSS_START
983 		    && gd->gd_state != RPCSEC_GSS_ESTABLISHED)
984 			msleep(gd, &gd->gd_lock, 0, "gssstate", 0);
985 		mtx_unlock(&gd->gd_lock);
986 		return;
987 	}
988 	gd->gd_state = RPCSEC_GSS_DESTROYING;
989 	mtx_unlock(&gd->gd_lock);
990 
991 	if (send_destroy) {
992 		gd->gd_cred.gc_proc = RPCSEC_GSS_DESTROY;
993 		bzero(&ext, sizeof(ext));
994 		ext.rc_auth = auth;
995 		CLNT_CALL_EXT(gd->gd_clnt, &ext, NULLPROC,
996 		    (xdrproc_t)xdr_void, NULL,
997 		    (xdrproc_t)xdr_void, NULL, AUTH_TIMEOUT);
998 	}
999 
1000 	while ((pr = LIST_FIRST(&gd->gd_reqs)) != NULL) {
1001 		LIST_REMOVE(pr, pr_link);
1002 		mem_free(pr, sizeof(*pr));
1003 	}
1004 
1005 	/*
1006 	 * Free the context token. Remember that this was
1007 	 * allocated by XDR, not GSS-API.
1008 	 */
1009 	xdr_free((xdrproc_t) xdr_gss_buffer_desc,
1010 	    (char *) &gd->gd_cred.gc_handle);
1011 	gd->gd_cred.gc_handle.length = 0;
1012 
1013 	if (gd->gd_ctx != GSS_C_NO_CONTEXT)
1014 		gss_delete_sec_context(&min_stat, &gd->gd_ctx, NULL);
1015 
1016 	mtx_lock(&gd->gd_lock);
1017 	gd->gd_state = RPCSEC_GSS_START;
1018 	wakeup(gd);
1019 	mtx_unlock(&gd->gd_lock);
1020 }
1021 
1022 static void
1023 rpc_gss_destroy(AUTH *auth)
1024 {
1025 	struct rpc_gss_data	*gd;
1026 
1027 	rpc_gss_log_debug("in rpc_gss_destroy()");
1028 
1029 	gd = AUTH_PRIVATE(auth);
1030 
1031 	if (!refcount_release(&gd->gd_refs))
1032 		return;
1033 
1034 	rpc_gss_destroy_context(auth, TRUE);
1035 
1036 	CLNT_RELEASE(gd->gd_clnt);
1037 	crfree(gd->gd_ucred);
1038 	free(gd->gd_principal, M_RPC);
1039 	if (gd->gd_verf.value)
1040 		xdr_free((xdrproc_t) xdr_gss_buffer_desc,
1041 		    (char *) &gd->gd_verf);
1042 	mtx_destroy(&gd->gd_lock);
1043 
1044 	mem_free(gd, sizeof(*gd));
1045 	mem_free(auth, sizeof(*auth));
1046 }
1047 
1048 int
1049 rpc_gss_max_data_length(AUTH *auth, int max_tp_unit_len)
1050 {
1051 	struct rpc_gss_data	*gd;
1052 	int			want_conf;
1053 	OM_uint32		max;
1054 	OM_uint32		maj_stat, min_stat;
1055 	int			result;
1056 
1057 	gd = AUTH_PRIVATE(auth);
1058 
1059 	switch (gd->gd_cred.gc_svc) {
1060 	case rpc_gss_svc_none:
1061 		return (max_tp_unit_len);
1062 		break;
1063 
1064 	case rpc_gss_svc_default:
1065 	case rpc_gss_svc_integrity:
1066 		want_conf = FALSE;
1067 		break;
1068 
1069 	case rpc_gss_svc_privacy:
1070 		want_conf = TRUE;
1071 		break;
1072 
1073 	default:
1074 		return (0);
1075 	}
1076 
1077 	maj_stat = gss_wrap_size_limit(&min_stat, gd->gd_ctx, want_conf,
1078 	    gd->gd_qop, max_tp_unit_len, &max);
1079 
1080 	if (maj_stat == GSS_S_COMPLETE) {
1081 		result = (int) max;
1082 		if (result < 0)
1083 			result = 0;
1084 		return (result);
1085 	} else {
1086 		rpc_gss_log_status("gss_wrap_size_limit", gd->gd_mech,
1087 		    maj_stat, min_stat);
1088 		return (0);
1089 	}
1090 }
1091