Esempio n. 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;
}
Esempio n. 2
0
/**
 * This function prunes an HDB entry's keys that are too old to have been used
 * to mint still valid tickets (based on the entry's maximum ticket lifetime).
 * 
 * @param context   Context
 * @param entry	    HDB entry
 */
krb5_error_code
hdb_prune_keys(krb5_context context, hdb_entry *entry)
{
    HDB_extension *ext;
    HDB_Ext_KeySet *keys;
    size_t nelem;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    if (ext == NULL)
	return 0;
    keys = &ext->data.u.hist_keys;
    nelem = keys->len;

    /* Optionally drop key history for keys older than now - max_life */
    if (entry->max_life != NULL && nelem > 0
	&& krb5_config_get_bool_default(context, NULL, FALSE,
					"kadmin", "prune-key-history", NULL)) {
	hdb_keyset *elem;
	time_t ceiling = time(NULL) - *entry->max_life;
	time_t keep_time = 0;
	size_t i;

	/*
	 * Compute most recent key timestamp that predates the current time
	 * by at least the entry's maximum ticket lifetime.
	 */
	for (i = 0; i < nelem; ++i) {
	    elem = &keys->val[i];
	    if (elem->set_time && *elem->set_time < ceiling
		&& (keep_time == 0 || *elem->set_time > keep_time))
		keep_time = *elem->set_time;
	}

	/* Drop obsolete entries */
	if (keep_time) {
	    for (i = 0; i < nelem; /* see below */) {
		elem = &keys->val[i];
		if (elem->set_time && *elem->set_time < keep_time) {
		    remove_HDB_Ext_KeySet(keys, i);
		    /*
		     * Removing the i'th element shifts the tail down, continue
		     * at same index with reduced upper bound.
		     */
		    --nelem;
		    continue;
		}
		++i;
	    }
	}
    }

    return 0;
}
Esempio n. 3
0
/**
 * This function changes an hdb_entry's kvno, swapping the current key
 * set with a historical keyset.  If no historical keys are found then
 * an error is returned (the caller can still set entry->kvno directly).
 *
 * @param context	krb5_context
 * @param new_kvno	New kvno for the entry
 * @param entry		hdb_entry to modify
 */
krb5_error_code
hdb_change_kvno(krb5_context context, krb5_kvno new_kvno, hdb_entry *entry)
{
    HDB_extension ext;
    HDB_extension *extp;
    hdb_keyset keyset;
    HDB_Ext_KeySet *hist_keys;
    size_t i;
    int found = 0;
    krb5_error_code ret;

    if (entry->kvno == new_kvno)
	return 0;

    extp = hdb_find_extension(entry, choice_HDB_extension_data_hist_keys);
    if (extp == NULL) {
	memset(&ext, 0, sizeof (ext));
	ext.data.element = choice_HDB_extension_data_hist_keys;
	extp = &ext;
    }

    memset(&keyset, 0, sizeof (keyset));
    hist_keys = &extp->data.u.hist_keys;
    for (i = 0; i < hist_keys->len; i++) {
	if (hist_keys->val[i].kvno == new_kvno) {
	    found = 1;
	    ret = copy_hdb_keyset(&hist_keys->val[i], &keyset);
	    if (ret)
		goto out;
	    ret = remove_HDB_Ext_KeySet(hist_keys, i);
	    if (ret)
		goto out;
	    break;
	}
    }

    if (!found)
	return HDB_ERR_KVNO_NOT_FOUND;

    ret = hdb_add_current_keys_to_history(context, entry);
    if (ret)
	goto out;

    /* Note: we do nothing with keyset.set_time */
    entry->kvno = new_kvno;
    entry->keys = keyset.keys; /* shortcut */
    memset(&keyset.keys, 0, sizeof (keyset.keys));

out:
    free_hdb_keyset(&keyset);
    return ret;
}
Esempio n. 4
0
krb5_error_code
hdb_entry_get_aliases(const hdb_entry *entry, const HDB_Ext_Aliases **a)
{
    const HDB_extension *ext;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_aliases);
    if (ext)
	*a = &ext->data.u.aliases;
    else
	*a = NULL;

    return 0;
}
Esempio n. 5
0
krb5_error_code
hdb_entry_get_pw_change_time(const hdb_entry *entry, time_t *t)
{
    const HDB_extension *ext;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_last_pw_change);
    if (ext)
	*t = ext->data.u.last_pw_change;
    else
	*t = 0;

    return 0;
}
Esempio n. 6
0
krb5_error_code
hdb_entry_get_pkinit_hash(const hdb_entry *entry, const HDB_Ext_PKINIT_hash **a)
{
    const HDB_extension *ext;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_pkinit_cert_hash);
    if (ext)
	*a = &ext->data.u.pkinit_cert_hash;
    else
	*a = NULL;

    return 0;
}
Esempio n. 7
0
krb5_error_code
hdb_entry_get_ConstrainedDelegACL(const hdb_entry *entry, 
				  const HDB_Ext_Constrained_delegation_acl **a)
{
    const HDB_extension *ext;

    ext = hdb_find_extension(entry, 
			     choice_HDB_extension_data_allowed_to_delegate_to);
    if (ext)
	*a = &ext->data.u.allowed_to_delegate_to;
    else
	*a = NULL;

    return 0;
}
Esempio n. 8
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;
}
Esempio n. 9
0
const Keys *
hdb_kvno2keys(krb5_context context,
	      const hdb_entry *e,
	      krb5_kvno kvno)
{
    HDB_Ext_KeySet *hist_keys;
    HDB_extension *extp;
    size_t i;

    if (kvno == 0)
	return &e->keys;

    extp = hdb_find_extension(e, choice_HDB_extension_data_hist_keys);
    if (extp == NULL)
	return 0;

    hist_keys = &extp->data.u.hist_keys;
    for (i = 0; i < hist_keys->len; i++) {
	if (hist_keys->val[i].kvno == kvno)
	    return &hist_keys->val[i].keys;
    }

    return NULL;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
int
hdb_entry_get_password(krb5_context context, HDB *db, 
		       const hdb_entry *entry, char **p)
{
    HDB_extension *ext;
    char *str;
    int ret;

    ext = hdb_find_extension(entry, choice_HDB_extension_data_password);
    if (ext) {
	heim_utf8_string str;
	heim_octet_string pw;

	if (db->hdb_master_key_set && ext->data.u.password.mkvno) {
	    hdb_master_key key;

	    key = _hdb_find_master_key(ext->data.u.password.mkvno, 
				       db->hdb_master_key);

	    if (key == NULL) {
		krb5_set_error_string(context, "master key %d missing",
				      *ext->data.u.password.mkvno);
		return HDB_ERR_NO_MKEY;
	    }

	    ret = _hdb_mkey_decrypt(context, key, HDB_KU_MKEY,
				    ext->data.u.password.password.data,
				    ext->data.u.password.password.length,
				    &pw);
	} else {
	    ret = der_copy_octet_string(&ext->data.u.password.password, &pw);
	}
	if (ret) {
	    krb5_clear_error_string(context);
	    return ret;
	}

	str = pw.data;
	if (str[pw.length - 1] != '\0') {
	    krb5_set_error_string(context, "password malformated");
	    return EINVAL;
	}

	*p = strdup(str);

	der_free_octet_string(&pw);
	if (*p == NULL) {
	    krb5_set_error_string(context, "malloc: out of memory");
	    return ENOMEM;
	}
	return 0;
    }

    ret = krb5_unparse_name(context, entry->principal, &str);
    if (ret == 0) {
	krb5_set_error_string(context, "no password attributefor %s", str);
	free(str);
    } else 
	krb5_clear_error_string(context);

    return ENOENT;
}
Esempio n. 13
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);
}
Esempio n. 14
0
krb5_error_code
entry2mit_string_int(krb5_context context, krb5_storage *sp, hdb_entry *ent)
{
    krb5_error_code ret;
    ssize_t sz;
    size_t i, k;
    size_t num_tl_data = 0;
    size_t num_key_data = 0;
    char *p;
    HDB_Ext_KeySet *hist_keys = NULL;
    HDB_extension *extp;
    time_t last_pw_chg = 0;
    time_t exp = 0;
    time_t pwexp = 0;
    unsigned int max_life = 0;
    unsigned int max_renew = 0;

    if (ent->modified_by)
        num_tl_data++;

    ret = hdb_entry_get_pw_change_time(ent, &last_pw_chg);
    if (ret) return ret;
    if (last_pw_chg)
        num_tl_data++;

    extp = hdb_find_extension(ent, choice_HDB_extension_data_hist_keys);
    if (extp)
        hist_keys = &extp->data.u.hist_keys;

    for (i = 0; i < ent->keys.len;i++) {
        if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
            ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
            continue;
        num_key_data++;
    }
    if (hist_keys) {
        for (i = 0; i < hist_keys->len; i++) {
            /*
             * MIT uses the highest kvno as the current kvno instead of
             * tracking kvno separately, so we can't dump keysets with kvno
             * higher than the entry's kvno.
             */
            if (hist_keys->val[i].kvno >= ent->kvno)
                continue;
            for (k = 0; k < hist_keys->val[i].keys.len; k++) {
                if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
                    ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
                    continue;
                num_key_data++;
            }
        }
    }

    ret = krb5_unparse_name(context, ent->principal, &p);
    if (ret) return ret;
    sz = append_string(context, sp, "princ\t38\t%u\t%u\t%u\t0\t%s\t%d",
                       strlen(p), num_tl_data, num_key_data, p,
                       flags_to_attr(ent->flags));
    free(p);
    if (sz == -1) return ENOMEM;

    if (ent->max_life)
        max_life = *ent->max_life;
    if (ent->max_renew)
        max_renew = *ent->max_renew;
    if (ent->valid_end)
        exp = *ent->valid_end;
    if (ent->pw_end)
        pwexp = *ent->pw_end;

    sz = append_string(context, sp, "\t%u\t%u\t%u\t%u\t0\t0\t0",
                       max_life, max_renew, exp, pwexp);
    if (sz == -1) return ENOMEM;

    /* Dump TL data we know: last pw chg and modified_by */
#define mit_KRB5_TL_LAST_PWD_CHANGE     1
#define mit_KRB5_TL_MOD_PRINC           2
    if (last_pw_chg) {
        krb5_data d;
        time_t val;
        unsigned char *ptr;
        
        ptr = (unsigned char *)&last_pw_chg;
        val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
        d.data = &val;
        d.length = sizeof (last_pw_chg);
        sz = append_string(context, sp, "\t%u\t%u\t",
                           mit_KRB5_TL_LAST_PWD_CHANGE, d.length);
        if (sz == -1) return ENOMEM;
        sz = append_hex(context, sp, 1, 1, &d);
        if (sz == -1) return ENOMEM;
    }
    if (ent->modified_by) {
        krb5_data d;
        unsigned int val;
        size_t plen;
        unsigned char *ptr;
        char *modby_p;

        ptr = (unsigned char *)&ent->modified_by->time;
        val = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
        d.data = &val;
        d.length = sizeof (ent->modified_by->time);
        ret = krb5_unparse_name(context, ent->modified_by->principal, &modby_p);
        if (ret) return ret;
        plen = strlen(modby_p);
        sz = append_string(context, sp, "\t%u\t%u\t",
                           mit_KRB5_TL_MOD_PRINC,
                           d.length + plen + 1 /* NULL counted */);
        if (sz == -1) return ENOMEM;
        sz = append_hex(context, sp, 1, 1, &d);
        if (sz == -1) {
            free(modby_p);
            return ENOMEM;
        }
        d.data = modby_p;
        d.length = plen + 1;
        sz = append_hex(context, sp, 1, 1, &d);
        free(modby_p);
        if (sz == -1) return ENOMEM;
    }
    /*
     * Dump keys (remembering to not include any with kvno higher than
     * the entry's because MIT doesn't track entry kvno separately from
     * the entry's keys -- max kvno is it)
     */
    for (i = 0; i < ent->keys.len; i++) {
        if (ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD4 ||
            ent->keys.val[i].key.keytype == ETYPE_DES_CBC_MD5)
            continue;
        sz = append_mit_key(context, sp, ent->principal, ent->kvno,
                            &ent->keys.val[i]);
        if (sz == -1) return ENOMEM;
    }
    for (i = 0; hist_keys && i < ent->kvno; i++) {
        size_t m;

        /* dump historical keys */
        for (k = 0; k < hist_keys->len; k++) {
            if (hist_keys->val[k].kvno != ent->kvno - i)
                continue;
            for (m = 0; m < hist_keys->val[k].keys.len; m++) {
                if (ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD4 ||
                    ent->keys.val[k].key.keytype == ETYPE_DES_CBC_MD5)
                    continue;
                sz = append_mit_key(context, sp, ent->principal,
                                    hist_keys->val[k].kvno,
                                    &hist_keys->val[k].keys.val[m]);
                if (sz == -1) return ENOMEM;
            }
        }
    }
    sz = append_string(context, sp, "\t-1;"); /* "extra data" */
    if (sz == -1) return ENOMEM;
    return 0;
}