From c72e317e5cff5e0c754934e5148ffaf54917d0df Mon Sep 17 00:00:00 2001 From: kcr Date: Fri, 30 May 2003 18:13:33 +0000 Subject: [PATCH] more from the krb5-interrealm patches git-svn-id: svn://svn.1ts.org/debian/branches/athena-update-branch@174 cbed1d16-5ef5-0310-b6a1-d4a37b08ba1f --- zephyr/lib/ZCkZAut.c | 280 ++++++++++++++++++++++++++++++++++++++++ zephyr/lib/ZMakeZcode.c | 80 ++++++++++++ zephyr/lib/ZReadZcode.c | 64 +++++++++ 3 files changed, 424 insertions(+) create mode 100644 zephyr/lib/ZCkZAut.c create mode 100644 zephyr/lib/ZMakeZcode.c create mode 100644 zephyr/lib/ZReadZcode.c diff --git a/zephyr/lib/ZCkZAut.c b/zephyr/lib/ZCkZAut.c new file mode 100644 index 0000000..c0f9628 --- /dev/null +++ b/zephyr/lib/ZCkZAut.c @@ -0,0 +1,280 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCheckAuthentication function. + * + * Created by: Robert French + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ +/* $Header$ */ + +#ifndef lint +static char rcsid_ZCheckAuthentication_c[] = + "$Zephyr: /mit/zephyr/src/lib/RCS/ZCheckAuthentication.c,v 1.14 89/03/24 14:17:38 jtkohl Exp Locker: raeburn $"; +#endif + +#include + +#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. + If it doesn't look authentic, return 0 + + When not using Kerberos, return true if the notice claims to be authentic. + Only used by clients; the server uses its own routine. + */ +Code_t ZCheckZcodeAuthentication(notice, from) + ZNotice_t *notice; + struct sockaddr_in *from; +{ + /* 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); + + if (!notice->z_ascii_checksum) + return (ZAUTH_NO); + +#ifdef HAVE_KRB5 + { + krb5_error_code result; + krb5_ccache ccache; + krb5_creds creds_in, *creds; + krb5_keyblock *keyblock; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + krb5_data cksumbuf; +#if HAVE_KRB5_C_MAKE_CHECKSUM + krb5_checksum checksum; + krb5_boolean valid; +#else + krb5_crypto cryptctx; + Checksum checksum; + size_t xlen; +#endif + char *cksum0_base, *cksum1_base, *cksum2_base; + char *svcinst, *x, *y; + char *asn1_data, *key_data; + int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len; + /* Get a pointer to the default ccache. We don't need to free this. */ + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (result) + return (ZAUTH_NO); + + /* GRRR. There's no allocator or constructor for krb5_creds */ + /* GRRR. It would be nice if this API were documented at all */ + memset(&creds_in, 0, sizeof(creds_in)); + + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client); + if (result) { + krb5_cc_close(Z_krb5_ctx, ccache); + return(result); + } + + /* construct the service principal */ + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(__Zephyr_realm), + __Zephyr_realm, + SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0); + if (result) { + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); + krb5_cc_close(Z_krb5_ctx, ccache); + return (ZAUTH_NO); + } + /* HOLDING: creds_in.server */ + + /* look up or get the credentials we need */ + result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache, + &creds_in, &creds); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */ + krb5_cc_close(Z_krb5_ctx, ccache); + + if (result) + return (ZAUTH_NO); + /* HOLDING: creds */ + + /* Figure out what checksum type to use */ +#if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + keyblock = &creds->keyblock; + key_data = keyblock->contents; + key_len = keyblock->length; + enctype = keyblock->enctype; + result = Z_krb5_lookup_cksumtype(enctype, &cksumtype); + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (ZAUTH_FAILED); + } +#else + keyblock = &creds->session; + key_data = keyblock->keyvalue.data; + key_len = keyblock->keyvalue.length; + { + unsigned int len; + ENCTYPE *val; + int i = 0; + + result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype, + &len, &val); + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (ZAUTH_FAILED); + } + + do { + if (i == len) break; + result = Z_krb5_lookup_cksumtype(val[i], &cksumtype); + i++; + } while (result != 0); + + if (result) { + krb5_free_creds(Z_krb5_ctx, creds); + return (ZAUTH_FAILED); + } + enctype = val[i-1]; + } +#endif + /* HOLDING: creds */ + + /* Assemble the things to be checksummed */ + /* first part is from start of packet through z_default_format: + * - z_version + * - z_num_other_fields + * - z_kind + * - z_uid + * - z_port + * - z_auth + * - z_authent_len + * - z_ascii_authent + * - z_class + * - z_class_inst + * - z_opcode + * - z_sender + * - z_recipient + * - z_default_format + */ + cksum0_base = notice->z_packet; + x = notice->z_default_format; + cksum0_len = x + strlen(x) + 1 - cksum0_base; + /* second part is from z_multinotice through other fields: + * - z_multinotice + * - z_multiuid + * - z_other_fields[] + */ + cksum1_base = notice->z_multinotice; + if (notice->z_num_other_fields) + x = notice->z_other_fields[notice->z_num_other_fields]; + else + x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */ + cksum1_len = x + strlen(x) + 1 - cksum1_base; + + /* last part is the message body */ + cksum2_base = notice->z_message; + cksum2_len = notice->z_message_len; + + if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') && + key_len == 8 && + (enctype == ENCTYPE_DES_CBC_CRC || + enctype == ENCTYPE_DES_CBC_MD4 || + enctype == ENCTYPE_DES_CBC_MD5)) { + /* try old-format checksum (covers cksum0 only) */ + + ZChecksum_t our_checksum; + + our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0, + key_data); + if (our_checksum == notice->z_checksum) { + krb5_free_creds(Z_krb5_ctx, creds); + return ZAUTH_YES; + } + } + /* HOLDING: creds */ + + cksumbuf.length = cksum0_len + cksum1_len + cksum2_len; + cksumbuf.data = malloc(cksumbuf.length); + if (!cksumbuf.data) { + krb5_free_creds(Z_krb5_ctx, creds); + return ZAUTH_NO; + } + /* HOLDING: creds, cksumbuf.data */ + + memcpy(cksumbuf.data, cksum0_base, cksum0_len); + memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len); + memcpy(cksumbuf.data + cksum0_len + cksum1_len, + cksum2_base, cksum2_len); + + /* decode zcoded checksum */ + /* The encoded form is always longer than the original */ + asn1_len = strlen(notice->z_ascii_checksum) + 1; + asn1_data = malloc(asn1_len); + if (!asn1_data) { + krb5_free_creds(Z_krb5_ctx, creds); + free(cksumbuf.data); + return ZAUTH_FAILED; + } + /* HOLDING: creds, asn1_data, cksumbuf.data */ + result = ZReadZcode(notice->z_ascii_checksum, + asn1_data, asn1_len, &asn1_len); + if (result != ZERR_NONE) { + krb5_free_creds(Z_krb5_ctx, creds); + free(asn1_data); + free(cksumbuf.data); + return ZAUTH_FAILED; + } + /* HOLDING: creds, asn1_data, cksumbuf.data */ + +#if HAVE_KRB5_C_MAKE_CHECKSUM + /* Verify the checksum -- MIT crypto API */ + memset(&checksum, 0, sizeof(checksum)); + 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); + free(asn1_data); + krb5_free_creds(Z_krb5_ctx, creds); + free(cksumbuf.data); + if (!result && valid) + return (ZAUTH_YES); + else + return (ZAUTH_FAILED); +#else + checksum.checksum.length = asn1_len; + checksum.checksum.data = asn1_data; + checksum.cksumtype = cksumtype; + /* HOLDING: creds, asn1_data, cksumbuf.data */ + + result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx); + krb5_free_creds(Z_krb5_ctx, creds); + if (result) { + free(asn1_data); + free(cksumbuf.data); + return result; + } + /* HOLDING: cryptctx, checksum, cksumbuf.data */ + result = krb5_verify_checksum(Z_krb5_ctx, cryptctx, + Z_KEYUSAGE_SRV_CKSUM, + cksumbuf.data, cksumbuf.length, + &checksum); + krb5_crypto_destroy(Z_krb5_ctx, cryptctx); + free(asn1_data); + free(cksumbuf.data); + if (result) + return (ZAUTH_FAILED); + else + return (ZAUTH_YES); +#endif + } +#endif /* HAVE_KRB5 */ + return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO); +} diff --git a/zephyr/lib/ZMakeZcode.c b/zephyr/lib/ZMakeZcode.c new file mode 100644 index 0000000..6229bef --- /dev/null +++ b/zephyr/lib/ZMakeZcode.c @@ -0,0 +1,80 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZMakeZcode function. + * + * Created by: Jeffrey Hutzelman + * + * $Id$ + * + * Copyright (c) 1987, 2002 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#ifndef lint +static const char rcsid_ZMakeZcode_c[] = "$Id$"; +#endif + +Code_t ZMakeZcode32(ptr, len, val) + char *ptr; + int len; + unsigned long val; +{ + unsigned char buf[4]; + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = val & 0xff; + return ZMakeZcode(ptr, len, buf, 4); +} + +Code_t ZMakeZcode(ptr, len, field, num) + register char *ptr; + int len; + unsigned char *field; + int num; +{ + int i; + + /* + * This optimistic check lets us discover quickly if the buffer + * is not even large enough to hold the field without escapes. + * It also insures we'll have space for the leading 'Z' and the + * trailing NUL. Note that this does _not_ remove the need for + * checking length as we encode. + */ + if (len < num + 2) + return ZERR_FIELDLEN; + *ptr++ = 'Z'; + --len; + for (i=0;i +#include + + +Code_t +ZReadAsciiOrZcode(char *buf, int buflen, unsigned char *data, int datalen) +{ + if (buf[0] == 'Z') + return ZReadZcode(buf, buflen, data, datalen); + else + return ZReadAscii(buf, buflen, data, datalen); +} + +Code_t ZReadZcode32(ptr, value_ptr) + unsigned char *ptr; + unsigned long *value_ptr; +{ + abort(); +} + +Code_t ZReadZcode(ptr, field, max, len) + unsigned char *ptr; + unsigned char *field; + int max; + int *len; +{ + int n = 0; + + if (*ptr++ != 'Z') + return ZERR_BADFIELD; + + while (*ptr && n < max) { + if (*ptr == 0xff) { + ptr++; + switch (*ptr++) { + case 0xf0: field[n++] = 0x00; continue; + case 0xf1: field[n++] = 0xff; continue; + default: return ZERR_BADFIELD; + } + } else { + field[n++] = *ptr++; + } + } + if (*ptr) + return (ZERR_BADFIELD); + *len = n; + return (ZERR_NONE); +} -- 2.45.2