From c57cb726d8889f9bafa558698d98376485900034 Mon Sep 17 00:00:00 2001 From: Karl Ramm Date: Mon, 27 Jul 2009 05:31:53 +0000 Subject: Refactor ZCheckRealmAuthentication into ZCheckSrvAuthentication. (also fiddle around with what krb4 checksums are available in krb5-only land) --- server/dispatch.c | 6 +- server/kstuff.c | 371 +++++------------------------------------------------- server/zserver.h | 3 +- 3 files changed, 35 insertions(+), 345 deletions(-) (limited to 'server') diff --git a/server/dispatch.c b/server/dispatch.c index 10b6296..888790e 100644 --- a/server/dispatch.c +++ b/server/dispatch.c @@ -214,11 +214,7 @@ handle_packet(void) authentic = ZAUTH_YES; } else { realm = realm_which_realm(whence); - if (realm) { - authentic = ZCheckRealmAuthentication(&new_notice, whence, - realm->name); - } else - authentic = ZCheckSrvAuthentication(&new_notice, whence); + authentic = ZCheckSrvAuthentication(&new_notice, whence, realm ? realm->name : NULL); } message_notices.val++; diff --git a/server/kstuff.c b/server/kstuff.c index fcb3218..3677a80 100644 --- a/server/kstuff.c +++ b/server/kstuff.c @@ -21,10 +21,10 @@ static const char rcsid_kstuff_c[] = "$Id$"; #endif #if defined(HAVE_KRB4) && defined(HAVE_KRB5) -static ZChecksum_t compute_checksum(ZNotice_t *, C_Block); static Code_t ZCheckAuthentication4(ZNotice_t *notice, struct sockaddr_in *from); #endif #ifdef HAVE_KRB5 +static ZChecksum_t compute_checksum(ZNotice_t *, unsigned char *); static ZChecksum_t compute_rlm_checksum(ZNotice_t *, unsigned char *); #endif @@ -240,329 +240,10 @@ SendKrb5Data(int fd, krb5_data *data) { } #endif -Code_t -ZCheckRealmAuthentication(ZNotice_t *notice, - struct sockaddr_in *from, - char *realm) -{ -#ifdef HAVE_KRB5 - char *authbuf; - char rlmprincipal[MAX_PRINCIPAL_SIZE]; - krb5_principal princ; - krb5_data packet; - krb5_ticket *tkt; - char *name; - krb5_error_code result; - krb5_principal server; - krb5_keytab keytabid = 0; - krb5_auth_context authctx; - krb5_keyblock *keyblock; - krb5_enctype enctype; - krb5_cksumtype cksumtype; - krb5_data cksumbuf; - int valid; - char *cksum0_base, *cksum1_base = NULL, *cksum2_base; - char *x; - unsigned char *asn1_data; - unsigned char *key_data; - int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0; - krb5_flags acflags; -#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER - krb5_authenticator *authenticator; -#define KRB5AUTHENT authenticator -#else - krb5_authenticator authenticator; -#define KRB5AUTHENT &authenticator -#endif - int len; - - if (!notice->z_auth) - return ZAUTH_NO; - - /* Check for bogus authentication data length. */ - if (notice->z_authent_len <= 0) - return ZAUTH_FAILED; - - len = strlen(notice->z_ascii_authent)+1; - authbuf = malloc(len); - - /* Read in the authentication data. */ - if (ZReadZcode((unsigned char *)notice->z_ascii_authent, - (unsigned char *)authbuf, - len, &len) == ZERR_BADFIELD) { - return ZAUTH_FAILED; - } - - (void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE, - SERVER_INSTANCE, realm); - - packet.length = len; - packet.data = authbuf; - - result = krb5_kt_resolve(Z_krb5_ctx, - keytab_file, &keytabid); - if (result) { - free(authbuf); - return (result); - } - - /* HOLDING: authbuf, keytabid */ - /* Create the auth context */ - result = krb5_auth_con_init(Z_krb5_ctx, &authctx); - if (result) { - krb5_kt_close(Z_krb5_ctx, keytabid); - free(authbuf); - return (result); - } - - result = krb5_auth_con_getflags(Z_krb5_ctx, authctx, &acflags); - if (result) { - krb5_kt_close(Z_krb5_ctx, keytabid); - free(authbuf); - return (result); - } - - acflags &= ~KRB5_AUTH_CONTEXT_DO_TIME; - - result = krb5_auth_con_setflags(Z_krb5_ctx, authctx, acflags); - if (result) { - krb5_kt_close(Z_krb5_ctx, keytabid); - free(authbuf); - return (result); - } - - /* HOLDING: authbuf, authctx */ - result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm), - __Zephyr_realm, SERVER_SERVICE, - SERVER_INSTANCE, NULL); - if (!result) { - result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server, - keytabid, NULL, &tkt); - krb5_free_principal(Z_krb5_ctx, server); - } - krb5_kt_close(Z_krb5_ctx, keytabid); - - if (result) { - if (result == KRB5KRB_AP_ERR_REPEAT) { - syslog(LOG_DEBUG, "ZCheckRealmAuthentication: k5 auth failed: %s", - error_message(result)); - } else { - syslog(LOG_WARNING,"ZCheckRealmAuthentication: k5 auth failed: %s", - error_message(result)); - } - free(authbuf); - krb5_auth_con_free(Z_krb5_ctx, authctx); - return ZAUTH_FAILED; - } - - /* HOLDING: authbuf, authctx, tkt */ - - if (tkt == 0 || !Z_tktprincp(tkt)) { - if (tkt) - krb5_free_ticket(Z_krb5_ctx, tkt); - free(authbuf); - krb5_auth_con_free(Z_krb5_ctx, authctx); - return ZAUTH_FAILED; - } - - princ = Z_tktprinc(tkt); - - if (princ == 0) { - krb5_free_ticket(Z_krb5_ctx, tkt); - free(authbuf); - krb5_auth_con_free(Z_krb5_ctx, authctx); - return ZAUTH_FAILED; - } - - /* HOLDING: authbuf, authctx, tkt */ - result = krb5_unparse_name(Z_krb5_ctx, princ, &name); - if (result) { - syslog(LOG_WARNING, "k5 unparse_name failed: %s", - error_message(result)); - free(authbuf); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_ticket(Z_krb5_ctx, tkt); - return ZAUTH_FAILED; - } - - krb5_free_ticket(Z_krb5_ctx, tkt); - - /* HOLDING: authbuf, authctx, name */ - if (strcmp(name, rlmprincipal)) { - syslog(LOG_WARNING, "k5 name mismatch: '%s' vs '%s'", - name, rlmprincipal); - krb5_auth_con_free(Z_krb5_ctx, authctx); - free(name); - free(authbuf); - return ZAUTH_FAILED; - } - free(name); - free(authbuf); - - /* HOLDING: authctx */ - /* Get an authenticator so we can get the keyblock */ - result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx, - &authenticator); - if(result) { - krb5_auth_con_free(Z_krb5_ctx, authctx); - return result; - } - - /* HOLDING: authctx, authenticator */ - result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock); - if (result) { - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - return (ZAUTH_FAILED); - } - - /* HOLDING: authctx, authenticator, keyblock */ - /* Figure out what checksum type to use */ - key_data = Z_keydata(keyblock); - key_len = Z_keylen(keyblock); - result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); - if (result) { - krb5_free_keyblock(Z_krb5_ctx, keyblock); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - return (ZAUTH_FAILED); - } - /* HOLDING: authctx, authenticator, keyblock */ - - /* 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_sender_(sock)addr - * - z_charset - * - z_other_fields[] - */ - if (notice->z_num_hdr_fields > 15 ) { - cksum1_base = notice->z_multinotice; - if (notice->z_num_other_fields) - x = notice->z_other_fields[notice->z_num_other_fields - 1]; - else { - /* see also ZCheckSrvAuthentication and - lib/ZCkZaut.c:ZCheckZcodeAuthentication */ - /* XXXXXXXXXXXXXXXXXXXXXXX */ - if (notice->z_num_hdr_fields > 16) - x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */ - if (notice->z_num_hdr_fields > 17) - x = x + strlen(x) + 1; /* multiuid */ - if (notice->z_num_hdr_fields > 18) - x = x + strlen(x) + 1; /* sender */ - } - cksum1_len = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */ - } - - /* 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 = compute_rlm_checksum(notice, key_data); - - krb5_free_keyblock(Z_krb5_ctx, keyblock); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - - if (our_checksum == notice->z_checksum) { - return ZAUTH_YES; - } else - return ZAUTH_FAILED; - } - - /* HOLDING: authctx, authenticator */ - - cksumbuf.length = cksum0_len + cksum1_len + cksum2_len; - cksumbuf.data = malloc(cksumbuf.length); - if (!cksumbuf.data) { - krb5_free_keyblock(Z_krb5_ctx, keyblock); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - return ZAUTH_FAILED; - } - /* HOLDING: authctx, authenticator, cksumbuf.data */ - - memcpy(cksumbuf.data, cksum0_base, cksum0_len); - if (cksum1_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_keyblock(Z_krb5_ctx, keyblock); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - free(cksumbuf.data); - return ZAUTH_FAILED; - } - /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */ - result = ZReadZcode((unsigned char *)notice->z_ascii_checksum, - asn1_data, asn1_len, &asn1_len); - if (result != ZERR_NONE) { - krb5_free_keyblock(Z_krb5_ctx, keyblock); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - free(asn1_data); - free(cksumbuf.data); - return ZAUTH_FAILED; - } - /* HOLDING: asn1_data, cksumbuf.data */ - - valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, - Z_KEYUSAGE_CLT_CKSUM, - asn1_data, asn1_len); - - free(asn1_data); - krb5_auth_con_free(Z_krb5_ctx, authctx); - krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); - krb5_free_keyblock(Z_krb5_ctx, keyblock); - free(cksumbuf.data); - - if (valid) - return (ZAUTH_YES); - else - return (ZAUTH_FAILED); -#else - return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO; -#endif -} - Code_t ZCheckSrvAuthentication(ZNotice_t *notice, - struct sockaddr_in *from) + struct sockaddr_in *from, + char *realm) { #ifdef HAVE_KRB5 unsigned char *authbuf; @@ -592,16 +273,18 @@ ZCheckSrvAuthentication(ZNotice_t *notice, #define KRB5AUTHENT &authenticator #endif int len; + char *sender; + char rlmprincipal[MAX_PRINCIPAL_SIZE]; if (!notice->z_auth) return ZAUTH_NO; /* Check for bogus authentication data length. */ - if (notice->z_authent_len <= 1) + if (notice->z_authent_len <= 0) return ZAUTH_FAILED; #ifdef HAVE_KRB4 - if (notice->z_ascii_authent[0] != 'Z') + if (notice->z_ascii_authent[0] != 'Z' && realm == NULL) return ZCheckAuthentication4(notice, from); #endif @@ -615,6 +298,14 @@ ZCheckSrvAuthentication(ZNotice_t *notice, return ZAUTH_FAILED; } + if (realm == NULL) { + sender = notice->z_sender; + } else { + (void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE, + SERVER_INSTANCE, realm); + sender = rlmprincipal; + } + packet.length = len; packet.data = (char *)authbuf; @@ -682,6 +373,7 @@ ZCheckSrvAuthentication(ZNotice_t *notice, krb5_auth_con_free(Z_krb5_ctx, authctx); return ZAUTH_FAILED; } + princ = Z_tktprinc(tkt); if (princ == 0) { @@ -705,9 +397,9 @@ ZCheckSrvAuthentication(ZNotice_t *notice, krb5_free_ticket(Z_krb5_ctx, tkt); /* HOLDING: authbuf, authctx, name */ - if (strcmp(name, notice->z_sender)) { + if (strcmp(name, sender)) { syslog(LOG_WARNING, "k5 name mismatch: '%s' vs '%s'", - name, notice->z_sender); + name, sender); krb5_auth_con_free(Z_krb5_ctx, authctx); free(name); free(authbuf); @@ -746,7 +438,8 @@ ZCheckSrvAuthentication(ZNotice_t *notice, } /* HOLDING: authctx, authenticator, keyblock */ - ZSetSession(keyblock); + if (realm == NULL) + ZSetSession(keyblock); /* Assemble the things to be checksummed */ /* first part is from start of packet through z_default_format: @@ -771,6 +464,8 @@ ZCheckSrvAuthentication(ZNotice_t *notice, /* second part is from z_multinotice through other fields: * - z_multinotice * - z_multiuid + * - z_sender_(sock)addr + * - z_charset * - z_other_fields[] */ if (notice->z_num_hdr_fields > 15 ) { @@ -795,7 +490,7 @@ ZCheckSrvAuthentication(ZNotice_t *notice, cksum2_base = notice->z_message; cksum2_len = notice->z_message_len; -#ifdef HAVE_KRB4 /*XXX*/ + /*XXX we may wish to ditch this code someday?*/ if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') && key_len == 8 && (enctype == ENCTYPE_DES_CBC_CRC || @@ -805,7 +500,10 @@ ZCheckSrvAuthentication(ZNotice_t *notice, ZChecksum_t our_checksum; - our_checksum = compute_checksum(notice, key_data); + if (realm == NULL) + our_checksum = compute_checksum(notice, key_data); + else + our_checksum = compute_rlm_checksum(notice, key_data); krb5_free_keyblock(Z_krb5_ctx, keyblock); krb5_auth_con_free(Z_krb5_ctx, authctx); @@ -816,7 +514,6 @@ ZCheckSrvAuthentication(ZNotice_t *notice, else return ZAUTH_FAILED; } -#endif /* HOLDING: authctx, authenticator */ @@ -935,25 +632,23 @@ ZCheckAuthentication4(ZNotice_t *notice, #endif -#if defined(HAVE_KRB4) && defined(HAVE_KRB5) +#ifdef HAVE_KRB5 static ZChecksum_t compute_checksum(ZNotice_t *notice, - C_Block session_key) + unsigned char *session_key) { ZChecksum_t checksum; char *cstart, *cend, *hstart = notice->z_packet, *hend = notice->z_message; cstart = notice->z_default_format + strlen(notice->z_default_format) + 1; cend = cstart + strlen(cstart) + 1; - checksum = des_quad_cksum((unsigned char *)hstart, NULL, cstart - hstart, 0, (C_Block *)session_key); - checksum ^= des_quad_cksum((unsigned char *)cend, NULL, hend - cend, 0, (C_Block *)session_key); - checksum ^= des_quad_cksum((unsigned char *)notice->z_message, NULL, notice->z_message_len, - 0, (C_Block *)session_key); + checksum = z_quad_cksum((unsigned char *)hstart, NULL, cstart - hstart, 0, session_key); + checksum ^= z_quad_cksum((unsigned char *)cend, NULL, hend - cend, 0, session_key); + checksum ^= z_quad_cksum((unsigned char *)notice->z_message, NULL, notice->z_message_len, + 0, session_key); return checksum; } -#endif -#ifdef HAVE_KRB5 static ZChecksum_t compute_rlm_checksum(ZNotice_t *notice, unsigned char *session_key) { diff --git a/server/zserver.h b/server/zserver.h index c0c84fc..2b5a908 100644 --- a/server/zserver.h +++ b/server/zserver.h @@ -292,8 +292,7 @@ Code_t xmit_frag(ZNotice_t *notice, char *buf, int len, int waitforack); void hostm_shutdown(void); /* found in kstuff.c */ -Code_t ZCheckSrvAuthentication(ZNotice_t *notice, struct sockaddr_in *from); -Code_t ZCheckRealmAuthentication(ZNotice_t *, struct sockaddr_in *, char *); +Code_t ZCheckSrvAuthentication(ZNotice_t *notice, struct sockaddr_in *from, char *realm); #if defined(HAVE_KRB4) || defined(HAVE_KRB5) Code_t ReadKerberosData(int, int *, char **, int *); void sweep_ticket_hash_table(void *); -- cgit v1.2.3