int hdb_entry_set_password(krb5_context context, HDB *db, hdb_entry *entry, const char *p) { HDB_extension ext; hdb_master_key key; int ret; ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_password; if (db->hdb_master_key_set) { key = _hdb_find_master_key(NULL, db->hdb_master_key); if (key == NULL) { krb5_set_error_message(context, HDB_ERR_NO_MKEY, "hdb_entry_set_password: "******"failed to find masterkey"); return HDB_ERR_NO_MKEY; } ret = _hdb_mkey_encrypt(context, key, HDB_KU_MKEY, p, strlen(p) + 1, &ext.data.u.password.password); if (ret) return ret; ext.data.u.password.mkvno = malloc(sizeof(*ext.data.u.password.mkvno)); if (ext.data.u.password.mkvno == NULL) { free_HDB_extension(&ext); krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } *ext.data.u.password.mkvno = _hdb_mkey_version(key); } else { ext.data.u.password.mkvno = NULL; ret = krb5_data_copy(&ext.data.u.password.password, p, strlen(p) + 1); if (ret) { krb5_set_error_message(context, ret, "malloc: out of memory"); free_HDB_extension(&ext); return ret; } } ret = hdb_replace_extension(context, entry, &ext); free_HDB_extension(&ext); return ret; }
krb5_error_code hdb_clear_extension(krb5_context context, hdb_entry *entry, int type) { int i; if (entry->extensions == NULL) return 0; for (i = 0; i < entry->extensions->len; i++) { if (entry->extensions->val[i].data.element == type) { free_HDB_extension(&entry->extensions->val[i]); memmove(&entry->extensions->val[i], &entry->extensions->val[i + 1], sizeof(entry->extensions->val[i]) * (entry->extensions->len - i - 1)); entry->extensions->len--; } } if (entry->extensions->len == 0) { free(entry->extensions->val); free(entry->extensions); entry->extensions = NULL; } return 0; }
/** * This function adds an HDB entry's current keyset to the entry's key * history. The current keyset is left alone; the caller is responsible * for freeing it. * * @param context Context * @param entry HDB entry */ krb5_error_code hdb_add_current_keys_to_history(krb5_context context, hdb_entry *entry) { krb5_boolean replace = FALSE; krb5_error_code ret; HDB_extension *ext; HDB_Ext_KeySet *keys; hdb_keyset newkeyset; time_t newtime; if (entry->keys.len == 0) return 0; /* nothing to do */ ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); if (ext == NULL) { replace = TRUE; ext = calloc(1, sizeof (*ext)); if (ext == NULL) return krb5_enomem(context); ext->data.element = choice_HDB_extension_data_hist_keys; } keys = &ext->data.u.hist_keys; ext->mandatory = FALSE; /* * Copy in newest old keyset */ ret = hdb_entry_get_pw_change_time(entry, &newtime); if (ret) goto out; memset(&newkeyset, 0, sizeof(newkeyset)); newkeyset.keys = entry->keys; newkeyset.kvno = entry->kvno; newkeyset.set_time = &newtime; ret = add_HDB_Ext_KeySet(keys, &newkeyset); if (ret) goto out; if (replace) { /* hdb_replace_extension() deep-copies ext; what a waste */ ret = hdb_replace_extension(context, entry, ext); if (ret) goto out; } ret = hdb_prune_keys(context, entry); if (ret) goto out; out: if (replace && ext) { free_HDB_extension(ext); free(ext); } return ret; }
static void add_constrained_delegation(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { krb5_error_code ret; HDB_extension ext; krb5_data buf; size_t size = 0; memset(&ext, 0, sizeof(ext)); ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_allowed_to_delegate_to; if (strings->num_strings == 1 && strings->strings[0][0] == '\0') { ext.data.u.allowed_to_delegate_to.val = NULL; ext.data.u.allowed_to_delegate_to.len = 0; } else { krb5_principal p; int i; ext.data.u.allowed_to_delegate_to.val = calloc(strings->num_strings, sizeof(ext.data.u.allowed_to_delegate_to.val[0])); ext.data.u.allowed_to_delegate_to.len = strings->num_strings; for (i = 0; i < strings->num_strings; i++) { ret = krb5_parse_name(contextp, strings->strings[i], &p); if (ret) abort(); ret = copy_Principal(p, &ext.data.u.allowed_to_delegate_to.val[i]); if (ret) abort(); krb5_free_principal(contextp, p); } } ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length, &ext, &size, ret); free_HDB_extension(&ext); if (ret) abort(); if (buf.length != size) abort(); add_tl(princ, KRB5_TL_EXTENSION, &buf); }
/** * This function adds a key to an HDB entry's key history. * * @param context Context * @param entry HDB entry * @param kvno Key version number of the key to add to the history * @param key The Key to add */ krb5_error_code hdb_add_history_key(krb5_context context, hdb_entry *entry, krb5_kvno kvno, Key *key) { size_t i; hdb_keyset keyset; HDB_Ext_KeySet *hist_keys; HDB_extension ext; HDB_extension *extp; krb5_error_code ret; memset(&keyset, 0, sizeof (keyset)); memset(&ext, 0, sizeof (ext)); extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys); if (extp == NULL) { ext.data.element = choice_HDB_extension_data_hist_keys; extp = &ext; } extp->mandatory = FALSE; hist_keys = &extp->data.u.hist_keys; for (i = 0; i < hist_keys->len; i++) { if (hist_keys->val[i].kvno == kvno) { ret = add_Keys(&hist_keys->val[i].keys, key); goto out; } } keyset.kvno = kvno; ret = add_Keys(&keyset.keys, key); if (ret) goto out; ret = add_HDB_Ext_KeySet(hist_keys, &keyset); if (ret) goto out; if (extp == &ext) { ret = hdb_replace_extension(context, entry, &ext); if (ret) goto out; } out: free_hdb_keyset(&keyset); free_HDB_extension(&ext); return ret; }
static kadm5_ret_t perform_tl_data(krb5_context context, HDB *db, hdb_entry_ex *ent, const krb5_tl_data *tl_data) { kadm5_ret_t ret = 0; if (tl_data->tl_data_type == KRB5_TL_PASSWORD) { heim_utf8_string pw = tl_data->tl_data_contents; if (pw[tl_data->tl_data_length] != '\0') return KADM5_BAD_TL_TYPE; ret = hdb_entry_set_password(context, db, &ent->entry, pw); } else if (tl_data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) { unsigned char *s; time_t t; if (tl_data->tl_data_length != 4) return KADM5_BAD_TL_TYPE; s = tl_data->tl_data_contents; t = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); ret = hdb_entry_set_pw_change_time(context, &ent->entry, t); } else if (tl_data->tl_data_type == KRB5_TL_EXTENSION) { HDB_extension ext; ret = decode_HDB_extension(tl_data->tl_data_contents, tl_data->tl_data_length, &ext, NULL); if (ret) return KADM5_BAD_TL_TYPE; ret = hdb_replace_extension(context, &ent->entry, &ext); free_HDB_extension(&ext); } else { return KADM5_BAD_TL_TYPE; } return ret; }
static void add_pkinit_acl(krb5_context contextp, kadm5_principal_ent_rec *princ, struct getarg_strings *strings) { krb5_error_code ret; HDB_extension ext; krb5_data buf; size_t size = 0; int i; memset(&ext, 0, sizeof(ext)); ext.mandatory = FALSE; ext.data.element = choice_HDB_extension_data_pkinit_acl; ext.data.u.aliases.case_insensitive = 0; if (strings->num_strings == 1 && strings->strings[0][0] == '\0') { ext.data.u.pkinit_acl.val = NULL; ext.data.u.pkinit_acl.len = 0; } else { ext.data.u.pkinit_acl.val = calloc(strings->num_strings, sizeof(ext.data.u.pkinit_acl.val[0])); ext.data.u.pkinit_acl.len = strings->num_strings; for (i = 0; i < strings->num_strings; i++) { ext.data.u.pkinit_acl.val[i].subject = estrdup(strings->strings[i]); } } ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length, &ext, &size, ret); free_HDB_extension(&ext); if (ret) abort(); if (buf.length != size) abort(); add_tl(princ, KRB5_TL_EXTENSION, &buf); }
krb5_error_code hdb_replace_extension(krb5_context context, hdb_entry *entry, const HDB_extension *ext) { HDB_extension *ext2; HDB_extension *es; int ret; ext2 = NULL; if (entry->extensions == NULL) { entry->extensions = calloc(1, sizeof(*entry->extensions)); if (entry->extensions == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } } else if (ext->data.element != choice_HDB_extension_data_asn1_ellipsis) { ext2 = hdb_find_extension(entry, ext->data.element); } else { /* * This is an unknown extention, and we are asked to replace a * possible entry in `entry' that is of the same type. This * might seem impossible, but ASN.1 CHOICE comes to our * rescue. The first tag in each branch in the CHOICE is * unique, so just find the element in the list that have the * same tag was we are putting into the list. */ Der_class replace_class, list_class; Der_type replace_type, list_type; unsigned int replace_tag, list_tag; size_t size; int i; ret = der_get_tag(ext->data.u.asn1_ellipsis.data, ext->data.u.asn1_ellipsis.length, &replace_class, &replace_type, &replace_tag, &size); if (ret) { krb5_set_error_string(context, "hdb: failed to decode " "replacement hdb extention"); return ret; } for (i = 0; i < entry->extensions->len; i++) { HDB_extension *ext3 = &entry->extensions->val[i]; if (ext3->data.element != choice_HDB_extension_data_asn1_ellipsis) continue; ret = der_get_tag(ext3->data.u.asn1_ellipsis.data, ext3->data.u.asn1_ellipsis.length, &list_class, &list_type, &list_tag, &size); if (ret) { krb5_set_error_string(context, "hdb: failed to decode " "present hdb extention"); return ret; } if (MAKE_TAG(replace_class,replace_type,replace_type) == MAKE_TAG(list_class,list_type,list_type)) { ext2 = ext3; break; } } } if (ext2) { free_HDB_extension(ext2); ret = copy_HDB_extension(ext, ext2); if (ret) krb5_set_error_string(context, "hdb: failed to copy replacement " "hdb extention"); return ret; } es = realloc(entry->extensions->val, (entry->extensions->len+1)*sizeof(entry->extensions->val[0])); if (es == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } entry->extensions->val = es; ret = copy_HDB_extension(ext, &entry->extensions->val[entry->extensions->len]); if (ret == 0) entry->extensions->len++; else krb5_set_error_string(context, "hdb: failed to copy new extension"); return ret; }