ntdll: While requesting TokenGroups calculate required user buffer size in server.

This commit is contained in:
Nikolay Sivov 2011-08-23 11:16:27 +04:00 committed by Alexandre Julliard
parent 18549f3357
commit 573db9ef63
3 changed files with 69 additions and 60 deletions

View File

@ -1442,6 +1442,24 @@ static void test_token_attr(void)
ok(ret, "OpenProcessToken failed with error %d\n", GetLastError()); ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
/* groups */ /* groups */
/* insufficient buffer length */
SetLastError(0xdeadbeef);
Size2 = 0;
ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size2);
ok(Size2 > 1, "got %d\n", Size2);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"%d with error %d\n", ret, GetLastError());
Size2 -= 1;
Groups = HeapAlloc(GetProcessHeap(), 0, Size2);
memset(Groups, 0xcc, Size2);
Size = 0;
ret = GetTokenInformation(Token, TokenGroups, Groups, Size2, &Size);
ok(Size > 1, "got %d\n", Size);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"%d with error %d\n", ret, GetLastError());
ok(*((BYTE*)Groups) == 0xcc, "buffer altered\n");
HeapFree(GetProcessHeap(), 0, Groups);
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size); ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,

View File

@ -320,68 +320,48 @@ NTSTATUS WINAPI NtQueryInformationToken(
break; break;
case TokenGroups: case TokenGroups:
{ {
char stack_buffer[256]; void *buffer;
unsigned int server_buf_len = sizeof(stack_buffer);
void *buffer = stack_buffer;
BOOLEAN need_more_memory;
/* we cannot work out the size of the server buffer required for the /* reply buffer is always shorter than output one */
* input size, since there are two factors affecting how much can be buffer = tokeninfolength ? RtlAllocateHeap(GetProcessHeap(), 0, tokeninfolength) : NULL;
* stored in the buffer - number of groups and lengths of sids */
do SERVER_START_REQ( get_token_groups )
{ {
need_more_memory = FALSE; TOKEN_GROUPS *groups = tokeninfo;
SERVER_START_REQ( get_token_groups ) req->handle = wine_server_obj_handle( token );
wine_server_set_reply( req, buffer, tokeninfolength );
status = wine_server_call( req );
if (status == STATUS_BUFFER_TOO_SMALL)
{ {
TOKEN_GROUPS *groups = tokeninfo; if (retlen) *retlen = reply->user_len;
req->handle = wine_server_obj_handle( token );
wine_server_set_reply( req, buffer, server_buf_len );
status = wine_server_call( req );
if (status == STATUS_BUFFER_TOO_SMALL)
{
if (buffer == stack_buffer)
buffer = RtlAllocateHeap(GetProcessHeap(), 0, reply->user_len);
else
buffer = RtlReAllocateHeap(GetProcessHeap(), 0, buffer, reply->user_len);
if (!buffer) return STATUS_NO_MEMORY;
server_buf_len = reply->user_len;
need_more_memory = TRUE;
}
else if (status == STATUS_SUCCESS)
{
struct token_groups *tg = buffer;
unsigned int *attr = (unsigned int *)(tg + 1);
ULONG i;
const int non_sid_portion = (sizeof(struct token_groups) + tg->count * sizeof(unsigned int));
SID *sids = (SID *)((char *)tokeninfo + FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ));
ULONG needed_bytes = FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ) +
reply->user_len - non_sid_portion;
if (retlen) *retlen = needed_bytes;
if (needed_bytes <= tokeninfolength)
{
groups->GroupCount = tg->count;
memcpy( sids, (char *)buffer + non_sid_portion,
reply->user_len - non_sid_portion );
for (i = 0; i < tg->count; i++)
{
groups->Groups[i].Attributes = attr[i];
groups->Groups[i].Sid = sids;
sids = (SID *)((char *)sids + RtlLengthSid(sids));
}
}
else status = STATUS_BUFFER_TOO_SMALL;
}
else if (retlen) *retlen = 0;
} }
SERVER_END_REQ; else if (status == STATUS_SUCCESS)
} while (need_more_memory); {
if (buffer != stack_buffer) RtlFreeHeap(GetProcessHeap(), 0, buffer); struct token_groups *tg = buffer;
unsigned int *attr = (unsigned int *)(tg + 1);
ULONG i;
const int non_sid_portion = (sizeof(struct token_groups) + tg->count * sizeof(unsigned int));
SID *sids = (SID *)((char *)tokeninfo + FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ));
if (retlen) *retlen = reply->user_len;
groups->GroupCount = tg->count;
memcpy( sids, (char *)buffer + non_sid_portion,
reply->user_len - non_sid_portion - FIELD_OFFSET( TOKEN_GROUPS, Groups[tg->count] ));
for (i = 0; i < tg->count; i++)
{
groups->Groups[i].Attributes = attr[i];
groups->Groups[i].Sid = sids;
sids = (SID *)((char *)sids + RtlLengthSid(sids));
}
}
else if (retlen) *retlen = 0;
}
SERVER_END_REQ;
RtlFreeHeap(GetProcessHeap(), 0, buffer);
break; break;
} }
case TokenPrimaryGroup: case TokenPrimaryGroup:

View File

@ -1295,19 +1295,30 @@ DECL_HANDLER(get_token_groups)
&token_ops ))) &token_ops )))
{ {
size_t size_needed = sizeof(struct token_groups); size_t size_needed = sizeof(struct token_groups);
size_t sid_size = 0;
unsigned int group_count = 0; unsigned int group_count = 0;
const struct group *group; const struct group *group;
LIST_FOR_EACH_ENTRY( group, &token->groups, const struct group, entry ) LIST_FOR_EACH_ENTRY( group, &token->groups, const struct group, entry )
{ {
group_count++; group_count++;
size_needed += FIELD_OFFSET(SID, SubAuthority[group->sid.SubAuthorityCount]); sid_size += FIELD_OFFSET(SID, SubAuthority[group->sid.SubAuthorityCount]);
} }
size_needed += sid_size;
/* attributes size */
size_needed += sizeof(unsigned int) * group_count; size_needed += sizeof(unsigned int) * group_count;
reply->user_len = size_needed; /* reply buffer contains size_needed bytes formatted as:
if (size_needed <= get_reply_max_size()) unsigned int count;
unsigned int attrib[count];
char sid_data[];
user_len includes extra data needed for TOKEN_GROUPS representation,
required caller buffer size calculated here to avoid extra server call */
reply->user_len = FIELD_OFFSET( TOKEN_GROUPS, Groups[group_count] ) + sid_size;
if (reply->user_len <= get_reply_max_size())
{ {
struct token_groups *tg = set_reply_data_size( size_needed ); struct token_groups *tg = set_reply_data_size( size_needed );
if (tg) if (tg)