1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/secload.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "secport.h" 1.9 +#include "nspr.h" 1.10 + 1.11 +#ifdef XP_UNIX 1.12 +#include <unistd.h> 1.13 +#define BL_MAXSYMLINKS 20 1.14 + 1.15 +/* 1.16 + * If 'link' is a symbolic link, this function follows the symbolic links 1.17 + * and returns the pathname of the ultimate source of the symbolic links. 1.18 + * If 'link' is not a symbolic link, this function returns NULL. 1.19 + * The caller should call PR_Free to free the string returned by this 1.20 + * function. 1.21 + */ 1.22 +static char* loader_GetOriginalPathname(const char* link) 1.23 +{ 1.24 + char* resolved = NULL; 1.25 + char* input = NULL; 1.26 + PRUint32 iterations = 0; 1.27 + PRInt32 len = 0, retlen = 0; 1.28 + if (!link) { 1.29 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.30 + return NULL; 1.31 + } 1.32 + len = PR_MAX(1024, strlen(link) + 1); 1.33 + resolved = PR_Malloc(len); 1.34 + input = PR_Malloc(len); 1.35 + if (!resolved || !input) { 1.36 + if (resolved) { 1.37 + PR_Free(resolved); 1.38 + } 1.39 + if (input) { 1.40 + PR_Free(input); 1.41 + } 1.42 + return NULL; 1.43 + } 1.44 + strcpy(input, link); 1.45 + while ( (iterations++ < BL_MAXSYMLINKS) && 1.46 + ( (retlen = readlink(input, resolved, len - 1)) > 0) ) { 1.47 + char* tmp = input; 1.48 + resolved[retlen] = '\0'; /* NULL termination */ 1.49 + input = resolved; 1.50 + resolved = tmp; 1.51 + } 1.52 + PR_Free(resolved); 1.53 + if (iterations == 1 && retlen < 0) { 1.54 + PR_Free(input); 1.55 + input = NULL; 1.56 + } 1.57 + return input; 1.58 +} 1.59 +#endif /* XP_UNIX */ 1.60 + 1.61 +/* 1.62 + * Load the library with the file name 'name' residing in the same 1.63 + * directory as the reference library, whose pathname is 'referencePath'. 1.64 + */ 1.65 +static PRLibrary * 1.66 +loader_LoadLibInReferenceDir(const char *referencePath, const char *name) 1.67 +{ 1.68 + PRLibrary *dlh = NULL; 1.69 + char *fullName = NULL; 1.70 + char* c; 1.71 + PRLibSpec libSpec; 1.72 + 1.73 + /* Remove the trailing filename from referencePath and add the new one */ 1.74 + c = strrchr(referencePath, PR_GetDirectorySeparator()); 1.75 + if (c) { 1.76 + size_t referencePathSize = 1 + c - referencePath; 1.77 + fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1); 1.78 + if (fullName) { 1.79 + memcpy(fullName, referencePath, referencePathSize); 1.80 + strcpy(fullName + referencePathSize, name); 1.81 +#ifdef DEBUG_LOADER 1.82 + PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", 1.83 + fullName); 1.84 +#endif 1.85 + libSpec.type = PR_LibSpec_Pathname; 1.86 + libSpec.value.pathname = fullName; 1.87 + dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL 1.88 +#ifdef PR_LD_ALT_SEARCH_PATH 1.89 + /* allow library's dependencies to be found in the same directory 1.90 + * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */ 1.91 + | PR_LD_ALT_SEARCH_PATH 1.92 +#endif 1.93 + ); 1.94 + PORT_Free(fullName); 1.95 + } 1.96 + } 1.97 + return dlh; 1.98 +} 1.99 + 1.100 +/* 1.101 + * Load a shared library called "newShLibName" in the same directory as 1.102 + * a shared library that is already loaded, called existingShLibName. 1.103 + * A pointer to a static function in that shared library, 1.104 + * staticShLibFunc, is required. 1.105 + * 1.106 + * existingShLibName: 1.107 + * The file name of the shared library that shall be used as the 1.108 + * "reference library". The loader will attempt to load the requested 1.109 + * library from the same directory as the reference library. 1.110 + * 1.111 + * staticShLibFunc: 1.112 + * Pointer to a static function in the "reference library". 1.113 + * 1.114 + * newShLibName: 1.115 + * The simple file name of the new shared library to be loaded. 1.116 + * 1.117 + * We use PR_GetLibraryFilePathname to get the pathname of the loaded 1.118 + * shared lib that contains this function, and then do a 1.119 + * PR_LoadLibraryWithFlags with an absolute pathname for the shared 1.120 + * library to be loaded. 1.121 + * 1.122 + * On Windows, the "alternate search path" strategy is employed, if available. 1.123 + * On Unix, if existingShLibName is a symbolic link, and no link exists for the 1.124 + * new library, the original link will be resolved, and the new library loaded 1.125 + * from the resolved location. 1.126 + * 1.127 + * If the new shared library is not found in the same location as the reference 1.128 + * library, it will then be loaded from the normal system library path. 1.129 + * 1.130 + */ 1.131 + 1.132 +PRLibrary * 1.133 +PORT_LoadLibraryFromOrigin(const char* existingShLibName, 1.134 + PRFuncPtr staticShLibFunc, 1.135 + const char *newShLibName) 1.136 +{ 1.137 + PRLibrary *lib = NULL; 1.138 + char* fullPath = NULL; 1.139 + PRLibSpec libSpec; 1.140 + 1.141 + /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so 1.142 + * PR_GetLibraryFilePathname works with either the base library name or a 1.143 + * function pointer, depending on the platform. 1.144 + * We require the address of a function in the "reference library", 1.145 + * provided by the caller. To avoid getting the address of the stub/thunk 1.146 + * of an exported function by accident, use the address of a static 1.147 + * function rather than an exported function. 1.148 + */ 1.149 + fullPath = PR_GetLibraryFilePathname(existingShLibName, 1.150 + staticShLibFunc); 1.151 + 1.152 + if (fullPath) { 1.153 + lib = loader_LoadLibInReferenceDir(fullPath, newShLibName); 1.154 +#ifdef XP_UNIX 1.155 + if (!lib) { 1.156 + /* 1.157 + * If fullPath is a symbolic link, resolve the symbolic 1.158 + * link and try again. 1.159 + */ 1.160 + char* originalfullPath = loader_GetOriginalPathname(fullPath); 1.161 + if (originalfullPath) { 1.162 + PR_Free(fullPath); 1.163 + fullPath = originalfullPath; 1.164 + lib = loader_LoadLibInReferenceDir(fullPath, newShLibName); 1.165 + } 1.166 + } 1.167 +#endif 1.168 + PR_Free(fullPath); 1.169 + } 1.170 + if (!lib) { 1.171 +#ifdef DEBUG_LOADER 1.172 + PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName); 1.173 +#endif 1.174 + libSpec.type = PR_LibSpec_Pathname; 1.175 + libSpec.value.pathname = newShLibName; 1.176 + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); 1.177 + } 1.178 + if (NULL == lib) { 1.179 +#ifdef DEBUG_LOADER 1.180 + PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName); 1.181 +#endif 1.182 + } 1.183 + return lib; 1.184 +} 1.185 +