]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/telnet/libtelnet/kerberos5.c
Help fix warnings by marking an argument as unused.
[FreeBSD/FreeBSD.git] / contrib / 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 <sys/cdefs.h>
55
56 __FBSDID("$FreeBSD$");
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
72 #include "encrypt.h"
73 #include "auth.h"
74 #include "misc.h"
75
76 int forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
77
78 /* These values need to be the same as those defined in telnet/main.c. */
79 /* Either define them in both places, or put in some common header file. */
80 #define OPTS_FORWARD_CREDS      0x00000002
81 #define OPTS_FORWARDABLE_CREDS  0x00000001
82
83 void kerberos5_forward (Authenticator *);
84
85 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
86                                         AUTHTYPE_KERBEROS_V5, };
87
88 #define KRB_AUTH                0       /* Authentication data follows */
89 #define KRB_REJECT              1       /* Rejected (reason might follow) */
90 #define KRB_ACCEPT              2       /* Accepted */
91 #define KRB_RESPONSE            3       /* Response for mutual auth. */
92
93 #define KRB_FORWARD             4       /* Forwarded credentials follow */
94 #define KRB_FORWARD_ACCEPT      5       /* Forwarded credentials accepted */
95 #define KRB_FORWARD_REJECT      6       /* Forwarded credentials rejected */
96
97 static  krb5_data auth;
98 static  krb5_ticket *ticket;
99
100 static krb5_context context;
101 static krb5_auth_context auth_context;
102
103 static int
104 Data(Authenticator *ap, int type, const char *d, int c)
105 {
106     unsigned char *p = str_data + 4;
107     const unsigned char *cd = d;
108
109     if (c == -1)
110         c = strlen(cd);
111
112     if (auth_debug_mode) {
113         printf("%s:%d: [%d] (%d)",
114                str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
115                str_data[3],
116                type, c);
117         printd(d, c);
118         printf("\r\n");
119     }
120     *p++ = ap->type;
121     *p++ = ap->way;
122     *p++ = type;
123     while (c-- > 0) {
124         if ((*p++ = *cd++) == IAC)
125             *p++ = IAC;
126     }
127     *p++ = IAC;
128     *p++ = SE;
129     if (str_data[3] == TELQUAL_IS)
130         printsub('>', &str_data[2], p - &str_data[2]);
131     return(net_write(str_data, p - str_data));
132 }
133
134 int
135 kerberos5_init(Authenticator *ap __unused, int server)
136 {
137     krb5_error_code ret;
138
139     ret = krb5_init_context(&context);
140     if (ret)
141         return 0;
142     if (server) {
143         krb5_keytab kt;
144         krb5_kt_cursor cursor;
145
146         ret = krb5_kt_default(context, &kt);
147         if (ret)
148             return 0;
149
150         ret = krb5_kt_start_seq_get (context, kt, &cursor);
151         if (ret) {
152             krb5_kt_close (context, kt);
153             return 0;
154         }
155         krb5_kt_end_seq_get (context, kt, &cursor);
156         krb5_kt_close (context, kt);
157
158         str_data[3] = TELQUAL_REPLY;
159     } else
160         str_data[3] = TELQUAL_IS;
161     return(1);
162 }
163
164 extern int net;
165
166 static int
167 kerberos5_send(const char *name, Authenticator *ap)
168 {
169     krb5_error_code ret;
170     krb5_ccache ccache;
171     int ap_opts;
172     krb5_data cksum_data;
173     char foo[2];
174     
175     if (!UserNameRequested) {
176         if (auth_debug_mode) {
177             printf("Kerberos V5: no user name supplied\r\n");
178         }
179         return(0);
180     }
181     
182     ret = krb5_cc_default(context, &ccache);
183     if (ret) {
184         if (auth_debug_mode) {
185             printf("Kerberos V5: could not get default ccache: %s\r\n",
186                    krb5_get_err_text (context, ret));
187         }
188         return 0;
189     }
190         
191     if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
192         ap_opts = AP_OPTS_MUTUAL_REQUIRED;
193     else
194         ap_opts = 0;
195     
196     ret = krb5_auth_con_init (context, &auth_context);
197     if (ret) {
198         if (auth_debug_mode) {
199             printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
200                    krb5_get_err_text(context, ret));
201         }
202         return(0);
203     }
204
205     ret = krb5_auth_con_setaddrs_from_fd (context,
206                                           auth_context,
207                                           &net);
208     if (ret) {
209         if (auth_debug_mode) {
210             printf ("Kerberos V5:"
211                     " krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
212                     krb5_get_err_text(context, ret));
213         }
214         return(0);
215     }
216
217     krb5_auth_con_setkeytype (context, auth_context, KEYTYPE_DES);
218
219     foo[0] = ap->type;
220     foo[1] = ap->way;
221
222     cksum_data.length = sizeof(foo);
223     cksum_data.data   = foo;
224
225
226     {
227         krb5_principal service;
228         char sname[128];
229
230
231         ret = krb5_sname_to_principal (context,
232                                        RemoteHostName,
233                                        NULL,
234                                        KRB5_NT_SRV_HST,
235                                        &service);
236         if(ret) {
237             if (auth_debug_mode) {
238                 printf ("Kerberos V5:"
239                         " krb5_sname_to_principal(%s) failed (%s)\r\n",
240                         RemoteHostName, krb5_get_err_text(context, ret));
241             }
242             return 0;
243         }
244         ret = krb5_unparse_name_fixed(context, service, sname, sizeof(sname));
245         if(ret) {
246             if (auth_debug_mode) {
247                 printf ("Kerberos V5:"
248                         " krb5_unparse_name_fixed failed (%s)\r\n",
249                         krb5_get_err_text(context, ret));
250             }
251             return 0;
252         }
253         printf("[ Trying %s (%s)... ]\r\n", name, sname);
254         ret = krb5_mk_req_exact(context, &auth_context, ap_opts,
255                                 service, 
256                                 &cksum_data, ccache, &auth);
257         krb5_free_principal (context, service);
258
259     }
260     if (ret) {
261         if (1 || auth_debug_mode) {
262             printf("Kerberos V5: mk_req failed (%s)\r\n",
263                    krb5_get_err_text(context, ret));
264         }
265         return(0);
266     }
267
268     if (!auth_sendname((unsigned char *)UserNameRequested,
269                        strlen(UserNameRequested))) {
270         if (auth_debug_mode)
271             printf("Not enough room for user name\r\n");
272         return(0);
273     }
274     if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
275         if (auth_debug_mode)
276             printf("Not enough room for authentication data\r\n");
277         return(0);
278     }
279     if (auth_debug_mode) {
280         printf("Sent Kerberos V5 credentials to server\r\n");
281     }
282     return(1);
283 }
284
285 int
286 kerberos5_send_mutual(Authenticator *ap)
287 {
288     return kerberos5_send("mutual KERBEROS5", ap);
289 }
290
291 int
292 kerberos5_send_oneway(Authenticator *ap)
293 {
294     return kerberos5_send("KERBEROS5", ap);
295 }
296
297 void
298 kerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
299 {
300     krb5_error_code ret;
301     krb5_data outbuf;
302     krb5_keyblock *key_block;
303     char *name;
304     krb5_principal server;
305     int zero = 0;
306
307     if (cnt-- < 1)
308         return;
309     switch (*data++) {
310     case KRB_AUTH:
311         auth.data = (char *)data;
312         auth.length = cnt;
313
314         auth_context = NULL;
315
316         ret = krb5_auth_con_init (context, &auth_context);
317         if (ret) {
318             Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
319             auth_finished(ap, AUTH_REJECT);
320             if (auth_debug_mode)
321                 printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
322                        krb5_get_err_text(context, ret));
323             return;
324         }
325
326         ret = krb5_auth_con_setaddrs_from_fd (context,
327                                               auth_context,
328                                               &zero);
329         if (ret) {
330             Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
331             auth_finished(ap, AUTH_REJECT);
332             if (auth_debug_mode)
333                 printf("Kerberos V5: "
334                        "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
335                        krb5_get_err_text(context, ret));
336             return;
337         }
338
339         ret = krb5_sock_to_principal (context,
340                                       0,
341                                       "host",
342                                       KRB5_NT_SRV_HST,
343                                       &server);
344         if (ret) {
345             Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
346             auth_finished(ap, AUTH_REJECT);
347             if (auth_debug_mode)
348                 printf("Kerberos V5: "
349                        "krb5_sock_to_principal failed (%s)\r\n",
350                        krb5_get_err_text(context, ret));
351             return;
352         }
353
354         ret = krb5_rd_req(context,
355                           &auth_context,
356                           &auth, 
357                           server,
358                           NULL,
359                           NULL,
360                           &ticket);
361
362         krb5_free_principal (context, server);
363         if (ret) {
364             char *errbuf;
365
366             asprintf(&errbuf,
367                      "Read req failed: %s",
368                      krb5_get_err_text(context, ret));
369             Data(ap, KRB_REJECT, errbuf, -1);
370             if (auth_debug_mode)
371                 printf("%s\r\n", errbuf);
372             free (errbuf);
373             return;
374         }
375         
376         {
377             char foo[2];
378             
379             foo[0] = ap->type;
380             foo[1] = ap->way;
381             
382             ret = krb5_verify_authenticator_checksum(context,
383                                                      auth_context,
384                                                      foo, 
385                                                      sizeof(foo));
386
387             if (ret) {
388                 char *errbuf;
389                 asprintf(&errbuf, "Bad checksum: %s", 
390                          krb5_get_err_text(context, ret));
391                 Data(ap, KRB_REJECT, errbuf, -1);
392                 if (auth_debug_mode)
393                     printf ("%s\r\n", errbuf);
394                 free(errbuf);
395                 return;
396             }
397         }
398         ret = krb5_auth_con_getremotesubkey (context,
399                                              auth_context,
400                                              &key_block);
401
402         if (ret) {
403             Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
404             auth_finished(ap, AUTH_REJECT);
405             if (auth_debug_mode)
406                 printf("Kerberos V5: "
407                        "krb5_auth_con_getremotesubkey failed (%s)\r\n",
408                        krb5_get_err_text(context, ret));
409             return;
410         }
411
412         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
413             ret = krb5_mk_rep(context, auth_context, &outbuf);
414             if (ret) {
415                 Data(ap, KRB_REJECT,
416                      "krb5_mk_rep failed", -1);
417                 auth_finished(ap, AUTH_REJECT);
418                 if (auth_debug_mode)
419                     printf("Kerberos V5: "
420                            "krb5_mk_rep failed (%s)\r\n",
421                            krb5_get_err_text(context, ret));
422                 return;
423             }
424             Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
425         }
426         if (krb5_unparse_name(context, ticket->client, &name))
427             name = 0;
428
429         if(UserNameRequested && krb5_kuserok(context,
430                                              ticket->client,
431                                              UserNameRequested)) {
432             Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
433             if (auth_debug_mode) {
434                 printf("Kerberos5 identifies him as ``%s''\r\n",
435                        name ? name : "");
436             }
437
438             if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
439                key_block->keytype == ETYPE_DES_CBC_MD4 ||
440                key_block->keytype == ETYPE_DES_CBC_CRC) {
441                 Session_Key skey;
442
443                 skey.type = SK_DES;
444                 skey.length = 8;
445                 skey.data = key_block->keyvalue.data;
446                 encrypt_session_key(&skey, 0);
447             }
448
449         } else {
450             char *msg;
451
452             asprintf (&msg, "user `%s' is not authorized to "
453                       "login as `%s'", 
454                       name ? name : "<unknown>",
455                       UserNameRequested ? UserNameRequested : "<nobody>");
456             if (msg == NULL)
457                 Data(ap, KRB_REJECT, NULL, 0);
458             else {
459                 Data(ap, KRB_REJECT, (void *)msg, -1);
460                 free(msg);
461             }
462             auth_finished (ap, AUTH_REJECT);
463             krb5_free_keyblock_contents(context, key_block);
464             break;
465         }
466         auth_finished(ap, AUTH_USER);
467         krb5_free_keyblock_contents(context, key_block);
468         
469         break;
470     case KRB_FORWARD: {
471         struct passwd *pwd;
472         char ccname[1024];      /* XXX */
473         krb5_data inbuf;
474         krb5_ccache ccache;
475         inbuf.data = (char *)data;
476         inbuf.length = cnt;
477
478         pwd = getpwnam (UserNameRequested);
479         if (pwd == NULL)
480             break;
481
482         snprintf (ccname, sizeof(ccname),
483                   "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
484
485         ret = krb5_cc_resolve (context, ccname, &ccache);
486         if (ret) {
487             if (auth_debug_mode)
488                 printf ("Kerberos V5: could not get ccache: %s\r\n",
489                         krb5_get_err_text(context, ret));
490             break;
491         }
492
493         ret = krb5_cc_initialize (context,
494                                   ccache,
495                                   ticket->client);
496         if (ret) {
497             if (auth_debug_mode)
498                 printf ("Kerberos V5: could not init ccache: %s\r\n",
499                         krb5_get_err_text(context, ret));
500             break;
501         }
502
503 #if defined(DCE)
504         esetenv("KRB5CCNAME", ccname, 1);
505 #endif
506         ret = krb5_rd_cred2 (context,
507                              auth_context,
508                              ccache,
509                              &inbuf);
510         if(ret) {
511             char *errbuf;
512
513             asprintf (&errbuf,
514                       "Read forwarded creds failed: %s",
515                       krb5_get_err_text (context, ret));
516             if(errbuf == NULL)
517                 Data(ap, KRB_FORWARD_REJECT, NULL, 0);
518             else
519                 Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
520             if (auth_debug_mode)
521                 printf("Could not read forwarded credentials: %s\r\n",
522                        errbuf);
523             free (errbuf);
524         } else {
525             Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
526 #if defined(DCE)
527             dfsfwd = 1;
528 #endif
529         }
530         chown (ccname + 5, pwd->pw_uid, -1);
531         if (auth_debug_mode)
532             printf("Forwarded credentials obtained\r\n");
533         break;
534     }
535     default:
536         if (auth_debug_mode)
537             printf("Unknown Kerberos option %d\r\n", data[-1]);
538         Data(ap, KRB_REJECT, 0, 0);
539         break;
540     }
541 }
542
543 void
544 kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
545 {
546     static int mutual_complete = 0;
547
548     if (cnt-- < 1)
549         return;
550     switch (*data++) {
551     case KRB_REJECT:
552         if (cnt > 0) {
553             printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
554                    cnt, data);
555         } else
556             printf("[ Kerberos V5 refuses authentication ]\r\n");
557         auth_send_retry();
558         return;
559     case KRB_ACCEPT: {
560         krb5_error_code ret;
561         Session_Key skey;
562         krb5_keyblock *keyblock;
563         
564         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
565             !mutual_complete) {
566             printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
567             auth_send_retry();
568             return;
569         }
570         if (cnt)
571             printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
572         else
573             printf("[ Kerberos V5 accepts you ]\r\n");
574               
575         ret = krb5_auth_con_getlocalsubkey (context,
576                                             auth_context,
577                                             &keyblock);
578         if (ret)
579             ret = krb5_auth_con_getkey (context,
580                                         auth_context,
581                                         &keyblock);
582         if(ret) {
583             printf("[ krb5_auth_con_getkey: %s ]\r\n",
584                    krb5_get_err_text(context, ret));
585             auth_send_retry();
586             return;
587         }
588               
589         skey.type = SK_DES;
590         skey.length = 8;
591         skey.data = keyblock->keyvalue.data;
592         encrypt_session_key(&skey, 0);
593         krb5_free_keyblock_contents (context, keyblock);
594         auth_finished(ap, AUTH_USER);
595         if (forward_flags & OPTS_FORWARD_CREDS)
596             kerberos5_forward(ap);
597         break;
598     }
599     case KRB_RESPONSE:
600         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
601             /* the rest of the reply should contain a krb_ap_rep */
602           krb5_ap_rep_enc_part *reply;
603           krb5_data inbuf;
604           krb5_error_code ret;
605             
606           inbuf.length = cnt;
607           inbuf.data = (char *)data;
608
609           ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
610           if (ret) {
611               printf("[ Mutual authentication failed: %s ]\r\n",
612                      krb5_get_err_text (context, ret));
613               auth_send_retry();
614               return;
615           }
616           krb5_free_ap_rep_enc_part(context, reply);
617           mutual_complete = 1;
618         }
619         return;
620     case KRB_FORWARD_ACCEPT:
621         printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
622         return;
623     case KRB_FORWARD_REJECT:
624         printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
625                cnt, data);
626         return;
627     default:
628         if (auth_debug_mode)
629             printf("Unknown Kerberos option %d\r\n", data[-1]);
630         return;
631     }
632 }
633
634 int
635 kerberos5_status(Authenticator *ap __unused, char *name, int level)
636 {
637     if (level < AUTH_USER)
638         return(level);
639
640     if (UserNameRequested &&
641         krb5_kuserok(context,
642                      ticket->client,
643                      UserNameRequested))
644         {
645             strcpy(name, UserNameRequested);
646             return(AUTH_VALID);
647         } else
648             return(AUTH_USER);
649 }
650
651 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
652 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
653
654 void
655 kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
656 {
657     int i;
658
659     buf[buflen-1] = '\0';               /* make sure its NULL terminated */
660     buflen -= 1;
661
662     switch(data[3]) {
663     case KRB_REJECT:            /* Rejected (reason might follow) */
664         strlcpy((char *)buf, " REJECT ", buflen);
665         goto common;
666
667     case KRB_ACCEPT:            /* Accepted (name might follow) */
668         strlcpy((char *)buf, " ACCEPT ", buflen);
669     common:
670         BUMP(buf, buflen);
671         if (cnt <= 4)
672             break;
673         ADDC(buf, buflen, '"');
674         for (i = 4; i < cnt; i++)
675             ADDC(buf, buflen, data[i]);
676         ADDC(buf, buflen, '"');
677         ADDC(buf, buflen, '\0');
678         break;
679
680
681     case KRB_AUTH:                      /* Authentication data follows */
682         strlcpy((char *)buf, " AUTH", buflen);
683         goto common2;
684
685     case KRB_RESPONSE:
686         strlcpy((char *)buf, " RESPONSE", buflen);
687         goto common2;
688
689     case KRB_FORWARD:           /* Forwarded credentials follow */
690         strlcpy((char *)buf, " FORWARD", buflen);
691         goto common2;
692
693     case KRB_FORWARD_ACCEPT:    /* Forwarded credentials accepted */
694         strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
695         goto common2;
696
697     case KRB_FORWARD_REJECT:    /* Forwarded credentials rejected */
698         /* (reason might follow) */
699         strlcpy((char *)buf, " FORWARD_REJECT", buflen);
700         goto common2;
701
702     default:
703         snprintf(buf, buflen, " %d (unknown)", data[3]);
704     common2:
705         BUMP(buf, buflen);
706         for (i = 4; i < cnt; i++) {
707             snprintf(buf, buflen, " %d", data[i]);
708             BUMP(buf, buflen);
709         }
710         break;
711     }
712 }
713
714 void
715 kerberos5_forward(Authenticator *ap)
716 {
717     krb5_error_code ret;
718     krb5_ccache     ccache;
719     krb5_creds      creds;
720     krb5_kdc_flags  flags;
721     krb5_data       out_data;
722     krb5_principal  principal;
723
724     ret = krb5_cc_default (context, &ccache);
725     if (ret) {
726         if (auth_debug_mode)
727             printf ("KerberosV5: could not get default ccache: %s\r\n",
728                     krb5_get_err_text (context, ret));
729         return;
730     }
731
732     ret = krb5_cc_get_principal (context, ccache, &principal);
733     if (ret) {
734         if (auth_debug_mode)
735             printf ("KerberosV5: could not get principal: %s\r\n",
736                     krb5_get_err_text (context, ret));
737         return;
738     }
739
740     memset (&creds, 0, sizeof(creds));
741
742     creds.client = principal;
743     
744     ret = krb5_build_principal (context,
745                                 &creds.server,
746                                 strlen(principal->realm),
747                                 principal->realm,
748                                 "krbtgt",
749                                 principal->realm,
750                                 NULL);
751
752     if (ret) {
753         if (auth_debug_mode)
754             printf ("KerberosV5: could not get principal: %s\r\n",
755                     krb5_get_err_text (context, ret));
756         return;
757     }
758
759     creds.times.endtime = 0;
760
761     flags.i = 0;
762     flags.b.forwarded = 1;
763     if (forward_flags & OPTS_FORWARDABLE_CREDS)
764         flags.b.forwardable = 1;
765
766     ret = krb5_get_forwarded_creds (context,
767                                     auth_context,
768                                     ccache,
769                                     flags.i,
770                                     RemoteHostName,
771                                     &creds,
772                                     &out_data);
773     if (ret) {
774         if (auth_debug_mode)
775             printf ("Kerberos V5: error getting forwarded creds: %s\r\n",
776                     krb5_get_err_text (context, ret));
777         return;
778     }
779
780     if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
781         if (auth_debug_mode)
782             printf("Not enough room for authentication data\r\n");
783     } else {
784         if (auth_debug_mode)
785             printf("Forwarded local Kerberos V5 credentials to server\r\n");
786     }
787 }
788
789 #if defined(DCE)
790 /* if this was a K5 authentication try and join a PAG for the user. */
791 void
792 kerberos5_dfspag(void)
793 {
794     if (dfsk5ok) {
795         dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
796                               UserNameRequested);
797     }
798 }
799 #endif
800
801 #endif /* KRB5 */