kadm5_ret_t kadm5_s_create_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, const char *password, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; if ((mask & KADM5_KVNO) == 0) { /* create_principal() through _kadm5_setup_entry(), will need this */ princ->kvno = 1; mask |= KADM5_KVNO; } ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_KEY_DATA | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if(ret) goto out; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, password, n_ks_tuple, ks_tuple); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) goto out; } ret = context->db->hdb_store(context->context, context->db, 0, &ent); if (!context->keep_open) context->db->hdb_close(context->context, context->db); if (ret) goto out; kadm5_log_create (context, &ent.entry); out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_create_principal_with_key(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; if ((mask & KADM5_KVNO) == 0) { /* create_principal() through _kadm5_setup_entry(), will need this */ princ->kvno = 1; mask |= KADM5_KVNO; } ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL | KADM5_KEY_DATA, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if (ret) return ret; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if (ret) { hdb_free_entry(context->context, &ent); return ret; } } ret = kadm5_log_init(context); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; /* This logs the change for iprop and writes to the HDB */ ret = kadm5_log_create(context, &ent.entry); out2: (void) kadm5_log_end(context); out: if (!context->keep_open) { kadm5_ret_t ret2; ret2 = context->db->hdb_close(context->context, context->db); if (ret == 0 && ret2 != 0) ret = ret2; } hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_chpass_principal_with_key(void *server_handle, krb5_principal princ, int n_key_data, krb5_key_data *key_data) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); if(ret == HDB_ERR_NOENTRY) goto out; ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data); if(ret) goto out2; ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
static kadm5_ret_t modify_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, uint32_t forbidden_mask) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; if((mask & forbidden_mask)) return KADM5_BAD_MASK; if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) return KADM5_UNK_POLICY; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch(context->context, context->db, princ->principal, HDB_F_GET_ANY, &ent); if(ret) goto out; ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0); if(ret) goto out2; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, mask | KADM5_MOD_NAME | KADM5_MOD_TIME); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_create_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, const char *password) { kadm5_ret_t ret; hdb_entry_ex ent; kadm5_server_context *context = server_handle; ret = create_principal(context, princ, mask, &ent, KADM5_PRINCIPAL, KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_MKVNO | KADM5_AUX_ATTRIBUTES | KADM5_KEY_DATA | KADM5_POLICY_CLR | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT); if(ret) goto out; if ((mask & KADM5_KVNO) == 0) ent.entry.kvno = 1; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, password); if (ret) goto out; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out; ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) goto out; ret = context->db->hdb_store(context->context, context->db, 0, &ent); context->db->hdb_close(context->context, context->db); if (ret) goto out; kadm5_log_create (context, &ent.entry); out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_delete_principal(void *server_handle, krb5_principal princ) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) { krb5_warn(context->context, ret, "opening database"); return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret == HDB_ERR_NOENTRY) goto out; if(ent.entry.flags.immutable) { ret = KADM5_PROTECT_PRINCIPAL; goto out2; } ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_remove(context->context, context->db, princ); if (ret) goto out2; kadm5_log_delete (context, princ); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_rename_principal(void *server_handle, krb5_principal source, krb5_principal target) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; krb5_principal oldname; memset(&ent, 0, sizeof(ent)); if(krb5_principal_compare(context->context, source, target)) return KADM5_DUP; /* XXX is this right? */ ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret){ context->db->hdb_close(context->context, context->db); goto out; } ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; { /* fix salt */ size_t i; Salt salt; krb5_salt salt2; memset(&salt, 0, sizeof(salt)); krb5_get_pw_salt(context->context, source, &salt2); salt.type = hdb_pw_salt; salt.salt = salt2.saltvalue; for(i = 0; i < ent.entry.keys.len; i++){ if(ent.entry.keys.val[i].salt == NULL){ ent.entry.keys.val[i].salt = malloc(sizeof(*ent.entry.keys.val[i].salt)); if(ent.entry.keys.val[i].salt == NULL) return ENOMEM; ret = copy_Salt(&salt, ent.entry.keys.val[i].salt); if(ret) break; } } krb5_free_salt(context->context, salt2); } if(ret) goto out2; oldname = ent.entry.principal; ent.entry.principal = target; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) { ent.entry.principal = oldname; goto out2; } kadm5_log_rename (context, source, &ent.entry); ret = context->db->hdb_store(context->context, context->db, 0, &ent); if(ret){ ent.entry.principal = oldname; goto out2; } ret = context->db->hdb_remove(context->context, context->db, oldname); ent.entry.principal = oldname; out2: context->db->hdb_close(context->context, context->db); hdb_free_entry(context->context, &ent); out: return _kadm5_error_code(ret); }
/** * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE * a previous entry may be replaced. * * @param context The current krb5_context * @param db Heimdal database handle * @param flags May currently only contain HDB_F_REPLACE * @param entry The data to store * * @return 0 if everything worked, an error code if not */ static krb5_error_code hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { int ret; int i; sqlite_int64 entry_id; const HDB_Ext_Aliases *aliases; hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); krb5_data value; sqlite3_stmt *get_ids = hsdb->get_ids; krb5_data_zero(&value); ret = hdb_sqlite_exec_stmt(context, hsdb, "BEGIN IMMEDIATE TRANSACTION", HDB_ERR_UK_SERROR); if(ret != SQLITE_OK) { ret = HDB_ERR_UK_SERROR; krb5_set_error_message(context, ret, "SQLite BEGIN TRANSACTION failed: %s", sqlite3_errmsg(hsdb->db)); goto rollback; } ret = hdb_seal_keys(context, db, &entry->entry); if(ret) { goto rollback; } ret = hdb_entry2value(context, &entry->entry, &value); if(ret) { goto rollback; } ret = bind_principal(context, entry->entry.principal, get_ids, 1); if (ret) goto rollback; ret = hdb_sqlite_step(context, hsdb->db, get_ids); if(ret == SQLITE_DONE) { /* No such principal */ sqlite3_bind_blob(hsdb->add_entry, 1, value.data, value.length, SQLITE_STATIC); ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); sqlite3_clear_bindings(hsdb->add_entry); sqlite3_reset(hsdb->add_entry); if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { ret = HDB_ERR_UK_SERROR; goto rollback; } if (ret == SQLITE_CONSTRAINT) { ret = HDB_ERR_EXISTS; goto rollback; } ret = 0; ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1); if (ret) goto rollback; ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); sqlite3_clear_bindings(hsdb->add_principal); sqlite3_reset(hsdb->add_principal); if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) { ret = HDB_ERR_UK_SERROR; goto rollback; } if (ret == SQLITE_CONSTRAINT) { ret = HDB_ERR_EXISTS; goto rollback; } /* Now let's learn what Entry ID we got for the new principal */ sqlite3_reset(get_ids); ret = hdb_sqlite_step(context, hsdb->db, get_ids); if (ret != SQLITE_ROW) { ret = HDB_ERR_UK_SERROR; goto rollback; } entry_id = sqlite3_column_int64(get_ids, 1); ret = 0; } else if(ret == SQLITE_ROW) { /* Found a principal */ if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */ goto rollback; entry_id = sqlite3_column_int64(get_ids, 1); sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); if (ret != SQLITE_DONE) { ret = HDB_ERR_UK_SERROR; goto rollback; } sqlite3_bind_blob(hsdb->update_entry, 1, value.data, value.length, SQLITE_STATIC); sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); if (ret != SQLITE_DONE) { ret = HDB_ERR_UK_SERROR; goto rollback; } } else { /* Error! */ ret = HDB_ERR_UK_SERROR; goto rollback; } ret = hdb_entry_get_aliases(&entry->entry, &aliases); if(ret || aliases == NULL) goto commit; for(i = 0; i < aliases->aliases.len; i++) { ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1); if (ret) goto rollback; sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); if (ret == SQLITE_CONSTRAINT) { ret = HDB_ERR_EXISTS; goto rollback; } if (ret != SQLITE_DONE) { ret = HDB_ERR_UK_SERROR; goto rollback; } } commit: krb5_data_free(&value); sqlite3_clear_bindings(get_ids); sqlite3_reset(get_ids); if ((flags & HDB_F_PRECHECK)) { (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); return 0; } ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR); if(ret != SQLITE_OK) krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s", (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db)); return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR; rollback: krb5_data_free(&value); sqlite3_clear_bindings(get_ids); sqlite3_reset(get_ids); krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", ret, sqlite3_errmsg(hsdb->db)); (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0); return ret; }
static kadm5_ret_t modify_principal(void *server_handle, kadm5_principal_ent_t princ, uint32_t mask, uint32_t forbidden_mask) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); if((mask & forbidden_mask)) return KADM5_BAD_MASK; if((mask & KADM5_POLICY) && strcmp(princ->policy, "default")) return KADM5_UNK_POLICY; if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; } ret = kadm5_log_init(context); if (ret) goto out; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ->principal, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret) goto out; ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0); if(ret) goto out2; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; /* * If any keys are bogus, disallow the modify. If the keys were * bogus as stored in the HDB we could allow those through, but * distinguishing that case from a pre-1.6 client using add_enctype * without the get-keys privilege requires more work (mainly: checking that * the bogus keys in princ->key_data[] have corresponding bogus keys in ent * before calling _kadm5_setup_entry()). */ if ((mask & KADM5_KEY_DATA) && kadm5_some_keys_are_bogus(princ->n_key_data, princ->key_data)) { ret = KADM5_AUTH_GET_KEYS; /* Not quite appropriate, but it'll do */ goto out2; } ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; if ((mask & KADM5_POLICY)) { HDB_extension ext; memset(&ext, 0, sizeof(ext)); /* XXX should be TRUE, but we don't yet support policies */ ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_policy; ext.data.u.policy = strdup(princ->policy); if (ext.data.u.policy == NULL) { ret = ENOMEM; goto out2; } /* This calls free_HDB_extension(), freeing ext.data.u.policy */ ret = hdb_replace_extension(context->context, &ent.entry, &ext); free(ext.data.u.policy); if (ret) goto out2; } /* This logs the change for iprop and writes to the HDB */ ret = kadm5_log_modify(context, &ent.entry, mask | KADM5_MOD_NAME | KADM5_MOD_TIME); out2: hdb_free_entry(context->context, &ent); out: (void) kadm5_log_end(context); if (!context->keep_open) { kadm5_ret_t ret2; ret2 = context->db->hdb_close(context->context, context->db); if (ret == 0 && ret2 != 0) ret = ret2; } return _kadm5_error_code(ret); }
static kadm5_ret_t change(void *server_handle, krb5_principal princ, int keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, const char *password, int cond) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; Key *keys; size_t num_keys; int existsp = 0; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret) goto out; if (keepold || cond) { /* * We save these for now so we can handle password history checking; * we handle keepold further below. */ ret = hdb_add_current_keys_to_history(context->context, &ent.entry); if (ret) goto out; } if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) { ret = context->db->hdb_password(context->context, context->db, &ent, password, cond); if (ret) goto out2; } else { num_keys = ent.entry.keys.len; keys = ent.entry.keys.val; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, n_ks_tuple, ks_tuple, password); if(ret) { _kadm5_free_keys(context->context, num_keys, keys); goto out2; } _kadm5_free_keys(context->context, num_keys, keys); if (cond) { HDB_extension *ext; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); if (ext != NULL) existsp = _kadm5_exists_keys_hist(ent.entry.keys.val, ent.entry.keys.len, &ext->data.u.hist_keys); } if (existsp) { ret = KADM5_PASS_REUSE; krb5_set_error_message(context->context, ret, "Password reuse forbidden"); goto out2; } } ent.entry.kvno++; ent.entry.flags.require_pwchange = 0; if (keepold) { ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; } else { HDB_extension ext; memset(&ext, 0, sizeof (ext)); ext.data.element = choice_HDB_extension_data_hist_keys; ext.data.u.hist_keys.len = 0; ext.data.u.hist_keys.val = NULL; ret = hdb_replace_extension(context->context, &ent.entry, &ext); if (ret) goto out2; } ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out2: hdb_free_entry(context->context, &ent); out: if (!context->keep_open) context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_randkey_principal(void *server_handle, krb5_principal princ, krb5_keyblock **new_keys, int *n_keys) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret) goto out; ret = _kadm5_set_keys_randomly (context, &ent.entry, new_keys, n_keys); if (ret) goto out2; ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out3; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out3: if (ret) { int i; for (i = 0; i < *n_keys; ++i) krb5_free_keyblock_contents (context->context, &(*new_keys)[i]); free (*new_keys); *new_keys = NULL; *n_keys = 0; } out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
static krb5_error_code LDAP_store(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry) { LDAPMod **mods = NULL; krb5_error_code ret; const char *errfn; int rc; LDAPMessage *msg = NULL, *e = NULL; char *dn = NULL, *name = NULL; ret = LDAP_principal2message(context, db, entry->principal, &msg); if (ret == 0) e = ldap_first_entry(HDB2LDAP(db), msg); ret = krb5_unparse_name(context, entry->principal, &name); if (ret) { free(name); return ret; } ret = hdb_seal_keys(context, db, entry); if (ret) goto out; /* turn new entry into LDAPMod array */ ret = LDAP_entry2mods(context, db, entry, e, &mods); if (ret) goto out; if (e == NULL) { ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db)); if (ret < 0) { krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; goto out; } } else if (flags & HDB_F_REPLACE) { /* Entry exists, and we're allowed to replace it. */ dn = ldap_get_dn(HDB2LDAP(db), e); } else { /* Entry exists, but we're not allowed to replace it. Bail. */ ret = HDB_ERR_EXISTS; goto out; } /* write entry into directory */ if (e == NULL) { /* didn't exist before */ rc = ldap_add_s(HDB2LDAP(db), dn, mods); errfn = "ldap_add_s"; } else { /* already existed, send deltas only */ rc = ldap_modify_s(HDB2LDAP(db), dn, mods); errfn = "ldap_modify_s"; } if (check_ldap(context, db, rc)) { char *ld_error = NULL; ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING, &ld_error); krb5_set_error_string(context, "%s: %s (dn=%s) %s: %s", errfn, name, dn, ldap_err2string(rc), ld_error); ret = HDB_ERR_CANT_LOCK_DB; } else ret = 0; out: /* free stuff */ if (dn) free(dn); if (msg) ldap_msgfree(msg); if (mods) ldap_mods_free(mods, 1); if (name) free(name); return ret; }
/** * Server-side function to set new keys for a principal. */ kadm5_ret_t kadm5_s_setkey_principal_3(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock *keyblocks, int n_keys) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret = 0; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if (ret) return ret; ret = kadm5_log_init(context); if (ret) { if (!context->keep_open) context->db->hdb_close(context->context, context->db); return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (ret) { (void) kadm5_log_end(context); if (!context->keep_open) context->db->hdb_close(context->context, context->db); return ret; } if (keepold) { ret = hdb_add_current_keys_to_history(context->context, &ent.entry); } else ret = hdb_clear_extension(context->context, &ent.entry, choice_HDB_extension_data_hist_keys); /* * Though in practice all real calls to this function will pass an empty * ks_tuple, and cannot in any case employ any salts that require * additional data, we go the extra mile to set any requested salt type * along with a zero length salt value. While we're at it we check that * each ks_tuple's enctype matches the corresponding key enctype. */ if (ret == 0) { int i; free_Keys(&ent.entry.keys); for (i = 0; i < n_keys; ++i) { Key k; Salt s; k.mkvno = 0; k.key = keyblocks[i]; if (n_ks_tuple == 0) k.salt = 0; else { if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) { ret = KADM5_SETKEY3_ETYPE_MISMATCH; break; } s.type = ks_tuple[i].ks_salttype; s.salt.data = 0; s.opaque = 0; k.salt = &s; } if ((ret = add_Keys(&ent.entry.keys, &k)) != 0) break; } } if (ret == 0) { ent.entry.kvno++; ent.entry.flags.require_pwchange = 0; hdb_entry_set_pw_change_time(context->context, &ent.entry, 0); hdb_entry_clear_password(context->context, &ent.entry); if ((ret = hdb_seal_keys(context->context, context->db, &ent.entry)) == 0 && (ret = _kadm5_set_modifier(context, &ent.entry)) == 0 && (ret = _kadm5_bump_pw_expire(context, &ent.entry)) == 0) ret = kadm5_log_modify(context, &ent.entry, KADM5_ATTRIBUTES | KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); } hdb_free_entry(context->context, &ent); (void) kadm5_log_end(context); if (!context->keep_open) context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_randkey_principal(void *server_handle, krb5_principal princ, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **new_keys, int *n_keys) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret) goto out; if (keepold) { ret = hdb_add_current_keys_to_history(context->context, &ent.entry); if (ret) goto out2; } ret = _kadm5_set_keys_randomly (context, &ent.entry, n_ks_tuple, ks_tuple, new_keys, n_keys); if (ret) goto out2; ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out3; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; if (keepold) { ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; } else { HDB_extension ext; ext.data.element = choice_HDB_extension_data_hist_keys; ext.data.u.hist_keys.len = 0; ext.data.u.hist_keys.val = NULL; hdb_replace_extension(context->context, &ent.entry, &ext); } ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out3: if (ret) { int i; for (i = 0; i < *n_keys; ++i) krb5_free_keyblock_contents (context->context, &(*new_keys)[i]); free (*new_keys); *new_keys = NULL; *n_keys = 0; } out2: hdb_free_entry(context->context, &ent); out: if (!context->keep_open) context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
static kadm5_ret_t change(void *server_handle, krb5_principal princ, const char *password, int cond) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; Key *keys; size_t num_keys; int existsp = 0; memset(&ent, 0, sizeof(ent)); ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if(ret) goto out; if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) { ret = context->db->hdb_password(context->context, context->db, &ent, password, cond); if (ret) goto out2; } else { num_keys = ent.entry.keys.len; keys = ent.entry.keys.val; ent.entry.keys.len = 0; ent.entry.keys.val = NULL; ret = _kadm5_set_keys(context, &ent.entry, password); if(ret) { _kadm5_free_keys (context->context, num_keys, keys); goto out2; } if (cond) existsp = _kadm5_exists_keys (ent.entry.keys.val, ent.entry.keys.len, keys, num_keys); _kadm5_free_keys (context->context, num_keys, keys); if (existsp) { ret = KADM5_PASS_REUSE; krb5_set_error_message(context->context, ret, "Password reuse forbidden"); goto out2; } ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; } ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out2: hdb_free_entry(context->context, &ent); out: context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
/** * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE * a previous entry may be replaced. * * @param context The current krb5_context * @param db Heimdal database handle * @param flags May currently only contain HDB_F_REPLACE * @param entry The data to store * * @return 0 if everything worked, an error code if not */ static krb5_error_code hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) { int ret; int i; sqlite_int64 entry_id; char *principal_string = NULL; char *alias_string; const HDB_Ext_Aliases *aliases; hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db); krb5_data value; sqlite3_stmt *get_ids = hsdb->get_ids; ret = hdb_sqlite_exec_stmt(context, hsdb->db, "BEGIN IMMEDIATE TRANSACTION", EINVAL); if(ret != SQLITE_OK) { krb5_set_error_string(context, "SQLite BEGIN TRANSACTION failed: %s", sqlite3_errmsg(hsdb->db)); goto rollback; } ret = krb5_unparse_name(context, entry->entry.principal, &principal_string); if (ret) { goto rollback; } ret = hdb_seal_keys(context, db, &entry->entry); if(ret) { goto rollback; } ret = hdb_entry2value(context, &entry->entry, &value); if(ret) { goto rollback; } sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC); ret = hdb_sqlite_step(context, hsdb->db, get_ids); if(ret == SQLITE_DONE) { /* No such principal */ sqlite3_bind_blob(hsdb->add_entry, 1, value.data, value.length, SQLITE_STATIC); ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry); sqlite3_clear_bindings(hsdb->add_entry); sqlite3_reset(hsdb->add_entry); if(ret != SQLITE_DONE) goto rollback; sqlite3_bind_text(hsdb->add_principal, 1, principal_string, -1, SQLITE_STATIC); ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal); sqlite3_clear_bindings(hsdb->add_principal); sqlite3_reset(hsdb->add_principal); if(ret != SQLITE_DONE) goto rollback; entry_id = sqlite3_column_int64(get_ids, 1); } else if(ret == SQLITE_ROW) { /* Found a principal */ if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */ goto rollback; entry_id = sqlite3_column_int64(get_ids, 1); sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases); if(ret != SQLITE_DONE) goto rollback; sqlite3_bind_blob(hsdb->update_entry, 1, value.data, value.length, SQLITE_STATIC); sqlite3_bind_int64(hsdb->update_entry, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->update_entry); if(ret != SQLITE_DONE) goto rollback; } else { /* Error! */ goto rollback; } ret = hdb_entry_get_aliases(&entry->entry, &aliases); if(ret || aliases == NULL) goto commit; for(i = 0; i < aliases->aliases.len; i++) { ret = krb5_unparse_name(context, &aliases->aliases.val[i], &alias_string); if (ret) { free(alias_string); goto rollback; } sqlite3_bind_text(hsdb->add_alias, 1, alias_string, -1, SQLITE_STATIC); sqlite3_bind_int64(hsdb->add_alias, 2, entry_id); ret = hdb_sqlite_step_once(context, db, hsdb->add_alias); free(alias_string); if(ret != SQLITE_DONE) goto rollback; } ret = 0; commit: free(principal_string); krb5_data_free(&value); sqlite3_clear_bindings(get_ids); sqlite3_reset(get_ids); ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL); if(ret != SQLITE_OK) krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s", ret, sqlite3_errmsg(hsdb->db)); return ret; rollback: krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s", ret, sqlite3_errmsg(hsdb->db)); free(principal_string); ret = hdb_sqlite_exec_stmt(context, hsdb->db, "ROLLBACK", EINVAL); return ret; }
kadm5_ret_t kadm5_s_chpass_principal_with_key(void *server_handle, krb5_principal princ, int keepold, int n_key_data, krb5_key_data *key_data) { kadm5_server_context *context = server_handle; hdb_entry_ex ent; kadm5_ret_t ret; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent); if(ret == HDB_ERR_NOENTRY) goto out; if (keepold) { ret = hdb_add_current_keys_to_history(context->context, &ent.entry); if (ret) goto out2; } ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data); if(ret) goto out2; ent.entry.kvno++; ret = _kadm5_set_modifier(context, &ent.entry); if(ret) goto out2; ret = _kadm5_bump_pw_expire(context, &ent.entry); if (ret) goto out2; if (keepold) { ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out2; } else { HDB_extension ext; memset(&ext, 0, sizeof (ext)); ext.data.element = choice_HDB_extension_data_hist_keys; ext.data.u.hist_keys.len = 0; ext.data.u.hist_keys.val = NULL; hdb_replace_extension(context->context, &ent.entry, &ext); } ret = context->db->hdb_store(context->context, context->db, HDB_F_REPLACE, &ent); if (ret) goto out2; kadm5_log_modify (context, &ent.entry, KADM5_PRINCIPAL | KADM5_MOD_NAME | KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO | KADM5_PW_EXPIRATION | KADM5_TL_DATA); out2: hdb_free_entry(context->context, &ent); out: if (!context->keep_open) context->db->hdb_close(context->context, context->db); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_rename_principal(void *server_handle, krb5_principal source, krb5_principal target) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; krb5_principal oldname; memset(&ent, 0, sizeof(ent)); if (krb5_principal_compare(context->context, source, target)) return KADM5_DUP; /* XXX is this right? */ if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) return ret; } ret = kadm5_log_init(context); if (ret) goto out; ret = context->db->hdb_fetch_kvno(context->context, context->db, source, HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (ret) goto out2; oldname = ent.entry.principal; ret = _kadm5_set_modifier(context, &ent.entry); if (ret) goto out3; { /* fix salt */ size_t i; Salt salt; krb5_salt salt2; memset(&salt, 0, sizeof(salt)); krb5_get_pw_salt(context->context, source, &salt2); salt.type = hdb_pw_salt; salt.salt = salt2.saltvalue; for(i = 0; i < ent.entry.keys.len; i++){ if(ent.entry.keys.val[i].salt == NULL){ ent.entry.keys.val[i].salt = malloc(sizeof(*ent.entry.keys.val[i].salt)); if (ent.entry.keys.val[i].salt == NULL) ret = ENOMEM; else ret = copy_Salt(&salt, ent.entry.keys.val[i].salt); if (ret) break; } } krb5_free_salt(context->context, salt2); } if (ret) goto out3; /* Borrow target */ ent.entry.principal = target; ret = hdb_seal_keys(context->context, context->db, &ent.entry); if (ret) goto out3; /* This logs the change for iprop and writes to the HDB */ ret = kadm5_log_rename(context, source, &ent.entry); out3: ent.entry.principal = oldname; /* Unborrow target */ hdb_free_entry(context->context, &ent); out2: (void) kadm5_log_end(context); out: if (!context->keep_open) { kadm5_ret_t ret2; ret2 = context->db->hdb_close(context->context, context->db); if (ret == 0 && ret2 != 0) ret = ret2; } return _kadm5_error_code(ret); }