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