static void search_modules(heim_object_t key, heim_object_t value, void *ctx) { struct iter_ctx *s = ctx; struct plugin2 *p = value; struct plug *pl = heim_dict_get_value(p->names, s->n); struct common_plugin_method *cpm; if (pl == NULL) { if (p->dsohandle == NULL) return; pl = heim_alloc(sizeof(*pl), "struct-plug", plug_free); cpm = pl->dataptr = dlsym(p->dsohandle, s->name); if (cpm) { int ret; ret = cpm->init(s->context, &pl->ctx); if (ret) cpm = pl->dataptr = NULL; } heim_dict_set_value(p->names, s->n, pl); heim_release(pl); } else { cpm = pl->dataptr; } if (cpm && cpm->version >= s->min_version) heim_array_append_value(s->result, pl); }
/** heim_db_register * @brief Registers a DB type for use with heim_db_create(). * * @param dbtype Name of DB type * @param data Private data argument to the dbtype's openf method * @param plugin Structure with DB type methods (function pointers) * * Backends that provide begin/commit/rollback methods must provide ACID * semantics. * * The registered DB type will have ACID semantics for backends that do * not provide begin/commit/rollback methods but do provide lock/unlock * and rdjournal/wrjournal methods (using a replay log journalling * scheme). * * If the registered DB type does not natively provide read vs. write * transaction isolation but does provide a lock method then the DB will * provide read/write transaction isolation. * * @return ENOMEM on failure, else 0. * * @addtogroup heimbase */ int heim_db_register(const char *dbtype, void *data, struct heim_db_type *plugin) { heim_dict_t plugins; heim_string_t s; db_plugin plug, plug2; int ret = 0; if ((plugin->beginf != NULL && plugin->commitf == NULL) || (plugin->beginf != NULL && plugin->rollbackf == NULL) || (plugin->lockf != NULL && plugin->unlockf == NULL) || plugin->copyf == NULL) heim_abort("Invalid DB plugin; make sure methods are paired"); /* Initialize */ plugins = heim_dict_create(11); if (plugins == NULL) return ENOMEM; heim_base_once_f(&db_plugin_init_once, plugins, db_init_plugins_once); heim_release(plugins); heim_assert(db_plugins != NULL, "heim_db plugin table initialized"); s = heim_string_create(dbtype); if (s == NULL) return ENOMEM; plug = heim_alloc(sizeof (*plug), "db_plug", plugin_dealloc); if (plug == NULL) { heim_release(s); return ENOMEM; } plug->name = heim_retain(s); plug->openf = plugin->openf; plug->clonef = plugin->clonef; plug->closef = plugin->closef; plug->lockf = plugin->lockf; plug->unlockf = plugin->unlockf; plug->syncf = plugin->syncf; plug->beginf = plugin->beginf; plug->commitf = plugin->commitf; plug->rollbackf = plugin->rollbackf; plug->copyf = plugin->copyf; plug->setf = plugin->setf; plug->delf = plugin->delf; plug->iterf = plugin->iterf; plug->data = data; HEIMDAL_MUTEX_lock(&db_type_mutex); plug2 = heim_dict_get_value(db_plugins, s); if (plug2 == NULL) ret = heim_dict_set_value(db_plugins, s, plug); HEIMDAL_MUTEX_unlock(&db_type_mutex); heim_release(plug); heim_release(s); return ret; }
static int parse_pair(heim_dict_t dict, struct parse_ctx *ctx) { heim_string_t key; heim_object_t value; if (white_spaces(ctx)) return -1; if (*ctx->p == '}') return 0; key = parse_string(ctx); if (key == NULL) return -1; if (white_spaces(ctx)) return -1; if (*ctx->p != ':') { heim_release(key); return -1; } ctx->p += 1; if (white_spaces(ctx)) { heim_release(key); return -1; } value = parse_value(ctx); if (value == NULL) { heim_release(key); return -1; } heim_dict_set_value(dict, key, value); heim_release(key); heim_release(value); if (white_spaces(ctx)) return -1; if (*ctx->p == '}') { ctx->p++; return 0; } else if (*ctx->p == ',') { ctx->p++; return 1; } return -1; }
heim_string_t __heim_string_constant(const char *_str) { static HEIMDAL_MUTEX mutex = HEIMDAL_MUTEX_INITIALIZER; static heim_base_once_t once; static heim_dict_t dict = NULL; heim_string_t s, s2; heim_base_once_f(&once, &dict, init_string); s = heim_string_create(_str); HEIMDAL_MUTEX_lock(&mutex); s2 = heim_dict_get_value(dict, s); if (s2) { heim_release(s); s = s2; } else { _heim_make_permanent(s); heim_dict_set_value(dict, s, s); } HEIMDAL_MUTEX_unlock(&mutex); return s; }
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; }
static int parse_pair(heim_dict_t dict, struct parse_ctx *ctx) { heim_string_t key; heim_object_t value; if (white_spaces(ctx)) return -1; if (*ctx->p == '}') { ctx->p++; return 0; } if (ctx->flags & HEIM_JSON_F_STRICT_DICT) /* JSON allows only string keys */ key = parse_string(ctx); else /* heim_dict_t allows any heim_object_t as key */ key = parse_value(ctx); if (key == NULL) /* Even heim_dict_t does not allow C NULLs as keys though! */ return -1; if (white_spaces(ctx)) { heim_release(key); return -1; } if (*ctx->p != ':') { heim_release(key); return -1; } ctx->p += 1; /* safe because we call white_spaces() next */ if (white_spaces(ctx)) { heim_release(key); return -1; } value = parse_value(ctx); if (value == NULL && (ctx->error != NULL || (ctx->flags & HEIM_JSON_F_NO_C_NULL))) { if (ctx->error == NULL) ctx->error = heim_error_create(EINVAL, "Invalid JSON encoding"); heim_release(key); return -1; } heim_dict_set_value(dict, key, value); heim_release(key); heim_release(value); if (white_spaces(ctx)) return -1; if (*ctx->p == '}') { /* * Return 1 but don't consume the '}' so we can count the one * pair in a one-pair dict */ return 1; } else if (*ctx->p == ',') { ctx->p++; return 1; } return -1; }
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; }
/** * Load plugins (new system) for the given module @name (typicall * "krb5") from the given directory @paths. * * Inputs: * * @context A krb5_context * @name Name of plugin module (typically "krb5") * @paths Array of directory paths where to look */ void _krb5_load_plugins(krb5_context context, const char *name, const char **paths) { #ifdef HAVE_DLOPEN heim_string_t s = heim_string_create(name); heim_dict_t module; struct dirent *entry; krb5_error_code ret; const char **di; DIR *d; HEIMDAL_MUTEX_lock(&plugin_mutex); if (modules == NULL) { modules = heim_dict_create(11); if (modules == NULL) { HEIMDAL_MUTEX_unlock(&plugin_mutex); return; } } module = heim_dict_get_value(modules, s); if (module == NULL) { module = heim_dict_create(11); if (module == NULL) { HEIMDAL_MUTEX_unlock(&plugin_mutex); heim_release(s); return; } heim_dict_set_value(modules, s, module); heim_release(module); } heim_release(s); for (di = paths; *di != NULL; di++) { d = opendir(*di); if (d == NULL) continue; rk_cloexec_dir(d); while ((entry = readdir(d)) != NULL) { char *n = entry->d_name; char *path = NULL; heim_string_t spath; struct plugin2 *p; /* skip . and .. */ if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) continue; ret = 0; #ifdef __APPLE__ { /* support loading bundles on MacOS */ size_t len = strlen(n); if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n); } #endif if (ret < 0 || path == NULL) ret = asprintf(&path, "%s/%s", *di, n); if (ret < 0 || path == NULL) continue; spath = heim_string_create(n); if (spath == NULL) { free(path); continue; } /* check if already cached */ p = heim_dict_get_value(module, spath); if (p == NULL) { p = heim_alloc(sizeof(*p), "krb5-plugin", plug_dealloc); if (p) p->dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY); if (p->dsohandle) { p->path = heim_retain(spath); p->names = heim_dict_create(11); heim_dict_set_value(module, spath, p); } heim_release(p); } heim_release(spath); free(path); } closedir(d); } HEIMDAL_MUTEX_unlock(&plugin_mutex); #endif /* HAVE_DLOPEN */ }