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