xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/support/plugins.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
154925bf6Swillf /*
254925bf6Swillf  * util/support/plugins.c
354925bf6Swillf  *
454925bf6Swillf  * Copyright 2006 by the Massachusetts Institute of Technology.
554925bf6Swillf  * All Rights Reserved.
654925bf6Swillf  *
754925bf6Swillf  * Export of this software from the United States of America may
854925bf6Swillf  *   require a specific license from the United States Government.
954925bf6Swillf  *   It is the responsibility of any person or organization contemplating
1054925bf6Swillf  *   export to obtain such a license before exporting.
1154925bf6Swillf  *
1254925bf6Swillf  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
1354925bf6Swillf  * distribute this software and its documentation for any purpose and
1454925bf6Swillf  * without fee is hereby granted, provided that the above copyright
1554925bf6Swillf  * notice appear in all copies and that both that copyright notice and
1654925bf6Swillf  * this permission notice appear in supporting documentation, and that
1754925bf6Swillf  * the name of M.I.T. not be used in advertising or publicity pertaining
1854925bf6Swillf  * to distribution of the software without specific, written prior
1954925bf6Swillf  * permission.  Furthermore if you modify this software you must label
2054925bf6Swillf  * your software as modified software and not distribute it in such a
2154925bf6Swillf  * fashion that it might be confused with the original M.I.T. software.
2254925bf6Swillf  * M.I.T. makes no representations about the suitability of
2354925bf6Swillf  * this software for any purpose.  It is provided "as is" without express
2454925bf6Swillf  * or implied warranty.
2554925bf6Swillf  *
2654925bf6Swillf  *
2754925bf6Swillf  * Plugin module support, and shims around dlopen/whatever.
2854925bf6Swillf  */
2954925bf6Swillf 
30*159d09a2SMark Phalan /*
31*159d09a2SMark Phalan  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32*159d09a2SMark Phalan  * Use is subject to license terms.
33*159d09a2SMark Phalan  */
34*159d09a2SMark Phalan 
35*159d09a2SMark Phalan 
3654925bf6Swillf #include "k5-plugin.h"
3754925bf6Swillf #if USE_DLOPEN
3854925bf6Swillf #include <dlfcn.h>
3954925bf6Swillf #endif
4054925bf6Swillf #if USE_CFBUNDLE
4154925bf6Swillf #include <CoreFoundation/CoreFoundation.h>
4254925bf6Swillf #endif
4354925bf6Swillf #include <stdio.h>
4454925bf6Swillf #include <sys/types.h>
4554925bf6Swillf #ifdef HAVE_SYS_STAT_H
4654925bf6Swillf #include <sys/stat.h>
4754925bf6Swillf #endif
4854925bf6Swillf #ifdef HAVE_SYS_PARAM_H
4954925bf6Swillf #include <sys/param.h>
5054925bf6Swillf #endif
5154925bf6Swillf #include <errno.h>
5254925bf6Swillf #include <stdlib.h>
5354925bf6Swillf #include <string.h>
5454925bf6Swillf #ifdef HAVE_UNISTD_H
5554925bf6Swillf #include <unistd.h>
5654925bf6Swillf #endif
5754925bf6Swillf 
5854925bf6Swillf #include <stdarg.h>
5954925bf6Swillf /*ARGSUSED*/
Tprintf(const char * fmt,...)6054925bf6Swillf static void Tprintf (const char *fmt, ...)
6154925bf6Swillf {
6254925bf6Swillf #ifdef DEBUG
6354925bf6Swillf     va_list va;
6454925bf6Swillf     va_start (va, fmt);
6554925bf6Swillf     vfprintf (stderr, fmt, va);
6654925bf6Swillf     va_end (va);
6754925bf6Swillf #endif
6854925bf6Swillf }
6954925bf6Swillf 
7054925bf6Swillf struct plugin_file_handle {
7154925bf6Swillf #if USE_DLOPEN
7254925bf6Swillf     void *dlhandle;
7354925bf6Swillf #endif
7454925bf6Swillf #if USE_CFBUNDLE
7554925bf6Swillf     CFBundleRef bundle;
7654925bf6Swillf #endif
7754925bf6Swillf #if !defined (USE_DLOPEN) && !defined (USE_CFBUNDLE)
7854925bf6Swillf     char dummy;
7954925bf6Swillf #endif
8054925bf6Swillf };
8154925bf6Swillf 
8254925bf6Swillf /*ARGSUSED2*/
8354925bf6Swillf long KRB5_CALLCONV
krb5int_open_plugin(const char * filepath,struct plugin_file_handle ** h,struct errinfo * ep)8454925bf6Swillf krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct errinfo *ep)
8554925bf6Swillf {
8654925bf6Swillf     long err = 0;
8754925bf6Swillf     struct stat statbuf;
8854925bf6Swillf     struct plugin_file_handle *htmp = NULL;
8954925bf6Swillf     int got_plugin = 0;
9054925bf6Swillf 
9154925bf6Swillf     if (!err) {
9254925bf6Swillf         if (stat (filepath, &statbuf) < 0) {
9354925bf6Swillf             Tprintf ("stat(%s): %s\n", filepath, strerror (errno));
9454925bf6Swillf             err = errno;
9554925bf6Swillf         }
9654925bf6Swillf     }
9754925bf6Swillf 
9854925bf6Swillf     if (!err) {
9954925bf6Swillf         htmp = calloc (1, sizeof (*htmp)); /* calloc initializes ptrs to NULL */
10054925bf6Swillf         if (htmp == NULL) { err = errno; }
10154925bf6Swillf     }
10254925bf6Swillf 
10354925bf6Swillf #if USE_DLOPEN
10454925bf6Swillf     if (!err && (statbuf.st_mode & S_IFMT) == S_IFREG) {
10554925bf6Swillf         void *handle = NULL;
10654925bf6Swillf #ifdef RTLD_GROUP
10754925bf6Swillf #define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | RTLD_GROUP)
10854925bf6Swillf #else
10954925bf6Swillf #define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL)
11054925bf6Swillf #endif
11154925bf6Swillf 
11254925bf6Swillf         if (!err) {
11354925bf6Swillf             handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS);
11454925bf6Swillf             if (handle == NULL) {
11554925bf6Swillf                 const char *e = dlerror();
11654925bf6Swillf                 Tprintf ("dlopen(%s): %s\n", filepath, e);
11754925bf6Swillf                 err = ENOENT; /* XXX */
11854925bf6Swillf 		krb5int_set_error (ep, err, "%s", e);
11954925bf6Swillf             }
12054925bf6Swillf         }
12154925bf6Swillf 
12254925bf6Swillf         if (!err) {
12354925bf6Swillf             got_plugin = 1;
12454925bf6Swillf             htmp->dlhandle = handle;
12554925bf6Swillf             handle = NULL;
12654925bf6Swillf         }
12754925bf6Swillf 
12854925bf6Swillf         if (handle != NULL) { dlclose (handle); }
12954925bf6Swillf     }
13054925bf6Swillf #endif
13154925bf6Swillf 
13254925bf6Swillf #if USE_CFBUNDLE
13354925bf6Swillf     if (!err && (statbuf.st_mode & S_IFMT) == S_IFDIR) {
13454925bf6Swillf         CFStringRef pluginPath = NULL;
13554925bf6Swillf         CFURLRef pluginURL = NULL;
13654925bf6Swillf         CFBundleRef pluginBundle = NULL;
13754925bf6Swillf 
13854925bf6Swillf         if (!err) {
13954925bf6Swillf             pluginPath = CFStringCreateWithCString (kCFAllocatorDefault, filepath,
14054925bf6Swillf                                                     kCFStringEncodingASCII);
14154925bf6Swillf             if (pluginPath == NULL) { err = ENOMEM; }
14254925bf6Swillf         }
14354925bf6Swillf 
14454925bf6Swillf         if (!err) {
14554925bf6Swillf             pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pluginPath,
14654925bf6Swillf                                                        kCFURLPOSIXPathStyle, true);
14754925bf6Swillf             if (pluginURL == NULL) { err = ENOMEM; }
14854925bf6Swillf         }
14954925bf6Swillf 
15054925bf6Swillf         if (!err) {
15154925bf6Swillf             pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
15254925bf6Swillf             if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
15354925bf6Swillf         }
15454925bf6Swillf 
15554925bf6Swillf         if (!err) {
15654925bf6Swillf             if (!CFBundleIsExecutableLoaded (pluginBundle)) {
15754925bf6Swillf                 int loaded = CFBundleLoadExecutable (pluginBundle);
15854925bf6Swillf                 if (!loaded) { err = ENOENT; }  /* XXX need better error */
15954925bf6Swillf             }
16054925bf6Swillf         }
16154925bf6Swillf 
16254925bf6Swillf         if (!err) {
16354925bf6Swillf             got_plugin = 1;
16454925bf6Swillf             htmp->bundle = pluginBundle;
16554925bf6Swillf             pluginBundle = NULL;  /* htmp->bundle takes ownership */
16654925bf6Swillf         }
16754925bf6Swillf 
16854925bf6Swillf         if (pluginBundle != NULL) { CFRelease (pluginBundle); }
16954925bf6Swillf         if (pluginURL    != NULL) { CFRelease (pluginURL); }
17054925bf6Swillf         if (pluginPath   != NULL) { CFRelease (pluginPath); }
17154925bf6Swillf     }
17254925bf6Swillf #endif
17354925bf6Swillf 
17454925bf6Swillf     if (!err && !got_plugin) {
17554925bf6Swillf         err = ENOENT;  /* no plugin or no way to load plugins */
17654925bf6Swillf     }
17754925bf6Swillf 
17854925bf6Swillf     if (!err) {
17954925bf6Swillf         *h = htmp;
18054925bf6Swillf         htmp = NULL;  /* h takes ownership */
18154925bf6Swillf     }
18254925bf6Swillf 
18354925bf6Swillf     if (htmp != NULL) { free (htmp); }
18454925bf6Swillf 
18554925bf6Swillf     return err;
18654925bf6Swillf }
18754925bf6Swillf 
18854925bf6Swillf /*ARGSUSED*/
18954925bf6Swillf static long
krb5int_get_plugin_sym(struct plugin_file_handle * h,const char * csymname,int isfunc,void ** ptr,struct errinfo * ep)19054925bf6Swillf krb5int_get_plugin_sym (struct plugin_file_handle *h,
19154925bf6Swillf                         const char *csymname, int isfunc, void **ptr,
19254925bf6Swillf 			struct errinfo *ep)
19354925bf6Swillf {
19454925bf6Swillf     long err = 0;
19554925bf6Swillf     void *sym = NULL;
19654925bf6Swillf 
19754925bf6Swillf #if USE_DLOPEN
19854925bf6Swillf     if (!err && !sym && (h->dlhandle != NULL)) {
19954925bf6Swillf         /* XXX Do we need to add a leading "_" to the symbol name on any
20054925bf6Swillf         modern platforms?  */
20154925bf6Swillf         sym = dlsym (h->dlhandle, csymname);
20254925bf6Swillf         if (sym == NULL) {
20354925bf6Swillf             const char *e = dlerror (); /* XXX copy and save away */
20454925bf6Swillf             Tprintf ("dlsym(%s): %s\n", csymname, e);
20554925bf6Swillf             err = ENOENT; /* XXX */
20654925bf6Swillf 	    krb5int_set_error(ep, err, "%s", e);
20754925bf6Swillf         }
20854925bf6Swillf     }
20954925bf6Swillf #endif
21054925bf6Swillf 
21154925bf6Swillf #if USE_CFBUNDLE
21254925bf6Swillf     if (!err && !sym && (h->bundle != NULL)) {
21354925bf6Swillf         CFStringRef cfsymname = NULL;
21454925bf6Swillf 
21554925bf6Swillf         if (!err) {
21654925bf6Swillf             cfsymname = CFStringCreateWithCString (kCFAllocatorDefault, csymname,
21754925bf6Swillf                                                    kCFStringEncodingASCII);
21854925bf6Swillf             if (cfsymname == NULL) { err = ENOMEM; }
21954925bf6Swillf         }
22054925bf6Swillf 
22154925bf6Swillf         if (!err) {
22254925bf6Swillf             if (isfunc) {
22354925bf6Swillf                 sym = CFBundleGetFunctionPointerForName (h->bundle, cfsymname);
22454925bf6Swillf             } else {
22554925bf6Swillf                 sym = CFBundleGetDataPointerForName (h->bundle, cfsymname);
22654925bf6Swillf             }
22754925bf6Swillf             if (sym == NULL) { err = ENOENT; }  /* XXX */
22854925bf6Swillf         }
22954925bf6Swillf 
23054925bf6Swillf         if (cfsymname != NULL) { CFRelease (cfsymname); }
23154925bf6Swillf     }
23254925bf6Swillf #endif
23354925bf6Swillf 
23454925bf6Swillf     if (!err && (sym == NULL)) {
23554925bf6Swillf         err = ENOENT;  /* unimplemented */
23654925bf6Swillf     }
23754925bf6Swillf 
23854925bf6Swillf     if (!err) {
23954925bf6Swillf         *ptr = sym;
24054925bf6Swillf     }
24154925bf6Swillf 
24254925bf6Swillf     return err;
24354925bf6Swillf }
24454925bf6Swillf 
24554925bf6Swillf long KRB5_CALLCONV
krb5int_get_plugin_data(struct plugin_file_handle * h,const char * csymname,void ** ptr,struct errinfo * ep)24654925bf6Swillf krb5int_get_plugin_data (struct plugin_file_handle *h, const char *csymname,
24754925bf6Swillf 			 void **ptr, struct errinfo *ep)
24854925bf6Swillf {
24954925bf6Swillf     return krb5int_get_plugin_sym (h, csymname, 0, ptr, ep);
25054925bf6Swillf }
25154925bf6Swillf 
25254925bf6Swillf long KRB5_CALLCONV
krb5int_get_plugin_func(struct plugin_file_handle * h,const char * csymname,void (** ptr)(),struct errinfo * ep)25354925bf6Swillf krb5int_get_plugin_func (struct plugin_file_handle *h, const char *csymname,
25454925bf6Swillf 			 void (**ptr)(), struct errinfo *ep)
25554925bf6Swillf {
25654925bf6Swillf     void *dptr = NULL;
25754925bf6Swillf     long err = krb5int_get_plugin_sym (h, csymname, 1, &dptr, ep);
25854925bf6Swillf     if (!err) {
25954925bf6Swillf         /* Cast function pointers to avoid code duplication */
26054925bf6Swillf         *ptr = (void (*)()) dptr;
26154925bf6Swillf     }
26254925bf6Swillf     return err;
26354925bf6Swillf }
26454925bf6Swillf 
26554925bf6Swillf void KRB5_CALLCONV
krb5int_close_plugin(struct plugin_file_handle * h)26654925bf6Swillf krb5int_close_plugin (struct plugin_file_handle *h)
26754925bf6Swillf {
26854925bf6Swillf #if USE_DLOPEN
26954925bf6Swillf     if (h->dlhandle != NULL) { dlclose(h->dlhandle); }
27054925bf6Swillf #endif
27154925bf6Swillf #if USE_CFBUNDLE
27254925bf6Swillf     /* Do not call CFBundleUnloadExecutable because it's not ref counted.
27354925bf6Swillf      * CFRelease will unload the bundle if the internal refcount goes to zero. */
27454925bf6Swillf     if (h->bundle != NULL) { CFRelease (h->bundle); }
27554925bf6Swillf #endif
27654925bf6Swillf     free (h);
27754925bf6Swillf }
27854925bf6Swillf 
27954925bf6Swillf /* autoconf docs suggest using this preference order */
28054925bf6Swillf #if HAVE_DIRENT_H || USE_DIRENT_H
28154925bf6Swillf #include <dirent.h>
28254925bf6Swillf #define NAMELEN(D) strlen((D)->d_name)
28354925bf6Swillf #else
28454925bf6Swillf #define dirent direct
28554925bf6Swillf #define NAMELEN(D) ((D)->d->namlen)
28654925bf6Swillf #if HAVE_SYS_NDIR_H
28754925bf6Swillf # include <sys/ndir.h>
28854925bf6Swillf #elif HAVE_SYS_DIR_H
28954925bf6Swillf # include <sys/dir.h>
29054925bf6Swillf #elif HAVE_NDIR_H
29154925bf6Swillf # include <ndir.h>
29254925bf6Swillf #endif
29354925bf6Swillf #endif
29454925bf6Swillf 
29554925bf6Swillf 
29654925bf6Swillf #ifdef HAVE_STRERROR_R
29754925bf6Swillf #define ERRSTR(ERR, BUF) \
29854925bf6Swillf     (strerror_r (ERR, BUF, sizeof(BUF)) == 0 ? BUF : strerror (ERR))
29954925bf6Swillf #else
30054925bf6Swillf #define ERRSTR(ERR, BUF) \
30154925bf6Swillf     (strerror (ERR))
30254925bf6Swillf #endif
30354925bf6Swillf 
30454925bf6Swillf static long
krb5int_plugin_file_handle_array_init(struct plugin_file_handle *** harray)30554925bf6Swillf krb5int_plugin_file_handle_array_init (struct plugin_file_handle ***harray)
30654925bf6Swillf {
30754925bf6Swillf     long err = 0;
30854925bf6Swillf 
30954925bf6Swillf     *harray = calloc (1, sizeof (**harray)); /* calloc initializes to NULL */
31054925bf6Swillf     if (*harray == NULL) { err = errno; }
31154925bf6Swillf 
31254925bf6Swillf     return err;
31354925bf6Swillf }
31454925bf6Swillf 
31554925bf6Swillf static long
krb5int_plugin_file_handle_array_add(struct plugin_file_handle *** harray,int * count,struct plugin_file_handle * p)31654925bf6Swillf krb5int_plugin_file_handle_array_add (struct plugin_file_handle ***harray, int *count,
31754925bf6Swillf                                       struct plugin_file_handle *p)
31854925bf6Swillf {
31954925bf6Swillf     long err = 0;
32054925bf6Swillf     struct plugin_file_handle **newharray = NULL;
32154925bf6Swillf     int newcount = *count + 1;
32254925bf6Swillf 
32354925bf6Swillf     newharray = realloc (*harray, ((newcount + 1) * sizeof (**harray))); /* +1 for NULL */
32454925bf6Swillf     if (newharray == NULL) {
32554925bf6Swillf         err = errno;
32654925bf6Swillf     } else {
32754925bf6Swillf         newharray[newcount - 1] = p;
32854925bf6Swillf         newharray[newcount] = NULL;
32954925bf6Swillf 	*count = newcount;
33054925bf6Swillf         *harray = newharray;
33154925bf6Swillf     }
33254925bf6Swillf 
33354925bf6Swillf     return err;
33454925bf6Swillf }
33554925bf6Swillf 
33654925bf6Swillf static void
krb5int_plugin_file_handle_array_free(struct plugin_file_handle ** harray)33754925bf6Swillf krb5int_plugin_file_handle_array_free (struct plugin_file_handle **harray)
33854925bf6Swillf {
33954925bf6Swillf     if (harray != NULL) {
34054925bf6Swillf         int i;
34154925bf6Swillf         for (i = 0; harray[i] != NULL; i++) {
34254925bf6Swillf             krb5int_close_plugin (harray[i]);
34354925bf6Swillf         }
34454925bf6Swillf         free (harray);
34554925bf6Swillf     }
34654925bf6Swillf }
34754925bf6Swillf 
34854925bf6Swillf #if TARGET_OS_MAC
34954925bf6Swillf #define FILEEXTS { "", ".bundle", ".so", NULL }
35054925bf6Swillf #elif defined(_WIN32)
35154925bf6Swillf #define FILEEXTS  { "", ".dll", NULL }
35254925bf6Swillf #else
35354925bf6Swillf #define FILEEXTS  { "", ".so", NULL }
35454925bf6Swillf #endif
35554925bf6Swillf 
35654925bf6Swillf 
35754925bf6Swillf static void
krb5int_free_plugin_filenames(char ** filenames)35854925bf6Swillf krb5int_free_plugin_filenames (char **filenames)
35954925bf6Swillf {
36054925bf6Swillf     if (filenames != NULL) {
36154925bf6Swillf         int i;
36254925bf6Swillf         for (i = 0; filenames[i] != NULL; i++) {
36354925bf6Swillf             free (filenames[i]);
36454925bf6Swillf         }
36554925bf6Swillf         free (filenames);
36654925bf6Swillf     }
36754925bf6Swillf }
36854925bf6Swillf 
36954925bf6Swillf 
37054925bf6Swillf static long
krb5int_get_plugin_filenames(const char * const * filebases,char *** filenames)37154925bf6Swillf krb5int_get_plugin_filenames (const char * const *filebases, char ***filenames)
37254925bf6Swillf {
37354925bf6Swillf     long err = 0;
37454925bf6Swillf     static const char *const fileexts[] = FILEEXTS;
37554925bf6Swillf     char **tempnames = NULL;
37654925bf6Swillf     int i;
37754925bf6Swillf 
37854925bf6Swillf     if (!err) {
37954925bf6Swillf         size_t count = 0;
38054925bf6Swillf         for (i = 0; filebases[i] != NULL; i++, count++);
38154925bf6Swillf         for (i = 0; fileexts[i] != NULL; i++, count++);
38254925bf6Swillf         tempnames = calloc (count, sizeof (char *));
38354925bf6Swillf         if (tempnames == NULL) { err = errno; }
38454925bf6Swillf     }
38554925bf6Swillf 
38654925bf6Swillf     if (!err) {
38754925bf6Swillf         int j;
38854925bf6Swillf         for (i = 0; !err && (filebases[i] != NULL); i++) {
38954925bf6Swillf             size_t baselen = strlen (filebases[i]);
39054925bf6Swillf             for (j = 0; !err && (fileexts[j] != NULL); j++) {
39154925bf6Swillf                 size_t len = baselen + strlen (fileexts[j]) + 2; /* '.' + NULL */
39254925bf6Swillf                 tempnames[i+j] = malloc (len * sizeof (char));
39354925bf6Swillf                 if (tempnames[i+j] == NULL) {
39454925bf6Swillf                     err = errno;
39554925bf6Swillf                 } else {
39654925bf6Swillf 		    /*LINTED*/
39754925bf6Swillf                     sprintf (tempnames[i+j], "%s%s", filebases[i], fileexts[j]);
39854925bf6Swillf                 }
39954925bf6Swillf             }
40054925bf6Swillf         }
40154925bf6Swillf     }
40254925bf6Swillf 
40354925bf6Swillf     if (!err) {
40454925bf6Swillf         *filenames = tempnames;
40554925bf6Swillf         tempnames = NULL;
40654925bf6Swillf     }
40754925bf6Swillf 
40854925bf6Swillf     if (tempnames != NULL) { krb5int_free_plugin_filenames (tempnames); }
40954925bf6Swillf 
41054925bf6Swillf     return err;
41154925bf6Swillf }
41254925bf6Swillf 
41354925bf6Swillf 
41454925bf6Swillf /* Takes a NULL-terminated list of directories.  If filebases is NULL, filebases is ignored
41554925bf6Swillf  * all plugins in the directories are loaded.  If filebases is a NULL-terminated array of names,
41654925bf6Swillf  * only plugins in the directories with those name (plus any platform extension) are loaded. */
41754925bf6Swillf 
41854925bf6Swillf long KRB5_CALLCONV
krb5int_open_plugin_dirs(const char * const * dirnames,const char * const * filebases,struct plugin_dir_handle * dirhandle,struct errinfo * ep)41954925bf6Swillf krb5int_open_plugin_dirs (const char * const *dirnames,
42054925bf6Swillf                           const char * const *filebases,
42154925bf6Swillf 			  struct plugin_dir_handle *dirhandle,
42254925bf6Swillf                           struct errinfo *ep)
42354925bf6Swillf {
42454925bf6Swillf     long err = 0;
42554925bf6Swillf     struct plugin_file_handle **h = NULL;
42654925bf6Swillf     int count = 0;
42754925bf6Swillf     char **filenames = NULL;
42854925bf6Swillf     int i;
42954925bf6Swillf 
43054925bf6Swillf     if (!err) {
43154925bf6Swillf         err = krb5int_plugin_file_handle_array_init (&h);
43254925bf6Swillf     }
43354925bf6Swillf 
43454925bf6Swillf     if (!err && (filebases != NULL)) {
43554925bf6Swillf 	err = krb5int_get_plugin_filenames (filebases, &filenames);
43654925bf6Swillf     }
43754925bf6Swillf 
43854925bf6Swillf     for (i = 0; !err && dirnames[i] != NULL; i++) {
43954925bf6Swillf 	size_t dirnamelen = strlen (dirnames[i]) + 1; /* '/' */
44054925bf6Swillf         if (filenames != NULL) {
44154925bf6Swillf             /* load plugins with names from filenames from each directory */
44254925bf6Swillf             int j;
44354925bf6Swillf 
44454925bf6Swillf             for (j = 0; !err && filenames[j] != NULL; j++) {
44554925bf6Swillf                 struct plugin_file_handle *handle = NULL;
44654925bf6Swillf 		char *filepath = NULL;
44754925bf6Swillf 
44854925bf6Swillf 		if (!err) {
44954925bf6Swillf 		    filepath = malloc (dirnamelen + strlen (filenames[j]) + 1); /* NULL */
45054925bf6Swillf 		    if (filepath == NULL) {
45154925bf6Swillf 			err = errno;
45254925bf6Swillf 		    } else {
45354925bf6Swillf 			/*LINTED*/
45454925bf6Swillf 			sprintf (filepath, "%s/%s", dirnames[i], filenames[j]);
45554925bf6Swillf 		    }
45654925bf6Swillf 		}
45754925bf6Swillf 
45854925bf6Swillf                 if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
45954925bf6Swillf                     err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
46054925bf6Swillf                     if (!err) { handle = NULL; }  /* h takes ownership */
46154925bf6Swillf                 }
46254925bf6Swillf 
46354925bf6Swillf 		if (filepath != NULL) { free (filepath); }
46454925bf6Swillf 		if (handle   != NULL) { krb5int_close_plugin (handle); }
46554925bf6Swillf             }
46654925bf6Swillf         } else {
46754925bf6Swillf             /* load all plugins in each directory */
46854925bf6Swillf #ifndef _WIN32
469*159d09a2SMark Phalan 	    DIR *dir = opendir (dirnames[i]);
47054925bf6Swillf 
471*159d09a2SMark Phalan             while (dir != NULL && !err) {
47254925bf6Swillf                 struct dirent *d = NULL;
47354925bf6Swillf                 char *filepath = NULL;
47454925bf6Swillf                 struct plugin_file_handle *handle = NULL;
475*159d09a2SMark Phalan                 int len;
47654925bf6Swillf 
47754925bf6Swillf                 d = readdir (dir);
47854925bf6Swillf                 if (d == NULL) { break; }
47954925bf6Swillf 
48054925bf6Swillf                 if ((strcmp (d->d_name, ".") == 0) ||
48154925bf6Swillf                     (strcmp (d->d_name, "..") == 0)) {
48254925bf6Swillf                     continue;
48354925bf6Swillf                 }
48454925bf6Swillf 
485*159d09a2SMark Phalan 		/* Solaris Kerberos: Only open files with a .so extension */
486*159d09a2SMark Phalan 		len = NAMELEN (d);
487*159d09a2SMark Phalan 		if (len < 3 || strcmp(".so", d->d_name + len - 3 ) != 0)
488*159d09a2SMark Phalan 			continue;
489*159d09a2SMark Phalan 
49054925bf6Swillf 		if (!err) {
49154925bf6Swillf 		    filepath = malloc (dirnamelen + len + 1); /* NULL */
49254925bf6Swillf 		    if (filepath == NULL) {
49354925bf6Swillf 			err = errno;
49454925bf6Swillf 		    } else {
49554925bf6Swillf 			/*LINTED*/
49654925bf6Swillf 			sprintf (filepath, "%s/%*s", dirnames[i], len, d->d_name);
49754925bf6Swillf 		    }
49854925bf6Swillf 		}
49954925bf6Swillf 
50054925bf6Swillf                 if (!err) {
50154925bf6Swillf                     if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
50254925bf6Swillf                         err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
50354925bf6Swillf                         if (!err) { handle = NULL; }  /* h takes ownership */
50454925bf6Swillf                     }
50554925bf6Swillf                 }
50654925bf6Swillf 
50754925bf6Swillf                 if (filepath  != NULL) { free (filepath); }
50854925bf6Swillf                 if (handle    != NULL) { krb5int_close_plugin (handle); }
50954925bf6Swillf             }
51054925bf6Swillf 
51154925bf6Swillf             if (dir != NULL) { closedir (dir); }
51254925bf6Swillf #else
51354925bf6Swillf 	    /* Until a Windows implementation of this code is implemented */
51454925bf6Swillf 	    err = ENOENT;
51554925bf6Swillf #endif /* _WIN32 */
51654925bf6Swillf         }
51754925bf6Swillf     }
51854925bf6Swillf 
51954925bf6Swillf     if (err == ENOENT) {
52054925bf6Swillf         err = 0;  /* ran out of plugins -- do nothing */
52154925bf6Swillf     }
52254925bf6Swillf 
52354925bf6Swillf     if (!err) {
52454925bf6Swillf         dirhandle->files = h;
52554925bf6Swillf         h = NULL;  /* dirhandle->files takes ownership */
52654925bf6Swillf     }
52754925bf6Swillf 
52854925bf6Swillf     if (filenames != NULL) { krb5int_free_plugin_filenames (filenames); }
52954925bf6Swillf     if (h         != NULL) { krb5int_plugin_file_handle_array_free (h); }
53054925bf6Swillf 
53154925bf6Swillf     return err;
53254925bf6Swillf }
53354925bf6Swillf 
53454925bf6Swillf void KRB5_CALLCONV
krb5int_close_plugin_dirs(struct plugin_dir_handle * dirhandle)53554925bf6Swillf krb5int_close_plugin_dirs (struct plugin_dir_handle *dirhandle)
53654925bf6Swillf {
53754925bf6Swillf     if (dirhandle->files != NULL) {
53854925bf6Swillf         int i;
53954925bf6Swillf         for (i = 0; dirhandle->files[i] != NULL; i++) {
54054925bf6Swillf             krb5int_close_plugin (dirhandle->files[i]);
54154925bf6Swillf         }
54254925bf6Swillf         free (dirhandle->files);
54354925bf6Swillf         dirhandle->files = NULL;
54454925bf6Swillf     }
54554925bf6Swillf }
54654925bf6Swillf 
54754925bf6Swillf void KRB5_CALLCONV
krb5int_free_plugin_dir_data(void ** ptrs)54854925bf6Swillf krb5int_free_plugin_dir_data (void **ptrs)
54954925bf6Swillf {
55054925bf6Swillf     /* Nothing special to be done per pointer.  */
55154925bf6Swillf     free(ptrs);
55254925bf6Swillf }
55354925bf6Swillf 
55454925bf6Swillf long KRB5_CALLCONV
krb5int_get_plugin_dir_data(struct plugin_dir_handle * dirhandle,const char * symname,void *** ptrs,struct errinfo * ep)55554925bf6Swillf krb5int_get_plugin_dir_data (struct plugin_dir_handle *dirhandle,
55654925bf6Swillf 			     const char *symname,
55754925bf6Swillf 			     void ***ptrs,
55854925bf6Swillf 			     struct errinfo *ep)
55954925bf6Swillf {
56054925bf6Swillf     long err = 0;
56154925bf6Swillf     void **p = NULL;
56254925bf6Swillf     int count = 0;
56354925bf6Swillf 
56454925bf6Swillf     /* XXX Do we need to add a leading "_" to the symbol name on any
56554925bf6Swillf        modern platforms?  */
56654925bf6Swillf 
56754925bf6Swillf     Tprintf("get_plugin_data_sym(%s)\n", symname);
56854925bf6Swillf 
56954925bf6Swillf     if (!err) {
57054925bf6Swillf         p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
57154925bf6Swillf         if (p == NULL) { err = errno; }
57254925bf6Swillf     }
57354925bf6Swillf 
57454925bf6Swillf     if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
57554925bf6Swillf         int i = 0;
57654925bf6Swillf 
57754925bf6Swillf         for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
57854925bf6Swillf             void *sym = NULL;
57954925bf6Swillf 
58054925bf6Swillf             if (krb5int_get_plugin_data (dirhandle->files[i], symname, &sym, ep) == 0) {
58154925bf6Swillf                 void **newp = NULL;
58254925bf6Swillf 
58354925bf6Swillf                 count++;
58454925bf6Swillf                 newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
58554925bf6Swillf                 if (newp == NULL) {
58654925bf6Swillf                     err = errno;
58754925bf6Swillf                 } else {
58854925bf6Swillf                     p = newp;
58954925bf6Swillf                     p[count - 1] = sym;
59054925bf6Swillf                     p[count] = NULL;
59154925bf6Swillf                 }
59254925bf6Swillf             }
59354925bf6Swillf         }
59454925bf6Swillf     }
59554925bf6Swillf 
59654925bf6Swillf     if (!err) {
59754925bf6Swillf         *ptrs = p;
59854925bf6Swillf         p = NULL; /* ptrs takes ownership */
59954925bf6Swillf     }
60054925bf6Swillf 
60154925bf6Swillf     if (p != NULL) { free (p); }
60254925bf6Swillf 
60354925bf6Swillf     return err;
60454925bf6Swillf }
60554925bf6Swillf 
60654925bf6Swillf void KRB5_CALLCONV
krb5int_free_plugin_dir_func(void (** ptrs)(void))60754925bf6Swillf krb5int_free_plugin_dir_func (void (**ptrs)(void))
60854925bf6Swillf {
60954925bf6Swillf     /* Nothing special to be done per pointer.  */
61054925bf6Swillf     free(ptrs);
61154925bf6Swillf }
61254925bf6Swillf 
61354925bf6Swillf long KRB5_CALLCONV
krb5int_get_plugin_dir_func(struct plugin_dir_handle * dirhandle,const char * symname,void (*** ptrs)(void),struct errinfo * ep)61454925bf6Swillf krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle,
61554925bf6Swillf 			     const char *symname,
61654925bf6Swillf 			     void (***ptrs)(void),
61754925bf6Swillf 			     struct errinfo *ep)
61854925bf6Swillf {
61954925bf6Swillf     long err = 0;
62054925bf6Swillf     void (**p)() = NULL;
62154925bf6Swillf     int count = 0;
62254925bf6Swillf 
62354925bf6Swillf     /* XXX Do we need to add a leading "_" to the symbol name on any
62454925bf6Swillf         modern platforms?  */
62554925bf6Swillf 
62654925bf6Swillf     Tprintf("get_plugin_data_sym(%s)\n", symname);
62754925bf6Swillf 
62854925bf6Swillf     if (!err) {
62954925bf6Swillf         p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
63054925bf6Swillf         if (p == NULL) { err = errno; }
63154925bf6Swillf     }
63254925bf6Swillf 
63354925bf6Swillf     if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
63454925bf6Swillf         int i = 0;
63554925bf6Swillf 
63654925bf6Swillf         for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
63754925bf6Swillf             void (*sym)() = NULL;
63854925bf6Swillf 
63954925bf6Swillf             if (krb5int_get_plugin_func (dirhandle->files[i], symname, &sym, ep) == 0) {
64054925bf6Swillf                 void (**newp)() = NULL;
64154925bf6Swillf 
64254925bf6Swillf                 count++;
64354925bf6Swillf                 newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
64454925bf6Swillf                 if (newp == NULL) {
64554925bf6Swillf                     err = errno;
64654925bf6Swillf                 } else {
64754925bf6Swillf                     p = newp;
64854925bf6Swillf                     p[count - 1] = sym;
64954925bf6Swillf                     p[count] = NULL;
65054925bf6Swillf                 }
65154925bf6Swillf             }
65254925bf6Swillf         }
65354925bf6Swillf     }
65454925bf6Swillf 
65554925bf6Swillf     if (!err) {
65654925bf6Swillf         *ptrs = p;
65754925bf6Swillf         p = NULL; /* ptrs takes ownership */
65854925bf6Swillf     }
65954925bf6Swillf 
66054925bf6Swillf     if (p != NULL) { free (p); }
66154925bf6Swillf 
66254925bf6Swillf     return err;
66354925bf6Swillf }
664