From 1a0e03eb19998ab496a6ea845ff2c42d9a02df0b Mon Sep 17 00:00:00 2001 From: Karl Ramm Date: Tue, 25 Dec 2007 00:56:08 +0000 Subject: applied athena-update-branch patch --- server/kstuff.c | 811 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 663 insertions(+), 148 deletions(-) (limited to 'server/kstuff.c') diff --git a/server/kstuff.c b/server/kstuff.c index eff445d..b4b48d7 100644 --- a/server/kstuff.c +++ b/server/kstuff.c @@ -22,30 +22,6 @@ static const char rcsid_kstuff_c[] = "$Id$"; #ifdef HAVE_KRB4 -/* Keep a hash table mapping tickets to session keys, so we can do a fast - * check of the cryptographic checksum without doing and DES decryptions. - * Also remember the expiry time of the ticket, so that we can sweep the - * table periodically. */ - -#define HASHTAB_SIZE 4091 - -typedef struct hash_entry Hash_entry; - -/* The ticket comes at the end, in a variable-length array. */ -struct hash_entry { - C_Block session_key; - time_t expires; - char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4]; - Hash_entry *next; - int ticket_len; - unsigned char ticket[1]; -}; - -Hash_entry *hashtab[HASHTAB_SIZE]; - -static int hash_ticket __P((unsigned char *, int)); -static void add_session_key __P((KTEXT, C_Block, char *, time_t)); -static int find_session_key __P((KTEXT, C_Block, char *)); static ZChecksum_t compute_checksum __P((ZNotice_t *, C_Block)); static ZChecksum_t compute_rlm_checksum __P((ZNotice_t *, C_Block)); @@ -113,6 +89,10 @@ GetKerberosData(fd, haddr, kdata, service, srvtab) * get the ticket and write it to the file descriptor */ +#if !defined(krb_err_base) && defined(ERROR_TABLE_BASE_krb) +#define krb_err_base ERROR_TABLE_BASE_krb +#endif + Code_t SendKerberosData(fd, ticket, service, host) int fd; /* file descriptor to write onto */ @@ -142,21 +122,93 @@ SendKerberosData(fd, ticket, service, host) #endif /* HAVE_KRB4 */ +#ifdef HAVE_KRB5 +Code_t +GetKrb5Data(int fd, krb5_data *data) { + char p[20]; + int i; + unsigned char *dst; + Code_t retval; + + for (i=0; i<20; i++) { + if (read(fd, &p[i], 1) != 1) { + syslog(LOG_WARNING,"bad read reply len"); + return(KFAILURE); + } + if (p[i] == ' ') { + p[i] = '\0'; + break; + } + } + if (i == 20 || strncmp(p, "V5-", 3) || !atoi(p+3)) { + syslog(LOG_WARNING,"bad reply len"); + return ZSRV_PKSHORT; + } + data->length = atoi(p+3); + data->data = malloc(data->length); + if (! data->data) { + data->length = 0; + return errno; + } + dst=data->data; + for (i=0; i < data->length; i++) { + if (read(fd, dst++, 1) != 1) { + free(data->data); + memset((char *)data, 0, sizeof(krb5_data)); + syslog(LOG_WARNING,"bad read reply string"); + return ZSRV_PKSHORT; + } + } + return 0; +} +Code_t +SendKrb5Data(int fd, krb5_data *data) { + char p[32]; + int written, size_to_write; + sprintf(p, "V5-%d", data->length); + size_to_write = strlen (p); + if (size_to_write != (written = write(fd, p, size_to_write)) || + data->length != (written = write(fd, data->data, data->length))) { + return (written < 0) ? errno : ZSRV_PKSHORT; + } + return 0; +} +#endif + Code_t ZCheckRealmAuthentication(notice, from, realm) ZNotice_t *notice; struct sockaddr_in *from; char *realm; { -#ifdef HAVE_KRB4 - int result; - char rlmprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4]; - char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4]; - KTEXT_ST authent, ticket; - AUTH_DAT dat; - ZChecksum_t checksum; - CREDENTIALS cred; - C_Block session_key; +#ifdef HAVE_KRB5 + char *authbuf; + char rlmprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4+1024]; + 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, *cksum2_base; + char *svcinst, *x, *y; + char *asn1_data, *key_data; + int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len; +#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; @@ -165,52 +217,537 @@ ZCheckRealmAuthentication(notice, from, realm) 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 (ZReadAscii(notice->z_ascii_authent, - strlen(notice->z_ascii_authent)+1, - (unsigned char *)authent.dat, - notice->z_authent_len) == ZERR_BADFIELD) { + if (ZReadZcode(notice->z_ascii_authent, + authbuf, + len, &len) == ZERR_BADFIELD) { return ZAUTH_FAILED; } - authent.length = notice->z_authent_len; - (void) sprintf(rlmprincipal, "%s.%s@%s", SERVER_SERVICE, + (void) sprintf(rlmprincipal, "%s/%s@%s", SERVER_SERVICE, SERVER_INSTANCE, realm); - result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, - from->sin_addr.s_addr, &dat, srvtab_file); - if (result == RD_AP_OK) { - sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "", - dat.pinst, dat.prealm); - if (strcmp(rlmprincipal, srcprincipal)) - return ZAUTH_FAILED; - } else { - return ZAUTH_FAILED; /* didn't decode correctly */ + packet.length = len; + packet.data = authbuf; + + result = krb5_kt_resolve(Z_krb5_ctx, + keytab_file, &keytabid); + if (result) { + free(authbuf); + return (result); } - /* Check the cryptographic checksum. */ -#ifdef NOENCRYPTION - checksum = 0; + /* 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); + } + + /* 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, 0, &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_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 = 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_NO; + } + /* HOLDING: authctx, authenticator, 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_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(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, 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 - checksum = compute_rlm_checksum(notice, dat.session); + return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO; #endif - if (checksum != notice->z_checksum) { -#ifndef NOENCRYPTION - checksum = compute_checksum(notice, dat.session); - if (checksum != notice->z_checksum) +} + +Code_t +ZCheckAuthentication(notice, from) + ZNotice_t *notice; + struct sockaddr_in *from; +{ +#ifdef HAVE_KRB5 + char *authbuf; + 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, *cksum2_base; + char *svcinst, *x, *y; + char *asn1_data, *key_data; + int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len; +#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 <= 1) + return ZAUTH_FAILED; + +#ifdef HAVE_KRB4 + if (notice->z_ascii_authent[0] != 'Z') + return ZCheckAuthentication4(notice, from); +#endif + + len = strlen(notice->z_ascii_authent)+1; + authbuf=malloc(len); + + /* Read in the authentication data. */ + if (ZReadZcode(notice->z_ascii_authent, + authbuf, + len, &len) == ZERR_BADFIELD) { return ZAUTH_FAILED; } - return ZAUTH_YES; + packet.length = len; + packet.data = authbuf; -#else /* !HAVE_KRB4 */ + 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); + } + + /* 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, 0, &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, "ZCheckAuthentication: k5 auth failed: %s", error_message(result)); + else + syslog(LOG_WARNING,"ZCheckAuthentication: 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, notice->z_sender)) { + syslog(LOG_WARNING, "k5 name mismatch: '%s' vs '%s'", + name, notice->z_sender); + 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 */ + + ZSetSession(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_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 = compute_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_NO; + } + /* HOLDING: authctx, authenticator, 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_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(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, authctx, authenticator */ + + valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, 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 } +#undef KRB5AUTHENT + Code_t -ZCheckAuthentication(notice, from) +ZCheckAuthentication4(notice, from) ZNotice_t *notice; struct sockaddr_in *from; { @@ -221,6 +758,7 @@ ZCheckAuthentication(notice, from) AUTH_DAT dat; ZChecksum_t checksum; C_Block session_key; + char instance[INST_SZ+1]; if (!notice->z_auth) return ZAUTH_NO; @@ -238,10 +776,13 @@ ZCheckAuthentication(notice, from) } authent.length = notice->z_authent_len; - result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, + strcpy(instance, SERVER_INSTANCE); + + /* We don't have the session key cached; do it the long way. */ + result = krb_rd_req(&authent, SERVER_SERVICE, instance, from->sin_addr.s_addr, &dat, srvtab_file); if (result == RD_AP_OK) { - memcpy(__Zephyr_session, dat.session, sizeof(C_Block)); + ZSetSessionDES(&dat.session); sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "", dat.pinst, dat.prealm); if (strcmp(srcprincipal, notice->z_sender)) @@ -266,76 +807,8 @@ ZCheckAuthentication(notice, from) #endif } -#ifdef HAVE_KRB4 - -static int hash_ticket(p, len) - unsigned char *p; - int len; -{ - unsigned long hashval = 0, g; - - for (; len > 0; p++, len--) { - hashval = (hashval << 4) + *p; - g = hashval & 0xf0000000; - if (g) { - hashval ^= g >> 24; - hashval ^= g; - } - } - return hashval % HASHTAB_SIZE; -} - -static void add_session_key(ticket, session_key, srcprincipal, expires) - KTEXT ticket; - C_Block session_key; - char *srcprincipal; - time_t expires; -{ - Hash_entry *entry; - int hashval; - - /* If we can't allocate memory for the hash table entry, just forget - * about it. */ - entry = (Hash_entry *) malloc(sizeof(Hash_entry) - 1 + ticket->length); - if (!entry) - return; - - /* Initialize the new entry. */ - memcpy(entry->session_key, session_key, sizeof(entry->session_key)); - strcpy(entry->srcprincipal, srcprincipal); - entry->expires = expires; - entry->ticket_len = ticket->length; - memcpy(entry->ticket, ticket->dat, ticket->length * sizeof(unsigned char)); - - /* Insert the new entry in the hash table. */ - hashval = hash_ticket(ticket->dat, ticket->length); - entry->next = hashtab[hashval]; - hashtab[hashval] = entry; -} - -static int find_session_key(ticket, key, srcprincipal) - KTEXT ticket; - C_Block key; - char *srcprincipal; -{ - unsigned char *dat; - int hashval, len; - Hash_entry *entry; - - dat = ticket->dat; - len = ticket->length; - hashval = hash_ticket(dat, len); - - for (entry = hashtab[hashval]; entry; entry = entry->next) { - if (entry->ticket_len == len && memcmp(entry->ticket, dat, len) == 0) { - memcpy(key, entry->session_key, sizeof(entry->session_key)); - strcpy(srcprincipal, entry->srcprincipal); - return 0; - } - } - return -1; -} +#ifdef HAVE_KRB4 static ZChecksum_t compute_checksum(notice, session_key) ZNotice_t *notice; C_Block session_key; @@ -373,26 +846,68 @@ static ZChecksum_t compute_rlm_checksum(notice, session_key) #endif } -void sweep_ticket_hash_table(arg) - void *arg; -{ - int i; - Hash_entry **ptr, *entry; - - for (i = 0; i < HASHTAB_SIZE; i++) { - ptr = &hashtab[i]; - while (*ptr) { - entry = *ptr; - if (entry->expires < NOW) { - *ptr = entry->next; - free(entry); - } else { - ptr = &(*ptr)->next; - } - } +#ifdef HAVE_KRB5 +void +ZSetSession(krb5_keyblock *keyblock) { +#if 1 + krb5_error_code result; + + if (__Zephyr_keyblock) { + krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock); + result = krb5_copy_keyblock_contents(Z_krb5_ctx, keyblock, __Zephyr_keyblock); + } else { + result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &__Zephyr_keyblock); } - timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL); + + if (result) /*XXX we're out of memory? */ + ; +#else + memcpy(__Zephyr_session, Z_keydata(keyblock), sizeof(C_Block)); +#endif } +#endif +#ifdef HAVE_KRB4 +void +ZSetSessionDES(C_Block *key) { +#ifdef HAVE_KRB5 + Code_t result; +#ifdef HAVE_KRB5_INIT_KEYBLOCK + if (__Zephyr_keyblock) { + krb5_free_keyblock(__Zephyr_keyblock); + __Zephyr_keyblock=NULL; + } + result = krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC, + sizeof(C_Block) + &__Zephyr_keyblock); + if (result) /*XXX we're out of memory? */ + return; + + memcpy(Z_keydata(__Zephyr_keyblock), key, sizeof(C_Block)); +#else + krb5_keyblock *tmp, tmp_ss; + tmp = &tmp_ss; + Z_keylen(tmp)=sizeof(C_Block); + Z_keydata(tmp)=key; +#if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + tmp->enctype = ENCTYPE_DES_CBC_CRC; +#else + tmp->keytype = KEYTYPE_DES; +#endif + if (__Zephyr_keyblock) { + krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock); + result = krb5_copy_keyblock_contents(Z_krb5_ctx, tmp, + __Zephyr_keyblock); + } else { + result = krb5_copy_keyblock(Z_krb5_ctx, tmp, &__Zephyr_keyblock); + } + if (result) /*XXX we're out of memory? */ + ; +#endif +#else + memcpy(__Zephyr_session, key, sizeof(C_Block)); +#endif +} +#endif #endif /* HAVE_KRB4 */ -- cgit v1.2.3