1/* 2 * appl/telnet/libtelnet/kerberos5.c 3 */ 4 5/*- 6 * Copyright (c) 1991, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38/* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */ 39 40/* 41 * Copyright (C) 1990 by the Massachusetts Institute of Technology 42 * 43 * Export of this software from the United States of America may 44 * require a specific license from the United States Government. 45 * It is the responsibility of any person or organization contemplating 46 * export to obtain such a license before exporting. 47 * 48 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 49 * distribute this software and its documentation for any purpose and 50 * without fee is hereby granted, provided that the above copyright 51 * notice appear in all copies and that both that copyright notice and 52 * this permission notice appear in supporting documentation, and that 53 * the name of M.I.T. not be used in advertising or publicity pertaining 54 * to distribution of the software without specific, written prior 55 * permission. Furthermore if you modify this software you must label 56 * your software as modified software and not distribute it in such a 57 * fashion that it might be confused with the original M.I.T. software. 58 * M.I.T. makes no representations about the suitability of 59 * this software for any purpose. It is provided "as is" without express 60 * or implied warranty. 61 */ 62 63 64#ifdef KRB5 65#include <arpa/telnet.h> 66#include <stdio.h> 67#define KRB5_DEPRECATED 1 /* krb5_auth_con_getremotesubkey */ 68#include <krb5.h> 69#include "com_err.h" 70#include <netdb.h> 71#include <ctype.h> 72#include <syslog.h> 73#include <sys/errno.h> 74 75#ifdef HAVE_STDLIB_H 76#include <stdlib.h> 77#else 78extern char *malloc(); 79#endif 80#ifdef HAVE_STRING_H 81#include <string.h> 82#else 83#include <strings.h> 84#endif 85 86#include "encrypt.h" 87#include "auth.h" 88#include "misc.h" 89 90extern int auth_debug_mode; 91extern int net; 92 93#ifdef FORWARD 94int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ 95 96void kerberos5_forward(); 97krb5_error_code 98rd_and_store_for_creds(krb5_context context, krb5_auth_context auth_context, krb5_data *inbuf, krb5_ticket *ticket); 99 100#endif /* FORWARD */ 101 102static unsigned char str_data[8192] = {IAC, SB, TELOPT_AUTHENTICATION, 0, 103 AUTHTYPE_KERBEROS_V5, }; 104/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 105 TELQUAL_NAME, };*/ 106 107#define AUTH_ENCRYPT_OFF 0 108#define AUTH_ENCRYPT_ON 4 109#define AUTH_ENCRYPT_MASK 4 110 111#define KRB_AUTH 0 /* Authentication data follows */ 112#define KRB_REJECT 1 /* Rejected (reason might follow) */ 113#define KRB_ACCEPT 2 /* Accepted */ 114#define KRB_RESPONSE 3 /* Response for mutual auth. */ 115 116#ifdef FORWARD 117#define KRB_FORWARD 4 /* Forwarded credentials follow */ 118#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 119#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 120#endif /* FORWARD */ 121 122krb5_auth_context auth_context = 0; 123 124static krb5_data auth; 125 /* telnetd gets session key from here */ 126static krb5_ticket * ticket = NULL; 127/* telnet matches the AP_REQ and AP_REP with this */ 128 129/* some compilers can't hack void *, so we use the Kerberos krb5_pointer, 130 which is either void * or char *, depending on the compiler. */ 131 132#define Voidptr krb5_pointer 133 134krb5_keyblock *session_key = 0; 135char * telnet_srvtab = NULL; 136char * telnet_krb5_realm = NULL; 137 138 static int 139Data(ap, type, d, c) 140 Authenticator *ap; 141 int type; 142 Voidptr d; 143 int c; 144{ 145 unsigned char *p = str_data + 4; 146 unsigned char *cd = (unsigned char *)d; 147 size_t spaceleft = sizeof(str_data) - 4; 148 149 if (c == -1) 150 c = strlen((char *)cd); 151 152 if (auth_debug_mode) { 153 printf("%s:%d: [%d] (%d)", 154 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 155 str_data[3], 156 type, c); 157 printd(d, c); 158 printf("\r\n"); 159 } 160 *p++ = ap->type; 161 *p++ = ap->way; 162 *p++ = type; 163 spaceleft -= 3; 164 while (c-- > 0) { 165 if ((*p++ = *cd++) == IAC) { 166 *p++ = IAC; 167 spaceleft--; 168 } 169 if ((--spaceleft < 4) && c) { 170 errno = ENOMEM; 171 return -1; 172 } 173 } 174 *p++ = IAC; 175 *p++ = SE; 176 if (str_data[3] == TELQUAL_IS) 177 printsub('>', &str_data[2], p - &str_data[2]); 178 return(net_write(str_data, p - str_data)); 179} 180 181krb5_context telnet_context = 0; 182int 183kerberos5_init(ap, server) 184 Authenticator *ap; 185 int server; 186{ 187 krb5_error_code retval; 188 189 if (server) 190 str_data[3] = TELQUAL_REPLY; 191 else 192 str_data[3] = TELQUAL_IS; 193 if (telnet_context == 0) { 194 retval = krb5_init_context(&telnet_context); 195 if (retval) 196 return 0; 197 } 198 return(1); 199} 200 201void 202kerberos5_cleanup() 203{ 204 krb5_error_code retval; 205 krb5_ccache ccache; 206 char *ccname; 207 208 if (telnet_context == 0) 209 return; 210 211 ccname = getenv("KRB5CCNAME"); 212 if (ccname) { 213 retval = krb5_cc_resolve(telnet_context, ccname, &ccache); 214 if (!retval) 215 retval = krb5_cc_destroy(telnet_context, ccache); 216 } 217 218 krb5_free_context(telnet_context); 219 telnet_context = 0; 220} 221 222 223 int 224kerberos5_send(ap) 225 Authenticator *ap; 226{ 227 krb5_error_code r; 228 krb5_ccache ccache; 229 krb5_creds creds; /* telnet gets session key from here */ 230 krb5_creds * new_creds = 0; 231 int ap_opts; 232 char type_check[2]; 233 krb5_data check_data; 234 235#ifdef ENCRYPTION 236 krb5_keyblock *newkey = 0; 237#endif /* ENCRYPTION */ 238 239 if (!UserNameRequested) { 240 if (auth_debug_mode) { 241 printf( 242 "telnet: Kerberos V5: no user name supplied\r\n"); 243 } 244 return(0); 245 } 246 247 if ((r = krb5_cc_default(telnet_context, &ccache))) { 248 if (auth_debug_mode) { 249 printf( 250 "telnet: Kerberos V5: could not get default ccache\r\n"); 251 } 252 return(0); 253 } 254 255 memset((char *)&creds, 0, sizeof(creds)); 256 if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, 257 "host", KRB5_NT_SRV_HST, 258 &creds.server))) { 259 if (auth_debug_mode) 260 printf("telnet: Kerberos V5: error while constructing service name: %s\r\n", error_message(r)); 261 return(0); 262 } 263 264 if (telnet_krb5_realm != NULL) { 265 krb5_data rdata; 266 267 rdata.length = strlen(telnet_krb5_realm); 268 rdata.data = (char *) malloc(rdata.length + 1); 269 if (rdata.data == NULL) { 270 fprintf(stderr, "malloc failed\n"); 271 return(0); 272 } 273 strcpy(rdata.data, telnet_krb5_realm); 274 krb5_princ_set_realm(telnet_context, creds.server, &rdata); 275 } 276 277 if ((r = krb5_cc_get_principal(telnet_context, ccache, 278 &creds.client))) { 279 if (auth_debug_mode) { 280 printf( 281 "telnet: Kerberos V5: failure on principal (%s)\r\n", 282 error_message(r)); 283 } 284 krb5_free_cred_contents(telnet_context, &creds); 285 return(0); 286 } 287 288 creds.keyblock.enctype=ENCTYPE_DES_CBC_CRC; 289 if ((r = krb5_get_credentials(telnet_context, 0, 290 ccache, &creds, &new_creds))) { 291 if (auth_debug_mode) { 292 printf( 293 "telnet: Kerberos V5: failure on credentials(%s)\r\n", 294 error_message(r)); 295 } 296 krb5_free_cred_contents(telnet_context, &creds); 297 return(0); 298 } 299 300 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 301 ap_opts = AP_OPTS_MUTUAL_REQUIRED; 302 else 303 ap_opts = 0; 304 305#ifdef ENCRYPTION 306 ap_opts |= AP_OPTS_USE_SUBKEY; 307#endif /* ENCRYPTION */ 308 309 if (auth_context) { 310 krb5_auth_con_free(telnet_context, auth_context); 311 auth_context = 0; 312 } 313 if ((r = krb5_auth_con_init(telnet_context, &auth_context))) { 314 if (auth_debug_mode) { 315 printf("Kerberos V5: failed to init auth_context (%s)\r\n", 316 error_message(r)); 317 } 318 return(0); 319 } 320 321 krb5_auth_con_setflags(telnet_context, auth_context, 322 KRB5_AUTH_CONTEXT_RET_TIME); 323 324 type_check[0] = ap->type; 325 type_check[1] = ap->way; 326 check_data.magic = KV5M_DATA; 327 check_data.length = 2; 328 check_data.data = (char *) &type_check; 329 330 r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts, 331 &check_data, new_creds, &auth); 332 333#ifdef ENCRYPTION 334 krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey); 335 if (session_key) { 336 krb5_free_keyblock(telnet_context, session_key); 337 session_key = 0; 338 } 339 340 if (newkey) { 341 /* keep the key in our private storage, but don't use it 342 yet---see kerberos5_reply() below */ 343 if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) && 344 (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) { 345 if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) || 346 (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) 347 /* use the session key in credentials instead */ 348 krb5_copy_keyblock(telnet_context,&new_creds->keyblock, 349 &session_key); 350 else 351 /* XXX ? */; 352 } else { 353 krb5_copy_keyblock(telnet_context, newkey, &session_key); 354 } 355 krb5_free_keyblock(telnet_context, newkey); 356 } 357#endif /* ENCRYPTION */ 358 krb5_free_cred_contents(telnet_context, &creds); 359 krb5_free_creds(telnet_context, new_creds); 360 if (r) { 361 if (auth_debug_mode) { 362 printf("telnet: Kerberos V5: mk_req failed (%s)\r\n", 363 error_message(r)); 364 } 365 return(0); 366 } 367 368 if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { 369 if (auth_debug_mode) 370 printf("telnet: Not enough room for user name\r\n"); 371 return(0); 372 } 373 if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 374 if (auth_debug_mode) 375 printf( 376 "telnet: Not enough room for authentication data\r\n"); 377 return(0); 378 } 379 if (auth_debug_mode) { 380 printf("telnet: Sent Kerberos V5 credentials to server\r\n"); 381 } 382 return(1); 383} 384 385 void 386kerberos5_is(ap, data, cnt) 387 Authenticator *ap; 388 unsigned char *data; 389 int cnt; 390{ 391 int r = 0; 392 krb5_principal server; 393 krb5_keyblock *newkey = NULL; 394 krb5_keytab keytabid = 0; 395 krb5_data outbuf; 396#ifdef ENCRYPTION 397 Session_Key skey; 398#endif 399 char errbuf[320]; 400 char *name; 401 char *getenv(); 402 krb5_data inbuf; 403 krb5_authenticator *authenticator; 404 405 if (cnt-- < 1) 406 return; 407 switch (*data++) { 408 case KRB_AUTH: 409 auth.data = (char *)data; 410 auth.length = cnt; 411 412 if (!r && !auth_context) 413 r = krb5_auth_con_init(telnet_context, &auth_context); 414 if (!r) { 415 krb5_rcache rcache; 416 417 r = krb5_auth_con_getrcache(telnet_context, auth_context, 418 &rcache); 419 if (!r && !rcache) { 420 r = krb5_sname_to_principal(telnet_context, 0, 0, 421 KRB5_NT_SRV_HST, &server); 422 if (!r) { 423 r = krb5_get_server_rcache(telnet_context, 424 krb5_princ_component(telnet_context, 425 server, 0), 426 &rcache); 427 krb5_free_principal(telnet_context, server); 428 } 429 } 430 if (!r) 431 r = krb5_auth_con_setrcache(telnet_context, 432 auth_context, rcache); 433 } 434 if (!r && telnet_srvtab) 435 r = krb5_kt_resolve(telnet_context, 436 telnet_srvtab, &keytabid); 437 if (!r) 438 r = krb5_rd_req(telnet_context, &auth_context, &auth, 439 NULL, keytabid, NULL, &ticket); 440 if (r) { 441 (void) strcpy(errbuf, "krb5_rd_req failed: "); 442 errbuf[sizeof(errbuf) - 1] = '\0'; 443 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 444 goto errout; 445 } 446 447 /* 448 * 256 bytes should be much larger than any reasonable 449 * first component of a service name especially since 450 * the default is of length 4. 451 */ 452 if (krb5_princ_component(telnet_context,ticket->server,0)->length < 256) { 453 char princ[256]; 454 strncpy(princ, 455 krb5_princ_component(telnet_context, ticket->server,0)->data, 456 krb5_princ_component(telnet_context, ticket->server,0)->length); 457 princ[krb5_princ_component(telnet_context, 458 ticket->server,0)->length] = '\0'; 459 if (strcmp("host", princ)) { 460 if(strlen(princ) < sizeof(errbuf) - 39) { 461 (void) sprintf(errbuf, "incorrect service name: \"%s\" != \"host\"", 462 princ); 463 } else { 464 (void) sprintf(errbuf, "incorrect service name: principal != \"host\""); 465 } 466 goto errout; 467 } 468 } else { 469 (void) strcpy(errbuf, "service name too long"); 470 goto errout; 471 } 472 473 r = krb5_auth_con_getauthenticator(telnet_context, 474 auth_context, 475 &authenticator); 476 if (r) { 477 (void) strcpy(errbuf, 478 "krb5_auth_con_getauthenticator failed: "); 479 errbuf[sizeof(errbuf) - 1] = '\0'; 480 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 481 goto errout; 482 } 483 if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON && 484 !authenticator->checksum) { 485 (void) strcpy(errbuf, 486 "authenticator is missing required checksum"); 487 goto errout; 488 } 489 if (authenticator->checksum) { 490 char type_check[2]; 491 krb5_checksum *cksum = authenticator->checksum; 492 krb5_keyblock *key; 493 494 type_check[0] = ap->type; 495 type_check[1] = ap->way; 496 497 r = krb5_auth_con_getkey(telnet_context, auth_context, 498 &key); 499 if (r) { 500 (void) strcpy(errbuf, "krb5_auth_con_getkey failed: "); 501 errbuf[sizeof(errbuf) - 1] = '\0'; 502 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 503 goto errout; 504 } 505 r = krb5_verify_checksum(telnet_context, 506 cksum->checksum_type, cksum, 507 &type_check, 2, key->contents, 508 key->length); 509 /* 510 * Note that krb5_verify_checksum() will fail if a pre- 511 * MIT Kerberos Beta 5 client is attempting to connect 512 * to this server (Beta 6 or later). There is not way to 513 * fix this without compromising encryption. It would be 514 * reasonable to add a -i option to telnetd to ignore 515 * checksums (like in klogind). Such an option is not 516 * present at this time. 517 */ 518 if (r) { 519 (void) strcpy(errbuf, 520 "checksum verification failed: "); 521 errbuf[sizeof(errbuf) - 1] = '\0'; 522 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 523 goto errout; 524 } 525 krb5_free_keyblock(telnet_context, key); 526 } 527 krb5_free_authenticator(telnet_context, authenticator); 528 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 529 /* do ap_rep stuff here */ 530 if ((r = krb5_mk_rep(telnet_context, auth_context, 531 &outbuf))) { 532 (void) strcpy(errbuf, "Make reply failed: "); 533 errbuf[sizeof(errbuf) - 1] = '\0'; 534 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 535 goto errout; 536 } 537 538 Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 539 } 540 if (krb5_unparse_name(telnet_context, 541 ticket->enc_part2 ->client, 542 &name)) 543 name = 0; 544 Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 545 if (auth_debug_mode) { 546 printf( 547 "telnetd: Kerberos5 identifies him as ``%s''\r\n", 548 name ? name : ""); 549 } 550 auth_finished(ap, AUTH_USER); 551 552 if (name) 553 free(name); 554 krb5_auth_con_getremotesubkey(telnet_context, auth_context, 555 &newkey); 556 if (session_key) { 557 krb5_free_keyblock(telnet_context, session_key); 558 session_key = 0; 559 } 560 if (newkey) { 561 krb5_copy_keyblock(telnet_context, newkey, &session_key); 562 krb5_free_keyblock(telnet_context, newkey); 563 } else { 564 krb5_copy_keyblock(telnet_context, 565 ticket->enc_part2->session, 566 &session_key); 567 } 568 569#ifdef ENCRYPTION 570 skey.type = SK_DES; 571 skey.length = 8; 572 skey.data = session_key->contents; 573 encrypt_session_key(&skey, 1); 574#endif 575 break; 576#ifdef FORWARD 577 case KRB_FORWARD: 578 inbuf.length = cnt; 579 inbuf.data = (char *)data; 580 if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, 581 net, KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) || 582 (r = rd_and_store_for_creds(telnet_context, auth_context, 583 &inbuf, ticket))) { 584 585 char errbuf[128]; 586 587 (void) strcpy(errbuf, "Read forwarded creds failed: "); 588 errbuf[sizeof(errbuf) - 1] = '\0'; 589 (void) strncat(errbuf, error_message(r), sizeof(errbuf) - 1 - strlen(errbuf)); 590 Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 591 if (auth_debug_mode) 592 printf( 593 "telnetd: Could not read forwarded credentials\r\n"); 594 } 595 else 596 Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 597 if (auth_debug_mode) 598 printf("telnetd: Forwarded credentials obtained\r\n"); 599 break; 600#endif /* FORWARD */ 601 default: 602 if (auth_debug_mode) 603 printf("telnetd: Unknown Kerberos option %d\r\n", 604 data[-1]); 605 Data(ap, KRB_REJECT, 0, 0); 606 break; 607 } 608 return; 609 610 errout: 611 { 612 char eerrbuf[329]; 613 614 strcpy(eerrbuf, "telnetd: "); 615 eerrbuf[sizeof(eerrbuf) - 1] = '\0'; 616 strncat(eerrbuf, errbuf, sizeof(eerrbuf) - 1 - strlen(eerrbuf)); 617 Data(ap, KRB_REJECT, eerrbuf, -1); 618 } 619 if (auth_debug_mode) 620 printf("telnetd: %s\r\n", errbuf); 621 syslog(LOG_ERR, "%s", errbuf); 622 if (auth_context) { 623 krb5_auth_con_free(telnet_context, auth_context); 624 auth_context = 0; 625 } 626 return; 627} 628 629 void 630kerberos5_reply(ap, data, cnt) 631 Authenticator *ap; 632 unsigned char *data; 633 int cnt; 634{ 635#ifdef ENCRYPTION 636 Session_Key skey; 637#endif 638 static int mutual_complete = 0; 639 640 if (cnt-- < 1) 641 return; 642 switch (*data++) { 643 case KRB_REJECT: 644 if (cnt > 0) { 645 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 646 cnt, data); 647 } else 648 printf("[ Kerberos V5 refuses authentication ]\r\n"); 649 auth_send_retry(); 650 return; 651 case KRB_ACCEPT: 652 if (!mutual_complete) { 653 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 654 printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 655 auth_send_retry(); 656 return; 657 } 658#ifdef ENCRYPTION 659 if (session_key) { 660 skey.type = SK_DES; 661 skey.length = 8; 662 skey.data = session_key->contents; 663 encrypt_session_key(&skey, 0); 664 } 665#endif /* ENCRYPTION */ 666 } 667 if (cnt) 668 printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 669 else 670 printf("[ Kerberos V5 accepts you ]\r\n"); 671 auth_finished(ap, AUTH_USER); 672#ifdef FORWARD 673 if (forward_flags & OPTS_FORWARD_CREDS) 674 kerberos5_forward(ap); 675#endif /* FORWARD */ 676 break; 677 case KRB_RESPONSE: 678 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 679 /* the rest of the reply should contain a krb_ap_rep */ 680 krb5_ap_rep_enc_part *reply; 681 krb5_data inbuf; 682 krb5_error_code r; 683 684 inbuf.length = cnt; 685 inbuf.data = (char *)data; 686 687 if ((r = krb5_rd_rep(telnet_context, auth_context, &inbuf, 688 &reply))) { 689 printf("[ Mutual authentication failed: %s ]\r\n", 690 error_message(r)); 691 auth_send_retry(); 692 return; 693 } 694 krb5_free_ap_rep_enc_part(telnet_context, reply); 695#ifdef ENCRYPTION 696 if (session_key) { 697 skey.type = SK_DES; 698 skey.length = 8; 699 skey.data = session_key->contents; 700 encrypt_session_key(&skey, 0); 701 } 702#endif /* ENCRYPTION */ 703 mutual_complete = 1; 704 } 705 return; 706#ifdef FORWARD 707 case KRB_FORWARD_ACCEPT: 708 printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 709 return; 710 case KRB_FORWARD_REJECT: 711 printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 712 cnt, data); 713 return; 714#endif /* FORWARD */ 715 default: 716 if (auth_debug_mode) 717 printf("Unknown Kerberos option %d\r\n", data[-1]); 718 return; 719 } 720 return; 721} 722 723 int 724kerberos5_status(ap, name, level) 725 Authenticator *ap; 726 char *name; 727 int level; 728{ 729 if (level < AUTH_USER) 730 return(level); 731 732 if (UserNameRequested && 733 krb5_kuserok(telnet_context, ticket->enc_part2->client, 734 UserNameRequested)) 735 { 736 /* the name buffer comes from telnetd/telnetd{-ktd}.c */ 737 strncpy(name, UserNameRequested, 255); 738 name[255] = '\0'; 739 return(AUTH_VALID); 740 } else 741 return(AUTH_USER); 742} 743 744#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 745#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 746 747 void 748kerberos5_printsub(data, cnt, buf, buflen) 749 unsigned char *data, *buf; 750 int cnt, buflen; 751{ 752 char lbuf[32]; 753 register int i; 754 755 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 756 buflen -= 1; 757 758 switch(data[3]) { 759 case KRB_REJECT: /* Rejected (reason might follow) */ 760 strncpy((char *)buf, " REJECT ", buflen); 761 goto common; 762 763 case KRB_ACCEPT: /* Accepted (name might follow) */ 764 strncpy((char *)buf, " ACCEPT ", buflen); 765 common: 766 BUMP(buf, buflen); 767 if (cnt <= 4) 768 break; 769 ADDC(buf, buflen, '"'); 770 for (i = 4; i < cnt; i++) 771 ADDC(buf, buflen, data[i]); 772 ADDC(buf, buflen, '"'); 773 ADDC(buf, buflen, '\0'); 774 break; 775 776 777 case KRB_AUTH: /* Authentication data follows */ 778 strncpy((char *)buf, " AUTH", buflen); 779 goto common2; 780 781 case KRB_RESPONSE: 782 strncpy((char *)buf, " RESPONSE", buflen); 783 goto common2; 784 785#ifdef FORWARD 786 case KRB_FORWARD: /* Forwarded credentials follow */ 787 strncpy((char *)buf, " FORWARD", buflen); 788 goto common2; 789 790 case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 791 strncpy((char *)buf, " FORWARD_ACCEPT", buflen); 792 goto common2; 793 794 case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 795 /* (reason might follow) */ 796 strncpy((char *)buf, " FORWARD_REJECT", buflen); 797 goto common2; 798#endif /* FORWARD */ 799 800 default: 801 sprintf(lbuf, " %d (unknown)", data[3]); 802 strncpy((char *)buf, lbuf, buflen); 803 common2: 804 BUMP(buf, buflen); 805 for (i = 4; i < cnt; i++) { 806 sprintf(lbuf, " %d", data[i]); 807 strncpy((char *)buf, lbuf, buflen); 808 BUMP(buf, buflen); 809 } 810 break; 811 } 812} 813 814#ifdef FORWARD 815 816void 817kerberos5_forward(ap) 818 Authenticator *ap; 819{ 820 krb5_error_code r; 821 krb5_ccache ccache; 822 krb5_principal client = 0; 823 krb5_principal server = 0; 824 krb5_data forw_creds; 825 826 forw_creds.data = 0; 827 828 if ((r = krb5_cc_default(telnet_context, &ccache))) { 829 if (auth_debug_mode) 830 printf("Kerberos V5: could not get default ccache - %s\r\n", 831 error_message(r)); 832 return; 833 } 834 835 if ((r = krb5_cc_get_principal(telnet_context, ccache, &client))) { 836 if (auth_debug_mode) 837 printf("Kerberos V5: could not get default principal - %s\r\n", 838 error_message(r)); 839 goto cleanup; 840 } 841 842 if ((r = krb5_sname_to_principal(telnet_context, RemoteHostName, "host", 843 KRB5_NT_SRV_HST, &server))) { 844 if (auth_debug_mode) 845 printf("Kerberos V5: could not make server principal - %s\r\n", 846 error_message(r)); 847 goto cleanup; 848 } 849 850 if ((r = krb5_auth_con_genaddrs(telnet_context, auth_context, net, 851 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR))) { 852 if (auth_debug_mode) 853 printf("Kerberos V5: could not gen local full address - %s\r\n", 854 error_message(r)); 855 goto cleanup; 856 } 857 858 if ((r = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client, 859 server, ccache, 860 forward_flags & OPTS_FORWARDABLE_CREDS, 861 &forw_creds))) { 862 if (auth_debug_mode) 863 printf("Kerberos V5: error getting forwarded creds - %s\r\n", 864 error_message(r)); 865 goto cleanup; 866 } 867 868 /* Send forwarded credentials */ 869 if (!Data(ap, KRB_FORWARD, forw_creds.data, forw_creds.length)) { 870 if (auth_debug_mode) 871 printf("Not enough room for authentication data\r\n"); 872 } else { 873 if (auth_debug_mode) 874 printf("Forwarded local Kerberos V5 credentials to server\r\n"); 875 } 876 877cleanup: 878 if (client) 879 krb5_free_principal(telnet_context, client); 880 if (server) 881 krb5_free_principal(telnet_context, server); 882 if (forw_creds.data) 883 free(forw_creds.data); 884 krb5_cc_close(telnet_context, ccache); 885} 886#endif /* FORWARD */ 887 888#endif /* KRB5 */ 889