advapi32: Make it possible to free data buffer returned from LsaLookupSids().
This commit is contained in:
parent
cf195437c6
commit
af641dc94c
|
@ -32,4 +32,22 @@ BOOL lookup_local_user_name(const LSA_UNICODE_STRING*, PSID, LPDWORD, LPWSTR, LP
|
||||||
WCHAR *SERV_dup(const char *str) DECLSPEC_HIDDEN;
|
WCHAR *SERV_dup(const char *str) DECLSPEC_HIDDEN;
|
||||||
NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD) DECLSPEC_HIDDEN;
|
NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, DWORD, LPDWORD) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
/* heap allocation helpers */
|
||||||
|
static void *heap_alloc( size_t len ) __WINE_ALLOC_SIZE(1);
|
||||||
|
static inline void *heap_alloc( size_t len )
|
||||||
|
{
|
||||||
|
return HeapAlloc( GetProcessHeap(), 0, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *heap_realloc( void *mem, size_t len ) __WINE_ALLOC_SIZE(2);
|
||||||
|
static inline void *heap_realloc( void *mem, size_t len )
|
||||||
|
{
|
||||||
|
return HeapReAlloc( GetProcessHeap(), 0, mem, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BOOL heap_free( void *mem )
|
||||||
|
{
|
||||||
|
return HeapFree( GetProcessHeap(), 0, mem );
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __WINE_ADVAPI32MISC_H */
|
#endif /* __WINE_ADVAPI32MISC_H */
|
||||||
|
|
|
@ -344,6 +344,56 @@ static INT build_domain(PLSA_REFERENCED_DOMAIN_LIST currentList, PLSA_UNICODE_ST
|
||||||
return currentList->Entries-1;
|
return currentList->Entries-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adds domain info to referenced domain list.
|
||||||
|
Domain list is stored as plain buffer, layout is:
|
||||||
|
|
||||||
|
LSA_REFERENCED_DOMAIN_LIST,
|
||||||
|
LSA_TRUST_INFORMATION array,
|
||||||
|
domain data array of
|
||||||
|
{
|
||||||
|
domain name data (WCHAR buffer),
|
||||||
|
SID data
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
list [I] referenced list pointer
|
||||||
|
domain [I] domain name string
|
||||||
|
data [IO] pointer to domain data array
|
||||||
|
*/
|
||||||
|
static LONG lsa_reflist_add_domain(LSA_REFERENCED_DOMAIN_LIST *list, LSA_UNICODE_STRING *domain, char **data)
|
||||||
|
{
|
||||||
|
ULONG sid_size = 0,domain_size = 0;
|
||||||
|
BOOL handled = FALSE;
|
||||||
|
SID_NAME_USE use;
|
||||||
|
LONG i;
|
||||||
|
|
||||||
|
for (i = 0; i < list->Entries; i++)
|
||||||
|
{
|
||||||
|
/* try to reuse index */
|
||||||
|
if ((list->Domains[i].Name.Length == domain->Length) &&
|
||||||
|
(!strncmpiW(list->Domains[i].Name.Buffer, domain->Buffer, (domain->Length / sizeof(WCHAR)))))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no matching domain found, store name */
|
||||||
|
list->Domains[list->Entries].Name.Length = domain->Length;
|
||||||
|
list->Domains[list->Entries].Name.MaximumLength = domain->MaximumLength;
|
||||||
|
list->Domains[list->Entries].Name.Buffer = (WCHAR*)*data;
|
||||||
|
memcpy(list->Domains[list->Entries].Name.Buffer, domain->Buffer, domain->MaximumLength);
|
||||||
|
*data += domain->MaximumLength;
|
||||||
|
|
||||||
|
/* get and store SID data */
|
||||||
|
list->Domains[list->Entries].Sid = *data;
|
||||||
|
lookup_name(domain, NULL, &sid_size, NULL, &domain_size, &use, &handled);
|
||||||
|
domain_size = 0;
|
||||||
|
lookup_name(domain, list->Domains[list->Entries].Sid, &sid_size, NULL, &domain_size, &use, &handled);
|
||||||
|
*data += sid_size;
|
||||||
|
|
||||||
|
return list->Entries++;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* LsaLookupNames2 [ADVAPI32.@]
|
* LsaLookupNames2 [ADVAPI32.@]
|
||||||
*
|
*
|
||||||
|
@ -450,70 +500,127 @@ NTSTATUS WINAPI LsaLookupNames2( LSA_HANDLE policy, ULONG flags, ULONG count,
|
||||||
* Failure: STATUS_NONE_MAPPED or NTSTATUS code.
|
* Failure: STATUS_NONE_MAPPED or NTSTATUS code.
|
||||||
*/
|
*/
|
||||||
NTSTATUS WINAPI LsaLookupSids(
|
NTSTATUS WINAPI LsaLookupSids(
|
||||||
IN LSA_HANDLE PolicyHandle,
|
LSA_HANDLE PolicyHandle,
|
||||||
IN ULONG Count,
|
ULONG Count,
|
||||||
IN PSID *Sids,
|
PSID *Sids,
|
||||||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
LSA_REFERENCED_DOMAIN_LIST **ReferencedDomains,
|
||||||
OUT PLSA_TRANSLATED_NAME *Names )
|
LSA_TRANSLATED_NAME **Names)
|
||||||
{
|
{
|
||||||
ULONG i, mapped, size;
|
ULONG i, mapped, name_fullsize, domain_fullsize;
|
||||||
ULONG name_size, domain_size;
|
ULONG name_size, domain_size;
|
||||||
|
LSA_UNICODE_STRING domain;
|
||||||
|
WCHAR *name_buffer;
|
||||||
|
char *domain_data;
|
||||||
SID_NAME_USE use;
|
SID_NAME_USE use;
|
||||||
|
|
||||||
TRACE("(%p,%u,%p,%p,%p) stub\n", PolicyHandle, Count, Sids,
|
TRACE("(%p, %u, %p, %p, %p)\n", PolicyHandle, Count, Sids, ReferencedDomains, Names);
|
||||||
ReferencedDomains, Names);
|
|
||||||
|
|
||||||
size = sizeof(LSA_TRANSLATED_NAME) * Count;
|
/* this length does not include actual string length yet */
|
||||||
if (!(*Names = HeapAlloc( GetProcessHeap(), 0, size) )) return STATUS_NO_MEMORY;
|
name_fullsize = sizeof(LSA_TRANSLATED_NAME) * Count;
|
||||||
if (!(*ReferencedDomains = HeapAlloc( GetProcessHeap(), 0, sizeof(LSA_REFERENCED_DOMAIN_LIST)) ))
|
if (!(*Names = heap_alloc(name_fullsize))) return STATUS_NO_MEMORY;
|
||||||
|
/* maximum count of stored domain infos is Count, allocate it like that cause really needed
|
||||||
|
count could only be computed after sid data is retrieved */
|
||||||
|
domain_fullsize = sizeof(LSA_REFERENCED_DOMAIN_LIST) + sizeof(LSA_TRUST_INFORMATION)*Count;
|
||||||
|
if (!(*ReferencedDomains = heap_alloc(domain_fullsize)))
|
||||||
{
|
{
|
||||||
HeapFree( GetProcessHeap(), 0, *Names);
|
heap_free(*Names);
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
}
|
}
|
||||||
(*ReferencedDomains)->Entries = 0;
|
(*ReferencedDomains)->Entries = 0;
|
||||||
(*ReferencedDomains)->Domains = NULL;
|
(*ReferencedDomains)->Domains = (LSA_TRUST_INFORMATION*)((char*)*ReferencedDomains + sizeof(LSA_REFERENCED_DOMAIN_LIST));
|
||||||
|
|
||||||
|
/* Get full names data length and full length needed to store domain name and SID */
|
||||||
|
for (i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
(*Names)[i].Use = SidTypeUnknown;
|
||||||
|
(*Names)[i].DomainIndex = -1;
|
||||||
|
(*Names)[i].Name.Buffer = NULL;
|
||||||
|
|
||||||
|
memset(&(*ReferencedDomains)->Domains[i], 0, sizeof(LSA_TRUST_INFORMATION));
|
||||||
|
|
||||||
|
name_size = domain_size = 0;
|
||||||
|
if (!LookupAccountSidW(NULL, Sids[i], NULL, &name_size, NULL, &domain_size, &use) &&
|
||||||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
{
|
||||||
|
if (name_size)
|
||||||
|
{
|
||||||
|
(*Names)[i].Name.Length = (name_size - 1) * sizeof(WCHAR);
|
||||||
|
(*Names)[i].Name.MaximumLength = name_size * sizeof(WCHAR);
|
||||||
|
name_fullsize += (*Names)[i].Name.MaximumLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*Names)[i].Name.Length = 0;
|
||||||
|
(*Names)[i].Name.MaximumLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This potentially allocates more than needed, cause different names will reuse same domain index.
|
||||||
|
Also it's not possible to store domain name length right here for the same reason. */
|
||||||
|
if (domain_size)
|
||||||
|
{
|
||||||
|
ULONG sid_size = 0;
|
||||||
|
BOOL handled = FALSE;
|
||||||
|
WCHAR *name;
|
||||||
|
|
||||||
|
domain_fullsize += domain_size * sizeof(WCHAR);
|
||||||
|
|
||||||
|
/* get domain SID size too */
|
||||||
|
name = heap_alloc(domain_size * sizeof(WCHAR));
|
||||||
|
*name = 0;
|
||||||
|
LookupAccountSidW(NULL, Sids[i], NULL, &name_size, name, &domain_size, &use);
|
||||||
|
|
||||||
|
domain.Buffer = name;
|
||||||
|
domain.Length = domain_size * sizeof(WCHAR);
|
||||||
|
domain.MaximumLength = domain_size * sizeof(WCHAR);
|
||||||
|
|
||||||
|
lookup_name(&domain, NULL, &sid_size, NULL, &domain_size, &use, &handled);
|
||||||
|
domain_fullsize += sid_size;
|
||||||
|
|
||||||
|
heap_free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have full length needed for both */
|
||||||
|
*Names = heap_realloc(*Names, name_fullsize);
|
||||||
|
name_buffer = (WCHAR*)((char*)*Names + sizeof(LSA_TRANSLATED_NAME)*Count);
|
||||||
|
|
||||||
|
*ReferencedDomains = heap_realloc(*ReferencedDomains, domain_fullsize);
|
||||||
|
/* fix pointer after reallocation */
|
||||||
|
(*ReferencedDomains)->Domains = (LSA_TRUST_INFORMATION*)((char*)*ReferencedDomains + sizeof(LSA_REFERENCED_DOMAIN_LIST));
|
||||||
|
domain_data = (char*)(*ReferencedDomains)->Domains + sizeof(LSA_TRUST_INFORMATION)*Count;
|
||||||
|
|
||||||
mapped = 0;
|
mapped = 0;
|
||||||
for (i = 0; i < Count; i++)
|
for (i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
name_size = domain_size = 0;
|
name_size = domain_size = 0;
|
||||||
(*Names)[i].Use = SidTypeUnknown;
|
|
||||||
(*Names)[i].DomainIndex = -1;
|
|
||||||
(*Names)[i].Name.Length = 0;
|
|
||||||
(*Names)[i].Name.MaximumLength = 0;
|
|
||||||
(*Names)[i].Name.Buffer = NULL;
|
|
||||||
|
|
||||||
if (!LookupAccountSidW(NULL, Sids[i], NULL, &name_size, NULL, &domain_size, &use) &&
|
if (!LookupAccountSidW(NULL, Sids[i], NULL, &name_size, NULL, &domain_size, &use) &&
|
||||||
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||||
{
|
{
|
||||||
LSA_UNICODE_STRING domain;
|
|
||||||
|
|
||||||
mapped++;
|
mapped++;
|
||||||
|
|
||||||
if (domain_size)
|
if (domain_size)
|
||||||
{
|
{
|
||||||
domain.Length = (domain_size - 1) * sizeof(WCHAR);
|
domain.Length = (domain_size - 1) * sizeof(WCHAR);
|
||||||
domain.MaximumLength = domain_size*sizeof(WCHAR);
|
domain.MaximumLength = domain_size * sizeof(WCHAR);
|
||||||
domain.Buffer = HeapAlloc(GetProcessHeap(),0,domain.MaximumLength);
|
domain.Buffer = heap_alloc(domain.MaximumLength);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
domain.Length = 0;
|
|
||||||
domain.MaximumLength = 0;
|
|
||||||
domain.Buffer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(*Names)[i].Name.Length = (name_size - 1) * sizeof(WCHAR);
|
(*Names)[i].Name.Buffer = name_buffer;
|
||||||
(*Names)[i].Name.MaximumLength = name_size * sizeof(WCHAR);
|
|
||||||
(*Names)[i].Name.Buffer = HeapAlloc(GetProcessHeap(), 0, name_size * sizeof(WCHAR));
|
|
||||||
LookupAccountSidW(NULL, Sids[i], (*Names)[i].Name.Buffer, &name_size, domain.Buffer, &domain_size, &use);
|
LookupAccountSidW(NULL, Sids[i], (*Names)[i].Name.Buffer, &name_size, domain.Buffer, &domain_size, &use);
|
||||||
(*Names)[i].Use = use;
|
(*Names)[i].Use = use;
|
||||||
|
|
||||||
if (domain_size)
|
if (domain_size)
|
||||||
(*Names)[i].DomainIndex = build_domain(*ReferencedDomains, &domain);
|
{
|
||||||
|
(*Names)[i].DomainIndex = lsa_reflist_add_domain(*ReferencedDomains, &domain, &domain_data);
|
||||||
|
heap_free(domain.Buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACE("mapped %u out of %u\n",mapped,Count);
|
|
||||||
|
name_buffer += name_size;
|
||||||
|
}
|
||||||
|
TRACE("mapped %u out of %u\n", mapped, Count);
|
||||||
|
|
||||||
if (mapped == Count) return STATUS_SUCCESS;
|
if (mapped == Count) return STATUS_SUCCESS;
|
||||||
if (mapped) return STATUS_SOME_NOT_MAPPED;
|
if (mapped) return STATUS_SOME_NOT_MAPPED;
|
||||||
|
|
|
@ -43,6 +43,7 @@ static NTSTATUS (WINAPI *pLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBU
|
||||||
static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
|
static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
|
||||||
static BOOL (WINAPI *pConvertSidToStringSidA)(PSID,LPSTR*);
|
static BOOL (WINAPI *pConvertSidToStringSidA)(PSID,LPSTR*);
|
||||||
static NTSTATUS (WINAPI *pLsaLookupNames2)(LSA_HANDLE,ULONG,ULONG,PLSA_UNICODE_STRING,PLSA_REFERENCED_DOMAIN_LIST*,PLSA_TRANSLATED_SID2*);
|
static NTSTATUS (WINAPI *pLsaLookupNames2)(LSA_HANDLE,ULONG,ULONG,PLSA_UNICODE_STRING,PLSA_REFERENCED_DOMAIN_LIST*,PLSA_TRANSLATED_SID2*);
|
||||||
|
static NTSTATUS (WINAPI *pLsaLookupSids)(LSA_HANDLE,ULONG,PSID*,LSA_REFERENCED_DOMAIN_LIST**,LSA_TRANSLATED_NAME**);
|
||||||
|
|
||||||
static BOOL init(void)
|
static BOOL init(void)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,7 @@ static BOOL init(void)
|
||||||
pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy");
|
pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy");
|
||||||
pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
|
pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
|
||||||
pLsaLookupNames2 = (void*)GetProcAddress(hadvapi32, "LsaLookupNames2");
|
pLsaLookupNames2 = (void*)GetProcAddress(hadvapi32, "LsaLookupNames2");
|
||||||
|
pLsaLookupSids = (void*)GetProcAddress(hadvapi32, "LsaLookupSids");
|
||||||
|
|
||||||
if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA)
|
if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -351,6 +353,55 @@ static void test_LsaLookupNames2(void)
|
||||||
ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
|
ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_LsaLookupSids(void)
|
||||||
|
{
|
||||||
|
LSA_REFERENCED_DOMAIN_LIST *list;
|
||||||
|
LSA_OBJECT_ATTRIBUTES attrs;
|
||||||
|
LSA_TRANSLATED_NAME *names;
|
||||||
|
LSA_HANDLE policy;
|
||||||
|
TOKEN_USER *user;
|
||||||
|
NTSTATUS status;
|
||||||
|
HANDLE token;
|
||||||
|
DWORD size;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
memset(&attrs, 0, sizeof(attrs));
|
||||||
|
attrs.Length = sizeof(attrs);
|
||||||
|
|
||||||
|
status = pLsaOpenPolicy(NULL, &attrs, POLICY_LOOKUP_NAMES, &policy);
|
||||||
|
ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
|
||||||
|
|
||||||
|
ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
|
||||||
|
ok(ret, "got %d\n", ret);
|
||||||
|
|
||||||
|
ret = GetTokenInformation(token, TokenUser, NULL, 0, &size);
|
||||||
|
ok(!ret, "gotr %d\n", ret);
|
||||||
|
|
||||||
|
user = HeapAlloc(GetProcessHeap(), 0, size);
|
||||||
|
ret = GetTokenInformation(token, TokenUser, user, size, &size);
|
||||||
|
ok(ret, "got %d\n", ret);
|
||||||
|
|
||||||
|
status = pLsaLookupSids(policy, 1, &user->User.Sid, &list, &names);
|
||||||
|
ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
|
||||||
|
|
||||||
|
ok(list->Entries > 0, "got %d\n", list->Entries);
|
||||||
|
if (list->Entries)
|
||||||
|
{
|
||||||
|
ok((char*)list->Domains - (char*)list > 0, "%p, %p\n", list, list->Domains);
|
||||||
|
ok((char*)list->Domains[0].Sid - (char*)list->Domains > 0, "%p, %p\n", list->Domains, list->Domains[0].Sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
pLsaFreeMemory(names);
|
||||||
|
pLsaFreeMemory(list);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, user);
|
||||||
|
|
||||||
|
CloseHandle(token);
|
||||||
|
|
||||||
|
status = pLsaClose(policy);
|
||||||
|
ok(status == STATUS_SUCCESS, "got 0x%08x\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
START_TEST(lsa)
|
START_TEST(lsa)
|
||||||
{
|
{
|
||||||
if (!init()) {
|
if (!init()) {
|
||||||
|
@ -360,4 +411,5 @@ START_TEST(lsa)
|
||||||
|
|
||||||
test_lsa();
|
test_lsa();
|
||||||
test_LsaLookupNames2();
|
test_LsaLookupNames2();
|
||||||
|
test_LsaLookupSids();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue