Blob Blame History Raw
From 593109802b52e3f89c3a65436bfdba78f8c517c4 Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 23 Jun 2022 16:41:40 -0400
Subject: [PATCH] Simplify plugin loading code

Remove the USE_CFBUNDLE code, which was only used by KfM.  Handle
platform conditionals according to current practice.  Use
k5_dir_filenames() instead of opendir() and remove the Windows
implementation of opendir().
---
 src/util/support/plugins.c | 507 +++++++++++--------------------------
 1 file changed, 150 insertions(+), 357 deletions(-)

diff --git a/src/util/support/plugins.c b/src/util/support/plugins.c
index c6a9a21d57..0850565687 100644
--- a/src/util/support/plugins.c
+++ b/src/util/support/plugins.c
@@ -29,16 +29,6 @@
 #if USE_DLOPEN
 #include <dlfcn.h>
 #endif
-#include <sys/types.h>
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 
 #if USE_DLOPEN
 #ifdef RTLD_GROUP
@@ -68,16 +58,6 @@
 #endif
 #endif
 
-#if USE_DLOPEN && USE_CFBUNDLE
-#include <CoreFoundation/CoreFoundation.h>
-
-/* Currently CoreFoundation only exists on the Mac so we just use
- * pthreads directly to avoid creating empty function calls on other
- * platforms.  If a thread initializer ever gets created in the common
- * plugin code, move this there */
-static pthread_mutex_t krb5int_bundle_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
 #include <stdarg.h>
 static void Tprintf (const char *fmt, ...)
 {
@@ -90,374 +70,193 @@ static void Tprintf (const char *fmt, ...)
 }
 
 struct plugin_file_handle {
-#if USE_DLOPEN
+#if defined(USE_DLOPEN)
     void *dlhandle;
-#endif
-#ifdef _WIN32
-    HMODULE hinstPlugin;
-#endif
-#if !defined (USE_DLOPEN) && !defined (_WIN32)
+#elif defined(_WIN32)
+    HMODULE module;
+#else
     char dummy;
 #endif
 };
 
-#ifdef _WIN32
-struct dirent {
-    long d_ino;                 /* inode (always 1 in WIN32) */
-    off_t d_off;                /* offset to this dirent */
-    unsigned short d_reclen;    /* length of d_name */
-    char d_name[_MAX_FNAME+1];  /* filename (null terminated) */
-};
-
-typedef struct {
-    intptr_t handle;            /* _findfirst/_findnext handle */
-    short offset;               /* offset into directory */
-    short finished;             /* 1 if there are not more files */
-    struct _finddata_t fileinfo;/* from _findfirst/_findnext */
-    char *dir;                  /* the dir we are reading */
-    struct dirent dent;         /* the dirent to return */
-} DIR;
+#if defined(USE_DLOPEN)
 
-DIR * opendir(const char *dir)
+static long
+open_plugin_dlfcn(struct plugin_file_handle *h, const char *filename,
+                  struct errinfo *ep)
 {
-    DIR *dp;
-    char *filespec;
-    intptr_t handle;
-    int index;
-
-    filespec = malloc(strlen(dir) + 2 + 1);
-    strcpy(filespec, dir);
-    index = strlen(filespec) - 1;
-    if (index >= 0 && (filespec[index] == '/' || filespec[index] == '\\'))
-        filespec[index] = '\0';
-    strcat(filespec, "/*");
-
-    dp = (DIR *)malloc(sizeof(DIR));
-    dp->offset = 0;
-    dp->finished = 0;
-    dp->dir = strdup(dir);
-
-    if ((handle = _findfirst(filespec, &(dp->fileinfo))) < 0) {
-        if (errno == ENOENT)
-            dp->finished = 1;
-        else {
-            free(filespec);
-            free(dp->dir);
-            free(dp);
-            return NULL;
-        }
+    const char *e;
+
+    h->dlhandle = dlopen(filename, PLUGIN_DLOPEN_FLAGS);
+    if (h->dlhandle == NULL) {
+        e = dlerror();
+        if (e == NULL)
+            e = _("unknown failure");
+        Tprintf("dlopen(%s): %s\n", filename, e);
+        k5_set_error(ep, ENOENT, _("unable to load plugin [%s]: %s"),
+                     filename, e);
+        return ENOENT;
     }
-
-    dp->handle = handle;
-    free(filespec);
-
-    return dp;
+    return 0;
 }
+#define open_plugin open_plugin_dlfcn
 
-struct dirent * readdir(DIR *dp)
+static long
+get_sym_dlfcn(struct plugin_file_handle *h, const char *csymname,
+              void **sym_out, struct errinfo *ep)
 {
-    if (!dp || dp->finished) return NULL;
-
-    if (dp->offset != 0) {
-        if (_findnext(dp->handle, &(dp->fileinfo)) < 0) {
-            dp->finished = 1;
-            return NULL;
-        }
+    const char *e;
+
+    if (h->dlhandle == NULL)
+        return ENOENT;
+    *sym_out = dlsym(h->dlhandle, csymname);
+    if (*sym_out == NULL) {
+        e = dlerror();
+        if (e == NULL)
+            e = _("unknown failure");
+        Tprintf("dlsym(%s): %s\n", csymname, e);
+        k5_set_error(ep, ENOENT, "%s", e);
+        return ENOENT;
     }
-    dp->offset++;
-
-    strncpy(dp->dent.d_name, dp->fileinfo.name, _MAX_FNAME);
-    dp->dent.d_ino = 1;
-    dp->dent.d_reclen = (unsigned short)strlen(dp->dent.d_name);
-    dp->dent.d_off = dp->offset;
-
-    return &(dp->dent);
-}
-
-int closedir(DIR *dp)
-{
-    if (!dp) return 0;
-    _findclose(dp->handle);
-    free(dp->dir);
-    free(dp);
-
     return 0;
 }
-#endif
+#define get_sym get_sym_dlfcn
 
-long KRB5_CALLCONV
-krb5int_open_plugin (const char *filepath, struct plugin_file_handle **h, struct errinfo *ep)
+static void
+close_plugin_dlfcn(struct plugin_file_handle *h)
 {
-    long err = 0;
-    struct plugin_file_handle *htmp = NULL;
-    int got_plugin = 0;
-#if defined(USE_CFBUNDLE) || defined(_WIN32)
-    struct stat statbuf;
-
-    if (!err) {
-        if (stat (filepath, &statbuf) < 0) {
-            err = errno;
-            Tprintf ("stat(%s): %s\n", filepath, strerror (err));
-            k5_set_error(ep, err, _("unable to find plugin [%s]: %s"),
-                         filepath, strerror(err));
-        }
-    }
-#endif
-
-    if (!err) {
-        htmp = calloc (1, sizeof (*htmp)); /* calloc initializes ptrs to NULL */
-        if (htmp == NULL) { err = ENOMEM; }
-    }
-
-#if USE_DLOPEN
-    if (!err
-#if USE_CFBUNDLE
-                 && ((statbuf.st_mode & S_IFMT) == S_IFREG
-                 || (statbuf.st_mode & S_IFMT) == S_IFDIR)
-#endif /* USE_CFBUNDLE */
-        ) {
-        void *handle = NULL;
-
-#if USE_CFBUNDLE
-        char executablepath[MAXPATHLEN];
-
-        if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
-            int lock_err = 0;
-            CFStringRef pluginString = NULL;
-            CFURLRef pluginURL = NULL;
-            CFBundleRef pluginBundle = NULL;
-            CFURLRef executableURL = NULL;
-
-            /* Lock around CoreFoundation calls since objects are refcounted
-             * and the refcounts are not thread-safe.  Using pthreads directly
-             * because this code is Mac-specific */
-            lock_err = pthread_mutex_lock(&krb5int_bundle_mutex);
-            if (lock_err) { err = lock_err; }
-
-            if (!err) {
-                pluginString = CFStringCreateWithCString (kCFAllocatorDefault,
-                                                          filepath,
-                                                          kCFStringEncodingASCII);
-                if (pluginString == NULL) { err = ENOMEM; }
-            }
-
-            if (!err) {
-                pluginURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault,
-                                                           pluginString,
-                                                           kCFURLPOSIXPathStyle,
-                                                           true);
-                if (pluginURL == NULL) { err = ENOMEM; }
-            }
-
-            if (!err) {
-                pluginBundle = CFBundleCreate (kCFAllocatorDefault, pluginURL);
-                if (pluginBundle == NULL) { err = ENOENT; } /* XXX need better error */
-            }
-
-            if (!err) {
-                executableURL = CFBundleCopyExecutableURL (pluginBundle);
-                if (executableURL == NULL) { err = ENOMEM; }
-            }
-
-            if (!err) {
-                if (!CFURLGetFileSystemRepresentation (executableURL,
-                                                       true, /* absolute */
-                                                       (UInt8 *)executablepath,
-                                                       sizeof (executablepath))) {
-                    err = ENOMEM;
-                }
-            }
-
-            if (!err) {
-                /* override the path the caller passed in */
-                filepath = executablepath;
-            }
-
-            if (executableURL    != NULL) { CFRelease (executableURL); }
-            if (pluginBundle     != NULL) { CFRelease (pluginBundle); }
-            if (pluginURL        != NULL) { CFRelease (pluginURL); }
-            if (pluginString     != NULL) { CFRelease (pluginString); }
-
-            /* unlock after CFRelease calls since they modify refcounts */
-            if (!lock_err) { pthread_mutex_unlock (&krb5int_bundle_mutex); }
-        }
-#endif /* USE_CFBUNDLE */
-
-        if (!err) {
-            handle = dlopen(filepath, PLUGIN_DLOPEN_FLAGS);
-            if (handle == NULL) {
-                const char *e = dlerror();
-                if (e == NULL)
-                    e = _("unknown failure");
-                Tprintf ("dlopen(%s): %s\n", filepath, e);
-                err = ENOENT; /* XXX */
-                k5_set_error(ep, err, _("unable to load plugin [%s]: %s"),
-                             filepath, e);
-            }
-        }
+    if (h->dlhandle != NULL)
+        dlclose(h->dlhandle);
+}
+#define close_plugin close_plugin_dlfcn
 
-        if (!err) {
-            got_plugin = 1;
-            htmp->dlhandle = handle;
-            handle = NULL;
-        }
+#elif defined(_WIN32)
 
-        if (handle != NULL) { dlclose (handle); }
+static long
+open_plugin_win32(struct plugin_file_handle *h, const char *filename,
+                  struct errinfo *ep)
+{
+    h->module = LoadLibrary(filename);
+    if (h == NULL) {
+        Tprintf("Unable to load dll: %s\n", filename);
+        k5_set_error(ep, ENOENT, _("unable to load DLL [%s]"), filename);
+        return ENOENT;
     }
-#endif /* USE_DLOPEN */
-
-#ifdef _WIN32
-    if (!err && (statbuf.st_mode & S_IFMT) == S_IFREG) {
-        HMODULE handle = NULL;
+    return 0;
+}
+#define open_plugin open_plugin_win32
 
-        handle = LoadLibrary(filepath);
-        if (handle == NULL) {
-            Tprintf ("Unable to load dll: %s\n", filepath);
-            err = ENOENT; /* XXX */
-            k5_set_error(ep, err, _("unable to load DLL [%s]"), filepath);
-        }
+static long
+get_sym_win32(struct plugin_file_handle *h, const char *csymname,
+              void **sym_out, struct errinfo *ep)
+{
+    LPVOID lpMsgBuf;
+    DWORD dw;
 
-        if (!err) {
-            got_plugin = 1;
-            htmp->hinstPlugin = handle;
-            handle = NULL;
+    if (h->module == NULL)
+        return ENOENT;
+    *sym_out = GetProcAddress(h->module, csymname);
+    if (*sym_out == NULL) {
+        Tprintf("GetProcAddress(%s): %i\n", csymname, GetLastError());
+        dw = GetLastError();
+        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                          FORMAT_MESSAGE_FROM_SYSTEM,
+                          NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                          (LPTSTR)&lpMsgBuf, 0, NULL)) {
+            k5_set_error(ep, ENOENT, _("unable to get DLL Symbol: %s"),
+                         (char *)lpMsgBuf);
+            LocalFree(lpMsgBuf);
         }
-
-        if (handle != NULL)
-            FreeLibrary(handle);
-    }
-#endif
-
-    if (!err && !got_plugin) {
-        err = ENOENT;  /* no plugin or no way to load plugins */
-        k5_set_error(ep, err, _("plugin unavailable: %s"), strerror(err));
+        return ENOENT;
     }
+    return 0;
+}
+#define get_sym get_sym_win32
 
-    if (!err) {
-        *h = htmp;
-        htmp = NULL;  /* h takes ownership */
-    }
+static void
+close_plugin_win32(struct plugin_file_handle *h)
+{
+    if (h->module != NULL)
+        FreeLibrary(h->module);
+}
+#define close_plugin close_plugin_win32
 
-    free(htmp);
+#else
 
-    return err;
+static long
+open_plugin_dummy(struct plugin_file_handle *h, const char *filename,
+                  struct errinfo *ep)
+{
+    k5_set_error(ep, ENOENT, _("plugin loading unavailable"));
+    return ENOENT;
 }
+#define open_plugin open_plugin_dummy
 
 static long
-krb5int_get_plugin_sym (struct plugin_file_handle *h,
-                        const char *csymname, int isfunc, void **ptr,
-                        struct errinfo *ep)
+get_sym_dummy(struct plugin_file_handle *h, const char *csymname,
+              void **sym_out, struct errinfo *ep)
 {
-    long err = 0;
-    void *sym = NULL;
+    return ENOENT;
+}
+#define get_sym get_sym_dummy
+
+static void
+close_plugin_dummy(struct plugin_file_handle *h)
+{
+}
+#define close_plugin close_plugin_dummy
 
-#if USE_DLOPEN
-    if (!err && !sym && (h->dlhandle != NULL)) {
-        /* XXX Do we need to add a leading "_" to the symbol name on any
-           modern platforms?  */
-        sym = dlsym (h->dlhandle, csymname);
-        if (sym == NULL) {
-            const char *e = dlerror (); /* XXX copy and save away */
-            if (e == NULL)
-                e = "unknown failure";
-            Tprintf ("dlsym(%s): %s\n", csymname, e);
-            err = ENOENT; /* XXX */
-            k5_set_error(ep, err, "%s", e);
-        }
-    }
 #endif
 
-#ifdef _WIN32
-    LPVOID lpMsgBuf;
-    DWORD dw;
+long KRB5_CALLCONV
+krb5int_open_plugin(const char *filename,
+                    struct plugin_file_handle **handle_out, struct errinfo *ep)
+{
+    long ret;
+    struct plugin_file_handle *h;
 
-    if (!err && !sym && (h->hinstPlugin != NULL)) {
-        sym = GetProcAddress(h->hinstPlugin, csymname);
-        if (sym == NULL) {
-            const char *e = "unable to get dll symbol"; /* XXX copy and save away */
-            Tprintf ("GetProcAddress(%s): %i\n", csymname, GetLastError());
-            err = ENOENT; /* XXX */
-            k5_set_error(ep, err, "%s", e);
-
-            dw = GetLastError();
-            if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                              FORMAT_MESSAGE_FROM_SYSTEM,
-                              NULL,
-                              dw,
-                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                              (LPTSTR) &lpMsgBuf,
-                              0, NULL )) {
-
-                fprintf (stderr, "unable to get dll symbol, %s\n", (LPCTSTR)lpMsgBuf);
-                LocalFree(lpMsgBuf);
-            }
-        }
-    }
-#endif
+    *handle_out = NULL;
 
-    if (!err && (sym == NULL)) {
-        err = ENOENT;  /* unimplemented */
-    }
+    h = calloc(1, sizeof(*h));
+    if (h == NULL)
+        return ENOMEM;
 
-    if (!err) {
-        *ptr = sym;
+    ret = open_plugin(h, filename, ep);
+    if (ret) {
+        free(h);
+        return ret;
     }
 
-    return err;
+    *handle_out = h;
+    return 0;
 }
 
 long KRB5_CALLCONV
-krb5int_get_plugin_data (struct plugin_file_handle *h, const char *csymname,
-                         void **ptr, struct errinfo *ep)
+krb5int_get_plugin_data(struct plugin_file_handle *h, const char *csymname,
+                        void **sym_out, struct errinfo *ep)
 {
-    return krb5int_get_plugin_sym (h, csymname, 0, ptr, ep);
+    return get_sym(h, csymname, sym_out, ep);
 }
 
 long KRB5_CALLCONV
-krb5int_get_plugin_func (struct plugin_file_handle *h, const char *csymname,
-                         void (**ptr)(), struct errinfo *ep)
+krb5int_get_plugin_func(struct plugin_file_handle *h, const char *csymname,
+                        void (**sym_out)(), struct errinfo *ep)
 {
     void *dptr = NULL;
-    long err = krb5int_get_plugin_sym (h, csymname, 1, &dptr, ep);
-    if (!err) {
-        /* Cast function pointers to avoid code duplication */
-        *ptr = (void (*)()) dptr;
-    }
-    return err;
+    long ret = get_sym(h, csymname, &dptr, ep);
+
+    if (!ret)
+        *sym_out = (void (*)())dptr;
+    return ret;
 }
 
 void KRB5_CALLCONV
 krb5int_close_plugin (struct plugin_file_handle *h)
 {
-#if USE_DLOPEN
-    if (h->dlhandle != NULL) { dlclose(h->dlhandle); }
-#endif
-#ifdef _WIN32
-    if (h->hinstPlugin != NULL) { FreeLibrary(h->hinstPlugin); }
-#endif
-    free (h);
+    close_plugin(h);
+    free(h);
 }
 
-/* autoconf docs suggest using this preference order */
-#if HAVE_DIRENT_H || USE_DIRENT_H
-#include <dirent.h>
-#define NAMELEN(D) strlen((D)->d_name)
-#else
-#ifndef _WIN32
-#define dirent direct
-#define NAMELEN(D) ((D)->d->namlen)
-#else
-#define NAMELEN(D) strlen((D)->d_name)
-#endif
-#if HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-#elif HAVE_SYS_DIR_H
-# include <sys/dir.h>
-#elif HAVE_NDIR_H
-# include <ndir.h>
-#endif
-#endif
-
 static long
 krb5int_plugin_file_handle_array_init (struct plugin_file_handle ***harray)
 {
@@ -619,42 +418,36 @@ krb5int_open_plugin_dirs (const char * const *dirnames,
                 if (handle   != NULL) { krb5int_close_plugin (handle); }
             }
         } else {
-            /* load all plugins in each directory */
-            DIR *dir = opendir (dirnames[i]);
+            char **fnames = NULL;
+            int j;
 
-            while (dir != NULL && !err) {
-                struct dirent *d = NULL;
+            err = k5_dir_filenames(dirnames[i], &fnames);
+            for (j = 0; !err && fnames[j] != NULL; j++) {
                 char *filepath = NULL;
                 struct plugin_file_handle *handle = NULL;
 
-                d = readdir (dir);
-                if (d == NULL) { break; }
-
-                if ((strcmp (d->d_name, ".") == 0) ||
-                    (strcmp (d->d_name, "..") == 0)) {
+                if (strcmp(fnames[j], ".") == 0 ||
+                    strcmp(fnames[j], "..") == 0)
                     continue;
-                }
 
-                if (!err) {
-                    int len = NAMELEN (d);
-                    if (asprintf(&filepath, "%s/%*s", dirnames[i], len, d->d_name) < 0) {
-                        filepath = NULL;
-                        err = ENOMEM;
-                    }
+                if (asprintf(&filepath, "%s/%s", dirnames[i], fnames[j]) < 0) {
+                    filepath = NULL;
+                    err = ENOMEM;
                 }
 
-                if (!err) {
-                    if (krb5int_open_plugin (filepath, &handle, ep) == 0) {
-                        err = krb5int_plugin_file_handle_array_add (&h, &count, handle);
-                        if (!err) { handle = NULL; }  /* h takes ownership */
-                    }
+                if (!err && krb5int_open_plugin(filepath, &handle, ep) == 0) {
+                    err = krb5int_plugin_file_handle_array_add(&h, &count,
+                                                               handle);
+                    if (!err)
+                        handle = NULL;  /* h takes ownership */
                 }
 
                 free(filepath);
-                if (handle    != NULL) { krb5int_close_plugin (handle); }
+                if (handle != NULL)
+                    krb5int_close_plugin(handle);
             }
 
-            if (dir != NULL) { closedir (dir); }
+            k5_free_filenames(fnames);
         }
     }
 
-- 
2.38.1