xref: /original-bsd/lib/libtelnet/krb4encpwd.c (revision c4f3b704)
178a89ac8Sdab /*-
2bd8e26d4Sbostic  * Copyright (c) 1992, 1993
3bd8e26d4Sbostic  *	The Regents of the University of California.  All rights reserved.
478a89ac8Sdab  *
578a89ac8Sdab  * %sccs.include.redist.c%
678a89ac8Sdab  */
778a89ac8Sdab 
878a89ac8Sdab #ifndef lint
9*c4f3b704Sdab static char sccsid[] = "@(#)krb4encpwd.c	8.3 (Berkeley) 05/30/95";
1078a89ac8Sdab #endif /* not lint */
1178a89ac8Sdab 
1278a89ac8Sdab 
1378a89ac8Sdab #ifdef	KRB4_ENCPWD
1478a89ac8Sdab /*
1578a89ac8Sdab  * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
1678a89ac8Sdab  * ALL RIGHTS RESERVED
1778a89ac8Sdab  *
1878a89ac8Sdab  * "Digital Equipment Corporation authorizes the reproduction,
1978a89ac8Sdab  * distribution and modification of this software subject to the following
2078a89ac8Sdab  * restrictions:
2178a89ac8Sdab  *
2278a89ac8Sdab  * 1.  Any partial or whole copy of this software, or any modification
2378a89ac8Sdab  * thereof, must include this copyright notice in its entirety.
2478a89ac8Sdab  *
2578a89ac8Sdab  * 2.  This software is supplied "as is" with no warranty of any kind,
2678a89ac8Sdab  * expressed or implied, for any purpose, including any warranty of fitness
2778a89ac8Sdab  * or merchantibility.  DIGITAL assumes no responsibility for the use or
2878a89ac8Sdab  * reliability of this software, nor promises to provide any form of
2978a89ac8Sdab  * support for it on any basis.
3078a89ac8Sdab  *
3178a89ac8Sdab  * 3.  Distribution of this software is authorized only if no profit or
3278a89ac8Sdab  * remuneration of any kind is received in exchange for such distribution.
3378a89ac8Sdab  *
3478a89ac8Sdab  * 4.  This software produces public key authentication certificates
3578a89ac8Sdab  * bearing an expiration date established by DIGITAL and RSA Data
3678a89ac8Sdab  * Security, Inc.  It may cease to generate certificates after the expiration
3778a89ac8Sdab  * date.  Any modification of this software that changes or defeats
3878a89ac8Sdab  * the expiration date or its effect is unauthorized.
3978a89ac8Sdab  *
4078a89ac8Sdab  * 5.  Software that will renew or extend the expiration date of
4178a89ac8Sdab  * authentication certificates produced by this software may be obtained
4278a89ac8Sdab  * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
4378a89ac8Sdab  * 94065, (415)595-8782, or from DIGITAL"
4478a89ac8Sdab  *
4578a89ac8Sdab  */
4678a89ac8Sdab 
4778a89ac8Sdab #include <sys/types.h>
4878a89ac8Sdab #include <arpa/telnet.h>
4978a89ac8Sdab #include <pwd.h>
5078a89ac8Sdab #include <stdio.h>
5178a89ac8Sdab 
5278a89ac8Sdab #include <des.h>
5378a89ac8Sdab #include <krb.h>
5478a89ac8Sdab #ifdef	__STDC__
5578a89ac8Sdab #include <stdlib.h>
5678a89ac8Sdab #endif
5778a89ac8Sdab #ifdef	NO_STRING_H
5878a89ac8Sdab #include <strings.h>
5978a89ac8Sdab #else
6078a89ac8Sdab #include <string.h>
6178a89ac8Sdab #endif
6278a89ac8Sdab 
6378a89ac8Sdab #include "encrypt.h"
6478a89ac8Sdab #include "auth.h"
6578a89ac8Sdab #include "misc.h"
6678a89ac8Sdab 
6778a89ac8Sdab int krb_mk_encpwd_req P((KTEXT, char *, char *, char *, char *, char *, char *));
6878a89ac8Sdab int krb_rd_encpwd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *, char *, char *, char *));
6978a89ac8Sdab 
7078a89ac8Sdab extern auth_debug_mode;
7178a89ac8Sdab 
7278a89ac8Sdab static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
7378a89ac8Sdab 			  		AUTHTYPE_KRB4_ENCPWD, };
7478a89ac8Sdab static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
7578a89ac8Sdab 					TELQUAL_NAME, };
7678a89ac8Sdab 
7778a89ac8Sdab #define	KRB4_ENCPWD_AUTH	0	/* Authentication data follows */
7878a89ac8Sdab #define	KRB4_ENCPWD_REJECT	1	/* Rejected (reason might follow) */
7978a89ac8Sdab #define KRB4_ENCPWD_ACCEPT	2	/* Accepted */
8078a89ac8Sdab #define	KRB4_ENCPWD_CHALLENGE	3	/* Challenge for mutual auth. */
8178a89ac8Sdab #define	KRB4_ENCPWD_ACK		4	/* Acknowledge */
8278a89ac8Sdab 
8378a89ac8Sdab #define KRB_SERVICE_NAME    "rcmd"
8478a89ac8Sdab 
8578a89ac8Sdab static	KTEXT_ST auth;
8678a89ac8Sdab static	char name[ANAME_SZ];
8778a89ac8Sdab static	char user_passwd[ANAME_SZ];
8878a89ac8Sdab static	AUTH_DAT adat = { 0 };
89900e5c23Sdab #ifdef	ENCRYPTION
9078a89ac8Sdab static Block	session_key	= { 0 };
91900e5c23Sdab #endif	/* ENCRYPTION */
9278a89ac8Sdab static Schedule sched;
9378a89ac8Sdab static char  challenge[REALM_SZ];
9478a89ac8Sdab 
9578a89ac8Sdab 	static int
Data(ap,type,d,c)9678a89ac8Sdab Data(ap, type, d, c)
9778a89ac8Sdab 	Authenticator *ap;
9878a89ac8Sdab 	int type;
9978a89ac8Sdab 	void *d;
10078a89ac8Sdab 	int c;
10178a89ac8Sdab {
10278a89ac8Sdab 	unsigned char *p = str_data + 4;
10378a89ac8Sdab 	unsigned char *cd = (unsigned char *)d;
10478a89ac8Sdab 
10578a89ac8Sdab 	if (c == -1)
10678a89ac8Sdab 		c = strlen((char *)cd);
10778a89ac8Sdab 
10878a89ac8Sdab 	if (0) {
10978a89ac8Sdab 		printf("%s:%d: [%d] (%d)",
11078a89ac8Sdab 			str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
11178a89ac8Sdab 			str_data[3],
11278a89ac8Sdab 			type, c);
11378a89ac8Sdab 		printd(d, c);
11478a89ac8Sdab 		printf("\r\n");
11578a89ac8Sdab 	}
11678a89ac8Sdab 	*p++ = ap->type;
11778a89ac8Sdab 	*p++ = ap->way;
11878a89ac8Sdab 	*p++ = type;
11978a89ac8Sdab 	while (c-- > 0) {
12078a89ac8Sdab 		if ((*p++ = *cd++) == IAC)
12178a89ac8Sdab 			*p++ = IAC;
12278a89ac8Sdab 	}
12378a89ac8Sdab 	*p++ = IAC;
12478a89ac8Sdab 	*p++ = SE;
12578a89ac8Sdab 	if (str_data[3] == TELQUAL_IS)
12678a89ac8Sdab 		printsub('>', &str_data[2], p - (&str_data[2]));
12778a89ac8Sdab 	return(net_write(str_data, p - str_data));
12878a89ac8Sdab }
12978a89ac8Sdab 
13078a89ac8Sdab 	int
krb4encpwd_init(ap,server)13178a89ac8Sdab krb4encpwd_init(ap, server)
13278a89ac8Sdab 	Authenticator *ap;
13378a89ac8Sdab 	int server;
13478a89ac8Sdab {
13578a89ac8Sdab 	char hostname[80], *cp, *realm;
13678a89ac8Sdab 	C_Block skey;
13778a89ac8Sdab 
13878a89ac8Sdab 	if (server) {
13978a89ac8Sdab 		str_data[3] = TELQUAL_REPLY;
14078a89ac8Sdab 	} else {
14178a89ac8Sdab 		str_data[3] = TELQUAL_IS;
14278a89ac8Sdab 		gethostname(hostname, sizeof(hostname));
14378a89ac8Sdab 		realm = krb_realmofhost(hostname);
144*c4f3b704Sdab 		cp = strchr(hostname, '.');
14578a89ac8Sdab 		if (*cp != NULL) *cp = NULL;
14678a89ac8Sdab 		if (read_service_key(KRB_SERVICE_NAME, hostname, realm, 0,
14778a89ac8Sdab 					KEYFILE, (char *)skey)) {
14878a89ac8Sdab 		  return(0);
14978a89ac8Sdab 		}
15078a89ac8Sdab 	}
15178a89ac8Sdab 	return(1);
15278a89ac8Sdab }
15378a89ac8Sdab 
15478a89ac8Sdab 	int
krb4encpwd_send(ap)15578a89ac8Sdab krb4encpwd_send(ap)
15678a89ac8Sdab 	Authenticator *ap;
15778a89ac8Sdab {
15878a89ac8Sdab 
15978a89ac8Sdab 	printf("[ Trying KRB4ENCPWD ... ]\n");
16078a89ac8Sdab 	if (!UserNameRequested) {
16178a89ac8Sdab 		return(0);
16278a89ac8Sdab 	}
16378a89ac8Sdab 	if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
16478a89ac8Sdab 		return(0);
16578a89ac8Sdab 	}
16678a89ac8Sdab 
16778a89ac8Sdab 	if (!Data(ap, KRB4_ENCPWD_ACK, (void *)NULL, 0)) {
16878a89ac8Sdab 		return(0);
16978a89ac8Sdab 	}
17078a89ac8Sdab 
17178a89ac8Sdab 	return(1);
17278a89ac8Sdab }
17378a89ac8Sdab 
17478a89ac8Sdab 	void
krb4encpwd_is(ap,data,cnt)17578a89ac8Sdab krb4encpwd_is(ap, data, cnt)
17678a89ac8Sdab 	Authenticator *ap;
17778a89ac8Sdab 	unsigned char *data;
17878a89ac8Sdab 	int cnt;
17978a89ac8Sdab {
18078a89ac8Sdab 	Session_Key skey;
18178a89ac8Sdab 	Block datablock;
18278a89ac8Sdab 	char  r_passwd[ANAME_SZ], r_user[ANAME_SZ];
18378a89ac8Sdab 	char  lhostname[ANAME_SZ], *cp;
18478a89ac8Sdab 	int r;
18578a89ac8Sdab 	time_t now;
18678a89ac8Sdab 
18778a89ac8Sdab 	if (cnt-- < 1)
18878a89ac8Sdab 		return;
18978a89ac8Sdab 	switch (*data++) {
19078a89ac8Sdab 	case KRB4_ENCPWD_AUTH:
191*c4f3b704Sdab 		memmove((void *)auth.dat, (void *)data, auth.length = cnt);
19278a89ac8Sdab 
19378a89ac8Sdab 		gethostname(lhostname, sizeof(lhostname));
194*c4f3b704Sdab 		if ((cp = strchr(lhostname, '.')) != 0)  *cp = '\0';
19578a89ac8Sdab 
19678a89ac8Sdab 		if (r = krb_rd_encpwd_req(&auth, KRB_SERVICE_NAME, lhostname, 0, &adat, NULL, challenge, r_user, r_passwd)) {
19778a89ac8Sdab 			Data(ap, KRB4_ENCPWD_REJECT, (void *)"Auth failed", -1);
19878a89ac8Sdab 			auth_finished(ap, AUTH_REJECT);
19978a89ac8Sdab 			return;
20078a89ac8Sdab 		}
20178a89ac8Sdab 		auth_encrypt_userpwd(r_passwd);
20278a89ac8Sdab 		if (passwdok(UserNameRequested, UserPassword) == 0) {
20378a89ac8Sdab 		  /*
20478a89ac8Sdab 		   *  illegal username and password
20578a89ac8Sdab 		   */
20678a89ac8Sdab 		  Data(ap, KRB4_ENCPWD_REJECT, (void *)"Illegal password", -1);
20778a89ac8Sdab 		  auth_finished(ap, AUTH_REJECT);
20878a89ac8Sdab 		  return;
20978a89ac8Sdab 		}
21078a89ac8Sdab 
211*c4f3b704Sdab 		memmove((void *)session_key, (void *)adat.session, sizeof(Block));
21278a89ac8Sdab 		Data(ap, KRB4_ENCPWD_ACCEPT, (void *)0, 0);
21378a89ac8Sdab 		auth_finished(ap, AUTH_USER);
21478a89ac8Sdab 		break;
21578a89ac8Sdab 
21678a89ac8Sdab 	case KRB4_ENCPWD_CHALLENGE:
21778a89ac8Sdab 		/*
21878a89ac8Sdab 		 *  Take the received random challenge text and save
21978a89ac8Sdab 		 *  for future authentication.
22078a89ac8Sdab 		 */
221*c4f3b704Sdab 		memmove((void *)challenge, (void *)data, sizeof(Block));
22278a89ac8Sdab 		break;
22378a89ac8Sdab 
22478a89ac8Sdab 
22578a89ac8Sdab 	case KRB4_ENCPWD_ACK:
22678a89ac8Sdab 		/*
22778a89ac8Sdab 		 *  Receive ack, if mutual then send random challenge
22878a89ac8Sdab 		 */
22978a89ac8Sdab 
23078a89ac8Sdab 		/*
23178a89ac8Sdab 		 * If we are doing mutual authentication, get set up to send
2328a34ee9eSdab 		 * the challenge, and verify it when the response comes back.
23378a89ac8Sdab 		 */
23478a89ac8Sdab 
23578a89ac8Sdab 		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
23678a89ac8Sdab 		  register int i;
23778a89ac8Sdab 
23878a89ac8Sdab 		  time(&now);
23978a89ac8Sdab 		  sprintf(challenge, "%x", now);
24078a89ac8Sdab 		  Data(ap, KRB4_ENCPWD_CHALLENGE, (void *)challenge, strlen(challenge));
24178a89ac8Sdab 		}
24278a89ac8Sdab 		break;
24378a89ac8Sdab 
24478a89ac8Sdab 	default:
24578a89ac8Sdab 		Data(ap, KRB4_ENCPWD_REJECT, 0, 0);
24678a89ac8Sdab 		break;
24778a89ac8Sdab 	}
24878a89ac8Sdab }
24978a89ac8Sdab 
25078a89ac8Sdab 
25178a89ac8Sdab 	void
krb4encpwd_reply(ap,data,cnt)25278a89ac8Sdab krb4encpwd_reply(ap, data, cnt)
25378a89ac8Sdab 	Authenticator *ap;
25478a89ac8Sdab 	unsigned char *data;
25578a89ac8Sdab 	int cnt;
25678a89ac8Sdab {
25778a89ac8Sdab 	Session_Key skey;
25878a89ac8Sdab 	KTEXT_ST krb_token;
25978a89ac8Sdab 	Block enckey;
26078a89ac8Sdab 	CREDENTIALS cred;
26178a89ac8Sdab 	int r;
26278a89ac8Sdab 	char	randchal[REALM_SZ], instance[ANAME_SZ], *cp;
26378a89ac8Sdab 	char	hostname[80], *realm;
26478a89ac8Sdab 
26578a89ac8Sdab 	if (cnt-- < 1)
26678a89ac8Sdab 		return;
26778a89ac8Sdab 	switch (*data++) {
26878a89ac8Sdab 	case KRB4_ENCPWD_REJECT:
26978a89ac8Sdab 		if (cnt > 0) {
27078a89ac8Sdab 			printf("[ KRB4_ENCPWD refuses authentication because %.*s ]\r\n",
27178a89ac8Sdab 				cnt, data);
27278a89ac8Sdab 		} else
27378a89ac8Sdab 			printf("[ KRB4_ENCPWD refuses authentication ]\r\n");
27478a89ac8Sdab 		auth_send_retry();
27578a89ac8Sdab 		return;
27678a89ac8Sdab 	case KRB4_ENCPWD_ACCEPT:
27778a89ac8Sdab 		printf("[ KRB4_ENCPWD accepts you ]\n");
27878a89ac8Sdab 		auth_finished(ap, AUTH_USER);
27978a89ac8Sdab 		return;
28078a89ac8Sdab 	case KRB4_ENCPWD_CHALLENGE:
28178a89ac8Sdab 		/*
28278a89ac8Sdab 		 * Verify that the response to the challenge is correct.
28378a89ac8Sdab 		 */
28478a89ac8Sdab 
28578a89ac8Sdab 		gethostname(hostname, sizeof(hostname));
28678a89ac8Sdab 		realm = krb_realmofhost(hostname);
287*c4f3b704Sdab 		memmove((void *)challenge, (void *)data, cnt);
288*c4f3b704Sdab 		memset(user_passwd, 0, sizeof(user_passwd));
28978a89ac8Sdab 		local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0);
29078a89ac8Sdab 		UserPassword = user_passwd;
29178a89ac8Sdab 		Challenge = challenge;
29278a89ac8Sdab 		strcpy(instance, RemoteHostName);
293*c4f3b704Sdab 		if ((cp = strchr(instance, '.')) != 0)  *cp = '\0';
29478a89ac8Sdab 
29578a89ac8Sdab 		if (r = krb_mk_encpwd_req(&krb_token, KRB_SERVICE_NAME, instance, realm, Challenge, UserNameRequested, user_passwd)) {
29678a89ac8Sdab 		  krb_token.length = 0;
29778a89ac8Sdab 		}
29878a89ac8Sdab 
29978a89ac8Sdab 		if (!Data(ap, KRB4_ENCPWD_AUTH, (void *)krb_token.dat, krb_token.length)) {
30078a89ac8Sdab 		  return;
30178a89ac8Sdab 		}
30278a89ac8Sdab 
30378a89ac8Sdab 		break;
30478a89ac8Sdab 
30578a89ac8Sdab 	default:
30678a89ac8Sdab 		return;
30778a89ac8Sdab 	}
30878a89ac8Sdab }
30978a89ac8Sdab 
31078a89ac8Sdab 	int
krb4encpwd_status(ap,name,level)31178a89ac8Sdab krb4encpwd_status(ap, name, level)
31278a89ac8Sdab 	Authenticator *ap;
31378a89ac8Sdab 	char *name;
31478a89ac8Sdab 	int level;
31578a89ac8Sdab {
31678a89ac8Sdab 
31778a89ac8Sdab 	if (level < AUTH_USER)
31878a89ac8Sdab 		return(level);
31978a89ac8Sdab 
32078a89ac8Sdab 	if (UserNameRequested && passwdok(UserNameRequested, UserPassword)) {
32178a89ac8Sdab 		strcpy(name, UserNameRequested);
32278a89ac8Sdab 		return(AUTH_VALID);
32378a89ac8Sdab 	} else {
32478a89ac8Sdab 		return(AUTH_USER);
32578a89ac8Sdab 	}
32678a89ac8Sdab }
32778a89ac8Sdab 
32878a89ac8Sdab #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
32978a89ac8Sdab #define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
33078a89ac8Sdab 
33178a89ac8Sdab 	void
krb4encpwd_printsub(data,cnt,buf,buflen)33278a89ac8Sdab krb4encpwd_printsub(data, cnt, buf, buflen)
33378a89ac8Sdab 	unsigned char *data, *buf;
33478a89ac8Sdab 	int cnt, buflen;
33578a89ac8Sdab {
33678a89ac8Sdab 	char lbuf[32];
33778a89ac8Sdab 	register int i;
33878a89ac8Sdab 
33978a89ac8Sdab 	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
34078a89ac8Sdab 	buflen -= 1;
34178a89ac8Sdab 
34278a89ac8Sdab 	switch(data[3]) {
34378a89ac8Sdab 	case KRB4_ENCPWD_REJECT:	/* Rejected (reason might follow) */
34478a89ac8Sdab 		strncpy((char *)buf, " REJECT ", buflen);
34578a89ac8Sdab 		goto common;
34678a89ac8Sdab 
34778a89ac8Sdab 	case KRB4_ENCPWD_ACCEPT:	/* Accepted (name might follow) */
34878a89ac8Sdab 		strncpy((char *)buf, " ACCEPT ", buflen);
34978a89ac8Sdab 	common:
35078a89ac8Sdab 		BUMP(buf, buflen);
35178a89ac8Sdab 		if (cnt <= 4)
35278a89ac8Sdab 			break;
35378a89ac8Sdab 		ADDC(buf, buflen, '"');
35478a89ac8Sdab 		for (i = 4; i < cnt; i++)
35578a89ac8Sdab 			ADDC(buf, buflen, data[i]);
35678a89ac8Sdab 		ADDC(buf, buflen, '"');
35778a89ac8Sdab 		ADDC(buf, buflen, '\0');
35878a89ac8Sdab 		break;
35978a89ac8Sdab 
36078a89ac8Sdab 	case KRB4_ENCPWD_AUTH:		/* Authentication data follows */
36178a89ac8Sdab 		strncpy((char *)buf, " AUTH", buflen);
36278a89ac8Sdab 		goto common2;
36378a89ac8Sdab 
36478a89ac8Sdab 	case KRB4_ENCPWD_CHALLENGE:
36578a89ac8Sdab 		strncpy((char *)buf, " CHALLENGE", buflen);
36678a89ac8Sdab 		goto common2;
36778a89ac8Sdab 
36878a89ac8Sdab 	case KRB4_ENCPWD_ACK:
36978a89ac8Sdab 		strncpy((char *)buf, " ACK", buflen);
37078a89ac8Sdab 		goto common2;
37178a89ac8Sdab 
37278a89ac8Sdab 	default:
37378a89ac8Sdab 		sprintf(lbuf, " %d (unknown)", data[3]);
37478a89ac8Sdab 		strncpy((char *)buf, lbuf, buflen);
37578a89ac8Sdab 	common2:
37678a89ac8Sdab 		BUMP(buf, buflen);
37778a89ac8Sdab 		for (i = 4; i < cnt; i++) {
37878a89ac8Sdab 			sprintf(lbuf, " %d", data[i]);
37978a89ac8Sdab 			strncpy((char *)buf, lbuf, buflen);
38078a89ac8Sdab 			BUMP(buf, buflen);
38178a89ac8Sdab 		}
38278a89ac8Sdab 		break;
38378a89ac8Sdab 	}
38478a89ac8Sdab }
38578a89ac8Sdab 
passwdok(name,passwd)38678a89ac8Sdab int passwdok(name, passwd)
38778a89ac8Sdab char *name, *passwd;
38878a89ac8Sdab {
38978a89ac8Sdab   char *crypt();
39078a89ac8Sdab   char *salt, *p;
39178a89ac8Sdab   struct passwd *pwd;
39278a89ac8Sdab   int   passwdok_status = 0;
39378a89ac8Sdab 
39478a89ac8Sdab   if (pwd = getpwnam(name))
39578a89ac8Sdab     salt = pwd->pw_passwd;
39678a89ac8Sdab   else salt = "xx";
39778a89ac8Sdab 
39878a89ac8Sdab   p = crypt(passwd, salt);
39978a89ac8Sdab 
40078a89ac8Sdab   if (pwd && !strcmp(p, pwd->pw_passwd)) {
40178a89ac8Sdab     passwdok_status = 1;
40278a89ac8Sdab   } else passwdok_status = 0;
40378a89ac8Sdab   return(passwdok_status);
40478a89ac8Sdab }
40578a89ac8Sdab 
40678a89ac8Sdab #endif
40778a89ac8Sdab 
40878a89ac8Sdab #ifdef notdef
40978a89ac8Sdab 
prkey(msg,key)41078a89ac8Sdab prkey(msg, key)
41178a89ac8Sdab 	char *msg;
41278a89ac8Sdab 	unsigned char *key;
41378a89ac8Sdab {
41478a89ac8Sdab 	register int i;
41578a89ac8Sdab 	printf("%s:", msg);
41678a89ac8Sdab 	for (i = 0; i < 8; i++)
41778a89ac8Sdab 		printf(" %3d", key[i]);
41878a89ac8Sdab 	printf("\r\n");
41978a89ac8Sdab }
42078a89ac8Sdab #endif
421