Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / appl / telnet / libtelnet / kerberos.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/kerberosIV/appl/telnet/libtelnet/kerberos.c,v 1.2.2.2 2003/02/13 21:34:35 nectar Exp $ */
34
35 /*
36  * Copyright (C) 1990 by the Massachusetts Institute of Technology
37  *
38  * Export of this software from the United States of America is assumed
39  * to require a specific license from the United States Government.
40  * It is the responsibility of any person or organization contemplating
41  * export to obtain such a license before exporting.
42  *
43  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
44  * distribute this software and its documentation for any purpose and
45  * without fee is hereby granted, provided that the above copyright
46  * notice appear in all copies and that both that copyright notice and
47  * this permission notice appear in supporting documentation, and that
48  * the name of M.I.T. not be used in advertising or publicity pertaining
49  * to distribution of the software without specific, written prior
50  * permission.  M.I.T. makes no representations about the suitability of
51  * this software for any purpose.  It is provided "as is" without express
52  * or implied warranty.
53  */
54
55 #ifdef HAVE_CONFIG_H
56 #include <config.h>
57 #endif
58
59 RCSID("$Id: kerberos.c,v 1.46 1999/09/16 20:41:33 assar Exp $");
60
61 #ifdef  KRB4
62 #ifdef HAVE_SYS_TYPES_H
63 #include <sys/types.h>
64 #endif
65 #ifdef HAVE_ARPA_TELNET_H
66 #include <arpa/telnet.h>
67 #endif
68 #include <stdio.h>
69 #define OPENSSL_DES_LIBDES_COMPATIBILITY
70 #include <openssl/des.h>        /* BSD wont include this in krb.h, so we do it here */
71 #include <krb.h>
72 #include <pwd.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <roken.h>
76 #ifdef SOCKS
77 #include <socks.h>
78 #endif
79
80
81 #include "encrypt.h"
82 #include "auth.h"
83 #include "misc.h"
84
85 int kerberos4_cksum (unsigned char *, int);
86 extern int auth_debug_mode;
87
88 static unsigned char str_data[2048] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
89                                         AUTHTYPE_KERBEROS_V4, };
90
91 #define KRB_AUTH        0               /* Authentication data follows */
92 #define KRB_REJECT      1               /* Rejected (reason might follow) */
93 #define KRB_ACCEPT      2               /* Accepted */
94 #define KRB_CHALLENGE   3               /* Challenge for mutual auth. */
95 #define KRB_RESPONSE    4               /* Response for mutual auth. */
96
97 #define KRB_FORWARD             5       /* */
98 #define KRB_FORWARD_ACCEPT      6       /* */
99 #define KRB_FORWARD_REJECT      7       /* */
100
101 #define KRB_SERVICE_NAME   "rcmd"
102
103 static  KTEXT_ST auth;
104 static  char name[ANAME_SZ];
105 static  AUTH_DAT adat;
106 static des_cblock session_key;
107 static des_cblock cred_session;
108 static des_key_schedule sched;
109 static des_cblock challenge;
110 static int auth_done; /* XXX */
111
112 static int pack_cred(CREDENTIALS *cred, unsigned char *buf);
113 static int unpack_cred(unsigned char *buf, int len, CREDENTIALS *cred);
114
115
116 static int
117 Data(Authenticator *ap, int type, const void *d, int c)
118 {
119     unsigned char *p = str_data + 4;
120     const unsigned char *cd = (const unsigned char *)d;
121
122     if (c == -1)
123         c = strlen((const char *)cd);
124
125     if (auth_debug_mode) {
126         printf("%s:%d: [%d] (%d)",
127                str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
128                str_data[3],
129                type, c);
130         printd(d, c);
131         printf("\r\n");
132     }
133     *p++ = ap->type;
134     *p++ = ap->way;
135     *p++ = type;
136     while (c-- > 0) {
137         if ((*p++ = *cd++) == IAC)
138             *p++ = IAC;
139     }
140     *p++ = IAC;
141     *p++ = SE;
142     if (str_data[3] == TELQUAL_IS)
143         printsub('>', &str_data[2], p - (&str_data[2]));
144     return(telnet_net_write(str_data, p - str_data));
145 }
146
147 int
148 kerberos4_init(Authenticator *ap, int server)
149 {
150     FILE *fp;
151
152     if (server) {
153         str_data[3] = TELQUAL_REPLY;
154         if ((fp = fopen(KEYFILE, "r")) == NULL)
155             return(0);
156         fclose(fp);
157     } else {
158         str_data[3] = TELQUAL_IS;
159     }
160     return(1);
161 }
162
163 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
164 int dst_realm_sz = REALM_SZ;
165
166 static int
167 kerberos4_send(char *name, Authenticator *ap)
168 {
169     KTEXT_ST auth;
170     char instance[INST_SZ];
171     char *realm;
172     CREDENTIALS cred;
173     int r;
174
175     printf("[ Trying %s ... ]\r\n", name);
176     if (!UserNameRequested) {
177         if (auth_debug_mode) {
178             printf("Kerberos V4: no user name supplied\r\n");
179         }
180         return(0);
181     }
182
183     memset(instance, 0, sizeof(instance));
184
185     strlcpy (instance,
186                      krb_get_phost(RemoteHostName),
187                      INST_SZ);
188
189     realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
190
191     if (!realm) {
192         printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
193         return(0);
194     }
195     r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L);
196     if (r) {
197         printf("mk_req failed: %s\r\n", krb_get_err_text(r));
198         return(0);
199     }
200     r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred);
201     if (r) {
202         printf("get_cred failed: %s\r\n", krb_get_err_text(r));
203         return(0);
204     }
205     if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
206         if (auth_debug_mode)
207             printf("Not enough room for user name\r\n");
208         return(0);
209     }
210     if (auth_debug_mode)
211         printf("Sent %d bytes of authentication data\r\n", auth.length);
212     if (!Data(ap, KRB_AUTH, (void *)auth.dat, auth.length)) {
213         if (auth_debug_mode)
214             printf("Not enough room for authentication data\r\n");
215         return(0);
216     }
217 #ifdef ENCRYPTION
218     /* create challenge */
219     if ((ap->way & AUTH_HOW_MASK)==AUTH_HOW_MUTUAL) {
220         int i;
221
222         des_key_sched(&cred.session, sched);
223         memcpy (&cred_session, &cred.session, sizeof(cred_session));
224         des_init_random_number_generator(&cred.session);
225         des_new_random_key(&session_key);
226         des_ecb_encrypt(&session_key, &session_key, sched, 0);
227         des_ecb_encrypt(&session_key, &challenge, sched, 0);
228
229         /*
230           old code
231           Some CERT Advisory thinks this is a bad thing...
232             
233           des_init_random_number_generator(&cred.session);
234           des_new_random_key(&challenge);
235           des_ecb_encrypt(&challenge, &session_key, sched, 1);
236           */
237           
238         /*
239          * Increment the challenge by 1, and encrypt it for
240          * later comparison.
241          */
242         for (i = 7; i >= 0; --i) 
243             if(++challenge[i] != 0) /* No carry! */
244                 break;
245         des_ecb_encrypt(&challenge, &challenge, sched, 1);
246     }
247
248 #endif
249
250     if (auth_debug_mode) {
251         printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
252         printd(auth.dat, auth.length);
253         printf("\r\n");
254         printf("Sent Kerberos V4 credentials to server\r\n");
255     }
256     return(1);
257 }
258 int
259 kerberos4_send_mutual(Authenticator *ap)
260 {
261     return kerberos4_send("mutual KERBEROS4", ap);
262 }
263
264 int
265 kerberos4_send_oneway(Authenticator *ap)
266 {
267     return kerberos4_send("KERBEROS4", ap);
268 }
269
270 void
271 kerberos4_is(Authenticator *ap, unsigned char *data, int cnt)
272 {
273     struct sockaddr_in addr;
274     char realm[REALM_SZ];
275     char instance[INST_SZ];
276     int r;
277     int addr_len;
278
279     if (cnt-- < 1)
280         return;
281     switch (*data++) {
282     case KRB_AUTH:
283         if (krb_get_lrealm(realm, 1) != KSUCCESS) {
284             Data(ap, KRB_REJECT, (void *)"No local V4 Realm.", -1);
285             auth_finished(ap, AUTH_REJECT);
286             if (auth_debug_mode)
287                 printf("No local realm\r\n");
288             return;
289         }
290         memmove(auth.dat, data, auth.length = cnt);
291         if (auth_debug_mode) {
292             printf("Got %d bytes of authentication data\r\n", cnt);
293             printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length));
294             printd(auth.dat, auth.length);
295             printf("\r\n");
296         }
297         k_getsockinst(0, instance, sizeof(instance));
298         addr_len = sizeof(addr);
299         if(getpeername(0, (struct sockaddr *)&addr, &addr_len) < 0) {
300             if(auth_debug_mode)
301                 printf("getpeername failed\r\n");
302             Data(ap, KRB_REJECT, "getpeername failed", -1);
303             auth_finished(ap, AUTH_REJECT);
304             return;
305         }
306         if (addr.sin_family != AF_INET) {
307             if (auth_debug_mode)
308                 printf("unknown address family: %d\r\n", addr.sin_family);
309             Data(ap, KRB_REJECT, "bad address family", -1);
310             auth_finished(ap, AUTH_REJECT);
311             return;
312         }
313
314         r = krb_rd_req(&auth, KRB_SERVICE_NAME,
315                        instance, addr.sin_addr.s_addr, &adat, "");
316         if (r) {
317             if (auth_debug_mode)
318                 printf("Kerberos failed him as %s\r\n", name);
319             Data(ap, KRB_REJECT, (void *)krb_get_err_text(r), -1);
320             auth_finished(ap, AUTH_REJECT);
321             return;
322         }
323         /* save the session key */
324         memmove(session_key, adat.session, sizeof(adat.session));
325         krb_kntoln(&adat, name);
326
327         if (UserNameRequested && !kuserok(&adat, UserNameRequested)){
328             char ts[MaxPathLen];
329             struct passwd *pw = getpwnam(UserNameRequested);
330
331             if(pw){
332                 snprintf(ts, sizeof(ts),
333                          "%s%u",
334                          TKT_ROOT,
335                          (unsigned)pw->pw_uid);
336                 setenv("KRBTKFILE", ts, 1);
337
338                 if (pw->pw_uid == 0)
339                     syslog(LOG_INFO|LOG_AUTH,
340                            "ROOT Kerberos login from %s on %s\n",
341                            krb_unparse_name_long(adat.pname,
342                                                  adat.pinst,
343                                                  adat.prealm),
344                            RemoteHostName);
345             }
346             Data(ap, KRB_ACCEPT, NULL, 0);
347         } else {
348             char *msg;
349
350             asprintf (&msg, "user `%s' is not authorized to "
351                       "login as `%s'", 
352                       krb_unparse_name_long(adat.pname, 
353                                             adat.pinst, 
354                                             adat.prealm), 
355                       UserNameRequested ? UserNameRequested : "<nobody>");
356             if (msg == NULL)
357                 Data(ap, KRB_REJECT, NULL, 0);
358             else {
359                 Data(ap, KRB_REJECT, (void *)msg, -1);
360                 free(msg);
361             }
362         }
363         auth_finished(ap, AUTH_USER);
364         break;
365         
366     case KRB_CHALLENGE:
367 #ifndef ENCRYPTION
368         Data(ap, KRB_RESPONSE, NULL, 0);
369 #else
370         if(!VALIDKEY(session_key)){
371             Data(ap, KRB_RESPONSE, NULL, 0);
372             break;
373         }
374         des_key_sched(&session_key, sched);
375         {
376             des_cblock d_block;
377             int i;
378             Session_Key skey;
379
380             memmove(d_block, data, sizeof(d_block));
381
382             /* make a session key for encryption */
383             des_ecb_encrypt(&d_block, &session_key, sched, 1);
384             skey.type=SK_DES;
385             skey.length=8;
386             skey.data=session_key;
387             encrypt_session_key(&skey, 1);
388
389             /* decrypt challenge, add one and encrypt it */
390             des_ecb_encrypt(&d_block, &challenge, sched, 0);
391             for (i = 7; i >= 0; i--)
392                 if(++challenge[i] != 0)
393                     break;
394             des_ecb_encrypt(&challenge, &challenge, sched, 1);
395             Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge));
396         }
397 #endif
398         break;
399
400     case KRB_FORWARD:
401         {
402             des_key_schedule ks;
403             unsigned char netcred[sizeof(CREDENTIALS)];
404             CREDENTIALS cred;
405             int ret;
406             if(cnt > sizeof(cred))
407                 abort();
408
409             memcpy (session_key, adat.session, sizeof(session_key));
410             des_set_key(&session_key, ks);
411             des_pcbc_encrypt((void*)data, (void*)netcred, cnt, 
412                              ks, &session_key, DES_DECRYPT);
413             unpack_cred(netcred, cnt, &cred);
414             {
415                 if(strcmp(cred.service, KRB_TICKET_GRANTING_TICKET) ||
416                    strncmp(cred.instance, cred.realm, sizeof(cred.instance)) ||
417                    cred.lifetime < 0 || cred.lifetime > 255 ||
418                    cred.kvno < 0 || cred.kvno > 255 ||
419                    cred.issue_date < 0 || 
420                    cred.issue_date > time(0) + CLOCK_SKEW ||
421                    strncmp(cred.pname, adat.pname, sizeof(cred.pname)) ||
422                    strncmp(cred.pinst, adat.pinst, sizeof(cred.pinst))){
423                     Data(ap, KRB_FORWARD_REJECT, "Bad credentials", -1);
424                 }else{
425                     if((ret = tf_setup(&cred,
426                                        cred.pname,
427                                        cred.pinst)) == KSUCCESS){
428                         struct passwd *pw = getpwnam(UserNameRequested);
429
430                         if (pw)
431                           chown(tkt_string(), pw->pw_uid, pw->pw_gid);
432                         Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
433                     } else{
434                         Data(ap, KRB_FORWARD_REJECT, 
435                              krb_get_err_text(ret), -1);
436                     }
437                 }
438             }
439             memset(data, 0, cnt);
440             memset(ks, 0, sizeof(ks));
441             memset(&cred, 0, sizeof(cred));
442         }
443         
444         break;
445
446     default:
447         if (auth_debug_mode)
448             printf("Unknown Kerberos option %d\r\n", data[-1]);
449         Data(ap, KRB_REJECT, 0, 0);
450         break;
451     }
452 }
453
454 void
455 kerberos4_reply(Authenticator *ap, unsigned char *data, int cnt)
456 {
457     Session_Key skey;
458
459     if (cnt-- < 1)
460         return;
461     switch (*data++) {
462     case KRB_REJECT:
463         if(auth_done){ /* XXX Ick! */
464             printf("[ Kerberos V4 received unknown opcode ]\r\n");
465         }else{
466             printf("[ Kerberos V4 refuses authentication ");
467             if (cnt > 0) 
468                 printf("because %.*s ", cnt, data);
469             printf("]\r\n");
470             auth_send_retry();
471         }
472         return;
473     case KRB_ACCEPT:
474         printf("[ Kerberos V4 accepts you ]\r\n");
475         auth_done = 1;
476         if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
477             /*
478              * Send over the encrypted challenge.
479              */
480             Data(ap, KRB_CHALLENGE, session_key, 
481                  sizeof(session_key));
482             des_ecb_encrypt(&session_key, &session_key, sched, 1);
483             skey.type = SK_DES;
484             skey.length = 8;
485             skey.data = session_key;
486             encrypt_session_key(&skey, 0);
487 #if 0
488             kerberos4_forward(ap, &cred_session);
489 #endif
490             return;
491         }
492         auth_finished(ap, AUTH_USER);
493         return;
494     case KRB_RESPONSE:
495         /* make sure the response is correct */
496         if ((cnt != sizeof(des_cblock)) ||
497             (memcmp(data, challenge, sizeof(challenge)))){
498             printf("[ Kerberos V4 challenge failed!!! ]\r\n");
499             auth_send_retry();
500             return;
501         }
502         printf("[ Kerberos V4 challenge successful ]\r\n");
503         auth_finished(ap, AUTH_USER);
504         break;
505     case KRB_FORWARD_ACCEPT:
506         printf("[ Kerberos V4 accepted forwarded credentials ]\r\n");
507         break;
508     case KRB_FORWARD_REJECT:
509         printf("[ Kerberos V4 rejected forwarded credentials: `%.*s']\r\n",
510                cnt, data);
511         break;
512     default:
513         if (auth_debug_mode)
514             printf("Unknown Kerberos option %d\r\n", data[-1]);
515         return;
516     }
517 }
518
519 int
520 kerberos4_status(Authenticator *ap, char *name, size_t name_sz, int level)
521 {
522     if (level < AUTH_USER)
523         return(level);
524
525     if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
526         strlcpy(name, UserNameRequested, name_sz);
527         return(AUTH_VALID);
528     } else
529         return(AUTH_USER);
530 }
531
532 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
533 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
534
535 void
536 kerberos4_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
537 {
538     int i;
539
540     buf[buflen-1] = '\0';               /* make sure its NULL terminated */
541     buflen -= 1;
542
543     switch(data[3]) {
544     case KRB_REJECT:            /* Rejected (reason might follow) */
545         strlcpy((char *)buf, " REJECT ", buflen);
546         goto common;
547
548     case KRB_ACCEPT:            /* Accepted (name might follow) */
549         strlcpy((char *)buf, " ACCEPT ", buflen);
550     common:
551         BUMP(buf, buflen);
552         if (cnt <= 4)
553             break;
554         ADDC(buf, buflen, '"');
555         for (i = 4; i < cnt; i++)
556             ADDC(buf, buflen, data[i]);
557         ADDC(buf, buflen, '"');
558         ADDC(buf, buflen, '\0');
559         break;
560
561     case KRB_AUTH:                      /* Authentication data follows */
562         strlcpy((char *)buf, " AUTH", buflen);
563         goto common2;
564
565     case KRB_CHALLENGE:
566         strlcpy((char *)buf, " CHALLENGE", buflen);
567         goto common2;
568
569     case KRB_RESPONSE:
570         strlcpy((char *)buf, " RESPONSE", buflen);
571         goto common2;
572
573     default:
574         snprintf(buf, buflen, " %d (unknown)", data[3]);
575     common2:
576         BUMP(buf, buflen);
577         for (i = 4; i < cnt; i++) {
578             snprintf(buf, buflen, " %d", data[i]);
579             BUMP(buf, buflen);
580         }
581         break;
582     }
583 }
584
585 int
586 kerberos4_cksum(unsigned char *d, int n)
587 {
588     int ck = 0;
589
590     /*
591      * A comment is probably needed here for those not
592      * well versed in the "C" language.  Yes, this is
593      * supposed to be a "switch" with the body of the
594      * "switch" being a "while" statement.  The whole
595      * purpose of the switch is to allow us to jump into
596      * the middle of the while() loop, and then not have
597      * to do any more switch()s.
598      *
599      * Some compilers will spit out a warning message
600      * about the loop not being entered at the top.
601      */
602     switch (n&03)
603         while (n > 0) {
604         case 0:
605             ck ^= (int)*d++ << 24;
606             --n;
607         case 3:
608             ck ^= (int)*d++ << 16;
609             --n;
610         case 2:
611             ck ^= (int)*d++ << 8;
612             --n;
613         case 1:
614             ck ^= (int)*d++;
615             --n;
616         }
617     return(ck);
618 }
619
620 static int
621 pack_cred(CREDENTIALS *cred, unsigned char *buf)
622 {
623     unsigned char *p = buf;
624     
625     memcpy (p, cred->service, ANAME_SZ);
626     p += ANAME_SZ;
627     memcpy (p, cred->instance, INST_SZ);
628     p += INST_SZ;
629     memcpy (p, cred->realm, REALM_SZ);
630     p += REALM_SZ;
631     memcpy(p, cred->session, 8);
632     p += 8;
633     p += KRB_PUT_INT(cred->lifetime, p, 4, 4);
634     p += KRB_PUT_INT(cred->kvno, p, 4, 4);
635     p += KRB_PUT_INT(cred->ticket_st.length, p, 4, 4);
636     memcpy(p, cred->ticket_st.dat, cred->ticket_st.length);
637     p += cred->ticket_st.length;
638     p += KRB_PUT_INT(0, p, 4, 4);
639     p += KRB_PUT_INT(cred->issue_date, p, 4, 4);
640     memcpy (p, cred->pname, ANAME_SZ);
641     p += ANAME_SZ;
642     memcpy (p, cred->pinst, INST_SZ);
643     p += INST_SZ;
644     return p - buf;
645 }
646
647 static int
648 unpack_cred(unsigned char *buf, int len, CREDENTIALS *cred)
649 {
650     unsigned char *p = buf;
651     u_int32_t tmp;
652
653     strncpy (cred->service, p, ANAME_SZ);
654     cred->service[ANAME_SZ - 1] = '\0';
655     p += ANAME_SZ;
656     strncpy (cred->instance, p, INST_SZ);
657     cred->instance[INST_SZ - 1] = '\0';
658     p += INST_SZ;
659     strncpy (cred->realm, p, REALM_SZ);
660     cred->realm[REALM_SZ - 1] = '\0';
661     p += REALM_SZ;
662
663     memcpy(cred->session, p, 8);
664     p += 8;
665     p += krb_get_int(p, &tmp, 4, 0);
666     cred->lifetime = tmp;
667     p += krb_get_int(p, &tmp, 4, 0);
668     cred->kvno = tmp;
669
670     p += krb_get_int(p, &cred->ticket_st.length, 4, 0);
671     memcpy(cred->ticket_st.dat, p, cred->ticket_st.length);
672     p += cred->ticket_st.length;
673     p += krb_get_int(p, &tmp, 4, 0);
674     cred->ticket_st.mbz = 0;
675     p += krb_get_int(p, (u_int32_t *)&cred->issue_date, 4, 0);
676
677     strncpy (cred->pname, p, ANAME_SZ);
678     cred->pname[ANAME_SZ - 1] = '\0';
679     p += ANAME_SZ;
680     strncpy (cred->pinst, p, INST_SZ);
681     cred->pinst[INST_SZ - 1] = '\0';
682     p += INST_SZ;
683     return 0;
684 }
685
686
687 int
688 kerberos4_forward(Authenticator *ap, void *v)
689 {
690     des_cblock *key = (des_cblock *)v;
691     CREDENTIALS cred;
692     char *realm;
693     des_key_schedule ks;
694     int len;
695     unsigned char netcred[sizeof(CREDENTIALS)];
696     int ret;
697
698     realm = krb_realmofhost(RemoteHostName);
699     if(realm == NULL)
700         return -1;
701     memset(&cred, 0, sizeof(cred));
702     ret = krb_get_cred(KRB_TICKET_GRANTING_TICKET,
703                        realm,
704                        realm, 
705                        &cred);
706     if(ret)
707         return ret;
708     des_set_key(key, ks);
709     len = pack_cred(&cred, netcred);
710     des_pcbc_encrypt((void*)netcred, (void*)netcred, len,
711                      ks, key, DES_ENCRYPT);
712     memset(ks, 0, sizeof(ks));
713     Data(ap, KRB_FORWARD, netcred, len);
714     memset(netcred, 0, sizeof(netcred));
715     return 0;
716 }
717
718 #endif /* KRB4 */
719