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