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