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