AuthorizationData child;
krb5_error_code ret;
int pos;
-
+
if (ad == NULL || ad->len == 0)
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
KRB5SignedPath sp;
krb5_data data;
krb5_crypto crypto = NULL;
- size_t size;
+ size_t size = 0;
if (server && principals) {
ret = add_Principals(principals, server);
{
KRB5SignedPathData spd;
-
+
spd.client = client;
spd.authtime = tkt->authtime;
spd.delegated = principals;
spd.method_data = NULL;
-
+
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
&spd, &size, ret);
if (ret)
if (ret == 0) {
KRB5SignedPathData spd;
KRB5SignedPath sp;
- size_t size;
+ size_t size = 0;
ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
krb5_data_free(&data);
check_PAC(krb5_context context,
krb5_kdc_configuration *config,
const krb5_principal client_principal,
+ const krb5_principal delegated_proxy_principal,
hdb_entry_ex *client,
hdb_entry_ex *server,
hdb_entry_ex *krbtgt,
}
ret = _kdc_pac_verify(context, client_principal,
+ delegated_proxy_principal,
client, server, krbtgt, &pac, &signed_pac);
if (ret) {
krb5_pac_free(context, pac);
server_sign_key, krbtgt_sign_key, rspac);
}
krb5_pac_free(context, pac);
-
+
return ret;
}
}
KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
{
KDCOptions f = b->kdc_options;
-
+
if(f.validate){
if(!tgt->flags.invalid || tgt->starttime == NULL){
kdc_log(context, config, 0,
}
if(tgt->flags.forwarded)
et->flags.forwarded = 1;
-
+
if(f.proxiable){
if(!tgt->flags.proxiable){
kdc_log(context, config, 0,
et->endtime = *et->starttime + old_life;
if (et->renew_till != NULL)
et->endtime = min(*et->renew_till, et->endtime);
- }
+ }
#if 0
/* checks for excess flags */
krb5_kdc_configuration *config,
HDB *clientdb,
hdb_entry_ex *client,
- krb5_const_principal server)
+ hdb_entry_ex *server,
+ krb5_const_principal target)
{
const HDB_Ext_Constrained_delegation_acl *acl;
krb5_error_code ret;
- int i;
+ size_t i;
- /* if client delegates to itself, that ok */
- if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
- return 0;
+ /*
+ * constrained_delegation (S4U2Proxy) only works within
+ * the same realm. We use the already canonicalized version
+ * of the principals here, while "target" is the principal
+ * provided by the client.
+ */
+ if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ kdc_log(context, config, 0,
+ "Bad request for constrained delegation");
+ return ret;
+ }
if (clientdb->hdb_check_constrained_delegation) {
- ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, server);
+ ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
if (ret == 0)
return 0;
} else {
+ /* if client delegates to itself, that ok */
+ if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
+ return 0;
+
ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
if (ret) {
krb5_clear_error_message(context);
return ret;
}
-
+
if (acl) {
for (i = 0; i < acl->len; i++) {
- if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
+ if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
return 0;
}
}
krb5_error_code ret = 0;
char **realms, **tmp;
unsigned int num_realms;
- int i;
+ size_t i;
switch (tr->tr_type) {
case DOMAIN_X500_COMPRESS:
renew = min(renew, *server->entry.max_renew);
*et.renew_till = et.authtime + renew;
}
-
+
if(et.renew_till){
*et.renew_till = min(*et.renew_till, *tgt->renew_till);
*et.starttime = min(*et.starttime, *et.renew_till);
if (ret)
goto out;
}
-
+
if (auth_data) {
unsigned int i = 0;
ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
if (ret)
goto out;
- et.crealm = tgt->crealm;
+ et.crealm = tgt_name->realm;
et.cname = tgt_name->name;
-
+
ek.key = et.key;
/* MIT must have at least one last_req */
ek.last_req.len = 1;
krb5_keyblock *key)
{
krb5_authenticator auth;
- size_t len;
+ size_t len = 0;
unsigned char *buf;
size_t buf_size;
krb5_error_code ret;
ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
goto out;
}
-
+
/* XXX should not re-encode this */
ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
if(ret){
NULL);
return new_realm;
}
-
+
static krb5_boolean
need_referral(krb5_context context, krb5_kdc_configuration *config,
if (server->name.name_string.len == 1)
name = server->name.name_string.val[0];
- else if (server->name.name_string.len > 1)
+ else if (server->name.name_string.len == 3 &&
+ strcasecmp("E3514235-4B06-11D1-AB04-00C04FC2DCD2", server->name.name_string.val[0]) == 0) {
+ /*
+ This is used to give referrals for the
+ E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
+ SPN form, which is used for inter-domain communication in AD
+ */
+ name = server->name.name_string.val[2];
+ kdc_log(context, config, 0, "Giving 3 part DRSUAPI referral for %s", name);
+ *realms = malloc(sizeof(char *)*2);
+ if (*realms == NULL) {
+ krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+ return FALSE;
+ }
+ (*realms)[0] = strdup(name);
+ (*realms)[1] = NULL;
+ return TRUE;
+ } else if (server->name.name_string.len > 1)
name = server->name.name_string.val[1];
else
return FALSE;
krb5_keyblock **replykey,
int *rk_is_subkey)
{
+ static char failed[] = "<unparse_name failed>";
krb5_ap_req ap_req;
krb5_error_code ret;
krb5_principal princ;
char *p;
ret = krb5_unparse_name(context, princ, &p);
if (ret != 0)
- p = "<unparse_name failed>";
+ p = failed;
krb5_free_principal(context, princ);
kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
if (ret == 0)
char *p;
ret = krb5_unparse_name(context, princ, &p);
if (ret != 0)
- p = "<unparse_name failed>";
+ p = failed;
krb5_free_principal(context, princ);
kdc_log(context, config, 0,
"Ticket-granting ticket not found in database: %s", msg);
ret = krb5_unparse_name (context, princ, &p);
krb5_free_principal(context, princ);
if (ret != 0)
- p = "<unparse_name failed>";
+ p = failed;
kdc_log(context, config, 0,
"Ticket kvno = %d, DB kvno = %d (%s)",
*ap_req.ticket.enc_part.kvno,
&ap_req_options,
ticket,
KRB5_KU_TGS_REQ_AUTH);
-
+
krb5_free_principal(context, princ);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
const PrincipalName *true_principal_name,
const PrincipalName *requested_principal,
krb5_data *outdata)
-{
+{
PA_ServerReferralData ref;
krb5_error_code ret;
EncryptedData ed;
krb5_data data;
- size_t size;
+ size_t size = 0;
memset(&ref, 0, sizeof(ref));
const struct sockaddr *from_addr)
{
krb5_error_code ret;
- krb5_principal cp = NULL, sp = NULL, tp = NULL;
+ krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
krb5_principal krbtgt_principal = NULL;
- char *spn = NULL, *cpn = NULL, *tpn = NULL;
+ char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
HDB *clientdb, *s4u2self_impersonated_clientdb;
krb5_realm ref_realm = NULL;
Key *tkey_check;
Key *tkey_sign;
+ Key *tkey_krbtgt_check = NULL;
+ int flags = HDB_F_FOR_TGS_REQ;
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
s = b->sname;
r = b->realm;
+ if (b->kdc_options.canonicalize)
+ flags |= HDB_F_CANON;
+
if(b->kdc_options.enc_tkt_in_skey){
Ticket *t;
hdb_entry_ex *uu;
krb5_principal p;
Key *uukey;
-
+
if(b->additional_tickets == NULL ||
b->additional_tickets->len == 0){
ret = KRB5KDC_ERR_BADOPTION; /* ? */
}
_krb5_principalname2krb5_principal(context, &sp, *s, r);
- ret = krb5_unparse_name(context, sp, &spn);
+ ret = krb5_unparse_name(context, sp, &spn);
if (ret)
goto out;
_krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
*/
server_lookup:
- ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
+ ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
NULL, NULL, &server);
if(ret == HDB_ERR_NOT_FOUND_HERE) {
free(spn);
krb5_make_principal(context, &sp, r,
KRB5_TGS_NAME, new_rlm, NULL);
- ret = krb5_unparse_name(context, sp, &spn);
+ ret = krb5_unparse_name(context, sp, &spn);
if (ret)
goto out;
krb5_enctype etype;
if(b->kdc_options.enc_tkt_in_skey) {
- int i;
+ size_t i;
ekey = &adtkt.key;
for(i = 0; i < b->etype.len; i++)
if (b->etype.val[i] == adtkt.key.keytype)
kvno = 0;
} else {
Key *skey;
-
- ret = _kdc_find_etype(context, server,
- b->etype.val, b->etype.len, &skey);
+
+ ret = _kdc_find_etype(context,
+ config->tgs_use_strongest_session_key, FALSE,
+ server, b->etype.val, b->etype.len, NULL,
+ &skey);
if(ret) {
kdc_log(context, config, 0,
"Server (%s) has no support for etypes", spn);
etype = skey->key.keytype;
kvno = server->entry.kvno;
}
-
+
ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
if (ret)
goto out;
/* Now refetch the primary krbtgt, and get the current kvno (the
* sign check may have been on an old kvno, and the server may
* have been an incoming trust) */
- ret = krb5_make_principal(context, &krbtgt_principal,
+ ret = krb5_make_principal(context, &krbtgt_principal,
krb5_principal_get_comp_string(context,
krbtgt->entry.principal,
1),
- KRB5_TGS_NAME,
+ KRB5_TGS_NAME,
krb5_principal_get_comp_string(context,
krbtgt->entry.principal,
1), NULL);
goto out;
}
- ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
+ /* Check if we would know the krbtgt key for the PAC. We would
+ * only know this if the krbtgt principal was the same (ie, in our
+ * realm, regardless of KVNO) */
+ if (krb5_principal_compare(context, krbtgt_out->entry.principal, krbtgt->entry.principal)) {
+ tkey_krbtgt_check = tkey_check;
+ }
+
+ ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
NULL, &clientdb, &client);
if(ret == HDB_ERR_NOT_FOUND_HERE) {
/* This is OK, we are just trying to find out if they have
krb5_free_error_message(context, msg);
}
- ret = check_PAC(context, config, cp,
+ ret = check_PAC(context, config, cp, NULL,
client, server, krbtgt,
- &tkey_check->key, &tkey_check->key,
+ &tkey_check->key,
+ tkey_krbtgt_check ? &tkey_krbtgt_check->key : NULL,
ekey, &tkey_sign->key,
tgt, &rspac, &signedpath);
if (ret) {
if(rspac.data) {
krb5_pac p = NULL;
krb5_data_free(&rspac);
- ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | HDB_F_CANON,
+ ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
if (ret) {
const char *msg;
goto out;
}
+ ret = _krb5_principalname2krb5_principal(context,
+ &tp,
+ adtkt.cname,
+ adtkt.crealm);
+ if (ret)
+ goto out;
+
+ ret = krb5_unparse_name(context, tp, &tpn);
+ if (ret)
+ goto out;
+
+ ret = _krb5_principalname2krb5_principal(context,
+ &dp,
+ t->sname,
+ t->realm);
+ if (ret)
+ goto out;
+
+ ret = krb5_unparse_name(context, dp, &dpn);
+ if (ret)
+ goto out;
+
/* check that ticket is valid */
if (adtkt.flags.forwardable == 0) {
kdc_log(context, config, 0,
"Missing forwardable flag on ticket for "
- "constrained delegation from %s to %s ", cpn, spn);
+ "constrained delegation from %s (%s) as %s to %s ",
+ cpn, dpn, tpn, spn);
ret = KRB5KDC_ERR_BADOPTION;
goto out;
}
- ret = check_constrained_delegation(context, config, clientdb,
- client, sp);
+ ret = check_constrained_delegation(context, config, clientdb,
+ client, server, sp);
if (ret) {
kdc_log(context, config, 0,
- "constrained delegation from %s to %s not allowed",
- cpn, spn);
+ "constrained delegation from %s (%s) as %s to %s not allowed",
+ cpn, dpn, tpn, spn);
goto out;
}
- ret = _krb5_principalname2krb5_principal(context,
- &tp,
- adtkt.cname,
- adtkt.crealm);
- if (ret)
+ ret = verify_flags(context, config, &adtkt, tpn);
+ if (ret) {
goto out;
+ }
- ret = krb5_unparse_name(context, tp, &tpn);
- if (ret)
- goto out;
+ krb5_data_free(&rspac);
- ret = verify_flags(context, config, &adtkt, tpn);
+ /*
+ * generate the PAC for the user.
+ *
+ * TODO: pass in t->sname and t->realm and build
+ * a S4U_DELEGATION_INFO blob to the PAC.
+ */
+ ret = check_PAC(context, config, tp, dp,
+ client, server, krbtgt,
+ &clientkey->key, &tkey_check->key,
+ ekey, &tkey_sign->key,
+ &adtkt, &rspac, &ad_signedpath);
if (ret) {
+ const char *msg = krb5_get_error_message(context, ret);
+ kdc_log(context, config, 0,
+ "Verify delegated PAC failed to %s for client"
+ "%s (%s) as %s from %s with %s",
+ spn, cpn, dpn, tpn, from, msg);
+ krb5_free_error_message(context, msg);
goto out;
}
ret = check_KRB5SignedPath(context,
config,
krbtgt,
- tp,
+ cp,
&adtkt,
NULL,
&ad_signedpath);
- if (ret == 0 && !ad_signedpath)
- ret = KRB5KDC_ERR_BADOPTION;
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
"KRB5SignedPath check from service %s failed "
- "for delegation to %s for client %s "
+ "for delegation to %s for client %s (%s)"
"from %s failed with %s",
- spn, tpn, cpn, from, msg);
+ spn, tpn, dpn, cpn, from, msg);
krb5_free_error_message(context, msg);
goto out;
}
+ if (!ad_signedpath) {
+ ret = KRB5KDC_ERR_BADOPTION;
+ kdc_log(context, config, 0,
+ "Ticket not signed with PAC nor SignedPath service %s failed "
+ "for delegation to %s for client %s (%s)"
+ "from %s",
+ spn, tpn, dpn, cpn, from);
+ goto out;
+ }
+
kdc_log(context, config, 0, "constrained delegation for %s "
- "from %s to %s", tpn, cpn, spn);
+ "from %s (%s) to %s", tpn, cpn, dpn, spn);
}
/*
kdc_log(context, config, 0, "Request from wrong address");
goto out;
}
-
+
/*
* If this is an referral, add server referral data to the
* auth_data reply .
&enc_pa_data,
e_text,
reply);
-
+
out:
if (tpn != cpn)
free(tpn);
free(spn);
free(cpn);
-
+ if (dpn)
+ free(dpn);
+
krb5_data_free(&rspac);
krb5_free_keyblock_contents(context, &sessionkey);
if(krbtgt_out)
krb5_free_principal(context, tp);
if (cp)
krb5_free_principal(context, cp);
+ if (dp)
+ krb5_free_principal(context, dp);
if (sp)
krb5_free_principal(context, sp);
if (ref_realm)
if(tgs_req == NULL){
ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
-
+
kdc_log(context, config, 0,
"TGS-REQ from %s without PA-TGS-REQ", from);
goto out;