Home | History | Annotate | Download | only in importer
      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/utility/importer/nss_decryptor_win.h"
      6 
      7 #include "base/files/file_path.h"
      8 #include "base/strings/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:
     18   explicit SetDllDirectoryCaller() : func_(NULL) { }
     19 
     20   ~SetDllDirectoryCaller() {
     21     if (func_)
     22       func_(NULL);
     23   }
     24 
     25   // Sets the SetDllDirectory function pointer to activates this object.
     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 
     40 bool NSSDecryptor::Init(const base::FilePath& dll_path,
     41                         const base::FilePath& db_path) {
     42   // We call SetDllDirectory to work around a Purify bug (GetModuleHandle
     43   // fails inside Purify under certain conditions).  SetDllDirectory only
     44   // exists on Windows XP SP1 or later, so we look up its address at run time.
     45   HMODULE kernel32_dll = GetModuleHandle(L"kernel32.dll");
     46   if (kernel32_dll == NULL)
     47     return false;
     48   SetDllDirectoryFunc set_dll_directory =
     49       (SetDllDirectoryFunc)GetProcAddress(kernel32_dll, "SetDllDirectoryW");
     50   SetDllDirectoryCaller caller;
     51 
     52   if (set_dll_directory != NULL) {
     53     if (!set_dll_directory(dll_path.value().c_str()))
     54       return false;
     55     caller.set_func(set_dll_directory);
     56     nss3_dll_ = LoadLibrary(kNSS3Library);
     57     if (nss3_dll_ == NULL)
     58       return false;
     59   } else {
     60     // Fall back on LoadLibraryEx if SetDllDirectory isn't available.  We
     61     // actually prefer this method because it doesn't change the DLL search
     62     // path, which is a process-wide property.
     63     base::FilePath path = dll_path.Append(kNSS3Library);
     64     nss3_dll_ = LoadLibraryEx(path.value().c_str(), NULL,
     65                               LOAD_WITH_ALTERED_SEARCH_PATH);
     66     if (nss3_dll_ == NULL)
     67       return false;
     68 
     69     // Firefox 2 uses NSS 3.11.  Firefox 3 uses NSS 3.12.  NSS 3.12 has two
     70     // changes in its DLLs:
     71     // 1. nss3.dll is not linked with softokn3.dll at build time, but rather
     72     //    loads softokn3.dll using LoadLibrary in NSS_Init.
     73     // 2. softokn3.dll has a new dependency sqlite3.dll.
     74     // NSS_Init's LoadLibrary call has trouble finding sqlite3.dll.  To help
     75     // it out, we preload softokn3.dll using LoadLibraryEx with the
     76     // LOAD_WITH_ALTERED_SEARCH_PATH flag.  This helps because LoadLibrary
     77     // doesn't load a DLL again if it's already loaded.  This workaround is
     78     // harmless for NSS 3.11.
     79     path = base::FilePath(dll_path).Append(kSoftokn3Library);
     80     softokn3_dll_ = LoadLibraryEx(path.value().c_str(), NULL,
     81                                   LOAD_WITH_ALTERED_SEARCH_PATH);
     82     if (softokn3_dll_ == NULL) {
     83       Free();
     84       return false;
     85     }
     86   }
     87   HMODULE plds4_dll = GetModuleHandle(kPLDS4Library);
     88   HMODULE nspr4_dll = GetModuleHandle(kNSPR4Library);
     89 
     90   // On Firefox 22 and higher, NSPR is part of nss3.dll rather than separate
     91   // DLLs.
     92   if (plds4_dll == NULL) {
     93     plds4_dll = nss3_dll_;
     94     nspr4_dll = nss3_dll_;
     95   }
     96   return InitNSS(db_path, plds4_dll, nspr4_dll);
     97 }
     98 
     99 NSSDecryptor::NSSDecryptor()
    100     : NSS_Init(NULL), NSS_Shutdown(NULL), PK11_GetInternalKeySlot(NULL),
    101       PK11_CheckUserPassword(NULL), PK11_FreeSlot(NULL),
    102       PK11_Authenticate(NULL), PK11SDR_Decrypt(NULL), SECITEM_FreeItem(NULL),
    103       PL_ArenaFinish(NULL), PR_Cleanup(NULL),
    104       nss3_dll_(NULL), softokn3_dll_(NULL),
    105       is_nss_initialized_(false) {
    106 }
    107 
    108 NSSDecryptor::~NSSDecryptor() {
    109   Free();
    110 }
    111 
    112 bool NSSDecryptor::InitNSS(const base::FilePath& db_path,
    113                            base::NativeLibrary plds4_dll,
    114                            base::NativeLibrary nspr4_dll) {
    115   // Gets the function address.
    116   NSS_Init = (NSSInitFunc)
    117       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Init");
    118   NSS_Shutdown = (NSSShutdownFunc)
    119       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "NSS_Shutdown");
    120   PK11_GetInternalKeySlot = (PK11GetInternalKeySlotFunc)
    121       base::GetFunctionPointerFromNativeLibrary(nss3_dll_,
    122                                                 "PK11_GetInternalKeySlot");
    123   PK11_FreeSlot = (PK11FreeSlotFunc)
    124       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_FreeSlot");
    125   PK11_Authenticate = (PK11AuthenticateFunc)
    126       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11_Authenticate");
    127   PK11SDR_Decrypt = (PK11SDRDecryptFunc)
    128       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "PK11SDR_Decrypt");
    129   SECITEM_FreeItem = (SECITEMFreeItemFunc)
    130       base::GetFunctionPointerFromNativeLibrary(nss3_dll_, "SECITEM_FreeItem");
    131   PL_ArenaFinish = (PLArenaFinishFunc)
    132       base::GetFunctionPointerFromNativeLibrary(plds4_dll, "PL_ArenaFinish");
    133   PR_Cleanup = (PRCleanupFunc)
    134       base::GetFunctionPointerFromNativeLibrary(nspr4_dll, "PR_Cleanup");
    135 
    136   if (NSS_Init == NULL || NSS_Shutdown == NULL ||
    137       PK11_GetInternalKeySlot == NULL || PK11_FreeSlot == NULL ||
    138       PK11_Authenticate == NULL || PK11SDR_Decrypt == NULL ||
    139       SECITEM_FreeItem == NULL || PL_ArenaFinish == NULL ||
    140       PR_Cleanup == NULL) {
    141     Free();
    142     return false;
    143   }
    144 
    145   SECStatus result = NSS_Init(base::SysWideToNativeMB(db_path.value()).c_str());
    146   if (result != SECSuccess) {
    147     Free();
    148     return false;
    149   }
    150 
    151   is_nss_initialized_ = true;
    152   return true;
    153 }
    154 
    155 void NSSDecryptor::Free() {
    156   if (is_nss_initialized_) {
    157     NSS_Shutdown();
    158     PL_ArenaFinish();
    159     PR_Cleanup();
    160     is_nss_initialized_ = false;
    161   }
    162   if (softokn3_dll_ != NULL)
    163     base::UnloadNativeLibrary(softokn3_dll_);
    164   if (nss3_dll_ != NULL)
    165     base::UnloadNativeLibrary(nss3_dll_);
    166   NSS_Init = NULL;
    167   NSS_Shutdown = NULL;
    168   PK11_GetInternalKeySlot = NULL;
    169   PK11_FreeSlot = NULL;
    170   PK11_Authenticate = NULL;
    171   PK11SDR_Decrypt = NULL;
    172   SECITEM_FreeItem = NULL;
    173   PL_ArenaFinish = NULL;
    174   PR_Cleanup = NULL;
    175   nss3_dll_ = NULL;
    176   softokn3_dll_ = NULL;
    177 }
    178