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 * usr/src/cmd/cmd-inet/usr.bin/telnet/kerberos5.c 10 * 11 * Copyright (c) 1991, 1993 12 * The Regents of the University of California. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 */ 42 43 /* based on @(#)kerberos5.c 8.1 (Berkeley) 6/4/93 */ 44 45 /* 46 * Copyright (C) 1990 by the Massachusetts Institute of Technology 47 * 48 * Export of this software from the United States of America may 49 * require a specific license from the United States Government. 50 * It is the responsibility of any person or organization contemplating 51 * export to obtain such a license before exporting. 52 * 53 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 54 * distribute this software and its documentation for any purpose and 55 * without fee is hereby granted, provided that the above copyright 56 * notice appear in all copies and that both that copyright notice and 57 * this permission notice appear in supporting documentation, and that 58 * the name of M.I.T. not be used in advertising or publicity pertaining 59 * to distribution of the software without specific, written prior 60 * permission. Furthermore if you modify this software you must label 61 * your software as modified software and not distribute it in such a 62 * fashion that it might be confused with the original M.I.T. software. 63 * M.I.T. makes no representations about the suitability of 64 * this software for any purpose. It is provided "as is" without express 65 * or implied warranty. 66 */ 67 68 69 #include <arpa/telnet.h> 70 #include <stdio.h> 71 #include <ctype.h> 72 #include <syslog.h> 73 #include <stdlib.h> 74 75 /* the following are from the kerberos tree */ 76 #include <k5-int.h> 77 #include <com_err.h> 78 #include <netdb.h> 79 #include <profile/prof_int.h> 80 #include <sys/param.h> 81 #include "externs.h" 82 83 extern char *RemoteHostName; 84 extern boolean_t auth_debug_mode; 85 extern int net; 86 87 #define ACCEPTED_ENCTYPE(a) \ 88 (a == ENCTYPE_DES_CBC_CRC || a == ENCTYPE_DES_CBC_MD5) 89 /* for comapatibility with non-Solaris KDC's, this has to be big enough */ 90 #define KERBEROS_BUFSIZ 8192 91 92 int forward_flags = 0; /* Flags get set in telnet/main.c on -f and -F */ 93 static void kerberos5_forward(Authenticator *); 94 95 static unsigned char str_data[KERBEROS_BUFSIZ] = { IAC, SB, 96 TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V5, }; 97 static char *appdef[] = { "appdefaults", "telnet", NULL }; 98 static char *realmdef[] = { "realms", NULL, "telnet", NULL }; 99 100 static krb5_auth_context auth_context = 0; 101 102 static krb5_data auth; /* telnetd gets session key from here */ 103 static krb5_ticket *ticket = NULL; 104 /* telnet matches the AP_REQ and AP_REP with this */ 105 106 static krb5_keyblock *session_key = 0; 107 char *telnet_krb5_realm = NULL; 108 109 /* 110 * Change the kerberos realm 111 */ 112 void 113 set_krb5_realm(char *name) 114 { 115 if (name == NULL) { 116 (void) fprintf(stderr, gettext("Could not set Kerberos realm, " 117 "no realm provided.\n")); 118 return; 119 } 120 121 if (telnet_krb5_realm) 122 free(telnet_krb5_realm); 123 124 telnet_krb5_realm = (char *)strdup(name); 125 126 if (telnet_krb5_realm == NULL) 127 (void) fprintf(stderr, gettext( 128 "Could not set Kerberos realm, malloc failed\n")); 129 } 130 131 #define RETURN_NOMEM { errno = ENOMEM; return (-1); } 132 133 static int 134 krb5_send_data(Authenticator *ap, int type, krb5_pointer d, int c) 135 { 136 /* the first 3 bytes are control chars */ 137 unsigned char *p = str_data + 4; 138 unsigned char *cd = (unsigned char *)d; 139 /* spaceleft is incremented whenever p is decremented */ 140 size_t spaceleft = sizeof (str_data) - 4; 141 142 if (c == -1) 143 c = strlen((char *)cd); 144 145 if (auth_debug_mode) { 146 (void) printf("%s:%d: [%d] (%d)", 147 str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY", 148 str_data[3], type, c); 149 printd(d, c); 150 (void) printf("\r\n"); 151 } 152 153 if (spaceleft < 3) 154 RETURN_NOMEM; 155 *p++ = ap->type; 156 *p++ = ap->way; 157 *p++ = type; 158 spaceleft -= 3; 159 160 while (c-- > 0) { 161 if (spaceleft < 2) 162 RETURN_NOMEM; 163 if ((*p++ = *cd++) == IAC) { 164 *p++ = IAC; 165 spaceleft -= 2; 166 } 167 } 168 169 if (spaceleft < 2) 170 RETURN_NOMEM; 171 *p++ = IAC; 172 *p++ = SE; 173 if (str_data[3] == TELQUAL_IS) 174 printsub('>', &str_data[2], p - &str_data[2]); 175 return (net_write(str_data, p - str_data)); 176 } 177 178 krb5_context telnet_context = 0; 179 180 /* ARGSUSED */ 181 int 182 kerberos5_init(Authenticator *ap) 183 { 184 krb5_error_code retval; 185 186 str_data[3] = TELQUAL_IS; 187 if (krb5auth_flag && (telnet_context == 0)) { 188 retval = krb5_init_context(&telnet_context); 189 if (retval) 190 return (0); 191 } 192 return (1); 193 } 194 195 int 196 kerberos5_send(Authenticator *ap) 197 { 198 krb5_error_code retval; 199 krb5_ccache ccache; 200 krb5_creds creds; /* telnet gets session key from here */ 201 krb5_creds *new_creds = 0; 202 int ap_opts; 203 char type_check[2]; 204 krb5_data check_data; 205 206 krb5_keyblock *newkey = 0; 207 208 int i; 209 krb5_enctype *ktypes; 210 211 if (!UserNameRequested) { 212 if (auth_debug_mode) 213 (void) printf(gettext("telnet: Kerberos V5: " 214 "no user name supplied\r\n")); 215 return (0); 216 } 217 218 if ((retval = krb5_cc_default(telnet_context, &ccache))) { 219 if (auth_debug_mode) 220 (void) printf(gettext("telnet: Kerberos V5: " 221 "could not get default ccache\r\n")); 222 return (0); 223 } 224 225 (void) memset((char *)&creds, 0, sizeof (creds)); 226 if (auth_debug_mode) 227 printf("telnet: calling krb5_sname_to_principal\n"); 228 if ((retval = krb5_sname_to_principal(telnet_context, RemoteHostName, 229 "host", KRB5_NT_SRV_HST, &creds.server))) { 230 if (auth_debug_mode) 231 (void) printf(gettext("telnet: Kerberos V5: error " 232 "while constructing service name: %s\r\n"), 233 error_message(retval)); 234 return (0); 235 } 236 if (auth_debug_mode) 237 printf("telnet: done calling krb5_sname_to_principal\n"); 238 239 if (telnet_krb5_realm != NULL) { 240 krb5_data rdata; 241 242 rdata.magic = 0; 243 rdata.length = strlen(telnet_krb5_realm); 244 rdata.data = (char *)malloc(rdata.length + 1); 245 if (rdata.data == NULL) { 246 (void) fprintf(stderr, gettext("malloc failed\n")); 247 return (0); 248 } 249 (void) strcpy(rdata.data, telnet_krb5_realm); 250 krb5_princ_set_realm(telnet_context, creds.server, &rdata); 251 if (auth_debug_mode) 252 (void) printf(gettext( 253 "telnet: Kerberos V5: set kerberos realm to %s\r\n"), 254 telnet_krb5_realm); 255 } 256 257 if ((retval = krb5_cc_get_principal(telnet_context, ccache, 258 &creds.client)) != NULL) { 259 if (auth_debug_mode) { 260 (void) printf(gettext( 261 "telnet: Kerberos V5: failure on principal " 262 "(%s)\r\n"), error_message(retval)); 263 } 264 krb5_free_cred_contents(telnet_context, &creds); 265 return (0); 266 } 267 /* 268 * Check to to confirm that at least one of the supported 269 * encryption types (des-cbc-md5, des-cbc-crc is available. If 270 * one is available then use it to obtain credentials. 271 */ 272 273 if ((retval = krb5_get_tgs_ktypes(telnet_context, creds.server, 274 &ktypes))) { 275 if (auth_debug_mode) { 276 (void) printf(gettext( 277 "telnet: Kerberos V5: could not determine " 278 "TGS encryption types " 279 "(see default_tgs_enctypes in krb5.conf) " 280 "(%s)\r\n"), error_message(retval)); 281 } 282 krb5_free_cred_contents(telnet_context, &creds); 283 return (0); 284 } 285 286 for (i = 0; ktypes[i]; i++) { 287 if (ACCEPTED_ENCTYPE(ktypes[i])) 288 break; 289 } 290 291 if (ktypes[i] == 0) { 292 if (auth_debug_mode) { 293 (void) printf(gettext( 294 "telnet: Kerberos V5: " 295 "failure on encryption types. " 296 "Cannot find des-cbc-md5 or des-cbc-crc " 297 "in list of TGS encryption types " 298 "(see default_tgs_enctypes in krb5.conf)\n")); 299 } 300 krb5_free_cred_contents(telnet_context, &creds); 301 return (0); 302 } 303 304 creds.keyblock.enctype = ktypes[i]; 305 if ((retval = krb5_get_credentials(telnet_context, 0, 306 ccache, &creds, &new_creds))) { 307 if (auth_debug_mode) { 308 (void) printf(gettext( 309 "telnet: Kerberos V5: failure on credentials " 310 "(%s)\r\n"), error_message(retval)); 311 } 312 krb5_free_cred_contents(telnet_context, &creds); 313 return (0); 314 } 315 316 ap_opts = ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 317 AP_OPTS_MUTUAL_REQUIRED : 0; 318 319 ap_opts |= AP_OPTS_USE_SUBKEY; 320 321 if (auth_context) { 322 krb5_auth_con_free(telnet_context, auth_context); 323 auth_context = 0; 324 } 325 if ((retval = krb5_auth_con_init(telnet_context, &auth_context))) { 326 if (auth_debug_mode) { 327 (void) printf(gettext( 328 "Kerberos V5: failed to init auth_context " 329 "(%s)\r\n"), error_message(retval)); 330 } 331 return (0); 332 } 333 334 krb5_auth_con_setflags(telnet_context, auth_context, 335 KRB5_AUTH_CONTEXT_RET_TIME); 336 337 type_check[0] = ap->type; 338 type_check[1] = ap->way; 339 check_data.magic = KV5M_DATA; 340 check_data.length = 2; 341 check_data.data = (char *)&type_check; 342 343 retval = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts, 344 &check_data, new_creds, &auth); 345 346 krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey); 347 if (session_key) { 348 krb5_free_keyblock(telnet_context, session_key); 349 session_key = 0; 350 } 351 352 if (newkey) { 353 /* 354 * keep the key in our private storage, but don't use it 355 * yet---see kerberos5_reply() below 356 */ 357 if (!(ACCEPTED_ENCTYPE(newkey->enctype))) { 358 if (!(ACCEPTED_ENCTYPE(new_creds->keyblock.enctype))) 359 /* use the session key in credentials instead */ 360 krb5_copy_keyblock(telnet_context, 361 &new_creds->keyblock, &session_key); 362 } else 363 krb5_copy_keyblock(telnet_context, 364 newkey, &session_key); 365 366 krb5_free_keyblock(telnet_context, newkey); 367 } 368 369 krb5_free_cred_contents(telnet_context, &creds); 370 krb5_free_creds(telnet_context, new_creds); 371 372 if (retval) { 373 if (auth_debug_mode) 374 (void) printf(gettext( 375 "telnet: Kerberos V5: mk_req failed (%s)\r\n"), 376 error_message(retval)); 377 return (0); 378 } 379 380 if ((auth_sendname((uchar_t *)UserNameRequested, 381 strlen(UserNameRequested))) == NULL) { 382 if (auth_debug_mode) 383 (void) printf(gettext( 384 "telnet: Not enough room for user name\r\n")); 385 return (0); 386 } 387 retval = krb5_send_data(ap, KRB_AUTH, auth.data, auth.length); 388 if (auth_debug_mode && retval) { 389 (void) printf(gettext( 390 "telnet: Sent Kerberos V5 credentials to server\r\n")); 391 } else if (auth_debug_mode) { 392 (void) printf(gettext( 393 "telnet: Not enough room for authentication data\r\n")); 394 return (0); 395 } 396 return (1); 397 } 398 399 void 400 kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt) 401 { 402 Session_Key skey; 403 static boolean_t mutual_complete = B_FALSE; 404 405 if (cnt-- < 1) 406 return; 407 switch (*data++) { 408 case KRB_REJECT: 409 if (cnt > 0) 410 (void) printf(gettext( 411 "[ Kerberos V5 refuses authentication because " 412 "%.*s ]\r\n"), cnt, data); 413 else 414 (void) printf(gettext( 415 "[ Kerberos V5 refuses authentication ]\r\n")); 416 auth_send_retry(); 417 return; 418 case KRB_ACCEPT: 419 if (!mutual_complete) { 420 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 421 (void) printf(gettext( 422 "[ Kerberos V5 accepted you, but didn't " 423 "provide mutual authentication! ]\r\n")); 424 auth_send_retry(); 425 return; 426 } 427 428 if (session_key) { 429 skey.type = SK_DES; 430 skey.length = 8; 431 skey.data = session_key->contents; 432 encrypt_session_key(&skey); 433 } 434 } 435 if (cnt) 436 (void) printf(gettext( 437 "[ Kerberos V5 accepts you as ``%.*s'' ]\r\n"), 438 cnt, data); 439 else 440 (void) printf(gettext( 441 "[ Kerberos V5 accepts you ]\r\n")); 442 auth_finished(ap, AUTH_USER); 443 444 if (forward_flags & OPTS_FORWARD_CREDS) 445 kerberos5_forward(ap); 446 447 break; 448 case KRB_RESPONSE: 449 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { 450 /* the rest of the reply should contain a krb_ap_rep */ 451 krb5_ap_rep_enc_part *reply; 452 krb5_data inbuf; 453 krb5_error_code retval; 454 455 inbuf.length = cnt; 456 inbuf.data = (char *)data; 457 458 retval = krb5_rd_rep(telnet_context, auth_context, 459 &inbuf, &reply); 460 if (retval) { 461 (void) printf(gettext( 462 "[ Mutual authentication failed: " 463 "%s ]\r\n"), error_message(retval)); 464 auth_send_retry(); 465 return; 466 } 467 krb5_free_ap_rep_enc_part(telnet_context, reply); 468 469 if (session_key) { 470 skey.type = SK_DES; 471 skey.length = 8; 472 skey.data = session_key->contents; 473 encrypt_session_key(&skey); 474 } 475 mutual_complete = B_TRUE; 476 } 477 return; 478 case KRB_FORWARD_ACCEPT: 479 (void) printf(gettext( 480 "[ Kerberos V5 accepted forwarded credentials ]\r\n")); 481 return; 482 case KRB_FORWARD_REJECT: 483 (void) printf(gettext( 484 "[ Kerberos V5 refuses forwarded credentials because " 485 "%.*s ]\r\n"), cnt, data); 486 return; 487 default: 488 if (auth_debug_mode) 489 (void) printf(gettext( 490 "Unknown Kerberos option %d\r\n"), data[-1]); 491 return; 492 } 493 } 494 495 /* ARGSUSED */ 496 int 497 kerberos5_status(Authenticator *ap, char *name, int level) 498 { 499 if (level < AUTH_USER) 500 return (level); 501 502 if (UserNameRequested && krb5_kuserok(telnet_context, 503 ticket->enc_part2->client, UserNameRequested)) { 504 505 /* the name buffer comes from telnetd/telnetd{-ktd}.c */ 506 (void) strncpy(name, UserNameRequested, MAXNAMELEN); 507 name[MAXNAMELEN-1] = '\0'; 508 return (AUTH_VALID); 509 } else 510 return (AUTH_USER); 511 } 512 513 #define BUMP(buf, len) while (*(buf)) {++(buf), --(len); } 514 #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len); } 515 516 /* 517 * Used with the set opt command to print suboptions 518 */ 519 void 520 kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen) 521 { 522 char lbuf[AUTH_LBUF_BUFSIZ]; 523 register int i; 524 525 buf[buflen-1] = '\0'; /* make sure its NULL terminated */ 526 buflen -= 1; 527 528 switch (data[3]) { 529 case KRB_REJECT: /* Rejected (reason might follow) */ 530 (void) strncpy((char *)buf, " REJECT ", buflen); 531 goto common; 532 533 case KRB_ACCEPT: /* Accepted (name might follow) */ 534 (void) strncpy((char *)buf, " ACCEPT ", buflen); 535 common: 536 BUMP(buf, buflen); 537 if (cnt <= 4) 538 break; 539 ADDC(buf, buflen, '"'); 540 for (i = 4; i < cnt; i++) 541 ADDC(buf, buflen, data[i]); 542 ADDC(buf, buflen, '"'); 543 ADDC(buf, buflen, '\0'); 544 break; 545 546 case KRB_AUTH: /* Authentication data follows */ 547 (void) strncpy((char *)buf, " AUTH", buflen); 548 goto common2; 549 550 case KRB_RESPONSE: 551 (void) strncpy((char *)buf, " RESPONSE", buflen); 552 goto common2; 553 554 case KRB_FORWARD: /* Forwarded credentials follow */ 555 (void) strncpy((char *)buf, " FORWARD", buflen); 556 goto common2; 557 558 case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */ 559 (void) strncpy((char *)buf, " FORWARD_ACCEPT", buflen); 560 goto common2; 561 562 case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */ 563 /* (reason might follow) */ 564 (void) strncpy((char *)buf, " FORWARD_REJECT", buflen); 565 goto common2; 566 567 default: 568 (void) snprintf(lbuf, AUTH_LBUF_BUFSIZ, 569 gettext(" %d (unknown)"), 570 data[3]); 571 (void) strncpy((char *)buf, lbuf, buflen); 572 common2: 573 BUMP(buf, buflen); 574 for (i = 4; i < cnt; i++) { 575 (void) snprintf(lbuf, AUTH_LBUF_BUFSIZ, " %d", data[i]); 576 (void) strncpy((char *)buf, lbuf, buflen); 577 BUMP(buf, buflen); 578 } 579 break; 580 } 581 } 582 583 void 584 krb5_profile_get_options(char *host, char *realm, 585 profile_options_boolean *optionsp) 586 { 587 char **realms = NULL; 588 krb5_error_code err = 0; 589 590 if (!telnet_context) { 591 err = krb5_init_context(&telnet_context); 592 if (err) { 593 (void) fprintf(stderr, gettext( 594 "Error initializing Kerberos 5 library: %s\n"), 595 error_message(err)); 596 return; 597 } 598 } 599 600 if ((realmdef[1] = realm) == NULL) { 601 err = krb5_get_host_realm(telnet_context, host, &realms); 602 if (err) { 603 (void) fprintf(stderr, gettext( 604 "Error getting Kerberos 5 realms for: %s (%s)\n"), 605 host, error_message(err)); 606 return; 607 } 608 realmdef[1] = realms[0]; 609 } 610 611 profile_get_options_boolean(telnet_context->profile, 612 realmdef, optionsp); 613 profile_get_options_boolean(telnet_context->profile, 614 appdef, optionsp); 615 } 616 617 static void 618 kerberos5_forward(Authenticator *ap) 619 { 620 krb5_error_code retval; 621 krb5_ccache ccache; 622 krb5_principal client = 0; 623 krb5_principal server = 0; 624 krb5_data forw_creds; 625 626 forw_creds.data = 0; 627 628 if ((retval = krb5_cc_default(telnet_context, &ccache))) { 629 if (auth_debug_mode) 630 (void) printf(gettext( 631 "Kerberos V5: could not get default ccache - %s\r\n"), 632 error_message(retval)); 633 return; 634 } 635 636 retval = krb5_cc_get_principal(telnet_context, ccache, &client); 637 if (retval) { 638 if (auth_debug_mode) 639 (void) printf(gettext( 640 "Kerberos V5: could not get default " 641 "principal - %s\r\n"), error_message(retval)); 642 goto cleanup; 643 } 644 645 retval = krb5_sname_to_principal(telnet_context, RemoteHostName, 646 "host", KRB5_NT_SRV_HST, &server); 647 if (retval) { 648 if (auth_debug_mode) 649 (void) printf(gettext( 650 "Kerberos V5: could not make server " 651 "principal - %s\r\n"), error_message(retval)); 652 goto cleanup; 653 } 654 655 retval = krb5_auth_con_genaddrs(telnet_context, auth_context, net, 656 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); 657 if (retval) { 658 if (auth_debug_mode) 659 (void) printf(gettext( 660 "Kerberos V5: could not gen local full " 661 "address - %s\r\n"), error_message(retval)); 662 goto cleanup; 663 } 664 665 retval = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client, 666 server, ccache, forward_flags & OPTS_FORWARDABLE_CREDS, 667 &forw_creds); 668 if (retval) { 669 if (auth_debug_mode) 670 (void) printf(gettext( 671 "Kerberos V5: error getting forwarded " 672 "creds - %s\r\n"), error_message(retval)); 673 goto cleanup; 674 } 675 676 /* Send forwarded credentials */ 677 if (!krb5_send_data(ap, KRB_FORWARD, forw_creds.data, 678 forw_creds.length)) { 679 if (auth_debug_mode) 680 (void) printf(gettext( 681 "Not enough room for authentication data\r\n")); 682 } else if (auth_debug_mode) 683 (void) printf(gettext( 684 "Forwarded local Kerberos V5 credentials to server\r\n")); 685 cleanup: 686 if (client) 687 krb5_free_principal(telnet_context, client); 688 if (server) 689 krb5_free_principal(telnet_context, server); 690 if (forw_creds.data) 691 free(forw_creds.data); 692 /* LINTED */ 693 krb5_cc_close(telnet_context, ccache); 694 } 695