- Implement AdjustTokenPrivileges, DuplicateTokenEx and
GetTokenInformation (for the TokenPrivileges case).
- Return STATUS_NO_TOKEN for OpenThreadToken when there is no token
set for the thread.
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c
index fe4c962..6b12d94 100644
--- a/dlls/advapi32/security.c
+++ b/dlls/advapi32/security.c
@@ -238,9 +238,18 @@
LPVOID NewState, DWORD BufferLength,
LPVOID PreviousState, LPDWORD ReturnLength )
{
- return set_ntstatus( NtAdjustPrivilegesToken(TokenHandle, DisableAllPrivileges,
+ NTSTATUS status;
+
+ TRACE("\n");
+
+ status = NtAdjustPrivilegesToken(TokenHandle, DisableAllPrivileges,
NewState, BufferLength, PreviousState,
- ReturnLength));
+ ReturnLength);
+ SetLastError( RtlNtStatusToDosError( status ));
+ if ((status == STATUS_SUCCESS) || (status == STATUS_NOT_ALL_ASSIGNED))
+ return TRUE;
+ else
+ return FALSE;
}
/******************************************************************************
@@ -2996,10 +3005,24 @@
TOKEN_TYPE TokenType,
PHANDLE DuplicateTokenHandle )
{
- FIXME("%p 0x%08lx 0x%08x 0x%08x %p - stub\n", ExistingTokenHandle, dwDesiredAccess,
+ OBJECT_ATTRIBUTES ObjectAttributes;
+
+ TRACE("%p 0x%08lx 0x%08x 0x%08x %p\n", ExistingTokenHandle, dwDesiredAccess,
ImpersonationLevel, TokenType, DuplicateTokenHandle);
- return FALSE;
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ NULL,
+ (lpTokenAttributes && lpTokenAttributes->bInheritHandle) ? OBJ_INHERIT : 0,
+ NULL,
+ lpTokenAttributes ? lpTokenAttributes->lpSecurityDescriptor : NULL );
+
+ return set_ntstatus( NtDuplicateToken( ExistingTokenHandle,
+ dwDesiredAccess,
+ &ObjectAttributes,
+ ImpersonationLevel,
+ TokenType,
+ DuplicateTokenHandle ) );
}
BOOL WINAPI DuplicateToken(
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index c359707..e70bf27 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -88,11 +88,26 @@
IN TOKEN_TYPE TokenType,
OUT PHANDLE NewToken)
{
- FIXME("(%p,0x%08lx,%p,0x%08x,0x%08x,%p),stub!\n",
- ExistingToken, DesiredAccess, ObjectAttributes,
- ImpersonationLevel, TokenType, NewToken);
- dump_ObjectAttributes(ObjectAttributes);
- return 0;
+ NTSTATUS status;
+
+ TRACE("(%p,0x%08lx,%p,0x%08x,0x%08x,%p)\n",
+ ExistingToken, DesiredAccess, ObjectAttributes,
+ ImpersonationLevel, TokenType, NewToken);
+ dump_ObjectAttributes(ObjectAttributes);
+
+ SERVER_START_REQ( duplicate_token )
+ {
+ req->handle = ExistingToken;
+ req->access = DesiredAccess;
+ req->inherit = ObjectAttributes && (ObjectAttributes->Attributes & OBJ_INHERIT);
+ req->primary = (TokenType == TokenPrimary);
+ req->impersonation_level = ImpersonationLevel;
+ status = wine_server_call( req );
+ if (!status) *NewToken = reply->new_handle;
+ }
+ SERVER_END_REQ;
+
+ return status;
}
/******************************************************************************
@@ -162,9 +177,34 @@
OUT PTOKEN_PRIVILEGES PreviousState,
OUT PDWORD ReturnLength)
{
- FIXME("(%p,0x%08x,%p,0x%08lx,%p,%p),stub!\n",
- TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength);
- return 0;
+ NTSTATUS ret;
+
+ TRACE("(%p,0x%08x,%p,0x%08lx,%p,%p)\n",
+ TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength);
+
+ SERVER_START_REQ( adjust_token_privileges )
+ {
+ req->handle = TokenHandle;
+ req->disable_all = DisableAllPrivileges;
+ req->get_modified_state = (PreviousState != NULL);
+ if (!DisableAllPrivileges)
+ {
+ wine_server_add_data( req, &NewState->Privileges,
+ NewState->PrivilegeCount * sizeof(NewState->Privileges[0]) );
+ }
+ if (PreviousState && BufferLength >= FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges ))
+ wine_server_set_reply( req, &PreviousState->Privileges,
+ BufferLength - FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges ) );
+ ret = wine_server_call( req );
+ if (PreviousState)
+ {
+ *ReturnLength = reply->len + FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges );
+ PreviousState->PrivilegeCount = reply->len / sizeof(LUID_AND_ATTRIBUTES);
+ }
+ }
+ SERVER_END_REQ;
+
+ return ret;
}
/******************************************************************************
@@ -185,6 +225,7 @@
LPDWORD retlen )
{
unsigned int len = 0;
+ NTSTATUS status = STATUS_SUCCESS;
TRACE("(%p,%ld,%p,%ld,%p)\n",
token,tokeninfoclass,tokeninfo,tokeninfolength,retlen);
@@ -197,9 +238,6 @@
case TokenGroups:
len = sizeof(TOKEN_GROUPS);
break;
- case TokenPrivileges:
- len = sizeof(TOKEN_PRIVILEGES);
- break;
case TokenOwner:
len = sizeof(TOKEN_OWNER) + sizeof(SID);
break;
@@ -271,11 +309,17 @@
}
break;
case TokenPrivileges:
- if (tokeninfo)
+ SERVER_START_REQ( get_token_privileges )
{
TOKEN_PRIVILEGES *tpriv = tokeninfo;
- tpriv->PrivilegeCount = 1;
+ req->handle = token;
+ if (tpriv && tokeninfolength > FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges ))
+ wine_server_set_reply( req, &tpriv->Privileges, tokeninfolength - FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges ) );
+ status = wine_server_call( req );
+ *retlen = FIELD_OFFSET( TOKEN_PRIVILEGES, Privileges ) + reply->len;
+ if (tpriv) tpriv->PrivilegeCount = reply->len / sizeof(LUID_AND_ATTRIBUTES);
}
+ SERVER_END_REQ;
break;
case TokenOwner:
if (tokeninfo)
@@ -294,7 +338,7 @@
return STATUS_NOT_IMPLEMENTED;
}
}
- return 0;
+ return status;
}
/******************************************************************************
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index b375e0b..445ee70 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -3171,6 +3171,50 @@
#define SET_GLOBAL_TASKMAN_WINDOW 0x04
+struct adjust_token_privileges_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+ int disable_all;
+ int get_modified_state;
+ /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
+};
+struct adjust_token_privileges_reply
+{
+ struct reply_header __header;
+ unsigned int len;
+ /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
+};
+
+
+struct get_token_privileges_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+};
+struct get_token_privileges_reply
+{
+ struct reply_header __header;
+ unsigned int len;
+ /* VARARG(privileges,LUID_AND_ATTRIBUTES); */
+};
+
+struct duplicate_token_request
+{
+ struct request_header __header;
+ obj_handle_t handle;
+ unsigned int access;
+ int inherit;
+ int primary;
+ int impersonation_level;
+};
+struct duplicate_token_reply
+{
+ struct reply_header __header;
+ obj_handle_t new_handle;
+};
+
+
enum request
{
REQ_new_process,
@@ -3353,6 +3397,9 @@
REQ_set_clipboard_info,
REQ_open_token,
REQ_set_global_windows,
+ REQ_adjust_token_privileges,
+ REQ_get_token_privileges,
+ REQ_duplicate_token,
REQ_NB_REQUESTS
};
@@ -3540,6 +3587,9 @@
struct set_clipboard_info_request set_clipboard_info_request;
struct open_token_request open_token_request;
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 duplicate_token_request duplicate_token_request;
};
union generic_reply
{
@@ -3725,8 +3775,11 @@
struct set_clipboard_info_reply set_clipboard_info_reply;
struct open_token_reply open_token_reply;
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 duplicate_token_reply duplicate_token_reply;
};
-#define SERVER_PROTOCOL_VERSION 156
+#define SERVER_PROTOCOL_VERSION 157
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winnt.h b/include/winnt.h
index 1dbe3af..4abae5c 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -2808,6 +2808,7 @@
#define SE_PRIVILEGE_ENABLED_BY_DEFAULT 0x00000001
#define SE_PRIVILEGE_ENABLED 0x00000002
+#define SE_PRIVILEGE_REMOVE 0x00000004
#define SE_PRIVILEGE_USED_FOR_ACCESS 0x80000000
#define SE_OWNER_DEFAULTED 0x00000001
diff --git a/include/winternl.h b/include/winternl.h
index cd202ea..23c4b27 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1396,6 +1396,7 @@
NTSTATUS WINAPI NtDeleteValueKey(HKEY,const UNICODE_STRING *);
NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG);
NTSTATUS WINAPI NtDuplicateObject(HANDLE,HANDLE,HANDLE,PHANDLE,ACCESS_MASK,ULONG,ULONG);
+NTSTATUS WINAPI NtDuplicateToken(HANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
NTSTATUS WINAPI NtEnumerateKey(HKEY,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *);
NTSTATUS WINAPI NtEnumerateValueKey(HKEY,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
NTSTATUS WINAPI NtFlushBuffersFile(HANDLE,IO_STATUS_BLOCK*);
diff --git a/server/object.h b/server/object.h
index e3c2a5d..c42b49c 100644
--- a/server/object.h
+++ b/server/object.h
@@ -153,7 +153,7 @@
/* token functions */
-extern struct token *create_token(void);
+extern struct token *create_admin_token(void);
/* atom functions */
diff --git a/server/process.c b/server/process.c
index fc69e50..36cf4c1 100644
--- a/server/process.c
+++ b/server/process.c
@@ -278,7 +278,7 @@
process->exe.namelen = 0;
process->exe.filename = NULL;
process->group_id = 0;
- process->token = create_token();
+ process->token = create_admin_token();
list_init( &process->locks );
list_init( &process->classes );
diff --git a/server/protocol.def b/server/protocol.def
index 94af8ad..1de2607 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2229,3 +2229,32 @@
#define SET_GLOBAL_SHELL_WINDOWS 0x01 /* set both main shell and listview windows */
#define SET_GLOBAL_PROGMAN_WINDOW 0x02
#define SET_GLOBAL_TASKMAN_WINDOW 0x04
+
+/* Adjust the privileges held by a token */
+@REQ(adjust_token_privileges)
+ obj_handle_t handle; /* handle to the token */
+ int disable_all; /* disable all privileges? */
+ int get_modified_state; /* get modified privileges? */
+ VARARG(privileges,LUID_AND_ATTRIBUTES); /* privileges to enable/disable/remove */
+@REPLY
+ unsigned int len; /* total length in bytes required to store token privileges */
+ VARARG(privileges,LUID_AND_ATTRIBUTES); /* modified privileges */
+@END
+
+/* Retrieves the set of privileges held by or available to a token */
+@REQ(get_token_privileges)
+ obj_handle_t handle; /* handle to the token */
+@REPLY
+ unsigned int len; /* total length in bytes required to store token 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 */
+ int inherit; /* inherit flag */
+ int primary; /* is the new token to be a primary one? */
+ int impersonation_level; /* impersonation level of the new token */
+@REPLY
+ obj_handle_t new_handle; /* duplicated handle */
+@END
diff --git a/server/request.h b/server/request.h
index 2b77919..3902c7b 100644
--- a/server/request.h
+++ b/server/request.h
@@ -283,6 +283,9 @@
DECL_HANDLER(set_clipboard_info);
DECL_HANDLER(open_token);
DECL_HANDLER(set_global_windows);
+DECL_HANDLER(adjust_token_privileges);
+DECL_HANDLER(get_token_privileges);
+DECL_HANDLER(duplicate_token);
#ifdef WANT_REQUEST_HANDLERS
@@ -469,6 +472,9 @@
(req_handler)req_set_clipboard_info,
(req_handler)req_open_token,
(req_handler)req_set_global_windows,
+ (req_handler)req_adjust_token_privileges,
+ (req_handler)req_get_token_privileges,
+ (req_handler)req_duplicate_token,
};
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/token.c b/server/token.c
index 67d42b4..94a2167 100644
--- a/server/token.c
+++ b/server/token.c
@@ -35,9 +35,19 @@
struct token
{
struct object obj; /* object header */
+ struct list privileges; /* privileges available to the token */
+};
+
+struct privilege
+{
+ struct list entry;
+ LUID luid;
+ int enabled : 1; /* is the privilege currently enabled? */
+ int def : 1; /* is the privilege enabled by default? */
};
static void token_dump( struct object *obj, int verbose );
+static void token_destroy( struct object *obj );
static const struct object_ops token_ops =
{
@@ -48,7 +58,7 @@
NULL, /* signaled */
NULL, /* satified */
no_get_fd, /* get_fd */
- no_destroy /* destroy */
+ token_destroy /* destroy */
};
@@ -57,12 +67,163 @@
fprintf( stderr, "Security token\n" );
}
-struct token *create_token( void )
+static inline int is_equal_luid( const LUID *luid1, const LUID *luid2 )
+{
+ return (luid1->LowPart == luid2->LowPart && luid1->HighPart == luid2->HighPart);
+}
+
+static inline void luid_and_attr_from_privilege( LUID_AND_ATTRIBUTES *out, const struct privilege *in)
+{
+ out->Luid = in->luid;
+ out->Attributes =
+ (in->enabled ? SE_PRIVILEGE_ENABLED : 0) |
+ (in->def ? SE_PRIVILEGE_ENABLED_BY_DEFAULT : 0);
+}
+
+static struct privilege *privilege_add( struct token *token, const LUID *luid, int enabled )
+{
+ struct privilege *privilege = mem_alloc( sizeof(*privilege) );
+ if (privilege)
+ {
+ privilege->luid = *luid;
+ privilege->def = privilege->enabled = (enabled != 0);
+ list_add_tail( &token->privileges, &privilege->entry );
+ }
+ return privilege;
+}
+
+static void privilege_remove( struct privilege *privilege )
+{
+ list_remove( &privilege->entry );
+ free( privilege );
+}
+
+static void token_destroy( struct object *obj )
+{
+ struct token* token;
+ struct list *cursor, *cursor_next;
+
+ assert( obj->ops == &token_ops );
+ token = (struct token *)obj;
+
+ LIST_FOR_EACH_SAFE( cursor, cursor_next, &token->privileges )
+ {
+ struct privilege *privilege = LIST_ENTRY( cursor, struct privilege, entry );
+ privilege_remove( privilege );
+ }
+}
+
+static struct token *create_token( const LUID_AND_ATTRIBUTES *privs, unsigned int priv_count )
{
struct token *token = alloc_object( &token_ops );
+ if (token)
+ {
+ int i;
+ list_init( &token->privileges );
+ for (i = 0; i < priv_count; i++)
+ {
+ /* note: we don't check uniqueness: the caller must make sure
+ * privs doesn't contain any duplicate luids */
+ if (!privilege_add( token, &privs[i].Luid,
+ privs[i].Attributes & SE_PRIVILEGE_ENABLED ))
+ {
+ release_object( token );
+ return NULL;
+ }
+ }
+ }
return token;
}
+struct token *create_admin_token( void )
+{
+ static 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 */
+ };
+ return create_token( admin_privs, sizeof(admin_privs)/sizeof(admin_privs[0]) );
+}
+
+static struct privilege *token_find_privilege( struct token *token, const LUID *luid, int enabled_only)
+{
+ struct privilege *privilege;
+ LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
+ {
+ if (is_equal_luid( luid, &privilege->luid ))
+ {
+ if (enabled_only && !privilege->enabled)
+ return NULL;
+ return privilege;
+ }
+ }
+ return NULL;
+}
+
+static unsigned int token_adjust_privileges( struct token *token, const LUID_AND_ATTRIBUTES *privs,
+ unsigned int count, LUID_AND_ATTRIBUTES *mod_privs,
+ unsigned int mod_privs_count)
+{
+ int i;
+ unsigned int modified_count = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ struct privilege *privilege =
+ token_find_privilege( token, &privs[i].Luid, FALSE );
+ if (!privilege)
+ {
+ set_error( STATUS_NOT_ALL_ASSIGNED );
+ continue;
+ }
+
+ if (privs[i].Attributes & SE_PRIVILEGE_REMOVE)
+ privilege_remove( privilege );
+ else
+ {
+ /* save previous state for caller */
+ if (mod_privs_count)
+ {
+ luid_and_attr_from_privilege(mod_privs, privilege);
+ mod_privs++;
+ mod_privs_count--;
+ modified_count++;
+ }
+
+ if (privs[i].Attributes & SE_PRIVILEGE_ENABLED)
+ privilege->enabled = TRUE;
+ else
+ privilege->enabled = FALSE;
+ }
+ }
+ return modified_count;
+}
+
+static void token_disable_privileges( struct token *token )
+{
+ struct privilege *privilege;
+ LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
+ privilege->enabled = FALSE;
+}
+
/* open a security token */
DECL_HANDLER(open_token)
{
@@ -73,6 +234,8 @@
{
if (thread->token)
reply->token = alloc_handle( current->process, thread->token, TOKEN_ALL_ACCESS, 0);
+ else
+ set_error(STATUS_NO_TOKEN);
release_object( thread );
}
}
@@ -83,7 +246,117 @@
{
if (process->token)
reply->token = alloc_handle( current->process, process->token, TOKEN_ALL_ACCESS, 0);
+ else
+ set_error(STATUS_NO_TOKEN);
release_object( process );
}
}
}
+
+/* adjust the privileges held by a token */
+DECL_HANDLER(adjust_token_privileges)
+{
+ struct token *token;
+ unsigned int access = TOKEN_ADJUST_PRIVILEGES;
+
+ if (req->get_modified_state) access |= TOKEN_QUERY;
+
+ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
+ access, &token_ops )))
+ {
+ const LUID_AND_ATTRIBUTES *privs = get_req_data();
+ LUID_AND_ATTRIBUTES *modified_privs = NULL;
+ unsigned int priv_count = get_req_data_size() / sizeof(LUID_AND_ATTRIBUTES);
+ unsigned int modified_priv_count = 0;
+
+ if (req->get_modified_state && !req->disable_all)
+ {
+ int i;
+ /* count modified privs */
+ for (i = 0; i < priv_count; i++)
+ {
+ struct privilege *privilege =
+ token_find_privilege( token, &privs[i].Luid, FALSE );
+ if (privilege && req->get_modified_state)
+ modified_priv_count++;
+ }
+ reply->len = modified_priv_count;
+ modified_priv_count = min( modified_priv_count, get_reply_max_size() / sizeof(*modified_privs) );
+ if (modified_priv_count)
+ modified_privs = set_reply_data_size( modified_priv_count * sizeof(*modified_privs) );
+ }
+ reply->len = modified_priv_count * sizeof(*modified_privs);
+
+ if (req->disable_all)
+ token_disable_privileges( token );
+ else
+ modified_priv_count = token_adjust_privileges( token, privs,
+ priv_count, modified_privs, modified_priv_count );
+
+ release_object( token );
+ }
+}
+
+/* retrieves the list of privileges that may be held be the token */
+DECL_HANDLER(get_token_privileges)
+{
+ struct token *token;
+
+ if ((token = (struct token *)get_handle_obj( current->process, req->handle,
+ TOKEN_QUERY,
+ &token_ops )))
+ {
+ int priv_count = 0;
+ LUID_AND_ATTRIBUTES *privs;
+ struct privilege *privilege;
+
+ LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
+ priv_count++;
+
+ reply->len = priv_count * sizeof(*privs);
+ if (reply->len <= get_reply_max_size())
+ {
+ privs = set_reply_data_size( priv_count * sizeof(*privs) );
+ if (privs)
+ {
+ int i = 0;
+ LIST_FOR_EACH_ENTRY( privilege, &token->privileges, struct privilege, entry )
+ {
+ luid_and_attr_from_privilege( &privs[i], privilege );
+ i++;
+ }
+ }
+ }
+ else
+ set_error(STATUS_BUFFER_TOO_SMALL);
+
+ release_object( token );
+ }
+}
+
+/* creates a duplicate of the token */
+DECL_HANDLER(duplicate_token)
+{
+ struct token *src_token;
+ if ((src_token = (struct token *)get_handle_obj( current->process, req->handle,
+ TOKEN_DUPLICATE,
+ &token_ops )))
+ {
+ /* FIXME: use req->primary and req->impersonation_level */
+ struct token *token = create_token( NULL, 0 );
+ if (token)
+ {
+ struct privilege *privilege;
+ unsigned int access;
+
+ LIST_FOR_EACH_ENTRY( privilege, &src_token->privileges, struct privilege, entry )
+ privilege_add( token, &privilege->luid, privilege->enabled );
+
+ access = req->access;
+ if (access & MAXIMUM_ALLOWED) access = TOKEN_ALL_ACCESS; /* FIXME: needs general solution */
+ reply->new_handle = alloc_handle( current->process, token, access, req->inherit);
+ release_object( token );
+ }
+ release_object( src_token );
+ }
+}
diff --git a/server/trace.c b/server/trace.c
index b499013..bfd6919 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -407,6 +407,23 @@
remove_data( size );
}
+static void dump_varargs_LUID_AND_ATTRIBUTES( size_t size )
+{
+ const LUID_AND_ATTRIBUTES *lat = cur_data;
+ size_t len = size / sizeof(*lat);
+
+ fputc( '{', stderr );
+ while (len > 0)
+ {
+ fprintf( stderr, "{luid=%08lx%08lx,attr=%lx}",
+ lat->Luid.HighPart, lat->Luid.LowPart, lat->Attributes );
+ lat++;
+ if (--len) fputc( ',', stderr );
+ }
+ fputc( '}', stderr );
+ remove_data( size );
+}
+
typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */
@@ -2623,6 +2640,48 @@
fprintf( stderr, " old_taskman_window=%p", req->old_taskman_window );
}
+static void dump_adjust_token_privileges_request( const struct adjust_token_privileges_request *req )
+{
+ fprintf( stderr, " handle=%p,", req->handle );
+ fprintf( stderr, " disable_all=%d,", req->disable_all );
+ fprintf( stderr, " get_modified_state=%d,", req->get_modified_state );
+ fprintf( stderr, " privileges=" );
+ dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
+}
+
+static void dump_adjust_token_privileges_reply( const struct adjust_token_privileges_reply *req )
+{
+ fprintf( stderr, " len=%08x,", req->len );
+ fprintf( stderr, " privileges=" );
+ dump_varargs_LUID_AND_ATTRIBUTES( cur_size );
+}
+
+static void dump_get_token_privileges_request( const struct get_token_privileges_request *req )
+{
+ fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_token_privileges_reply( const struct get_token_privileges_reply *req )
+{
+ fprintf( stderr, " len=%08x,", req->len );
+ 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 );
+ fprintf( stderr, " access=%08x,", req->access );
+ fprintf( stderr, " inherit=%d,", req->inherit );
+ fprintf( stderr, " primary=%d,", req->primary );
+ fprintf( stderr, " impersonation_level=%d", req->impersonation_level );
+}
+
+static void dump_duplicate_token_reply( const struct duplicate_token_reply *req )
+{
+ fprintf( stderr, " new_handle=%p", req->new_handle );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -2804,6 +2863,9 @@
(dump_func)dump_set_clipboard_info_request,
(dump_func)dump_open_token_request,
(dump_func)dump_set_global_windows_request,
+ (dump_func)dump_adjust_token_privileges_request,
+ (dump_func)dump_get_token_privileges_request,
+ (dump_func)dump_duplicate_token_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2987,6 +3049,9 @@
(dump_func)dump_set_clipboard_info_reply,
(dump_func)dump_open_token_reply,
(dump_func)dump_set_global_windows_reply,
+ (dump_func)dump_adjust_token_privileges_reply,
+ (dump_func)dump_get_token_privileges_reply,
+ (dump_func)dump_duplicate_token_reply,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -3170,6 +3235,9 @@
"set_clipboard_info",
"open_token",
"set_global_windows",
+ "adjust_token_privileges",
+ "get_token_privileges",
+ "duplicate_token",
};
/* ### make_requests end ### */