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