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/FileFind.h"
11#include "../../../Windows/FileIO.h"
12#include "../../../Windows/PropVariantConv.h"
13
14#include "../../PropID.h"
15
16#include "PropIDUtils.h"
17
18#define Get16(x) GetUi16(x)
19#define Get32(x) GetUi32(x)
20
21using namespace NWindows;
22
23static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_";
24/*
250 READONLY
261 HIDDEN
272 SYSTEM
28
294 DIRECTORY
305 ARCHIVE
316 DEVICE
327 NORMAL
338 TEMPORARY
349 SPARSE_FILE
3510 REPARSE_POINT
3611 COMPRESSED
3712 OFFLINE
3813 NOT_CONTENT_INDEXED
3914 ENCRYPTED
40
4116 VIRTUAL
42*/
43
44void ConvertWinAttribToString(char *s, UInt32 wa)
45{
46  for (int i = 0; i < 16; i++)
47    if ((wa & (1 << i)) && i != 7)
48      *s++ = g_WinAttribChars[i];
49  *s = 0;
50}
51
52static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
53#define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-';
54
55void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw()
56{
57  *dest = 0;
58  if (prop.vt == VT_FILETIME)
59  {
60    FILETIME localFileTime;
61    if ((prop.filetime.dwHighDateTime == 0 &&
62        prop.filetime.dwLowDateTime == 0) ||
63        !::FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
64      return;
65    ConvertFileTimeToString(localFileTime, dest, true, full);
66    return;
67  }
68  switch (propID)
69  {
70    case kpidCRC:
71    {
72      if (prop.vt != VT_UI4)
73        break;
74      ConvertUInt32ToHex8Digits(prop.ulVal, dest);
75      return;
76    }
77    case kpidAttrib:
78    {
79      if (prop.vt != VT_UI4)
80        break;
81      ConvertWinAttribToString(dest, prop.ulVal);
82      return;
83    }
84    case kpidPosixAttrib:
85    {
86      if (prop.vt != VT_UI4)
87        break;
88      UString res;
89      UInt32 a = prop.ulVal;
90
91      dest[0] = kPosixTypes[(a >> 12) & 0xF];
92      for (int i = 6; i >= 0; i -= 3)
93      {
94        dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
95        dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
96        dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
97      }
98      if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S');
99      if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S');
100      if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T');
101      dest[10] = 0;
102
103      a &= ~(UInt32)0xFFFF;
104      if (a != 0)
105      {
106        dest[10] = ' ';
107        ConvertUInt32ToHex8Digits(a, dest + 11);
108      }
109      return;
110    }
111    case kpidINode:
112    {
113      if (prop.vt != VT_UI8)
114        break;
115      ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
116      dest += strlen(dest);
117      *dest++ = '-';
118      UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
119      ConvertUInt64ToString(low, dest);
120      return;
121    }
122    case kpidVa:
123    {
124      UInt64 v = 0;
125      if (ConvertPropVariantToUInt64(prop, v))
126      {
127        dest[0] = '0';
128        dest[1] = 'x';
129        ConvertUInt64ToHex(prop.ulVal, dest + 2);
130        return;
131      }
132      break;
133    }
134  }
135  ConvertPropVariantToShortString(prop, dest);
136}
137
138void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full)
139{
140  if (prop.vt == VT_BSTR)
141  {
142    dest = prop.bstrVal;
143    return;
144  }
145  char temp[64];
146  ConvertPropertyToShortString(temp, prop, propID, full);
147  int len = MyStringLen(temp);
148  wchar_t *str = dest.GetBuffer(len);
149  for (int i = 0; i < len; i++)
150    str[i] = temp[i];
151  dest.ReleaseBuffer(len);
152}
153
154static inline char GetHex(Byte value)
155{
156  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
157}
158
159#ifndef _SFX
160
161static inline void AddHexToString(AString &res, Byte value)
162{
163  res += GetHex((Byte)(value >> 4));
164  res += GetHex((Byte)(value & 0xF));
165  res += ' ';
166}
167
168/*
169static AString Data_To_Hex(const Byte *data, size_t size)
170{
171  AString s;
172  for (size_t i = 0; i < size; i++)
173    AddHexToString(s, data[i]);
174  return s;
175}
176*/
177
178static const char *sidNames[] =
179{
180  "0",
181  "Dialup",
182  "Network",
183  "Batch",
184  "Interactive",
185  "Logon",  // S-1-5-5-X-Y
186  "Service",
187  "Anonymous",
188  "Proxy",
189  "EnterpriseDC",
190  "Self",
191  "AuthenticatedUsers",
192  "RestrictedCode",
193  "TerminalServer",
194  "RemoteInteractiveLogon",
195  "ThisOrganization",
196  "16",
197  "IUserIIS",
198  "LocalSystem",
199  "LocalService",
200  "NetworkService",
201  "Domains"
202};
203
204struct CSecID2Name
205{
206  UInt32 n;
207  const char *sz;
208};
209
210const CSecID2Name sid_32_Names[] =
211{
212  { 544, "Administrators" },
213  { 545, "Users" },
214  { 546, "Guests" },
215  { 547, "PowerUsers" },
216  { 548, "AccountOperators" },
217  { 549, "ServerOperators" },
218  { 550, "PrintOperators" },
219  { 551, "BackupOperators" },
220  { 552, "Replicators" },
221  { 553, "Backup Operators" },
222  { 554, "PreWindows2000CompatibleAccess" },
223  { 555, "RemoteDesktopUsers" },
224  { 556, "NetworkConfigurationOperators" },
225  { 557, "IncomingForestTrustBuilders" },
226  { 558, "PerformanceMonitorUsers" },
227  { 559, "PerformanceLogUsers" },
228  { 560, "WindowsAuthorizationAccessGroup" },
229  { 561, "TerminalServerLicenseServers" },
230  { 562, "DistributedCOMUsers" },
231  { 569, "CryptographicOperators" },
232  { 573, "EventLogReaders" },
233  { 574, "CertificateServiceDCOMAccess" }
234};
235
236static const CSecID2Name sid_21_Names[] =
237{
238  { 500, "Administrator" },
239  { 501, "Guest" },
240  { 502, "KRBTGT" },
241  { 512, "DomainAdmins" },
242  { 513, "DomainUsers" },
243  { 515, "DomainComputers" },
244  { 516, "DomainControllers" },
245  { 517, "CertPublishers" },
246  { 518, "SchemaAdmins" },
247  { 519, "EnterpriseAdmins" },
248  { 520, "GroupPolicyCreatorOwners" },
249  { 553, "RASandIASServers" },
250  { 553, "RASandIASServers" },
251  { 571, "AllowedRODCPasswordReplicationGroup" },
252  { 572, "DeniedRODCPasswordReplicationGroup" }
253};
254
255struct CServicesToName
256{
257  UInt32 n[5];
258  const char *sz;
259};
260
261static const CServicesToName services_to_name[] =
262{
263  { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
264};
265
266static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
267{
268  sidSize = 0;
269  if (lim < 8)
270  {
271    s += "ERROR";
272    return;
273  }
274  UInt32 rev = p[0];
275  if (rev != 1)
276  {
277    s += "UNSUPPORTED";
278    return;
279  }
280  UInt32 num = p[1];
281  if (8 + num * 4 > lim)
282  {
283    s += "ERROR";
284    return;
285  }
286  sidSize = 8 + num * 4;
287  UInt32 authority = GetBe32(p + 4);
288
289  if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
290  {
291    UInt32 v0 = Get32(p + 8);
292    if (v0 < ARRAY_SIZE(sidNames))
293    {
294      s += sidNames[v0];
295      return;
296    }
297    if (v0 == 32 && num == 2)
298    {
299      UInt32 v1 = Get32(p + 12);
300      for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++)
301        if (sid_32_Names[i].n == v1)
302        {
303          s += sid_32_Names[i].sz;
304          return;
305        }
306    }
307    if (v0 == 21 && num == 5)
308    {
309      UInt32 v4 = Get32(p + 8 + 4 * 4);
310      for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++)
311        if (sid_21_Names[i].n == v4)
312        {
313          s += sid_21_Names[i].sz;
314          return;
315        }
316    }
317    if (v0 == 80 && num == 6)
318    {
319      for (int i = 0; i < ARRAY_SIZE(services_to_name); i++)
320      {
321        const CServicesToName &sn = services_to_name[i];
322        int j;
323        for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
324        if (j == 5)
325        {
326          s += sn.sz;
327          return;
328        }
329      }
330    }
331  }
332
333  char sz[16];
334  s += "S-1-";
335  if (p[2] == 0 && p[3] == 0)
336  {
337    ConvertUInt32ToString(authority, sz);
338    s += sz;
339  }
340  else
341  {
342    s += "0x";
343    for (int i = 2; i < 8; i++)
344      AddHexToString(s, p[i]);
345  }
346  for (UInt32 i = 0; i < num; i++)
347  {
348    s += '-';
349    ConvertUInt32ToString(Get32(p + 8 + i * 4), sz);
350    s += sz;
351  }
352}
353
354static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
355{
356  if (pos > size)
357  {
358    s += "ERROR";
359    return;
360  }
361  UInt32 sidSize = 0;
362  ParseSid(s, p + pos, size - pos, sidSize);
363}
364
365static void AddUInt32ToString(AString &s, UInt32 val)
366{
367  char sz[16];
368  ConvertUInt32ToString(val, sz);
369  s += sz;
370}
371
372static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
373{
374  UInt32 control = Get16(p + 2);
375  if ((flags & control) == 0)
376    return;
377  UInt32 pos = Get32(p + offset);
378  s += ' ';
379  s += strName;
380  if (pos >= size)
381    return;
382  p += pos;
383  size -= pos;
384  if (size < 8)
385    return;
386  if (Get16(p) != 2) // revision
387    return;
388  // UInt32 aclSize = Get16(p + 2);
389  UInt32 num = Get32(p + 4);
390  AddUInt32ToString(s, num);
391  /*
392  if (num >= (1 << 16))
393    return;
394  if (aclSize > size)
395    return;
396  size = aclSize;
397  size -= 8;
398  p += 8;
399  for (UInt32 i = 0 ; i < num; i++)
400  {
401    if (size <= 8)
402      return;
403    // Byte type = p[0];
404    // Byte flags = p[1];
405    // UInt32 aceSize = Get16(p + 2);
406    // UInt32 mask = Get32(p + 4);
407    p += 8;
408    size -= 8;
409
410    UInt32 sidSize = 0;
411    s += ' ';
412    s += ParseSid(p, size, sidSize);
413    if (sidSize == 0)
414      return;
415    p += sidSize;
416    size -= sidSize;
417  }
418  if (size != 0)
419    s += " ERROR";
420  */
421}
422
423#define MY_SE_OWNER_DEFAULTED       (0x0001)
424#define MY_SE_GROUP_DEFAULTED       (0x0002)
425#define MY_SE_DACL_PRESENT          (0x0004)
426#define MY_SE_DACL_DEFAULTED        (0x0008)
427#define MY_SE_SACL_PRESENT          (0x0010)
428#define MY_SE_SACL_DEFAULTED        (0x0020)
429#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
430#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
431#define MY_SE_DACL_AUTO_INHERITED   (0x0400)
432#define MY_SE_SACL_AUTO_INHERITED   (0x0800)
433#define MY_SE_DACL_PROTECTED        (0x1000)
434#define MY_SE_SACL_PROTECTED        (0x2000)
435#define MY_SE_RM_CONTROL_VALID      (0x4000)
436#define MY_SE_SELF_RELATIVE         (0x8000)
437
438void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
439{
440  s.Empty();
441  if (size < 20 || size > (1 << 18))
442  {
443    s += "ERROR";
444    return;
445  }
446  if (Get16(data) != 1) // revision
447  {
448    s += "UNSUPPORTED";
449    return;
450  }
451  ParseOwner(s, data, size, Get32(data + 4));
452  s += ' ';
453  ParseOwner(s, data, size, Get32(data + 8));
454  ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
455  ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
456  s += ' ';
457  AddUInt32ToString(s, size);
458  // s += '\n';
459  // s += Data_To_Hex(data, size);
460}
461
462#ifdef _WIN32
463
464static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos)
465{
466  if (pos >= size)
467    return false;
468  size -= pos;
469  if (size < 8)
470    return false;
471  UInt32 rev = data[pos];
472  if (rev != 1)
473    return false;
474  UInt32 num = data[pos + 1];
475  return (8 + num * 4 <= size);
476}
477
478static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset)
479{
480  UInt32 control = Get16(p + 2);
481  if ((flags & control) == 0)
482    return true;
483  UInt32 pos = Get32(p + offset);
484  if (pos >= size)
485    return false;
486  p += pos;
487  size -= pos;
488  if (size < 8)
489    return false;
490  UInt32 aclSize = Get16(p + 2);
491  return (aclSize <= size);
492}
493
494bool CheckNtSecure(const Byte *data, UInt32 size)
495{
496  if (size < 20)
497    return false;
498  if (Get16(data) != 1) // revision
499    return true; // windows function can handle such error, so we allow it
500  if (size > (1 << 18))
501    return false;
502  if (!CheckSid(data, size, Get32(data + 4))) return false;
503  if (!CheckSid(data, size, Get32(data + 8))) return false;
504  if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
505  if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
506  return true;
507}
508
509#endif
510
511bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
512{
513  s.Empty();
514  NFile::CReparseAttr attr;
515  if (attr.Parse(data, size))
516  {
517    if (!attr.IsSymLink())
518      s += L"Junction: ";
519    s += attr.GetPath();
520    if (!attr.IsOkNamePair())
521    {
522      s += L" : ";
523      s += attr.PrintName;
524    }
525    return true;
526  }
527
528  if (size < 8)
529    return false;
530  UInt32 tag = Get32(data);
531  UInt32 len = Get16(data + 4);
532  if (len + 8 > size)
533    return false;
534  if (Get16(data + 6) != 0) // padding
535    return false;
536
537  char hex[16];
538  ConvertUInt32ToHex8Digits(tag, hex);
539  s.AddAsciiStr(hex);
540  s += L' ';
541
542  data += 8;
543
544  for (UInt32 i = 0; i < len; i++)
545  {
546    Byte b = ((const Byte *)data)[i];
547    s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF));
548    s += (wchar_t)GetHex((Byte)(b & 0xF));
549  }
550  return true;
551}
552
553#endif
554