Exemple #1
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;
}
Exemple #2
0
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;
}
Exemple #3
0
krb5_error_code
hdb_entry_set_pw_change_time(krb5_context context, 
			     hdb_entry *entry,
			     time_t t)
{
    HDB_extension ext;

    ext.mandatory = FALSE;
    ext.data.element = choice_HDB_extension_data_last_pw_change;
    if (t == 0)
	t = time(NULL);
    ext.data.u.last_pw_change = t;

    return hdb_replace_extension(context, entry, &ext);
}
Exemple #4
0
/**
 * 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;
}
Exemple #5
0
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;
}
Exemple #6
0
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);
}
Exemple #7
0
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);
}
Exemple #8
0
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_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);
}