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