1 /*
2 * loader.c - load platform dependent DSO containing freebl implementation.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #define _GNU_SOURCE 1
9 #include "loader.h"
10 #include "prmem.h"
11 #include "prerror.h"
12 #include "prinit.h"
13 #include "prenv.h"
14 #include "blname.c"
15
16 #include "prio.h"
17 #include "prprf.h"
18 #include <stdio.h>
19 #include "prsystem.h"
20 #include "nsslowhash.h"
21 #include <dlfcn.h>
22 #include "pratom.h"
23
24 static PRLibrary *blLib;
25
26 #define LSB(x) ((x)&0xff)
27 #define MSB(x) ((x) >> 8)
28
29 static const NSSLOWVector *vector;
30 static const char *libraryName = NULL;
31
32 /* pretty much only glibc uses this, make sure we don't have any depenencies
33 * on nspr.. */
34 #undef PORT_Alloc
35 #undef PORT_Free
36 #define PORT_Alloc malloc
37 #define PR_Malloc malloc
38 #define PORT_Free free
39 #define PR_Free free
40 #define PR_GetDirectorySeparator() '/'
41 #define PR_LoadLibraryWithFlags(libspec, flags) \
42 (PRLibrary *)dlopen(libSpec.value.pathname, RTLD_NOW | RTLD_LOCAL)
43 #define PR_GetLibraryFilePathname(name, addr) \
44 freebl_lowhash_getLibraryFilePath(addr)
45
46 static char *
freebl_lowhash_getLibraryFilePath(void * addr)47 freebl_lowhash_getLibraryFilePath(void *addr)
48 {
49 Dl_info dli;
50 if (dladdr(addr, &dli) == 0) {
51 return NULL;
52 }
53 return strdup(dli.dli_fname);
54 }
55
56 /*
57 * The PR_LoadLibraryWithFlags call above defines this variable away, so we
58 * don't need it..
59 */
60 #ifdef nodef
61 static const char *NameOfThisSharedLib =
62 SHLIB_PREFIX "freebl" SHLIB_VERSION "." SHLIB_SUFFIX;
63 #endif
64
65 #include "genload.c"
66
67 /* This function must be run only once. */
68 /* determine if hybrid platform, then actually load the DSO. */
69 static PRStatus
freebl_LoadDSO(void)70 freebl_LoadDSO(void)
71 {
72 PRLibrary *handle;
73 const char *name = getLibName();
74
75 if (!name) {
76 /*PR_SetError(PR_LOAD_LIBRARY_ERROR,0); */
77 return PR_FAILURE;
78 }
79 handle = loader_LoadLibrary(name);
80 if (handle) {
81 void *address = dlsym(handle, "NSSLOW_GetVector");
82 if (address) {
83 NSSLOWGetVectorFn *getVector = (NSSLOWGetVectorFn *)address;
84 const NSSLOWVector *dsoVector = getVector();
85 if (dsoVector) {
86 unsigned short dsoVersion = dsoVector->version;
87 unsigned short myVersion = NSSLOW_VERSION;
88 if (MSB(dsoVersion) == MSB(myVersion) &&
89 LSB(dsoVersion) >= LSB(myVersion) &&
90 dsoVector->length >= sizeof(NSSLOWVector)) {
91 vector = dsoVector;
92 libraryName = name;
93 blLib = handle;
94 return PR_SUCCESS;
95 }
96 }
97 }
98 (void)dlclose(handle);
99 }
100 return PR_FAILURE;
101 }
102
103 static PRCallOnceType loadFreeBLOnce;
104
105 static void
freebl_RunLoaderOnce(void)106 freebl_RunLoaderOnce(void)
107 {
108 /* Don't have NSPR, so can use the real PR_CallOnce, implement a stripped
109 * down version. */
110 if (loadFreeBLOnce.initialized) {
111 return;
112 }
113 if (__sync_lock_test_and_set(&loadFreeBLOnce.inProgress, 1) == 0) {
114 loadFreeBLOnce.status = freebl_LoadDSO();
115 loadFreeBLOnce.initialized = 1;
116 } else {
117 /* shouldn't have a lot of takers on the else clause, which is good
118 * since we don't have condition variables yet.
119 * 'initialized' only ever gets set (not cleared) so we don't
120 * need the traditional locks. */
121 while (!loadFreeBLOnce.initialized) {
122 sleep(1); /* don't have condition variables, just give up the CPU */
123 }
124 }
125 }
126
127 static const NSSLOWVector *
freebl_InitVector(void)128 freebl_InitVector(void)
129 {
130 if (!vector) {
131 freebl_RunLoaderOnce();
132 }
133 return vector;
134 }
135
136 const FREEBLVector *
FREEBL_GetVector(void)137 FREEBL_GetVector(void)
138 {
139 if (freebl_InitVector()) {
140 return (vector->p_FREEBL_GetVector)();
141 }
142 return NULL;
143 }
144
145 NSSLOWInitContext *
NSSLOW_Init(void)146 NSSLOW_Init(void)
147 {
148 if (freebl_InitVector()) {
149 return (vector->p_NSSLOW_Init)();
150 }
151 return NULL;
152 }
153
154 void
NSSLOW_Shutdown(NSSLOWInitContext * context)155 NSSLOW_Shutdown(NSSLOWInitContext *context)
156 {
157 if (freebl_InitVector()) {
158 (vector->p_NSSLOW_Shutdown)(context);
159 }
160 }
161
162 void
NSSLOW_Reset(NSSLOWInitContext * context)163 NSSLOW_Reset(NSSLOWInitContext *context)
164 {
165 if (freebl_InitVector()) {
166 (vector->p_NSSLOW_Reset)(context);
167 }
168 }
169
170 NSSLOWHASHContext *
NSSLOWHASH_NewContext(NSSLOWInitContext * initContext,HASH_HashType hashType)171 NSSLOWHASH_NewContext(
172 NSSLOWInitContext *initContext,
173 HASH_HashType hashType)
174 {
175 if (freebl_InitVector()) {
176 return (vector->p_NSSLOWHASH_NewContext)(initContext, hashType);
177 }
178 return NULL;
179 }
180
181 void
NSSLOWHASH_Begin(NSSLOWHASHContext * context)182 NSSLOWHASH_Begin(NSSLOWHASHContext *context)
183 {
184 if (freebl_InitVector()) {
185 (vector->p_NSSLOWHASH_Begin)(context);
186 }
187 }
188
189 void
NSSLOWHASH_Update(NSSLOWHASHContext * context,const unsigned char * buf,unsigned int len)190 NSSLOWHASH_Update(NSSLOWHASHContext *context,
191 const unsigned char *buf,
192 unsigned int len)
193 {
194 if (freebl_InitVector()) {
195 (vector->p_NSSLOWHASH_Update)(context, buf, len);
196 }
197 }
198
199 void
NSSLOWHASH_End(NSSLOWHASHContext * context,unsigned char * buf,unsigned int * ret,unsigned int len)200 NSSLOWHASH_End(NSSLOWHASHContext *context,
201 unsigned char *buf,
202 unsigned int *ret, unsigned int len)
203 {
204 if (freebl_InitVector()) {
205 (vector->p_NSSLOWHASH_End)(context, buf, ret, len);
206 }
207 }
208
209 void
NSSLOWHASH_Destroy(NSSLOWHASHContext * context)210 NSSLOWHASH_Destroy(NSSLOWHASHContext *context)
211 {
212 if (freebl_InitVector()) {
213 (vector->p_NSSLOWHASH_Destroy)(context);
214 }
215 }
216
217 unsigned int
NSSLOWHASH_Length(NSSLOWHASHContext * context)218 NSSLOWHASH_Length(NSSLOWHASHContext *context)
219 {
220 if (freebl_InitVector()) {
221 return (vector->p_NSSLOWHASH_Length)(context);
222 }
223 return -1;
224 }
225