From a36a075433165839ec7a02379ad83c03e08498a5 Mon Sep 17 00:00:00 2001 From: Kenneth G Raeburn Date: Tue, 13 Nov 1990 12:02:59 +0000 Subject: C++ conversion and lots of modifications from summer & fall work --- server/kstuff.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 236 insertions(+), 23 deletions(-) (limited to 'server/kstuff.c') diff --git a/server/kstuff.c b/server/kstuff.c index 1c12328..ca4ab3f 100644 --- a/server/kstuff.c +++ b/server/kstuff.c @@ -14,16 +14,17 @@ */ #ifndef lint -static char rcsid_kstuff_c[] = "$Header$"; -#endif lint +static const char rcsid_kstuff_c[] = "$Header$"; +#endif #include "zserver.h" -#include +extern "C" { #include #include - -char *index(); +#include +#include +} /* @@ -34,12 +35,12 @@ char *index(); * the value of rd_ap_req() applied to the ticket. */ int -GetKerberosData(fd, haddr, kdata, service, srvtab) - int fd; /* file descr. to read from */ - struct in_addr haddr; /* address of foreign host on fd */ - AUTH_DAT *kdata; /* kerberos data (returned) */ - char *service; /* service principal desired */ - char *srvtab; /* file to get keys from */ +GetKerberosData(int fd, struct in_addr haddr, AUTH_DAT *kdata, char *service, char *srvtab) + /* file descr. to read from */ + /* address of foreign host on fd */ + /* kerberos data (returned) */ + /* service principal desired */ + /* file to get keys from */ { char p[20]; @@ -90,37 +91,41 @@ GetKerberosData(fd, haddr, kdata, service, srvtab) * get the ticket and write it to the file descriptor */ -SendKerberosData(fd, ticket, service, host) -int fd; /* file descriptor to write onto */ -KTEXT ticket; /* where to put ticket (return) */ -char *service, *host; /* service name, foreign host */ +SendKerberosData(int fd, KTEXT ticket, char *service, char *host) + /* file descriptor to write onto */ + /* where to put ticket (return) */ + /* service name, foreign host */ { int rem; char p[32]; char krb_realm[REALM_SZ]; + static int failed = 0; int written; rem=KSUCCESS; + if (failed) abort(); + rem = krb_get_lrealm(krb_realm,1); if (rem != KSUCCESS) - return rem + ERROR_TABLE_BASE_krb; + return rem + krb_err_base; rem = krb_mk_req( ticket, service, host, krb_realm, (u_long)0 ); if (rem != KSUCCESS) - return rem + ERROR_TABLE_BASE_krb; + return rem + krb_err_base; (void) sprintf(p,"%d ",ticket->length); - if ((written = write(fd, p, strlen(p))) != strlen(p)) + int size_to_write = strlen (p); + if ((written = write(fd, p, size_to_write)) != size_to_write) if (written < 0) return errno; else - return(ZSRV_PKSHORT); + return ZSRV_PKSHORT; if ((written = write(fd, (caddr_t) (ticket->dat), ticket->length)) != ticket->length) if (written < 0) return errno; else - return(ZSRV_PKSHORT); + return ZSRV_PKSHORT; return 0; } @@ -130,8 +135,216 @@ static char tkt_file[] = ZEPHYR_TKFILE; /* Hack to replace the kerberos library's idea of the ticket file with our idea */ char * -tkt_string() +tkt_string(void) { - return(tkt_file); + return tkt_file; +} + +/* 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 (looks-authentic-p) + */ +struct AuthEnt { + const char *data; + int len; + ZString principal; +#ifndef NOENCRYPTION + C_Block session_key; +#endif + long expire_time; + sockaddr_in from; + AuthEnt () { + data = 0; + } + void expire () { + if (data) { + zfree ((void *) data, strlen (data) + 1); + data = 0; + } + len = 0; + expire_time = 0; + principal = 0; + } +}; + +#define HASH_SIZE_1 513 +#define HASH_SIZE_2 3 +static AuthEnt auth_cache[HASH_SIZE_1][HASH_SIZE_2]; + +static int auth_hash (const char *str, int len) { + unsigned long hash; + if (len <= 3) + return str[0]; + hash = str[len - 1] * 256 + str[len-2] * 16 + str[len-3]; + hash %= HASH_SIZE_1; + return hash; +} + +static int check_cache (ZNotice_t *notice, sockaddr_in *from) { + const char *str = notice->z_ascii_authent; + int len = strlen (str), i; + unsigned int hash = 0; + unsigned long now = time(0); + AuthEnt *a; + + hash = auth_hash (str, len); + for (i = 0; i < HASH_SIZE_2; i++) { + a = &auth_cache[hash][i]; + if (!a->data) { + continue; + } + if (now > a->expire_time) { + a->expire (); + continue; + } + if (len != a->len) { + continue; + } + if (strcmp (notice->z_ascii_authent, a->data)) { + continue; + } + /* Okay, we know we've got the same authenticator. */ + if (strcmp (notice->z_sender, a->principal.value ())) { + return ZAUTH_FAILED; + } + if (from->sin_addr.s_addr != a->from.sin_addr.s_addr) { + return ZAUTH_FAILED; + } +#ifndef NOENCRYPTION + bcopy (a->session_key, __Zephyr_session, sizeof (C_Block)); +#endif + return ZAUTH_YES; + } + return ZAUTH_NO; +} + +void add_to_cache (const AuthEnt& a) { + int len = a.len, i, j; + AuthEnt *entries; + unsigned int hash = 0; + + hash = auth_hash (a.data, len); + entries = auth_cache[hash]; + j = 0; + for (i = 0; i < HASH_SIZE_2; i++) { + if (entries[i].data == 0) { + j = i; + goto ok; + } + if (i == j) + continue; + if (entries[i].expire_time < entries[j].expire_time) + j = i; + } +ok: + if (entries[j].data) + entries[j].expire (); + entries[j] = a; } -#endif KERBEROS + +int ZCheckAuthentication(ZNotice_t *notice, sockaddr_in *from) { + int result; + char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4]; + KTEXT_ST authent; + AUTH_DAT dat; + ZChecksum_t our_checksum; + CREDENTIALS cred; + AuthEnt a; + int auth_len = 0; + + if (!notice->z_auth) { + return (ZAUTH_NO); + } + + if (__Zephyr_server) { + + if (notice->z_authent_len <= 0) { /* bogus length */ +#if 1 + syslog (LOG_DEBUG, "z_authent_len = %d -> AUTH_FAILED", + notice->z_authent_len); +#endif + return(ZAUTH_FAILED); + } + + auth_len = strlen (notice->z_ascii_authent); + if (ZReadAscii(notice->z_ascii_authent, auth_len + 1, + (unsigned char *)authent.dat, + notice->z_authent_len) == ZERR_BADFIELD) { +#if 1 + syslog (LOG_DEBUG, "ZReadAscii failed (len:%s) -> AUTH_FAILED", + error_message (ZERR_BADFIELD)); +#endif + return (ZAUTH_FAILED); + } + authent.length = notice->z_authent_len; + result = check_cache (notice, from); + if (result != ZAUTH_NO) + return result; + + /* Well, it's not in the cache... decode it. */ + result = krb_rd_req(&authent, SERVER_SERVICE, + SERVER_INSTANCE, from->sin_addr.s_addr, + &dat, SERVER_SRVTAB); + if (result == RD_AP_OK) { + bcopy ((void *) dat.session, (void *) a.session_key, + sizeof(C_Block)); + bcopy((char *)dat.session, (char *)__Zephyr_session, + sizeof(C_Block)); + (void) sprintf(srcprincipal, "%s%s%s@%s", dat.pname, + dat.pinst[0]?".":"", dat.pinst, dat.prealm); + if (strcmp(srcprincipal, notice->z_sender)) { +#if 1 + syslog (LOG_DEBUG, "principal mismatch->AUTH_FAILED"); +#endif + return (ZAUTH_FAILED); + } + a.principal = srcprincipal; + a.expire_time = time (0) + 5 * 60; /* add 5 minutes */ + a.from = *from; + char *s = (char *) zalloc (auth_len + 1); + strcpy (s, notice->z_ascii_authent); + a.data = s; + a.len = auth_len; + add_to_cache (a); + return(ZAUTH_YES); + } else { +#if 1 + syslog (LOG_DEBUG, "krb_rd_req failed->AUTH_FAILED: %s", + krb_err_txt [result]); +#endif + return (ZAUTH_FAILED); /* didn't decode correctly */ + } + } + + if (result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, + __Zephyr_realm, &cred)) { +#if 1 + syslog (LOG_DEBUG, "krb_get_cred failed->AUTH_NO: %s", + krb_err_txt [result]); +#endif + return (ZAUTH_NO); + } + +#ifdef NOENCRYPTION + our_checksum = 0; +#else + our_checksum = (ZChecksum_t)des_quad_cksum(notice->z_packet, NULL, + notice->z_default_format+ + strlen(notice->z_default_format)+1- + notice->z_packet, 0, cred.session); +#endif + /* if mismatched checksum, then the packet was corrupted */ + if (our_checksum == notice->z_checksum) { + return ZAUTH_YES; + } + else { +#if 1 + syslog (LOG_DEBUG, "checksum mismatch->AUTH_FAILED"); +#endif + return ZAUTH_FAILED; + } +} +#endif /* KERBEROS */ -- cgit v1.2.3