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