summaryrefslogtreecommitdiff
path: root/source4/heimdal/kdc/krb5tgs.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2007-01-10 01:57:32 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:37:20 -0500
commitf7242f643763ccb6e10801af4ce53d0873e2d3e1 (patch)
treecd06665f49d12795e23699e6666d85da1f64d7bd /source4/heimdal/kdc/krb5tgs.c
parent08976cb3d2adfe5ea90ed53e6aa6fa8161649f7a (diff)
downloadsamba-f7242f643763ccb6e10801af4ce53d0873e2d3e1.tar.gz
r20640: Commit part 2/2
Update Heimdal to match current lorikeet-heimdal. This includes integrated PAC hooks, so Samba doesn't have to handle this any more. This also brings in the PKINIT code, hence so many new files. Andrew Bartlett (This used to be commit 351f7040f7bb73b9a60b22b564686f7c2f98a729)
Diffstat (limited to 'source4/heimdal/kdc/krb5tgs.c')
-rw-r--r--source4/heimdal/kdc/krb5tgs.c338
1 files changed, 228 insertions, 110 deletions
diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c
index dcf29eb6e98..a056839e5f3 100644
--- a/source4/heimdal/kdc/krb5tgs.c
+++ b/source4/heimdal/kdc/krb5tgs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -33,7 +33,7 @@
#include "kdc_locl.h"
-RCSID("$Id: krb5tgs.c,v 1.16 2006/10/22 15:54:37 lha Exp $");
+RCSID("$Id: krb5tgs.c,v 1.25 2007/01/04 12:49:45 lha Exp $");
/*
* return the realm of a krbtgt-ticket or NULL
@@ -119,7 +119,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
if (server && principals) {
ret = add_KRB5SignedPathPrincipals(principals, server);
if (ret)
- goto out;
+ return ret;
}
{
@@ -131,7 +131,7 @@ _kdc_add_KRB5SignedPath(krb5_context context,
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
&spd, &size, ret);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
}
@@ -159,12 +159,12 @@ _kdc_add_KRB5SignedPath(krb5_context context,
krb5_crypto_destroy(context, crypto);
free(data.data);
if (ret)
- goto out;
+ return ret;
ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
free_Checksum(&sp.cksum);
if (ret)
- goto out;
+ return ret;
if (data.length != size)
krb5_abortx(context, "internal asn.1 encoder error");
@@ -174,46 +174,11 @@ _kdc_add_KRB5SignedPath(krb5_context context,
* authorization data field.
*/
- if (tkt->authorization_data == NULL) {
- tkt->authorization_data = calloc(1, sizeof(*tkt->authorization_data));
- if (tkt->authorization_data == NULL) {
- ret = ENOMEM;
- goto out;
- }
- }
-
- /* add the entry to the last element */
- {
- AuthorizationData ad = { 0, NULL };
- AuthorizationDataElement ade;
-
- ade.ad_type = KRB5_AUTHDATA_SIGNTICKET;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(&ad, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
-
- ASN1_MALLOC_ENCODE(AuthorizationData, data.data, data.length,
- &ad, &size, ret);
- free_AuthorizationData(&ad);
- if (ret)
- return ret;
- if (data.length != size)
- krb5_abortx(context, "internal asn.1 encoder error");
-
- ade.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
- ade.ad_data = data;
-
- ret = add_AuthorizationData(tkt->authorization_data, &ade);
- krb5_data_free(&data);
- if (ret)
- return ret;
- }
+ ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
+ KRB5_AUTHDATA_SIGNTICKET, &data);
+ krb5_data_free(&data);
-out:
- return 0;
+ return ret;
}
static krb5_error_code
@@ -307,6 +272,87 @@ check_KRB5SignedPath(krb5_context context,
return 0;
}
+/*
+ *
+ */
+
+static krb5_error_code
+check_PAC(krb5_context context,
+ krb5_kdc_configuration *config,
+ const krb5_principal client_principal,
+ hdb_entry_ex *client,
+ hdb_entry_ex *server,
+ const EncryptionKey *server_key,
+ const EncryptionKey *krbtgt_key,
+ EncTicketPart *tkt,
+ krb5_data *rspac,
+ int *require_signedpath)
+{
+ AuthorizationData *ad = tkt->authorization_data;
+ unsigned i, j;
+ krb5_error_code ret;
+
+ if (ad == NULL || ad->len == 0)
+ return 0;
+
+ for (i = 0; i < ad->len; i++) {
+ AuthorizationData child;
+
+ if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ ret = decode_AuthorizationData(ad->val[i].ad_data.data,
+ ad->val[i].ad_data.length,
+ &child,
+ NULL);
+ if (ret) {
+ krb5_set_error_string(context, "Failed to decode "
+ "IF_RELEVANT with %d", ret);
+ return ret;
+ }
+ for (j = 0; j < child.len; j++) {
+
+ if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
+ krb5_pac pac;
+
+ /* Found PAC */
+ ret = krb5_pac_parse(context,
+ child.val[j].ad_data.data,
+ child.val[j].ad_data.length,
+ &pac);
+ free_AuthorizationData(&child);
+ if (ret)
+ return ret;
+
+ ret = krb5_pac_verify(context, pac, tkt->authtime,
+ client_principal,
+ krbtgt_key, NULL);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+
+ ret = _kdc_pac_verify(context, client_principal,
+ client, server, &pac);
+ if (ret) {
+ krb5_pac_free(context, pac);
+ return ret;
+ }
+ *require_signedpath = 0;
+
+ ret = _krb5_pac_sign(context, pac, tkt->authtime,
+ client_principal,
+ server_key, krbtgt_key, rspac);
+
+ krb5_pac_free(context, pac);
+
+ return ret;
+ }
+ }
+ free_AuthorizationData(&child);
+ }
+ return 0;
+}
/*
*
@@ -610,9 +656,10 @@ tgs_make_reply(krb5_context context,
KDC_REQ_BODY *b,
krb5_const_principal tgt_name,
const EncTicketPart *tgt,
- const EncTicketPart *adtkt,
+ const EncryptionKey *ekey,
+ const krb5_keyblock *sessionkey,
+ krb5_kvno kvno,
AuthorizationData *auth_data,
- krb5_ticket *tgs_ticket,
hdb_entry_ex *server,
const char *server_name,
hdb_entry_ex *client,
@@ -620,7 +667,7 @@ tgs_make_reply(krb5_context context,
hdb_entry_ex *krbtgt,
krb5_enctype krbtgt_etype,
KRB5SignedPathPrincipals *spp,
- EncryptionKey *tgtkey,
+ const krb5_data *rspac,
const char **e_text,
krb5_data *reply)
{
@@ -629,32 +676,6 @@ tgs_make_reply(krb5_context context,
EncTicketPart et;
KDCOptions f = b->kdc_options;
krb5_error_code ret;
- krb5_enctype etype;
- Key *skey;
- const EncryptionKey *ekey;
- AuthorizationData *new_auth_data = NULL;
-
- if(adtkt) {
- int i;
- ekey = &adtkt->key;
- for(i = 0; i < b->etype.len; i++)
- if (b->etype.val[i] == adtkt->key.keytype)
- break;
- if(i == b->etype.len) {
- krb5_clear_error_string(context);
- return KRB5KDC_ERR_ETYPE_NOSUPP;
- }
- etype = b->etype.val[i];
- }else{
- ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
- &skey, &etype);
- if(ret) {
- kdc_log(context, config, 0,
- "Server (%s) has no support for etypes", server_name);
- return ret;
- }
- ekey = &skey->key;
- }
memset(&rep, 0, sizeof(rep));
memset(&et, 0, sizeof(et));
@@ -768,26 +789,47 @@ tgs_make_reply(krb5_context context,
et.flags.anonymous = tgt->flags.anonymous;
et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
-
- krb5_generate_random_keyblock(context, etype, &et.key);
-
- if (server->authz_data_tgs_req) {
- ret = server->authz_data_tgs_req(context, server,
- client_principal,
- tgs_ticket->ticket.authorization_data,
- tgs_ticket->ticket.authtime,
- tgtkey,
- ekey,
- &et.key,
- &new_auth_data);
- if (ret) {
- new_auth_data = NULL;
+ if (auth_data) {
+ /* XXX Check enc-authorization-data */
+ et.authorization_data = calloc(1, sizeof(*et.authorization_data));
+ if (et.authorization_data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = copy_AuthorizationData(auth_data, et.authorization_data);
+ if (ret)
+ goto out;
+
+ /* Filter out type KRB5SignedPath */
+ ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
+ if (ret == 0) {
+ if (et.authorization_data->len == 1) {
+ free_AuthorizationData(et.authorization_data);
+ free(et.authorization_data);
+ et.authorization_data = NULL;
+ } else {
+ AuthorizationData *ad = et.authorization_data;
+ free_AuthorizationDataElement(&ad->val[ad->len - 1]);
+ ad->len--;
}
+ }
}
- /* XXX Check enc-authorization-data */
- et.authorization_data = new_auth_data;
+ if(rspac->length) {
+ /*
+ * No not need to filter out the any PAC from the
+ * auth_data since its signed by the KDC.
+ */
+ ret = _kdc_tkt_add_if_relevant_ad(context, &et,
+ KRB5_AUTHDATA_WIN2K_PAC,
+ rspac);
+ if (ret)
+ goto out;
+ }
+ ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
+ if (ret)
+ goto out;
et.crealm = tgt->crealm;
et.cname = tgt_name->name;
@@ -795,6 +837,10 @@ tgs_make_reply(krb5_context context,
/* MIT must have at least one last_req */
ek.last_req.len = 1;
ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
+ if (ek.last_req.val == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
ek.nonce = b->nonce;
ek.flags = et.flags;
ek.authtime = et.authtime;
@@ -817,7 +863,7 @@ tgs_make_reply(krb5_context context,
krbtgt,
krbtgt_etype,
NULL,
- NULL,
+ spp,
&et);
if (ret)
goto out;
@@ -835,8 +881,8 @@ tgs_make_reply(krb5_context context,
etype list, even if we don't want a session key with
DES3? */
ret = _kdc_encode_reply(context, config,
- &rep, &et, &ek, etype,
- adtkt ? 0 : server->entry.kvno,
+ &rep, &et, &ek, et.key.keytype,
+ kvno,
ekey, 0, &tgt->key, e_text, reply);
out:
free_TGS_REP(&rep);
@@ -973,8 +1019,7 @@ tgs_parse_request(krb5_context context,
const struct sockaddr *from_addr,
time_t **csec,
int **cusec,
- AuthorizationData **auth_data,
- EncryptionKey **tgtkey)
+ AuthorizationData **auth_data)
{
krb5_ap_req ap_req;
krb5_error_code ret;
@@ -1060,8 +1105,6 @@ tgs_parse_request(krb5_context context,
ret = KRB5KRB_AP_ERR_BADKEYVER;
goto out;
}
-
- *tgtkey = &tkey->key;
if (b->kdc_options.validate)
verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
@@ -1201,8 +1244,8 @@ tgs_build_reply(krb5_context context,
const char *from,
const char **e_text,
AuthorizationData *auth_data,
- EncryptionKey *tgtkey,
- const struct sockaddr *from_addr)
+ const struct sockaddr *from_addr,
+ int datagram_reply)
{
krb5_error_code ret;
krb5_principal cp = NULL, sp = NULL;
@@ -1211,6 +1254,10 @@ tgs_build_reply(krb5_context context,
hdb_entry_ex *server = NULL, *client = NULL;
EncTicketPart *tgt = &ticket->ticket;
KRB5SignedPathPrincipals *spp = NULL;
+ const EncryptionKey *ekey;
+ krb5_keyblock sessionkey;
+ krb5_kvno kvno;
+ krb5_data rspac;
PrincipalName *s;
Realm r;
@@ -1219,7 +1266,9 @@ tgs_build_reply(krb5_context context,
char opt_str[128];
int require_signedpath = 0;
+ memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
+ krb5_data_zero(&rspac);
s = b->sname;
r = b->realm;
@@ -1436,7 +1485,7 @@ server_lookup:
ret = krb5_verify_checksum(context,
crypto,
- KRB5_KU_TGS_IMPERSONATE,
+ KRB5_KU_OTHER_CKSUM,
datack.data,
datack.length,
&self.cksum);
@@ -1617,6 +1666,67 @@ server_lookup:
goto out;
}
+ /*
+ * Select enctype, return key and kvno.
+ */
+
+ {
+ krb5_enctype etype;
+
+ if(b->kdc_options.enc_tkt_in_skey) {
+ int i;
+ ekey = &adtkt.key;
+ for(i = 0; i < b->etype.len; i++)
+ if (b->etype.val[i] == adtkt.key.keytype)
+ break;
+ if(i == b->etype.len) {
+ krb5_clear_error_string(context);
+ return KRB5KDC_ERR_ETYPE_NOSUPP;
+ }
+ etype = b->etype.val[i];
+ kvno = 0;
+ } else {
+ Key *skey;
+
+ ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
+ &skey, &etype);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Server (%s) has no support for etypes", spp);
+ return ret;
+ }
+ ekey = &skey->key;
+ kvno = server->entry.kvno;
+ }
+
+ ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
+ if (ret)
+ goto out;
+ }
+
+ /* check PAC if there is one */
+ {
+ Key *tkey;
+
+ ret = hdb_enctype2key(context, &krbtgt->entry,
+ krbtgt_etype, &tkey);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Failed to find key for krbtgt PAC check");
+ goto out;
+ }
+
+ ret = check_PAC(context, config, client_principal,
+ client, server, ekey, &tkey->key,
+ tgt, &rspac, &require_signedpath);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "check_PAC check failed for %s (%s) from %s with %s",
+ spn, cpn, from, krb5_get_err_text(context, ret));
+ goto out;
+ }
+ }
+
/* also check the krbtgt for signature */
ret = check_KRB5SignedPath(context,
config,
@@ -1640,9 +1750,10 @@ server_lookup:
b,
client_principal,
tgt,
- b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
+ ekey,
+ &sessionkey,
+ kvno,
auth_data,
- ticket,
server,
spn,
client,
@@ -1650,7 +1761,7 @@ server_lookup:
krbtgt,
krbtgt_etype,
spp,
- tgtkey,
+ &rspac,
e_text,
reply);
@@ -1658,6 +1769,8 @@ out:
free(spn);
free(cpn);
+ krb5_data_free(&rspac);
+ krb5_free_keyblock_contents(context, &sessionkey);
if(server)
_kdc_free_ent(context, server);
if(client)
@@ -1685,7 +1798,8 @@ _kdc_tgs_rep(krb5_context context,
KDC_REQ *req,
krb5_data *data,
const char *from,
- struct sockaddr *from_addr)
+ struct sockaddr *from_addr,
+ int datagram_reply)
{
AuthorizationData *auth_data = NULL;
krb5_error_code ret;
@@ -1696,8 +1810,6 @@ _kdc_tgs_rep(krb5_context context,
krb5_ticket *ticket = NULL;
const char *e_text = NULL;
krb5_enctype krbtgt_etype = ETYPE_NULL;
- EncryptionKey *tgtkey = NULL;
-
time_t *csec = NULL;
int *cusec = NULL;
@@ -1726,8 +1838,7 @@ _kdc_tgs_rep(krb5_context context,
&e_text,
from, from_addr,
&csec, &cusec,
- &auth_data,
- &tgtkey);
+ &auth_data);
if (ret) {
kdc_log(context, config, 0,
"Failed parsing TGS-REQ from %s", from);
@@ -1745,14 +1856,21 @@ _kdc_tgs_rep(krb5_context context,
from,
&e_text,
auth_data,
- tgtkey,
- from_addr);
+ from_addr,
+ datagram_reply);
if (ret) {
kdc_log(context, config, 0,
"Failed building TGS-REP to %s", from);
goto out;
}
+ /* */
+ if (datagram_reply && data->length > config->max_datagram_reply_length) {
+ krb5_data_free(data);
+ ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
+ e_text = "Reply packet too large";
+ }
+
out:
if(ret && data->data == NULL){
krb5_mk_error(context,