137Srgrimes/*- 237Srgrimes * Copyright (c) 1991, 1993 3147Srgrimes * The Regents of the University of California. All rights reserved. 4147Srgrimes * 5147Srgrimes * Redistribution and use in source and binary forms, with or without 637Srgrimes * modification, are permitted provided that the following conditions 737Srgrimes * are met: 837Srgrimes * 1. Redistributions of source code must retain the above copyright 937Srgrimes * notice, this list of conditions and the following disclaimer. 10147Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 11147Srgrimes * notice, this list of conditions and the following disclaimer in the 12147Srgrimes * documentation and/or other materials provided with the distribution. 13207Snate * 3. All advertising materials mentioning features or use of this software 14258Srgrimes * must display the following acknowledgement: 15147Srgrimes * This product includes software developed by the University of 16147Srgrimes * California, Berkeley and its contributors. 1737Srgrimes * 4. Neither the name of the University nor the names of its contributors 1837Srgrimes * may be used to endorse or promote products derived from this software 1937Srgrimes * without specific prior written permission. 2037Srgrimes * 21147Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22147Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23147Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2437Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2537Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2637Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2737Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2837Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2937Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30263Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31284Srgrimes * SUCH DAMAGE. 32284Srgrimes */ 33277Srgrimes 34277Srgrimes/* 35284Srgrimes * Copyright (C) 1990 by the Massachusetts Institute of Technology 36284Srgrimes * 37284Srgrimes * Export of this software from the United States of America may 38284Srgrimes * require a specific license from the United States Government. 39284Srgrimes * It is the responsibility of any person or organization contemplating 40284Srgrimes * export to obtain such a license before exporting. 41284Srgrimes * 42284Srgrimes * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 43284Srgrimes * distribute this software and its documentation for any purpose and 44284Srgrimes * without fee is hereby granted, provided that the above copyright 45284Srgrimes * notice appear in all copies and that both that copyright notice and 46284Srgrimes * this permission notice appear in supporting documentation, and that 47284Srgrimes * the name of M.I.T. not be used in advertising or publicity pertaining 48284Srgrimes * to distribution of the software without specific, written prior 49284Srgrimes * permission. M.I.T. makes no representations about the suitability of 50284Srgrimes * this software for any purpose. It is provided "as is" without express 51284Srgrimes * or implied warranty. 52284Srgrimes */ 53284Srgrimes 54284Srgrimes#include <config.h> 55284Srgrimes 56284SrgrimesRCSID("$Id$"); 57284Srgrimes 58284Srgrimes#ifdef KRB5 59263Srgrimes 60284Srgrimes#include <arpa/telnet.h> 61284Srgrimes#include <stdio.h> 62284Srgrimes#include <stdlib.h> 63284Srgrimes#include <string.h> 64284Srgrimes#include <unistd.h> 65284Srgrimes#include <netdb.h> 66284Srgrimes#include <ctype.h> 67284Srgrimes#include <pwd.h> 68284Srgrimes#define Authenticator k5_Authenticator 69284Srgrimes#include <krb5.h> 70284Srgrimes#undef Authenticator 71284Srgrimes#include <roken.h> 72284Srgrimes#ifdef SOCKS 73284Srgrimes#include <socks.h> 74284Srgrimes#endif 7537Srgrimes 7637Srgrimes 77147Srgrimes#include "encrypt.h" 7837Srgrimes#include "auth.h" 7937Srgrimes#include "misc.h" 80147Srgrimes 81147Srgrimes#if defined(DCE) 82238Srootint dfsk5ok = 0; 8337Srgrimesint dfspag = 0; 84163Srgrimesint dfsfwd = 0; 85238Sroot#endif 86163Srgrimes 87163Srgrimesint forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ 88163Srgrimes 89163Srgrimesint forward(int); 90163Srgrimesint forwardable(int); 91163Srgrimes 92284Srgrimes/* These values need to be the same as those defined in telnet/main.c. */ 9337Srgrimes/* Either define them in both places, or put in some common header file. */ 9437Srgrimes#define OPTS_FORWARD_CREDS 0x00000002 95147Srgrimes#define OPTS_FORWARDABLE_CREDS 0x00000001 9637Srgrimes 9737Srgrimes 9837Srgrimesvoid kerberos5_forward (Authenticator *); 9937Srgrimes 10037Srgrimesstatic unsigned char str_data[4] = { IAC, SB, TELOPT_AUTHENTICATION, 0 }; 10137Srgrimes 10237Srgrimes#define KRB_AUTH 0 /* Authentication data follows */ 10337Srgrimes#define KRB_REJECT 1 /* Rejected (reason might follow) */ 10437Srgrimes#define KRB_ACCEPT 2 /* Accepted */ 10537Srgrimes#define KRB_RESPONSE 3 /* Response for mutual auth. */ 10637Srgrimes 10737Srgrimes#define KRB_FORWARD 4 /* Forwarded credentials follow */ 10837Srgrimes#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 10937Srgrimes#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 11037Srgrimes 11137Srgrimesstatic krb5_data auth; 112147Srgrimesstatic krb5_ticket *ticket; 113147Srgrimes 11437Srgrimesstatic krb5_context context; 11537Srgrimesstatic krb5_auth_context auth_context; 116147Srgrimes 117147Srgrimesstatic int 11837SrgrimesData(Authenticator *ap, int type, const void *d, int c) 119147Srgrimes{ 12037Srgrimes const unsigned char *cp, *cd = d; 12137Srgrimes unsigned char *p0, *p; 12237Srgrimes size_t len = sizeof(str_data) + 3 + 2; 123284Srgrimes int ret; 124284Srgrimes 125147Srgrimes if (c == -1) 12637Srgrimes c = strlen((const char*)cd); 127147Srgrimes 128147Srgrimes for (cp = cd; cp - cd < c; cp++, len++) 12937Srgrimes if (*cp == IAC) 13037Srgrimes len++; 131147Srgrimes 13237Srgrimes p0 = malloc(len); 13337Srgrimes if (p0 == NULL) 13437Srgrimes return 0; 13537Srgrimes 13637Srgrimes memcpy(p0, str_data, sizeof(str_data)); 13737Srgrimes p = p0 + sizeof(str_data); 13837Srgrimes 13937Srgrimes if (auth_debug_mode) { 140168Srgrimes printf("%s:%d: [%d] (%d)", 141277Srgrimes str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 142277Srgrimes str_data[3], 143284Srgrimes type, c); 144284Srgrimes printd(d, c); 145277Srgrimes printf("\r\n"); 146277Srgrimes } 147277Srgrimes *p++ = ap->type; 148277Srgrimes *p++ = ap->way; 149238Sroot *p++ = type; 150238Sroot while (c-- > 0) { 151277Srgrimes if ((*p++ = *cd++) == IAC) 152277Srgrimes *p++ = IAC; 153168Srgrimes } 154277Srgrimes *p++ = IAC; 155277Srgrimes *p++ = SE; 156277Srgrimes if (str_data[3] == TELQUAL_IS) 157277Srgrimes printsub('>', &p0[2], len - 2); 158277Srgrimes ret = telnet_net_write(p0, len); 159266Srgrimes free(p0); 160168Srgrimes return ret; 16137Srgrimes} 16237Srgrimes 16337Srgrimesint 16437Srgrimeskerberos5_init(Authenticator *ap, int server) 16537Srgrimes{ 166284Srgrimes krb5_error_code ret; 167277Srgrimes 168277Srgrimes ret = krb5_init_context(&context); 169277Srgrimes if (ret) 170284Srgrimes return 0; 171284Srgrimes if (server) { 172277Srgrimes krb5_keytab kt; 173277Srgrimes krb5_kt_cursor cursor; 174277Srgrimes 175277Srgrimes ret = krb5_kt_default(context, &kt); 176284Srgrimes if (ret) 177284Srgrimes return 0; 178277Srgrimes 179277Srgrimes ret = krb5_kt_start_seq_get (context, kt, &cursor); 180277Srgrimes if (ret) { 181277Srgrimes krb5_kt_close (context, kt); 182277Srgrimes return 0; 183277Srgrimes } 184277Srgrimes krb5_kt_end_seq_get (context, kt, &cursor); 185277Srgrimes krb5_kt_close (context, kt); 186284Srgrimes 187284Srgrimes str_data[3] = TELQUAL_REPLY; 188284Srgrimes } else 189284Srgrimes str_data[3] = TELQUAL_IS; 190284Srgrimes return(1); 191284Srgrimes} 192284Srgrimes 193284Srgrimesextern int net; 194284Srgrimesstatic int 195284Srgrimeskerberos5_send(char *name, Authenticator *ap) 196284Srgrimes{ 197284Srgrimes krb5_error_code ret; 198284Srgrimes krb5_ccache ccache; 199284Srgrimes int ap_opts; 200284Srgrimes krb5_data cksum_data; 201284Srgrimes char ap_msg[2]; 202284Srgrimes 203284Srgrimes if (!UserNameRequested) { 204284Srgrimes if (auth_debug_mode) { 205284Srgrimes printf("Kerberos V5: no user name supplied\r\n"); 206284Srgrimes } 207284Srgrimes return(0); 208284Srgrimes } 209284Srgrimes 210284Srgrimes ret = krb5_cc_default(context, &ccache); 211284Srgrimes if (ret) { 212284Srgrimes if (auth_debug_mode) { 213284Srgrimes printf("Kerberos V5: could not get default ccache: %s\r\n", 214284Srgrimes krb5_get_err_text (context, ret)); 215284Srgrimes } 216284Srgrimes return 0; 217284Srgrimes } 218284Srgrimes 219284Srgrimes if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 220284Srgrimes ap_opts = AP_OPTS_MUTUAL_REQUIRED; 221284Srgrimes else 222284Srgrimes ap_opts = 0; 223284Srgrimes 224284Srgrimes ap_opts |= AP_OPTS_USE_SUBKEY; 225284Srgrimes 226147Srgrimes ret = krb5_auth_con_init (context, &auth_context); 227238Sroot if (ret) { 228147Srgrimes if (auth_debug_mode) { 229147Srgrimes printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", 230147Srgrimes krb5_get_err_text(context, ret)); 231196Snate } 232147Srgrimes return(0); 23337Srgrimes } 234 235 ret = krb5_auth_con_setaddrs_from_fd (context, 236 auth_context, 237 &net); 238 if (ret) { 239 if (auth_debug_mode) { 240 printf ("Kerberos V5:" 241 " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", 242 krb5_get_err_text(context, ret)); 243 } 244 return(0); 245 } 246 247 krb5_auth_con_setkeytype (context, auth_context, KRB5_ENCTYPE_DES_CBC_CRC); 248 249 ap_msg[0] = ap->type; 250 ap_msg[1] = ap->way; 251 252 cksum_data.length = sizeof(ap_msg); 253 cksum_data.data = ap_msg; 254 255 256 { 257 krb5_principal service; 258 char sname[128]; 259 260 261 ret = krb5_sname_to_principal (context, 262 RemoteHostName, 263 NULL, 264 KRB5_NT_SRV_HST, 265 &service); 266 if(ret) { 267 if (auth_debug_mode) { 268 printf ("Kerberos V5:" 269 " krb5_sname_to_principal(%s) failed (%s)\r\n", 270 RemoteHostName, krb5_get_err_text(context, ret)); 271 } 272 return 0; 273 } 274 ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname)); 275 if(ret) { 276 if (auth_debug_mode) { 277 printf ("Kerberos V5:" 278 " krb5_unparse_name_fixed failed (%s)\r\n", 279 krb5_get_err_text(context, ret)); 280 } 281 return 0; 282 } 283 printf("[ Trying %s (%s)... ]\r\n", name, sname); 284 ret = krb5_mk_req_exact(context, &auth_context, ap_opts, 285 service, 286 &cksum_data, ccache, &auth); 287 krb5_free_principal (context, service); 288 289 } 290 if (ret) { 291 if (1 || auth_debug_mode) { 292 printf("Kerberos V5: mk_req failed (%s)\r\n", 293 krb5_get_err_text(context, ret)); 294 } 295 return(0); 296 } 297 298 if (!auth_sendname((unsigned char *)UserNameRequested, 299 strlen(UserNameRequested))) { 300 if (auth_debug_mode) 301 printf("Not enough room for user name\r\n"); 302 return(0); 303 } 304 if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 305 if (auth_debug_mode) 306 printf("Not enough room for authentication data\r\n"); 307 return(0); 308 } 309 if (auth_debug_mode) { 310 printf("Sent Kerberos V5 credentials to server\r\n"); 311 } 312 return(1); 313} 314 315int 316kerberos5_send_mutual(Authenticator *ap) 317{ 318 return kerberos5_send("mutual KERBEROS5", ap); 319} 320 321int 322kerberos5_send_oneway(Authenticator *ap) 323{ 324 return kerberos5_send("KERBEROS5", ap); 325} 326 327static void log_message(const char *fmt, ...) 328{ 329 va_list ap; 330 va_start(ap, fmt); 331 if (auth_debug_mode) { 332 va_start(ap, fmt); 333 vfprintf(stdout, fmt, ap); 334 va_end(ap); 335 fprintf(stdout, "\r\n"); 336 } 337 va_start(ap, fmt); 338 vsyslog(LOG_NOTICE, fmt, ap); 339 va_end(ap); 340} 341 342void 343kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) 344{ 345 krb5_error_code ret; 346 krb5_data outbuf; 347 krb5_keyblock *key_block; 348 char *name; 349 krb5_principal server; 350 int zero = 0; 351 352 if (cnt-- < 1) 353 return; 354 switch (*data++) { 355 case KRB_AUTH: 356 auth.data = (char *)data; 357 auth.length = cnt; 358 359 auth_context = NULL; 360 361 ret = krb5_auth_con_init (context, &auth_context); 362 if (ret) { 363 Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); 364 auth_finished(ap, AUTH_REJECT); 365 log_message("Kerberos V5: krb5_auth_con_init failed (%s)", 366 krb5_get_err_text(context, ret)); 367 return; 368 } 369 370 ret = krb5_auth_con_setaddrs_from_fd (context, 371 auth_context, 372 &zero); 373 if (ret) { 374 Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); 375 auth_finished(ap, AUTH_REJECT); 376 log_message("Kerberos V5: " 377 "krb5_auth_con_setaddrs_from_fd failed (%s)", 378 krb5_get_err_text(context, ret)); 379 return; 380 } 381 382 ret = krb5_sock_to_principal (context, 383 0, 384 "host", 385 KRB5_NT_SRV_HST, 386 &server); 387 if (ret) { 388 Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); 389 auth_finished(ap, AUTH_REJECT); 390 log_message("Kerberos V5: " 391 "krb5_sock_to_principal failed (%s)", 392 krb5_get_err_text(context, ret)); 393 return; 394 } 395 396 ret = krb5_rd_req(context, 397 &auth_context, 398 &auth, 399 server, 400 NULL, 401 NULL, 402 &ticket); 403 404 krb5_free_principal (context, server); 405 if (ret) { 406 const char *errbuf2 = "Read req failed"; 407 char *errbuf; 408 int ret2; 409 410 ret2 = asprintf(&errbuf, 411 "Read req failed: %s", 412 krb5_get_err_text(context, ret)); 413 if (ret2 != -1) 414 errbuf2 = errbuf; 415 Data(ap, KRB_REJECT, errbuf2, -1); 416 log_message("%s", errbuf2); 417 if (ret2 != -1) 418 free (errbuf); 419 return; 420 } 421 422 { 423 char ap_msg[2]; 424 425 ap_msg[0] = ap->type; 426 ap_msg[1] = ap->way; 427 428 ret = krb5_verify_authenticator_checksum(context, 429 auth_context, 430 ap_msg, 431 sizeof(ap_msg)); 432 433 if (ret) { 434 const char *errbuf2 = "Bad checksum"; 435 char *errbuf; 436 int ret2; 437 438 ret2 = asprintf(&errbuf, "Bad checksum: %s", 439 krb5_get_err_text(context, ret)); 440 if (ret2 != -1) 441 errbuf2 = errbuf; 442 Data(ap, KRB_REJECT, errbuf2, -1); 443 log_message("%s", errbuf2); 444 if (ret2 != -1) 445 free(errbuf); 446 return; 447 } 448 } 449 ret = krb5_auth_con_getremotesubkey (context, 450 auth_context, 451 &key_block); 452 453 if (ret) { 454 Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); 455 auth_finished(ap, AUTH_REJECT); 456 log_message("Kerberos V5: " 457 "krb5_auth_con_getremotesubkey failed (%s)", 458 krb5_get_err_text(context, ret)); 459 return; 460 } 461 462 if (key_block == NULL) { 463 ret = krb5_auth_con_getkey(context, 464 auth_context, 465 &key_block); 466 } 467 if (ret) { 468 Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); 469 auth_finished(ap, AUTH_REJECT); 470 log_message("Kerberos V5: " 471 "krb5_auth_con_getkey failed (%s)", 472 krb5_get_err_text(context, ret)); 473 return; 474 } 475 if (key_block == NULL) { 476 Data(ap, KRB_REJECT, "no subkey received", -1); 477 auth_finished(ap, AUTH_REJECT); 478 log_message("Kerberos V5: " 479 "krb5_auth_con_getremotesubkey returned NULL key"); 480 return; 481 } 482 483 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 484 ret = krb5_mk_rep(context, auth_context, &outbuf); 485 if (ret) { 486 Data(ap, KRB_REJECT, 487 "krb5_mk_rep failed", -1); 488 auth_finished(ap, AUTH_REJECT); 489 log_message("Kerberos V5: " 490 "krb5_mk_rep failed (%s)", 491 krb5_get_err_text(context, ret)); 492 krb5_free_keyblock(context, key_block); 493 return; 494 } 495 Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 496 } 497 if (krb5_unparse_name(context, ticket->client, &name)) 498 name = 0; 499 500 if(UserNameRequested && krb5_kuserok(context, 501 ticket->client, 502 UserNameRequested)) { 503 Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 504 log_message("%s accepted as user %s from %s", 505 name ? name : "<unknown>", 506 UserNameRequested ? UserNameRequested : "<unknown>", 507 RemoteHostName ? RemoteHostName : "<unknown>"); 508 509 if(key_block->keytype == ETYPE_DES_CBC_MD5 || 510 key_block->keytype == ETYPE_DES_CBC_MD4 || 511 key_block->keytype == ETYPE_DES_CBC_CRC) { 512 Session_Key skey; 513 514 skey.type = SK_DES; 515 skey.length = 8; 516 skey.data = key_block->keyvalue.data; 517 encrypt_session_key(&skey, 0); 518 } 519 520 } else { 521 const char *msg2 = "user is not authorized to login"; 522 char *msg; 523 524 ret = asprintf (&msg, "user `%s' is not authorized to " 525 "login as `%s'", 526 name ? name : "<unknown>", 527 UserNameRequested ? UserNameRequested : "<nobody>"); 528 if (ret != -1) 529 msg2 = msg; 530 Data(ap, KRB_REJECT, (void *)msg2, -1); 531 if (ret != -1) 532 free(msg); 533 auth_finished (ap, AUTH_REJECT); 534 krb5_free_keyblock(context, key_block); 535 break; 536 } 537 auth_finished(ap, AUTH_USER); 538 krb5_free_keyblock(context, key_block); 539 540 break; 541 case KRB_FORWARD: { 542 struct passwd *pwd; 543 char ccname[1024]; /* XXX */ 544 krb5_data inbuf; 545 krb5_ccache ccache; 546 inbuf.data = (char *)data; 547 inbuf.length = cnt; 548 549 pwd = getpwnam (UserNameRequested); 550 if (pwd == NULL) 551 break; 552 553 snprintf (ccname, sizeof(ccname), 554 "FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid); 555 556 ret = krb5_cc_resolve (context, ccname, &ccache); 557 if (ret) { 558 log_message("Kerberos V5: could not get ccache: %s", 559 krb5_get_err_text(context, ret)); 560 break; 561 } 562 563 ret = krb5_cc_initialize (context, 564 ccache, 565 ticket->client); 566 if (ret) { 567 log_message("Kerberos V5: could not init ccache: %s", 568 krb5_get_err_text(context, ret)); 569 break; 570 } 571 572#if defined(DCE) 573 esetenv("KRB5CCNAME", ccname, 1); 574#endif 575 ret = krb5_rd_cred2 (context, 576 auth_context, 577 ccache, 578 &inbuf); 579 if(ret) { 580 const char *errbuf2 = "Read forwarded creds failed"; 581 char *errbuf; 582 int ret2; 583 584 ret2 = asprintf (&errbuf, 585 "Read forwarded creds failed: %s", 586 krb5_get_err_text (context, ret)); 587 if (ret2 != -1) 588 errbuf2 = errbuf; 589 Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 590 log_message("Could not read forwarded credentials: %s", errbuf); 591 592 if (ret2 != -1) 593 free (errbuf); 594 } else { 595 Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 596#if defined(DCE) 597 dfsfwd = 1; 598#endif 599 } 600 chown (ccname + 5, pwd->pw_uid, -1); 601 log_message("Forwarded credentials obtained"); 602 break; 603 } 604 default: 605 log_message("Unknown Kerberos option %d", data[-1]); 606 Data(ap, KRB_REJECT, 0, 0); 607 break; 608 } 609} 610 611void 612kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt) 613{ 614 static int mutual_complete = 0; 615 616 if (cnt-- < 1) 617 return; 618 switch (*data++) { 619 case KRB_REJECT: 620 if (cnt > 0) { 621 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 622 cnt, data); 623 } else 624 printf("[ Kerberos V5 refuses authentication ]\r\n"); 625 auth_send_retry(); 626 return; 627 case KRB_ACCEPT: { 628 krb5_error_code ret; 629 Session_Key skey; 630 krb5_keyblock *keyblock; 631 632 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && 633 !mutual_complete) { 634 printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 635 auth_send_retry(); 636 return; 637 } 638 if (cnt) 639 printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 640 else 641 printf("[ Kerberos V5 accepts you ]\r\n"); 642 643 ret = krb5_auth_con_getlocalsubkey (context, 644 auth_context, 645 &keyblock); 646 if (ret) 647 ret = krb5_auth_con_getkey (context, 648 auth_context, 649 &keyblock); 650 if(ret) { 651 printf("[ krb5_auth_con_getkey: %s ]\r\n", 652 krb5_get_err_text(context, ret)); 653 auth_send_retry(); 654 return; 655 } 656 657 skey.type = SK_DES; 658 skey.length = 8; 659 skey.data = keyblock->keyvalue.data; 660 encrypt_session_key(&skey, 0); 661 krb5_free_keyblock (context, keyblock); 662 auth_finished(ap, AUTH_USER); 663 if (forward_flags & OPTS_FORWARD_CREDS) 664 kerberos5_forward(ap); 665 break; 666 } 667 case KRB_RESPONSE: 668 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 669 /* the rest of the reply should contain a krb_ap_rep */ 670 krb5_ap_rep_enc_part *reply; 671 krb5_data inbuf; 672 krb5_error_code ret; 673 674 inbuf.length = cnt; 675 inbuf.data = (char *)data; 676 677 ret = krb5_rd_rep(context, auth_context, &inbuf, &reply); 678 if (ret) { 679 printf("[ Mutual authentication failed: %s ]\r\n", 680 krb5_get_err_text (context, ret)); 681 auth_send_retry(); 682 return; 683 } 684 krb5_free_ap_rep_enc_part(context, reply); 685 mutual_complete = 1; 686 } 687 return; 688 case KRB_FORWARD_ACCEPT: 689 printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 690 return; 691 case KRB_FORWARD_REJECT: 692 printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 693 cnt, data); 694 return; 695 default: 696 if (auth_debug_mode) 697 printf("Unknown Kerberos option %d\r\n", data[-1]); 698 return; 699 } 700} 701 702int 703kerberos5_status(Authenticator *ap, char *name, size_t name_sz, int level) 704{ 705 if (level < AUTH_USER) 706 return(level); 707 708 if (UserNameRequested && 709 krb5_kuserok(context, 710 ticket->client, 711 UserNameRequested)) 712 { 713 strlcpy(name, UserNameRequested, name_sz); 714#if defined(DCE) 715 dfsk5ok = 1; 716#endif 717 return(AUTH_VALID); 718 } else 719 return(AUTH_USER); 720} 721 722#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 723#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 724 725void 726kerberos5_printsub(unsigned char *data, size_t cnt, 727 unsigned char *buf, size_t buflen) 728{ 729 int i; 730 731 buf[buflen-1] = '\0'; /* make sure it's NULL terminated */ 732 buflen -= 1; 733 734 switch(data[3]) { 735 case KRB_REJECT: /* Rejected (reason might follow) */ 736 strlcpy((char *)buf, " REJECT ", buflen); 737 goto common; 738 739 case KRB_ACCEPT: /* Accepted (name might follow) */ 740 strlcpy((char *)buf, " ACCEPT ", buflen); 741 common: 742 BUMP(buf, buflen); 743 if (cnt <= 4) 744 break; 745 ADDC(buf, buflen, '"'); 746 for (i = 4; i < cnt; i++) 747 ADDC(buf, buflen, data[i]); 748 ADDC(buf, buflen, '"'); 749 ADDC(buf, buflen, '\0'); 750 break; 751 752 753 case KRB_AUTH: /* Authentication data follows */ 754 strlcpy((char *)buf, " AUTH", buflen); 755 goto common2; 756 757 case KRB_RESPONSE: 758 strlcpy((char *)buf, " RESPONSE", buflen); 759 goto common2; 760 761 case KRB_FORWARD: /* Forwarded credentials follow */ 762 strlcpy((char *)buf, " FORWARD", buflen); 763 goto common2; 764 765 case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 766 strlcpy((char *)buf, " FORWARD_ACCEPT", buflen); 767 goto common2; 768 769 case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 770 /* (reason might follow) */ 771 strlcpy((char *)buf, " FORWARD_REJECT", buflen); 772 goto common2; 773 774 default: 775 snprintf((char*)buf, buflen, " %d (unknown)", data[3]); 776 common2: 777 BUMP(buf, buflen); 778 for (i = 4; i < cnt; i++) { 779 snprintf((char*)buf, buflen, " %d", data[i]); 780 BUMP(buf, buflen); 781 } 782 break; 783 } 784} 785 786void 787kerberos5_forward(Authenticator *ap) 788{ 789 krb5_error_code ret; 790 krb5_ccache ccache; 791 krb5_creds creds; 792 KDCOptions flags; 793 krb5_data out_data; 794 krb5_principal principal; 795 796 ret = krb5_cc_default (context, &ccache); 797 if (ret) { 798 if (auth_debug_mode) 799 printf ("KerberosV5: could not get default ccache: %s\r\n", 800 krb5_get_err_text (context, ret)); 801 return; 802 } 803 804 ret = krb5_cc_get_principal (context, ccache, &principal); 805 if (ret) { 806 if (auth_debug_mode) 807 printf ("KerberosV5: could not get principal: %s\r\n", 808 krb5_get_err_text (context, ret)); 809 return; 810 } 811 812 memset (&creds, 0, sizeof(creds)); 813 814 creds.client = principal; 815 816 ret = krb5_make_principal(context, 817 &creds.server, 818 principal->realm, 819 "krbtgt", 820 principal->realm, 821 NULL); 822 823 if (ret) { 824 if (auth_debug_mode) 825 printf ("KerberosV5: could not get principal: %s\r\n", 826 krb5_get_err_text (context, ret)); 827 return; 828 } 829 830 creds.times.endtime = 0; 831 832 memset(&flags, 0, sizeof(flags)); 833 flags.forwarded = 1; 834 if (forward_flags & OPTS_FORWARDABLE_CREDS) 835 flags.forwardable = 1; 836 837 ret = krb5_get_forwarded_creds (context, 838 auth_context, 839 ccache, 840 KDCOptions2int(flags), 841 RemoteHostName, 842 &creds, 843 &out_data); 844 if (ret) { 845 if (auth_debug_mode) 846 printf ("Kerberos V5: error getting forwarded creds: %s\r\n", 847 krb5_get_err_text (context, ret)); 848 return; 849 } 850 851 if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { 852 if (auth_debug_mode) 853 printf("Not enough room for authentication data\r\n"); 854 } else { 855 if (auth_debug_mode) 856 printf("Forwarded local Kerberos V5 credentials to server\r\n"); 857 } 858} 859 860#if defined(DCE) 861/* if this was a K5 authentication try and join a PAG for the user. */ 862void 863kerberos5_dfspag(void) 864{ 865 if (dfsk5ok) { 866 dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client, 867 UserNameRequested); 868 } 869} 870#endif 871 872int 873kerberos5_set_forward(int on) 874{ 875 if(on == 0) 876 forward_flags &= ~OPTS_FORWARD_CREDS; 877 if(on == 1) 878 forward_flags |= OPTS_FORWARD_CREDS; 879 if(on == -1) 880 forward_flags ^= OPTS_FORWARD_CREDS; 881 return 0; 882} 883 884int 885kerberos5_set_forwardable(int on) 886{ 887 if(on == 0) 888 forward_flags &= ~OPTS_FORWARDABLE_CREDS; 889 if(on == 1) 890 forward_flags |= OPTS_FORWARDABLE_CREDS; 891 if(on == -1) 892 forward_flags ^= OPTS_FORWARDABLE_CREDS; 893 return 0; 894} 895 896#endif /* KRB5 */ 897