1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 2009 by the Massachusetts Institute of Technology. 4 * All Rights Reserved. 5 * 6 * Export of this software from the United States of America may 7 * require a specific license from the United States Government. 8 * It is the responsibility of any person or organization contemplating 9 * export to obtain such a license before exporting. 10 * 11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 12 * distribute this software and its documentation for any purpose and 13 * without fee is hereby granted, provided that the above copyright 14 * notice appear in all copies and that both that copyright notice and 15 * this permission notice appear in supporting documentation, and that 16 * the name of M.I.T. not be used in advertising or publicity pertaining 17 * to distribution of the software without specific, written prior 18 * permission. Furthermore if you modify this software you must label 19 * your software as modified software and not distribute it in such a 20 * fashion that it might be confused with the original M.I.T. software. 21 * M.I.T. makes no representations about the suitability of 22 * this software for any purpose. It is provided "as is" without express 23 * or implied warranty. 24 */ 25 #include "k5-int.h" 26 #include "k5-der.h" 27 #include "gssapiP_krb5.h" 28 29 /* 30 * IAKERB implementation 31 */ 32 33 enum iakerb_state { 34 IAKERB_REALM_DISCOVERY, /* querying server for its realm */ 35 IAKERB_AS_REQ, /* acquiring ticket with initial creds */ 36 IAKERB_TGS_REQ, /* acquiring ticket with TGT */ 37 IAKERB_AP_REQ /* hand-off to normal GSS AP-REQ exchange */ 38 }; 39 40 struct _iakerb_ctx_id_rec { 41 krb5_magic magic; /* KG_IAKERB_CONTEXT */ 42 krb5_context k5c; 43 gss_cred_id_t defcred; /* Initiator only */ 44 enum iakerb_state state; /* Initiator only */ 45 krb5_init_creds_context icc; /* Initiator only */ 46 krb5_tkt_creds_context tcc; /* Initiator only */ 47 gss_ctx_id_t gssc; 48 krb5_data conv; /* conversation for checksumming */ 49 unsigned int count; /* number of round trips */ 50 int initiate; 51 int established; 52 krb5_get_init_creds_opt *gic_opts; 53 }; 54 55 #define IAKERB_MAX_HOPS ( 16 /* MAX_IN_TKT_LOOPS */ + KRB5_REFERRAL_MAXHOPS ) 56 57 typedef struct _iakerb_ctx_id_rec iakerb_ctx_id_rec; 58 typedef iakerb_ctx_id_rec *iakerb_ctx_id_t; 59 60 /* 61 * Release an IAKERB context 62 */ 63 static void 64 iakerb_release_context(iakerb_ctx_id_t ctx) 65 { 66 OM_uint32 tmp; 67 68 if (ctx == NULL) 69 return; 70 71 krb5_gss_release_cred(&tmp, &ctx->defcred); 72 krb5_init_creds_free(ctx->k5c, ctx->icc); 73 krb5_tkt_creds_free(ctx->k5c, ctx->tcc); 74 krb5_gss_delete_sec_context(&tmp, &ctx->gssc, NULL); 75 krb5_free_data_contents(ctx->k5c, &ctx->conv); 76 krb5_get_init_creds_opt_free(ctx->k5c, ctx->gic_opts); 77 krb5_free_context(ctx->k5c); 78 free(ctx); 79 } 80 81 /* Encode a KRB-ERROR message with the given protocol code. Use the server 82 * principal from verifier_cred if one is available. */ 83 static krb5_error_code 84 iakerb_mk_error(krb5_context context, gss_cred_id_t verifier_cred, 85 int protocol_err, krb5_data *enc_err) 86 { 87 krb5_error error = { 0 }; 88 krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)verifier_cred; 89 90 error.error = protocol_err; 91 92 /* We must provide a server principal, although we expect the recipient to 93 * care chiefly about the error code. */ 94 if (cred != NULL && cred->name != NULL) 95 error.server = cred->name->princ; 96 else 97 error.server = (krb5_principal)krb5_anonymous_principal(); 98 99 return krb5_mk_error(context, &error, enc_err); 100 } 101 102 /* Decode a KRB-ERROR message and return the associated com_err code. */ 103 static krb5_error_code 104 iakerb_rd_error(krb5_context context, const krb5_data *enc_err) 105 { 106 krb5_error_code ret; 107 krb5_error *error; 108 109 ret = krb5_rd_error(context, enc_err, &error); 110 if (ret) 111 return ret; 112 113 if (error->error > 0 && error->error <= KRB_ERR_MAX) 114 ret = error->error + ERROR_TABLE_BASE_krb5; 115 else 116 ret = KRB5KRB_ERR_GENERIC; 117 krb5_free_error(context, error); 118 return ret; 119 } 120 121 /* 122 * Create a IAKERB-FINISHED structure containing a checksum of 123 * the entire IAKERB exchange. 124 */ 125 krb5_error_code 126 iakerb_make_finished(krb5_context context, 127 krb5_key key, 128 const krb5_data *conv, 129 krb5_data **finished) 130 { 131 krb5_error_code code; 132 krb5_iakerb_finished iaf; 133 134 *finished = NULL; 135 136 memset(&iaf, 0, sizeof(iaf)); 137 138 if (key == NULL) 139 return KRB5KDC_ERR_NULL_KEY; 140 141 code = krb5_k_make_checksum(context, 0, key, KRB5_KEYUSAGE_FINISHED, conv, 142 &iaf.checksum); 143 if (code != 0) 144 return code; 145 146 code = encode_krb5_iakerb_finished(&iaf, finished); 147 148 krb5_free_checksum_contents(context, &iaf.checksum); 149 150 return code; 151 } 152 153 /* 154 * Verify a IAKERB-FINISHED structure submitted by the initiator 155 */ 156 krb5_error_code 157 iakerb_verify_finished(krb5_context context, 158 krb5_key key, 159 const krb5_data *conv, 160 const krb5_data *finished) 161 { 162 krb5_error_code code; 163 krb5_iakerb_finished *iaf; 164 krb5_boolean valid = FALSE; 165 166 if (key == NULL) 167 return KRB5KDC_ERR_NULL_KEY; 168 169 code = decode_krb5_iakerb_finished(finished, &iaf); 170 if (code != 0) 171 return code; 172 173 code = krb5_k_verify_checksum(context, key, KRB5_KEYUSAGE_FINISHED, conv, 174 &iaf->checksum, &valid); 175 if (code == 0 && valid == FALSE) 176 code = KRB5KRB_AP_ERR_BAD_INTEGRITY; 177 178 krb5_free_iakerb_finished(context, iaf); 179 180 return code; 181 } 182 183 /* 184 * Save a token for future checksumming. 185 */ 186 static krb5_error_code 187 iakerb_save_token(iakerb_ctx_id_t ctx, const gss_buffer_t token) 188 { 189 char *p; 190 191 p = realloc(ctx->conv.data, ctx->conv.length + token->length); 192 if (p == NULL) 193 return ENOMEM; 194 195 memcpy(p + ctx->conv.length, token->value, token->length); 196 ctx->conv.data = p; 197 ctx->conv.length += token->length; 198 199 return 0; 200 } 201 202 /* 203 * Parse a token into IAKERB-HEADER and KRB-KDC-REQ/REP 204 */ 205 static krb5_error_code 206 iakerb_parse_token(iakerb_ctx_id_t ctx, 207 const gss_buffer_t token, 208 krb5_data *realm, 209 krb5_data **cookie, 210 krb5_data *request) 211 { 212 krb5_error_code code; 213 krb5_iakerb_header *iah = NULL; 214 const uint8_t *token_body; 215 krb5_data data; 216 struct k5input in, seq; 217 218 if (token == GSS_C_NO_BUFFER || token->length == 0) { 219 code = KRB5_BAD_MSIZE; 220 goto cleanup; 221 } 222 223 k5_input_init(&in, token->value, token->length); 224 if (!g_verify_token_header(&in, gss_mech_iakerb) || 225 k5_input_get_uint16_be(&in) != IAKERB_TOK_PROXY) { 226 code = G_BAD_TOK_HEADER; 227 goto cleanup; 228 } 229 230 /* Find the end of the DER sequence tag and decode it (with the tag) as the 231 * IAKERB header. */ 232 token_body = in.ptr; 233 if (!k5_der_get_value(&in, 0x30, &seq)) { 234 code = ASN1_BAD_ID; 235 goto cleanup; 236 } 237 data = make_data((uint8_t *)token_body, seq.ptr + seq.len - token_body); 238 code = decode_krb5_iakerb_header(&data, &iah); 239 if (code != 0) 240 goto cleanup; 241 242 if (realm != NULL) { 243 *realm = iah->target_realm; 244 iah->target_realm.data = NULL; 245 } 246 247 if (cookie != NULL) { 248 *cookie = iah->cookie; 249 iah->cookie = NULL; 250 } 251 252 /* The remainder of the token body is the request. */ 253 *request = make_data((uint8_t *)in.ptr, in.len); 254 assert(request->data + request->length == 255 (char *)token->value + token->length); 256 257 cleanup: 258 krb5_free_iakerb_header(ctx->k5c, iah); 259 260 return code; 261 } 262 263 /* 264 * Create a token from IAKERB-HEADER and KRB-KDC-REQ/REP. Save the generated 265 * token for the finish checksum and increment the message count. 266 */ 267 static krb5_error_code 268 iakerb_make_token(iakerb_ctx_id_t ctx, 269 krb5_data *realm, 270 krb5_data *cookie, 271 krb5_data *request, 272 gss_buffer_t token) 273 { 274 krb5_error_code code; 275 krb5_iakerb_header iah; 276 krb5_data *data = NULL; 277 char *p; 278 unsigned int tokenSize; 279 struct k5buf buf; 280 281 token->value = NULL; 282 token->length = 0; 283 284 /* 285 * Assemble the IAKERB-HEADER from the realm and cookie 286 */ 287 iah.target_realm = *realm; 288 iah.cookie = cookie; 289 290 code = encode_krb5_iakerb_header(&iah, &data); 291 if (code != 0) 292 goto cleanup; 293 294 /* 295 * Concatenate Kerberos request. 296 */ 297 p = realloc(data->data, data->length + request->length); 298 if (p == NULL) { 299 code = ENOMEM; 300 goto cleanup; 301 } 302 data->data = p; 303 304 if (request->length > 0) 305 memcpy(data->data + data->length, request->data, request->length); 306 data->length += request->length; 307 308 tokenSize = g_token_size(gss_mech_iakerb, data->length); 309 token->value = gssalloc_malloc(tokenSize); 310 if (token->value == NULL) { 311 code = ENOMEM; 312 goto cleanup; 313 } 314 token->length = tokenSize; 315 k5_buf_init_fixed(&buf, token->value, token->length); 316 317 g_make_token_header(&buf, gss_mech_iakerb, data->length, IAKERB_TOK_PROXY); 318 k5_buf_add_len(&buf, data->data, data->length); 319 assert(buf.len == token->length); 320 321 code = iakerb_save_token(ctx, token); 322 if (code != 0) 323 goto cleanup; 324 ctx->count++; 325 326 cleanup: 327 krb5_free_data(ctx->k5c, data); 328 329 return code; 330 } 331 332 /* Generate a response to a realm discovery request. */ 333 static krb5_error_code 334 iakerb_acceptor_realm(iakerb_ctx_id_t ctx, gss_cred_id_t verifier_cred, 335 gss_buffer_t output_token) 336 { 337 krb5_error_code ret; 338 OM_uint32 dummy; 339 krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)verifier_cred; 340 krb5_data realm = empty_data(), reply = empty_data(); 341 char *defrealm = NULL; 342 343 /* Get the acceptor realm from the verifier cred if we can; otherwise try 344 * to use the default realm. */ 345 if (cred != NULL && cred->name != NULL && 346 cred->name->princ->realm.length > 0) { 347 realm = cred->name->princ->realm; 348 } else { 349 ret = krb5_get_default_realm(ctx->k5c, &defrealm); 350 if (ret) { 351 /* Generate an error reply if there is no default realm. */ 352 ret = iakerb_mk_error(ctx->k5c, verifier_cred, 353 KRB_AP_ERR_IAKERB_KDC_NOT_FOUND, &reply); 354 if (ret) 355 goto cleanup; 356 } else { 357 realm = string2data(defrealm); 358 } 359 } 360 361 ret = iakerb_make_token(ctx, &realm, NULL, &reply, output_token); 362 if (ret) 363 goto cleanup; 364 365 cleanup: 366 if (ret) 367 gss_release_buffer(&dummy, output_token); 368 krb5_free_default_realm(ctx->k5c, defrealm); 369 krb5_free_data_contents(ctx->k5c, &reply); 370 return ret; 371 } 372 373 /* 374 * Parse the IAKERB token in input_token and send the contained KDC 375 * request to the KDC for the realm. 376 * 377 * Wrap the KDC reply in output_token. 378 */ 379 static krb5_error_code 380 iakerb_acceptor_step(iakerb_ctx_id_t ctx, gss_cred_id_t verifier_cred, 381 const gss_buffer_t input_token, 382 gss_buffer_t output_token) 383 { 384 krb5_error_code code; 385 krb5_data request = empty_data(), reply = empty_data(); 386 krb5_data realm = empty_data(); 387 OM_uint32 tmp; 388 int tcp_only, use_primary, protocol_err; 389 krb5_ui_4 kdc_code; 390 391 output_token->length = 0; 392 output_token->value = NULL; 393 394 if (ctx->count >= IAKERB_MAX_HOPS) { 395 code = KRB5_KDC_UNREACH; 396 goto cleanup; 397 } 398 399 code = iakerb_parse_token(ctx, input_token, &realm, NULL, &request); 400 if (code != 0) 401 goto cleanup; 402 403 code = iakerb_save_token(ctx, input_token); 404 if (code != 0) 405 goto cleanup; 406 407 if (realm.length == 0 && request.length == 0) { 408 /* This is a realm discovery request. */ 409 code = iakerb_acceptor_realm(ctx, verifier_cred, output_token); 410 goto cleanup; 411 } else if (realm.length == 0 || request.length == 0) { 412 code = KRB5_BAD_MSIZE; 413 goto cleanup; 414 } 415 416 for (tcp_only = 0; tcp_only <= 1; tcp_only++) { 417 use_primary = 0; 418 code = krb5_sendto_kdc(ctx->k5c, &request, &realm, 419 &reply, &use_primary, tcp_only); 420 if (code == 0 && krb5_is_krb_error(&reply)) { 421 krb5_error *error; 422 423 code = decode_krb5_error(&reply, &error); 424 if (code != 0) 425 goto cleanup; 426 kdc_code = error->error; 427 krb5_free_error(ctx->k5c, error); 428 if (kdc_code == KRB_ERR_RESPONSE_TOO_BIG) { 429 krb5_free_data_contents(ctx->k5c, &reply); 430 reply = empty_data(); 431 continue; 432 } 433 } 434 break; 435 } 436 437 if (code == KRB5_KDC_UNREACH || code == KRB5_REALM_UNKNOWN) { 438 protocol_err = (code == KRB5_KDC_UNREACH) ? 439 KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE : 440 KRB_AP_ERR_IAKERB_KDC_NOT_FOUND; 441 code = iakerb_mk_error(ctx->k5c, verifier_cred, protocol_err, &reply); 442 if (code != 0) 443 goto cleanup; 444 } else if (code != 0) 445 goto cleanup; 446 447 code = iakerb_make_token(ctx, &realm, NULL, &reply, output_token); 448 449 cleanup: 450 if (code != 0) 451 gss_release_buffer(&tmp, output_token); 452 /* request is a pointer into input_token, no need to free */ 453 krb5_free_data_contents(ctx->k5c, &realm); 454 krb5_free_data_contents(ctx->k5c, &reply); 455 456 return code; 457 } 458 459 /* 460 * Initialise the krb5_init_creds context for the IAKERB context 461 */ 462 static krb5_error_code 463 iakerb_init_creds_ctx(iakerb_ctx_id_t ctx, 464 krb5_gss_cred_id_t cred, 465 OM_uint32 time_req) 466 { 467 krb5_error_code code; 468 469 if (cred->iakerb_mech == 0) { 470 code = EINVAL; 471 goto cleanup; 472 } 473 474 assert(cred->name != NULL); 475 assert(cred->name->princ != NULL); 476 477 code = krb5_get_init_creds_opt_alloc(ctx->k5c, &ctx->gic_opts); 478 if (code != 0) 479 goto cleanup; 480 481 if (time_req != 0 && time_req != GSS_C_INDEFINITE) 482 krb5_get_init_creds_opt_set_tkt_life(ctx->gic_opts, time_req); 483 484 code = krb5_get_init_creds_opt_set_out_ccache(ctx->k5c, ctx->gic_opts, 485 cred->ccache); 486 if (code != 0) 487 goto cleanup; 488 489 code = krb5_init_creds_init(ctx->k5c, 490 cred->name->princ, 491 NULL, /* prompter */ 492 NULL, /* data */ 493 0, /* start_time */ 494 ctx->gic_opts, 495 &ctx->icc); 496 if (code != 0) 497 goto cleanup; 498 499 if (cred->password != NULL) { 500 code = krb5_init_creds_set_password(ctx->k5c, ctx->icc, 501 cred->password); 502 } else if (cred->client_keytab != NULL) { 503 code = krb5_init_creds_set_keytab(ctx->k5c, ctx->icc, 504 cred->client_keytab); 505 } else { 506 code = KRB5_KT_NOTFOUND; 507 } 508 if (code != 0) 509 goto cleanup; 510 511 cleanup: 512 return code; 513 } 514 515 /* 516 * Initialise the krb5_tkt_creds context for the IAKERB context 517 */ 518 static krb5_error_code 519 iakerb_tkt_creds_ctx(iakerb_ctx_id_t ctx, 520 krb5_gss_cred_id_t cred, 521 krb5_gss_name_t name, 522 OM_uint32 time_req) 523 524 { 525 krb5_error_code code; 526 krb5_creds creds; 527 krb5_timestamp now; 528 529 assert(cred->name != NULL); 530 assert(cred->name->princ != NULL); 531 532 memset(&creds, 0, sizeof(creds)); 533 534 creds.client = cred->name->princ; 535 creds.server = name->princ; 536 537 if (time_req != 0 && time_req != GSS_C_INDEFINITE) { 538 code = krb5_timeofday(ctx->k5c, &now); 539 if (code != 0) 540 goto cleanup; 541 542 creds.times.endtime = ts_incr(now, time_req); 543 } 544 545 if (cred->name->ad_context != NULL) { 546 code = krb5_authdata_export_authdata(ctx->k5c, 547 cred->name->ad_context, 548 AD_USAGE_TGS_REQ, 549 &creds.authdata); 550 if (code != 0) 551 goto cleanup; 552 } 553 554 code = krb5_tkt_creds_init(ctx->k5c, cred->ccache, &creds, 0, &ctx->tcc); 555 if (code != 0) 556 goto cleanup; 557 558 cleanup: 559 krb5_free_authdata(ctx->k5c, creds.authdata); 560 561 return code; 562 } 563 564 /* 565 * Parse the IAKERB token in input_token and process the KDC 566 * response. 567 * 568 * Emit the next KDC request, if any, in output_token. 569 */ 570 static krb5_error_code 571 iakerb_initiator_step(iakerb_ctx_id_t ctx, 572 krb5_gss_cred_id_t cred, 573 krb5_gss_name_t name, 574 OM_uint32 time_req, 575 const gss_buffer_t input_token, 576 gss_buffer_t output_token) 577 { 578 krb5_error_code code = 0; 579 krb5_data in = empty_data(), out = empty_data(); 580 krb5_data realm = empty_data(), server_realm = empty_data(); 581 krb5_data *cookie = NULL; 582 OM_uint32 tmp; 583 unsigned int flags = 0; 584 krb5_ticket_times times; 585 krb5_boolean first_token; 586 587 output_token->length = 0; 588 output_token->value = NULL; 589 590 first_token = (input_token == GSS_C_NO_BUFFER || input_token->length == 0); 591 if (!first_token) { 592 code = iakerb_parse_token(ctx, input_token, &server_realm, &cookie, 593 &in); 594 if (code != 0) 595 goto cleanup; 596 597 code = iakerb_save_token(ctx, input_token); 598 if (code != 0) 599 goto cleanup; 600 601 if (krb5_is_krb_error(&in)) { 602 code = iakerb_rd_error(ctx->k5c, &in); 603 if (code == KRB5KRB_AP_ERR_IAKERB_KDC_NOT_FOUND && 604 ctx->state == IAKERB_REALM_DISCOVERY) { 605 save_error_string(code, _("The IAKERB proxy could not " 606 "determine its realm")); 607 } 608 if (code == KRB5KRB_AP_ERR_IAKERB_KDC_NOT_FOUND || 609 code == KRB5KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE) 610 goto cleanup; 611 code = 0; 612 } 613 } 614 615 switch (ctx->state) { 616 case IAKERB_REALM_DISCOVERY: 617 if (first_token) { 618 /* Send the discovery request. */ 619 code = iakerb_make_token(ctx, &realm, cookie, &out, output_token); 620 goto cleanup; 621 } 622 623 /* The acceptor should have sent us its realm. */ 624 if (server_realm.length == 0) { 625 code = KRB5_BAD_MSIZE; 626 goto cleanup; 627 } 628 629 /* Steal the received server realm for the client principal. */ 630 krb5_free_data_contents(ctx->k5c, &cred->name->princ->realm); 631 cred->name->princ->realm = server_realm; 632 server_realm = empty_data(); 633 634 /* Done with realm discovery; fall through to AS request. */ 635 case IAKERB_AS_REQ: 636 if (ctx->icc == NULL) { 637 code = iakerb_init_creds_ctx(ctx, cred, time_req); 638 if (code != 0) 639 goto cleanup; 640 } 641 642 code = krb5_init_creds_step(ctx->k5c, ctx->icc, &in, &out, &realm, 643 &flags); 644 if (code != 0) { 645 if (cred->have_tgt) { 646 /* We were trying to refresh; keep going with current creds. */ 647 ctx->state = IAKERB_TGS_REQ; 648 krb5_clear_error_message(ctx->k5c); 649 } else { 650 goto cleanup; 651 } 652 } else if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) { 653 krb5_init_creds_get_times(ctx->k5c, ctx->icc, ×); 654 kg_cred_set_initial_refresh(ctx->k5c, cred, ×); 655 cred->expire = times.endtime; 656 657 krb5_init_creds_free(ctx->k5c, ctx->icc); 658 ctx->icc = NULL; 659 660 ctx->state = IAKERB_TGS_REQ; 661 } else 662 break; 663 in = empty_data(); 664 /* Done with AS request; fall through to TGS request. */ 665 case IAKERB_TGS_REQ: 666 if (ctx->tcc == NULL) { 667 code = iakerb_tkt_creds_ctx(ctx, cred, name, time_req); 668 if (code != 0) 669 goto cleanup; 670 } 671 672 code = krb5_tkt_creds_step(ctx->k5c, ctx->tcc, &in, &out, &realm, 673 &flags); 674 if (code != 0) 675 goto cleanup; 676 if (!(flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE)) { 677 krb5_tkt_creds_get_times(ctx->k5c, ctx->tcc, ×); 678 cred->expire = times.endtime; 679 680 krb5_tkt_creds_free(ctx->k5c, ctx->tcc); 681 ctx->tcc = NULL; 682 683 ctx->state = IAKERB_AP_REQ; 684 } else 685 break; 686 /* Done with TGS request; fall through to AP request. */ 687 case IAKERB_AP_REQ: 688 break; 689 } 690 691 if (out.length != 0) { 692 assert(ctx->state != IAKERB_AP_REQ); 693 code = iakerb_make_token(ctx, &realm, cookie, &out, output_token); 694 } 695 696 cleanup: 697 if (code != 0) 698 gss_release_buffer(&tmp, output_token); 699 krb5_free_data(ctx->k5c, cookie); 700 krb5_free_data_contents(ctx->k5c, &out); 701 krb5_free_data_contents(ctx->k5c, &server_realm); 702 krb5_free_data_contents(ctx->k5c, &realm); 703 704 return code; 705 } 706 707 /* 708 * Determine the starting IAKERB state for a context. If we already 709 * have a ticket, we may not need to do IAKERB at all. 710 */ 711 static krb5_error_code 712 iakerb_get_initial_state(iakerb_ctx_id_t ctx, 713 krb5_gss_cred_id_t cred, 714 krb5_gss_name_t target, 715 OM_uint32 time_req, 716 enum iakerb_state *state) 717 { 718 krb5_creds in_creds, *out_creds = NULL; 719 krb5_error_code code; 720 721 if (cred->name->princ->realm.length == 0) { 722 *state = IAKERB_REALM_DISCOVERY; 723 return 0; 724 } 725 726 memset(&in_creds, 0, sizeof(in_creds)); 727 728 in_creds.client = cred->name->princ; 729 in_creds.server = target->princ; 730 731 if (cred->name->ad_context != NULL) { 732 code = krb5_authdata_export_authdata(ctx->k5c, 733 cred->name->ad_context, 734 AD_USAGE_TGS_REQ, 735 &in_creds.authdata); 736 if (code != 0) 737 goto cleanup; 738 } 739 740 if (time_req != 0 && time_req != GSS_C_INDEFINITE) { 741 krb5_timestamp now; 742 743 code = krb5_timeofday(ctx->k5c, &now); 744 if (code != 0) 745 goto cleanup; 746 747 in_creds.times.endtime = ts_incr(now, time_req); 748 } 749 750 /* Make an AS request if we have no creds or it's time to refresh them. */ 751 if (cred->expire == 0 || kg_cred_time_to_refresh(ctx->k5c, cred)) { 752 *state = IAKERB_AS_REQ; 753 code = 0; 754 goto cleanup; 755 } 756 757 code = krb5_get_credentials(ctx->k5c, KRB5_GC_CACHED, cred->ccache, 758 &in_creds, &out_creds); 759 if (code == KRB5_CC_NOTFOUND || code == KRB5_CC_NOT_KTYPE) { 760 *state = cred->have_tgt ? IAKERB_TGS_REQ : IAKERB_AS_REQ; 761 code = 0; 762 } else if (code == 0) { 763 *state = IAKERB_AP_REQ; 764 krb5_free_creds(ctx->k5c, out_creds); 765 } 766 767 cleanup: 768 krb5_free_authdata(ctx->k5c, in_creds.authdata); 769 770 return code; 771 } 772 773 /* 774 * Allocate and initialise an IAKERB context 775 */ 776 static krb5_error_code 777 iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate) 778 { 779 iakerb_ctx_id_t ctx; 780 krb5_error_code code; 781 782 *pctx = NULL; 783 784 ctx = k5alloc(sizeof(*ctx), &code); 785 if (ctx == NULL) 786 goto cleanup; 787 ctx->defcred = GSS_C_NO_CREDENTIAL; 788 ctx->magic = KG_IAKERB_CONTEXT; 789 ctx->state = IAKERB_AS_REQ; 790 ctx->count = 0; 791 ctx->initiate = initiate; 792 ctx->established = 0; 793 794 code = krb5_gss_init_context(&ctx->k5c); 795 if (code != 0) 796 goto cleanup; 797 798 *pctx = ctx; 799 800 cleanup: 801 if (code != 0) 802 iakerb_release_context(ctx); 803 804 return code; 805 } 806 807 OM_uint32 KRB5_CALLCONV 808 iakerb_gss_delete_sec_context(OM_uint32 *minor_status, 809 gss_ctx_id_t *context_handle, 810 gss_buffer_t output_token) 811 { 812 iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle; 813 814 if (output_token != GSS_C_NO_BUFFER) { 815 output_token->length = 0; 816 output_token->value = NULL; 817 } 818 819 *minor_status = 0; 820 *context_handle = GSS_C_NO_CONTEXT; 821 iakerb_release_context(iakerb_ctx); 822 823 return GSS_S_COMPLETE; 824 } 825 826 static krb5_boolean 827 iakerb_is_iakerb_token(const gss_buffer_t token) 828 { 829 struct k5input in; 830 831 k5_input_init(&in, token->value, token->length); 832 return g_verify_token_header(&in, gss_mech_iakerb) && 833 k5_input_get_uint16_be(&in) == IAKERB_TOK_PROXY; 834 } 835 836 static void 837 iakerb_make_exts(iakerb_ctx_id_t ctx, krb5_gss_ctx_ext_rec *exts) 838 { 839 memset(exts, 0, sizeof(*exts)); 840 841 if (ctx->conv.length != 0) 842 exts->iakerb.conv = &ctx->conv; 843 } 844 845 OM_uint32 KRB5_CALLCONV 846 iakerb_gss_accept_sec_context(OM_uint32 *minor_status, 847 gss_ctx_id_t *context_handle, 848 gss_cred_id_t verifier_cred_handle, 849 gss_buffer_t input_token, 850 gss_channel_bindings_t input_chan_bindings, 851 gss_name_t *src_name, 852 gss_OID *mech_type, 853 gss_buffer_t output_token, 854 OM_uint32 *ret_flags, 855 OM_uint32 *time_rec, 856 gss_cred_id_t *delegated_cred_handle) 857 { 858 OM_uint32 major_status = GSS_S_FAILURE; 859 OM_uint32 code; 860 iakerb_ctx_id_t ctx; 861 krb5_boolean first_token = (*context_handle == GSS_C_NO_CONTEXT); 862 863 if (first_token) { 864 code = iakerb_alloc_context(&ctx, 0); 865 if (code != 0) 866 goto cleanup; 867 868 } else 869 ctx = (iakerb_ctx_id_t)*context_handle; 870 871 if (iakerb_is_iakerb_token(input_token)) { 872 if (ctx->gssc != GSS_C_NO_CONTEXT) { 873 /* We shouldn't get an IAKERB token now. */ 874 code = G_WRONG_TOKID; 875 major_status = GSS_S_DEFECTIVE_TOKEN; 876 goto cleanup; 877 } 878 code = iakerb_acceptor_step(ctx, verifier_cred_handle, input_token, 879 output_token); 880 if (code == (OM_uint32)KRB5_BAD_MSIZE) 881 major_status = GSS_S_DEFECTIVE_TOKEN; 882 if (code != 0) 883 goto cleanup; 884 if (src_name != NULL) 885 *src_name = GSS_C_NO_NAME; 886 if (ret_flags != NULL) 887 *ret_flags = 0; 888 if (time_rec != NULL) 889 *time_rec = 0; 890 if (delegated_cred_handle != NULL) 891 *delegated_cred_handle = GSS_C_NO_CREDENTIAL; 892 major_status = GSS_S_CONTINUE_NEEDED; 893 } else { 894 krb5_gss_ctx_ext_rec exts; 895 896 iakerb_make_exts(ctx, &exts); 897 898 major_status = krb5_gss_accept_sec_context_ext(&code, 899 &ctx->gssc, 900 verifier_cred_handle, 901 input_token, 902 input_chan_bindings, 903 src_name, 904 NULL, 905 output_token, 906 ret_flags, 907 time_rec, 908 delegated_cred_handle, 909 &exts); 910 if (major_status == GSS_S_COMPLETE) 911 ctx->established = 1; 912 } 913 914 if (mech_type != NULL) 915 *mech_type = gss_mech_iakerb; 916 917 cleanup: 918 if (first_token) { 919 if (GSS_ERROR(major_status)) { 920 iakerb_release_context(ctx); 921 *context_handle = GSS_C_NO_CONTEXT; 922 } else { 923 *context_handle = (gss_ctx_id_t)ctx; 924 } 925 } 926 927 *minor_status = code; 928 return major_status; 929 } 930 931 OM_uint32 KRB5_CALLCONV 932 iakerb_gss_init_sec_context(OM_uint32 *minor_status, 933 gss_cred_id_t claimant_cred_handle, 934 gss_ctx_id_t *context_handle, 935 gss_name_t target_name, 936 gss_OID mech_type, 937 OM_uint32 req_flags, 938 OM_uint32 time_req, 939 gss_channel_bindings_t input_chan_bindings, 940 gss_buffer_t input_token, 941 gss_OID *actual_mech_type, 942 gss_buffer_t output_token, 943 OM_uint32 *ret_flags, 944 OM_uint32 *time_rec) 945 { 946 OM_uint32 major_status = GSS_S_FAILURE; 947 krb5_error_code code; 948 iakerb_ctx_id_t ctx; 949 krb5_gss_cred_id_t kcred; 950 krb5_gss_name_t kname; 951 krb5_boolean cred_locked = FALSE; 952 int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT); 953 954 if (initialContextToken) { 955 code = iakerb_alloc_context(&ctx, 1); 956 if (code != 0) { 957 *minor_status = code; 958 goto cleanup; 959 } 960 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { 961 major_status = iakerb_gss_acquire_cred(minor_status, NULL, 962 GSS_C_INDEFINITE, 963 GSS_C_NULL_OID_SET, 964 GSS_C_INITIATE, 965 &ctx->defcred, NULL, NULL); 966 if (GSS_ERROR(major_status)) 967 goto cleanup; 968 claimant_cred_handle = ctx->defcred; 969 } 970 } else { 971 ctx = (iakerb_ctx_id_t)*context_handle; 972 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) 973 claimant_cred_handle = ctx->defcred; 974 } 975 976 kname = (krb5_gss_name_t)target_name; 977 978 major_status = kg_cred_resolve(minor_status, ctx->k5c, 979 claimant_cred_handle, target_name); 980 if (GSS_ERROR(major_status)) 981 goto cleanup; 982 cred_locked = TRUE; 983 kcred = (krb5_gss_cred_id_t)claimant_cred_handle; 984 985 major_status = GSS_S_FAILURE; 986 987 if (initialContextToken) { 988 code = iakerb_get_initial_state(ctx, kcred, kname, time_req, 989 &ctx->state); 990 if (code != 0) { 991 *minor_status = code; 992 goto cleanup; 993 } 994 *context_handle = (gss_ctx_id_t)ctx; 995 } 996 997 if (ctx->state != IAKERB_AP_REQ) { 998 /* We need to do IAKERB. */ 999 code = iakerb_initiator_step(ctx, 1000 kcred, 1001 kname, 1002 time_req, 1003 input_token, 1004 output_token); 1005 if (code == KRB5_BAD_MSIZE) 1006 major_status = GSS_S_DEFECTIVE_TOKEN; 1007 if (code != 0) { 1008 *minor_status = code; 1009 goto cleanup; 1010 } 1011 } 1012 1013 if (ctx->state == IAKERB_AP_REQ) { 1014 krb5_gss_ctx_ext_rec exts; 1015 1016 if (cred_locked) { 1017 k5_mutex_unlock(&kcred->lock); 1018 cred_locked = FALSE; 1019 } 1020 1021 iakerb_make_exts(ctx, &exts); 1022 1023 if (ctx->gssc == GSS_C_NO_CONTEXT) 1024 input_token = GSS_C_NO_BUFFER; 1025 1026 /* IAKERB is finished, or we skipped to Kerberos directly. */ 1027 major_status = krb5_gss_init_sec_context_ext(minor_status, 1028 (gss_cred_id_t) kcred, 1029 &ctx->gssc, 1030 target_name, 1031 (gss_OID)gss_mech_iakerb, 1032 req_flags, 1033 time_req, 1034 input_chan_bindings, 1035 input_token, 1036 NULL, 1037 output_token, 1038 ret_flags, 1039 time_rec, 1040 &exts); 1041 if (major_status == GSS_S_COMPLETE) 1042 ctx->established = 1; 1043 } else { 1044 if (ret_flags != NULL) 1045 *ret_flags = 0; 1046 if (time_rec != NULL) 1047 *time_rec = 0; 1048 major_status = GSS_S_CONTINUE_NEEDED; 1049 } 1050 1051 if (actual_mech_type != NULL) 1052 *actual_mech_type = gss_mech_iakerb; 1053 1054 cleanup: 1055 if (cred_locked) 1056 k5_mutex_unlock(&kcred->lock); 1057 if (initialContextToken && GSS_ERROR(major_status)) { 1058 iakerb_release_context(ctx); 1059 *context_handle = GSS_C_NO_CONTEXT; 1060 } 1061 1062 return major_status; 1063 } 1064 1065 OM_uint32 KRB5_CALLCONV 1066 iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1067 gss_buffer_t input_message_buffer, 1068 gss_buffer_t output_message_buffer, int *conf_state, 1069 gss_qop_t *qop_state) 1070 { 1071 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1072 1073 if (ctx->gssc == GSS_C_NO_CONTEXT) 1074 return GSS_S_NO_CONTEXT; 1075 1076 return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer, 1077 output_message_buffer, conf_state, qop_state); 1078 } 1079 1080 OM_uint32 KRB5_CALLCONV 1081 iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1082 int conf_req_flag, gss_qop_t qop_req, 1083 gss_buffer_t input_message_buffer, int *conf_state, 1084 gss_buffer_t output_message_buffer) 1085 { 1086 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1087 1088 if (ctx->gssc == GSS_C_NO_CONTEXT) 1089 return GSS_S_NO_CONTEXT; 1090 1091 return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req, 1092 input_message_buffer, conf_state, 1093 output_message_buffer); 1094 } 1095 1096 OM_uint32 KRB5_CALLCONV 1097 iakerb_gss_process_context_token(OM_uint32 *minor_status, 1098 const gss_ctx_id_t context_handle, 1099 const gss_buffer_t token_buffer) 1100 { 1101 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1102 1103 if (ctx->gssc == GSS_C_NO_CONTEXT) 1104 return GSS_S_DEFECTIVE_TOKEN; 1105 1106 return krb5_gss_process_context_token(minor_status, ctx->gssc, 1107 token_buffer); 1108 } 1109 1110 OM_uint32 KRB5_CALLCONV 1111 iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1112 OM_uint32 *time_rec) 1113 { 1114 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1115 1116 if (ctx->gssc == GSS_C_NO_CONTEXT) 1117 return GSS_S_NO_CONTEXT; 1118 1119 return krb5_gss_context_time(minor_status, ctx->gssc, time_rec); 1120 } 1121 1122 #ifndef LEAN_CLIENT 1123 1124 OM_uint32 KRB5_CALLCONV 1125 iakerb_gss_export_sec_context(OM_uint32 *minor_status, 1126 gss_ctx_id_t *context_handle, 1127 gss_buffer_t interprocess_token) 1128 { 1129 OM_uint32 maj; 1130 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle; 1131 1132 /* We don't currently support exporting partially established contexts. */ 1133 if (!ctx->established) 1134 return GSS_S_UNAVAILABLE; 1135 1136 maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc, 1137 interprocess_token); 1138 if (ctx->gssc == GSS_C_NO_CONTEXT) { 1139 iakerb_release_context(ctx); 1140 *context_handle = GSS_C_NO_CONTEXT; 1141 } 1142 return maj; 1143 } 1144 1145 OM_uint32 KRB5_CALLCONV 1146 iakerb_gss_import_sec_context(OM_uint32 *minor_status, 1147 gss_buffer_t interprocess_token, 1148 gss_ctx_id_t *context_handle) 1149 { 1150 OM_uint32 maj, tmpmin; 1151 krb5_error_code code; 1152 gss_ctx_id_t gssc; 1153 krb5_gss_ctx_id_t kctx; 1154 iakerb_ctx_id_t ctx; 1155 1156 maj = krb5_gss_import_sec_context(minor_status, interprocess_token, &gssc); 1157 if (maj != GSS_S_COMPLETE) 1158 return maj; 1159 kctx = (krb5_gss_ctx_id_t)gssc; 1160 1161 if (!kctx->established) { 1162 /* We don't currently support importing partially established 1163 * contexts. */ 1164 krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER); 1165 return GSS_S_FAILURE; 1166 } 1167 1168 code = iakerb_alloc_context(&ctx, kctx->initiate); 1169 if (code != 0) { 1170 krb5_gss_delete_sec_context(&tmpmin, &gssc, GSS_C_NO_BUFFER); 1171 *minor_status = code; 1172 return GSS_S_FAILURE; 1173 } 1174 1175 ctx->gssc = gssc; 1176 ctx->established = 1; 1177 *context_handle = (gss_ctx_id_t)ctx; 1178 return GSS_S_COMPLETE; 1179 } 1180 #endif /* LEAN_CLIENT */ 1181 1182 OM_uint32 KRB5_CALLCONV 1183 iakerb_gss_inquire_context(OM_uint32 *minor_status, 1184 gss_ctx_id_t context_handle, gss_name_t *src_name, 1185 gss_name_t *targ_name, OM_uint32 *lifetime_rec, 1186 gss_OID *mech_type, OM_uint32 *ctx_flags, 1187 int *initiate, int *opened) 1188 { 1189 OM_uint32 ret; 1190 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1191 1192 if (src_name != NULL) 1193 *src_name = GSS_C_NO_NAME; 1194 if (targ_name != NULL) 1195 *targ_name = GSS_C_NO_NAME; 1196 if (lifetime_rec != NULL) 1197 *lifetime_rec = 0; 1198 if (mech_type != NULL) 1199 *mech_type = (gss_OID)gss_mech_iakerb; 1200 if (ctx_flags != NULL) 1201 *ctx_flags = 0; 1202 if (initiate != NULL) 1203 *initiate = ctx->initiate; 1204 if (opened != NULL) 1205 *opened = ctx->established; 1206 1207 if (ctx->gssc == GSS_C_NO_CONTEXT) 1208 return GSS_S_COMPLETE; 1209 1210 ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name, 1211 targ_name, lifetime_rec, mech_type, 1212 ctx_flags, initiate, opened); 1213 1214 if (!ctx->established) { 1215 /* Report IAKERB as the mech OID until the context is established. */ 1216 if (mech_type != NULL) 1217 *mech_type = (gss_OID)gss_mech_iakerb; 1218 1219 /* We don't support exporting partially-established contexts. */ 1220 if (ctx_flags != NULL) 1221 *ctx_flags &= ~GSS_C_TRANS_FLAG; 1222 } 1223 1224 return ret; 1225 } 1226 1227 OM_uint32 KRB5_CALLCONV 1228 iakerb_gss_wrap_size_limit(OM_uint32 *minor_status, 1229 gss_ctx_id_t context_handle, int conf_req_flag, 1230 gss_qop_t qop_req, OM_uint32 req_output_size, 1231 OM_uint32 *max_input_size) 1232 { 1233 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1234 1235 if (ctx->gssc == GSS_C_NO_CONTEXT) 1236 return GSS_S_NO_CONTEXT; 1237 1238 return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag, 1239 qop_req, req_output_size, max_input_size); 1240 } 1241 1242 OM_uint32 KRB5_CALLCONV 1243 iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1244 gss_qop_t qop_req, gss_buffer_t message_buffer, 1245 gss_buffer_t message_token) 1246 { 1247 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1248 1249 if (ctx->gssc == GSS_C_NO_CONTEXT) 1250 return GSS_S_NO_CONTEXT; 1251 1252 return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer, 1253 message_token); 1254 } 1255 1256 OM_uint32 KRB5_CALLCONV 1257 iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1258 gss_buffer_t msg_buffer, gss_buffer_t token_buffer, 1259 gss_qop_t *qop_state) 1260 { 1261 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1262 1263 if (ctx->gssc == GSS_C_NO_CONTEXT) 1264 return GSS_S_NO_CONTEXT; 1265 1266 return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer, 1267 token_buffer, qop_state); 1268 } 1269 1270 OM_uint32 KRB5_CALLCONV 1271 iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status, 1272 const gss_ctx_id_t context_handle, 1273 const gss_OID desired_object, 1274 gss_buffer_set_t *data_set) 1275 { 1276 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1277 1278 if (ctx->gssc == GSS_C_NO_CONTEXT) 1279 return GSS_S_UNAVAILABLE; 1280 1281 return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc, 1282 desired_object, data_set); 1283 } 1284 1285 OM_uint32 KRB5_CALLCONV 1286 iakerb_gss_set_sec_context_option(OM_uint32 *minor_status, 1287 gss_ctx_id_t *context_handle, 1288 const gss_OID desired_object, 1289 const gss_buffer_t value) 1290 { 1291 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle; 1292 1293 if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT) 1294 return GSS_S_UNAVAILABLE; 1295 1296 return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc, 1297 desired_object, value); 1298 } 1299 1300 OM_uint32 KRB5_CALLCONV 1301 iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1302 int conf_req_flag, gss_qop_t qop_req, int *conf_state, 1303 gss_iov_buffer_desc *iov, int iov_count) 1304 { 1305 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1306 1307 if (ctx->gssc == GSS_C_NO_CONTEXT) 1308 return GSS_S_NO_CONTEXT; 1309 1310 return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req, 1311 conf_state, iov, iov_count); 1312 } 1313 1314 OM_uint32 KRB5_CALLCONV 1315 iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1316 int *conf_state, gss_qop_t *qop_state, 1317 gss_iov_buffer_desc *iov, int iov_count) 1318 { 1319 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1320 1321 if (ctx->gssc == GSS_C_NO_CONTEXT) 1322 return GSS_S_NO_CONTEXT; 1323 1324 return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state, 1325 iov, iov_count); 1326 } 1327 1328 OM_uint32 KRB5_CALLCONV 1329 iakerb_gss_wrap_iov_length(OM_uint32 *minor_status, 1330 gss_ctx_id_t context_handle, int conf_req_flag, 1331 gss_qop_t qop_req, int *conf_state, 1332 gss_iov_buffer_desc *iov, int iov_count) 1333 { 1334 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1335 1336 if (ctx->gssc == GSS_C_NO_CONTEXT) 1337 return GSS_S_NO_CONTEXT; 1338 1339 return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag, 1340 qop_req, conf_state, iov, iov_count); 1341 } 1342 1343 OM_uint32 KRB5_CALLCONV 1344 iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1345 int prf_key, const gss_buffer_t prf_in, 1346 ssize_t desired_output_len, gss_buffer_t prf_out) 1347 { 1348 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1349 1350 if (ctx->gssc == GSS_C_NO_CONTEXT) 1351 return GSS_S_NO_CONTEXT; 1352 1353 return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in, 1354 desired_output_len, prf_out); 1355 } 1356 1357 OM_uint32 KRB5_CALLCONV 1358 iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1359 gss_qop_t qop_req, gss_iov_buffer_desc *iov, 1360 int iov_count) 1361 { 1362 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1363 1364 if (ctx->gssc == GSS_C_NO_CONTEXT) 1365 return GSS_S_NO_CONTEXT; 1366 1367 return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov, 1368 iov_count); 1369 } 1370 1371 OM_uint32 KRB5_CALLCONV 1372 iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, 1373 gss_qop_t *qop_state, gss_iov_buffer_desc *iov, 1374 int iov_count) 1375 { 1376 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1377 1378 if (ctx->gssc == GSS_C_NO_CONTEXT) 1379 return GSS_S_NO_CONTEXT; 1380 1381 return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov, 1382 iov_count); 1383 } 1384 1385 OM_uint32 KRB5_CALLCONV 1386 iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status, 1387 gss_ctx_id_t context_handle, gss_qop_t qop_req, 1388 gss_iov_buffer_desc *iov, int iov_count) 1389 { 1390 iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle; 1391 1392 if (ctx->gssc == GSS_C_NO_CONTEXT) 1393 return GSS_S_NO_CONTEXT; 1394 1395 return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov, 1396 iov_count); 1397 } 1398