1 /* 2 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. 3 * 4 */ 5 6 #include <stdio.h> 7 #include <string.h> 8 #include <sys/errno.h> 9 10 #include <gssapi/gssapi.h> 11 #include <gssapi/gssapi_generic.h> 12 #ifdef GSSAPI_KRB5 13 #include <gssapi/gssapi_krb5.h> 14 #endif 15 16 #include <gssrpc/rpc.h> 17 #include <gssrpc/auth_gssapi.h> 18 19 #include "gssrpcint.h" 20 21 #ifdef __CODECENTER__ 22 #define DEBUG_GSSAPI 1 23 #endif 24 25 #ifdef DEBUG_GSSAPI 26 int auth_debug_gssapi = DEBUG_GSSAPI; 27 extern void gssrpcint_printf(const char *format, ...); 28 #define L_PRINTF(l,args) if (auth_debug_gssapi >= l) gssrpcint_printf args 29 #define PRINTF(args) L_PRINTF(99, args) 30 #define AUTH_GSSAPI_DISPLAY_STATUS(args) \ 31 if (auth_debug_gssapi) auth_gssapi_display_status args 32 #else 33 #define PRINTF(args) 34 #define L_PRINTF(l, args) 35 #define AUTH_GSSAPI_DISPLAY_STATUS(args) 36 #endif 37 38 static void auth_gssapi_nextverf(AUTH *); 39 static bool_t auth_gssapi_marshall(AUTH *, XDR *); 40 static bool_t auth_gssapi_validate(AUTH *, struct opaque_auth *); 41 static bool_t auth_gssapi_refresh(AUTH *, struct rpc_msg *); 42 static bool_t auth_gssapi_wrap(AUTH *, XDR *, xdrproc_t, caddr_t); 43 static bool_t auth_gssapi_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t); 44 static void auth_gssapi_destroy(AUTH *); 45 46 static bool_t marshall_new_creds(AUTH *, bool_t, gss_buffer_t); 47 48 static struct auth_ops auth_gssapi_ops = { 49 auth_gssapi_nextverf, 50 auth_gssapi_marshall, 51 auth_gssapi_validate, 52 auth_gssapi_refresh, 53 auth_gssapi_destroy, 54 auth_gssapi_wrap, 55 auth_gssapi_unwrap, 56 }; 57 58 /* 59 * the ah_private data structure for an auth_handle 60 */ 61 struct auth_gssapi_data { 62 bool_t established; 63 CLIENT *clnt; 64 gss_ctx_id_t context; 65 gss_buffer_desc client_handle; 66 uint32_t seq_num; 67 int def_cred; 68 69 /* pre-serialized ah_cred */ 70 unsigned char cred_buf[MAX_AUTH_BYTES]; 71 uint32_t cred_len; 72 }; 73 #define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private) 74 75 /* 76 * Function: auth_gssapi_create_default 77 * 78 * Purpose: Create a GSS-API style authenticator, with default 79 * options, and return the handle. 80 * 81 * Effects: See design document, section XXX. 82 */ 83 AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name) 84 { 85 AUTH *auth; 86 OM_uint32 gssstat, minor_stat; 87 gss_buffer_desc input_name; 88 gss_name_t target_name; 89 90 input_name.value = service_name; 91 input_name.length = strlen(service_name) + 1; 92 93 gssstat = gss_import_name(&minor_stat, &input_name, 94 gss_nt_service_name, &target_name); 95 if (gssstat != GSS_S_COMPLETE) { 96 AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat, 97 minor_stat)); 98 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 99 rpc_createerr.cf_error.re_errno = ENOMEM; 100 return NULL; 101 } 102 103 auth = auth_gssapi_create(clnt, 104 &gssstat, 105 &minor_stat, 106 GSS_C_NO_CREDENTIAL, 107 target_name, 108 GSS_C_NULL_OID, 109 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, 110 0, 111 NULL, 112 NULL, 113 NULL); 114 115 gss_release_name(&minor_stat, &target_name); 116 return auth; 117 } 118 119 /* 120 * Function: auth_gssapi_create 121 * 122 * Purpose: Create a GSS-API style authenticator, with all the 123 * options, and return the handle. 124 * 125 * Effects: See design document, section XXX. 126 */ 127 AUTH *auth_gssapi_create( 128 CLIENT *clnt, 129 OM_uint32 *gssstat, 130 OM_uint32 *minor_stat, 131 gss_cred_id_t claimant_cred_handle, 132 gss_name_t target_name, 133 gss_OID mech_type, 134 OM_uint32 req_flags, 135 OM_uint32 time_req, 136 gss_OID *actual_mech_type, 137 OM_uint32 *ret_flags, 138 OM_uint32 *time_rec) 139 { 140 AUTH *auth, *save_auth; 141 struct auth_gssapi_data *pdata; 142 struct gss_channel_bindings_struct bindings, *bindp; 143 struct sockaddr_in laddr, raddr; 144 enum clnt_stat callstat; 145 struct timeval timeout; 146 int bindings_failed; 147 rpcproc_t init_func; 148 149 auth_gssapi_init_arg call_arg; 150 auth_gssapi_init_res call_res; 151 gss_buffer_desc *input_token, isn_buf; 152 153 memset(&rpc_createerr, 0, sizeof(rpc_createerr)); 154 155 /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */ 156 /* has not already been called.. therefore, we can just pick */ 157 /* something reasonable-sounding.. */ 158 timeout.tv_sec = 30; 159 timeout.tv_usec = 0; 160 161 auth = NULL; 162 pdata = NULL; 163 164 /* don't assume the caller will want to change clnt->cl_auth */ 165 save_auth = clnt->cl_auth; 166 167 auth = (AUTH *) malloc(sizeof(*auth)); 168 pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata)); 169 if (auth == NULL || pdata == NULL) { 170 /* They needn't both have failed; clean up. */ 171 free(auth); 172 free(pdata); 173 auth = NULL; 174 pdata = NULL; 175 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 176 rpc_createerr.cf_error.re_errno = ENOMEM; 177 goto cleanup; 178 } 179 memset(auth, 0, sizeof(*auth)); 180 memset(pdata, 0, sizeof(*pdata)); 181 182 auth->ah_ops = &auth_gssapi_ops; 183 auth->ah_private = (caddr_t) pdata; 184 185 /* initial creds are auth_msg TRUE and no handle */ 186 marshall_new_creds(auth, TRUE, NULL); 187 188 /* initial verifier is empty */ 189 auth->ah_verf.oa_flavor = AUTH_GSSAPI; 190 auth->ah_verf.oa_base = NULL; 191 auth->ah_verf.oa_length = 0; 192 193 AUTH_PRIVATE(auth)->established = FALSE; 194 AUTH_PRIVATE(auth)->clnt = clnt; 195 AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle == 196 GSS_C_NO_CREDENTIAL); 197 198 clnt->cl_auth = auth; 199 200 /* start by trying latest version */ 201 call_arg.version = 4; 202 bindings_failed = 0; 203 204 try_new_version: 205 /* set state for initial call to init_sec_context */ 206 input_token = GSS_C_NO_BUFFER; 207 AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT; 208 init_func = AUTH_GSSAPI_INIT; 209 210 #ifdef GSSAPI_KRB5 211 /* 212 * OV servers up to version 3 used the old mech id. Beta 7 213 * servers used version 3 with the new mech id; however, the beta 214 * 7 gss-api accept_sec_context accepts either mech id. Thus, if 215 * any server rejects version 4, we fall back to version 3 with 216 * the old mech id; for the OV server it will be right, and for 217 * the beta 7 server it will be accepted. Not ideal, but it 218 * works. 219 */ 220 if (call_arg.version < 4 && (mech_type == gss_mech_krb5 || 221 mech_type == GSS_C_NULL_OID)) 222 mech_type = (gss_OID) gss_mech_krb5_old; 223 #endif 224 225 if (!bindings_failed && call_arg.version >= 3) { 226 if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) { 227 PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed")); 228 goto cleanup; 229 } 230 if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) { 231 PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed")); 232 goto cleanup; 233 } 234 235 memset(&bindings, 0, sizeof(bindings)); 236 bindings.application_data.length = 0; 237 bindings.initiator_addrtype = GSS_C_AF_INET; 238 bindings.initiator_address.length = 4; 239 bindings.initiator_address.value = &laddr.sin_addr.s_addr; 240 241 bindings.acceptor_addrtype = GSS_C_AF_INET; 242 bindings.acceptor_address.length = 4; 243 bindings.acceptor_address.value = &raddr.sin_addr.s_addr; 244 bindp = &bindings; 245 } else { 246 bindp = NULL; 247 } 248 249 memset(&call_res, 0, sizeof(call_res)); 250 251 next_token: 252 *gssstat = gss_init_sec_context(minor_stat, 253 claimant_cred_handle, 254 &AUTH_PRIVATE(auth)->context, 255 target_name, 256 mech_type, 257 req_flags, 258 time_req, 259 bindp, 260 input_token, 261 actual_mech_type, 262 &call_arg.token, 263 ret_flags, 264 time_rec); 265 266 if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { 267 AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat, 268 *minor_stat)); 269 goto cleanup; 270 } 271 272 /* if we got a token, pass it on */ 273 if (call_arg.token.length != 0) { 274 275 /* 276 * sanity check: if we received a signed isn in the last 277 * response then there *cannot* be another token to send 278 */ 279 if (call_res.signed_isn.length != 0) { 280 PRINTF(("gssapi_create: unexpected token from init_sec\n")); 281 goto cleanup; 282 } 283 284 PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func)); 285 286 xdr_free(xdr_authgssapi_init_res, &call_res); 287 memset(&call_res, 0, sizeof(call_res)); 288 callstat = clnt_call(clnt, init_func, 289 xdr_authgssapi_init_arg, &call_arg, 290 xdr_authgssapi_init_res, &call_res, 291 timeout); 292 gss_release_buffer(minor_stat, &call_arg.token); 293 294 if (callstat != RPC_SUCCESS) { 295 struct rpc_err err; 296 297 clnt_geterr(clnt, &err); 298 if (callstat == RPC_AUTHERROR && 299 (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED) 300 && call_arg.version >= 1) { 301 L_PRINTF(1, 302 ("call_arg protocol version %d rejected, trying %d.\n", 303 call_arg.version, call_arg.version-1)); 304 call_arg.version--; 305 goto try_new_version; 306 } else { 307 PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n", 308 init_func, callstat)); 309 } 310 311 goto cleanup; 312 } else if (call_res.version != call_arg.version && 313 !(call_arg.version == 2 && call_res.version == 1)) { 314 /* 315 * The Secure 1.1 servers always respond with version 316 * 1. Thus, if we just tried a version >=3, fall all 317 * the way back to version 1 since that is all they 318 * understand 319 */ 320 if (call_arg.version > 2 && call_res.version == 1) { 321 L_PRINTF(1, 322 ("Talking to Secure 1.1 server, using version 1.\n")); 323 call_arg.version = 1; 324 goto try_new_version; 325 } 326 327 PRINTF(("gssapi_create: invalid call_res vers %d\n", 328 call_res.version)); 329 goto cleanup; 330 } else if (call_res.gss_major != GSS_S_COMPLETE) { 331 AUTH_GSSAPI_DISPLAY_STATUS(("in response from server", 332 call_res.gss_major, 333 call_res.gss_minor)); 334 goto cleanup; 335 } 336 337 PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func)); 338 init_func = AUTH_GSSAPI_CONTINUE_INIT; 339 340 /* check for client_handle */ 341 if (AUTH_PRIVATE(auth)->client_handle.length == 0) { 342 if (call_res.client_handle.length == 0) { 343 PRINTF(("gssapi_create: expected client_handle\n")); 344 goto cleanup; 345 } else { 346 PRINTF(("gssapi_create: got client_handle %d\n", 347 *((uint32_t *)call_res.client_handle.value))); 348 349 GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle, 350 call_res.client_handle); 351 352 /* auth_msg is TRUE; there may be more tokens */ 353 marshall_new_creds(auth, TRUE, 354 &AUTH_PRIVATE(auth)->client_handle); 355 } 356 } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle, 357 call_res.client_handle)) { 358 PRINTF(("gssapi_create: got different client_handle\n")); 359 goto cleanup; 360 } 361 362 /* check for token */ 363 if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) { 364 PRINTF(("gssapi_create: expected token\n")); 365 goto cleanup; 366 } else if (call_res.token.length != 0) { 367 if (*gssstat == GSS_S_COMPLETE) { 368 PRINTF(("gssapi_create: got unexpected token\n")); 369 goto cleanup; 370 } else { 371 /* assumes call_res is safe until init_sec_context */ 372 input_token = &call_res.token; 373 PRINTF(("gssapi_create: got new token\n")); 374 } 375 } 376 } 377 378 /* check for isn */ 379 if (*gssstat == GSS_S_COMPLETE) { 380 if (call_res.signed_isn.length == 0) { 381 PRINTF(("gssapi_created: expected signed isn\n")); 382 goto cleanup; 383 } else { 384 PRINTF(("gssapi_create: processing signed isn\n")); 385 386 /* don't check conf (integ only) or qop (accept default) */ 387 *gssstat = gss_unseal(minor_stat, 388 AUTH_PRIVATE(auth)->context, 389 &call_res.signed_isn, 390 &isn_buf, NULL, NULL); 391 392 if (*gssstat != GSS_S_COMPLETE) { 393 AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn", 394 *gssstat, *minor_stat)); 395 goto cleanup; 396 } else if (isn_buf.length != sizeof(uint32_t)) { 397 PRINTF(("gssapi_create: gss_unseal gave %d bytes\n", 398 (int) isn_buf.length)); 399 goto cleanup; 400 } 401 402 AUTH_PRIVATE(auth)->seq_num = (uint32_t) 403 ntohl(*((uint32_t*)isn_buf.value)); 404 *gssstat = gss_release_buffer(minor_stat, &isn_buf); 405 if (*gssstat != GSS_S_COMPLETE) { 406 AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn", 407 *gssstat, *minor_stat)); 408 goto cleanup; 409 } 410 411 PRINTF(("gssapi_create: isn is %d\n", 412 AUTH_PRIVATE(auth)->seq_num)); 413 } 414 } else if (call_res.signed_isn.length != 0) { 415 PRINTF(("gssapi_create: got signed isn, can't check yet\n")); 416 } 417 418 /* results were okay.. continue if necessary */ 419 if (*gssstat == GSS_S_CONTINUE_NEEDED) { 420 PRINTF(("gssapi_create: not done, continuing\n")); 421 goto next_token; 422 } 423 424 /* 425 * Done! Context is established, we have client_handle and isn. 426 */ 427 AUTH_PRIVATE(auth)->established = TRUE; 428 429 marshall_new_creds(auth, FALSE, 430 &AUTH_PRIVATE(auth)->client_handle); 431 432 PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n", 433 *((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value), 434 AUTH_PRIVATE(auth)->seq_num)); 435 436 /* don't assume the caller will want to change clnt->cl_auth */ 437 clnt->cl_auth = save_auth; 438 439 xdr_free(xdr_authgssapi_init_res, &call_res); 440 return auth; 441 442 /******************************************************************/ 443 444 cleanup: 445 PRINTF(("gssapi_create: bailing\n\n")); 446 447 if (auth) { 448 if (AUTH_PRIVATE(auth)) 449 auth_gssapi_destroy(auth); 450 else 451 free(auth); 452 auth = NULL; 453 } 454 455 /* don't assume the caller will want to change clnt->cl_auth */ 456 clnt->cl_auth = save_auth; 457 458 if (rpc_createerr.cf_stat == 0) 459 rpc_createerr.cf_stat = RPC_AUTHERROR; 460 461 xdr_free(xdr_authgssapi_init_res, &call_res); 462 return auth; 463 } 464 465 /* 466 * Function: marshall_new_creds 467 * 468 * Purpose: (pre-)serialize auth_msg and client_handle fields of 469 * auth_gssapi_creds into auth->cred_buf 470 * 471 * Arguments: 472 * 473 * auth (r/w) the AUTH structure to modify 474 * auth_msg (r) the auth_msg field to serialize 475 * client_handle (r) the client_handle field to serialize, or 476 * NULL 477 * 478 * Returns: TRUE if successful, FALSE if not 479 * 480 * Requires: auth must point to a valid GSS-API auth structure, auth_msg 481 * must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid 482 * value and length field or NULL. 483 * 484 * Effects: auth->ah_cred is set to the serialized auth_gssapi_creds 485 * version 2 structure (stored in the cred_buf field of private data) 486 * containing version, auth_msg and client_handle. 487 * auth->ah_cred.oa_flavor is set to AUTH_GSSAPI. If cliend_handle is 488 * NULL, it is treated as if it had a length of 0 and a value of NULL. 489 * 490 * Modifies: auth 491 */ 492 static bool_t marshall_new_creds( 493 AUTH *auth, 494 bool_t auth_msg, 495 gss_buffer_t client_handle) 496 { 497 auth_gssapi_creds creds; 498 XDR xdrs; 499 500 PRINTF(("marshall_new_creds: starting\n")); 501 502 creds.version = 2; 503 504 creds.auth_msg = auth_msg; 505 if (client_handle) 506 GSS_COPY_BUFFER(creds.client_handle, *client_handle) 507 else { 508 creds.client_handle.length = 0; 509 creds.client_handle.value = NULL; 510 } 511 512 xdrmem_create(&xdrs, (caddr_t) AUTH_PRIVATE(auth)->cred_buf, 513 MAX_AUTH_BYTES, XDR_ENCODE); 514 if (! xdr_authgssapi_creds(&xdrs, &creds)) { 515 PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n")); 516 XDR_DESTROY(&xdrs); 517 return FALSE; 518 } 519 AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs); 520 XDR_DESTROY(&xdrs); 521 522 PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n", 523 AUTH_PRIVATE(auth)->cred_len)); 524 525 auth->ah_cred.oa_flavor = AUTH_GSSAPI; 526 auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf; 527 auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len; 528 529 PRINTF(("marshall_new_creds: succeeding\n")); 530 531 return TRUE; 532 } 533 534 535 /* 536 * Function: auth_gssapi_nextverf 537 * 538 * Purpose: None. 539 * 540 * Effects: None. Never called. 541 */ 542 static void auth_gssapi_nextverf(AUTH *auth) 543 { 544 } 545 546 /* 547 * Function: auth_gssapi_marhsall 548 * 549 * Purpose: Marshall RPC credentials and verifier onto xdr stream. 550 * 551 * Arguments: 552 * 553 * auth (r/w) AUTH structure for client 554 * xdrs (r/w) XDR stream to marshall to 555 * 556 * Returns: boolean indicating success/failure 557 * 558 * Effects: 559 * 560 * The pre-serialized credentials in cred_buf are serialized. If the 561 * context is established, the sealed sequence number is serialized as 562 * the verifier. If the context is not established, an empty verifier 563 * is serialized. The sequence number is *not* incremented, because 564 * this function is called multiple times if retransmission is required. 565 * 566 * If this took all the header fields as arguments, it could sign 567 * them. 568 */ 569 static bool_t auth_gssapi_marshall( 570 AUTH *auth, 571 XDR *xdrs) 572 { 573 OM_uint32 minor_stat; 574 gss_buffer_desc out_buf; 575 uint32_t seq_num; 576 577 if (AUTH_PRIVATE(auth)->established == TRUE) { 578 PRINTF(("gssapi_marshall: starting\n")); 579 580 seq_num = AUTH_PRIVATE(auth)->seq_num + 1; 581 582 PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num)); 583 584 if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num, 585 &out_buf) == FALSE) { 586 PRINTF(("gssapi_marhshall: seal failed\n")); 587 } 588 589 auth->ah_verf.oa_base = out_buf.value; 590 auth->ah_verf.oa_length = out_buf.length; 591 592 if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || 593 ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { 594 (void) gss_release_buffer(&minor_stat, &out_buf); 595 return FALSE; 596 } 597 (void) gss_release_buffer(&minor_stat, &out_buf); 598 } else { 599 PRINTF(("gssapi_marshall: not established, sending null verf\n")); 600 601 auth->ah_verf.oa_base = NULL; 602 auth->ah_verf.oa_length = 0; 603 604 if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || 605 ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { 606 return FALSE; 607 } 608 } 609 610 return TRUE; 611 } 612 613 /* 614 * Function: auth_gssapi_validate 615 * 616 * Purpose: Validate RPC response verifier from server. 617 * 618 * Effects: See design document, section XXX. 619 */ 620 static bool_t auth_gssapi_validate( 621 AUTH *auth, 622 struct opaque_auth *verf) 623 { 624 gss_buffer_desc in_buf; 625 uint32_t seq_num; 626 627 if (AUTH_PRIVATE(auth)->established == FALSE) { 628 PRINTF(("gssapi_validate: not established, noop\n")); 629 return TRUE; 630 } 631 632 PRINTF(("gssapi_validate: starting\n")); 633 634 in_buf.length = verf->oa_length; 635 in_buf.value = verf->oa_base; 636 if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf, 637 &seq_num) == FALSE) { 638 PRINTF(("gssapi_validate: failed unsealing verifier\n")); 639 return FALSE; 640 } 641 642 /* we sent seq_num+1, so we should get back seq_num+2 */ 643 if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) { 644 PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n", 645 AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num)); 646 return FALSE; 647 } 648 PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num)); 649 650 /* +1 for successful transmission, +1 for successful validation */ 651 AUTH_PRIVATE(auth)->seq_num += 2; 652 653 PRINTF(("gssapi_validate: succeeding\n")); 654 655 return TRUE; 656 } 657 658 /* 659 * Function: auth_gssapi_refresh 660 * 661 * Purpose: Attempts to resyncrhonize the sequence number. 662 * 663 * Effects: 664 * 665 * When the server receives a properly authenticated RPC call, it 666 * increments the sequence number it is expecting from the client. 667 * But if the server's response is lost for any reason, the client 668 * can't know whether the server ever received it, assumes it didn't, 669 * and does *not* increment its sequence number. Thus, the client's 670 * next call will fail with AUTH_REJECTEDCRED because the server will 671 * think it is a replay attack. 672 * 673 * When an AUTH_REJECTEDCRED error arrives, this function attempts to 674 * resyncrhonize by incrementing the client's sequence number and 675 * returning TRUE. If any other error arrives, it returns FALSE. 676 */ 677 static bool_t auth_gssapi_refresh( 678 AUTH *auth, 679 struct rpc_msg *msg) 680 { 681 if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR && 682 msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) { 683 PRINTF(("gssapi_refresh: rejected verifier, incrementing\n")); 684 AUTH_PRIVATE(auth)->seq_num++; 685 return TRUE; 686 } else { 687 PRINTF(("gssapi_refresh: failing\n")); 688 return FALSE; 689 } 690 } 691 692 /* 693 * Function: auth_gssapi_destroy 694 * 695 * Purpose: Destroy a GSS-API authentication structure. 696 * 697 * Effects: This function destroys the GSS-API authentication 698 * context, and sends a message to the server instructing it to 699 * invokte gss_process_token() and thereby destroy its corresponding 700 * context. Since the client doesn't really care whether the server 701 * gets this message, no failures are reported. 702 */ 703 static void auth_gssapi_destroy(AUTH *auth) 704 { 705 struct timeval timeout; 706 OM_uint32 gssstat, minor_stat; 707 gss_cred_id_t cred; 708 int callstat; 709 710 if (AUTH_PRIVATE(auth)->client_handle.length == 0) { 711 PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n")); 712 goto skip_call; 713 } 714 715 PRINTF(("gssapi_destroy: marshalling new creds\n")); 716 if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) { 717 PRINTF(("gssapi_destroy: marshall_new_creds failed\n")); 718 goto skip_call; 719 } 720 721 PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n")); 722 timeout.tv_sec = 1; 723 timeout.tv_usec = 0; 724 callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY, 725 xdr_void, NULL, xdr_void, NULL, timeout); 726 if (callstat != RPC_SUCCESS) 727 clnt_sperror(AUTH_PRIVATE(auth)->clnt, 728 "gssapi_destroy: GSSAPI_DESTROY failed"); 729 730 skip_call: 731 PRINTF(("gssapi_destroy: deleting context\n")); 732 gssstat = gss_delete_sec_context(&minor_stat, 733 &AUTH_PRIVATE(auth)->context, 734 NULL); 735 if (gssstat != GSS_S_COMPLETE) 736 AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat, 737 minor_stat)); 738 if (AUTH_PRIVATE(auth)->def_cred) { 739 cred = GSS_C_NO_CREDENTIAL; 740 gssstat = gss_release_cred(&minor_stat, &cred); 741 if (gssstat != GSS_S_COMPLETE) 742 AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential", 743 gssstat, minor_stat)); 744 } 745 746 free(AUTH_PRIVATE(auth)->client_handle.value); 747 free(auth->ah_private); 748 free(auth); 749 PRINTF(("gssapi_destroy: done\n")); 750 } 751 752 /* 753 * Function: auth_gssapi_wrap 754 * 755 * Purpose: encrypt the serialized arguments from xdr_func applied to 756 * xdr_ptr and write the result to xdrs. 757 * 758 * Effects: See design doc, section XXX. 759 */ 760 static bool_t auth_gssapi_wrap( 761 AUTH *auth, 762 XDR *out_xdrs, 763 bool_t (*xdr_func)(), 764 caddr_t xdr_ptr) 765 { 766 OM_uint32 gssstat, minor_stat; 767 768 if (! AUTH_PRIVATE(auth)->established) { 769 PRINTF(("gssapi_wrap: context not established, noop\n")); 770 return (*xdr_func)(out_xdrs, xdr_ptr); 771 } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat, 772 AUTH_PRIVATE(auth)->context, 773 AUTH_PRIVATE(auth)->seq_num+1, 774 out_xdrs, xdr_func, xdr_ptr)) { 775 if (gssstat != GSS_S_COMPLETE) 776 AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments", 777 gssstat, minor_stat)); 778 return FALSE; 779 } else 780 return TRUE; 781 } 782 783 /* 784 * Function: auth_gssapi_unwrap 785 * 786 * Purpose: read encrypted arguments from xdrs, decrypt, and 787 * deserialize with xdr_func into xdr_ptr. 788 * 789 * Effects: See design doc, section XXX. 790 */ 791 static bool_t auth_gssapi_unwrap( 792 AUTH *auth, 793 XDR *in_xdrs, 794 bool_t (*xdr_func)(), 795 caddr_t xdr_ptr) 796 { 797 OM_uint32 gssstat, minor_stat; 798 799 if (! AUTH_PRIVATE(auth)->established) { 800 PRINTF(("gssapi_unwrap: context not established, noop\n")); 801 return (*xdr_func)(in_xdrs, xdr_ptr); 802 } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat, 803 AUTH_PRIVATE(auth)->context, 804 AUTH_PRIVATE(auth)->seq_num, 805 in_xdrs, xdr_func, xdr_ptr)) { 806 if (gssstat != GSS_S_COMPLETE) 807 AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments", 808 gssstat, minor_stat)); 809 return FALSE; 810 } else 811 return TRUE; 812 } 813