Commit a52cf805 authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

ntdll: Implement NtCreateToken().

parent 50948335
......@@ -192,7 +192,7 @@
@ stdcall -syscall NtCreateThread(ptr long ptr long ptr ptr ptr long)
@ stdcall -syscall NtCreateThreadEx(ptr long ptr long ptr ptr long long long long ptr)
@ stdcall -syscall NtCreateTimer(ptr long ptr long)
# @ stub NtCreateToken
@ stdcall -syscall NtCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr)
@ stdcall -syscall NtCreateTransaction(ptr long ptr ptr long long long long ptr ptr)
@ stdcall -syscall NtCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr)
# @ stub NtCreateWaitablePort
......@@ -1241,7 +1241,7 @@
@ stdcall -private -syscall ZwCreateThread(ptr long ptr long ptr ptr ptr long) NtCreateThread
@ stdcall -private -syscall ZwCreateThreadEx(ptr long ptr long ptr ptr long long long long ptr) NtCreateThreadEx
@ stdcall -private -syscall ZwCreateTimer(ptr long ptr long) NtCreateTimer
# @ stub ZwCreateToken
@ stdcall -private -syscall ZwCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) NtCreateToken
@ stdcall -private -syscall ZwCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) NtCreateUserProcess
# @ stub ZwCreateWaitablePort
@ stdcall -private -syscall ZwDebugActiveProcess(long long) NtDebugActiveProcess
......
......@@ -166,6 +166,7 @@ static void * const syscalls[] =
NtCreateThread,
NtCreateThreadEx,
NtCreateTimer,
NtCreateToken,
NtCreateTransaction,
NtCreateUserProcess,
NtDebugActiveProcess,
......
......@@ -36,6 +36,113 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
static BOOL is_equal_sid( const SID *sid1, const SID *sid2 )
{
size_t size1 = offsetof( SID, SubAuthority[sid1->SubAuthorityCount] );
size_t size2 = offsetof( SID, SubAuthority[sid2->SubAuthorityCount] );
return size1 == size2 && !memcmp( sid1, sid2, size1 );
}
/***********************************************************************
* NtCreateToken (NTDLL.@)
*/
NTSTATUS WINAPI NtCreateToken( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
TOKEN_TYPE type, LUID *token_id, LARGE_INTEGER *expire, TOKEN_USER *user,
TOKEN_GROUPS *groups, TOKEN_PRIVILEGES *privs, TOKEN_OWNER *owner,
TOKEN_PRIMARY_GROUP *group, TOKEN_DEFAULT_DACL *dacl, TOKEN_SOURCE *source)
{
SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous;
unsigned int status, i, *attrs;
data_size_t objattr_size, groups_size, size;
struct object_attributes *objattr;
void *groups_info;
BYTE *p;
SID *sid;
int primary_group = -1;
TRACE( "(%p,0x%08x,%p,%d,%p,%p,%p,%p,%p,%p,%p,%p,%p)\n", handle, (int)access, attr,
type, token_id, expire, user, groups, privs, owner, group, dacl, source );
*handle = 0;
if ((status = alloc_object_attributes( attr, &objattr, &objattr_size ))) return status;
if (attr->SecurityQualityOfService)
{
SECURITY_QUALITY_OF_SERVICE *qos = attr->SecurityQualityOfService;
TRACE( "ObjectAttributes->SecurityQualityOfService = {%d, %d, %d, %s}\n",
(int)qos->Length, qos->ImpersonationLevel, qos->ContextTrackingMode,
qos->EffectiveOnly ? "TRUE" : "FALSE");
level = qos->ImpersonationLevel;
}
groups_size = groups->GroupCount * sizeof( attrs[0] );
for (i = 0; i < groups->GroupCount; i++)
{
SID *group_sid = group->PrimaryGroup;
sid = groups->Groups[i].Sid;
groups_size += offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
if (is_equal_sid( sid, group_sid ))
primary_group = i;
}
if (primary_group == -1)
return STATUS_INVALID_PRIMARY_GROUP;
groups_info = malloc( groups_size );
if (!groups_info)
{
free( objattr );
return STATUS_NO_MEMORY;
}
attrs = (unsigned int *)groups_info;
p = (BYTE *)&attrs[groups->GroupCount];
for (i = 0; i < groups->GroupCount; i++)
{
sid = groups->Groups[i].Sid;
attrs[i] = groups->Groups[i].Attributes;
size = offsetof( SID, SubAuthority[sid->SubAuthorityCount] );
memcpy( p, sid, size );
p += size;
}
SERVER_START_REQ( create_token )
{
req->token_id.low_part = token_id->LowPart;
req->token_id.high_part = token_id->HighPart;
req->access = access;
req->primary = (type == TokenPrimary);
req->impersonation_level = level;
req->expire = expire->QuadPart;
wine_server_add_data( req, objattr, objattr_size );
sid = user->User.Sid;
wine_server_add_data( req, sid, offsetof( SID, SubAuthority[sid->SubAuthorityCount] ) );
req->group_count = groups->GroupCount;
wine_server_add_data( req, groups_info, groups_size );
req->primary_group = primary_group;
req->priv_count = privs->PrivilegeCount;
wine_server_add_data( req, privs->Privileges, privs->PrivilegeCount * sizeof(privs->Privileges[0]) );
if (dacl && dacl->DefaultDacl)
wine_server_add_data( req, dacl->DefaultDacl, dacl->DefaultDacl->AclSize );
status = wine_server_call( req );
if (!status) *handle = wine_server_ptr_handle( reply->token );
}
SERVER_END_REQ;
free( groups_info );
free( objattr );
return status;
}
/***********************************************************************
* NtOpenProcessToken (NTDLL.@)
......
......@@ -155,6 +155,42 @@ NTSTATUS WINAPI wow64_NtCreateLowBoxToken( UINT *args )
/**********************************************************************
* wow64_NtCreateToken
*/
NTSTATUS WINAPI wow64_NtCreateToken( UINT *args )
{
ULONG *handle_ptr = get_ptr( &args );
ACCESS_MASK access = get_ulong( &args );
OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args );
TOKEN_TYPE type = get_ulong( &args );
LUID *luid = get_ptr( &args );
LARGE_INTEGER *expire = get_ptr( &args );
TOKEN_USER32 *user32 = get_ptr( &args );
TOKEN_GROUPS32 *groups32 = get_ptr( &args );
TOKEN_PRIVILEGES *privs = get_ptr( &args );
TOKEN_OWNER32 *owner32 = get_ptr( &args );
TOKEN_PRIMARY_GROUP32 *group32 = get_ptr( &args );
TOKEN_DEFAULT_DACL32 *dacl32 = get_ptr( &args );
TOKEN_SOURCE *source = get_ptr( &args );
struct object_attr64 attr;
TOKEN_USER user;
TOKEN_OWNER owner;
TOKEN_PRIMARY_GROUP group;
TOKEN_DEFAULT_DACL dacl;
HANDLE handle = 0;
NTSTATUS status;
status = NtCreateToken( &handle, access, objattr_32to64( &attr, attr32 ), type, luid, expire,
token_user_32to64( &user, user32 ), token_groups_32to64( groups32 ), privs,
token_owner_32to64( &owner, owner32 ), token_primary_group_32to64( &group, group32 ),
token_default_dacl_32to64( &dacl, dacl32 ), source );
put_handle( handle_ptr, handle );
return status;
}
/**********************************************************************
* wow64_NtDuplicateToken
*/
NTSTATUS WINAPI wow64_NtDuplicateToken( UINT *args )
......
......@@ -374,6 +374,11 @@ typedef struct
typedef struct
{
ULONG PrimaryGroup;
} TOKEN_PRIMARY_GROUP32;
typedef struct
{
SID_AND_ATTRIBUTES32 User;
} TOKEN_USER32;
......
......@@ -70,6 +70,7 @@
SYSCALL_ENTRY( NtCreateThread ) \
SYSCALL_ENTRY( NtCreateThreadEx ) \
SYSCALL_ENTRY( NtCreateTimer ) \
SYSCALL_ENTRY( NtCreateToken ) \
SYSCALL_ENTRY( NtCreateTransaction ) \
SYSCALL_ENTRY( NtCreateUserProcess ) \
SYSCALL_ENTRY( NtDebugActiveProcess ) \
......
......@@ -188,6 +188,31 @@ static inline OBJECT_ATTRIBUTES *objattr_32to64_redirect( struct object_attr64 *
return attr;
}
static inline TOKEN_USER *token_user_32to64( TOKEN_USER *out, const TOKEN_USER32 *in )
{
out->User.Sid = ULongToPtr( in->User.Sid );
out->User.Attributes = in->User.Attributes;
return out;
}
static inline TOKEN_OWNER *token_owner_32to64( TOKEN_OWNER *out, const TOKEN_OWNER32 *in )
{
out->Owner = ULongToPtr( in->Owner );
return out;
}
static inline TOKEN_PRIMARY_GROUP *token_primary_group_32to64( TOKEN_PRIMARY_GROUP *out, const TOKEN_PRIMARY_GROUP32 *in )
{
out->PrimaryGroup = ULongToPtr( in->PrimaryGroup );
return out;
}
static inline TOKEN_DEFAULT_DACL *token_default_dacl_32to64( TOKEN_DEFAULT_DACL *out, const TOKEN_DEFAULT_DACL32 *in )
{
out->DefaultDacl = ULongToPtr( in->DefaultDacl );
return out;
}
static inline void put_handle( ULONG *handle32, HANDLE handle )
{
*handle32 = HandleToULong( handle );
......
......@@ -4482,6 +4482,33 @@ struct remove_clipboard_listener_reply
struct create_token_request
{
struct request_header __header;
struct luid token_id;
unsigned int access;
int primary;
int impersonation_level;
abstime_t expire;
int group_count;
int primary_group;
int priv_count;
char __pad_52[4];
};
struct create_token_reply
{
struct reply_header __header;
obj_handle_t token;
char __pad_12[4];
};
struct open_token_request
{
struct request_header __header;
......@@ -5807,6 +5834,7 @@ enum request
REQ_set_clipboard_viewer,
REQ_add_clipboard_listener,
REQ_remove_clipboard_listener,
REQ_create_token,
REQ_open_token,
REQ_set_global_windows,
REQ_adjust_token_privileges,
......@@ -6096,6 +6124,7 @@ union generic_request
struct set_clipboard_viewer_request set_clipboard_viewer_request;
struct add_clipboard_listener_request add_clipboard_listener_request;
struct remove_clipboard_listener_request remove_clipboard_listener_request;
struct create_token_request create_token_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;
......@@ -6383,6 +6412,7 @@ union generic_reply
struct set_clipboard_viewer_reply set_clipboard_viewer_reply;
struct add_clipboard_listener_reply add_clipboard_listener_reply;
struct remove_clipboard_listener_reply remove_clipboard_listener_reply;
struct create_token_reply create_token_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;
......@@ -6457,7 +6487,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 781
#define SERVER_PROTOCOL_VERSION 782
/* ### protocol_version end ### */
......
......@@ -3187,6 +3187,26 @@ enum caret_state
@END
/* Create a security token */
@REQ(create_token)
struct luid token_id;
unsigned int access; /* access rights to the new token */
int primary; /* is the new token to be a primary one? */
int impersonation_level; /* impersonation level of the new token */
abstime_t expire; /* expiration time */
int group_count;
int primary_group;
int priv_count;
/* VARARG(objattr,object_attributes); */
/* VARARG(user,sid); */
/* VARARG(groups,sid); */
/* VARARG(privs,luid_attr); */
/* VARARG(dacl,acl); */
@REPLY
obj_handle_t token; /* handle to the token */
@END
/* Open a security token */
@REQ(open_token)
obj_handle_t handle; /* handle to the thread or process */
......
......@@ -331,6 +331,7 @@ DECL_HANDLER(get_clipboard_info);
DECL_HANDLER(set_clipboard_viewer);
DECL_HANDLER(add_clipboard_listener);
DECL_HANDLER(remove_clipboard_listener);
DECL_HANDLER(create_token);
DECL_HANDLER(open_token);
DECL_HANDLER(set_global_windows);
DECL_HANDLER(adjust_token_privileges);
......@@ -619,6 +620,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_set_clipboard_viewer,
(req_handler)req_add_clipboard_listener,
(req_handler)req_remove_clipboard_listener,
(req_handler)req_create_token,
(req_handler)req_open_token,
(req_handler)req_set_global_windows,
(req_handler)req_adjust_token_privileges,
......@@ -1970,6 +1972,17 @@ C_ASSERT( FIELD_OFFSET(struct add_clipboard_listener_request, window) == 12 );
C_ASSERT( sizeof(struct add_clipboard_listener_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct remove_clipboard_listener_request, window) == 12 );
C_ASSERT( sizeof(struct remove_clipboard_listener_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, token_id) == 12 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, access) == 20 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, primary) == 24 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, impersonation_level) == 28 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, expire) == 32 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, group_count) == 40 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, primary_group) == 44 );
C_ASSERT( FIELD_OFFSET(struct create_token_request, priv_count) == 48 );
C_ASSERT( sizeof(struct create_token_request) == 56 );
C_ASSERT( FIELD_OFFSET(struct create_token_reply, token) == 8 );
C_ASSERT( sizeof(struct create_token_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct open_token_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct open_token_request, access) == 16 );
C_ASSERT( FIELD_OFFSET(struct open_token_request, attributes) == 20 );
......
......@@ -472,7 +472,7 @@ static struct token *create_token( unsigned int primary, unsigned int session_id
const struct sid_attrs *groups, unsigned int group_count,
const struct luid_attr *privs, unsigned int priv_count,
const struct acl *default_dacl, const struct luid *modified_id,
int impersonation_level, int elevation )
unsigned int primary_group, int impersonation_level, int elevation )
{
struct token *token = alloc_object( &token_ops );
if (token)
......@@ -519,8 +519,8 @@ static struct token *create_token( unsigned int primary, unsigned int session_id
group->attrs = groups[i].attrs;
copy_sid( &group->sid, groups[i].sid );
list_add_tail( &token->groups, &group->entry );
/* Use first owner capable group as owner and primary group */
if (!token->primary_group && (group->attrs & SE_GROUP_OWNER))
if (primary_group == i)
{
token->owner = &group->sid;
token->primary_group = &group->sid;
......@@ -598,7 +598,7 @@ struct token *token_duplicate( struct token *src_token, unsigned primary,
token = create_token( primary, src_token->session_id, src_token->user, NULL, 0,
NULL, 0, src_token->default_dacl, modified_id,
impersonation_level, src_token->elevation );
0, impersonation_level, src_token->elevation );
if (!token) return token;
/* copy groups */
......@@ -773,7 +773,7 @@ struct token *token_create_admin( unsigned primary, int impersonation_level, int
token = create_token( primary, session_id, user_sid, admin_groups, ARRAY_SIZE( admin_groups ),
admin_privs, ARRAY_SIZE( admin_privs ), default_dacl,
NULL, impersonation_level, elevation );
NULL, 4 /* domain_users */, impersonation_level, elevation );
/* we really need a primary group */
assert( token->primary_group );
......@@ -1089,6 +1089,102 @@ int check_object_access(struct token *token, struct object *obj, unsigned int *a
}
/* create a security token */
DECL_HANDLER(create_token)
{
struct token *token;
struct object_attributes *objattr;
struct sid *user;
struct sid_attrs *groups;
struct luid_attr *privs;
struct acl *dacl = NULL;
unsigned int i;
data_size_t data_size, groups_size;
struct acl *default_dacl = NULL;
unsigned int *attrs;
struct sid *sid;
objattr = (struct object_attributes *)get_req_data();
user = (struct sid *)get_req_data_after_objattr( objattr, &data_size );
if (!user || !sid_valid_size( user, data_size ))
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
data_size -= sid_len( user );
groups_size = req->group_count * sizeof( attrs[0] );
if (data_size < groups_size)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
if (req->primary_group < 0 || req->primary_group >= req->group_count)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
groups = mem_alloc( req->group_count * sizeof( groups[0] ) );
if (!groups) return;
attrs = (unsigned int *)((char *)user + sid_len( user ));
sid = (struct sid *)&attrs[req->group_count];
for (i = 0; i < req->group_count; i++)
{
groups[i].attrs = attrs[i];
groups[i].sid = sid;
if (!sid_valid_size( sid, data_size - groups_size ))
{
free( groups );
set_error( STATUS_INVALID_PARAMETER );
return;
}
groups_size += sid_len( sid );
sid = (struct sid *)((char *)sid + sid_len( sid ));
}
data_size -= groups_size;
if (data_size < req->priv_count * sizeof( privs[0] ))
{
free( groups );
set_error( STATUS_INVALID_PARAMETER );
return;
}
privs = (struct luid_attr *)((char *)attrs + groups_size);
data_size -= req->priv_count * sizeof( privs[0] );
if (data_size)
{
dacl = (struct acl *)((char *)privs + req->priv_count * sizeof(privs[0]));
if (!acl_is_valid( dacl, data_size ))
{
free( groups );
set_error( STATUS_INVALID_PARAMETER );
return;
}
}
else
dacl = default_dacl = create_default_dacl( &domain_users_sid );
token = create_token( req->primary, default_session_id, user, groups, req->group_count,
privs, req->priv_count, dacl, NULL, req->primary_group, req->impersonation_level, 0 );
if (token)
reply->token = alloc_handle( current->process, token, req->access, objattr->attributes );
free( default_dacl );
free( groups );
}
/* open a security token */
DECL_HANDLER(open_token)
{
......
......@@ -3841,6 +3841,23 @@ static void dump_remove_clipboard_listener_request( const struct remove_clipboar
fprintf( stderr, " window=%08x", req->window );
}
static void dump_create_token_request( const struct create_token_request *req )
{
dump_luid( " token_id=", &req->token_id );
fprintf( stderr, ", access=%08x", req->access );
fprintf( stderr, ", primary=%d", req->primary );
fprintf( stderr, ", impersonation_level=%d", req->impersonation_level );
dump_abstime( ", expire=", &req->expire );
fprintf( stderr, ", group_count=%d", req->group_count );
fprintf( stderr, ", primary_group=%d", req->primary_group );
fprintf( stderr, ", priv_count=%d", req->priv_count );
}
static void dump_create_token_reply( const struct create_token_reply *req )
{
fprintf( stderr, " token=%04x", req->token );
}
static void dump_open_token_request( const struct open_token_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
......@@ -4792,6 +4809,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_clipboard_viewer_request,
(dump_func)dump_add_clipboard_listener_request,
(dump_func)dump_remove_clipboard_listener_request,
(dump_func)dump_create_token_request,
(dump_func)dump_open_token_request,
(dump_func)dump_set_global_windows_request,
(dump_func)dump_adjust_token_privileges_request,
......@@ -5077,6 +5095,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_clipboard_viewer_reply,
NULL,
NULL,
(dump_func)dump_create_token_reply,
(dump_func)dump_open_token_reply,
(dump_func)dump_set_global_windows_reply,
(dump_func)dump_adjust_token_privileges_reply,
......@@ -5362,6 +5381,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_clipboard_viewer",
"add_clipboard_listener",
"remove_clipboard_listener",
"create_token",
"open_token",
"set_global_windows",
"adjust_token_privileges",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment