1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/genload.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,167 @@ 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 +/* 1.9 + * This file is meant to be included by other .c files. 1.10 + * This file takes a "parameter", the scope which includes this 1.11 + * code shall declare this variable: 1.12 + * const char *NameOfThisSharedLib; 1.13 + * 1.14 + * NameOfThisSharedLib: 1.15 + * The file name of the shared library that shall be used as the 1.16 + * "reference library". The loader will attempt to load the requested 1.17 + * library from the same directory as the reference library. 1.18 + */ 1.19 + 1.20 +#ifdef XP_UNIX 1.21 +#include <unistd.h> 1.22 +#define BL_MAXSYMLINKS 20 1.23 + 1.24 +/* 1.25 + * If 'link' is a symbolic link, this function follows the symbolic links 1.26 + * and returns the pathname of the ultimate source of the symbolic links. 1.27 + * If 'link' is not a symbolic link, this function returns NULL. 1.28 + * The caller should call PR_Free to free the string returned by this 1.29 + * function. 1.30 + */ 1.31 +static char* loader_GetOriginalPathname(const char* link) 1.32 +{ 1.33 +#ifdef __GLIBC__ 1.34 + char* tmp = realpath(link, NULL); 1.35 + char* resolved; 1.36 + if (! tmp) 1.37 + return NULL; 1.38 + resolved = PR_Malloc(strlen(tmp) + 1); 1.39 + strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */ 1.40 + free(tmp); 1.41 + return resolved; 1.42 +#else 1.43 + char* resolved = NULL; 1.44 + char* input = NULL; 1.45 + PRUint32 iterations = 0; 1.46 + PRInt32 len = 0, retlen = 0; 1.47 + if (!link) { 1.48 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.49 + return NULL; 1.50 + } 1.51 + len = PR_MAX(1024, strlen(link) + 1); 1.52 + resolved = PR_Malloc(len); 1.53 + input = PR_Malloc(len); 1.54 + if (!resolved || !input) { 1.55 + if (resolved) { 1.56 + PR_Free(resolved); 1.57 + } 1.58 + if (input) { 1.59 + PR_Free(input); 1.60 + } 1.61 + return NULL; 1.62 + } 1.63 + strcpy(input, link); 1.64 + while ( (iterations++ < BL_MAXSYMLINKS) && 1.65 + ( (retlen = readlink(input, resolved, len - 1)) > 0) ) { 1.66 + char* tmp = input; 1.67 + resolved[retlen] = '\0'; /* NULL termination */ 1.68 + input = resolved; 1.69 + resolved = tmp; 1.70 + } 1.71 + PR_Free(resolved); 1.72 + if (iterations == 1 && retlen < 0) { 1.73 + PR_Free(input); 1.74 + input = NULL; 1.75 + } 1.76 + return input; 1.77 +#endif 1.78 +} 1.79 +#endif /* XP_UNIX */ 1.80 + 1.81 +/* 1.82 + * Load the library with the file name 'name' residing in the same 1.83 + * directory as the reference library, whose pathname is 'referencePath'. 1.84 + */ 1.85 +static PRLibrary * 1.86 +loader_LoadLibInReferenceDir(const char *referencePath, const char *name) 1.87 +{ 1.88 + PRLibrary *dlh = NULL; 1.89 + char *fullName = NULL; 1.90 + char* c; 1.91 + PRLibSpec libSpec; 1.92 + 1.93 + /* Remove the trailing filename from referencePath and add the new one */ 1.94 + c = strrchr(referencePath, PR_GetDirectorySeparator()); 1.95 + if (c) { 1.96 + size_t referencePathSize = 1 + c - referencePath; 1.97 + fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1); 1.98 + if (fullName) { 1.99 + memcpy(fullName, referencePath, referencePathSize); 1.100 + strcpy(fullName + referencePathSize, name); 1.101 +#ifdef DEBUG_LOADER 1.102 + PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", 1.103 + fullName); 1.104 +#endif 1.105 + libSpec.type = PR_LibSpec_Pathname; 1.106 + libSpec.value.pathname = fullName; 1.107 + dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); 1.108 + PORT_Free(fullName); 1.109 + } 1.110 + } 1.111 + return dlh; 1.112 +} 1.113 + 1.114 +/* 1.115 + * We use PR_GetLibraryFilePathname to get the pathname of the loaded 1.116 + * shared lib that contains this function, and then do a PR_LoadLibrary 1.117 + * with an absolute pathname for the softoken shared library. 1.118 + */ 1.119 + 1.120 +static PRLibrary * 1.121 +loader_LoadLibrary(const char *nameToLoad) 1.122 +{ 1.123 + PRLibrary *lib = NULL; 1.124 + char* fullPath = NULL; 1.125 + PRLibSpec libSpec; 1.126 + 1.127 + /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so 1.128 + * PR_GetLibraryFilePathname works with either the base library name or a 1.129 + * function pointer, depending on the platform. We can't query an exported 1.130 + * symbol such as NSC_GetFunctionList, because on some platforms we can't 1.131 + * find symbols in loaded implicit dependencies. 1.132 + * But we can just get the address of this function ! 1.133 + */ 1.134 + fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib, 1.135 + (PRFuncPtr)&loader_LoadLibrary); 1.136 + 1.137 + if (fullPath) { 1.138 + lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); 1.139 +#ifdef XP_UNIX 1.140 + if (!lib) { 1.141 + /* 1.142 + * If fullPath is a symbolic link, resolve the symbolic 1.143 + * link and try again. 1.144 + */ 1.145 + char* originalfullPath = loader_GetOriginalPathname(fullPath); 1.146 + if (originalfullPath) { 1.147 + PR_Free(fullPath); 1.148 + fullPath = originalfullPath; 1.149 + lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); 1.150 + } 1.151 + } 1.152 +#endif 1.153 + PR_Free(fullPath); 1.154 + } 1.155 + if (!lib) { 1.156 +#ifdef DEBUG_LOADER 1.157 + PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad); 1.158 +#endif 1.159 + libSpec.type = PR_LibSpec_Pathname; 1.160 + libSpec.value.pathname = nameToLoad; 1.161 + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); 1.162 + } 1.163 + if (NULL == lib) { 1.164 +#ifdef DEBUG_LOADER 1.165 + PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad); 1.166 +#endif 1.167 + } 1.168 + return lib; 1.169 +} 1.170 +