/src/mozilla-central/security/nss/lib/freebl/genload.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 | | /* |
6 | | * This file is meant to be included by other .c files. |
7 | | * This file takes a "parameter", the scope which includes this |
8 | | * code shall declare this variable: |
9 | | * const char *NameOfThisSharedLib; |
10 | | * |
11 | | * NameOfThisSharedLib: |
12 | | * The file name of the shared library that shall be used as the |
13 | | * "reference library". The loader will attempt to load the requested |
14 | | * library from the same directory as the reference library. |
15 | | */ |
16 | | |
17 | | #ifdef XP_UNIX |
18 | | #include <unistd.h> |
19 | | #define BL_MAXSYMLINKS 20 |
20 | | |
21 | | /* |
22 | | * If 'link' is a symbolic link, this function follows the symbolic links |
23 | | * and returns the pathname of the ultimate source of the symbolic links. |
24 | | * If 'link' is not a symbolic link, this function returns NULL. |
25 | | * The caller should call PR_Free to free the string returned by this |
26 | | * function. |
27 | | */ |
28 | | static char* |
29 | | loader_GetOriginalPathname(const char* link) |
30 | 0 | { |
31 | 0 | #ifdef __GLIBC__ |
32 | 0 | char* tmp = realpath(link, NULL); |
33 | 0 | char* resolved; |
34 | 0 | if (!tmp) |
35 | 0 | return NULL; |
36 | 0 | resolved = PR_Malloc(strlen(tmp) + 1); |
37 | 0 | strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */ |
38 | 0 | free(tmp); |
39 | 0 | return resolved; |
40 | | #else |
41 | | char* resolved = NULL; |
42 | | char* input = NULL; |
43 | | PRUint32 iterations = 0; |
44 | | PRInt32 len = 0, retlen = 0; |
45 | | if (!link) { |
46 | | PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
47 | | return NULL; |
48 | | } |
49 | | len = PR_MAX(1024, strlen(link) + 1); |
50 | | resolved = PR_Malloc(len); |
51 | | input = PR_Malloc(len); |
52 | | if (!resolved || !input) { |
53 | | if (resolved) { |
54 | | PR_Free(resolved); |
55 | | } |
56 | | if (input) { |
57 | | PR_Free(input); |
58 | | } |
59 | | return NULL; |
60 | | } |
61 | | strcpy(input, link); |
62 | | while ((iterations++ < BL_MAXSYMLINKS) && |
63 | | ((retlen = readlink(input, resolved, len - 1)) > 0)) { |
64 | | char* tmp = input; |
65 | | resolved[retlen] = '\0'; /* NULL termination */ |
66 | | input = resolved; |
67 | | resolved = tmp; |
68 | | } |
69 | | PR_Free(resolved); |
70 | | if (iterations == 1 && retlen < 0) { |
71 | | PR_Free(input); |
72 | | input = NULL; |
73 | | } |
74 | | return input; |
75 | | #endif |
76 | | } |
77 | | #endif /* XP_UNIX */ |
78 | | |
79 | | /* |
80 | | * Load the library with the file name 'name' residing in the same |
81 | | * directory as the reference library, whose pathname is 'referencePath'. |
82 | | */ |
83 | | static PRLibrary* |
84 | | loader_LoadLibInReferenceDir(const char* referencePath, const char* name) |
85 | 0 | { |
86 | 0 | PRLibrary* dlh = NULL; |
87 | 0 | char* fullName = NULL; |
88 | 0 | char* c; |
89 | 0 | PRLibSpec libSpec; |
90 | 0 |
|
91 | 0 | /* Remove the trailing filename from referencePath and add the new one */ |
92 | 0 | c = strrchr(referencePath, PR_GetDirectorySeparator()); |
93 | 0 | if (c) { |
94 | 0 | size_t referencePathSize = 1 + c - referencePath; |
95 | 0 | fullName = (char*)PORT_Alloc(strlen(name) + referencePathSize + 1); |
96 | 0 | if (fullName) { |
97 | 0 | memcpy(fullName, referencePath, referencePathSize); |
98 | 0 | strcpy(fullName + referencePathSize, name); |
99 | | #ifdef DEBUG_LOADER |
100 | | PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n", |
101 | | fullName); |
102 | | #endif |
103 | | libSpec.type = PR_LibSpec_Pathname; |
104 | 0 | libSpec.value.pathname = fullName; |
105 | 0 | dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); |
106 | 0 | PORT_Free(fullName); |
107 | 0 | } |
108 | 0 | } |
109 | 0 | return dlh; |
110 | 0 | } |
111 | | |
112 | | /* |
113 | | * We use PR_GetLibraryFilePathname to get the pathname of the loaded |
114 | | * shared lib that contains this function, and then do a PR_LoadLibrary |
115 | | * with an absolute pathname for the softoken shared library. |
116 | | */ |
117 | | |
118 | | static PRLibrary* |
119 | | loader_LoadLibrary(const char* nameToLoad) |
120 | 0 | { |
121 | 0 | PRLibrary* lib = NULL; |
122 | 0 | char* fullPath = NULL; |
123 | 0 | PRLibSpec libSpec; |
124 | 0 |
|
125 | 0 | /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so |
126 | 0 | * PR_GetLibraryFilePathname works with either the base library name or a |
127 | 0 | * function pointer, depending on the platform. We can't query an exported |
128 | 0 | * symbol such as NSC_GetFunctionList, because on some platforms we can't |
129 | 0 | * find symbols in loaded implicit dependencies. |
130 | 0 | * But we can just get the address of this function ! |
131 | 0 | */ |
132 | 0 | fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib, |
133 | 0 | (PRFuncPtr)&loader_LoadLibrary); |
134 | 0 |
|
135 | 0 | if (fullPath) { |
136 | 0 | lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); |
137 | 0 | #ifdef XP_UNIX |
138 | 0 | if (!lib) { |
139 | 0 | /* |
140 | 0 | * If fullPath is a symbolic link, resolve the symbolic |
141 | 0 | * link and try again. |
142 | 0 | */ |
143 | 0 | char* originalfullPath = loader_GetOriginalPathname(fullPath); |
144 | 0 | if (originalfullPath) { |
145 | 0 | PR_Free(fullPath); |
146 | 0 | fullPath = originalfullPath; |
147 | 0 | lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad); |
148 | 0 | } |
149 | 0 | } |
150 | 0 | #endif |
151 | 0 | PR_Free(fullPath); |
152 | 0 | } |
153 | 0 | if (!lib) { |
154 | | #ifdef DEBUG_LOADER |
155 | | PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad); |
156 | | #endif |
157 | | libSpec.type = PR_LibSpec_Pathname; |
158 | 0 | libSpec.value.pathname = nameToLoad; |
159 | 0 | lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); |
160 | 0 | } |
161 | 0 | if (NULL == lib) { |
162 | | #ifdef DEBUG_LOADER |
163 | | PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad); |
164 | | #endif |
165 | | } |
166 | 0 | return lib; |
167 | 0 | } |