1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/importer/nss_decryptor_win.h"
6
7 #include "base/file_path.h"
8 #include "base/sys_string_conversions.h"
9
10 namespace {
11
12 typedef BOOL (WINAPI* SetDllDirectoryFunc)(LPCTSTR lpPathName);
13
14 // A helper class whose destructor calls SetDllDirectory(NULL) to undo the
15 // effects of a previous SetDllDirectory call.
16 class SetDllDirectoryCaller {
17 public:
SetDllDirectoryCaller()18 explicit SetDllDirectoryCaller() : func_(NULL) { }
19
~SetDllDirectoryCaller()20 ~SetDllDirectoryCaller() {
21 if (func_)
22 func_(NULL);
23 }
24
25 // Sets the SetDllDirectory function pointer to activates this object.
set_func(SetDllDirectoryFunc func)26 void set_func(SetDllDirectoryFunc func) { func_ = func; }
27
28 private:
29 SetDllDirectoryFunc func_;
30 };
31
32 } // namespace
33
34 // static
35 const wchar_t NSSDecryptor::kNSS3Library[] = L"nss3.dll";
36 const wchar_t NSSDecryptor::kSoftokn3Library[] = L"softokn3.dll";
37 const wchar_t NSSDecryptor::kPLDS4Library[] = L"plds4.dll";
38 const wchar_t NSSDecryptor::kNSPR4Library[] = L"nspr4.dll";
39
Init(const FilePath & dll_path,const FilePath & db_path)40 bool NSSDecryptor::Init(const FilePath& dll_path, const FilePath& db_path) {
41 // We call SetDllDirectory to work around a Purify bug (GetModuleHandle
42 // fails inside Purify under certain conditions). SetDllDirectory only
43 // exists on Windows XP SP1 or later, so we look up its address at run time.
44 HMODULE kernel32_dll = GetModuleHandle(L"kernel32.dll");
45 if (kernel32_dll == NULL)
46 return false;
47 SetDllDirectoryFunc set_dll_directory =
48 (SetDllDirectoryFunc)GetProcAddress(kernel32_dll, "SetDllDirectoryW");
49 SetDllDirectoryCaller caller;
50
51 if (set_dll_directory != NULL) {
52 if (!set_dll_directory(dll_path.value().c_str()))
53 return false;
54 caller.set_func(set_dll_directory);
55 nss3_dll_ = LoadLibrary(kNSS3Library);
56 if (nss3_dll_ == NULL)
57 return false;
58 } else {
59 // Fall back on LoadLibraryEx if SetDllDirectory isn't available. We
60 // actually prefer this method because it doesn't change the DLL search
61 // path, which is a process-wide property.
62 FilePath path = dll_path.Append(kNSS3Library);
63 nss3_dll_ = LoadLibraryEx(path.value().c_str(), NULL,
64 LOAD_WITH_ALTERED_SEARCH_PATH);
65 if (nss3_dll_ == NULL)
66 return false;
67
68 // Firefox 2 uses NSS 3.11. Firefox 3 uses NSS 3.12. NSS 3.12 has two
69 // changes in its DLLs:
70 // 1. nss3.dll is not linked with softokn3.dll at build time, but rather
71 // loads softokn3.dll using LoadLibrary in NSS_Init.
72 // 2. softokn3.dll has a new dependency sqlite3.dll.
73 // NSS_Init's LoadLibrary call has trouble finding sqlite3.dll. To help
74 // it out, we preload softokn3.dll using LoadLibraryEx with the
75 // LOAD_WITH_ALTERED_SEARCH_PATH flag. This helps because LoadLibrary
76 // doesn't load a DLL again if it's already loaded. This workaround is
77 // harmless for NSS 3.11.
78 path = FilePath(dll_path).Append(kSoftokn3Library);
79 softokn3_dll_ = LoadLibraryEx(path.value().c_str(), NULL,
80 LOAD_WITH_ALTERED_SEARCH_PATH);
81 if (softokn3_dll_ == NULL) {
82 Free();
83 return false;
84 }
85 }
86 HMODULE plds4_dll = GetModuleHandle(kPLDS4Library);
87 HMODULE nspr4_dll = GetModuleHandle(kNSPR4Library);
88
89 return InitNSS(db_path, plds4_dll, nspr4_dll);
90 }
91
NSSDecryptor()92 NSSDecryptor::NSSDecryptor()
93 : NSS_Init(NULL), NSS_Shutdown(NULL), PK11_GetInternalKeySlot(NULL),
94 PK11_CheckUserPassword(NULL), PK11_FreeSlot(NULL),
95 PK11_Authenticate(NULL), PK11SDR_Decrypt(NULL), SECITEM_FreeItem(NULL),
96 PL_ArenaFinish(NULL), PR_Cleanup(NULL),
97 nss3_dll_(NULL), softokn3_dll_(NULL),
98 is_nss_initialized_(false) {
99 }
100
~NSSDecryptor()101 NSSDecryptor::~NSSDecryptor() {
102 Free();
103 }
104
InitNSS(const FilePath & db_path,base::NativeLibrary plds4_dll,base::NativeLibrary nspr4_dll)105 bool NSSDecryptor::InitNSS(const FilePath& db_path,
106 base::NativeLibrary plds4_dll,
107 base::NativeLibrary nspr4_dll) {
108 // NSPR DLLs are already loaded now.
109 if (plds4_dll == NULL || nspr4_dll == NULL) {
110 Free();
111 return false;
112 }
113
114 // Gets the function address.
115 NSS_Init = (NSSInitFunc)
116 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Init");
117 NSS_Shutdown = (NSSShutdownFunc)
118 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Shutdown");
119 PK11_GetInternalKeySlot = (PK11GetInternalKeySlotFunc)
120 base::GetFunctionPointerFromNativeLibrary(nss3_dll_,
121 "PK11_GetInternalKeySlot");
122 PK11_FreeSlot = (PK11FreeSlotFunc)
123 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_FreeSlot");
124 PK11_Authenticate = (PK11AuthenticateFunc)
125 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_Authenticate");
126 PK11SDR_Decrypt = (PK11SDRDecryptFunc)
127 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11SDR_Decrypt");
128 SECITEM_FreeItem = (SECITEMFreeItemFunc)
129 base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "SECITEM_FreeItem");
130 PL_ArenaFinish = (PLArenaFinishFunc)
131 base::GetFunctionPointerFromNativeLibrary(plds4_dll, "PL_ArenaFinish");
132 PR_Cleanup = (PRCleanupFunc)
133 base::GetFunctionPointerFromNativeLibrary(nspr4_dll, "PR_Cleanup");
134
135 if (NSS_Init == NULL || NSS_Shutdown == NULL ||
136 PK11_GetInternalKeySlot == NULL || PK11_FreeSlot == NULL ||
137 PK11_Authenticate == NULL || PK11SDR_Decrypt == NULL ||
138 SECITEM_FreeItem == NULL || PL_ArenaFinish == NULL ||
139 PR_Cleanup == NULL) {
140 Free();
141 return false;
142 }
143
144 SECStatus result = NSS_Init(base::SysWideToNativeMB(db_path.value()).c_str());
145 if (result != SECSuccess) {
146 Free();
147 return false;
148 }
149
150 is_nss_initialized_ = true;
151 return true;
152 }
153
Free()154 void NSSDecryptor::Free() {
155 if (is_nss_initialized_) {
156 NSS_Shutdown();
157 PL_ArenaFinish();
158 PR_Cleanup();
159 is_nss_initialized_ = false;
160 }
161 if (softokn3_dll_ != NULL)
162 base::UnloadNativeLibrary(softokn3_dll_);
163 if (nss3_dll_ != NULL)
164 base::UnloadNativeLibrary(nss3_dll_);
165 NSS_Init = NULL;
166 NSS_Shutdown = NULL;
167 PK11_GetInternalKeySlot = NULL;
168 PK11_FreeSlot = NULL;
169 PK11_Authenticate = NULL;
170 PK11SDR_Decrypt = NULL;
171 SECITEM_FreeItem = NULL;
172 PL_ArenaFinish = NULL;
173 PR_Cleanup = NULL;
174 nss3_dll_ = NULL;
175 softokn3_dll_ = NULL;
176 }
177