diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c index b4e57735b7f..73807863f15 100644 --- a/dlls/ntdll/sec.c +++ b/dlls/ntdll/sec.c @@ -1539,15 +1539,82 @@ NtAccessCheck( /****************************************************************************** * NtSetSecurityObject [NTDLL.@] + * ZwSetSecurityObject [NTDLL.@] + * + * Sets specified parts of the object's security descriptor. + * + * PARAMS + * Handle [I] Handle to the object to change security descriptor of. + * SecurityInformation [I] Specifies which parts of the security descriptor to set. + * SecurityDescriptor [I] New parts of a security descriptor for the object. + * + * RETURNS + * NTSTATUS code. + * */ -NTSTATUS WINAPI -NtSetSecurityObject( - IN HANDLE Handle, - IN SECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR SecurityDescriptor) +NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor) { - FIXME("%p 0x%08x %p\n", Handle, SecurityInformation, SecurityDescriptor); - return STATUS_SUCCESS; + NTSTATUS status; + struct security_descriptor sd; + PACL dacl, sacl; + PSID owner, group; + BOOLEAN defaulted, present; + DWORD revision; + SECURITY_DESCRIPTOR_CONTROL control; + + TRACE("%p 0x%08x %p\n", Handle, SecurityInformation, SecurityDescriptor); + + if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION; + + memset( &sd, 0, sizeof(sd) ); + RtlGetControlSecurityDescriptor( SecurityDescriptor, &control, &revision ); + sd.control = control & ~SE_SELF_RELATIVE; + + if (SecurityInformation & OWNER_SECURITY_INFORMATION) + { + RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &owner, &defaulted ); + if (!(sd.owner_len = RtlLengthSid( owner ))) + return STATUS_INVALID_SECURITY_DESCR; + } + + if (SecurityInformation & GROUP_SECURITY_INFORMATION) + { + RtlGetGroupSecurityDescriptor( SecurityDescriptor, &group, &defaulted ); + if (!(sd.group_len = RtlLengthSid( group ))) + return STATUS_INVALID_SECURITY_DESCR; + } + + if (SecurityInformation & SACL_SECURITY_INFORMATION) + { + RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted ); + sd.sacl_len = present ? sacl->AclSize : 0; + sd.control |= SE_SACL_PRESENT; + } + + if (SecurityInformation & DACL_SECURITY_INFORMATION) + { + RtlGetDaclSecurityDescriptor( SecurityDescriptor, &present, &dacl, &defaulted ); + sd.dacl_len = present ? dacl->AclSize : 0; + sd.control |= SE_DACL_PRESENT; + } + + SERVER_START_REQ( set_security_object ) + { + req->handle = Handle; + req->security_info = SecurityInformation; + + wine_server_add_data( req, &sd, sizeof(sd) ); + wine_server_add_data( req, owner, sd.owner_len ); + wine_server_add_data( req, group, sd.group_len ); + wine_server_add_data( req, sacl, sd.sacl_len ); + wine_server_add_data( req, dacl, sd.dacl_len ); + status = wine_server_call( req ); + } + SERVER_END_REQ; + + return status; } /****************************************************************************** diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index be21fc4d984..4e7cec0e021 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3836,6 +3836,18 @@ struct get_token_groups_reply /* VARARG(user,token_groups); */ }; +struct set_security_object_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int security_info; + /* VARARG(sd,security_descriptor); */ +}; +struct set_security_object_reply +{ + struct reply_header __header; +}; + struct create_mailslot_request { @@ -4189,6 +4201,7 @@ enum request REQ_access_check, REQ_get_token_user, REQ_get_token_groups, + REQ_set_security_object, REQ_create_mailslot, REQ_open_mailslot, REQ_set_mailslot_info, @@ -4411,6 +4424,7 @@ union generic_request struct access_check_request access_check_request; struct get_token_user_request get_token_user_request; struct get_token_groups_request get_token_groups_request; + struct set_security_object_request set_security_object_request; struct create_mailslot_request create_mailslot_request; struct open_mailslot_request open_mailslot_request; struct set_mailslot_info_request set_mailslot_info_request; @@ -4631,6 +4645,7 @@ union generic_reply struct access_check_reply access_check_reply; struct get_token_user_reply get_token_user_reply; struct get_token_groups_reply get_token_groups_reply; + struct set_security_object_reply set_security_object_reply; struct create_mailslot_reply create_mailslot_reply; struct open_mailslot_reply open_mailslot_reply; struct set_mailslot_info_reply set_mailslot_info_reply; @@ -4642,6 +4657,6 @@ union generic_reply struct get_object_info_reply get_object_info_reply; }; -#define SERVER_PROTOCOL_VERSION 275 +#define SERVER_PROTOCOL_VERSION 276 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index f49f3317fac..2073a20990a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2759,6 +2759,12 @@ enum message_type VARARG(user,token_groups); /* groups the token's user belongs to */ @END +@REQ(set_security_object) + obj_handle_t handle; /* handle to the object */ + unsigned int security_info; /* which parts of security descriptor to set */ + VARARG(sd,security_descriptor); /* security descriptor to set */ +@END + /* Create a mailslot */ @REQ(create_mailslot) unsigned int access; /* wanted access rights */ diff --git a/server/request.h b/server/request.h index b52c1aa4d88..9119ec1994b 100644 --- a/server/request.h +++ b/server/request.h @@ -316,6 +316,7 @@ DECL_HANDLER(duplicate_token); DECL_HANDLER(access_check); DECL_HANDLER(get_token_user); DECL_HANDLER(get_token_groups); +DECL_HANDLER(set_security_object); DECL_HANDLER(create_mailslot); DECL_HANDLER(open_mailslot); DECL_HANDLER(set_mailslot_info); @@ -537,6 +538,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_access_check, (req_handler)req_get_token_user, (req_handler)req_get_token_groups, + (req_handler)req_set_security_object, (req_handler)req_create_mailslot, (req_handler)req_open_mailslot, (req_handler)req_set_mailslot_info, diff --git a/server/token.c b/server/token.c index 9a591886aec..88558e6e5fa 100644 --- a/server/token.c +++ b/server/token.c @@ -886,6 +886,93 @@ const ACL *token_get_default_dacl( struct token *token ) return token->default_dacl; } +static void set_object_sd( struct object *obj, const struct security_descriptor *sd, + unsigned int set_info ) +{ + struct security_descriptor new_sd, *pnew_sd; + int present; + const SID *owner, *group; + const ACL *sacl, *dacl; + char *ptr; + + if (!set_info) return; + + new_sd.control = sd->control & ~SE_SELF_RELATIVE; + + owner = sd_get_owner( sd ); + if (set_info & OWNER_SECURITY_INFORMATION && owner) + new_sd.owner_len = sd->owner_len; + else + { + owner = current->process->token->user; + new_sd.owner_len = FIELD_OFFSET(SID, SubAuthority[owner->SubAuthorityCount]); + new_sd.control |= SE_OWNER_DEFAULTED; + } + + group = sd_get_group( sd ); + if (set_info & GROUP_SECURITY_INFORMATION && group) + new_sd.group_len = sd->group_len; + else + { + group = current->process->token->primary_group; + new_sd.group_len = FIELD_OFFSET(SID, SubAuthority[group->SubAuthorityCount]); + new_sd.control |= SE_GROUP_DEFAULTED; + } + + new_sd.control |= SE_SACL_PRESENT; + sacl = sd_get_sacl( sd, &present ); + if (set_info & SACL_SECURITY_INFORMATION && present) + new_sd.sacl_len = sd->sacl_len; + else + { + if (obj->sd) sacl = sd_get_sacl( obj->sd, &present ); + + if (obj->sd && present) + new_sd.sacl_len = obj->sd->sacl_len; + else + { + new_sd.sacl_len = 0; + new_sd.control |= SE_SACL_DEFAULTED; + } + } + + new_sd.control |= SE_DACL_PRESENT; + dacl = sd_get_dacl( sd, &present ); + if (set_info & DACL_SECURITY_INFORMATION && present) + new_sd.dacl_len = sd->dacl_len; + else + { + if (obj->sd) dacl = sd_get_dacl( obj->sd, &present ); + + if (obj->sd && present) + new_sd.dacl_len = obj->sd->dacl_len; + else + { + dacl = token_get_default_dacl( current->process->token ); + new_sd.dacl_len = dacl->AclSize; + new_sd.control |= SE_DACL_DEFAULTED; + } + } + + ptr = mem_alloc( sizeof(new_sd) + new_sd.owner_len + new_sd.group_len + + new_sd.sacl_len + new_sd.dacl_len ); + if (!ptr) return; + pnew_sd = (struct security_descriptor*)ptr; + + memcpy( ptr, &new_sd, sizeof(new_sd) ); + ptr += sizeof(new_sd); + memcpy( ptr, owner, new_sd.owner_len ); + ptr += new_sd.owner_len; + memcpy( ptr, group, new_sd.group_len ); + ptr += new_sd.group_len; + memcpy( ptr, sacl, new_sd.sacl_len ); + ptr += new_sd.sacl_len; + memcpy( ptr, dacl, new_sd.dacl_len ); + + free( obj->sd ); + obj->sd = pnew_sd; +} + /* open a security token */ DECL_HANDLER(open_token) { @@ -1206,3 +1293,30 @@ DECL_HANDLER(get_token_groups) release_object( token ); } } + +DECL_HANDLER(set_security_object) +{ + data_size_t sd_size = get_req_data_size(); + const struct security_descriptor *sd = get_req_data(); + struct object *obj; + unsigned int access = 0; + + if (!sd_is_valid( sd, sd_size )) + { + set_error( STATUS_ACCESS_VIOLATION ); + return; + } + + if (req->security_info & OWNER_SECURITY_INFORMATION || + req->security_info & GROUP_SECURITY_INFORMATION) + access |= WRITE_OWNER; + if (req->security_info & SACL_SECURITY_INFORMATION) + access |= ACCESS_SYSTEM_SECURITY; + if (req->security_info & DACL_SECURITY_INFORMATION) + access |= WRITE_DAC; + + if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return; + + set_object_sd( obj, sd, req->security_info ); + release_object( obj ); +} diff --git a/server/trace.c b/server/trace.c index f9ff323bce6..2909dedd810 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3309,6 +3309,14 @@ static void dump_get_token_groups_reply( const struct get_token_groups_reply *re dump_varargs_token_groups( cur_size ); } +static void dump_set_security_object_request( const struct set_security_object_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " security_info=%08x,", req->security_info ); + fprintf( stderr, " sd=" ); + dump_varargs_security_descriptor( cur_size ); +} + static void dump_create_mailslot_request( const struct create_mailslot_request *req ) { fprintf( stderr, " access=%08x,", req->access ); @@ -3642,6 +3650,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_access_check_request, (dump_func)dump_get_token_user_request, (dump_func)dump_get_token_groups_request, + (dump_func)dump_set_security_object_request, (dump_func)dump_create_mailslot_request, (dump_func)dump_open_mailslot_request, (dump_func)dump_set_mailslot_info_request, @@ -3860,6 +3869,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_access_check_reply, (dump_func)dump_get_token_user_reply, (dump_func)dump_get_token_groups_reply, + (dump_func)0, (dump_func)dump_create_mailslot_reply, (dump_func)dump_open_mailslot_reply, (dump_func)dump_set_mailslot_info_reply, @@ -4078,6 +4088,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "access_check", "get_token_user", "get_token_groups", + "set_security_object", "create_mailslot", "open_mailslot", "set_mailslot_info",