/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Allow freebl and softoken to be loaded without util or NSPR. * * These symbols are overridden once real NSPR, and libutil are attached. */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Android API < 21 doesn't define RTLD_NOLOAD */ #ifndef RTLD_NOLOAD #define RTLD_NOLOAD 0 #endif #define FREEBL_NO_WEAK 1 #define WEAK __attribute__((weak)) #ifdef FREEBL_NO_WEAK /* * This uses function pointers. * * CONS: A separate function is needed to * fill in the function pointers. * * PROS: it works on all platforms. * it allows for dynamically finding nspr and libutil, even once * softoken is loaded and running. (NOTE: this may be a problem if * we switch between the stubs and real NSPR on the fly. NSPR will * do bad things if passed an _FakeArena to free or allocate from). */ #define STUB_DECLARE(ret, fn, args) \ typedef ret(*type_##fn) args; \ static type_##fn ptr_##fn = NULL #define STUB_SAFE_CALL0(fn) \ if (ptr_##fn) { \ return ptr_##fn(); \ } #define STUB_SAFE_CALL1(fn, a1) \ if (ptr_##fn) { \ return ptr_##fn(a1); \ } #define STUB_SAFE_CALL2(fn, a1, a2) \ if (ptr_##fn) { \ return ptr_##fn(a1, a2); \ } #define STUB_SAFE_CALL3(fn, a1, a2, a3) \ if (ptr_##fn) { \ return ptr_##fn(a1, a2, a3); \ } #define STUB_SAFE_CALL4(fn, a1, a2, a3, a4) \ if (ptr_##fn) { \ return ptr_##fn(a1, a2, a3, a4); \ } #define STUB_SAFE_CALL5(fn, a1, a2, a3, a4, a5) \ if (ptr_##fn) { \ return ptr_##fn(a1, a2, a3, a4, a5); \ } #define STUB_SAFE_CALL6(fn, a1, a2, a3, a4, a5, a6) \ if (ptr_##fn) { \ return ptr_##fn(a1, a2, a3, a4, a5, a6); \ } #define STUB_FETCH_FUNCTION(fn) \ ptr_##fn = (type_##fn)dlsym(lib, #fn); \ if (ptr_##fn == NULL) { \ return SECFailure; \ } #else /* * this uses the loader weak attribute. it works automatically, but once * freebl is loaded, the symbols are 'fixed' (later loading of NSPR or * libutil will not resolve these symbols). */ #define STUB_DECLARE(ret, fn, args) \ WEAK extern ret fn args #define STUB_SAFE_CALL0(fn) \ if (fn) { \ return fn(); \ } #define STUB_SAFE_CALL1(fn, a1) \ if (fn) { \ return fn(a1); \ } #define STUB_SAFE_CALL2(fn, a1, a2) \ if (fn) { \ return fn(a1, a2); \ } #define STUB_SAFE_CALL3(fn, a1, a2, a3) \ if (fn) { \ return fn(a1, a2, a3); \ } #define STUB_SAFE_CALL4(fn, a1, a2, a3, a4) \ if (fn) { \ return fn(a1, a2, a3, a4); \ } #define STUB_SAFE_CALL6(fn, a1, a2, a3, a4, a5, a6) \ if (fn) { \ return fn(a1, a2, a3, a4, a5, a6); \ } #endif STUB_DECLARE(void *, PORT_Alloc_Util, (size_t len)); STUB_DECLARE(void *, PORT_ArenaAlloc_Util, (PLArenaPool * arena, size_t size)); STUB_DECLARE(void *, PORT_ArenaZAlloc_Util, (PLArenaPool * arena, size_t size)); STUB_DECLARE(void, PORT_Free_Util, (void *ptr)); STUB_DECLARE(void, PORT_FreeArena_Util, (PLArenaPool * arena, PRBool zero)); STUB_DECLARE(int, PORT_GetError_Util, (void)); STUB_DECLARE(PLArenaPool *, PORT_NewArena_Util, (unsigned long chunksize)); STUB_DECLARE(void, PORT_SetError_Util, (int value)); STUB_DECLARE(void *, PORT_ZAlloc_Util, (size_t len)); STUB_DECLARE(void *, PORT_ZAllocAligned_Util, (size_t bytes, size_t alignment, void **mem)); STUB_DECLARE(void *, PORT_ZAllocAlignedOffset_Util, (size_t bytes, size_t alignment, size_t offset)); STUB_DECLARE(void, PORT_ZFree_Util, (void *ptr, size_t len)); STUB_DECLARE(void, PR_Assert, (const char *s, const char *file, PRIntn ln)); STUB_DECLARE(PRStatus, PR_Access, (const char *name, PRAccessHow how)); STUB_DECLARE(PRStatus, PR_CallOnce, (PRCallOnceType * once, PRCallOnceFN func)); STUB_DECLARE(PRStatus, PR_Close, (PRFileDesc * fd)); STUB_DECLARE(void, PR_DestroyLock, (PRLock * lock)); STUB_DECLARE(void, PR_DestroyCondVar, (PRCondVar * cvar)); STUB_DECLARE(void, PR_Free, (void *ptr)); STUB_DECLARE(char *, PR_GetLibraryFilePathname, (const char *name, PRFuncPtr addr)); STUB_DECLARE(PRFileDesc *, PR_ImportPipe, (PROsfd osfd)); STUB_DECLARE(void, PR_Lock, (PRLock * lock)); STUB_DECLARE(PRCondVar *, PR_NewCondVar, (PRLock * lock)); STUB_DECLARE(PRLock *, PR_NewLock, (void)); STUB_DECLARE(PRStatus, PR_NotifyCondVar, (PRCondVar * cvar)); STUB_DECLARE(PRStatus, PR_NotifyAllCondVar, (PRCondVar * cvar)); STUB_DECLARE(PRFileDesc *, PR_Open, (const char *name, PRIntn flags, PRIntn mode)); STUB_DECLARE(PRInt32, PR_Read, (PRFileDesc * fd, void *buf, PRInt32 amount)); STUB_DECLARE(PROffset32, PR_Seek, (PRFileDesc * fd, PROffset32 offset, PRSeekWhence whence)); STUB_DECLARE(PRStatus, PR_Sleep, (PRIntervalTime ticks)); STUB_DECLARE(PRStatus, PR_Unlock, (PRLock * lock)); STUB_DECLARE(PRStatus, PR_WaitCondVar, (PRCondVar * cvar, PRIntervalTime timeout)); STUB_DECLARE(char *, PR_GetEnvSecure, (const char *)); STUB_DECLARE(SECItem *, SECITEM_AllocItem_Util, (PLArenaPool * arena, SECItem *item, unsigned int len)); STUB_DECLARE(SECComparison, SECITEM_CompareItem_Util, (const SECItem *a, const SECItem *b)); STUB_DECLARE(PRBool, SECITEM_ItemsAreEqual_Util, (const SECItem *a, const SECItem *b)); STUB_DECLARE(SECStatus, SECITEM_CopyItem_Util, (PLArenaPool * arena, SECItem *to, const SECItem *from)); STUB_DECLARE(void, SECITEM_FreeItem_Util, (SECItem * zap, PRBool freeit)); STUB_DECLARE(void, SECITEM_ZfreeItem_Util, (SECItem * zap, PRBool freeit)); STUB_DECLARE(SECOidTag, SECOID_FindOIDTag_Util, (const SECItem *oid)); STUB_DECLARE(int, NSS_SecureMemcmp, (const void *a, const void *b, size_t n)); STUB_DECLARE(unsigned int, NSS_SecureMemcmpZero, (const void *mem, size_t n)); STUB_DECLARE(void, NSS_SecureSelect, (void *dest, const void *src0, const void *src1, size_t n, unsigned char b)); #ifndef NSS_FIPS_DISABLED STUB_DECLARE(PRBool, NSS_GetSystemFIPSEnabled, (void)); #endif #define PORT_ZNew_stub(type) (type *)PORT_ZAlloc_stub(sizeof(type)) #define PORT_New_stub(type) (type *)PORT_Alloc_stub(sizeof(type)) #define PORT_ZNewArray_stub(type, num) \ (type *)PORT_ZAlloc_stub(sizeof(type) * (num)) #define PORT_ZNewAligned_stub(type, alignment, mem) \ (type *)PORT_ZAllocAlignedOffset_stub(sizeof(type), alignment, offsetof(type, mem)) /* * NOTE: in order to support hashing only the memory allocation stubs, * the get library name stubs, and the file io stubs are needed (the latter * two are for the library verification). The remaining stubs are simply to * compile. Attempts to use the library for other operations without NSPR * will most likely fail. */ /* memory */ extern void * PORT_Alloc_stub(size_t len) { STUB_SAFE_CALL1(PORT_Alloc_Util, len); return malloc(len); } extern void PORT_Free_stub(void *ptr) { STUB_SAFE_CALL1(PORT_Free_Util, ptr); return free(ptr); } extern void * PORT_ZAlloc_stub(size_t len) { STUB_SAFE_CALL1(PORT_ZAlloc_Util, len); void *ptr = malloc(len); if (ptr) { memset(ptr, 0, len); } return ptr; } /* aligned_alloc is C11. This is an alternative to get aligned memory. */ extern void * PORT_ZAllocAligned_stub(size_t bytes, size_t alignment, void **mem) { STUB_SAFE_CALL3(PORT_ZAllocAligned_Util, bytes, alignment, mem); /* This only works if alignement is a power of 2. */ if ((alignment == 0) || (alignment & (alignment - 1))) { return NULL; } size_t x = alignment - 1; size_t len = (bytes ? bytes : 1) + x; if (!mem) { return NULL; } /* Always allocate a non-zero amount of bytes */ *mem = malloc(len); if (!*mem) { return NULL; } memset(*mem, 0, len); /* We're pretty sure this is non-zero, but let's assure scan-build too. */ void *ret = (void *)(((uintptr_t)*mem + x) & ~(uintptr_t)x); assert(ret); return ret; } extern void * PORT_ZAllocAlignedOffset_stub(size_t size, size_t alignment, size_t offset) { STUB_SAFE_CALL3(PORT_ZAllocAlignedOffset_Util, size, alignment, offset); if (offset > size) { return NULL; } void *mem = NULL; void *v = PORT_ZAllocAligned_stub(size, alignment, &mem); if (!v) { return NULL; } *((void **)((uintptr_t)v + offset)) = mem; return v; } extern void PORT_ZFree_stub(void *ptr, size_t len) { STUB_SAFE_CALL2(PORT_ZFree_Util, ptr, len); memset(ptr, 0, len); return free(ptr); } extern void PR_Free_stub(void *ptr) { STUB_SAFE_CALL1(PR_Free, ptr); return free(ptr); } /* we have defensive returns after abort(), which is marked noreturn on some * platforms, making the compiler legitimately complain. */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunreachable-code-return" #endif /* * arenas * */ extern PLArenaPool * PORT_NewArena_stub(unsigned long chunksize) { STUB_SAFE_CALL1(PORT_NewArena_Util, chunksize); abort(); return NULL; } extern void * PORT_ArenaAlloc_stub(PLArenaPool *arena, size_t size) { STUB_SAFE_CALL2(PORT_ArenaZAlloc_Util, arena, size); abort(); return NULL; } extern void * PORT_ArenaZAlloc_stub(PLArenaPool *arena, size_t size) { STUB_SAFE_CALL2(PORT_ArenaZAlloc_Util, arena, size); abort(); return NULL; } extern void PORT_FreeArena_stub(PLArenaPool *arena, PRBool zero) { STUB_SAFE_CALL2(PORT_FreeArena_Util, arena, zero); abort(); } /* io */ extern PRFileDesc * PR_Open_stub(const char *name, PRIntn flags, PRIntn mode) { int *lfd = NULL; int fd; int lflags = 0; STUB_SAFE_CALL3(PR_Open, name, flags, mode); if (flags & PR_RDWR) { lflags = O_RDWR; } else if (flags & PR_WRONLY) { lflags = O_WRONLY; } else { lflags = O_RDONLY; } if (flags & PR_EXCL) lflags |= O_EXCL; if (flags & PR_APPEND) lflags |= O_APPEND; if (flags & PR_TRUNCATE) lflags |= O_TRUNC; fd = open(name, lflags, mode); if (fd >= 0) { lfd = PORT_New_stub(int); if (lfd != NULL) { *lfd = fd; } else { close(fd); } } return (PRFileDesc *)lfd; } extern PRFileDesc * PR_ImportPipe_stub(PROsfd fd) { int *lfd = NULL; STUB_SAFE_CALL1(PR_ImportPipe, fd); lfd = PORT_New_stub(int); if (lfd != NULL) { *lfd = fd; } return (PRFileDesc *)lfd; } extern PRStatus PR_Close_stub(PRFileDesc *fd) { int *lfd; STUB_SAFE_CALL1(PR_Close, fd); lfd = (int *)fd; close(*lfd); PORT_Free_stub(lfd); return PR_SUCCESS; } extern PRInt32 PR_Read_stub(PRFileDesc *fd, void *buf, PRInt32 amount) { int *lfd; STUB_SAFE_CALL3(PR_Read, fd, buf, amount); lfd = (int *)fd; return read(*lfd, buf, amount); } extern PROffset32 PR_Seek_stub(PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence) { int *lfd; int lwhence = SEEK_SET; STUB_SAFE_CALL3(PR_Seek, fd, offset, whence); lfd = (int *)fd; switch (whence) { case PR_SEEK_CUR: lwhence = SEEK_CUR; break; case PR_SEEK_END: lwhence = SEEK_END; break; case PR_SEEK_SET: break; } return lseek(*lfd, offset, lwhence); } PRStatus PR_Access_stub(const char *name, PRAccessHow how) { int mode = F_OK; int rv; STUB_SAFE_CALL2(PR_Access, name, how); switch (how) { case PR_ACCESS_WRITE_OK: mode = W_OK; break; case PR_ACCESS_READ_OK: mode = R_OK; break; /* assume F_OK for all others */ default: break; } rv = access(name, mode); if (rv == 0) { return PR_SUCCESS; } return PR_FAILURE; } /* * library */ extern char * PR_GetLibraryFilePathname_stub(const char *name, PRFuncPtr addr) { Dl_info dli; char *result; STUB_SAFE_CALL2(PR_GetLibraryFilePathname, name, addr); if (dladdr((void *)addr, &dli) == 0) { return NULL; } result = PORT_Alloc_stub(strlen(dli.dli_fname) + 1); if (result != NULL) { strcpy(result, dli.dli_fname); } return result; } #include /* errors */ extern int PORT_GetError_stub(void) { STUB_SAFE_CALL0(PORT_GetError_Util); return errno; } extern void PORT_SetError_stub(int value) { STUB_SAFE_CALL1(PORT_SetError_Util, value); errno = value; } /* misc */ extern void PR_Assert_stub(const char *s, const char *file, PRIntn ln) { STUB_SAFE_CALL3(PR_Assert, s, file, ln); fprintf(stderr, "%s line %d: %s\n", file, ln, s); abort(); } /* time */ extern PRStatus PR_Sleep_stub(PRIntervalTime ticks) { STUB_SAFE_CALL1(PR_Sleep, ticks); usleep(ticks * 1000); return PR_SUCCESS; } /* locking */ extern PRLock * PR_NewLock_stub(void) { STUB_SAFE_CALL0(PR_NewLock); abort(); return NULL; } extern PRStatus PR_Unlock_stub(PRLock *lock) { STUB_SAFE_CALL1(PR_Unlock, lock); abort(); return PR_FAILURE; } extern void PR_Lock_stub(PRLock *lock) { STUB_SAFE_CALL1(PR_Lock, lock); abort(); return; } extern void PR_DestroyLock_stub(PRLock *lock) { STUB_SAFE_CALL1(PR_DestroyLock, lock); abort(); return; } extern PRCondVar * PR_NewCondVar_stub(PRLock *lock) { STUB_SAFE_CALL1(PR_NewCondVar, lock); abort(); return NULL; } extern PRStatus PR_NotifyCondVar_stub(PRCondVar *cvar) { STUB_SAFE_CALL1(PR_NotifyCondVar, cvar); abort(); return PR_FAILURE; } extern PRStatus PR_NotifyAllCondVar_stub(PRCondVar *cvar) { STUB_SAFE_CALL1(PR_NotifyAllCondVar, cvar); abort(); return PR_FAILURE; } extern PRStatus PR_WaitCondVar_stub(PRCondVar *cvar, PRIntervalTime timeout) { STUB_SAFE_CALL2(PR_WaitCondVar, cvar, timeout); abort(); return PR_FAILURE; } extern char * PR_GetEnvSecure_stub(const char *var) { STUB_SAFE_CALL1(PR_GetEnvSecure, var); #ifdef __USE_GNU return secure_getenv(var); #else return getenv(var); #endif } extern void PR_DestroyCondVar_stub(PRCondVar *cvar) { STUB_SAFE_CALL1(PR_DestroyCondVar, cvar); abort(); return; } /* * NOTE: this presupposes GCC 4.1 */ extern PRStatus PR_CallOnce_stub(PRCallOnceType *once, PRCallOnceFN func) { STUB_SAFE_CALL2(PR_CallOnce, once, func); abort(); return PR_FAILURE; } /* * SECITEMS implement Item Utilities */ extern void SECITEM_FreeItem_stub(SECItem *zap, PRBool freeit) { STUB_SAFE_CALL2(SECITEM_FreeItem_Util, zap, freeit); abort(); } extern SECItem * SECITEM_AllocItem_stub(PLArenaPool *arena, SECItem *item, unsigned int len) { STUB_SAFE_CALL3(SECITEM_AllocItem_Util, arena, item, len); abort(); return NULL; } extern SECComparison SECITEM_CompareItem_stub(const SECItem *a, const SECItem *b) { STUB_SAFE_CALL2(SECITEM_CompareItem_Util, a, b); abort(); return SECEqual; } extern PRBool SECITEM_ItemsAreEqual_stub(const SECItem *a, const SECItem *b) { STUB_SAFE_CALL2(SECITEM_ItemsAreEqual_Util, a, b); /* two nulls are equal */ if (!a && !b) { return PR_TRUE; } /* only one NULL is not equal */ if (!a || !b) { return PR_FALSE; } /* we know both secitems have been set, now make sure the lengths * are equal */ if (a->len != b->len) { return PR_FALSE; } /* lengths are equal, safe to verify the data */ if (PORT_Memcmp(a->data, b->data, b->len) != 0) { return PR_FALSE; } return PR_TRUE; } extern SECStatus SECITEM_CopyItem_stub(PLArenaPool *arena, SECItem *to, const SECItem *from) { STUB_SAFE_CALL3(SECITEM_CopyItem_Util, arena, to, from); abort(); return SECFailure; } extern SECOidTag SECOID_FindOIDTag_stub(const SECItem *oid) { STUB_SAFE_CALL1(SECOID_FindOIDTag_Util, oid); abort(); return SEC_OID_UNKNOWN; } #ifdef __clang__ #pragma clang diagnostic pop #endif extern void SECITEM_ZfreeItem_stub(SECItem *zap, PRBool freeit) { STUB_SAFE_CALL2(SECITEM_ZfreeItem_Util, zap, freeit); if (zap) { if (zap->data) { PORT_Memset(zap->data, 0, zap->len); PORT_Free_stub(zap->data); } PORT_Memset(zap, 0, sizeof(SECItem)); if (freeit) { PORT_Free_stub(zap); } } } extern int NSS_SecureMemcmp_stub(const void *a, const void *b, size_t n) { STUB_SAFE_CALL3(NSS_SecureMemcmp, a, b, n); abort(); } extern unsigned int NSS_SecureMemcmpZero_stub(const void *mem, size_t n) { STUB_SAFE_CALL2(NSS_SecureMemcmpZero, mem, n); abort(); } extern void NSS_SecureSelect_stub(void *dest, const void *src0, const void *src1, size_t n, unsigned char b) { STUB_SAFE_CALL5(NSS_SecureSelect, dest, src0, src1, n, b); abort(); } #ifndef NSS_FIPS_DISABLED PRBool NSS_GetSystemFIPSEnabled_stub(void) { STUB_SAFE_CALL0(NSS_GetSystemFIPSEnabled); const char *env; /* The environment variable is active for all platforms */ env = PR_GetEnvSecure_stub("NSS_FIPS"); /* we generally accept y, Y, 1, FIPS, TRUE, and ON as turning on FIPS * mode. Anything else is considered 'off' */ if (env && (*env == 'y' || *env == '1' || *env == 'Y' || (strcasecmp(env, "fips") == 0) || (strcasecmp(env, "true") == 0) || (strcasecmp(env, "on") == 0))) { return PR_TRUE; } /* currently only Linux has a system FIPS indicator. Add others here * as they become available/known */ #ifdef LINUX { FILE *f; char d; size_t size; f = fopen("/proc/sys/crypto/fips_enabled", "r"); if (!f) return PR_FALSE; size = fread(&d, 1, 1, f); fclose(f); if (size != 1) return PR_FALSE; if (d == '1') return PR_TRUE; } #endif /* LINUX */ return PR_FALSE; } #endif /* NSS_FIPS_DISABLED = 0 */ #ifdef FREEBL_NO_WEAK static const char *nsprLibName = SHLIB_PREFIX "nspr4." SHLIB_SUFFIX; static const char *nssutilLibName = SHLIB_PREFIX "nssutil3." SHLIB_SUFFIX; static SECStatus freebl_InitNSPR(void *lib) { STUB_FETCH_FUNCTION(PR_Free); STUB_FETCH_FUNCTION(PR_Open); STUB_FETCH_FUNCTION(PR_ImportPipe); STUB_FETCH_FUNCTION(PR_Close); STUB_FETCH_FUNCTION(PR_Read); STUB_FETCH_FUNCTION(PR_Seek); STUB_FETCH_FUNCTION(PR_GetLibraryFilePathname); STUB_FETCH_FUNCTION(PR_Assert); STUB_FETCH_FUNCTION(PR_Access); STUB_FETCH_FUNCTION(PR_Sleep); STUB_FETCH_FUNCTION(PR_CallOnce); STUB_FETCH_FUNCTION(PR_NewCondVar); STUB_FETCH_FUNCTION(PR_NotifyCondVar); STUB_FETCH_FUNCTION(PR_NotifyAllCondVar); STUB_FETCH_FUNCTION(PR_WaitCondVar); STUB_FETCH_FUNCTION(PR_DestroyCondVar); STUB_FETCH_FUNCTION(PR_NewLock); STUB_FETCH_FUNCTION(PR_Unlock); STUB_FETCH_FUNCTION(PR_Lock); STUB_FETCH_FUNCTION(PR_DestroyLock); STUB_FETCH_FUNCTION(PR_GetEnvSecure); return SECSuccess; } static SECStatus freebl_InitNSSUtil(void *lib) { STUB_FETCH_FUNCTION(PORT_Alloc_Util); STUB_FETCH_FUNCTION(PORT_Free_Util); STUB_FETCH_FUNCTION(PORT_ZAlloc_Util); STUB_FETCH_FUNCTION(PORT_ZFree_Util); STUB_FETCH_FUNCTION(PORT_NewArena_Util); STUB_FETCH_FUNCTION(PORT_ArenaAlloc_Util); STUB_FETCH_FUNCTION(PORT_ArenaZAlloc_Util); STUB_FETCH_FUNCTION(PORT_FreeArena_Util); STUB_FETCH_FUNCTION(PORT_GetError_Util); STUB_FETCH_FUNCTION(PORT_SetError_Util); STUB_FETCH_FUNCTION(SECITEM_FreeItem_Util); STUB_FETCH_FUNCTION(SECITEM_AllocItem_Util); STUB_FETCH_FUNCTION(SECITEM_CompareItem_Util); STUB_FETCH_FUNCTION(SECITEM_CopyItem_Util); STUB_FETCH_FUNCTION(SECITEM_ZfreeItem_Util); STUB_FETCH_FUNCTION(SECOID_FindOIDTag_Util); STUB_FETCH_FUNCTION(NSS_SecureMemcmp); STUB_FETCH_FUNCTION(NSS_SecureMemcmpZero); STUB_FETCH_FUNCTION(NSS_SecureSelect); return SECSuccess; } /* * fetch the library if it's loaded. For NSS it should already be loaded */ #define freebl_getLibrary(libName) \ dlopen(libName, RTLD_LAZY | RTLD_NOLOAD) #define freebl_releaseLibrary(lib) \ if (lib) \ dlclose(lib) static void *FREEBLnsprGlobalLib = NULL; static void *FREEBLnssutilGlobalLib = NULL; void __attribute((destructor)) FREEBL_unload() { freebl_releaseLibrary(FREEBLnsprGlobalLib); freebl_releaseLibrary(FREEBLnssutilGlobalLib); } #endif /* * load the symbols from the real libraries if available. * * if force is set, explicitly load the libraries if they are not already * loaded. If we could not use the real libraries, return failure. */ extern SECStatus FREEBL_InitStubs() { SECStatus rv = SECSuccess; #ifdef FREEBL_NO_WEAK void *nspr = NULL; void *nssutil = NULL; /* NSPR should be first */ if (!FREEBLnsprGlobalLib) { nspr = freebl_getLibrary(nsprLibName); if (!nspr) { return SECFailure; } rv = freebl_InitNSPR(nspr); if (rv != SECSuccess) { freebl_releaseLibrary(nspr); return rv; } FREEBLnsprGlobalLib = nspr; /* adopt */ } /* now load NSSUTIL */ if (!FREEBLnssutilGlobalLib) { nssutil = freebl_getLibrary(nssutilLibName); if (!nssutil) { return SECFailure; } rv = freebl_InitNSSUtil(nssutil); if (rv != SECSuccess) { freebl_releaseLibrary(nssutil); return rv; } FREEBLnssutilGlobalLib = nssutil; /* adopt */ } #endif return rv; }