#include "des.h"
#include "krb.h"
#include "prot.h"
#include <string.h>
#include <krb5.h>
#include <krb54proto.h>
extern int krb_ap_req_debug;
static int
krb_rd_req_with_key(KTEXT, char *, char *, KRB_UINT32, AUTH_DAT *,
Key_schedule, krb5_keyblock *);
int krb_ignore_ip_address = 0;
static Key_schedule serv_key;
static C_Block ky;
static int st_kvno;
static char st_rlm[REALM_SZ];
static char st_nam[ANAME_SZ];
static char st_inst[INST_SZ];
static int krb5_key;
static krb5_keyblock srv_k5key;
int
krb_set_key(key, cvt)
char *key;
int cvt;
{
if (krb5_key)
krb5_free_keyblock_contents(NULL, &srv_k5key);
krb5_key = 0;
#ifdef NOENCRYPTION
memset(ky, 0, sizeof(ky));
return KSUCCESS;
#else
if (cvt)
string_to_key(key, ky);
else
memcpy((char *)ky, key, 8);
return des_key_sched(ky,serv_key);
#endif
}
int
krb_set_key_krb5(ctx, key)
krb5_context ctx;
krb5_keyblock *key;
{
if (krb5_key)
krb5_free_keyblock_contents(ctx, &srv_k5key);
krb5_key = 1;
return krb5_copy_keyblock_contents(ctx, key, &srv_k5key);
}
void
krb_clear_key_krb5(ctx)
krb5_context ctx;
{
if (krb5_key)
krb5_free_keyblock_contents(ctx, &srv_k5key);
krb5_key = 0;
}
static int
krb_rd_req_with_key(authent, service, instance, from_addr, ad, ks, k5key)
register KTEXT authent;
char *service;
char *instance;
unsigned KRB4_32 from_addr;
AUTH_DAT *ad;
Key_schedule ks;
krb5_keyblock *k5key;
{
KTEXT_ST ticket;
KTEXT tkt = &ticket;
KTEXT_ST req_id_st;
register KTEXT req_id = &req_id_st;
char realm[REALM_SZ];
Key_schedule seskey_sched;
char sname[SNAME_SZ];
char iname[INST_SZ];
char r_aname[ANAME_SZ];
char r_inst[INST_SZ];
char r_realm[REALM_SZ];
unsigned int r_time_ms;
unsigned KRB4_32 r_time_sec;
register unsigned char *ptr;
unsigned KRB4_32 t_local;
KRB4_32 delta_t;
#ifdef KRB_CRYPT_DEBUG
KRB4_32 tkt_age;
#endif
int le;
int mutual;
int t;
unsigned char s_kvno;
int ret;
int len;
tkt->mbz = req_id->mbz = 0;
if (authent->length < 1 + 1 + 1)
return RD_AP_MODIFIED;
ptr = authent->dat;
#define AUTHENT_REMAIN (authent->length - (ptr - authent->dat))
if (KRB_PROT_VERSION != *ptr++)
return RD_AP_VERSION;
t = *ptr++;
le = t & 1;
mutual = 0;
switch (t & ~1) {
case AUTH_MSG_APPL_REQUEST:
break;
case AUTH_MSG_APPL_REQUEST_MUTUAL:
mutual++;
break;
default:
return RD_AP_MSG_TYPE;
}
#ifdef lint
if (mutual)
mutual = 0;
#endif
s_kvno = *ptr++;
len = krb4int_strnlen((char *)ptr, AUTHENT_REMAIN) + 1;
if (len <= 0 || len > sizeof(realm)) {
return RD_AP_MODIFIED;
}
(void)memcpy(realm, ptr, (size_t)len);
ptr += len;
tkt->length = *ptr++;
req_id->length = *ptr++;
if (AUTHENT_REMAIN < tkt->length + req_id->length)
return RD_AP_MODIFIED;
memcpy(tkt->dat, ptr, (size_t)tkt->length);
ptr += tkt->length;
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug)
log("ticket->length: %d",tkt->length);
if (krb_ap_req_debug)
log("authent->length: %d", authent->length);
#endif
#ifndef NOENCRYPTION
#endif
if (k5key == NULL) {
if (decomp_ticket(tkt,&ad->k_flags,ad->pname,ad->pinst,ad->prealm,
&(ad->address),ad->session, &(ad->life),
&(ad->time_sec),sname,iname,ky,ks)) {
#ifdef KRB_CRYPT_DEBUG
log("Can't decode ticket");
#endif
return(RD_AP_UNDEC);
}
} else {
if (decomp_tkt_krb5(tkt, &ad->k_flags, ad->pname, ad->pinst,
ad->prealm, &ad->address, ad->session,
&ad->life, &ad->time_sec, sname, iname,
k5key)) {
return RD_AP_UNDEC;
}
}
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug) {
log("Ticket Contents.");
log(" Aname: %s%s%s@%s",ad->pname,
((int)*(ad->pinst) ? "." : ""), ad->pinst,
((int)*(ad->prealm) ? ad->prealm : "Athena"));
log(" Service: %s%s%s",sname,((int)*iname ? "." : ""),iname);
log(" sname=%s, sinst=%s", sname, iname);
}
#endif
memcpy(req_id->dat, ptr, (size_t)req_id->length);
#ifndef NOENCRYPTION
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug) log("About to decrypt authenticator");
#endif
key_sched(ad->session, seskey_sched);
pcbc_encrypt((C_Block *)req_id->dat, (C_Block *)req_id->dat,
(long)req_id->length,
seskey_sched, &ad->session, DES_DECRYPT);
memset(seskey_sched, 0, sizeof(seskey_sched));
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug) log("Done.");
#endif
#endif
ptr = req_id->dat;
#define REQID_REMAIN (req_id->length - (ptr - req_id->dat))
ret = RD_AP_MODIFIED;
len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
if (len <= 0 || len > ANAME_SZ)
goto cleanup;
memcpy(r_aname, ptr, (size_t)len);
ptr += len;
len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
if (len <= 0 || len > INST_SZ)
goto cleanup;
memcpy(r_inst, ptr, (size_t)len);
ptr += len;
len = krb4int_strnlen((char *)ptr, REQID_REMAIN) + 1;
if (len <= 0 || len > REALM_SZ)
goto cleanup;
memcpy(r_realm, ptr, (size_t)len);
ptr += len;
if (REQID_REMAIN < 4 + 1 + 4)
goto cleanup;
KRB4_GET32(ad->checksum, ptr, le);
r_time_ms = *ptr++;
#ifdef lint
if (r_time_ms)
r_time_ms = 0;
#endif
KRB4_GET32(r_time_sec, ptr, le);
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug)
log("Pname: %s %s",ad->pname,r_aname);
#endif
ret = RD_AP_INCON;
if (strcmp(ad->pname,r_aname) != 0)
goto cleanup;
if (strcmp(ad->pinst,r_inst) != 0)
goto cleanup;
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug)
log("Realm: %s %s",ad->prealm,r_realm);
#endif
if (strcmp(ad->prealm,r_realm) != 0)
goto cleanup;
ret = RD_AP_TIME;
t_local = TIME_GMT_UNIXSEC;
delta_t = t_local - r_time_sec;
if (delta_t < 0) delta_t = -delta_t;
if (delta_t > CLOCK_SKEW) {
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug)
log("Time out of range: %d - %d = %d",
time_secs, r_time_sec, delta_t);
#endif
goto cleanup;
}
ret = RD_AP_NYV;
#ifdef KRB_CRYPT_DEBUG
tkt_age = t_local - ad->time_sec;
if (krb_ap_req_debug)
log("Time: %d Issue Date: %d Diff: %d Life %x",
time_secs, ad->time_sec, tkt_age, ad->life);
#endif
if (t_local < ad->time_sec) {
if ((ad->time_sec - t_local) > CLOCK_SKEW)
goto cleanup;
} else if (krb_life_to_time((KRB4_32)ad->time_sec, ad->life)
< t_local + CLOCK_SKEW) {
ret = RD_AP_EXP;
goto cleanup;
}
#ifdef KRB_CRYPT_DEBUG
if (krb_ap_req_debug)
log("Address: %d %d",ad->address,from_addr);
#endif
if (!krb_ignore_ip_address
&& from_addr && (ad->address != from_addr)) {
ret = RD_AP_BADD;
goto cleanup;
}
ad->reply.length = 0;
ret = 0;
cleanup:
if (ret) {
memset(ad->session, 0, sizeof(ad->session));
return ret;
}
return RD_AP_OK;
}
int KRB5_CALLCONV
krb_rd_req_int(authent, service, instance, from_addr, ad, key)
KTEXT authent;
char *service;
char *instance;
KRB_UINT32 from_addr;
AUTH_DAT *ad;
C_Block key;
{
Key_schedule ks;
int ret;
do {
ret = des_key_sched(key, ks);
if (ret) break;
ret = krb_rd_req_with_key(authent, service, instance,
from_addr, ad, ks, NULL);
} while (0);
memset(ks, 0, sizeof(ks));
return ret;
}
int KRB5_CALLCONV
krb_rd_req(authent, service, instance, from_addr, ad, fn)
register KTEXT authent;
char *service;
char *instance;
unsigned KRB4_32 from_addr;
AUTH_DAT *ad;
char *fn;
{
unsigned char *ptr;
unsigned char s_kvno;
char realm[REALM_SZ];
unsigned char skey[KKEY_SZ];
#ifdef KRB4_USE_KEYTAB
krb5_keyblock keyblock;
#endif
int len;
int status;
#define AUTHENT_REMAIN (authent->length - (ptr - authent->dat))
if (authent->length < 3)
return RD_AP_MODIFIED;
ptr = authent->dat + 2;
s_kvno = *ptr++;
len = krb4int_strnlen((char *)ptr, AUTHENT_REMAIN) + 1;
if (len <= 0 || len > sizeof(realm))
return RD_AP_MODIFIED;
(void)memcpy(realm, ptr, (size_t)len);
#undef AUTHENT_REMAIN
if (fn && (strcmp(st_nam,service) || strcmp(st_inst,instance)
|| strcmp(st_rlm,realm) || (st_kvno != s_kvno))) {
if (*fn == 0)
fn = KEYFILE;
st_kvno = s_kvno;
if (read_service_key(service,instance,realm, (int)s_kvno,
fn, (char *)skey) == 0) {
if ((status = krb_set_key((char *)skey,0)))
return(status);
#ifdef KRB4_USE_KEYTAB
} else if (krb54_get_service_keyblock(service, instance,
realm, (int)s_kvno,
fn, &keyblock) == 0) {
krb_set_key_krb5(krb5__krb4_context, &keyblock);
krb5_free_keyblock_contents(krb5__krb4_context, &keyblock);
#endif
} else
return RD_AP_UNDEC;
len = krb4int_strnlen(realm, sizeof(st_rlm)) + 1;
if (len <= 0)
return KFAILURE;
memcpy(st_rlm, realm, (size_t)len);
len = krb4int_strnlen(service, sizeof(st_nam)) + 1;
if (len <= 0)
return KFAILURE;
memcpy(st_nam, service, (size_t)len);
len = krb4int_strnlen(instance, sizeof(st_inst)) + 1;
if (len <= 0)
return KFAILURE;
memcpy(st_inst, instance, (size_t)len);
}
return krb_rd_req_with_key(authent, service, instance,
from_addr, ad,
krb5_key ? NULL : serv_key,
krb5_key ? &srv_k5key : NULL);
}