tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PropIDUtils.cpp (15012B)


      1 // PropIDUtils.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../../../C/CpuArch.h"
      6 
      7 #include "../../../Common/IntToString.h"
      8 #include "../../../Common/StringConvert.h"
      9 
     10 #include "../../../Windows/FileIO.h"
     11 #include "../../../Windows/PropVariantConv.h"
     12 
     13 #include "../../PropID.h"
     14 
     15 #include "PropIDUtils.h"
     16 
     17 #define Get16(x) GetUi16(x)
     18 #define Get32(x) GetUi32(x)
     19 
     20 using namespace NWindows;
     21 
     22 static const unsigned kNumWinAtrribFlags = 21;
     23 static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU";
     24 
     25 /*
     26 FILE_ATTRIBUTE_
     27 
     28 0 READONLY
     29 1 HIDDEN
     30 2 SYSTEM
     31 3 (Volume label - obsolete)
     32 4 DIRECTORY
     33 5 ARCHIVE
     34 6 DEVICE
     35 7 NORMAL
     36 8 TEMPORARY
     37 9 SPARSE_FILE
     38 10 REPARSE_POINT
     39 11 COMPRESSED
     40 12 OFFLINE
     41 13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer)
     42 14 ENCRYPTED
     43 15 INTEGRITY_STREAM (V - ReFS Win8/Win2012)
     44 16 VIRTUAL (reserved)
     45 17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib)
     46 18 RECALL_ON_OPEN or EA
     47 19 PINNED
     48 20 UNPINNED
     49 21 STRICTLY_SEQUENTIAL
     50 22 RECALL_ON_DATA_ACCESS
     51 */
     52 
     53 
     54 static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
     55 #define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-';
     56 
     57 static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
     58 {
     59  s[0] = kPosixTypes[(a >> 12) & 0xF];
     60  for (int i = 6; i >= 0; i -= 3)
     61  {
     62    s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
     63    s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
     64    s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
     65  }
     66  if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S');
     67  if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S');
     68  if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T');
     69  s[10] = 0;
     70  
     71  a &= ~(UInt32)0xFFFF;
     72  if (a != 0)
     73  {
     74    s[10] = ' ';
     75    ConvertUInt32ToHex8Digits(a, s + 11);
     76  }
     77 }
     78 
     79 
     80 void ConvertWinAttribToString(char *s, UInt32 wa) throw()
     81 {
     82  /*
     83  some programs store posix attributes in high 16 bits.
     84  p7zip - stores additional 0x8000 flag marker.
     85  macos - stores additional 0x4000 flag marker.
     86  info-zip - no additional marker.
     87  */
     88  
     89  bool isPosix = ((wa & 0xF0000000) != 0);
     90  
     91  UInt32 posix = 0;
     92  if (isPosix)
     93  {
     94    posix = wa >> 16;
     95    wa &= (UInt32)0x3FFF;
     96  }
     97 
     98  for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
     99  {
    100    UInt32 flag = (1 << i);
    101    if ((wa & flag) != 0)
    102    {
    103      char c = g_WinAttribChars[i];
    104      if (c != '.')
    105      {
    106        wa &= ~flag;
    107        // if (i != 7) // we can disable N (NORMAL) printing
    108        *s++ = c;
    109      }
    110    }
    111  }
    112  
    113  if (wa != 0)
    114  {
    115    *s++ = ' ';
    116    ConvertUInt32ToHex8Digits(wa, s);
    117    s += strlen(s);
    118  }
    119 
    120  *s = 0;
    121 
    122  if (isPosix)
    123  {
    124    *s++ = ' ';
    125    ConvertPosixAttribToString(s, posix);
    126  }
    127 }
    128 
    129 
    130 void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw()
    131 {
    132  *dest = 0;
    133  
    134  if (prop.vt == VT_FILETIME)
    135  {
    136    const FILETIME &ft = prop.filetime;
    137    if ((ft.dwHighDateTime == 0 &&
    138         ft.dwLowDateTime == 0))
    139      return;
    140    ConvertUtcFileTimeToString(prop.filetime, dest, level);
    141    return;
    142  }
    143 
    144  switch (propID)
    145  {
    146    case kpidCRC:
    147    {
    148      if (prop.vt != VT_UI4)
    149        break;
    150      ConvertUInt32ToHex8Digits(prop.ulVal, dest);
    151      return;
    152    }
    153    case kpidAttrib:
    154    {
    155      if (prop.vt != VT_UI4)
    156        break;
    157      UInt32 a = prop.ulVal;
    158 
    159      /*
    160      if ((a & 0x8000) && (a & 0x7FFF) == 0)
    161        ConvertPosixAttribToString(dest, a >> 16);
    162      else
    163      */
    164      ConvertWinAttribToString(dest, a);
    165      return;
    166    }
    167    case kpidPosixAttrib:
    168    {
    169      if (prop.vt != VT_UI4)
    170        break;
    171      ConvertPosixAttribToString(dest, prop.ulVal);
    172      return;
    173    }
    174    case kpidINode:
    175    {
    176      if (prop.vt != VT_UI8)
    177        break;
    178      ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
    179      dest += strlen(dest);
    180      *dest++ = '-';
    181      UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
    182      ConvertUInt64ToString(low, dest);
    183      return;
    184    }
    185    case kpidVa:
    186    {
    187      UInt64 v = 0;
    188      if (prop.vt == VT_UI4)
    189        v = prop.ulVal;
    190      else if (prop.vt == VT_UI8)
    191        v = (UInt64)prop.uhVal.QuadPart;
    192      else
    193        break;
    194      dest[0] = '0';
    195      dest[1] = 'x';
    196      ConvertUInt64ToHex(v, dest + 2);
    197      return;
    198    }
    199  }
    200  
    201  ConvertPropVariantToShortString(prop, dest);
    202 }
    203 
    204 void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level)
    205 {
    206  if (prop.vt == VT_BSTR)
    207  {
    208    dest.SetFromBstr(prop.bstrVal);
    209    return;
    210  }
    211  char temp[64];
    212  ConvertPropertyToShortString2(temp, prop, propID, level);
    213  dest = temp;
    214 }
    215 
    216 static inline unsigned GetHex(unsigned v)
    217 {
    218  return (v < 10) ? ('0' + v) : ('A' + (v - 10));
    219 }
    220 
    221 #ifndef _SFX
    222 
    223 static inline void AddHexToString(AString &res, unsigned v)
    224 {
    225  res += (char)GetHex(v >> 4);
    226  res += (char)GetHex(v & 0xF);
    227 }
    228 
    229 /*
    230 static AString Data_To_Hex(const Byte *data, size_t size)
    231 {
    232  AString s;
    233  for (size_t i = 0; i < size; i++)
    234    AddHexToString(s, data[i]);
    235  return s;
    236 }
    237 */
    238 
    239 static const char * const sidNames[] =
    240 {
    241    "0"
    242  , "Dialup"
    243  , "Network"
    244  , "Batch"
    245  , "Interactive"
    246  , "Logon"  // S-1-5-5-X-Y
    247  , "Service"
    248  , "Anonymous"
    249  , "Proxy"
    250  , "EnterpriseDC"
    251  , "Self"
    252  , "AuthenticatedUsers"
    253  , "RestrictedCode"
    254  , "TerminalServer"
    255  , "RemoteInteractiveLogon"
    256  , "ThisOrganization"
    257  , "16"
    258  , "IUserIIS"
    259  , "LocalSystem"
    260  , "LocalService"
    261  , "NetworkService"
    262  , "Domains"
    263 };
    264 
    265 struct CSecID2Name
    266 {
    267  UInt32 n;
    268  const char *sz;
    269 };
    270 
    271 static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id)
    272 {
    273  for (unsigned i = 0; i < num; i++)
    274    if (pairs[i].n == id)
    275      return i;
    276  return -1;
    277 }
    278 
    279 static const CSecID2Name sid_32_Names[] =
    280 {
    281  { 544, "Administrators" },
    282  { 545, "Users" },
    283  { 546, "Guests" },
    284  { 547, "PowerUsers" },
    285  { 548, "AccountOperators" },
    286  { 549, "ServerOperators" },
    287  { 550, "PrintOperators" },
    288  { 551, "BackupOperators" },
    289  { 552, "Replicators" },
    290  { 553, "Backup Operators" },
    291  { 554, "PreWindows2000CompatibleAccess" },
    292  { 555, "RemoteDesktopUsers" },
    293  { 556, "NetworkConfigurationOperators" },
    294  { 557, "IncomingForestTrustBuilders" },
    295  { 558, "PerformanceMonitorUsers" },
    296  { 559, "PerformanceLogUsers" },
    297  { 560, "WindowsAuthorizationAccessGroup" },
    298  { 561, "TerminalServerLicenseServers" },
    299  { 562, "DistributedCOMUsers" },
    300  { 569, "CryptographicOperators" },
    301  { 573, "EventLogReaders" },
    302  { 574, "CertificateServiceDCOMAccess" }
    303 };
    304 
    305 static const CSecID2Name sid_21_Names[] =
    306 {
    307  { 500, "Administrator" },
    308  { 501, "Guest" },
    309  { 502, "KRBTGT" },
    310  { 512, "DomainAdmins" },
    311  { 513, "DomainUsers" },
    312  { 515, "DomainComputers" },
    313  { 516, "DomainControllers" },
    314  { 517, "CertPublishers" },
    315  { 518, "SchemaAdmins" },
    316  { 519, "EnterpriseAdmins" },
    317  { 520, "GroupPolicyCreatorOwners" },
    318  { 553, "RASandIASServers" },
    319  { 553, "RASandIASServers" },
    320  { 571, "AllowedRODCPasswordReplicationGroup" },
    321  { 572, "DeniedRODCPasswordReplicationGroup" }
    322 };
    323 
    324 struct CServicesToName
    325 {
    326  UInt32 n[5];
    327  const char *sz;
    328 };
    329 
    330 static const CServicesToName services_to_name[] =
    331 {
    332  { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
    333 };
    334 
    335 static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
    336 {
    337  sidSize = 0;
    338  if (lim < 8)
    339  {
    340    s += "ERROR";
    341    return;
    342  }
    343  UInt32 rev = p[0];
    344  if (rev != 1)
    345  {
    346    s += "UNSUPPORTED";
    347    return;
    348  }
    349  UInt32 num = p[1];
    350  if (8 + num * 4 > lim)
    351  {
    352    s += "ERROR";
    353    return;
    354  }
    355  sidSize = 8 + num * 4;
    356  UInt32 authority = GetBe32(p + 4);
    357 
    358  if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
    359  {
    360    UInt32 v0 = Get32(p + 8);
    361    if (v0 < ARRAY_SIZE(sidNames))
    362    {
    363      s += sidNames[v0];
    364      return;
    365    }
    366    if (v0 == 32 && num == 2)
    367    {
    368      UInt32 v1 = Get32(p + 12);
    369      int index = FindPairIndex(sid_32_Names, ARRAY_SIZE(sid_32_Names), v1);
    370      if (index >= 0)
    371      {
    372        s += sid_32_Names[(unsigned)index].sz;
    373        return;
    374      }
    375    }
    376    if (v0 == 21 && num == 5)
    377    {
    378      UInt32 v4 = Get32(p + 8 + 4 * 4);
    379      int index = FindPairIndex(sid_21_Names, ARRAY_SIZE(sid_21_Names), v4);
    380      if (index >= 0)
    381      {
    382        s += sid_21_Names[(unsigned)index].sz;
    383        return;
    384      }
    385    }
    386    if (v0 == 80 && num == 6)
    387    {
    388      for (unsigned i = 0; i < ARRAY_SIZE(services_to_name); i++)
    389      {
    390        const CServicesToName &sn = services_to_name[i];
    391        int j;
    392        for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
    393        if (j == 5)
    394        {
    395          s += sn.sz;
    396          return;
    397        }
    398      }
    399    }
    400  }
    401  
    402  s += "S-1-";
    403  if (p[2] == 0 && p[3] == 0)
    404    s.Add_UInt32(authority);
    405  else
    406  {
    407    s += "0x";
    408    for (int i = 2; i < 8; i++)
    409      AddHexToString(s, p[i]);
    410  }
    411  for (UInt32 i = 0; i < num; i++)
    412  {
    413    s += '-';
    414    s.Add_UInt32(Get32(p + 8 + i * 4));
    415  }
    416 }
    417 
    418 static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
    419 {
    420  if (pos > size)
    421  {
    422    s += "ERROR";
    423    return;
    424  }
    425  UInt32 sidSize = 0;
    426  ParseSid(s, p + pos, size - pos, sidSize);
    427 }
    428 
    429 static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
    430 {
    431  UInt32 control = Get16(p + 2);
    432  if ((flags & control) == 0)
    433    return;
    434  UInt32 pos = Get32(p + offset);
    435  s.Add_Space();
    436  s += strName;
    437  if (pos >= size)
    438    return;
    439  p += pos;
    440  size -= pos;
    441  if (size < 8)
    442    return;
    443  if (Get16(p) != 2) // revision
    444    return;
    445  UInt32 num = Get32(p + 4);
    446  s.Add_UInt32(num);
    447  
    448  /*
    449  UInt32 aclSize = Get16(p + 2);
    450  if (num >= (1 << 16))
    451    return;
    452  if (aclSize > size)
    453    return;
    454  size = aclSize;
    455  size -= 8;
    456  p += 8;
    457  for (UInt32 i = 0 ; i < num; i++)
    458  {
    459    if (size <= 8)
    460      return;
    461    // Byte type = p[0];
    462    // Byte flags = p[1];
    463    // UInt32 aceSize = Get16(p + 2);
    464    // UInt32 mask = Get32(p + 4);
    465    p += 8;
    466    size -= 8;
    467 
    468    UInt32 sidSize = 0;
    469    s.Add_Space();
    470    ParseSid(s, p, size, sidSize);
    471    if (sidSize == 0)
    472      return;
    473    p += sidSize;
    474    size -= sidSize;
    475  }
    476 
    477  // the tail can contain zeros. So (size != 0) is not ERROR
    478  // if (size != 0) s += " ERROR";
    479  */
    480 }
    481 
    482 #define MY_SE_OWNER_DEFAULTED       (0x0001)
    483 #define MY_SE_GROUP_DEFAULTED       (0x0002)
    484 #define MY_SE_DACL_PRESENT          (0x0004)
    485 #define MY_SE_DACL_DEFAULTED        (0x0008)
    486 #define MY_SE_SACL_PRESENT          (0x0010)
    487 #define MY_SE_SACL_DEFAULTED        (0x0020)
    488 #define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
    489 #define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
    490 #define MY_SE_DACL_AUTO_INHERITED   (0x0400)
    491 #define MY_SE_SACL_AUTO_INHERITED   (0x0800)
    492 #define MY_SE_DACL_PROTECTED        (0x1000)
    493 #define MY_SE_SACL_PROTECTED        (0x2000)
    494 #define MY_SE_RM_CONTROL_VALID      (0x4000)
    495 #define MY_SE_SELF_RELATIVE         (0x8000)
    496 
    497 void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
    498 {
    499  s.Empty();
    500  if (size < 20 || size > (1 << 18))
    501  {
    502    s += "ERROR";
    503    return;
    504  }
    505  if (Get16(data) != 1) // revision
    506  {
    507    s += "UNSUPPORTED";
    508    return;
    509  }
    510  ParseOwner(s, data, size, Get32(data + 4));
    511  s.Add_Space();
    512  ParseOwner(s, data, size, Get32(data + 8));
    513  ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
    514  ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
    515  s.Add_Space();
    516  s.Add_UInt32(size);
    517  // s += '\n';
    518  // s += Data_To_Hex(data, size);
    519 }
    520 
    521 #ifdef _WIN32
    522 
    523 static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()
    524 {
    525  if (pos >= size)
    526    return false;
    527  size -= pos;
    528  if (size < 8)
    529    return false;
    530  UInt32 rev = data[pos];
    531  if (rev != 1)
    532    return false;
    533  UInt32 num = data[pos + 1];
    534  return (8 + num * 4 <= size);
    535 }
    536 
    537 static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()
    538 {
    539  UInt32 control = Get16(p + 2);
    540  if ((flags & control) == 0)
    541    return true;
    542  UInt32 pos = Get32(p + offset);
    543  if (pos >= size)
    544    return false;
    545  p += pos;
    546  size -= pos;
    547  if (size < 8)
    548    return false;
    549  UInt32 aclSize = Get16(p + 2);
    550  return (aclSize <= size);
    551 }
    552 
    553 bool CheckNtSecure(const Byte *data, UInt32 size) throw()
    554 {
    555  if (size < 20)
    556    return false;
    557  if (Get16(data) != 1) // revision
    558    return true; // windows function can handle such error, so we allow it
    559  if (size > (1 << 18))
    560    return false;
    561  if (!CheckSid(data, size, Get32(data + 4))) return false;
    562  if (!CheckSid(data, size, Get32(data + 8))) return false;
    563  if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
    564  if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
    565  return true;
    566 }
    567 
    568 #endif
    569 
    570 
    571 
    572 // IO_REPARSE_TAG_*
    573 
    574 static const CSecID2Name k_ReparseTags[] =
    575 {
    576  { 0xA0000003, "MOUNT_POINT" },
    577  { 0xC0000004, "HSM" },
    578  { 0x80000005, "DRIVE_EXTENDER" },
    579  { 0x80000006, "HSM2" },
    580  { 0x80000007, "SIS" },
    581  { 0x80000008, "WIM" },
    582  { 0x80000009, "CSV" },
    583  { 0x8000000A, "DFS" },
    584  { 0x8000000B, "FILTER_MANAGER" },
    585  { 0xA000000C, "SYMLINK" },
    586  { 0xA0000010, "IIS_CACHE" },
    587  { 0x80000012, "DFSR" },
    588  { 0x80000013, "DEDUP" },
    589  { 0xC0000014, "APPXSTRM" },
    590  { 0x80000014, "NFS" },
    591  { 0x80000015, "FILE_PLACEHOLDER" },
    592  { 0x80000016, "DFM" },
    593  { 0x80000017, "WOF" }
    594 };
    595 
    596 bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
    597 {
    598  s.Empty();
    599  NFile::CReparseAttr attr;
    600  DWORD errorCode = 0;
    601  if (attr.Parse(data, size, errorCode))
    602  {
    603    if (!attr.IsSymLink())
    604      s += "Junction: ";
    605    s += attr.GetPath();
    606    if (!attr.IsOkNamePair())
    607    {
    608      s += " : ";
    609      s += attr.PrintName;
    610    }
    611    return true;
    612  }
    613 
    614  if (size < 8)
    615    return false;
    616  UInt32 tag = Get32(data);
    617  UInt32 len = Get16(data + 4);
    618  if (len + 8 > size)
    619    return false;
    620  if (Get16(data + 6) != 0) // padding
    621    return false;
    622 
    623  /*
    624  #define _my_IO_REPARSE_TAG_DEDUP        (0x80000013L)
    625  if (tag == _my_IO_REPARSE_TAG_DEDUP)
    626  {
    627  }
    628  */
    629 
    630  {
    631    int index = FindPairIndex(k_ReparseTags, ARRAY_SIZE(k_ReparseTags), tag);
    632    if (index >= 0)
    633      s += k_ReparseTags[(unsigned)index].sz;
    634    else
    635    {
    636      s += "REPARSE:";
    637      char hex[16];
    638      ConvertUInt32ToHex8Digits(tag, hex);
    639      s += hex;
    640    }
    641  }
    642 
    643  s += ":";
    644  s.Add_UInt32(len);
    645 
    646  if (len != 0)
    647  {
    648    s.Add_Space();
    649    
    650    data += 8;
    651    
    652    for (UInt32 i = 0; i < len; i++)
    653    {
    654      if (i >= 8)
    655      {
    656        s += "...";
    657        break;
    658      }
    659      unsigned b = data[i];
    660      s += (char)GetHex((b >> 4) & 0xF);
    661      s += (char)GetHex(b & 0xF);
    662    }
    663  }
    664 
    665  return true;
    666 }
    667 
    668 #endif