diff options
Diffstat (limited to 'security/nss/lib/freebl/genload.c')
-rw-r--r-- | security/nss/lib/freebl/genload.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/genload.c b/security/nss/lib/freebl/genload.c new file mode 100644 index 000000000..832deb58c --- /dev/null +++ b/security/nss/lib/freebl/genload.c @@ -0,0 +1,167 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * This file is meant to be included by other .c files. + * This file takes a "parameter", the scope which includes this + * code shall declare this variable: + * const char *NameOfThisSharedLib; + * + * NameOfThisSharedLib: + * The file name of the shared library that shall be used as the + * "reference library". The loader will attempt to load the requested + * library from the same directory as the reference library. + */ + +#ifdef XP_UNIX +#include <unistd.h> +#define BL_MAXSYMLINKS 20 + +/* + * If 'link' is a symbolic link, this function follows the symbolic links + * and returns the pathname of the ultimate source of the symbolic links. + * If 'link' is not a symbolic link, this function returns NULL. + * The caller should call PR_Free to free the string returned by this + * function. + */ +static char* +loader_GetOriginalPathname(const char* link) +{ +#ifdef __GLIBC__ + char* tmp = realpath(link, NULL); + char* resolved; + if (!tmp) + return NULL; + resolved = PR_Malloc(strlen(tmp) + 1); + strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */ + free(tmp); + return resolved; +#else + char* resolved = NULL; + char* input = NULL; + PRUint32 iterations = 0; + PRInt32 len = 0, retlen = 0; + if (!link) { + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); + return NULL; + } + len = PR_MAX(1024, strlen(link) + 1); + resolved = PR_Malloc(len); + input = PR_Malloc(len); + if (!resolved || !input) { + if (resolved) { + PR_Free(resolved); + } + if (input) { + PR_Free(input); + } + return NULL; + } + strcpy(input, link); + while ((iterations++ < BL_MAXSYMLINKS) && + ((retlen = readlink(input, resolved, len - 1)) > 0)) { + char* tmp = input; + resolved[retlen] = '\0'; /* NULL termination */ + input = resolved; + resolved = tmp; + } + PR_Free(resolved); + if (iterations == 1 && retlen < 0) { + PR_Free(input); + input = NULL; + } + return input; +#endif +} +#endif /* XP_UNIX */ + +/* + * Load the library with the file name 'name' residing in the same + * directory as the reference library, whose pathname is 'referencePath'. + */ +static PRLibrary* +loader_LoadLibInReferenceDir(const char* referencePath, const char* name) +{ + PRLibrary* dlh = NULL; + char* fullName = NULL; + char* c; + PRLibSpec libSpec; + + /* Remove the trailing filename from referencePath and add the new one */ + c = strrchr(referencePath, PR_GetDirectorySeparator()); + if (c) { + size_t referencePathSize = 1 + c - referencePath; + fullName = (char*)PORT_Alloc(strlen(name) + referencePathSize + 1); + if (fullName) { + memcpy(fullName, referencePath, referencePathSize); + strcpy(fullName + referencePathSize, name); +#ifdef DEBUG_LOADER + PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", + fullName); +#endif + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = fullName; + dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + PORT_Free(fullName); + } + } + return dlh; +} + +/* + * We use PR_GetLibraryFilePathname to get the pathname of the loaded + * shared lib that contains this function, and then do a PR_LoadLibrary + * with an absolute pathname for the softoken shared library. + */ + +static PRLibrary* +loader_LoadLibrary(const char* nameToLoad) +{ + PRLibrary* lib = NULL; + char* fullPath = NULL; + PRLibSpec libSpec; + + /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so + * PR_GetLibraryFilePathname works with either the base library name or a + * function pointer, depending on the platform. We can't query an exported + * symbol such as NSC_GetFunctionList, because on some platforms we can't + * find symbols in loaded implicit dependencies. + * But we can just get the address of this function ! + */ + fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib, + (PRFuncPtr)&loader_LoadLibrary); + + if (fullPath) { + lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); +#ifdef XP_UNIX + if (!lib) { + /* + * If fullPath is a symbolic link, resolve the symbolic + * link and try again. + */ + char* originalfullPath = loader_GetOriginalPathname(fullPath); + if (originalfullPath) { + PR_Free(fullPath); + fullPath = originalfullPath; + lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); + } + } +#endif + PR_Free(fullPath); + } + if (!lib) { +#ifdef DEBUG_LOADER + PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad); +#endif + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = nameToLoad; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + } + if (NULL == lib) { +#ifdef DEBUG_LOADER + PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad); +#endif + } + return lib; +} |