1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 4554 ps57422 * Common Development and Distribution License (the "License"). 6 4554 ps57422 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 4554 ps57422 22 0 stevel /* 23 6636 gtb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 4554 ps57422 * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel /* 30 0 stevel * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 31 0 stevel * 32 0 stevel * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $ 33 0 stevel */ 34 0 stevel 35 0 stevel /* 36 0 stevel * Server side handling of RPCSEC_GSS flavor. 37 0 stevel */ 38 0 stevel 39 0 stevel #include <stdio.h> 40 0 stevel #include <stdlib.h> 41 0 stevel #include <strings.h> 42 0 stevel #include <sys/stat.h> 43 0 stevel #include <sys/time.h> 44 0 stevel #include <gssapi/gssapi.h> 45 0 stevel #include <gssapi/gssapi_ext.h> 46 0 stevel #include <rpc/rpc.h> 47 0 stevel #include <rpc/rpcsec_defs.h> 48 0 stevel #include <sys/file.h> 49 0 stevel #include <fcntl.h> 50 0 stevel #include <pwd.h> 51 0 stevel #include <stdio.h> 52 0 stevel #include <syslog.h> 53 0 stevel 54 0 stevel /* 55 0 stevel * Sequence window definitions. 56 0 stevel */ 57 0 stevel #define SEQ_ARR_SIZE 4 58 0 stevel #define SEQ_WIN (SEQ_ARR_SIZE*32) 59 0 stevel #define SEQ_HI_BIT 0x80000000 60 0 stevel #define SEQ_LO_BIT 1 61 0 stevel #define DIV_BY_32 5 62 0 stevel #define SEQ_MASK 0x1f 63 0 stevel #define SEQ_MAX 0x80000000 64 0 stevel 65 0 stevel 66 0 stevel /* cache retransmit data */ 67 0 stevel typedef struct _retrans_entry { 68 0 stevel uint32_t xid; 69 0 stevel rpc_gss_init_res result; 70 0 stevel struct _retrans_entry *next, *prev; 71 0 stevel } retrans_entry; 72 0 stevel 73 0 stevel /* 74 0 stevel * Server side RPCSEC_GSS context information. 75 0 stevel */ 76 0 stevel typedef struct _svc_rpc_gss_data { 77 0 stevel struct _svc_rpc_gss_data *next, *prev; 78 0 stevel struct _svc_rpc_gss_data *lru_next, *lru_prev; 79 0 stevel bool_t established; 80 0 stevel gss_ctx_id_t context; 81 0 stevel gss_name_t client_name; 82 0 stevel gss_cred_id_t server_creds; 83 0 stevel uint_t expiration; 84 0 stevel uint_t seq_num; 85 0 stevel uint_t seq_bits[SEQ_ARR_SIZE]; 86 0 stevel uint_t key; 87 0 stevel OM_uint32 qop; 88 0 stevel bool_t done_docallback; 89 0 stevel bool_t locked; 90 0 stevel rpc_gss_rawcred_t raw_cred; 91 0 stevel rpc_gss_ucred_t u_cred; 92 0 stevel bool_t u_cred_set; 93 0 stevel void *cookie; 94 0 stevel gss_cred_id_t deleg; 95 0 stevel mutex_t clm; 96 0 stevel int ref_cnt; 97 0 stevel bool_t stale; 98 0 stevel time_t time_secs_set; 99 0 stevel retrans_entry *retrans_data; 100 0 stevel } svc_rpc_gss_data; 101 0 stevel 102 0 stevel /* 103 0 stevel * Data structures used for LRU based context management. 104 0 stevel */ 105 0 stevel #define HASHMOD 256 106 0 stevel #define HASHMASK 255 107 0 stevel 108 0 stevel static svc_rpc_gss_data *clients[HASHMOD]; 109 0 stevel static svc_rpc_gss_data *lru_first, *lru_last; 110 0 stevel static int num_gss_contexts = 0; 111 0 stevel static int max_gss_contexts = 128; 112 0 stevel static int sweep_interval = 10; 113 0 stevel static int last_swept = 0; 114 0 stevel static uint_t max_lifetime = GSS_C_INDEFINITE; 115 6636 gtb static int init_lifetime = 0; 116 0 stevel static uint_t gid_timeout = 43200; /* 43200 secs = 12 hours */ 117 0 stevel 118 0 stevel /* 119 0 stevel * lock used with context/lru variables 120 0 stevel */ 121 0 stevel static mutex_t ctx_mutex = DEFAULTMUTEX; 122 0 stevel 123 0 stevel /* 124 0 stevel * server credential management data and structures 125 0 stevel */ 126 0 stevel typedef struct svc_creds_list_s { 127 0 stevel struct svc_creds_list_s *next; 128 0 stevel gss_cred_id_t cred; 129 0 stevel gss_name_t name; 130 0 stevel rpcprog_t program; 131 0 stevel rpcvers_t version; 132 0 stevel gss_OID_set oid_set; 133 0 stevel OM_uint32 req_time; 134 0 stevel char *server_name; 135 0 stevel mutex_t refresh_mutex; 136 0 stevel } svc_creds_list_t; 137 0 stevel 138 0 stevel 139 0 stevel static svc_creds_list_t *svc_creds_list; 140 0 stevel static int svc_creds_count = 0; 141 0 stevel 142 0 stevel /* 143 0 stevel * lock used with server credential variables list 144 0 stevel * 145 0 stevel * server cred list locking guidelines: 146 0 stevel * - Writer's lock holder has exclusive access to the list 147 0 stevel * - Reader's lock holder(s) must also lock (refresh_mutex) each node 148 0 stevel * before accessing that node's elements (ie. cred) 149 0 stevel */ 150 0 stevel static rwlock_t cred_lock = DEFAULTRWLOCK; 151 0 stevel 152 0 stevel /* 153 0 stevel * server callback list 154 0 stevel */ 155 0 stevel typedef struct cblist_s { 156 0 stevel struct cblist_s *next; 157 0 stevel rpc_gss_callback_t cb; 158 0 stevel } cblist_t; 159 0 stevel 160 0 stevel cblist_t *cblist = NULL; 161 0 stevel 162 0 stevel /* 163 0 stevel * lock used with callback variables 164 0 stevel */ 165 0 stevel static mutex_t cb_mutex = DEFAULTMUTEX; 166 0 stevel 167 0 stevel /* 168 0 stevel * forward declarations 169 0 stevel */ 170 0 stevel static bool_t svc_rpc_gss_wrap(); 171 0 stevel static bool_t svc_rpc_gss_unwrap(); 172 0 stevel static svc_rpc_gss_data *create_client(); 173 0 stevel static svc_rpc_gss_data *get_client(); 174 0 stevel static svc_rpc_gss_data *find_client(); 175 0 stevel static void destroy_client(); 176 0 stevel static void sweep_clients(); 177 0 stevel static void drop_lru_client(); 178 0 stevel static void insert_client(); 179 0 stevel static bool_t check_verf(); 180 0 stevel static bool_t rpc_gss_refresh_svc_cred(); 181 0 stevel static bool_t set_response_verf(); 182 0 stevel static void retrans_add(svc_rpc_gss_data *, uint32_t, 183 0 stevel rpc_gss_init_res *); 184 0 stevel static void retrans_del(struct _svc_rpc_gss_data *); 185 0 stevel 186 0 stevel 187 0 stevel /* 188 0 stevel * server side wrap/unwrap routines 189 0 stevel */ 190 0 stevel struct svc_auth_ops svc_rpc_gss_ops = { 191 0 stevel svc_rpc_gss_wrap, 192 0 stevel svc_rpc_gss_unwrap, 193 0 stevel }; 194 0 stevel 195 0 stevel /* 196 0 stevel * Fetch server side authentication structure. 197 0 stevel */ 198 0 stevel extern SVCAUTH *__svc_get_svcauth(); 199 0 stevel 200 0 stevel /* 201 0 stevel * Cleanup routine for destroying context, called after service 202 0 stevel * procedure is executed, for MT safeness. 203 0 stevel */ 204 0 stevel extern void *__svc_set_proc_cleanup_cb(); 205 0 stevel static void (*old_cleanup_cb)() = NULL; 206 0 stevel static bool_t cleanup_cb_set = FALSE; 207 0 stevel 208 0 stevel static void 209 0 stevel ctx_cleanup(xprt) 210 0 stevel SVCXPRT *xprt; 211 0 stevel { 212 0 stevel svc_rpc_gss_data *cl; 213 0 stevel SVCAUTH *svcauth; 214 0 stevel 215 0 stevel if (old_cleanup_cb != NULL) 216 0 stevel (*old_cleanup_cb)(xprt); 217 0 stevel 218 0 stevel /* 219 0 stevel * First check if current context needs to be cleaned up. 220 0 stevel */ 221 0 stevel svcauth = __svc_get_svcauth(xprt); 222 0 stevel /*LINTED*/ 223 0 stevel if ((cl = (svc_rpc_gss_data *)svcauth->svc_ah_private) != NULL) { 224 0 stevel mutex_lock(&cl->clm); 225 0 stevel if (--cl->ref_cnt == 0 && cl->stale) { 226 0 stevel mutex_unlock(&cl->clm); 227 0 stevel mutex_lock(&ctx_mutex); 228 0 stevel destroy_client(cl); 229 0 stevel mutex_unlock(&ctx_mutex); 230 0 stevel } else 231 0 stevel mutex_unlock(&cl->clm); 232 0 stevel } 233 0 stevel 234 0 stevel /* 235 0 stevel * Check for other expired contexts. 236 0 stevel */ 237 0 stevel if ((time(0) - last_swept) > sweep_interval) { 238 0 stevel mutex_lock(&ctx_mutex); 239 0 stevel /* 240 0 stevel * Check again, in case some other thread got in. 241 0 stevel */ 242 0 stevel if ((time(0) - last_swept) > sweep_interval) 243 0 stevel sweep_clients(); 244 0 stevel mutex_unlock(&ctx_mutex); 245 0 stevel } 246 0 stevel } 247 0 stevel 248 0 stevel /* 249 0 stevel * Set server parameters. 250 0 stevel */ 251 0 stevel void 252 0 stevel __rpc_gss_set_server_parms(init_cred_lifetime, max_cred_lifetime, cache_size) 253 0 stevel int init_cred_lifetime; 254 0 stevel int max_cred_lifetime; 255 0 stevel int cache_size; 256 0 stevel { 257 0 stevel /* 258 0 stevel * Ignore parameters unless greater than zero. 259 0 stevel */ 260 0 stevel mutex_lock(&ctx_mutex); 261 0 stevel if (cache_size > 0) 262 0 stevel max_gss_contexts = cache_size; 263 0 stevel if (max_cred_lifetime > 0) 264 0 stevel max_lifetime = (uint_t)max_cred_lifetime; 265 0 stevel if (init_cred_lifetime > 0) 266 0 stevel init_lifetime = init_cred_lifetime; 267 0 stevel mutex_unlock(&ctx_mutex); 268 0 stevel } 269 0 stevel 270 0 stevel /* 271 0 stevel * Shift the array arr of length arrlen right by nbits bits. 272 0 stevel */ 273 0 stevel static void 274 0 stevel shift_bits(arr, arrlen, nbits) 275 0 stevel uint_t *arr; 276 0 stevel int arrlen; 277 0 stevel int nbits; 278 0 stevel { 279 0 stevel int i, j; 280 0 stevel uint_t lo, hi; 281 0 stevel 282 0 stevel /* 283 0 stevel * If the number of bits to be shifted exceeds SEQ_WIN, just 284 0 stevel * zero out the array. 285 0 stevel */ 286 0 stevel if (nbits < SEQ_WIN) { 287 0 stevel for (i = 0; i < nbits; i++) { 288 0 stevel hi = 0; 289 0 stevel for (j = 0; j < arrlen; j++) { 290 0 stevel lo = arr[j] & SEQ_LO_BIT; 291 0 stevel arr[j] >>= 1; 292 0 stevel if (hi) 293 0 stevel arr[j] |= SEQ_HI_BIT; 294 0 stevel hi = lo; 295 0 stevel } 296 0 stevel } 297 0 stevel } else { 298 0 stevel for (j = 0; j < arrlen; j++) 299 0 stevel arr[j] = 0; 300 0 stevel } 301 0 stevel } 302 0 stevel 303 0 stevel /* 304 0 stevel * Check that the received sequence number seq_num is valid. 305 0 stevel */ 306 0 stevel static bool_t 307 0 stevel check_seq(cl, seq_num, kill_context) 308 0 stevel svc_rpc_gss_data *cl; 309 0 stevel uint_t seq_num; 310 0 stevel bool_t *kill_context; 311 0 stevel { 312 0 stevel int i, j; 313 0 stevel uint_t bit; 314 0 stevel 315 0 stevel /* 316 0 stevel * If it exceeds the maximum, kill context. 317 0 stevel */ 318 0 stevel if (seq_num >= SEQ_MAX) { 319 0 stevel *kill_context = TRUE; 320 0 stevel return (FALSE); 321 0 stevel } 322 0 stevel 323 0 stevel /* 324 0 stevel * If greater than the last seen sequence number, just shift 325 0 stevel * the sequence window so that it starts at the new sequence 326 0 stevel * number and extends downwards by SEQ_WIN. 327 0 stevel */ 328 0 stevel if (seq_num > cl->seq_num) { 329 0 stevel shift_bits(cl->seq_bits, SEQ_ARR_SIZE, seq_num - cl->seq_num); 330 0 stevel cl->seq_bits[0] |= SEQ_HI_BIT; 331 0 stevel cl->seq_num = seq_num; 332 0 stevel return (TRUE); 333 0 stevel } 334 0 stevel 335 0 stevel /* 336 0 stevel * If it is outside the sequence window, return failure. 337 0 stevel */ 338 0 stevel i = cl->seq_num - seq_num; 339 0 stevel if (i >= SEQ_WIN) 340 0 stevel return (FALSE); 341 0 stevel 342 0 stevel /* 343 0 stevel * If within sequence window, set the bit corresponding to it 344 0 stevel * if not already seen; if already seen, return failure. 345 0 stevel */ 346 0 stevel j = SEQ_MASK - (i & SEQ_MASK); 347 0 stevel bit = j > 0 ? (1 << j) : 1; 348 0 stevel i >>= DIV_BY_32; 349 0 stevel if (cl->seq_bits[i] & bit) 350 0 stevel return (FALSE); 351 0 stevel cl->seq_bits[i] |= bit; 352 0 stevel return (TRUE); 353 0 stevel } 354 0 stevel 355 0 stevel /* 356 0 stevel * Convert a name in gss exported type to rpc_gss_principal_t type. 357 0 stevel */ 358 0 stevel static bool_t 359 0 stevel __rpc_gss_make_principal(principal, name) 360 0 stevel rpc_gss_principal_t *principal; 361 0 stevel gss_buffer_desc *name; 362 0 stevel { 363 0 stevel int plen; 364 0 stevel char *s; 365 0 stevel 366 0 stevel plen = RNDUP(name->length) + sizeof (int); 367 0 stevel (*principal) = (rpc_gss_principal_t)malloc(plen); 368 0 stevel if ((*principal) == NULL) 369 0 stevel return (FALSE); 370 0 stevel bzero((caddr_t)(*principal), plen); 371 0 stevel (*principal)->len = RNDUP(name->length); 372 0 stevel s = (*principal)->name; 373 0 stevel memcpy(s, name->value, name->length); 374 0 stevel return (TRUE); 375 0 stevel } 376 0 stevel 377 0 stevel /* 378 0 stevel * Convert a name in internal form to the exported type. 379 0 stevel */ 380 0 stevel static bool_t 381 0 stevel set_client_principal(g_name, r_name) 382 0 stevel gss_name_t g_name; 383 0 stevel rpc_gss_principal_t *r_name; 384 0 stevel { 385 0 stevel gss_buffer_desc name; 386 0 stevel OM_uint32 major, minor; 387 0 stevel bool_t ret = FALSE; 388 0 stevel 389 0 stevel major = gss_export_name(&minor, g_name, &name); 390 0 stevel if (major != GSS_S_COMPLETE) 391 0 stevel return (FALSE); 392 0 stevel ret = __rpc_gss_make_principal(r_name, &name); 393 0 stevel (void) gss_release_buffer(&minor, &name); 394 0 stevel return (ret); 395 0 stevel } 396 0 stevel 397 0 stevel /* 398 0 stevel * Set server callback. 399 0 stevel */ 400 0 stevel bool_t 401 0 stevel __rpc_gss_set_callback(cb) 402 0 stevel rpc_gss_callback_t *cb; 403 0 stevel { 404 0 stevel cblist_t *cbl; 405 0 stevel 406 0 stevel if (cb->callback == NULL) 407 0 stevel return (FALSE); 408 0 stevel if ((cbl = (cblist_t *)malloc(sizeof (*cbl))) == NULL) 409 0 stevel return (FALSE); 410 0 stevel cbl->cb = *cb; 411 0 stevel mutex_lock(&cb_mutex); 412 0 stevel cbl->next = cblist; 413 0 stevel cblist = cbl; 414 0 stevel mutex_unlock(&cb_mutex); 415 0 stevel return (TRUE); 416 0 stevel } 417 0 stevel 418 0 stevel /* 419 0 stevel * Locate callback (if specified) and call server. Release any 420 0 stevel * delegated credentials unless passed to server and the server 421 0 stevel * accepts the context. If a callback is not specified, accept 422 0 stevel * the incoming context. 423 0 stevel */ 424 0 stevel static bool_t 425 0 stevel do_callback(req, client_data) 426 0 stevel struct svc_req *req; 427 0 stevel svc_rpc_gss_data *client_data; 428 0 stevel { 429 0 stevel cblist_t *cbl; 430 0 stevel bool_t ret = TRUE, found = FALSE; 431 0 stevel rpc_gss_lock_t lock; 432 0 stevel OM_uint32 minor; 433 0 stevel 434 0 stevel mutex_lock(&cb_mutex); 435 0 stevel for (cbl = cblist; cbl != NULL; cbl = cbl->next) { 436 0 stevel if (req->rq_prog != cbl->cb.program || 437 0 stevel req->rq_vers != cbl->cb.version) 438 0 stevel continue; 439 0 stevel found = TRUE; 440 0 stevel lock.locked = FALSE; 441 0 stevel lock.raw_cred = &client_data->raw_cred; 442 0 stevel ret = (*cbl->cb.callback)(req, client_data->deleg, 443 0 stevel client_data->context, &lock, &client_data->cookie); 444 0 stevel if (ret) { 445 0 stevel client_data->locked = lock.locked; 446 0 stevel client_data->deleg = GSS_C_NO_CREDENTIAL; 447 0 stevel } 448 0 stevel break; 449 0 stevel } 450 0 stevel if (!found) { 451 0 stevel if (client_data->deleg != GSS_C_NO_CREDENTIAL) { 452 0 stevel (void) gss_release_cred(&minor, &client_data->deleg); 453 0 stevel client_data->deleg = GSS_C_NO_CREDENTIAL; 454 0 stevel } 455 0 stevel } 456 0 stevel mutex_unlock(&cb_mutex); 457 0 stevel return (ret); 458 0 stevel } 459 0 stevel 460 0 stevel /* 461 0 stevel * Return caller credentials. 462 0 stevel */ 463 0 stevel bool_t 464 0 stevel __rpc_gss_getcred(req, rcred, ucred, cookie) 465 0 stevel struct svc_req *req; 466 0 stevel rpc_gss_rawcred_t **rcred; 467 0 stevel rpc_gss_ucred_t **ucred; 468 0 stevel void **cookie; 469 0 stevel { 470 0 stevel SVCAUTH *svcauth; 471 0 stevel svc_rpc_gss_data *client_data; 472 0 stevel svc_rpc_gss_parms_t *gss_parms; 473 0 stevel gss_OID oid; 474 0 stevel OM_uint32 status; 475 0 stevel int len = 0; 476 0 stevel struct timeval now; 477 0 stevel 478 0 stevel svcauth = __svc_get_svcauth(req->rq_xprt); 479 0 stevel /*LINTED*/ 480 0 stevel client_data = (svc_rpc_gss_data *)svcauth->svc_ah_private; 481 0 stevel gss_parms = &svcauth->svc_gss_parms; 482 0 stevel 483 0 stevel mutex_lock(&client_data->clm); 484 0 stevel 485 0 stevel if (rcred != NULL) { 486 0 stevel svcauth->raw_cred = client_data->raw_cred; 487 0 stevel svcauth->raw_cred.service = gss_parms->service; 488 0 stevel svcauth->raw_cred.qop = __rpc_gss_num_to_qop( 489 0 stevel svcauth->raw_cred.mechanism, gss_parms->qop_rcvd); 490 0 stevel *rcred = &svcauth->raw_cred; 491 0 stevel } 492 0 stevel if (ucred != NULL) { 493 0 stevel if (!client_data->u_cred_set) { 494 0 stevel /* 495 0 stevel * Double check making sure ucred is not set 496 0 stevel * after acquiring the lock. 497 0 stevel */ 498 0 stevel if (!client_data->u_cred_set) { 499 0 stevel if (!__rpc_gss_mech_to_oid( 500 0 stevel (*rcred)->mechanism, &oid)) { 501 0 stevel fprintf(stderr, dgettext(TEXT_DOMAIN, 502 0 stevel "mech_to_oid failed in getcred.\n")); 503 0 stevel *ucred = NULL; 504 0 stevel } else { 505 0 stevel status = gsscred_name_to_unix_cred( 506 0 stevel client_data->client_name, oid, 507 0 stevel &client_data->u_cred.uid, 508 0 stevel &client_data->u_cred.gid, 509 0 stevel &client_data->u_cred.gidlist, 510 0 stevel &len); 511 0 stevel if (status == GSS_S_COMPLETE) { 512 0 stevel client_data->u_cred_set = TRUE; 513 0 stevel client_data->u_cred.gidlen = 514 0 stevel (short)len; 515 0 stevel gettimeofday(&now, 516 0 stevel (struct timezone *)NULL); 517 0 stevel client_data->time_secs_set = 518 0 stevel now.tv_sec; 519 0 stevel *ucred = &client_data->u_cred; 520 0 stevel } else 521 0 stevel *ucred = NULL; 522 0 stevel } 523 0 stevel } 524 0 stevel } else { 525 0 stevel /* 526 0 stevel * gid's already set; 527 0 stevel * check if they have expired. 528 0 stevel */ 529 0 stevel gettimeofday(&now, (struct timezone *)NULL); 530 0 stevel if ((now.tv_sec - client_data->time_secs_set) 531 0 stevel > gid_timeout) { 532 0 stevel /* Refresh gid's */ 533 0 stevel status = gss_get_group_info( 534 0 stevel client_data->u_cred.uid, 535 0 stevel &client_data->u_cred.gid, 536 0 stevel &client_data->u_cred.gidlist, 537 0 stevel &len); 538 0 stevel if (status == GSS_S_COMPLETE) { 539 0 stevel client_data->u_cred.gidlen = 540 0 stevel (short)len; 541 0 stevel gettimeofday(&now, 542 0 stevel (struct timezone *)NULL); 543 0 stevel client_data->time_secs_set = now.tv_sec; 544 0 stevel *ucred = &client_data->u_cred; 545 0 stevel } else { 546 0 stevel client_data->u_cred_set = FALSE; 547 0 stevel *ucred = NULL; 548 0 stevel } 549 0 stevel } 550 0 stevel else 551 0 stevel *ucred = &client_data->u_cred; 552 0 stevel } 553 0 stevel } 554 0 stevel if (cookie != NULL) 555 0 stevel *cookie = client_data->cookie; 556 0 stevel 557 0 stevel mutex_unlock(&client_data->clm); 558 0 stevel 559 0 stevel return (TRUE); 560 0 stevel } 561 0 stevel 562 0 stevel /* 563 0 stevel * Server side authentication for RPCSEC_GSS. 564 0 stevel */ 565 0 stevel 566 0 stevel enum auth_stat 567 0 stevel __svcrpcsec_gss(rqst, msg, no_dispatch) 568 0 stevel struct svc_req *rqst; 569 0 stevel struct rpc_msg *msg; 570 0 stevel bool_t *no_dispatch; 571 0 stevel { 572 0 stevel XDR xdrs; 573 0 stevel rpc_gss_creds creds; 574 0 stevel rpc_gss_init_arg call_arg; 575 0 stevel rpc_gss_init_res call_res, *retrans_result; 576 0 stevel gss_buffer_desc output_token; 577 0 stevel OM_uint32 gssstat, minor_stat, time_rec, ret_flags; 578 0 stevel struct opaque_auth *cred; 579 0 stevel svc_rpc_gss_data *client_data; 580 0 stevel int ret; 581 0 stevel svc_creds_list_t *sc; 582 0 stevel SVCAUTH *svcauth; 583 0 stevel svc_rpc_gss_parms_t *gss_parms; 584 0 stevel gss_OID mech_type = GSS_C_NULL_OID; 585 0 stevel 586 0 stevel /* 587 0 stevel * Initialize response verifier to NULL verifier. If 588 0 stevel * necessary, this will be changed later. 589 0 stevel */ 590 0 stevel rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NONE; 591 0 stevel rqst->rq_xprt->xp_verf.oa_base = NULL; 592 0 stevel rqst->rq_xprt->xp_verf.oa_length = 0; 593 0 stevel /* 594 0 stevel * Need to null out results to start with. 595 0 stevel */ 596 0 stevel memset((char *)&call_res, 0, sizeof (call_res)); 597 0 stevel 598 0 stevel /* 599 0 stevel * Pull out and check credential and verifier. 600 0 stevel */ 601 0 stevel cred = &msg->rm_call.cb_cred; 602 0 stevel if (cred->oa_length == 0) { 603 4554 ps57422 return (AUTH_BADCRED); 604 0 stevel } 605 0 stevel 606 0 stevel xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); 607 0 stevel 608 0 stevel memset((char *)&creds, 0, sizeof (creds)); 609 0 stevel if (!__xdr_rpc_gss_creds(&xdrs, &creds)) { 610 0 stevel XDR_DESTROY(&xdrs); 611 0 stevel ret = AUTH_BADCRED; 612 0 stevel goto error; 613 0 stevel } 614 0 stevel XDR_DESTROY(&xdrs); 615 0 stevel 616 0 stevel /* 617 0 stevel * If this is a control message and proc is GSSAPI_INIT, then 618 0 stevel * create a client handle for this client. Otherwise, look up 619 0 stevel * the existing handle. 620 0 stevel */ 621 0 stevel if (creds.gss_proc == RPCSEC_GSS_INIT) { 622 0 stevel if (creds.ctx_handle.length != 0) { 623 0 stevel ret = AUTH_BADCRED; 624 0 stevel goto error; 625 0 stevel } 626 0 stevel if ((client_data = create_client()) == NULL) { 627 0 stevel ret = AUTH_FAILED; 628 0 stevel goto error; 629 0 stevel } 630 0 stevel } else { 631 0 stevel /* 632 0 stevel * Only verify values for service parameter when proc 633 0 stevel * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT. 634 0 stevel * RFC2203 says contents for sequence and service args 635 0 stevel * are undefined for creation procs. 636 0 stevel * 637 0 stevel * Note: only need to check for *CONTINUE_INIT here because 638 0 stevel * if() clause already checked for RPCSEC_GSS_INIT 639 0 stevel */ 640 0 stevel if (creds.gss_proc != RPCSEC_GSS_CONTINUE_INIT) { 641 0 stevel switch (creds.service) { 642 0 stevel case rpc_gss_svc_none: 643 0 stevel case rpc_gss_svc_integrity: 644 0 stevel case rpc_gss_svc_privacy: 645 0 stevel break; 646 0 stevel default: 647 0 stevel ret = AUTH_BADCRED; 648 0 stevel goto error; 649 0 stevel } 650 0 stevel } 651 0 stevel if (creds.ctx_handle.length == 0) { 652 0 stevel ret = AUTH_BADCRED; 653 0 stevel goto error; 654 0 stevel } 655 0 stevel if ((client_data = get_client(&creds.ctx_handle)) == NULL) { 656 0 stevel ret = RPCSEC_GSS_NOCRED; 657 0 stevel goto error; 658 0 stevel } 659 0 stevel } 660 0 stevel 661 0 stevel /* 662 0 stevel * lock the client data until it's safe; if it's already stale, 663 0 stevel * no more processing is possible 664 0 stevel */ 665 0 stevel mutex_lock(&client_data->clm); 666 0 stevel if (client_data->stale) { 667 0 stevel ret = RPCSEC_GSS_NOCRED; 668 0 stevel goto error2; 669 0 stevel } 670 0 stevel 671 0 stevel /* 672 0 stevel * Any response we send will use ctx_handle, so set it now; 673 0 stevel * also set seq_window since this won't change. 674 0 stevel */ 675 0 stevel call_res.ctx_handle.length = sizeof (client_data->key); 676 0 stevel call_res.ctx_handle.value = (char *)&client_data->key; 677 0 stevel call_res.seq_window = SEQ_WIN; 678 0 stevel 679 0 stevel /* 680 0 stevel * Set the appropriate wrap/unwrap routine for RPCSEC_GSS. 681 0 stevel */ 682 0 stevel svcauth = __svc_get_svcauth(rqst->rq_xprt); 683 0 stevel svcauth->svc_ah_ops = svc_rpc_gss_ops; 684 0 stevel svcauth->svc_ah_private = (caddr_t)client_data; 685 0 stevel 686 0 stevel /* 687 0 stevel * Keep copy of parameters we'll need for response, for the 688 0 stevel * sake of reentrancy (we don't want to look in the context 689 0 stevel * data because when we are sending a response, another 690 0 stevel * request may have come in. 691 0 stevel */ 692 0 stevel gss_parms = &svcauth->svc_gss_parms; 693 0 stevel gss_parms->established = client_data->established; 694 0 stevel gss_parms->service = creds.service; 695 0 stevel gss_parms->qop_rcvd = (uint_t)client_data->qop; 696 0 stevel gss_parms->context = (void *)client_data->context; 697 0 stevel gss_parms->seq_num = creds.seq_num; 698 0 stevel 699 0 stevel if (!client_data->established) { 700 0 stevel if (creds.gss_proc == RPCSEC_GSS_DATA) { 701 0 stevel ret = RPCSEC_GSS_FAILED; 702 0 stevel client_data->stale = TRUE; 703 0 stevel goto error2; 704 0 stevel } 705 0 stevel 706 0 stevel /* 707 0 stevel * If the context is not established, then only GSSAPI_INIT 708 0 stevel * and _CONTINUE requests are valid. 709 0 stevel */ 710 0 stevel if (creds.gss_proc != RPCSEC_GSS_INIT && creds.gss_proc != 711 0 stevel RPCSEC_GSS_CONTINUE_INIT) { 712 0 stevel ret = RPCSEC_GSS_FAILED; 713 0 stevel client_data->stale = TRUE; 714 0 stevel goto error2; 715 0 stevel } 716 0 stevel 717 0 stevel /* 718 0 stevel * call is for us, deserialize arguments 719 0 stevel */ 720 0 stevel memset(&call_arg, 0, sizeof (call_arg)); 721 0 stevel if (!svc_getargs(rqst->rq_xprt, __xdr_rpc_gss_init_arg, 722 0 stevel (caddr_t)&call_arg)) { 723 0 stevel ret = RPCSEC_GSS_FAILED; 724 0 stevel client_data->stale = TRUE; 725 0 stevel goto error2; 726 0 stevel } 727 0 stevel 728 0 stevel gssstat = GSS_S_FAILURE; 729 0 stevel minor_stat = 0; 730 0 stevel rw_rdlock(&cred_lock); 731 0 stevel /* 732 0 stevel * set next sc to point to the server cred 733 0 stevel * if the client_data contains server_creds 734 0 stevel */ 735 0 stevel for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 736 0 stevel if (rqst->rq_prog != sc->program || 737 0 stevel rqst->rq_vers != sc->version) 738 0 stevel continue; 739 0 stevel 740 0 stevel mutex_lock(&sc->refresh_mutex); 741 0 stevel gssstat = gss_accept_sec_context(&minor_stat, 742 0 stevel &client_data->context, 743 0 stevel sc->cred, 744 0 stevel &call_arg, 745 0 stevel GSS_C_NO_CHANNEL_BINDINGS, 746 0 stevel &client_data->client_name, 747 0 stevel &mech_type, 748 0 stevel &output_token, 749 0 stevel &ret_flags, 750 0 stevel &time_rec, 751 0 stevel NULL); 752 0 stevel 753 0 stevel if (gssstat == GSS_S_CREDENTIALS_EXPIRED) { 754 0 stevel if (rpc_gss_refresh_svc_cred(sc)) { 755 0 stevel gssstat = gss_accept_sec_context( 756 0 stevel &minor_stat, 757 0 stevel &client_data->context, 758 0 stevel sc->cred, 759 0 stevel &call_arg, 760 0 stevel GSS_C_NO_CHANNEL_BINDINGS, 761 0 stevel &client_data->client_name, 762 0 stevel &mech_type, 763 0 stevel &output_token, 764 0 stevel &ret_flags, 765 0 stevel &time_rec, 766 0 stevel NULL); 767 0 stevel mutex_unlock(&sc->refresh_mutex); 768 0 stevel 769 0 stevel } else { 770 0 stevel mutex_unlock(&sc->refresh_mutex); 771 0 stevel gssstat = GSS_S_NO_CRED; 772 0 stevel break; 773 0 stevel } 774 0 stevel 775 0 stevel } else 776 0 stevel mutex_unlock(&sc->refresh_mutex); 777 0 stevel 778 0 stevel if (gssstat == GSS_S_COMPLETE) { 779 0 stevel /* 780 0 stevel * Server_creds was right - set it. Also 781 0 stevel * set the raw and unix credentials at this 782 0 stevel * point. This saves a lot of computation 783 0 stevel * later when credentials are retrieved. 784 0 stevel */ 785 0 stevel /* 786 0 stevel * XXX server_creds will prob be stale 787 0 stevel * after rpc_gss_refresh_svc_cred(), but 788 0 stevel * it appears not to ever be referenced 789 0 stevel * anyways. 790 0 stevel */ 791 0 stevel mutex_lock(&sc->refresh_mutex); 792 0 stevel client_data->server_creds = sc->cred; 793 0 stevel client_data->raw_cred.version = creds.version; 794 0 stevel client_data->raw_cred.service = creds.service; 795 0 stevel client_data->raw_cred.svc_principal = 796 0 stevel sc->server_name; 797 0 stevel mutex_unlock(&sc->refresh_mutex); 798 0 stevel 799 0 stevel if ((client_data->raw_cred.mechanism 800 0 stevel = __rpc_gss_oid_to_mech(mech_type)) 801 0 stevel == NULL) { 802 0 stevel gssstat = GSS_S_FAILURE; 803 0 stevel (void) gss_release_buffer(&minor_stat, 804 0 stevel &output_token); 805 0 stevel } else if (!set_client_principal(client_data-> 806 0 stevel client_name, &client_data-> 807 0 stevel raw_cred.client_principal)) { 808 0 stevel gssstat = GSS_S_FAILURE; 809 0 stevel (void) gss_release_buffer(&minor_stat, 810 0 stevel &output_token); 811 0 stevel } 812 0 stevel break; 813 0 stevel } 814 0 stevel 815 0 stevel if (gssstat == GSS_S_CONTINUE_NEEDED) { 816 0 stevel /* 817 0 stevel * XXX server_creds will prob be stale 818 0 stevel * after rpc_gss_refresh_svc_cred(), but 819 0 stevel * it appears not to ever be referenced 820 0 stevel * anyways. 821 0 stevel */ 822 0 stevel mutex_lock(&sc->refresh_mutex); 823 0 stevel client_data->server_creds = sc->cred; 824 0 stevel mutex_unlock(&sc->refresh_mutex); 825 0 stevel break; 826 0 stevel } 827 0 stevel 828 0 stevel } 829 0 stevel rw_unlock(&cred_lock); 830 0 stevel 831 0 stevel call_res.gss_major = gssstat; 832 0 stevel call_res.gss_minor = minor_stat; 833 0 stevel 834 0 stevel xdr_free(__xdr_rpc_gss_init_arg, (caddr_t)&call_arg); 835 0 stevel 836 0 stevel if (gssstat != GSS_S_COMPLETE && 837 0 stevel gssstat != GSS_S_CONTINUE_NEEDED) { 838 0 stevel /* 839 0 stevel * We have a failure - send response and delete 840 0 stevel * the context. Don't dispatch. Set ctx_handle 841 0 stevel * to NULL and seq_window to 0. 842 0 stevel */ 843 0 stevel call_res.ctx_handle.length = 0; 844 0 stevel call_res.ctx_handle.value = NULL; 845 0 stevel call_res.seq_window = 0; 846 0 stevel 847 0 stevel svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 848 0 stevel (caddr_t)&call_res); 849 0 stevel *no_dispatch = TRUE; 850 0 stevel ret = AUTH_OK; 851 0 stevel client_data->stale = TRUE; 852 0 stevel goto error2; 853 0 stevel } 854 0 stevel 855 0 stevel /* 856 0 stevel * This step succeeded. Send a response, along with 857 0 stevel * a token if there's one. Don't dispatch. 858 0 stevel */ 859 0 stevel if (output_token.length != 0) { 860 0 stevel GSS_COPY_BUFFER(call_res.token, output_token); 861 0 stevel } 862 0 stevel 863 0 stevel /* 864 0 stevel * set response verifier: checksum of SEQ_WIN 865 0 stevel */ 866 0 stevel if (gssstat == GSS_S_COMPLETE) { 867 0 stevel if (!set_response_verf(rqst, msg, client_data, 868 0 stevel (uint_t)SEQ_WIN)) { 869 0 stevel ret = RPCSEC_GSS_FAILED; 870 0 stevel client_data->stale = TRUE; 871 0 stevel (void) gss_release_buffer(&minor_stat, 872 0 stevel &output_token); 873 0 stevel goto error2; 874 0 stevel } 875 0 stevel } 876 0 stevel 877 0 stevel svc_sendreply(rqst->rq_xprt, __xdr_rpc_gss_init_res, 878 0 stevel (caddr_t)&call_res); 879 0 stevel /* 880 0 stevel * Cache last response in case it is lost and the client 881 0 stevel * retries on an established context. 882 0 stevel */ 883 0 stevel (void) retrans_add(client_data, msg->rm_xid, &call_res); 884 0 stevel *no_dispatch = TRUE; 885 0 stevel (void) gss_release_buffer(&minor_stat, &output_token); 886 0 stevel 887 0 stevel /* 888 0 stevel * If appropriate, set established to TRUE *after* sending 889 0 stevel * response (otherwise, the client will receive the final 890 0 stevel * token encrypted) 891 0 stevel */ 892 0 stevel if (gssstat == GSS_S_COMPLETE) { 893 0 stevel /* 894 0 stevel * Context is established. Set expiry time for 895 0 stevel * context (the minimum of time_rec and max_lifetime). 896 0 stevel */ 897 0 stevel client_data->seq_num = 1; 898 0 stevel if (time_rec == GSS_C_INDEFINITE) { 899 0 stevel if (max_lifetime != GSS_C_INDEFINITE) 900 0 stevel client_data->expiration = 901 0 stevel max_lifetime + time(0); 902 0 stevel else 903 0 stevel client_data->expiration = 904 0 stevel GSS_C_INDEFINITE; 905 0 stevel } else if (max_lifetime == GSS_C_INDEFINITE || 906 0 stevel max_lifetime > time_rec) 907 0 stevel client_data->expiration = time_rec + time(0); 908 0 stevel else 909 0 stevel client_data->expiration = max_lifetime + 910 0 stevel time(0); 911 0 stevel client_data->established = TRUE; 912 0 stevel } 913 0 stevel 914 0 stevel } else { 915 0 stevel if ((creds.gss_proc != RPCSEC_GSS_DATA) && 916 0 stevel (creds.gss_proc != RPCSEC_GSS_DESTROY)) { 917 0 stevel 918 0 stevel switch (creds.gss_proc) { 919 0 stevel 920 0 stevel case RPCSEC_GSS_CONTINUE_INIT: 921 0 stevel /* 922 0 stevel * This is an established context. Continue to 923 0 stevel * satisfy retried continue init requests out of 924 0 stevel * the retransmit cache. Throw away any that don't 925 0 stevel * have a matching xid or the cach is empty. 926 0 stevel * Delete the retransmit cache once the client sends 927 0 stevel * a data request. 928 0 stevel */ 929 0 stevel if (client_data->retrans_data && 930 0 stevel (client_data->retrans_data->xid == msg->rm_xid)) { 931 0 stevel 932 0 stevel retrans_result = &client_data->retrans_data->result; 933 0 stevel if (set_response_verf(rqst, msg, client_data, 934 0 stevel (uint_t)retrans_result->seq_window)) { 935 0 stevel 936 0 stevel gss_parms->established = FALSE; 937 0 stevel svc_sendreply(rqst->rq_xprt, 938 0 stevel __xdr_rpc_gss_init_res, 939 0 stevel (caddr_t)retrans_result); 940 0 stevel *no_dispatch = TRUE; 941 0 stevel goto success; 942 0 stevel } 943 0 stevel } 944 0 stevel /* fall thru to default */ 945 0 stevel 946 0 stevel default: 947 0 stevel syslog(LOG_ERR, "_svcrpcsec_gss: non-data request " 948 0 stevel "on an established context"); 949 0 stevel ret = AUTH_FAILED; 950 0 stevel goto error2; 951 0 stevel } 952 0 stevel } 953 0 stevel 954 0 stevel /* 955 0 stevel * Once the context is established and there is no more 956 0 stevel * retransmission of last continue init request, it is safe 957 0 stevel * to delete the retransmit cache entry. 958 0 stevel */ 959 0 stevel if (client_data->retrans_data) 960 0 stevel retrans_del(client_data); 961 0 stevel 962 0 stevel /* 963 0 stevel * Context is already established. Check verifier, and 964 0 stevel * note parameters we will need for response in gss_parms. 965 0 stevel */ 966 0 stevel if (!check_verf(msg, client_data->context, 967 0 stevel &gss_parms->qop_rcvd)) { 968 0 stevel ret = RPCSEC_GSS_NOCRED; 969 0 stevel goto error2; 970 0 stevel } 971 0 stevel /* 972 0 stevel * Check and invoke callback if necessary. 973 0 stevel */ 974 0 stevel if (!client_data->done_docallback) { 975 0 stevel client_data->done_docallback = TRUE; 976 0 stevel client_data->qop = gss_parms->qop_rcvd; 977 0 stevel client_data->raw_cred.qop = __rpc_gss_num_to_qop( 978 0 stevel client_data->raw_cred.mechanism, 979 0 stevel gss_parms->qop_rcvd); 980 0 stevel client_data->raw_cred.service = creds.service; 981 0 stevel if (!do_callback(rqst, client_data)) { 982 0 stevel ret = AUTH_FAILED; 983 0 stevel client_data->stale = TRUE; 984 0 stevel goto error2; 985 0 stevel } 986 0 stevel } 987 0 stevel 988 0 stevel /* 989 0 stevel * If the context was locked, make sure that the client 990 0 stevel * has not changed QOP. 991 0 stevel */ 992 0 stevel if (client_data->locked && 993 0 stevel gss_parms->qop_rcvd != client_data->qop) { 994 0 stevel ret = AUTH_BADVERF; 995 0 stevel goto error2; 996 0 stevel } 997 0 stevel 998 0 stevel /* 999 0 stevel * Validate sequence number. 1000 0 stevel */ 1001 0 stevel if (!check_seq(client_data, creds.seq_num, 1002 0 stevel &client_data->stale)) { 1003 0 stevel if (client_data->stale) 1004 0 stevel ret = RPCSEC_GSS_FAILED; 1005 0 stevel else { 1006 0 stevel /* 1007 0 stevel * Operational error, drop packet silently. 1008 0 stevel * The client will recover after timing out, 1009 0 stevel * assuming this is a client error and not 1010 0 stevel * a relpay attack. Don't dispatch. 1011 0 stevel */ 1012 0 stevel ret = AUTH_OK; 1013 0 stevel *no_dispatch = TRUE; 1014 0 stevel } 1015 0 stevel goto error2; 1016 0 stevel } 1017 0 stevel 1018 0 stevel /* 1019 0 stevel * set response verifier 1020 0 stevel */ 1021 0 stevel if (!set_response_verf(rqst, msg, client_data, creds.seq_num)) { 1022 0 stevel ret = RPCSEC_GSS_FAILED; 1023 0 stevel client_data->stale = TRUE; 1024 0 stevel goto error2; 1025 0 stevel } 1026 0 stevel 1027 0 stevel /* 1028 0 stevel * If this is a control message RPCSEC_GSS_DESTROY, process 1029 0 stevel * the call; otherwise, return AUTH_OK so it will be 1030 0 stevel * dispatched to the application server. 1031 0 stevel */ 1032 0 stevel if (creds.gss_proc == RPCSEC_GSS_DESTROY) { 1033 0 stevel svc_sendreply(rqst->rq_xprt, xdr_void, NULL); 1034 0 stevel *no_dispatch = TRUE; 1035 0 stevel client_data->stale = TRUE; 1036 0 stevel 1037 0 stevel } else { 1038 0 stevel /* 1039 0 stevel * This should be an RPCSEC_GSS_DATA request. 1040 0 stevel * If context is locked, make sure that the client 1041 0 stevel * has not changed the security service. 1042 0 stevel */ 1043 0 stevel if (client_data->locked && 1044 0 stevel client_data->raw_cred.service != creds.service) { 1045 0 stevel ret = AUTH_FAILED; 1046 0 stevel goto error2; 1047 0 stevel } 1048 0 stevel 1049 0 stevel /* 1050 0 stevel * Set client credentials to raw credential 1051 0 stevel * structure in context. This is okay, since 1052 0 stevel * this will not change during the lifetime of 1053 0 stevel * the context (so it's MT safe). 1054 0 stevel */ 1055 0 stevel rqst->rq_clntcred = (char *)&client_data->raw_cred; 1056 0 stevel } 1057 0 stevel } 1058 0 stevel 1059 0 stevel success: 1060 0 stevel /* 1061 0 stevel * Success. 1062 0 stevel */ 1063 0 stevel if (creds.ctx_handle.length != 0) 1064 0 stevel xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1065 0 stevel mutex_unlock(&client_data->clm); 1066 0 stevel return (AUTH_OK); 1067 0 stevel error2: 1068 0 stevel mutex_unlock(&client_data->clm); 1069 0 stevel error: 1070 0 stevel /* 1071 0 stevel * Failure. 1072 0 stevel */ 1073 0 stevel if (creds.ctx_handle.length != 0) 1074 0 stevel xdr_free(__xdr_rpc_gss_creds, (caddr_t)&creds); 1075 0 stevel return (ret); 1076 0 stevel } 1077 0 stevel 1078 0 stevel /* 1079 0 stevel * Check verifier. The verifier is the checksum of the RPC header 1080 0 stevel * upto and including the credentials field. 1081 0 stevel */ 1082 0 stevel static bool_t 1083 0 stevel check_verf(msg, context, qop_state) 1084 0 stevel struct rpc_msg *msg; 1085 0 stevel gss_ctx_id_t context; 1086 0 stevel int *qop_state; 1087 0 stevel { 1088 0 stevel int *buf, *tmp; 1089 0 stevel int hdr[32]; 1090 0 stevel struct opaque_auth *oa; 1091 0 stevel int len; 1092 0 stevel gss_buffer_desc msg_buf; 1093 0 stevel gss_buffer_desc tok_buf; 1094 0 stevel OM_uint32 gssstat, minor_stat; 1095 0 stevel 1096 0 stevel /* 1097 0 stevel * We have to reconstruct the RPC header from the previously 1098 0 stevel * parsed information, since we haven't kept the header intact. 1099 0 stevel */ 1100 5101 pk193450 1101 5101 pk193450 oa = &msg->rm_call.cb_cred; 1102 5101 pk193450 if (oa->oa_length > MAX_AUTH_BYTES) 1103 5101 pk193450 return (FALSE); 1104 5101 pk193450 1105 5101 pk193450 /* 8 XDR units from the IXDR macro calls. */ 1106 5101 pk193450 if (sizeof (hdr) < (8 * BYTES_PER_XDR_UNIT + 1107 5101 pk193450 RNDUP(oa->oa_length))) 1108 5101 pk193450 return (FALSE); 1109 0 stevel buf = hdr; 1110 5101 pk193450 1111 0 stevel IXDR_PUT_U_INT32(buf, msg->rm_xid); 1112 0 stevel IXDR_PUT_ENUM(buf, msg->rm_direction); 1113 0 stevel IXDR_PUT_U_INT32(buf, msg->rm_call.cb_rpcvers); 1114 0 stevel IXDR_PUT_U_INT32(buf, msg->rm_call.cb_prog); 1115 0 stevel IXDR_PUT_U_INT32(buf, msg->rm_call.cb_vers); 1116 0 stevel IXDR_PUT_U_INT32(buf, msg->rm_call.cb_proc); 1117 0 stevel IXDR_PUT_ENUM(buf, oa->oa_flavor); 1118 0 stevel IXDR_PUT_U_INT32(buf, oa->oa_length); 1119 0 stevel if (oa->oa_length) { 1120 0 stevel len = RNDUP(oa->oa_length); 1121 0 stevel tmp = buf; 1122 0 stevel buf += len / sizeof (int); 1123 0 stevel *(buf - 1) = 0; 1124 0 stevel (void) memcpy((caddr_t)tmp, oa->oa_base, oa->oa_length); 1125 0 stevel } 1126 0 stevel len = ((char *)buf) - (char *)hdr; 1127 0 stevel msg_buf.length = len; 1128 0 stevel msg_buf.value = (char *)hdr; 1129 0 stevel oa = &msg->rm_call.cb_verf; 1130 0 stevel tok_buf.length = oa->oa_length; 1131 0 stevel tok_buf.value = oa->oa_base; 1132 0 stevel 1133 0 stevel gssstat = gss_verify(&minor_stat, context, &msg_buf, &tok_buf, 1134 0 stevel qop_state); 1135 0 stevel if (gssstat != GSS_S_COMPLETE) 1136 0 stevel return (FALSE); 1137 0 stevel return (TRUE); 1138 0 stevel } 1139 0 stevel 1140 0 stevel /* 1141 0 stevel * Set response verifier. This is the checksum of the given number. 1142 0 stevel * (e.g. sequence number or sequence window) 1143 0 stevel */ 1144 0 stevel static bool_t 1145 0 stevel set_response_verf(rqst, msg, cl, num) 1146 0 stevel struct svc_req *rqst; 1147 0 stevel struct rpc_msg *msg; 1148 0 stevel svc_rpc_gss_data *cl; 1149 0 stevel uint_t num; 1150 0 stevel { 1151 0 stevel OM_uint32 minor; 1152 0 stevel gss_buffer_desc in_buf, out_buf; 1153 0 stevel uint_t num_net; 1154 0 stevel 1155 0 stevel num_net = (uint_t)htonl(num); 1156 0 stevel in_buf.length = sizeof (num); 1157 0 stevel in_buf.value = (char *)&num_net; 1158 0 stevel if (gss_sign(&minor, cl->context, cl->qop, &in_buf, 1159 0 stevel &out_buf) != GSS_S_COMPLETE) 1160 0 stevel return (FALSE); 1161 0 stevel rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 1162 0 stevel rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; 1163 0 stevel rqst->rq_xprt->xp_verf.oa_length = out_buf.length; 1164 0 stevel memcpy(rqst->rq_xprt->xp_verf.oa_base, out_buf.value, 1165 0 stevel out_buf.length); 1166 0 stevel (void) gss_release_buffer(&minor, &out_buf); 1167 0 stevel return (TRUE); 1168 0 stevel } 1169 0 stevel 1170 0 stevel /* 1171 0 stevel * Create client context. 1172 0 stevel */ 1173 0 stevel static svc_rpc_gss_data * 1174 0 stevel create_client() 1175 0 stevel { 1176 0 stevel svc_rpc_gss_data *client_data; 1177 0 stevel static uint_t key = 1; 1178 0 stevel 1179 0 stevel client_data = (svc_rpc_gss_data *) malloc(sizeof (*client_data)); 1180 0 stevel if (client_data == NULL) 1181 0 stevel return (NULL); 1182 0 stevel memset((char *)client_data, 0, sizeof (*client_data)); 1183 0 stevel 1184 0 stevel /* 1185 0 stevel * set up client data structure 1186 0 stevel */ 1187 0 stevel client_data->established = FALSE; 1188 0 stevel client_data->locked = FALSE; 1189 0 stevel client_data->u_cred_set = FALSE; 1190 0 stevel client_data->context = GSS_C_NO_CONTEXT; 1191 0 stevel client_data->expiration = init_lifetime + time(0); 1192 0 stevel client_data->ref_cnt = 1; 1193 0 stevel client_data->qop = GSS_C_QOP_DEFAULT; 1194 0 stevel client_data->done_docallback = FALSE; 1195 0 stevel client_data->stale = FALSE; 1196 0 stevel client_data->time_secs_set = 0; 1197 0 stevel client_data->retrans_data = NULL; 1198 0 stevel mutex_init(&client_data->clm, USYNC_THREAD, NULL); 1199 0 stevel /* 1200 0 stevel * Check totals. If we've hit the limit, we destroy a context 1201 0 stevel * based on LRU method. 1202 0 stevel */ 1203 0 stevel mutex_lock(&ctx_mutex); 1204 0 stevel if (num_gss_contexts >= max_gss_contexts) { 1205 0 stevel /* 1206 0 stevel * now try on LRU basis 1207 0 stevel */ 1208 0 stevel drop_lru_client(); 1209 0 stevel if (num_gss_contexts >= max_gss_contexts) { 1210 0 stevel mutex_unlock(&ctx_mutex); 1211 0 stevel free((char *)client_data); 1212 0 stevel return (NULL); 1213 0 stevel } 1214 0 stevel } 1215 0 stevel 1216 0 stevel /* 1217 0 stevel * The client context handle is a 32-bit key (unsigned int). 1218 0 stevel * The key is incremented until there is no duplicate for it. 1219 0 stevel */ 1220 0 stevel for (;;) { 1221 0 stevel client_data->key = key++; 1222 0 stevel if (find_client(client_data->key) == NULL) { 1223 0 stevel insert_client(client_data); 1224 0 stevel /* 1225 0 stevel * Set cleanup callback if we haven't. 1226 0 stevel */ 1227 0 stevel if (!cleanup_cb_set) { 1228 0 stevel old_cleanup_cb = 1229 6636 gtb (void (*)()) __svc_set_proc_cleanup_cb( 1230 6636 gtb (void *)ctx_cleanup); 1231 0 stevel cleanup_cb_set = TRUE; 1232 0 stevel } 1233 0 stevel mutex_unlock(&ctx_mutex); 1234 0 stevel return (client_data); 1235 0 stevel } 1236 0 stevel } 1237 0 stevel /*NOTREACHED*/ 1238 0 stevel } 1239 0 stevel 1240 0 stevel /* 1241 0 stevel * Insert client context into hash list and LRU list. 1242 0 stevel */ 1243 0 stevel static void 1244 0 stevel insert_client(client_data) 1245 0 stevel svc_rpc_gss_data *client_data; 1246 0 stevel { 1247 0 stevel svc_rpc_gss_data *cl; 1248 0 stevel int index = (client_data->key & HASHMASK); 1249 0 stevel 1250 0 stevel client_data->prev = NULL; 1251 0 stevel cl = clients[index]; 1252 0 stevel if ((client_data->next = cl) != NULL) 1253 0 stevel cl->prev = client_data; 1254 0 stevel clients[index] = client_data; 1255 0 stevel 1256 0 stevel client_data->lru_prev = NULL; 1257 0 stevel if ((client_data->lru_next = lru_first) != NULL) 1258 0 stevel lru_first->lru_prev = client_data; 1259 0 stevel else 1260 0 stevel lru_last = client_data; 1261 0 stevel lru_first = client_data; 1262 0 stevel 1263 0 stevel num_gss_contexts++; 1264 0 stevel } 1265 0 stevel 1266 0 stevel /* 1267 0 stevel * Fetch a client, given the client context handle. Move it to the 1268 0 stevel * top of the LRU list since this is the most recently used context. 1269 0 stevel */ 1270 0 stevel static svc_rpc_gss_data * 1271 0 stevel get_client(ctx_handle) 1272 0 stevel gss_buffer_t ctx_handle; 1273 0 stevel { 1274 0 stevel uint_t key = *(uint_t *)ctx_handle->value; 1275 0 stevel svc_rpc_gss_data *cl; 1276 0 stevel 1277 0 stevel mutex_lock(&ctx_mutex); 1278 0 stevel if ((cl = find_client(key)) != NULL) { 1279 0 stevel mutex_lock(&cl->clm); 1280 0 stevel if (cl->stale) { 1281 0 stevel mutex_unlock(&cl->clm); 1282 0 stevel mutex_unlock(&ctx_mutex); 1283 0 stevel return (NULL); 1284 0 stevel } 1285 0 stevel cl->ref_cnt++; 1286 0 stevel mutex_unlock(&cl->clm); 1287 0 stevel if (cl != lru_first) { 1288 0 stevel cl->lru_prev->lru_next = cl->lru_next; 1289 0 stevel if (cl->lru_next != NULL) 1290 0 stevel cl->lru_next->lru_prev = cl->lru_prev; 1291 0 stevel else 1292 0 stevel lru_last = cl->lru_prev; 1293 0 stevel cl->lru_prev = NULL; 1294 0 stevel cl->lru_next = lru_first; 1295 0 stevel lru_first->lru_prev = cl; 1296 0 stevel lru_first = cl; 1297 0 stevel } 1298 0 stevel } 1299 0 stevel mutex_unlock(&ctx_mutex); 1300 0 stevel return (cl); 1301 0 stevel } 1302 0 stevel 1303 0 stevel /* 1304 0 stevel * Given the client context handle, find the context corresponding to it. 1305 0 stevel * Don't change its LRU state since it may not be used. 1306 0 stevel */ 1307 0 stevel static svc_rpc_gss_data * 1308 0 stevel find_client(key) 1309 0 stevel uint_t key; 1310 0 stevel { 1311 0 stevel int index = (key & HASHMASK); 1312 0 stevel svc_rpc_gss_data *cl; 1313 0 stevel 1314 0 stevel for (cl = clients[index]; cl != NULL; cl = cl->next) { 1315 0 stevel if (cl->key == key) 1316 0 stevel break; 1317 0 stevel } 1318 0 stevel return (cl); 1319 0 stevel } 1320 0 stevel 1321 0 stevel /* 1322 0 stevel * Destroy a client context. 1323 0 stevel */ 1324 0 stevel static void 1325 0 stevel destroy_client(client_data) 1326 0 stevel svc_rpc_gss_data *client_data; 1327 0 stevel { 1328 0 stevel OM_uint32 minor; 1329 0 stevel int index = (client_data->key & HASHMASK); 1330 0 stevel 1331 0 stevel /* 1332 0 stevel * remove from hash list 1333 0 stevel */ 1334 0 stevel if (client_data->prev == NULL) 1335 0 stevel clients[index] = client_data->next; 1336 0 stevel else 1337 0 stevel client_data->prev->next = client_data->next; 1338 0 stevel if (client_data->next != NULL) 1339 0 stevel client_data->next->prev = client_data->prev; 1340 0 stevel 1341 0 stevel /* 1342 0 stevel * remove from LRU list 1343 0 stevel */ 1344 0 stevel if (client_data->lru_prev == NULL) 1345 0 stevel lru_first = client_data->lru_next; 1346 0 stevel else 1347 0 stevel client_data->lru_prev->lru_next = client_data->lru_next; 1348 0 stevel if (client_data->lru_next != NULL) 1349 0 stevel client_data->lru_next->lru_prev = client_data->lru_prev; 1350 0 stevel else 1351 0 stevel lru_last = client_data->lru_prev; 1352 0 stevel 1353 0 stevel /* 1354 0 stevel * If there is a GSS context, clean up GSS state. 1355 0 stevel */ 1356 0 stevel if (client_data->context != GSS_C_NO_CONTEXT) { 1357 0 stevel (void) gss_delete_sec_context(&minor, &client_data->context, 1358 0 stevel NULL); 1359 0 stevel if (client_data->client_name) 1360 0 stevel (void) gss_release_name(&minor, &client_data->client_name); 1361 0 stevel if (client_data->raw_cred.client_principal) 1362 0 stevel free((char *)client_data->raw_cred.client_principal); 1363 0 stevel if (client_data->u_cred.gidlist != NULL) 1364 0 stevel free((char *)client_data->u_cred.gidlist); 1365 0 stevel if (client_data->deleg != GSS_C_NO_CREDENTIAL) 1366 0 stevel (void) gss_release_cred(&minor, &client_data->deleg); 1367 0 stevel } 1368 0 stevel 1369 0 stevel if (client_data->retrans_data != NULL) 1370 0 stevel retrans_del(client_data); 1371 0 stevel 1372 0 stevel free(client_data); 1373 0 stevel num_gss_contexts--; 1374 0 stevel } 1375 0 stevel 1376 0 stevel /* 1377 0 stevel * Check for expired client contexts. 1378 0 stevel */ 1379 0 stevel static void 1380 0 stevel sweep_clients() 1381 0 stevel { 1382 0 stevel svc_rpc_gss_data *cl, *next; 1383 0 stevel int index; 1384 0 stevel 1385 0 stevel for (index = 0; index < HASHMOD; index++) { 1386 0 stevel cl = clients[index]; 1387 0 stevel while (cl) { 1388 0 stevel next = cl->next; 1389 0 stevel mutex_lock(&cl->clm); 1390 0 stevel if ((cl->expiration != GSS_C_INDEFINITE && 1391 0 stevel cl->expiration <= time(0)) || cl->stale) { 1392 0 stevel cl->stale = TRUE; 1393 0 stevel if (cl->ref_cnt == 0) { 1394 0 stevel mutex_unlock(&cl->clm); 1395 0 stevel destroy_client(cl); 1396 0 stevel } else 1397 0 stevel mutex_unlock(&cl->clm); 1398 0 stevel } else 1399 0 stevel mutex_unlock(&cl->clm); 1400 0 stevel cl = next; 1401 0 stevel } 1402 0 stevel } 1403 0 stevel last_swept = time(0); 1404 0 stevel } 1405 0 stevel 1406 0 stevel /* 1407 0 stevel * Drop the least recently used client context, if possible. 1408 0 stevel */ 1409 0 stevel static void 1410 0 stevel drop_lru_client() 1411 0 stevel { 1412 0 stevel mutex_lock(&lru_last->clm); 1413 0 stevel lru_last->stale = TRUE; 1414 0 stevel mutex_unlock(&lru_last->clm); 1415 0 stevel if (lru_last->ref_cnt == 0) 1416 0 stevel destroy_client(lru_last); 1417 0 stevel else 1418 0 stevel sweep_clients(); 1419 0 stevel } 1420 0 stevel 1421 0 stevel /* 1422 0 stevel * find service credentials 1423 0 stevel * return cred if found, 1424 0 stevel * other wise, NULL 1425 0 stevel */ 1426 0 stevel 1427 0 stevel svc_creds_list_t * 1428 0 stevel find_svc_cred(char *service_name, uint_t program, uint_t version) { 1429 0 stevel 1430 0 stevel svc_creds_list_t *sc; 1431 0 stevel 1432 0 stevel if (!svc_creds_list) 1433 0 stevel return (NULL); 1434 0 stevel 1435 0 stevel for (sc = svc_creds_list; sc != NULL; sc = sc->next) { 1436 0 stevel if (program != sc->program || version != sc->version) 1437 0 stevel continue; 1438 0 stevel 1439 0 stevel if (strcmp(service_name, sc->server_name) != 0) 1440 0 stevel continue; 1441 0 stevel return (sc); 1442 0 stevel } 1443 0 stevel return (NULL); 1444 0 stevel } 1445 0 stevel 1446 0 stevel /* 1447 0 stevel * Set the server principal name. 1448 0 stevel */ 1449 0 stevel bool_t 1450 0 stevel __rpc_gss_set_svc_name(server_name, mech, req_time, program, version) 1451 0 stevel char *server_name; 1452 0 stevel char *mech; 1453 0 stevel OM_uint32 req_time; 1454 0 stevel uint_t program; 1455 0 stevel uint_t version; 1456 0 stevel { 1457 0 stevel gss_name_t name; 1458 0 stevel svc_creds_list_t *svc_cred; 1459 0 stevel gss_OID mechanism; 1460 0 stevel gss_OID_set_desc oid_set_desc; 1461 0 stevel gss_OID_set oid_set; 1462 0 stevel OM_uint32 ret_time; 1463 0 stevel OM_uint32 major, minor; 1464 0 stevel gss_buffer_desc name_buf; 1465 0 stevel 1466 0 stevel if (!__rpc_gss_mech_to_oid(mech, &mechanism)) { 1467 0 stevel return (FALSE); 1468 0 stevel } 1469 0 stevel 1470 0 stevel name_buf.value = server_name; 1471 0 stevel name_buf.length = strlen(server_name); 1472 0 stevel major = gss_import_name(&minor, &name_buf, 1473 0 stevel (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &name); 1474 0 stevel if (major != GSS_S_COMPLETE) { 1475 0 stevel return (FALSE); 1476 0 stevel } 1477 0 stevel 1478 0 stevel /* Check if there is already an entry in the svc_creds_list. */ 1479 0 stevel rw_wrlock(&cred_lock); 1480 0 stevel if (svc_cred = find_svc_cred(server_name, program, version)) { 1481 0 stevel 1482 0 stevel major = gss_add_cred(&minor, svc_cred->cred, name, 1483 0 stevel mechanism, GSS_C_ACCEPT, 1484 0 stevel 0, req_time, NULL, 1485 0 stevel &oid_set, NULL, 1486 0 stevel &ret_time); 1487 0 stevel (void) gss_release_name(&minor, &name); 1488 0 stevel if (major == GSS_S_COMPLETE) { 1489 0 stevel /* 1490 0 stevel * Successfully added the mech to the cred handle 1491 0 stevel * free the existing oid_set in svc_cred 1492 0 stevel */ 1493 0 stevel gss_release_oid_set(&minor, &svc_cred->oid_set); 1494 0 stevel svc_cred->oid_set = oid_set; 1495 0 stevel rw_unlock(&cred_lock); 1496 0 stevel return (TRUE); 1497 0 stevel } else if (major == GSS_S_DUPLICATE_ELEMENT) { 1498 0 stevel rw_unlock(&cred_lock); 1499 0 stevel return (TRUE); 1500 0 stevel } else if (major == GSS_S_CREDENTIALS_EXPIRED) { 1501 0 stevel if (rpc_gss_refresh_svc_cred(svc_cred)) { 1502 0 stevel rw_unlock(&cred_lock); 1503 0 stevel return (TRUE); 1504 0 stevel } else { 1505 0 stevel rw_unlock(&cred_lock); 1506 0 stevel return (FALSE); 1507 0 stevel } 1508 0 stevel } else { 1509 0 stevel rw_unlock(&cred_lock); 1510 0 stevel return (FALSE); 1511 0 stevel } 1512 0 stevel } else { 1513 0 stevel svc_cred = (svc_creds_list_t *)malloc(sizeof (*svc_cred)); 1514 0 stevel if (svc_cred == NULL) { 1515 0 stevel (void) gss_release_name(&minor, &name); 1516 0 stevel rw_unlock(&cred_lock); 1517 0 stevel return (FALSE); 1518 0 stevel } 1519 0 stevel oid_set_desc.count = 1; 1520 0 stevel oid_set_desc.elements = mechanism; 1521 0 stevel major = gss_acquire_cred(&minor, name, req_time, 1522 0 stevel &oid_set_desc, 1523 0 stevel GSS_C_ACCEPT, 1524 0 stevel &svc_cred->cred, 1525 0 stevel &oid_set, &ret_time); 1526 0 stevel 1527 0 stevel if (major != GSS_S_COMPLETE) { 1528 0 stevel (void) gss_release_name(&minor, &name); 1529 0 stevel free(svc_cred); 1530 0 stevel rw_unlock(&cred_lock); 1531 0 stevel return (FALSE); 1532 0 stevel } 1533 0 stevel 1534 0 stevel svc_cred->name = name; 1535 0 stevel svc_cred->program = program; 1536 0 stevel svc_cred->version = version; 1537 0 stevel svc_cred->req_time = req_time; 1538 0 stevel svc_cred->oid_set = oid_set; 1539 0 stevel svc_cred->server_name = strdup(server_name); 1540 0 stevel if (svc_cred->server_name == NULL) { 1541 0 stevel (void) gss_release_name(&minor, &name); 1542 0 stevel free((char *)svc_cred); 1543 0 stevel rw_unlock(&cred_lock); 1544 0 stevel return (FALSE); 1545 0 stevel } 1546 0 stevel mutex_init(&svc_cred->refresh_mutex, USYNC_THREAD, NULL); 1547 0 stevel 1548 0 stevel svc_cred->next = svc_creds_list; 1549 0 stevel svc_creds_list = svc_cred; 1550 0 stevel svc_creds_count++; 1551 0 stevel rw_unlock(&cred_lock); 1552 0 stevel 1553 0 stevel return (TRUE); 1554 0 stevel } 1555 0 stevel } 1556 0 stevel /* 1557 0 stevel * Refresh server credentials. 1558 0 stevel */ 1559 0 stevel static bool_t 1560 0 stevel rpc_gss_refresh_svc_cred(svc_cred) 1561 0 stevel svc_creds_list_t *svc_cred; 1562 0 stevel { 1563 0 stevel OM_uint32 major, minor; 1564 0 stevel gss_OID_set oid_set; 1565 0 stevel OM_uint32 ret_time; 1566 0 stevel 1567 0 stevel (void) gss_release_cred(&minor, &svc_cred->cred); 1568 0 stevel svc_cred->cred = GSS_C_NO_CREDENTIAL; 1569 0 stevel major = gss_acquire_cred(&minor, svc_cred->name, svc_cred->req_time, 1570 0 stevel svc_cred->oid_set, GSS_C_ACCEPT, &svc_cred->cred, &oid_set, 1571 0 stevel &ret_time); 1572 0 stevel if (major != GSS_S_COMPLETE) { 1573 0 stevel return (FALSE); 1574 0 stevel } 1575 0 stevel gss_release_oid_set(&minor, &svc_cred->oid_set); 1576 0 stevel svc_cred->oid_set = oid_set; 1577 0 stevel return (TRUE); 1578 0 stevel } 1579 0 stevel 1580 0 stevel /* 1581 0 stevel * Encrypt the serialized arguments from xdr_func applied to xdr_ptr 1582 0 stevel * and write the result to xdrs. 1583 0 stevel */ 1584 0 stevel static bool_t 1585 0 stevel svc_rpc_gss_wrap(auth, out_xdrs, xdr_func, xdr_ptr) 1586 0 stevel SVCAUTH *auth; 1587 0 stevel XDR *out_xdrs; 1588 0 stevel bool_t (*xdr_func)(); 1589 0 stevel caddr_t xdr_ptr; 1590 0 stevel { 1591 0 stevel svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1592 0 stevel 1593 0 stevel /* 1594 0 stevel * If context is not established, or if neither integrity nor 1595 0 stevel * privacy service is used, don't wrap - just XDR encode. 1596 0 stevel * Otherwise, wrap data using service and QOP parameters. 1597 0 stevel */ 1598 0 stevel if (!gss_parms->established || 1599 0 stevel gss_parms->service == rpc_gss_svc_none) 1600 0 stevel return ((*xdr_func)(out_xdrs, xdr_ptr)); 1601 0 stevel 1602 0 stevel return (__rpc_gss_wrap_data(gss_parms->service, 1603 0 stevel (OM_uint32)gss_parms->qop_rcvd, 1604 0 stevel (gss_ctx_id_t)gss_parms->context, 1605 0 stevel gss_parms->seq_num, 1606 0 stevel out_xdrs, xdr_func, xdr_ptr)); 1607 0 stevel } 1608 0 stevel 1609 0 stevel /* 1610 0 stevel * Decrypt the serialized arguments and XDR decode them. 1611 0 stevel */ 1612 0 stevel static bool_t 1613 0 stevel svc_rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) 1614 0 stevel SVCAUTH *auth; 1615 0 stevel XDR *in_xdrs; 1616 0 stevel bool_t (*xdr_func)(); 1617 0 stevel caddr_t xdr_ptr; 1618 0 stevel { 1619 0 stevel svc_rpc_gss_parms_t *gss_parms = &auth->svc_gss_parms; 1620 0 stevel 1621 0 stevel /* 1622 0 stevel * If context is not established, or if neither integrity nor 1623 0 stevel * privacy service is used, don't unwrap - just XDR decode. 1624 0 stevel * Otherwise, unwrap data. 1625 0 stevel */ 1626 0 stevel if (!gss_parms->established || 1627 0 stevel gss_parms->service == rpc_gss_svc_none) 1628 0 stevel return ((*xdr_func)(in_xdrs, xdr_ptr)); 1629 0 stevel 1630 0 stevel return (__rpc_gss_unwrap_data(gss_parms->service, 1631 0 stevel (gss_ctx_id_t)gss_parms->context, 1632 0 stevel gss_parms->seq_num, 1633 0 stevel gss_parms->qop_rcvd, 1634 0 stevel in_xdrs, xdr_func, xdr_ptr)); 1635 0 stevel } 1636 0 stevel 1637 0 stevel int 1638 0 stevel __rpc_gss_svc_max_data_length(req, max_tp_unit_len) 1639 0 stevel struct svc_req *req; 1640 0 stevel int max_tp_unit_len; 1641 0 stevel { 1642 0 stevel SVCAUTH *svcauth; 1643 0 stevel svc_rpc_gss_parms_t *gss_parms; 1644 0 stevel 1645 0 stevel svcauth = __svc_get_svcauth(req->rq_xprt); 1646 0 stevel gss_parms = &svcauth->svc_gss_parms; 1647 0 stevel 1648 0 stevel if (!gss_parms->established || max_tp_unit_len <= 0) 1649 0 stevel return (0); 1650 0 stevel 1651 0 stevel return (__find_max_data_length(gss_parms->service, 1652 0 stevel (gss_ctx_id_t)gss_parms->context, 1653 0 stevel gss_parms->qop_rcvd, max_tp_unit_len)); 1654 0 stevel } 1655 0 stevel 1656 0 stevel /* 1657 0 stevel * Add retransmit entry to the context cache entry for a new xid. 1658 0 stevel * If there is already an entry, delete it before adding the new one. 1659 0 stevel */ 1660 0 stevel static void retrans_add(client, xid, result) 1661 0 stevel svc_rpc_gss_data *client; 1662 0 stevel uint32_t xid; 1663 0 stevel rpc_gss_init_res *result; 1664 0 stevel { 1665 0 stevel retrans_entry *rdata; 1666 0 stevel 1667 0 stevel if (client->retrans_data && client->retrans_data->xid == xid) 1668 0 stevel return; 1669 0 stevel 1670 0 stevel rdata = (retrans_entry *) malloc(sizeof (*rdata)); 1671 0 stevel if (rdata == NULL) 1672 0 stevel return; 1673 0 stevel 1674 0 stevel rdata->xid = xid; 1675 0 stevel rdata->result = *result; 1676 0 stevel 1677 0 stevel if (result->token.length != 0) { 1678 0 stevel GSS_DUP_BUFFER(rdata->result.token, result->token); 1679 0 stevel } 1680 0 stevel 1681 0 stevel if (client->retrans_data) 1682 0 stevel retrans_del(client); 1683 0 stevel 1684 0 stevel client->retrans_data = rdata; 1685 0 stevel } 1686 0 stevel 1687 0 stevel /* 1688 0 stevel * Delete the retransmit data from the context cache entry. 1689 0 stevel */ 1690 0 stevel static void retrans_del(client) 1691 0 stevel svc_rpc_gss_data *client; 1692 0 stevel { 1693 0 stevel retrans_entry *rdata; 1694 0 stevel OM_uint32 minor_stat; 1695 0 stevel 1696 0 stevel if (client->retrans_data == NULL) 1697 0 stevel return; 1698 0 stevel 1699 0 stevel rdata = client->retrans_data; 1700 0 stevel if (rdata->result.token.length != 0) { 1701 0 stevel (void) gss_release_buffer(&minor_stat, &rdata->result.token); 1702 0 stevel } 1703 0 stevel 1704 0 stevel free((caddr_t)rdata); 1705 0 stevel client->retrans_data = NULL; 1706 0 stevel } 1707