Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / rpc / sec_gss / svc_rpcsec_gss.c
blobbf8e6ed3a16311f61db091c7541a6c19786b104e
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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 * Copyright 2012 Marcel Telka <marcel@telka.sk>
27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
31 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
33 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
37 * Server side handling of RPCSEC_GSS flavor.
40 #include <sys/systm.h>
41 #include <sys/kstat.h>
42 #include <sys/cmn_err.h>
43 #include <sys/debug.h>
44 #include <sys/types.h>
45 #include <sys/time.h>
46 #include <gssapi/gssapi.h>
47 #include <gssapi/gssapi_ext.h>
48 #include <rpc/rpc.h>
49 #include <rpc/rpcsec_defs.h>
50 #include <sys/sunddi.h>
51 #include <sys/atomic.h>
53 extern bool_t __rpc_gss_make_principal(rpc_gss_principal_t *, gss_buffer_t);
55 #ifdef DEBUG
56 extern void prom_printf(const char *, ...);
57 #endif
59 #ifdef _KERNEL
60 #define memcmp(a, b, l) bcmp((a), (b), (l))
61 #endif
65 * Sequence window definitions.
67 #define SEQ_ARR_SIZE 4
68 #define SEQ_WIN (SEQ_ARR_SIZE*32)
69 #define SEQ_HI_BIT 0x80000000
70 #define SEQ_LO_BIT 1
71 #define DIV_BY_32 5
72 #define SEQ_MASK 0x1f
73 #define SEQ_MAX ((unsigned int)0x80000000)
76 /* cache retransmit data */
77 typedef struct _retrans_entry {
78 uint32_t xid;
79 rpc_gss_init_res result;
80 } retrans_entry;
83 * Server side RPCSEC_GSS context information.
85 typedef struct _svc_rpc_gss_data {
86 struct _svc_rpc_gss_data *next, *prev;
87 struct _svc_rpc_gss_data *lru_next, *lru_prev;
88 bool_t established;
89 gss_ctx_id_t context;
90 gss_buffer_desc client_name;
91 time_t expiration;
92 uint_t seq_num;
93 uint_t seq_bits[SEQ_ARR_SIZE];
94 uint_t key;
95 OM_uint32 qop;
96 bool_t done_docallback;
97 bool_t locked;
98 rpc_gss_rawcred_t raw_cred;
99 rpc_gss_ucred_t u_cred;
100 time_t u_cred_set;
101 void *cookie;
102 gss_cred_id_t deleg;
103 kmutex_t clm;
104 int ref_cnt;
105 time_t last_ref_time;
106 bool_t stale;
107 retrans_entry *retrans_data;
108 } svc_rpc_gss_data;
111 * Data structures used for LRU based context management.
115 #define HASH(key) ((key) % svc_rpc_gss_hashmod)
116 /* Size of hash table for svc_rpc_gss_data structures */
117 #define GSS_DATA_HASH_SIZE 1024
120 * The following two defines specify a time delta that is used in
121 * sweep_clients. When the last_ref_time of a context is older than
122 * than the current time minus the delta, i.e, the context has not
123 * been referenced in the last delta seconds, we will return the
124 * context back to the cache if the ref_cnt is zero. The first delta
125 * value will be used when sweep_clients is called from
126 * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
127 * all entries except those that are currently "active". By active we
128 * mean those that have been referenced in the last ACTIVE_DELTA
129 * seconds. If sweep_client is not being called from reclaim, then we
130 * will reclaim all entries that are "inactive". By inactive we mean
131 * those entries that have not been accessed in INACTIVE_DELTA
132 * seconds. Note we always assume that ACTIVE_DELTA is less than
133 * INACTIVE_DELTA, so that reaping entries from a reclaim operation
134 * will necessarily imply reaping all "inactive" entries and then
135 * some.
139 * If low on memory reap cache entries that have not been active for
140 * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
142 #define ACTIVE_DELTA 30*60 /* 30 minutes */
145 * If in sweeping contexts we find contexts with a ref_cnt equal to zero
146 * and the context has not been referenced in INACTIVE_DELTA seconds, return
147 * the entry to the cache.
149 #define INACTIVE_DELTA 8*60*60 /* 8 hours */
151 int svc_rpc_gss_hashmod = GSS_DATA_HASH_SIZE;
152 static svc_rpc_gss_data **clients;
153 static svc_rpc_gss_data *lru_first, *lru_last;
154 static time_t sweep_interval = 60*60;
155 static time_t last_swept = 0;
156 static int num_gss_contexts = 0;
157 static time_t svc_rpcgss_gid_timeout = 60*60*12;
158 static kmem_cache_t *svc_data_handle;
159 static time_t svc_rpc_gss_active_delta = ACTIVE_DELTA;
160 static time_t svc_rpc_gss_inactive_delta = INACTIVE_DELTA;
163 * lock used with context/lru variables
165 static kmutex_t ctx_mutex;
168 * Data structure to contain cache statistics
171 static struct {
172 int64_t total_entries_allocated;
173 int64_t no_reclaims;
174 int64_t no_returned_by_reclaim;
175 } svc_rpc_gss_cache_stats;
179 * lock used with server credential variables list
181 * server cred list locking guidelines:
182 * - Writer's lock holder has exclusive access to the list
184 static krwlock_t cred_lock;
187 * server callback list
189 typedef struct rpc_gss_cblist_s {
190 struct rpc_gss_cblist_s *next;
191 rpc_gss_callback_t cb;
192 } rpc_gss_cblist_t;
194 static rpc_gss_cblist_t *rpc_gss_cblist = NULL;
197 * lock used with callback variables
199 static kmutex_t cb_mutex;
202 * forward declarations
204 static bool_t svc_rpc_gss_wrap();
205 static bool_t svc_rpc_gss_unwrap();
206 static svc_rpc_gss_data *create_client();
207 static svc_rpc_gss_data *get_client();
208 static svc_rpc_gss_data *find_client();
209 static void destroy_client();
210 static void sweep_clients(bool_t);
211 static void insert_client();
212 static bool_t check_verf(struct rpc_msg *, gss_ctx_id_t,
213 int *, uid_t);
214 static bool_t set_response_verf();
215 static void retrans_add(svc_rpc_gss_data *, uint32_t,
216 rpc_gss_init_res *);
217 static void retrans_del(svc_rpc_gss_data *);
218 static bool_t transfer_sec_context(svc_rpc_gss_data *);
219 static void common_client_data_free(svc_rpc_gss_data *);
222 * server side wrap/unwrap routines
224 struct svc_auth_ops svc_rpc_gss_ops = {
225 svc_rpc_gss_wrap,
226 svc_rpc_gss_unwrap,
229 /* taskq(9F) */
230 typedef struct svcrpcsec_gss_taskq_arg {
231 SVCXPRT *rq_xprt;
232 rpc_gss_init_arg *rpc_call_arg;
233 struct rpc_msg *msg;
234 svc_rpc_gss_data *client_data;
235 uint_t cr_version;
236 rpc_gss_service_t cr_service;
237 } svcrpcsec_gss_taskq_arg_t;
239 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
240 int rpcsec_gss_init_taskq_nthreads = 1;
241 static ddi_taskq_t *svcrpcsec_gss_init_taskq = NULL;
243 extern struct rpc_msg *rpc_msg_dup(struct rpc_msg *);
244 extern void rpc_msg_free(struct rpc_msg **, int);
247 * from svc_clts.c:
248 * Transport private data.
249 * Kept in xprt->xp_p2buf.
251 struct udp_data {
252 mblk_t *ud_resp; /* buffer for response */
253 mblk_t *ud_inmp; /* mblk chain of request */
256 /*ARGSUSED*/
257 static int
258 svc_gss_data_create(void *buf, void *pdata, int kmflag)
260 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
262 mutex_init(&client_data->clm, NULL, MUTEX_DEFAULT, NULL);
264 return (0);
267 /*ARGSUSED*/
268 static void
269 svc_gss_data_destroy(void *buf, void *pdata)
271 svc_rpc_gss_data *client_data = (svc_rpc_gss_data *)buf;
273 mutex_destroy(&client_data->clm);
277 /*ARGSUSED*/
278 static void
279 svc_gss_data_reclaim(void *pdata)
281 mutex_enter(&ctx_mutex);
283 svc_rpc_gss_cache_stats.no_reclaims++;
284 sweep_clients(TRUE);
286 mutex_exit(&ctx_mutex);
290 * Init stuff on the server side.
292 void
293 svc_gss_init()
295 mutex_init(&cb_mutex, NULL, MUTEX_DEFAULT, NULL);
296 mutex_init(&ctx_mutex, NULL, MUTEX_DEFAULT, NULL);
297 rw_init(&cred_lock, NULL, RW_DEFAULT, NULL);
298 clients = (svc_rpc_gss_data **)
299 kmem_zalloc(svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *),
300 KM_SLEEP);
301 svc_data_handle = kmem_cache_create("rpc_gss_data_cache",
302 sizeof (svc_rpc_gss_data), 0,
303 svc_gss_data_create,
304 svc_gss_data_destroy,
305 svc_gss_data_reclaim,
306 NULL, NULL, 0);
308 if (svcrpcsec_gss_init_taskq == NULL) {
309 svcrpcsec_gss_init_taskq = ddi_taskq_create(NULL,
310 "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads,
311 TASKQ_DEFAULTPRI, 0);
312 if (svcrpcsec_gss_init_taskq == NULL)
313 cmn_err(CE_NOTE,
314 "svc_gss_init: ddi_taskq_create failed");
319 * Destroy structures allocated in svc_gss_init().
320 * This routine is called by _init() if mod_install() failed.
322 void
323 svc_gss_fini()
325 mutex_destroy(&cb_mutex);
326 mutex_destroy(&ctx_mutex);
327 rw_destroy(&cred_lock);
328 kmem_free(clients, svc_rpc_gss_hashmod * sizeof (svc_rpc_gss_data *));
329 kmem_cache_destroy(svc_data_handle);
333 * Cleanup routine for destroying context, called after service
334 * procedure is executed. Actually we just decrement the reference count
335 * associated with this context. If the reference count is zero and the
336 * context is marked as stale, we would then destroy the context. Additionally,
337 * we check if its been longer than sweep_interval since the last sweep_clients
338 * was run, and if so run sweep_clients to free all stale contexts with zero
339 * reference counts or contexts that are old. (Haven't been access in
340 * svc_rpc_inactive_delta seconds).
342 void
343 rpc_gss_cleanup(SVCXPRT *clone_xprt)
345 svc_rpc_gss_data *cl;
346 SVCAUTH *svcauth;
349 * First check if current context needs to be cleaned up.
350 * There might be other threads stale this client data
351 * in between.
353 svcauth = &clone_xprt->xp_auth;
354 mutex_enter(&ctx_mutex);
355 if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) {
356 mutex_enter(&cl->clm);
357 ASSERT(cl->ref_cnt > 0);
358 if (--cl->ref_cnt == 0 && cl->stale) {
359 mutex_exit(&cl->clm);
360 destroy_client(cl);
361 svcauth->svc_ah_private = NULL;
362 } else
363 mutex_exit(&cl->clm);
367 * Check for other expired contexts.
369 if ((gethrestime_sec() - last_swept) > sweep_interval)
370 sweep_clients(FALSE);
372 mutex_exit(&ctx_mutex);
376 * Shift the array arr of length arrlen right by nbits bits.
378 static void
379 shift_bits(uint_t *arr, int arrlen, int nbits)
381 int i, j;
382 uint_t lo, hi;
385 * If the number of bits to be shifted exceeds SEQ_WIN, just
386 * zero out the array.
388 if (nbits < SEQ_WIN) {
389 for (i = 0; i < nbits; i++) {
390 hi = 0;
391 for (j = 0; j < arrlen; j++) {
392 lo = arr[j] & SEQ_LO_BIT;
393 arr[j] >>= 1;
394 if (hi)
395 arr[j] |= SEQ_HI_BIT;
396 hi = lo;
399 } else {
400 for (j = 0; j < arrlen; j++)
401 arr[j] = 0;
406 * Check that the received sequence number seq_num is valid.
408 static bool_t
409 check_seq(svc_rpc_gss_data *cl, uint_t seq_num, bool_t *kill_context)
411 int i, j;
412 uint_t bit;
415 * If it exceeds the maximum, kill context.
417 if (seq_num >= SEQ_MAX) {
418 *kill_context = TRUE;
419 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
420 return (FALSE);
424 * If greater than the last seen sequence number, just shift
425 * the sequence window so that it starts at the new sequence
426 * number and extends downwards by SEQ_WIN.
428 if (seq_num > cl->seq_num) {
429 (void) shift_bits(cl->seq_bits, SEQ_ARR_SIZE,
430 (int)(seq_num - cl->seq_num));
431 cl->seq_bits[0] |= SEQ_HI_BIT;
432 cl->seq_num = seq_num;
433 return (TRUE);
437 * If it is outside the sequence window, return failure.
439 i = cl->seq_num - seq_num;
440 if (i >= SEQ_WIN) {
441 RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
442 return (FALSE);
446 * If within sequence window, set the bit corresponding to it
447 * if not already seen; if already seen, return failure.
449 j = SEQ_MASK - (i & SEQ_MASK);
450 bit = j > 0 ? (1 << j) : 1;
451 i >>= DIV_BY_32;
452 if (cl->seq_bits[i] & bit) {
453 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
454 return (FALSE);
456 cl->seq_bits[i] |= bit;
457 return (TRUE);
461 * Set server callback.
463 bool_t
464 rpc_gss_set_callback(rpc_gss_callback_t *cb)
466 rpc_gss_cblist_t *cbl, *tmp;
468 if (cb->callback == NULL) {
469 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
470 return (FALSE);
473 /* check if there is already an entry in the rpc_gss_cblist. */
474 mutex_enter(&cb_mutex);
475 if (rpc_gss_cblist) {
476 for (tmp = rpc_gss_cblist; tmp != NULL; tmp = tmp->next) {
477 if ((tmp->cb.callback == cb->callback) &&
478 (tmp->cb.version == cb->version) &&
479 (tmp->cb.program == cb->program)) {
480 mutex_exit(&cb_mutex);
481 return (TRUE);
486 /* Not in rpc_gss_cblist. Create a new entry. */
487 if ((cbl = (rpc_gss_cblist_t *)kmem_alloc(sizeof (*cbl), KM_SLEEP))
488 == NULL) {
489 mutex_exit(&cb_mutex);
490 return (FALSE);
492 cbl->cb = *cb;
493 cbl->next = rpc_gss_cblist;
494 rpc_gss_cblist = cbl;
495 mutex_exit(&cb_mutex);
496 return (TRUE);
500 * Locate callback (if specified) and call server. Release any
501 * delegated credentials unless passed to server and the server
502 * accepts the context. If a callback is not specified, accept
503 * the incoming context.
505 static bool_t
506 do_callback(struct svc_req *req, svc_rpc_gss_data *client_data)
508 rpc_gss_cblist_t *cbl;
509 bool_t ret = TRUE, found = FALSE;
510 rpc_gss_lock_t lock;
511 OM_uint32 minor;
512 mutex_enter(&cb_mutex);
513 for (cbl = rpc_gss_cblist; cbl != NULL; cbl = cbl->next) {
514 if (req->rq_prog != cbl->cb.program ||
515 req->rq_vers != cbl->cb.version)
516 continue;
517 found = TRUE;
518 lock.locked = FALSE;
519 lock.raw_cred = &client_data->raw_cred;
520 ret = (*cbl->cb.callback)(req, client_data->deleg,
521 client_data->context, &lock, &client_data->cookie);
522 req->rq_xprt->xp_cookie = client_data->cookie;
524 if (ret) {
525 client_data->locked = lock.locked;
526 client_data->deleg = GSS_C_NO_CREDENTIAL;
528 break;
530 if (!found) {
531 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
532 (void) kgss_release_cred(&minor, &client_data->deleg,
533 crgetuid(CRED()));
534 client_data->deleg = GSS_C_NO_CREDENTIAL;
537 mutex_exit(&cb_mutex);
538 return (ret);
542 * Get caller credentials.
544 bool_t
545 rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
546 rpc_gss_ucred_t **ucred, void **cookie)
548 SVCAUTH *svcauth;
549 svc_rpc_gss_data *client_data;
550 int gssstat, gidlen;
552 svcauth = &req->rq_xprt->xp_auth;
553 client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private;
555 mutex_enter(&client_data->clm);
557 if (rcred != NULL) {
558 svcauth->raw_cred = client_data->raw_cred;
559 *rcred = &svcauth->raw_cred;
561 if (ucred != NULL) {
562 *ucred = &client_data->u_cred;
564 if (client_data->u_cred_set == 0 ||
565 client_data->u_cred_set < gethrestime_sec()) {
566 if (client_data->u_cred_set == 0) {
567 if ((gssstat = kgsscred_expname_to_unix_cred(
568 &client_data->client_name,
569 &client_data->u_cred.uid,
570 &client_data->u_cred.gid,
571 &client_data->u_cred.gidlist,
572 &gidlen, crgetuid(CRED())))
573 != GSS_S_COMPLETE) {
574 RPCGSS_LOG(1, "rpc_gss_getcred: "
575 "kgsscred_expname_to_unix_cred "
576 "failed %x\n", gssstat);
577 *ucred = NULL;
578 } else {
579 client_data->u_cred.gidlen =
580 (short)gidlen;
581 client_data->u_cred_set =
582 gethrestime_sec() +
583 svc_rpcgss_gid_timeout;
585 } else if (client_data->u_cred_set
586 < gethrestime_sec()) {
587 if ((gssstat = kgss_get_group_info(
588 client_data->u_cred.uid,
589 &client_data->u_cred.gid,
590 &client_data->u_cred.gidlist,
591 &gidlen, crgetuid(CRED())))
592 != GSS_S_COMPLETE) {
593 RPCGSS_LOG(1, "rpc_gss_getcred: "
594 "kgss_get_group_info failed %x\n",
595 gssstat);
596 *ucred = NULL;
597 } else {
598 client_data->u_cred.gidlen =
599 (short)gidlen;
600 client_data->u_cred_set =
601 gethrestime_sec() +
602 svc_rpcgss_gid_timeout;
608 if (cookie != NULL)
609 *cookie = client_data->cookie;
610 req->rq_xprt->xp_cookie = client_data->cookie;
612 mutex_exit(&client_data->clm);
614 return (TRUE);
618 * Transfer the context data from the user land to the kernel.
620 bool_t transfer_sec_context(svc_rpc_gss_data *client_data) {
622 gss_buffer_desc process_token;
623 OM_uint32 gssstat, minor;
626 * Call kgss_export_sec_context
627 * if an error is returned log a message
628 * go to error handling
629 * Otherwise call kgss_import_sec_context to
630 * convert the token into a context
632 gssstat = kgss_export_sec_context(&minor, client_data->context,
633 &process_token);
635 * if export_sec_context returns an error we delete the
636 * context just to be safe.
638 if (gssstat == GSS_S_NAME_NOT_MN) {
639 RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
640 "Kernel mod unavailable\n");
642 } else if (gssstat != GSS_S_COMPLETE) {
643 RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed "
644 " gssstat = 0x%x\n", gssstat);
645 (void) gss_release_buffer(&minor, &process_token);
646 (void) kgss_delete_sec_context(&minor, &client_data->context,
647 NULL);
648 return (FALSE);
650 } else if (process_token.length == 0) {
651 RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
652 "for export_sec_context, but "
653 "gsstat == GSS_S_COMPLETE\n");
654 (void) kgss_delete_sec_context(&minor, &client_data->context,
655 NULL);
656 return (FALSE);
658 } else {
659 gssstat = kgss_import_sec_context(&minor, &process_token,
660 client_data->context);
661 if (gssstat != GSS_S_COMPLETE) {
662 RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
663 " failed gssstat = 0x%x\n", gssstat);
664 (void) kgss_delete_sec_context(&minor,
665 &client_data->context, NULL);
666 (void) gss_release_buffer(&minor, &process_token);
667 return (FALSE);
670 RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
671 (void) gss_release_buffer(&minor, &process_token);
674 return (TRUE);
678 * do_gss_accept is called from a taskq and does all the work for a
679 * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
681 static enum auth_stat
682 do_gss_accept(
683 SVCXPRT *xprt,
684 rpc_gss_init_arg *call_arg,
685 struct rpc_msg *msg,
686 svc_rpc_gss_data *client_data,
687 uint_t cr_version,
688 rpc_gss_service_t cr_service)
690 rpc_gss_init_res call_res;
691 gss_buffer_desc output_token;
692 OM_uint32 gssstat, minor, minor_stat, time_rec;
693 int ret_flags, ret;
694 gss_OID mech_type = GSS_C_NULL_OID;
695 int free_mech_type = 1;
696 struct svc_req r, *rqst;
698 rqst = &r;
699 rqst->rq_xprt = xprt;
702 * Initialize output_token.
704 output_token.length = 0;
705 output_token.value = NULL;
707 bzero((char *)&call_res, sizeof (call_res));
709 mutex_enter(&client_data->clm);
710 if (client_data->stale) {
711 ret = RPCSEC_GSS_NOCRED;
712 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
713 goto error2;
717 * Any response we send will use ctx_handle, so set it now;
718 * also set seq_window since this won't change.
720 call_res.ctx_handle.length = sizeof (client_data->key);
721 call_res.ctx_handle.value = (char *)&client_data->key;
722 call_res.seq_window = SEQ_WIN;
724 gssstat = GSS_S_FAILURE;
725 minor = 0;
726 minor_stat = 0;
727 rw_enter(&cred_lock, RW_READER);
729 if (client_data->client_name.length) {
730 (void) gss_release_buffer(&minor,
731 &client_data->client_name);
733 gssstat = kgss_accept_sec_context(&minor_stat,
734 &client_data->context,
735 GSS_C_NO_CREDENTIAL,
736 call_arg,
737 GSS_C_NO_CHANNEL_BINDINGS,
738 &client_data->client_name,
739 &mech_type,
740 &output_token,
741 &ret_flags,
742 &time_rec,
743 NULL, /* don't need a delegated cred back */
744 crgetuid(CRED()));
746 RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat);
748 if (gssstat == GSS_S_COMPLETE) {
750 * Set the raw and unix credentials at this
751 * point. This saves a lot of computation
752 * later when credentials are retrieved.
754 client_data->raw_cred.version = cr_version;
755 client_data->raw_cred.service = cr_service;
757 if (client_data->raw_cred.mechanism) {
758 kgss_free_oid(client_data->raw_cred.mechanism);
759 client_data->raw_cred.mechanism = NULL;
761 client_data->raw_cred.mechanism = (rpc_gss_OID) mech_type;
763 * client_data is now responsible for freeing
764 * the data of 'mech_type'.
766 free_mech_type = 0;
768 if (client_data->raw_cred.client_principal) {
769 kmem_free((caddr_t)client_data->\
770 raw_cred.client_principal,
771 client_data->raw_cred.\
772 client_principal->len + sizeof (int));
773 client_data->raw_cred.client_principal = NULL;
777 * The client_name returned from
778 * kgss_accept_sec_context() is in an
779 * exported flat format.
781 if (! __rpc_gss_make_principal(
782 &client_data->raw_cred.client_principal,
783 &client_data->client_name)) {
784 RPCGSS_LOG0(1, "_svcrpcsec_gss: "
785 "make principal failed\n");
786 gssstat = GSS_S_FAILURE;
787 (void) gss_release_buffer(&minor_stat, &output_token);
791 rw_exit(&cred_lock);
793 call_res.gss_major = gssstat;
794 call_res.gss_minor = minor_stat;
796 if (gssstat != GSS_S_COMPLETE &&
797 gssstat != GSS_S_CONTINUE_NEEDED) {
798 call_res.ctx_handle.length = 0;
799 call_res.ctx_handle.value = NULL;
800 call_res.seq_window = 0;
801 rpc_gss_display_status(gssstat, minor_stat, mech_type,
802 crgetuid(CRED()),
803 "_svc_rpcsec_gss gss_accept_sec_context");
804 (void) svc_sendreply(rqst->rq_xprt,
805 __xdr_rpc_gss_init_res, (caddr_t)&call_res);
806 client_data->stale = TRUE;
807 ret = AUTH_OK;
808 goto error2;
812 * If appropriate, set established to TRUE *after* sending
813 * response (otherwise, the client will receive the final
814 * token encrypted)
816 if (gssstat == GSS_S_COMPLETE) {
818 * Context is established. Set expiration time
819 * for the context.
821 client_data->seq_num = 1;
822 if ((time_rec == GSS_C_INDEFINITE) || (time_rec == 0)) {
823 client_data->expiration = GSS_C_INDEFINITE;
824 } else {
825 client_data->expiration =
826 time_rec + gethrestime_sec();
829 if (!transfer_sec_context(client_data)) {
830 ret = RPCSEC_GSS_FAILED;
831 client_data->stale = TRUE;
832 RPCGSS_LOG0(1,
833 "_svc_rpcsec_gss: transfer sec context failed\n");
834 goto error2;
837 client_data->established = TRUE;
841 * This step succeeded. Send a response, along with
842 * a token if there's one. Don't dispatch.
845 if (output_token.length != 0)
846 GSS_COPY_BUFFER(call_res.token, output_token);
849 * If GSS_S_COMPLETE: set response verifier to
850 * checksum of SEQ_WIN
852 if (gssstat == GSS_S_COMPLETE) {
853 if (!set_response_verf(rqst, msg, client_data,
854 (uint_t)SEQ_WIN)) {
855 ret = RPCSEC_GSS_FAILED;
856 client_data->stale = TRUE;
857 RPCGSS_LOG0(1,
858 "_svc_rpcsec_gss:set response verifier failed\n");
859 goto error2;
863 if (!svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res,
864 (caddr_t)&call_res)) {
865 ret = RPCSEC_GSS_FAILED;
866 client_data->stale = TRUE;
867 RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
868 goto error2;
872 * Cache last response in case it is lost and the client
873 * retries on an established context.
875 (void) retrans_add(client_data, msg->rm_xid, &call_res);
876 ASSERT(client_data->ref_cnt > 0);
877 client_data->ref_cnt--;
878 mutex_exit(&client_data->clm);
880 (void) gss_release_buffer(&minor_stat, &output_token);
882 return (AUTH_OK);
884 error2:
885 ASSERT(client_data->ref_cnt > 0);
886 client_data->ref_cnt--;
887 mutex_exit(&client_data->clm);
888 (void) gss_release_buffer(&minor_stat, &output_token);
889 if (free_mech_type && mech_type)
890 kgss_free_oid(mech_type);
892 return (ret);
895 static void
896 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg)
898 enum auth_stat retval;
899 svcrpcsec_gss_taskq_arg_t *arg = svcrpcsecgss_taskq_arg;
901 retval = do_gss_accept(arg->rq_xprt, arg->rpc_call_arg, arg->msg,
902 arg->client_data, arg->cr_version, arg->cr_service);
903 if (retval != AUTH_OK) {
904 cmn_err(CE_NOTE,
905 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
906 retval);
908 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
909 SVC_RELE(arg->rq_xprt, NULL, FALSE);
910 svc_clone_unlink(arg->rq_xprt);
911 svc_clone_free(arg->rq_xprt);
912 xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)arg->rpc_call_arg);
913 kmem_free(arg->rpc_call_arg, sizeof (*arg->rpc_call_arg));
915 kmem_free(arg, sizeof (*arg));
918 static enum auth_stat
919 rpcsec_gss_init(
920 struct svc_req *rqst,
921 struct rpc_msg *msg,
922 rpc_gss_creds creds,
923 bool_t *no_dispatch,
924 svc_rpc_gss_data *c_d) /* client data, can be NULL */
926 svc_rpc_gss_data *client_data;
927 int ret;
928 svcrpcsec_gss_taskq_arg_t *arg;
930 if (creds.ctx_handle.length != 0) {
931 RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
932 ret = AUTH_BADCRED;
933 return (ret);
936 client_data = c_d ? c_d : create_client();
937 if (client_data == NULL) {
938 RPCGSS_LOG0(1,
939 "_svcrpcsec_gss: can't create a new cache entry\n");
940 ret = AUTH_FAILED;
941 return (ret);
944 mutex_enter(&client_data->clm);
945 if (client_data->stale) {
946 ret = RPCSEC_GSS_NOCRED;
947 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
948 goto error2;
952 * kgss_accept_sec_context()/gssd(8) can be overly time
953 * consuming so let's queue it and return asap.
955 * taskq func must free arg.
957 arg = kmem_alloc(sizeof (*arg), KM_SLEEP);
959 /* taskq func must free rpc_call_arg & deserialized arguments */
960 arg->rpc_call_arg = kmem_zalloc(sizeof (*arg->rpc_call_arg), KM_SLEEP);
962 /* deserialize arguments */
963 if (!SVC_GETARGS(rqst->rq_xprt, __xdr_rpc_gss_init_arg,
964 (caddr_t)arg->rpc_call_arg)) {
965 ret = RPCSEC_GSS_FAILED;
966 client_data->stale = TRUE;
967 goto error2;
970 /* get a xprt clone for taskq thread, taskq func must free it */
971 arg->rq_xprt = svc_clone_init();
972 svc_clone_link(rqst->rq_xprt->xp_master, arg->rq_xprt, rqst->rq_xprt);
973 arg->rq_xprt->xp_xid = rqst->rq_xprt->xp_xid;
976 * Increment the reference count on the rpcmod slot so that is not
977 * freed before the task has finished.
979 SVC_HOLD(arg->rq_xprt);
981 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
982 arg->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
983 arg->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
985 /* get a dup of rpc msg for taskq thread */
986 arg->msg = rpc_msg_dup(msg); /* taskq func must free msg dup */
988 arg->client_data = client_data;
989 arg->cr_version = creds.version;
990 arg->cr_service = creds.service;
992 /* should be ok to hold clm lock as taskq will have new thread(s) */
993 ret = ddi_taskq_dispatch(svcrpcsec_gss_init_taskq,
994 svcrpcsec_gss_taskq_func, arg, DDI_SLEEP);
995 if (ret == DDI_FAILURE) {
996 cmn_err(CE_NOTE, "rpcsec_gss_init: taskq dispatch fail");
997 ret = RPCSEC_GSS_FAILED;
998 rpc_msg_free(&arg->msg, MAX_AUTH_BYTES);
999 SVC_RELE(arg->rq_xprt, NULL, FALSE);
1000 svc_clone_unlink(arg->rq_xprt);
1001 svc_clone_free(arg->rq_xprt);
1002 kmem_free(arg, sizeof (*arg));
1003 goto error2;
1006 mutex_exit(&client_data->clm);
1007 *no_dispatch = TRUE;
1008 return (AUTH_OK);
1010 error2:
1011 ASSERT(client_data->ref_cnt > 0);
1012 client_data->ref_cnt--;
1013 mutex_exit(&client_data->clm);
1014 cmn_err(CE_NOTE, "rpcsec_gss_init: error 0x%x", ret);
1015 return (ret);
1018 static enum auth_stat
1019 rpcsec_gss_continue_init(
1020 struct svc_req *rqst,
1021 struct rpc_msg *msg,
1022 rpc_gss_creds creds,
1023 bool_t *no_dispatch)
1025 int ret;
1026 svc_rpc_gss_data *client_data;
1027 svc_rpc_gss_parms_t *gss_parms;
1028 rpc_gss_init_res *retrans_result;
1030 if (creds.ctx_handle.length == 0) {
1031 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1032 ret = AUTH_BADCRED;
1033 return (ret);
1035 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1036 ret = RPCSEC_GSS_NOCRED;
1037 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1038 return (ret);
1041 mutex_enter(&client_data->clm);
1042 if (client_data->stale) {
1043 ret = RPCSEC_GSS_NOCRED;
1044 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1045 goto error2;
1049 * If context not established, go thru INIT code but with
1050 * this client handle.
1052 if (!client_data->established) {
1053 mutex_exit(&client_data->clm);
1054 return (rpcsec_gss_init(rqst, msg, creds, no_dispatch,
1055 client_data));
1059 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1061 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1062 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1065 * Keep copy of parameters we'll need for response, for the
1066 * sake of reentrancy (we don't want to look in the context
1067 * data because when we are sending a response, another
1068 * request may have come in).
1070 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1071 gss_parms->established = client_data->established;
1072 gss_parms->service = creds.service;
1073 gss_parms->qop_rcvd = (uint_t)client_data->qop;
1074 gss_parms->context = (void *)client_data->context;
1075 gss_parms->seq_num = creds.seq_num;
1078 * This is an established context. Continue to
1079 * satisfy retried continue init requests out of
1080 * the retransmit cache. Throw away any that don't
1081 * have a matching xid or the cach is empty.
1082 * Delete the retransmit cache once the client sends
1083 * a data request.
1085 if (client_data->retrans_data &&
1086 (client_data->retrans_data->xid == msg->rm_xid)) {
1087 retrans_result = &client_data->retrans_data->result;
1088 if (set_response_verf(rqst, msg, client_data,
1089 (uint_t)retrans_result->seq_window)) {
1090 gss_parms->established = FALSE;
1091 (void) svc_sendreply(rqst->rq_xprt,
1092 __xdr_rpc_gss_init_res, (caddr_t)retrans_result);
1093 *no_dispatch = TRUE;
1094 ASSERT(client_data->ref_cnt > 0);
1095 client_data->ref_cnt--;
1098 mutex_exit(&client_data->clm);
1100 return (AUTH_OK);
1102 error2:
1103 ASSERT(client_data->ref_cnt > 0);
1104 client_data->ref_cnt--;
1105 mutex_exit(&client_data->clm);
1106 return (ret);
1109 static enum auth_stat
1110 rpcsec_gss_data(
1111 struct svc_req *rqst,
1112 struct rpc_msg *msg,
1113 rpc_gss_creds creds,
1114 bool_t *no_dispatch)
1116 int ret;
1117 svc_rpc_gss_parms_t *gss_parms;
1118 svc_rpc_gss_data *client_data;
1120 switch (creds.service) {
1121 case rpc_gss_svc_none:
1122 case rpc_gss_svc_integrity:
1123 case rpc_gss_svc_privacy:
1124 break;
1125 default:
1126 cmn_err(CE_NOTE, "__svcrpcsec_gss: unknown service type=0x%x",
1127 creds.service);
1128 RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1129 creds.service);
1130 ret = AUTH_BADCRED;
1131 return (ret);
1134 if (creds.ctx_handle.length == 0) {
1135 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1136 ret = AUTH_BADCRED;
1137 return (ret);
1139 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1140 ret = RPCSEC_GSS_NOCRED;
1141 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1142 return (ret);
1146 mutex_enter(&client_data->clm);
1147 if (!client_data->established) {
1148 ret = AUTH_FAILED;
1149 goto error2;
1151 if (client_data->stale) {
1152 ret = RPCSEC_GSS_NOCRED;
1153 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1154 goto error2;
1158 * Once the context is established and there is no more
1159 * retransmission of last continue init request, it is safe
1160 * to delete the retransmit cache entry.
1162 if (client_data->retrans_data)
1163 retrans_del(client_data);
1166 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1168 rqst->rq_xprt->xp_auth.svc_ah_ops = svc_rpc_gss_ops;
1169 rqst->rq_xprt->xp_auth.svc_ah_private = (caddr_t)client_data;
1172 * Keep copy of parameters we'll need for response, for the
1173 * sake of reentrancy (we don't want to look in the context
1174 * data because when we are sending a response, another
1175 * request may have come in).
1177 gss_parms = &rqst->rq_xprt->xp_auth.svc_gss_parms;
1178 gss_parms->established = client_data->established;
1179 gss_parms->service = creds.service;
1180 gss_parms->qop_rcvd = (uint_t)client_data->qop;
1181 gss_parms->context = (void *)client_data->context;
1182 gss_parms->seq_num = creds.seq_num;
1185 * Context is already established. Check verifier, and
1186 * note parameters we will need for response in gss_parms.
1188 if (!check_verf(msg, client_data->context,
1189 (int *)&gss_parms->qop_rcvd, client_data->u_cred.uid)) {
1190 ret = RPCSEC_GSS_NOCRED;
1191 RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1192 goto error2;
1196 * Check and invoke callback if necessary.
1198 if (!client_data->done_docallback) {
1199 client_data->done_docallback = TRUE;
1200 client_data->qop = gss_parms->qop_rcvd;
1201 client_data->raw_cred.qop = gss_parms->qop_rcvd;
1202 client_data->raw_cred.service = creds.service;
1203 if (!do_callback(rqst, client_data)) {
1204 ret = AUTH_FAILED;
1205 RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1206 goto error2;
1211 * If the context was locked, make sure that the client
1212 * has not changed QOP.
1214 if (client_data->locked && gss_parms->qop_rcvd != client_data->qop) {
1215 ret = AUTH_BADVERF;
1216 RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1217 goto error2;
1221 * Validate sequence number.
1223 if (!check_seq(client_data, creds.seq_num, &client_data->stale)) {
1224 if (client_data->stale) {
1225 ret = RPCSEC_GSS_FAILED;
1226 RPCGSS_LOG0(1,
1227 "_svc_rpcsec_gss:check seq failed\n");
1228 } else {
1229 RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1230 "failed on good context. Ignoring "
1231 "request\n");
1233 * Operational error, drop packet silently.
1234 * The client will recover after timing out,
1235 * assuming this is a client error and not
1236 * a relpay attack. Don't dispatch.
1238 ret = AUTH_OK;
1239 *no_dispatch = TRUE;
1241 goto error2;
1245 * set response verifier
1247 if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) {
1248 ret = RPCSEC_GSS_FAILED;
1249 client_data->stale = TRUE;
1250 RPCGSS_LOG0(1,
1251 "_svc_rpcsec_gss:set response verifier failed\n");
1252 goto error2;
1256 * If context is locked, make sure that the client
1257 * has not changed the security service.
1259 if (client_data->locked &&
1260 client_data->raw_cred.service != creds.service) {
1261 RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1262 "security service changed.\n");
1263 ret = AUTH_FAILED;
1264 goto error2;
1268 * Set client credentials to raw credential
1269 * structure in context. This is okay, since
1270 * this will not change during the lifetime of
1271 * the context (so it's MT safe).
1273 rqst->rq_clntcred = (char *)&client_data->raw_cred;
1275 mutex_exit(&client_data->clm);
1276 return (AUTH_OK);
1278 error2:
1279 ASSERT(client_data->ref_cnt > 0);
1280 client_data->ref_cnt--;
1281 mutex_exit(&client_data->clm);
1282 return (ret);
1286 * Note we don't have a client yet to use this routine and test it.
1288 static enum auth_stat
1289 rpcsec_gss_destroy(
1290 struct svc_req *rqst,
1291 rpc_gss_creds creds,
1292 bool_t *no_dispatch)
1294 svc_rpc_gss_data *client_data;
1295 int ret;
1297 if (creds.ctx_handle.length == 0) {
1298 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1299 ret = AUTH_BADCRED;
1300 return (ret);
1302 if ((client_data = get_client(&creds.ctx_handle)) == NULL) {
1303 ret = RPCSEC_GSS_NOCRED;
1304 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1305 return (ret);
1308 mutex_enter(&client_data->clm);
1309 if (!client_data->established) {
1310 ret = AUTH_FAILED;
1311 goto error2;
1313 if (client_data->stale) {
1314 ret = RPCSEC_GSS_NOCRED;
1315 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1316 goto error2;
1319 (void) svc_sendreply(rqst->rq_xprt, xdr_void, NULL);
1320 *no_dispatch = TRUE;
1321 ASSERT(client_data->ref_cnt > 0);
1322 client_data->ref_cnt--;
1323 client_data->stale = TRUE;
1324 mutex_exit(&client_data->clm);
1325 return (AUTH_OK);
1327 error2:
1328 ASSERT(client_data->ref_cnt > 0);
1329 client_data->ref_cnt--;
1330 client_data->stale = TRUE;
1331 mutex_exit(&client_data->clm);
1332 return (ret);
1336 * Server side authentication for RPCSEC_GSS.
1338 enum auth_stat
1339 __svcrpcsec_gss(
1340 struct svc_req *rqst,
1341 struct rpc_msg *msg,
1342 bool_t *no_dispatch)
1344 XDR xdrs;
1345 rpc_gss_creds creds;
1346 struct opaque_auth *cred;
1347 int ret;
1349 *no_dispatch = FALSE;
1352 * Initialize response verifier to NULL verifier. If
1353 * necessary, this will be changed later.
1355 rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE;
1356 rqst->rq_xprt->xp_verf.oa_base = NULL;
1357 rqst->rq_xprt->xp_verf.oa_length = 0;
1360 * Pull out and check credential and verifier.
1362 cred = &msg->rm_call.cb_cred;
1364 if (cred->oa_length == 0) {
1365 RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1366 return (AUTH_BADCRED);
1369 xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);
1370 bzero((char *)&creds, sizeof (creds));
1371 if (!__xdr_rpc_gss_creds(&xdrs, &creds)) {
1372 XDR_DESTROY(&xdrs);
1373 RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1374 ret = AUTH_BADCRED;
1375 return (AUTH_BADCRED);
1377 XDR_DESTROY(&xdrs);
1379 switch (creds.gss_proc) {
1380 case RPCSEC_GSS_INIT:
1381 ret = rpcsec_gss_init(rqst, msg, creds, no_dispatch, NULL);
1382 break;
1383 case RPCSEC_GSS_CONTINUE_INIT:
1384 ret = rpcsec_gss_continue_init(rqst, msg, creds, no_dispatch);
1385 break;
1386 case RPCSEC_GSS_DATA:
1387 ret = rpcsec_gss_data(rqst, msg, creds, no_dispatch);
1388 break;
1389 case RPCSEC_GSS_DESTROY:
1390 ret = rpcsec_gss_destroy(rqst, creds, no_dispatch);
1391 break;
1392 default:
1393 cmn_err(CE_NOTE, "__svcrpcsec_gss: bad proc=%d",
1394 creds.gss_proc);
1395 ret = AUTH_BADCRED;
1398 if (creds.ctx_handle.length != 0)
1399 xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds);
1400 return (ret);
1404 * Check verifier. The verifier is the checksum of the RPC header
1405 * upto and including the credentials field.
1408 /* ARGSUSED */
1409 static bool_t
1410 check_verf(struct rpc_msg *msg, gss_ctx_id_t context, int *qop_state, uid_t uid)
1412 int *buf, *tmp;
1413 char hdr[128];
1414 struct opaque_auth *oa;
1415 int len;
1416 gss_buffer_desc msg_buf;
1417 gss_buffer_desc tok_buf;
1418 OM_uint32 gssstat, minor_stat;
1421 * We have to reconstruct the RPC header from the previously
1422 * parsed information, since we haven't kept the header intact.
1425 oa = &msg->rm_call.cb_cred;
1426 if (oa->oa_length > MAX_AUTH_BYTES)
1427 return (FALSE);
1429 /* 8 XDR units from the IXDR macro calls. */
1430 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT +
1431 RNDUP(oa->oa_length)))
1432 return (FALSE);
1433 buf = (int *)hdr;
1434 IXDR_PUT_U_INT32(buf, msg->rm_xid);
1435 IXDR_PUT_ENUM(buf, msg->rm_direction);
1436 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers);
1437 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog);
1438 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers);
1439 IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc);
1440 IXDR_PUT_ENUM(buf, oa->oa_flavor);
1441 IXDR_PUT_U_INT32(buf, oa->oa_length);
1442 if (oa->oa_length) {
1443 len = RNDUP(oa->oa_length);
1444 tmp = buf;
1445 buf += len / sizeof (int);
1446 *(buf - 1) = 0;
1447 (void) bcopy(oa->oa_base, (caddr_t)tmp, oa->oa_length);
1449 len = ((char *)buf) - hdr;
1450 msg_buf.length = len;
1451 msg_buf.value = hdr;
1452 oa = &msg->rm_call.cb_verf;
1453 tok_buf.length = oa->oa_length;
1454 tok_buf.value = oa->oa_base;
1456 gssstat = kgss_verify(&minor_stat, context, &msg_buf, &tok_buf,
1457 qop_state);
1458 if (gssstat != GSS_S_COMPLETE) {
1459 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat);
1461 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len);
1462 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr);
1463 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1464 tok_buf.length);
1465 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1466 (void *)oa->oa_base);
1467 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context);
1469 return (FALSE);
1471 return (TRUE);
1476 * Set response verifier. This is the checksum of the given number.
1477 * (e.g. sequence number or sequence window)
1479 static bool_t
1480 set_response_verf(struct svc_req *rqst, struct rpc_msg *msg,
1481 svc_rpc_gss_data *cl, uint_t num)
1483 OM_uint32 minor;
1484 gss_buffer_desc in_buf, out_buf;
1485 uint_t num_net;
1487 num_net = (uint_t)htonl(num);
1488 in_buf.length = sizeof (num);
1489 in_buf.value = (char *)&num_net;
1490 /* XXX uid ? */
1492 if ((kgss_sign(&minor, cl->context, cl->qop, &in_buf, &out_buf))
1493 != GSS_S_COMPLETE)
1494 return (FALSE);
1496 rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
1497 rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
1498 rqst->rq_xprt->xp_verf.oa_length = out_buf.length;
1499 bcopy(out_buf.value, rqst->rq_xprt->xp_verf.oa_base, out_buf.length);
1500 (void) gss_release_buffer(&minor, &out_buf);
1501 return (TRUE);
1505 * Create client context.
1507 static svc_rpc_gss_data *
1508 create_client()
1510 svc_rpc_gss_data *client_data;
1511 static uint_t key = 1;
1513 client_data = (svc_rpc_gss_data *) kmem_cache_alloc(svc_data_handle,
1514 KM_SLEEP);
1515 if (client_data == NULL)
1516 return (NULL);
1519 * set up client data structure
1521 client_data->next = NULL;
1522 client_data->prev = NULL;
1523 client_data->lru_next = NULL;
1524 client_data->lru_prev = NULL;
1525 client_data->client_name.length = 0;
1526 client_data->client_name.value = NULL;
1527 client_data->seq_num = 0;
1528 bzero(client_data->seq_bits, sizeof (client_data->seq_bits));
1529 client_data->key = 0;
1530 client_data->cookie = NULL;
1531 bzero(&client_data->u_cred, sizeof (client_data->u_cred));
1532 client_data->established = FALSE;
1533 client_data->locked = FALSE;
1534 client_data->u_cred_set = 0;
1535 client_data->context = GSS_C_NO_CONTEXT;
1536 client_data->expiration = GSS_C_INDEFINITE;
1537 client_data->deleg = GSS_C_NO_CREDENTIAL;
1538 client_data->ref_cnt = 1;
1539 client_data->last_ref_time = gethrestime_sec();
1540 client_data->qop = GSS_C_QOP_DEFAULT;
1541 client_data->done_docallback = FALSE;
1542 client_data->stale = FALSE;
1543 client_data->retrans_data = NULL;
1544 bzero(&client_data->raw_cred, sizeof (client_data->raw_cred));
1547 * The client context handle is a 32-bit key (unsigned int).
1548 * The key is incremented until there is no duplicate for it.
1551 svc_rpc_gss_cache_stats.total_entries_allocated++;
1552 mutex_enter(&ctx_mutex);
1553 for (;;) {
1554 client_data->key = key++;
1555 if (find_client(client_data->key) == NULL) {
1556 insert_client(client_data);
1557 mutex_exit(&ctx_mutex);
1558 return (client_data);
1561 /*NOTREACHED*/
1565 * Insert client context into hash list and LRU list.
1567 static void
1568 insert_client(svc_rpc_gss_data *client_data)
1570 svc_rpc_gss_data *cl;
1571 int index = HASH(client_data->key);
1573 ASSERT(mutex_owned(&ctx_mutex));
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;
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;
1588 num_gss_contexts++;
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.
1595 static svc_rpc_gss_data *
1596 get_client(gss_buffer_t ctx_handle)
1598 uint_t key = *(uint_t *)ctx_handle->value;
1599 svc_rpc_gss_data *cl;
1601 mutex_enter(&ctx_mutex);
1602 if ((cl = find_client(key)) != NULL) {
1603 mutex_enter(&cl->clm);
1604 if (cl->stale) {
1605 if (cl->ref_cnt == 0) {
1606 mutex_exit(&cl->clm);
1607 destroy_client(cl);
1608 } else {
1609 mutex_exit(&cl->clm);
1611 mutex_exit(&ctx_mutex);
1612 return (NULL);
1614 cl->ref_cnt++;
1615 cl->last_ref_time = gethrestime_sec();
1616 mutex_exit(&cl->clm);
1617 if (cl != lru_first) {
1618 cl->lru_prev->lru_next = cl->lru_next;
1619 if (cl->lru_next != NULL)
1620 cl->lru_next->lru_prev = cl->lru_prev;
1621 else
1622 lru_last = cl->lru_prev;
1623 cl->lru_prev = NULL;
1624 cl->lru_next = lru_first;
1625 lru_first->lru_prev = cl;
1626 lru_first = cl;
1629 mutex_exit(&ctx_mutex);
1630 return (cl);
1634 * Given the client context handle, find the context corresponding to it.
1635 * Don't change its LRU state since it may not be used.
1637 static svc_rpc_gss_data *
1638 find_client(uint_t key)
1640 int index = HASH(key);
1641 svc_rpc_gss_data *cl = NULL;
1643 ASSERT(mutex_owned(&ctx_mutex));
1645 for (cl = clients[index]; cl != NULL; cl = cl->next) {
1646 if (cl->key == key)
1647 break;
1649 return (cl);
1653 * Destroy a client context.
1655 static void
1656 destroy_client(svc_rpc_gss_data *client_data)
1658 OM_uint32 minor;
1659 int index = HASH(client_data->key);
1661 ASSERT(mutex_owned(&ctx_mutex));
1664 * remove from hash list
1666 if (client_data->prev == NULL)
1667 clients[index] = client_data->next;
1668 else
1669 client_data->prev->next = client_data->next;
1670 if (client_data->next != NULL)
1671 client_data->next->prev = client_data->prev;
1674 * remove from LRU list
1676 if (client_data->lru_prev == NULL)
1677 lru_first = client_data->lru_next;
1678 else
1679 client_data->lru_prev->lru_next = client_data->lru_next;
1680 if (client_data->lru_next != NULL)
1681 client_data->lru_next->lru_prev = client_data->lru_prev;
1682 else
1683 lru_last = client_data->lru_prev;
1686 * If there is a GSS context, clean up GSS state.
1688 if (client_data->context != GSS_C_NO_CONTEXT) {
1689 (void) kgss_delete_sec_context(&minor, &client_data->context,
1690 NULL);
1692 common_client_data_free(client_data);
1694 if (client_data->deleg != GSS_C_NO_CREDENTIAL) {
1695 (void) kgss_release_cred(&minor, &client_data->deleg,
1696 crgetuid(CRED()));
1700 if (client_data->u_cred.gidlist != NULL) {
1701 kmem_free((char *)client_data->u_cred.gidlist,
1702 client_data->u_cred.gidlen * sizeof (gid_t));
1703 client_data->u_cred.gidlist = NULL;
1705 if (client_data->retrans_data != NULL)
1706 retrans_del(client_data);
1708 kmem_cache_free(svc_data_handle, client_data);
1709 num_gss_contexts--;
1713 * Check for expired and stale client contexts.
1715 static void
1716 sweep_clients(bool_t from_reclaim)
1718 svc_rpc_gss_data *cl, *next;
1719 time_t last_reference_needed;
1720 time_t now = gethrestime_sec();
1722 ASSERT(mutex_owned(&ctx_mutex));
1724 last_reference_needed = now - (from_reclaim ?
1725 svc_rpc_gss_active_delta : svc_rpc_gss_inactive_delta);
1727 cl = lru_last;
1728 while (cl) {
1730 * We assume here that any manipulation of the LRU pointers
1731 * and hash bucket pointers are only done when holding the
1732 * ctx_mutex.
1734 next = cl->lru_prev;
1736 mutex_enter(&cl->clm);
1738 if ((cl->expiration != GSS_C_INDEFINITE &&
1739 cl->expiration <= now) || cl->stale ||
1740 cl->last_ref_time <= last_reference_needed) {
1742 if ((cl->expiration != GSS_C_INDEFINITE &&
1743 cl->expiration <= now) || cl->stale ||
1744 (cl->last_ref_time <= last_reference_needed &&
1745 cl->ref_cnt == 0)) {
1747 cl->stale = TRUE;
1749 if (cl->ref_cnt == 0) {
1750 mutex_exit(&cl->clm);
1751 if (from_reclaim)
1752 svc_rpc_gss_cache_stats.
1753 no_returned_by_reclaim++;
1754 destroy_client(cl);
1755 } else
1756 mutex_exit(&cl->clm);
1757 } else
1758 mutex_exit(&cl->clm);
1759 } else
1760 mutex_exit(&cl->clm);
1762 cl = next;
1765 last_swept = gethrestime_sec();
1769 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1770 * and write the result to xdrs.
1772 static bool_t
1773 svc_rpc_gss_wrap(SVCAUTH *auth, XDR *out_xdrs, bool_t (*xdr_func)(),
1774 caddr_t xdr_ptr)
1776 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1777 bool_t ret;
1780 * If context is not established, or if neither integrity nor
1781 * privacy service is used, don't wrap - just XDR encode.
1782 * Otherwise, wrap data using service and QOP parameters.
1784 if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1785 return ((*xdr_func)(out_xdrs, xdr_ptr));
1787 ret = __rpc_gss_wrap_data(gss_parms->service,
1788 (OM_uint32)gss_parms->qop_rcvd,
1789 (gss_ctx_id_t)gss_parms->context,
1790 gss_parms->seq_num,
1791 out_xdrs, xdr_func, xdr_ptr);
1792 return (ret);
1796 * Decrypt the serialized arguments and XDR decode them.
1798 static bool_t
1799 svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *in_xdrs, bool_t (*xdr_func)(),
1800 caddr_t xdr_ptr)
1802 svc_rpc_gss_parms_t *gss_parms = SVCAUTH_GSSPARMS(auth);
1805 * If context is not established, or if neither integrity nor
1806 * privacy service is used, don't unwrap - just XDR decode.
1807 * Otherwise, unwrap data.
1809 if (!gss_parms->established || gss_parms->service == rpc_gss_svc_none)
1810 return ((*xdr_func)(in_xdrs, xdr_ptr));
1812 return (__rpc_gss_unwrap_data(gss_parms->service,
1813 (gss_ctx_id_t)gss_parms->context,
1814 gss_parms->seq_num,
1815 gss_parms->qop_rcvd,
1816 in_xdrs, xdr_func, xdr_ptr));
1820 /* ARGSUSED */
1822 rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len)
1824 return (0);
1828 * Add retransmit entry to the context cache entry for a new xid.
1829 * If there is already an entry, delete it before adding the new one.
1831 static void retrans_add(client, xid, result)
1832 svc_rpc_gss_data *client;
1833 uint32_t xid;
1834 rpc_gss_init_res *result;
1836 retrans_entry *rdata;
1838 if (client->retrans_data && client->retrans_data->xid == xid)
1839 return;
1841 rdata = kmem_zalloc(sizeof (*rdata), KM_SLEEP);
1843 if (rdata == NULL)
1844 return;
1846 rdata->xid = xid;
1847 rdata->result = *result;
1849 if (result->token.length != 0) {
1850 GSS_DUP_BUFFER(rdata->result.token, result->token);
1853 if (client->retrans_data)
1854 retrans_del(client);
1856 client->retrans_data = rdata;
1860 * Delete the retransmit data from the context cache entry.
1862 static void retrans_del(client)
1863 svc_rpc_gss_data *client;
1865 retrans_entry *rdata;
1866 OM_uint32 minor_stat;
1868 if (client->retrans_data == NULL)
1869 return;
1871 rdata = client->retrans_data;
1872 if (rdata->result.token.length != 0) {
1873 (void) gss_release_buffer(&minor_stat, &rdata->result.token);
1876 kmem_free((caddr_t)rdata, sizeof (*rdata));
1877 client->retrans_data = NULL;
1881 * This function frees the following fields of svc_rpc_gss_data:
1882 * client_name, raw_cred.client_principal, raw_cred.mechanism.
1884 static void
1885 common_client_data_free(svc_rpc_gss_data *client_data)
1887 if (client_data->client_name.length > 0) {
1888 (void) gss_release_buffer(NULL, &client_data->client_name);
1891 if (client_data->raw_cred.client_principal) {
1892 kmem_free((caddr_t)client_data->raw_cred.client_principal,
1893 client_data->raw_cred.client_principal->len +
1894 sizeof (int));
1895 client_data->raw_cred.client_principal = NULL;
1899 * In the user GSS-API library, mechanism (mech_type returned
1900 * by gss_accept_sec_context) is static storage, however
1901 * since all the work is done for gss_accept_sec_context under
1902 * gssd, what is returned in the kernel, is a copy from the oid
1903 * obtained under from gssd, so need to free it when destroying
1904 * the client data.
1907 if (client_data->raw_cred.mechanism) {
1908 kgss_free_oid(client_data->raw_cred.mechanism);
1909 client_data->raw_cred.mechanism = NULL;