server: Add get_token_impersonation_level server call for retrieving the impersonation level from a token.
Add tests for GetTokenInformation(TokenImpersonationLevel).
diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c
index 201c649..95d2f9c 100644
--- a/dlls/advapi32/tests/security.c
+++ b/dlls/advapi32/tests/security.c
@@ -840,7 +840,7 @@
/* test GetTokenInformation for the various attributes */
static void test_token_attr(void)
{
- HANDLE Token;
+ HANDLE Token, ImpersonationToken;
DWORD Size;
TOKEN_PRIVILEGES *Privileges;
TOKEN_GROUPS *Groups;
@@ -848,6 +848,7 @@
BOOL ret;
DWORD i, GLE;
LPSTR SidString;
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
/* cygwin-like use case */
ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &Token);
@@ -855,16 +856,20 @@
if (ret)
{
BYTE buf[1024];
- DWORD bufsize = sizeof(buf);
- ret = GetTokenInformation(Token, TokenUser,(void*)buf, bufsize, &bufsize);
+ Size = sizeof(buf);
+ ret = GetTokenInformation(Token, TokenUser,(void*)buf, Size, &Size);
ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
+ Size = sizeof(ImpersonationLevel);
+ ret = GetTokenInformation(Token, TokenImpersonationLevel, &ImpersonationLevel, Size, &Size);
+ GLE = GetLastError();
+ ok(!ret && (GLE == ERROR_INVALID_PARAMETER), "GetTokenInformation(TokenImpersonationLevel) on primary token should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GLE);
CloseHandle(Token);
}
if(!pConvertSidToStringSidA)
return;
- ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
+ ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &Token);
GLE = GetLastError();
ok(ret || (GLE == ERROR_CALL_NOT_IMPLEMENTED),
"OpenProcessToken failed with error %d\n", GLE);
@@ -928,6 +933,17 @@
trace("\t%s, 0x%x\n", Name, Privileges->Privileges[i].Attributes);
}
HeapFree(GetProcessHeap(), 0, Privileges);
+
+ ret = DuplicateToken(Token, SecurityAnonymous, &ImpersonationToken);
+ ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
+
+ Size = sizeof(ImpersonationLevel);
+ ret = GetTokenInformation(ImpersonationToken, TokenImpersonationLevel, &ImpersonationLevel, Size, &Size);
+ ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError());
+ ok(ImpersonationLevel == SecurityAnonymous, "ImpersonationLevel should have been SecurityAnonymous instead of %d\n", ImpersonationLevel);
+
+ CloseHandle(ImpersonationToken);
+ CloseHandle(Token);
}
typedef union _MAX_SID
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 43ce6e1..ce3c31a 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -217,8 +217,10 @@
case TokenType:
len = sizeof (TOKEN_TYPE);
break;
-#if 0
case TokenImpersonationLevel:
+ len = sizeof(SECURITY_IMPERSONATION_LEVEL);
+ break;
+#if 0
case TokenStatistics:
#endif /* 0 */
default:
@@ -352,6 +354,17 @@
owner->Owner = sid;
}
break;
+ case TokenImpersonationLevel:
+ SERVER_START_REQ( get_token_impersonation_level )
+ {
+ SECURITY_IMPERSONATION_LEVEL *impersonation_level = tokeninfo;
+ req->handle = token;
+ status = wine_server_call( req );
+ if (status == STATUS_SUCCESS)
+ *impersonation_level = reply->impersonation_level;
+ }
+ SERVER_END_REQ;
+ break;
default:
{
ERR("Unhandled Token Information class %d!\n", tokeninfoclass);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index b5c6201..db13e0c 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3992,6 +3992,18 @@
};
+struct get_token_impersonation_level_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+};
+struct get_token_impersonation_level_reply
+{
+ struct reply_header __header;
+ int impersonation_level;
+};
+
+
enum request
{
REQ_new_process,
@@ -4210,6 +4222,7 @@
REQ_open_symlink,
REQ_query_symlink,
REQ_get_object_info,
+ REQ_get_token_impersonation_level,
REQ_NB_REQUESTS
};
@@ -4433,6 +4446,7 @@
struct open_symlink_request open_symlink_request;
struct query_symlink_request query_symlink_request;
struct get_object_info_request get_object_info_request;
+ struct get_token_impersonation_level_request get_token_impersonation_level_request;
};
union generic_reply
{
@@ -4654,8 +4668,9 @@
struct open_symlink_reply open_symlink_reply;
struct query_symlink_reply query_symlink_reply;
struct get_object_info_reply get_object_info_reply;
+ struct get_token_impersonation_level_reply get_token_impersonation_level_reply;
};
-#define SERVER_PROTOCOL_VERSION 277
+#define SERVER_PROTOCOL_VERSION 278
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index e4f16a9..69daab37 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2862,3 +2862,10 @@
unsigned int access; /* granted access mask */
unsigned int ref_count; /* object ref count */
@END
+
+/* Query the impersonation level of an impersonation token */
+@REQ(get_token_impersonation_level)
+ obj_handle_t handle; /* handle to the object */
+@REPLY
+ int impersonation_level; /* impersonation level of the impersonation token */
+@END
diff --git a/server/request.h b/server/request.h
index 9119ec1..b24d7c7 100644
--- a/server/request.h
+++ b/server/request.h
@@ -326,6 +326,7 @@
DECL_HANDLER(open_symlink);
DECL_HANDLER(query_symlink);
DECL_HANDLER(get_object_info);
+DECL_HANDLER(get_token_impersonation_level);
#ifdef WANT_REQUEST_HANDLERS
@@ -548,6 +549,7 @@
(req_handler)req_open_symlink,
(req_handler)req_query_symlink,
(req_handler)req_get_object_info,
+ (req_handler)req_get_token_impersonation_level,
};
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/token.c b/server/token.c
index c4906a5..573634b 100644
--- a/server/token.c
+++ b/server/token.c
@@ -1386,6 +1386,23 @@
}
}
+DECL_HANDLER(get_token_impersonation_level)
+{
+ struct token *token;
+
+ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
+ TOKEN_QUERY,
+ &token_ops )))
+ {
+ if (token->primary)
+ set_error( STATUS_INVALID_PARAMETER );
+ else
+ reply->impersonation_level = token->impersonation_level;
+
+ release_object( token );
+ }
+}
+
DECL_HANDLER(set_security_object)
{
data_size_t sd_size = get_req_data_size();
diff --git a/server/trace.c b/server/trace.c
index 50926f5..d4bcf08 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3443,6 +3443,16 @@
fprintf( stderr, " ref_count=%08x", req->ref_count );
}
+static void dump_get_token_impersonation_level_request( const struct get_token_impersonation_level_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_token_impersonation_level_reply( const struct get_token_impersonation_level_reply *req )
+{
+ fprintf( stderr, " impersonation_level=%d", req->impersonation_level );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -3660,6 +3670,7 @@
(dump_func)dump_open_symlink_request,
(dump_func)dump_query_symlink_request,
(dump_func)dump_get_object_info_request,
+ (dump_func)dump_get_token_impersonation_level_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -3879,6 +3890,7 @@
(dump_func)dump_open_symlink_reply,
(dump_func)dump_query_symlink_reply,
(dump_func)dump_get_object_info_reply,
+ (dump_func)dump_get_token_impersonation_level_reply,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -4098,6 +4110,7 @@
"open_symlink",
"query_symlink",
"get_object_info",
+ "get_token_impersonation_level",
};
static const struct