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