From: Dmitry Timoshkov dmitry@baikal.ru
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/ntdll/ntdll.spec | 4 +- dlls/ntdll/unix/loader.c | 1 + dlls/ntdll/unix/security.c | 110 +++++++++++++++++++++++++++++++++++++ server/protocol.def | 19 +++++++ server/token.c | 87 +++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 011f0648522..37fc5be61d3 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -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 @@ -1235,7 +1235,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 diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 28f0c4bf245..5824712b110 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -166,6 +166,7 @@ static void * const syscalls[] = NtCreateThread, NtCreateThreadEx, NtCreateTimer, + NtCreateToken, NtCreateTransaction, NtCreateUserProcess, NtDebugActiveProcess, diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index 8351f8b1993..3ea66ce57f5 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -36,6 +36,116 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+/*********************************************************************** + * 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, group_count, i, *attrs; + data_size_t objattr_size, groups_size, size; + struct object_attributes *objattr; + void *groups_info; + BYTE *tmp; + SID *sid; + + 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 ); + + if (!handle || !attr || !expire || !user || !groups || !privs) + return STATUS_INVALID_PARAMETER; + + *handle = 0; + if ((status = alloc_object_attributes( attr, &objattr, &objattr_size ))) return status; + + if (attr && 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; + } + + group_count = groups->GroupCount; + groups_size = group_count * sizeof( attrs[0] ); + + for (i = 0; i < group_count; i++) + { + sid = groups->Groups[i].Sid; + groups_size += offsetof( SID, SubAuthority[sid->SubAuthorityCount] ); + } + + if (group) + { + sid = group->PrimaryGroup; + groups_size += sizeof( attrs[0] ) + offsetof( SID, SubAuthority[sid->SubAuthorityCount] ); + group_count++; + } + + groups_info = malloc( groups_size ); + if (!groups_info) + { + free( objattr ); + return STATUS_NO_MEMORY; + } + + attrs = (unsigned int *)groups_info; + tmp = (BYTE *)&attrs[group_count]; + 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( tmp, sid, size ); + tmp += size; + } + + if (group) + { + sid = group->PrimaryGroup; + attrs[group_count - 1] = SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT|SE_GROUP_MANDATORY|SE_GROUP_OWNER; + size = offsetof( SID, SubAuthority[sid->SubAuthorityCount] ); + memcpy( tmp, sid, size ); + } + + SERVER_START_REQ( create_token ) + { + SID *sid; + + 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 = group_count; + wine_server_add_data( req, groups_info, groups_size ); + + 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.@) diff --git a/server/protocol.def b/server/protocol.def index 919297c818c..59dceb65b8d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3186,6 +3186,25 @@ 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 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 */ diff --git a/server/token.c b/server/token.c index 99f5e36e279..b71643d4c86 100644 --- a/server/token.c +++ b/server/token.c @@ -1089,6 +1089,93 @@ 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 = NULL; + struct luid_attr *privs = NULL; + struct acl *dacl = NULL; + unsigned int group_count = 0, priv_count = 0, i; + data_size_t data_size, groups_size = 0; + struct acl *default_dacl = NULL; + + objattr = (struct object_attributes *)get_req_data(); + user = (struct sid *)get_req_data_after_objattr( objattr, &data_size ); + + if (!user || data_size < sid_len( user ) ) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + data_size -= sid_len( user ); + + if (data_size) + { + unsigned int *attrs = (unsigned int *)((char *)user + sid_len( user )); + struct sid *sid = (struct sid *)&attrs[req->group_count]; + + group_count = req->group_count; + groups_size = group_count * sizeof( attrs[0] ); + + groups = malloc( group_count * sizeof( groups[0] ) ); + if (!groups) + { + set_error( STATUS_NO_MEMORY ); + return; + } + + for (i = 0; i < group_count; i++) + { + groups[i].attrs = attrs[i]; + groups[i].sid = sid; + + groups_size += sid_len( sid ); + sid = (struct sid *)((char *)sid + sid_len( sid )); + } + + if (data_size < groups_size) + { + free( groups ); + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + data_size -= groups_size; + } + + if (data_size) + { + priv_count = req->priv_count; + + if (data_size < priv_count * sizeof( privs[0] )) + { + free( groups ); + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + data_size -= priv_count * sizeof( privs[0] ); + privs = (struct luid_attr *)((char *)groups + groups_size); + } + + if (data_size) + dacl = (struct acl *)((char *)privs + priv_count * sizeof(privs[0])); + else + dacl = default_dacl = create_default_dacl( &domain_users_sid ); + + token = create_token( req->primary, default_session_id, user, groups, group_count, + privs, priv_count, dacl, NULL, 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) {