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

Alexandre Julliard julliard at winehq.org
Tue Aug 23 12:45:04 CDT 2011


Module: wine
Branch: master
Commit: 573db9ef639f65385f1efab5593b52c72b4b4108
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=573db9ef639f65385f1efab5593b52c72b4b4108

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Tue Aug 23 11:16:27 2011 +0400

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

---

 dlls/advapi32/tests/security.c |   18 ++++++++
 dlls/ntdll/nt.c                |   92 ++++++++++++++++------------------------
 server/token.c                 |   17 ++++++-
 3 files changed, 68 insertions(+), 59 deletions(-)

diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 17c52dc..336cc9c 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -1442,6 +1442,24 @@ static void test_token_attr(void)
     ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
 
     /* 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);
     ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size);
     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 3e5d420..83a341f 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -320,68 +320,48 @@ NTSTATUS WINAPI NtQueryInformationToken(
         break;
     case TokenGroups:
     {
-        char stack_buffer[256];
-        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
-         * input size, since there are two factors affecting how much can be
-         * stored in the buffer - number of groups and lengths of sids */
-        do
+        void *buffer;
+
+        /* reply buffer is always shorter than output one */
+        buffer = tokeninfolength ? RtlAllocateHeap(GetProcessHeap(), 0, tokeninfolength) : NULL;
+
+        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;
-
-                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 = reply->user_len;
+            }
+            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] ));
 
-                    if (retlen) *retlen = needed_bytes;
+                if (retlen) *retlen = reply->user_len;
 
-                    if (needed_bytes <= tokeninfolength)
-                    {
-                        groups->GroupCount = tg->count;
-                        memcpy( sids, (char *)buffer + non_sid_portion,
-                                reply->user_len - non_sid_portion );
+                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 status = STATUS_BUFFER_TOO_SMALL;
+                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;
-        } while (need_more_memory);
-        if (buffer != stack_buffer) RtlFreeHeap(GetProcessHeap(), 0, buffer);
+             }
+             else if (retlen) *retlen = 0;
+        }
+        SERVER_END_REQ;
+
+        RtlFreeHeap(GetProcessHeap(), 0, buffer);
         break;
     }
     case TokenPrimaryGroup:
diff --git a/server/token.c b/server/token.c
index ab07a81..a0ec143 100644
--- a/server/token.c
+++ b/server/token.c
@@ -1295,19 +1295,30 @@ DECL_HANDLER(get_token_groups)
                                                  &token_ops )))
     {
         size_t size_needed = sizeof(struct token_groups);
+        size_t sid_size = 0;
         unsigned int group_count = 0;
         const struct group *group;
 
         LIST_FOR_EACH_ENTRY( group, &token->groups, const struct group, entry )
         {
             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;
 
-        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 );
             if (tg)




More information about the wine-cvs mailing list