1178825Sdfr/* 2233294Sstas * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "krb5_locl.h" 35233294Sstas 36178825Sdfr#ifdef HAVE_DLFCN_H 37178825Sdfr#include <dlfcn.h> 38178825Sdfr#endif 39178825Sdfr#include <dirent.h> 40178825Sdfr 41178825Sdfrstruct krb5_plugin { 42178825Sdfr void *symbol; 43178825Sdfr struct krb5_plugin *next; 44178825Sdfr}; 45178825Sdfr 46178825Sdfrstruct plugin { 47233294Sstas enum { DSO, SYMBOL } type; 48233294Sstas union { 49233294Sstas struct { 50233294Sstas char *path; 51233294Sstas void *dsohandle; 52233294Sstas } dso; 53233294Sstas struct { 54233294Sstas enum krb5_plugin_type type; 55233294Sstas char *name; 56233294Sstas char *symbol; 57233294Sstas } symbol; 58233294Sstas } u; 59178825Sdfr struct plugin *next; 60178825Sdfr}; 61178825Sdfr 62178825Sdfrstatic HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER; 63178825Sdfrstatic struct plugin *registered = NULL; 64233294Sstasstatic int plugins_needs_scan = 1; 65178825Sdfr 66233294Sstasstatic const char *sysplugin_dirs[] = { 67233294Sstas LIBDIR "/plugin/krb5", 68233294Sstas#ifdef __APPLE__ 69233294Sstas "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", 70233294Sstas#endif 71233294Sstas NULL 72233294Sstas}; 73178825Sdfr 74178825Sdfr/* 75178825Sdfr * 76178825Sdfr */ 77178825Sdfr 78178825Sdfrvoid * 79178825Sdfr_krb5_plugin_get_symbol(struct krb5_plugin *p) 80178825Sdfr{ 81178825Sdfr return p->symbol; 82178825Sdfr} 83178825Sdfr 84178825Sdfrstruct krb5_plugin * 85178825Sdfr_krb5_plugin_get_next(struct krb5_plugin *p) 86178825Sdfr{ 87178825Sdfr return p->next; 88178825Sdfr} 89178825Sdfr 90178825Sdfr/* 91178825Sdfr * 92178825Sdfr */ 93178825Sdfr 94178825Sdfr#ifdef HAVE_DLOPEN 95178825Sdfr 96178825Sdfrstatic krb5_error_code 97233294Sstasloadlib(krb5_context context, char *path) 98178825Sdfr{ 99233294Sstas struct plugin *e; 100233294Sstas 101233294Sstas e = calloc(1, sizeof(*e)); 102233294Sstas if (e == NULL) { 103233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 104233294Sstas free(path); 105178825Sdfr return ENOMEM; 106178825Sdfr } 107178825Sdfr 108178825Sdfr#ifndef RTLD_LAZY 109178825Sdfr#define RTLD_LAZY 0 110178825Sdfr#endif 111233294Sstas#ifndef RTLD_LOCAL 112233294Sstas#define RTLD_LOCAL 0 113233294Sstas#endif 114233294Sstas e->type = DSO; 115233294Sstas /* ignore error from dlopen, and just keep it as negative cache entry */ 116233294Sstas e->u.dso.dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY); 117233294Sstas e->u.dso.path = path; 118178825Sdfr 119233294Sstas e->next = registered; 120233294Sstas registered = e; 121178825Sdfr 122178825Sdfr return 0; 123178825Sdfr} 124178825Sdfr#endif /* HAVE_DLOPEN */ 125178825Sdfr 126178825Sdfr/** 127178825Sdfr * Register a plugin symbol name of specific type. 128178825Sdfr * @param context a Keberos context 129178825Sdfr * @param type type of plugin symbol 130178825Sdfr * @param name name of plugin symbol 131178825Sdfr * @param symbol a pointer to the named symbol 132178825Sdfr * @return In case of error a non zero error com_err error is returned 133178825Sdfr * and the Kerberos error string is set. 134178825Sdfr * 135178825Sdfr * @ingroup krb5_support 136178825Sdfr */ 137178825Sdfr 138233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 139178825Sdfrkrb5_plugin_register(krb5_context context, 140178825Sdfr enum krb5_plugin_type type, 141233294Sstas const char *name, 142178825Sdfr void *symbol) 143178825Sdfr{ 144178825Sdfr struct plugin *e; 145178825Sdfr 146233294Sstas HEIMDAL_MUTEX_lock(&plugin_mutex); 147233294Sstas 148233294Sstas /* check for duplicates */ 149233294Sstas for (e = registered; e != NULL; e = e->next) { 150233294Sstas if (e->type == SYMBOL && 151233294Sstas strcmp(e->u.symbol.name, name) == 0 && 152233294Sstas e->u.symbol.type == type && e->u.symbol.symbol == symbol) { 153233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 154233294Sstas return 0; 155233294Sstas } 156233294Sstas } 157233294Sstas 158178825Sdfr e = calloc(1, sizeof(*e)); 159178825Sdfr if (e == NULL) { 160233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 161233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 162178825Sdfr return ENOMEM; 163178825Sdfr } 164233294Sstas e->type = SYMBOL; 165233294Sstas e->u.symbol.type = type; 166233294Sstas e->u.symbol.name = strdup(name); 167233294Sstas if (e->u.symbol.name == NULL) { 168233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 169178825Sdfr free(e); 170233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 171178825Sdfr return ENOMEM; 172178825Sdfr } 173233294Sstas e->u.symbol.symbol = symbol; 174178825Sdfr 175178825Sdfr e->next = registered; 176178825Sdfr registered = e; 177178825Sdfr HEIMDAL_MUTEX_unlock(&plugin_mutex); 178178825Sdfr 179178825Sdfr return 0; 180178825Sdfr} 181178825Sdfr 182233294Sstasstatic int 183233294Sstasis_valid_plugin_filename(const char * n) 184178825Sdfr{ 185233294Sstas if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) 186233294Sstas return 0; 187233294Sstas 188233294Sstas#ifdef _WIN32 189233294Sstas /* On Windows, we only attempt to load .dll files as plug-ins. */ 190233294Sstas { 191233294Sstas const char * ext; 192233294Sstas 193233294Sstas ext = strrchr(n, '.'); 194233294Sstas if (ext == NULL) 195233294Sstas return 0; 196233294Sstas 197233294Sstas return !stricmp(ext, ".dll"); 198233294Sstas } 199233294Sstas#else 200233294Sstas return 1; 201233294Sstas#endif 202233294Sstas} 203233294Sstas 204233294Sstasstatic void 205233294Sstastrim_trailing_slash(char * path) 206233294Sstas{ 207233294Sstas size_t l; 208233294Sstas 209233294Sstas l = strlen(path); 210233294Sstas while (l > 0 && (path[l - 1] == '/' 211233294Sstas#ifdef BACKSLASH_PATH_DELIM 212233294Sstas || path[l - 1] == '\\' 213233294Sstas#endif 214233294Sstas )) { 215233294Sstas path[--l] = '\0'; 216233294Sstas } 217233294Sstas} 218233294Sstas 219233294Sstasstatic krb5_error_code 220233294Sstasload_plugins(krb5_context context) 221233294Sstas{ 222233294Sstas struct plugin *e; 223178825Sdfr krb5_error_code ret; 224178825Sdfr char **dirs = NULL, **di; 225178825Sdfr struct dirent *entry; 226178825Sdfr char *path; 227178825Sdfr DIR *d = NULL; 228178825Sdfr 229233294Sstas if (!plugins_needs_scan) 230233294Sstas return 0; 231233294Sstas plugins_needs_scan = 0; 232178825Sdfr 233178825Sdfr#ifdef HAVE_DLOPEN 234178825Sdfr 235233294Sstas dirs = krb5_config_get_strings(context, NULL, "libdefaults", 236178825Sdfr "plugin_dir", NULL); 237233294Sstas if (dirs == NULL) 238233294Sstas dirs = rk_UNCONST(sysplugin_dirs); 239178825Sdfr 240178825Sdfr for (di = dirs; *di != NULL; di++) { 241233294Sstas char * dir = *di; 242178825Sdfr 243233294Sstas#ifdef KRB5_USE_PATH_TOKENS 244233294Sstas if (_krb5_expand_path_tokens(context, *di, &dir)) 245233294Sstas goto next_dir; 246233294Sstas#endif 247233294Sstas 248233294Sstas trim_trailing_slash(dir); 249233294Sstas 250233294Sstas d = opendir(dir); 251233294Sstas 252178825Sdfr if (d == NULL) 253233294Sstas goto next_dir; 254178825Sdfr 255233294Sstas rk_cloexec_dir(d); 256233294Sstas 257178825Sdfr while ((entry = readdir(d)) != NULL) { 258233294Sstas char *n = entry->d_name; 259233294Sstas 260233294Sstas /* skip . and .. */ 261233294Sstas if (!is_valid_plugin_filename(n)) 262233294Sstas continue; 263233294Sstas 264233294Sstas path = NULL; 265233294Sstas ret = 0; 266233294Sstas#ifdef __APPLE__ 267233294Sstas { /* support loading bundles on MacOS */ 268233294Sstas size_t len = strlen(n); 269233294Sstas if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) 270233294Sstas ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", dir, n, (int)(len - 7), n); 271233294Sstas } 272233294Sstas#endif 273233294Sstas if (ret < 0 || path == NULL) 274233294Sstas ret = asprintf(&path, "%s/%s", dir, n); 275233294Sstas 276233294Sstas if (ret < 0 || path == NULL) { 277178825Sdfr ret = ENOMEM; 278233294Sstas krb5_set_error_message(context, ret, "malloc: out of memory"); 279233294Sstas return ret; 280178825Sdfr } 281233294Sstas 282233294Sstas /* check if already tried */ 283233294Sstas for (e = registered; e != NULL; e = e->next) 284233294Sstas if (e->type == DSO && strcmp(e->u.dso.path, path) == 0) 285233294Sstas break; 286233294Sstas if (e) { 287233294Sstas free(path); 288233294Sstas } else { 289233294Sstas loadlib(context, path); /* store or frees path */ 290233294Sstas } 291178825Sdfr } 292178825Sdfr closedir(d); 293233294Sstas 294233294Sstas next_dir: 295233294Sstas if (dir != *di) 296233294Sstas free(dir); 297178825Sdfr } 298233294Sstas if (dirs != rk_UNCONST(sysplugin_dirs)) 299178825Sdfr krb5_config_free_strings(dirs); 300178825Sdfr#endif /* HAVE_DLOPEN */ 301233294Sstas return 0; 302233294Sstas} 303178825Sdfr 304233294Sstasstatic krb5_error_code 305233294Sstasadd_symbol(krb5_context context, struct krb5_plugin **list, void *symbol) 306233294Sstas{ 307233294Sstas struct krb5_plugin *e; 308233294Sstas 309233294Sstas e = calloc(1, sizeof(*e)); 310233294Sstas if (e == NULL) { 311233294Sstas krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 312233294Sstas return ENOMEM; 313233294Sstas } 314233294Sstas e->symbol = symbol; 315233294Sstas e->next = *list; 316233294Sstas *list = e; 317233294Sstas return 0; 318233294Sstas} 319233294Sstas 320233294Sstaskrb5_error_code 321233294Sstas_krb5_plugin_find(krb5_context context, 322233294Sstas enum krb5_plugin_type type, 323233294Sstas const char *name, 324233294Sstas struct krb5_plugin **list) 325233294Sstas{ 326233294Sstas struct plugin *e; 327233294Sstas krb5_error_code ret; 328233294Sstas 329233294Sstas *list = NULL; 330233294Sstas 331233294Sstas HEIMDAL_MUTEX_lock(&plugin_mutex); 332233294Sstas 333233294Sstas load_plugins(context); 334233294Sstas 335233294Sstas for (ret = 0, e = registered; e != NULL; e = e->next) { 336233294Sstas switch(e->type) { 337233294Sstas case DSO: { 338233294Sstas void *sym; 339233294Sstas if (e->u.dso.dsohandle == NULL) 340233294Sstas continue; 341233294Sstas sym = dlsym(e->u.dso.dsohandle, name); 342233294Sstas if (sym) 343233294Sstas ret = add_symbol(context, list, sym); 344233294Sstas break; 345233294Sstas } 346233294Sstas case SYMBOL: 347233294Sstas if (strcmp(e->u.symbol.name, name) == 0 && e->u.symbol.type == type) 348233294Sstas ret = add_symbol(context, list, e->u.symbol.symbol); 349233294Sstas break; 350233294Sstas } 351233294Sstas if (ret) { 352233294Sstas _krb5_plugin_free(*list); 353233294Sstas *list = NULL; 354233294Sstas } 355233294Sstas } 356233294Sstas 357233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 358233294Sstas if (ret) 359233294Sstas return ret; 360233294Sstas 361178825Sdfr if (*list == NULL) { 362233294Sstas krb5_set_error_message(context, ENOENT, "Did not find a plugin for %s", name); 363178825Sdfr return ENOENT; 364178825Sdfr } 365178825Sdfr 366178825Sdfr return 0; 367178825Sdfr} 368178825Sdfr 369178825Sdfrvoid 370178825Sdfr_krb5_plugin_free(struct krb5_plugin *list) 371178825Sdfr{ 372178825Sdfr struct krb5_plugin *next; 373178825Sdfr while (list) { 374178825Sdfr next = list->next; 375178825Sdfr free(list); 376178825Sdfr list = next; 377178825Sdfr } 378178825Sdfr} 379233294Sstas/* 380233294Sstas * module - dict of { 381233294Sstas * ModuleName = [ 382233294Sstas * plugin = object{ 383233294Sstas * array = { ptr, ctx } 384233294Sstas * } 385233294Sstas * ] 386233294Sstas * } 387233294Sstas */ 388233294Sstas 389233294Sstasstatic heim_dict_t modules; 390233294Sstas 391233294Sstasstruct plugin2 { 392233294Sstas heim_string_t path; 393233294Sstas void *dsohandle; 394233294Sstas heim_dict_t names; 395233294Sstas}; 396233294Sstas 397233294Sstasstatic void 398233294Sstasplug_dealloc(void *ptr) 399233294Sstas{ 400233294Sstas struct plugin2 *p = ptr; 401233294Sstas heim_release(p->path); 402233294Sstas heim_release(p->names); 403233294Sstas if (p->dsohandle) 404233294Sstas dlclose(p->dsohandle); 405233294Sstas} 406233294Sstas 407233294Sstas 408233294Sstasvoid 409233294Sstas_krb5_load_plugins(krb5_context context, const char *name, const char **paths) 410233294Sstas{ 411233294Sstas#ifdef HAVE_DLOPEN 412233294Sstas heim_string_t s = heim_string_create(name); 413233294Sstas heim_dict_t module; 414233294Sstas struct dirent *entry; 415233294Sstas krb5_error_code ret; 416233294Sstas const char **di; 417233294Sstas DIR *d; 418233294Sstas 419233294Sstas HEIMDAL_MUTEX_lock(&plugin_mutex); 420233294Sstas 421233294Sstas if (modules == NULL) { 422233294Sstas modules = heim_dict_create(11); 423233294Sstas if (modules == NULL) { 424233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 425233294Sstas return; 426233294Sstas } 427233294Sstas } 428233294Sstas 429233294Sstas module = heim_dict_copy_value(modules, s); 430233294Sstas if (module == NULL) { 431233294Sstas module = heim_dict_create(11); 432233294Sstas if (module == NULL) { 433233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 434233294Sstas heim_release(s); 435233294Sstas return; 436233294Sstas } 437233294Sstas heim_dict_add_value(modules, s, module); 438233294Sstas } 439233294Sstas heim_release(s); 440233294Sstas 441233294Sstas for (di = paths; *di != NULL; di++) { 442233294Sstas d = opendir(*di); 443233294Sstas if (d == NULL) 444233294Sstas continue; 445233294Sstas rk_cloexec_dir(d); 446233294Sstas 447233294Sstas while ((entry = readdir(d)) != NULL) { 448233294Sstas char *n = entry->d_name; 449233294Sstas char *path = NULL; 450233294Sstas heim_string_t spath; 451233294Sstas struct plugin2 *p; 452233294Sstas 453233294Sstas /* skip . and .. */ 454233294Sstas if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) 455233294Sstas continue; 456233294Sstas 457233294Sstas ret = 0; 458233294Sstas#ifdef __APPLE__ 459233294Sstas { /* support loading bundles on MacOS */ 460233294Sstas size_t len = strlen(n); 461233294Sstas if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) 462233294Sstas ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n); 463233294Sstas } 464233294Sstas#endif 465233294Sstas if (ret < 0 || path == NULL) 466233294Sstas ret = asprintf(&path, "%s/%s", *di, n); 467233294Sstas 468233294Sstas if (ret < 0 || path == NULL) 469233294Sstas continue; 470233294Sstas 471233294Sstas spath = heim_string_create(n); 472233294Sstas if (spath == NULL) { 473233294Sstas free(path); 474233294Sstas continue; 475233294Sstas } 476233294Sstas 477233294Sstas /* check if already cached */ 478233294Sstas p = heim_dict_copy_value(module, spath); 479233294Sstas if (p == NULL) { 480233294Sstas p = heim_alloc(sizeof(*p), "krb5-plugin", plug_dealloc); 481233294Sstas if (p) 482233294Sstas p->dsohandle = dlopen(path, RTLD_LOCAL|RTLD_LAZY); 483233294Sstas 484233294Sstas if (p->dsohandle) { 485233294Sstas p->path = heim_retain(spath); 486233294Sstas p->names = heim_dict_create(11); 487233294Sstas heim_dict_add_value(module, spath, p); 488233294Sstas } 489233294Sstas } 490233294Sstas heim_release(spath); 491233294Sstas heim_release(p); 492233294Sstas free(path); 493233294Sstas } 494233294Sstas closedir(d); 495233294Sstas } 496233294Sstas heim_release(module); 497233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 498233294Sstas#endif /* HAVE_DLOPEN */ 499233294Sstas} 500233294Sstas 501233294Sstasvoid 502233294Sstas_krb5_unload_plugins(krb5_context context, const char *name) 503233294Sstas{ 504233294Sstas HEIMDAL_MUTEX_lock(&plugin_mutex); 505233294Sstas heim_release(modules); 506233294Sstas modules = NULL; 507233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 508233294Sstas} 509233294Sstas 510233294Sstas/* 511233294Sstas * 512233294Sstas */ 513233294Sstas 514233294Sstasstruct common_plugin_method { 515233294Sstas int version; 516233294Sstas krb5_error_code (*init)(krb5_context, void **); 517233294Sstas void (*fini)(void *); 518233294Sstas}; 519233294Sstas 520233294Sstasstruct plug { 521233294Sstas void *dataptr; 522233294Sstas void *ctx; 523233294Sstas}; 524233294Sstas 525233294Sstasstatic void 526233294Sstasplug_free(void *ptr) 527233294Sstas{ 528233294Sstas struct plug *pl = ptr; 529233294Sstas if (pl->dataptr) { 530233294Sstas struct common_plugin_method *cpm = pl->dataptr; 531233294Sstas cpm->fini(pl->ctx); 532233294Sstas } 533233294Sstas} 534233294Sstas 535233294Sstasstruct iter_ctx { 536233294Sstas krb5_context context; 537233294Sstas heim_string_t n; 538233294Sstas const char *name; 539233294Sstas int min_version; 540233294Sstas heim_array_t result; 541233294Sstas krb5_error_code (*func)(krb5_context, const void *, void *, void *); 542233294Sstas void *userctx; 543233294Sstas krb5_error_code ret; 544233294Sstas}; 545233294Sstas 546233294Sstasstatic void 547233294Sstassearch_modules(void *ctx, heim_object_t key, heim_object_t value) 548233294Sstas{ 549233294Sstas struct iter_ctx *s = ctx; 550233294Sstas struct plugin2 *p = value; 551233294Sstas struct plug *pl = heim_dict_copy_value(p->names, s->n); 552233294Sstas struct common_plugin_method *cpm; 553233294Sstas 554233294Sstas if (pl == NULL) { 555233294Sstas if (p->dsohandle == NULL) 556233294Sstas return; 557233294Sstas 558233294Sstas pl = heim_alloc(sizeof(*pl), "struct-plug", plug_free); 559233294Sstas 560233294Sstas cpm = pl->dataptr = dlsym(p->dsohandle, s->name); 561233294Sstas if (cpm) { 562233294Sstas int ret; 563233294Sstas 564233294Sstas ret = cpm->init(s->context, &pl->ctx); 565233294Sstas if (ret) 566233294Sstas cpm = pl->dataptr = NULL; 567233294Sstas } 568233294Sstas heim_dict_add_value(p->names, s->n, pl); 569233294Sstas } else { 570233294Sstas cpm = pl->dataptr; 571233294Sstas } 572233294Sstas 573233294Sstas if (cpm && cpm->version >= s->min_version) 574233294Sstas heim_array_append_value(s->result, pl); 575233294Sstas 576233294Sstas heim_release(pl); 577233294Sstas} 578233294Sstas 579233294Sstasstatic void 580233294Sstaseval_results(heim_object_t value, void *ctx) 581233294Sstas{ 582233294Sstas struct plug *pl = value; 583233294Sstas struct iter_ctx *s = ctx; 584233294Sstas 585233294Sstas if (s->ret != KRB5_PLUGIN_NO_HANDLE) 586233294Sstas return; 587233294Sstas 588233294Sstas s->ret = s->func(s->context, pl->dataptr, pl->ctx, s->userctx); 589233294Sstas} 590233294Sstas 591233294Sstaskrb5_error_code 592233294Sstas_krb5_plugin_run_f(krb5_context context, 593233294Sstas const char *module, 594233294Sstas const char *name, 595233294Sstas int min_version, 596233294Sstas int flags, 597233294Sstas void *userctx, 598233294Sstas krb5_error_code (*func)(krb5_context, const void *, void *, void *)) 599233294Sstas{ 600233294Sstas heim_string_t m = heim_string_create(module); 601233294Sstas heim_dict_t dict; 602233294Sstas struct iter_ctx s; 603233294Sstas 604233294Sstas HEIMDAL_MUTEX_lock(&plugin_mutex); 605233294Sstas 606233294Sstas dict = heim_dict_copy_value(modules, m); 607233294Sstas heim_release(m); 608233294Sstas if (dict == NULL) { 609233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 610233294Sstas return KRB5_PLUGIN_NO_HANDLE; 611233294Sstas } 612233294Sstas 613233294Sstas s.context = context; 614233294Sstas s.name = name; 615233294Sstas s.n = heim_string_create(name); 616233294Sstas s.min_version = min_version; 617233294Sstas s.result = heim_array_create(); 618233294Sstas s.func = func; 619233294Sstas s.userctx = userctx; 620233294Sstas 621233294Sstas heim_dict_iterate_f(dict, search_modules, &s); 622233294Sstas 623233294Sstas heim_release(dict); 624233294Sstas 625233294Sstas HEIMDAL_MUTEX_unlock(&plugin_mutex); 626233294Sstas 627233294Sstas s.ret = KRB5_PLUGIN_NO_HANDLE; 628233294Sstas 629233294Sstas heim_array_iterate_f(s.result, eval_results, &s); 630233294Sstas 631233294Sstas heim_release(s.result); 632233294Sstas heim_release(s.n); 633233294Sstas 634233294Sstas return s.ret; 635233294Sstas} 636