Tor  0.4.7.0-alpha-dev
uname.c
Go to the documentation of this file.
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 
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 {
69 #ifdef HAVE_UNAME
70  struct utsname u;
71 #endif
72  if (!uname_result_is_set) {
73 #ifdef HAVE_UNAME
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));
77  } else
78 #endif /* defined(HAVE_UNAME) */
79  {
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));
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))
123  "Very recent version of Windows [major=%d,minor=%d]",
124  (int)info.dwMajorVersion,(int)info.dwMinorVersion);
125  else
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  strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
152  /* LCOV_EXCL_STOP */
153 #endif /* defined(_WIN32) */
154  }
156  }
157  return uname_result;
158 }
Header for compat_string.c.
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
Header for printf.c.
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
static int uname_result_is_set
Definition: uname.c:28
const char * get_uname(void)
Definition: uname.c:67
static char uname_result[256]
Definition: uname.c:26
Header for uname.c.