/src/tor/src/lib/osinfo/uname.c
Line | Count | Source |
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 */ |
5 | | |
6 | | /** |
7 | | * \file uname.c |
8 | | * \brief Look up a description of the operating system. |
9 | | **/ |
10 | | |
11 | | #include "orconfig.h" |
12 | | #include "lib/osinfo/uname.h" |
13 | | |
14 | | #include "lib/string/compat_string.h" |
15 | | #include "lib/string/printf.h" |
16 | | |
17 | | #ifdef HAVE_UNAME |
18 | | #include <sys/utsname.h> |
19 | | #endif |
20 | | #ifdef _WIN32 |
21 | | #include <windows.h> |
22 | | #endif |
23 | | #include <string.h> |
24 | | |
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; |
29 | | |
30 | | #ifdef _WIN32 |
31 | | /** Table to map claimed windows versions into human-readable windows |
32 | | * versions. */ |
33 | | static struct { |
34 | | unsigned major; |
35 | | unsigned minor; |
36 | | const char *client_version; |
37 | | const char *server_version; |
38 | | } win_version_table[] = { |
39 | | /* This table must be sorted in descending order. |
40 | | * Sources: |
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 |
44 | | */ |
45 | | /* Windows Server 2019 is indistinguishable from Windows Server 2016 |
46 | | * using GetVersionEx(). |
47 | | { 10, 0, NULL, "Windows Server 2019" }, */ |
48 | | // clang-format off |
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(). */ |
59 | | { 0, 0, NULL, NULL } |
60 | | // clang-format on |
61 | | }; |
62 | | #endif /* defined(_WIN32) */ |
63 | | |
64 | | /** Return a pointer to a description of our platform. |
65 | | */ |
66 | | MOCK_IMPL(const char *, |
67 | | get_uname,(void)) |
68 | 0 | { |
69 | 0 | #ifdef HAVE_UNAME |
70 | 0 | struct utsname u; |
71 | 0 | #endif |
72 | 0 | if (!uname_result_is_set) { |
73 | 0 | #ifdef HAVE_UNAME |
74 | 0 | if (uname(&u) != -1) { |
75 | | /* (Linux says 0 is success, Solaris says 1 is success) */ |
76 | 0 | strlcpy(uname_result, u.sysname, sizeof(uname_result)); |
77 | 0 | } else |
78 | 0 | #endif /* defined(HAVE_UNAME) */ |
79 | 0 | { |
80 | | #ifdef _WIN32 |
81 | | OSVERSIONINFOEX info; |
82 | | int i; |
83 | | int is_client = 0; |
84 | | int is_server = 0; |
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; |
92 | | return uname_result; |
93 | | } |
94 | | #ifdef VER_NT_SERVER |
95 | | if (info.wProductType == VER_NT_SERVER || |
96 | | info.wProductType == VER_NT_DOMAIN_CONTROLLER) { |
97 | | is_server = 1; |
98 | | } else { |
99 | | is_client = 1; |
100 | | } |
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) { |
106 | | if (is_server) { |
107 | | plat = win_version_table[i].server_version; |
108 | | } else { |
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; |
112 | | } |
113 | | break; |
114 | | } |
115 | | } |
116 | | if (plat) { |
117 | | strlcpy(uname_result, plat, sizeof(uname_result)); |
118 | | } else { |
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); |
125 | | else |
126 | | tor_snprintf(uname_result, sizeof(uname_result), |
127 | | "Unrecognized version of Windows [major=%d,minor=%d]", |
128 | | (int)info.dwMajorVersion,(int)info.dwMinorVersion); |
129 | | } |
130 | | /* Now append extra information to the name. |
131 | | * |
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). |
135 | | * |
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 |
141 | | * later version. */ |
142 | | strlcat(uname_result, " [or later]", sizeof(uname_result)); |
143 | | } |
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)); |
148 | | } |
149 | | #else /* !defined(_WIN32) */ |
150 | | /* LCOV_EXCL_START -- can't provoke uname failure */ |
151 | 0 | strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); |
152 | | /* LCOV_EXCL_STOP */ |
153 | 0 | #endif /* defined(_WIN32) */ |
154 | 0 | } |
155 | 0 | uname_result_is_set = 1; |
156 | 0 | } |
157 | 0 | return uname_result; |
158 | 0 | } |