server: Use the security descriptor passed in when creating events.
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 21a9814..b2b3069 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -61,6 +61,74 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+static NTSTATUS create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd,
+ data_size_t *server_sd_len)
+{
+ unsigned int len;
+ PSID owner, group;
+ ACL *dacl, *sacl;
+ BOOLEAN owner_present, group_present, dacl_present, sacl_present;
+ BOOLEAN defaulted;
+ NTSTATUS status;
+ unsigned char *ptr;
+
+ if (!nt_sd)
+ {
+ *server_sd = NULL;
+ *server_sd_len = 0;
+ return STATUS_SUCCESS;
+ }
+
+ len = sizeof(struct security_descriptor);
+
+ status = RtlGetOwnerSecurityDescriptor(nt_sd, &owner, &owner_present);
+ if (status != STATUS_SUCCESS) return status;
+ status = RtlGetGroupSecurityDescriptor(nt_sd, &group, &group_present);
+ if (status != STATUS_SUCCESS) return status;
+ status = RtlGetSaclSecurityDescriptor(nt_sd, &sacl_present, &sacl, &defaulted);
+ if (status != STATUS_SUCCESS) return status;
+ status = RtlGetDaclSecurityDescriptor(nt_sd, &dacl_present, &dacl, &defaulted);
+ if (status != STATUS_SUCCESS) return status;
+
+ if (owner_present)
+ len += RtlLengthSid(owner);
+ if (group_present)
+ len += RtlLengthSid(group);
+ if (sacl_present && sacl)
+ len += sacl->AclSize;
+ if (dacl_present && dacl)
+ len += dacl->AclSize;
+
+ /* fix alignment for the Unicode name that follows the structure */
+ len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
+ *server_sd = RtlAllocateHeap(GetProcessHeap(), 0, len);
+ if (!*server_sd) return STATUS_NO_MEMORY;
+
+ (*server_sd)->control = ((SECURITY_DESCRIPTOR *)nt_sd)->Control & ~SE_SELF_RELATIVE;
+ (*server_sd)->owner_len = owner_present ? RtlLengthSid(owner) : 0;
+ (*server_sd)->group_len = group_present ? RtlLengthSid(group) : 0;
+ (*server_sd)->sacl_len = (sacl_present && sacl) ? sacl->AclSize : 0;
+ (*server_sd)->dacl_len = (dacl_present && dacl) ? dacl->AclSize : 0;
+
+ ptr = (unsigned char *)(*server_sd + 1);
+ memcpy(ptr, owner, (*server_sd)->owner_len);
+ ptr += (*server_sd)->owner_len;
+ memcpy(ptr, group, (*server_sd)->group_len);
+ ptr += (*server_sd)->group_len;
+ memcpy(ptr, sacl, (*server_sd)->sacl_len);
+ ptr += (*server_sd)->sacl_len;
+ memcpy(ptr, dacl, (*server_sd)->dacl_len);
+
+ *server_sd_len = len;
+
+ return STATUS_SUCCESS;
+}
+
+static void free_struct_sd(struct security_descriptor *server_sd)
+{
+ RtlFreeHeap(GetProcessHeap(), 0, server_sd);
+}
+
/*
* Semaphores
*/
@@ -172,21 +240,35 @@
{
DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
NTSTATUS ret;
+ struct security_descriptor *sd = NULL;
+ struct object_attributes objattr;
if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
+ objattr.rootdir = attr ? attr->RootDirectory : 0;
+ objattr.sd_len = 0;
+ if (attr)
+ {
+ ret = create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
+ if (ret != STATUS_SUCCESS) return ret;
+ }
+
SERVER_START_REQ( create_event )
{
req->access = DesiredAccess;
req->attributes = (attr) ? attr->Attributes : 0;
- req->rootdir = attr ? attr->RootDirectory : 0;
req->manual_reset = ManualReset;
req->initial_state = InitialState;
+ wine_server_add_data( req, &objattr, sizeof(objattr) );
+ if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
ret = wine_server_call( req );
*EventHandle = reply->handle;
}
SERVER_END_REQ;
+
+ free_struct_sd( sd );
+
return ret;
}
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 116216b..312d822 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -217,6 +217,14 @@
};
+struct object_attributes
+{
+ obj_handle_t rootdir;
+ data_size_t sd_len;
+
+
+};
+
struct token_groups
{
unsigned int count;
@@ -860,10 +868,9 @@
struct request_header __header;
unsigned int access;
unsigned int attributes;
- obj_handle_t rootdir;
int manual_reset;
int initial_state;
- /* VARARG(name,unicode_str); */
+ /* VARARG(objattr,object_attributes); */
};
struct create_event_reply
{
@@ -4873,6 +4880,6 @@
struct set_completion_info_reply set_completion_info_reply;
};
-#define SERVER_PROTOCOL_VERSION 317
+#define SERVER_PROTOCOL_VERSION 318
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/console.c b/server/console.c
index 61c4924..5f00588 100644
--- a/server/console.c
+++ b/server/console.c
@@ -289,7 +289,7 @@
console_input->input_cp = 0;
console_input->output_cp = 0;
console_input->win = 0;
- console_input->event = create_event( NULL, NULL, 0, 1, 0 );
+ console_input->event = create_event( NULL, NULL, 0, 1, 0, NULL );
if (!console_input->history || !console_input->evt)
{
diff --git a/server/event.c b/server/event.c
index 5d49845..f866211 100644
--- a/server/event.c
+++ b/server/event.c
@@ -34,6 +34,7 @@
#include "handle.h"
#include "thread.h"
#include "request.h"
+#include "security.h"
struct event
{
@@ -69,7 +70,8 @@
struct event *create_event( struct directory *root, const struct unicode_str *name,
- unsigned int attr, int manual_reset, int initial_state )
+ unsigned int attr, int manual_reset, int initial_state,
+ const struct security_descriptor *sd )
{
struct event *event;
@@ -80,6 +82,10 @@
/* initialize it if it didn't already exist */
event->manual_reset = manual_reset;
event->signaled = initial_state;
+ if (sd) default_set_sd( &event->obj, sd, OWNER_SECURITY_INFORMATION|
+ GROUP_SECURITY_INFORMATION|
+ DACL_SECURITY_INFORMATION|
+ SACL_SECURITY_INFORMATION );
}
}
return event;
@@ -165,13 +171,24 @@
struct event *event;
struct unicode_str name;
struct directory *root = NULL;
+ const struct object_attributes *objattr = get_req_data();
+ const struct security_descriptor *sd;
reply->handle = 0;
- get_req_unicode_str( &name );
- if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
+
+ if (!objattr_is_valid( objattr, get_req_data_size() ))
return;
- if ((event = create_event( root, &name, req->attributes, req->manual_reset, req->initial_state )))
+ sd = objattr->sd_len ? (const struct security_descriptor *)(objattr + 1) : NULL;
+
+ /* get unicode string */
+ name.len = ((get_req_data_size() - sizeof(*objattr) - objattr->sd_len) / sizeof(WCHAR)) * sizeof(WCHAR);
+ name.str = (const WCHAR *)get_req_data() + (sizeof(*objattr) + objattr->sd_len) / sizeof(WCHAR);
+
+ if (objattr->rootdir && !(root = get_directory_obj( current->process, objattr->rootdir, 0 )))
+ return;
+
+ if ((event = create_event( root, &name, req->attributes, req->manual_reset, req->initial_state, sd )))
{
reply->handle = alloc_handle( current->process, event, req->access, req->attributes );
release_object( event );
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 51da895..d277cdc 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -539,7 +539,7 @@
{
/* this kind of sux -
there's no unix way to be alerted when a pipe becomes empty */
- server->event = create_event( NULL, NULL, 0, 0, 0 );
+ server->event = create_event( NULL, NULL, 0, 0, 0, NULL );
if (!server->event) return;
server->flush_poll = add_timeout_user( -TICKS_PER_SEC / 10, check_flushed, server );
*event = server->event;
@@ -569,7 +569,7 @@
static obj_handle_t alloc_wait_event( struct process *process )
{
obj_handle_t handle = 0;
- struct event *event = create_event( NULL, NULL, 0, 1, 0 );
+ struct event *event = create_event( NULL, NULL, 0, 1, 0, NULL );
if (event)
{
diff --git a/server/object.h b/server/object.h
index cb5822a..d1af7f2 100644
--- a/server/object.h
+++ b/server/object.h
@@ -148,7 +148,8 @@
struct event;
extern struct event *create_event( struct directory *root, const struct unicode_str *name,
- unsigned int attr, int manual_reset, int initial_state );
+ unsigned int attr, int manual_reset, int initial_state,
+ const struct security_descriptor *sd );
extern struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access );
extern void pulse_event( struct event *event );
extern void set_event( struct event *event );
diff --git a/server/process.c b/server/process.c
index 8ca20d8..7031e14 100644
--- a/server/process.c
+++ b/server/process.c
@@ -991,7 +991,7 @@
generate_startup_debug_events( process, req->entry );
set_process_startup_state( process, STARTUP_DONE );
- if (req->gui) process->idle_event = create_event( NULL, NULL, 0, 1, 0 );
+ if (req->gui) process->idle_event = create_event( NULL, NULL, 0, 1, 0, NULL );
if (current->suspend + process->suspend > 0) stop_thread( current );
if (process->debugger) set_process_debug_flag( process, 1 );
}
@@ -1170,7 +1170,7 @@
if (!user_process_event)
{
- if (!(user_process_event = create_event( NULL, NULL, 0, 1, 0 ))) return;
+ if (!(user_process_event = create_event( NULL, NULL, 0, 1, 0, NULL ))) return;
make_object_static( (struct object *)user_process_event );
}
diff --git a/server/protocol.def b/server/protocol.def
index a00ccb9..41f71ca 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -227,17 +227,25 @@
data_size_t group_len;
data_size_t sacl_len;
data_size_t dacl_len;
- /* VARARGS(owner,SID); */
- /* VARARGS(group,SID); */
- /* VARARGS(sacl,ACL); */
- /* VARARGS(dacl,ACL); */
+ /* VARARG(owner,SID); */
+ /* VARARG(group,SID); */
+ /* VARARG(sacl,ACL); */
+ /* VARARG(dacl,ACL); */
+};
+
+struct object_attributes
+{
+ obj_handle_t rootdir; /* root directory */
+ data_size_t sd_len; /* length of security_descriptor data. may be 0 */
+ /* VARARG(sd,security_descriptor); */
+ /* VARARG(name,unicode_str); */
};
struct token_groups
{
unsigned int count;
/* unsigned int attributes[count]; */
- /* VARARGS(sids,SID); */
+ /* VARARG(sids,SID); */
};
enum apc_type
@@ -743,10 +751,9 @@
@REQ(create_event)
unsigned int access; /* wanted access rights */
unsigned int attributes; /* object attributes */
- obj_handle_t rootdir; /* root directory */
int manual_reset; /* manual reset event */
int initial_state; /* initial state of the event */
- VARARG(name,unicode_str); /* object name */
+ VARARG(objattr,object_attributes); /* object attributes */
@REPLY
obj_handle_t handle; /* handle to the event */
@END
diff --git a/server/security.h b/server/security.h
index 5df5887..50fba52 100644
--- a/server/security.h
+++ b/server/security.h
@@ -127,3 +127,7 @@
else
return NULL;
}
+
+/* determines whether an object_attributes struct is valid in a buffer
+ * and calls set_error appropriately */
+extern int objattr_is_valid( const struct object_attributes *objattr, data_size_t size );
diff --git a/server/token.c b/server/token.c
index 38877fe..b6ba50d 100644
--- a/server/token.c
+++ b/server/token.c
@@ -305,6 +305,29 @@
return TRUE;
}
+/* determines whether an object_attributes struct is valid in a buffer
+ * and calls set_error appropriately */
+int objattr_is_valid( const struct object_attributes *objattr, data_size_t size )
+{
+ if ((size < sizeof(*objattr)) || (size - sizeof(*objattr) < objattr->sd_len))
+ {
+ set_error( STATUS_ACCESS_VIOLATION );
+ return FALSE;
+ }
+
+ if (objattr->sd_len)
+ {
+ const struct security_descriptor *sd = (const struct security_descriptor *)(objattr + 1);
+ if (!sd_is_valid( sd, objattr->sd_len ))
+ {
+ set_error( STATUS_INVALID_SECURITY_DESCR );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
/* maps from generic rights to specific rights as given by a mapping */
static inline void map_generic_mask(unsigned int *mask, const GENERIC_MAPPING *mapping)
{
diff --git a/server/trace.c b/server/trace.c
index e0a2e96..4abdb55 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -782,6 +782,26 @@
fputc( '}', stderr );
}
+static void dump_varargs_object_attributes( data_size_t size )
+{
+ const struct object_attributes *objattr = cur_data;
+ fputc( '{', stderr );
+ if (size >= sizeof(struct object_attributes))
+ {
+ const WCHAR *str;
+ fprintf( stderr, "rootdir=%p,sd=", objattr->rootdir );
+ if (objattr->sd_len > size - sizeof(*objattr)) return;
+ dump_inline_security_descriptor( (const struct security_descriptor *)(objattr + 1), objattr->sd_len );
+ str = (const WCHAR *)cur_data + (sizeof(*objattr) + objattr->sd_len) / sizeof(WCHAR);
+ fprintf( stderr, ",name=L\"" );
+ dump_strW( str, (size - sizeof(*objattr) - objattr->sd_len) / sizeof(WCHAR),
+ stderr, "\"\"" );
+ fputc( '\"', stderr );
+ remove_data( size );
+ }
+ fputc( '}', stderr );
+}
+
typedef void (*dump_func)( const void *req );
/* Everything below this line is generated automatically by tools/make_requests */
@@ -1136,11 +1156,10 @@
{
fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " attributes=%08x,", req->attributes );
- fprintf( stderr, " rootdir=%p,", req->rootdir );
fprintf( stderr, " manual_reset=%d,", req->manual_reset );
fprintf( stderr, " initial_state=%d,", req->initial_state );
- fprintf( stderr, " name=" );
- dump_varargs_unicode_str( cur_size );
+ fprintf( stderr, " objattr=" );
+ dump_varargs_object_attributes( cur_size );
}
static void dump_create_event_reply( const struct create_event_reply *req )