Пример #1
0
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);
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
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;
    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);
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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);
}
Пример #8
0
/**
 * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
 * a previous entry may be replaced.
 *
 * @param context The current krb5_context
 * @param db      Heimdal database handle
 * @param flags   May currently only contain HDB_F_REPLACE
 * @param entry   The data to store
 *
 * @return        0 if everything worked, an error code if not
 */
static krb5_error_code
hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
                 hdb_entry_ex *entry)
{
    int ret;
    int i;
    sqlite_int64 entry_id;
    const HDB_Ext_Aliases *aliases;

    hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
    krb5_data value;
    sqlite3_stmt *get_ids = hsdb->get_ids;

    krb5_data_zero(&value);

    ret = hdb_sqlite_exec_stmt(context, hsdb,
                               "BEGIN IMMEDIATE TRANSACTION",
                               HDB_ERR_UK_SERROR);
    if(ret != SQLITE_OK) {
	ret = HDB_ERR_UK_SERROR;
        krb5_set_error_message(context, ret,
			       "SQLite BEGIN TRANSACTION failed: %s",
			       sqlite3_errmsg(hsdb->db));
        goto rollback;
    }

    ret = hdb_seal_keys(context, db, &entry->entry);
    if(ret) {
        goto rollback;
    }

    ret = hdb_entry2value(context, &entry->entry, &value);
    if(ret) {
        goto rollback;
    }

    ret = bind_principal(context, entry->entry.principal, get_ids, 1);
    if (ret)
	goto rollback;

    ret = hdb_sqlite_step(context, hsdb->db, get_ids);

    if(ret == SQLITE_DONE) { /* No such principal */

        sqlite3_bind_blob(hsdb->add_entry, 1,
                          value.data, value.length, SQLITE_STATIC);
        ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
        sqlite3_clear_bindings(hsdb->add_entry);
        sqlite3_reset(hsdb->add_entry);
        if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }
        if (ret == SQLITE_CONSTRAINT) {
            ret = HDB_ERR_EXISTS;
            goto rollback;
        }
        ret = 0;

	ret = bind_principal(context, entry->entry.principal, hsdb->add_principal, 1);
	if (ret)
	    goto rollback;

        ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
        sqlite3_clear_bindings(hsdb->add_principal);
        sqlite3_reset(hsdb->add_principal);
        if (ret != SQLITE_DONE && ret != SQLITE_CONSTRAINT) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }
        if (ret == SQLITE_CONSTRAINT) {
            ret = HDB_ERR_EXISTS;
            goto rollback;
        }

        /* Now let's learn what Entry ID we got for the new principal */
        sqlite3_reset(get_ids);
        ret = hdb_sqlite_step(context, hsdb->db, get_ids);
        if (ret != SQLITE_ROW) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }

        entry_id = sqlite3_column_int64(get_ids, 1);

        ret = 0;

    } else if(ret == SQLITE_ROW) { /* Found a principal */

        if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
            goto rollback;

        entry_id = sqlite3_column_int64(get_ids, 1);

        sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
        if (ret != SQLITE_DONE) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }

        sqlite3_bind_blob(hsdb->update_entry, 1,
                          value.data, value.length, SQLITE_STATIC);
        sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
        if (ret != SQLITE_DONE) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }

    } else {
	/* Error! */
        ret = HDB_ERR_UK_SERROR;
        goto rollback;
    }

    ret = hdb_entry_get_aliases(&entry->entry, &aliases);
    if(ret || aliases == NULL)
        goto commit;

    for(i = 0; i < aliases->aliases.len; i++) {

	ret = bind_principal(context, &aliases->aliases.val[i], hsdb->add_alias, 1);
        if (ret)
            goto rollback;

        sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);
        if (ret == SQLITE_CONSTRAINT) {
            ret = HDB_ERR_EXISTS;
            goto rollback;
        }
        if (ret != SQLITE_DONE) {
            ret = HDB_ERR_UK_SERROR;
            goto rollback;
        }
    }

commit:
    krb5_data_free(&value);
    sqlite3_clear_bindings(get_ids);
    sqlite3_reset(get_ids);

    if ((flags & HDB_F_PRECHECK)) {
        (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
        return 0;
    }

    ret = hdb_sqlite_exec_stmt(context, hsdb, "COMMIT", HDB_ERR_UK_SERROR);
    if(ret != SQLITE_OK)
	krb5_warnx(context, "hdb-sqlite: COMMIT problem: %ld: %s",
		   (long)HDB_ERR_UK_SERROR, sqlite3_errmsg(hsdb->db));

    return ret == SQLITE_OK ? 0 : HDB_ERR_UK_SERROR;

rollback:
    krb5_data_free(&value);
    sqlite3_clear_bindings(get_ids);
    sqlite3_reset(get_ids);
    krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
	       ret, sqlite3_errmsg(hsdb->db));

    (void) hdb_sqlite_exec_stmt(context, hsdb, "ROLLBACK", 0);
    return ret;
}
Пример #9
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);
}
Пример #10
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);
}
Пример #11
0
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);
}
Пример #12
0
static krb5_error_code
LDAP_store(krb5_context context, HDB * db, unsigned flags,
	   hdb_entry * entry)
{
    LDAPMod **mods = NULL;
    krb5_error_code ret;
    const char *errfn;
    int rc;
    LDAPMessage *msg = NULL, *e = NULL;
    char *dn = NULL, *name = NULL;

    ret = LDAP_principal2message(context, db, entry->principal, &msg);
    if (ret == 0)
	e = ldap_first_entry(HDB2LDAP(db), msg);

    ret = krb5_unparse_name(context, entry->principal, &name);
    if (ret) {
	free(name);
	return ret;
    }

    ret = hdb_seal_keys(context, db, entry);
    if (ret)
	goto out;

    /* turn new entry into LDAPMod array */
    ret = LDAP_entry2mods(context, db, entry, e, &mods);
    if (ret)
	goto out;

    if (e == NULL) {
	ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db));
	if (ret < 0) {
	    krb5_set_error_string(context, "asprintf: out of memory");
	    ret = ENOMEM;
	    goto out;
	}
    } else if (flags & HDB_F_REPLACE) {
	/* Entry exists, and we're allowed to replace it. */
	dn = ldap_get_dn(HDB2LDAP(db), e);
    } else {
	/* Entry exists, but we're not allowed to replace it. Bail. */
	ret = HDB_ERR_EXISTS;
	goto out;
    }

    /* write entry into directory */
    if (e == NULL) {
	/* didn't exist before */
	rc = ldap_add_s(HDB2LDAP(db), dn, mods);
	errfn = "ldap_add_s";
    } else {
	/* already existed, send deltas only */
	rc = ldap_modify_s(HDB2LDAP(db), dn, mods);
	errfn = "ldap_modify_s";
    }

    if (check_ldap(context, db, rc)) {
	char *ld_error = NULL;
	ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING,
			&ld_error);
	krb5_set_error_string(context, "%s: %s (dn=%s) %s: %s", 
			      errfn, name, dn, ldap_err2string(rc), ld_error);
	ret = HDB_ERR_CANT_LOCK_DB;
    } else
	ret = 0;

  out:
    /* free stuff */
    if (dn)
	free(dn);
    if (msg)
	ldap_msgfree(msg);
    if (mods)
	ldap_mods_free(mods, 1);
    if (name)
	free(name);

    return ret;
}
Пример #13
0
/**
 * 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);
}
Пример #14
0
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);
}
Пример #15
0
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);
}
Пример #16
0
/**
 * Stores an hdb_entry in the database. If flags contains HDB_F_REPLACE
 * a previous entry may be replaced.
 *
 * @param context The current krb5_context
 * @param db      Heimdal database handle
 * @param flags   May currently only contain HDB_F_REPLACE
 * @param entry   The data to store
 *
 * @return        0 if everything worked, an error code if not
 */
static krb5_error_code
hdb_sqlite_store(krb5_context context, HDB *db, unsigned flags,
                 hdb_entry_ex *entry)
{
    int ret;
    int i;
    sqlite_int64 entry_id;
    char *principal_string = NULL;
    char *alias_string;
    const HDB_Ext_Aliases *aliases;

    hdb_sqlite_db *hsdb = (hdb_sqlite_db *)(db->hdb_db);
    krb5_data value;
    sqlite3_stmt *get_ids = hsdb->get_ids;

    ret = hdb_sqlite_exec_stmt(context, hsdb->db,
                               "BEGIN IMMEDIATE TRANSACTION", EINVAL);
    if(ret != SQLITE_OK) {
        krb5_set_error_string(context, "SQLite BEGIN TRANSACTION failed: %s",
                              sqlite3_errmsg(hsdb->db));
        goto rollback;
    }
    
    ret = krb5_unparse_name(context,
                            entry->entry.principal, &principal_string);
    if (ret) {
        goto rollback;
    }

    ret = hdb_seal_keys(context, db, &entry->entry);
    if(ret) {
        goto rollback;
    }

    ret = hdb_entry2value(context, &entry->entry, &value);
    if(ret) {
        goto rollback;
    }

    sqlite3_bind_text(get_ids, 1, principal_string, -1, SQLITE_STATIC);
    ret = hdb_sqlite_step(context, hsdb->db, get_ids);

    if(ret == SQLITE_DONE) { /* No such principal */

        sqlite3_bind_blob(hsdb->add_entry, 1,
                          value.data, value.length, SQLITE_STATIC);
        ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_entry);
        sqlite3_clear_bindings(hsdb->add_entry);
        sqlite3_reset(hsdb->add_entry);
        if(ret != SQLITE_DONE)
            goto rollback;

        sqlite3_bind_text(hsdb->add_principal, 1,
                          principal_string, -1, SQLITE_STATIC);
        ret = hdb_sqlite_step(context, hsdb->db, hsdb->add_principal);
        sqlite3_clear_bindings(hsdb->add_principal);
        sqlite3_reset(hsdb->add_principal);
        if(ret != SQLITE_DONE)
            goto rollback;

        entry_id = sqlite3_column_int64(get_ids, 1);
        
    } else if(ret == SQLITE_ROW) { /* Found a principal */

        if(! (flags & HDB_F_REPLACE)) /* Not allowed to replace it */
            goto rollback;

        entry_id = sqlite3_column_int64(get_ids, 1);

        sqlite3_bind_int64(hsdb->delete_aliases, 1, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->delete_aliases);
        if(ret != SQLITE_DONE)
            goto rollback;

        sqlite3_bind_blob(hsdb->update_entry, 1,
                          value.data, value.length, SQLITE_STATIC);
        sqlite3_bind_int64(hsdb->update_entry, 2, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->update_entry);
        if(ret != SQLITE_DONE)
            goto rollback;

    } else {
	/* Error! */
        goto rollback;
    }

    ret = hdb_entry_get_aliases(&entry->entry, &aliases);
    if(ret || aliases == NULL)
        goto commit;

    for(i = 0; i < aliases->aliases.len; i++) {

        ret = krb5_unparse_name(context, &aliases->aliases.val[i],
				&alias_string);
        if (ret) {
            free(alias_string);
            goto rollback;
        }

        sqlite3_bind_text(hsdb->add_alias, 1, alias_string,
                          -1, SQLITE_STATIC);
        sqlite3_bind_int64(hsdb->add_alias, 2, entry_id);
        ret = hdb_sqlite_step_once(context, db, hsdb->add_alias);

        free(alias_string);
        
        if(ret != SQLITE_DONE)
            goto rollback;
    }

    ret = 0;

commit:

    free(principal_string);
    
    krb5_data_free(&value);

    sqlite3_clear_bindings(get_ids);
    sqlite3_reset(get_ids);
    
    ret = hdb_sqlite_exec_stmt(context, hsdb->db, "COMMIT", EINVAL);
    if(ret != SQLITE_OK)
	krb5_warnx(context, "hdb-sqlite: COMMIT problem: %d: %s",
		   ret, sqlite3_errmsg(hsdb->db));

    return ret;

rollback:

    krb5_warnx(context, "hdb-sqlite: store rollback problem: %d: %s",
	       ret, sqlite3_errmsg(hsdb->db));

    free(principal_string);

    ret = hdb_sqlite_exec_stmt(context, hsdb->db,
                               "ROLLBACK", EINVAL);
    return ret;
}
Пример #17
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);
}
Пример #18
0
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);
}