/* If map is for a dynamic module which hasn't been loaded yet, attempt to load * it. Only try to load a module once. */ static void load_if_needed(krb5_context context, struct plugin_mapping *map, const char *iname) { char *symname = NULL; struct plugin_file_handle *handle = NULL; void (*initvt_fn)(); if (map->module != NULL || map->dyn_path == NULL) return; if (asprintf(&symname, "%s_%s_initvt", iname, map->modname) < 0) return; if (krb5int_open_plugin(map->dyn_path, &handle, &context->err)) goto err; if (krb5int_get_plugin_func(handle, symname, &initvt_fn, &context->err)) goto err; free(symname); map->dyn_handle = handle; map->module = (krb5_plugin_initvt_fn)initvt_fn; return; err: /* Clean up, and also null out map->dyn_path so we don't try again. */ if (handle != NULL) krb5int_close_plugin(handle); free(symname); free(map->dyn_path); map->dyn_path = NULL; }
long KRB5_CALLCONV krb5int_get_plugin_dir_func (struct plugin_dir_handle *dirhandle, const char *symname, void (***ptrs)(void), struct errinfo *ep) { long err = 0; void (**p)() = NULL; int count = 0; /* XXX Do we need to add a leading "_" to the symbol name on any modern platforms? */ Tprintf("get_plugin_data_sym(%s)\n", symname); if (!err) { p = calloc (1, sizeof (*p)); /* calloc initializes to NULL */ if (p == NULL) { err = errno; } } if (!err && (dirhandle != NULL) && (dirhandle->files != NULL)) { int i = 0; for (i = 0; !err && (dirhandle->files[i] != NULL); i++) { void (*sym)() = NULL; if (krb5int_get_plugin_func (dirhandle->files[i], symname, &sym, ep) == 0) { void (**newp)() = NULL; count++; newp = realloc (p, ((count + 1) * sizeof (*p))); /* +1 for NULL */ if (newp == NULL) { err = errno; } else { p = newp; p[count - 1] = sym; p[count] = NULL; } } } } if (!err) { *ptrs = p; p = NULL; /* ptrs takes ownership */ } if (p != NULL) { free (p); } return err; }
/* Load a dynamic profile module as specified by modspec and create a vtable * profile for it in *ret_profile. */ static errcode_t init_load_module(const char *modspec, profile_t *ret_profile) { char *modpath = NULL, *residual = NULL; struct errinfo einfo = { 0 }; prf_lib_handle_t lib_handle = NULL; struct plugin_file_handle *plhandle = NULL; void *cbdata = NULL, (*fptr)(); int have_lock = 0, have_cbdata = 0; struct profile_vtable vtable = { 1 }; /* Set minor_ver to 1, rest null. */ errcode_t err; profile_module_init_fn initfn; err = parse_modspec(modspec, &modpath, &residual); if (err) goto cleanup; /* Allocate a reference-counted library handle container. */ lib_handle = malloc(sizeof(*lib_handle)); if (lib_handle == NULL) goto cleanup; err = k5_mutex_init(&lib_handle->lock); if (err) goto cleanup; have_lock = 1; /* Open the module and get its initializer. */ err = krb5int_open_plugin(modpath, &plhandle, &einfo); if (err) goto cleanup; err = krb5int_get_plugin_func(plhandle, "profile_module_init", &fptr, &einfo); if (err == ENOENT) err = PROF_MODULE_INVALID; if (err) goto cleanup; /* Get the profile vtable and callback data pointer. */ initfn = (profile_module_init_fn)fptr; err = (*initfn)(residual, &vtable, &cbdata); if (err) goto cleanup; have_cbdata = 1; /* Create a vtable profile with the information obtained. */ lib_handle->plugin_handle = plhandle; lib_handle->refcount = 1; err = init_module(&vtable, cbdata, lib_handle, ret_profile); cleanup: free(modpath); free(residual); k5_clear_error(&einfo); if (err) { if (have_cbdata && vtable.cleanup) vtable.cleanup(cbdata); if (have_lock) k5_mutex_destroy(&lib_handle->lock); free(lib_handle); if (plhandle) krb5int_close_plugin(plhandle); } return err; }