Bug 1427276 - Fix sdb to handle UTF-8 paths correctly on Windows. r=fkiefer NSS_3_35_BRANCH NSS_3_35_BETA1
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Fri, 29 Dec 2017 21:57:34 +0900
branchNSS_3_35_BRANCH
changeset 14210 e34893b446f95ecde2a22d4744fe3448eeb7633a
parent 14206 16c622c9e1ccc60020ec1ac9b3a4a221c454778c
child 14211 1a685d98e6264211a2c3789147c6fc5d35d5c7e9
push id2955
push userkaie@kuix.de
push dateThu, 11 Jan 2018 12:15:46 +0000
reviewersfkiefer
bugs1427276
Bug 1427276 - Fix sdb to handle UTF-8 paths correctly on Windows. r=fkiefer
gtests/softoken_gtest/softoken_gtest.cc
lib/softoken/sdb.c
lib/softoken/sdb.h
lib/softoken/sftkdb.c
lib/util/nssutil.def
lib/util/utilmod.c
lib/util/utilpars.h
--- a/gtests/softoken_gtest/softoken_gtest.cc
+++ b/gtests/softoken_gtest/softoken_gtest.cc
@@ -1,9 +1,13 @@
 #include <cstdlib>
+#if defined(_WIN32)
+#include <windows.h>
+#include <codecvt>
+#endif
 
 #include "cert.h"
 #include "certdb.h"
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
 #include "secerr.h"
 
@@ -29,23 +33,25 @@ namespace nss_test {
 class ScopedUniqueDirectory {
  public:
   explicit ScopedUniqueDirectory(const std::string &prefix);
 
   // NB: the directory must be empty upon destruction
   ~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
 
   const std::string &GetPath() { return mPath; }
+  const std::string &GetUTF8Path() { return mUTF8Path; }
 
  private:
   static const int RETRY_LIMIT = 5;
   static void GenerateRandomName(/*in/out*/ std::string &prefix);
   static bool TryMakingDirectory(/*in/out*/ std::string &prefix);
 
   std::string mPath;
+  std::string mUTF8Path;
 };
 
 ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string &prefix) {
   std::string path;
   const char *workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
   if (workingDirectory) {
     path.assign(workingDirectory);
   }
@@ -55,16 +61,28 @@ ScopedUniqueDirectory::ScopedUniqueDirec
     // TryMakingDirectory will modify its input. If it fails, we want to throw
     // away the modified result.
     if (TryMakingDirectory(pathCopy)) {
       mPath.assign(pathCopy);
       break;
     }
   }
   assert(mPath.length() > 0);
+#if defined(_WIN32)
+  // sqldb always uses UTF-8 regardless of the current system locale.
+  DWORD len =
+      MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), nullptr, 0);
+  std::vector<wchar_t> buf(len, L'\0');
+  MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), buf.data(),
+                      buf.size());
+  std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
+  mUTF8Path = converter.to_bytes(std::wstring(buf.begin(), buf.end()));
+#else
+  mUTF8Path = mPath;
+#endif
 }
 
 void ScopedUniqueDirectory::GenerateRandomName(std::string &prefix) {
   std::stringstream ss;
   ss << prefix;
   // RAND_MAX is at least 32767.
   ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
   // This will overwrite the value of prefix. This is a little inefficient, but
@@ -79,20 +97,21 @@ bool ScopedUniqueDirectory::TryMakingDir
 #else
   return mkdir(prefix.c_str(), 0777) == 0;
 #endif
 }
 
 class SoftokenTest : public ::testing::Test {
  protected:
   SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
+  SoftokenTest(const std::string &prefix) : mNSSDBDir(prefix) {}
 
   virtual void SetUp() {
     std::string nssInitArg("sql:");
-    nssInitArg.append(mNSSDBDir.GetPath());
+    nssInitArg.append(mNSSDBDir.GetUTF8Path());
     ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
                                          NSS_INIT_NOROOTINIT));
   }
 
   virtual void TearDown() {
     ASSERT_EQ(SECSuccess, NSS_Shutdown());
     const std::string &nssDBDirPath = mNSSDBDir.GetPath();
     ASSERT_EQ(0, unlink((nssDBDirPath + "/cert9.db").c_str()));
@@ -197,16 +216,29 @@ TEST_F(SoftokenTest, CreateObjectChangeT
   EXPECT_EQ(SEC_ERROR_TOKEN_NOT_LOGGED_IN, PORT_GetError());
   ScopedPK11GenericObject obj(PK11_CreateGenericObject(
       slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
   // Because there's no password we can't logout and the operation should have
   // succeeded.
   EXPECT_NE(nullptr, obj);
 }
 
+class SoftokenNonAsciiTest : public SoftokenTest {
+ protected:
+  SoftokenNonAsciiTest() : SoftokenTest("SoftokenTest.\xF7-") {}
+};
+
+TEST_F(SoftokenNonAsciiTest, NonAsciiPathWorking) {
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+  EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
+  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+}
+
 // This is just any X509 certificate. Its contents don't matter.
 static unsigned char certDER[] = {
     0x30, 0x82, 0x01, 0xEF, 0x30, 0x82, 0x01, 0x94, 0xA0, 0x03, 0x02, 0x01,
     0x02, 0x02, 0x14, 0x49, 0xC4, 0xC4, 0x4A, 0xB6, 0x86, 0x07, 0xA3, 0x06,
     0xDC, 0x4D, 0xC8, 0xC3, 0xFE, 0xC7, 0x21, 0x3A, 0x2D, 0xE4, 0xDA, 0x30,
     0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
     0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C,
     0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31,
--- a/lib/softoken/sdb.c
+++ b/lib/softoken/sdb.c
@@ -32,16 +32,17 @@
 #include "prsystem.h" /* for PR_GetDirectorySeparator() */
 #include <sys/stat.h>
 #if defined(_WIN32)
 #include <io.h>
 #include <windows.h>
 #elif defined(XP_UNIX)
 #include <unistd.h>
 #endif
+#include "utilpars.h"
 
 #ifdef SQLITE_UNSAFE_THREADS
 #include "prlock.h"
 /*
  * SQLite can be compiled to be thread safe or not.
  * turn on SQLITE_UNSAFE_THREADS if the OS does not support
  * a thread safe version of sqlite.
  */
@@ -185,16 +186,44 @@ sdb_done(int err, int *count)
     }
     /* err == SQLITE_BUSY, Dont' retry forever in this case */
     if (++(*count) >= SDB_MAX_BUSY_RETRIES) {
         return 1;
     }
     return 0;
 }
 
+#if defined(_WIN32)
+/*
+ * NSPR functions and narrow CRT functions do not handle UTF-8 file paths that
+ * sqlite3 expects.
+ */
+
+static int
+sdb_chmod(const char *filename, int pmode)
+{
+    int result;
+
+    if (!filename) {
+        return -1;
+    }
+
+    wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
+    if (!filenameWide) {
+        return -1;
+    }
+    result = _wchmod(filenameWide, pmode);
+    PORT_Free(filenameWide);
+
+    return result;
+}
+#else
+#define sdb_chmod(filename, pmode) chmod((filename), (pmode))
+#endif
+
 /*
  * find out where sqlite stores the temp tables. We do this by replicating
  * the logic from sqlite.
  */
 #if defined(_WIN32)
 static char *
 sdb_getFallbackTempDir(void)
 {
@@ -1734,34 +1763,34 @@ sdb_init(char *dbname, char *table, sdbD
     *pSdb = NULL;
     *inUpdate = 0;
 
     /* sqlite3 doesn't have a flag to specify that we want to
      * open the database read only. If the db doesn't exist,
      * sqlite3 will always create it.
      */
     LOCK_SQLITE();
-    create = (PR_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS);
+    create = (_NSSUTIL_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS);
     if ((flags == SDB_RDONLY) && create) {
         error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
         goto loser;
     }
     sqlerr = sdb_openDB(dbname, &sqlDB, flags);
     if (sqlerr != SQLITE_OK) {
         error = sdb_mapSQLError(type, sqlerr);
         goto loser;
     }
 
     /*
      * SQL created the file, but it doesn't set appropriate modes for
      * a database.
      *
      * NO NSPR call for chmod? :(
      */
-    if (create && chmod(dbname, 0600) != 0) {
+    if (create && sdb_chmod(dbname, 0600) != 0) {
         error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
         goto loser;
     }
 
     if (flags != SDB_RDONLY) {
         sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL);
         if (sqlerr != SQLITE_OK) {
             error = sdb_mapSQLError(type, sqlerr);
--- a/lib/softoken/sdb.h
+++ b/lib/softoken/sdb.h
@@ -78,16 +78,20 @@ struct SDBStr {
 };
 
 CK_RV s_open(const char *directory, const char *certPrefix,
              const char *keyPrefix,
              int cert_version, int key_version,
              int flags, SDB **certdb, SDB **keydb, int *newInit);
 CK_RV s_shutdown();
 
+#if defined(_WIN32)
+wchar_t *sdb_UTF8ToWide(const char *buf);
+#endif
+
 /* flags */
 #define SDB_RDONLY 1
 #define SDB_RDWR 2
 #define SDB_CREATE 4
 #define SDB_HAS_META 8
 #define SDB_FIPS 0x10
 
 #endif
--- a/lib/softoken/sftkdb.c
+++ b/lib/softoken/sftkdb.c
@@ -23,16 +23,19 @@
 #include "pkcs11i.h"
 #include "sdb.h"
 #include "prprf.h"
 #include "pratom.h"
 #include "lgglue.h"
 #include "utilpars.h"
 #include "secerr.h"
 #include "softoken.h"
+#if defined(_WIN32)
+#include <windows.h>
+#endif
 
 /*
  * We want all databases to have the same binary representation independent of
  * endianness or length of the host architecture. In general PKCS #11 attributes
  * are endian/length independent except those attributes that pass CK_ULONG.
  *
  * The following functions fixes up the CK_ULONG type attributes so that the data
  * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
@@ -2504,16 +2507,63 @@ sftk_oldVersionExists(const char *dir, i
         PR_smprintf_free(file);
         if (exists == PR_SUCCESS) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
 }
 
+#if defined(_WIN32)
+/*
+ * Convert an sdb path (encoded in UTF-8) to a legacy path (encoded in the
+ * current system codepage). Fails if the path contains a character outside
+ * the current system codepage.
+ */
+static char *
+sftk_legacyPathFromSDBPath(const char *confdir)
+{
+    wchar_t *confdirWide;
+    DWORD size;
+    char *nconfdir;
+    BOOL unmappable;
+
+    if (!confdir) {
+        return NULL;
+    }
+    confdirWide = _NSSUTIL_UTF8ToWide(confdir);
+    if (!confdirWide) {
+        return NULL;
+    }
+
+    size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
+                               NULL, 0, NULL, &unmappable);
+    if (size == 0 || unmappable) {
+        PORT_Free(confdirWide);
+        return NULL;
+    }
+    nconfdir = PORT_Alloc(sizeof(char) * size);
+    if (!nconfdir) {
+        PORT_Free(confdirWide);
+        return NULL;
+    }
+    size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
+                               nconfdir, size, NULL, &unmappable);
+    PORT_Free(confdirWide);
+    if (size == 0 || unmappable) {
+        PORT_Free(nconfdir);
+        return NULL;
+    }
+
+    return nconfdir;
+}
+#else
+#define sftk_legacyPathFromSDBPath(confdir) PORT_Strdup((confdir))
+#endif
+
 static PRBool
 sftk_hasLegacyDB(const char *confdir, const char *certPrefix,
                  const char *keyPrefix, int certVersion, int keyVersion)
 {
     char *dir;
     PRBool exists;
 
     if (certPrefix == NULL) {
@@ -2563,16 +2613,17 @@ sftk_DBInit(const char *configdir, const
     const char *confdir;
     NSSDBType dbType = NSS_DB_TYPE_NONE;
     char *appName = NULL;
     SDB *keySDB, *certSDB;
     CK_RV crv = CKR_OK;
     int flags = SDB_RDONLY;
     PRBool newInit = PR_FALSE;
     PRBool needUpdate = PR_FALSE;
+    char *nconfdir = NULL;
 
     if (!readOnly) {
         flags = SDB_CREATE;
     }
     if (isFIPS) {
         flags |= SDB_FIPS;
     }
 
@@ -2601,21 +2652,24 @@ sftk_DBInit(const char *configdir, const
             crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
                          noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
 
             /*
              * if we failed to open the DB's read only, use the old ones if
              * the exists.
              */
             if (crv != CKR_OK) {
-                if (((flags & SDB_RDONLY) == SDB_RDONLY) &&
-                    sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
+                if ((flags & SDB_RDONLY) == SDB_RDONLY) {
+                    nconfdir = sftk_legacyPathFromSDBPath(confdir);
+                }
+                if (nconfdir &&
+                    sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
                     /* we have legacy databases, if we failed to open the new format
                      * DB's read only, just use the legacy ones */
-                    crv = sftkdbCall_open(confdir, certPrefix,
+                    crv = sftkdbCall_open(nconfdir, certPrefix,
                                           keyPrefix, 8, 3, flags,
                                           noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
                 }
                 /* Handle the database merge case.
                  *
                  * For the merge case, we need help from the application. Only
                  * the application knows where the old database is, and what unique
                  * identifier it has associated with it.
@@ -2634,17 +2688,20 @@ sftk_DBInit(const char *configdir, const
                 confdir = updatedir;
                 certPrefix = updCertPrefix;
                 keyPrefix = updKeyPrefix;
                 needUpdate = PR_TRUE;
             } else if (newInit) {
                 /* if the new format DB was also a newly created DB, and we
                  * succeeded, then need to update that new database with data
                  * from the existing legacy DB */
-                if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
+                nconfdir = sftk_legacyPathFromSDBPath(confdir);
+                if (nconfdir &&
+                    sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
+                    confdir = nconfdir;
                     needUpdate = PR_TRUE;
                 }
             }
             break;
         default:
             crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST
                                       * return one of the types we already
                                       * specified. */
@@ -2707,16 +2764,19 @@ sftk_DBInit(const char *configdir, const
                 sftkdb_Update(*certDB, NULL);
             }
         }
     }
 done:
     if (appName) {
         PORT_Free(appName);
     }
+    if (nconfdir) {
+        PORT_Free(nconfdir);
+    }
     return forceOpen ? CKR_OK : crv;
 }
 
 CK_RV
 sftkdb_Shutdown(void)
 {
     s_shutdown();
     sftkdbCall_Shutdown();
--- a/lib/util/nssutil.def
+++ b/lib/util/nssutil.def
@@ -310,8 +310,16 @@ PK11URI_GetQueryAttribute;
 ;+NSSUTIL_3.33 {         # NSS Utilities 3.33 release
 ;+    global:
 PORT_ZAllocAligned_Util;
 PORT_ZAllocAlignedOffset_Util;
 NSS_SecureMemcmpZero;
 ;+    local:
 ;+       *;
 ;+};
+;-NSSUTIL_3.35 {         # NSS Utilities 3.35 release
+;-    global:
+;-# private exports for softoken
+_NSSUTIL_UTF8ToWide;-
+_NSSUTIL_Access;-
+;-    local:
+;-       *;
+;-};
--- a/lib/util/utilmod.c
+++ b/lib/util/utilmod.c
@@ -19,43 +19,215 @@
 #include "prprf.h"
 #include "prsystem.h"
 #include "secport.h"
 #include "utilpars.h"
 #include "secerr.h"
 
 #if defined(_WIN32)
 #include <io.h>
+#include <windows.h>
 #endif
 #ifdef XP_UNIX
 #include <unistd.h>
 #endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 
 #if defined(_WIN32)
-#define os_open _open
 #define os_fdopen _fdopen
-#define os_stat _stat
 #define os_truncate_open_flags _O_CREAT | _O_RDWR | _O_TRUNC
 #define os_append_open_flags _O_CREAT | _O_RDWR | _O_APPEND
 #define os_open_permissions_type int
 #define os_open_permissions_default _S_IREAD | _S_IWRITE
 #define os_stat_type struct _stat
+
+/*
+ * Convert a UTF8 string to Unicode wide character
+ */
+LPWSTR
+_NSSUTIL_UTF8ToWide(const char *buf)
+{
+    DWORD size;
+    LPWSTR wide;
+
+    if (!buf) {
+        return NULL;
+    }
+
+    size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0);
+    if (size == 0) {
+        return NULL;
+    }
+    wide = PORT_Alloc(sizeof(WCHAR) * size);
+    if (!wide) {
+        return NULL;
+    }
+    size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size);
+    if (size == 0) {
+        PORT_Free(wide);
+        return NULL;
+    }
+    return wide;
+}
+
+static int
+os_open(const char *filename, int oflag, int pmode)
+{
+    int fd;
+
+    if (!filename) {
+        return -1;
+    }
+
+    wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
+    if (!filenameWide) {
+        return -1;
+    }
+    fd = _wopen(filenameWide, oflag, pmode);
+    PORT_Free(filenameWide);
+
+    return fd;
+}
+
+static int
+os_stat(const char *path, os_stat_type *buffer)
+{
+    int result;
+
+    if (!path) {
+        return -1;
+    }
+
+    wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path);
+    if (!pathWide) {
+        return -1;
+    }
+    result = _wstat(pathWide, buffer);
+    PORT_Free(pathWide);
+
+    return result;
+}
+
+static FILE *
+os_fopen(const char *filename, const char *mode)
+{
+    FILE *fp;
+
+    if (!filename || !mode) {
+        return NULL;
+    }
+
+    wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
+    if (!filenameWide) {
+        return NULL;
+    }
+    wchar_t *modeWide = _NSSUTIL_UTF8ToWide(mode);
+    if (!modeWide) {
+        PORT_Free(filenameWide);
+        return NULL;
+    }
+    fp = _wfopen(filenameWide, modeWide);
+    PORT_Free(filenameWide);
+    PORT_Free(modeWide);
+
+    return fp;
+}
+
+PRStatus
+_NSSUTIL_Access(const char *path, PRAccessHow how)
+{
+    int result;
+
+    if (!path) {
+        return PR_FAILURE;
+    }
+
+    int mode;
+    switch (how) {
+        case PR_ACCESS_WRITE_OK:
+            mode = 2;
+            break;
+        case PR_ACCESS_READ_OK:
+            mode = 4;
+            break;
+        case PR_ACCESS_EXISTS:
+            mode = 0;
+            break;
+        default:
+            return PR_FAILURE;
+    }
+
+    wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path);
+    if (!pathWide) {
+        return PR_FAILURE;
+    }
+    result = _waccess(pathWide, mode);
+    PORT_Free(pathWide);
+
+    return result < 0 ? PR_FAILURE : PR_SUCCESS;
+}
+
+static PRStatus
+nssutil_Delete(const char *name)
+{
+    BOOL result;
+
+    if (!name) {
+        return PR_FAILURE;
+    }
+
+    wchar_t *nameWide = _NSSUTIL_UTF8ToWide(name);
+    if (!nameWide) {
+        return PR_FAILURE;
+    }
+    result = DeleteFileW(nameWide);
+    PORT_Free(nameWide);
+
+    return result ? PR_SUCCESS : PR_FAILURE;
+}
+
+static PRStatus
+nssutil_Rename(const char *from, const char *to)
+{
+    BOOL result;
+
+    if (!from || !to) {
+        return PR_FAILURE;
+    }
+
+    wchar_t *fromWide = _NSSUTIL_UTF8ToWide(from);
+    if (!fromWide) {
+        return PR_FAILURE;
+    }
+    wchar_t *toWide = _NSSUTIL_UTF8ToWide(to);
+    if (!toWide) {
+        PORT_Free(fromWide);
+        return PR_FAILURE;
+    }
+    result = MoveFileW(fromWide, toWide);
+    PORT_Free(fromWide);
+    PORT_Free(toWide);
+
+    return result ? PR_SUCCESS : PR_FAILURE;
+}
 #else
+#define os_fopen fopen
 #define os_open open
 #define os_fdopen fdopen
 #define os_stat stat
 #define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC
 #define os_append_open_flags O_CREAT | O_RDWR | O_APPEND
 #define os_open_permissions_type mode_t
 #define os_open_permissions_default 0600
 #define os_stat_type struct stat
+#define nssutil_Delete PR_Delete
+#define nssutil_Rename PR_Rename
 #endif
 
 /****************************************************************
  *
  * Secmod database.
  *
  * The new secmod database is simply a text file with each of the module
  * entries in the following form:
@@ -214,17 +386,17 @@ nssutil_ReadSecmodDB(const char *appName
     if (moduleList == NULL)
         return NULL;
 
     if (dbname == NULL) {
         goto return_default;
     }
 
     /* do we really want to use streams here */
-    fd = fopen(dbname, "r");
+    fd = os_fopen(dbname, "r");
     if (fd == NULL)
         goto done;
 
     /*
      * the following loop takes line separated config lines and collapses
      * the lines to a single string, escaping and quoting as necessary.
      */
     /* loop state variables */
@@ -398,17 +570,17 @@ done:
         PRStatus status;
 
         /* couldn't get the old name */
         if (!olddbname) {
             goto bail;
         }
 
         /* old one exists */
-        status = PR_Access(olddbname, PR_ACCESS_EXISTS);
+        status = _NSSUTIL_Access(olddbname, PR_ACCESS_EXISTS);
         if (status == PR_SUCCESS) {
             PR_smprintf_free(olddbname);
             PORT_ZFree(moduleList, useCount * sizeof(char *));
             PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
             return NULL;
         }
 
     bail:
@@ -527,17 +699,17 @@ nssutil_DeleteSecmodDBEntry(const char *
     /* get the permissions of the existing file, or use the default */
     if (!os_stat(dbname, &stat_existing)) {
         file_mode = stat_existing.st_mode;
     } else {
         file_mode = os_open_permissions_default;
     }
 
     /* do we really want to use streams here */
-    fd = fopen(dbname, "r");
+    fd = os_fopen(dbname, "r");
     if (fd == NULL)
         goto loser;
 
     fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
 
     if (fd2 == NULL)
         goto loser;
 
@@ -597,36 +769,36 @@ nssutil_DeleteSecmodDBEntry(const char *
         }
         /* we are definately not in a deleted block anymore */
         skip = PR_FALSE;
     }
     fclose(fd);
     fclose(fd2);
     if (found) {
         /* rename dbname2 to dbname */
-        PR_Delete(dbname);
-        PR_Rename(dbname2, dbname);
+        nssutil_Delete(dbname);
+        nssutil_Rename(dbname2, dbname);
     } else {
-        PR_Delete(dbname2);
+        nssutil_Delete(dbname2);
     }
     PORT_Free(dbname2);
     PORT_Free(lib);
     PORT_Free(name);
     PORT_Free(block);
     return SECSuccess;
 
 loser:
     if (fd != NULL) {
         fclose(fd);
     }
     if (fd2 != NULL) {
         fclose(fd2);
     }
     if (dbname2) {
-        PR_Delete(dbname2);
+        nssutil_Delete(dbname2);
         PORT_Free(dbname2);
     }
     PORT_Free(lib);
     PORT_Free(name);
     return SECFailure;
 }
 
 /*
--- a/lib/util/utilpars.h
+++ b/lib/util/utilpars.h
@@ -54,10 +54,16 @@ char *NSSUTIL_MkNSSString(char **slotStr
                           unsigned long cipherOrder, unsigned long ssl0, unsigned long ssl1);
 
 /*
  * private functions for softoken.
  */
 char *_NSSUTIL_GetSecmodName(const char *param, NSSDBType *dbType,
                              char **appName, char **filename, PRBool *rw);
 const char *_NSSUTIL_EvaluateConfigDir(const char *configdir, NSSDBType *dbType, char **app);
+#if defined(_WIN32)
+wchar_t *_NSSUTIL_UTF8ToWide(const char *buf);
+PRStatus _NSSUTIL_Access(const char *path, PRAccessHow how);
+#else
+#define _NSSUTIL_Access(path, how) PR_Access((path), (how))
+#endif
 
 #endif /* _UTILPARS_H_ */