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