xref: /dragonfly/lib/libtelnet/kerberos5.c (revision dc71b7ab81c4f5270d3668e1625d94a58895fa7a)
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
Data(Authenticator * ap,int type,const char * d,int c)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
kerberos5_init(Authenticator * ap __unused,int server)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
kerberos5_send(const char * name,Authenticator * ap)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
kerberos5_send_mutual(Authenticator * ap)281 kerberos5_send_mutual(Authenticator *ap)
282 {
283     return kerberos5_send("mutual KERBEROS5", ap);
284 }
285 
286 int
kerberos5_send_oneway(Authenticator * ap)287 kerberos5_send_oneway(Authenticator *ap)
288 {
289     return kerberos5_send("KERBEROS5", ap);
290 }
291 
292 void
kerberos5_is(Authenticator * ap,unsigned char * data,int cnt)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
kerberos5_reply(Authenticator * ap,unsigned char * data,int cnt)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
kerberos5_status(Authenticator * ap __unused,char * name,int level)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
kerberos5_printsub(unsigned char * data,int cnt,unsigned char * buf,int buflen)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
kerberos5_forward(Authenticator * ap)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
kerberos5_dfspag(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 */
820