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
as_rep(KDC_REQ *req,
krb5_data *reply,
@@ -128,6 +254,19 @@ as_rep(KDC_REQ *req,
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);
if(server == NULL){
@@ -148,12 +287,6 @@ as_rep(KDC_REQ *req,
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){
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Principal (%s) may not act as server -- %s",
@@ -161,18 +294,18 @@ as_rep(KDC_REQ *req,
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) {
ret = KRB5KDC_ERR_POLICY;
kdc_log(0, "Server (%s) has invalid bit set", server_name);
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
&& !server->flags.change_pw) {
ret = KRB5KDC_ERR_KEY_EXPIRED;
@@ -184,13 +317,11 @@ as_rep(KDC_REQ *req,
memset(&ek, 0, sizeof(ek));
if(req->padata){
int i;
int i = 0;
PA_DATA *pa;
int found_pa = 0;
kdc_log(5, "Looking for pa-data -- %s", client_name);
for(i = 0; i < req->padata->len; i++){
PA_DATA *pa = &req->padata->val[i];
if(pa->padata_type == pa_enc_timestamp){
while((pa = find_padata(req, &i, pa_enc_timestamp))){
krb5_data ts_data;
PA_ENC_TS_ENC p;
time_t patime;
@@ -198,8 +329,6 @@ as_rep(KDC_REQ *req,
EncryptedData enc_data;
Key *pa_key;
kdc_log(5, "Found pa-enc-timestamp -- %s",
client_name);
found_pa = 1;
ret = decode_EncryptedData(pa->padata_value.data,
@@ -223,10 +352,8 @@ as_rep(KDC_REQ *req,
continue;
}
ret = krb5_decrypt (context,
enc_data.cipher.data,
enc_data.cipher.length,
enc_data.etype,
ret = krb5_decrypt_EncryptedData (context,
&enc_data,
&pa_key->key,
&ts_data);
free_EncryptedData(&enc_data);
@@ -253,28 +380,14 @@ as_rep(KDC_REQ *req,
free_PA_ENC_TS_ENC(&p);
if (abs(kdc_time - p.patimestamp) > context->max_skew) {
ret = KRB5KDC_ERR_PREAUTH_FAILED;
krb5_mk_error (context,
ret,
"Too large time skew",
NULL,
client_princ,
server_princ,
0,
reply);
kdc_log(0, "Too large time skew -- %s",
client_name);
goto out2;
e_text = "Too large time skew";
kdc_log(0, "Too large time skew -- %s", client_name);
goto out;
}
et.flags.pre_authent = 1;
kdc_log(2, "Pre-authentication succeded -- %s",
client_name);
kdc_log(2, "Pre-authentication succeded -- %s", client_name);
break;
} else {
kdc_log(5, "Found pa-data of type %d -- %s",
pa->padata_type, client_name);
}
}
/* XXX */
if(found_pa == 0 && require_preauth)
goto use_pa;
/* We come here if we found a pa-enc-timestamp, but if there
@@ -285,6 +398,7 @@ as_rep(KDC_REQ *req,
goto out;
}
}else if (require_preauth || client->flags.require_preauth) {
/* XXX check server->flags.require_preauth? */
METHOD_DATA method_data;
PA_DATA pa_data;
u_char buf[16];
@@ -320,45 +434,12 @@ as_rep(KDC_REQ *req,
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 = hdb_etype2key(context, server, b->etype.val[i], &skey);
if(ret == 0)
break;
}
if(ret){
ret = KRB5KDC_ERR_ETYPE_NOSUPP;
kdc_log(0, "No support for etypes -- %s", client_name);
ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
&sess_ktype, b->etype.val, b->etype.len);
if(ret)
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;
@@ -386,7 +467,15 @@ as_rep(KDC_REQ *req,
copy_Realm(&b->realm, &rep.ticket.realm);
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;
kdc_log(0, "Bad KDC options -- %s", client_name);
goto out;
@@ -430,8 +519,6 @@ as_rep(KDC_REQ *req,
start = *et.starttime = *req->req_body.from;
et.flags.invalid = 1;
et.flags.postdated = 1; /* XXX ??? */
kdc_log(2, "Postdated ticket requested -- %s",
client_name);
}
fix_time(&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
* 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
*
@@ -521,14 +608,12 @@ as_rep(KDC_REQ *req,
if (et.starttime) {
ALLOC(ek.starttime);
*ek.starttime = *et.starttime;
} else
ek.starttime = et.starttime;
}
ek.endtime = et.endtime;
if (et.renew_till) {
ALLOC(ek.renew_till);
*ek.renew_till = *et.renew_till;
} else
ek.renew_till = et.renew_till;
}
copy_Realm(&rep.ticket.realm, &ek.srealm);
copy_PrincipalName(&rep.ticket.sname, &ek.sname);
if(et.caddr){
@@ -536,51 +621,12 @@ as_rep(KDC_REQ *req,
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);
ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
cetype, client->kvno, &ckey->key, reply);
free_EncTicketPart(&et);
free_EncKDCRepPart(&ek);
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:
if(ret){
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;
}
/* 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;
}
@@ -790,35 +840,14 @@ tgs_make_reply(KDC_REQ_BODY *b,
EncryptionKey *ekey;
krb5_keytype sess_ktype;
/* Find appropriate key */
for(i = 0; i < b->etype.len; i++){
ret = hdb_etype2key(context, server, b->etype.val[i], &skey);
if(ret == 0)
break;
}
if(ret){
kdc_log(0, "Failed to find requested etype");
return KRB5KDC_ERR_ETYPE_NOSUPP;
}
sess_ktype = skey->key.keytype;
skey = NULL;
ret = find_keys(NULL, server, NULL, NULL, &skey, &setype,
&sess_ktype, b->etype.val, b->etype.len);
if(ret)
return ret;
if(adtkt)
ekey = &adtkt->key;
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;
}
else
ekey = &skey->key;
}
ret = krb5_keytype_to_etype(context, ekey->keytype, &setype);
memset(&rep, 0, sizeof(rep));
@@ -925,31 +954,6 @@ tgs_make_reply(KDC_REQ_BODY *b,
ek.srealm = rep.ticket.realm;
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
encryption should come from. What we have is a session
key in the passed tgt, and a list of preferred etypes
@@ -960,22 +964,8 @@ tgs_make_reply(KDC_REQ_BODY *b,
CAST session key. Should the DES3 etype be added to the
etype list, even if we don't want a session key with
DES3? */
krb5_encrypt_EncryptedData(context,
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);
ret = encode_reply(&rep, &et, &ek, setype, adtkt ? 0 : server->kvno, ekey,
cetype, 0, &tgt->key, reply);
out:
free_TGS_REP(&rep);
free_TransitedEncoding(&et.transited);
@@ -986,7 +976,6 @@ tgs_make_reply(KDC_REQ_BODY *b,
free_LastReq(&ek.last_req);
memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
free_EncryptionKey(&et.key);
}
return ret;
}
@@ -1162,6 +1151,7 @@ tgs_rep2(KDC_REQ_BODY *b,
TransitedEncoding tr;
int loop = 0;
EncTicketPart adtkt;
char opt_str[128];
s = b->sname;
r = b->realm;
@@ -1207,6 +1197,12 @@ tgs_rep2(KDC_REQ_BODY *b,
krb5_unparse_name(context, sp, &spn);
principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
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);
server_lookup:
server = db_fetch(sp);
@@ -1297,6 +1293,7 @@ out2:
return ret;
}
krb5_error_code
tgs_rep(KDC_REQ *req,
krb5_data *data,