~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/util/support/plugins.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman, Russ Allbery, Sam Hartman
  • Date: 2008-08-21 10:41:41 UTC
  • mfrom: (11.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080821104141-a0f9c4o4cpo8xd0o
Tags: 1.6.dfsg.4~beta1-4
[ Russ Allbery ]
* Translation updates:
  - Swedish, thanks Martin Bagge.  (Closes: #487669, #491774)
  - Italian, thanks Luca Monducci.  (Closes: #493962)

[ Sam Hartman ]
* Translation Updates:
    - Dutch, Thanks Vincent Zweije, Closes: #495733

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * util/support/plugins.c
 
3
 *
 
4
 * Copyright 2006 by the Massachusetts Institute of Technology.
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Export of this software from the United States of America may
 
8
 *   require a specific license from the United States Government.
 
9
 *   It is the responsibility of any person or organization contemplating
 
10
 *   export to obtain such a license before exporting.
 
11
 * 
 
12
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 
13
 * distribute this software and its documentation for any purpose and
 
14
 * without fee is hereby granted, provided that the above copyright
 
15
 * notice appear in all copies and that both that copyright notice and
 
16
 * this permission notice appear in supporting documentation, and that
 
17
 * the name of M.I.T. not be used in advertising or publicity pertaining
 
18
 * to distribution of the software without specific, written prior
 
19
 * permission.  Furthermore if you modify this software you must label
 
20
 * your software as modified software and not distribute it in such a
 
21
 * fashion that it might be confused with the original M.I.T. software.
 
22
 * M.I.T. makes no representations about the suitability of
 
23
 * this software for any purpose.  It is provided "as is" without express
 
24
 * or implied warranty.
 
25
 * 
 
26
 *
 
27
 * Plugin module support, and shims around dlopen/whatever.
 
28
 */
 
29
 
 
30
#include "k5-plugin.h"
 
31
#if USE_DLOPEN
 
32
#include <dlfcn.h>
 
33
#endif
 
34
#if USE_CFBUNDLE
 
35
#include <CoreFoundation/CoreFoundation.h>
 
36
#endif
 
37
#include <stdio.h>
 
38
#include <sys/types.h>
 
39
#ifdef HAVE_SYS_STAT_H
 
40
#include <sys/stat.h>
 
41
#endif
 
42
#ifdef HAVE_SYS_PARAM_H
 
43
#include <sys/param.h>
 
44
#endif
 
45
#include <errno.h>
 
46
#include <stdlib.h>
 
47
#include <string.h>
 
48
#ifdef HAVE_UNISTD_H
 
49
#include <unistd.h>
 
50
#endif
 
51
 
 
52
#include <stdarg.h>
 
53
static void Tprintf (const char *fmt, ...)
 
54
{
 
55
#ifdef DEBUG
 
56
    va_list va;
 
57
    va_start (va, fmt);
 
58
    vfprintf (stderr, fmt, va);
 
59
    va_end (va);
 
60
#endif
 
61
}
 
62
 
 
63
struct plugin_file_handle {
 
64
#if USE_DLOPEN
 
65
    void *dlhandle;
 
66
#endif
 
67
#if USE_CFBUNDLE
 
68
    CFBundleRef bundle;
 
69
#endif
 
70
#if !defined (USE_DLOPEN) && !defined (USE_CFBUNDLE)
 
71
    char dummy;
 
72
#endif
 
73
};
 
74
 
 
75
long KRB5_CALLCONV
 
76
krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct errinfo *ep)
 
77
{
 
78
    long err = 0;
 
79
    struct stat statbuf;
 
80
    struct plugin_file_handle *htmp = NULL;
 
81
    int got_plugin = 0;
 
82
 
 
83
    if (!err) {
 
84
        if (stat (filepath, &statbuf) < 0) {
 
85
            Tprintf ("stat(%s): %s\n", filepath, strerror (errno));
 
86
            err = errno;
 
87
        }
 
88
    }
 
89
 
 
90
    if (!err) {
 
91
        htmp = calloc (1, sizeof (*htmp)); /* calloc initializes ptrs to NULL */
 
92
        if (htmp == NULL) { err = errno; }
 
93
    }
 
94
 
 
95
#if USE_DLOPEN
 
96
    if (!err && (statbuf.st_mode & S_IFMT) == S_IFREG) {
 
97
        void *handle = NULL;
 
98
#ifdef RTLD_GROUP
 
99
#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL | RTLD_GROUP)
 
100
#else
 
101
#define PLUGIN_DLOPEN_FLAGS (RTLD_NOW | RTLD_LOCAL)
 
102
#endif
 
103
 
 
104
        if (!err) {
 
105
            handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS);
 
106
            if (handle == NULL) {
 
107
                const char *e = dlerror();
 
108
                Tprintf ("dlopen(%s): %s\n", filepath, e);
 
109
                err = ENOENT; /* XXX */
 
110
                krb5int_set_error (ep, err, "%s", e);
 
111
            }
 
112
        }
 
113
 
 
114
        if (!err) {
 
115
            got_plugin = 1;
 
116
            htmp->dlhandle = handle;
 
117
            handle = NULL;
 
118
        }
 
119
 
 
120
        if (handle != NULL) { dlclose (handle); }
 
121
    }
 
122
#endif
 
123
 
 
124
#if USE_CFBUNDLE
 
125
    if (!err && (statbuf.st_mode & S_IFMT) == S_IFDIR) {
 
126
        CFStringRef pluginPath = NULL;
 
127
        CFURLRef pluginURL = NULL;
 
128
        CFBundleRef pluginBundle = NULL;
 
129
 
 
130
        if (!err) {
 
131
            pluginPath = CFStringCreateWithCString (kCFAllocatorDefault, filepath, 
 
132
                                                    kCFStringEncodingASCII);
 
133
            if (pluginPath == NULL) { err = ENOMEM; }
 
134
        }
 
135
        
 
136
        if (!err) {
 
137
            pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, pluginPath, 
 
138
                                                       kCFURLPOSIXPathStyle, true);
 
139
            if (pluginURL == NULL) { err = ENOMEM; }
 
140
        }
 
141
        
 
142
        if (!err) {
 
143
            pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
 
144
            if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
 
145
        }
 
146
        
 
147
        if (!err) {
 
148
            if (!CFBundleIsExecutableLoaded (pluginBundle)) {
 
149
                int loaded = CFBundleLoadExecutable (pluginBundle);
 
150
                if (!loaded) { err = ENOENT; }  /* XXX need better error */
 
151
            }
 
152
        }
 
153
        
 
154
        if (!err) {
 
155
            got_plugin = 1;
 
156
            htmp->bundle = pluginBundle;
 
157
            pluginBundle = NULL;  /* htmp->bundle takes ownership */
 
158
        }
 
159
 
 
160
        if (pluginBundle != NULL) { CFRelease (pluginBundle); }
 
161
        if (pluginURL    != NULL) { CFRelease (pluginURL); }
 
162
        if (pluginPath   != NULL) { CFRelease (pluginPath); }
 
163
    }
 
164
#endif
 
165
        
 
166
    if (!err && !got_plugin) {
 
167
        err = ENOENT;  /* no plugin or no way to load plugins */
 
168
    }
 
169
    
 
170
    if (!err) {
 
171
        *h = htmp;
 
172
        htmp = NULL;  /* h takes ownership */
 
173
    }
 
174
    
 
175
    if (htmp != NULL) { free (htmp); }
 
176
    
 
177
    return err;
 
178
}
 
179
 
 
180
static long
 
181
krb5int_get_plugin_sym (struct plugin_file_handle *h, 
 
182
                        const char *csymname, int isfunc, void **ptr,
 
183
                        struct errinfo *ep)
 
184
{
 
185
    long err = 0;
 
186
    void *sym = NULL;
 
187
    
 
188
#if USE_DLOPEN
 
189
    if (!err && !sym && (h->dlhandle != NULL)) {
 
190
        /* XXX Do we need to add a leading "_" to the symbol name on any
 
191
        modern platforms?  */
 
192
        sym = dlsym (h->dlhandle, csymname);
 
193
        if (sym == NULL) {
 
194
            const char *e = dlerror (); /* XXX copy and save away */
 
195
            Tprintf ("dlsym(%s): %s\n", csymname, e);
 
196
            err = ENOENT; /* XXX */
 
197
            krb5int_set_error(ep, err, "%s", e);
 
198
        }
 
199
    }
 
200
#endif
 
201
    
 
202
#if USE_CFBUNDLE
 
203
    if (!err && !sym && (h->bundle != NULL)) {
 
204
        CFStringRef cfsymname = NULL;
 
205
        
 
206
        if (!err) {
 
207
            cfsymname = CFStringCreateWithCString (kCFAllocatorDefault, csymname, 
 
208
                                                   kCFStringEncodingASCII);
 
209
            if (cfsymname == NULL) { err = ENOMEM; }
 
210
        }
 
211
        
 
212
        if (!err) {
 
213
            if (isfunc) {
 
214
                sym = CFBundleGetFunctionPointerForName (h->bundle, cfsymname);
 
215
            } else {
 
216
                sym = CFBundleGetDataPointerForName (h->bundle, cfsymname);
 
217
            }
 
218
            if (sym == NULL) { err = ENOENT; }  /* XXX */       
 
219
        }
 
220
        
 
221
        if (cfsymname != NULL) { CFRelease (cfsymname); }
 
222
    }
 
223
#endif
 
224
    
 
225
    if (!err && (sym == NULL)) {
 
226
        err = ENOENT;  /* unimplemented */
 
227
    }
 
228
    
 
229
    if (!err) {
 
230
        *ptr = sym;
 
231
    }
 
232
    
 
233
    return err;
 
234
}
 
235
 
 
236
long KRB5_CALLCONV
 
237
krb5int_get_plugin_data (struct plugin_file_handle *h, const char *csymname,
 
238
                         void **ptr, struct errinfo *ep)
 
239
{
 
240
    return krb5int_get_plugin_sym (h, csymname, 0, ptr, ep);
 
241
}
 
242
 
 
243
long KRB5_CALLCONV
 
244
krb5int_get_plugin_func (struct plugin_file_handle *h, const char *csymname,
 
245
                         void (**ptr)(), struct errinfo *ep)
 
246
{
 
247
    void *dptr = NULL;    
 
248
    long err = krb5int_get_plugin_sym (h, csymname, 1, &dptr, ep);
 
249
    if (!err) {
 
250
        /* Cast function pointers to avoid code duplication */
 
251
        *ptr = (void (*)()) dptr;
 
252
    }
 
253
    return err;
 
254
}
 
255
 
 
256
void KRB5_CALLCONV
 
257
krb5int_close_plugin (struct plugin_file_handle *h)
 
258
{
 
259
#if USE_DLOPEN
 
260
    if (h->dlhandle != NULL) { dlclose(h->dlhandle); }
 
261
#endif
 
262
#if USE_CFBUNDLE
 
263
    /* Do not call CFBundleUnloadExecutable because it's not ref counted. 
 
264
     * CFRelease will unload the bundle if the internal refcount goes to zero. */
 
265
    if (h->bundle != NULL) { CFRelease (h->bundle); }
 
266
#endif
 
267
    free (h);
 
268
}
 
269
 
 
270
/* autoconf docs suggest using this preference order */
 
271
#if HAVE_DIRENT_H || USE_DIRENT_H
 
272
#include <dirent.h>
 
273
#define NAMELEN(D) strlen((D)->d_name)
 
274
#else
 
275
#define dirent direct
 
276
#define NAMELEN(D) ((D)->d->namlen)
 
277
#if HAVE_SYS_NDIR_H
 
278
# include <sys/ndir.h>
 
279
#elif HAVE_SYS_DIR_H
 
280
# include <sys/dir.h>
 
281
#elif HAVE_NDIR_H
 
282
# include <ndir.h>
 
283
#endif
 
284
#endif
 
285
 
 
286
 
 
287
#ifdef HAVE_STRERROR_R
 
288
#define ERRSTR(ERR, BUF) \
 
289
    (strerror_r (ERR, BUF, sizeof(BUF)) == 0 ? BUF : strerror (ERR))
 
290
#else
 
291
#define ERRSTR(ERR, BUF) \
 
292
    (strerror (ERR))
 
293
#endif
 
294
 
 
295
static long
 
296
krb5int_plugin_file_handle_array_init (struct plugin_file_handle ***harray)
 
297
{
 
298
    long err = 0;
 
299
 
 
300
    *harray = calloc (1, sizeof (**harray)); /* calloc initializes to NULL */
 
301
    if (*harray == NULL) { err = errno; }
 
302
 
 
303
    return err;
 
304
}
 
305
 
 
306
static long
 
307
krb5int_plugin_file_handle_array_add (struct plugin_file_handle ***harray, int *count, 
 
308
                                      struct plugin_file_handle *p)
 
309
{
 
310
    long err = 0;
 
311
    struct plugin_file_handle **newharray = NULL;
 
312
    int newcount = *count + 1;
 
313
    
 
314
    newharray = realloc (*harray, ((newcount + 1) * sizeof (**harray))); /* +1 for NULL */
 
315
    if (newharray == NULL) { 
 
316
        err = errno; 
 
317
    } else {
 
318
        newharray[newcount - 1] = p;
 
319
        newharray[newcount] = NULL;
 
320
        *count = newcount;
 
321
        *harray = newharray;
 
322
    }
 
323
 
 
324
    return err;    
 
325
}
 
326
 
 
327
static void
 
328
krb5int_plugin_file_handle_array_free (struct plugin_file_handle **harray)
 
329
{
 
330
    if (harray != NULL) {
 
331
        int i;
 
332
        for (i = 0; harray[i] != NULL; i++) {
 
333
            krb5int_close_plugin (harray[i]);
 
334
        }
 
335
        free (harray);
 
336
    }
 
337
}
 
338
 
 
339
#if TARGET_OS_MAC
 
340
#define FILEEXTS { "", ".bundle", ".so", NULL }
 
341
#elif defined(_WIN32)
 
342
#define FILEEXTS  { "", ".dll", NULL }
 
343
#else
 
344
#define FILEEXTS  { "", ".so", NULL }
 
345
#endif
 
346
 
 
347
 
 
348
static void 
 
349
krb5int_free_plugin_filenames (char **filenames)
 
350
{
 
351
    if (filenames != NULL) { 
 
352
        int i;
 
353
        for (i = 0; filenames[i] != NULL; i++) {
 
354
            free (filenames[i]);
 
355
        }
 
356
        free (filenames); 
 
357
    }    
 
358
}
 
359
 
 
360
 
 
361
static long 
 
362
krb5int_get_plugin_filenames (const char * const *filebases, char ***filenames)
 
363
{
 
364
    long err = 0;
 
365
    static const char *const fileexts[] = FILEEXTS;
 
366
    char **tempnames = NULL;
 
367
    int i;
 
368
 
 
369
    if (!err) {
 
370
        size_t count = 0;
 
371
        for (i = 0; filebases[i] != NULL; i++, count++);
 
372
        for (i = 0; fileexts[i] != NULL; i++, count++);
 
373
        tempnames = calloc (count, sizeof (char *));
 
374
        if (tempnames == NULL) { err = errno; }
 
375
    }
 
376
 
 
377
    if (!err) {
 
378
        int j;
 
379
        for (i = 0; !err && (filebases[i] != NULL); i++) {
 
380
            size_t baselen = strlen (filebases[i]);
 
381
            for (j = 0; !err && (fileexts[j] != NULL); j++) {
 
382
                size_t len = baselen + strlen (fileexts[j]) + 2; /* '.' + NULL */
 
383
                tempnames[i+j] = malloc (len * sizeof (char));
 
384
                if (tempnames[i+j] == NULL) { 
 
385
                    err = errno; 
 
386
                } else {
 
387
                    sprintf (tempnames[i+j], "%s%s", filebases[i], fileexts[j]);
 
388
                }
 
389
            }
 
390
        }
 
391
    }
 
392
    
 
393
    if (!err) {
 
394
        *filenames = tempnames;
 
395
        tempnames = NULL;
 
396
    }
 
397
    
 
398
    if (tempnames != NULL) { krb5int_free_plugin_filenames (tempnames); }
 
399
    
 
400
    return err;
 
401
}
 
402
 
 
403
 
 
404
/* Takes a NULL-terminated list of directories.  If filebases is NULL, filebases is ignored
 
405
 * all plugins in the directories are loaded.  If filebases is a NULL-terminated array of names, 
 
406
 * only plugins in the directories with those name (plus any platform extension) are loaded. */
 
407
 
 
408
long KRB5_CALLCONV
 
409
krb5int_open_plugin_dirs (const char * const *dirnames,
 
410
                          const char * const *filebases,
 
411
                          struct plugin_dir_handle *dirhandle,
 
412
                          struct errinfo *ep)
 
413
{
 
414
    long err = 0;
 
415
    struct plugin_file_handle **h = NULL;
 
416
    int count = 0;
 
417
    char **filenames = NULL;
 
418
    int i;
 
419
 
 
420
    if (!err) {
 
421
        err = krb5int_plugin_file_handle_array_init (&h);
 
422
    }
 
423
    
 
424
    if (!err && (filebases != NULL)) {
 
425
        err = krb5int_get_plugin_filenames (filebases, &filenames);
 
426
    }
 
427
    
 
428
    for (i = 0; !err && dirnames[i] != NULL; i++) {
 
429
        size_t dirnamelen = strlen (dirnames[i]) + 1; /* '/' */
 
430
        if (filenames != NULL) {
 
431
            /* load plugins with names from filenames from each directory */
 
432
            int j;
 
433
            
 
434
            for (j = 0; !err && filenames[j] != NULL; j++) {
 
435
                struct plugin_file_handle *handle = NULL;
 
436
                char *filepath = NULL;
 
437
                
 
438
                if (!err) {
 
439
                    filepath = malloc (dirnamelen + strlen (filenames[j]) + 1); /* NULL */
 
440
                    if (filepath == NULL) { 
 
441
                        err = errno; 
 
442
                    } else {
 
443
                        sprintf (filepath, "%s/%s", dirnames[i], filenames[j]);
 
444
                    }
 
445
                }
 
446
                
 
447
                if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
 
448
                    err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
 
449
                    if (!err) { handle = NULL; }  /* h takes ownership */
 
450
                }
 
451
                
 
452
                if (filepath != NULL) { free (filepath); }
 
453
                if (handle   != NULL) { krb5int_close_plugin (handle); }
 
454
            }
 
455
        } else {
 
456
            /* load all plugins in each directory */
 
457
#ifndef _WIN32
 
458
            DIR *dir = opendir (dirnames[i]);
 
459
            
 
460
            while (dir != NULL && !err) {
 
461
                struct dirent *d = NULL;
 
462
                char *filepath = NULL;
 
463
                struct plugin_file_handle *handle = NULL;
 
464
                
 
465
                d = readdir (dir);
 
466
                if (d == NULL) { break; }
 
467
                
 
468
                if ((strcmp (d->d_name, ".") == 0) || 
 
469
                    (strcmp (d->d_name, "..") == 0)) {
 
470
                    continue;
 
471
                }
 
472
                
 
473
                if (!err) {
 
474
                    int len = NAMELEN (d);
 
475
                    filepath = malloc (dirnamelen + len + 1); /* NULL */
 
476
                    if (filepath == NULL) { 
 
477
                        err = errno; 
 
478
                    } else {
 
479
                        sprintf (filepath, "%s/%*s", dirnames[i], len, d->d_name);
 
480
                    }
 
481
                }
 
482
                
 
483
                if (!err) {            
 
484
                    if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
 
485
                        err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
 
486
                        if (!err) { handle = NULL; }  /* h takes ownership */
 
487
                    }
 
488
                }
 
489
                
 
490
                if (filepath  != NULL) { free (filepath); }
 
491
                if (handle    != NULL) { krb5int_close_plugin (handle); }
 
492
            }
 
493
            
 
494
            if (dir != NULL) { closedir (dir); }
 
495
#else
 
496
            /* Until a Windows implementation of this code is implemented */
 
497
            err = ENOENT;
 
498
#endif /* _WIN32 */
 
499
        }
 
500
    }
 
501
        
 
502
    if (err == ENOENT) {
 
503
        err = 0;  /* ran out of plugins -- do nothing */
 
504
    }
 
505
     
 
506
    if (!err) {
 
507
        dirhandle->files = h;
 
508
        h = NULL;  /* dirhandle->files takes ownership */
 
509
    }
 
510
    
 
511
    if (filenames != NULL) { krb5int_free_plugin_filenames (filenames); }
 
512
    if (h         != NULL) { krb5int_plugin_file_handle_array_free (h); }
 
513
    
 
514
    return err;
 
515
}
 
516
 
 
517
void KRB5_CALLCONV
 
518
krb5int_close_plugin_dirs (struct plugin_dir_handle *dirhandle)
 
519
{
 
520
    if (dirhandle->files != NULL) {
 
521
        int i;
 
522
        for (i = 0; dirhandle->files[i] != NULL; i++) {
 
523
            krb5int_close_plugin (dirhandle->files[i]);
 
524
        }
 
525
        free (dirhandle->files);
 
526
        dirhandle->files = NULL;
 
527
    }
 
528
}
 
529
 
 
530
void KRB5_CALLCONV
 
531
krb5int_free_plugin_dir_data (void **ptrs)
 
532
{
 
533
    /* Nothing special to be done per pointer.  */
 
534
    free(ptrs);
 
535
}
 
536
 
 
537
long KRB5_CALLCONV
 
538
krb5int_get_plugin_dir_data (struct plugin_dir_handle *dirhandle,
 
539
                             const char *symname,
 
540
                             void ***ptrs,
 
541
                             struct errinfo *ep)
 
542
{
 
543
    long err = 0;
 
544
    void **p = NULL;
 
545
    int count = 0;
 
546
 
 
547
    /* XXX Do we need to add a leading "_" to the symbol name on any
 
548
       modern platforms?  */
 
549
    
 
550
    Tprintf("get_plugin_data_sym(%s)\n", symname);
 
551
 
 
552
    if (!err) {
 
553
        p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
 
554
        if (p == NULL) { err = errno; }
 
555
    }
 
556
    
 
557
    if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
 
558
        int i = 0;
 
559
 
 
560
        for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
 
561
            void *sym = NULL;
 
562
 
 
563
            if (krb5int_get_plugin_data (dirhandle->files[i], symname, &sym, ep) == 0) {
 
564
                void **newp = NULL;
 
565
 
 
566
                count++;
 
567
                newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
 
568
                if (newp == NULL) { 
 
569
                    err = errno; 
 
570
                } else {
 
571
                    p = newp;
 
572
                    p[count - 1] = sym;
 
573
                    p[count] = NULL;
 
574
                }
 
575
            }
 
576
        }
 
577
    }
 
578
    
 
579
    if (!err) {
 
580
        *ptrs = p;
 
581
        p = NULL; /* ptrs takes ownership */
 
582
    }
 
583
    
 
584
    if (p != NULL) { free (p); }
 
585
    
 
586
    return err;
 
587
}
 
588
 
 
589
void KRB5_CALLCONV
 
590
krb5int_free_plugin_dir_func (void (**ptrs)(void))
 
591
{
 
592
    /* Nothing special to be done per pointer.  */
 
593
    free(ptrs);
 
594
}
 
595
 
 
596
long KRB5_CALLCONV
 
597
krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle,
 
598
                             const char *symname,
 
599
                             void (***ptrs)(void),
 
600
                             struct errinfo *ep)
 
601
{
 
602
    long err = 0;
 
603
    void (**p)() = NULL;
 
604
    int count = 0;
 
605
    
 
606
    /* XXX Do we need to add a leading "_" to the symbol name on any
 
607
        modern platforms?  */
 
608
    
 
609
    Tprintf("get_plugin_data_sym(%s)\n", symname);
 
610
    
 
611
    if (!err) {
 
612
        p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */
 
613
        if (p == NULL) { err = errno; }
 
614
    }
 
615
    
 
616
    if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) {
 
617
        int i = 0;
 
618
        
 
619
        for (i = 0; !err && (dirhandle->files[i] != NULL); i++) {
 
620
            void (*sym)() = NULL;
 
621
            
 
622
            if (krb5int_get_plugin_func (dirhandle->files[i], symname, &sym, ep) == 0) {
 
623
                void (**newp)() = NULL;
 
624
 
 
625
                count++;
 
626
                newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */
 
627
                if (newp == NULL) { 
 
628
                    err = errno; 
 
629
                } else {
 
630
                    p = newp;
 
631
                    p[count - 1] = sym;
 
632
                    p[count] = NULL;
 
633
                }
 
634
            }
 
635
        }
 
636
    }
 
637
    
 
638
    if (!err) {
 
639
        *ptrs = p;
 
640
        p = NULL; /* ptrs takes ownership */
 
641
    }
 
642
    
 
643
    if (p != NULL) { free (p); }
 
644
    
 
645
    return err;
 
646
}