Example #1
0
File: db.c Project: InvLim/heimdal
static int
db_do_log_actions(heim_db_t db, heim_error_t *error)
{
    int ret;

    if (error)
	*error = NULL;

    db->ret = 0;
    db->error = NULL;
    if (db->set_keys != NULL)
	heim_dict_iterate_f(db->set_keys, db, db_replay_log_set_keys_iter);
    if (db->del_keys != NULL)
	heim_dict_iterate_f(db->del_keys, db, db_replay_log_del_keys_iter);

    ret = db->ret;
    db->ret = 0;
    if (error && db->error) {
	*error = db->error;
	db->error = NULL;
    } else {
	heim_release(db->error);
	db->error = NULL;
    }
    return ret;
}
Example #2
0
static int
base2json(heim_object_t obj, struct twojson *j)
{
    heim_tid_t type;

    if (obj == NULL) {
	indent(j);
	j->out(j->ctx, "<NULL>\n");
    }

    type = heim_get_tid(obj);
    switch (type) {
    case HEIM_TID_ARRAY:
	indent(j);
	j->out(j->ctx, "[\n");
	j->indent++;
	heim_array_iterate_f(obj, j, array2json);
	j->indent--;
	indent(j);
	j->out(j->ctx, "]\n");
	break;

    case HEIM_TID_DICT:
	indent(j);
	j->out(j->ctx, "{\n");
	j->indent++;
	heim_dict_iterate_f(obj, j, dict2json);
	j->indent--;
	indent(j);
	j->out(j->ctx, "}\n");
	break;

    case HEIM_TID_STRING:
	indent(j);
	j->out(j->ctx, "\"");
	j->out(j->ctx, heim_string_get_utf8(obj));
	j->out(j->ctx, "\"");
	break;

    case HEIM_TID_NUMBER: {
	char num[16];
	indent(j);
	snprintf(num, sizeof(num), "%d", heim_number_get_int(obj));
	j->out(j->ctx, num);
	break;
    }
    case HEIM_TID_NULL:
	indent(j);
	j->out(j->ctx, "null");
	break;
    case HEIM_TID_BOOL:
	indent(j);
	j->out(j->ctx, heim_bool_val(obj) ? "true" : "false");
	break;
    default:
	return 1;
    }
    return 0;
}
Example #3
0
File: db.c Project: InvLim/heimdal
static void
db_replay_log_set_keys_iter(heim_object_t table, heim_object_t table_dict,
			    void *arg)
{
    heim_db_t db = arg;

    if (db->ret)
	return;

    db->current_table = table;
    heim_dict_iterate_f(table_dict, db, db_replay_log_table_set_keys_iter);
}
krb5_error_code
krb5_plugin_run_f(krb5_context context,
		  const char *module,
		  const char *name,
		  int min_version,
		  int flags,
		  void *userctx,
		  krb5_error_code (*func)(krb5_context, const void *, void *, void *))
{
    heim_string_t m = heim_string_create(module);
    heim_dict_t dict;
    struct iter_ctx s;

    HEIMDAL_MUTEX_lock(&plugin_mutex);

    dict = heim_dict_copy_value(modules, m);
    heim_release(m);
    if (dict == NULL) {
	HEIMDAL_MUTEX_unlock(&plugin_mutex);
	return KRB5_PLUGIN_NO_HANDLE;
    }

    s.context = context;
    s.name = name;
    s.n = heim_string_create(name);
    s.min_version = min_version;
    s.result = heim_array_create();
    s.func = func;
    s.userctx = userctx;

    heim_dict_iterate_f(dict, search_modules, &s);

    heim_release(dict);

    HEIMDAL_MUTEX_unlock(&plugin_mutex);

    s.ret = KRB5_PLUGIN_NO_HANDLE;

    heim_array_iterate_f(s.result, &s, eval_results);

    heim_release(s.result);
    heim_release(s.n);

    return s.ret;
}
Example #5
0
File: db.c Project: InvLim/heimdal
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);
}
Example #6
0
File: db.c Project: InvLim/heimdal
/**
 * Open a database of the given dbtype.
 *
 * Database type names can be composed of one or more pseudo-DB types
 * and one concrete DB type joined with a '+' between each.  For
 * example: "transaction+bdb" might be a Berkeley DB with a layer above
 * that provides transactions.
 *
 * Options may be provided via a dict (an associative array).  Existing
 * options include:
 *
 *  - "create", with any value (create if DB doesn't exist)
 *  - "exclusive", with any value (exclusive create)
 *  - "truncate", with any value (truncate the DB)
 *  - "read-only", with any value (disallow writes)
 *  - "sync", with any value (make transactions durable)
 *  - "journal-name", with a string value naming a journal file name
 *
 * @param dbtype  Name of DB type
 * @param dbname  Name of DB (likely a file path)
 * @param options Options dict
 * @param db      Output open DB handle
 * @param error   Output error  object
 *
 * @return a DB handle
 *
 * @addtogroup heimbase
 */
heim_db_t
heim_db_create(const char *dbtype, const char *dbname,
	       heim_dict_t options, heim_error_t *error)
{
    heim_string_t s;
    char *p;
    db_plugin plug;
    heim_db_t db;
    int ret = 0;

    if (options == NULL) {
	options = heim_dict_create(11);
	if (options == NULL) {
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}
    } else {
	(void) heim_retain(options);
    }

    if (db_plugins == NULL) {
	heim_release(options);
	return NULL;
    }

    if (dbtype == NULL || *dbtype == '\0') {
	struct dbtype_iter iter_ctx = { NULL, dbname, options, error};

	/* Try all dbtypes */
	heim_dict_iterate_f(db_plugins, &iter_ctx, dbtype_iter2create_f);
	heim_release(options);
	return iter_ctx.db;
    } else if (strstr(dbtype, "json")) {
	(void) heim_db_register(dbtype, NULL, &json_dbt);
    }

    /*
     * Allow for dbtypes that are composed from pseudo-dbtypes chained
     * to a real DB type with '+'.  For example a pseudo-dbtype might
     * add locking, transactions, transcoding of values, ...
     */
    p = strchr(dbtype, '+');
    if (p != NULL)
	s = heim_string_create_with_bytes(dbtype, p - dbtype);
    else
	s = heim_string_create(dbtype);
    if (s == NULL) {
	heim_release(options);
	return NULL;
    }

    HEIMDAL_MUTEX_lock(&db_type_mutex);
    plug = heim_dict_get_value(db_plugins, s);
    HEIMDAL_MUTEX_unlock(&db_type_mutex);
    heim_release(s);
    if (plug == NULL) {
	if (error)
	    *error = heim_error_create(ENOENT,
				       N_("Heimdal DB plugin not found: %s", ""),
				       dbtype);
	heim_release(options);
	return NULL;
    }

    db = _heim_alloc_object(&db_object, sizeof(*db));
    if (db == NULL) {
	heim_release(options);
	return NULL;
    }

    db->in_transaction = 0;
    db->ro_tx = 0;
    db->set_keys = NULL;
    db->del_keys = NULL;
    db->plug = plug;
    db->options = options;

    ret = plug->openf(plug->data, dbtype, dbname, options, &db->db_data, error);
    if (ret) {
	heim_release(db);
	if (error && *error == NULL)
	    *error = heim_error_create(ENOENT,
				       N_("Heimdal DB could not be opened: %s", ""),
				       dbname);
	return NULL;
    }

    ret = db_replay_log(db, error);
    if (ret) {
	heim_release(db);
	return NULL;
    }

    if (plug->clonef == NULL) {
	db->dbtype = heim_string_create(dbtype);
	db->dbname = heim_string_create(dbname);

	if (!db->dbtype || ! db->dbname) {
	    heim_release(db);
	    if (error)
		*error = heim_error_create_enomem();
	    return NULL;
	}
    }

    return db;
}
Example #7
0
File: json.c Project: kaduk/heimdal
static int
base2json(heim_object_t obj, struct twojson *j)
{
    heim_tid_t type;
    int first = 0;

    if (obj == NULL) {
	if (j->flags & HEIM_JSON_F_CNULL2JSNULL) {
	    obj = heim_null_create();
	} else if (j->flags & HEIM_JSON_F_NO_C_NULL) {
	    return EINVAL;
	} else {
	    indent(j);
	    j->out(j->ctx, "<NULL>\n"); /* This is NOT valid JSON! */
	    return 0;
	}
    }

    type = heim_get_tid(obj);
    switch (type) {
    case HEIM_TID_ARRAY:
	indent(j);
	j->out(j->ctx, "[\n");
	j->indent++;
	first = j->first;
	j->first = 1;
	heim_array_iterate_f(obj, j, array2json);
	j->indent--;
	if (!j->first)
	    j->out(j->ctx, "\n");
	indent(j);
	j->out(j->ctx, "]\n");
	j->first = first;
	break;

    case HEIM_TID_DICT:
	indent(j);
	j->out(j->ctx, "{\n");
	j->indent++;
	first = j->first;
	j->first = 1;
	heim_dict_iterate_f(obj, j, dict2json);
	j->indent--;
	if (!j->first)
	    j->out(j->ctx, "\n");
	indent(j);
	j->out(j->ctx, "}\n");
	j->first = first;
	break;

    case HEIM_TID_STRING:
	indent(j);
	j->out(j->ctx, "\"");
	j->out(j->ctx, heim_string_get_utf8(obj));
	j->out(j->ctx, "\"");
	break;

    case HEIM_TID_DATA: {
	heim_dict_t d;
	heim_string_t v;
	const heim_octet_string *data;
	char *b64 = NULL;
	int ret;

	if (j->flags & HEIM_JSON_F_NO_DATA)
	    return EINVAL; /* JSON doesn't do binary */

	data = heim_data_get_data(obj);
	ret = base64_encode(data->data, data->length, &b64);
	if (ret < 0 || b64 == NULL)
	    return ENOMEM;

	if (j->flags & HEIM_JSON_F_NO_DATA_DICT) {
	    indent(j);
	    j->out(j->ctx, "\"");
	    j->out(j->ctx, b64); /* base64-encode; hope there's no aliasing */
	    j->out(j->ctx, "\"");
	    free(b64);
	} else {
	    /*
	     * JSON has no way to represent binary data, therefore the
	     * following is a Heimdal-specific convention.
	     *
	     * We encode binary data as a dict with a single very magic
	     * key with a base64-encoded value.  The magic key includes
	     * a uuid, so we're not likely to alias accidentally.
	     */
	    d = heim_dict_create(2);
	    if (d == NULL) {
		free(b64);
		return ENOMEM;
	    }
	    v = heim_string_ref_create(b64, free);
	    if (v == NULL) {
		free(b64);
		heim_release(d);
		return ENOMEM;
	    }
	    ret = heim_dict_set_value(d, heim_tid_data_uuid_key, v);
	    heim_release(v);
	    if (ret) {
		heim_release(d);
		return ENOMEM;
	    }
	    ret = base2json(d, j);
	    heim_release(d);
	    if (ret)
		return ret;
	}
	break;
    }

    case HEIM_TID_NUMBER: {
	char num[32];
	indent(j);
	snprintf(num, sizeof (num), "%d", heim_number_get_int(obj));
	j->out(j->ctx, num);
	break;
    }
    case HEIM_TID_NULL:
	indent(j);
	j->out(j->ctx, "null");
	break;
    case HEIM_TID_BOOL:
	indent(j);
	j->out(j->ctx, heim_bool_val(obj) ? "true" : "false");
	break;
    default:
	return 1;
    }
    return 0;
}
Example #8
0
/**
 * Run plugins for the given @module (e.g., "krb5") and @name (e.g.,
 * "kuserok").  Specifically, the @func is invoked once per-plugin with
 * four arguments: the @context, the plugin symbol value (a pointer to a
 * struct whose first three fields are the same as struct common_plugin_method),
 * a context value produced by the plugin's init method, and @userctx.
 *
 * @func should unpack arguments for a plugin function and invoke it
 * with arguments taken from @userctx.  @func should save plugin
 * outputs, if any, in @userctx.
 *
 * All loaded and registered plugins are invoked via @func until @func
 * returns something other than KRB5_PLUGIN_NO_HANDLE.  Plugins that
 * have nothing to do for the given arguments should return
 * KRB5_PLUGIN_NO_HANDLE.
 *
 * Inputs:
 *
 * @context     A krb5_context
 * @module      Name of module (typically "krb5")
 * @name        Name of pluggable interface (e.g., "kuserok")
 * @min_version Lowest acceptable plugin minor version number
 * @flags       Flags (none defined at this time)
 * @userctx     Callback data for the callback function @func
 * @func        A callback function, invoked once per-plugin
 *
 * Outputs: None, other than the return value and such outputs as are
 *          gathered by @func.
 */
krb5_error_code
_krb5_plugin_run_f(krb5_context context,
		   const char *module,
		   const char *name,
		   int min_version,
		   int flags,
		   void *userctx,
		   krb5_error_code (KRB5_LIB_CALL *func)(krb5_context, const void *, void *, void *))
{
    heim_string_t m = heim_string_create(module);
    heim_dict_t dict;
    void *plug_ctx;
    struct common_plugin_method *cpm;
    struct iter_ctx s;
    struct krb5_plugin *registered_plugins = NULL;
    struct krb5_plugin *p;

    /* Get registered plugins */
    (void) _krb5_plugin_find(context, SYMBOL, name, &registered_plugins);

    HEIMDAL_MUTEX_lock(&plugin_mutex);

    s.context = context;
    s.name = name;
    s.n = heim_string_create(name);
    s.min_version = min_version;
    s.result = heim_array_create();
    s.func = func;
    s.userctx = userctx;
    s.ret = KRB5_PLUGIN_NO_HANDLE;

    /* Get loaded plugins */
    dict = heim_dict_get_value(modules, m);
    heim_release(m);

    /* Add loaded plugins to s.result array */
    if (dict)
	heim_dict_iterate_f(dict, &s, search_modules);

    /* We don't need to hold plugin_mutex during plugin invocation */
    HEIMDAL_MUTEX_unlock(&plugin_mutex);

    /* Invoke registered plugins (old system) */
    for (p = registered_plugins; p; p = p->next) {
	/*
	 * XXX This is the wrong way to handle registered plugins, as we
	 * call init/fini on each invocation!  We do this because we
	 * have nowhere in the struct plugin registered list to store
	 * the context allocated by the plugin's init function.  (But at
	 * least we do call init/fini!)
	 *
	 * What we should do is adapt the old plugin system to the new
	 * one and change how we register plugins so that we use the new
	 * struct plug to keep track of their context structures, that
	 * way we can init once, invoke many times, then fini.
	 */
	cpm = (struct common_plugin_method *)p->symbol;
	s.ret = cpm->init(context, &plug_ctx);
	if (s.ret)
	    continue;
	s.ret = s.func(s.context, p->symbol, plug_ctx, s.userctx);
	cpm->fini(plug_ctx);
	if (s.ret != KRB5_PLUGIN_NO_HANDLE)
	    break;
    }
    _krb5_plugin_free(registered_plugins);

    /* Invoke loaded plugins (new system) */
    if (s.ret != KRB5_PLUGIN_NO_HANDLE)
	heim_array_iterate_f(s.result, &s, eval_results);

    heim_release(s.result);
    heim_release(s.n);

    return s.ret;
}