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