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 20using namespace NWindows; 21 22static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_"; 23/* 240 READONLY 251 HIDDEN 262 SYSTEM 27 284 DIRECTORY 295 ARCHIVE 306 DEVICE 317 NORMAL 328 TEMPORARY 339 SPARSE_FILE 3410 REPARSE_POINT 3511 COMPRESSED 3612 OFFLINE 3713 NOT_CONTENT_INDEXED 3814 ENCRYPTED 39 4016 VIRTUAL 41*/ 42 43static 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 46static 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 68void 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 86void 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 161void 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 173static inline unsigned GetHex(unsigned v) 174{ 175 return (v < 10) ? ('0' + v) : ('A' + (v - 10)); 176} 177 178#ifndef _SFX 179 180static 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/* 188static 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 197static 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 223struct CSecID2Name 224{ 225 UInt32 n; 226 const char *sz; 227}; 228 229static 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 255static 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 274struct CServicesToName 275{ 276 UInt32 n[5]; 277 const char *sz; 278}; 279 280static const CServicesToName services_to_name[] = 281{ 282 { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } 283}; 284 285static 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 373static 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 384static void AddUInt32ToString(AString &s, UInt32 val) 385{ 386 char sz[16]; 387 ConvertUInt32ToString(val, sz); 388 s += sz; 389} 390 391static 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 459void 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 485static 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 499static 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 515bool 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 532bool 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