Add impersonation.

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17622 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Love Hörnquist Åstrand
2006-06-06 15:07:46 +00:00
parent 03deef10a4
commit a060a07f20

View File

@@ -38,7 +38,7 @@ RCSID("$Id$");
static krb5_error_code static krb5_error_code
check_tgs_flags(krb5_context context, check_tgs_flags(krb5_context context,
krb5_kdc_configuration *config, krb5_kdc_configuration *config,
KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et) KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
{ {
KDCOptions f = b->kdc_options; KDCOptions f = b->kdc_options;
@@ -161,11 +161,46 @@ check_tgs_flags(krb5_context context,
return 0; return 0;
} }
/*
*
*/
static krb5_error_code
check_constrained_delegation(krb5_context context,
krb5_kdc_configuration *config,
hdb_entry_ex *client,
krb5_const_principal server)
{
const HDB_Ext_Constrained_delegation_acl *acl;
krb5_error_code ret;
int i;
ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
if (ret) {
krb5_clear_error_string(context);
return ret;
}
if (acl) {
for (i = 0; i < acl->len; i++) {
if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
return 0;
}
}
kdc_log(context, config, 0,
"Bad request for constrained delegation");
return KRB5KDC_ERR_BADOPTION;
}
/*
*
*/
static krb5_error_code static krb5_error_code
fix_transited_encoding(krb5_context context, fix_transited_encoding(krb5_context context,
krb5_kdc_configuration *config, krb5_kdc_configuration *config,
krb5_boolean check_policy, krb5_boolean check_policy,
TransitedEncoding *tr, const TransitedEncoding *tr,
EncTicketPart *et, EncTicketPart *et,
const char *client_realm, const char *client_realm,
const char *server_realm, const char *server_realm,
@@ -275,8 +310,9 @@ static krb5_error_code
tgs_make_reply(krb5_context context, tgs_make_reply(krb5_context context,
krb5_kdc_configuration *config, krb5_kdc_configuration *config,
KDC_REQ_BODY *b, KDC_REQ_BODY *b,
EncTicketPart *tgt, krb5_const_principal tgt_name,
EncTicketPart *adtkt, const EncTicketPart *tgt,
const EncTicketPart *adtkt,
AuthorizationData *auth_data, AuthorizationData *auth_data,
hdb_entry_ex *server, hdb_entry_ex *server,
const char *server_name, const char *server_name,
@@ -293,7 +329,7 @@ tgs_make_reply(krb5_context context,
krb5_error_code ret; krb5_error_code ret;
krb5_enctype etype; krb5_enctype etype;
Key *skey; Key *skey;
EncryptionKey *ekey; const EncryptionKey *ekey;
if(adtkt) { if(adtkt) {
int i; int i;
@@ -369,11 +405,11 @@ tgs_make_reply(krb5_context context,
copy_Realm(krb5_princ_realm(context, server->entry.principal), copy_Realm(krb5_princ_realm(context, server->entry.principal),
&rep.ticket.realm); &rep.ticket.realm);
_krb5_principal2principalname(&rep.ticket.sname, server->entry.principal); _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
copy_Realm(&tgt->crealm, &rep.crealm); copy_Realm(&tgt_name->realm, &rep.crealm);
if (f.request_anonymous) if (f.request_anonymous)
_kdc_make_anonymous_principalname (&tgt->cname); _kdc_make_anonymous_principalname (&rep.cname);
else else
copy_PrincipalName(&tgt->cname, &rep.cname); copy_PrincipalName(&tgt_name->name, &rep.cname);
rep.ticket.tkt_vno = 5; rep.ticket.tkt_vno = 5;
ek.caddr = et.caddr; ek.caddr = et.caddr;
@@ -433,7 +469,7 @@ tgs_make_reply(krb5_context context,
krb5_generate_random_keyblock(context, etype, &et.key); krb5_generate_random_keyblock(context, etype, &et.key);
et.crealm = tgt->crealm; et.crealm = tgt->crealm;
et.cname = tgt->cname; et.cname = tgt_name->name;
ek.key = et.key; ek.key = et.key;
/* MIT must have at least one last_req */ /* MIT must have at least one last_req */
@@ -818,6 +854,7 @@ out:
static krb5_error_code static krb5_error_code
tgs_build_reply(krb5_context context, tgs_build_reply(krb5_context context,
krb5_kdc_configuration *config, krb5_kdc_configuration *config,
KDC_REQ *req,
KDC_REQ_BODY *b, KDC_REQ_BODY *b,
hdb_entry_ex *krbtgt, hdb_entry_ex *krbtgt,
krb5_ticket *ticket, krb5_ticket *ticket,
@@ -828,8 +865,8 @@ tgs_build_reply(krb5_context context,
const struct sockaddr *from_addr) const struct sockaddr *from_addr)
{ {
krb5_error_code ret; krb5_error_code ret;
krb5_principal cp = NULL; krb5_principal cp = NULL, sp = NULL;
krb5_principal sp = NULL; krb5_principal client_principal = NULL;
char *spn = NULL, *cpn = NULL; char *spn = NULL, *cpn = NULL;
hdb_entry_ex *server = NULL, *client = NULL; hdb_entry_ex *server = NULL, *client = NULL;
EncTicketPart *tgt = &ticket->ticket; EncTicketPart *tgt = &ticket->ticket;
@@ -907,6 +944,11 @@ tgs_build_reply(krb5_context context,
else else
kdc_log(context, config, 0, kdc_log(context, config, 0,
"TGS-REQ %s from %s for %s", cpn, from, spn); "TGS-REQ %s from %s for %s", cpn, from, spn);
/*
* Fetch server
*/
server_lookup: server_lookup:
ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, &server); ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, &server);
@@ -1005,6 +1047,128 @@ server_lookup:
} }
/*
*
*/
client_principal = cp;
if (client) {
const PA_DATA *sdata;
int i = 0;
sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
if (sdata) {
krb5_crypto crypto;
krb5_data datack;
PA_S4U2Self self;
char *selfcpn = NULL;
const char *str;
ret = decode_PA_S4U2Self(sdata->padata_value.data,
sdata->padata_value.length,
&self, NULL);
if (ret) {
kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
goto out;
}
ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
if (ret)
goto out;
ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
if (ret) {
free_PA_S4U2Self(&self);
krb5_data_free(&datack);
kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
krb5_get_err_text(context, ret));
goto out;
}
ret = krb5_verify_checksum(context,
crypto,
KRB5_KU_TGS_IMPERSONATE,
datack.data,
datack.length,
&self.cksum);
krb5_data_free(&datack);
krb5_crypto_destroy(context, crypto);
if (ret) {
free_PA_S4U2Self(&self);
kdc_log(context, config, 0,
"krb5_verify_checksum failed for S4U2Self: %s",
krb5_get_err_text(context, ret));
goto out;
}
ret = _krb5_principalname2krb5_principal(&client_principal,
self.name,
self.realm);
free_PA_S4U2Self(&self);
if (ret)
goto out;
ret = krb5_unparse_name(context, client_principal, &selfcpn);
if (ret)
goto out;
/*
* Check that service doing the impersonating is
* requesting a ticket to it-self.
*/
if (krb5_principal_compare(context, cp, sp) != TRUE) {
kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
"to impersonate some other user "
"(tried for user %s to service %s)",
cpn, selfcpn, spn);
free(selfcpn);
ret = KRB5KDC_ERR_BADOPTION; /* ? */
goto out;
}
/*
* If the service isn't trusted for authentication to
* delegation, remove the forward flag.
*/
if (client->entry.flags.trusted_for_delegation) {
str = "[forwardable]";
} else {
b->kdc_options.forwardable = 0;
str = "";
}
kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
"service %s %s", cpn, selfcpn, spn, str);
free(selfcpn);
}
}
/*
*
*/
if (b->additional_tickets != NULL
&& b->additional_tickets->len != 0
&& b->kdc_options.enc_tkt_in_skey == 0)
{
/* check that ticket is valid */
/* check that ticket is issued to client */
/* check that ticket have the forwardable flag set */
ret = check_constrained_delegation(context, config, client, sp);
if (ret) {
kdc_log(context, config, 0,
"constrained delegation from %s to %s not allowed",
spn, cpn);
goto out;
}
}
/*
* Check flags
*/
ret = _kdc_check_flags(context, config, ret = _kdc_check_flags(context, config,
client, cpn, client, cpn,
server, spn, server, spn,
@@ -1031,6 +1195,7 @@ server_lookup:
ret = tgs_make_reply(context, ret = tgs_make_reply(context,
config, config,
b, b,
client_principal,
tgt, tgt,
b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
auth_data, auth_data,
@@ -1051,7 +1216,11 @@ out:
if(client) if(client)
_kdc_free_ent(context, client); _kdc_free_ent(context, client);
if (client_principal && client_principal != cp)
krb5_free_principal(context, client_principal);
if (cp)
krb5_free_principal(context, cp); krb5_free_principal(context, cp);
if (sp)
krb5_free_principal(context, sp); krb5_free_principal(context, sp);
free_EncTicketPart(&adtkt); free_EncTicketPart(&adtkt);
@@ -1114,6 +1283,7 @@ _kdc_tgs_rep(krb5_context context,
ret = tgs_build_reply(context, ret = tgs_build_reply(context,
config, config,
req,
&req->req_body, &req->req_body,
krbtgt, krbtgt,
ticket, ticket,