advapi32: Make it possible to free data buffer returned from LsaLookupSids().

This commit is contained in:
Nikolay Sivov 2013-01-19 23:26:05 +04:00 committed by Alexandre Julliard
parent cf195437c6
commit af641dc94c
3 changed files with 210 additions and 33 deletions

View File

@ -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;
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 */

View File

@ -344,6 +344,56 @@ static INT build_domain(PLSA_REFERENCED_DOMAIN_LIST currentList, PLSA_UNICODE_ST
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.@]
*
@ -450,70 +500,127 @@ NTSTATUS WINAPI LsaLookupNames2( LSA_HANDLE policy, ULONG flags, ULONG count,
* Failure: STATUS_NONE_MAPPED or NTSTATUS code.
*/
NTSTATUS WINAPI LsaLookupSids(
IN LSA_HANDLE PolicyHandle,
IN ULONG Count,
IN PSID *Sids,
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
OUT PLSA_TRANSLATED_NAME *Names )
LSA_HANDLE PolicyHandle,
ULONG Count,
PSID *Sids,
LSA_REFERENCED_DOMAIN_LIST **ReferencedDomains,
LSA_TRANSLATED_NAME **Names)
{
ULONG i, mapped, size;
ULONG i, mapped, name_fullsize, domain_fullsize;
ULONG name_size, domain_size;
LSA_UNICODE_STRING domain;
WCHAR *name_buffer;
char *domain_data;
SID_NAME_USE use;
TRACE("(%p,%u,%p,%p,%p) stub\n", PolicyHandle, Count, Sids,
ReferencedDomains, Names);
TRACE("(%p, %u, %p, %p, %p)\n", PolicyHandle, Count, Sids, ReferencedDomains, Names);
size = sizeof(LSA_TRANSLATED_NAME) * Count;
if (!(*Names = HeapAlloc( GetProcessHeap(), 0, size) )) return STATUS_NO_MEMORY;
if (!(*ReferencedDomains = HeapAlloc( GetProcessHeap(), 0, sizeof(LSA_REFERENCED_DOMAIN_LIST)) ))
/* this length does not include actual string length yet */
name_fullsize = sizeof(LSA_TRANSLATED_NAME) * Count;
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;
}
(*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;
for (i = 0; i < Count; i++)
{
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) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
LSA_UNICODE_STRING domain;
mapped++;
if (domain_size)
{
domain.Length = (domain_size - 1) * sizeof(WCHAR);
domain.MaximumLength = domain_size*sizeof(WCHAR);
domain.Buffer = HeapAlloc(GetProcessHeap(),0,domain.MaximumLength);
}
else
{
domain.Length = 0;
domain.MaximumLength = 0;
domain.Buffer = NULL;
domain.MaximumLength = domain_size * sizeof(WCHAR);
domain.Buffer = heap_alloc(domain.MaximumLength);
}
(*Names)[i].Name.Length = (name_size - 1) * sizeof(WCHAR);
(*Names)[i].Name.MaximumLength = name_size * sizeof(WCHAR);
(*Names)[i].Name.Buffer = HeapAlloc(GetProcessHeap(), 0, name_size * sizeof(WCHAR));
(*Names)[i].Name.Buffer = name_buffer;
LookupAccountSidW(NULL, Sids[i], (*Names)[i].Name.Buffer, &name_size, domain.Buffer, &domain_size, &use);
(*Names)[i].Use = use;
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);
}
}
name_buffer += name_size;
}
TRACE("mapped %u out of %u\n",mapped,Count);
TRACE("mapped %u out of %u\n", mapped, Count);
if (mapped == Count) return STATUS_SUCCESS;
if (mapped) return STATUS_SOME_NOT_MAPPED;

View File

@ -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 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 *pLsaLookupSids)(LSA_HANDLE,ULONG,PSID*,LSA_REFERENCED_DOMAIN_LIST**,LSA_TRANSLATED_NAME**);
static BOOL init(void)
{
@ -55,6 +56,7 @@ static BOOL init(void)
pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy");
pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
pLsaLookupNames2 = (void*)GetProcAddress(hadvapi32, "LsaLookupNames2");
pLsaLookupSids = (void*)GetProcAddress(hadvapi32, "LsaLookupSids");
if (pLsaClose && pLsaEnumerateAccountRights && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA)
return TRUE;
@ -351,6 +353,55 @@ static void test_LsaLookupNames2(void)
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)
{
if (!init()) {
@ -360,4 +411,5 @@ START_TEST(lsa)
test_lsa();
test_LsaLookupNames2();
test_LsaLookupSids();
}