我正在尝试使用本机LookupAccountSid
WinAPI函数为Windows中的每个SACL实例(用于安全审核)获取正确的SID(主名称)。
请参阅下面的屏幕快照,其中是我要测试的一个示例文件:
但是我的代码产生了如下所示的错误信息:
下面是应该发生的事情。
sidName = Everyone, size = 9
sidName = Everyone, size = 9
sidName = trevm, size = 6
我认为我已经仔细遵循了MSDN文档,但是没有帮助吗?
https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-lookupaccountsidw
我的代码可以使用GetSecurityDescriptorSacl
毫无疑问地获得安全描述符,但是LookupAccountSid
有问题。我出了什么问题?下面是我的C代码。有人知道为什么吗?
int getSACLinfo(HANDLE rToken, SE_OBJECT_TYPE objectType, ACEVALUE*& aceRef, int* count)
{
int arrSize = 0;
int retVal = ERROR_SUCCESS;
PACL sacl = NULL;
SYSTEM_AUDIT_ACE* ace = NULL;
PSECURITY_DESCRIPTOR pSS = NULL;
PSID sid;
PSID sidOwner;
BOOL saclPresent;
BOOL saclDefaulted;
wchar_t sidName[512];
wchar_t domainName[512];
ULONG result = GetSecurityInfo(rToken, objectType,
OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
&sidOwner, NULL, NULL, &sacl, &pSS);
if (result == ERROR_SUCCESS)
{
/* Get SACL security descriptor */
GetSecurityDescriptorSacl(pSS, &saclPresent, &sacl, &saclDefaulted);
if (saclPresent && (sacl != NULL))
{
for (int i = 0; i < sacl->AceCount; i++)
{
GetAce(sacl, i, (PVOID*)&ace);
/* Get SID from Ace */
sid = (PSID)&ace->SidStart;
if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
{
arrSize++;
}
}
// Allocate memory for the data structures to be exported
aceRef = (ACEVALUE*)malloc(arrSize * sizeof(ACEVALUE));
if (arrSize > 0 && aceRef != NULL)
{
size_t len;
wchar_t* buf;
DWORD namelen;
DWORD domainnamelen;
SID_NAME_USE peUse;
for (int i = 0; i < sacl->AceCount; i++)
{
GetAce(sacl, i, (PVOID*)&ace);
sid = (PSID)&ace->SidStart;
if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
{
LookupAccountSid(NULL, sid, sidName, &namelen, domainName, &domainnamelen, &peUse);
wprintf(L"sidName = %s, size = %d\n", sidName, namelen);
len = wcslen(sidName) + 1;
buf = (wchar_t*)malloc(len * sizeof(wchar_t));
if (buf != NULL)
{
wcscpy_s(buf, len, sidName);
aceRef[i].Name = buf;
}
aceRef[i].AceMask = ace->Mask;
aceRef[i].AceType = ace->Header.AceType;
aceRef[i].AceFlags = ace->Header.AceFlags;
}
}
}
}
}
else
{
retVal = GetLastError();
}
*count = arrSize;
if (pSS != NULL)
{
LocalFree((HLOCAL)pSS);
wprintf(L"FREED!\n");
}
return retVal;
}
答案 0 :(得分:0)
更新:下面是纠正我的错误的更新代码。经过进一步研究,我发现问题是由于我没有在原始代码中为两个变量: namelen 和 domainnamelen 指定缓冲区大小(感谢@RbMm和@jwdonahue指出)。
DWORD getSACLinfo(HANDLE rToken, SE_OBJECT_TYPE objectType, ACEVALUE*& aceRef, int* count)
{
size_t len;
int arrSize = 0;
wchar_t* buf;
wchar_t* sidName = NULL;
wchar_t* domainName = NULL;
PSID sid;
PSID sidOwner;
PACL sacl = NULL;
DWORD retValue;
DWORD dwRevision;
DWORD namelen;
DWORD domainnamelen;
SYSTEM_AUDIT_ACE* ace = NULL;
PSECURITY_DESCRIPTOR pSS = NULL;
SECURITY_DESCRIPTOR_CONTROL sdControl;
/* Get SACL security descriptor */
retValue = GetSecurityInfo(rToken, objectType,
OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
&sidOwner, NULL, NULL, &sacl, &pSS);
if (retValue == ERROR_SUCCESS)
{
if (GetSecurityDescriptorControl(pSS, &sdControl, &dwRevision) == FALSE)
{
retValue = ERROR_INVALID_FUNCTION;
}
else if (sacl != NULL && (sdControl & SE_SACL_PRESENT) == SE_SACL_PRESENT)
{
for (int i = 0; i < sacl->AceCount; i++)
{
GetAce(sacl, i, (PVOID*)&ace);
/* Get SID from Ace */
sid = (PSID)&ace->SidStart;
if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
{
arrSize++;
}
}
// Allocate memory for the data structures to be exported
aceRef = (ACEVALUE*)malloc(arrSize * sizeof(ACEVALUE));
if (arrSize > 0 && aceRef != NULL)
{
for (int i = 0; i < sacl->AceCount; i++)
{
GetAce(sacl, i, (PVOID*)&ace);
sid = (PSID)&ace->SidStart;
if (IsValidSid(sid) && ace->Header.AceType == SYSTEM_AUDIT_ACE_TYPE)
{
// ADDED TO FIX THE PROBLEM
getNameBySID(sid, sidName, &namelen, domainName, &domainnamelen);
wprintf(L"size = %d, Owner = %s\n", namelen, sidName);
len = wcslen(sidName) + 1;
buf = (wchar_t*)malloc(len * sizeof(wchar_t));
if (buf != NULL)
{
wcscpy_s(buf, len, sidName);
aceRef[i].Name = buf;
}
aceRef[i].AceMask = ace->Mask;
aceRef[i].AceType = ace->Header.AceType;
aceRef[i].AceFlags = ace->Header.AceFlags;
}
}
}
}
}
else
{
retValue = GetLastError();
}
*count = arrSize;
// Memory deallocations
free(sidName);
free(domainName);
LocalFree((HLOCAL)pSS);
wprintf(L"FREED!\n");
return retValue;
}
要修复,我添加了一个新函数getNameBySID
,以便为缓冲区 sidName 和 domainName 提供正确的内存空间。该逻辑仅涉及一个do-while循环以继续迭代,直到满足LookupAccountSid
的要求为止,此时这两个缓冲区的缓冲区大小正确。如果先前的缓冲区大小太小而无法填充缓冲区,它将释放先前分配的缓冲区,然后以正确的大小重新分配并重试。
DWORD getNameBySID(PSID sid, wchar_t *&oNameBuf, DWORD *owNameSize, wchar_t *&dNameBuf, DWORD *dnNameSize)
{
const DWORD DEFAULT_SIZE = 256;
const wchar_t NONAME[] = L"Unknown";
bool status;
SID_NAME_USE peUse;
DWORD retValue;
DWORD ownerBufSize = *owNameSize;
DWORD domainBufSize = *dnNameSize;
// Create buffers that may be large enough
if (oNameBuf == NULL || dNameBuf == NULL)
{
ownerBufSize = domainBufSize = DEFAULT_SIZE;
oNameBuf = (wchar_t*)malloc(ownerBufSize * sizeof(wchar_t));
dNameBuf = (wchar_t*)malloc(domainBufSize * sizeof(wchar_t));
if (oNameBuf == NULL)
{
return ERROR_INSUFFICIENT_BUFFER;
}
if (dNameBuf == NULL)
{
free(oNameBuf);
return ERROR_INSUFFICIENT_BUFFER;
}
*owNameSize = ownerBufSize;
*dnNameSize = domainBufSize;
memset(oNameBuf, 0, ownerBufSize * sizeof(wchar_t));
memset(dNameBuf, 0, domainBufSize * sizeof(wchar_t));
}
do
{
status = (LookupAccountSid(NULL, sid, oNameBuf, owNameSize, dNameBuf, dnNameSize, &peUse) == TRUE);
if (!status)
{
retValue = GetLastError();
if (*owNameSize > ownerBufSize)
{
// Reallocate memory for the buffer and try again.
//wprintf(L"The account name buffer was too small. It will be reallocated.\n");
free(oNameBuf);
oNameBuf = (wchar_t*)malloc(*owNameSize * sizeof(wchar_t));
if (oNameBuf == NULL)
{
return ERROR_INSUFFICIENT_BUFFER;
}
ownerBufSize = *owNameSize;
memset(oNameBuf, 0, ownerBufSize * sizeof(wchar_t));
}
else if (*dnNameSize > domainBufSize)
{
// Reallocate memory for the buffer and try again.
//wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
free(dNameBuf);
dNameBuf = (wchar_t*)malloc(*dnNameSize * sizeof(wchar_t));
if (dNameBuf == NULL)
{
return ERROR_INSUFFICIENT_BUFFER;
}
domainBufSize = *dnNameSize;
memset(dNameBuf, 0, domainBufSize * sizeof(wchar_t));
}
else if (retValue == ERROR_NONE_MAPPED)
{
// A name could not be found for the SID due to an unexpected error occurred.
if (ownerBufSize > wcslen(NONAME))
{
wcscpy_s(oNameBuf, wcslen(NONAME) + 1, NONAME);
oNameBuf[wcslen(NONAME)] = L'\0';
}
dNameBuf[0] = L'\0';
break;
}
else
{
wprintf(L"LookupAccountSid failed. GetLastError returned: %d\n", retValue);
break;
}
}
} while (!status);
*owNameSize = ownerBufSize;
*dnNameSize = domainBufSize;
return (status ? ERROR_SUCCESS : retValue);
}
基本上,我的getSACLinfo
函数基本相同,除了调用getNameBySID
来获取这两个名称的正确大小的缓冲区外。
下面将产生预期的信息。