- 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",