1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright 2000 by the Massachusetts Institute of Technology. 10 * All Rights Reserved. 11 * 12 * Export of this software from the United States of America may 13 * require a specific license from the United States Government. 14 * It is the responsibility of any person or organization contemplating 15 * export to obtain such a license before exporting. 16 * 17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 18 * distribute this software and its documentation for any purpose and 19 * without fee is hereby granted, provided that the above copyright 20 * notice appear in all copies and that both that copyright notice and 21 * this permission notice appear in supporting documentation, and that 22 * the name of M.I.T. not be used in advertising or publicity pertaining 23 * to distribution of the software without specific, written prior 24 * permission. Furthermore if you modify this software you must label 25 * your software as modified software and not distribute it in such a 26 * fashion that it might be confused with the original M.I.T. software. 27 * M.I.T. makes no representations about the suitability of 28 * this software for any purpose. It is provided "as is" without express 29 * or implied warranty. 30 * 31 */ 32 /* 33 * Copyright 1993 by OpenVision Technologies, Inc. 34 * 35 * Permission to use, copy, modify, distribute, and sell this software 36 * and its documentation for any purpose is hereby granted without fee, 37 * provided that the above copyright notice appears in all copies and 38 * that both that copyright notice and this permission notice appear in 39 * supporting documentation, and that the name of OpenVision not be used 40 * in advertising or publicity pertaining to distribution of the software 41 * without specific, written prior permission. OpenVision makes no 42 * representations about the suitability of this software for any 43 * purpose. It is provided "as is" without express or implied warranty. 44 * 45 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 46 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 47 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 48 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 49 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 50 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 51 * PERFORMANCE OF THIS SOFTWARE. 52 */ 53 54 /* 55 * Copyright (C) 1998 by the FundsXpress, INC. 56 * 57 * All rights reserved. 58 * 59 * Export of this software from the United States of America may require 60 * a specific license from the United States Government. It is the 61 * responsibility of any person or organization contemplating export to 62 * obtain such a license before exporting. 63 * 64 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 65 * distribute this software and its documentation for any purpose and 66 * without fee is hereby granted, provided that the above copyright 67 * notice appear in all copies and that both that copyright notice and 68 * this permission notice appear in supporting documentation, and that 69 * the name of FundsXpress. not be used in advertising or publicity pertaining 70 * to distribution of the software without specific, written prior 71 * permission. FundsXpress makes no representations about the suitability of 72 * this software for any purpose. It is provided "as is" without express 73 * or implied warranty. 74 * 75 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 76 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 77 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 78 */ 79 80 #include <gssapiP_krb5.h> 81 #include <k5-int.h> 82 #include <memory.h> 83 #include <stdlib.h> 84 #include <syslog.h> 85 #include <assert.h> 86 #define ROOT_UID 0 87 #define KRB5_DEFAULT_LIFE 60*60*10 88 #define CACHE_FILENAME_LEN 35 89 90 /* 91 * $Id: init_sec_context.c,v 1.51.2.7 2000/06/28 02:48:22 tlyu Exp $ 92 */ 93 94 extern int 95 safechown(const char *src, uid_t uid, gid_t gid, int mode); 96 97 /* 98 * XXX This is for debugging only!!! Should become a real bitfield 99 * at some point 100 */ 101 int krb5_gss_dbg_client_expcreds = 0; 102 103 /* 104 * Common code which fetches the correct krb5 credentials from the 105 * ccache. 106 */ 107 static krb5_error_code get_credentials(context, cred, server, now, 108 endtime, out_creds) 109 krb5_context context; 110 krb5_gss_cred_id_t cred; 111 krb5_principal server; 112 krb5_timestamp now; 113 krb5_timestamp endtime; 114 krb5_creds **out_creds; 115 { 116 krb5_error_code code; 117 krb5_creds in_creds; 118 119 KRB5_LOG0(KRB5_INFO, "get_credentials() start\n"); 120 121 memset((char *) &in_creds, 0, sizeof(krb5_creds)); 122 123 if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client))) 124 goto cleanup; 125 if ((code = krb5_copy_principal(context, server, &in_creds.server))) 126 goto cleanup; 127 in_creds.times.endtime = endtime; 128 129 in_creds.keyblock.enctype = 0; 130 131 code = krb5_get_credentials(context, 0, cred->ccache, 132 &in_creds, out_creds); 133 if (code) 134 goto cleanup; 135 136 /* 137 * Enforce a stricter limit (without timeskew forgiveness at the 138 * boundaries) because accept_sec_context code is also similarly 139 * non-forgiving. 140 */ 141 if (!krb5_gss_dbg_client_expcreds && *out_creds != NULL && 142 (*out_creds)->times.endtime < now) { 143 code = KRB5KRB_AP_ERR_TKT_EXPIRED; 144 goto cleanup; 145 } 146 147 cleanup: 148 if (in_creds.client) 149 krb5_free_principal(context, in_creds.client); 150 if (in_creds.server) 151 krb5_free_principal(context, in_creds.server); 152 153 KRB5_LOG(KRB5_INFO, "get_credentials() end, code = %d\n", code); 154 155 return code; 156 } 157 158 struct gss_checksum_data { 159 krb5_gss_ctx_id_rec *ctx; 160 krb5_gss_cred_id_t cred; 161 krb5_checksum md5; 162 krb5_data checksum_data; 163 }; 164 165 static krb5_error_code KRB5_CALLCONV 166 make_gss_checksum (krb5_context context, krb5_auth_context auth_context, 167 void *cksum_data, krb5_data **out) 168 { 169 krb5_error_code code; 170 krb5_int32 con_flags; 171 unsigned char *ptr; 172 struct gss_checksum_data *data = cksum_data; 173 krb5_data credmsg; 174 int junk; 175 176 data->checksum_data.data = 0; 177 credmsg.data = 0; 178 /* build the checksum field */ 179 180 if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) { 181 /* first get KRB_CRED message, so we know its length */ 182 183 /* clear the time check flag that was set in krb5_auth_con_init() */ 184 krb5_auth_con_getflags(context, auth_context, &con_flags); 185 krb5_auth_con_setflags(context, auth_context, 186 con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME); 187 188 code = krb5_fwd_tgt_creds(context, auth_context, 0, 189 data->cred->princ, data->ctx->there, 190 data->cred->ccache, 1, 191 &credmsg); 192 193 /* turn KRB5_AUTH_CONTEXT_DO_TIME back on */ 194 krb5_auth_con_setflags(context, auth_context, con_flags); 195 196 if (code) { 197 /* don't fail here; just don't accept/do the delegation 198 request */ 199 data->ctx->gss_flags &= ~GSS_C_DELEG_FLAG; 200 201 data->checksum_data.length = 24; 202 } else { 203 if (credmsg.length+28 > KRB5_INT16_MAX) { 204 krb5_free_data_contents(context, &credmsg); 205 return(KRB5KRB_ERR_FIELD_TOOLONG); 206 } 207 208 data->checksum_data.length = 28+credmsg.length; 209 } 210 } else { 211 data->checksum_data.length = 24; 212 } 213 #ifdef CFX_EXERCISE 214 if (data->ctx->auth_context->keyblock->enctype == 18) { 215 srand(time(0) ^ getpid()); 216 /* Our ftp client code stupidly assumes a base64-encoded 217 version of the token will fit in 10K, so don't make this 218 too big. */ 219 junk = rand() & 0xff; 220 } else 221 junk = 0; 222 #else 223 junk = 0; 224 #endif 225 226 data->checksum_data.length += junk; 227 228 /* now allocate a buffer to hold the checksum data and 229 (maybe) KRB_CRED msg */ 230 231 if ((data->checksum_data.data = 232 (char *) xmalloc(data->checksum_data.length)) == NULL) { 233 if (credmsg.data) 234 krb5_free_data_contents(context, &credmsg); 235 return(ENOMEM); 236 } 237 238 ptr = (uchar_t *)data->checksum_data.data; 239 240 TWRITE_INT(ptr, data->md5.length, 0); 241 TWRITE_STR(ptr, (unsigned char *) data->md5.contents, data->md5.length); 242 TWRITE_INT(ptr, data->ctx->gss_flags, 0); 243 244 /* done with this, free it */ 245 xfree(data->md5.contents); 246 247 if (credmsg.data) { 248 TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0); 249 TWRITE_INT16(ptr, credmsg.length, 0); 250 TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length); 251 252 /* free credmsg data */ 253 krb5_free_data_contents(context, &credmsg); 254 } 255 if (junk) 256 memset(ptr, 'i', junk); 257 *out = &data->checksum_data; 258 return 0; 259 } 260 261 static krb5_error_code 262 make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token) 263 krb5_context context; 264 krb5_gss_ctx_id_rec *ctx; 265 krb5_gss_cred_id_t cred; 266 krb5_creds *k_cred; 267 gss_channel_bindings_t chan_bindings; 268 gss_OID mech_type; 269 gss_buffer_t token; 270 { 271 krb5_flags mk_req_flags = 0; 272 krb5_error_code code; 273 struct gss_checksum_data cksum_struct; 274 krb5_checksum md5; 275 krb5_data ap_req; 276 krb5_data *checksum_data = NULL; 277 unsigned char *ptr; 278 unsigned char *t; 279 int tlen; 280 281 ap_req.data = 0; 282 283 /* build the checksum buffer */ 284 KRB5_LOG0(KRB5_INFO, "make_ap_req_v1() start\n"); 285 286 /* compute the hash of the channel bindings */ 287 288 if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0))) 289 return(code); 290 291 krb5_auth_con_set_req_cksumtype(context, ctx->auth_context, 292 CKSUMTYPE_KG_CB); 293 294 cksum_struct.md5 = md5; 295 cksum_struct.ctx = ctx; 296 cksum_struct.cred = cred; 297 cksum_struct.checksum_data.data = NULL; 298 switch (k_cred->keyblock.enctype) { 299 case ENCTYPE_DES_CBC_CRC: 300 case ENCTYPE_DES_CBC_MD4: 301 case ENCTYPE_DES_CBC_MD5: 302 case ENCTYPE_DES3_CBC_SHA1: 303 code = make_gss_checksum(context, ctx->auth_context, &cksum_struct, 304 &checksum_data); 305 if (code) 306 goto cleanup; 307 break; 308 default: 309 krb5_auth_con_set_checksum_func(context, ctx->auth_context, 310 make_gss_checksum, &cksum_struct); 311 break; 312 } 313 314 /* call mk_req. subkey and ap_req need to be used or destroyed */ 315 316 mk_req_flags = AP_OPTS_USE_SUBKEY; 317 318 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) 319 mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED; 320 321 if ((code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags, 322 checksum_data, k_cred, &ap_req))) 323 goto cleanup; 324 325 /* store the interesting stuff from creds and authent */ 326 ctx->endtime = k_cred->times.endtime; 327 ctx->krb_flags = k_cred->ticket_flags; 328 329 /* build up the token */ 330 331 /* allocate space for the token */ 332 tlen = g_token_size((gss_OID) mech_type, ap_req.length); 333 334 if ((t = (unsigned char *) xmalloc(tlen)) == NULL) { 335 code = ENOMEM; 336 goto cleanup; 337 } 338 339 /* fill in the buffer */ 340 341 ptr = t; 342 343 g_make_token_header((gss_OID) mech_type, ap_req.length, 344 &ptr, KG_TOK_CTX_AP_REQ); 345 346 TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length); 347 348 /* pass it back */ 349 350 token->length = tlen; 351 token->value = (void *) t; 352 353 code = 0; 354 355 cleanup: 356 /* 357 * We only free cksum_struct.checksum_data here, because checksum_data 358 * could point to cksum_struct.checksum_data or NULL. 359 */ 360 if (cksum_struct.checksum_data.data) 361 krb5_free_data_contents(context, &cksum_struct.checksum_data); 362 if (ap_req.data) 363 xfree(ap_req.data); 364 365 KRB5_LOG(KRB5_INFO, "make_ap_req_v1() end, code = %d\n", code); 366 367 return (code); 368 } 369 370 371 372 static krb5_boolean 373 principal_ignore_inst_compare(context, princ1, princ2) 374 krb5_context context; 375 krb5_const_principal princ1; 376 krb5_const_principal princ2; 377 { 378 krb5_int32 nelem; 379 380 nelem = krb5_princ_size(context, princ1); 381 if (nelem != krb5_princ_size(context, princ2)) 382 return FALSE; 383 384 if (! krb5_realm_compare(context, princ1, princ2)) 385 return FALSE; 386 387 /* 388 * Solaris Kerberos 389 * If princ1 is elem1/metachar@REALM, compare just elem1 (and REALM). 390 */ 391 if (nelem == 2) { 392 const krb5_data *p = krb5_princ_component(context, princ1, 1); 393 394 if (p->length == 1) { 395 const char *s = p->data; 396 397 if (s[0] == '*') { 398 const krb5_data *p1 = krb5_princ_component(context, princ1, 0); 399 const krb5_data *p2 = krb5_princ_component(context, princ2, 0); 400 401 if (p1->length != p2->length || 402 memcmp(p1->data, p2->data, p1->length)) 403 return FALSE; 404 405 return TRUE; 406 } 407 } 408 } 409 410 return FALSE; 411 } 412 413 /* 414 * Solaris Kerberos 415 * This is a dup of krb5_ktfile_get_entry (sigh) but is necessary to 416 * to get a custom princ compare above (principal_ignore_inst_compare) 417 * and thus avoid mucking w/important krb5 internal 418 * api (krb5_principal_compare) 419 */ 420 #include "../krb5/keytab/file/ktfile.h" 421 422 static krb5_error_code KRB5_CALLCONV 423 ktfile_get_entry(context, id, principal, kvno, enctype, entry) 424 krb5_context context; 425 krb5_keytab id; 426 krb5_const_principal principal; 427 krb5_kvno kvno; 428 krb5_enctype enctype; 429 krb5_keytab_entry * entry; 430 { 431 krb5_keytab_entry cur_entry, new_entry; 432 krb5_error_code kerror = 0; 433 int found_wrong_kvno = 0; 434 krb5_boolean similar; 435 int kvno_offset = 0; 436 437 KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() start\n"); 438 439 /* Open the keyfile for reading */ 440 if ((kerror = krb5_ktfileint_openr(context, id))){ 441 KRB5_LOG(KRB5_ERR, "ktfile_get_entry() end, ktfileint_openr() " 442 "kerror= %d\n", kerror); 443 return(kerror); 444 } 445 446 /* 447 * For efficiency and simplicity, we'll use a while true that 448 * is exited with a break statement. 449 */ 450 cur_entry.principal = 0; 451 cur_entry.vno = 0; 452 cur_entry.key.contents = 0; 453 /*CONSTCOND*/ 454 while (TRUE) { 455 if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry))) 456 break; 457 458 /* 459 * by the time this loop exits, it must either free cur_entry, 460 * and copy new_entry there, or free new_entry. Otherwise, it 461 * leaks. 462 */ 463 464 /* 465 * if the principal isn't the one requested, free new_entry 466 * and continue to the next. 467 */ 468 469 if (!principal_ignore_inst_compare(context, principal, 470 new_entry.principal)) { 471 krb5_kt_free_entry(context, &new_entry); 472 continue; 473 } 474 475 /* 476 * if the enctype is not ignored and doesn't match, free new_entry 477 * and continue to the next 478 */ 479 480 if (enctype != IGNORE_ENCTYPE) { 481 if ((kerror = krb5_c_enctype_compare(context, enctype, 482 new_entry.key.enctype, 483 &similar))) { 484 krb5_kt_free_entry(context, &new_entry); 485 break; 486 } 487 488 if (!similar) { 489 krb5_kt_free_entry(context, &new_entry); 490 continue; 491 } 492 /* 493 * Coerce the enctype of the output keyblock in case we 494 * got an inexact match on the enctype. 495 */ 496 new_entry.key.enctype = enctype; 497 } 498 499 if (kvno == IGNORE_VNO) { 500 /* 501 * if this is the first match, or if the new vno is 502 * bigger, free the current and keep the new. Otherwise, 503 * free the new. 504 */ 505 /* 506 * A 1.2.x keytab contains only the low 8 bits of the key 507 * version number. Since it can be much bigger, and thus 508 * the 8-bit value can wrap, we need some heuristics to 509 * figure out the "highest" numbered key if some numbers 510 * close to 255 and some near 0 are used. 511 * 512 * The heuristic here: 513 514 * If we have any keys with versions over 240, then assume 515 * that all version numbers 0-127 refer to 256+N instead. 516 * Not perfect, but maybe good enough? 517 */ 518 519 #define M(VNO) (((VNO) - kvno_offset + 256) % 256) 520 521 if (new_entry.vno > 240) 522 kvno_offset = 128; 523 if (! cur_entry.principal || 524 M(new_entry.vno) > M(cur_entry.vno)) { 525 krb5_kt_free_entry(context, &cur_entry); 526 cur_entry = new_entry; 527 } else { 528 krb5_kt_free_entry(context, &new_entry); 529 } 530 } else { 531 /* 532 * if this kvno matches, free the current (will there ever 533 * be one?), keep the new, and break out. Otherwise, remember 534 * that we were here so we can return the right error, and 535 * free the new 536 */ 537 /* 538 * Yuck. The krb5-1.2.x keytab format only stores one byte 539 * for the kvno, so we're toast if the kvno requested is 540 * higher than that. Short-term workaround: only compare 541 * the low 8 bits. 542 */ 543 544 if (new_entry.vno == (kvno & 0xff)) { 545 krb5_kt_free_entry(context, &cur_entry); 546 cur_entry = new_entry; 547 break; 548 } else { 549 found_wrong_kvno++; 550 krb5_kt_free_entry(context, &new_entry); 551 } 552 } 553 } 554 555 if (kerror == KRB5_KT_END) { 556 if (cur_entry.principal) 557 kerror = 0; 558 else if (found_wrong_kvno) 559 kerror = KRB5_KT_KVNONOTFOUND; 560 else 561 kerror = KRB5_KT_NOTFOUND; 562 } 563 if (kerror) { 564 (void) krb5_ktfileint_close(context, id); 565 krb5_kt_free_entry(context, &cur_entry); 566 KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, kerror=" 567 "%d\n", kerror); 568 return kerror; 569 } 570 if ((kerror = krb5_ktfileint_close(context, id)) != 0) { 571 krb5_kt_free_entry(context, &cur_entry); 572 KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, ktfileint_close() " 573 "kerror= %d\n", kerror); 574 return kerror; 575 } 576 *entry = cur_entry; 577 578 /* Let us close the file before we leave */ 579 (void) krb5_ktfileint_close(context, id); 580 581 KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() end"); 582 583 return 0; 584 } 585 586 587 /* 588 * Solaris Kerberos 589 * Given a princ of name/instance@LOCALREALM, search the keytab 590 * for a match of name and LOCALREALM and if found, return instance 591 * as a string. 592 * 593 * Caller must free returned string. 594 */ 595 static krb5_error_code 596 get_instance_keytab( 597 krb5_context context, 598 const char *sname, 599 krb5_keytab keytab, 600 char **instance) /* out */ 601 { 602 krb5_error_code ret=0; 603 krb5_keytab_entry kt_ent; 604 krb5_int32 nelem, free_kt_ent=0; 605 register const krb5_data *p; 606 char *realm=NULL, *s=NULL; 607 krb5_principal client=NULL, princ=NULL; 608 609 if (!keytab) 610 return EINVAL; 611 612 if (ret = krb5_get_default_realm(context, &realm)) 613 return ret; 614 615 ret = krb5_build_principal(context, &client, strlen(realm), 616 realm, sname, "*", 617 (char *)0); 618 if (ret) 619 goto out; 620 621 ret = ktfile_get_entry(context, keytab, client, 622 0, /* don't have vno available */ 623 0, &kt_ent); 624 if (ret) 625 goto out; 626 627 free_kt_ent++; /* kt_ent is not a ptr */ 628 629 princ = kt_ent.principal; 630 nelem = krb5_princ_size(context, princ); 631 if (nelem != 2) { 632 ret = KRB5_PRINC_NOMATCH; 633 goto out; 634 } 635 636 p = krb5_princ_component(context, princ, 1); 637 s = calloc(p->length + sizeof(char), sizeof(char)); 638 if (!s) { 639 ret = ENOMEM; 640 goto out; 641 } 642 643 (void) memcpy(s, p->data, p->length); 644 645 646 out: 647 free(realm); 648 if (client) 649 krb5_free_principal(context, client); 650 if (free_kt_ent) 651 (void) krb5_kt_free_entry(context, &kt_ent); 652 653 if (ret == 0) 654 *instance = s; 655 return ret; 656 } 657 658 static OM_uint32 659 load_root_cred_using_keytab( 660 OM_uint32 *minor_status, 661 krb5_context context, 662 const char *sname, 663 int use_nodename) 664 { 665 krb5_creds my_creds; 666 krb5_principal me; 667 krb5_principal server; 668 krb5_error_code code; 669 krb5_ccache ccache = NULL; 670 krb5_keytab keytab = NULL; 671 krb5_timestamp now; 672 krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */ 673 krb5_get_init_creds_opt opt; 674 krb5_data tgtname = { 675 0, 676 KRB5_TGS_NAME_SIZE, 677 KRB5_TGS_NAME 678 }; 679 char *svcname = NULL; 680 681 KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() start \n"); 682 683 if (!sname) 684 return (GSS_S_FAILURE); 685 686 memset((char *)&my_creds, 0, sizeof(my_creds)); 687 688 if (code = krb5_kt_default(context, &keytab)) { 689 *minor_status = code; 690 return (GSS_S_FAILURE); 691 } 692 693 if (!use_nodename) { 694 char *instance = NULL; 695 696 code = get_instance_keytab(context, sname, keytab, &instance); 697 if (code == 0) { 698 code = krb5_sname_to_principal(context, 699 instance, sname, 700 KRB5_NT_UNKNOWN, &me); 701 free(instance); 702 } 703 } else { 704 code = krb5_sname_to_principal(context, NULL, sname, 705 KRB5_NT_SRV_HST, &me); 706 } 707 if (code) { 708 (void) krb5_kt_close(context, keytab); 709 *minor_status = code; 710 return (GSS_S_FAILURE); 711 } 712 my_creds.client = me; 713 714 if((code = krb5_build_principal_ext(context, &server, 715 krb5_princ_realm(context, me)->length, 716 krb5_princ_realm(context, me)->data, 717 tgtname.length, tgtname.data, 718 krb5_princ_realm(context, me)->length, 719 krb5_princ_realm(context, me)->data, 720 0))) { 721 *minor_status = code; 722 krb5_free_cred_contents(context, &my_creds); 723 (void) krb5_kt_close(context, keytab); 724 725 return (GSS_S_FAILURE); 726 } 727 728 my_creds.server = server; 729 my_creds.times.starttime = 0; /* start timer 730 * when request 731 * gets to KDC 732 */ 733 if ((code = krb5_timeofday(context, &now))) { 734 *minor_status = code; 735 krb5_free_cred_contents(context, &my_creds); 736 (void) krb5_kt_close(context, keytab); 737 738 return (GSS_S_FAILURE); 739 } 740 my_creds.times.endtime = now + lifetime; 741 my_creds.times.renew_till = 0; 742 743 memset(&opt, 0, sizeof (opt)); 744 krb5_get_init_creds_opt_init(&opt); 745 krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime); 746 747 code = krb5_unparse_name(context, server, &svcname); 748 if (code != 0) { 749 *minor_status = code; 750 krb5_free_cred_contents(context, &my_creds); 751 (void) krb5_kt_close(context, keytab); 752 753 return (GSS_S_FAILURE); 754 } 755 code = krb5_get_init_creds_keytab(context, 756 &my_creds, me, keytab, 757 0, svcname, &opt); 758 759 (void) krb5_kt_close(context, keytab); 760 761 if (svcname != NULL) 762 free(svcname); 763 if (code) { 764 *minor_status = code; 765 krb5_free_cred_contents(context, &my_creds); 766 767 return (GSS_S_FAILURE); 768 } 769 code = krb5_cc_resolve (context, 770 krb5_cc_default_name(context), 771 &ccache); 772 if (code != 0) { 773 *minor_status = code; 774 krb5_free_cred_contents(context, &my_creds); 775 776 return (GSS_S_FAILURE); 777 } 778 code = krb5_cc_initialize (context, ccache, me); 779 if (code != 0) { 780 *minor_status = code; 781 krb5_free_cred_contents(context, &my_creds); 782 (void) krb5_cc_close(context, ccache); 783 784 return (GSS_S_FAILURE); 785 } 786 787 code = krb5_cc_store_cred(context, ccache, 788 &my_creds); 789 krb5_free_cred_contents(context, &my_creds); 790 (void) krb5_cc_close(context, ccache); 791 792 if (code) { 793 *minor_status = code; 794 795 KRB5_LOG(KRB5_ERR, "load_root_cred_using_keytab() end, error " 796 "code = %d\n", code); 797 798 return (GSS_S_FAILURE); 799 } 800 801 KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() end \n"); 802 803 return (GSS_S_COMPLETE); 804 } 805 806 static OM_uint32 807 renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid) 808 { 809 krb5_principal me; 810 krb5_principal server; 811 krb5_creds creds; 812 krb5_creds tmpcreds; 813 krb5_creds *out_creds; 814 krb5_error_code code; 815 krb5_ccache ccache = NULL; 816 static char ccache_name_buf[CACHE_FILENAME_LEN]; 817 int options = 0; 818 krb5_data tgtname = { 819 0, 820 KRB5_TGS_NAME_SIZE, 821 KRB5_TGS_NAME 822 }; 823 gid_t gid = getgid(); 824 825 memset((char *)&creds, 0, sizeof(creds)); 826 memset((char *)&tmpcreds, 0, sizeof(creds)); 827 828 if ((code = krb5_cc_default(context, &ccache))) { 829 *minor_status = code; 830 (void) krb5_cc_close(context, ccache); 831 return (GSS_S_FAILURE); 832 } 833 834 if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) { 835 *minor_status = code; 836 (void) krb5_cc_close(context, ccache); 837 return (GSS_S_FAILURE); 838 } 839 840 creds.client = me; 841 842 if((code = krb5_build_principal_ext(context, &server, 843 krb5_princ_realm(context, me)->length, 844 krb5_princ_realm(context, me)->data, 845 tgtname.length, tgtname.data, 846 krb5_princ_realm(context, me)->length, 847 krb5_princ_realm(context, me)->data, 848 0))) { 849 krb5_free_principal(context, me); 850 (void) krb5_cc_close(context, ccache); 851 *minor_status = code; 852 return (GSS_S_FAILURE); 853 } 854 855 creds.server = server; 856 creds.ticket_flags = TKT_FLG_RENEWABLE; 857 858 if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS, 859 &creds, &tmpcreds))) { 860 (void) krb5_cc_close(context, ccache); 861 return (KDC_ERR_BADOPTION); 862 } 863 864 creds.ticket_flags = 0; 865 code = krb5_get_credentials_renew(context, options, ccache, 866 &creds, &out_creds); 867 krb5_free_cred_contents(context, &creds); 868 krb5_free_cred_contents(context, &tmpcreds); 869 870 if (code) { 871 *minor_status = code; 872 return (GSS_S_FAILURE); 873 } 874 875 krb5_free_creds(context, out_creds); 876 snprintf(ccache_name_buf, CACHE_FILENAME_LEN, "/tmp/krb5cc_%d", 877 uid, -1); 878 code = safechown(ccache_name_buf, uid, gid, -1); 879 880 if (code == -1) { 881 (void) krb5_cc_destroy(context, ccache); 882 *minor_status = code; 883 return (GSS_S_FAILURE); 884 } 885 886 (void) krb5_cc_close(context, ccache); 887 888 return (GSS_S_COMPLETE); 889 890 } 891 892 /* 893 * Solaris Kerberos: 894 * We enforce a minimum refresh time on the root cred. This avoids problems for 895 * the higher level communication protocol for having valid creds and 896 * setting up a valid context, only to have it expire before or while 897 * it is being used. For non root users we don't care since we do not refresh 898 * there creds, they get what they can get. 899 */ 900 #define MIN_REFRESH_TIME 300 901 #define MIN_RENEW_TIME 1500 902 903 /* get_default_cred() must be called with the krb5_mutex lock held */ 904 static OM_uint32 905 get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle) 906 { 907 krb5_timestamp now; 908 krb5_gss_cred_id_t cred; 909 OM_uint32 major; 910 OM_uint32 mntmp; 911 uid_t uid = getuid(); 912 krb5_context context = (krb5_context)ct; 913 914 KRB5_LOG0(KRB5_INFO, "get_default_cred() start\n"); 915 916 /* Get the default cred for user */ 917 if (((major = kg_get_defcred(minor_status, cred_handle)) != NULL) && 918 GSS_ERROR(major)) { 919 920 /* If we're not root we're done */ 921 if (uid != ROOT_UID) 922 return (major); 923 924 /* 925 * Try and get root's cred in the cache using keytab. 926 * 927 * First try "root" and then try "host" - this allows 928 * Secure NFS to use the host principal for mounting if 929 * there is no root principal. 930 * 931 * Then try "host/<anything>" to match any instance (needed 932 * for DHCP clients). 933 */ 934 major = load_root_cred_using_keytab(minor_status, 935 context, "root", 1); 936 937 if (major != GSS_S_COMPLETE) 938 major = load_root_cred_using_keytab(minor_status, 939 context, "host", 1); 940 if (major != GSS_S_COMPLETE) 941 major = load_root_cred_using_keytab(minor_status, 942 context, "host", 0); 943 944 if (major != GSS_S_COMPLETE) 945 return (major); 946 947 /* We should have valid tgt now in the cache, so get it. */ 948 major = kg_get_defcred(minor_status, cred_handle); 949 950 return (major); 951 } 952 953 /* We've got a gss cred handle that is a kerberos cred handle. */ 954 cred = (krb5_gss_cred_id_t)*cred_handle; 955 956 /* If we can't get the time, assume the worst. */ 957 if (krb5_timeofday(context, &now)) { 958 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 959 return (GSS_S_CREDENTIALS_EXPIRED); 960 } 961 962 /* If root's cred has expired re-get it */ 963 if (cred->tgt_expire < now + MIN_REFRESH_TIME && uid == ROOT_UID) { 964 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 965 966 major = load_root_cred_using_keytab(minor_status, 967 context, "root", 1); 968 969 if (major != GSS_S_COMPLETE) 970 major = load_root_cred_using_keytab(minor_status, 971 context, "host", 1); 972 973 if (major != GSS_S_COMPLETE) 974 major = load_root_cred_using_keytab(minor_status, 975 context, "host", 0); 976 977 if (major != GSS_S_COMPLETE) 978 return (major); 979 980 major = kg_get_defcred(minor_status, cred_handle); 981 if (major != GSS_S_COMPLETE) 982 return (major); 983 984 /* Any body else is SOL unless we can renew their credential cache */ 985 } else if ((cred->tgt_expire < now + MIN_RENEW_TIME) && 986 (cred->tgt_expire > now)) { 987 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 988 989 major = renew_ccache(minor_status, context, uid); 990 if ((major != GSS_S_COMPLETE) && 991 (major != KDC_ERR_BADOPTION)) 992 return (major); 993 994 major = kg_get_defcred(minor_status, cred_handle); 995 if (major != GSS_S_COMPLETE) 996 return (major); 997 998 } 999 1000 /* Otherwise we got non expired creds */ 1001 1002 KRB5_LOG0(KRB5_INFO, "get_default_cred() end\n"); 1003 1004 return (GSS_S_COMPLETE); 1005 } 1006 1007 /* 1008 * setup_enc 1009 * 1010 * Fill in the encryption descriptors. Called after AP-REQ is made. 1011 */ 1012 static OM_uint32 1013 setup_enc( 1014 OM_uint32 *minor_status, 1015 krb5_gss_ctx_id_rec *ctx, 1016 krb5_context context) 1017 { 1018 krb5_error_code code; 1019 OM_uint32 ret = GSS_S_COMPLETE; 1020 int i; 1021 1022 ctx->have_acceptor_subkey = 0; 1023 ctx->proto = 0; 1024 ctx->cksumtype = 0; 1025 1026 KRB5_LOG(KRB5_ERR, "setup_enc() enctype = %d\n", 1027 ctx->subkey->enctype); 1028 1029 switch(ctx->subkey->enctype) { 1030 case ENCTYPE_DES_CBC_MD5: 1031 case ENCTYPE_DES_CBC_MD4: 1032 case ENCTYPE_DES_CBC_CRC: 1033 ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; 1034 ctx->signalg = SGN_ALG_DES_MAC_MD5; 1035 ctx->cksum_size = 8; 1036 ctx->sealalg = SEAL_ALG_DES; 1037 1038 /* The encryption key is the session key XOR 1039 0xf0f0f0f0f0f0f0f0. */ 1040 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) 1041 goto fail; 1042 1043 for (i=0; i<ctx->enc->length; i++) 1044 ctx->enc->contents[i] ^= 0xf0; 1045 1046 goto copy_subkey_to_seq; 1047 1048 case ENCTYPE_DES3_CBC_SHA1: 1049 /* MIT extension */ 1050 ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW; 1051 ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; 1052 ctx->cksum_size = 20; 1053 ctx->sealalg = SEAL_ALG_DES3KD; 1054 1055 copy_subkey: 1056 code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); 1057 if (code) 1058 goto fail; 1059 copy_subkey_to_seq: 1060 code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); 1061 if (code) { 1062 krb5_free_keyblock (context, ctx->enc); 1063 goto fail; 1064 } 1065 break; 1066 1067 case ENCTYPE_ARCFOUR_HMAC: 1068 /* Microsoft extension */ 1069 ctx->signalg = SGN_ALG_HMAC_MD5 ; 1070 ctx->cksum_size = 8; 1071 ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; 1072 1073 goto copy_subkey; 1074 1075 default: 1076 /* Fill some fields we shouldn't be using on this path 1077 with garbage. */ 1078 ctx->signalg = -10; 1079 ctx->sealalg = -10; 1080 1081 ctx->proto = 1; 1082 code = krb5int_c_mandatory_cksumtype(context, ctx->subkey->enctype, 1083 &ctx->cksumtype); 1084 if (code) 1085 goto fail; 1086 code = krb5_c_checksum_length(context, ctx->cksumtype, 1087 (size_t *)&ctx->cksum_size); 1088 if (code) 1089 goto fail; 1090 goto copy_subkey; 1091 } 1092 fail: 1093 if (code) { 1094 *minor_status = code; 1095 ret = GSS_S_FAILURE; 1096 } 1097 success: 1098 return (ret); 1099 } 1100 1101 /* 1102 * new_connection 1103 * 1104 * Do the grunt work of setting up a new context. 1105 */ 1106 static OM_uint32 1107 new_connection( 1108 OM_uint32 *minor_status, 1109 krb5_gss_cred_id_t cred, 1110 gss_ctx_id_t *context_handle, 1111 gss_name_t target_name, 1112 gss_OID mech_type, 1113 OM_uint32 req_flags, 1114 OM_uint32 time_req, 1115 gss_channel_bindings_t input_chan_bindings, 1116 gss_buffer_t input_token, 1117 gss_OID *actual_mech_type, 1118 gss_buffer_t output_token, 1119 OM_uint32 *ret_flags, 1120 OM_uint32 *time_rec, 1121 krb5_context context, 1122 int default_mech) 1123 { 1124 OM_uint32 major_status; 1125 krb5_error_code code; 1126 krb5_creds *k_cred; 1127 krb5_gss_ctx_id_rec *ctx, *ctx_free; 1128 krb5_timestamp now; 1129 gss_buffer_desc token; 1130 1131 major_status = GSS_S_FAILURE; 1132 token.length = 0; 1133 token.value = NULL; 1134 1135 /* make sure the cred is usable for init */ 1136 1137 if ((cred->usage != GSS_C_INITIATE) && 1138 (cred->usage != GSS_C_BOTH)) { 1139 *minor_status = 0; 1140 return(GSS_S_NO_CRED); 1141 } 1142 1143 /* complain if the input token is non-null */ 1144 1145 if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { 1146 *minor_status = 0; 1147 return(GSS_S_DEFECTIVE_TOKEN); 1148 } 1149 1150 /* create the ctx */ 1151 1152 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) 1153 == NULL) { 1154 *minor_status = ENOMEM; 1155 return(GSS_S_FAILURE); 1156 } 1157 1158 /* fill in the ctx */ 1159 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); 1160 ctx_free = ctx; 1161 if ((code = krb5_auth_con_init(context, &ctx->auth_context))) 1162 goto fail; 1163 krb5_auth_con_setflags(context, ctx->auth_context, 1164 KRB5_AUTH_CONTEXT_DO_SEQUENCE); 1165 ctx->initiate = 1; 1166 ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | 1167 GSS_C_TRANS_FLAG | GSS_C_PROT_READY_FLAG | 1168 ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | 1169 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG))); 1170 ctx->seed_init = 0; 1171 ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ 1172 ctx->seqstate = 0; 1173 if ((code = krb5_timeofday(context, &now))) 1174 goto fail; 1175 1176 if (time_req == 0 || time_req == GSS_C_INDEFINITE) { 1177 ctx->endtime = 0; 1178 } else { 1179 ctx->endtime = now + time_req; 1180 } 1181 1182 if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) 1183 goto fail; 1184 1185 if ((code = krb5_copy_principal(context, (krb5_principal) target_name, 1186 &ctx->there))) 1187 goto fail; 1188 1189 code = get_credentials(context, cred, ctx->there, now, 1190 ctx->endtime, &k_cred); 1191 if (code) 1192 goto fail; 1193 1194 if (default_mech) { 1195 mech_type = (gss_OID) gss_mech_krb5; 1196 } 1197 /* Solaris Kerberos: we allocate the memory for mech_used here 1198 * because we store mech_used as a gss_OID and not a (gss_OID *) 1199 */ 1200 ctx->mech_used.elements = malloc(mech_type->length); 1201 if ( (ctx->mech_used.elements) == NULL ) { 1202 code = ENOMEM; 1203 major_status = GSS_S_FAILURE; 1204 goto fail; 1205 } 1206 ctx->mech_used.length = mech_type->length; 1207 memcpy(ctx->mech_used.elements, mech_type->elements, mech_type->length); 1208 1209 /* 1210 * Now try to make it static if at all possible.... 1211 */ 1212 /* Solaris Kerberos: our mech_used is part of the ctx structure */ 1213 /* ctx->mech_used = krb5_gss_convert_static_mech_oid(&(ctx->mech_used)); */ 1214 { 1215 /* gsskrb5 v1 */ 1216 krb5_ui_4 seq_temp; 1217 if ((code = make_ap_req_v1(context, ctx, 1218 cred, k_cred, input_chan_bindings, 1219 mech_type, &token))) { 1220 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || 1221 (code == KG_EMPTY_CCACHE)) 1222 major_status = GSS_S_NO_CRED; 1223 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) 1224 major_status = GSS_S_CREDENTIALS_EXPIRED; 1225 goto fail; 1226 } 1227 1228 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, 1229 (krb5_int32 *)&seq_temp); 1230 ctx->seq_send = seq_temp; 1231 krb5_auth_con_getsendsubkey(context, ctx->auth_context, 1232 &ctx->subkey); 1233 } 1234 1235 major_status = setup_enc(minor_status, ctx, context); 1236 1237 if (k_cred) { 1238 krb5_free_creds(context, k_cred); 1239 k_cred = 0; 1240 } 1241 1242 /* at this point, the context is constructed and valid, 1243 hence, releaseable */ 1244 1245 /* intern the context handle */ 1246 1247 if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { 1248 code = G_VALIDATE_FAILED; 1249 goto fail; 1250 } 1251 *context_handle = (gss_ctx_id_t) ctx; 1252 ctx_free = 0; 1253 /* compute time_rec */ 1254 if (time_rec) { 1255 if ((code = krb5_timeofday(context, &now))) 1256 goto fail; 1257 *time_rec = ctx->endtime - now; 1258 } 1259 1260 /* set the other returns */ 1261 *output_token = token; 1262 1263 if (ret_flags) 1264 *ret_flags = ctx->gss_flags; 1265 1266 if (actual_mech_type) 1267 *actual_mech_type = mech_type; 1268 1269 /* return successfully */ 1270 1271 *minor_status = 0; 1272 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { 1273 ctx->established = 0; 1274 return(GSS_S_CONTINUE_NEEDED); 1275 } else { 1276 ctx->seq_recv = ctx->seq_send; 1277 g_order_init(&(ctx->seqstate), ctx->seq_recv, 1278 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, 1279 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto); 1280 ctx->gss_flags |= GSS_C_PROT_READY_FLAG; 1281 ctx->established = 1; 1282 return(GSS_S_COMPLETE); 1283 } 1284 1285 fail: 1286 if (ctx_free) { 1287 if (ctx_free->auth_context) 1288 krb5_auth_con_free(context, ctx_free->auth_context); 1289 if (ctx_free->here) 1290 krb5_free_principal(context, ctx_free->here); 1291 if (ctx_free->there) 1292 krb5_free_principal(context, ctx_free->there); 1293 if (ctx_free->subkey) 1294 krb5_free_keyblock(context, ctx_free->subkey); 1295 xfree(ctx_free); 1296 } else { 1297 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1298 context_handle, NULL); 1299 } 1300 1301 *minor_status = code; 1302 return (major_status); 1303 } 1304 1305 /* 1306 * mutual_auth 1307 * 1308 * Handle the reply from the acceptor, if we're doing mutual auth. 1309 */ 1310 static OM_uint32 1311 mutual_auth( 1312 OM_uint32 *minor_status, 1313 krb5_gss_cred_id_t cred, 1314 gss_ctx_id_t *context_handle, 1315 gss_name_t target_name, 1316 gss_OID mech_type, 1317 OM_uint32 req_flags, 1318 OM_uint32 time_req, 1319 gss_channel_bindings_t input_chan_bindings, 1320 gss_buffer_t input_token, 1321 gss_OID *actual_mech_type, 1322 gss_buffer_t output_token, 1323 OM_uint32 *ret_flags, 1324 OM_uint32 *time_rec, 1325 krb5_context context) 1326 { 1327 OM_uint32 major_status; 1328 unsigned char *ptr; 1329 char *sptr; 1330 krb5_data ap_rep; 1331 krb5_ap_rep_enc_part *ap_rep_data; 1332 krb5_timestamp now; 1333 krb5_gss_ctx_id_rec *ctx; 1334 krb5_error *krb_error; 1335 krb5_error_code code; 1336 1337 major_status = GSS_S_FAILURE; 1338 1339 /* validate the context handle */ 1340 /*SUPPRESS 29*/ 1341 if (! kg_validate_ctx_id(*context_handle)) { 1342 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 1343 return(GSS_S_NO_CONTEXT); 1344 } 1345 1346 ctx = (krb5_gss_ctx_id_rec *) *context_handle; 1347 1348 /* make sure the context is non-established, and that certain 1349 arguments are unchanged */ 1350 1351 if ((ctx->established) || 1352 ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { 1353 code = KG_CONTEXT_ESTABLISHED; 1354 goto fail; 1355 } 1356 1357 if (! krb5_principal_compare(context, ctx->there, 1358 (krb5_principal) target_name)) { 1359 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1360 context_handle, NULL); 1361 code = 0; 1362 major_status = GSS_S_BAD_NAME; 1363 goto fail; 1364 } 1365 1366 /* verify the token and leave the AP_REP message in ap_rep */ 1367 1368 if (input_token == GSS_C_NO_BUFFER) { 1369 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1370 context_handle, NULL); 1371 code = 0; 1372 major_status = GSS_S_DEFECTIVE_TOKEN; 1373 goto fail; 1374 } 1375 1376 ptr = (unsigned char *) input_token->value; 1377 1378 if (g_verify_token_header(&ctx->mech_used, 1379 (uint32_t *)&(ap_rep.length), 1380 &ptr, KG_TOK_CTX_AP_REP, 1381 input_token->length, 1)) { 1382 if (g_verify_token_header(&ctx->mech_used, 1383 (uint32_t *)&(ap_rep.length), 1384 &ptr, KG_TOK_CTX_ERROR, 1385 input_token->length, 1) == 0) { 1386 1387 /* Handle a KRB_ERROR message from the server */ 1388 1389 sptr = (char *) ptr; /* PC compiler bug */ 1390 TREAD_STR(sptr, ap_rep.data, ap_rep.length); 1391 1392 code = krb5_rd_error(context, &ap_rep, &krb_error); 1393 if (code) 1394 goto fail; 1395 if (krb_error->error) 1396 code = krb_error->error + ERROR_TABLE_BASE_krb5; 1397 else 1398 code = 0; 1399 krb5_free_error(context, krb_error); 1400 goto fail; 1401 } else { 1402 *minor_status = 0; 1403 return(GSS_S_DEFECTIVE_TOKEN); 1404 } 1405 } 1406 1407 sptr = (char *) ptr; /* PC compiler bug */ 1408 TREAD_STR(sptr, ap_rep.data, ap_rep.length); 1409 1410 /* decode the ap_rep */ 1411 if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, 1412 &ap_rep_data))) { 1413 /* 1414 * XXX A hack for backwards compatiblity. 1415 * To be removed in 1999 -- proven 1416 */ 1417 krb5_auth_con_setuseruserkey(context, ctx->auth_context, 1418 ctx->subkey); 1419 if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, 1420 &ap_rep_data))) 1421 goto fail; 1422 } 1423 1424 /* store away the sequence number */ 1425 ctx->seq_recv = ap_rep_data->seq_number; 1426 g_order_init(&(ctx->seqstate), ctx->seq_recv, 1427 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, 1428 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto); 1429 1430 if (ctx->proto == 1 && ap_rep_data->subkey) { 1431 /* Keep acceptor's subkey. */ 1432 ctx->have_acceptor_subkey = 1; 1433 code = krb5_copy_keyblock(context, ap_rep_data->subkey, 1434 &ctx->acceptor_subkey); 1435 if (code) 1436 goto fail; 1437 code = krb5int_c_mandatory_cksumtype(context, 1438 ctx->acceptor_subkey->enctype, 1439 &ctx->acceptor_subkey_cksumtype); 1440 if (code) 1441 goto fail; 1442 } 1443 1444 /* free the ap_rep_data */ 1445 krb5_free_ap_rep_enc_part(context, ap_rep_data); 1446 1447 /* set established */ 1448 ctx->established = 1; 1449 1450 /* set returns */ 1451 1452 if (time_rec) { 1453 if ((code = krb5_timeofday(context, &now))) 1454 goto fail; 1455 *time_rec = ctx->endtime - now; 1456 } 1457 if (ret_flags) 1458 *ret_flags = ctx->gss_flags; 1459 1460 if (actual_mech_type) 1461 *actual_mech_type = mech_type; 1462 1463 /* success */ 1464 1465 *minor_status = 0; 1466 return GSS_S_COMPLETE; 1467 1468 fail: 1469 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1470 context_handle, NULL); 1471 1472 *minor_status = code; 1473 return (major_status); 1474 } 1475 1476 /* 1477 * krb5_gss_init_sec_context 1478 * This has been broken up into smaller chunks for CFX support. 1479 * MIT KRB5 1.3.2 1480 */ 1481 OM_uint32 1482 krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, 1483 context_handle, target_name, mech_type, 1484 req_flags, time_req, input_chan_bindings, 1485 input_token, actual_mech_type, output_token, 1486 ret_flags, time_rec) 1487 void *ct; 1488 OM_uint32 *minor_status; 1489 gss_cred_id_t claimant_cred_handle; 1490 gss_ctx_id_t *context_handle; 1491 gss_name_t target_name; 1492 gss_OID mech_type; 1493 OM_uint32 req_flags; 1494 OM_uint32 time_req; 1495 gss_channel_bindings_t input_chan_bindings; 1496 gss_buffer_t input_token; 1497 gss_OID *actual_mech_type; 1498 gss_buffer_t output_token; 1499 OM_uint32 *ret_flags; 1500 OM_uint32 *time_rec; 1501 { 1502 krb5_context context; 1503 krb5_gss_cred_id_t cred = NULL; 1504 int err; 1505 int default_mech = 0; 1506 OM_uint32 major_status; 1507 OM_uint32 tmp_min_stat; 1508 1509 /* Solaris Kerberos: for MT safety, we avoid the use of a default 1510 * context via kg_get_context() */ 1511 #if 0 1512 if (GSS_ERROR(kg_get_context(minor_status, &context))) 1513 return(GSS_S_FAILURE); 1514 #endif 1515 1516 KRB5_LOG0(KRB5_INFO, "krb5_gss_init_sec_context() start\n"); 1517 1518 mutex_lock(&krb5_mutex); 1519 context = ct; 1520 1521 /* set up return values so they can be "freed" successfully */ 1522 1523 major_status = GSS_S_FAILURE; /* Default major code */ 1524 output_token->length = 0; 1525 output_token->value = NULL; 1526 if (actual_mech_type) 1527 *actual_mech_type = NULL; 1528 1529 /* verify that the target_name is valid and usable */ 1530 1531 if (! kg_validate_name(target_name)) { 1532 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 1533 major_status = (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); 1534 goto unlock; 1535 } 1536 1537 /* verify the credential, or use the default */ 1538 /*SUPPRESS 29*/ 1539 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { 1540 /* 1541 * Solaris Kerberos: here we are using the Solaris specific 1542 * function get_default_cred() to handle the special case of a 1543 * root principal 1544 */ 1545 major_status = get_default_cred(minor_status, ct, (gss_cred_id_t *)&cred); 1546 if (major_status && GSS_ERROR(major_status)) { 1547 KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1548 "major_status = %d\n", major_status); 1549 goto unlock; 1550 } 1551 } else { 1552 major_status = krb5_gss_validate_cred_no_lock(ct, minor_status, 1553 claimant_cred_handle); 1554 if (GSS_ERROR(major_status)) { 1555 KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1556 "major_status = %d\n", major_status); 1557 goto unlock; 1558 } 1559 cred = (krb5_gss_cred_id_t) claimant_cred_handle; 1560 } 1561 1562 /* verify the mech_type */ 1563 1564 err = 0; 1565 if (mech_type == GSS_C_NULL_OID) { 1566 default_mech = 1; 1567 if (cred->rfc_mech) { 1568 mech_type = (gss_OID) gss_mech_krb5; 1569 } else if (cred->prerfc_mech) { 1570 mech_type = (gss_OID) gss_mech_krb5_old; 1571 } else { 1572 err = 1; 1573 } 1574 } else if (g_OID_equal(mech_type, gss_mech_krb5)) { 1575 if (!cred->rfc_mech) 1576 err = 1; 1577 } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { 1578 if (!cred->prerfc_mech) 1579 err = 1; 1580 } else { 1581 err = 1; 1582 } 1583 1584 if (err) { 1585 *minor_status = 0; 1586 major_status = GSS_S_BAD_MECH; 1587 goto unlock; 1588 } 1589 1590 /* is this a new connection or not? */ 1591 1592 /*SUPPRESS 29*/ 1593 if (*context_handle == GSS_C_NO_CONTEXT) { 1594 major_status = new_connection(minor_status, cred, context_handle, 1595 target_name, mech_type, req_flags, 1596 time_req, input_chan_bindings, 1597 input_token, actual_mech_type, 1598 output_token, ret_flags, time_rec, 1599 context, default_mech); 1600 } else { 1601 major_status = mutual_auth(minor_status, cred, context_handle, 1602 target_name, mech_type, req_flags, 1603 time_req, input_chan_bindings, 1604 input_token, actual_mech_type, 1605 output_token, ret_flags, time_rec, 1606 context); 1607 } 1608 1609 unlock: 1610 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL && cred != NULL) 1611 krb5_gss_release_cred_no_lock(context, &tmp_min_stat, (gss_cred_id_t *)cred); 1612 1613 mutex_unlock(&krb5_mutex); 1614 1615 KRB5_LOG1(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1616 "major_status = %d, minor_status = %d\n", 1617 major_status, *minor_status); 1618 1619 return (major_status); 1620 } 1621