Merge from vendor branch OPENSSH:
[dragonfly.git] / crypto / 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  * $FreeBSD: src/crypto/telnet/libtelnet/kerberos5.c,v 1.1.1.1.8.2 2003/04/24 19:13:59 nectar Exp $
34  * $DragonFly: src/crypto/telnet/libtelnet/kerberos5.c,v 1.2 2003/06/17 04:24:37 dillon Exp $
35  */
36
37 /*
38  * Copyright (C) 1990 by the Massachusetts Institute of Technology
39  *
40  * Export of this software from the United States of America may
41  * require a specific license from the United States Government.
42  * It is the responsibility of any person or organization contemplating
43  * export to obtain such a license before exporting.
44  *
45  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
46  * distribute this software and its documentation for any purpose and
47  * without fee is hereby granted, provided that the above copyright
48  * notice appear in all copies and that both that copyright notice and
49  * this permission notice appear in supporting documentation, and that
50  * the name of M.I.T. not be used in advertising or publicity pertaining
51  * to distribution of the software without specific, written prior
52  * permission.  M.I.T. makes no representations about the suitability of
53  * this software for any purpose.  It is provided "as is" without express
54  * or implied warranty.
55  */
56
57 #ifdef  KRB5
58
59 #include <arpa/telnet.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <netdb.h>
65 #include <ctype.h>
66 #include <pwd.h>
67 #define Authenticator k5_Authenticator
68 #include <krb5.h>
69 #undef Authenticator
70
71 #include "encrypt.h"
72 #include "auth.h"
73 #include "misc.h"
74
75 int forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
76
77 /* These values need to be the same as those defined in telnet/main.c. */
78 /* Either define them in both places, or put in some common header file. */
79 #define OPTS_FORWARD_CREDS      0x00000002
80 #define OPTS_FORWARDABLE_CREDS  0x00000001
81
82 void kerberos5_forward (Authenticator *);
83
84 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
85                                         AUTHTYPE_KERBEROS_V5, };
86
87 #define KRB_AUTH                0       /* Authentication data follows */
88 #define KRB_REJECT              1       /* Rejected (reason might follow) */
89 #define KRB_ACCEPT              2       /* Accepted */
90 #define KRB_RESPONSE            3       /* Response for mutual auth. */
91
92 #define KRB_FORWARD             4       /* Forwarded credentials follow */
93 #define KRB_FORWARD_ACCEPT      5       /* Forwarded credentials accepted */
94 #define KRB_FORWARD_REJECT      6       /* Forwarded credentials rejected */
95
96 static  krb5_data auth;
97 static  krb5_ticket *ticket;
98
99 static krb5_context context;
100 static krb5_auth_context auth_context;
101
102 static int
103 Data(Authenticator *ap, int type, const char *d, int c)
104 {
105     unsigned char *p = str_data + 4;
106     const unsigned char *cd = d;
107
108     if (c == -1)
109         c = strlen(cd);
110
111     if (auth_debug_mode) {
112         printf("%s:%d: [%d] (%d)",
113                str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
114                str_data[3],
115                type, c);
116         printd(d, c);
117         printf("\r\n");
118     }
119     *p++ = ap->type;
120     *p++ = ap->way;
121     *p++ = type;
122     while (c-- > 0) {
123         if ((*p++ = *cd++) == IAC)
124             *p++ = IAC;
125     }
126     *p++ = IAC;
127     *p++ = SE;
128     if (str_data[3] == TELQUAL_IS)
129         printsub('>', &str_data[2], p - &str_data[2]);
130     return(net_write(str_data, p - str_data));
131 }
132
133 int
134 kerberos5_init(Authenticator *ap __unused, int server)
135 {
136     krb5_error_code ret;
137
138     ret = krb5_init_context(&context);
139     if (ret)
140         return 0;
141     if (server) {
142         krb5_keytab kt;
143         krb5_kt_cursor cursor;
144
145         ret = krb5_kt_default(context, &kt);
146         if (ret)
147             return 0;
148
149         ret = krb5_kt_start_seq_get (context, kt, &cursor);
150         if (ret) {
151             krb5_kt_close (context, kt);
152             return 0;
153         }
154         krb5_kt_end_seq_get (context, kt, &cursor);
155         krb5_kt_close (context, kt);
156
157         str_data[3] = TELQUAL_REPLY;
158     } else
159         str_data[3] = TELQUAL_IS;
160     return(1);
161 }
162
163 extern int net;
164
165 static int
166 kerberos5_send(const char *name, Authenticator *ap)
167 {
168     krb5_error_code ret;
169     krb5_ccache ccache;
170     int ap_opts;
171     krb5_data cksum_data;
172     char foo[2];
173     
174     if (!UserNameRequested) {
175         if (auth_debug_mode) {
176             printf("Kerberos V5: no user name supplied\r\n");
177         }
178         return(0);
179     }
180     
181     ret = krb5_cc_default(context, &ccache);
182     if (ret) {
183         if (auth_debug_mode) {
184             printf("Kerberos V5: could not get default ccache: %s\r\n",
185                    krb5_get_err_text (context, ret));
186         }
187         return 0;
188     }
189         
190     if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
191         ap_opts = AP_OPTS_MUTUAL_REQUIRED;
192     else
193         ap_opts = 0;
194     ap_opts |= AP_OPTS_USE_SUBKEY;
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 (key_block == NULL) {
413             ret = krb5_auth_con_getkey(context,
414                                        auth_context,
415                                        &key_block);
416         }
417         if (ret) {
418             Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
419             auth_finished(ap, AUTH_REJECT);
420             if (auth_debug_mode)
421                 printf("Kerberos V5: "
422                        "krb5_auth_con_getkey failed (%s)\r\n",
423                        krb5_get_err_text(context, ret));
424             return;
425         }
426         if (key_block == NULL) {
427             Data(ap, KRB_REJECT, "no subkey received", -1);
428             auth_finished(ap, AUTH_REJECT);
429             if (auth_debug_mode)
430                 printf("Kerberos V5: "
431                        "krb5_auth_con_getremotesubkey returned NULL key\r\n");
432             return;
433         }
434
435         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
436             ret = krb5_mk_rep(context, auth_context, &outbuf);
437             if (ret) {
438                 Data(ap, KRB_REJECT,
439                      "krb5_mk_rep failed", -1);
440                 auth_finished(ap, AUTH_REJECT);
441                 if (auth_debug_mode)
442                     printf("Kerberos V5: "
443                            "krb5_mk_rep failed (%s)\r\n",
444                            krb5_get_err_text(context, ret));
445                 return;
446             }
447             Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
448         }
449         if (krb5_unparse_name(context, ticket->client, &name))
450             name = 0;
451
452         if(UserNameRequested && krb5_kuserok(context,
453                                              ticket->client,
454                                              UserNameRequested)) {
455             Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
456             if (auth_debug_mode) {
457                 printf("Kerberos5 identifies him as ``%s''\r\n",
458                        name ? name : "");
459             }
460
461             if(key_block->keytype == ETYPE_DES_CBC_MD5 ||
462                key_block->keytype == ETYPE_DES_CBC_MD4 ||
463                key_block->keytype == ETYPE_DES_CBC_CRC) {
464                 Session_Key skey;
465
466                 skey.type = SK_DES;
467                 skey.length = 8;
468                 skey.data = key_block->keyvalue.data;
469                 encrypt_session_key(&skey, 0);
470             }
471
472         } else {
473             char *msg;
474
475             asprintf (&msg, "user `%s' is not authorized to "
476                       "login as `%s'", 
477                       name ? name : "<unknown>",
478                       UserNameRequested ? UserNameRequested : "<nobody>");
479             if (msg == NULL)
480                 Data(ap, KRB_REJECT, NULL, 0);
481             else {
482                 Data(ap, KRB_REJECT, (void *)msg, -1);
483                 free(msg);
484             }
485             auth_finished (ap, AUTH_REJECT);
486             krb5_free_keyblock_contents(context, key_block);
487             break;
488         }
489         auth_finished(ap, AUTH_USER);
490         krb5_free_keyblock_contents(context, key_block);
491         
492         break;
493     case KRB_FORWARD: {
494         struct passwd *pwd;
495         char ccname[1024];      /* XXX */
496         krb5_data inbuf;
497         krb5_ccache ccache;
498         inbuf.data = (char *)data;
499         inbuf.length = cnt;
500
501         pwd = getpwnam (UserNameRequested);
502         if (pwd == NULL)
503             break;
504
505         snprintf (ccname, sizeof(ccname),
506                   "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
507
508         ret = krb5_cc_resolve (context, ccname, &ccache);
509         if (ret) {
510             if (auth_debug_mode)
511                 printf ("Kerberos V5: could not get ccache: %s\r\n",
512                         krb5_get_err_text(context, ret));
513             break;
514         }
515
516         ret = krb5_cc_initialize (context,
517                                   ccache,
518                                   ticket->client);
519         if (ret) {
520             if (auth_debug_mode)
521                 printf ("Kerberos V5: could not init ccache: %s\r\n",
522                         krb5_get_err_text(context, ret));
523             break;
524         }
525
526 #if defined(DCE)
527         esetenv("KRB5CCNAME", ccname, 1);
528 #endif
529         ret = krb5_rd_cred2 (context,
530                              auth_context,
531                              ccache,
532                              &inbuf);
533         if(ret) {
534             char *errbuf;
535
536             asprintf (&errbuf,
537                       "Read forwarded creds failed: %s",
538                       krb5_get_err_text (context, ret));
539             if(errbuf == NULL)
540                 Data(ap, KRB_FORWARD_REJECT, NULL, 0);
541             else
542                 Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
543             if (auth_debug_mode)
544                 printf("Could not read forwarded credentials: %s\r\n",
545                        errbuf);
546             free (errbuf);
547         } else {
548             Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
549 #if defined(DCE)
550             dfsfwd = 1;
551 #endif
552         }
553         chown (ccname + 5, pwd->pw_uid, -1);
554         if (auth_debug_mode)
555             printf("Forwarded credentials obtained\r\n");
556         break;
557     }
558     default:
559         if (auth_debug_mode)
560             printf("Unknown Kerberos option %d\r\n", data[-1]);
561         Data(ap, KRB_REJECT, 0, 0);
562         break;
563     }
564 }
565
566 void
567 kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
568 {
569     static int mutual_complete = 0;
570
571     if (cnt-- < 1)
572         return;
573     switch (*data++) {
574     case KRB_REJECT:
575         if (cnt > 0) {
576             printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
577                    cnt, data);
578         } else
579             printf("[ Kerberos V5 refuses authentication ]\r\n");
580         auth_send_retry();
581         return;
582     case KRB_ACCEPT: {
583         krb5_error_code ret;
584         Session_Key skey;
585         krb5_keyblock *keyblock;
586         
587         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
588             !mutual_complete) {
589             printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
590             auth_send_retry();
591             return;
592         }
593         if (cnt)
594             printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
595         else
596             printf("[ Kerberos V5 accepts you ]\r\n");
597               
598         ret = krb5_auth_con_getlocalsubkey (context,
599                                             auth_context,
600                                             &keyblock);
601         if (ret)
602             ret = krb5_auth_con_getkey (context,
603                                         auth_context,
604                                         &keyblock);
605         if(ret) {
606             printf("[ krb5_auth_con_getkey: %s ]\r\n",
607                    krb5_get_err_text(context, ret));
608             auth_send_retry();
609             return;
610         }
611               
612         skey.type = SK_DES;
613         skey.length = 8;
614         skey.data = keyblock->keyvalue.data;
615         encrypt_session_key(&skey, 0);
616         krb5_free_keyblock_contents (context, keyblock);
617         auth_finished(ap, AUTH_USER);
618         if (forward_flags & OPTS_FORWARD_CREDS)
619             kerberos5_forward(ap);
620         break;
621     }
622     case KRB_RESPONSE:
623         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
624             /* the rest of the reply should contain a krb_ap_rep */
625           krb5_ap_rep_enc_part *reply;
626           krb5_data inbuf;
627           krb5_error_code ret;
628             
629           inbuf.length = cnt;
630           inbuf.data = (char *)data;
631
632           ret = krb5_rd_rep(context, auth_context, &inbuf, &reply);
633           if (ret) {
634               printf("[ Mutual authentication failed: %s ]\r\n",
635                      krb5_get_err_text (context, ret));
636               auth_send_retry();
637               return;
638           }
639           krb5_free_ap_rep_enc_part(context, reply);
640           mutual_complete = 1;
641         }
642         return;
643     case KRB_FORWARD_ACCEPT:
644         printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
645         return;
646     case KRB_FORWARD_REJECT:
647         printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
648                cnt, data);
649         return;
650     default:
651         if (auth_debug_mode)
652             printf("Unknown Kerberos option %d\r\n", data[-1]);
653         return;
654     }
655 }
656
657 int
658 kerberos5_status(Authenticator *ap __unused, char *name, int level)
659 {
660     if (level < AUTH_USER)
661         return(level);
662
663     if (UserNameRequested &&
664         krb5_kuserok(context,
665                      ticket->client,
666                      UserNameRequested))
667         {
668             strcpy(name, UserNameRequested);
669             return(AUTH_VALID);
670         } else
671             return(AUTH_USER);
672 }
673
674 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
675 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
676
677 void
678 kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
679 {
680     int i;
681
682     buf[buflen-1] = '\0';               /* make sure its NULL terminated */
683     buflen -= 1;
684
685     switch(data[3]) {
686     case KRB_REJECT:            /* Rejected (reason might follow) */
687         strlcpy((char *)buf, " REJECT ", buflen);
688         goto common;
689
690     case KRB_ACCEPT:            /* Accepted (name might follow) */
691         strlcpy((char *)buf, " ACCEPT ", buflen);
692     common:
693         BUMP(buf, buflen);
694         if (cnt <= 4)
695             break;
696         ADDC(buf, buflen, '"');
697         for (i = 4; i < cnt; i++)
698             ADDC(buf, buflen, data[i]);
699         ADDC(buf, buflen, '"');
700         ADDC(buf, buflen, '\0');
701         break;
702
703
704     case KRB_AUTH:                      /* Authentication data follows */
705         strlcpy((char *)buf, " AUTH", buflen);
706         goto common2;
707
708     case KRB_RESPONSE:
709         strlcpy((char *)buf, " RESPONSE", buflen);
710         goto common2;
711
712     case KRB_FORWARD:           /* Forwarded credentials follow */
713         strlcpy((char *)buf, " FORWARD", buflen);
714         goto common2;
715
716     case KRB_FORWARD_ACCEPT:    /* Forwarded credentials accepted */
717         strlcpy((char *)buf, " FORWARD_ACCEPT", buflen);
718         goto common2;
719
720     case KRB_FORWARD_REJECT:    /* Forwarded credentials rejected */
721         /* (reason might follow) */
722         strlcpy((char *)buf, " FORWARD_REJECT", buflen);
723         goto common2;
724
725     default:
726         snprintf(buf, buflen, " %d (unknown)", data[3]);
727     common2:
728         BUMP(buf, buflen);
729         for (i = 4; i < cnt; i++) {
730             snprintf(buf, buflen, " %d", data[i]);
731             BUMP(buf, buflen);
732         }
733         break;
734     }
735 }
736
737 void
738 kerberos5_forward(Authenticator *ap)
739 {
740     krb5_error_code ret;
741     krb5_ccache     ccache;
742     krb5_creds      creds;
743     krb5_kdc_flags  flags;
744     krb5_data       out_data;
745     krb5_principal  principal;
746
747     ret = krb5_cc_default (context, &ccache);
748     if (ret) {
749         if (auth_debug_mode)
750             printf ("KerberosV5: could not get default ccache: %s\r\n",
751                     krb5_get_err_text (context, ret));
752         return;
753     }
754
755     ret = krb5_cc_get_principal (context, ccache, &principal);
756     if (ret) {
757         if (auth_debug_mode)
758             printf ("KerberosV5: could not get principal: %s\r\n",
759                     krb5_get_err_text (context, ret));
760         return;
761     }
762
763     memset (&creds, 0, sizeof(creds));
764
765     creds.client = principal;
766     
767     ret = krb5_build_principal (context,
768                                 &creds.server,
769                                 strlen(principal->realm),
770                                 principal->realm,
771                                 "krbtgt",
772                                 principal->realm,
773                                 NULL);
774
775     if (ret) {
776         if (auth_debug_mode)
777             printf ("KerberosV5: could not get principal: %s\r\n",
778                     krb5_get_err_text (context, ret));
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             printf ("Kerberos V5: error getting forwarded creds: %s\r\n",
799                     krb5_get_err_text (context, ret));
800         return;
801     }
802
803     if(!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
804         if (auth_debug_mode)
805             printf("Not enough room for authentication data\r\n");
806     } else {
807         if (auth_debug_mode)
808             printf("Forwarded local Kerberos V5 credentials to server\r\n");
809     }
810 }
811
812 #if defined(DCE)
813 /* if this was a K5 authentication try and join a PAG for the user. */
814 void
815 kerberos5_dfspag(void)
816 {
817     if (dfsk5ok) {
818         dfspag = krb5_dfs_pag(context, dfsfwd, ticket->client,
819                               UserNameRequested);
820     }
821 }
822 #endif
823
824 #endif /* KRB5 */