summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Karl Ramm <kcr@mit.edu>2007-12-25 00:56:08 +0000
committerGravatar Karl Ramm <kcr@mit.edu>2007-12-25 00:56:08 +0000
commit1a0e03eb19998ab496a6ea845ff2c42d9a02df0b (patch)
tree29b47c8532e1f1678063fbb1b851ee4208134626 /lib
parent3f120f880be9ae9aa1612ddc2412e9acb9a8e85e (diff)
applied athena-update-branch patch
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.in3
-rw-r--r--lib/ZCkAuth.c36
-rw-r--r--lib/ZFmtAuth.c70
-rw-r--r--lib/ZFmtNotice.c26
-rw-r--r--lib/ZFmtSmRaw.c23
-rw-r--r--lib/ZGetSender.c45
-rw-r--r--lib/ZInit.c45
-rw-r--r--lib/ZMkAuth.c188
-rw-r--r--lib/ZParseNot.c21
-rw-r--r--lib/Zinternal.c518
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(&notice);
}
+#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(&notice->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 *)&notice->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 *)&notice->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