summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>2017-12-29 21:57:34 +0900
committerMasatoshi Kimura <VYV03354@nifty.ne.jp>2017-12-29 21:57:34 +0900
commitcaffe4cb2452782c0938c198095ff8b81f639adc (patch)
treef44afc7a106833e9fcd4cc75318beb58d7cddea8
parent57bdcd5d3e1df03bcac189cf25c9ba4ebe0d4bf5 (diff)
downloadnss-hg-caffe4cb2452782c0938c198095ff8b81f639adc.tar.gz
Bug 1427276 - Fix sdb to handle UTF-8 paths correctly on Windows. r=fkieferNSS_3_35_BETA1
-rw-r--r--gtests/softoken_gtest/softoken_gtest.cc34
-rw-r--r--lib/softoken/sdb.c33
-rw-r--r--lib/softoken/sdb.h4
-rw-r--r--lib/softoken/sftkdb.c68
-rw-r--r--lib/util/nssutil.def8
-rw-r--r--lib/util/utilmod.c190
-rw-r--r--lib/util/utilpars.h6
7 files changed, 327 insertions, 16 deletions
diff --git a/gtests/softoken_gtest/softoken_gtest.cc b/gtests/softoken_gtest/softoken_gtest.cc
index 9b9927a74..d61e2e75f 100644
--- a/gtests/softoken_gtest/softoken_gtest.cc
+++ b/gtests/softoken_gtest/softoken_gtest.cc
@@ -1,4 +1,8 @@
#include <cstdlib>
+#if defined(_WIN32)
+#include <windows.h>
+#include <codecvt>
+#endif
#include "cert.h"
#include "certdb.h"
@@ -34,6 +38,7 @@ class ScopedUniqueDirectory {
~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;
@@ -41,6 +46,7 @@ class ScopedUniqueDirectory {
static bool TryMakingDirectory(/*in/out*/ std::string &prefix);
std::string mPath;
+ std::string mUTF8Path;
};
ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string &prefix) {
@@ -60,6 +66,18 @@ ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string &prefix) {
}
}
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) {
@@ -84,10 +102,11 @@ bool ScopedUniqueDirectory::TryMakingDirectory(std::string &prefix) {
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));
}
@@ -202,6 +221,19 @@ TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
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,
diff --git a/lib/softoken/sdb.c b/lib/softoken/sdb.c
index 57337e334..96717cb26 100644
--- a/lib/softoken/sdb.c
+++ b/lib/softoken/sdb.c
@@ -37,6 +37,7 @@
#elif defined(XP_UNIX)
#include <unistd.h>
#endif
+#include "utilpars.h"
#ifdef SQLITE_UNSAFE_THREADS
#include "prlock.h"
@@ -190,6 +191,34 @@ sdb_done(int err, int *count)
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.
@@ -1739,7 +1768,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
* 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;
@@ -1756,7 +1785,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
*
* 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;
}
diff --git a/lib/softoken/sdb.h b/lib/softoken/sdb.h
index 04b873e02..8ff254bf7 100644
--- a/lib/softoken/sdb.h
+++ b/lib/softoken/sdb.h
@@ -83,6 +83,10 @@ CK_RV s_open(const char *directory, const char *certPrefix,
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
diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
index 716f62c0b..2ae084068 100644
--- a/lib/softoken/sftkdb.c
+++ b/lib/softoken/sftkdb.c
@@ -28,6 +28,9 @@
#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
@@ -2509,6 +2512,53 @@ sftk_oldVersionExists(const char *dir, int version)
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)
@@ -2568,6 +2618,7 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
int flags = SDB_RDONLY;
PRBool newInit = PR_FALSE;
PRBool needUpdate = PR_FALSE;
+ char *nconfdir = NULL;
if (!readOnly) {
flags = SDB_CREATE;
@@ -2606,11 +2657,14 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
* 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);
}
@@ -2639,7 +2693,10 @@ sftk_DBInit(const char *configdir, const char *certPrefix,
/* 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;
}
}
@@ -2712,6 +2769,9 @@ done:
if (appName) {
PORT_Free(appName);
}
+ if (nconfdir) {
+ PORT_Free(nconfdir);
+ }
return forceOpen ? CKR_OK : crv;
}
diff --git a/lib/util/nssutil.def b/lib/util/nssutil.def
index 4159b786f..936455f6e 100644
--- a/lib/util/nssutil.def
+++ b/lib/util/nssutil.def
@@ -315,3 +315,11 @@ NSS_SecureMemcmpZero;
;+ local:
;+ *;
;+};
+;-NSSUTIL_3.35 { # NSS Utilities 3.35 release
+;- global:
+;-# private exports for softoken
+_NSSUTIL_UTF8ToWide;-
+_NSSUTIL_Access;-
+;- local:
+;- *;
+;-};
diff --git a/lib/util/utilmod.c b/lib/util/utilmod.c
index 971b6c1dc..7d3fcda81 100644
--- a/lib/util/utilmod.c
+++ b/lib/util/utilmod.c
@@ -24,6 +24,7 @@
#if defined(_WIN32)
#include <io.h>
+#include <windows.h>
#endif
#ifdef XP_UNIX
#include <unistd.h>
@@ -34,15 +35,184 @@
#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
@@ -51,6 +221,8 @@
#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
/****************************************************************
@@ -219,7 +391,7 @@ nssutil_ReadSecmodDB(const char *appName,
}
/* do we really want to use streams here */
- fd = fopen(dbname, "r");
+ fd = os_fopen(dbname, "r");
if (fd == NULL)
goto done;
@@ -403,7 +575,7 @@ done:
}
/* 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 *));
@@ -532,7 +704,7 @@ nssutil_DeleteSecmodDBEntry(const char *appName,
}
/* do we really want to use streams here */
- fd = fopen(dbname, "r");
+ fd = os_fopen(dbname, "r");
if (fd == NULL)
goto loser;
@@ -602,10 +774,10 @@ nssutil_DeleteSecmodDBEntry(const char *appName,
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);
@@ -621,7 +793,7 @@ loser:
fclose(fd2);
}
if (dbname2) {
- PR_Delete(dbname2);
+ nssutil_Delete(dbname2);
PORT_Free(dbname2);
}
PORT_Free(lib);
diff --git a/lib/util/utilpars.h b/lib/util/utilpars.h
index 70767263a..1b0b1ff1c 100644
--- a/lib/util/utilpars.h
+++ b/lib/util/utilpars.h
@@ -59,5 +59,11 @@ char *NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
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_ */