tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

uname.c (5937B)


      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 {
     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));
     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        strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
    152        /* LCOV_EXCL_STOP */
    153 #endif /* defined(_WIN32) */
    154      }
    155    uname_result_is_set = 1;
    156  }
    157  return uname_result;
    158 }