From 0e39a0bc3be480f86dfc7dbd61b3f133f7e27039 Mon Sep 17 00:00:00 2001 From: "Dave A. Borman" Date: Fri, 18 Dec 1992 22:11:18 -0800 Subject: [PATCH] Change ENCRYPT to ENCRYPTION Change AUTHENTICATE to AUTHENTICATION Latest version of Kerberos V stuff Bug fixes SCCS-vsn: lib/libtelnet/enc_des.c 5.2 SCCS-vsn: lib/libtelnet/encrypt.h 5.3 SCCS-vsn: lib/libtelnet/enc-proto.h 5.3 SCCS-vsn: lib/libtelnet/kerberos.c 5.3 SCCS-vsn: lib/libtelnet/Makefile 5.5 SCCS-vsn: lib/libtelnet/getent.c 5.2 SCCS-vsn: lib/libtelnet/kerberos5.c 5.3 SCCS-vsn: lib/libtelnet/encrypt.c 5.3 SCCS-vsn: lib/libtelnet/misc.c 5.2 SCCS-vsn: lib/libtelnet/auth-proto.h 5.3 SCCS-vsn: lib/libtelnet/auth.c 5.3 --- usr/src/lib/libtelnet/Makefile | 4 +- usr/src/lib/libtelnet/auth-proto.h | 4 +- usr/src/lib/libtelnet/auth.c | 72 +++++- usr/src/lib/libtelnet/enc-proto.h | 13 +- usr/src/lib/libtelnet/enc_des.c | 6 +- usr/src/lib/libtelnet/encrypt.c | 12 +- usr/src/lib/libtelnet/encrypt.h | 6 +- usr/src/lib/libtelnet/getent.c | 4 +- usr/src/lib/libtelnet/kerberos.c | 157 +++++++------ usr/src/lib/libtelnet/kerberos5.c | 339 ++++++++++++++++------------- usr/src/lib/libtelnet/misc.c | 6 +- 11 files changed, 380 insertions(+), 243 deletions(-) diff --git a/usr/src/lib/libtelnet/Makefile b/usr/src/lib/libtelnet/Makefile index 0e747210ea..d3bcc4bfbc 100644 --- a/usr/src/lib/libtelnet/Makefile +++ b/usr/src/lib/libtelnet/Makefile @@ -1,10 +1,10 @@ -# @(#)Makefile 5.4 (Berkeley) %G% +# @(#)Makefile 5.5 (Berkeley) %G% LIB= telnet SRCS= auth.c encrypt.c genget.c getent.c gettytab.c misc.c SRCS+= kerberos.c enc_des.c #SRCS+= kerberos5.c -CFLAGS+= -DENCRYPT -DAUTHENTICATE +CFLAGS+= -DENCRYPTION -DAUTHENTICATION CFLAGS+= -DKRB4 -DDES_ENCRYPT -I/usr/include/kerberosIV .PATH: ${.CURDIR}/../../libexec/getty diff --git a/usr/src/lib/libtelnet/auth-proto.h b/usr/src/lib/libtelnet/auth-proto.h index 4eb0d4ea48..ca0a150945 100644 --- a/usr/src/lib/libtelnet/auth-proto.h +++ b/usr/src/lib/libtelnet/auth-proto.h @@ -4,7 +4,7 @@ * * %sccs.include.redist.c% * - * @(#)auth-proto.h 5.2 (Berkeley) %G% + * @(#)auth-proto.h 5.3 (Berkeley) %G% */ /* @@ -35,7 +35,7 @@ #endif #endif -#if defined(AUTHENTICATE) +#if defined(AUTHENTICATION) Authenticator *findauthenticator P((int, int)); void auth_init P((char *, int)); diff --git a/usr/src/lib/libtelnet/auth.c b/usr/src/lib/libtelnet/auth.c index fb0d4cbab1..8874b36be5 100644 --- a/usr/src/lib/libtelnet/auth.c +++ b/usr/src/lib/libtelnet/auth.c @@ -6,7 +6,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)auth.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)auth.c 5.3 (Berkeley) %G%"; #endif /* not lint */ /* @@ -30,7 +30,7 @@ static char sccsid[] = "@(#)auth.c 5.2 (Berkeley) %G%"; */ -#if defined(AUTHENTICATE) +#if defined(AUTHENTICATION) #include #include #include @@ -52,6 +52,24 @@ static char sccsid[] = "@(#)auth.c 5.2 (Berkeley) %G%"; #define typemask(x) (1<<((x)-1)) +#ifdef KRB4_ENCPWD +extern krb4encpwd_init(); +extern krb4encpwd_send(); +extern krb4encpwd_is(); +extern krb4encpwd_reply(); +extern krb4encpwd_status(); +extern krb4encpwd_printsub(); +#endif + +#ifdef RSA_ENCPWD +extern rsaencpwd_init(); +extern rsaencpwd_send(); +extern rsaencpwd_is(); +extern rsaencpwd_reply(); +extern rsaencpwd_status(); +extern rsaencpwd_printsub(); +#endif + int auth_debug_mode = 0; static char *Name = "Noname"; static int Server = 0; @@ -67,7 +85,24 @@ static int auth_send_cnt = 0; * in priority order, i.e. try the first one first. */ Authenticator authenticators[] = { +#ifdef SPX + { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, + spx_init, + spx_send, + spx_is, + spx_reply, + spx_status, + spx_printsub }, + { AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, + spx_init, + spx_send, + spx_is, + spx_reply, + spx_status, + spx_printsub }, +#endif #ifdef KRB5 +# ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos5_init, kerberos5_send, @@ -75,6 +110,7 @@ Authenticator authenticators[] = { kerberos5_reply, kerberos5_status, kerberos5_printsub }, +# endif { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos5_init, kerberos5_send, @@ -84,6 +120,7 @@ Authenticator authenticators[] = { kerberos5_printsub }, #endif #ifdef KRB4 +# ifdef ENCRYPTION { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos4_init, kerberos4_send, @@ -91,6 +128,7 @@ Authenticator authenticators[] = { kerberos4_reply, kerberos4_status, kerberos4_printsub }, +# endif { AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, kerberos4_init, kerberos4_send, @@ -98,6 +136,24 @@ Authenticator authenticators[] = { kerberos4_reply, kerberos4_status, kerberos4_printsub }, +#endif +#ifdef KRB4_ENCPWD + { AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, + krb4encpwd_init, + krb4encpwd_send, + krb4encpwd_is, + krb4encpwd_reply, + krb4encpwd_status, + krb4encpwd_printsub }, +#endif +#ifdef RSA_ENCPWD + { AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY, + rsaencpwd_init, + rsaencpwd_send, + rsaencpwd_is, + rsaencpwd_reply, + rsaencpwd_status, + rsaencpwd_printsub }, #endif { 0, }, }; @@ -340,9 +396,7 @@ auth_send(data, cnt) if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) { ap = findauthenticator(auth_send_data[0], auth_send_data[1]); - if (!ap) { - printf("Internal state error: cannot find authentication type %d a second time\r\n", *auth_send_data); - } else if (ap->send) { + if (ap && ap->send) { if (auth_debug_mode) printf(">>>%s: Trying %d %d\r\n", Name, auth_send_data[0], @@ -372,6 +426,14 @@ auth_send(data, cnt) if (auth_debug_mode) printf(">>>%s: Sent failure message\r\n", Name); auth_finished(0, AUTH_REJECT); +#ifdef KANNAN + /* + * We requested strong authentication, however no mechanisms worked. + * Therefore, exit on client end. + */ + printf("Unable to securely authenticate user ... exit\n"); + exit(0); +#endif /* KANNAN */ } void diff --git a/usr/src/lib/libtelnet/enc-proto.h b/usr/src/lib/libtelnet/enc-proto.h index db5ddd1d75..cd8c52a6a3 100644 --- a/usr/src/lib/libtelnet/enc-proto.h +++ b/usr/src/lib/libtelnet/enc-proto.h @@ -4,7 +4,7 @@ * * %sccs.include.redist.c% * - * @(#)enc-proto.h 5.2 (Berkeley) %G% + * @(#)enc-proto.h 5.3 (Berkeley) %G% */ /* @@ -34,7 +34,7 @@ #endif #endif -#if defined(ENCRYPT) +#if defined(ENCRYPTION) void encrypt_init P((char *, int)); Encryptions *findencryption P((int)); void encrypt_send_supprt P((void)); @@ -62,6 +62,15 @@ int encrypt_cmd P((int, char **)); void encrypt_display P((void)); #endif +void krbdes_encrypt P((unsigned char *, int)); +int krbdes_decrypt P((int)); +int krbdes_is P((unsigned char *, int)); +int krbdes_reply P((unsigned char *, int)); +void krbdes_init P((int)); +int krbdes_start P((int, int)); +void krbdes_session P((Session_Key *, int)); +void krbdes_printsub P((unsigned char *, int, unsigned char *, int)); + void cfb64_encrypt P((unsigned char *, int)); int cfb64_decrypt P((int)); void cfb64_init P((int)); diff --git a/usr/src/lib/libtelnet/enc_des.c b/usr/src/lib/libtelnet/enc_des.c index 7d665d88c5..6afdb067ee 100644 --- a/usr/src/lib/libtelnet/enc_des.c +++ b/usr/src/lib/libtelnet/enc_des.c @@ -6,10 +6,10 @@ */ #ifndef lint -static char sccsid[] = "@(#)enc_des.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)enc_des.c 5.2 (Berkeley) %G%"; #endif /* not lint */ -#if defined(AUTHENTICATE) && defined(ENCRYPT) && defined(DES_ENCRYPT) +#if defined(AUTHENTICATION) && defined(ENCRYPTION) && defined(DES_ENCRYPTION) #include #include #ifdef __STDC__ @@ -342,7 +342,7 @@ fb64_reply(data, cnt, fbp) if (state == FAILED) state = IN_PROGRESS; state &= ~NO_RECV_IV; - encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1); + encrypt_send_keyid(DIR_ENCRYPT, "\0", 1, 1); break; case FB64_IV_BAD: diff --git a/usr/src/lib/libtelnet/encrypt.c b/usr/src/lib/libtelnet/encrypt.c index 12841a1c81..c2b9015a95 100644 --- a/usr/src/lib/libtelnet/encrypt.c +++ b/usr/src/lib/libtelnet/encrypt.c @@ -6,7 +6,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)encrypt.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)encrypt.c 5.3 (Berkeley) %G%"; #endif /* not lint */ /* @@ -29,7 +29,7 @@ static char sccsid[] = "@(#)encrypt.c 5.2 (Berkeley) %G%"; * or implied warranty. */ -#if defined(ENCRYPT) +#if defined(ENCRYPTION) #define ENCRYPT_NAMES #include @@ -78,7 +78,7 @@ static long remote_supports_encrypt = 0; static long remote_supports_decrypt = 0; static Encryptions encryptions[] = { -#if defined(DES_ENCRYPT) +#if defined(DES_ENCRYPTION) { "DES_CFB64", ENCTYPE_DES_CFB64, cfb64_encrypt, cfb64_decrypt, @@ -646,6 +646,12 @@ encrypt_session_key(key, server) while (ep->type) { if (ep->session) (*ep->session)(key, server); +#ifdef notdef + if (!encrypt_output && autoencrypt && !server) + encrypt_start_output(ep->type); + if (!decrypt_input && autodecrypt && !server) + encrypt_send_request_start(); +#endif ++ep; } } diff --git a/usr/src/lib/libtelnet/encrypt.h b/usr/src/lib/libtelnet/encrypt.h index 8d13c42bab..005bfc0c6d 100644 --- a/usr/src/lib/libtelnet/encrypt.h +++ b/usr/src/lib/libtelnet/encrypt.h @@ -4,7 +4,7 @@ * * %sccs.include.redist.c% * - * @(#)encrypt.h 5.2 (Berkeley) %G% + * @(#)encrypt.h 5.3 (Berkeley) %G% */ /* @@ -27,8 +27,8 @@ * or implied warranty. */ -#ifndef __ENCRYPT__ -#define __ENCRYPT__ +#ifndef __ENCRYPTION__ +#define __ENCRYPTION__ #define DIR_DECRYPT 1 #define DIR_ENCRYPT 2 diff --git a/usr/src/lib/libtelnet/getent.c b/usr/src/lib/libtelnet/getent.c index f6d08f4798..2b506da248 100644 --- a/usr/src/lib/libtelnet/getent.c +++ b/usr/src/lib/libtelnet/getent.c @@ -6,7 +6,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)getent.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)getent.c 5.2 (Berkeley) %G%"; #endif /* not lint */ /* @@ -35,6 +35,7 @@ char *cp, *name; return(0); } +#ifndef __svr4__ /*ARGSUSED*/ char * getstr(cp, cpp) @@ -42,3 +43,4 @@ char *cp, **cpp; { return(0); } +#endif diff --git a/usr/src/lib/libtelnet/kerberos.c b/usr/src/lib/libtelnet/kerberos.c index 24967f6097..e5edb09d6e 100644 --- a/usr/src/lib/libtelnet/kerberos.c +++ b/usr/src/lib/libtelnet/kerberos.c @@ -6,7 +6,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)kerberos.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)kerberos.c 5.3 (Berkeley) %G%"; #endif /* not lint */ /* @@ -33,16 +33,8 @@ static char sccsid[] = "@(#)kerberos.c 5.2 (Berkeley) %G%"; #include #include #include -#if defined(ENCRYPT) -#define __NEED_ENCRYPT__ -#undef ENCRYPT -#endif #include /* BSD wont include this in krb.h, so we do it here */ #include -#if defined(__NEED_ENCRYPT__) && !defined(ENCRYPT) -#define ENCRYPT -#undef __NEED_ENCRYPT__ -#endif #ifdef __STDC__ #include #endif @@ -56,7 +48,7 @@ static char sccsid[] = "@(#)kerberos.c 5.2 (Berkeley) %G%"; #include "auth.h" #include "misc.h" -int cksum P((unsigned char *, int)); +int kerberos4_cksum P((unsigned char *, int)); int krb_mk_req P((KTEXT, char *, char *, char *, u_long)); int krb_rd_req P((KTEXT, char *, char *, u_long, AUTH_DAT *, char *)); int krb_kntoln P((AUTH_DAT *, char *)); @@ -74,17 +66,19 @@ static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, #define KRB_AUTH 0 /* Authentication data follows */ #define KRB_REJECT 1 /* Rejected (reason might follow) */ #define KRB_ACCEPT 2 /* Accepted */ -#define KRB_CHALLANGE 3 /* Challange for mutual auth. */ +#define KRB_CHALLENGE 3 /* Challenge for mutual auth. */ #define KRB_RESPONSE 4 /* Response for mutual auth. */ +#define KRB_SERVICE_NAME "rcmd" + static KTEXT_ST auth; static char name[ANAME_SZ]; static AUTH_DAT adat = { 0 }; -#if defined(ENCRYPT) +#if defined(ENCRYPTION) static Block session_key = { 0 }; -#endif static Schedule sched; -static Block challange = { 0 }; +static Block challenge = { 0 }; +#endif static int Data(ap, type, d, c) @@ -126,10 +120,16 @@ kerberos4_init(ap, server) Authenticator *ap; int server; { - if (server) + FILE *fp; + + if (server) { str_data[3] = TELQUAL_REPLY; - else + if ((fp = fopen(KEYFILE, "r")) == NULL) + return(0); + fclose(fp); + } else { str_data[3] = TELQUAL_IS; + } return(1); } @@ -148,7 +148,8 @@ kerberos4_send(ap) char *krb_get_phost(); CREDENTIALS cred; int r; - + + printf("[ Trying KERBEROS4 ... ]\n"); if (!UserNameRequested) { if (auth_debug_mode) { printf("Kerberos V4: no user name supplied\r\n"); @@ -157,27 +158,24 @@ kerberos4_send(ap) } bzero(instance, sizeof(instance)); + if (realm = krb_get_phost(RemoteHostName)) strncpy(instance, realm, sizeof(instance)); + instance[sizeof(instance)-1] = '\0'; realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName); + if (!realm) { - if (auth_debug_mode) { - printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); - } + printf("Kerberos V4: no realm for %s\r\n", RemoteHostName); return(0); } - if (r = krb_mk_req(&auth, "rcmd", instance, realm, 0L)) { - if (auth_debug_mode) { - printf("mk_req failed: %s\r\n", krb_err_txt[r]); - } + if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) { + printf("mk_req failed: %s\r\n", krb_err_txt[r]); return(0); } - if (r = krb_get_cred("rcmd", instance, realm, &cred)) { - if (auth_debug_mode) { - printf("get_cred failed: %s\r\n", krb_err_txt[r]); - } + if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) { + printf("get_cred failed: %s\r\n", krb_err_txt[r]); return(0); } if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) { @@ -192,33 +190,35 @@ kerberos4_send(ap) printf("Not enough room for authentication data\r\n"); return(0); } +#if defined(ENCRYPTION) /* * If we are doing mutual authentication, get set up to send - * the challange, and verify it when the response comes back. + * the challenge, and verify it when the response comes back. */ if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { register int i; des_key_sched(cred.session, sched); des_set_random_generator_seed(cred.session); - des_new_random_key(challange); - des_ecb_encrypt(challange, session_key, sched, 1); + des_new_random_key(challenge); + des_ecb_encrypt(challenge, session_key, sched, 1); /* - * Increment the challange by 1, and encrypt it for + * Increment the challenge by 1, and encrypt it for * later comparison. */ for (i = 7; i >= 0; --i) { register int x; - x = (unsigned int)challange[i] + 1; - challange[i] = x; /* ignore overflow */ + x = (unsigned int)challenge[i] + 1; + challenge[i] = x; /* ignore overflow */ if (x < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challange, challange, sched, 1); + des_ecb_encrypt(challenge, challenge, sched, 1); } +#endif if (auth_debug_mode) { - printf("CK: %d:", cksum(auth.dat, auth.length)); + printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); printf("Sent Kerberos V4 credentials to server\r\n"); @@ -252,28 +252,36 @@ kerberos4_is(ap, data, cnt) bcopy((void *)data, (void *)auth.dat, auth.length = cnt); if (auth_debug_mode) { printf("Got %d bytes of authentication data\r\n", cnt); - printf("CK: %d:", cksum(auth.dat, auth.length)); + printf("CK: %d:", kerberos4_cksum(auth.dat, auth.length)); printd(auth.dat, auth.length); printf("\r\n"); } instance[0] = '*'; instance[1] = 0; - if (r = krb_rd_req(&auth, "rcmd", instance, 0, &adat, "")) { + if (r = krb_rd_req(&auth, KRB_SERVICE_NAME, + instance, 0, &adat, "")) { if (auth_debug_mode) printf("Kerberos failed him as %s\r\n", name); Data(ap, KRB_REJECT, (void *)krb_err_txt[r], -1); auth_finished(ap, AUTH_REJECT); return; } +#ifdef ENCRYPTION bcopy((void *)adat.session, (void *)session_key, sizeof(Block)); +#endif krb_kntoln(&adat, name); - Data(ap, KRB_ACCEPT, (void *)0, 0); + + if (UserNameRequested && !kuserok(&adat, UserNameRequested)) + Data(ap, KRB_ACCEPT, (void *)0, 0); + else + Data(ap, KRB_REJECT, + (void *)"user is not authorized", -1); auth_finished(ap, AUTH_USER); - if (auth_debug_mode) { - printf("Kerberos accepting him as %s\r\n", name); - } break; - case KRB_CHALLANGE: + case KRB_CHALLENGE: +#if !defined(ENCRYPTION) + Data(ap, KRB_RESPONSE, (void *)0, 0); +#else if (!VALIDKEY(session_key)) { /* * We don't have a valid session key, so just @@ -287,7 +295,7 @@ kerberos4_is(ap, data, cnt) des_key_sched(session_key, sched); bcopy((void *)data, (void *)datablock, sizeof(Block)); /* - * Take the received encrypted challange, and encrypt + * Take the received encrypted challenge, and encrypt * it again to get a unique session_key for the * ENCRYPT option. */ @@ -297,19 +305,20 @@ kerberos4_is(ap, data, cnt) skey.data = session_key; encrypt_session_key(&skey, 1); /* - * Now decrypt the received encrypted challange, + * Now decrypt the received encrypted challenge, * increment by one, re-encrypt it and send it back. */ - des_ecb_encrypt(datablock, challange, sched, 0); + des_ecb_encrypt(datablock, challenge, sched, 0); for (r = 7; r >= 0; r++) { register int t; - t = (unsigned int)challange[r] + 1; - challange[r] = t; /* ignore overflow */ + t = (unsigned int)challenge[r] + 1; + challenge[r] = t; /* ignore overflow */ if (t < 256) /* if no overflow, all done */ break; } - des_ecb_encrypt(challange, challange, sched, 1); - Data(ap, KRB_RESPONSE, (void *)challange, sizeof(challange)); + des_ecb_encrypt(challenge, challenge, sched, 1); + Data(ap, KRB_RESPONSE, (void *)challenge, sizeof(challenge)); +#endif break; default: @@ -343,11 +352,13 @@ kerberos4_reply(ap, data, cnt) printf("[ Kerberos V4 accepts you ]\n"); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* - * Send over the encrypted challange. + * Send over the encrypted challenge. */ - Data(ap, KRB_CHALLANGE, (void *)session_key, +#if !defined(ENCRYPTION) + Data(ap, KRB_CHALLENGE, (void *)0, 0); +#else + Data(ap, KRB_CHALLENGE, (void *)session_key, sizeof(session_key)); -#if defined(ENCRYPT) des_ecb_encrypt(session_key, session_key, sched, 1); skey.type = SK_DES; skey.length = 8; @@ -359,19 +370,23 @@ kerberos4_reply(ap, data, cnt) auth_finished(ap, AUTH_USER); return; case KRB_RESPONSE: +#if defined(ENCRYPTION) /* - * Verify that the response to the challange is correct. + * Verify that the response to the challenge is correct. */ if ((cnt != sizeof(Block)) || - (0 != memcmp((void *)data, (void *)challange, - sizeof(challange)))) + (0 != memcmp((void *)data, (void *)challenge, + sizeof(challenge)))) { - printf("[ Kerberos V4 challange failed!!! ]\r\n"); +#endif + printf("[ Kerberos V4 challenge failed!!! ]\r\n"); auth_send_retry(); return; +#if defined(ENCRYPTION) } - printf("[ Kerberos V4 challange successful ]\r\n"); + printf("[ Kerberos V4 challenge successful ]\r\n"); auth_finished(ap, AUTH_USER); +#endif break; default: if (auth_debug_mode) @@ -432,8 +447,8 @@ kerberos4_printsub(data, cnt, buf, buflen) strncpy((char *)buf, " AUTH", buflen); goto common2; - case KRB_CHALLANGE: - strncpy((char *)buf, " CHALLANGE", buflen); + case KRB_CHALLENGE: + strncpy((char *)buf, " CHALLENGE", buflen); goto common2; case KRB_RESPONSE: @@ -455,25 +470,37 @@ kerberos4_printsub(data, cnt, buf, buflen) } int -cksum(d, n) +kerberos4_cksum(d, n) unsigned char *d; int n; { int ck = 0; + /* + * A comment is probably needed here for those not + * well versed in the "C" language. Yes, this is + * supposed to be a "switch" with the body of the + * "switch" being a "while" statement. The whole + * purpose of the switch is to allow us to jump into + * the middle of the while() loop, and then not have + * to do any more switch()s. + * + * Some compilers will spit out a warning message + * about the loop not being entered at the top. + */ switch (n&03) while (n > 0) { case 0: - ck ^= *d++ << 24; + ck ^= (int)*d++ << 24; --n; case 3: - ck ^= *d++ << 16; + ck ^= (int)*d++ << 16; --n; case 2: - ck ^= *d++ << 8; + ck ^= (int)*d++ << 8; --n; case 1: - ck ^= *d++; + ck ^= (int)*d++; --n; } return(ck); diff --git a/usr/src/lib/libtelnet/kerberos5.c b/usr/src/lib/libtelnet/kerberos5.c index bc397505cd..530b0972fa 100644 --- a/usr/src/lib/libtelnet/kerberos5.c +++ b/usr/src/lib/libtelnet/kerberos5.c @@ -1,3 +1,17 @@ +/* + * $Source: /afs/athena.mit.edu/astaff/project/krb5/src/appl/telnet/libtelnet/RCS/kerberos5.c,v $ + * $Author: jtkohl $ + * $Id: kerberos5.c,v 1.3 91/07/19 16:37:57 jtkohl Exp Locker: tytso $ + */ + +#if !defined(lint) && !defined(SABER) +static +#ifdef __STDC__ +const +#endif +char rcsid_kerberos5_c[] = "$Id: kerberos5.c,v 1.3 91/07/19 16:37:57 jtkohl Exp Locker: tytso $"; +#endif /* lint */ + /*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. @@ -6,7 +20,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)kerberos5.c 5.2 (Berkeley) %G%"; +static char sccsid[] = "@(#)kerberos5.c 5.3 (Berkeley) %G%"; #endif /* not lint */ /* @@ -35,53 +49,52 @@ static char sccsid[] = "@(#)kerberos5.c 5.2 (Berkeley) %G%"; #include #include #include -#include +#include +#include +#include #include #include -#ifdef __STDC__ -#include -#endif -#ifdef NO_STRING_H -#include -#else -#include -#endif +/* kerberos 5 include files (ext-proto.h) will get an appropriate stdlib.h + and string.h/strings.h */ + #include "encrypt.h" #include "auth.h" #include "misc.h" extern auth_debug_mode; -char *malloc(); static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V5, }; -static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_NAME, }; +/*static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION, + TELQUAL_NAME, };*/ #define KRB_AUTH 0 /* Authentication data follows */ #define KRB_REJECT 1 /* Rejected (reason might follow) */ #define KRB_ACCEPT 2 /* Accepted */ -#define KRB_CHALLANGE 3 /* Challange for mutual auth. */ -#define KRB_RESPONSE 4 /* Response for mutual auth. */ +#define KRB_RESPONSE 3 /* Response for mutual auth. */ static krb5_data auth; /* telnetd gets session key from here */ static krb5_tkt_authent *authdat = NULL; +/* telnet matches the AP_REQ and AP_REP with this */ +static krb5_authenticator authenticator; -#if defined(ENCRYPT) +/* some compilers can't hack void *, so we use the Kerberos krb5_pointer, + which is either void * or char *, depending on the compiler. */ + +#define Voidptr krb5_pointer + +#if defined(ENCRYPTION) Block session_key; #endif -static Schedule sched; -static Block challange; - static int Data(ap, type, d, c) Authenticator *ap; int type; - void *d; + Voidptr d; int c; { unsigned char *p = str_data + 4; @@ -134,17 +147,21 @@ kerberos5_send(ap) char *p1, *p2; krb5_checksum ksum; krb5_octet sum[CRC32_CKSUM_LENGTH]; - krb5_data *server[4]; - krb5_data srvdata[3]; + krb5_principal server; krb5_error_code r; krb5_ccache ccache; krb5_creds creds; /* telnet gets session key from here */ extern krb5_flags krb5_kdc_default_options; + int ap_opts; + +#if defined(ENCRYPTION) + krb5_keyblock *newkey = 0; +#endif ksum.checksum_type = CKSUMTYPE_CRC32; ksum.contents = sum; ksum.length = sizeof(sum); - bzero((void *)sum, sizeof(sum)); + bzero((Voidptr )sum, sizeof(sum)); if (!UserNameRequested) { if (auth_debug_mode) { @@ -182,49 +199,85 @@ kerberos5_send(ap) ++p2; } - srvdata[0].data = realms[0]; - srvdata[0].length = strlen(realms[0]); - srvdata[1].data = "rcmd"; - srvdata[1].length = 4; - srvdata[2].data = name; - srvdata[2].length = p2 - name; - - server[0] = &srvdata[0]; - server[1] = &srvdata[1]; - server[2] = &srvdata[2]; - server[3] = 0; + if (r = krb5_build_principal_ext(&server, + strlen(realms[0]), realms[0], + 4, "rcmd", + p2 - name, name, + 0)) { + if (auth_debug_mode) { + printf("Kerberos V5: failure setting up principal (%s)\r\n", + error_message(r)); + } + free(name); + krb5_free_host_realm(realms); + return(0); + } + bzero((char *)&creds, sizeof(creds)); - creds.server = (krb5_principal)server; + creds.server = server; if (r = krb5_cc_get_principal(ccache, &creds.client)) { if (auth_debug_mode) { - printf("Keberos V5: failure on principal (%d)\r\n", + printf("Kerberos V5: failure on principal (%s)\r\n", error_message(r)); } free(name); + krb5_free_principal(server); krb5_free_host_realm(realms); return(0); } if (r = krb5_get_credentials(krb5_kdc_default_options, ccache, &creds)) { if (auth_debug_mode) { - printf("Keberos V5: failure on credentials(%d)\r\n",r); + printf("Kerberos V5: failure on credentials(%d)\r\n",r); } free(name); krb5_free_host_realm(realms); + krb5_free_principal(server); return(0); } - r = krb5_mk_req_extended(0, &ksum, &creds.times, - krb5_kdc_default_options, - ccache, &creds, 0, &auth); + if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) + ap_opts = AP_OPTS_MUTUAL_REQUIRED; + else + ap_opts = 0; + + r = krb5_mk_req_extended(ap_opts, &ksum, krb5_kdc_default_options, 0, +#if defined(ENCRYPTION) + &newkey, +#else + 0, +#endif + ccache, &creds, &authenticator, &auth); + /* don't let the key get freed if we clean up the authenticator */ + authenticator.subkey = 0; free(name); krb5_free_host_realm(realms); + krb5_free_principal(server); +#if defined(ENCRYPTION) + if (newkey) { + /* keep the key in our private storage, but don't use it + yet---see kerberos5_reply() below */ + if (newkey->keytype != KEYTYPE_DES) { + if (creds.keyblock.keytype == KEYTYPE_DES) + /* use the session key in credentials instead */ + memcpy((char *)session_key, + (char *)creds.keyblock.contents, sizeof(Block)); + else + /* XXX ? */; + } else { + memcpy((char *)session_key, (char *)newkey->contents, + sizeof(Block)); + } + krb5_free_keyblock(newkey); + } +#endif if (r) { if (auth_debug_mode) { - printf("Keberos V5: mk_req failed\r\n"); + printf("Kerberos V5: mk_req failed (%s)\r\n", + error_message(r)); } return(0); } @@ -239,32 +292,6 @@ kerberos5_send(ap) printf("Not enough room for authentication data\r\n"); return(0); } - /* - * If we are doing mutual authentication, get set up to send - * the challange, and verify it when the response comes back. - */ - if (((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) - && (creds.keyblock.keytype == KEYTYPE_DES)) { - register int i; - - des_key_sched(creds.keyblock.contents, sched); - des_set_random_generator_seed(creds.keyblock.contents); - des_new_random_key(challange); - des_ecb_encrypt(challange, session_key, sched, 1); - /* - * Increment the challange by 1, and encrypt it for - * later comparison. - */ - for (i = 7; i >= 0; --i) { - register int x; - x = (unsigned int)challange[i] + 1; - challange[i] = x; /* ignore overflow */ - if (x < 256) /* if no overflow, all done */ - break; - } - des_ecb_encrypt(challange, challange, sched, 1); - } - if (auth_debug_mode) { printf("Sent Kerberos V5 credentials to server\r\n"); } @@ -281,9 +308,10 @@ kerberos5_is(ap, data, cnt) struct hostent *hp; char *p1, *p2; static char *realm = NULL; - krb5_data *server[4]; - krb5_data srvdata[3]; - Session_Key skey; + krb5_principal server; + krb5_ap_rep_enc_part reply; + krb5_data outbuf; + Session_Key skey; char *name; char *getenv(); @@ -304,7 +332,7 @@ kerberos5_is(ap, data, cnt) if (!realm && (krb5_get_default_realm(&realm))) { if (auth_debug_mode) - printf("Could not get defualt realm\r\n"); + printf("Could not get default realm\r\n"); Data(ap, KRB_REJECT, "Could not get default realm.", -1); auth_finished(ap, AUTH_REJECT); return; @@ -327,23 +355,22 @@ kerberos5_is(ap, data, cnt) ++p2; } - srvdata[0].data = realm; - srvdata[0].length = strlen(realm); - srvdata[1].data = "rcmd"; - srvdata[1].length = 4; - srvdata[2].data = name; - srvdata[2].length = p2 - name; - - server[0] = &srvdata[0]; - server[1] = &srvdata[1]; - server[2] = &srvdata[2]; - server[3] = 0; - if (authdat) krb5_free_tkt_authent(authdat); - if (r = krb5_rd_req_simple(&auth, server, 0, &authdat)) { + + r = krb5_build_principal_ext(&server, + strlen(realm), realm, + 4, "rcmd", + p2 - name, name, + 0); + if (!r) { + r = krb5_rd_req_simple(&auth, server, 0, &authdat); + krb5_free_principal(server); + } + if (r) { char errbuf[128]; + errout: authdat = 0; (void) strcpy(errbuf, "Read req failed: "); (void) strcat(errbuf, error_message(r)); @@ -353,60 +380,50 @@ kerberos5_is(ap, data, cnt) return; } free(name); + if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { + /* do ap_rep stuff here */ + reply.ctime = authdat->authenticator->ctime; + reply.cusec = authdat->authenticator->cusec; + reply.subkey = 0; /* use the one he gave us, so don't + need to return one here */ + reply.seq_number = 0; /* we don't do seq #'s. */ + + if (r = krb5_mk_rep(&reply, + authdat->authenticator->subkey ? + authdat->authenticator->subkey : + authdat->ticket->enc_part2->session, + &outbuf)) { + goto errout; + } + Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); + } if (krb5_unparse_name(authdat->ticket->enc_part2 ->client, &name)) name = 0; Data(ap, KRB_ACCEPT, name, name ? -1 : 0); if (auth_debug_mode) { - printf("Kerberos5 accepting him as ``%s''\r\n", + printf("Kerberos5 identifies him as ``%s''\r\n", name ? name : ""); } auth_finished(ap, AUTH_USER); - if (authdat->ticket->enc_part2->session->keytype != KEYTYPE_DES) - break; - bcopy((void *)authdat->ticket->enc_part2->session->contents, - (void *)session_key, sizeof(Block)); - break; - - case KRB_CHALLANGE: - if (!VALIDKEY(session_key)) { - /* - * We don't have a valid session key, so just - * send back a response with an empty session - * key. - */ - Data(ap, KRB_RESPONSE, (void *)0, 0); - break; - } + + free(name); + if (authdat->authenticator->subkey && + authdat->authenticator->subkey->keytype == KEYTYPE_DES) { + bcopy((Voidptr )authdat->authenticator->subkey->contents, + (Voidptr )session_key, sizeof(Block)); + } else if (authdat->ticket->enc_part2->session->keytype == + KEYTYPE_DES) { + bcopy((Voidptr )authdat->ticket->enc_part2->session->contents, + (Voidptr )session_key, sizeof(Block)); + } else + break; - des_key_sched(session_key, sched); - bcopy((void *)data, (void *)datablock, sizeof(Block)); - /* - * Take the received encrypted challange, and encrypt - * it again to get a unique session_key for the - * ENCRYPT option. - */ - des_ecb_encrypt(datablock, session_key, sched, 1); skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 1); - /* - * Now decrypt the received encrypted challange, - * increment by one, re-encrypt it and send it back. - */ - des_ecb_encrypt(datablock, challange, sched, 0); - for (r = 7; r >= 0; r++) { - register int t; - t = (unsigned int)challange[r] + 1; - challange[r] = t; /* ignore overflow */ - if (t < 256) /* if no overflow, all done */ - break; - } - des_ecb_encrypt(challange, challange, sched, 1); - Data(ap, KRB_RESPONSE, (void *)challange, sizeof(challange)); break; - default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); @@ -422,6 +439,7 @@ kerberos5_reply(ap, data, cnt) int cnt; { Session_Key skey; + static int mutual_complete = 0; if (cnt-- < 1) return; @@ -435,39 +453,55 @@ kerberos5_reply(ap, data, cnt) auth_send_retry(); return; case KRB_ACCEPT: - printf("[ Kerberos V5 accepts you ]\n", cnt, data); + if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && + !mutual_complete) { + printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\n"); + auth_send_retry(); + return; + } + if (cnt) + printf("[ Kerberos V5 accepts you as ``%.*s'' ]\n", cnt, data); + else + printf("[ Kerberos V5 accepts you ]\n"); + auth_finished(ap, AUTH_USER); + break; + case KRB_RESPONSE: if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { - /* - * Send over the encrypted challange. - */ - Data(ap, KRB_CHALLANGE, (void *)session_key, - sizeof(session_key)); -#if defined(ENCRYPT) - des_ecb_encrypt(session_key, session_key, sched, 1); + /* the rest of the reply should contain a krb_ap_rep */ + krb5_ap_rep_enc_part *reply; + krb5_data inbuf; + krb5_error_code r; + krb5_keyblock tmpkey; + + inbuf.length = cnt; + inbuf.data = (char *)data; + + tmpkey.keytype = KEYTYPE_DES; + tmpkey.contents = session_key; + tmpkey.length = sizeof(Block); + + if (r = krb5_rd_rep(&inbuf, &tmpkey, &reply)) { + printf("[ Mutual authentication failed: %s ]\n", + error_message(r)); + auth_send_retry(); + return; + } + if (reply->ctime != authenticator.ctime || + reply->cusec != authenticator.cusec) { + printf("[ Mutual authentication failed (mismatched KRB_AP_REP) ]\n"); + auth_send_retry(); + return; + } + krb5_free_ap_rep_enc_part(reply); +#if defined(ENCRYPTION) skey.type = SK_DES; skey.length = 8; skey.data = session_key; encrypt_session_key(&skey, 0); #endif - return; + mutual_complete = 1; } - auth_finished(ap, AUTH_USER); return; - case KRB_RESPONSE: - /* - * Verify that the response to the challange is correct. - */ - if ((cnt != sizeof(Block)) || - (0 != memcmp((void *)data, (void *)challange, - sizeof(challange)))) - { - printf("[ Kerberos V5 challange failed!!! ]\r\n"); - auth_send_retry(); - return; - } - printf("[ Kerberos V5 challange successful ]\r\n"); - auth_finished(ap, AUTH_USER); - break; default: if (auth_debug_mode) printf("Unknown Kerberos option %d\r\n", data[-1]); @@ -494,7 +528,7 @@ kerberos5_status(ap, name, level) } #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);} -#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len));} +#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);} void kerberos5_printsub(data, cnt, buf, buflen) @@ -525,14 +559,11 @@ kerberos5_printsub(data, cnt, buf, buflen) ADDC(buf, buflen, '\0'); break; + case KRB_AUTH: /* Authentication data follows */ strncpy((char *)buf, " AUTH", buflen); goto common2; - case KRB_CHALLANGE: - strncpy((char *)buf, " CHALLANGE", buflen); - goto common2; - case KRB_RESPONSE: strncpy((char *)buf, " RESPONSE", buflen); goto common2; diff --git a/usr/src/lib/libtelnet/misc.c b/usr/src/lib/libtelnet/misc.c index 385587f946..d0baea9ebe 100644 --- a/usr/src/lib/libtelnet/misc.c +++ b/usr/src/lib/libtelnet/misc.c @@ -6,7 +6,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)misc.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)misc.c 5.2 (Berkeley) %G%"; #endif /* not lint */ /* @@ -44,10 +44,10 @@ auth_encrypt_init(local, remote, name, server) { RemoteHostName = remote; LocalHostName = local; -#if defined(AUTHENTICATE) +#if defined(AUTHENTICATION) auth_init(name, server); #endif -#if defined(ENCRYPT) +#if defined(ENCRYPTION) encrypt_init(name, server); #endif if (UserNameRequested) { -- 2.20.1