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