1 /* 2 * Copyright 2007 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 713 /* 714 * Solaris Kerberos: 715 * If the client's realm is empty (using a fallback method to determine 716 * the realm) then make sure to set the client's realm to the default 717 * realm. This ensures that the TGT is built correctly. 718 */ 719 if (krb5_is_referral_realm(&(me->realm))) { 720 char *realm; 721 722 free(me->realm.data); 723 code = krb5_get_default_realm(context, &realm); 724 if (code) { 725 (void) krb5_kt_close(context, keytab); 726 *minor_status = code; 727 return (GSS_S_FAILURE); 728 } 729 730 me->realm.data = realm; 731 me->realm.length = strlen(realm); 732 } 733 734 my_creds.client = me; 735 736 if((code = krb5_build_principal_ext(context, &server, 737 krb5_princ_realm(context, me)->length, 738 krb5_princ_realm(context, me)->data, 739 tgtname.length, tgtname.data, 740 krb5_princ_realm(context, me)->length, 741 krb5_princ_realm(context, me)->data, 742 0))) { 743 *minor_status = code; 744 krb5_free_cred_contents(context, &my_creds); 745 (void) krb5_kt_close(context, keytab); 746 747 return (GSS_S_FAILURE); 748 } 749 750 my_creds.server = server; 751 my_creds.times.starttime = 0; /* start timer 752 * when request 753 * gets to KDC 754 */ 755 if ((code = krb5_timeofday(context, &now))) { 756 *minor_status = code; 757 krb5_free_cred_contents(context, &my_creds); 758 (void) krb5_kt_close(context, keytab); 759 760 return (GSS_S_FAILURE); 761 } 762 my_creds.times.endtime = now + lifetime; 763 my_creds.times.renew_till = 0; 764 765 memset(&opt, 0, sizeof (opt)); 766 krb5_get_init_creds_opt_init(&opt); 767 krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime); 768 769 code = krb5_unparse_name(context, server, &svcname); 770 if (code != 0) { 771 *minor_status = code; 772 krb5_free_cred_contents(context, &my_creds); 773 (void) krb5_kt_close(context, keytab); 774 775 return (GSS_S_FAILURE); 776 } 777 code = krb5_get_init_creds_keytab(context, 778 &my_creds, me, keytab, 779 0, svcname, &opt); 780 781 (void) krb5_kt_close(context, keytab); 782 783 if (svcname != NULL) 784 free(svcname); 785 if (code) { 786 *minor_status = code; 787 krb5_free_cred_contents(context, &my_creds); 788 789 return (GSS_S_FAILURE); 790 } 791 code = krb5_cc_resolve (context, 792 krb5_cc_default_name(context), 793 &ccache); 794 if (code != 0) { 795 *minor_status = code; 796 krb5_free_cred_contents(context, &my_creds); 797 798 return (GSS_S_FAILURE); 799 } 800 code = krb5_cc_initialize (context, ccache, me); 801 if (code != 0) { 802 *minor_status = code; 803 krb5_free_cred_contents(context, &my_creds); 804 (void) krb5_cc_close(context, ccache); 805 806 return (GSS_S_FAILURE); 807 } 808 809 code = krb5_cc_store_cred(context, ccache, 810 &my_creds); 811 krb5_free_cred_contents(context, &my_creds); 812 (void) krb5_cc_close(context, ccache); 813 814 if (code) { 815 *minor_status = code; 816 817 KRB5_LOG(KRB5_ERR, "load_root_cred_using_keytab() end, error " 818 "code = %d\n", code); 819 820 return (GSS_S_FAILURE); 821 } 822 823 KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() end \n"); 824 825 return (GSS_S_COMPLETE); 826 } 827 828 static OM_uint32 829 renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid) 830 { 831 krb5_principal me; 832 krb5_principal server; 833 krb5_creds creds; 834 krb5_creds tmpcreds; 835 krb5_creds *out_creds; 836 krb5_error_code code; 837 krb5_ccache ccache = NULL; 838 static char ccache_name_buf[CACHE_FILENAME_LEN]; 839 int options = 0; 840 krb5_data tgtname = { 841 0, 842 KRB5_TGS_NAME_SIZE, 843 KRB5_TGS_NAME 844 }; 845 gid_t gid = getgid(); 846 847 memset((char *)&creds, 0, sizeof(creds)); 848 memset((char *)&tmpcreds, 0, sizeof(creds)); 849 850 if ((code = krb5_cc_default(context, &ccache))) { 851 *minor_status = code; 852 (void) krb5_cc_close(context, ccache); 853 return (GSS_S_FAILURE); 854 } 855 856 if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) { 857 *minor_status = code; 858 (void) krb5_cc_close(context, ccache); 859 return (GSS_S_FAILURE); 860 } 861 862 creds.client = me; 863 864 if((code = krb5_build_principal_ext(context, &server, 865 krb5_princ_realm(context, me)->length, 866 krb5_princ_realm(context, me)->data, 867 tgtname.length, tgtname.data, 868 krb5_princ_realm(context, me)->length, 869 krb5_princ_realm(context, me)->data, 870 0))) { 871 krb5_free_principal(context, me); 872 (void) krb5_cc_close(context, ccache); 873 *minor_status = code; 874 return (GSS_S_FAILURE); 875 } 876 877 creds.server = server; 878 creds.ticket_flags = TKT_FLG_RENEWABLE; 879 880 if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS, 881 &creds, &tmpcreds))) { 882 (void) krb5_cc_close(context, ccache); 883 return (KDC_ERR_BADOPTION); 884 } 885 886 creds.ticket_flags = 0; 887 code = krb5_get_credentials_renew(context, options, ccache, 888 &creds, &out_creds); 889 krb5_free_cred_contents(context, &creds); 890 krb5_free_cred_contents(context, &tmpcreds); 891 892 if (code) { 893 *minor_status = code; 894 return (GSS_S_FAILURE); 895 } 896 897 krb5_free_creds(context, out_creds); 898 snprintf(ccache_name_buf, CACHE_FILENAME_LEN, "/tmp/krb5cc_%d", 899 uid, -1); 900 code = safechown(ccache_name_buf, uid, gid, -1); 901 902 if (code == -1) { 903 (void) krb5_cc_destroy(context, ccache); 904 *minor_status = code; 905 return (GSS_S_FAILURE); 906 } 907 908 (void) krb5_cc_close(context, ccache); 909 910 return (GSS_S_COMPLETE); 911 912 } 913 914 /* 915 * Solaris Kerberos: 916 * We enforce a minimum refresh time on the root cred. This avoids problems for 917 * the higher level communication protocol for having valid creds and 918 * setting up a valid context, only to have it expire before or while 919 * it is being used. For non root users we don't care since we do not refresh 920 * there creds, they get what they can get. 921 */ 922 #define MIN_REFRESH_TIME 300 923 #define MIN_RENEW_TIME 1500 924 925 /* get_default_cred() must be called with the krb5_mutex lock held */ 926 static OM_uint32 927 get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle) 928 { 929 krb5_timestamp now; 930 krb5_gss_cred_id_t cred; 931 OM_uint32 major; 932 OM_uint32 mntmp; 933 /* 934 * Solaris Kerberos 935 * Use krb5_getuid() to select the mechanism to obtain the uid. 936 */ 937 uid_t uid = krb5_getuid(); 938 krb5_context context = (krb5_context)ct; 939 940 KRB5_LOG0(KRB5_INFO, "get_default_cred() start\n"); 941 942 /* Get the default cred for user */ 943 if (((major = kg_get_defcred(minor_status, cred_handle)) != NULL) && 944 GSS_ERROR(major)) { 945 946 /* If we're not root we're done */ 947 if (uid != ROOT_UID) 948 return (major); 949 950 /* 951 * Try and get root's cred in the cache using keytab. 952 * 953 * First try "root" and then try "host" - this allows 954 * Secure NFS to use the host principal for mounting if 955 * there is no root principal. 956 * 957 * Then try "host/<anything>" to match any instance (needed 958 * for DHCP clients). 959 */ 960 major = load_root_cred_using_keytab(minor_status, 961 context, "root", 1); 962 963 if (major != GSS_S_COMPLETE) 964 major = load_root_cred_using_keytab(minor_status, 965 context, "host", 1); 966 if (major != GSS_S_COMPLETE) 967 major = load_root_cred_using_keytab(minor_status, 968 context, "host", 0); 969 970 if (major != GSS_S_COMPLETE) 971 return (major); 972 973 /* We should have valid tgt now in the cache, so get it. */ 974 major = kg_get_defcred(minor_status, cred_handle); 975 976 return (major); 977 } 978 979 /* We've got a gss cred handle that is a kerberos cred handle. */ 980 cred = (krb5_gss_cred_id_t)*cred_handle; 981 982 /* If we can't get the time, assume the worst. */ 983 if (krb5_timeofday(context, &now)) { 984 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 985 return (GSS_S_CREDENTIALS_EXPIRED); 986 } 987 988 /* If root's cred has expired re-get it */ 989 if (cred->tgt_expire < now + MIN_REFRESH_TIME && uid == ROOT_UID) { 990 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 991 992 major = load_root_cred_using_keytab(minor_status, 993 context, "root", 1); 994 995 if (major != GSS_S_COMPLETE) 996 major = load_root_cred_using_keytab(minor_status, 997 context, "host", 1); 998 999 if (major != GSS_S_COMPLETE) 1000 major = load_root_cred_using_keytab(minor_status, 1001 context, "host", 0); 1002 1003 if (major != GSS_S_COMPLETE) 1004 return (major); 1005 1006 major = kg_get_defcred(minor_status, cred_handle); 1007 if (major != GSS_S_COMPLETE) 1008 return (major); 1009 1010 /* Any body else is SOL unless we can renew their credential cache */ 1011 } else if ((cred->tgt_expire < now + MIN_RENEW_TIME) && 1012 (cred->tgt_expire > now)) { 1013 (void) krb5_gss_release_cred_no_lock(ct, &mntmp, cred_handle); 1014 1015 major = renew_ccache(minor_status, context, uid); 1016 if ((major != GSS_S_COMPLETE) && 1017 (major != KDC_ERR_BADOPTION)) 1018 return (major); 1019 1020 major = kg_get_defcred(minor_status, cred_handle); 1021 if (major != GSS_S_COMPLETE) 1022 return (major); 1023 1024 } 1025 1026 /* Otherwise we got non expired creds */ 1027 1028 KRB5_LOG0(KRB5_INFO, "get_default_cred() end\n"); 1029 1030 return (GSS_S_COMPLETE); 1031 } 1032 1033 /* 1034 * setup_enc 1035 * 1036 * Fill in the encryption descriptors. Called after AP-REQ is made. 1037 */ 1038 static OM_uint32 1039 setup_enc( 1040 OM_uint32 *minor_status, 1041 krb5_gss_ctx_id_rec *ctx, 1042 krb5_context context) 1043 { 1044 krb5_error_code code; 1045 OM_uint32 ret = GSS_S_COMPLETE; 1046 int i; 1047 1048 ctx->have_acceptor_subkey = 0; 1049 ctx->proto = 0; 1050 ctx->cksumtype = 0; 1051 1052 KRB5_LOG(KRB5_ERR, "setup_enc() enctype = %d\n", 1053 ctx->subkey->enctype); 1054 1055 switch(ctx->subkey->enctype) { 1056 case ENCTYPE_DES_CBC_MD5: 1057 case ENCTYPE_DES_CBC_MD4: 1058 case ENCTYPE_DES_CBC_CRC: 1059 ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; 1060 ctx->signalg = SGN_ALG_DES_MAC_MD5; 1061 ctx->cksum_size = 8; 1062 ctx->sealalg = SEAL_ALG_DES; 1063 1064 /* The encryption key is the session key XOR 1065 0xf0f0f0f0f0f0f0f0. */ 1066 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) 1067 goto fail; 1068 1069 for (i=0; i<ctx->enc->length; i++) 1070 ctx->enc->contents[i] ^= 0xf0; 1071 1072 goto copy_subkey_to_seq; 1073 1074 case ENCTYPE_DES3_CBC_SHA1: 1075 /* MIT extension */ 1076 ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW; 1077 ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; 1078 ctx->cksum_size = 20; 1079 ctx->sealalg = SEAL_ALG_DES3KD; 1080 1081 copy_subkey: 1082 code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); 1083 if (code) 1084 goto fail; 1085 copy_subkey_to_seq: 1086 code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); 1087 if (code) { 1088 krb5_free_keyblock (context, ctx->enc); 1089 goto fail; 1090 } 1091 break; 1092 1093 case ENCTYPE_ARCFOUR_HMAC: 1094 /* Microsoft extension */ 1095 ctx->signalg = SGN_ALG_HMAC_MD5 ; 1096 ctx->cksum_size = 8; 1097 ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; 1098 1099 goto copy_subkey; 1100 1101 default: 1102 /* Fill some fields we shouldn't be using on this path 1103 with garbage. */ 1104 ctx->signalg = -10; 1105 ctx->sealalg = -10; 1106 1107 ctx->proto = 1; 1108 code = krb5int_c_mandatory_cksumtype(context, ctx->subkey->enctype, 1109 &ctx->cksumtype); 1110 if (code) 1111 goto fail; 1112 code = krb5_c_checksum_length(context, ctx->cksumtype, 1113 (size_t *)&ctx->cksum_size); 1114 if (code) 1115 goto fail; 1116 goto copy_subkey; 1117 } 1118 fail: 1119 if (code) { 1120 *minor_status = code; 1121 ret = GSS_S_FAILURE; 1122 } 1123 success: 1124 return (ret); 1125 } 1126 1127 /* 1128 * new_connection 1129 * 1130 * Do the grunt work of setting up a new context. 1131 */ 1132 static OM_uint32 1133 new_connection( 1134 OM_uint32 *minor_status, 1135 krb5_gss_cred_id_t cred, 1136 gss_ctx_id_t *context_handle, 1137 gss_name_t target_name, 1138 gss_OID mech_type, 1139 OM_uint32 req_flags, 1140 OM_uint32 time_req, 1141 gss_channel_bindings_t input_chan_bindings, 1142 gss_buffer_t input_token, 1143 gss_OID *actual_mech_type, 1144 gss_buffer_t output_token, 1145 OM_uint32 *ret_flags, 1146 OM_uint32 *time_rec, 1147 krb5_context context, 1148 int default_mech) 1149 { 1150 OM_uint32 major_status; 1151 krb5_error_code code; 1152 krb5_creds *k_cred; 1153 krb5_gss_ctx_id_rec *ctx, *ctx_free; 1154 krb5_timestamp now; 1155 gss_buffer_desc token; 1156 1157 major_status = GSS_S_FAILURE; 1158 token.length = 0; 1159 token.value = NULL; 1160 1161 /* make sure the cred is usable for init */ 1162 1163 if ((cred->usage != GSS_C_INITIATE) && 1164 (cred->usage != GSS_C_BOTH)) { 1165 *minor_status = 0; 1166 return(GSS_S_NO_CRED); 1167 } 1168 1169 /* complain if the input token is non-null */ 1170 1171 if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { 1172 *minor_status = 0; 1173 return(GSS_S_DEFECTIVE_TOKEN); 1174 } 1175 1176 /* create the ctx */ 1177 1178 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) 1179 == NULL) { 1180 *minor_status = ENOMEM; 1181 return(GSS_S_FAILURE); 1182 } 1183 1184 /* fill in the ctx */ 1185 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); 1186 ctx_free = ctx; 1187 if ((code = krb5_auth_con_init(context, &ctx->auth_context))) 1188 goto fail; 1189 krb5_auth_con_setflags(context, ctx->auth_context, 1190 KRB5_AUTH_CONTEXT_DO_SEQUENCE); 1191 ctx->initiate = 1; 1192 ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | 1193 GSS_C_TRANS_FLAG | GSS_C_PROT_READY_FLAG | 1194 ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | 1195 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG))); 1196 ctx->seed_init = 0; 1197 ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ 1198 ctx->seqstate = 0; 1199 if ((code = krb5_timeofday(context, &now))) 1200 goto fail; 1201 1202 if (time_req == 0 || time_req == GSS_C_INDEFINITE) { 1203 ctx->endtime = 0; 1204 } else { 1205 ctx->endtime = now + time_req; 1206 } 1207 1208 if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) 1209 goto fail; 1210 1211 if ((code = krb5_copy_principal(context, (krb5_principal) target_name, 1212 &ctx->there))) 1213 goto fail; 1214 1215 code = get_credentials(context, cred, ctx->there, now, 1216 ctx->endtime, &k_cred); 1217 if (code) 1218 goto fail; 1219 1220 if (default_mech) { 1221 mech_type = (gss_OID) gss_mech_krb5; 1222 } 1223 /* Solaris Kerberos: we allocate the memory for mech_used here 1224 * because we store mech_used as a gss_OID and not a (gss_OID *) 1225 */ 1226 ctx->mech_used.elements = malloc(mech_type->length); 1227 if ( (ctx->mech_used.elements) == NULL ) { 1228 code = ENOMEM; 1229 major_status = GSS_S_FAILURE; 1230 goto fail; 1231 } 1232 ctx->mech_used.length = mech_type->length; 1233 memcpy(ctx->mech_used.elements, mech_type->elements, mech_type->length); 1234 1235 /* 1236 * Now try to make it static if at all possible.... 1237 */ 1238 /* Solaris Kerberos: our mech_used is part of the ctx structure */ 1239 /* ctx->mech_used = krb5_gss_convert_static_mech_oid(&(ctx->mech_used)); */ 1240 { 1241 /* gsskrb5 v1 */ 1242 krb5_ui_4 seq_temp; 1243 if ((code = make_ap_req_v1(context, ctx, 1244 cred, k_cred, input_chan_bindings, 1245 mech_type, &token))) { 1246 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || 1247 (code == KG_EMPTY_CCACHE)) 1248 major_status = GSS_S_NO_CRED; 1249 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) 1250 major_status = GSS_S_CREDENTIALS_EXPIRED; 1251 goto fail; 1252 } 1253 1254 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, 1255 (krb5_int32 *)&seq_temp); 1256 ctx->seq_send = seq_temp; 1257 krb5_auth_con_getsendsubkey(context, ctx->auth_context, 1258 &ctx->subkey); 1259 } 1260 1261 major_status = setup_enc(minor_status, ctx, context); 1262 1263 if (k_cred) { 1264 krb5_free_creds(context, k_cred); 1265 k_cred = 0; 1266 } 1267 1268 /* at this point, the context is constructed and valid, 1269 hence, releaseable */ 1270 1271 /* intern the context handle */ 1272 1273 if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { 1274 code = G_VALIDATE_FAILED; 1275 goto fail; 1276 } 1277 *context_handle = (gss_ctx_id_t) ctx; 1278 ctx_free = 0; 1279 /* compute time_rec */ 1280 if (time_rec) { 1281 if ((code = krb5_timeofday(context, &now))) 1282 goto fail; 1283 *time_rec = ctx->endtime - now; 1284 } 1285 1286 /* set the other returns */ 1287 *output_token = token; 1288 1289 if (ret_flags) 1290 *ret_flags = ctx->gss_flags; 1291 1292 if (actual_mech_type) 1293 *actual_mech_type = mech_type; 1294 1295 /* return successfully */ 1296 1297 *minor_status = 0; 1298 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { 1299 ctx->established = 0; 1300 return(GSS_S_CONTINUE_NEEDED); 1301 } else { 1302 ctx->seq_recv = ctx->seq_send; 1303 g_order_init(&(ctx->seqstate), ctx->seq_recv, 1304 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, 1305 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto); 1306 ctx->gss_flags |= GSS_C_PROT_READY_FLAG; 1307 ctx->established = 1; 1308 return(GSS_S_COMPLETE); 1309 } 1310 1311 fail: 1312 if (ctx_free) { 1313 if (ctx_free->auth_context) 1314 krb5_auth_con_free(context, ctx_free->auth_context); 1315 if (ctx_free->here) 1316 krb5_free_principal(context, ctx_free->here); 1317 if (ctx_free->there) 1318 krb5_free_principal(context, ctx_free->there); 1319 if (ctx_free->subkey) 1320 krb5_free_keyblock(context, ctx_free->subkey); 1321 xfree(ctx_free); 1322 } else { 1323 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1324 context_handle, NULL); 1325 } 1326 1327 *minor_status = code; 1328 return (major_status); 1329 } 1330 1331 /* 1332 * mutual_auth 1333 * 1334 * Handle the reply from the acceptor, if we're doing mutual auth. 1335 */ 1336 static OM_uint32 1337 mutual_auth( 1338 OM_uint32 *minor_status, 1339 krb5_gss_cred_id_t cred, 1340 gss_ctx_id_t *context_handle, 1341 gss_name_t target_name, 1342 gss_OID mech_type, 1343 OM_uint32 req_flags, 1344 OM_uint32 time_req, 1345 gss_channel_bindings_t input_chan_bindings, 1346 gss_buffer_t input_token, 1347 gss_OID *actual_mech_type, 1348 gss_buffer_t output_token, 1349 OM_uint32 *ret_flags, 1350 OM_uint32 *time_rec, 1351 krb5_context context) 1352 { 1353 OM_uint32 major_status; 1354 unsigned char *ptr; 1355 char *sptr; 1356 krb5_data ap_rep; 1357 krb5_ap_rep_enc_part *ap_rep_data; 1358 krb5_timestamp now; 1359 krb5_gss_ctx_id_rec *ctx; 1360 krb5_error *krb_error; 1361 krb5_error_code code; 1362 1363 major_status = GSS_S_FAILURE; 1364 1365 /* validate the context handle */ 1366 /*SUPPRESS 29*/ 1367 if (! kg_validate_ctx_id(*context_handle)) { 1368 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 1369 return(GSS_S_NO_CONTEXT); 1370 } 1371 1372 ctx = (krb5_gss_ctx_id_rec *) *context_handle; 1373 1374 /* make sure the context is non-established, and that certain 1375 arguments are unchanged */ 1376 1377 if ((ctx->established) || 1378 ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { 1379 code = KG_CONTEXT_ESTABLISHED; 1380 goto fail; 1381 } 1382 1383 if (! krb5_principal_compare(context, ctx->there, 1384 (krb5_principal) target_name)) { 1385 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1386 context_handle, NULL); 1387 code = 0; 1388 major_status = GSS_S_BAD_NAME; 1389 goto fail; 1390 } 1391 1392 /* verify the token and leave the AP_REP message in ap_rep */ 1393 1394 if (input_token == GSS_C_NO_BUFFER) { 1395 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1396 context_handle, NULL); 1397 code = 0; 1398 major_status = GSS_S_DEFECTIVE_TOKEN; 1399 goto fail; 1400 } 1401 1402 ptr = (unsigned char *) input_token->value; 1403 1404 if (g_verify_token_header(&ctx->mech_used, 1405 (uint32_t *)&(ap_rep.length), 1406 &ptr, KG_TOK_CTX_AP_REP, 1407 input_token->length, 1)) { 1408 if (g_verify_token_header(&ctx->mech_used, 1409 (uint32_t *)&(ap_rep.length), 1410 &ptr, KG_TOK_CTX_ERROR, 1411 input_token->length, 1) == 0) { 1412 1413 /* Handle a KRB_ERROR message from the server */ 1414 1415 sptr = (char *) ptr; /* PC compiler bug */ 1416 TREAD_STR(sptr, ap_rep.data, ap_rep.length); 1417 1418 code = krb5_rd_error(context, &ap_rep, &krb_error); 1419 if (code) 1420 goto fail; 1421 if (krb_error->error) 1422 code = krb_error->error + ERROR_TABLE_BASE_krb5; 1423 else 1424 code = 0; 1425 krb5_free_error(context, krb_error); 1426 goto fail; 1427 } else { 1428 *minor_status = 0; 1429 return(GSS_S_DEFECTIVE_TOKEN); 1430 } 1431 } 1432 1433 sptr = (char *) ptr; /* PC compiler bug */ 1434 TREAD_STR(sptr, ap_rep.data, ap_rep.length); 1435 1436 /* decode the ap_rep */ 1437 if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, 1438 &ap_rep_data))) { 1439 /* 1440 * XXX A hack for backwards compatiblity. 1441 * To be removed in 1999 -- proven 1442 */ 1443 krb5_auth_con_setuseruserkey(context, ctx->auth_context, 1444 ctx->subkey); 1445 if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, 1446 &ap_rep_data))) 1447 goto fail; 1448 } 1449 1450 /* store away the sequence number */ 1451 ctx->seq_recv = ap_rep_data->seq_number; 1452 g_order_init(&(ctx->seqstate), ctx->seq_recv, 1453 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, 1454 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto); 1455 1456 if (ctx->proto == 1 && ap_rep_data->subkey) { 1457 /* Keep acceptor's subkey. */ 1458 ctx->have_acceptor_subkey = 1; 1459 code = krb5_copy_keyblock(context, ap_rep_data->subkey, 1460 &ctx->acceptor_subkey); 1461 if (code) 1462 goto fail; 1463 code = krb5int_c_mandatory_cksumtype(context, 1464 ctx->acceptor_subkey->enctype, 1465 &ctx->acceptor_subkey_cksumtype); 1466 if (code) 1467 goto fail; 1468 } 1469 1470 /* free the ap_rep_data */ 1471 krb5_free_ap_rep_enc_part(context, ap_rep_data); 1472 1473 /* set established */ 1474 ctx->established = 1; 1475 1476 /* set returns */ 1477 1478 if (time_rec) { 1479 if ((code = krb5_timeofday(context, &now))) 1480 goto fail; 1481 *time_rec = ctx->endtime - now; 1482 } 1483 if (ret_flags) 1484 *ret_flags = ctx->gss_flags; 1485 1486 if (actual_mech_type) 1487 *actual_mech_type = mech_type; 1488 1489 /* success */ 1490 1491 *minor_status = 0; 1492 return GSS_S_COMPLETE; 1493 1494 fail: 1495 (void)krb5_gss_delete_sec_context_no_lock(context, minor_status, 1496 context_handle, NULL); 1497 1498 *minor_status = code; 1499 return (major_status); 1500 } 1501 1502 /* 1503 * krb5_gss_init_sec_context 1504 * This has been broken up into smaller chunks for CFX support. 1505 * MIT KRB5 1.3.2 1506 */ 1507 OM_uint32 1508 krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, 1509 context_handle, target_name, mech_type, 1510 req_flags, time_req, input_chan_bindings, 1511 input_token, actual_mech_type, output_token, 1512 ret_flags, time_rec) 1513 void *ct; 1514 OM_uint32 *minor_status; 1515 gss_cred_id_t claimant_cred_handle; 1516 gss_ctx_id_t *context_handle; 1517 gss_name_t target_name; 1518 gss_OID mech_type; 1519 OM_uint32 req_flags; 1520 OM_uint32 time_req; 1521 gss_channel_bindings_t input_chan_bindings; 1522 gss_buffer_t input_token; 1523 gss_OID *actual_mech_type; 1524 gss_buffer_t output_token; 1525 OM_uint32 *ret_flags; 1526 OM_uint32 *time_rec; 1527 { 1528 krb5_context context; 1529 krb5_gss_cred_id_t cred = NULL; 1530 int err; 1531 int default_mech = 0; 1532 OM_uint32 major_status; 1533 OM_uint32 tmp_min_stat; 1534 1535 /* Solaris Kerberos: for MT safety, we avoid the use of a default 1536 * context via kg_get_context() */ 1537 #if 0 1538 if (GSS_ERROR(kg_get_context(minor_status, &context))) 1539 return(GSS_S_FAILURE); 1540 #endif 1541 1542 KRB5_LOG0(KRB5_INFO, "krb5_gss_init_sec_context() start\n"); 1543 1544 mutex_lock(&krb5_mutex); 1545 context = ct; 1546 1547 /* set up return values so they can be "freed" successfully */ 1548 1549 major_status = GSS_S_FAILURE; /* Default major code */ 1550 output_token->length = 0; 1551 output_token->value = NULL; 1552 if (actual_mech_type) 1553 *actual_mech_type = NULL; 1554 1555 /* verify that the target_name is valid and usable */ 1556 1557 if (! kg_validate_name(target_name)) { 1558 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 1559 major_status = (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); 1560 goto unlock; 1561 } 1562 1563 /* verify the credential, or use the default */ 1564 /*SUPPRESS 29*/ 1565 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { 1566 /* 1567 * Solaris Kerberos: here we are using the Solaris specific 1568 * function get_default_cred() to handle the special case of a 1569 * root principal 1570 */ 1571 major_status = get_default_cred(minor_status, ct, (gss_cred_id_t *)&cred); 1572 if (major_status && GSS_ERROR(major_status)) { 1573 KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1574 "major_status = %d\n", major_status); 1575 goto unlock; 1576 } 1577 } else { 1578 major_status = krb5_gss_validate_cred_no_lock(ct, minor_status, 1579 claimant_cred_handle); 1580 if (GSS_ERROR(major_status)) { 1581 KRB5_LOG(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1582 "major_status = %d\n", major_status); 1583 goto unlock; 1584 } 1585 cred = (krb5_gss_cred_id_t) claimant_cred_handle; 1586 } 1587 1588 /* verify the mech_type */ 1589 1590 err = 0; 1591 if (mech_type == GSS_C_NULL_OID) { 1592 default_mech = 1; 1593 if (cred->rfc_mech) { 1594 mech_type = (gss_OID) gss_mech_krb5; 1595 } else if (cred->prerfc_mech) { 1596 mech_type = (gss_OID) gss_mech_krb5_old; 1597 } else { 1598 err = 1; 1599 } 1600 } else if (g_OID_equal(mech_type, gss_mech_krb5)) { 1601 if (!cred->rfc_mech) 1602 err = 1; 1603 } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { 1604 if (!cred->prerfc_mech) 1605 err = 1; 1606 } else { 1607 err = 1; 1608 } 1609 1610 if (err) { 1611 *minor_status = 0; 1612 major_status = GSS_S_BAD_MECH; 1613 goto unlock; 1614 } 1615 1616 /* is this a new connection or not? */ 1617 1618 /*SUPPRESS 29*/ 1619 if (*context_handle == GSS_C_NO_CONTEXT) { 1620 major_status = new_connection(minor_status, cred, context_handle, 1621 target_name, mech_type, req_flags, 1622 time_req, input_chan_bindings, 1623 input_token, actual_mech_type, 1624 output_token, ret_flags, time_rec, 1625 context, default_mech); 1626 } else { 1627 major_status = mutual_auth(minor_status, cred, context_handle, 1628 target_name, mech_type, req_flags, 1629 time_req, input_chan_bindings, 1630 input_token, actual_mech_type, 1631 output_token, ret_flags, time_rec, 1632 context); 1633 } 1634 1635 unlock: 1636 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL && cred != NULL) 1637 krb5_gss_release_cred_no_lock(context, &tmp_min_stat, (gss_cred_id_t *)cred); 1638 1639 mutex_unlock(&krb5_mutex); 1640 1641 KRB5_LOG1(KRB5_ERR, "krb5_gss_init_sec_context() end, error " 1642 "major_status = %d, minor_status = %d\n", 1643 major_status, *minor_status); 1644 1645 return (major_status); 1646 } 1647