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 
21 using namespace NWindows;
22 
23 static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_";
24 /*
25 0 READONLY
26 1 HIDDEN
27 2 SYSTEM
28 
29 4 DIRECTORY
30 5 ARCHIVE
31 6 DEVICE
32 7 NORMAL
33 8 TEMPORARY
34 9 SPARSE_FILE
35 10 REPARSE_POINT
36 11 COMPRESSED
37 12 OFFLINE
38 13 NOT_CONTENT_INDEXED
39 14 ENCRYPTED
40 
41 16 VIRTUAL
42 */
43 
ConvertWinAttribToString(char * s,UInt32 wa)44 void 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 
52 static 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 
ConvertPropertyToShortString(char * dest,const PROPVARIANT & prop,PROPID propID,bool full)55 void 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 
ConvertPropertyToString(UString & dest,const PROPVARIANT & prop,PROPID propID,bool full)138 void 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 
GetHex(Byte value)154 static inline char GetHex(Byte value)
155 {
156   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
157 }
158 
159 #ifndef _SFX
160 
AddHexToString(AString & res,Byte value)161 static 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 /*
169 static 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 
178 static 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 
204 struct CSecID2Name
205 {
206   UInt32 n;
207   const char *sz;
208 };
209 
210 const 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 
236 static 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 
255 struct CServicesToName
256 {
257   UInt32 n[5];
258   const char *sz;
259 };
260 
261 static const CServicesToName services_to_name[] =
262 {
263   { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
264 };
265 
ParseSid(AString & s,const Byte * p,UInt32 lim,UInt32 & sidSize)266 static 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 
ParseOwner(AString & s,const Byte * p,UInt32 size,UInt32 pos)354 static 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 
AddUInt32ToString(AString & s,UInt32 val)365 static void AddUInt32ToString(AString &s, UInt32 val)
366 {
367   char sz[16];
368   ConvertUInt32ToString(val, sz);
369   s += sz;
370 }
371 
ParseAcl(AString & s,const Byte * p,UInt32 size,const char * strName,UInt32 flags,UInt32 offset)372 static 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 
ConvertNtSecureToString(const Byte * data,UInt32 size,AString & s)438 void 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 
CheckSid(const Byte * data,UInt32 size,UInt32 pos)464 static 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 
CheckAcl(const Byte * p,UInt32 size,UInt32 flags,UInt32 offset)478 static 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 
CheckNtSecure(const Byte * data,UInt32 size)494 bool 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 
ConvertNtReparseToString(const Byte * data,UInt32 size,UString & s)511 bool 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