diff --git a/kdc/kdc-tester.c b/kdc/kdc-tester.c index afc833cb8..75a36add1 100644 --- a/kdc/kdc-tester.c +++ b/kdc/kdc-tester.c @@ -34,6 +34,7 @@ */ #include "kdc_locl.h" +#include "send_to_kdc_plugin.h" struct perf { unsigned long as_req; @@ -62,10 +63,37 @@ static void eval_object(heim_object_t); */ static krb5_error_code -send_to_kdc(krb5_context c, void *ptr, krb5_krbhst_info *hi, time_t timeout, - const krb5_data *in, krb5_data *out) +plugin_init(krb5_context context, void **pctx) { - krb5_error_code ret; + *pctx = NULL; + return 0; +} + +static void +plugin_fini(void *ctx) +{ +} + +static krb5_error_code +plugin_send_to_kdc(krb5_context context, + void *ctx, + krb5_krbhst_info *ho, + time_t timeout, + const krb5_data *in, + krb5_data *out) +{ + return KRB5_PLUGIN_NO_HANDLE; +} + +static krb5_error_code +plugin_send_to_realm(krb5_context context, + void *ctx, + krb5_const_realm realm, + time_t timeout, + const krb5_data *in, + krb5_data *out) +{ + int ret; krb5_kdc_update_time(NULL); @@ -74,11 +102,19 @@ send_to_kdc(krb5_context c, void *ptr, krb5_krbhst_info *hi, time_t timeout, out, NULL, astr, (struct sockaddr *)&sa, 0); if (ret) - krb5_err(c, 1, ret, "krb5_kdc_process_request"); + krb5_err(kdc_context, 1, ret, "krb5_kdc_process_request"); return 0; } +static krb5plugin_send_to_kdc_ftable send_to_kdc = { + KRB5_PLUGIN_SEND_TO_KDC_VERSION_2, + plugin_init, + plugin_fini, + plugin_send_to_kdc, + plugin_send_to_realm +}; + static void perf_start(struct perf *perf) { @@ -443,7 +479,8 @@ main(int argc, char **argv) if (argc == 0) errx(1, "missing operations"); - krb5_set_send_to_kdc_func(kdc_context, send_to_kdc, NULL); + krb5_plugin_register(kdc_context, PLUGIN_TYPE_DATA, + KRB5_PLUGIN_SEND_TO_KDC, &send_to_kdc); { void *buf; diff --git a/kdc/windc.c b/kdc/windc.c index 7cd64ca9f..919015649 100644 --- a/kdc/windc.c +++ b/kdc/windc.c @@ -43,6 +43,7 @@ static void *windcctx; krb5_error_code krb5_kdc_windc_init(krb5_context context) { +#if 0 struct krb5_plugin *list = NULL, *e; krb5_error_code ret; @@ -65,7 +66,7 @@ krb5_kdc_windc_init(krb5_context context) windcft = NULL; return ENOENT; } - +#endif return 0; } diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 8fc1002af..7be765692 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -404,6 +404,9 @@ krb5_init_context(krb5_context *context) if(ret) goto out; + /* done enough to load plugins */ + heim_base_once_f(&init_context, p, init_context_once); + /* init error tables */ krb5_init_ets(p); cc_ops_register(p); @@ -421,8 +424,6 @@ out: if(ret) { krb5_free_context(p); p = NULL; - } else { - heim_base_once_f(&init_context, p, init_context_once); } *context = p; return ret; diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index f79f6af63..6840d8522 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -749,10 +749,6 @@ EXPORTS _krb5_pk_load_id _krb5_pk_mk_ContentInfo _krb5_pk_octetstring2key - _krb5_plugin_find - _krb5_plugin_free - _krb5_plugin_get_next - _krb5_plugin_get_symbol _krb5_principal2principalname _krb5_principalname2krb5_principal _krb5_put_int diff --git a/lib/krb5/pcache.c b/lib/krb5/pcache.c index 23d5389a6..df89e7dcd 100644 --- a/lib/krb5/pcache.c +++ b/lib/krb5/pcache.c @@ -36,31 +36,30 @@ #endif #include +static krb5_error_code KRB5_LIB_CALL +callback(krb5_context context, const void *plug, void *plugctx, void *userctx) +{ + krb5_cc_ops *ccops = (krb5_cc_ops *)plug; + krb5_error_code ret; + + if (ccops != NULL && ccops->version >= KRB5_CC_OPS_VERSION) + return KRB5_PLUGIN_NO_HANDLE; + + ret = krb5_cc_register(context, ccops, TRUE); + if (ret != 0) + *((krb5_error_code *)userctx) = ret; + + return KRB5_PLUGIN_NO_HANDLE; +} + + krb5_error_code _krb5_load_ccache_plugins(krb5_context context) { - struct krb5_plugin * plist = NULL; - struct krb5_plugin *p; - krb5_error_code code; + krb5_error_code userctx = 0; - code = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, KRB5_PLUGIN_CCACHE, - &plist); - if (code) - return code; + (void)_krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_CCACHE, + 0, 0, &userctx, callback); - for (p = plist; p != NULL; p = _krb5_plugin_get_next(p)) { - krb5_cc_ops * ccops; - krb5_error_code c_load; - - ccops = _krb5_plugin_get_symbol(p); - if (ccops != NULL && ccops->version == KRB5_CC_OPS_VERSION) { - c_load = krb5_cc_register(context, ccops, TRUE); - if (c_load != 0) - code = c_load; - } - } - - _krb5_plugin_free(plist); - - return code; + return userctx; } diff --git a/lib/krb5/plugin.c b/lib/krb5/plugin.c index 93c37a80a..102ecb7cc 100644 --- a/lib/krb5/plugin.c +++ b/lib/krb5/plugin.c @@ -60,322 +60,7 @@ struct plugin { }; static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER; -static struct plugin *registered = NULL; -static int plugins_needs_scan = 1; -static const char *sysplugin_dirs[] = { - LIBDIR "/plugin/krb5", -#ifdef __APPLE__ - "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", -#endif - NULL -}; - -/* - * - */ - -void * -_krb5_plugin_get_symbol(struct krb5_plugin *p) -{ - return p->symbol; -} - -struct krb5_plugin * -_krb5_plugin_get_next(struct krb5_plugin *p) -{ - return p->next; -} - -/* - * - */ - -#ifdef HAVE_DLOPEN - -static krb5_error_code -loadlib(krb5_context context, char *path) -{ - struct plugin *e; - - e = calloc(1, sizeof(*e)); - if (e == NULL) { - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - free(path); - return ENOMEM; - } - -#ifndef RTLD_LAZY -#define RTLD_LAZY 0 -#endif -#ifndef RTLD_LOCAL -#define RTLD_LOCAL 0 -#endif - e->type = DSO; - /* ignore error from dlopen, and just keep it as negative cache entry */ - e->u.dso.dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY); - e->u.dso.path = path; - - e->next = registered; - registered = e; - - return 0; -} -#endif /* HAVE_DLOPEN */ - -/** - * Register a plugin symbol name of specific type. - * @param context a Keberos context - * @param type type of plugin symbol - * @param name name of plugin symbol - * @param symbol a pointer to the named symbol - * @return In case of error a non zero error com_err error is returned - * and the Kerberos error string is set. - * - * @ingroup krb5_support - */ - -KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -krb5_plugin_register(krb5_context context, - enum krb5_plugin_type type, - const char *name, - void *symbol) -{ - struct plugin *e; - - HEIMDAL_MUTEX_lock(&plugin_mutex); - - /* check for duplicates */ - for (e = registered; e != NULL; e = e->next) { - if (e->type == SYMBOL && - strcmp(e->u.symbol.name, name) == 0 && - e->u.symbol.type == type && e->u.symbol.symbol == symbol) { - HEIMDAL_MUTEX_unlock(&plugin_mutex); - return 0; - } - } - - e = calloc(1, sizeof(*e)); - if (e == NULL) { - HEIMDAL_MUTEX_unlock(&plugin_mutex); - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; - } - e->type = SYMBOL; - e->u.symbol.type = type; - e->u.symbol.name = strdup(name); - if (e->u.symbol.name == NULL) { - HEIMDAL_MUTEX_unlock(&plugin_mutex); - free(e); - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; - } - e->u.symbol.symbol = symbol; - - e->next = registered; - registered = e; - HEIMDAL_MUTEX_unlock(&plugin_mutex); - - return 0; -} - -static int -is_valid_plugin_filename(const char * n) -{ - if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) - return 0; - -#ifdef _WIN32 - /* On Windows, we only attempt to load .dll files as plug-ins. */ - { - const char * ext; - - ext = strrchr(n, '.'); - if (ext == NULL) - return 0; - - return !stricmp(ext, ".dll"); - } -#else - return 1; -#endif -} - -static void -trim_trailing_slash(char * path) -{ - size_t l; - - l = strlen(path); - while (l > 0 && (path[l - 1] == '/' -#ifdef BACKSLASH_PATH_DELIM - || path[l - 1] == '\\' -#endif - )) { - path[--l] = '\0'; - } -} - -static krb5_error_code -load_plugins(krb5_context context) -{ - struct plugin *e; - krb5_error_code ret; - char **dirs = NULL, **di; - struct dirent *entry; - char *path; - DIR *d = NULL; - - if (!plugins_needs_scan) - return 0; - plugins_needs_scan = 0; - -#ifdef HAVE_DLOPEN - - dirs = krb5_config_get_strings(context, NULL, "libdefaults", - "plugin_dir", NULL); - if (dirs == NULL) - dirs = rk_UNCONST(sysplugin_dirs); - - for (di = dirs; *di != NULL; di++) { - char * dir = *di; - -#ifdef KRB5_USE_PATH_TOKENS - if (_krb5_expand_path_tokens(context, *di, &dir)) - goto next_dir; -#endif - - trim_trailing_slash(dir); - - d = opendir(dir); - - if (d == NULL) - goto next_dir; - - rk_cloexec_dir(d); - - while ((entry = readdir(d)) != NULL) { - char *n = entry->d_name; - - /* skip . and .. */ - if (!is_valid_plugin_filename(n)) - continue; - - path = NULL; - 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", dir, n, (int)(len - 7), n); - } -#endif - if (ret < 0 || path == NULL) - ret = asprintf(&path, "%s/%s", dir, n); - - if (ret < 0 || path == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, "malloc: out of memory"); - return ret; - } - - /* check if already tried */ - for (e = registered; e != NULL; e = e->next) - if (e->type == DSO && strcmp(e->u.dso.path, path) == 0) - break; - if (e) { - free(path); - } else { - loadlib(context, path); /* store or frees path */ - } - } - closedir(d); - - next_dir: - if (dir != *di) - free(dir); - } - if (dirs != rk_UNCONST(sysplugin_dirs)) - krb5_config_free_strings(dirs); -#endif /* HAVE_DLOPEN */ - return 0; -} - -static krb5_error_code -add_symbol(krb5_context context, struct krb5_plugin **list, void *symbol) -{ - struct krb5_plugin *e; - - e = calloc(1, sizeof(*e)); - if (e == NULL) { - krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); - return ENOMEM; - } - e->symbol = symbol; - e->next = *list; - *list = e; - return 0; -} - -krb5_error_code -_krb5_plugin_find(krb5_context context, - enum krb5_plugin_type type, - const char *name, - struct krb5_plugin **list) -{ - struct plugin *e; - krb5_error_code ret; - - *list = NULL; - - HEIMDAL_MUTEX_lock(&plugin_mutex); - - load_plugins(context); - - for (ret = 0, e = registered; e != NULL; e = e->next) { - switch(e->type) { - case DSO: { - void *sym; - if (e->u.dso.dsohandle == NULL) - continue; - sym = dlsym(e->u.dso.dsohandle, name); - if (sym) - ret = add_symbol(context, list, sym); - break; - } - case SYMBOL: - if (strcmp(e->u.symbol.name, name) == 0 && e->u.symbol.type == type) - ret = add_symbol(context, list, e->u.symbol.symbol); - break; - } - if (ret) { - _krb5_plugin_free(*list); - *list = NULL; - } - } - - HEIMDAL_MUTEX_unlock(&plugin_mutex); - if (ret) - return ret; - - if (*list == NULL) { - krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name); - return ENOENT; - } - - return 0; -} - -void -_krb5_plugin_free(struct krb5_plugin *list) -{ - struct krb5_plugin *next; - while (list) { - next = list->next; - free(list); - list = next; - } -} /* * module - dict of { * ModuleName = [ @@ -404,6 +89,28 @@ plug_dealloc(void *ptr) dlclose(p->dsohandle); } +static heim_dict_t +get_module(heim_string_t string) +{ + heim_dict_t module; + + if (modules == NULL) { + modules = heim_dict_create(11); + if (modules == NULL) + return NULL; + } + + module = heim_dict_get_value(modules, string); + if (module == NULL) { + module = heim_dict_create(11); + if (module == NULL) + return NULL; + + heim_dict_set_value(modules, string, module); + heim_release(module); + } + return module; +} /** * Load plugins (new system) for the given module @name (typicall @@ -428,26 +135,12 @@ _krb5_load_plugins(krb5_context context, const char *name, const char **paths) 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); - } + module = get_module(s); heim_release(s); + if (module == NULL) { + HEIMDAL_MUTEX_unlock(&plugin_mutex); + return; + } for (di = paths; *di != NULL; di++) { d = opendir(*di); @@ -466,6 +159,15 @@ _krb5_load_plugins(krb5_context context, const char *name, const char **paths) continue; ret = 0; +#ifdef _WIN32 + { /* On Windows, we only attempt to load .dll files as plug-ins. */ + const char *ext; + + ext = strrchr(n, '.'); + if (ext == NULL || !stricmp(ext, ".dll") + continue; + } +#endif #ifdef __APPLE__ { /* support loading bundles on MacOS */ size_t len = strlen(n); @@ -492,7 +194,7 @@ _krb5_load_plugins(krb5_context context, const char *name, const char **paths) if (p) p->dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY); - if (p->dsohandle) { + if (p && p->dsohandle) { p->path = heim_retain(spath); p->names = heim_dict_create(11); heim_dict_set_value(module, spath, p); @@ -594,10 +296,9 @@ eval_results(heim_object_t value, void *ctx, int *stop) struct plug *pl = value; struct iter_ctx *s = ctx; - if (s->ret != KRB5_PLUGIN_NO_HANDLE) - return; - s->ret = s->func(s->context, pl->dataptr, pl->ctx, s->userctx); + if (s->ret == 0 || s->ret != KRB5_PLUGIN_NO_HANDLE) + *stop = 1; } /** @@ -640,14 +341,7 @@ _krb5_plugin_run_f(krb5_context context, { 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, ®istered_plugins); HEIMDAL_MUTEX_lock(&plugin_mutex); @@ -671,37 +365,79 @@ _krb5_plugin_run_f(krb5_context context, /* 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); + /* Invoke loaded plugins */ + heim_array_iterate_f(s.result, &s, eval_results); heim_release(s.result); heim_release(s.n); return s.ret; } + +/** + * Register a plugin symbol name of specific type. + * @param context a Keberos context + * @param type type of plugin symbol + * @param name name of plugin symbol + * @param symbol a pointer to the named symbol + * @return In case of error a non zero error com_err error is returned + * and the Kerberos error string is set. + * + * @ingroup krb5_support + */ + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_plugin_register(krb5_context context, + enum krb5_plugin_type type, + const char *name, + void *symbol) +{ + struct common_plugin_method *cpm = symbol; + heim_dict_t module; + heim_string_t s; + struct plug *pl; + struct plugin2 *p; + heim_string_t name_string; + int ret; + + name_string = heim_string_create(name); + + /* setyp a plugin and one name */ + + p = heim_alloc(sizeof(*p), "krb5-plugin", plug_dealloc); + if (p == NULL) { + heim_release(name_string); + return ENOMEM; + } + + p->dsohandle = NULL; + + p->path = heim_string_create_with_format("unique:%p", p); + p->names = heim_dict_create(11); + + pl = heim_alloc(sizeof(*pl), "struct-plug", plug_free); + + cpm = pl->dataptr = symbol; + + ret = cpm->init(context, &pl->ctx); + if (ret) + cpm = pl->dataptr = NULL; + + heim_dict_set_value(p->names, name_string, pl); + heim_release(name_string); + heim_release(pl); + + /* Hook in the plugin into kerberos by default */ + + HEIMDAL_MUTEX_lock(&plugin_mutex); + + s = heim_string_create("krb5"); + module = get_module(s); + heim_release(s); + + heim_dict_set_value(module, p->path, p); + + HEIMDAL_MUTEX_unlock(&plugin_mutex); + + return 0; +} diff --git a/lib/krb5/test_plugin.c b/lib/krb5/test_plugin.c index 4235442b9..e53a9975c 100644 --- a/lib/krb5/test_plugin.c +++ b/lib/krb5/test_plugin.c @@ -113,7 +113,7 @@ main(int argc, char **argv) while(krb5_krbhst_next_as_string(context, handle, host, sizeof(host)) == 0){ found++; - if (strcmp(host, "127.0.0.2") != 0) + if (strcmp(host, "127.0.0.2") != 0 && strcmp(host, "tcp/127.0.0.2") != 0) krb5_errx(context, 1, "wrong address: %s", host); } if (!found) diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index b49c165dd..0d85ffcd1 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -737,10 +737,6 @@ HEIMDAL_KRB5_2.0 { _krb5_pk_load_id; _krb5_pk_mk_ContentInfo; _krb5_pk_octetstring2key; - _krb5_plugin_find; - _krb5_plugin_free; - _krb5_plugin_get_next; - _krb5_plugin_get_symbol; _krb5_principal2principalname; _krb5_principalname2krb5_principal; _krb5_put_int;