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