This should allow master key rollover.
(but the real reason is to allow multiple krbtgt accounts, as used by
Active Directory to implement RODC support)
return ret;
}
ret = _kdc_db_fetch(context, config, sprinc, HDB_F_GET_SERVER,
- NULL, server);
+ NULL, NULL, server);
krb5_free_principal(context, sprinc);
if (ret) {
kdc_log(context, config, 0,
krb5_principal_set_type(context, client, KRB5_NT_NTLM);
ret = _kdc_db_fetch(context, config, client,
- HDB_F_GET_CLIENT, NULL, &user);
+ HDB_F_GET_CLIENT, NULL, NULL, &user);
krb5_free_principal(context, client);
if (ret)
goto failed;
return ret;
ret = _kdc_db_fetch(context, config, clientprincipal,
- HDB_F_GET_CLIENT, &db, &user);
+ HDB_F_GET_CLIENT, NULL, &db, &user);
krb5_free_principal(context, clientprincipal);
if (ret)
return ret;
krb5_clear_error_message(context);
ret = _kdc_db_fetch(context, config, principal,
- HDB_F_GET_SERVER, NULL, &server);
+ HDB_F_GET_SERVER, NULL, NULL, &server);
if (ret)
goto out;
}
ret = _kdc_db_fetch(context, config, principal,
- HDB_F_GET_CLIENT, NULL, &client);
+ HDB_F_GET_CLIENT, NULL, NULL, &client);
krb5_free_principal(context, principal);
if (ret)
goto out;
goto failed;
ret = _kdc_db_fetch(context, config, clientprincipal,
- HDB_F_GET_CLIENT, NULL, &user);
+ HDB_F_GET_CLIENT, NULL, NULL, &user);
krb5_free_principal(context, clientprincipal);
if (ret) {
krb5_set_error_message(context, ret,
goto failed;
ret = _kdc_db_fetch(context, config, clientprincipal,
- HDB_F_GET_CLIENT, NULL, &user);
+ HDB_F_GET_CLIENT, NULL, NULL, &user);
krb5_free_principal(context, clientprincipal);
if (ret) {
krb5_set_error_message(context, ret, "NTLM user %s not in database",
ret = krb5_unparse_name(context, princ, &s);
if (ret)
return FALSE;
- ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, &ent);
+ ret = _kdc_db_fetch(context, ctx->config, princ, ctx->flags, NULL, NULL, &ent);
if (ret) {
kdc_log(context, ctx->config, 7, "Lookup %s failed: %s", s,
krb5_get_err_text (context, ret));
valid_princ, &ctx, 0, &p);
if(ret)
return ret;
- ret = _kdc_db_fetch(context, config, p, flags, NULL, ent);
+ ret = _kdc_db_fetch(context, config, p, flags, NULL, NULL, ent);
krb5_free_principal(context, p);
return ret;
}
}
ret = _kdc_db_fetch(context, config, tgt_princ,
- HDB_F_GET_KRBTGT, NULL, &tgt);
+ HDB_F_GET_KRBTGT, NULL, NULL, &tgt);
if(ret){
char *s;
s = kdc_log_msg(context, config, 0, "Ticket-granting ticket not "
*/
ret = _kdc_db_fetch(context, config, client_princ,
- HDB_F_GET_CLIENT | flags, &clientdb, &client);
+ HDB_F_GET_CLIENT | flags, NULL,
+ &clientdb, &client);
if(ret){
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, msg);
ret = _kdc_db_fetch(context, config, server_princ,
HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
- NULL, &server);
+ NULL, NULL, &server);
if(ret){
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name, msg);
const krb5_principal client_principal,
hdb_entry_ex *client,
hdb_entry_ex *server,
+ hdb_entry_ex *krbtgt,
const EncryptionKey *server_key,
- const EncryptionKey *krbtgt_key,
+ const EncryptionKey *krbtgt_check_key,
+ const EncryptionKey *krbtgt_sign_key,
EncTicketPart *tkt,
krb5_data *rspac,
int *signedpath)
ret = krb5_pac_verify(context, pac, tkt->authtime,
client_principal,
- krbtgt_key, NULL);
+ krbtgt_check_key, NULL);
if (ret) {
krb5_pac_free(context, pac);
return ret;
}
ret = _kdc_pac_verify(context, client_principal,
- client, server, &pac, &signed_pac);
+ client, server, krbtgt, &pac, &signed_pac);
if (ret) {
krb5_pac_free(context, pac);
return ret;
*signedpath = 1;
ret = _krb5_pac_sign(context, pac, tkt->authtime,
client_principal,
- server_key, krbtgt_key, rspac);
+ server_key, krbtgt_sign_key, rspac);
}
krb5_pac_free(context, pac);
ap_req.ticket.sname,
ap_req.ticket.realm);
- ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
+ ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
if(ret) {
const char *msg = krb5_get_error_message(context, ret);
krb5_kvno kvno;
krb5_data rspac;
+ hdb_entry_ex *krbtgt_out = NULL;
+
METHOD_DATA enc_pa_data;
PrincipalName *s;
char opt_str[128];
int signedpath = 0;
- Key *tkey;
+ Key *tkey_check;
+ Key *tkey_sign;
memset(&sessionkey, 0, sizeof(sessionkey));
memset(&adtkt, 0, sizeof(adtkt));
}
_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
ret = _kdc_db_fetch(context, config, p,
- HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
+ HDB_F_GET_KRBTGT, t->enc_part.kvno,
NULL, &uu);
krb5_free_principal(context, p);
if(ret){
server_lookup:
ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
- NULL, &server);
+ NULL, NULL, &server);
if(ret){
const char *new_rlm, *msg;
}
ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
- &clientdb, &client);
+ NULL, &clientdb, &client);
if(ret) {
const char *krbtgt_realm, *msg;
*/
ret = hdb_enctype2key(context, &krbtgt->entry,
- krbtgt_etype, &tkey);
+ krbtgt_etype, &tkey_check);
if(ret) {
kdc_log(context, config, 0,
"Failed to find key for krbtgt PAC check");
goto out;
}
+ /* Now refetch the krbtgt, but get the current kvno (the sign check may have been on an old kvno) */
+ ret = _kdc_db_fetch(context, config, krbtgt->entry.principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
+ if (ret) {
+ kdc_log(context, config, 0,
+ "Failed to find krbtgt in DB for krbtgt PAC signature");
+ goto out;
+ }
+
+ ret = hdb_enctype2key(context, &krbtgt_out->entry,
+ krbtgt_etype, &tkey_sign);
+ if(ret) {
+ kdc_log(context, config, 0,
+ "Failed to find key for krbtgt PAC signature");
+ goto out;
+ }
+
ret = check_PAC(context, config, cp,
- client, server, ekey, &tkey->key,
+ client, server, krbtgt, ekey, &tkey_check->key, &tkey_sign->key,
tgt, &rspac, &signedpath);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
krb5_pac p = NULL;
krb5_data_free(&rspac);
ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON,
- &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
+ NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
if (ret) {
const char *msg;
if (p != NULL) {
ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
s4u2self_impersonated_client->entry.principal,
- ekey, &tkey->key,
+ ekey, &tkey_sign->key,
&rspac);
krb5_pac_free(context, p);
if (ret) {
spn,
client,
cp,
- krbtgt,
+ krbtgt_out,
krbtgt_etype,
spp,
&rspac,
krb5_data_free(&rspac);
krb5_free_keyblock_contents(context, &sessionkey);
+ if(krbtgt_out)
+ _kdc_free_ent(context, krbtgt_out);
if(server)
_kdc_free_ent(context, server);
if(client)
krb5_kdc_configuration *config,
krb5_const_principal principal,
unsigned flags,
+ krb5int32 *kvno_ptr,
HDB **db,
hdb_entry_ex **h)
{
hdb_entry_ex *ent;
krb5_error_code ret;
int i;
+ unsigned kvno = 0;
+
+ if (kvno_ptr) {
+ kvno = *kvno_ptr;
+ flags |= HDB_F_KVNO_SPECIFIED;
+ }
ent = calloc (1, sizeof (*ent));
if (ent == NULL) {
continue;
}
- ret = config->db[i]->hdb_fetch(context,
- config->db[i],
- principal,
- flags | HDB_F_DECRYPT,
- ent);
+ if (config->db[i]->hdb_fetch_kvno) {
+ ret = config->db[i]->hdb_fetch_kvno(context,
+ config->db[i],
+ principal,
+ flags | HDB_F_DECRYPT,
+ kvno,
+ ent);
+ } else {
+ flags &= ~HDB_F_KVNO_SPECIFIED;
+ ret = config->db[i]->hdb_fetch(context,
+ config->db[i],
+ principal,
+ flags | HDB_F_DECRYPT,
+ ent);
+ }
+
krb5_free_principal(context, enterprise_principal);
config->db[i]->hdb_close(context, config->db[i]);
const krb5_principal client_principal,
hdb_entry_ex *client,
hdb_entry_ex *server,
+ hdb_entry_ex *krbtgt,
krb5_pac *pac,
int *verified)
{
return 0;
ret = windcft->pac_verify(windcctx, context,
- client_principal, client, server, pac);
+ client_principal, client, server, krbtgt, pac);
if (ret == 0)
*verified = 1;
return ret;
const krb5_principal,
struct hdb_entry_ex *,
struct hdb_entry_ex *,
+ struct hdb_entry_ex *,
krb5_pac *);
typedef krb5_error_code
}
static krb5_error_code
-hkt_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
- unsigned flags, hdb_entry_ex * entry)
+hkt_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
+ unsigned flags, unsigned kvno, hdb_entry_ex * entry)
{
hdb_keytab k = (hdb_keytab)db->hdb_db;
krb5_error_code ret;
krb5_keytab_entry ktentry;
+ if (!(flags & HDB_F_KVNO_SPECIFIED)) {
+ /* Preserve previous behaviour if no kvno specified */
+ kvno = 0;
+ }
+
memset(&ktentry, 0, sizeof(ktentry));
entry->entry.flags.server = 1;
* enctypes should work.
*/
- ret = krb5_kt_get_entry(context, k->keytab, principal, 0, 0, &ktentry);
+ ret = krb5_kt_get_entry(context, k->keytab, principal, kvno, 0, &ktentry);
if (ret) {
ret = HDB_ERR_NOENTRY;
goto out;
return ret;
}
+static krb5_error_code
+hkt_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
+ unsigned flags, hdb_entry_ex * entry)
+{
+ return hkt_fetch_kvno(context, db, principal, flags & ~HDB_F_KVNO_SPECIFIED, 0, entry);
+}
+
static krb5_error_code
hkt_store(krb5_context context, HDB * db, unsigned flags,
hdb_entry_ex * entry)
(*db)->hdb_open = hkt_open;
(*db)->hdb_close = hkt_close;
(*db)->hdb_fetch = hkt_fetch;
+ (*db)->hdb_fetch_kvno = hkt_fetch_kvno;
(*db)->hdb_store = hkt_store;
(*db)->hdb_remove = NULL;
(*db)->hdb_firstkey = hkt_firstkey;
#define HDB_F_GET_ANY 28 /* fetch any of client,server,krbtgt */
#define HDB_F_CANON 32 /* want canonicalition */
#define HDB_F_ADMIN_DATA 64 /* want data that kdc don't use */
+#define HDB_F_KVNO_SPECIFIED 128 /* we want a particular KVNO */
/* hdb_capability_flags */
#define HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL 1
* should be fetch: client, server, krbtgt.
*/
krb5_error_code (*hdb_fetch)(krb5_context, struct HDB*,
- krb5_const_principal, unsigned,
+ krb5_const_principal, unsigned,
hdb_entry_ex*);
+ /**
+ * Fetch an entry from the backend
+ *
+ * Fetch an entry from the backend, flags are what type of entry
+ * should be fetch: client, server, krbtgt.
+ * knvo (if specified and flags HDB_F_KVNO_SPECIFIED set) is the kvno to get
+ */
+ krb5_error_code (*hdb_fetch_kvno)(krb5_context, struct HDB*,
+ krb5_const_principal, unsigned, unsigned,
+ hdb_entry_ex*);
/**
* Store an entry to database
*/
(*db->hdb_destroy)(context, db);
goto out2;
}
- ret = (*db->hdb_fetch)(context, db, principal,
- HDB_F_DECRYPT|
- HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
- &ent);
+
+ if (*db->hdb_fetch_kvno) {
+ ret = (*db->hdb_fetch_kvno)(context, db, principal,
+ HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ kvno, &ent);
+ } else {
+ ret = (*db->hdb_fetch)(context, db, principal,
+ HDB_F_DECRYPT|
+ HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT,
+ &ent);
+ }
if(ret == HDB_ERR_NOENTRY) {
ret = KRB5_KT_NOTFOUND;