Rob Shearman : server: Track the impersonation level of tokens.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Feb 16 07:08:40 CST 2007


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

Author: Rob Shearman <rob at codeweavers.com>
Date:   Thu Feb 15 23:21:40 2007 +0000

server: Track the impersonation level of tokens.

---

 dlls/advapi32/tests/security.c |    8 +----
 server/token.c                 |   62 +++++++++++++++++++++++++++++++--------
 2 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 11863ed..ef342b5 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -812,10 +812,8 @@ static void test_AccessCheck(void)
     ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
                       PrivSet, &PrivSetLen, &Access, &AccessStatus);
     err = GetLastError();
-    todo_wine {
     ok(!ret && err == ERROR_BAD_IMPERSONATION_LEVEL, "AccessCheck should have failed "
        "with ERROR_BAD_IMPERSONATION_LEVEL, instead of %d\n", err);
-    }
 
     CloseHandle(Token);
 
@@ -1572,11 +1570,11 @@ static void test_impersonation_level(void)
     ret = ImpersonateSelf(SecurityAnonymous);
     ok(ret, "ImpersonateSelf(SecurityAnonymous) failed with error %d\n", GetLastError());
     ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
-    todo_wine {
     ok(!ret, "OpenThreadToken should have failed\n");
     error = GetLastError();
     ok(error == ERROR_CANT_OPEN_ANONYMOUS, "OpenThreadToken on anonymous token should have returned ERROR_CANT_OPEN_ANONYMOUS instead of %d\n", error);
     /* can't perform access check when opening object against an anonymous impersonation token */
+    todo_wine {
     error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
     ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error);
     }
@@ -1592,10 +1590,8 @@ static void test_impersonation_level(void)
     /* can't increase the impersonation level */
     ret = DuplicateToken(Token, SecurityIdentification, &Token2);
     error = GetLastError();
-    todo_wine {
     ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL,
         "Duplicating a token and increasing the impersonation level should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
-    }
     /* we can query anything from an anonymous token, including the user */
     ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
     error = GetLastError();
@@ -1621,9 +1617,7 @@ static void test_impersonation_level(void)
 
     ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
     error = GetLastError();
-    todo_wine {
     ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL, "PrivilegeCheck for SecurityAnonymous token should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
-    }
 
     CloseHandle(Token);
 
diff --git a/server/token.c b/server/token.c
index 41a2026..f49b355 100644
--- a/server/token.c
+++ b/server/token.c
@@ -88,6 +88,7 @@ struct token
     unsigned       primary;         /* is this a primary or impersonation token? */
     ACL           *default_dacl;    /* the default DACL to assign to objects created by this user */
     TOKEN_SOURCE   source;          /* source of the token */
+    SECURITY_IMPERSONATION_LEVEL impersonation_level; /* impersonation level this token is capable of if non-primary token */
 };
 
 struct privilege
@@ -428,7 +429,8 @@ static struct token *create_token( unsigned primary, const SID *user,
                                    const SID_AND_ATTRIBUTES *groups, unsigned int group_count,
                                    const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count,
                                    const ACL *default_dacl, TOKEN_SOURCE source,
-                                   const LUID *modified_id )
+                                   const LUID *modified_id,
+                                   SECURITY_IMPERSONATION_LEVEL impersonation_level )
 {
     struct token *token = alloc_object( &token_ops );
     if (token)
@@ -443,6 +445,11 @@ static struct token *create_token( unsigned primary, const SID *user,
         list_init( &token->privileges );
         list_init( &token->groups );
         token->primary = primary;
+        /* primary tokens don't have impersonation levels */
+        if (primary)
+            token->impersonation_level = -1;
+        else
+            token->impersonation_level = impersonation_level;
         token->default_dacl = NULL;
         token->primary_group = NULL;
 
@@ -614,7 +621,7 @@ struct token *token_create_admin( void )
         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, admin_source, NULL );
+                            default_dacl, admin_source, NULL, -1 );
         /* we really need a primary group */
         assert( token->primary_group );
     }
@@ -1007,10 +1014,15 @@ DECL_HANDLER(open_token)
         if (thread)
         {
             if (thread->token)
-                reply->token = alloc_handle( current->process, thread->token, req->access,
-                                             req->attributes );
+            {
+                if (thread->token->impersonation_level <= SecurityAnonymous)
+                    set_error( STATUS_CANT_OPEN_ANONYMOUS );
+                else
+                    reply->token = alloc_handle( current->process, thread->token,
+                                                 req->access, req->attributes );
+            }
             else
-                set_error(STATUS_NO_TOKEN);
+                set_error( STATUS_NO_TOKEN );
             release_object( thread );
         }
     }
@@ -1023,7 +1035,7 @@ DECL_HANDLER(open_token)
                 reply->token = alloc_handle( current->process, process->token, req->access,
                                              req->attributes );
             else
-                set_error(STATUS_NO_TOKEN);
+                set_error( STATUS_NO_TOKEN );
             release_object( process );
         }
     }
@@ -1114,16 +1126,30 @@ DECL_HANDLER(get_token_privileges)
 DECL_HANDLER(duplicate_token)
 {
     struct token *src_token;
+
+    if ((req->impersonation_level < SecurityAnonymous) ||
+        (req->impersonation_level > SecurityDelegation))
+    {
+        set_error( STATUS_BAD_IMPERSONATION_LEVEL );
+        return;
+    }
+
     if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
                                                      TOKEN_DUPLICATE,
                                                      &token_ops )))
     {
-        /* FIXME: use req->impersonation_level */
-        struct token *token = create_token( req->primary, src_token->user,
-                                            NULL, 0, NULL, 0,
-                                            src_token->default_dacl,
-                                            src_token->source,
-                                            &src_token->modified_id );
+        const LUID *modified_id =
+            req->primary || (req->impersonation_level == src_token->impersonation_level) ?
+                &src_token->modified_id : NULL;
+        struct token *token = NULL;
+
+        if (req->primary || (req->impersonation_level <= src_token->impersonation_level))
+            token = create_token( req->primary, src_token->user, NULL, 0,
+                                  NULL, 0, src_token->default_dacl,
+                                  src_token->source, modified_id,
+                                  req->impersonation_level );
+        else set_error( STATUS_BAD_IMPERSONATION_LEVEL );
+
         if (token)
         {
             struct privilege *privilege;
@@ -1170,7 +1196,10 @@ DECL_HANDLER(check_token_privileges)
                                                  &token_ops )))
     {
         unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
-        if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
+
+        if (!token->primary && token->impersonation_level <= SecurityAnonymous)
+            set_error( STATUS_BAD_IMPERSONATION_LEVEL );
+        else if (get_reply_max_size() >= count * sizeof(LUID_AND_ATTRIBUTES))
         {
             LUID_AND_ATTRIBUTES *usedprivs = set_reply_data_size( count * sizeof(*usedprivs) );
             reply->has_privileges = token_check_privileges( token, req->all_required, get_req_data(), count, usedprivs );
@@ -1213,6 +1242,13 @@ DECL_HANDLER(access_check)
             release_object( token );
             return;
         }
+        /* anonymous impersonation tokens can't be used */
+        if (token->impersonation_level <= SecurityAnonymous)
+        {
+            set_error( STATUS_BAD_IMPERSONATION_LEVEL );
+            release_object( token );
+            return;
+        }
 
         mapping.GenericRead = req->mapping_read;
         mapping.GenericWrite = req->mapping_write;




More information about the wine-cvs mailing list