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