xref: /freebsd/crypto/krb5/src/util/support/plugins.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* util/support/plugins.c - Plugin module support functions */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 2006, 2008 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All Rights Reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert 
27*7f2fe78bSCy Schubert #include "k5-platform.h"
28*7f2fe78bSCy Schubert #include "k5-plugin.h"
29*7f2fe78bSCy Schubert #if USE_DLOPEN
30*7f2fe78bSCy Schubert #include <dlfcn.h>
31*7f2fe78bSCy Schubert #endif
32*7f2fe78bSCy Schubert 
33*7f2fe78bSCy Schubert #if USE_DLOPEN
34*7f2fe78bSCy Schubert #ifdef RTLD_GROUP
35*7f2fe78bSCy Schubert #define GROUP RTLD_GROUP
36*7f2fe78bSCy Schubert #else
37*7f2fe78bSCy Schubert #define GROUP 0
38*7f2fe78bSCy Schubert #endif
39*7f2fe78bSCy Schubert #ifdef RTLD_NODELETE
40*7f2fe78bSCy Schubert #define NODELETE RTLD_NODELETE
41*7f2fe78bSCy Schubert #else
42*7f2fe78bSCy Schubert #define NODELETE 0
43*7f2fe78bSCy Schubert #endif
44*7f2fe78bSCy Schubert #define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | GROUP | NODELETE)
45*7f2fe78bSCy Schubert #endif
46*7f2fe78bSCy Schubert 
47*7f2fe78bSCy Schubert /*
48*7f2fe78bSCy Schubert  * glibc bug 11941, fixed in release 2.25, can cause an assertion failure in
49*7f2fe78bSCy Schubert  * dlclose() on process exit.  Our workaround is to leak dlopen() handles
50*7f2fe78bSCy Schubert  * (which doesn't typically manifest in leak detection tools because the
51*7f2fe78bSCy Schubert  * handles are still reachable via a global table in libdl).  Because we
52*7f2fe78bSCy Schubert  * dlopen() with RTLD_NODELETE, we weren't going to unload the plugin objects
53*7f2fe78bSCy Schubert  * anyway.
54*7f2fe78bSCy Schubert  */
55*7f2fe78bSCy Schubert #ifdef __GLIBC_PREREQ
56*7f2fe78bSCy Schubert #if ! __GLIBC_PREREQ(2, 25)
57*7f2fe78bSCy Schubert #define dlclose(x)
58*7f2fe78bSCy Schubert #endif
59*7f2fe78bSCy Schubert #endif
60*7f2fe78bSCy Schubert 
61*7f2fe78bSCy Schubert #include <stdarg.h>
Tprintf(const char * fmt,...)62*7f2fe78bSCy Schubert static void Tprintf (const char *fmt, ...)
63*7f2fe78bSCy Schubert {
64*7f2fe78bSCy Schubert #ifdef DEBUG
65*7f2fe78bSCy Schubert     va_list va;
66*7f2fe78bSCy Schubert     va_start (va, fmt);
67*7f2fe78bSCy Schubert     vfprintf (stderr, fmt, va);
68*7f2fe78bSCy Schubert     va_end (va);
69*7f2fe78bSCy Schubert #endif
70*7f2fe78bSCy Schubert }
71*7f2fe78bSCy Schubert 
72*7f2fe78bSCy Schubert struct plugin_file_handle {
73*7f2fe78bSCy Schubert #if defined(USE_DLOPEN)
74*7f2fe78bSCy Schubert     void *dlhandle;
75*7f2fe78bSCy Schubert #elif defined(_WIN32)
76*7f2fe78bSCy Schubert     HMODULE module;
77*7f2fe78bSCy Schubert #else
78*7f2fe78bSCy Schubert     char dummy;
79*7f2fe78bSCy Schubert #endif
80*7f2fe78bSCy Schubert };
81*7f2fe78bSCy Schubert 
82*7f2fe78bSCy Schubert #if defined(USE_DLOPEN)
83*7f2fe78bSCy Schubert 
84*7f2fe78bSCy Schubert static long
open_plugin_dlfcn(struct plugin_file_handle * h,const char * filename,struct errinfo * ep)85*7f2fe78bSCy Schubert open_plugin_dlfcn(struct plugin_file_handle *h, const char *filename,
86*7f2fe78bSCy Schubert                   struct errinfo *ep)
87*7f2fe78bSCy Schubert {
88*7f2fe78bSCy Schubert     const char *e;
89*7f2fe78bSCy Schubert 
90*7f2fe78bSCy Schubert     h->dlhandle = dlopen(filename, PLUGIN_DLOPEN_FLAGS);
91*7f2fe78bSCy Schubert     if (h->dlhandle == NULL) {
92*7f2fe78bSCy Schubert         e = dlerror();
93*7f2fe78bSCy Schubert         if (e == NULL)
94*7f2fe78bSCy Schubert             e = _("unknown failure");
95*7f2fe78bSCy Schubert         Tprintf("dlopen(%s): %s\n", filename, e);
96*7f2fe78bSCy Schubert         k5_set_error(ep, ENOENT, _("unable to load plugin [%s]: %s"),
97*7f2fe78bSCy Schubert                      filename, e);
98*7f2fe78bSCy Schubert         return ENOENT;
99*7f2fe78bSCy Schubert     }
100*7f2fe78bSCy Schubert     return 0;
101*7f2fe78bSCy Schubert }
102*7f2fe78bSCy Schubert #define open_plugin open_plugin_dlfcn
103*7f2fe78bSCy Schubert 
104*7f2fe78bSCy Schubert static long
get_sym_dlfcn(struct plugin_file_handle * h,const char * csymname,void ** sym_out,struct errinfo * ep)105*7f2fe78bSCy Schubert get_sym_dlfcn(struct plugin_file_handle *h, const char *csymname,
106*7f2fe78bSCy Schubert               void **sym_out, struct errinfo *ep)
107*7f2fe78bSCy Schubert {
108*7f2fe78bSCy Schubert     const char *e;
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert     if (h->dlhandle == NULL)
111*7f2fe78bSCy Schubert         return ENOENT;
112*7f2fe78bSCy Schubert     *sym_out = dlsym(h->dlhandle, csymname);
113*7f2fe78bSCy Schubert     if (*sym_out == NULL) {
114*7f2fe78bSCy Schubert         e = dlerror();
115*7f2fe78bSCy Schubert         if (e == NULL)
116*7f2fe78bSCy Schubert             e = _("unknown failure");
117*7f2fe78bSCy Schubert         Tprintf("dlsym(%s): %s\n", csymname, e);
118*7f2fe78bSCy Schubert         k5_set_error(ep, ENOENT, "%s", e);
119*7f2fe78bSCy Schubert         return ENOENT;
120*7f2fe78bSCy Schubert     }
121*7f2fe78bSCy Schubert     return 0;
122*7f2fe78bSCy Schubert }
123*7f2fe78bSCy Schubert #define get_sym get_sym_dlfcn
124*7f2fe78bSCy Schubert 
125*7f2fe78bSCy Schubert static void
close_plugin_dlfcn(struct plugin_file_handle * h)126*7f2fe78bSCy Schubert close_plugin_dlfcn(struct plugin_file_handle *h)
127*7f2fe78bSCy Schubert {
128*7f2fe78bSCy Schubert     if (h->dlhandle != NULL)
129*7f2fe78bSCy Schubert         dlclose(h->dlhandle);
130*7f2fe78bSCy Schubert }
131*7f2fe78bSCy Schubert #define close_plugin close_plugin_dlfcn
132*7f2fe78bSCy Schubert 
133*7f2fe78bSCy Schubert #elif defined(_WIN32)
134*7f2fe78bSCy Schubert 
135*7f2fe78bSCy Schubert static long
open_plugin_win32(struct plugin_file_handle * h,const char * filename,struct errinfo * ep)136*7f2fe78bSCy Schubert open_plugin_win32(struct plugin_file_handle *h, const char *filename,
137*7f2fe78bSCy Schubert                   struct errinfo *ep)
138*7f2fe78bSCy Schubert {
139*7f2fe78bSCy Schubert     h->module = LoadLibrary(filename);
140*7f2fe78bSCy Schubert     if (h == NULL) {
141*7f2fe78bSCy Schubert         Tprintf("Unable to load dll: %s\n", filename);
142*7f2fe78bSCy Schubert         k5_set_error(ep, ENOENT, _("unable to load DLL [%s]"), filename);
143*7f2fe78bSCy Schubert         return ENOENT;
144*7f2fe78bSCy Schubert     }
145*7f2fe78bSCy Schubert     return 0;
146*7f2fe78bSCy Schubert }
147*7f2fe78bSCy Schubert #define open_plugin open_plugin_win32
148*7f2fe78bSCy Schubert 
149*7f2fe78bSCy Schubert static long
get_sym_win32(struct plugin_file_handle * h,const char * csymname,void ** sym_out,struct errinfo * ep)150*7f2fe78bSCy Schubert get_sym_win32(struct plugin_file_handle *h, const char *csymname,
151*7f2fe78bSCy Schubert               void **sym_out, struct errinfo *ep)
152*7f2fe78bSCy Schubert {
153*7f2fe78bSCy Schubert     LPVOID lpMsgBuf;
154*7f2fe78bSCy Schubert     DWORD dw;
155*7f2fe78bSCy Schubert 
156*7f2fe78bSCy Schubert     if (h->module == NULL)
157*7f2fe78bSCy Schubert         return ENOENT;
158*7f2fe78bSCy Schubert     *sym_out = GetProcAddress(h->module, csymname);
159*7f2fe78bSCy Schubert     if (*sym_out == NULL) {
160*7f2fe78bSCy Schubert         Tprintf("GetProcAddress(%s): %i\n", csymname, GetLastError());
161*7f2fe78bSCy Schubert         dw = GetLastError();
162*7f2fe78bSCy Schubert         if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
163*7f2fe78bSCy Schubert                           FORMAT_MESSAGE_FROM_SYSTEM,
164*7f2fe78bSCy Schubert                           NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
165*7f2fe78bSCy Schubert                           (LPTSTR)&lpMsgBuf, 0, NULL)) {
166*7f2fe78bSCy Schubert             k5_set_error(ep, ENOENT, _("unable to get DLL Symbol: %s"),
167*7f2fe78bSCy Schubert                          (char *)lpMsgBuf);
168*7f2fe78bSCy Schubert             LocalFree(lpMsgBuf);
169*7f2fe78bSCy Schubert         }
170*7f2fe78bSCy Schubert         return ENOENT;
171*7f2fe78bSCy Schubert     }
172*7f2fe78bSCy Schubert     return 0;
173*7f2fe78bSCy Schubert }
174*7f2fe78bSCy Schubert #define get_sym get_sym_win32
175*7f2fe78bSCy Schubert 
176*7f2fe78bSCy Schubert static void
close_plugin_win32(struct plugin_file_handle * h)177*7f2fe78bSCy Schubert close_plugin_win32(struct plugin_file_handle *h)
178*7f2fe78bSCy Schubert {
179*7f2fe78bSCy Schubert     if (h->module != NULL)
180*7f2fe78bSCy Schubert         FreeLibrary(h->module);
181*7f2fe78bSCy Schubert }
182*7f2fe78bSCy Schubert #define close_plugin close_plugin_win32
183*7f2fe78bSCy Schubert 
184*7f2fe78bSCy Schubert #else
185*7f2fe78bSCy Schubert 
186*7f2fe78bSCy Schubert static long
open_plugin_dummy(struct plugin_file_handle * h,const char * filename,struct errinfo * ep)187*7f2fe78bSCy Schubert open_plugin_dummy(struct plugin_file_handle *h, const char *filename,
188*7f2fe78bSCy Schubert                   struct errinfo *ep)
189*7f2fe78bSCy Schubert {
190*7f2fe78bSCy Schubert     k5_set_error(ep, ENOENT, _("plugin loading unavailable"));
191*7f2fe78bSCy Schubert     return ENOENT;
192*7f2fe78bSCy Schubert }
193*7f2fe78bSCy Schubert #define open_plugin open_plugin_dummy
194*7f2fe78bSCy Schubert 
195*7f2fe78bSCy Schubert static long
get_sym_dummy(struct plugin_file_handle * h,const char * csymname,void ** sym_out,struct errinfo * ep)196*7f2fe78bSCy Schubert get_sym_dummy(struct plugin_file_handle *h, const char *csymname,
197*7f2fe78bSCy Schubert               void **sym_out, struct errinfo *ep)
198*7f2fe78bSCy Schubert {
199*7f2fe78bSCy Schubert     return ENOENT;
200*7f2fe78bSCy Schubert }
201*7f2fe78bSCy Schubert #define get_sym get_sym_dummy
202*7f2fe78bSCy Schubert 
203*7f2fe78bSCy Schubert static void
close_plugin_dummy(struct plugin_file_handle * h)204*7f2fe78bSCy Schubert close_plugin_dummy(struct plugin_file_handle *h)
205*7f2fe78bSCy Schubert {
206*7f2fe78bSCy Schubert }
207*7f2fe78bSCy Schubert #define close_plugin close_plugin_dummy
208*7f2fe78bSCy Schubert 
209*7f2fe78bSCy Schubert #endif
210*7f2fe78bSCy Schubert 
211*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_open_plugin(const char * filename,struct plugin_file_handle ** handle_out,struct errinfo * ep)212*7f2fe78bSCy Schubert krb5int_open_plugin(const char *filename,
213*7f2fe78bSCy Schubert                     struct plugin_file_handle **handle_out, struct errinfo *ep)
214*7f2fe78bSCy Schubert {
215*7f2fe78bSCy Schubert     long ret;
216*7f2fe78bSCy Schubert     struct plugin_file_handle *h;
217*7f2fe78bSCy Schubert 
218*7f2fe78bSCy Schubert     *handle_out = NULL;
219*7f2fe78bSCy Schubert 
220*7f2fe78bSCy Schubert     h = calloc(1, sizeof(*h));
221*7f2fe78bSCy Schubert     if (h == NULL)
222*7f2fe78bSCy Schubert         return ENOMEM;
223*7f2fe78bSCy Schubert 
224*7f2fe78bSCy Schubert     ret = open_plugin(h, filename, ep);
225*7f2fe78bSCy Schubert     if (ret) {
226*7f2fe78bSCy Schubert         free(h);
227*7f2fe78bSCy Schubert         return ret;
228*7f2fe78bSCy Schubert     }
229*7f2fe78bSCy Schubert 
230*7f2fe78bSCy Schubert     *handle_out = h;
231*7f2fe78bSCy Schubert     return 0;
232*7f2fe78bSCy Schubert }
233*7f2fe78bSCy Schubert 
234*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_get_plugin_data(struct plugin_file_handle * h,const char * csymname,void ** sym_out,struct errinfo * ep)235*7f2fe78bSCy Schubert krb5int_get_plugin_data(struct plugin_file_handle *h, const char *csymname,
236*7f2fe78bSCy Schubert                         void **sym_out, struct errinfo *ep)
237*7f2fe78bSCy Schubert {
238*7f2fe78bSCy Schubert     return get_sym(h, csymname, sym_out, ep);
239*7f2fe78bSCy Schubert }
240*7f2fe78bSCy Schubert 
241*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_get_plugin_func(struct plugin_file_handle * h,const char * csymname,void (** sym_out)(),struct errinfo * ep)242*7f2fe78bSCy Schubert krb5int_get_plugin_func(struct plugin_file_handle *h, const char *csymname,
243*7f2fe78bSCy Schubert                         void (**sym_out)(), struct errinfo *ep)
244*7f2fe78bSCy Schubert {
245*7f2fe78bSCy Schubert     void *dptr = NULL;
246*7f2fe78bSCy Schubert     long ret = get_sym(h, csymname, &dptr, ep);
247*7f2fe78bSCy Schubert 
248*7f2fe78bSCy Schubert     if (!ret)
249*7f2fe78bSCy Schubert         *sym_out = (void (*)())dptr;
250*7f2fe78bSCy Schubert     return ret;
251*7f2fe78bSCy Schubert }
252*7f2fe78bSCy Schubert 
253*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_close_plugin(struct plugin_file_handle * h)254*7f2fe78bSCy Schubert krb5int_close_plugin (struct plugin_file_handle *h)
255*7f2fe78bSCy Schubert {
256*7f2fe78bSCy Schubert     close_plugin(h);
257*7f2fe78bSCy Schubert     free(h);
258*7f2fe78bSCy Schubert }
259*7f2fe78bSCy Schubert 
260*7f2fe78bSCy Schubert static long
krb5int_plugin_file_handle_array_init(struct plugin_file_handle *** harray)261*7f2fe78bSCy Schubert krb5int_plugin_file_handle_array_init (struct plugin_file_handle ***harray)
262*7f2fe78bSCy Schubert {
263*7f2fe78bSCy Schubert     long err = 0;
264*7f2fe78bSCy Schubert 
265*7f2fe78bSCy Schubert     *harray = calloc (1, sizeof (**harray)); /* calloc initializes to NULL */
266*7f2fe78bSCy Schubert     if (*harray == NULL) { err = ENOMEM; }
267*7f2fe78bSCy Schubert 
268*7f2fe78bSCy Schubert     return err;
269*7f2fe78bSCy Schubert }
270*7f2fe78bSCy Schubert 
271*7f2fe78bSCy Schubert static long
krb5int_plugin_file_handle_array_add(struct plugin_file_handle *** harray,size_t * count,struct plugin_file_handle * p)272*7f2fe78bSCy Schubert krb5int_plugin_file_handle_array_add (struct plugin_file_handle ***harray, size_t *count,
273*7f2fe78bSCy Schubert                                       struct plugin_file_handle *p)
274*7f2fe78bSCy Schubert {
275*7f2fe78bSCy Schubert     long err = 0;
276*7f2fe78bSCy Schubert     struct plugin_file_handle **newharray = NULL;
277*7f2fe78bSCy Schubert     size_t newcount = *count + 1;
278*7f2fe78bSCy Schubert 
279*7f2fe78bSCy Schubert     newharray = realloc (*harray, ((newcount + 1) * sizeof (**harray))); /* +1 for NULL */
280*7f2fe78bSCy Schubert     if (newharray == NULL) {
281*7f2fe78bSCy Schubert         err = ENOMEM;
282*7f2fe78bSCy Schubert     } else {
283*7f2fe78bSCy Schubert         newharray[newcount - 1] = p;
284*7f2fe78bSCy Schubert         newharray[newcount] = NULL;
285*7f2fe78bSCy Schubert         *count = newcount;
286*7f2fe78bSCy Schubert         *harray = newharray;
287*7f2fe78bSCy Schubert     }
288*7f2fe78bSCy Schubert 
289*7f2fe78bSCy Schubert     return err;
290*7f2fe78bSCy Schubert }
291*7f2fe78bSCy Schubert 
292*7f2fe78bSCy Schubert static void
krb5int_plugin_file_handle_array_free(struct plugin_file_handle ** harray)293*7f2fe78bSCy Schubert krb5int_plugin_file_handle_array_free (struct plugin_file_handle **harray)
294*7f2fe78bSCy Schubert {
295*7f2fe78bSCy Schubert     if (harray != NULL) {
296*7f2fe78bSCy Schubert         int i;
297*7f2fe78bSCy Schubert         for (i = 0; harray[i] != NULL; i++) {
298*7f2fe78bSCy Schubert             krb5int_close_plugin (harray[i]);
299*7f2fe78bSCy Schubert         }
300*7f2fe78bSCy Schubert         free (harray);
301*7f2fe78bSCy Schubert     }
302*7f2fe78bSCy Schubert }
303*7f2fe78bSCy Schubert 
304*7f2fe78bSCy Schubert #if TARGET_OS_MAC
305*7f2fe78bSCy Schubert #define FILEEXTS { "", ".bundle", ".dylib", ".so", NULL }
306*7f2fe78bSCy Schubert #elif defined(_WIN32)
307*7f2fe78bSCy Schubert #define FILEEXTS  { "", ".dll", NULL }
308*7f2fe78bSCy Schubert #else
309*7f2fe78bSCy Schubert #define FILEEXTS  { "", ".so", NULL }
310*7f2fe78bSCy Schubert #endif
311*7f2fe78bSCy Schubert 
312*7f2fe78bSCy Schubert 
313*7f2fe78bSCy Schubert static void
krb5int_free_plugin_filenames(char ** filenames)314*7f2fe78bSCy Schubert krb5int_free_plugin_filenames (char **filenames)
315*7f2fe78bSCy Schubert {
316*7f2fe78bSCy Schubert     if (filenames != NULL) {
317*7f2fe78bSCy Schubert         int i;
318*7f2fe78bSCy Schubert         for (i = 0; filenames[i] != NULL; i++) {
319*7f2fe78bSCy Schubert             free (filenames[i]);
320*7f2fe78bSCy Schubert         }
321*7f2fe78bSCy Schubert         free (filenames);
322*7f2fe78bSCy Schubert     }
323*7f2fe78bSCy Schubert }
324*7f2fe78bSCy Schubert 
325*7f2fe78bSCy Schubert 
326*7f2fe78bSCy Schubert static long
krb5int_get_plugin_filenames(const char * const * filebases,char *** filenames)327*7f2fe78bSCy Schubert krb5int_get_plugin_filenames (const char * const *filebases, char ***filenames)
328*7f2fe78bSCy Schubert {
329*7f2fe78bSCy Schubert     long err = 0;
330*7f2fe78bSCy Schubert     static const char *const fileexts[] = FILEEXTS;
331*7f2fe78bSCy Schubert     char **tempnames = NULL;
332*7f2fe78bSCy Schubert     size_t bases_count = 0;
333*7f2fe78bSCy Schubert     size_t exts_count = 0;
334*7f2fe78bSCy Schubert     size_t i;
335*7f2fe78bSCy Schubert 
336*7f2fe78bSCy Schubert     if (!filebases) { err = EINVAL; }
337*7f2fe78bSCy Schubert     if (!filenames) { err = EINVAL; }
338*7f2fe78bSCy Schubert 
339*7f2fe78bSCy Schubert     if (!err) {
340*7f2fe78bSCy Schubert         for (i = 0; filebases[i]; i++) { bases_count++; }
341*7f2fe78bSCy Schubert         for (i = 0; fileexts[i]; i++) { exts_count++; }
342*7f2fe78bSCy Schubert         tempnames = calloc ((bases_count * exts_count)+1, sizeof (char *));
343*7f2fe78bSCy Schubert         if (!tempnames) { err = ENOMEM; }
344*7f2fe78bSCy Schubert     }
345*7f2fe78bSCy Schubert 
346*7f2fe78bSCy Schubert     if (!err) {
347*7f2fe78bSCy Schubert         size_t j;
348*7f2fe78bSCy Schubert         for (i = 0; !err && filebases[i]; i++) {
349*7f2fe78bSCy Schubert             for (j = 0; !err && fileexts[j]; j++) {
350*7f2fe78bSCy Schubert                 if (asprintf(&tempnames[(i*exts_count)+j], "%s%s",
351*7f2fe78bSCy Schubert                              filebases[i], fileexts[j]) < 0) {
352*7f2fe78bSCy Schubert                     tempnames[(i*exts_count)+j] = NULL;
353*7f2fe78bSCy Schubert                     err = ENOMEM;
354*7f2fe78bSCy Schubert                 }
355*7f2fe78bSCy Schubert             }
356*7f2fe78bSCy Schubert         }
357*7f2fe78bSCy Schubert         tempnames[bases_count * exts_count] = NULL; /* NUL-terminate */
358*7f2fe78bSCy Schubert     }
359*7f2fe78bSCy Schubert 
360*7f2fe78bSCy Schubert     if (!err) {
361*7f2fe78bSCy Schubert         *filenames = tempnames;
362*7f2fe78bSCy Schubert         tempnames = NULL;
363*7f2fe78bSCy Schubert     }
364*7f2fe78bSCy Schubert 
365*7f2fe78bSCy Schubert     krb5int_free_plugin_filenames(tempnames);
366*7f2fe78bSCy Schubert 
367*7f2fe78bSCy Schubert     return err;
368*7f2fe78bSCy Schubert }
369*7f2fe78bSCy Schubert 
370*7f2fe78bSCy Schubert 
371*7f2fe78bSCy Schubert /* Takes a NULL-terminated list of directories.  If filebases is NULL, filebases is ignored
372*7f2fe78bSCy Schubert  * all plugins in the directories are loaded.  If filebases is a NULL-terminated array of names,
373*7f2fe78bSCy Schubert  * only plugins in the directories with those name (plus any platform extension) are loaded. */
374*7f2fe78bSCy Schubert 
375*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_open_plugin_dirs(const char * const * dirnames,const char * const * filebases,struct plugin_dir_handle * dirhandle,struct errinfo * ep)376*7f2fe78bSCy Schubert krb5int_open_plugin_dirs (const char * const *dirnames,
377*7f2fe78bSCy Schubert                           const char * const *filebases,
378*7f2fe78bSCy Schubert                           struct plugin_dir_handle *dirhandle,
379*7f2fe78bSCy Schubert                           struct errinfo *ep)
380*7f2fe78bSCy Schubert {
381*7f2fe78bSCy Schubert     long err = 0;
382*7f2fe78bSCy Schubert     struct plugin_file_handle **h = NULL;
383*7f2fe78bSCy Schubert     size_t count = 0;
384*7f2fe78bSCy Schubert     char **filenames = NULL;
385*7f2fe78bSCy Schubert     int i;
386*7f2fe78bSCy Schubert 
387*7f2fe78bSCy Schubert     if (!err) {
388*7f2fe78bSCy Schubert         err = krb5int_plugin_file_handle_array_init (&h);
389*7f2fe78bSCy Schubert     }
390*7f2fe78bSCy Schubert 
391*7f2fe78bSCy Schubert     if (!err && (filebases != NULL)) {
392*7f2fe78bSCy Schubert         err = krb5int_get_plugin_filenames (filebases, &filenames);
393*7f2fe78bSCy Schubert     }
394*7f2fe78bSCy Schubert 
395*7f2fe78bSCy Schubert     for (i = 0; !err && dirnames[i] != NULL; i++) {
396*7f2fe78bSCy Schubert         if (filenames != NULL) {
397*7f2fe78bSCy Schubert             /* load plugins with names from filenames from each directory */
398*7f2fe78bSCy Schubert             int j;
399*7f2fe78bSCy Schubert 
400*7f2fe78bSCy Schubert             for (j = 0; !err && filenames[j] != NULL; j++) {
401*7f2fe78bSCy Schubert                 struct plugin_file_handle *handle = NULL;
402*7f2fe78bSCy Schubert                 char *filepath = NULL;
403*7f2fe78bSCy Schubert 
404*7f2fe78bSCy Schubert                 if (!err) {
405*7f2fe78bSCy Schubert                     if (asprintf(&filepath, "%s/%s", dirnames[i], filenames[j]) < 0) {
406*7f2fe78bSCy Schubert                         filepath = NULL;
407*7f2fe78bSCy Schubert                         err = ENOMEM;
408*7f2fe78bSCy Schubert                     }
409*7f2fe78bSCy Schubert                 }
410*7f2fe78bSCy Schubert 
411*7f2fe78bSCy Schubert                 if (!err && krb5int_open_plugin(filepath, &handle, ep) == 0) {
412*7f2fe78bSCy Schubert                     err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
413*7f2fe78bSCy Schubert                     if (!err)
414*7f2fe78bSCy Schubert                         handle = NULL; /* h takes ownership */
415*7f2fe78bSCy Schubert                 }
416*7f2fe78bSCy Schubert 
417*7f2fe78bSCy Schubert                 free(filepath);
418*7f2fe78bSCy Schubert                 if (handle   != NULL) { krb5int_close_plugin (handle); }
419*7f2fe78bSCy Schubert             }
420*7f2fe78bSCy Schubert         } else {
421*7f2fe78bSCy Schubert             char **fnames = NULL;
422*7f2fe78bSCy Schubert             int j;
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert             err = k5_dir_filenames(dirnames[i], &fnames);
425*7f2fe78bSCy Schubert             for (j = 0; !err && fnames[j] != NULL; j++) {
426*7f2fe78bSCy Schubert                 char *filepath = NULL;
427*7f2fe78bSCy Schubert                 struct plugin_file_handle *handle = NULL;
428*7f2fe78bSCy Schubert 
429*7f2fe78bSCy Schubert                 if (strcmp(fnames[j], ".") == 0 ||
430*7f2fe78bSCy Schubert                     strcmp(fnames[j], "..") == 0)
431*7f2fe78bSCy Schubert                     continue;
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert                 if (asprintf(&filepath, "%s/%s", dirnames[i], fnames[j]) < 0) {
434*7f2fe78bSCy Schubert                     filepath = NULL;
435*7f2fe78bSCy Schubert                     err = ENOMEM;
436*7f2fe78bSCy Schubert                 }
437*7f2fe78bSCy Schubert 
438*7f2fe78bSCy Schubert                 if (!err && krb5int_open_plugin(filepath, &handle, ep) == 0) {
439*7f2fe78bSCy Schubert                     err = krb5int_plugin_file_handle_array_add(&h, &count,
440*7f2fe78bSCy Schubert                                                                handle);
441*7f2fe78bSCy Schubert                     if (!err)
442*7f2fe78bSCy Schubert                         handle = NULL;  /* h takes ownership */
443*7f2fe78bSCy Schubert                 }
444*7f2fe78bSCy Schubert 
445*7f2fe78bSCy Schubert                 free(filepath);
446*7f2fe78bSCy Schubert                 if (handle != NULL)
447*7f2fe78bSCy Schubert                     krb5int_close_plugin(handle);
448*7f2fe78bSCy Schubert             }
449*7f2fe78bSCy Schubert 
450*7f2fe78bSCy Schubert             k5_free_filenames(fnames);
451*7f2fe78bSCy Schubert         }
452*7f2fe78bSCy Schubert     }
453*7f2fe78bSCy Schubert 
454*7f2fe78bSCy Schubert     if (err == ENOENT) {
455*7f2fe78bSCy Schubert         err = 0;  /* ran out of plugins -- do nothing */
456*7f2fe78bSCy Schubert     }
457*7f2fe78bSCy Schubert 
458*7f2fe78bSCy Schubert     if (!err) {
459*7f2fe78bSCy Schubert         dirhandle->files = h;
460*7f2fe78bSCy Schubert         h = NULL;  /* dirhandle->files takes ownership */
461*7f2fe78bSCy Schubert     }
462*7f2fe78bSCy Schubert 
463*7f2fe78bSCy Schubert     if (filenames != NULL) { krb5int_free_plugin_filenames (filenames); }
464*7f2fe78bSCy Schubert     if (h         != NULL) { krb5int_plugin_file_handle_array_free (h); }
465*7f2fe78bSCy Schubert 
466*7f2fe78bSCy Schubert     return err;
467*7f2fe78bSCy Schubert }
468*7f2fe78bSCy Schubert 
469*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_close_plugin_dirs(struct plugin_dir_handle * dirhandle)470*7f2fe78bSCy Schubert krb5int_close_plugin_dirs (struct plugin_dir_handle *dirhandle)
471*7f2fe78bSCy Schubert {
472*7f2fe78bSCy Schubert     if (dirhandle->files != NULL) {
473*7f2fe78bSCy Schubert         int i;
474*7f2fe78bSCy Schubert         for (i = 0; dirhandle->files[i] != NULL; i++) {
475*7f2fe78bSCy Schubert             krb5int_close_plugin (dirhandle->files[i]);
476*7f2fe78bSCy Schubert         }
477*7f2fe78bSCy Schubert         free (dirhandle->files);
478*7f2fe78bSCy Schubert         dirhandle->files = NULL;
479*7f2fe78bSCy Schubert     }
480*7f2fe78bSCy Schubert }
481*7f2fe78bSCy Schubert 
482*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_free_plugin_dir_data(void ** ptrs)483*7f2fe78bSCy Schubert krb5int_free_plugin_dir_data (void **ptrs)
484*7f2fe78bSCy Schubert {
485*7f2fe78bSCy Schubert     /* Nothing special to be done per pointer.  */
486*7f2fe78bSCy Schubert     free(ptrs);
487*7f2fe78bSCy Schubert }
488*7f2fe78bSCy Schubert 
489*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_get_plugin_dir_data(struct plugin_dir_handle * dirhandle,const char * symname,void *** ptrs,struct errinfo * ep)490*7f2fe78bSCy Schubert krb5int_get_plugin_dir_data (struct plugin_dir_handle *dirhandle,
491*7f2fe78bSCy Schubert                              const char *symname,
492*7f2fe78bSCy Schubert                              void ***ptrs,
493*7f2fe78bSCy Schubert                              struct errinfo *ep)
494*7f2fe78bSCy Schubert {
495*7f2fe78bSCy Schubert     long err = 0;
496*7f2fe78bSCy Schubert     void **p = NULL;
497*7f2fe78bSCy Schubert     size_t count = 0;
498*7f2fe78bSCy Schubert 
499*7f2fe78bSCy Schubert     /* XXX Do we need to add a leading "_" to the symbol name on any
500*7f2fe78bSCy Schubert        modern platforms?  */
501*7f2fe78bSCy Schubert 
502*7f2fe78bSCy Schubert     Tprintf("get_plugin_data_sym(%s)\n", symname);
503*7f2fe78bSCy Schubert 
504*7f2fe78bSCy Schubert     if (!err) {
505*7f2fe78bSCy Schubert         p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
506*7f2fe78bSCy Schubert         if (p == NULL) { err = ENOMEM; }
507*7f2fe78bSCy Schubert     }
508*7f2fe78bSCy Schubert 
509*7f2fe78bSCy Schubert     if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
510*7f2fe78bSCy Schubert         int i = 0;
511*7f2fe78bSCy Schubert 
512*7f2fe78bSCy Schubert         for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
513*7f2fe78bSCy Schubert             void *sym = NULL;
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert             if (krb5int_get_plugin_data (dirhandle->files[i], symname, &sym, ep) == 0) {
516*7f2fe78bSCy Schubert                 void **newp = NULL;
517*7f2fe78bSCy Schubert 
518*7f2fe78bSCy Schubert                 count++;
519*7f2fe78bSCy Schubert                 newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
520*7f2fe78bSCy Schubert                 if (newp == NULL) {
521*7f2fe78bSCy Schubert                     err = ENOMEM;
522*7f2fe78bSCy Schubert                 } else {
523*7f2fe78bSCy Schubert                     p = newp;
524*7f2fe78bSCy Schubert                     p[count - 1] = sym;
525*7f2fe78bSCy Schubert                     p[count] = NULL;
526*7f2fe78bSCy Schubert                 }
527*7f2fe78bSCy Schubert             }
528*7f2fe78bSCy Schubert         }
529*7f2fe78bSCy Schubert     }
530*7f2fe78bSCy Schubert 
531*7f2fe78bSCy Schubert     if (!err) {
532*7f2fe78bSCy Schubert         *ptrs = p;
533*7f2fe78bSCy Schubert         p = NULL; /* ptrs takes ownership */
534*7f2fe78bSCy Schubert     }
535*7f2fe78bSCy Schubert 
536*7f2fe78bSCy Schubert     free(p);
537*7f2fe78bSCy Schubert 
538*7f2fe78bSCy Schubert     return err;
539*7f2fe78bSCy Schubert }
540*7f2fe78bSCy Schubert 
541*7f2fe78bSCy Schubert void KRB5_CALLCONV
krb5int_free_plugin_dir_func(void (** ptrs)(void))542*7f2fe78bSCy Schubert krb5int_free_plugin_dir_func (void (**ptrs)(void))
543*7f2fe78bSCy Schubert {
544*7f2fe78bSCy Schubert     /* Nothing special to be done per pointer.  */
545*7f2fe78bSCy Schubert     free(ptrs);
546*7f2fe78bSCy Schubert }
547*7f2fe78bSCy Schubert 
548*7f2fe78bSCy Schubert long KRB5_CALLCONV
krb5int_get_plugin_dir_func(struct plugin_dir_handle * dirhandle,const char * symname,void (*** ptrs)(void),struct errinfo * ep)549*7f2fe78bSCy Schubert krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle,
550*7f2fe78bSCy Schubert                              const char *symname,
551*7f2fe78bSCy Schubert                              void (***ptrs)(void),
552*7f2fe78bSCy Schubert                              struct errinfo *ep)
553*7f2fe78bSCy Schubert {
554*7f2fe78bSCy Schubert     long err = 0;
555*7f2fe78bSCy Schubert     void (**p)() = NULL;
556*7f2fe78bSCy Schubert     size_t count = 0;
557*7f2fe78bSCy Schubert 
558*7f2fe78bSCy Schubert     /* XXX Do we need to add a leading "_" to the symbol name on any
559*7f2fe78bSCy Schubert        modern platforms?  */
560*7f2fe78bSCy Schubert 
561*7f2fe78bSCy Schubert     Tprintf("get_plugin_data_sym(%s)\n", symname);
562*7f2fe78bSCy Schubert 
563*7f2fe78bSCy Schubert     if (!err) {
564*7f2fe78bSCy Schubert         p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
565*7f2fe78bSCy Schubert         if (p == NULL) { err = ENOMEM; }
566*7f2fe78bSCy Schubert     }
567*7f2fe78bSCy Schubert 
568*7f2fe78bSCy Schubert     if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
569*7f2fe78bSCy Schubert         int i = 0;
570*7f2fe78bSCy Schubert 
571*7f2fe78bSCy Schubert         for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
572*7f2fe78bSCy Schubert             void (*sym)() = NULL;
573*7f2fe78bSCy Schubert 
574*7f2fe78bSCy Schubert             if (krb5int_get_plugin_func (dirhandle->files[i], symname, &sym, ep) == 0) {
575*7f2fe78bSCy Schubert                 void (**newp)() = NULL;
576*7f2fe78bSCy Schubert 
577*7f2fe78bSCy Schubert                 count++;
578*7f2fe78bSCy Schubert                 newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
579*7f2fe78bSCy Schubert                 if (newp == NULL) {
580*7f2fe78bSCy Schubert                     err = ENOMEM;
581*7f2fe78bSCy Schubert                 } else {
582*7f2fe78bSCy Schubert                     p = newp;
583*7f2fe78bSCy Schubert                     p[count - 1] = sym;
584*7f2fe78bSCy Schubert                     p[count] = NULL;
585*7f2fe78bSCy Schubert                 }
586*7f2fe78bSCy Schubert             }
587*7f2fe78bSCy Schubert         }
588*7f2fe78bSCy Schubert     }
589*7f2fe78bSCy Schubert 
590*7f2fe78bSCy Schubert     if (!err) {
591*7f2fe78bSCy Schubert         *ptrs = p;
592*7f2fe78bSCy Schubert         p = NULL; /* ptrs takes ownership */
593*7f2fe78bSCy Schubert     }
594*7f2fe78bSCy Schubert 
595*7f2fe78bSCy Schubert     free(p);
596*7f2fe78bSCy Schubert 
597*7f2fe78bSCy Schubert     return err;
598*7f2fe78bSCy Schubert }
599