// PropIDUtils.cpp | |
#include "StdAfx.h" | |
#include "../../../../C/CpuArch.h" | |
#include "../../../Common/IntToString.h" | |
#include "../../../Common/StringConvert.h" | |
#include "../../../Windows/FileFind.h" | |
#include "../../../Windows/FileIO.h" | |
#include "../../../Windows/PropVariantConv.h" | |
#include "../../PropID.h" | |
#include "PropIDUtils.h" | |
#define Get16(x) GetUi16(x) | |
#define Get32(x) GetUi32(x) | |
using namespace NWindows; | |
static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_"; | |
/* | |
0 READONLY | |
1 HIDDEN | |
2 SYSTEM | |
4 DIRECTORY | |
5 ARCHIVE | |
6 DEVICE | |
7 NORMAL | |
8 TEMPORARY | |
9 SPARSE_FILE | |
10 REPARSE_POINT | |
11 COMPRESSED | |
12 OFFLINE | |
13 NOT_CONTENT_INDEXED | |
14 ENCRYPTED | |
16 VIRTUAL | |
*/ | |
void ConvertWinAttribToString(char *s, UInt32 wa) | |
{ | |
for (int i = 0; i < 16; i++) | |
if ((wa & (1 << i)) && i != 7) | |
*s++ = g_WinAttribChars[i]; | |
*s = 0; | |
} | |
static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; | |
#define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-'; | |
void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw() | |
{ | |
*dest = 0; | |
if (prop.vt == VT_FILETIME) | |
{ | |
FILETIME localFileTime; | |
if ((prop.filetime.dwHighDateTime == 0 && | |
prop.filetime.dwLowDateTime == 0) || | |
!::FileTimeToLocalFileTime(&prop.filetime, &localFileTime)) | |
return; | |
ConvertFileTimeToString(localFileTime, dest, true, full); | |
return; | |
} | |
switch (propID) | |
{ | |
case kpidCRC: | |
{ | |
if (prop.vt != VT_UI4) | |
break; | |
ConvertUInt32ToHex8Digits(prop.ulVal, dest); | |
return; | |
} | |
case kpidAttrib: | |
{ | |
if (prop.vt != VT_UI4) | |
break; | |
ConvertWinAttribToString(dest, prop.ulVal); | |
return; | |
} | |
case kpidPosixAttrib: | |
{ | |
if (prop.vt != VT_UI4) | |
break; | |
UString res; | |
UInt32 a = prop.ulVal; | |
dest[0] = kPosixTypes[(a >> 12) & 0xF]; | |
for (int i = 6; i >= 0; i -= 3) | |
{ | |
dest[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); | |
dest[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); | |
dest[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); | |
} | |
if ((a & 0x800) != 0) dest[3] = ((a & (1 << 6)) ? 's' : 'S'); | |
if ((a & 0x400) != 0) dest[6] = ((a & (1 << 3)) ? 's' : 'S'); | |
if ((a & 0x200) != 0) dest[9] = ((a & (1 << 0)) ? 't' : 'T'); | |
dest[10] = 0; | |
a &= ~(UInt32)0xFFFF; | |
if (a != 0) | |
{ | |
dest[10] = ' '; | |
ConvertUInt32ToHex8Digits(a, dest + 11); | |
} | |
return; | |
} | |
case kpidINode: | |
{ | |
if (prop.vt != VT_UI8) | |
break; | |
ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest); | |
dest += strlen(dest); | |
*dest++ = '-'; | |
UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1); | |
ConvertUInt64ToString(low, dest); | |
return; | |
} | |
case kpidVa: | |
{ | |
UInt64 v = 0; | |
if (ConvertPropVariantToUInt64(prop, v)) | |
{ | |
dest[0] = '0'; | |
dest[1] = 'x'; | |
ConvertUInt64ToHex(prop.ulVal, dest + 2); | |
return; | |
} | |
break; | |
} | |
} | |
ConvertPropVariantToShortString(prop, dest); | |
} | |
void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full) | |
{ | |
if (prop.vt == VT_BSTR) | |
{ | |
dest = prop.bstrVal; | |
return; | |
} | |
char temp[64]; | |
ConvertPropertyToShortString(temp, prop, propID, full); | |
int len = MyStringLen(temp); | |
wchar_t *str = dest.GetBuffer(len); | |
for (int i = 0; i < len; i++) | |
str[i] = temp[i]; | |
dest.ReleaseBuffer(len); | |
} | |
static inline char GetHex(Byte value) | |
{ | |
return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); | |
} | |
#ifndef _SFX | |
static inline void AddHexToString(AString &res, Byte value) | |
{ | |
res += GetHex((Byte)(value >> 4)); | |
res += GetHex((Byte)(value & 0xF)); | |
res += ' '; | |
} | |
/* | |
static AString Data_To_Hex(const Byte *data, size_t size) | |
{ | |
AString s; | |
for (size_t i = 0; i < size; i++) | |
AddHexToString(s, data[i]); | |
return s; | |
} | |
*/ | |
static const char *sidNames[] = | |
{ | |
"0", | |
"Dialup", | |
"Network", | |
"Batch", | |
"Interactive", | |
"Logon", // S-1-5-5-X-Y | |
"Service", | |
"Anonymous", | |
"Proxy", | |
"EnterpriseDC", | |
"Self", | |
"AuthenticatedUsers", | |
"RestrictedCode", | |
"TerminalServer", | |
"RemoteInteractiveLogon", | |
"ThisOrganization", | |
"16", | |
"IUserIIS", | |
"LocalSystem", | |
"LocalService", | |
"NetworkService", | |
"Domains" | |
}; | |
struct CSecID2Name | |
{ | |
UInt32 n; | |
const char *sz; | |
}; | |
const CSecID2Name sid_32_Names[] = | |
{ | |
{ 544, "Administrators" }, | |
{ 545, "Users" }, | |
{ 546, "Guests" }, | |
{ 547, "PowerUsers" }, | |
{ 548, "AccountOperators" }, | |
{ 549, "ServerOperators" }, | |
{ 550, "PrintOperators" }, | |
{ 551, "BackupOperators" }, | |
{ 552, "Replicators" }, | |
{ 553, "Backup Operators" }, | |
{ 554, "PreWindows2000CompatibleAccess" }, | |
{ 555, "RemoteDesktopUsers" }, | |
{ 556, "NetworkConfigurationOperators" }, | |
{ 557, "IncomingForestTrustBuilders" }, | |
{ 558, "PerformanceMonitorUsers" }, | |
{ 559, "PerformanceLogUsers" }, | |
{ 560, "WindowsAuthorizationAccessGroup" }, | |
{ 561, "TerminalServerLicenseServers" }, | |
{ 562, "DistributedCOMUsers" }, | |
{ 569, "CryptographicOperators" }, | |
{ 573, "EventLogReaders" }, | |
{ 574, "CertificateServiceDCOMAccess" } | |
}; | |
static const CSecID2Name sid_21_Names[] = | |
{ | |
{ 500, "Administrator" }, | |
{ 501, "Guest" }, | |
{ 502, "KRBTGT" }, | |
{ 512, "DomainAdmins" }, | |
{ 513, "DomainUsers" }, | |
{ 515, "DomainComputers" }, | |
{ 516, "DomainControllers" }, | |
{ 517, "CertPublishers" }, | |
{ 518, "SchemaAdmins" }, | |
{ 519, "EnterpriseAdmins" }, | |
{ 520, "GroupPolicyCreatorOwners" }, | |
{ 553, "RASandIASServers" }, | |
{ 553, "RASandIASServers" }, | |
{ 571, "AllowedRODCPasswordReplicationGroup" }, | |
{ 572, "DeniedRODCPasswordReplicationGroup" } | |
}; | |
struct CServicesToName | |
{ | |
UInt32 n[5]; | |
const char *sz; | |
}; | |
static const CServicesToName services_to_name[] = | |
{ | |
{ { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" } | |
}; | |
static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize) | |
{ | |
sidSize = 0; | |
if (lim < 8) | |
{ | |
s += "ERROR"; | |
return; | |
} | |
UInt32 rev = p[0]; | |
if (rev != 1) | |
{ | |
s += "UNSUPPORTED"; | |
return; | |
} | |
UInt32 num = p[1]; | |
if (8 + num * 4 > lim) | |
{ | |
s += "ERROR"; | |
return; | |
} | |
sidSize = 8 + num * 4; | |
UInt32 authority = GetBe32(p + 4); | |
if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1) | |
{ | |
UInt32 v0 = Get32(p + 8); | |
if (v0 < ARRAY_SIZE(sidNames)) | |
{ | |
s += sidNames[v0]; | |
return; | |
} | |
if (v0 == 32 && num == 2) | |
{ | |
UInt32 v1 = Get32(p + 12); | |
for (int i = 0; i < ARRAY_SIZE(sid_32_Names); i++) | |
if (sid_32_Names[i].n == v1) | |
{ | |
s += sid_32_Names[i].sz; | |
return; | |
} | |
} | |
if (v0 == 21 && num == 5) | |
{ | |
UInt32 v4 = Get32(p + 8 + 4 * 4); | |
for (int i = 0; i < ARRAY_SIZE(sid_21_Names); i++) | |
if (sid_21_Names[i].n == v4) | |
{ | |
s += sid_21_Names[i].sz; | |
return; | |
} | |
} | |
if (v0 == 80 && num == 6) | |
{ | |
for (int i = 0; i < ARRAY_SIZE(services_to_name); i++) | |
{ | |
const CServicesToName &sn = services_to_name[i]; | |
int j; | |
for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++); | |
if (j == 5) | |
{ | |
s += sn.sz; | |
return; | |
} | |
} | |
} | |
} | |
char sz[16]; | |
s += "S-1-"; | |
if (p[2] == 0 && p[3] == 0) | |
{ | |
ConvertUInt32ToString(authority, sz); | |
s += sz; | |
} | |
else | |
{ | |
s += "0x"; | |
for (int i = 2; i < 8; i++) | |
AddHexToString(s, p[i]); | |
} | |
for (UInt32 i = 0; i < num; i++) | |
{ | |
s += '-'; | |
ConvertUInt32ToString(Get32(p + 8 + i * 4), sz); | |
s += sz; | |
} | |
} | |
static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos) | |
{ | |
if (pos > size) | |
{ | |
s += "ERROR"; | |
return; | |
} | |
UInt32 sidSize = 0; | |
ParseSid(s, p + pos, size - pos, sidSize); | |
} | |
static void AddUInt32ToString(AString &s, UInt32 val) | |
{ | |
char sz[16]; | |
ConvertUInt32ToString(val, sz); | |
s += sz; | |
} | |
static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset) | |
{ | |
UInt32 control = Get16(p + 2); | |
if ((flags & control) == 0) | |
return; | |
UInt32 pos = Get32(p + offset); | |
s += ' '; | |
s += strName; | |
if (pos >= size) | |
return; | |
p += pos; | |
size -= pos; | |
if (size < 8) | |
return; | |
if (Get16(p) != 2) // revision | |
return; | |
// UInt32 aclSize = Get16(p + 2); | |
UInt32 num = Get32(p + 4); | |
AddUInt32ToString(s, num); | |
/* | |
if (num >= (1 << 16)) | |
return; | |
if (aclSize > size) | |
return; | |
size = aclSize; | |
size -= 8; | |
p += 8; | |
for (UInt32 i = 0 ; i < num; i++) | |
{ | |
if (size <= 8) | |
return; | |
// Byte type = p[0]; | |
// Byte flags = p[1]; | |
// UInt32 aceSize = Get16(p + 2); | |
// UInt32 mask = Get32(p + 4); | |
p += 8; | |
size -= 8; | |
UInt32 sidSize = 0; | |
s += ' '; | |
s += ParseSid(p, size, sidSize); | |
if (sidSize == 0) | |
return; | |
p += sidSize; | |
size -= sidSize; | |
} | |
if (size != 0) | |
s += " ERROR"; | |
*/ | |
} | |
#define MY_SE_OWNER_DEFAULTED (0x0001) | |
#define MY_SE_GROUP_DEFAULTED (0x0002) | |
#define MY_SE_DACL_PRESENT (0x0004) | |
#define MY_SE_DACL_DEFAULTED (0x0008) | |
#define MY_SE_SACL_PRESENT (0x0010) | |
#define MY_SE_SACL_DEFAULTED (0x0020) | |
#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100) | |
#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200) | |
#define MY_SE_DACL_AUTO_INHERITED (0x0400) | |
#define MY_SE_SACL_AUTO_INHERITED (0x0800) | |
#define MY_SE_DACL_PROTECTED (0x1000) | |
#define MY_SE_SACL_PROTECTED (0x2000) | |
#define MY_SE_RM_CONTROL_VALID (0x4000) | |
#define MY_SE_SELF_RELATIVE (0x8000) | |
void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s) | |
{ | |
s.Empty(); | |
if (size < 20 || size > (1 << 18)) | |
{ | |
s += "ERROR"; | |
return; | |
} | |
if (Get16(data) != 1) // revision | |
{ | |
s += "UNSUPPORTED"; | |
return; | |
} | |
ParseOwner(s, data, size, Get32(data + 4)); | |
s += ' '; | |
ParseOwner(s, data, size, Get32(data + 8)); | |
ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); | |
ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); | |
s += ' '; | |
AddUInt32ToString(s, size); | |
// s += '\n'; | |
// s += Data_To_Hex(data, size); | |
} | |
#ifdef _WIN32 | |
static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) | |
{ | |
if (pos >= size) | |
return false; | |
size -= pos; | |
if (size < 8) | |
return false; | |
UInt32 rev = data[pos]; | |
if (rev != 1) | |
return false; | |
UInt32 num = data[pos + 1]; | |
return (8 + num * 4 <= size); | |
} | |
static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) | |
{ | |
UInt32 control = Get16(p + 2); | |
if ((flags & control) == 0) | |
return true; | |
UInt32 pos = Get32(p + offset); | |
if (pos >= size) | |
return false; | |
p += pos; | |
size -= pos; | |
if (size < 8) | |
return false; | |
UInt32 aclSize = Get16(p + 2); | |
return (aclSize <= size); | |
} | |
bool CheckNtSecure(const Byte *data, UInt32 size) | |
{ | |
if (size < 20) | |
return false; | |
if (Get16(data) != 1) // revision | |
return true; // windows function can handle such error, so we allow it | |
if (size > (1 << 18)) | |
return false; | |
if (!CheckSid(data, size, Get32(data + 4))) return false; | |
if (!CheckSid(data, size, Get32(data + 8))) return false; | |
if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false; | |
if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false; | |
return true; | |
} | |
#endif | |
bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) | |
{ | |
s.Empty(); | |
NFile::CReparseAttr attr; | |
if (attr.Parse(data, size)) | |
{ | |
if (!attr.IsSymLink()) | |
s += L"Junction: "; | |
s += attr.GetPath(); | |
if (!attr.IsOkNamePair()) | |
{ | |
s += L" : "; | |
s += attr.PrintName; | |
} | |
return true; | |
} | |
if (size < 8) | |
return false; | |
UInt32 tag = Get32(data); | |
UInt32 len = Get16(data + 4); | |
if (len + 8 > size) | |
return false; | |
if (Get16(data + 6) != 0) // padding | |
return false; | |
char hex[16]; | |
ConvertUInt32ToHex8Digits(tag, hex); | |
s.AddAsciiStr(hex); | |
s += L' '; | |
data += 8; | |
for (UInt32 i = 0; i < len; i++) | |
{ | |
Byte b = ((const Byte *)data)[i]; | |
s += (wchar_t)GetHex((Byte)((b >> 4) & 0xF)); | |
s += (wchar_t)GetHex((Byte)(b & 0xF)); | |
} | |
return true; | |
} | |
#endif |