1 /* $NetBSD: kerberos5.c,v 1.4 2000/06/22 06:47:44 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * Copyright (C) 1990 by the Massachusetts Institute of Technology 38 * 39 * Export of this software from the United States of America may 40 * require a specific license from the United States Government. 41 * It is the responsibility of any person or organization contemplating 42 * export to obtain such a license before exporting. 43 * 44 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 45 * distribute this software and its documentation for any purpose and 46 * without fee is hereby granted, provided that the above copyright 47 * notice appear in all copies and that both that copyright notice and 48 * this permission notice appear in supporting documentation, and that 49 * the name of M.I.T. not be used in advertising or publicity pertaining 50 * to distribution of the software without specific, written prior 51 * permission. M.I.T. makes no representations about the suitability of 52 * this software for any purpose. It is provided "as is" without express 53 * or implied warranty. 54 */ 55 56 #ifdef KRB5 57 #include <arpa/telnet.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <netdb.h> 63 #include <ctype.h> 64 #include <pwd.h> 65 #define Authenticator k5_Authenticator 66 #include <krb5.h> 67 #undef Authenticator 68 /* #include <roken.h> */ 69 70 #include "encrypt.h" 71 #include "auth.h" 72 #include "misc.h" 73 74 int forward_flags; /* Flags get set in telnet/main.c on -f and -F */ 75 int got_forwarded_creds;/* Tell telnetd to pass -F or -f to login. */ 76 77 int require_hwpreauth; 78 79 void kerberos5_forward(Authenticator *); 80 81 static unsigned char str_data[1024] = {IAC, SB, TELOPT_AUTHENTICATION, 0, 82 AUTHTYPE_KERBEROS_V5,}; 83 84 #define KRB_AUTH 0 /* Authentication data follows */ 85 #define KRB_REJECT 1 /* Rejected (reason might follow) */ 86 #define KRB_ACCEPT 2 /* Accepted */ 87 #define KRB_RESPONSE 3 /* Response for mutual auth. */ 88 89 #define KRB_FORWARD 4 /* Forwarded credentials follow */ 90 #define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */ 91 #define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */ 92 93 static krb5_data auth; 94 static krb5_ticket *ticket; 95 96 krb5_context telnet_context; 97 static krb5_auth_context auth_context; 98 99 static int 100 Data(Authenticator *ap, int type, void *d, int c) 101 { 102 unsigned char *p = str_data + 4; 103 unsigned char *cd = (unsigned char *) d; 104 105 if (c == -1) 106 c = strlen(cd); 107 108 if (auth_debug_mode) { 109 printf("%s:%d: [%d] (%d)", 110 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 111 str_data[3], 112 type, c); 113 printd(d, c); 114 printf("\r\n"); 115 } 116 *p++ = ap->type; 117 *p++ = ap->way; 118 *p++ = type; 119 while (c-- > 0) { 120 if ((*p++ = *cd++) == IAC) 121 *p++ = IAC; 122 } 123 *p++ = IAC; 124 *p++ = SE; 125 if (str_data[3] == TELQUAL_IS) 126 printsub('>', &str_data[2], p - &str_data[2]); 127 return (telnet_net_write(str_data, p - str_data)); 128 } 129 130 int 131 kerberos5_init(Authenticator *ap, int server) 132 { 133 134 if (telnet_context == 0) 135 krb5_init_context(&telnet_context); 136 137 if (server) { 138 krb5_error_code ret; 139 krb5_keytab kt; 140 krb5_kt_cursor cursor; 141 142 ret = krb5_kt_default(telnet_context, &kt); 143 if (ret) 144 return 0; 145 146 ret = krb5_kt_start_seq_get(telnet_context, kt, &cursor); 147 if (ret) { 148 krb5_kt_close(telnet_context, kt); 149 return 0; 150 } 151 krb5_kt_end_seq_get(telnet_context, kt, &cursor); 152 krb5_kt_close(telnet_context, kt); 153 154 str_data[3] = TELQUAL_REPLY; 155 } else 156 str_data[3] = TELQUAL_IS; 157 return (1); 158 } 159 160 int 161 kerberos5_send(Authenticator *ap) 162 { 163 krb5_error_code ret; 164 krb5_ccache ccache; 165 int ap_opts; 166 krb5_data cksum_data; 167 char foo[2]; 168 extern int net; 169 170 printf("[ Trying KERBEROS5 ... ]\r\n"); 171 172 if (!UserNameRequested) { 173 if (auth_debug_mode) { 174 printf("Kerberos V5: no user name supplied\r\n"); 175 } 176 return (0); 177 } 178 ret = krb5_cc_default(telnet_context, &ccache); 179 if (ret) { 180 if (auth_debug_mode) { 181 printf( 182 "Kerberos V5: could not get default ccache: %s\r\n", 183 krb5_get_err_text(telnet_context, ret)); 184 } 185 return (0); 186 } 187 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) 188 ap_opts = AP_OPTS_MUTUAL_REQUIRED; 189 else 190 ap_opts = 0; 191 192 ret = krb5_auth_con_init(telnet_context, &auth_context); 193 if (ret) { 194 if (auth_debug_mode) { 195 printf( 196 "Kerberos V5: krb5_auth_con_init failed: %s\r\n", 197 krb5_get_err_text(telnet_context, ret)); 198 } 199 return (0); 200 } 201 ret = krb5_auth_con_setaddrs_from_fd(telnet_context, 202 auth_context, &net); 203 if (ret) { 204 if (auth_debug_mode) { 205 printf("Kerberos V5: " 206 "krb5_auth_con_setaddrs_from_fd failed: %s\r\n", 207 krb5_get_err_text(telnet_context, ret)); 208 } 209 return (0); 210 } 211 krb5_auth_setkeytype(telnet_context, auth_context, KEYTYPE_DES); 212 213 foo[0] = ap->type; 214 foo[1] = ap->way; 215 216 cksum_data.length = sizeof(foo); 217 cksum_data.data = foo; 218 ret = krb5_mk_req(telnet_context, &auth_context, ap_opts, "host", 219 RemoteHostName, &cksum_data, ccache, &auth); 220 if (ret) { 221 if (1 || auth_debug_mode) { 222 printf("Kerberos V5: mk_req failed (%s)\r\n", 223 krb5_get_err_text(telnet_context, ret)); 224 } 225 return (0); 226 } 227 228 if (!auth_sendname((unsigned char *) UserNameRequested, 229 strlen(UserNameRequested))) { 230 if (auth_debug_mode) 231 printf("Not enough room for user name\r\n"); 232 return (0); 233 } 234 if (!Data(ap, KRB_AUTH, auth.data, auth.length)) { 235 if (auth_debug_mode) 236 printf("Not enough room for authentication data\r\n"); 237 return (0); 238 } 239 if (auth_debug_mode) { 240 printf("Sent Kerberos V5 credentials to server\r\n"); 241 } 242 return (1); 243 } 244 245 void 246 kerberos5_is(Authenticator * ap, unsigned char *data, int cnt) 247 { 248 krb5_error_code ret; 249 krb5_data outbuf; 250 krb5_keyblock *key_block; 251 char *name; 252 krb5_principal server; 253 int zero = 0; 254 255 if (cnt-- < 1) 256 return; 257 switch (*data++) { 258 case KRB_AUTH: 259 auth.data = (char *) data; 260 auth.length = cnt; 261 262 auth_context = NULL; 263 264 ret = krb5_auth_con_init(telnet_context, &auth_context); 265 if (ret) { 266 Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1); 267 auth_finished(ap, AUTH_REJECT); 268 if (auth_debug_mode) 269 printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n", 270 krb5_get_err_text(telnet_context, ret)); 271 return; 272 } 273 ret = krb5_auth_con_setaddrs_from_fd(telnet_context, 274 auth_context, &zero); 275 if (ret) { 276 Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1); 277 auth_finished(ap, AUTH_REJECT); 278 if (auth_debug_mode) 279 printf("Kerberos V5: " 280 "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n", 281 krb5_get_err_text(telnet_context, ret)); 282 return; 283 } 284 ret = krb5_sock_to_principal(telnet_context, 0, "host", 285 KRB5_NT_SRV_HST, &server); 286 if (ret) { 287 Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1); 288 auth_finished(ap, AUTH_REJECT); 289 if (auth_debug_mode) 290 printf("Kerberos V5: " 291 "krb5_sock_to_principal failed (%s)\r\n", 292 krb5_get_err_text(telnet_context, ret)); 293 return; 294 } 295 ret = krb5_rd_req(telnet_context, &auth_context, &auth, 296 server, NULL, NULL, &ticket); 297 krb5_free_principal(telnet_context, server); 298 299 if (ret) { 300 char *errbuf; 301 302 asprintf(&errbuf, 303 "Read req failed: %s", 304 krb5_get_err_text(telnet_context, ret)); 305 Data(ap, KRB_REJECT, errbuf, -1); 306 if (auth_debug_mode) 307 printf("%s\r\n", errbuf); 308 free(errbuf); 309 return; 310 } { 311 char foo[2]; 312 313 foo[0] = ap->type; 314 foo[1] = ap->way; 315 316 ret = krb5_verify_authenticator_checksum(telnet_context, 317 auth_context, foo, sizeof(foo)); 318 319 if (ret) { 320 char *errbuf; 321 asprintf(&errbuf, "Bad checksum: %s", 322 krb5_get_err_text(telnet_context, ret)); 323 Data(ap, KRB_REJECT, errbuf, -1); 324 if (auth_debug_mode) 325 printf("%s\r\n", errbuf); 326 free(errbuf); 327 return; 328 } 329 } 330 ret = krb5_auth_con_getremotesubkey(telnet_context, 331 auth_context, &key_block); 332 333 if (ret) { 334 Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1); 335 auth_finished(ap, AUTH_REJECT); 336 if (auth_debug_mode) 337 printf("Kerberos V5: " 338 "krb5_auth_con_getremotesubkey failed (%s)\r\n", 339 krb5_get_err_text(telnet_context, ret)); 340 return; 341 } 342 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 343 ret = krb5_mk_rep(telnet_context, 344 &auth_context, &outbuf); 345 if (ret) { 346 Data(ap, KRB_REJECT, 347 "krb5_mk_rep failed", -1); 348 auth_finished(ap, AUTH_REJECT); 349 if (auth_debug_mode) 350 printf("Kerberos V5: " 351 "krb5_mk_rep failed (%s)\r\n", 352 krb5_get_err_text(telnet_context, 353 ret)); 354 return; 355 } 356 Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); 357 } 358 if (krb5_unparse_name(telnet_context, ticket->client, &name)) 359 name = 0; 360 361 if (UserNameRequested && krb5_kuserok(telnet_context, 362 ticket->client, UserNameRequested)) { 363 Data(ap, KRB_ACCEPT, name, name ? -1 : 0); 364 if (auth_debug_mode) { 365 printf("Kerberos5 identifies him as ``%s''\r\n", 366 name ? name : ""); 367 } 368 if (key_block->keytype == ETYPE_DES_CBC_MD5 || 369 key_block->keytype == ETYPE_DES_CBC_MD4 || 370 key_block->keytype == ETYPE_DES_CBC_CRC) { 371 Session_Key skey; 372 373 skey.type = SK_DES; 374 skey.length = 8; 375 skey.data = key_block->keyvalue.data; 376 encrypt_session_key(&skey, 0); 377 } 378 } else { 379 char *msg; 380 381 asprintf(&msg, "user `%s' is not authorized to " 382 "login as `%s'", 383 name ? name : "<unknown>", 384 UserNameRequested ? UserNameRequested : "<nobody>"); 385 if (msg == NULL) 386 Data(ap, KRB_REJECT, NULL, 0); 387 else { 388 Data(ap, KRB_REJECT, (void *) msg, -1); 389 free(msg); 390 } 391 auth_finished(ap, AUTH_REJECT); 392 krb5_free_keyblock_contents(telnet_context, key_block); 393 break; 394 } 395 auth_finished(ap, AUTH_USER); 396 krb5_free_keyblock_contents(telnet_context, key_block); 397 398 break; 399 case KRB_FORWARD:{ 400 struct passwd *pwd; 401 char ccname[1024]; /* XXX */ 402 krb5_data inbuf; 403 krb5_ccache ccache; 404 inbuf.data = (char *) data; 405 inbuf.length = cnt; 406 407 pwd = getpwnam(UserNameRequested); 408 if (pwd == NULL) 409 break; 410 411 snprintf(ccname, sizeof(ccname), 412 "FILE:/tmp/krb5cc_%u", pwd->pw_uid); 413 414 ret = krb5_cc_resolve(telnet_context, ccname, &ccache); 415 if (ret) { 416 if (auth_debug_mode) 417 printf("Kerberos V5: could not get ccache: %s\r\n", 418 krb5_get_err_text(telnet_context, 419 ret)); 420 break; 421 } 422 ret = krb5_cc_initialize(telnet_context, ccache, 423 ticket->client); 424 if (ret) { 425 if (auth_debug_mode) 426 printf("Kerberos V5: could not init ccache: %s\r\n", 427 krb5_get_err_text(telnet_context, 428 ret)); 429 break; 430 } 431 ret = krb5_rd_cred(telnet_context, auth_context, 432 ccache, &inbuf); 433 if (ret) { 434 char *errbuf; 435 436 asprintf(&errbuf, 437 "Read forwarded creds failed: %s", 438 krb5_get_err_text(telnet_context, ret)); 439 if (errbuf == NULL) 440 Data(ap, KRB_FORWARD_REJECT, NULL, 0); 441 else 442 Data(ap, KRB_FORWARD_REJECT, errbuf, -1); 443 if (auth_debug_mode) 444 printf("Could not read forwarded credentials: %s\r\n", 445 errbuf); 446 free(errbuf); 447 } else 448 Data(ap, KRB_FORWARD_ACCEPT, 0, 0); 449 chown(ccname + 5, pwd->pw_uid, -1); 450 if (auth_debug_mode) 451 printf("Forwarded credentials obtained\r\n"); 452 break; 453 } 454 default: 455 if (auth_debug_mode) 456 printf("Unknown Kerberos option %d\r\n", data[-1]); 457 Data(ap, KRB_REJECT, 0, 0); 458 break; 459 } 460 } 461 462 void 463 kerberos5_reply(Authenticator * ap, unsigned char *data, int cnt) 464 { 465 static int mutual_complete = 0; 466 467 if (cnt-- < 1) 468 return; 469 switch (*data++) { 470 case KRB_REJECT: 471 if (cnt > 0) { 472 printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n", 473 cnt, data); 474 } else 475 printf("[ Kerberos V5 refuses authentication ]\r\n"); 476 auth_send_retry(); 477 return; 478 case KRB_ACCEPT:{ 479 krb5_error_code ret; 480 Session_Key skey; 481 krb5_keyblock *keyblock; 482 483 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && 484 !mutual_complete) { 485 printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); 486 auth_send_retry(); 487 return; 488 } 489 if (cnt) 490 printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); 491 else 492 printf("[ Kerberos V5 accepts you ]\r\n"); 493 494 ret = krb5_auth_con_getlocalsubkey(telnet_context, 495 auth_context, &keyblock); 496 if (ret) 497 ret = krb5_auth_con_getkey(telnet_context, 498 auth_context, &keyblock); 499 if (ret) { 500 printf("[ krb5_auth_con_getkey: %s ]\r\n", 501 krb5_get_err_text(telnet_context, ret)); 502 auth_send_retry(); 503 return; 504 } 505 skey.type = SK_DES; 506 skey.length = 8; 507 skey.data = keyblock->keyvalue.data; 508 encrypt_session_key(&skey, 0); 509 krb5_free_keyblock_contents(telnet_context, keyblock); 510 auth_finished(ap, AUTH_USER); 511 if (forward_flags & OPTS_FORWARD_CREDS) 512 kerberos5_forward(ap); 513 break; 514 } 515 case KRB_RESPONSE: 516 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 517 /* the rest of the reply should contain a krb_ap_rep */ 518 krb5_ap_rep_enc_part *reply; 519 krb5_data inbuf; 520 krb5_error_code ret; 521 522 inbuf.length = cnt; 523 inbuf.data = (char *) data; 524 525 ret = krb5_rd_rep(telnet_context, 526 auth_context, &inbuf, &reply); 527 if (ret) { 528 printf("[ Mutual authentication failed: %s ]\r\n", 529 krb5_get_err_text(telnet_context, ret)); 530 auth_send_retry(); 531 return; 532 } 533 krb5_free_ap_rep_enc_part(telnet_context, reply); 534 mutual_complete = 1; 535 } 536 return; 537 case KRB_FORWARD_ACCEPT: 538 printf("[ Kerberos V5 accepted forwarded credentials ]\r\n"); 539 return; 540 case KRB_FORWARD_REJECT: 541 printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n", 542 cnt, data); 543 return; 544 default: 545 if (auth_debug_mode) 546 printf("Unknown Kerberos option %d\r\n", data[-1]); 547 return; 548 } 549 } 550 551 int 552 kerberos5_status(Authenticator *ap, char *name, int level) 553 { 554 if (level < AUTH_USER) 555 return (level); 556 557 if (UserNameRequested && 558 krb5_kuserok(telnet_context, ticket->client, UserNameRequested)) { 559 strcpy(name, UserNameRequested); 560 return (AUTH_VALID); 561 } else 562 return (AUTH_USER); 563 } 564 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} 565 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} 566 567 void 568 kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen) 569 { 570 int i; 571 572 buf[buflen - 1] = '\0'; /* make sure its NULL terminated */ 573 buflen -= 1; 574 575 switch (data[3]) { 576 case KRB_REJECT: /* Rejected (reason might follow) */ 577 strlcpy((char *) buf, " REJECT ", buflen); 578 goto common; 579 580 case KRB_ACCEPT: /* Accepted (name might follow) */ 581 strlcpy((char *) buf, " ACCEPT ", buflen); 582 common: 583 BUMP(buf, buflen); 584 if (cnt <= 4) 585 break; 586 ADDC(buf, buflen, '"'); 587 for (i = 4; i < cnt; i++) 588 ADDC(buf, buflen, data[i]); 589 ADDC(buf, buflen, '"'); 590 ADDC(buf, buflen, '\0'); 591 break; 592 593 594 case KRB_AUTH: /* Authentication data follows */ 595 strlcpy((char *) buf, " AUTH", buflen); 596 goto common2; 597 598 case KRB_RESPONSE: 599 strlcpy((char *) buf, " RESPONSE", buflen); 600 goto common2; 601 602 case KRB_FORWARD: /* Forwarded credentials follow */ 603 strlcpy((char *) buf, " FORWARD", buflen); 604 goto common2; 605 606 case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 607 strlcpy((char *) buf, " FORWARD_ACCEPT", buflen); 608 goto common2; 609 610 case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 611 /* (reason might follow) */ 612 strlcpy((char *) buf, " FORWARD_REJECT", buflen); 613 goto common2; 614 615 default: 616 snprintf(buf, buflen, " %d (unknown)", data[3]); 617 common2: 618 BUMP(buf, buflen); 619 for (i = 4; i < cnt; i++) { 620 snprintf(buf, buflen, " %d", data[i]); 621 BUMP(buf, buflen); 622 } 623 break; 624 } 625 } 626 627 void 628 kerberos5_forward(Authenticator * ap) 629 { 630 krb5_error_code ret; 631 krb5_ccache ccache; 632 krb5_creds creds; 633 krb5_kdc_flags flags; 634 krb5_data out_data; 635 krb5_principal principal; 636 637 ret = krb5_cc_default(telnet_context, &ccache); 638 if (ret) { 639 if (auth_debug_mode) 640 printf("KerberosV5: could not get default ccache: %s\r\n", 641 krb5_get_err_text(telnet_context, ret)); 642 return; 643 } 644 ret = krb5_cc_get_principal(telnet_context, ccache, &principal); 645 if (ret) { 646 if (auth_debug_mode) 647 printf("KerberosV5: could not get principal: %s\r\n", 648 krb5_get_err_text(telnet_context, ret)); 649 return; 650 } 651 memset(&creds, 0, sizeof(creds)); 652 653 creds.client = principal; 654 655 ret = krb5_build_principal(telnet_context, &creds.server, 656 strlen(principal->realm), principal->realm, "krbtgt", 657 principal->realm, NULL); 658 659 if (ret) { 660 if (auth_debug_mode) 661 printf("KerberosV5: could not get principal: %s\r\n", 662 krb5_get_err_text(telnet_context, ret)); 663 return; 664 } 665 creds.times.endtime = 0; 666 667 flags.i = 0; 668 flags.b.forwarded = 1; 669 if (forward_flags & OPTS_FORWARDABLE_CREDS) 670 flags.b.forwardable = 1; 671 672 ret = krb5_get_forwarded_creds(telnet_context, auth_context, 673 ccache, flags.i, RemoteHostName, &creds, &out_data); 674 if (ret) { 675 if (auth_debug_mode) 676 printf("Kerberos V5: error getting forwarded creds: %s\r\n", 677 krb5_get_err_text(telnet_context, ret)); 678 return; 679 } 680 if (!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) { 681 if (auth_debug_mode) 682 printf("Not enough room for authentication data\r\n"); 683 } else { 684 if (auth_debug_mode) 685 printf("Forwarded local Kerberos V5 credentials to server\r\n"); 686 } 687 } 688 #endif /* KRB5 */ 689