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