- Clean up well-known privileges.
- Implement checking tokens for privileges in the server.
- Implement NtPrivilegeCheck.

diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index 7fd2ffc..bcc3f45 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -376,6 +376,34 @@
     return STATUS_NOT_IMPLEMENTED;
 }
 
+/******************************************************************************
+*  NtPrivilegeCheck		[NTDLL.@]
+*  ZwPrivilegeCheck		[NTDLL.@]
+*/
+NTSTATUS WINAPI NtPrivilegeCheck(
+    HANDLE ClientToken,
+    PPRIVILEGE_SET RequiredPrivileges,
+    PBOOLEAN Result)
+{
+    NTSTATUS status;
+    SERVER_START_REQ( check_token_privileges )
+    {
+        req->handle = ClientToken;
+        req->all_required = ((RequiredPrivileges->Control & PRIVILEGE_SET_ALL_NECESSARY) ? TRUE : FALSE);
+        wine_server_add_data( req, &RequiredPrivileges->Privilege,
+            RequiredPrivileges->PrivilegeCount * sizeof(RequiredPrivileges->Privilege[0]) );
+        wine_server_set_reply( req, &RequiredPrivileges->Privilege,
+            RequiredPrivileges->PrivilegeCount * sizeof(RequiredPrivileges->Privilege[0]) );
+
+        status = wine_server_call( req );
+
+        if (status == STATUS_SUCCESS)
+            *Result = (reply->has_privileges ? TRUE : FALSE);
+    }
+    SERVER_END_REQ;
+    return status;
+}
+
 /*
  *	Section
  */
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 0ef50d7..317a528 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -156,7 +156,7 @@
 @ stdcall NtOpenTimer(ptr long ptr)
 @ stub NtPlugPlayControl
 @ stdcall NtPowerInformation(long ptr long ptr long)
-@ stub NtPrivilegeCheck
+@ stdcall NtPrivilegeCheck(ptr ptr ptr)
 @ stub NtPrivilegeObjectAuditAlarm
 @ stub NtPrivilegedServiceAuditAlarm
 @ stdcall NtProtectVirtualMemory(long ptr ptr long ptr)
@@ -746,7 +746,7 @@
 @ stdcall ZwOpenThreadToken(long long long long) NtOpenThreadToken
 @ stdcall ZwOpenTimer(ptr long ptr) NtOpenTimer
 @ stub ZwPlugPlayControl
-@ stub ZwPrivilegeCheck
+@ stdcall ZwPrivilegeCheck(ptr ptr ptr) NtPrivilegeCheck
 @ stub ZwPrivilegeObjectAuditAlarm
 @ stub ZwPrivilegedServiceAuditAlarm
 @ stdcall ZwProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 7caeae4..eb41556 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3237,6 +3237,21 @@
     /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
 };
 
+
+struct check_token_privileges_request
+{
+    struct request_header __header;
+    obj_handle_t  handle;
+    int           all_required;
+    /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
+};
+struct check_token_privileges_reply
+{
+    struct reply_header __header;
+    int           has_privileges;
+    /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
+};
+
 struct duplicate_token_request
 {
     struct request_header __header;
@@ -3490,6 +3505,7 @@
     REQ_set_global_windows,
     REQ_adjust_token_privileges,
     REQ_get_token_privileges,
+    REQ_check_token_privileges,
     REQ_duplicate_token,
     REQ_create_mailslot,
     REQ_open_mailslot,
@@ -3685,6 +3701,7 @@
     struct set_global_windows_request set_global_windows_request;
     struct adjust_token_privileges_request adjust_token_privileges_request;
     struct get_token_privileges_request get_token_privileges_request;
+    struct check_token_privileges_request check_token_privileges_request;
     struct duplicate_token_request duplicate_token_request;
     struct create_mailslot_request create_mailslot_request;
     struct open_mailslot_request open_mailslot_request;
@@ -3878,12 +3895,13 @@
     struct set_global_windows_reply set_global_windows_reply;
     struct adjust_token_privileges_reply adjust_token_privileges_reply;
     struct get_token_privileges_reply get_token_privileges_reply;
+    struct check_token_privileges_reply check_token_privileges_reply;
     struct duplicate_token_reply duplicate_token_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 169
+#define SERVER_PROTOCOL_VERSION 170
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winnt.h b/include/winnt.h
index 93ae35a..d8a99d9 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -2823,6 +2823,8 @@
 #define SE_PRIVILEGE_REMOVE		0x00000004
 #define SE_PRIVILEGE_USED_FOR_ACCESS 	0x80000000
 
+#define PRIVILEGE_SET_ALL_NECESSARY     1
+
 #define SE_OWNER_DEFAULTED		0x00000001
 #define SE_GROUP_DEFAULTED		0x00000002
 #define SE_DACL_PRESENT			0x00000004
diff --git a/include/winternl.h b/include/winternl.h
index b16efa4..23cd849 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1469,6 +1469,7 @@
 NTSTATUS  WINAPI NtOpenThreadToken(HANDLE,DWORD,BOOLEAN,HANDLE *);
 NTSTATUS  WINAPI NtOpenTimer(HANDLE*, ACCESS_MASK, const OBJECT_ATTRIBUTES*);
 NTSTATUS  WINAPI NtPowerInformation(POWER_INFORMATION_LEVEL,PVOID,ULONG,PVOID,ULONG);
+NTSTATUS  WINAPI NtPrivilegeCheck(HANDLE,PPRIVILEGE_SET,PBOOLEAN);
 NTSTATUS  WINAPI NtProtectVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG,ULONG*);
 NTSTATUS  WINAPI NtPulseEvent(HANDLE,PULONG);
 NTSTATUS  WINAPI NtQueueApcThread(HANDLE,PNTAPCFUNC,ULONG_PTR,ULONG_PTR,ULONG_PTR);
diff --git a/server/object.h b/server/object.h
index 23dd4b5..44dfe18 100644
--- a/server/object.h
+++ b/server/object.h
@@ -149,10 +149,6 @@
 extern void init_signals(void);
 extern void close_signals(void);
 
-/* token functions */
-
-extern struct token *create_admin_token(void);
-
 /* atom functions */
 
 extern void close_atom_table(void);
diff --git a/server/process.c b/server/process.c
index c89fa1c..12f9a1e 100644
--- a/server/process.c
+++ b/server/process.c
@@ -48,6 +48,7 @@
 #include "request.h"
 #include "console.h"
 #include "user.h"
+#include "security.h"
 
 /* process structure */
 
@@ -284,7 +285,7 @@
     process->exe.namelen     = 0;
     process->exe.filename    = NULL;
     process->group_id        = 0;
-    process->token           = create_admin_token();
+    process->token           = token_create_admin();
     list_init( &process->thread_list );
     list_init( &process->locks );
     list_init( &process->classes );
diff --git a/server/protocol.def b/server/protocol.def
index 7825a58..3427fd0 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2275,6 +2275,16 @@
     VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges held by or available to a token */
 @END
 
+/* Check the token has the required privileges */
+@REQ(check_token_privileges)
+    obj_handle_t  handle; /* handle to the token */
+    int           all_required; /* are all the privileges required for the check to succeed? */
+    VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges to check */
+@REPLY
+    int           has_privileges; /* does the token have the required privileges? */
+    VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges held by or available to a token */
+@END
+
 @REQ(duplicate_token)
     obj_handle_t  handle; /* handle to the token to duplicate */
     unsigned int  access; /* access rights to the new token */
diff --git a/server/request.h b/server/request.h
index 5d314db..49228dc 100644
--- a/server/request.h
+++ b/server/request.h
@@ -287,6 +287,7 @@
 DECL_HANDLER(set_global_windows);
 DECL_HANDLER(adjust_token_privileges);
 DECL_HANDLER(get_token_privileges);
+DECL_HANDLER(check_token_privileges);
 DECL_HANDLER(duplicate_token);
 DECL_HANDLER(create_mailslot);
 DECL_HANDLER(open_mailslot);
@@ -481,6 +482,7 @@
     (req_handler)req_set_global_windows,
     (req_handler)req_adjust_token_privileges,
     (req_handler)req_get_token_privileges,
+    (req_handler)req_check_token_privileges,
     (req_handler)req_duplicate_token,
     (req_handler)req_create_mailslot,
     (req_handler)req_open_mailslot,
diff --git a/server/security.h b/server/security.h
new file mode 100644
index 0000000..0be5f20
--- /dev/null
+++ b/server/security.h
@@ -0,0 +1,55 @@
+/*
+ * Security Management
+ *
+ * Copyright (C) 2005 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+extern const LUID SeIncreaseQuotaPrivilege;
+extern const LUID SeSecurityPrivilege;
+extern const LUID SeTakeOwnershipPrivilege;
+extern const LUID SeLoadDriverPrivilege;
+extern const LUID SeSystemProfilePrivilege;
+extern const LUID SeSystemtimePrivilege;
+extern const LUID SeProfileSingleProcessPrivilege;
+extern const LUID SeIncreaseBasePriorityPrivilege;
+extern const LUID SeCreatePagefilePrivilege;
+extern const LUID SeBackupPrivilege;
+extern const LUID SeRestorePrivilege;
+extern const LUID SeShutdownPrivilege;
+extern const LUID SeDebugPrivilege;
+extern const LUID SeSystemEnvironmentPrivilege;
+extern const LUID SeChangeNotifyPrivilege;
+extern const LUID SeRemoteShutdownPrivilege;
+extern const LUID SeUndockPrivilege;
+extern const LUID SeManageVolumePrivilege;
+extern const LUID SeImpersonatePrivilege;
+extern const LUID SeCreateGlobalPrivilege;
+
+extern struct token *token_create_admin(void);
+extern int token_check_privileges( struct token *token, int all_required,
+                                   const LUID_AND_ATTRIBUTES *reqprivs,
+                                   unsigned int count, LUID_AND_ATTRIBUTES *usedprivs);
+
+static inline int thread_single_check_privilege( struct thread *thread, const LUID *priv)
+{
+    struct token *token = thread_get_impersonation_token( thread );
+    const LUID_AND_ATTRIBUTES privs = { *priv, 0 };
+
+    if (!token) return FALSE;
+
+    return token_check_privileges( token, TRUE, &privs, 1, NULL );
+}
diff --git a/server/thread.c b/server/thread.c
index 059aec4..af6657e 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -767,6 +767,15 @@
     return snapshot;
 }
 
+/* gets the current impersonation token */
+struct token *thread_get_impersonation_token( struct thread *thread )
+{
+    if (thread->token)
+        return thread->token;
+    else
+        return thread->process->token;
+}
+
 /* signal that we are finished booting on the client side */
 DECL_HANDLER(boot_done)
 {
diff --git a/server/thread.h b/server/thread.h
index d13199b..d471686 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -114,6 +114,7 @@
 extern int thread_add_inflight_fd( struct thread *thread, int client, int server );
 extern int thread_get_inflight_fd( struct thread *thread, int client );
 extern struct thread_snapshot *thread_snap( int *count );
+extern struct token *thread_get_impersonation_token( struct thread *thread );
 
 /* ptrace functions */
 
diff --git a/server/token.c b/server/token.c
index 94a2167..23fe27c 100644
--- a/server/token.c
+++ b/server/token.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998 Alexandre Julliard
  * Copyright (C) 2003 Mike McCormack
+ * Copyright (C) 2005 Robert Shearman
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,6 +32,28 @@
 #include "thread.h"
 #include "process.h"
 #include "request.h"
+#include "security.h"
+
+const LUID SeIncreaseQuotaPrivilege        = {  5, 0 };
+const LUID SeSecurityPrivilege             = {  8, 0 };
+const LUID SeTakeOwnershipPrivilege        = {  9, 0 };
+const LUID SeLoadDriverPrivilege           = { 10, 0 };
+const LUID SeSystemProfilePrivilege        = { 11, 0 };
+const LUID SeSystemtimePrivilege           = { 12, 0 };
+const LUID SeProfileSingleProcessPrivilege = { 13, 0 };
+const LUID SeIncreaseBasePriorityPrivilege = { 14, 0 };
+const LUID SeCreatePagefilePrivilege       = { 15, 0 };
+const LUID SeBackupPrivilege               = { 17, 0 };
+const LUID SeRestorePrivilege              = { 18, 0 };
+const LUID SeShutdownPrivilege             = { 19, 0 };
+const LUID SeDebugPrivilege                = { 20, 0 };
+const LUID SeSystemEnvironmentPrivilege    = { 22, 0 };
+const LUID SeChangeNotifyPrivilege         = { 23, 0 };
+const LUID SeRemoteShutdownPrivilege       = { 24, 0 };
+const LUID SeUndockPrivilege               = { 25, 0 };
+const LUID SeManageVolumePrivilege         = { 28, 0 };
+const LUID SeImpersonatePrivilege          = { 29, 0 };
+const LUID SeCreateGlobalPrivilege         = { 30, 0 };
 
 struct token
 {
@@ -135,30 +158,30 @@
     return token;
 }
 
-struct token *create_admin_token( void )
+struct token *token_create_admin( void )
 {
-    static const LUID_AND_ATTRIBUTES admin_privs[] =
+    const LUID_AND_ATTRIBUTES admin_privs[] =
     {
-        { { 23, 0 }, SE_PRIVILEGE_ENABLED }, /* SeChangeNotifyPrivilege */
-        { {  8, 0 }, 0                    }, /* SeSecurityPrivilege */
-        { { 17, 0 }, 0                    }, /* SeBackupPrivilege */
-        { { 18, 0 }, 0                    }, /* SeRestorePrivilege */
-        { { 12, 0 }, 0                    }, /* SeSystemtimePrivilege */
-        { { 19, 0 }, 0                    }, /* SeShutdownPrivilege */
-        { { 24, 0 }, 0                    }, /* SeRemoteShutdownPrivilege */
-        { {  9, 0 }, 0                    }, /* SeTakeOwnershipPrivilege */
-        { { 20, 0 }, 0                    }, /* SeDebugPrivilege */
-        { { 22, 0 }, 0                    }, /* SeSystemEnvironmentPrivilege */
-        { { 11, 0 }, 0                    }, /* SeSystemProfilePrivilege */
-        { { 13, 0 }, 0                    }, /* SeProfileSingleProcessPrivilege */
-        { { 14, 0 }, 0                    }, /* SeIncreaseBasePriorityPrivilege */
-        { { 10, 0 }, 0                    }, /* SeLoadDriverPrivilege */
-        { { 15, 0 }, 0                    }, /* SeCreatePagefilePrivilege */
-        { {  5, 0 }, 0                    }, /* SeIncreaseQuotaPrivilege */
-        { { 25, 0 }, 0                    }, /* SeUndockPrivilege */
-        { { 28, 0 }, 0                    }, /* SeManageVolumePrivilege */
-        { { 29, 0 }, SE_PRIVILEGE_ENABLED }, /* SeImpersonatePrivilege */
-        { { 30, 0 }, SE_PRIVILEGE_ENABLED }, /* SeCreateGlobalPrivilege */
+        { SeChangeNotifyPrivilege        , SE_PRIVILEGE_ENABLED },
+        { SeSecurityPrivilege            , 0                    },
+        { SeBackupPrivilege              , 0                    },
+        { SeRestorePrivilege             , 0                    },
+        { SeSystemtimePrivilege          , 0                    },
+        { SeShutdownPrivilege            , 0                    },
+        { SeRemoteShutdownPrivilege      , 0                    },
+        { SeTakeOwnershipPrivilege       , 0                    },
+        { SeDebugPrivilege               , 0                    },
+        { SeSystemEnvironmentPrivilege   , 0                    },
+        { SeSystemProfilePrivilege       , 0                    },
+        { SeProfileSingleProcessPrivilege, 0                    },
+        { SeIncreaseBasePriorityPrivilege, 0                    },
+        { SeLoadDriverPrivilege          , 0                    },
+        { SeCreatePagefilePrivilege      , 0                    },
+        { SeIncreaseQuotaPrivilege       , 0                    },
+        { SeUndockPrivilege              , 0                    },
+        { SeManageVolumePrivilege        , 0                    },
+        { SeImpersonatePrivilege         , SE_PRIVILEGE_ENABLED },
+        { SeCreateGlobalPrivilege        , SE_PRIVILEGE_ENABLED },
     };
     return create_token( admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]) );
 }
@@ -224,6 +247,35 @@
         privilege->enabled = FALSE;
 }
 
+int token_check_privileges( struct token *token, int all_required,
+                            const LUID_AND_ATTRIBUTES *reqprivs,
+                            unsigned int count, LUID_AND_ATTRIBUTES *usedprivs)
+{
+    int i;
+    unsigned int enabled_count = 0;
+
+    for (i = 0; i < count; i++)
+    {
+        struct privilege *privilege = 
+            token_find_privilege( token, &reqprivs[i].Luid, TRUE );
+
+        if (usedprivs)
+            usedprivs[i] = reqprivs[i];
+
+        if (privilege && privilege->enabled)
+        {
+            enabled_count++;
+            if (usedprivs)
+                usedprivs[i].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS;
+        }
+    }
+
+    if (all_required)
+        return (enabled_count == count);
+    else
+        return (enabled_count > 0);
+}
+
 /* open a security token */
 DECL_HANDLER(open_token)
 {
@@ -360,3 +412,24 @@
         release_object( src_token );
     }
 }
+
+/* checks the specified privileges are held by the token */
+DECL_HANDLER(check_token_privileges)
+{
+    struct token *token;
+
+    if ((token = (struct token *)get_handle_obj( current->process, req->handle,
+                                                 TOKEN_QUERY,
+                                                 &token_ops )))
+    {
+        unsigned int count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
+        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 );
+        }
+        else
+            set_error( STATUS_BUFFER_OVERFLOW );
+        release_object( token );
+    }
+}
diff --git a/server/trace.c b/server/trace.c
index 898b000..d12c962 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2689,6 +2689,21 @@
     dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
 }
 
+static void dump_check_token_privileges_request( const struct check_token_privileges_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " all_required=%d,", req->all_required );
+    fprintf( stderr, " privileges=" );
+    dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
+}
+
+static void dump_check_token_privileges_reply( const struct check_token_privileges_reply *req )
+{
+    fprintf( stderr, " has_privileges=%d,", req->has_privileges );
+    fprintf( stderr, " privileges=" );
+    dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
+}
+
 static void dump_duplicate_token_request( const struct duplicate_token_request *req )
 {
     fprintf( stderr, " handle=%p,", req->handle );
@@ -2931,6 +2946,7 @@
     (dump_func)dump_set_global_windows_request,
     (dump_func)dump_adjust_token_privileges_request,
     (dump_func)dump_get_token_privileges_request,
+    (dump_func)dump_check_token_privileges_request,
     (dump_func)dump_duplicate_token_request,
     (dump_func)dump_create_mailslot_request,
     (dump_func)dump_open_mailslot_request,
@@ -3122,6 +3138,7 @@
     (dump_func)dump_set_global_windows_reply,
     (dump_func)dump_adjust_token_privileges_reply,
     (dump_func)dump_get_token_privileges_reply,
+    (dump_func)dump_check_token_privileges_reply,
     (dump_func)dump_duplicate_token_reply,
     (dump_func)dump_create_mailslot_reply,
     (dump_func)dump_open_mailslot_reply,
@@ -3313,6 +3330,7 @@
     "set_global_windows",
     "adjust_token_privileges",
     "get_token_privileges",
+    "check_token_privileges",
     "duplicate_token",
     "create_mailslot",
     "open_mailslot",