Commit 2fbc58cf authored by teor's avatar teor
Browse files

Windows: fix uname on recent Windows versions

Correctly identify Windows 8.1, Windows 10, and Windows Server 2008
and later from their NT versions.

On recent Windows versions, the GetVersionEx() function may report
an earlier Windows version than the running OS. To avoid user
confusion, add "[or later]" to Tor's version string on affected
versions of Windows.

Remove Windows versions that were never supported by the
GetVersionEx() function.

Stop duplicating the latest Windows version in get_uname().

Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
parent 7f042cbc
o Minor bugfixes (Windows):
- Correctly identify Windows 8.1, Windows 10, and Windows Server 2008
and later from their NT versions.
Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
- On recent Windows versions, the GetVersionEx() function may report
an earlier Windows version than the running OS. To avoid user
confusion, add "[or later]" to Tor's version string on affected
versions of Windows.
Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
- Remove Windows versions that were never supported by the
GetVersionEx() function. Stop duplicating the latest Windows
version in get_uname().
Fixes bug 28096; bugfix on 0.2.2.34; reported by Keifer Bly.
......@@ -2689,22 +2689,33 @@ MOCK_IMPL(const char *, get_uname, (void))
#ifdef _WIN32
OSVERSIONINFOEX info;
int i;
int is_client = 0;
int is_server = 0;
const char *plat = NULL;
static struct {
unsigned major; unsigned minor; const char *version;
unsigned major; unsigned minor;
const char *client_version; const char *server_version;
} win_version_table[] = {
{ 6, 2, "Windows 8" },
{ 6, 1, "Windows 7" },
{ 6, 0, "Windows Vista" },
{ 5, 2, "Windows Server 2003" },
{ 5, 1, "Windows XP" },
{ 5, 0, "Windows 2000" },
/* { 4, 0, "Windows NT 4.0" }, */
{ 4, 90, "Windows Me" },
{ 4, 10, "Windows 98" },
/* { 4, 0, "Windows 95" } */
{ 3, 51, "Windows NT 3.51" },
{ 0, 0, NULL }
/* This table must be sorted in descending order.
* Sources:
* https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
* https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
* ns-winnt-_osversioninfoexa#remarks
*/
/* Windows Server 2019 is indistinguishable from Windows Server 2016
* using GetVersionEx().
{ 10, 0, NULL, "Windows Server 2019" }, */
{ 10, 0, "Windows 10", "Windows Server 2016" },
{ 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
{ 6, 2, "Windows 8", "Windows Server 2012" },
{ 6, 1, "Windows 7", "Windows Server 2008 R2" },
{ 6, 0, "Windows Vista", "Windows Server 2008" },
{ 5, 2, "Windows XP Professional", "Windows Server 2003" },
/* Windows XP did not have a server version, but we need something here */
{ 5, 1, "Windows XP", "Windows XP Server" },
{ 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
/* Earlier versions are not supported by GetVersionEx(). */
{ 0, 0, NULL, NULL }
};
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
......@@ -2714,25 +2725,34 @@ MOCK_IMPL(const char *, get_uname, (void))
uname_result_is_set = 1;
return uname_result;
}
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
else
plat = "Windows 95";
#ifdef VER_NT_SERVER
if (info.wProductType == VER_NT_SERVER ||
info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
is_server = 1;
} else {
for (i=0; win_version_table[i].major>0; ++i) {
if (win_version_table[i].major == info.dwMajorVersion &&
win_version_table[i].minor == info.dwMinorVersion) {
plat = win_version_table[i].version;
break;
is_client = 1;
}
#endif
/* Search the version table for a matching version */
for (i=0; win_version_table[i].major>0; ++i) {
if (win_version_table[i].major == info.dwMajorVersion &&
win_version_table[i].minor == info.dwMinorVersion) {
if (is_server) {
plat = win_version_table[i].server_version;
} else {
/* Use client versions for clients, and when we don't know if it
* is a client or a server. */
plat = win_version_table[i].client_version;
}
break;
}
}
if (plat) {
strlcpy(uname_result, plat, sizeof(uname_result));
} else {
if (info.dwMajorVersion > 6 ||
(info.dwMajorVersion==6 && info.dwMinorVersion>2))
if (info.dwMajorVersion > win_version_table[0].major ||
(info.dwMajorVersion == win_version_table[0].major &&
info.dwMinorVersion > win_version_table[0].minor))
tor_snprintf(uname_result, sizeof(uname_result),
"Very recent version of Windows [major=%d,minor=%d]",
(int)info.dwMajorVersion,(int)info.dwMinorVersion);
......@@ -2741,12 +2761,25 @@ MOCK_IMPL(const char *, get_uname, (void))
"Unrecognized version of Windows [major=%d,minor=%d]",
(int)info.dwMajorVersion,(int)info.dwMinorVersion);
}
#ifdef VER_NT_SERVER
if (info.wProductType == VER_NT_SERVER ||
info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
strlcat(uname_result, " [server]", sizeof(uname_result));
}
#endif
/* Now append extra information to the name.
*
* Microsoft's API documentation says that on Windows 8.1 and later,
* GetVersionEx returns Windows 8 (6.2) for applications without an
* app compatibility manifest (including tor's default build).
*
* But in our testing, we have seen the actual Windows version on
* Windows Server 2012 R2, even without a manifest. */
if (info.dwMajorVersion > 6 ||
(info.dwMajorVersion == 6 && info.dwMinorVersion >= 2)) {
/* When GetVersionEx() returns Windows 8, the actual OS may be any
* later version. */
strlcat(uname_result, " [or later]", sizeof(uname_result));
}
/* When we don't know if the OS is a client or server version, we use
* the client version, and this qualifier. */
if (!is_server && !is_client) {
strlcat(uname_result, " [client or server]", sizeof(uname_result));
}
#else
/* LCOV_EXCL_START -- can't provoke uname failure */
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment