static kadm5_ret_t add_tl_data(kadm5_principal_ent_t ent, int16_t type, const void *data, size_t size) { krb5_tl_data *tl; tl = calloc(1, sizeof(*tl)); if (tl == NULL) return _kadm5_error_code(ENOMEM); tl->tl_data_type = type; tl->tl_data_length = size; tl->tl_data_contents = malloc(size); if (tl->tl_data_contents == NULL && size != 0) { free(tl); return _kadm5_error_code(ENOMEM); } memcpy(tl->tl_data_contents, data, size); tl->tl_data_next = ent->tl_data; ent->tl_data = tl; ent->n_tl_data++; return 0; }
kadm5_ret_t kadm5_s_get_principals(void *server_handle, const char *expression, char ***princs, int *count) { struct foreach_data d; kadm5_server_context *context = server_handle; kadm5_ret_t ret; ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) { krb5_warn(context->context, ret, "opening database"); return ret; } d.exp = expression; { krb5_realm r; krb5_get_default_realm(context->context, &r); asprintf(&d.exp2, "%s@%s", expression, r); free(r); } d.princs = NULL; d.count = 0; ret = hdb_foreach(context->context, context->db, HDB_F_ADMIN_DATA, foreach, &d); context->db->hdb_close(context->context, context->db); if(ret == 0) ret = add_princ(&d, NULL); if(ret == 0){ *princs = d.princs; *count = d.count - 1; }else kadm5_free_name_list(context, d.princs, &d.count); free(d.exp2); 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_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_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); }
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); }
/** * 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); }
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); }
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { kadm5_server_context *context = server_handle; kadm5_ret_t ret; hdb_entry_ex ent; memset(&ent, 0, sizeof(ent)); if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDONLY, 0); if(ret) return ret; } ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, HDB_F_DECRYPT|HDB_F_ALL_KVNOS| HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent); if (!context->keep_open) context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) { HDB_extension *ext; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_policy); if (ext == NULL) { out->policy = strdup("default"); /* It's OK if we retun NULL instead of "default" */ } else { out->policy = strdup(ext->data.u.policy); if (out->policy == NULL) { ret = ENOMEM; goto out; } } } if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; size_t n_keys = ent.entry.keys.len; krb5_salt salt; HDB_extension *ext; HDB_Ext_KeySet *hist_keys = NULL; ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys); if (ext != NULL) hist_keys = &ext->data.u.hist_keys; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) n_keys += hist_keys->val[i].keys.len; out->key_data = malloc(n_keys * sizeof(*out->key_data)); if (out->key_data == NULL && n_keys != 0) { ret = ENOMEM; goto out; } out->n_key_data = 0; ret = copy_keyset_to_kadm5(context, ent.entry.kvno, ent.entry.keys.len, ent.entry.keys.val, &salt, out); if (ret) goto out; for (i = 0; hist_keys != NULL && i < hist_keys->len; i++) { ret = copy_keyset_to_kadm5(context, hist_keys->val[i].kvno, hist_keys->val[i].keys.len, hist_keys->val[i].keys.val, &salt, out); if (ret) goto out; } krb5_free_salt(context->context, salt); assert( out->n_key_data == n_keys ); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: hdb_free_entry(context->context, &ent); return _kadm5_error_code(ret); }
kadm5_ret_t kadm5_s_get_principal(void *server_handle, krb5_principal princ, kadm5_principal_ent_t out, uint32_t mask) { 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_RDONLY, 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); context->db->hdb_close(context->context, context->db); if(ret) return _kadm5_error_code(ret); memset(out, 0, sizeof(*out)); if(mask & KADM5_PRINCIPAL) ret = krb5_copy_principal(context->context, ent.entry.principal, &out->principal); if(ret) goto out; if(mask & KADM5_PRINC_EXPIRE_TIME && ent.entry.valid_end) out->princ_expire_time = *ent.entry.valid_end; if(mask & KADM5_PW_EXPIRATION && ent.entry.pw_end) out->pw_expiration = *ent.entry.pw_end; if(mask & KADM5_LAST_PWD_CHANGE) hdb_entry_get_pw_change_time(&ent.entry, &out->last_pwd_change); if(mask & KADM5_ATTRIBUTES){ out->attributes |= ent.entry.flags.postdate ? 0 : KRB5_KDB_DISALLOW_POSTDATED; out->attributes |= ent.entry.flags.forwardable ? 0 : KRB5_KDB_DISALLOW_FORWARDABLE; out->attributes |= ent.entry.flags.initial ? KRB5_KDB_DISALLOW_TGT_BASED : 0; out->attributes |= ent.entry.flags.renewable ? 0 : KRB5_KDB_DISALLOW_RENEWABLE; out->attributes |= ent.entry.flags.proxiable ? 0 : KRB5_KDB_DISALLOW_PROXIABLE; out->attributes |= ent.entry.flags.invalid ? KRB5_KDB_DISALLOW_ALL_TIX : 0; out->attributes |= ent.entry.flags.require_preauth ? KRB5_KDB_REQUIRES_PRE_AUTH : 0; out->attributes |= ent.entry.flags.server ? 0 : KRB5_KDB_DISALLOW_SVR; out->attributes |= ent.entry.flags.change_pw ? KRB5_KDB_PWCHANGE_SERVICE : 0; out->attributes |= ent.entry.flags.ok_as_delegate ? KRB5_KDB_OK_AS_DELEGATE : 0; out->attributes |= ent.entry.flags.trusted_for_delegation ? KRB5_KDB_TRUSTED_FOR_DELEGATION : 0; out->attributes |= ent.entry.flags.allow_kerberos4 ? KRB5_KDB_ALLOW_KERBEROS4 : 0; out->attributes |= ent.entry.flags.allow_digest ? KRB5_KDB_ALLOW_DIGEST : 0; } if(mask & KADM5_MAX_LIFE) { if(ent.entry.max_life) out->max_life = *ent.entry.max_life; else out->max_life = INT_MAX; } if(mask & KADM5_MOD_TIME) { if(ent.entry.modified_by) out->mod_date = ent.entry.modified_by->time; else out->mod_date = ent.entry.created_by.time; } if(mask & KADM5_MOD_NAME) { if(ent.entry.modified_by) { if (ent.entry.modified_by->principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.modified_by->principal, &out->mod_name); } else if(ent.entry.created_by.principal != NULL) ret = krb5_copy_principal(context->context, ent.entry.created_by.principal, &out->mod_name); else out->mod_name = NULL; } if(ret) goto out; if(mask & KADM5_KVNO) out->kvno = ent.entry.kvno; if(mask & KADM5_MKVNO) { size_t n; out->mkvno = 0; /* XXX */ for(n = 0; n < ent.entry.keys.len; n++) if(ent.entry.keys.val[n].mkvno) { out->mkvno = *ent.entry.keys.val[n].mkvno; /* XXX this isn't right */ break; } } #if 0 /* XXX implement */ if(mask & KADM5_AUX_ATTRIBUTES) ; if(mask & KADM5_LAST_SUCCESS) ; if(mask & KADM5_LAST_FAILED) ; if(mask & KADM5_FAIL_AUTH_COUNT) ; #endif if(mask & KADM5_POLICY) out->policy = NULL; if(mask & KADM5_MAX_RLIFE) { if(ent.entry.max_renew) out->max_renewable_life = *ent.entry.max_renew; else out->max_renewable_life = INT_MAX; } if(mask & KADM5_KEY_DATA){ size_t i; Key *key; krb5_key_data *kd; krb5_salt salt; krb5_data *sp; krb5_get_pw_salt(context->context, ent.entry.principal, &salt); out->key_data = malloc(ent.entry.keys.len * sizeof(*out->key_data)); if (out->key_data == NULL && ent.entry.keys.len != 0) { ret = ENOMEM; goto out; } for(i = 0; i < ent.entry.keys.len; i++){ key = &ent.entry.keys.val[i]; kd = &out->key_data[i]; kd->key_data_ver = 2; kd->key_data_kvno = ent.entry.kvno; kd->key_data_type[0] = key->key.keytype; if(key->salt) kd->key_data_type[1] = key->salt->type; else kd->key_data_type[1] = KRB5_PADATA_PW_SALT; /* setup key */ kd->key_data_length[0] = key->key.keyvalue.length; kd->key_data_contents[0] = malloc(kd->key_data_length[0]); if(kd->key_data_contents[0] == NULL && kd->key_data_length[0] != 0){ ret = ENOMEM; break; } memcpy(kd->key_data_contents[0], key->key.keyvalue.data, kd->key_data_length[0]); /* setup salt */ if(key->salt) sp = &key->salt->salt; else sp = &salt.saltvalue; kd->key_data_length[1] = sp->length; kd->key_data_contents[1] = malloc(kd->key_data_length[1]); if(kd->key_data_length[1] != 0 && kd->key_data_contents[1] == NULL) { memset(kd->key_data_contents[0], 0, kd->key_data_length[0]); ret = ENOMEM; break; } memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]); out->n_key_data = i + 1; } krb5_free_salt(context->context, salt); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } if(mask & KADM5_TL_DATA) { time_t last_pw_expire; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_Aliases *aliases; ret = hdb_entry_get_pw_change_time(&ent.entry, &last_pw_expire); if (ret == 0 && last_pw_expire) { unsigned char buf[4]; _krb5_put_int(buf, last_pw_expire, sizeof(buf)); ret = add_tl_data(out, KRB5_TL_LAST_PWD_CHANGE, buf, sizeof(buf)); } if(ret){ kadm5_free_principal_ent(context, out); goto out; } /* * If the client was allowed to get key data, let it have the * password too. */ if(mask & KADM5_KEY_DATA) { heim_utf8_string pw; ret = hdb_entry_get_password(context->context, context->db, &ent.entry, &pw); if (ret == 0) { ret = add_tl_data(out, KRB5_TL_PASSWORD, pw, strlen(pw) + 1); free(pw); } krb5_clear_error_message(context->context); } ret = hdb_entry_get_pkinit_acl(&ent.entry, &acl); if (ret == 0 && acl) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_PKINIT_acl, buf.data, buf.length, acl, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_PKINIT_ACL, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } ret = hdb_entry_get_aliases(&ent.entry, &aliases); if (ret == 0 && aliases) { krb5_data buf; size_t len; ASN1_MALLOC_ENCODE(HDB_Ext_Aliases, buf.data, buf.length, aliases, &len, ret); if (ret) { kadm5_free_principal_ent(context, out); goto out; } if (len != buf.length) krb5_abortx(context->context, "internal ASN.1 encoder error"); ret = add_tl_data(out, KRB5_TL_ALIASES, buf.data, buf.length); free(buf.data); if (ret) { kadm5_free_principal_ent(context, out); goto out; } } if(ret){ kadm5_free_principal_ent(context, out); goto out; } } out: 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 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); }