Move stuff that's in common between as_rep and tgs_rep to separate

functions.


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@3677 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Johan Danielsson
1997-10-28 03:24:17 +00:00
parent 68f859225d
commit c0147303d1

View File

@@ -65,6 +65,132 @@ set_salt_padata (METHOD_DATA **m, Salt *salt)
} }
} }
static PA_DATA*
find_padata(KDC_REQ *req, int *start, int type)
{
while(*start < req->padata->len){
(*start)++;
if(req->padata->val[*start - 1].padata_type == type)
return &req->padata->val[*start - 1];
}
return NULL;
}
static krb5_error_code
find_etype(hdb_entry *princ, unsigned *etypes, unsigned len,
Key **key, int *index)
{
int i;
krb5_error_code ret = -1;
for(i = 0; i < len && ret != 0; i++)
ret = hdb_etype2key(context, princ, etypes[i], key);
if(index) *index = i;
return ret;
}
static krb5_error_code
find_keys(hdb_entry *client, hdb_entry *server,
Key **ckey, krb5_enctype *cetype,
Key **skey, krb5_enctype *setype, krb5_keytype *sess_ktype,
unsigned *etypes, unsigned num_etypes)
{
int i;
krb5_error_code ret;
if(client){
/* find client key */
ret = find_etype(client, etypes, num_etypes, ckey, &i);
if(ret){
kdc_log(0, "Client has no support for etypes");
return KRB5KDC_ERR_ETYPE_NOSUPP;
}
*cetype = etypes[i];
}
if(server){
/* find sesion key type */
ret = find_etype(server, etypes, num_etypes, skey, NULL);
if(ret){
kdc_log(0, "Server has no support for etypes");
return KRB5KDC_ERR_ETYPE_NOSUPP;
}
*sess_ktype = (*skey)->key.keytype;
}
if(server){
/* find server key */
*skey = NULL;
#define is_better(x, y) ((x) > (y))
for(i = 0; i < server->keys.len; i++){
if(*skey == NULL || is_better(server->keys.val[i].key.keytype,
(*skey)->key.keytype))
*skey = &server->keys.val[i];
}
if(*skey == NULL){
kdc_log(0, "No key found for server");
return KRB5KDC_ERR_NULL_KEY;
}
ret = krb5_keytype_to_etype(context, (*skey)->key.keytype, setype);
if(ret)
return ret;
}
return 0;
}
static krb5_error_code
encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek,
krb5_enctype setype, int skvno, EncryptionKey *skey,
krb5_enctype cetype, int ckvno, EncryptionKey *ckey,
krb5_data *reply)
{
unsigned char buf[8192]; /* XXX The data could be indefinite */
size_t len;
krb5_error_code ret;
ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf), et, &len);
if(ret) {
kdc_log(0, "Failed to encode ticket: %s",
krb5_get_err_text(context, ret));
return ret;
}
krb5_encrypt_EncryptedData(context,
buf + sizeof(buf) - len,
len,
setype,
skvno,
skey,
&rep->ticket.enc_part);
if(rep->msg_type == krb_as_rep)
ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf),
ek, &len);
else
ret = encode_EncTGSRepPart(buf + sizeof(buf) - 1, sizeof(buf),
ek, &len);
if(ret) {
kdc_log(0, "Failed to encode KDC-REP: %s",
krb5_get_err_text(context, ret));
return ret;
}
krb5_encrypt_EncryptedData(context,
buf + sizeof(buf) - len,
len,
cetype,
ckvno,
ckey,
&rep->enc_part);
if(rep->msg_type == krb_as_rep)
ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len);
else
ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len);
if(ret) {
kdc_log(0, "Failed to encode KDC-REP: %s",
krb5_get_err_text(context, ret));
return ret;
}
krb5_data_copy(reply, buf + sizeof(buf) - len, len);
}
krb5_error_code krb5_error_code
as_rep(KDC_REQ *req, as_rep(KDC_REQ *req,
krb5_data *reply, krb5_data *reply,
@@ -128,6 +254,19 @@ as_rep(KDC_REQ *req,
goto out; goto out;
} }
if(!client->flags.client){
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Principal may not act as client -- %s",
client_name);
goto out;
}
if (client->flags.invalid) {
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Client (%s) has invalid bit set", client_name);
goto out;
}
server = db_fetch(server_princ); server = db_fetch(server_princ);
if(server == NULL){ if(server == NULL){
@@ -148,12 +287,6 @@ as_rep(KDC_REQ *req,
goto out; goto out;
} }
if(!client->flags.client){
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Principal may not act as client -- %s",
client_name);
goto out;
}
if(!server->flags.server){ if(!server->flags.server){
ret = KRB5KDC_ERR_POLICY; ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Principal (%s) may not act as server -- %s", kdc_log(0, "Principal (%s) may not act as server -- %s",
@@ -161,18 +294,18 @@ as_rep(KDC_REQ *req,
goto out; goto out;
} }
if (client->flags.invalid) {
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Client (%s) has invalid bit set", client_name);
goto out;
}
if (server->flags.invalid) { if (server->flags.invalid) {
ret = KRB5KDC_ERR_POLICY; ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Server (%s) has invalid bit set", server_name); kdc_log(0, "Server (%s) has invalid bit set", server_name);
goto out; goto out;
} }
if (server->pw_end && *server->pw_end < kdc_time) {
ret = KRB5KDC_ERR_KEY_EXPIRED;
kdc_log(0, "Servers key has expired", server_name);
goto out;
}
if (client->pw_end && *client->pw_end < kdc_time if (client->pw_end && *client->pw_end < kdc_time
&& !server->flags.change_pw) { && !server->flags.change_pw) {
ret = KRB5KDC_ERR_KEY_EXPIRED; ret = KRB5KDC_ERR_KEY_EXPIRED;
@@ -184,13 +317,11 @@ as_rep(KDC_REQ *req,
memset(&ek, 0, sizeof(ek)); memset(&ek, 0, sizeof(ek));
if(req->padata){ if(req->padata){
int i; int i = 0;
PA_DATA *pa; PA_DATA *pa;
int found_pa = 0; int found_pa = 0;
kdc_log(5, "Looking for pa-data -- %s", client_name); kdc_log(5, "Looking for pa-data -- %s", client_name);
for(i = 0; i < req->padata->len; i++){ while((pa = find_padata(req, &i, pa_enc_timestamp))){
PA_DATA *pa = &req->padata->val[i];
if(pa->padata_type == pa_enc_timestamp){
krb5_data ts_data; krb5_data ts_data;
PA_ENC_TS_ENC p; PA_ENC_TS_ENC p;
time_t patime; time_t patime;
@@ -198,8 +329,6 @@ as_rep(KDC_REQ *req,
EncryptedData enc_data; EncryptedData enc_data;
Key *pa_key; Key *pa_key;
kdc_log(5, "Found pa-enc-timestamp -- %s",
client_name);
found_pa = 1; found_pa = 1;
ret = decode_EncryptedData(pa->padata_value.data, ret = decode_EncryptedData(pa->padata_value.data,
@@ -223,10 +352,8 @@ as_rep(KDC_REQ *req,
continue; continue;
} }
ret = krb5_decrypt (context, ret = krb5_decrypt_EncryptedData (context,
enc_data.cipher.data, &enc_data,
enc_data.cipher.length,
enc_data.etype,
&pa_key->key, &pa_key->key,
&ts_data); &ts_data);
free_EncryptedData(&enc_data); free_EncryptedData(&enc_data);
@@ -253,28 +380,14 @@ as_rep(KDC_REQ *req,
free_PA_ENC_TS_ENC(&p); free_PA_ENC_TS_ENC(&p);
if (abs(kdc_time - p.patimestamp) > context->max_skew) { if (abs(kdc_time - p.patimestamp) > context->max_skew) {
ret = KRB5KDC_ERR_PREAUTH_FAILED; ret = KRB5KDC_ERR_PREAUTH_FAILED;
krb5_mk_error (context, e_text = "Too large time skew";
ret, kdc_log(0, "Too large time skew -- %s", client_name);
"Too large time skew", goto out;
NULL,
client_princ,
server_princ,
0,
reply);
kdc_log(0, "Too large time skew -- %s",
client_name);
goto out2;
} }
et.flags.pre_authent = 1; et.flags.pre_authent = 1;
kdc_log(2, "Pre-authentication succeded -- %s", kdc_log(2, "Pre-authentication succeded -- %s", client_name);
client_name);
break; break;
} else {
kdc_log(5, "Found pa-data of type %d -- %s",
pa->padata_type, client_name);
} }
}
/* XXX */
if(found_pa == 0 && require_preauth) if(found_pa == 0 && require_preauth)
goto use_pa; goto use_pa;
/* We come here if we found a pa-enc-timestamp, but if there /* We come here if we found a pa-enc-timestamp, but if there
@@ -285,6 +398,7 @@ as_rep(KDC_REQ *req,
goto out; goto out;
} }
}else if (require_preauth || client->flags.require_preauth) { }else if (require_preauth || client->flags.require_preauth) {
/* XXX check server->flags.require_preauth? */
METHOD_DATA method_data; METHOD_DATA method_data;
PA_DATA pa_data; PA_DATA pa_data;
u_char buf[16]; u_char buf[16];
@@ -320,45 +434,12 @@ as_rep(KDC_REQ *req,
goto out2; goto out2;
} }
/* find client key */
for(i = 0; i < b->etype.len; i++){
ret = hdb_etype2key(context, client, b->etype.val[i], &ckey);
if(ret == 0)
break;
}
if(ret){
ret = KRB5KDC_ERR_ETYPE_NOSUPP;
kdc_log(0, "No support for etypes -- %s", client_name);
goto out;
}
cetype = b->etype.val[i];
/* find sesion key type */
for(i = 0; i < b->etype.len; i++){ ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
ret = hdb_etype2key(context, server, b->etype.val[i], &skey); &sess_ktype, b->etype.val, b->etype.len);
if(ret == 0) if(ret)
break;
}
if(ret){
ret = KRB5KDC_ERR_ETYPE_NOSUPP;
kdc_log(0, "No support for etypes -- %s", client_name);
goto out; goto out;
}
sess_ktype = skey->key.keytype;
/* find server key */
skey = NULL;
#define is_better(x, y) ((x) > (y))
for(i = 0; i < server->keys.len; i++){
if(skey == NULL || is_better(server->keys.val[i].key.keytype,
skey->key.keytype))
skey = &server->keys.val[i];
}
if(skey == NULL){
ret = KRB5KDC_ERR_NULL_KEY;
kdc_log(0, "No key found for server");
goto out;
}
ret = krb5_keytype_to_etype(context, skey->key.keytype, &setype);
{ {
char *cet, *set, *skt; char *cet, *set, *skt;
@@ -386,7 +467,15 @@ as_rep(KDC_REQ *req,
copy_Realm(&b->realm, &rep.ticket.realm); copy_Realm(&b->realm, &rep.ticket.realm);
copy_PrincipalName(b->sname, &rep.ticket.sname); copy_PrincipalName(b->sname, &rep.ticket.sname);
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey){ {
char str[128];
unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
if(*str)
kdc_log(2, "Requested flags: %s", str);
}
if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey ||
f.request_anonymous){
ret = KRB5KDC_ERR_BADOPTION; ret = KRB5KDC_ERR_BADOPTION;
kdc_log(0, "Bad KDC options -- %s", client_name); kdc_log(0, "Bad KDC options -- %s", client_name);
goto out; goto out;
@@ -430,8 +519,6 @@ as_rep(KDC_REQ *req,
start = *et.starttime = *req->req_body.from; start = *et.starttime = *req->req_body.from;
et.flags.invalid = 1; et.flags.invalid = 1;
et.flags.postdated = 1; /* XXX ??? */ et.flags.postdated = 1; /* XXX ??? */
kdc_log(2, "Postdated ticket requested -- %s",
client_name);
} }
fix_time(&b->till); fix_time(&b->till);
t = *b->till; t = *b->till;
@@ -478,7 +565,7 @@ as_rep(KDC_REQ *req,
/* The MIT ASN.1 library (obviously) doesn't tell lengths encoded /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
* as 0 and as 0x80 (meaning indefinite length) apart, and is thus * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
* incapable to correctly decode vectors of zero length. * incapable of correctly decoding SEQUENCE OF's of zero length.
* *
* To fix this, always send at least one no-op last_req * To fix this, always send at least one no-op last_req
* *
@@ -521,14 +608,12 @@ as_rep(KDC_REQ *req,
if (et.starttime) { if (et.starttime) {
ALLOC(ek.starttime); ALLOC(ek.starttime);
*ek.starttime = *et.starttime; *ek.starttime = *et.starttime;
} else }
ek.starttime = et.starttime;
ek.endtime = et.endtime; ek.endtime = et.endtime;
if (et.renew_till) { if (et.renew_till) {
ALLOC(ek.renew_till); ALLOC(ek.renew_till);
*ek.renew_till = *et.renew_till; *ek.renew_till = *et.renew_till;
} else }
ek.renew_till = et.renew_till;
copy_Realm(&rep.ticket.realm, &ek.srealm); copy_Realm(&rep.ticket.realm, &ek.srealm);
copy_PrincipalName(&rep.ticket.sname, &ek.sname); copy_PrincipalName(&rep.ticket.sname, &ek.sname);
if(et.caddr){ if(et.caddr){
@@ -536,51 +621,12 @@ as_rep(KDC_REQ *req,
copy_HostAddresses(et.caddr, ek.caddr); copy_HostAddresses(et.caddr, ek.caddr);
} }
{
unsigned char buf[8192]; /* XXX The data could be indefinite */
size_t len;
ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf),
&et, &len);
free_EncTicketPart(&et);
if(ret) {
kdc_log(0, "Failed to encode ticket -- %s", client);
goto out;
}
krb5_encrypt_EncryptedData(context,
buf + sizeof(buf) - len,
len,
setype,
server->kvno,
&skey->key,
&rep.ticket.enc_part);
ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf),
&ek, &len);
free_EncKDCRepPart(&ek);
if(ret) {
kdc_log(0, "Failed to encode KDC-REP -- %s", client_name);
goto out;
}
krb5_encrypt_EncryptedData(context,
buf + sizeof(buf) - len,
len,
cetype,
client->kvno,
&ckey->key,
&rep.enc_part);
set_salt_padata (&rep.padata, ckey->salt); set_salt_padata (&rep.padata, ckey->salt);
ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len); cetype, client->kvno, &ckey->key, reply);
free_EncTicketPart(&et);
free_EncKDCRepPart(&ek);
free_AS_REP(&rep); free_AS_REP(&rep);
if(ret) {
kdc_log(0, "Failed to encode AS-REP -- %s", client_name);
goto out;
}
krb5_data_copy(reply, buf + sizeof(buf) - len, len);
}
out: out:
if(ret){ if(ret){
krb5_mk_error(context, krb5_mk_error(context,
@@ -711,7 +757,11 @@ check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
et->endtime = *et->starttime + old_life; et->endtime = *et->starttime + old_life;
} }
/* check for excess flags */ /* checks for excess flags */
if(f.request_anonymous){
kdc_log(0, "Request for anonymous ticket");
return KRB5KDC_ERR_BADOPTION;
}
return 0; return 0;
} }
@@ -790,35 +840,14 @@ tgs_make_reply(KDC_REQ_BODY *b,
EncryptionKey *ekey; EncryptionKey *ekey;
krb5_keytype sess_ktype; krb5_keytype sess_ktype;
/* Find appropriate key */ ret = find_keys(NULL, server, NULL, NULL, &skey, &setype,
for(i = 0; i < b->etype.len; i++){ &sess_ktype, b->etype.val, b->etype.len);
ret = hdb_etype2key(context, server, b->etype.val[i], &skey); if(ret)
if(ret == 0) return ret;
break;
}
if(ret){
kdc_log(0, "Failed to find requested etype");
return KRB5KDC_ERR_ETYPE_NOSUPP;
}
sess_ktype = skey->key.keytype;
skey = NULL;
if(adtkt) if(adtkt)
ekey = &adtkt->key; ekey = &adtkt->key;
else{ else
for(i = 0; i < server->keys.len; i++){
if(skey == NULL || is_better(server->keys.val[i].key.keytype,
skey->key.keytype))
skey = &server->keys.val[i];
}
if(skey == NULL){
ret = KRB5KDC_ERR_NULL_KEY;
kdc_log(0, "No key found for server");
goto out;
}
ekey = &skey->key; ekey = &skey->key;
}
ret = krb5_keytype_to_etype(context, ekey->keytype, &setype); ret = krb5_keytype_to_etype(context, ekey->keytype, &setype);
memset(&rep, 0, sizeof(rep)); memset(&rep, 0, sizeof(rep));
@@ -925,31 +954,6 @@ tgs_make_reply(KDC_REQ_BODY *b,
ek.srealm = rep.ticket.realm; ek.srealm = rep.ticket.realm;
ek.sname = rep.ticket.sname; ek.sname = rep.ticket.sname;
{
unsigned char buf[8192]; /* XXX The data could be indefinite */
size_t len;
ret = encode_EncTicketPart(buf + sizeof(buf) - 1,
sizeof(buf), &et, &len);
if(ret){
kdc_log(0, "Failed to encode EncTicketPart: %s",
krb5_get_err_text(context, ret));
goto out;
}
krb5_encrypt_EncryptedData(context, buf + sizeof(buf) - len, len,
setype,
adtkt ? 0 : server->kvno,
ekey,
&rep.ticket.enc_part);
ret = encode_EncTGSRepPart(buf + sizeof(buf) - 1,
sizeof(buf), &ek, &len);
if(ret){
kdc_log(0, "Failed to encode EncTicketPart: %s",
krb5_get_err_text(context, ret));
goto out;
}
/* It is somewhat unclear where the etype in the following /* It is somewhat unclear where the etype in the following
encryption should come from. What we have is a session encryption should come from. What we have is a session
key in the passed tgt, and a list of preferred etypes key in the passed tgt, and a list of preferred etypes
@@ -960,23 +964,9 @@ tgs_make_reply(KDC_REQ_BODY *b,
CAST session key. Should the DES3 etype be added to the CAST session key. Should the DES3 etype be added to the
etype list, even if we don't want a session key with etype list, even if we don't want a session key with
DES3? */ DES3? */
ret = encode_reply(&rep, &et, &ek, setype, adtkt ? 0 : server->kvno, ekey,
cetype, 0, &tgt->key, reply);
krb5_encrypt_EncryptedData(context, out:
buf + sizeof(buf) - len, len,
cetype,
0,
&tgt->key,
&rep.enc_part);
ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
if(ret){
kdc_log(0, "Failed to encode TGS-REP: %s",
krb5_get_err_text(context, ret));
goto out;
}
krb5_data_copy(reply, buf + sizeof(buf) - len, len);
out:
free_TGS_REP(&rep); free_TGS_REP(&rep);
free_TransitedEncoding(&et.transited); free_TransitedEncoding(&et.transited);
if(et.starttime) if(et.starttime)
@@ -986,7 +976,6 @@ tgs_make_reply(KDC_REQ_BODY *b,
free_LastReq(&ek.last_req); free_LastReq(&ek.last_req);
memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
free_EncryptionKey(&et.key); free_EncryptionKey(&et.key);
}
return ret; return ret;
} }
@@ -1162,6 +1151,7 @@ tgs_rep2(KDC_REQ_BODY *b,
TransitedEncoding tr; TransitedEncoding tr;
int loop = 0; int loop = 0;
EncTicketPart adtkt; EncTicketPart adtkt;
char opt_str[128];
s = b->sname; s = b->sname;
r = b->realm; r = b->realm;
@@ -1207,6 +1197,12 @@ tgs_rep2(KDC_REQ_BODY *b,
krb5_unparse_name(context, sp, &spn); krb5_unparse_name(context, sp, &spn);
principalname2krb5_principal(&cp, tgt->cname, tgt->crealm); principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
krb5_unparse_name(context, cp, &cpn); krb5_unparse_name(context, cp, &cpn);
unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
opt_str, sizeof(opt_str));
if(*opt_str)
kdc_log(0, "TGS-REQ %s from %s for %s [%s]",
cpn, from, spn, opt_str);
else
kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn); kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
server_lookup: server_lookup:
server = db_fetch(sp); server = db_fetch(sp);
@@ -1297,6 +1293,7 @@ out2:
return ret; return ret;
} }
krb5_error_code krb5_error_code
tgs_rep(KDC_REQ *req, tgs_rep(KDC_REQ *req,
krb5_data *data, krb5_data *data,