diff options
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb.c | 26 | ||||
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb.h | 21 | ||||
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb_mkey.c | 148 | ||||
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb_passwords.c | 2 | ||||
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb_principals.c | 13 | ||||
-rw-r--r-- | ipaserver/install/krbinstance.py | 7 |
6 files changed, 161 insertions, 56 deletions
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c index fbcb03bee..7fc575b8f 100644 --- a/daemons/ipa-kdb/ipa_kdb.c +++ b/daemons/ipa-kdb/ipa_kdb.c @@ -43,7 +43,7 @@ struct ipadb_context *ipadb_get_context(krb5_context kcontext) static void ipadb_context_free(krb5_context kcontext, struct ipadb_context **ctx) { - struct ipadb_global_config *cfg; + struct ipadb_global_config *cfg; size_t c; if (*ctx != NULL) { @@ -69,6 +69,7 @@ static void ipadb_context_free(krb5_context kcontext, free(*ctx); *ctx = NULL; } + krb5_db_set_context(kcontext, NULL); } #define LDAPI_URI_PREFIX "ldapi://" @@ -515,8 +516,13 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext, /* only check for unsupported 'temporary' value for now */ for (i = 0; db_args != NULL && db_args[i] != NULL; i++) { - if (strncmp(db_args[i], IPA_SETUP, sizeof(IPA_SETUP)) == 0) { - ipactx->override_restrictions = true; + if (strncmp(db_args[i], IPA_OVERRIDE, sizeof(IPA_OVERRIDE)) == 0) { + ipactx->special_flags |= IPA_SPECIAL_OVERRIDE_RESTRICTION; + } + + if (strncmp(db_args[i], IPA_SETUP_CREATE, + sizeof(IPA_SETUP_CREATE)) == 0) { + ipactx->special_flags |= IPA_SPECIAL_CREATE_STEP; } if (strncmp(db_args[i], "temporary", 9) == 0) { @@ -578,6 +584,12 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext, goto fail; } + kerr = ipadb_check_master_key(ipactx); + if (kerr != 0) { + ret = ENOENT; + goto fail; + } + return 0; fail: @@ -600,7 +612,9 @@ static krb5_error_code ipadb_create(krb5_context kcontext, char *conf_section, char **db_args) { - return ipadb_init_module(kcontext, conf_section, db_args, 0); + char *setup_args[] = { IPA_OVERRIDE, IPA_SETUP_CREATE, NULL }; + + return ipadb_init_module(kcontext, conf_section, setup_args, 0); } static krb5_error_code ipadb_get_age(krb5_context kcontext, @@ -650,9 +664,9 @@ kdb_vftabl kdb_function_table = { ipadb_free_pwd_policy, /* free_policy */ ipadb_alloc, /* alloc */ ipadb_free, /* free */ - ipadb_fetch_master_key, /* fetch_master_key */ + NULL, /* fetch_master_key */ NULL, /* fetch_master_key_list */ - ipadb_store_master_key_list, /* store_master_key_list */ + NULL, /* store_master_key_list */ NULL, /* dbe_search_enctype */ ipadb_change_pwd, /* change_pwd */ NULL, /* promote_db */ diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index 1fdb409df..a9d66ad2f 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -72,11 +72,15 @@ #define KMASK_TL_DATA 0x040000 #define KMASK_LOAD 0x200000 -#define IPA_SETUP "ipa-setup-override-restrictions" +#define IPA_OVERRIDE "ipa-setup-override-restrictions" +#define IPA_SETUP_CREATE "ipa-setup-create-step" #define IPA_KRB_AUTHZ_DATA_ATTR "ipaKrbAuthzData" #define IPA_USER_AUTH_TYPE "ipaUserAuthType" +#define IPA_SPECIAL_OVERRIDE_RESTRICTION 0x01 +#define IPA_SPECIAL_CREATE_STEP 0x02 + struct ipadb_mspac; enum ipadb_user_auth { @@ -104,7 +108,7 @@ struct ipadb_context { char *kdc_hostname; LDAP *lcontext; krb5_context kcontext; - bool override_restrictions; + uint32_t special_flags; krb5_key_salt_tuple *supp_encs; int n_supp_encs; krb5_key_salt_tuple *def_encs; @@ -226,18 +230,7 @@ krb5_error_code ipadb_check_policy_as(krb5_context kcontext, krb5_pa_data ***e_data); /* MASTER KEY FUNCTIONS */ -krb5_error_code ipadb_fetch_master_key(krb5_context kcontext, - krb5_principal mname, - krb5_keyblock *key, - krb5_kvno *kvno, - char *db_args); -krb5_error_code ipadb_store_master_key_list(krb5_context kcontext, - char *db_arg, - krb5_principal mname, - krb5_keylist_node *keylist, - char *master_pwd); - -krb5_error_code ipadb_create_master_key(krb5_context kcontext); +krb5_error_code ipadb_check_master_key(struct ipadb_context *ipactx); /* PASSWORD FUNCTIONS */ krb5_error_code ipadb_change_pwd(krb5_context context, diff --git a/daemons/ipa-kdb/ipa_kdb_mkey.c b/daemons/ipa-kdb/ipa_kdb_mkey.c index 3d2f9753a..1d208e3cc 100644 --- a/daemons/ipa-kdb/ipa_kdb_mkey.c +++ b/daemons/ipa-kdb/ipa_kdb_mkey.c @@ -27,13 +27,10 @@ static char *krbmkey_attrs[] = { NULL }; -krb5_error_code ipadb_fetch_master_key(krb5_context kcontext, - krb5_principal mname, - krb5_keyblock *key, - krb5_kvno *kvno, - char *db_args) +static krb5_error_code ipadb_fetch_master_key(struct ipadb_context *ipactx, + krb5_keyblock *key, + krb5_kvno *kvno) { - struct ipadb_context *ipactx; LDAPMessage *res = NULL; LDAPMessage *first; struct berval **vals = NULL; @@ -44,11 +41,6 @@ krb5_error_code ipadb_fetch_master_key(krb5_context kcontext, int ret; int i; - ipactx = ipadb_get_context(kcontext); - if (!ipactx) { - return KRB5_KDB_DBNOTINITED; - } - if (!ipactx->lcontext) { ret = ipadb_get_connection(ipactx); if (ret != 0) { @@ -131,15 +123,10 @@ done: return kerr; } -krb5_error_code ipadb_store_master_key_list(krb5_context kcontext, - char *db_arg, - krb5_principal mname, - krb5_keylist_node *keylist, - char *master_pwd) +static krb5_error_code ipadb_store_master_key(struct ipadb_context *ipactx, + krb5_keylist_node *cur_key) { - struct ipadb_context *ipactx; BerElement *be = NULL; - krb5_keyblock k = { 0, 0, 0, NULL }; struct berval mkey; ber_int_t tvno; ber_int_t ttype; @@ -147,16 +134,6 @@ krb5_error_code ipadb_store_master_key_list(krb5_context kcontext, krb5_error_code kerr; int ret; - ipactx = ipadb_get_context(kcontext); - if (!ipactx) { - return KRB5_KDB_DBNOTINITED; - } - - /* we support storing only one key for now */ - if (!keylist || keylist->next) { - return EINVAL; - } - if (!ipactx->lcontext) { ret = ipadb_get_connection(ipactx); if (ret != 0) { @@ -172,10 +149,10 @@ krb5_error_code ipadb_store_master_key_list(krb5_context kcontext, } - tvno = keylist->kvno; - ttype = keylist->keyblock.enctype; - mkey.bv_len = keylist->keyblock.length; - mkey.bv_val = (void *)keylist->keyblock.contents; + tvno = cur_key->kvno; + ttype = cur_key->keyblock.enctype; + mkey.bv_len = cur_key->keyblock.length; + mkey.bv_val = (void *)cur_key->keyblock.contents; ret = ber_printf(be, "{i{iO}}", tvno, ttype, &mkey); if (ret == -1) { @@ -219,7 +196,112 @@ done: if (be) { ber_free(be, 1); } - krb5_free_keyblock_contents(kcontext, &k); ldap_mods_free(mods, 1); return kerr; } + +static krb5_error_code ipadb_update_krbMKey(struct ipadb_context *ipactx, + krb5_keylist_node *master_key, + bool update) +{ + krb5_error_code kerr; + LDAPMessage *res = NULL; + + if (update) { + /* check if we need to update the master key in LDAP for + * older replicas, if the attr is found, keep it updated */ + kerr = ipadb_simple_search(ipactx, ipactx->realm_base, + LDAP_SCOPE_BASE, "(krbMKey=*)", + krbmkey_attrs, &res); + switch (kerr) { + case 0: + ldap_msgfree(res); + break; + case KRB5_KDB_NOENTRY: + return 0; + default: + return kerr; + } + } + + /* FIXME: on domain level X we may want to not add the key */ + kerr = ipadb_store_master_key(ipactx, master_key); + if (kerr) { + com_err("IPA KDB driver", kerr, + "while storing master key (version %d)", + (int)master_key->kvno); + } + return kerr; +} + +krb5_error_code ipadb_check_db_exists(struct ipadb_context *ipactx) +{ + if (ipactx->special_flags & IPA_SPECIAL_CREATE_STEP) return EEXIST; + return 0; +} + +/* See if we have a keytab, if not try to fetch the key from ldap, and + * stash it for the future (upgrade path) */ +krb5_error_code ipadb_check_master_key(struct ipadb_context *ipactx) +{ + krb5_error_code kerr; + char *cmname = NULL; + krb5_principal mname = NULL; + krb5_keyblock mkey = { 0 }; + krb5_keylist_node *keylist; + krb5_kvno mkvno; + + kerr = asprintf(&cmname, KRB5_KDB_M_NAME"@%s", ipactx->realm); + if (kerr < 0) return ENOMEM; + + kerr = krb5_parse_name(ipactx->kcontext, cmname, &mname); + if (kerr) goto done; + + kerr = krb5_db_fetch_mkey(ipactx->kcontext, mname, ENCTYPE_UNKNOWN, + 0, 0, NULL, &mkvno, NULL, &mkey); + if (kerr == 0) kerr = ipadb_check_db_exists(ipactx); + if (kerr && (kerr != KRB5_KDB_CANTREAD_STORED)) goto done; + + if (kerr == KRB5_KDB_CANTREAD_STORED) { + /* check if we have a key in LDAP, and stash it in the keytab */ + kerr = ipadb_fetch_master_key(ipactx, &mkey, &mkvno); + if (kerr == 0) kerr = ipadb_check_db_exists(ipactx); + if (kerr) { + /* if we are setting up then lack of mkey is normal */ + if (ipactx->special_flags & IPA_SPECIAL_CREATE_STEP) kerr = 0; + goto done; + } + + kerr = krb5_db_store_master_key(ipactx->kcontext, NULL, + mname, mkvno, &mkey, NULL); + } else { + /* if override is set do extra checks on ldap keytab so that it + * is uploaded during initial setup if needed */ + if (ipactx->special_flags & IPA_SPECIAL_OVERRIDE_RESTRICTION) { + krb5_keylist_node curkey = { mkey, mkvno, NULL }; + kerr = ipadb_update_krbMKey(ipactx, &curkey, false); + if (kerr) goto done; + } + + /* check if we have the latest kvno as current key. If not stash + * the new keys in the keytab */ + kerr = krb5_db_fetch_mkey_list(ipactx->kcontext, mname, &mkey); + if (kerr) goto done; + + keylist = krb5_db_mkey_list_alias(ipactx->kcontext); + + if (keylist->kvno > mkvno) { + kerr = krb5_db_store_master_key_list(ipactx->kcontext, NULL, + mname, NULL); + + /* we do not consider it fatal if this fails on update */ + (void)ipadb_update_krbMKey(ipactx, keylist, true); + } + } + +done: + krb5_free_keyblock_contents(ipactx->kcontext, &mkey); + krb5_free_principal(ipactx->kcontext, mname); + free(cmname); + return kerr; +} diff --git a/daemons/ipa-kdb/ipa_kdb_passwords.c b/daemons/ipa-kdb/ipa_kdb_passwords.c index ad57181d5..5932eefbd 100644 --- a/daemons/ipa-kdb/ipa_kdb_passwords.c +++ b/daemons/ipa-kdb/ipa_kdb_passwords.c @@ -124,7 +124,7 @@ krb5_error_code ipadb_change_pwd(krb5_context context, } if (!db_entry->e_data) { - if (!ipactx->override_restrictions) { + if (!(ipactx->special_flags & IPA_SPECIAL_OVERRIDE_RESTRICTION)) { return EINVAL; } else { /* kadmin is creating a new principal */ diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index e32be856a..b3c6b5032 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -1855,7 +1855,16 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, } /* KADM5_TL_DATA */ + /* apparently, at least some versions of kdb5_util fails to set this + * flag when t sets master key rotation infomation in TL_DATA. + * So for now check if KADM5_KEY_DATA has been set, and just overwrite + * TL_DATA if any is present */ +#if KADM5_ACTUALLY_SETS_KADM5_TL_DATA_ON_MASTER_KEY_ROTATION if (entry->mask & KMASK_TL_DATA) { +#else + if (entry->n_tl_data && + entry->mask & KMASK_KEY_DATA) { +#endif kerr = ipadb_get_tl_data(entry, KRB5_TL_LAST_ADMIN_UNLOCK, sizeof(time32le), @@ -2015,7 +2024,7 @@ static krb5_error_code ipadb_add_principal(krb5_context kcontext, goto done; } - if (!ipactx->override_restrictions) { + if (!(ipactx->special_flags & IPA_SPECIAL_OVERRIDE_RESTRICTION)) { return KRB5_KDB_CONSTRAINT_VIOLATION; } @@ -2233,7 +2242,7 @@ krb5_error_code ipadb_delete_principal(krb5_context kcontext, return KRB5_KDB_DBNOTINITED; } - if (!ipactx->override_restrictions) { + if (!(ipactx->special_flags & IPA_SPECIAL_OVERRIDE_RESTRICTION)) { return KRB5_KDB_CONSTRAINT_VIOLATION; } diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py index 4f1995f7b..214945301 100644 --- a/ipaserver/install/krbinstance.py +++ b/ipaserver/install/krbinstance.py @@ -273,6 +273,13 @@ class KrbInstance(service.Service): os.chmod(path, chmod) def __init_ipa_kdb(self): + # Save away old stash file if any + old_stash = os.path.join(paths.VAR_KERBEROS_KRB5KDC_DIR, + '.k5.' + self.realm) + if os.path.exists(old_stash): + self.fstore.backup_file(old_stash); + os.unlink(old_stash); + # kdb5_util may take a very long time when entropy is low installutils.check_entropy() |