Exemple #1
0
static void
eval_kgetcred(heim_dict_t o)
{
    heim_string_t server, ccache;
    krb5_get_creds_opt opt;
    heim_bool_t nostore;
    krb5_error_code ret;
    krb5_ccache cc = NULL;
    krb5_principal s;
    krb5_creds *out = NULL;

    if (ptop)
	ptop->tgs_req++;

    server = heim_dict_get_value(o, HSTR("server"));
    if (server == NULL)
	krb5_errx(kdc_context, 1, "no server");

    ccache = heim_dict_get_value(o, HSTR("ccache"));
    if (ccache == NULL)
	krb5_errx(kdc_context, 1, "no ccache");

    nostore = heim_dict_get_value(o, HSTR("nostore"));
    if (nostore == NULL)
	nostore = heim_bool_create(1);

    ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(ccache), &cc);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");

    ret = krb5_parse_name(kdc_context, heim_string_get_utf8(server), &s);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_parse_name");

    ret = krb5_get_creds_opt_alloc(kdc_context, &opt);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_get_creds_opt_alloc");

    if (heim_bool_val(nostore))
	krb5_get_creds_opt_add_options(kdc_context, opt, KRB5_GC_NO_STORE);

    ret = krb5_get_creds(kdc_context, opt, cc, s, &out);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_get_creds");
    
    krb5_free_creds(kdc_context, out);
    krb5_free_principal(kdc_context, s);
    krb5_get_creds_opt_free(kdc_context, opt);
    krb5_cc_close(kdc_context, cc);
}
static void
merge_stack_args_cb(gpointer data, gpointer user_data)
{
	GdbLxValue *v = (GdbLxValue *) data;
	if (v && (v->type = vt_HASH))
	{
		GHashTable *hash = v->hash;
		HSTR(hash, level);
		HLST(hash, args);
		if (level && args)
		{
			gchar *tail;
			gint n = strtoull(level, &tail, 10);
			GdbFrameInfo *frame = NULL;
			GSList *p;
			for (p = frame_list; p; p = p->next)
			{
				if (p->data)
				{
					GdbFrameInfo *f = p->data;
					if (gdbio_atoi(f->level) == n)
					{
						frame = f;
						break;
					}
				}
			}
			if (frame)
			{
				for (p = args; p; p = p->next)
				{
					v = p->data;
					if (v && (v->type = vt_HASH))
					{
						HSTR(v->hash, name);
						HSTR(v->hash, value);
						if (name && value)
						{
							GdbVar *arg = g_new0(GdbVar, 1);
							arg->name = g_strdup(name);
							arg->value = g_strdup(value);
							frame->args =
								g_slist_append(frame->args, arg);
						}
					}
				}
			}
		}
	}
}
Exemple #3
0
static void
eval_object(heim_object_t o)
{
    heim_tid_t t = heim_get_tid(o);

    if (t == heim_array_get_type_id()) {
	heim_array_iterate_f(o, NULL, eval_array_element);
    } else if (t == heim_dict_get_type_id()) {
	const char *op = heim_dict_get_value(o, HSTR("op"));

	heim_assert(op != NULL, "op missing");

	if (strcmp(op, "repeat") == 0) {
	    eval_repeat(o);
	} else if (strcmp(op, "kinit") == 0) {
	    eval_kinit(o);
	} else if (strcmp(op, "kgetcred") == 0) {
	    eval_kgetcred(o);
	} else if (strcmp(op, "kdestroy") == 0) {
	    eval_kdestroy(o);
	} else {
	    errx(1, "unsupported ops %s", op);
	}

    } else
	errx(1, "unsupported");
}
Exemple #4
0
static int
json_db_del_key(void *db, heim_string_t table, heim_data_t key,
		heim_error_t *error)
{
    json_db_t jsondb = db;
    heim_string_t key_string;
    const heim_octet_string *key_data = heim_data_get_data(key);

    if (error)
	*error = NULL;

    if (strnlen(key_data->data, key_data->length) != key_data->length)
	return HEIM_ERROR(error, EINVAL,
			  (EINVAL,
			   N_("JSON DB requires keys that are actually strings",
			      "")));

    key_string = heim_string_create_with_bytes(key_data->data,
					       key_data->length);
    if (key_string == NULL)
	return HEIM_ENOMEM(error);

    if (table == NULL)
	table = HSTR("");

    heim_path_delete(jsondb->dict, error, table, key_string, NULL);
    heim_release(key_string);
    return 0;
}
Exemple #5
0
/**
 * Delete a key and its value from the DB
 *
 *
 * @param db    Open DB handle
 * @param key   Key
 * @param error Output error object
 *
 * @return 0 on success, system error otherwise
 *
 * @addtogroup heimbase
 */
int
heim_db_delete_key(heim_db_t db, heim_string_t table, heim_data_t key,
		   heim_error_t *error)
{
    heim_string_t key64 = NULL;
    int ret;

    if (error != NULL)
	*error = NULL;

    if (table == NULL)
	table = HSTR("");

    if (heim_get_tid(db) != HEIM_TID_DB)
	return EINVAL;

    if (db->plug->delf == NULL)
	return EBADF;

    if (!db->in_transaction) {
	ret = heim_db_begin(db, 0, error);
	if (ret)
	    goto err;
	heim_assert(db->in_transaction, "Internal error");
	ret = heim_db_delete_key(db, table, key, error);
	if (ret) {
	    (void) heim_db_rollback(db, NULL);
	    return ret;
	}
	return heim_db_commit(db, error);
    }

    /* Transaction emulation */
    heim_assert(db->set_keys != NULL, "Internal error");
    key64 = to_base64(key, error);
    if (key64 == NULL)
	return HEIM_ENOMEM(error);
    if (db->ro_tx) {
	ret = heim_db_begin(db, 0, error);
	if (ret)
	    goto err;
    }
    ret = heim_path_create(db->del_keys, 29, heim_number_create(1), error, table, key64, NULL);
    if (ret)
	goto err;
    heim_path_delete(db->set_keys, error, table, key64, NULL);
    heim_release(key64);

    return 0;

err:
    heim_release(key64);
    return HEIM_ERROR(error, ret,
		      (ret, N_("Could not set a dict value while while "
		       "deleting a DB value", "")));
}
Exemple #6
0
static int
db_replay_log(heim_db_t db, heim_error_t *error)
{
    int ret;
    heim_string_t journal_fname = NULL;
    heim_object_t journal;
    size_t len;

    heim_assert(!db->in_transaction, "DB transaction not open");
    heim_assert(db->set_keys == NULL && db->set_keys == NULL, "DB transaction not open");

    if (error)
	*error = NULL;

    if (db->options == NULL)
	return 0;

    journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename"));
    if (journal_fname == NULL)
	return 0;

    ret = read_json(heim_string_get_utf8(journal_fname), &journal, error);
    if (ret == ENOENT)
	return 0;
    if (ret == 0 && journal == NULL)
	return 0;
    if (ret != 0)
	return ret;

    if (heim_get_tid(journal) != HEIM_TID_ARRAY)
	return HEIM_ERROR(error, EINVAL,
			  (ret, N_("Invalid journal contents; delete journal",
				   "")));

    len = heim_array_get_length(journal);

    if (len > 0)
	db->set_keys = heim_array_get_value(journal, 0);
    if (len > 1)
	db->del_keys = heim_array_get_value(journal, 1);
    ret = db_do_log_actions(db, error);
    if (ret)
	return ret;

    /* Truncate replay log and we're done */
    ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error);
    if (ret)
	return ret;
    heim_release(db->set_keys);
    heim_release(db->del_keys);
    db->set_keys = NULL;
    db->del_keys = NULL;

    return 0;
}
Exemple #7
0
static void
eval_repeat(heim_dict_t o)
{
    heim_object_t or = heim_dict_get_value(o, HSTR("value"));
    heim_number_t n = heim_dict_get_value(o, HSTR("num"));
    int i, num;
    struct perf perf;

    perf_start(&perf);

    heim_assert(or != NULL, "value missing");
    heim_assert(n != NULL, "num missing");

    num = heim_number_get_int(n);
    heim_assert(num >= 0, "num >= 0");

    for (i = 0; i < num; i++)
	eval_object(or);

    perf_stop(&perf);
}
static void
stack_cb(gpointer data, gpointer user_data)
{
	GdbLxValue *v = (GdbLxValue *) data;
	if (v && (v->type == vt_HASH))
	{
		GHashTable *frame = v->hash;
		HSTR(frame, level);
		HSTR(frame, addr);
		HSTR(frame, func);
		HSTR(frame, file);
		HSTR(frame, fullname);
		HSTR(frame, line);
		if (!fullname)
			fullname = file;
		if (level && addr && func && fullname && line)
		{
			GdbFrameInfo *frame_info = g_new0(GdbFrameInfo, 1);
			strncpy(frame_info->level, level, sizeof(frame_info->level) - 1);
			strncpy(frame_info->addr, addr, sizeof(frame_info->addr) - 1);
			strncpy(frame_info->line, line, sizeof(frame_info->line) - 1);
			frame_info->func = g_strdup(func);
			frame_info->filename = g_strdup(fullname);
			frame_list = g_slist_append(frame_list, frame_info);
		}
	}
}
Exemple #9
0
static void
eval_kdestroy(heim_dict_t o)
{
    heim_string_t ccache = heim_dict_get_value(o, HSTR("ccache"));;
    krb5_error_code ret;
    const char *name;
    krb5_ccache cc;

    heim_assert(ccache != NULL, "ccache_missing");
	
    name = heim_string_get_utf8(ccache);

    ret = krb5_cc_resolve(kdc_context, name, &cc);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");

    krb5_cc_destroy(kdc_context, cc);
}
static void
get_env_path(gint seq, gchar ** list, gchar * resp)
{
	GHashTable *h = gdbio_get_results(resp, list);
	HSTR(h, path);
	gdbio_pop_seq(seq);
	if (path)
	{
		env_info.path = g_strdup(path);
	}
	else
	{
		gdbio_info_func(_("Failed to retrieve executable search path setting from GDB."));
//    gdblx_dump_table(h);
	}
	if (h)
		g_hash_table_destroy(h);
	gdbio_send_seq_cmd(get_env_dirs, "-environment-directory\n");
}
static void
get_env_cwd(gint seq, gchar ** list, gchar * resp)
{
	GHashTable *h = gdbio_get_results(resp, list);
	HSTR(h, cwd);
	gdbio_pop_seq(seq);
	free_env_info();
	if (cwd)
	{
		env_info.cwd = g_strdup(cwd);
	}
	else
	{
		gdbio_info_func(_("Failed to retrieve working directory setting from GDB."));
//    gdblx_dump_table(h);
	}
	if (h)
		g_hash_table_destroy(h);
	gdbio_send_seq_cmd(get_env_path, "-environment-path\n");
}
Exemple #12
0
/**
 * Lookup a key's value in the DB.
 *
 * Returns 0 on success, -1 if the key does not exist in the DB, or a
 * system error number on failure.
 *
 * @param db    Open DB handle
 * @param key   Key
 * @param error Output error object
 *
 * @return the value (retained), if there is one for the given key
 *
 * @addtogroup heimbase
 */
heim_data_t
heim_db_copy_value(heim_db_t db, heim_string_t table, heim_data_t key,
		   heim_error_t *error)
{
    heim_object_t v;
    heim_data_t result;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return NULL;

    if (error != NULL)
	*error = NULL;

    if (table == NULL)
	table = HSTR("");

    if (db->in_transaction) {
	heim_string_t key64;

	key64 = to_base64(key, error);
	if (key64 == NULL) {
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}

	v = heim_path_copy(db->set_keys, error, table, key64, NULL);
	if (v != NULL) {
	    heim_release(key64);
	    return v;
	}
	v = heim_path_copy(db->del_keys, error, table, key64, NULL); /* can't be NULL */
	heim_release(key64);
	if (v != NULL)
	    return NULL;
    }

    result = db->plug->copyf(db->db_data, table, key, error);

    return result;
}
static void
get_env_dirs(gint seq, gchar ** list, gchar * resp)
{
	GHashTable *h = gdbio_get_results(resp, list);
	HSTR(h, source_path);
	gdbio_pop_seq(seq);
	if (source_path)
	{
		gchar *p;
		env_info.dirs = g_strdup(source_path);
		p = strstr(env_info.dirs, "$cdir:$cwd");
		if (p)
		{
			memmove(p, p + 10, strlen(p + 10) + 1);
		}
		p = strchr(env_info.dirs, '\0');
		if (p)
		{
			while (p > env_info.dirs)
			{
				p--;
				if (*p == ':')
				{
					*p = '\0';
				}
				else
				{
					break;
				}
			}
		}
	}
	else
	{
		gdbio_info_func(_("Failed to retrieve source search path setting from GDB."));
//    gdblx_dump_table(h);
	}
	if (h)
		g_hash_table_destroy(h);
	gdbio_send_seq_cmd(get_env_args, "show args\n");
}
Exemple #14
0
static void
json_db_iter(void *db, heim_string_t table, void *iter_data,
	     heim_db_iterator_f_t iter_f, heim_error_t *error)
{
    json_db_t jsondb = db;
    struct json_db_iter_ctx ctx;
    heim_dict_t table_dict;

    if (error)
	*error = NULL;

    if (table == NULL)
	table = HSTR("");

    table_dict = heim_dict_get_value(jsondb->dict, table);
    if (table_dict == NULL)
	return;

    ctx.iter_ctx = iter_data;
    ctx.iter_f = iter_f;

    heim_dict_iterate_f(table_dict, &ctx, json_db_iter_f);
}
Exemple #15
0
/**
 * Commit an open transaction on the given db.
 *
 * @param db    Open DB handle
 * @param error Output error object
 *
 * @return 0 on success, system error otherwise
 *
 * @addtogroup heimbase
 */
int
heim_db_commit(heim_db_t db, heim_error_t *error)
{
    int ret, ret2;
    heim_string_t journal_fname = NULL;

    if (heim_get_tid(db) != HEIM_TID_DB)
	return EINVAL;
    if (!db->in_transaction)
	return 0;
    if (db->plug->commitf == NULL && db->plug->lockf == NULL)
	return EINVAL;

    if (db->plug->commitf != NULL) {
	ret = db->plug->commitf(db->db_data, error);
	if (ret)
	    (void) db->plug->rollbackf(db->db_data, error);

	db->in_transaction = 0;
	db->ro_tx = 0;
	return ret;
    }

    if (db->ro_tx) {
	ret = 0;
	goto done;
    }

    if (db->options == NULL)
	journal_fname = heim_dict_get_value(db->options, HSTR("journal-filename"));

    if (journal_fname != NULL) {
	heim_array_t a;
	heim_string_t journal_contents;
	size_t len, bytes;
	int save_errno;

	/* Create contents for replay log */
	ret = ENOMEM;
	a = heim_array_create();
	if (a == NULL)
	    goto err;
	ret = heim_array_append_value(a, db->set_keys);
	if (ret) {
	    heim_release(a);
	    goto err;
	}
	ret = heim_array_append_value(a, db->del_keys);
	if (ret) {
	    heim_release(a);
	    goto err;
	}
	journal_contents = heim_json_copy_serialize(a, 0, error);
	heim_release(a);

	/* Write replay log */
	if (journal_fname != NULL) {
	    int fd;

	    ret = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error);
	    if (ret) {
		heim_release(journal_contents);
		goto err;
	    }
	    len = strlen(heim_string_get_utf8(journal_contents));
	    bytes = write(fd, heim_string_get_utf8(journal_contents), len);
	    save_errno = errno;
	    heim_release(journal_contents);
	    ret = close(fd);
	    if (bytes != len) {
		/* Truncate replay log */
		(void) open_file(heim_string_get_utf8(journal_fname), 1, 0, NULL, error);
		ret = save_errno;
		goto err;
	    }
	    if (ret)
		goto err;
	}
    }

    /* Apply logged actions */
    ret = db_do_log_actions(db, error);
    if (ret)
	return ret;

    if (db->plug->syncf != NULL) {
	/* fsync() or whatever */
	ret = db->plug->syncf(db->db_data, error);
	if (ret)
	    return ret;
    }

    /* Truncate replay log and we're done */
    if (journal_fname != NULL) {
	int fd;

	ret2 = open_file(heim_string_get_utf8(journal_fname), 1, 0, &fd, error);
	if (ret2 == 0)
	    (void) close(fd);
    }

    /*
     * Clean up; if we failed to remore the replay log that's OK, we'll
     * handle that again in heim_db_commit()
     */
done:
    heim_release(db->set_keys);
    heim_release(db->del_keys);
    db->set_keys = NULL;
    db->del_keys = NULL;
    db->in_transaction = 0;
    db->ro_tx = 0;

    ret2 = db->plug->unlockf(db->db_data, error);
    if (ret == 0)
	ret = ret2;

    return ret;

err:
    return HEIM_ERROR(error, ret,
		      (ret, N_("Error while committing transaction: %s", ""),
		       strerror(ret)));
}
Exemple #16
0
static int
json_db_open(void *plug, const char *dbtype, const char *dbname,
	     heim_dict_t options, void **db, heim_error_t *error)
{
    json_db_t jsondb;
    heim_dict_t contents = NULL;
    heim_string_t dbname_s = NULL;
    heim_string_t bkpname_s = NULL;

    if (error)
	*error = NULL;
    if (dbtype && *dbtype && strcmp(dbtype, "json"))
	return HEIM_ERROR(error, EINVAL, (EINVAL, N_("Wrong DB type", "")));
    if (dbname && *dbname && strcmp(dbname, "MEMORY") != 0) {
	char *ext = strrchr(dbname, '.');
	char *bkpname;
	size_t len;
	int ret;

	if (ext == NULL || strcmp(ext, ".json") != 0)
	    return HEIM_ERROR(error, EINVAL,
			      (EINVAL, N_("JSON DB files must end in .json",
					  "")));

	if (options) {
	    heim_object_t vc, ve, vt;

	    vc = heim_dict_get_value(options, HSTR("create"));
	    ve = heim_dict_get_value(options, HSTR("exclusive"));
	    vt = heim_dict_get_value(options, HSTR("truncate"));
	    if (vc && vt) {
		ret = open_file(dbname, 1, ve ? 1 : 0, NULL, error);
		if (ret)
		    return ret;
	    } else if (vc || ve || vt) {
		return HEIM_ERROR(error, EINVAL,
				  (EINVAL, N_("Invalid JSON DB open options",
					      "")));
	    }
	    /*
	     * We don't want cloned handles to truncate the DB, eh?
	     *
	     * We should really just create a copy of the options dict
	     * rather than modify the caller's!  But for that it'd be
	     * nicer to have copy utilities in heimbase, something like
	     * this:
	     *
	     * heim_object_t heim_copy(heim_object_t src, int depth,
	     *                         heim_error_t *error);
	     * 
	     * so that options = heim_copy(options, 1); means copy the
	     * dict but nothing else (whereas depth == 0 would mean
	     * heim_retain(), and depth > 1 would be copy that many
	     * levels).
	     */
	    heim_dict_delete_key(options, HSTR("create"));
	    heim_dict_delete_key(options, HSTR("exclusive"));
	    heim_dict_delete_key(options, HSTR("truncate"));
	}
	dbname_s = heim_string_create(dbname);
	if (dbname_s == NULL)
	    return HEIM_ENOMEM(error);
	
	len = snprintf(NULL, 0, "%s~", dbname);
	bkpname = malloc(len + 2);
	if (bkpname == NULL) {
	    heim_release(dbname_s);
	    return HEIM_ENOMEM(error);
	}
	(void) snprintf(bkpname, len + 1, "%s~", dbname);
	bkpname_s = heim_string_create(bkpname);
	free(bkpname);
	if (bkpname_s == NULL) {
	    heim_release(dbname_s);
	    return HEIM_ENOMEM(error);
	}

	ret = read_json(dbname, (heim_object_t *)&contents, error);
	if (ret)
	    return ret;

	if (contents != NULL && heim_get_tid(contents) != HEIM_TID_DICT)
	    return HEIM_ERROR(error, EINVAL,
			      (EINVAL, N_("JSON DB contents not valid JSON",
					  "")));
    }

    jsondb = heim_alloc(sizeof (*jsondb), "json_db", NULL);
    if (jsondb == NULL) {
	heim_release(contents);
	heim_release(dbname_s);
	return ENOMEM;
    }

    jsondb->last_read_time = time(NULL);
    jsondb->fd = -1;
    jsondb->dbname = dbname_s;
    jsondb->bkpname = bkpname_s;
    jsondb->read_only = 0;

    if (contents != NULL)
	jsondb->dict = contents;
    else {
	jsondb->dict = heim_dict_create(29);
	if (jsondb->dict == NULL) {
	    heim_release(jsondb);
	    return ENOMEM;
	}
    }

    *db = jsondb;
    return 0;
}
Exemple #17
0
static krb5_error_code
an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context,
		     const char *rule,
		     krb5_const_principal aname,
		     set_result_f set_res_f, void *set_res_ctx)
{
    krb5_error_code ret;
    const char *an2ln_db_fname;
    heim_db_t dbh = NULL;
    heim_dict_t db_options;
    heim_data_t k, v;
    heim_error_t error;
    char *unparsed = NULL;
    char *value = NULL;

    _krb5_load_db_plugins(context);
    heim_base_once_f(&sorted_text_db_init_once, NULL, sorted_text_db_init_f);

    if (strncmp(rule, "DB:", strlen("DB:") != 0))
	return KRB5_PLUGIN_NO_HANDLE;

    an2ln_db_fname = &rule[strlen("DB:")];
    if (!*an2ln_db_fname)
	return KRB5_PLUGIN_NO_HANDLE;

    ret = krb5_unparse_name(context, aname, &unparsed);
    if (ret)
	return ret;

    db_options = heim_dict_create(11);
    if (db_options != NULL)
	heim_dict_set_value(db_options, HSTR("read-only"),
			    heim_number_create(1));
    dbh = heim_db_create(NULL, an2ln_db_fname, db_options, &error);
    if (dbh == NULL) {
	krb5_set_error_message(context, heim_error_get_code(error),
			       N_("Couldn't open aname2lname-text-db", ""));
	ret = KRB5_PLUGIN_NO_HANDLE;
	goto cleanup;
    }

    /* Binary search; file should be sorted (in C locale) */
    k = heim_data_ref_create(unparsed, strlen(unparsed), NULL);
    if (k == NULL)
	return krb5_enomem(context);
    v = heim_db_copy_value(dbh, NULL, k, &error);
    heim_release(k);
    if (v == NULL && error != NULL) {
	krb5_set_error_message(context, heim_error_get_code(error),
			       N_("Lookup in aname2lname-text-db failed", ""));
	ret = heim_error_get_code(error);
	goto cleanup;
    } else if (v == NULL) {
	ret = KRB5_PLUGIN_NO_HANDLE;
	goto cleanup;
    } else {
	/* found */
	if (heim_data_get_length(v) == 0) {
	    krb5_set_error_message(context, ret,
				   N_("Principal mapped to empty username", ""));
	    ret = KRB5_NO_LOCALNAME;
	    goto cleanup;
	}
	ret = set_res_f(set_res_ctx, heim_data_get_ptr(v));
	heim_release(v);
    }

cleanup:
    heim_release(dbh);
    free(unparsed);
    free(value);
    return ret;
}
Exemple #18
0
static void
eval_kinit(heim_dict_t o)
{
    heim_string_t user, password, keytab, fast_armor_cc, pk_user_id, ccache;
    krb5_get_init_creds_opt *opt;
    krb5_init_creds_context ctx;
    krb5_principal client;
    krb5_keytab ktmem = NULL;
    krb5_ccache fast_cc = NULL;
    krb5_error_code ret;

    if (ptop)
	ptop->as_req++;

    user = heim_dict_get_value(o, HSTR("client"));
    if (user == NULL)
	krb5_errx(kdc_context, 1, "no client");

    password = heim_dict_get_value(o, HSTR("password"));
    keytab = heim_dict_get_value(o, HSTR("keytab"));
    pk_user_id = heim_dict_get_value(o, HSTR("pkinit-user-cert-id"));
    if (password == NULL && keytab == NULL && pk_user_id == NULL)
	krb5_errx(kdc_context, 1, "password, keytab, nor PKINIT user cert ID");

    ccache = heim_dict_get_value(o, HSTR("ccache"));

    ret = krb5_parse_name(kdc_context, heim_string_get_utf8(user), &client);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_unparse_name");

    /* PKINIT parts */
    ret = krb5_get_init_creds_opt_alloc (kdc_context, &opt);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_alloc");

    if (pk_user_id) {
	heim_bool_t rsaobj = heim_dict_get_value(o, HSTR("pkinit-use-rsa"));
	int use_rsa = rsaobj ? heim_bool_val(rsaobj) : 0;

	ret = krb5_get_init_creds_opt_set_pkinit(kdc_context, opt,
						 client,
						 heim_string_get_utf8(pk_user_id),
						 NULL, NULL, NULL,
						 use_rsa ? 2 : 0,
						 NULL, NULL, NULL);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_set_pkinit");
    }

    ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_init_creds_init");

    fast_armor_cc = heim_dict_get_value(o, HSTR("fast-armor-cc"));
    if (fast_armor_cc) {

	ret = krb5_cc_resolve(kdc_context, heim_string_get_utf8(fast_armor_cc), &fast_cc);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");

	ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache");
    }
    
    if (password) {
	ret = krb5_init_creds_set_password(kdc_context, ctx, 
					   heim_string_get_utf8(password));
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_password");
    }
    if (keytab) {
	krb5_keytab kt = NULL;

	ret = krb5_kt_resolve(kdc_context, heim_string_get_utf8(keytab), &kt);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_kt_resolve");

	ret = krb5_kt_resolve(kdc_context, "MEMORY:keytab", &ktmem);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_kt_resolve(MEMORY)");

	ret = copy_keytab(kdc_context, kt, ktmem);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "copy_keytab");

	krb5_kt_close(kdc_context, kt);

	ret = krb5_init_creds_set_keytab(kdc_context, ctx, ktmem);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_keytab");
    }

    ret = krb5_init_creds_get(kdc_context, ctx);
    if (ret)
	krb5_err(kdc_context, 1, ret, "krb5_init_creds_get");

    if (ccache) {
	const char *name = heim_string_get_utf8(ccache);
	krb5_creds cred;
	krb5_ccache cc;

	ret = krb5_init_creds_get_creds(kdc_context, ctx, &cred);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_init_creds_get_creds");

	ret = krb5_cc_resolve(kdc_context, name, &cc);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_cc_resolve");

	krb5_init_creds_store(kdc_context, ctx, cc);

	ret = krb5_cc_close(kdc_context, cc);
	if (ret)
	    krb5_err(kdc_context, 1, ret, "krb5_cc_close");

	krb5_free_cred_contents(kdc_context, &cred);
    }

    krb5_init_creds_free(kdc_context, ctx);

    if (ktmem)
	krb5_kt_close(kdc_context, ktmem);
    if (fast_cc)
	krb5_cc_close(kdc_context, fast_cc);
}