From 593109802b52e3f89c3a65436bfdba78f8c517c4 Mon Sep 17 00:00:00 2001 From: Greg Hudson 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 #endif -#include -#ifdef HAVE_SYS_STAT_H -#include -#endif -#ifdef HAVE_SYS_PARAM_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif #if USE_DLOPEN #ifdef RTLD_GROUP @@ -68,16 +58,6 @@ #endif #endif -#if USE_DLOPEN && USE_CFBUNDLE -#include - -/* 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 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 -#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 -#elif HAVE_SYS_DIR_H -# include -#elif HAVE_NDIR_H -# include -#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