xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/support/plugins.c (revision 7934:6aeeafc994de)
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