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