14960Swillf /*
24960Swillf * util/support/plugins.c
34960Swillf *
44960Swillf * Copyright 2006 by the Massachusetts Institute of Technology.
54960Swillf * All Rights Reserved.
64960Swillf *
74960Swillf * Export of this software from the United States of America may
84960Swillf * require a specific license from the United States Government.
94960Swillf * It is the responsibility of any person or organization contemplating
104960Swillf * export to obtain such a license before exporting.
114960Swillf *
124960Swillf * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
134960Swillf * distribute this software and its documentation for any purpose and
144960Swillf * without fee is hereby granted, provided that the above copyright
154960Swillf * notice appear in all copies and that both that copyright notice and
164960Swillf * this permission notice appear in supporting documentation, and that
174960Swillf * the name of M.I.T. not be used in advertising or publicity pertaining
184960Swillf * to distribution of the software without specific, written prior
194960Swillf * permission. Furthermore if you modify this software you must label
204960Swillf * your software as modified software and not distribute it in such a
214960Swillf * fashion that it might be confused with the original M.I.T. software.
224960Swillf * M.I.T. makes no representations about the suitability of
234960Swillf * this software for any purpose. It is provided "as is" without express
244960Swillf * or implied warranty.
254960Swillf *
264960Swillf *
274960Swillf * Plugin module support, and shims around dlopen/whatever.
284960Swillf */
294960Swillf
30*7934SMark.Phalan@Sun.COM /*
31*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
32*7934SMark.Phalan@Sun.COM * Use is subject to license terms.
33*7934SMark.Phalan@Sun.COM */
34*7934SMark.Phalan@Sun.COM
35*7934SMark.Phalan@Sun.COM
364960Swillf #include "k5-plugin.h"
374960Swillf #if USE_DLOPEN
384960Swillf #include <dlfcn.h>
394960Swillf #endif
404960Swillf #if USE_CFBUNDLE
414960Swillf #include <CoreFoundation/CoreFoundation.h>
424960Swillf #endif
434960Swillf #include <stdio.h>
444960Swillf #include <sys/types.h>
454960Swillf #ifdef HAVE_SYS_STAT_H
464960Swillf #include <sys/stat.h>
474960Swillf #endif
484960Swillf #ifdef HAVE_SYS_PARAM_H
494960Swillf #include <sys/param.h>
504960Swillf #endif
514960Swillf #include <errno.h>
524960Swillf #include <stdlib.h>
534960Swillf #include <string.h>
544960Swillf #ifdef HAVE_UNISTD_H
554960Swillf #include <unistd.h>
564960Swillf #endif
574960Swillf
584960Swillf #include <stdarg.h>
594960Swillf /*ARGSUSED*/
Tprintf(const char * fmt,...)604960Swillf static void Tprintf (const char *fmt, ...)
614960Swillf {
624960Swillf #ifdef DEBUG
634960Swillf va_list va;
644960Swillf va_start (va, fmt);
654960Swillf vfprintf (stderr, fmt, va);
664960Swillf va_end (va);
674960Swillf #endif
684960Swillf }
694960Swillf
704960Swillf struct plugin_file_handle {
714960Swillf #if USE_DLOPEN
724960Swillf void *dlhandle;
734960Swillf #endif
744960Swillf #if USE_CFBUNDLE
754960Swillf CFBundleRef bundle;
764960Swillf #endif
774960Swillf #if !defined (USE_DLOPEN) && !defined (USE_CFBUNDLE)
784960Swillf char dummy;
794960Swillf #endif
804960Swillf };
814960Swillf
824960Swillf /*ARGSUSED2*/
834960Swillf long KRB5_CALLCONV
krb5int_open_plugin(const char * filepath,struct plugin_file_handle ** h,struct errinfo * ep)844960Swillf krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct errinfo *ep)
854960Swillf {
864960Swillf long err = 0;
874960Swillf struct stat statbuf;
884960Swillf struct plugin_file_handle *htmp = NULL;
894960Swillf int got_plugin = 0;
904960Swillf
914960Swillf if (!err) {
924960Swillf if (stat (filepath, &statbuf) < 0) {
934960Swillf Tprintf ("stat(%s): %s\n", filepath, strerror (errno));
944960Swillf err = errno;
954960Swillf }
964960Swillf }
974960Swillf
984960Swillf if (!err) {
994960Swillf htmp = calloc (1, sizeof (*htmp)); /* calloc initializes ptrs to NULL */
1004960Swillf if (htmp == NULL) { err = errno; }
1014960Swillf }
1024960Swillf
1034960Swillf #if USE_DLOPEN
1044960Swillf if (!err && (statbuf.st_mode & S_IFMT) == S_IFREG) {
1054960Swillf void *handle = NULL;
1064960Swillf #ifdef RTLD_GROUP
1074960Swillf #define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | RTLD_GROUP)
1084960Swillf #else
1094960Swillf #define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL)
1104960Swillf #endif
1114960Swillf
1124960Swillf if (!err) {
1134960Swillf handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS);
1144960Swillf if (handle == NULL) {
1154960Swillf const char *e = dlerror();
1164960Swillf Tprintf ("dlopen(%s): %s\n", filepath, e);
1174960Swillf err = ENOENT; /* XXX */
1184960Swillf krb5int_set_error (ep, err, "%s", e);
1194960Swillf }
1204960Swillf }
1214960Swillf
1224960Swillf if (!err) {
1234960Swillf got_plugin = 1;
1244960Swillf htmp->dlhandle = handle;
1254960Swillf handle = NULL;
1264960Swillf }
1274960Swillf
1284960Swillf if (handle != NULL) { dlclose (handle); }
1294960Swillf }
1304960Swillf #endif
1314960Swillf
1324960Swillf #if USE_CFBUNDLE
1334960Swillf if (!err && (statbuf.st_mode & S_IFMT) == S_IFDIR) {
1344960Swillf CFStringRef pluginPath = NULL;
1354960Swillf CFURLRef pluginURL = NULL;
1364960Swillf CFBundleRef pluginBundle = NULL;
1374960Swillf
1384960Swillf if (!err) {
1394960Swillf pluginPath = CFStringCreateWithCString (kCFAllocatorDefault, filepath,
1404960Swillf kCFStringEncodingASCII);
1414960Swillf if (pluginPath == NULL) { err = ENOMEM; }
1424960Swillf }
1434960Swillf
1444960Swillf if (!err) {
1454960Swillf pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pluginPath,
1464960Swillf kCFURLPOSIXPathStyle, true);
1474960Swillf if (pluginURL == NULL) { err = ENOMEM; }
1484960Swillf }
1494960Swillf
1504960Swillf if (!err) {
1514960Swillf pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
1524960Swillf if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
1534960Swillf }
1544960Swillf
1554960Swillf if (!err) {
1564960Swillf if (!CFBundleIsExecutableLoaded (pluginBundle)) {
1574960Swillf int loaded = CFBundleLoadExecutable (pluginBundle);
1584960Swillf if (!loaded) { err = ENOENT; } /* XXX need better error */
1594960Swillf }
1604960Swillf }
1614960Swillf
1624960Swillf if (!err) {
1634960Swillf got_plugin = 1;
1644960Swillf htmp->bundle = pluginBundle;
1654960Swillf pluginBundle = NULL; /* htmp->bundle takes ownership */
1664960Swillf }
1674960Swillf
1684960Swillf if (pluginBundle != NULL) { CFRelease (pluginBundle); }
1694960Swillf if (pluginURL != NULL) { CFRelease (pluginURL); }
1704960Swillf if (pluginPath != NULL) { CFRelease (pluginPath); }
1714960Swillf }
1724960Swillf #endif
1734960Swillf
1744960Swillf if (!err && !got_plugin) {
1754960Swillf err = ENOENT; /* no plugin or no way to load plugins */
1764960Swillf }
1774960Swillf
1784960Swillf if (!err) {
1794960Swillf *h = htmp;
1804960Swillf htmp = NULL; /* h takes ownership */
1814960Swillf }
1824960Swillf
1834960Swillf if (htmp != NULL) { free (htmp); }
1844960Swillf
1854960Swillf return err;
1864960Swillf }
1874960Swillf
1884960Swillf /*ARGSUSED*/
1894960Swillf static long
krb5int_get_plugin_sym(struct plugin_file_handle * h,const char * csymname,int isfunc,void ** ptr,struct errinfo * ep)1904960Swillf krb5int_get_plugin_sym (struct plugin_file_handle *h,
1914960Swillf const char *csymname, int isfunc, void **ptr,
1924960Swillf struct errinfo *ep)
1934960Swillf {
1944960Swillf long err = 0;
1954960Swillf void *sym = NULL;
1964960Swillf
1974960Swillf #if USE_DLOPEN
1984960Swillf if (!err && !sym && (h->dlhandle != NULL)) {
1994960Swillf /* XXX Do we need to add a leading "_" to the symbol name on any
2004960Swillf modern platforms? */
2014960Swillf sym = dlsym (h->dlhandle, csymname);
2024960Swillf if (sym == NULL) {
2034960Swillf const char *e = dlerror (); /* XXX copy and save away */
2044960Swillf Tprintf ("dlsym(%s): %s\n", csymname, e);
2054960Swillf err = ENOENT; /* XXX */
2064960Swillf krb5int_set_error(ep, err, "%s", e);
2074960Swillf }
2084960Swillf }
2094960Swillf #endif
2104960Swillf
2114960Swillf #if USE_CFBUNDLE
2124960Swillf if (!err && !sym && (h->bundle != NULL)) {
2134960Swillf CFStringRef cfsymname = NULL;
2144960Swillf
2154960Swillf if (!err) {
2164960Swillf cfsymname = CFStringCreateWithCString (kCFAllocatorDefault, csymname,
2174960Swillf kCFStringEncodingASCII);
2184960Swillf if (cfsymname == NULL) { err = ENOMEM; }
2194960Swillf }
2204960Swillf
2214960Swillf if (!err) {
2224960Swillf if (isfunc) {
2234960Swillf sym = CFBundleGetFunctionPointerForName (h->bundle, cfsymname);
2244960Swillf } else {
2254960Swillf sym = CFBundleGetDataPointerForName (h->bundle, cfsymname);
2264960Swillf }
2274960Swillf if (sym == NULL) { err = ENOENT; } /* XXX */
2284960Swillf }
2294960Swillf
2304960Swillf if (cfsymname != NULL) { CFRelease (cfsymname); }
2314960Swillf }
2324960Swillf #endif
2334960Swillf
2344960Swillf if (!err && (sym == NULL)) {
2354960Swillf err = ENOENT; /* unimplemented */
2364960Swillf }
2374960Swillf
2384960Swillf if (!err) {
2394960Swillf *ptr = sym;
2404960Swillf }
2414960Swillf
2424960Swillf return err;
2434960Swillf }
2444960Swillf
2454960Swillf long KRB5_CALLCONV
krb5int_get_plugin_data(struct plugin_file_handle * h,const char * csymname,void ** ptr,struct errinfo * ep)2464960Swillf krb5int_get_plugin_data (struct plugin_file_handle *h, const char *csymname,
2474960Swillf void **ptr, struct errinfo *ep)
2484960Swillf {
2494960Swillf return krb5int_get_plugin_sym (h, csymname, 0, ptr, ep);
2504960Swillf }
2514960Swillf
2524960Swillf long KRB5_CALLCONV
krb5int_get_plugin_func(struct plugin_file_handle * h,const char * csymname,void (** ptr)(),struct errinfo * ep)2534960Swillf krb5int_get_plugin_func (struct plugin_file_handle *h, const char *csymname,
2544960Swillf void (**ptr)(), struct errinfo *ep)
2554960Swillf {
2564960Swillf void *dptr = NULL;
2574960Swillf long err = krb5int_get_plugin_sym (h, csymname, 1, &dptr, ep);
2584960Swillf if (!err) {
2594960Swillf /* Cast function pointers to avoid code duplication */
2604960Swillf *ptr = (void (*)()) dptr;
2614960Swillf }
2624960Swillf return err;
2634960Swillf }
2644960Swillf
2654960Swillf void KRB5_CALLCONV
krb5int_close_plugin(struct plugin_file_handle * h)2664960Swillf krb5int_close_plugin (struct plugin_file_handle *h)
2674960Swillf {
2684960Swillf #if USE_DLOPEN
2694960Swillf if (h->dlhandle != NULL) { dlclose(h->dlhandle); }
2704960Swillf #endif
2714960Swillf #if USE_CFBUNDLE
2724960Swillf /* Do not call CFBundleUnloadExecutable because it's not ref counted.
2734960Swillf * CFRelease will unload the bundle if the internal refcount goes to zero. */
2744960Swillf if (h->bundle != NULL) { CFRelease (h->bundle); }
2754960Swillf #endif
2764960Swillf free (h);
2774960Swillf }
2784960Swillf
2794960Swillf /* autoconf docs suggest using this preference order */
2804960Swillf #if HAVE_DIRENT_H || USE_DIRENT_H
2814960Swillf #include <dirent.h>
2824960Swillf #define NAMELEN(D) strlen((D)->d_name)
2834960Swillf #else
2844960Swillf #define dirent direct
2854960Swillf #define NAMELEN(D) ((D)->d->namlen)
2864960Swillf #if HAVE_SYS_NDIR_H
2874960Swillf # include <sys/ndir.h>
2884960Swillf #elif HAVE_SYS_DIR_H
2894960Swillf # include <sys/dir.h>
2904960Swillf #elif HAVE_NDIR_H
2914960Swillf # include <ndir.h>
2924960Swillf #endif
2934960Swillf #endif
2944960Swillf
2954960Swillf
2964960Swillf #ifdef HAVE_STRERROR_R
2974960Swillf #define ERRSTR(ERR, BUF) \
2984960Swillf (strerror_r (ERR, BUF, sizeof(BUF)) == 0 ? BUF : strerror (ERR))
2994960Swillf #else
3004960Swillf #define ERRSTR(ERR, BUF) \
3014960Swillf (strerror (ERR))
3024960Swillf #endif
3034960Swillf
3044960Swillf static long
krb5int_plugin_file_handle_array_init(struct plugin_file_handle *** harray)3054960Swillf krb5int_plugin_file_handle_array_init (struct plugin_file_handle ***harray)
3064960Swillf {
3074960Swillf long err = 0;
3084960Swillf
3094960Swillf *harray = calloc (1, sizeof (**harray)); /* calloc initializes to NULL */
3104960Swillf if (*harray == NULL) { err = errno; }
3114960Swillf
3124960Swillf return err;
3134960Swillf }
3144960Swillf
3154960Swillf static long
krb5int_plugin_file_handle_array_add(struct plugin_file_handle *** harray,int * count,struct plugin_file_handle * p)3164960Swillf krb5int_plugin_file_handle_array_add (struct plugin_file_handle ***harray, int *count,
3174960Swillf struct plugin_file_handle *p)
3184960Swillf {
3194960Swillf long err = 0;
3204960Swillf struct plugin_file_handle **newharray = NULL;
3214960Swillf int newcount = *count + 1;
3224960Swillf
3234960Swillf newharray = realloc (*harray, ((newcount + 1) * sizeof (**harray))); /* +1 for NULL */
3244960Swillf if (newharray == NULL) {
3254960Swillf err = errno;
3264960Swillf } else {
3274960Swillf newharray[newcount - 1] = p;
3284960Swillf newharray[newcount] = NULL;
3294960Swillf *count = newcount;
3304960Swillf *harray = newharray;
3314960Swillf }
3324960Swillf
3334960Swillf return err;
3344960Swillf }
3354960Swillf
3364960Swillf static void
krb5int_plugin_file_handle_array_free(struct plugin_file_handle ** harray)3374960Swillf krb5int_plugin_file_handle_array_free (struct plugin_file_handle **harray)
3384960Swillf {
3394960Swillf if (harray != NULL) {
3404960Swillf int i;
3414960Swillf for (i = 0; harray[i] != NULL; i++) {
3424960Swillf krb5int_close_plugin (harray[i]);
3434960Swillf }
3444960Swillf free (harray);
3454960Swillf }
3464960Swillf }
3474960Swillf
3484960Swillf #if TARGET_OS_MAC
3494960Swillf #define FILEEXTS { "", ".bundle", ".so", NULL }
3504960Swillf #elif defined(_WIN32)
3514960Swillf #define FILEEXTS { "", ".dll", NULL }
3524960Swillf #else
3534960Swillf #define FILEEXTS { "", ".so", NULL }
3544960Swillf #endif
3554960Swillf
3564960Swillf
3574960Swillf static void
krb5int_free_plugin_filenames(char ** filenames)3584960Swillf krb5int_free_plugin_filenames (char **filenames)
3594960Swillf {
3604960Swillf if (filenames != NULL) {
3614960Swillf int i;
3624960Swillf for (i = 0; filenames[i] != NULL; i++) {
3634960Swillf free (filenames[i]);
3644960Swillf }
3654960Swillf free (filenames);
3664960Swillf }
3674960Swillf }
3684960Swillf
3694960Swillf
3704960Swillf static long
krb5int_get_plugin_filenames(const char * const * filebases,char *** filenames)3714960Swillf krb5int_get_plugin_filenames (const char * const *filebases, char ***filenames)
3724960Swillf {
3734960Swillf long err = 0;
3744960Swillf static const char *const fileexts[] = FILEEXTS;
3754960Swillf char **tempnames = NULL;
3764960Swillf int i;
3774960Swillf
3784960Swillf if (!err) {
3794960Swillf size_t count = 0;
3804960Swillf for (i = 0; filebases[i] != NULL; i++, count++);
3814960Swillf for (i = 0; fileexts[i] != NULL; i++, count++);
3824960Swillf tempnames = calloc (count, sizeof (char *));
3834960Swillf if (tempnames == NULL) { err = errno; }
3844960Swillf }
3854960Swillf
3864960Swillf if (!err) {
3874960Swillf int j;
3884960Swillf for (i = 0; !err && (filebases[i] != NULL); i++) {
3894960Swillf size_t baselen = strlen (filebases[i]);
3904960Swillf for (j = 0; !err && (fileexts[j] != NULL); j++) {
3914960Swillf size_t len = baselen + strlen (fileexts[j]) + 2; /* '.' + NULL */
3924960Swillf tempnames[i+j] = malloc (len * sizeof (char));
3934960Swillf if (tempnames[i+j] == NULL) {
3944960Swillf err = errno;
3954960Swillf } else {
3964960Swillf /*LINTED*/
3974960Swillf sprintf (tempnames[i+j], "%s%s", filebases[i], fileexts[j]);
3984960Swillf }
3994960Swillf }
4004960Swillf }
4014960Swillf }
4024960Swillf
4034960Swillf if (!err) {
4044960Swillf *filenames = tempnames;
4054960Swillf tempnames = NULL;
4064960Swillf }
4074960Swillf
4084960Swillf if (tempnames != NULL) { krb5int_free_plugin_filenames (tempnames); }
4094960Swillf
4104960Swillf return err;
4114960Swillf }
4124960Swillf
4134960Swillf
4144960Swillf /* Takes a NULL-terminated list of directories. If filebases is NULL, filebases is ignored
4154960Swillf * all plugins in the directories are loaded. If filebases is a NULL-terminated array of names,
4164960Swillf * only plugins in the directories with those name (plus any platform extension) are loaded. */
4174960Swillf
4184960Swillf long KRB5_CALLCONV
krb5int_open_plugin_dirs(const char * const * dirnames,const char * const * filebases,struct plugin_dir_handle * dirhandle,struct errinfo * ep)4194960Swillf krb5int_open_plugin_dirs (const char * const *dirnames,
4204960Swillf const char * const *filebases,
4214960Swillf struct plugin_dir_handle *dirhandle,
4224960Swillf struct errinfo *ep)
4234960Swillf {
4244960Swillf long err = 0;
4254960Swillf struct plugin_file_handle **h = NULL;
4264960Swillf int count = 0;
4274960Swillf char **filenames = NULL;
4284960Swillf int i;
4294960Swillf
4304960Swillf if (!err) {
4314960Swillf err = krb5int_plugin_file_handle_array_init (&h);
4324960Swillf }
4334960Swillf
4344960Swillf if (!err && (filebases != NULL)) {
4354960Swillf err = krb5int_get_plugin_filenames (filebases, &filenames);
4364960Swillf }
4374960Swillf
4384960Swillf for (i = 0; !err && dirnames[i] != NULL; i++) {
4394960Swillf size_t dirnamelen = strlen (dirnames[i]) + 1; /* '/' */
4404960Swillf if (filenames != NULL) {
4414960Swillf /* load plugins with names from filenames from each directory */
4424960Swillf int j;
4434960Swillf
4444960Swillf for (j = 0; !err && filenames[j] != NULL; j++) {
4454960Swillf struct plugin_file_handle *handle = NULL;
4464960Swillf char *filepath = NULL;
4474960Swillf
4484960Swillf if (!err) {
4494960Swillf filepath = malloc (dirnamelen + strlen (filenames[j]) + 1); /* NULL */
4504960Swillf if (filepath == NULL) {
4514960Swillf err = errno;
4524960Swillf } else {
4534960Swillf /*LINTED*/
4544960Swillf sprintf (filepath, "%s/%s", dirnames[i], filenames[j]);
4554960Swillf }
4564960Swillf }
4574960Swillf
4584960Swillf if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
4594960Swillf err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
4604960Swillf if (!err) { handle = NULL; } /* h takes ownership */
4614960Swillf }
4624960Swillf
4634960Swillf if (filepath != NULL) { free (filepath); }
4644960Swillf if (handle != NULL) { krb5int_close_plugin (handle); }
4654960Swillf }
4664960Swillf } else {
4674960Swillf /* load all plugins in each directory */
4684960Swillf #ifndef _WIN32
469*7934SMark.Phalan@Sun.COM DIR *dir = opendir (dirnames[i]);
4704960Swillf
471*7934SMark.Phalan@Sun.COM while (dir != NULL && !err) {
4724960Swillf struct dirent *d = NULL;
4734960Swillf char *filepath = NULL;
4744960Swillf struct plugin_file_handle *handle = NULL;
475*7934SMark.Phalan@Sun.COM int len;
4764960Swillf
4774960Swillf d = readdir (dir);
4784960Swillf if (d == NULL) { break; }
4794960Swillf
4804960Swillf if ((strcmp (d->d_name, ".") == 0) ||
4814960Swillf (strcmp (d->d_name, "..") == 0)) {
4824960Swillf continue;
4834960Swillf }
484*7934SMark.Phalan@Sun.COM
485*7934SMark.Phalan@Sun.COM /* Solaris Kerberos: Only open files with a .so extension */
486*7934SMark.Phalan@Sun.COM len = NAMELEN (d);
487*7934SMark.Phalan@Sun.COM if (len < 3 || strcmp(".so", d->d_name + len - 3 ) != 0)
488*7934SMark.Phalan@Sun.COM continue;
489*7934SMark.Phalan@Sun.COM
4904960Swillf if (!err) {
4914960Swillf filepath = malloc (dirnamelen + len + 1); /* NULL */
4924960Swillf if (filepath == NULL) {
4934960Swillf err = errno;
4944960Swillf } else {
4954960Swillf /*LINTED*/
4964960Swillf sprintf (filepath, "%s/%*s", dirnames[i], len, d->d_name);
4974960Swillf }
4984960Swillf }
4994960Swillf
5004960Swillf if (!err) {
5014960Swillf if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
5024960Swillf err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
5034960Swillf if (!err) { handle = NULL; } /* h takes ownership */
5044960Swillf }
5054960Swillf }
5064960Swillf
5074960Swillf if (filepath != NULL) { free (filepath); }
5084960Swillf if (handle != NULL) { krb5int_close_plugin (handle); }
5094960Swillf }
5104960Swillf
5114960Swillf if (dir != NULL) { closedir (dir); }
5124960Swillf #else
5134960Swillf /* Until a Windows implementation of this code is implemented */
5144960Swillf err = ENOENT;
5154960Swillf #endif /* _WIN32 */
5164960Swillf }
5174960Swillf }
5184960Swillf
5194960Swillf if (err == ENOENT) {
5204960Swillf err = 0; /* ran out of plugins -- do nothing */
5214960Swillf }
5224960Swillf
5234960Swillf if (!err) {
5244960Swillf dirhandle->files = h;
5254960Swillf h = NULL; /* dirhandle->files takes ownership */
5264960Swillf }
5274960Swillf
5284960Swillf if (filenames != NULL) { krb5int_free_plugin_filenames (filenames); }
5294960Swillf if (h != NULL) { krb5int_plugin_file_handle_array_free (h); }
5304960Swillf
5314960Swillf return err;
5324960Swillf }
5334960Swillf
5344960Swillf void KRB5_CALLCONV
krb5int_close_plugin_dirs(struct plugin_dir_handle * dirhandle)5354960Swillf krb5int_close_plugin_dirs (struct plugin_dir_handle *dirhandle)
5364960Swillf {
5374960Swillf if (dirhandle->files != NULL) {
5384960Swillf int i;
5394960Swillf for (i = 0; dirhandle->files[i] != NULL; i++) {
5404960Swillf krb5int_close_plugin (dirhandle->files[i]);
5414960Swillf }
5424960Swillf free (dirhandle->files);
5434960Swillf dirhandle->files = NULL;
5444960Swillf }
5454960Swillf }
5464960Swillf
5474960Swillf void KRB5_CALLCONV
krb5int_free_plugin_dir_data(void ** ptrs)5484960Swillf krb5int_free_plugin_dir_data (void **ptrs)
5494960Swillf {
5504960Swillf /* Nothing special to be done per pointer. */
5514960Swillf free(ptrs);
5524960Swillf }
5534960Swillf
5544960Swillf long KRB5_CALLCONV
krb5int_get_plugin_dir_data(struct plugin_dir_handle * dirhandle,const char * symname,void *** ptrs,struct errinfo * ep)5554960Swillf krb5int_get_plugin_dir_data (struct plugin_dir_handle *dirhandle,
5564960Swillf const char *symname,
5574960Swillf void ***ptrs,
5584960Swillf struct errinfo *ep)
5594960Swillf {
5604960Swillf long err = 0;
5614960Swillf void **p = NULL;
5624960Swillf int count = 0;
5634960Swillf
5644960Swillf /* XXX Do we need to add a leading "_" to the symbol name on any
5654960Swillf modern platforms? */
5664960Swillf
5674960Swillf Tprintf("get_plugin_data_sym(%s)\n", symname);
5684960Swillf
5694960Swillf if (!err) {
5704960Swillf p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
5714960Swillf if (p == NULL) { err = errno; }
5724960Swillf }
5734960Swillf
5744960Swillf if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
5754960Swillf int i = 0;
5764960Swillf
5774960Swillf for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
5784960Swillf void *sym = NULL;
5794960Swillf
5804960Swillf if (krb5int_get_plugin_data (dirhandle->files[i], symname, &sym, ep) == 0) {
5814960Swillf void **newp = NULL;
5824960Swillf
5834960Swillf count++;
5844960Swillf newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
5854960Swillf if (newp == NULL) {
5864960Swillf err = errno;
5874960Swillf } else {
5884960Swillf p = newp;
5894960Swillf p[count - 1] = sym;
5904960Swillf p[count] = NULL;
5914960Swillf }
5924960Swillf }
5934960Swillf }
5944960Swillf }
5954960Swillf
5964960Swillf if (!err) {
5974960Swillf *ptrs = p;
5984960Swillf p = NULL; /* ptrs takes ownership */
5994960Swillf }
6004960Swillf
6014960Swillf if (p != NULL) { free (p); }
6024960Swillf
6034960Swillf return err;
6044960Swillf }
6054960Swillf
6064960Swillf void KRB5_CALLCONV
krb5int_free_plugin_dir_func(void (** ptrs)(void))6074960Swillf krb5int_free_plugin_dir_func (void (**ptrs)(void))
6084960Swillf {
6094960Swillf /* Nothing special to be done per pointer. */
6104960Swillf free(ptrs);
6114960Swillf }
6124960Swillf
6134960Swillf long KRB5_CALLCONV
krb5int_get_plugin_dir_func(struct plugin_dir_handle * dirhandle,const char * symname,void (*** ptrs)(void),struct errinfo * ep)6144960Swillf krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle,
6154960Swillf const char *symname,
6164960Swillf void (***ptrs)(void),
6174960Swillf struct errinfo *ep)
6184960Swillf {
6194960Swillf long err = 0;
6204960Swillf void (**p)() = NULL;
6214960Swillf int count = 0;
6224960Swillf
6234960Swillf /* XXX Do we need to add a leading "_" to the symbol name on any
6244960Swillf modern platforms? */
6254960Swillf
6264960Swillf Tprintf("get_plugin_data_sym(%s)\n", symname);
6274960Swillf
6284960Swillf if (!err) {
6294960Swillf p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
6304960Swillf if (p == NULL) { err = errno; }
6314960Swillf }
6324960Swillf
6334960Swillf if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
6344960Swillf int i = 0;
6354960Swillf
6364960Swillf for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
6374960Swillf void (*sym)() = NULL;
6384960Swillf
6394960Swillf if (krb5int_get_plugin_func (dirhandle->files[i], symname, &sym, ep) == 0) {
6404960Swillf void (**newp)() = NULL;
6414960Swillf
6424960Swillf count++;
6434960Swillf newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
6444960Swillf if (newp == NULL) {
6454960Swillf err = errno;
6464960Swillf } else {
6474960Swillf p = newp;
6484960Swillf p[count - 1] = sym;
6494960Swillf p[count] = NULL;
6504960Swillf }
6514960Swillf }
6524960Swillf }
6534960Swillf }
6544960Swillf
6554960Swillf if (!err) {
6564960Swillf *ptrs = p;
6574960Swillf p = NULL; /* ptrs takes ownership */
6584960Swillf }
6594960Swillf
6604960Swillf if (p != NULL) { free (p); }
6614960Swillf
6624960Swillf return err;
6634960Swillf }
664