1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 */
27
28 /*
29 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
30 *
31 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
32 */
33
34 /*
35 * Server side handling of RPCSEC_GSS flavor.
36 */
37
38 #include <sys/systm.h>
39 #include <sys/kstat.h>
40 #include <sys/cmn_err.h>
41 #include <sys/debug.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_ext.h>
46 #include <rpc/rpc.h>
47 #include <rpc/rpcsec_defs.h>
48 #include <sys/sunddi.h>
49 #include <sys/atomic.h>
50
51 extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
52
53 #ifdef DEBUG
54 extern void prom_printf(const char *, ...);
55 #endif
56
57 #ifdef _KERNEL
58 #define memcmp(a, b, l) bcmp((a), (b), (l))
59 #endif
60
61
62 /*
63 * Sequence window definitions.
64 */
65 #define SEQ_ARR_SIZE 4
66 #define SEQ_WIN (SEQ_ARR_SIZE*32)
67 #define SEQ_HI_BIT 0x80000000
68 #define SEQ_LO_BIT 1
69 #define DIV_BY_32 5
70 #define SEQ_MASK 0x1f
71 #define SEQ_MAX ((unsigned int)0x80000000)
72
73
74 /* cache retransmit data */
75 typedef struct _retrans_entry {
76 uint32_t xid;
77 rpc_gss_init_res result;
78 } retrans_entry;
79
80 /*
81 * Server side RPCSEC_GSS context information.
82 */
83 typedef struct _svc_rpc_gss_data {
84 struct _svc_rpc_gss_data *next, *prev;
85 struct _svc_rpc_gss_data *lru_next, *lru_prev;
86 bool_t established;
87 gss_ctx_id_t context;
88 gss_buffer_desc client_name;
89 time_t expiration;
90 uint_t seq_num;
91 uint_t seq_bits[SEQ_ARR_SIZE];
92 uint_t key;
93 OM_uint32 qop;
94 bool_t done_docallback;
95 bool_t locked;
96 rpc_gss_rawcred_t raw_cred;
97 rpc_gss_ucred_t u_cred;
98 time_t u_cred_set;
99 void *cookie;
100 gss_cred_id_t deleg;
101 kmutex_t clm;
102 int ref_cnt;
103 time_t last_ref_time;
104 bool_t stale;
105 retrans_entry *retrans_data;
106 } svc_rpc_gss_data;
107
108 /*
109 * Data structures used for LRU based context management.
110 */
111
112
113 #define HASH(key) ((key) % svc_rpc_gss_hashmod)
114 /* Size of hash table for svc_rpc_gss_data structures */
115 #define GSS_DATA_HASH_SIZE 1024
116
117 /*
118 * The following two defines specify a time delta that is used in
119 * sweep_clients. When the last_ref_time of a context is older than
120 * than the current time minus the delta, i.e, the context has not
121 * been referenced in the last delta seconds, we will return the
122 * context back to the cache if the ref_cnt is zero. The first delta
123 * value will be used when sweep_clients is called from
124 * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
125 * all entries except those that are currently "active". By active we
126 * mean those that have been referenced in the last ACTIVE_DELTA
127 * seconds. If sweep_client is not being called from reclaim, then we
128 * will reclaim all entries that are "inactive". By inactive we mean
129 * those entries that have not been accessed in INACTIVE_DELTA
130 * seconds. Note we always assume that ACTIVE_DELTA is less than
131 * INACTIVE_DELTA, so that reaping entries from a reclaim operation
132 * will necessarily imply reaping all "inactive" entries and then
133 * some.
134 */
135
136 /*
137 * If low on memory reap cache entries that have not been active for
138 * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
139 */
140 #define ACTIVE_DELTA 30*60 /* 30 minutes */
141
142 /*
143 * If in sweeping contexts we find contexts with a ref_cnt equal to zero
144 * and the context has not been referenced in INACTIVE_DELTA seconds, return
145 * the entry to the cache.
146 */
147 #define INACTIVE_DELTA 8*60*60 /* 8 hours */
148
149 int svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
150 static svc_rpc_gss_data **clients;
151 static svc_rpc_gss_data *lru_first, *lru_last;
152 static time_t sweep_interval = 60*60;
153 static time_t last_swept = 0;
154 static int num_gss_contexts = 0;
155 static time_t svc_rpcgss_gid_timeout = 60*60*12;
156 static kmem_cache_t *svc_data_handle;
157 static time_t svc_rpc_gss_active_delta = ACTIVE_DELTA;
158 static time_t svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
159
160 /*
161 * lock used with context/lru variables
162 */
163 static kmutex_t ctx_mutex;
164
165 /*
166 * Data structure to contain cache statistics
167 */
168
169 static struct {
170 int64_t total_entries_allocated;
171 int64_t no_reclaims;
172 int64_t no_returned_by_reclaim;
173 } svc_rpc_gss_cache_stats;
174
175
176 /*
177 * lock used with server credential variables list
178 *
179 * server cred list locking guidelines:
180 * - Writer's lock holder has exclusive access to the list
181 */
182 static krwlock_t cred_lock;
183
184 /*
185 * server callback list
186 */
187 typedef struct rpc_gss_cblist_s {
188 struct rpc_gss_cblist_s *next;
189 rpc_gss_callback_t cb;
190 } rpc_gss_cblist_t;
191
192 static rpc_gss_cblist_t *rpc_gss_cblist = NULL;
193
194 /*
195 * lock used with callback variables
196 */
197 static kmutex_t cb_mutex;
198
199 /*
200 * forward declarations
201 */
202 static bool_t svc_rpc_gss_wrap();
203 static bool_t svc_rpc_gss_unwrap();
204 static svc_rpc_gss_data *create_client();
205 static svc_rpc_gss_data *get_client();
206 static svc_rpc_gss_data *find_client();
207 static void destroy_client();
208 static void sweep_clients(bool_t);
209 static void insert_client();
210 static bool_t check_verf(struct rpc_msg *, gss_ctx_id_t,
211 int *, uid_t);
212 static bool_t set_response_verf();
213 static void retrans_add(svc_rpc_gss_data *, uint32_t,
214 rpc_gss_init_res *);
215 static void retrans_del(svc_rpc_gss_data *);
216 static bool_t transfer_sec_context(svc_rpc_gss_data *);
217 static void common_client_data_free(svc_rpc_gss_data *);
218
219 /*
220 * server side wrap/unwrap routines
221 */
222 struct svc_auth_ops svc_rpc_gss_ops = {
223 svc_rpc_gss_wrap,
224 svc_rpc_gss_unwrap,
225 };
226
227 /* taskq(9F) */
228 typedef struct svcrpcsec_gss_taskq_arg {
229 SVCXPRT *rq_xprt;
230 rpc_gss_init_arg *rpc_call_arg;
231 struct rpc_msg *msg;
232 svc_rpc_gss_data *client_data;
233 uint_t cr_version;
234 rpc_gss_service_t cr_service;
235 } svcrpcsec_gss_taskq_arg_t;
236
237 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
238 int rpcsec_gss_init_taskq_nthreads = 1;
239 static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL;
240
241 extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
242 extern void rpc_msg_free(struct rpc_msg **, int);
243
244 /*
245 * from svc_clts.c:
246 * Transport private data.
247 * Kept in xprt->xp_p2buf.
248 */
249 struct udp_data {
250 mblk_t *ud_resp; /* buffer for response */
251 mblk_t *ud_inmp; /* mblk chain of request */
252 };
253
254 /*ARGSUSED*/
255 static int
svc_gss_data_create(void * buf,void * pdata,int kmflag)256 svc_gss_data_create(void *buf, void *pdata, int kmflag)
257 {
258 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
259
260 mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
261
262 return (0);
263 }
264
265 /*ARGSUSED*/
266 static void
svc_gss_data_destroy(void * buf,void * pdata)267 svc_gss_data_destroy(void *buf, void *pdata)
268 {
269 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
270
271 mutex_destroy(&client_data->clm);
272 }
273
274
275 /*ARGSUSED*/
276 static void
svc_gss_data_reclaim(void * pdata)277 svc_gss_data_reclaim(void *pdata)
278 {
279 mutex_enter(&ctx_mutex);
280
281 svc_rpc_gss_cache_stats.no_reclaims++;
282 sweep_clients(TRUE);
283
284 mutex_exit(&ctx_mutex);
285 }
286
287 /*
288 * Init stuff on the server side.
289 */
290 void
svc_gss_init()291 svc_gss_init()
292 {
293 mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
294 mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
295 rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
296 clients = (svc_rpc_gss_data **)
297 kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
298 KM_SLEEP);
299 svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
300 sizeof (svc_rpc_gss_data), 0,
301 svc_gss_data_create,
302 svc_gss_data_destroy,
303 svc_gss_data_reclaim,
304 NULL, NULL, 0);
305
306 if (svcrpcsec_gss_init_taskq == NULL) {
307 svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL,
308 "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads,
309 TASKQ_DEFAULTPRI, 0);
310 if (svcrpcsec_gss_init_taskq == NULL)
311 cmn_err(CE_NOTE,
312 "svc_gss_init: ddi_taskq_create failed");
313 }
314 }
315
316 /*
317 * Destroy structures allocated in svc_gss_init().
318 * This routine is called by _init() if mod_install() failed.
319 */
320 void
svc_gss_fini()321 svc_gss_fini()
322 {
323 mutex_destroy(&cb_mutex);
324 mutex_destroy(&ctx_mutex);
325 rw_destroy(&cred_lock);
326 kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
327 kmem_cache_destroy(svc_data_handle);
328 }
329
330 /*
331 * Cleanup routine for destroying context, called after service
332 * procedure is executed. Actually we just decrement the reference count
333 * associated with this context. If the reference count is zero and the
334 * context is marked as stale, we would then destroy the context. Additionally,
335 * we check if its been longer than sweep_interval since the last sweep_clients
336 * was run, and if so run sweep_clients to free all stale contexts with zero
337 * reference counts or contexts that are old. (Haven't been access in
338 * svc_rpc_inactive_delta seconds).
339 */
340 void
rpc_gss_cleanup(SVCXPRT * clone_xprt)341 rpc_gss_cleanup(SVCXPRT *clone_xprt)
342 {
343 svc_rpc_gss_data *cl;
344 SVCAUTH *svcauth;
345
346 /*
347 * First check if current context needs to be cleaned up.
348 * There might be other threads stale this client data
349 * in between.
350 */
351 svcauth = &clone_xprt->xp_auth;
352 mutex_enter(&ctx_mutex);
353 if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
354 mutex_enter(&cl->clm);
355 ASSERT(cl->ref_cnt > 0);
356 if (--cl->ref_cnt == 0 && cl->stale) {
357 mutex_exit(&cl->clm);
358 destroy_client(cl);
359 svcauth->svc_ah_private = NULL;
360 } else
361 mutex_exit(&cl->clm);
362 }
363
364 /*
365 * Check for other expired contexts.
366 */
367 if ((gethrestime_sec() - last_swept) > sweep_interval)
368 sweep_clients(FALSE);
369
370 mutex_exit(&ctx_mutex);
371 }
372
373 /*
374 * Shift the array arr of length arrlen right by nbits bits.
375 */
376 static void
shift_bits(arr,arrlen,nbits)377 shift_bits(arr, arrlen, nbits)
378 uint_t *arr;
379 int arrlen;
380 int nbits;
381 {
382 int i, j;
383 uint_t lo, hi;
384
385 /*
386 * If the number of bits to be shifted exceeds SEQ_WIN, just
387 * zero out the array.
388 */
389 if (nbits < SEQ_WIN) {
390 for (i = 0; i < nbits; i++) {
391 hi = 0;
392 for (j = 0; j < arrlen; j++) {
393 lo = arr[j] & SEQ_LO_BIT;
394 arr[j] >>= 1;
395 if (hi)
396 arr[j] |= SEQ_HI_BIT;
397 hi = lo;
398 }
399 }
400 } else {
401 for (j = 0; j < arrlen; j++)
402 arr[j] = 0;
403 }
404 }
405
406 /*
407 * Check that the received sequence number seq_num is valid.
408 */
409 static bool_t
check_seq(cl,seq_num,kill_context)410 check_seq(cl, seq_num, kill_context)
411 svc_rpc_gss_data *cl;
412 uint_t seq_num;
413 bool_t *kill_context;
414 {
415 int i, j;
416 uint_t bit;
417
418 /*
419 * If it exceeds the maximum, kill context.
420 */
421 if (seq_num >= SEQ_MAX) {
422 *kill_context = TRUE;
423 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
424 return (FALSE);
425 }
426
427 /*
428 * If greater than the last seen sequence number, just shift
429 * the sequence window so that it starts at the new sequence
430 * number and extends downwards by SEQ_WIN.
431 */
432 if (seq_num > cl->seq_num) {
433 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
434 (int)(seq_num - cl->seq_num));
435 cl->seq_bits[0] |= SEQ_HI_BIT;
436 cl->seq_num = seq_num;
437 return (TRUE);
438 }
439
440 /*
441 * If it is outside the sequence window, return failure.
442 */
443 i = cl->seq_num - seq_num;
444 if (i >= SEQ_WIN) {
445 RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
446 return (FALSE);
447 }
448
449 /*
450 * If within sequence window, set the bit corresponding to it
451 * if not already seen; if already seen, return failure.
452 */
453 j = SEQ_MASK - (i & SEQ_MASK);
454 bit = j > 0 ? (1 << j) : 1;
455 i >>= DIV_BY_32;
456 if (cl->seq_bits[i] & bit) {
457 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
458 return (FALSE);
459 }
460 cl->seq_bits[i] |= bit;
461 return (TRUE);
462 }
463
464 /*
465 * Set server callback.
466 */
467 bool_t
rpc_gss_set_callback(cb)468 rpc_gss_set_callback(cb)
469 rpc_gss_callback_t *cb;
470 {
471 rpc_gss_cblist_t *cbl, *tmp;
472
473 if (cb->callback == NULL) {
474 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
475 return (FALSE);
476 }
477
478 /* check if there is already an entry in the rpc_gss_cblist. */
479 mutex_enter(&cb_mutex);
480 if (rpc_gss_cblist) {
481 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
482 if ((tmp->cb.callback == cb->callback) &&
483 (tmp->cb.version == cb->version) &&
484 (tmp->cb.program == cb->program)) {
485 mutex_exit(&cb_mutex);
486 return (TRUE);
487 }
488 }
489 }
490
491 /* Not in rpc_gss_cblist. Create a new entry. */
492 if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
493 == NULL) {
494 mutex_exit(&cb_mutex);
495 return (FALSE);
496 }
497 cbl->cb = *cb;
498 cbl->next = rpc_gss_cblist;
499 rpc_gss_cblist = cbl;
500 mutex_exit(&cb_mutex);
501 return (TRUE);
502 }
503
504 /*
505 * Locate callback (if specified) and call server. Release any
506 * delegated credentials unless passed to server and the server
507 * accepts the context. If a callback is not specified, accept
508 * the incoming context.
509 */
510 static bool_t
do_callback(req,client_data)511 do_callback(req, client_data)
512 struct svc_req *req;
513 svc_rpc_gss_data *client_data;
514 {
515 rpc_gss_cblist_t *cbl;
516 bool_t ret = TRUE, found = FALSE;
517 rpc_gss_lock_t lock;
518 OM_uint32 minor;
519 mutex_enter(&cb_mutex);
520 for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
521 if (req->rq_prog != cbl->cb.program ||
522 req->rq_vers != cbl->cb.version)
523 continue;
524 found = TRUE;
525 lock.locked = FALSE;
526 lock.raw_cred = &client_data->raw_cred;
527 ret = (*cbl->cb.callback)(req, client_data->deleg,
528 client_data->context, &lock, &client_data->cookie);
529 req->rq_xprt->xp_cookie = client_data->cookie;
530
531 if (ret) {
532 client_data->locked = lock.locked;
533 client_data->deleg = GSS_C_NO_CREDENTIAL;
534 }
535 break;
536 }
537 if (!found) {
538 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
539 (void) kgss_release_cred(&minor, &client_data->deleg,
540 crgetuid(CRED()));
541 client_data->deleg = GSS_C_NO_CREDENTIAL;
542 }
543 }
544 mutex_exit(&cb_mutex);
545 return (ret);
546 }
547
548 /*
549 * Get caller credentials.
550 */
551 bool_t
rpc_gss_getcred(req,rcred,ucred,cookie)552 rpc_gss_getcred(req, rcred, ucred, cookie)
553 struct svc_req *req;
554 rpc_gss_rawcred_t **rcred;
555 rpc_gss_ucred_t **ucred;
556 void **cookie;
557 {
558 SVCAUTH *svcauth;
559 svc_rpc_gss_data *client_data;
560 int gssstat, gidlen;
561
562 svcauth = &req->rq_xprt->xp_auth;
563 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
564
565 mutex_enter(&client_data->clm);
566
567 if (rcred != NULL) {
568 svcauth->raw_cred = client_data->raw_cred;
569 *rcred = &svcauth->raw_cred;
570 }
571 if (ucred != NULL) {
572 *ucred = &client_data->u_cred;
573
574 if (client_data->u_cred_set == 0 ||
575 client_data->u_cred_set < gethrestime_sec()) {
576 if (client_data->u_cred_set == 0) {
577 if ((gssstat = kgsscred_expname_to_unix_cred(
578 &client_data->client_name,
579 &client_data->u_cred.uid,
580 &client_data->u_cred.gid,
581 &client_data->u_cred.gidlist,
582 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
583 RPCGSS_LOG(1, "rpc_gss_getcred: "
584 "kgsscred_expname_to_unix_cred failed %x\n",
585 gssstat);
586 *ucred = NULL;
587 } else {
588 client_data->u_cred.gidlen = (short)gidlen;
589 client_data->u_cred_set =
590 gethrestime_sec() + svc_rpcgss_gid_timeout;
591 }
592 } else if (client_data->u_cred_set < gethrestime_sec()) {
593 if ((gssstat = kgss_get_group_info(
594 client_data->u_cred.uid,
595 &client_data->u_cred.gid,
596 &client_data->u_cred.gidlist,
597 &gidlen, crgetuid(CRED()))) != GSS_S_COMPLETE) {
598 RPCGSS_LOG(1, "rpc_gss_getcred: "
599 "kgss_get_group_info failed %x\n",
600 gssstat);
601 *ucred = NULL;
602 } else {
603 client_data->u_cred.gidlen = (short)gidlen;
604 client_data->u_cred_set =
605 gethrestime_sec() + svc_rpcgss_gid_timeout;
606 }
607 }
608 }
609 }
610
611 if (cookie != NULL)
612 *cookie = client_data->cookie;
613 req->rq_xprt->xp_cookie = client_data->cookie;
614
615 mutex_exit(&client_data->clm);
616
617 return (TRUE);
618 }
619
620 /*
621 * Transfer the context data from the user land to the kernel.
622 */
transfer_sec_context(svc_rpc_gss_data * client_data)623 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
624
625 gss_buffer_desc process_token;
626 OM_uint32 gssstat, minor;
627
628 /*
629 * Call kgss_export_sec_context
630 * if an error is returned log a message
631 * go to error handling
632 * Otherwise call kgss_import_sec_context to
633 * convert the token into a context
634 */
635 gssstat = kgss_export_sec_context(&minor, client_data->context,
636 &process_token);
637 /*
638 * if export_sec_context returns an error we delete the
639 * context just to be safe.
640 */
641 if (gssstat == GSS_S_NAME_NOT_MN) {
642 RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
643 "Kernel mod unavailable\n");
644
645 } else if (gssstat != GSS_S_COMPLETE) {
646 RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed "
647 " gssstat = 0x%x\n", gssstat);
648 (void) gss_release_buffer(&minor, &process_token);
649 (void) kgss_delete_sec_context(&minor, &client_data->context,
650 NULL);
651 return (FALSE);
652
653 } else if (process_token.length == 0) {
654 RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
655 "for export_sec_context, but "
656 "gsstat == GSS_S_COMPLETE\n");
657 (void) kgss_delete_sec_context(&minor, &client_data->context,
658 NULL);
659 return (FALSE);
660
661 } else {
662 gssstat = kgss_import_sec_context(&minor, &process_token,
663 client_data->context);
664 if (gssstat != GSS_S_COMPLETE) {
665 RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
666 " failed gssstat = 0x%x\n", gssstat);
667 (void) kgss_delete_sec_context(&minor,
668 &client_data->context, NULL);
669 (void) gss_release_buffer(&minor, &process_token);
670 return (FALSE);
671 }
672
673 RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
674 (void) gss_release_buffer(&minor, &process_token);
675 }
676
677 return (TRUE);
678 }
679
680 /*
681 * do_gss_accept is called from a taskq and does all the work for a
682 * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
683 */
684 static enum auth_stat
do_gss_accept(SVCXPRT * xprt,rpc_gss_init_arg * call_arg,struct rpc_msg * msg,svc_rpc_gss_data * client_data,uint_t cr_version,rpc_gss_service_t cr_service)685 do_gss_accept(
686 SVCXPRT *xprt,
687 rpc_gss_init_arg *call_arg,
688 struct rpc_msg *msg,
689 svc_rpc_gss_data *client_data,
690 uint_t cr_version,
691 rpc_gss_service_t cr_service)
692 {
693 rpc_gss_init_res call_res;
694 gss_buffer_desc output_token;
695 OM_uint32 gssstat, minor, minor_stat, time_rec;
696 int ret_flags, ret;
697 gss_OID mech_type = GSS_C_NULL_OID;
698 int free_mech_type = 1;
699 struct svc_req r, *rqst;
700
701 rqst = &r;
702 rqst->rq_xprt = xprt;
703
704 /*
705 * Initialize output_token.
706 */
707 output_token.length = 0;
708 output_token.value = NULL;
709
710 bzero((char *)&call_res, sizeof (call_res));
711
712 mutex_enter(&client_data->clm);
713 if (client_data->stale) {
714 ret = RPCSEC_GSS_NOCRED;
715 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
716 goto error2;
717 }
718
719 /*
720 * Any response we send will use ctx_handle, so set it now;
721 * also set seq_window since this won't change.
722 */
723 call_res.ctx_handle.length = sizeof (client_data->key);
724 call_res.ctx_handle.value = (char *)&client_data->key;
725 call_res.seq_window = SEQ_WIN;
726
727 gssstat = GSS_S_FAILURE;
728 minor = 0;
729 minor_stat = 0;
730 rw_enter(&cred_lock, RW_READER);
731
732 if (client_data->client_name.length) {
733 (void) gss_release_buffer(&minor,
734 &client_data->client_name);
735 }
736 gssstat = kgss_accept_sec_context(&minor_stat,
737 &client_data->context,
738 GSS_C_NO_CREDENTIAL,
739 call_arg,
740 GSS_C_NO_CHANNEL_BINDINGS,
741 &client_data->client_name,
742 &mech_type,
743 &output_token,
744 &ret_flags,
745 &time_rec,
746 NULL, /* don't need a delegated cred back */
747 crgetuid(CRED()));
748
749 RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
750
751 if (gssstat == GSS_S_COMPLETE) {
752 /*
753 * Set the raw and unix credentials at this
754 * point. This saves a lot of computation
755 * later when credentials are retrieved.
756 */
757 client_data->raw_cred.version = cr_version;
758 client_data->raw_cred.service = cr_service;
759
760 if (client_data->raw_cred.mechanism) {
761 kgss_free_oid(client_data->raw_cred.mechanism);
762 client_data->raw_cred.mechanism = NULL;
763 }
764 client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
765 /*
766 * client_data is now responsible for freeing
767 * the data of 'mech_type'.
768 */
769 free_mech_type = 0;
770
771 if (client_data->raw_cred.client_principal) {
772 kmem_free((caddr_t)client_data->\
773 raw_cred.client_principal,
774 client_data->raw_cred.\
775 client_principal->len + sizeof (int));
776 client_data->raw_cred.client_principal = NULL;
777 }
778
779 /*
780 * The client_name returned from
781 * kgss_accept_sec_context() is in an
782 * exported flat format.
783 */
784 if (! __rpc_gss_make_principal(
785 &client_data->raw_cred.client_principal,
786 &client_data->client_name)) {
787 RPCGSS_LOG0(1, "_svcrpcsec_gss: "
788 "make principal failed\n");
789 gssstat = GSS_S_FAILURE;
790 (void) gss_release_buffer(&minor_stat, &output_token);
791 }
792 }
793
794 rw_exit(&cred_lock);
795
796 call_res.gss_major = gssstat;
797 call_res.gss_minor = minor_stat;
798
799 if (gssstat != GSS_S_COMPLETE &&
800 gssstat != GSS_S_CONTINUE_NEEDED) {
801 call_res.ctx_handle.length = 0;
802 call_res.ctx_handle.value = NULL;
803 call_res.seq_window = 0;
804 rpc_gss_display_status(gssstat, minor_stat, mech_type,
805 crgetuid(CRED()),
806 "_svc_rpcsec_gss gss_accept_sec_context");
807 (void) svc_sendreply(rqst->rq_xprt,
808 __xdr_rpc_gss_init_res, (caddr_t)&call_res);
809 client_data->stale = TRUE;
810 ret = AUTH_OK;
811 goto error2;
812 }
813
814 /*
815 * If appropriate, set established to TRUE *after* sending
816 * response (otherwise, the client will receive the final
817 * token encrypted)
818 */
819 if (gssstat == GSS_S_COMPLETE) {
820 /*
821 * Context is established. Set expiration time
822 * for the context.
823 */
824 client_data->seq_num = 1;
825 if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
826 client_data->expiration = GSS_C_INDEFINITE;
827 } else {
828 client_data->expiration =
829 time_rec + gethrestime_sec();
830 }
831
832 if (!transfer_sec_context(client_data)) {
833 ret = RPCSEC_GSS_FAILED;
834 client_data->stale = TRUE;
835 RPCGSS_LOG0(1,
836 "_svc_rpcsec_gss: transfer sec context failed\n");
837 goto error2;
838 }
839
840 client_data->established = TRUE;
841 }
842
843 /*
844 * This step succeeded. Send a response, along with
845 * a token if there's one. Don't dispatch.
846 */
847
848 if (output_token.length != 0)
849 GSS_COPY_BUFFER(call_res.token, output_token);
850
851 /*
852 * If GSS_S_COMPLETE: set response verifier to
853 * checksum of SEQ_WIN
854 */
855 if (gssstat == GSS_S_COMPLETE) {
856 if (!set_response_verf(rqst, msg, client_data,
857 (uint_t)SEQ_WIN)) {
858 ret = RPCSEC_GSS_FAILED;
859 client_data->stale = TRUE;
860 RPCGSS_LOG0(1,
861 "_svc_rpcsec_gss:set response verifier failed\n");
862 goto error2;
863 }
864 }
865
866 if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
867 (caddr_t)&call_res)) {
868 ret = RPCSEC_GSS_FAILED;
869 client_data->stale = TRUE;
870 RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
871 goto error2;
872 }
873
874 /*
875 * Cache last response in case it is lost and the client
876 * retries on an established context.
877 */
878 (void) retrans_add(client_data, msg->rm_xid, &call_res);
879 ASSERT(client_data->ref_cnt > 0);
880 client_data->ref_cnt--;
881 mutex_exit(&client_data->clm);
882
883 (void) gss_release_buffer(&minor_stat, &output_token);
884
885 return (AUTH_OK);
886
887 error2:
888 ASSERT(client_data->ref_cnt > 0);
889 client_data->ref_cnt--;
890 mutex_exit(&client_data->clm);
891 (void) gss_release_buffer(&minor_stat, &output_token);
892 if (free_mech_type && mech_type)
893 kgss_free_oid(mech_type);
894
895 return (ret);
896 }
897
898 static void
svcrpcsec_gss_taskq_func(void * svcrpcsecgss_taskq_arg)899 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
900 {
901 enum auth_stat retval;
902 svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
903
904 retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
905 arg->client_data, arg->cr_version, arg->cr_service);
906 if (retval != AUTH_OK) {
907 cmn_err(CE_NOTE,
908 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
909 retval);
910 }
911 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
912 svc_clone_unlink(arg->rq_xprt);
913 svc_clone_free(arg->rq_xprt);
914 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
915 kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
916
917 kmem_free(arg, sizeof (*arg));
918 }
919
920 static enum auth_stat
rpcsec_gss_init(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch,svc_rpc_gss_data * c_d)921 rpcsec_gss_init(
922 struct svc_req *rqst,
923 struct rpc_msg *msg,
924 rpc_gss_creds creds,
925 bool_t *no_dispatch,
926 svc_rpc_gss_data *c_d) /* client data, can be NULL */
927 {
928 svc_rpc_gss_data *client_data;
929 int ret;
930 svcrpcsec_gss_taskq_arg_t *arg;
931
932 if (creds.ctx_handle.length != 0) {
933 RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
934 ret = AUTH_BADCRED;
935 return (ret);
936 }
937
938 client_data = c_d ? c_d : create_client();
939 if (client_data == NULL) {
940 RPCGSS_LOG0(1,
941 "_svcrpcsec_gss: can't create a new cache entry\n");
942 ret = AUTH_FAILED;
943 return (ret);
944 }
945
946 mutex_enter(&client_data->clm);
947 if (client_data->stale) {
948 ret = RPCSEC_GSS_NOCRED;
949 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
950 goto error2;
951 }
952
953 /*
954 * kgss_accept_sec_context()/gssd(1M) can be overly time
955 * consuming so let's queue it and return asap.
956 *
957 * taskq func must free arg.
958 */
959 arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
960
961 /* taskq func must free rpc_call_arg & deserialized arguments */
962 arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
963
964 /* deserialize arguments */
965 if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
966 (caddr_t)arg->rpc_call_arg)) {
967 ret = RPCSEC_GSS_FAILED;
968 client_data->stale = TRUE;
969 goto error2;
970 }
971
972 /* get a xprt clone for taskq thread, taskq func must free it */
973 arg->rq_xprt = svc_clone_init();
974 svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
975 arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
976
977
978 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
979 arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
980 arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
981
982 /* get a dup of rpc msg for taskq thread */
983 arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */
984
985 arg->client_data = client_data;
986 arg->cr_version = creds.version;
987 arg->cr_service = creds.service;
988
989 /* should be ok to hold clm lock as taskq will have new thread(s) */
990 ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
991 svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
992 if (ret == DDI_FAILURE) {
993 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
994 ret = RPCSEC_GSS_FAILED;
995 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
996 svc_clone_unlink(arg->rq_xprt);
997 svc_clone_free(arg->rq_xprt);
998 kmem_free(arg, sizeof (*arg));
999 goto error2;
1000 }
1001
1002 mutex_exit(&client_data->clm);
1003 *no_dispatch = TRUE;
1004 return (AUTH_OK);
1005
1006 error2:
1007 ASSERT(client_data->ref_cnt > 0);
1008 client_data->ref_cnt--;
1009 mutex_exit(&client_data->clm);
1010 cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1011 return (ret);
1012 }
1013
1014 static enum auth_stat
rpcsec_gss_continue_init(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch)1015 rpcsec_gss_continue_init(
1016 struct svc_req *rqst,
1017 struct rpc_msg *msg,
1018 rpc_gss_creds creds,
1019 bool_t *no_dispatch)
1020 {
1021 int ret;
1022 svc_rpc_gss_data *client_data;
1023 svc_rpc_gss_parms_t *gss_parms;
1024 rpc_gss_init_res *retrans_result;
1025
1026 if (creds.ctx_handle.length == 0) {
1027 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1028 ret = AUTH_BADCRED;
1029 return (ret);
1030 }
1031 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1032 ret = RPCSEC_GSS_NOCRED;
1033 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1034 return (ret);
1035 }
1036
1037 mutex_enter(&client_data->clm);
1038 if (client_data->stale) {
1039 ret = RPCSEC_GSS_NOCRED;
1040 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1041 goto error2;
1042 }
1043
1044 /*
1045 * If context not established, go thru INIT code but with
1046 * this client handle.
1047 */
1048 if (!client_data->established) {
1049 mutex_exit(&client_data->clm);
1050 return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1051 client_data));
1052 }
1053
1054 /*
1055 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1056 */
1057 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1058 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1059
1060 /*
1061 * Keep copy of parameters we'll need for response, for the
1062 * sake of reentrancy (we don't want to look in the context
1063 * data because when we are sending a response, another
1064 * request may have come in).
1065 */
1066 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1067 gss_parms->established = client_data->established;
1068 gss_parms->service = creds.service;
1069 gss_parms->qop_rcvd = (uint_t)client_data->qop;
1070 gss_parms->context = (void *)client_data->context;
1071 gss_parms->seq_num = creds.seq_num;
1072
1073 /*
1074 * This is an established context. Continue to
1075 * satisfy retried continue init requests out of
1076 * the retransmit cache. Throw away any that don't
1077 * have a matching xid or the cach is empty.
1078 * Delete the retransmit cache once the client sends
1079 * a data request.
1080 */
1081 if (client_data->retrans_data &&
1082 (client_data->retrans_data->xid == msg->rm_xid)) {
1083 retrans_result = &client_data->retrans_data->result;
1084 if (set_response_verf(rqst, msg, client_data,
1085 (uint_t)retrans_result->seq_window)) {
1086 gss_parms->established = FALSE;
1087 (void) svc_sendreply(rqst->rq_xprt,
1088 __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
1089 *no_dispatch = TRUE;
1090 ASSERT(client_data->ref_cnt > 0);
1091 client_data->ref_cnt--;
1092 }
1093 }
1094 mutex_exit(&client_data->clm);
1095
1096 return (AUTH_OK);
1097
1098 error2:
1099 ASSERT(client_data->ref_cnt > 0);
1100 client_data->ref_cnt--;
1101 mutex_exit(&client_data->clm);
1102 return (ret);
1103 }
1104
1105 static enum auth_stat
rpcsec_gss_data(struct svc_req * rqst,struct rpc_msg * msg,rpc_gss_creds creds,bool_t * no_dispatch)1106 rpcsec_gss_data(
1107 struct svc_req *rqst,
1108 struct rpc_msg *msg,
1109 rpc_gss_creds creds,
1110 bool_t *no_dispatch)
1111 {
1112 int ret;
1113 svc_rpc_gss_parms_t *gss_parms;
1114 svc_rpc_gss_data *client_data;
1115
1116 switch (creds.service) {
1117 case rpc_gss_svc_none:
1118 case rpc_gss_svc_integrity:
1119 case rpc_gss_svc_privacy:
1120 break;
1121 default:
1122 cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1123 creds.service);
1124 RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1125 creds.service);
1126 ret = AUTH_BADCRED;
1127 return (ret);
1128 }
1129
1130 if (creds.ctx_handle.length == 0) {
1131 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1132 ret = AUTH_BADCRED;
1133 return (ret);
1134 }
1135 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1136 ret = RPCSEC_GSS_NOCRED;
1137 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1138 return (ret);
1139 }
1140
1141
1142 mutex_enter(&client_data->clm);
1143 if (!client_data->established) {
1144 ret = AUTH_FAILED;
1145 goto error2;
1146 }
1147 if (client_data->stale) {
1148 ret = RPCSEC_GSS_NOCRED;
1149 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1150 goto error2;
1151 }
1152
1153 /*
1154 * Once the context is established and there is no more
1155 * retransmission of last continue init request, it is safe
1156 * to delete the retransmit cache entry.
1157 */
1158 if (client_data->retrans_data)
1159 retrans_del(client_data);
1160
1161 /*
1162 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1163 */
1164 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1165 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1166
1167 /*
1168 * Keep copy of parameters we'll need for response, for the
1169 * sake of reentrancy (we don't want to look in the context
1170 * data because when we are sending a response, another
1171 * request may have come in).
1172 */
1173 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1174 gss_parms->established = client_data->established;
1175 gss_parms->service = creds.service;
1176 gss_parms->qop_rcvd = (uint_t)client_data->qop;
1177 gss_parms->context = (void *)client_data->context;
1178 gss_parms->seq_num = creds.seq_num;
1179
1180 /*
1181 * Context is already established. Check verifier, and
1182 * note parameters we will need for response in gss_parms.
1183 */
1184 if (!check_verf(msg, client_data->context,
1185 (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1186 ret = RPCSEC_GSS_NOCRED;
1187 RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1188 goto error2;
1189 }
1190
1191 /*
1192 * Check and invoke callback if necessary.
1193 */
1194 if (!client_data->done_docallback) {
1195 client_data->done_docallback = TRUE;
1196 client_data->qop = gss_parms->qop_rcvd;
1197 client_data->raw_cred.qop = gss_parms->qop_rcvd;
1198 client_data->raw_cred.service = creds.service;
1199 if (!do_callback(rqst, client_data)) {
1200 ret = AUTH_FAILED;
1201 RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1202 goto error2;
1203 }
1204 }
1205
1206 /*
1207 * If the context was locked, make sure that the client
1208 * has not changed QOP.
1209 */
1210 if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1211 ret = AUTH_BADVERF;
1212 RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1213 goto error2;
1214 }
1215
1216 /*
1217 * Validate sequence number.
1218 */
1219 if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1220 if (client_data->stale) {
1221 ret = RPCSEC_GSS_FAILED;
1222 RPCGSS_LOG0(1,
1223 "_svc_rpcsec_gss:check seq failed\n");
1224 } else {
1225 RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1226 "failed on good context. Ignoring "
1227 "request\n");
1228 /*
1229 * Operational error, drop packet silently.
1230 * The client will recover after timing out,
1231 * assuming this is a client error and not
1232 * a relpay attack. Don't dispatch.
1233 */
1234 ret = AUTH_OK;
1235 *no_dispatch = TRUE;
1236 }
1237 goto error2;
1238 }
1239
1240 /*
1241 * set response verifier
1242 */
1243 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1244 ret = RPCSEC_GSS_FAILED;
1245 client_data->stale = TRUE;
1246 RPCGSS_LOG0(1,
1247 "_svc_rpcsec_gss:set response verifier failed\n");
1248 goto error2;
1249 }
1250
1251 /*
1252 * If context is locked, make sure that the client
1253 * has not changed the security service.
1254 */
1255 if (client_data->locked &&
1256 client_data->raw_cred.service != creds.service) {
1257 RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1258 "security service changed.\n");
1259 ret = AUTH_FAILED;
1260 goto error2;
1261 }
1262
1263 /*
1264 * Set client credentials to raw credential
1265 * structure in context. This is okay, since
1266 * this will not change during the lifetime of
1267 * the context (so it's MT safe).
1268 */
1269 rqst->rq_clntcred = (char *)&client_data->raw_cred;
1270
1271 mutex_exit(&client_data->clm);
1272 return (AUTH_OK);
1273
1274 error2:
1275 ASSERT(client_data->ref_cnt > 0);
1276 client_data->ref_cnt--;
1277 mutex_exit(&client_data->clm);
1278 return (ret);
1279 }
1280
1281 /*
1282 * Note we don't have a client yet to use this routine and test it.
1283 */
1284 static enum auth_stat
rpcsec_gss_destroy(struct svc_req * rqst,rpc_gss_creds creds,bool_t * no_dispatch)1285 rpcsec_gss_destroy(
1286 struct svc_req *rqst,
1287 rpc_gss_creds creds,
1288 bool_t *no_dispatch)
1289 {
1290 svc_rpc_gss_data *client_data;
1291 int ret;
1292
1293 if (creds.ctx_handle.length == 0) {
1294 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1295 ret = AUTH_BADCRED;
1296 return (ret);
1297 }
1298 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1299 ret = RPCSEC_GSS_NOCRED;
1300 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1301 return (ret);
1302 }
1303
1304 mutex_enter(&client_data->clm);
1305 if (!client_data->established) {
1306 ret = AUTH_FAILED;
1307 goto error2;
1308 }
1309 if (client_data->stale) {
1310 ret = RPCSEC_GSS_NOCRED;
1311 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1312 goto error2;
1313 }
1314
1315 (void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1316 *no_dispatch = TRUE;
1317 ASSERT(client_data->ref_cnt > 0);
1318 client_data->ref_cnt--;
1319 client_data->stale = TRUE;
1320 mutex_exit(&client_data->clm);
1321 return (AUTH_OK);
1322
1323 error2:
1324 ASSERT(client_data->ref_cnt > 0);
1325 client_data->ref_cnt--;
1326 client_data->stale = TRUE;
1327 mutex_exit(&client_data->clm);
1328 return (ret);
1329 }
1330
1331 /*
1332 * Server side authentication for RPCSEC_GSS.
1333 */
1334 enum auth_stat
__svcrpcsec_gss(struct svc_req * rqst,struct rpc_msg * msg,bool_t * no_dispatch)1335 __svcrpcsec_gss(
1336 struct svc_req *rqst,
1337 struct rpc_msg *msg,
1338 bool_t *no_dispatch)
1339 {
1340 XDR xdrs;
1341 rpc_gss_creds creds;
1342 struct opaque_auth *cred;
1343 int ret;
1344
1345 *no_dispatch = FALSE;
1346
1347 /*
1348 * Initialize response verifier to NULL verifier. If
1349 * necessary, this will be changed later.
1350 */
1351 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1352 rqst->rq_xprt->xp_verf.oa_base = NULL;
1353 rqst->rq_xprt->xp_verf.oa_length = 0;
1354
1355 /*
1356 * Pull out and check credential and verifier.
1357 */
1358 cred = &msg->rm_call.cb_cred;
1359
1360 if (cred->oa_length == 0) {
1361 RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1362 return (AUTH_BADCRED);
1363 }
1364
1365 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1366 bzero((char *)&creds, sizeof (creds));
1367 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1368 XDR_DESTROY(&xdrs);
1369 RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1370 ret = AUTH_BADCRED;
1371 return (AUTH_BADCRED);
1372 }
1373 XDR_DESTROY(&xdrs);
1374
1375 switch (creds.gss_proc) {
1376 case RPCSEC_GSS_INIT:
1377 ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1378 break;
1379 case RPCSEC_GSS_CONTINUE_INIT:
1380 ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1381 break;
1382 case RPCSEC_GSS_DATA:
1383 ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1384 break;
1385 case RPCSEC_GSS_DESTROY:
1386 ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1387 break;
1388 default:
1389 cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1390 creds.gss_proc);
1391 ret = AUTH_BADCRED;
1392 }
1393
1394 if (creds.ctx_handle.length != 0)
1395 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1396 return (ret);
1397 }
1398
1399 /*
1400 * Check verifier. The verifier is the checksum of the RPC header
1401 * upto and including the credentials field.
1402 */
1403
1404 /* ARGSUSED */
1405 static bool_t
check_verf(struct rpc_msg * msg,gss_ctx_id_t context,int * qop_state,uid_t uid)1406 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1407 {
1408 int *buf, *tmp;
1409 char hdr[128];
1410 struct opaque_auth *oa;
1411 int len;
1412 gss_buffer_desc msg_buf;
1413 gss_buffer_desc tok_buf;
1414 OM_uint32 gssstat, minor_stat;
1415
1416 /*
1417 * We have to reconstruct the RPC header from the previously
1418 * parsed information, since we haven't kept the header intact.
1419 */
1420
1421 oa = &msg->rm_call.cb_cred;
1422 if (oa->oa_length > MAX_AUTH_BYTES)
1423 return (FALSE);
1424
1425 /* 8 XDR units from the IXDR macro calls. */
1426 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1427 RNDUP(oa->oa_length)))
1428 return (FALSE);
1429 buf = (int *)hdr;
1430 IXDR_PUT_U_INT32(buf, msg->rm_xid);
1431 IXDR_PUT_ENUM(buf, msg->rm_direction);
1432 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1433 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1434 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1435 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1436 IXDR_PUT_ENUM(buf, oa->oa_flavor);
1437 IXDR_PUT_U_INT32(buf, oa->oa_length);
1438 if (oa->oa_length) {
1439 len = RNDUP(oa->oa_length);
1440 tmp = buf;
1441 buf += len / sizeof (int);
1442 *(buf - 1) = 0;
1443 (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1444 }
1445 len = ((char *)buf) - hdr;
1446 msg_buf.length = len;
1447 msg_buf.value = hdr;
1448 oa = &msg->rm_call.cb_verf;
1449 tok_buf.length = oa->oa_length;
1450 tok_buf.value = oa->oa_base;
1451
1452 gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1453 qop_state);
1454 if (gssstat != GSS_S_COMPLETE) {
1455 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1456
1457 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1458 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1459 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1460 tok_buf.length);
1461 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1462 (void *)oa->oa_base);
1463 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1464
1465 return (FALSE);
1466 }
1467 return (TRUE);
1468 }
1469
1470
1471 /*
1472 * Set response verifier. This is the checksum of the given number.
1473 * (e.g. sequence number or sequence window)
1474 */
1475 static bool_t
set_response_verf(rqst,msg,cl,num)1476 set_response_verf(rqst, msg, cl, num)
1477 struct svc_req *rqst;
1478 struct rpc_msg *msg;
1479 svc_rpc_gss_data *cl;
1480 uint_t num;
1481 {
1482 OM_uint32 minor;
1483 gss_buffer_desc in_buf, out_buf;
1484 uint_t num_net;
1485
1486 num_net = (uint_t)htonl(num);
1487 in_buf.length = sizeof (num);
1488 in_buf.value = (char *)&num_net;
1489 /* XXX uid ? */
1490
1491 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf,
1492 &out_buf)) != GSS_S_COMPLETE)
1493 return (FALSE);
1494
1495 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1496 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1497 rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1498 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1499 (void) gss_release_buffer(&minor, &out_buf);
1500 return (TRUE);
1501 }
1502
1503 /*
1504 * Create client context.
1505 */
1506 static svc_rpc_gss_data *
create_client()1507 create_client()
1508 {
1509 svc_rpc_gss_data *client_data;
1510 static uint_t key = 1;
1511
1512 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1513 KM_SLEEP);
1514 if (client_data == NULL)
1515 return (NULL);
1516
1517 /*
1518 * set up client data structure
1519 */
1520 client_data->next = NULL;
1521 client_data->prev = NULL;
1522 client_data->lru_next = NULL;
1523 client_data->lru_prev = NULL;
1524 client_data->client_name.length = 0;
1525 client_data->client_name.value = NULL;
1526 client_data->seq_num = 0;
1527 bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1528 client_data->key = 0;
1529 client_data->cookie = NULL;
1530 bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1531 client_data->established = FALSE;
1532 client_data->locked = FALSE;
1533 client_data->u_cred_set = 0;
1534 client_data->context = GSS_C_NO_CONTEXT;
1535 client_data->expiration = GSS_C_INDEFINITE;
1536 client_data->deleg = GSS_C_NO_CREDENTIAL;
1537 client_data->ref_cnt = 1;
1538 client_data->last_ref_time = gethrestime_sec();
1539 client_data->qop = GSS_C_QOP_DEFAULT;
1540 client_data->done_docallback = FALSE;
1541 client_data->stale = FALSE;
1542 client_data->retrans_data = NULL;
1543 bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1544
1545 /*
1546 * The client context handle is a 32-bit key (unsigned int).
1547 * The key is incremented until there is no duplicate for it.
1548 */
1549
1550 svc_rpc_gss_cache_stats.total_entries_allocated++;
1551 mutex_enter(&ctx_mutex);
1552 for (;;) {
1553 client_data->key = key++;
1554 if (find_client(client_data->key) == NULL) {
1555 insert_client(client_data);
1556 mutex_exit(&ctx_mutex);
1557 return (client_data);
1558 }
1559 }
1560 /*NOTREACHED*/
1561 }
1562
1563 /*
1564 * Insert client context into hash list and LRU list.
1565 */
1566 static void
insert_client(client_data)1567 insert_client(client_data)
1568 svc_rpc_gss_data *client_data;
1569 {
1570 svc_rpc_gss_data *cl;
1571 int index = HASH(client_data->key);
1572
1573 ASSERT(mutex_owned(&ctx_mutex));
1574
1575 client_data->prev = NULL;
1576 cl = clients[index];
1577 if ((client_data->next = cl) != NULL)
1578 cl->prev = client_data;
1579 clients[index] = client_data;
1580
1581 client_data->lru_prev = NULL;
1582 if ((client_data->lru_next = lru_first) != NULL)
1583 lru_first->lru_prev = client_data;
1584 else
1585 lru_last = client_data;
1586 lru_first = client_data;
1587
1588 num_gss_contexts++;
1589 }
1590
1591 /*
1592 * Fetch a client, given the client context handle. Move it to the
1593 * top of the LRU list since this is the most recently used context.
1594 */
1595 static svc_rpc_gss_data *
get_client(ctx_handle)1596 get_client(ctx_handle)
1597 gss_buffer_t ctx_handle;
1598 {
1599 uint_t key = *(uint_t *)ctx_handle->value;
1600 svc_rpc_gss_data *cl;
1601
1602 mutex_enter(&ctx_mutex);
1603 if ((cl = find_client(key)) != NULL) {
1604 mutex_enter(&cl->clm);
1605 if (cl->stale) {
1606 if (cl->ref_cnt == 0) {
1607 mutex_exit(&cl->clm);
1608 destroy_client(cl);
1609 } else {
1610 mutex_exit(&cl->clm);
1611 }
1612 mutex_exit(&ctx_mutex);
1613 return (NULL);
1614 }
1615 cl->ref_cnt++;
1616 cl->last_ref_time = gethrestime_sec();
1617 mutex_exit(&cl->clm);
1618 if (cl != lru_first) {
1619 cl->lru_prev->lru_next = cl->lru_next;
1620 if (cl->lru_next != NULL)
1621 cl->lru_next->lru_prev = cl->lru_prev;
1622 else
1623 lru_last = cl->lru_prev;
1624 cl->lru_prev = NULL;
1625 cl->lru_next = lru_first;
1626 lru_first->lru_prev = cl;
1627 lru_first = cl;
1628 }
1629 }
1630 mutex_exit(&ctx_mutex);
1631 return (cl);
1632 }
1633
1634 /*
1635 * Given the client context handle, find the context corresponding to it.
1636 * Don't change its LRU state since it may not be used.
1637 */
1638 static svc_rpc_gss_data *
find_client(key)1639 find_client(key)
1640 uint_t key;
1641 {
1642 int index = HASH(key);
1643 svc_rpc_gss_data *cl = NULL;
1644
1645 ASSERT(mutex_owned(&ctx_mutex));
1646
1647 for (cl = clients[index]; cl != NULL; cl = cl->next) {
1648 if (cl->key == key)
1649 break;
1650 }
1651 return (cl);
1652 }
1653
1654 /*
1655 * Destroy a client context.
1656 */
1657 static void
destroy_client(client_data)1658 destroy_client(client_data)
1659 svc_rpc_gss_data *client_data;
1660 {
1661 OM_uint32 minor;
1662 int index = HASH(client_data->key);
1663
1664 ASSERT(mutex_owned(&ctx_mutex));
1665
1666 /*
1667 * remove from hash list
1668 */
1669 if (client_data->prev == NULL)
1670 clients[index] = client_data->next;
1671 else
1672 client_data->prev->next = client_data->next;
1673 if (client_data->next != NULL)
1674 client_data->next->prev = client_data->prev;
1675
1676 /*
1677 * remove from LRU list
1678 */
1679 if (client_data->lru_prev == NULL)
1680 lru_first = client_data->lru_next;
1681 else
1682 client_data->lru_prev->lru_next = client_data->lru_next;
1683 if (client_data->lru_next != NULL)
1684 client_data->lru_next->lru_prev = client_data->lru_prev;
1685 else
1686 lru_last = client_data->lru_prev;
1687
1688 /*
1689 * If there is a GSS context, clean up GSS state.
1690 */
1691 if (client_data->context != GSS_C_NO_CONTEXT) {
1692 (void) kgss_delete_sec_context(&minor, &client_data->context,
1693 NULL);
1694
1695 common_client_data_free(client_data);
1696
1697 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1698 (void) kgss_release_cred(&minor, &client_data->deleg,
1699 crgetuid(CRED()));
1700 }
1701 }
1702
1703 if (client_data->u_cred.gidlist != NULL) {
1704 kmem_free((char *)client_data->u_cred.gidlist,
1705 client_data->u_cred.gidlen * sizeof (gid_t));
1706 client_data->u_cred.gidlist = NULL;
1707 }
1708 if (client_data->retrans_data != NULL)
1709 retrans_del(client_data);
1710
1711 kmem_cache_free(svc_data_handle, client_data);
1712 num_gss_contexts--;
1713 }
1714
1715 /*
1716 * Check for expired and stale client contexts.
1717 */
1718 static void
sweep_clients(bool_t from_reclaim)1719 sweep_clients(bool_t from_reclaim)
1720 {
1721 svc_rpc_gss_data *cl, *next;
1722 time_t last_reference_needed;
1723 time_t now = gethrestime_sec();
1724
1725 ASSERT(mutex_owned(&ctx_mutex));
1726
1727 last_reference_needed = now - (from_reclaim ?
1728 svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
1729
1730 cl = lru_last;
1731 while (cl) {
1732 /*
1733 * We assume here that any manipulation of the LRU pointers
1734 * and hash bucket pointers are only done when holding the
1735 * ctx_mutex.
1736 */
1737 next = cl->lru_prev;
1738
1739 mutex_enter(&cl->clm);
1740
1741 if ((cl->expiration != GSS_C_INDEFINITE &&
1742 cl->expiration <= now) || cl->stale ||
1743 cl->last_ref_time <= last_reference_needed) {
1744
1745 if ((cl->expiration != GSS_C_INDEFINITE &&
1746 cl->expiration <= now) || cl->stale ||
1747 (cl->last_ref_time <= last_reference_needed &&
1748 cl->ref_cnt == 0)) {
1749
1750 cl->stale = TRUE;
1751
1752 if (cl->ref_cnt == 0) {
1753 mutex_exit(&cl->clm);
1754 if (from_reclaim)
1755 svc_rpc_gss_cache_stats.
1756 no_returned_by_reclaim++;
1757 destroy_client(cl);
1758 } else
1759 mutex_exit(&cl->clm);
1760 } else
1761 mutex_exit(&cl->clm);
1762 } else
1763 mutex_exit(&cl->clm);
1764
1765 cl = next;
1766 }
1767
1768 last_swept = gethrestime_sec();
1769 }
1770
1771 /*
1772 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1773 * and write the result to xdrs.
1774 */
1775 static bool_t
svc_rpc_gss_wrap(auth,out_xdrs,xdr_func,xdr_ptr)1776 svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr)
1777 SVCAUTH *auth;
1778 XDR *out_xdrs;
1779 bool_t (*xdr_func)();
1780 caddr_t xdr_ptr;
1781 {
1782 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1783 bool_t ret;
1784
1785 /*
1786 * If context is not established, or if neither integrity nor
1787 * privacy service is used, don't wrap - just XDR encode.
1788 * Otherwise, wrap data using service and QOP parameters.
1789 */
1790 if (!gss_parms->established ||
1791 gss_parms->service == rpc_gss_svc_none)
1792 return ((*xdr_func)(out_xdrs, xdr_ptr));
1793
1794 ret = __rpc_gss_wrap_data(gss_parms->service,
1795 (OM_uint32)gss_parms->qop_rcvd,
1796 (gss_ctx_id_t)gss_parms->context,
1797 gss_parms->seq_num,
1798 out_xdrs, xdr_func, xdr_ptr);
1799 return (ret);
1800 }
1801
1802 /*
1803 * Decrypt the serialized arguments and XDR decode them.
1804 */
1805 static bool_t
svc_rpc_gss_unwrap(auth,in_xdrs,xdr_func,xdr_ptr)1806 svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1807 SVCAUTH *auth;
1808 XDR *in_xdrs;
1809 bool_t (*xdr_func)();
1810 caddr_t xdr_ptr;
1811 {
1812 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1813
1814 /*
1815 * If context is not established, or if neither integrity nor
1816 * privacy service is used, don't unwrap - just XDR decode.
1817 * Otherwise, unwrap data.
1818 */
1819 if (!gss_parms->established ||
1820 gss_parms->service == rpc_gss_svc_none)
1821 return ((*xdr_func)(in_xdrs, xdr_ptr));
1822
1823 return (__rpc_gss_unwrap_data(gss_parms->service,
1824 (gss_ctx_id_t)gss_parms->context,
1825 gss_parms->seq_num,
1826 gss_parms->qop_rcvd,
1827 in_xdrs, xdr_func, xdr_ptr));
1828 }
1829
1830
1831 /* ARGSUSED */
1832 int
rpc_gss_svc_max_data_length(struct svc_req * req,int max_tp_unit_len)1833 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1834 {
1835 return (0);
1836 }
1837
1838 /*
1839 * Add retransmit entry to the context cache entry for a new xid.
1840 * If there is already an entry, delete it before adding the new one.
1841 */
retrans_add(client,xid,result)1842 static void retrans_add(client, xid, result)
1843 svc_rpc_gss_data *client;
1844 uint32_t xid;
1845 rpc_gss_init_res *result;
1846 {
1847 retrans_entry *rdata;
1848
1849 if (client->retrans_data && client->retrans_data->xid == xid)
1850 return;
1851
1852 rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1853
1854 if (rdata == NULL)
1855 return;
1856
1857 rdata->xid = xid;
1858 rdata->result = *result;
1859
1860 if (result->token.length != 0) {
1861 GSS_DUP_BUFFER(rdata->result.token, result->token);
1862 }
1863
1864 if (client->retrans_data)
1865 retrans_del(client);
1866
1867 client->retrans_data = rdata;
1868 }
1869
1870 /*
1871 * Delete the retransmit data from the context cache entry.
1872 */
retrans_del(client)1873 static void retrans_del(client)
1874 svc_rpc_gss_data *client;
1875 {
1876 retrans_entry *rdata;
1877 OM_uint32 minor_stat;
1878
1879 if (client->retrans_data == NULL)
1880 return;
1881
1882 rdata = client->retrans_data;
1883 if (rdata->result.token.length != 0) {
1884 (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1885 }
1886
1887 kmem_free((caddr_t)rdata, sizeof (*rdata));
1888 client->retrans_data = NULL;
1889 }
1890
1891 /*
1892 * This function frees the following fields of svc_rpc_gss_data:
1893 * client_name, raw_cred.client_principal, raw_cred.mechanism.
1894 */
1895 static void
common_client_data_free(svc_rpc_gss_data * client_data)1896 common_client_data_free(svc_rpc_gss_data *client_data)
1897 {
1898 if (client_data->client_name.length > 0) {
1899 (void) gss_release_buffer(NULL, &client_data->client_name);
1900 }
1901
1902 if (client_data->raw_cred.client_principal) {
1903 kmem_free((caddr_t)client_data->raw_cred.client_principal,
1904 client_data->raw_cred.client_principal->len +
1905 sizeof (int));
1906 client_data->raw_cred.client_principal = NULL;
1907 }
1908
1909 /*
1910 * In the user GSS-API library, mechanism (mech_type returned
1911 * by gss_accept_sec_context) is static storage, however
1912 * since all the work is done for gss_accept_sec_context under
1913 * gssd, what is returned in the kernel, is a copy from the oid
1914 * obtained under from gssd, so need to free it when destroying
1915 * the client data.
1916 */
1917
1918 if (client_data->raw_cred.mechanism) {
1919 kgss_free_oid(client_data->raw_cred.mechanism);
1920 client_data->raw_cred.mechanism = NULL;
1921 }
1922 }
1923