From 91eaea53ae301d5c6fc4a0606518191408db8a90 Mon Sep 17 00:00:00 2001
From: Robert Shearman <rob@codeweavers.com>
Date: Mon, 18 Jul 2005 13:22:55 +0000
Subject: [PATCH] - Change the default user SID to match what was previously
 returned by   NtQueryInformationToken. - Implement TokenUser for
 NtQueryInformationToken. - Add a function for getting the user's registry
 path from a SID.

---
 dlls/ntdll/nt.c                | 21 ++++++++++-------
 include/wine/server_protocol.h | 17 +++++++++++++-
 server/protocol.def            |  7 ++++++
 server/registry.c              | 31 ++++++++++++++++++++----
 server/request.h               |  2 ++
 server/security.h              |  2 ++
 server/token.c                 | 43 ++++++++++++++++++++++++++++------
 server/trace.c                 | 22 +++++++++++++++++
 8 files changed, 125 insertions(+), 20 deletions(-)

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index de489f1b17e..d9ba0560607 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -196,9 +196,6 @@ NTSTATUS WINAPI NtQueryInformationToken(
 
     switch (tokeninfoclass)
     {
-    case TokenUser:
-        len = sizeof(TOKEN_USER) + sizeof(SID);
-        break;
     case TokenGroups:
         len = sizeof(TOKEN_GROUPS);
         break;
@@ -232,15 +229,23 @@ NTSTATUS WINAPI NtQueryInformationToken(
     switch (tokeninfoclass)
     {
     case TokenUser:
-        if( tokeninfo )
+        SERVER_START_REQ( get_token_user )
         {
             TOKEN_USER * tuser = tokeninfo;
             PSID sid = (PSID) (tuser + 1);
-            SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY};
-            RtlInitializeSid(sid, &localSidAuthority, 1);
-            *(RtlSubAuthoritySid(sid, 0)) = SECURITY_INTERACTIVE_RID;
-            tuser->User.Sid = sid;
+            DWORD sid_len = tokeninfolength < sizeof(TOKEN_USER) ? 0 : tokeninfolength - sizeof(TOKEN_USER);
+
+            req->handle = token;
+            wine_server_set_reply( req, sid, sid_len );
+            status = wine_server_call( req );
+            *retlen = reply->user_len + sizeof(TOKEN_USER);
+            if (status == STATUS_SUCCESS)
+            {
+                tuser->User.Sid = sid;
+                tuser->User.Attributes = 0;
+            }
         }
+        SERVER_END_REQ;
         break;
     case TokenGroups:
         if (tokeninfo)
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index be5317fa982..b8e16c3ebfc 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3487,6 +3487,18 @@ struct access_check_reply
     /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
 };
 
+struct get_token_user_request
+{
+    struct request_header __header;
+    obj_handle_t    handle;
+};
+struct get_token_user_reply
+{
+    struct reply_header __header;
+    size_t          user_len;
+    /* VARARG(user,SID); */
+};
+
 
 struct create_mailslot_request
 {
@@ -3739,6 +3751,7 @@ enum request
     REQ_check_token_privileges,
     REQ_duplicate_token,
     REQ_access_check,
+    REQ_get_token_user,
     REQ_create_mailslot,
     REQ_open_mailslot,
     REQ_set_mailslot_info,
@@ -3948,6 +3961,7 @@ union generic_request
     struct check_token_privileges_request check_token_privileges_request;
     struct duplicate_token_request duplicate_token_request;
     struct access_check_request access_check_request;
+    struct get_token_user_request get_token_user_request;
     struct create_mailslot_request create_mailslot_request;
     struct open_mailslot_request open_mailslot_request;
     struct set_mailslot_info_request set_mailslot_info_request;
@@ -4155,11 +4169,12 @@ union generic_reply
     struct check_token_privileges_reply check_token_privileges_reply;
     struct duplicate_token_reply duplicate_token_reply;
     struct access_check_reply access_check_reply;
+    struct get_token_user_reply get_token_user_reply;
     struct create_mailslot_reply create_mailslot_reply;
     struct open_mailslot_reply open_mailslot_reply;
     struct set_mailslot_info_reply set_mailslot_info_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 187
+#define SERVER_PROTOCOL_VERSION 188
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index 25bc6d7a084..b18782d4d2f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2448,6 +2448,13 @@ enum message_type
     VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges used during access check */
 @END
 
+@REQ(get_token_user)
+    obj_handle_t    handle;       /* handle to the token */
+@REPLY
+    size_t          user_len;     /* length needed to store user */
+    VARARG(user,SID);             /* sid of the user the token represents */
+@END
+
 /* Create a mailslot */
 @REQ(create_mailslot)
     unsigned int   max_msgsize;
diff --git a/server/registry.c b/server/registry.c
index 40fdc36b434..ba78e1b84c6 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -1421,14 +1421,34 @@ static void load_init_registry_from_file( const char *filename, struct key *key
     }
 }
 
+static WCHAR *format_user_registry_path( const SID *sid )
+{
+    static const WCHAR prefixW[] = {'U','s','e','r','\\','S',0};
+    static const WCHAR formatW[] = {'-','%','u',0};
+    WCHAR buffer[7 + 10 + 10 + 10 * SID_MAX_SUB_AUTHORITIES];
+    WCHAR *p = buffer;
+    unsigned int i;
+
+    strcpyW( p, prefixW );
+    p += strlenW( prefixW );
+    p += sprintfW( p, formatW, sid->Revision );
+    p += sprintfW( p, formatW, MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5],
+                                                   sid->IdentifierAuthority.Value[4] ),
+                                         MAKEWORD( sid->IdentifierAuthority.Value[3],
+                                                   sid->IdentifierAuthority.Value[2] )));
+    for (i = 0; i < sid->SubAuthorityCount; i++)
+        p += sprintfW( p, formatW, sid->SubAuthority[i] );
+
+    return memdup( buffer, (p + 1 - buffer) * sizeof(WCHAR) );
+}
+
 /* registry initialisation */
 void init_registry(void)
 {
     static const WCHAR root_name[] = { 0 };
     static const WCHAR HKLM[] = { 'M','a','c','h','i','n','e' };
     static const WCHAR HKU_default[] = { 'U','s','e','r','\\','.','D','e','f','a','u','l','t' };
-    /* FIXME: hardcoded to match what NtQueryTokenInformation currently returns */
-    static const WCHAR HKCU[] = {'U','s','e','r','\\','S','-','1','-','5','-','4',0};
+    WCHAR *current_user_path;
 
     const char *config = wine_get_config_dir();
     char *p, *filename;
@@ -1465,9 +1485,12 @@ void init_registry(void)
 
     /* load user.reg into HKEY_CURRENT_USER */
 
-    if (!(key = create_key( root_key, copy_path( HKCU, sizeof(HKCU), 0 ),
-                            NULL, 0, time(NULL), &dummy )))
+    /* FIXME: match default user in token.c. should get from process token instead */
+    current_user_path = format_user_registry_path( security_interactive_sid );
+    if (!current_user_path ||
+        !(key = create_key( root_key, current_user_path, NULL, 0, time(NULL), &dummy )))
         fatal_error( "could not create HKEY_CURRENT_USER registry key\n" );
+    free( current_user_path );
     strcpy( p, "/user.reg" );
     load_init_registry_from_file( filename, key );
     release_object( key );
diff --git a/server/request.h b/server/request.h
index ea47a77536e..71dbc7d0078 100644
--- a/server/request.h
+++ b/server/request.h
@@ -302,6 +302,7 @@ DECL_HANDLER(get_token_privileges);
 DECL_HANDLER(check_token_privileges);
 DECL_HANDLER(duplicate_token);
 DECL_HANDLER(access_check);
+DECL_HANDLER(get_token_user);
 DECL_HANDLER(create_mailslot);
 DECL_HANDLER(open_mailslot);
 DECL_HANDLER(set_mailslot_info);
@@ -510,6 +511,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_check_token_privileges,
     (req_handler)req_duplicate_token,
     (req_handler)req_access_check,
+    (req_handler)req_get_token_user,
     (req_handler)req_create_mailslot,
     (req_handler)req_open_mailslot,
     (req_handler)req_set_mailslot_info,
diff --git a/server/security.h b/server/security.h
index 1864c4f106e..7fec9ed40d3 100644
--- a/server/security.h
+++ b/server/security.h
@@ -39,6 +39,8 @@ extern const LUID SeManageVolumePrivilege;
 extern const LUID SeImpersonatePrivilege;
 extern const LUID SeCreateGlobalPrivilege;
 
+extern const PSID security_interactive_sid;
+
 extern struct token *token_create_admin(void);
 extern int token_check_privileges( struct token *token, int all_required,
                                    const LUID_AND_ATTRIBUTES *reqprivs,
diff --git a/server/token.c b/server/token.c
index cdcd31da473..e42e891d844 100644
--- a/server/token.c
+++ b/server/token.c
@@ -34,6 +34,8 @@
 #include "request.h"
 #include "security.h"
 
+#include "wine/unicode.h"
+
 #define MAX_SUBAUTH_COUNT 1
 
 const LUID SeIncreaseQuotaPrivilege        = {  5, 0 };
@@ -62,10 +64,11 @@ static const SID local_sid = { SID_REVISION, 1, { SECURITY_LOCAL_SID_AUTHORITY }
 static const SID interactive_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_INTERACTIVE_RID } };
 static const SID authenticated_user_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_AUTHENTICATED_USER_RID } };
 static const SID local_system_sid = { SID_REVISION, 1, { SECURITY_NT_AUTHORITY }, { SECURITY_LOCAL_SYSTEM_RID } };
-static PSID security_world_sid = (PSID)&world_sid;
-static PSID security_local_sid = (PSID)&local_sid;
-static PSID security_interactive_sid = (PSID)&interactive_sid;
-static PSID security_authenticated_user_sid = (PSID)&authenticated_user_sid;
+static const PSID security_world_sid = (PSID)&world_sid;
+static const PSID security_local_sid = (PSID)&local_sid;
+const PSID security_interactive_sid = (PSID)&interactive_sid;
+static const PSID security_authenticated_user_sid = (PSID)&authenticated_user_sid;
+static const PSID security_local_system_sid = (PSID)&local_system_sid;
 
 struct token
 {
@@ -557,9 +560,9 @@ struct token *token_create_admin( void )
             { alias_admins_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
             { alias_users_sid, SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY },
         };
-        /* note: we just set the user sid to be the local system builtin sid -
-         * telling us what this should be is the job of a client-side program */
-        token = create_token( TRUE, &local_system_sid,
+        /* note: we just set the user sid to be the interactive builtin sid -
+         * we should really translate the UNIX user id to a sid */
+        token = create_token( TRUE, &interactive_sid,
                             admin_groups, sizeof(admin_groups)/sizeof(admin_groups[0]),
                             admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]),
                             default_dacl );
@@ -1091,3 +1094,29 @@ DECL_HANDLER(access_check)
         release_object( token );
     }
 }
+
+/* */
+DECL_HANDLER(get_token_user)
+{
+    struct token *token;
+
+    reply->user_len = 0;
+
+    if ((token = (struct token *)get_handle_obj( current->process, req->handle,
+                                                 TOKEN_QUERY,
+                                                 &token_ops )))
+    {
+        const SID *user = token->user;
+
+        reply->user_len = FIELD_OFFSET(SID, SubAuthority[user->SubAuthorityCount]);
+        if (reply->user_len <= get_reply_max_size())
+        {
+            SID *user_reply = set_reply_data_size( reply->user_len );
+            if (user_reply)
+                memcpy( user_reply, user, reply->user_len );
+        }
+        else set_error( STATUS_BUFFER_TOO_SMALL );
+
+        release_object( token );
+    }
+}
diff --git a/server/trace.c b/server/trace.c
index 304cc6ac998..94139568466 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -446,6 +446,13 @@ static void dump_inline_sid( const SID *sid, size_t size )
     fputc( '}', stderr );
 }
 
+static void dump_varargs_SID( size_t size )
+{
+    const SID *sid = cur_data;
+    dump_inline_sid( sid, size );
+    remove_data( size );
+}
+
 static void dump_inline_acl( const ACL *acl, size_t size )
 {
     const ACE_HEADER *ace;
@@ -3011,6 +3018,18 @@ static void dump_access_check_reply( const struct access_check_reply *req )
     dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
 }
 
+static void dump_get_token_user_request( const struct get_token_user_request *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_token_user_reply( const struct get_token_user_reply *req )
+{
+    fprintf( stderr, " user_len=%d,", req->user_len );
+    fprintf( stderr, " user=" );
+    dump_varargs_SID( cur_size );
+}
+
 static void dump_create_mailslot_request( const struct create_mailslot_request *req )
 {
     fprintf( stderr, " max_msgsize=%08x,", req->max_msgsize );
@@ -3254,6 +3273,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_check_token_privileges_request,
     (dump_func)dump_duplicate_token_request,
     (dump_func)dump_access_check_request,
+    (dump_func)dump_get_token_user_request,
     (dump_func)dump_create_mailslot_request,
     (dump_func)dump_open_mailslot_request,
     (dump_func)dump_set_mailslot_info_request,
@@ -3459,6 +3479,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_check_token_privileges_reply,
     (dump_func)dump_duplicate_token_reply,
     (dump_func)dump_access_check_reply,
+    (dump_func)dump_get_token_user_reply,
     (dump_func)dump_create_mailslot_reply,
     (dump_func)dump_open_mailslot_reply,
     (dump_func)dump_set_mailslot_info_reply,
@@ -3664,6 +3685,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "check_token_privileges",
     "duplicate_token",
     "access_check",
+    "get_token_user",
     "create_mailslot",
     "open_mailslot",
     "set_mailslot_info",
-- 
GitLab