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