#ifdef HAVE_KRB4
-static ZChecksum_t compute_checksum(ZNotice_t *, C_Block);
-static ZChecksum_t compute_rlm_checksum(ZNotice_t *, C_Block);
-static Code_t ZCheckAuthentication4(ZNotice_t *notice, struct sockaddr_in *from);
+/* 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));
/*
* GetKerberosData
* the value of rd_ap_req() applied to the ticket.
*/
int
-GetKerberosData(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(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 */
{
char p[20];
KTEXT_ST ticket; /* will get Kerberos ticket from client */
* 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(int fd, /* file descriptor to write onto */
- KTEXT ticket, /* where to put ticket (return) */
- char *service, /* service name, foreign host */
- char *host)
-
+SendKerberosData(fd, ticket, service, host)
+ int fd; /* file descriptor to write onto */
+ KTEXT ticket; /* where to put ticket (return) */
+ char *service; /* service name, foreign host */
+ char *host;
{
int rem;
char p[32];
#endif /* HAVE_KRB4 */
-#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
Code_t
-ReadKerberosData(int fd, int *size, char **data, int *proto) {
- char p[20];
- int i;
- char *dst;
- int len = 0;
-
- for (i=0; i<20; i++) {
- if (read(fd, &p[i], 1) != 1) {
- p[i] = 0;
- syslog(LOG_WARNING,"ReadKerberosData: bad read reply len @%d (got \"%s\"", i, p);
- return(KFAILURE);
- }
- if (p[i] == ' ') {
- p[i] = '\0';
- break;
- }
- }
-
- if (i == 20) {
- syslog(LOG_WARNING, "ReadKerberosData: read reply len exceeds buffer");
- return KFAILURE;
- }
-
- if (!strncmp(p, "V5-", 3) && (len = atoi(p+3)) > 0)
- *proto = 5;
- else if ((len = atoi(p)) > 0)
- *proto = 4;
-
- if ((*proto < 4) | (*proto > 5)) {
- syslog(LOG_WARNING, "ReadKerberosData: error parsing authenticator length (\"%s\")", p);
- return KFAILURE;
- }
-
- if (len <= 0) {
- syslog(LOG_WARNING, "ReadKerberosData: read reply len = %d", len);
- return KFAILURE;
- }
-
- *data = malloc(len);
- if (! *data) {
- syslog(LOG_WARNING, "ReadKerberosData: failure allocating %d bytes: %m", len);
- return errno;
- }
-
- dst=*data;
- for (i=0; i < len; i++) {
- if (read(fd, dst++, 1) != 1) {
- free(*data);
- *data = NULL;
- *size = 0;
- syslog(LOG_WARNING,"ReadKerberosData: bad read reply string");
- return ZSRV_PKSHORT;
- }
- }
- *size = len;
- return 0;
-}
-#endif
-
-#ifdef HAVE_KRB5
-Code_t
-GetKrb5Data(int fd, krb5_data *data) {
- char p[20];
- int i;
- char *dst;
-
- for (i=0; i<20; i++) {
- if (read(fd, &p[i], 1) != 1) {
- p[i] = 0;
- syslog(LOG_WARNING,"bad read reply len @%d (got \"%s\")", i, p);
- 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(ZNotice_t *notice,
- struct sockaddr_in *from,
- char *realm)
+ZCheckRealmAuthentication(notice, from, realm)
+ ZNotice_t *notice;
+ struct sockaddr_in *from;
+ char *realm;
{
-#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 *x;
- unsigned char *asn1_data;
- unsigned char *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;
+#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;
if (!notice->z_auth)
return ZAUTH_NO;
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) {
+ if (ZReadAscii(notice->z_ascii_authent,
+ strlen(notice->z_ascii_authent)+1,
+ (unsigned char *)authent.dat,
+ notice->z_authent_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);
- 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);
- }
-
- /* 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);
+ 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 */
}
- /* 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_FAILED;
- }
- /* 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((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, 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
-ZCheckAuthentication(ZNotice_t *notice,
- struct sockaddr_in *from)
-{
-#ifdef HAVE_KRB5
- unsigned 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 *x;
- unsigned 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
+ /* Check the cryptographic checksum. */
+#ifdef NOENCRYPTION
+ checksum = 0;
#else
- krb5_authenticator authenticator;
-#define KRB5AUTHENT &authenticator
+ checksum = compute_rlm_checksum(notice, dat.session);
#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);
+ if (checksum != notice->z_checksum) {
+#ifndef NOENCRYPTION
+ checksum = compute_checksum(notice, dat.session);
+ if (checksum != notice->z_checksum)
#endif
-
- len = strlen(notice->z_ascii_authent)+1;
- authbuf = malloc(len);
-
- /* Read in the authentication data. */
- if (ZReadZcode((unsigned char *)notice->z_ascii_authent,
- authbuf,
- len, &len) == ZERR_BADFIELD) {
return ZAUTH_FAILED;
}
- packet.length = len;
- packet.data = (char *)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);
- }
-
- /* 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;
- }
+ return ZAUTH_YES;
- /* 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_FAILED;
- }
- /* 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((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, 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
+#else /* !HAVE_KRB4 */
return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
#endif
}
-#undef KRB5AUTHENT
-
-static Code_t
-ZCheckAuthentication4(ZNotice_t *notice,
- struct sockaddr_in *from)
+Code_t
+ZCheckAuthentication(notice, from)
+ ZNotice_t *notice;
+ struct sockaddr_in *from;
{
#ifdef HAVE_KRB4
int result;
char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
- KTEXT_ST authent;
+ KTEXT_ST authent, ticket;
AUTH_DAT dat;
ZChecksum_t checksum;
- char instance[INST_SZ+1];
+ C_Block session_key;
if (!notice->z_auth)
return ZAUTH_NO;
}
authent.length = notice->z_authent_len;
- 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,
+ result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
from->sin_addr.s_addr, &dat, srvtab_file);
if (result == RD_AP_OK) {
- ZSetSessionDES(&dat.session);
+ memcpy(__Zephyr_session, dat.session, sizeof(C_Block));
sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
dat.pinst, dat.prealm);
if (strcmp(srcprincipal, notice->z_sender))
}
/* Check the cryptographic checksum. */
+#ifdef NOENCRYPTION
+ checksum = 0;
+#else
checksum = compute_checksum(notice, dat.session);
-
+#endif
if (checksum != notice->z_checksum)
return ZAUTH_FAILED;
#endif
}
-
#ifdef HAVE_KRB4
-static ZChecksum_t
-compute_checksum(ZNotice_t *notice,
- C_Block session_key)
+
+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;
+}
+
+static ZChecksum_t compute_checksum(notice, session_key)
+ ZNotice_t *notice;
+ C_Block session_key;
{
+#ifdef NOENCRYPTION
+ return 0;
+#else
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 = des_quad_cksum(hstart, NULL, cstart - hstart, 0, session_key);
+ checksum ^= des_quad_cksum(cend, NULL, hend - cend, 0, session_key);
+ checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
+ 0, session_key);
return checksum;
+#endif
}
-static ZChecksum_t compute_rlm_checksum(ZNotice_t *notice,
- C_Block session_key)
+static ZChecksum_t compute_rlm_checksum(notice, session_key)
+ ZNotice_t *notice;
+ C_Block session_key;
{
+#ifdef NOENCRYPTION
+ return 0;
+#else
ZChecksum_t checksum;
- char *cstart, *cend, *hstart = notice->z_packet;
+ 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(hstart, NULL, cstart - hstart, 0, session_key);
return checksum;
-}
-
-#ifdef HAVE_KRB5
-krb5_error_code
-Z_krb5_init_keyblock(krb5_context context,
- krb5_enctype type,
- size_t size,
- krb5_keyblock **key)
-{
-#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
- return krb5_init_keyblock(context, type, size, key);
-#else
- krb5_error_code ret;
- krb5_keyblock *tmp, tmp_ss;
- tmp = &tmp_ss;
-
- *key = NULL;
- Z_enctype(tmp) = type;
- Z_keylen(tmp) = size;
- Z_keydata(tmp) = malloc(size);
- if (!Z_keydata(tmp))
- return ENOMEM;
- ret = krb5_copy_keyblock(context, tmp, key);
- free(Z_keydata(tmp));
- return ret;
#endif
}
-void
-ZSetSession(krb5_keyblock *keyblock) {
- 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);
+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;
+ }
+ }
}
-
- if (result) /*XXX we're out of memory? */
- ;
-}
-#endif
-#ifdef HAVE_KRB4
-void
-ZSetSessionDES(C_Block *key) {
-#ifdef HAVE_KRB5
- Code_t result;
- if (__Zephyr_keyblock) {
- krb5_free_keyblock(Z_krb5_ctx, __Zephyr_keyblock);
- __Zephyr_keyblock=NULL;
- }
- result = Z_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
- memcpy(__Zephyr_session, key, sizeof(C_Block));
-#endif
+ timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL);
}
-#endif
#endif /* HAVE_KRB4 */