security/nss/lib/util/secload.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "secport.h"
michael@0 6 #include "nspr.h"
michael@0 7
michael@0 8 #ifdef XP_UNIX
michael@0 9 #include <unistd.h>
michael@0 10 #define BL_MAXSYMLINKS 20
michael@0 11
michael@0 12 /*
michael@0 13 * If 'link' is a symbolic link, this function follows the symbolic links
michael@0 14 * and returns the pathname of the ultimate source of the symbolic links.
michael@0 15 * If 'link' is not a symbolic link, this function returns NULL.
michael@0 16 * The caller should call PR_Free to free the string returned by this
michael@0 17 * function.
michael@0 18 */
michael@0 19 static char* loader_GetOriginalPathname(const char* link)
michael@0 20 {
michael@0 21 char* resolved = NULL;
michael@0 22 char* input = NULL;
michael@0 23 PRUint32 iterations = 0;
michael@0 24 PRInt32 len = 0, retlen = 0;
michael@0 25 if (!link) {
michael@0 26 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 27 return NULL;
michael@0 28 }
michael@0 29 len = PR_MAX(1024, strlen(link) + 1);
michael@0 30 resolved = PR_Malloc(len);
michael@0 31 input = PR_Malloc(len);
michael@0 32 if (!resolved || !input) {
michael@0 33 if (resolved) {
michael@0 34 PR_Free(resolved);
michael@0 35 }
michael@0 36 if (input) {
michael@0 37 PR_Free(input);
michael@0 38 }
michael@0 39 return NULL;
michael@0 40 }
michael@0 41 strcpy(input, link);
michael@0 42 while ( (iterations++ < BL_MAXSYMLINKS) &&
michael@0 43 ( (retlen = readlink(input, resolved, len - 1)) > 0) ) {
michael@0 44 char* tmp = input;
michael@0 45 resolved[retlen] = '\0'; /* NULL termination */
michael@0 46 input = resolved;
michael@0 47 resolved = tmp;
michael@0 48 }
michael@0 49 PR_Free(resolved);
michael@0 50 if (iterations == 1 && retlen < 0) {
michael@0 51 PR_Free(input);
michael@0 52 input = NULL;
michael@0 53 }
michael@0 54 return input;
michael@0 55 }
michael@0 56 #endif /* XP_UNIX */
michael@0 57
michael@0 58 /*
michael@0 59 * Load the library with the file name 'name' residing in the same
michael@0 60 * directory as the reference library, whose pathname is 'referencePath'.
michael@0 61 */
michael@0 62 static PRLibrary *
michael@0 63 loader_LoadLibInReferenceDir(const char *referencePath, const char *name)
michael@0 64 {
michael@0 65 PRLibrary *dlh = NULL;
michael@0 66 char *fullName = NULL;
michael@0 67 char* c;
michael@0 68 PRLibSpec libSpec;
michael@0 69
michael@0 70 /* Remove the trailing filename from referencePath and add the new one */
michael@0 71 c = strrchr(referencePath, PR_GetDirectorySeparator());
michael@0 72 if (c) {
michael@0 73 size_t referencePathSize = 1 + c - referencePath;
michael@0 74 fullName = (char*) PORT_Alloc(strlen(name) + referencePathSize + 1);
michael@0 75 if (fullName) {
michael@0 76 memcpy(fullName, referencePath, referencePathSize);
michael@0 77 strcpy(fullName + referencePathSize, name);
michael@0 78 #ifdef DEBUG_LOADER
michael@0 79 PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n",
michael@0 80 fullName);
michael@0 81 #endif
michael@0 82 libSpec.type = PR_LibSpec_Pathname;
michael@0 83 libSpec.value.pathname = fullName;
michael@0 84 dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL
michael@0 85 #ifdef PR_LD_ALT_SEARCH_PATH
michael@0 86 /* allow library's dependencies to be found in the same directory
michael@0 87 * on Windows even if PATH is not set. Requires NSPR 4.8.1 . */
michael@0 88 | PR_LD_ALT_SEARCH_PATH
michael@0 89 #endif
michael@0 90 );
michael@0 91 PORT_Free(fullName);
michael@0 92 }
michael@0 93 }
michael@0 94 return dlh;
michael@0 95 }
michael@0 96
michael@0 97 /*
michael@0 98 * Load a shared library called "newShLibName" in the same directory as
michael@0 99 * a shared library that is already loaded, called existingShLibName.
michael@0 100 * A pointer to a static function in that shared library,
michael@0 101 * staticShLibFunc, is required.
michael@0 102 *
michael@0 103 * existingShLibName:
michael@0 104 * The file name of the shared library that shall be used as the
michael@0 105 * "reference library". The loader will attempt to load the requested
michael@0 106 * library from the same directory as the reference library.
michael@0 107 *
michael@0 108 * staticShLibFunc:
michael@0 109 * Pointer to a static function in the "reference library".
michael@0 110 *
michael@0 111 * newShLibName:
michael@0 112 * The simple file name of the new shared library to be loaded.
michael@0 113 *
michael@0 114 * We use PR_GetLibraryFilePathname to get the pathname of the loaded
michael@0 115 * shared lib that contains this function, and then do a
michael@0 116 * PR_LoadLibraryWithFlags with an absolute pathname for the shared
michael@0 117 * library to be loaded.
michael@0 118 *
michael@0 119 * On Windows, the "alternate search path" strategy is employed, if available.
michael@0 120 * On Unix, if existingShLibName is a symbolic link, and no link exists for the
michael@0 121 * new library, the original link will be resolved, and the new library loaded
michael@0 122 * from the resolved location.
michael@0 123 *
michael@0 124 * If the new shared library is not found in the same location as the reference
michael@0 125 * library, it will then be loaded from the normal system library path.
michael@0 126 *
michael@0 127 */
michael@0 128
michael@0 129 PRLibrary *
michael@0 130 PORT_LoadLibraryFromOrigin(const char* existingShLibName,
michael@0 131 PRFuncPtr staticShLibFunc,
michael@0 132 const char *newShLibName)
michael@0 133 {
michael@0 134 PRLibrary *lib = NULL;
michael@0 135 char* fullPath = NULL;
michael@0 136 PRLibSpec libSpec;
michael@0 137
michael@0 138 /* Get the pathname for existingShLibName, e.g. /usr/lib/libnss3.so
michael@0 139 * PR_GetLibraryFilePathname works with either the base library name or a
michael@0 140 * function pointer, depending on the platform.
michael@0 141 * We require the address of a function in the "reference library",
michael@0 142 * provided by the caller. To avoid getting the address of the stub/thunk
michael@0 143 * of an exported function by accident, use the address of a static
michael@0 144 * function rather than an exported function.
michael@0 145 */
michael@0 146 fullPath = PR_GetLibraryFilePathname(existingShLibName,
michael@0 147 staticShLibFunc);
michael@0 148
michael@0 149 if (fullPath) {
michael@0 150 lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
michael@0 151 #ifdef XP_UNIX
michael@0 152 if (!lib) {
michael@0 153 /*
michael@0 154 * If fullPath is a symbolic link, resolve the symbolic
michael@0 155 * link and try again.
michael@0 156 */
michael@0 157 char* originalfullPath = loader_GetOriginalPathname(fullPath);
michael@0 158 if (originalfullPath) {
michael@0 159 PR_Free(fullPath);
michael@0 160 fullPath = originalfullPath;
michael@0 161 lib = loader_LoadLibInReferenceDir(fullPath, newShLibName);
michael@0 162 }
michael@0 163 }
michael@0 164 #endif
michael@0 165 PR_Free(fullPath);
michael@0 166 }
michael@0 167 if (!lib) {
michael@0 168 #ifdef DEBUG_LOADER
michael@0 169 PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", newShLibName);
michael@0 170 #endif
michael@0 171 libSpec.type = PR_LibSpec_Pathname;
michael@0 172 libSpec.value.pathname = newShLibName;
michael@0 173 lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
michael@0 174 }
michael@0 175 if (NULL == lib) {
michael@0 176 #ifdef DEBUG_LOADER
michael@0 177 PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", newShLibName);
michael@0 178 #endif
michael@0 179 }
michael@0 180 return lib;
michael@0 181 }
michael@0 182

mercurial