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