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 = #
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 }
Cache object: ec1eac22c3ced95f1460a2829b750e50
|