diff options
author | Masatoshi Kimura <VYV03354@nifty.ne.jp> | 2017-12-29 21:57:34 +0900 |
---|---|---|
committer | Masatoshi Kimura <VYV03354@nifty.ne.jp> | 2017-12-29 21:57:34 +0900 |
commit | caffe4cb2452782c0938c198095ff8b81f639adc (patch) | |
tree | f44afc7a106833e9fcd4cc75318beb58d7cddea8 | |
parent | 57bdcd5d3e1df03bcac189cf25c9ba4ebe0d4bf5 (diff) | |
download | nss-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.cc | 34 | ||||
-rw-r--r-- | lib/softoken/sdb.c | 33 | ||||
-rw-r--r-- | lib/softoken/sdb.h | 4 | ||||
-rw-r--r-- | lib/softoken/sftkdb.c | 68 | ||||
-rw-r--r-- | lib/util/nssutil.def | 8 | ||||
-rw-r--r-- | lib/util/utilmod.c | 190 | ||||
-rw-r--r-- | lib/util/utilpars.h | 6 |
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_ */ |