1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
8 * \brief Look up a description of the operating system.
12 #include "lib/osinfo/uname.h"
14 #include "lib/string/compat_string.h"
15 #include "lib/string/printf.h"
18 #include <sys/utsname.h>
25 /** Hold the result of our call to <b>uname</b>. */
26 static char uname_result
[256];
27 /** True iff uname_result is set. */
28 static int uname_result_is_set
= 0;
31 /** Table to map claimed windows versions into human-readable windows
36 const char *client_version
;
37 const char *server_version
;
38 } win_version_table
[] = {
39 /* This table must be sorted in descending order.
41 * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions
42 * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/
43 * ns-winnt-_osversioninfoexa#remarks
45 /* Windows Server 2019 is indistinguishable from Windows Server 2016
46 * using GetVersionEx().
47 { 10, 0, NULL, "Windows Server 2019" }, */
49 { 10, 0, "Windows 10", "Windows Server 2016" },
50 { 6, 3, "Windows 8.1", "Windows Server 2012 R2" },
51 { 6, 2, "Windows 8", "Windows Server 2012" },
52 { 6, 1, "Windows 7", "Windows Server 2008 R2" },
53 { 6, 0, "Windows Vista", "Windows Server 2008" },
54 { 5, 2, "Windows XP Professional", "Windows Server 2003" },
55 /* Windows XP did not have a server version, but we need something here */
56 { 5, 1, "Windows XP", "Windows XP Server" },
57 { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" },
58 /* Earlier versions are not supported by GetVersionEx(). */
62 #endif /* defined(_WIN32) */
64 /** Return a pointer to a description of our platform.
66 MOCK_IMPL(const char *,
72 if (!uname_result_is_set
) {
74 if (uname(&u
) != -1) {
75 /* (Linux says 0 is success, Solaris says 1 is success) */
76 strlcpy(uname_result
, u
.sysname
, sizeof(uname_result
));
78 #endif /* defined(HAVE_UNAME) */
85 const char *plat
= NULL
;
86 memset(&info
, 0, sizeof(info
));
87 info
.dwOSVersionInfoSize
= sizeof(info
);
88 if (! GetVersionEx((LPOSVERSIONINFO
)&info
)) {
89 strlcpy(uname_result
, "Bizarre version of Windows where GetVersionEx"
90 " doesn't work.", sizeof(uname_result
));
91 uname_result_is_set
= 1;
95 if (info
.wProductType
== VER_NT_SERVER
||
96 info
.wProductType
== VER_NT_DOMAIN_CONTROLLER
) {
101 #endif /* defined(VER_NT_SERVER) */
102 /* Search the version table for a matching version */
103 for (i
=0; win_version_table
[i
].major
>0; ++i
) {
104 if (win_version_table
[i
].major
== info
.dwMajorVersion
&&
105 win_version_table
[i
].minor
== info
.dwMinorVersion
) {
107 plat
= win_version_table
[i
].server_version
;
109 /* Use client versions for clients, and when we don't know if it
110 * is a client or a server. */
111 plat
= win_version_table
[i
].client_version
;
117 strlcpy(uname_result
, plat
, sizeof(uname_result
));
119 if (info
.dwMajorVersion
> win_version_table
[0].major
||
120 (info
.dwMajorVersion
== win_version_table
[0].major
&&
121 info
.dwMinorVersion
> win_version_table
[0].minor
))
122 tor_snprintf(uname_result
, sizeof(uname_result
),
123 "Very recent version of Windows [major=%d,minor=%d]",
124 (int)info
.dwMajorVersion
,(int)info
.dwMinorVersion
);
126 tor_snprintf(uname_result
, sizeof(uname_result
),
127 "Unrecognized version of Windows [major=%d,minor=%d]",
128 (int)info
.dwMajorVersion
,(int)info
.dwMinorVersion
);
130 /* Now append extra information to the name.
132 * Microsoft's API documentation says that on Windows 8.1 and later,
133 * GetVersionEx returns Windows 8 (6.2) for applications without an
134 * app compatibility manifest (including tor's default build).
136 * But in our testing, we have seen the actual Windows version on
137 * Windows Server 2012 R2, even without a manifest. */
138 if (info
.dwMajorVersion
> 6 ||
139 (info
.dwMajorVersion
== 6 && info
.dwMinorVersion
>= 2)) {
140 /* When GetVersionEx() returns Windows 8, the actual OS may be any
142 strlcat(uname_result
, " [or later]", sizeof(uname_result
));
144 /* When we don't know if the OS is a client or server version, we use
145 * the client version, and this qualifier. */
146 if (!is_server
&& !is_client
) {
147 strlcat(uname_result
, " [client or server]", sizeof(uname_result
));
149 #else /* !defined(_WIN32) */
150 /* LCOV_EXCL_START -- can't provoke uname failure */
151 strlcpy(uname_result
, "Unknown platform", sizeof(uname_result
));
153 #endif /* defined(_WIN32) */
155 uname_result_is_set
= 1;