diff options
author | Karl Ramm <kcr@mit.edu> | 2007-12-25 00:56:08 +0000 |
---|---|---|
committer | Karl Ramm <kcr@mit.edu> | 2007-12-25 00:56:08 +0000 |
commit | 1a0e03eb19998ab496a6ea845ff2c42d9a02df0b (patch) | |
tree | 29b47c8532e1f1678063fbb1b851ee4208134626 /lib | |
parent | 3f120f880be9ae9aa1612ddc2412e9acb9a8e85e (diff) |
applied athena-update-branch patch
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.in | 3 | ||||
-rw-r--r-- | lib/ZCkAuth.c | 36 | ||||
-rw-r--r-- | lib/ZFmtAuth.c | 70 | ||||
-rw-r--r-- | lib/ZFmtNotice.c | 26 | ||||
-rw-r--r-- | lib/ZFmtSmRaw.c | 23 | ||||
-rw-r--r-- | lib/ZGetSender.c | 45 | ||||
-rw-r--r-- | lib/ZInit.c | 45 | ||||
-rw-r--r-- | lib/ZMkAuth.c | 188 | ||||
-rw-r--r-- | lib/ZParseNot.c | 21 | ||||
-rw-r--r-- | lib/Zinternal.c | 518 |
10 files changed, 947 insertions, 28 deletions
diff --git a/lib/Makefile.in b/lib/Makefile.in index 5415797..40abb6e 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -39,7 +39,8 @@ OBJS = zephyr_err.lo ZAsyncLocate.lo ZCkAuth.lo ZCkIfNot.lo ZClosePort.lo \ ZPeekIfNot.lo ZPeekNot.lo ZPeekPkt.lo ZPending.lo ZReadAscii.lo \ ZRecvNot.lo ZRecvPkt.lo ZRetSubs.lo ZSendList.lo ZSendNot.lo \ ZSendPkt.lo ZSendRaw.lo ZSendRLst.lo ZSetDest.lo ZSetFD.lo ZSetSrv.lo \ - ZSubs.lo ZVariables.lo ZWait4Not.lo Zinternal.lo + ZSubs.lo ZVariables.lo ZWait4Not.lo Zinternal.lo ZMakeZcode.o \ + ZReadZcode.o ZCkZaut.o .SUFFIXES: .lo diff --git a/lib/ZCkAuth.c b/lib/ZCkAuth.c index 17fdc2b..4c83e6a 100644 --- a/lib/ZCkAuth.c +++ b/lib/ZCkAuth.c @@ -17,6 +17,10 @@ static char rcsid_ZCheckAuthentication_c[] = #include <internal.h> +#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA +#define krb5_free_data(ctx, dat) free((dat)->data) +#endif + /* Check authentication of the notice. If it looks authentic but fails the Kerberos check, return -1. If it looks authentic and passes the Kerberos check, return 1. @@ -28,30 +32,49 @@ static char rcsid_ZCheckAuthentication_c[] = Code_t ZCheckAuthentication(notice, from) ZNotice_t *notice; struct sockaddr_in *from; -{ -#ifdef HAVE_KRB4 +{ +#if 0 +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) int result; ZChecksum_t our_checksum; + C_Block *session; +#ifdef HAVE_KRB5 + krb5_creds *creds_out; +#else CREDENTIALS cred; - +#endif /* If the value is already known, return it. */ if (notice->z_checked_auth != ZAUTH_UNSET) return (notice->z_checked_auth); if (!notice->z_auth) return (ZAUTH_NO); - + +#ifdef HAVE_KRB5 + result = ZGetCreds(&creds_out); + if (result) + return ZAUTH_NO; + /* HOLDING: creds_out */ + + if (creds_out->keyblock.enctype != ENCTYPE_DES_CBC_CRC) + return (ZAUTH_NO); + session = (C_Block *)creds_out->keyblock.contents; + +#else if ((result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, __Zephyr_realm, &cred)) != 0) return (ZAUTH_NO); + session = (C_Block *)cred.session; +#endif + #ifdef NOENCRYPTION our_checksum = 0; #else our_checksum = des_quad_cksum(notice->z_packet, NULL, notice->z_default_format+ strlen(notice->z_default_format)+1- - notice->z_packet, 0, cred.session); + notice->z_packet, 0, session); #endif /* if mismatched checksum, then the packet was corrupted */ return ((our_checksum == notice->z_checksum) ? ZAUTH_YES : ZAUTH_FAILED); @@ -59,4 +82,7 @@ Code_t ZCheckAuthentication(notice, from) #else return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO); #endif +#else + ZCheckZcodeAuthentication(notice, from); +#endif } diff --git a/lib/ZFmtAuth.c b/lib/ZFmtAuth.c index c2d8a00..97a70f2 100644 --- a/lib/ZFmtAuth.c +++ b/lib/ZFmtAuth.c @@ -16,7 +16,7 @@ static char rcsid_ZFormatAuthenticNotice_c[] = "$Id$"; #include <internal.h> -#ifdef HAVE_KRB4 +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) Code_t ZFormatAuthenticNotice(notice, buffer, buffer_len, len, session) ZNotice_t *notice; register char *buffer; @@ -62,3 +62,71 @@ Code_t ZFormatAuthenticNotice(notice, buffer, buffer_len, len, session) return (ZERR_NONE); } #endif + +#ifdef HAVE_KRB5 +Code_t ZFormatAuthenticNoticeV5(notice, buffer, buffer_len, len, keyblock) + ZNotice_t *notice; + register char *buffer; + register int buffer_len; + int *len; + krb5_keyblock *keyblock; +{ + ZNotice_t newnotice; + char *ptr; + int retval, hdrlen, hdr_adj; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + int valid; + char *svcinst, *x, *y; + int key_len; + char *cksum_start, *cstart, *cend; + int cksum_len; + + key_len = Z_keylen(keyblock); + retval = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (retval) + return (ZAUTH_FAILED); + + if (key_len == 8 && (enctype == ENCTYPE_DES_CBC_CRC || + enctype == ENCTYPE_DES_CBC_MD4 || + enctype == ENCTYPE_DES_CBC_MD5)) { + C_Block tmp; + memcpy(&tmp, Z_keydata(keyblock), key_len); + return ZFormatAuthenticNotice(notice, buffer, buffer_len, len, + tmp); + } + + newnotice = *notice; + newnotice.z_auth = 1; + newnotice.z_authent_len = 0; + newnotice.z_ascii_authent = ""; + + if ((retval = Z_NewFormatRawHeader(&newnotice, buffer, buffer_len, + &hdrlen, + &cksum_start, &cksum_len, &cstart, + &cend)) != ZERR_NONE) + return (retval); + + retval = Z_InsertZcodeChecksum(keyblock, &newnotice, buffer, + cksum_start, cksum_len, cstart, cend, + buffer_len, &hdr_adj); + if (retval) + return retval; + + hdrlen += hdr_adj; + + ptr = buffer+hdrlen; + + if (newnotice.z_message_len+hdrlen > buffer_len) + return (ZERR_PKTLEN); + + (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len); + + *len = hdrlen+newnotice.z_message_len; + + if (*len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + return (ZERR_NONE); +} +#endif diff --git a/lib/ZFmtNotice.c b/lib/ZFmtNotice.c index d7876d7..0b9ca39 100644 --- a/lib/ZFmtNotice.c +++ b/lib/ZFmtNotice.c @@ -41,3 +41,29 @@ Code_t ZFormatNotice(notice, buffer, ret_len, cert_routine) return (ZERR_NONE); } + +Code_t ZNewFormatNotice(notice, buffer, ret_len, cert_routine) + register ZNotice_t *notice; + char **buffer; + int *ret_len; + Z_AuthProc cert_routine; +{ + char header[Z_MAXHEADERLEN]; + int hdrlen; + Code_t retval; + + if ((retval = Z_NewFormatHeader(notice, header, sizeof(header), &hdrlen, + cert_routine)) != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + /* Length can never be zero, don't have to worry about malloc(0). */ + if (!(*buffer = (char *) malloc((unsigned)*ret_len))) + return (ENOMEM); + + (void) memcpy(*buffer, header, hdrlen); + (void) memcpy(*buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} diff --git a/lib/ZFmtSmRaw.c b/lib/ZFmtSmRaw.c index a9ce79d..0fcd74c 100644 --- a/lib/ZFmtSmRaw.c +++ b/lib/ZFmtSmRaw.c @@ -37,3 +37,26 @@ Code_t ZFormatSmallRawNotice(notice, buffer, ret_len) return (ZERR_NONE); } + +Code_t ZNewFormatSmallRawNotice(notice, buffer, ret_len) + ZNotice_t *notice; + ZPacket_t buffer; + int *ret_len; +{ + Code_t retval; + int hdrlen; + + if ((retval = Z_AsciiFormatRawHeader(notice, buffer, Z_MAXHEADERLEN, + &hdrlen, NULL, NULL, NULL, NULL)) + != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + if (*ret_len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + (void) memcpy(buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} diff --git a/lib/ZGetSender.c b/lib/ZGetSender.c index df5f3e2..c495cec 100644 --- a/lib/ZGetSender.c +++ b/lib/ZGetSender.c @@ -22,31 +22,62 @@ static const char rcsid_ZGetSender_c[] = char *ZGetSender() { struct passwd *pw; + static char *sender = NULL; +#ifdef HAVE_KRB5 + krb5_ccache ccache; + krb5_principal principal; + char *prname; + int result; + char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; /*XXX*/ +#else #ifdef HAVE_KRB4 char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; - static char sender[ANAME_SZ+INST_SZ+REALM_SZ+3] = ""; -#else - static char sender[128] = ""; +#endif #endif /* Return it if already cached */ - if (*sender) + if (sender) return (sender); +#ifdef HAVE_KRB5 + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (!result) { + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &principal); + if (!result) { +#if 0 + krb5_unparse_name(Z_krb5_ctx, principal, &prname); + sender = strdup(prname); +#else + krb5_524_conv_principal(Z_krb5_ctx, principal, pname, pinst, prealm); + sender = malloc(ANAME_SZ+INST_SZ+REALM_SZ+3); + if (sender) + (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""), + pinst, prealm); +#endif + krb5_free_principal(Z_krb5_ctx, principal); + } + krb5_cc_close(Z_krb5_ctx, ccache); + } +#else #ifdef HAVE_KRB4 if (krb_get_tf_fullname((char *)TKT_FILE, pname, pinst, prealm) == KSUCCESS) { - (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""), - pinst, prealm); + sender = malloc(ANAME_SZ+INST_SZ+REALM_SZ+3); + if (sender) + (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""), + pinst, prealm); return (sender); } #endif +#endif /* XXX a uid_t is a u_short (now), but getpwuid * wants an int. AARGH! */ pw = getpwuid((int) getuid()); if (!pw) return ("unknown"); - (void) sprintf(sender, "%s@%s", pw->pw_name, __Zephyr_realm); + sender = malloc(strlen(pw->pw_name) + strlen(__Zephyr_realm) + 2); + if (sender) + (void) sprintf(sender, "%s@%s", pw->pw_name, __Zephyr_realm); return (sender); } diff --git a/lib/ZInit.c b/lib/ZInit.c index 401f6db..16d266e 100644 --- a/lib/ZInit.c +++ b/lib/ZInit.c @@ -21,6 +21,12 @@ static char rcsid_ZInitialize_c[] = #ifdef HAVE_KRB4 #include <krb_err.h> #endif +#ifdef HAVE_KRB5 +#include <krb5.h> +#endif +#ifdef HAVE_KRB5_ERR_H +#include <krb5_err.h> +#endif #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -36,13 +42,22 @@ Code_t ZInitialize() int s, sinsize = sizeof(sin); Code_t code; ZNotice_t notice; +#ifdef HAVE_KRB5 + char **krealms = NULL; +#else #ifdef HAVE_KRB4 char *krealm = NULL; int krbval; char d1[ANAME_SZ], d2[INST_SZ]; +#endif +#endif +#ifdef HAVE_KRB4 initialize_krb_error_table(); #endif +#ifdef HAVE_KRB5 + initialize_krb5_error_table(); +#endif initialize_zeph_error_table(); @@ -67,6 +82,11 @@ Code_t ZInitialize() __Q_Tail = NULL; __Q_Head = NULL; +#ifdef HAVE_KRB5 + if ((code = krb5_init_context(&Z_krb5_ctx))) + return(code); +#endif + /* if the application is a server, there might not be a zhm. The code will fall back to something which might not be "right", but this is is ok, since none of the servers call krb_rd_req. */ @@ -85,9 +105,15 @@ Code_t ZInitialize() If this code ever support a multiplexing zhm, this will have to be made smarter, and probably per-message */ +#ifdef HAVE_KRB5 + code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms); + if (code) + return(code); +#else #ifdef HAVE_KRB4 krealm = krb_realmofhost(notice.z_message); #endif +#endif hostent = gethostbyname(notice.z_message); if (hostent && hostent->h_addrtype == AF_INET) memcpy(&servaddr, hostent->h_addr, sizeof(servaddr)); @@ -95,6 +121,24 @@ Code_t ZInitialize() ZFreeNotice(¬ice); } +#ifdef HAVE_KRB5 + if (krealms) { + strcpy(__Zephyr_realm, krealms[0]); + krb5_free_host_realm(Z_krb5_ctx, krealms); + } else { + char *p; /* XXX define this somewhere portable */ + /* XXX check ticket file here */ + code = krb5_get_default_realm(Z_krb5_ctx, &p); + strcpy(__Zephyr_realm, p); +#ifdef HAVE_KRB5_FREE_DEFAULT_REALM + krb5_free_default_realm(Z_krb5_ctx, p); +#else + free(p); +#endif + if (code) + return code; + } +#else #ifdef HAVE_KRB4 if (krealm) { strcpy(__Zephyr_realm, krealm); @@ -106,6 +150,7 @@ Code_t ZInitialize() #else strcpy(__Zephyr_realm, "local-realm"); #endif +#endif __My_addr.s_addr = INADDR_NONE; if (servaddr.s_addr != INADDR_NONE) { diff --git a/lib/ZMkAuth.c b/lib/ZMkAuth.c index 5a6749c..92d0bd3 100644 --- a/lib/ZMkAuth.c +++ b/lib/ZMkAuth.c @@ -20,6 +20,10 @@ static const char rcsid_ZMakeAuthentication_c[] = "$Id$"; #include <krb_err.h> #endif +#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA +#define krb5_free_data(ctx, dat) free((dat)->data) +#endif + Code_t ZResetAuthentication () { return ZERR_NONE; } @@ -30,15 +34,39 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) int buffer_len; int *len; { -#ifdef HAVE_KRB4 +#if 1 + return ZMakeZcodeAuthentication(notice, buffer, buffer_len, len/*?XXX*/); +#else +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) int result; time_t now; KTEXT_ST authent; char *cstart, *cend; ZChecksum_t checksum; CREDENTIALS cred; - extern unsigned long des_quad_cksum(); + C_Block *session; +#ifdef HAVE_KRB5 + krb5_creds *creds_out; + + result = ZGetCreds(&creds_out); + if (result) + return result; + + result = krb5_524_convert_creds(Z_krb5_ctx, creds_out, &cred); + /* krb5_free_creds(Z_krb5_ctx, creds_out);*/ + if (result) + return result; + /* HOLDING: creds_out */ + + if (creds_out->keyblock.enctype != ENCTYPE_DES_CBC_CRC) + return (KRB5_BAD_ENCTYPE); + session = (C_Block *)creds_out->keyblock.contents; + result = krb_mk_req_creds(&authent, &cred, 0); + if (result != MK_AP_OK) + return result + krb_err_base; +#endif +#ifndef HAVE_KRB5 result = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, __Zephyr_realm, 0); if (result != MK_AP_OK) @@ -48,6 +76,9 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) if (result != KSUCCESS) return (result+krb_err_base); + session = (C_Block *)cred.session; +#endif + notice->z_auth = 1; notice->z_authent_len = authent.length; notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3); @@ -69,11 +100,11 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) return(result); /* Compute a checksum over the header and message. */ - checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, cred.session); + checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, session); checksum ^= des_quad_cksum(cend, NULL, buffer + *len - cend, 0, - cred.session); + session); checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len, - 0, cred.session); + 0, session); notice->z_checksum = checksum; ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum); @@ -85,4 +116,151 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) notice->z_ascii_authent = ""; return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL)); #endif +#endif } + +Code_t ZMakeZcodeAuthentication(notice, buffer, buffer_len, phdr_len) + register ZNotice_t *notice; + char *buffer; + int buffer_len; + int *phdr_len; +{ + return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len, + __Zephyr_realm); +} + +Code_t ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len, + realm) + register ZNotice_t *notice; + char *buffer; + int buffer_len; + int *phdr_len; + char *realm; +{ +#ifdef HAVE_KRB5 + krb5_error_code result; + krb5_creds *creds; + krb5_keyblock *keyblock; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + krb5_auth_context authctx; + krb5_data *authent; + char *svcinst, *x, *y; + char *cksum_start, *cstart, *cend, *asn1_data; + int i, cksum_len, zcode_len, asn1_len, phdr_adj; + + result = ZGetCredsRealm(&creds, realm); + if (result) + return result; + /* HOLDING: creds */ + + /* Figure out what checksum type to use */ + keyblock = Z_credskey(creds); + /* HOLDING: creds */ + + /* Create the authenticator */ + result = krb5_auth_con_init(Z_krb5_ctx, &authctx); + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (result); + } + + authent = (krb5_data *)malloc(sizeof(krb5_data)); + + /* HOLDING: creds, authctx */ + result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */, + 0 /* in_data */, creds, authent); + krb5_auth_con_free(Z_krb5_ctx, authctx); + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (result); + } + /* HOLDING: creds, authent */ + + /* Encode the authenticator */ + notice->z_auth = 1; + notice->z_authent_len = authent->length; + zcode_len = authent->length * 2 + 2; /* 2x growth plus Z and null */ + notice->z_ascii_authent = (char *)malloc(zcode_len); + if (!notice->z_ascii_authent) { + krb5_free_data(Z_krb5_ctx, authent); + krb5_free_creds(Z_krb5_ctx, creds); + return (ENOMEM); + } + /* HOLDING: creds, authent, notice->z_ascii_authent */ + result = ZMakeZcode(notice->z_ascii_authent, zcode_len, + authent->data, authent->length); + krb5_free_data(Z_krb5_ctx, authent); + if (result) { + free(notice->z_ascii_authent); + krb5_free_creds(Z_krb5_ctx, creds); + return (result); + } + /* HOLDING: creds, notice->z_ascii_authent */ + + /* format the notice header, with a zero checksum */ + result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len, + &cksum_start, &cksum_len, &cstart, &cend); + free(notice->z_ascii_authent); + notice->z_authent_len = 0; + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (result); + } + result = Z_InsertZcodeChecksum(keyblock, notice, buffer, cksum_start, + cksum_len, cstart, cend, buffer_len, + &phdr_adj); + krb5_free_creds(Z_krb5_ctx, creds); + if (result) { + return result; + } + *phdr_len += phdr_adj; + + return (result); +#endif /* HAVE_KRB5 */ +} + +#ifdef HAVE_KRB5 +int ZGetCreds(krb5_creds **creds_out) { + return ZGetCredsRealm(creds_out, __Zephyr_realm); +} + +int ZGetCredsRealm(krb5_creds **creds_out, char *realm) { + krb5_creds creds_in; + krb5_ccache ccache; /* XXX make this a global or static?*/ + int result; + + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (result) + return result; + + memset((char *)&creds_in, 0, sizeof(creds_in)); + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(realm), + realm, + SERVER_SERVICE, SERVER_INSTANCE, 0); + if (result) { + krb5_cc_close(Z_krb5_ctx, ccache); + return result; + } + + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client); + if (result) { + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */ + krb5_cc_close(Z_krb5_ctx, ccache); + return result; + } + +#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + creds_in.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* XXX? */ +#else + creds_in.session.keytype = KEYTYPE_DES; /* XXX? */ +#endif + + result = krb5_get_credentials(Z_krb5_ctx, 0, ccache, &creds_in, creds_out); + krb5_cc_close(Z_krb5_ctx, ccache); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */ + + return result; +} +#endif diff --git a/lib/ZParseNot.c b/lib/ZParseNot.c index 7950e96..a198845 100644 --- a/lib/ZParseNot.c +++ b/lib/ZParseNot.c @@ -209,11 +209,22 @@ Code_t ZParseNotice(buffer, len, notice) else notice->z_default_format = ""; - if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) - BAD_PACKET; - notice->z_checksum = temp; - numfields--; - ptr = next_field(ptr, end); + if (numfields && ptr < end) { + notice->z_ascii_checksum = ptr; + + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + notice->z_checksum = 0; + else + notice->z_checksum = temp; + + numfields--; + ptr = next_field (ptr, end); + } + else + { + notice->z_ascii_checksum = ""; + notice->z_checksum = 0; + } if (numfields && ptr < end) { notice->z_multinotice = ptr; diff --git a/lib/Zinternal.c b/lib/Zinternal.c index 0efcc56..4440dfe 100644 --- a/lib/Zinternal.c +++ b/lib/Zinternal.c @@ -44,9 +44,60 @@ int __subscriptions_num; int __subscriptions_next; int Z_discarded_packets = 0; -#ifdef HAVE_KRB4 -C_Block __Zephyr_session; -#endif +#ifdef HAVE_KRB5 +/* This context is used throughout */ +krb5_context Z_krb5_ctx; + +static struct cksum_map_s { + krb5_enctype e; + krb5_cksumtype c; +} cksum_map[] = { + /* per RFC1510 and draft-ietf-krb-wg-crypto-02.txt */ + { ENCTYPE_NULL, CKSUMTYPE_RSA_MD5 }, + { ENCTYPE_DES_CBC_CRC, CKSUMTYPE_RSA_MD5_DES }, + { ENCTYPE_DES_CBC_MD4, CKSUMTYPE_RSA_MD4_DES }, + { ENCTYPE_DES_CBC_MD5, CKSUMTYPE_RSA_MD5_DES }, + + /* + * The implementors hate us, and are inconsistent with names for + * most things defined after RFC1510. Note that des3-cbc-sha1 + * and des3-cbc-sha1-kd are listed by number to avoid confusion + * caused by inconsistency between the names used in the specs + * and those used by implementations. + * -- jhutz, 30-Nov-2002 + */ + + /* source lost in history (an expired internet-draft) */ + { 5 /* des3-cbc-md5 */, 9 /* rsa-md5-des3 */ }, + { 7 /* des3-cbc-sha1 */, 12 /* hmac-sha1-des3 */ }, + + /* per draft-ietf-krb-wg-crypto-02.txt */ + { 16 /* des3-cbc-sha1-kd */, 12 /* hmac-sha1-des3-kd */ }, + + /* per draft-raeburn-krb-rijndael-krb-02.txt */ + { 17 /* aes128-cts-hmac-sha1-96 */, 10 /* hmac-sha1-96-aes128 */ }, + { 18 /* aes256-cts-hmac-sha1-96 */, 11 /* hmac-sha1-96-aes256 */ }, + + /* per draft-brezak-win2k-krb-rc4-hmac-04.txt */ + { 23 /* rc4-hmac */, -138 /* hmac-md5 */ }, + { 24 /* rc4-hmac-exp */, -138 /* hmac-md5 */ }, +}; +#define N_CKSUM_MAP (sizeof(cksum_map) / sizeof(struct cksum_map_s)) + +Code_t Z_krb5_lookup_cksumtype(krb5_enctype e, krb5_cksumtype *c) +{ + int i; + + for (i = 0; i < N_CKSUM_MAP; i++) { + if (cksum_map[i].e == e) { + *c = cksum_map[i].c; + return ZERR_NONE; + } + } + return KRB5_PROG_ETYPE_NOSUPP; +} +#endif /* HAVE_KRB5 */ + char __Zephyr_realm[REALM_SZ]; #ifdef Z_DEBUG @@ -58,6 +109,8 @@ void *__Z_debug_print_closure; static int Z_AddField __P((char **ptr, char *field, char *end)); static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind)); +static Code_t Z_ZcodeFormatRawHeader __P((ZNotice_t *, char *, int, int *, char **, + int *, char **, char **, int cksumtype)); /* Find or insert uid in the old uids buffer. The buffer is a sorted * circular queue. We make the assumption that most packets arrive in @@ -633,6 +686,52 @@ Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine) return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine); } +Code_t Z_NewFormatHeader(notice, buffer, buffer_len, len, cert_routine) + ZNotice_t *notice; + char *buffer; + int buffer_len; + int *len; + Z_AuthProc cert_routine; +{ + Code_t retval; + static char version[BUFSIZ]; /* default init should be all \0 */ + struct sockaddr_in name; + struct timeval tv; + int namelen = sizeof(name); + + if (!notice->z_sender) + notice->z_sender = ZGetSender(); + + if (notice->z_port == 0) { + if (ZGetFD() < 0) { + retval = ZOpenPort((u_short *)0); + if (retval != ZERR_NONE) + return (retval); + } + retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen); + if (retval != 0) + return (retval); + notice->z_port = name.sin_port; + } + + notice->z_multinotice = ""; + + (void) gettimeofday(&tv, (struct timezone *)0); + notice->z_uid.tv.tv_sec = htonl((u_long) tv.tv_sec); + notice->z_uid.tv.tv_usec = htonl((u_long) tv.tv_usec); + + (void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr)); + + notice->z_multiuid = notice->z_uid; + + if (!version[0]) + (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR, + ZVERSIONMINOR); + notice->z_version = version; + + return Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine); +} + Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine) ZNotice_t *notice; char *buffer; @@ -652,6 +751,210 @@ Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine) return ((*cert_routine)(notice, buffer, buffer_len, len)); } +Code_t Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine) + ZNotice_t *notice; + char *buffer; + int buffer_len; + int *len; + Z_AuthProc cert_routine; +{ + if (!cert_routine) { + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + notice->z_checksum = 0; + return (Z_FormatRawHeader(notice, buffer, buffer_len, + len, NULL, NULL)); + } + + return ((*cert_routine)(notice, buffer, buffer_len, len)); +} + +Code_t Z_NewFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend) + ZNotice_t *notice; + char *buffer; + int buffer_len; + int *hdr_len; + char **cksum_start; + int *cksum_len; + char **cstart, **cend; +{ + return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend, 0)); +} + +Code_t Z_AsciiFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend) + ZNotice_t *notice; + char *buffer; + int buffer_len; + int *hdr_len; + char **cksum_start; + int *cksum_len; + char **cstart, **cend; +{ + return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend, 1)); +} + +static Code_t Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, cksum_start, + cksum_len, cstart, cend, cksumstyle) + ZNotice_t *notice; + char *buffer; + int buffer_len; + int *hdr_len; + char **cksum_start; + int *cksum_len; + char **cstart, **cend; + int cksumstyle; +{ + static char version_nogalaxy[BUFSIZ]; /* default init should be all \0 */ + char newrecip[BUFSIZ]; + char *ptr, *end; + int i; + + if (!notice->z_class) + notice->z_class = ""; + + if (!notice->z_class_inst) + notice->z_class_inst = ""; + + if (!notice->z_opcode) + notice->z_opcode = ""; + + if (!notice->z_recipient) + notice->z_recipient = ""; + + if (!notice->z_default_format) + notice->z_default_format = ""; + + ptr = buffer; + end = buffer+buffer_len; + + if (cksum_start) + *cksum_start = ptr; + + (void) sprintf(version_nogalaxy, "%s%d.%d", ZVERSIONHDR, + ZVERSIONMAJOR, ZVERSIONMINOR); + + notice->z_version = version_nogalaxy; + + if (Z_AddField(&ptr, version_nogalaxy, end)) + return (ZERR_HEADERLEN); + + if (ZMakeAscii32(ptr, end-ptr, + Z_NUMFIELDS + notice->z_num_other_fields) + == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid, + sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (Z_AddField(&ptr, notice->z_ascii_authent, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_class, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_class_inst, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_opcode, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_sender, end)) + return (ZERR_HEADERLEN); + if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) { + if (Z_AddField(&ptr, notice->z_recipient, end)) + return (ZERR_HEADERLEN); + } + else { + if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 > + sizeof(newrecip)) + return (ZERR_HEADERLEN); + (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm); + if (Z_AddField(&ptr, newrecip, end)) + return (ZERR_HEADERLEN); + } + if (Z_AddField(&ptr, notice->z_default_format, end)) + return (ZERR_HEADERLEN); + + /* copy back the end pointer location for crypto checksum */ + if (cstart) + *cstart = ptr; + if (cksumstyle == 1) { + if (Z_AddField(&ptr, notice->z_ascii_checksum, end)) + return (ZERR_HEADERLEN); + } else { +#ifdef xZCODE_K4SUM + if (ZMakeZcode32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) + return ZERR_HEADERLEN; +#else + if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); +#endif + ptr += strlen(ptr)+1; + } + if (cend) + *cend = ptr; + + if (Z_AddField(&ptr, notice->z_multinotice, end)) + return (ZERR_HEADERLEN); + + if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid, + sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + for (i=0;i<notice->z_num_other_fields;i++) + if (Z_AddField(&ptr, notice->z_other_fields[i], end)) + return (ZERR_HEADERLEN); + + if (cksum_len) + *cksum_len = ptr-*cksum_start; + + *hdr_len = ptr-buffer; + +#if 0 + { + printf("Z_FormatRawHeader output:\n"); + for (i = 0; i < *hdr_len; i += 16) { + int i2; + printf("%03d:", i); + for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++) + printf(" %02x", buffer[i2] & 0xff); + for (; i2 < i+16; i2++) + printf(" "); + printf(" "); + for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++) + printf("%c", + ((buffer[i2] > 0 && buffer[i2] < 127 && isprint(buffer[i2])) + ? buffer[i2] + : '.')); + printf("\n"); + } + } +#endif + + return (ZERR_NONE); +} + Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend) ZNotice_t *notice; char *buffer; @@ -742,7 +1045,7 @@ Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend) if (cstart) *cstart = ptr; if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) - return (ZERR_HEADERLEN); + return (ZERR_HEADERLEN); ptr += strlen(ptr)+1; if (cend) *cend = ptr; @@ -995,3 +1298,210 @@ void ZSetDebug(proc, arg) } #endif /* Z_DEBUG */ +#ifdef HAVE_KRB5 +Code_t Z_Checksum(krb5_data *cksumbuf, krb5_keyblock *keyblock, + krb5_cksumtype cksumtype, + char **asn1_data, int *asn1_len) { + krb5_error_code result; + char *data; + int len; +#if HAVE_KRB5_C_MAKE_CHECKSUM + krb5_checksum checksum; +#else + Checksum checksum; + krb5_crypto cryptctx; +#endif + +#if HAVE_KRB5_C_MAKE_CHECKSUM + /* Create the checksum -- MIT crypto API */ + result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype, + keyblock, Z_KEYUSAGE_CLT_CKSUM, + cksumbuf, &checksum); + if (result) + return result; + /* HOLDING: checksum */ + + data = checksum.contents; + len = checksum.length; +#else + /* Create the checksum -- heimdal crypto API */ + result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, + &cryptctx); + if (result) + return result; + + /* HOLDING: cryptctx */ + result = krb5_create_checksum(Z_krb5_ctx, cryptctx, + Z_KEYUSAGE_CLT_CKSUM, cksumtype, + cksumbuf->data, cksumbuf->length, + &checksum); + krb5_crypto_destroy(Z_krb5_ctx, cryptctx); + if (result) + return result; + + len = checksum.checksum.length; + data = checksum.checksum.data; + /* HOLDING: checksum */ +#endif + + *asn1_data = malloc(len); + if (*asn1_data == NULL) + return errno; + memcpy(*asn1_data, data, len); + *asn1_len = len; + +#if HAVE_KRB5_C_MAKE_CHECKSUM + krb5_free_checksum_contents(Z_krb5_ctx, &checksum); +#else + free_Checksum(&checksum); +#endif + + return 0; +} + +Code_t +Z_InsertZcodeChecksum(krb5_keyblock *keyblock, ZNotice_t *notice, + char *buffer, char *cksum_start, int cksum_len, + char *cstart, char *cend, int buffer_len, + int *length_adjust) +{ + int plain_len; /* length of part not to be checksummed */ + int cksum0_len; /* length of part before checksum */ + int cksum1_len; /* length of part after checksum */ + krb5_data cksumbuf; + krb5_data cksum; + char *key_data; + int key_len; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + Code_t result; + + key_data = Z_keydata(keyblock); + key_len = Z_keylen(keyblock); + result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (result) + return (ZAUTH_FAILED); + + /* Assemble the things to be checksummed */ + plain_len = cksum_start - buffer; + cksum0_len = cstart - cksum_start; + cksum1_len = (cksum_start + cksum_len) - cend; + memset(&cksumbuf, 0, sizeof(cksumbuf)); + cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len; + cksumbuf.data = malloc(cksumbuf.length); + if (!cksumbuf.data) + return ENOMEM; + memcpy(cksumbuf.data, cksum_start, cksum0_len); + memcpy(cksumbuf.data + cksum0_len, cend, cksum1_len); + memcpy(cksumbuf.data + cksum0_len + cksum1_len, + notice->z_message, notice->z_message_len); + /* compute the checksum */ + result = Z_Checksum(&cksumbuf, keyblock, cksumtype, + (char **)&cksum.data, &cksum.length); + if (result) { + free(cksumbuf.data); + return result; + } + + /* + * OK.... we can zcode to a space starting at 'cstart', + * with a length of buffer_len - (plain_len + cksum_len). + * Then we tack on the end part, which is located at + * cksumbuf.data + cksum0_len and has length cksum1_len + */ + + result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len), + cksum.data, cksum.length); + free(cksum.data); + if (!result) { + int zcode_len = strlen(cstart) + 1; + memcpy(cstart + zcode_len, cksumbuf.data + cksum0_len, cksum1_len); + *length_adjust = zcode_len - cksum_len + (cksum0_len + cksum1_len); + } + free(cksumbuf.data); + return result; +} + +Code_t +Z_ExtractEncCksum(krb5_keyblock *keyblock, krb5_enctype *enctype, + krb5_cksumtype *cksumtype) { +#if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + *enctype = keyblock->enctype; + return Z_krb5_lookup_cksumtype(*enctype, cksumtype); +#else + unsigned int len; + ENCTYPE *val; + int i = 0; + Code_t result; + + result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype, + &len, &val); + if (result) + return result; + + do { + if (i == len) break; + result = Z_krb5_lookup_cksumtype(val[i], cksumtype); + i++; + } while (result != 0); + + if (result) + return result; + + *enctype = val[i-1]; +#endif + return 0; +} +#endif + +#ifdef HAVE_KRB5 +/* returns 0 if invalid or losing, 1 if valid, *sigh* */ +int +Z_krb5_verify_cksum(krb5_keyblock *keyblock, krb5_data *cksumbuf, + krb5_cksumtype cksumtype, char *asn1_data, + int asn1_len) { + krb5_error_code result; +#if HAVE_KRB5_C_MAKE_CHECKSUM + krb5_checksum checksum; + krb5_boolean valid; +#else + krb5_crypto cryptctx; + Checksum checksum; + size_t xlen; +#endif + + memset(&checksum, 0, sizeof(checksum)); +#if HAVE_KRB5_C_MAKE_CHECKSUM + /* Verify the checksum -- MIT crypto API */ + checksum.length = asn1_len; + checksum.contents = asn1_data; + checksum.checksum_type = cksumtype; + result = krb5_c_verify_checksum(Z_krb5_ctx, + keyblock, Z_KEYUSAGE_SRV_CKSUM, + cksumbuf, &checksum, &valid); + if (!result && valid) + return 1; + else + return 0; +#else + checksum.checksum.length = asn1_len; + checksum.checksum.data = asn1_data; + checksum.cksumtype = cksumtype; + + result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, &cryptctx); + if (result) + return result; + + /* HOLDING: cryptctx */ + result = krb5_verify_checksum(Z_krb5_ctx, cryptctx, + Z_KEYUSAGE_SRV_CKSUM, + cksumbuf->data, cksumbuf->length, + &checksum); + krb5_crypto_destroy(Z_krb5_ctx, cryptctx); + if (result) + return 0; + else + return 1; +#endif +} +#endif |