From 1c5affa205ffd71df1581d5ae898e2d8649af0b7 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 31 Aug 2016 08:46:20 +0200 Subject: [PATCH] advapi32: Unify service startup and control handling. Signed-off-by: Sebastian Lackner Signed-off-by: Alexandre Julliard --- dlls/advapi32/service.c | 67 ++++++++++++++++++------------------ include/wine/svcctl.idl | 9 ++--- programs/services/rpc.c | 8 ++--- programs/services/services.c | 27 ++++++--------- programs/services/services.h | 3 +- 5 files changed, 53 insertions(+), 61 deletions(-) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index cd3cd2fcaef..11508054412 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -379,9 +379,9 @@ static DWORD WINAPI service_thread(LPVOID arg) /****************************************************************************** * service_handle_start */ -static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count) +static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size) { - TRACE("%s argsize %u\n", debugstr_w(service->name), count); + DWORD count = data_size / sizeof(WCHAR); if (service->thread) { @@ -390,8 +390,11 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR } heap_free(service->args); - service->args = heap_alloc(count * sizeof(WCHAR)); - memcpy( service->args, data, count * sizeof(WCHAR) ); + service->args = heap_alloc((count + 2) * sizeof(WCHAR)); + if (count) memcpy( service->args, data, count * sizeof(WCHAR) ); + service->args[count++] = 0; + service->args[count++] = 0; + service->thread = CreateThread( NULL, 0, service_thread, service, 0, NULL ); SetEvent( service_event ); /* notify the main loop */ @@ -401,14 +404,16 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR /****************************************************************************** * service_handle_control */ -static DWORD service_handle_control(const service_data *service, DWORD control, void *data) +static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size) { DWORD ret = ERROR_INVALID_SERVICE_CONTROL; - TRACE("%s control %u data %p\n", debugstr_w(service->name), control, data); + TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size); - if (service->handler) - ret = service->handler(control, 0, data, service->context); + if (control == SERVICE_CONTROL_START) + ret = service_handle_start(service, data, data_size); + else if (service->handler) + ret = service->handler(control, 0, (void *)data, service->context); return ret; } @@ -472,39 +477,33 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg) goto done; } - /* find the service */ - if (!(service = find_service_by_name( name ))) + if (info.magic != SERVICE_PROTOCOL_MAGIC) { - FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(name)); + ERR( "received invalid request for service %s\n", debugstr_w(name) ); result = ERROR_INVALID_PARAMETER; goto done; } - TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(name) ); - - /* handle the request */ - switch (info.cmd) + /* find the service */ + if (!(service = find_service_by_name( name ))) { - case WINESERV_STARTINFO: - if (!service->handle) - { - if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) || - !(service->full_access_handle = OpenServiceW( disp->manager, name, - GENERIC_READ|GENERIC_WRITE ))) - FIXME( "failed to open service %s\n", debugstr_w(name) ); - } - result = service_handle_start(service, (WCHAR *)data, data_size / sizeof(WCHAR)); - break; - case WINESERV_SENDCONTROL: - result = service_handle_control(service, info.control, (data_size > info.name_size * sizeof(WCHAR)) ? - &data[info.name_size * sizeof(WCHAR)] : NULL); - break; - default: - ERR("received invalid command %u\n", info.cmd); + FIXME( "got request for unknown service %s\n", debugstr_w(name) ); result = ERROR_INVALID_PARAMETER; - break; + goto done; } + if (!service->handle) + { + if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) || + !(service->full_access_handle = OpenServiceW( disp->manager, name, + GENERIC_READ|GENERIC_WRITE ))) + FIXME( "failed to open service %s\n", debugstr_w(name) ); + } + + data_size -= info.name_size * sizeof(WCHAR); + result = service_handle_control(service, info.control, data_size ? + &data[info.name_size * sizeof(WCHAR)] : NULL, data_size); + done: LeaveCriticalSection( &service_cs ); WriteFile( disp->pipe, &result, sizeof(result), &count, NULL ); @@ -592,13 +591,13 @@ static BOOL service_run_main_thread(void) { FIXME("service should be able to delay shutdown\n"); timeout += spi.dwPreshutdownTimeout; - ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL ); + ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 ); wait_handles[n++] = services[i]->thread; } } else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN)) { - ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL ); + ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 ); wait_handles[n++] = services[i]->thread; } } diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index 98412d6ec23..0c0b49b66ba 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -34,15 +34,12 @@ cpp_quote("#define SVCCTL_ENDPOINTA \"\\\\pipe\\\\svcctl\"") cpp_quote("#define SVCCTL_STARTED_EVENT {'_','_','w','i','n','e','_','S','v','c','c','t','l','S','t','a','r','t','e','d',0}") /* Service startup protocol over control pipe - not compatible with Windows */ -enum service_pipe_command -{ - WINESERV_STARTINFO = 1, - WINESERV_SENDCONTROL = 2 -}; +cpp_quote("#define SERVICE_PROTOCOL_MAGIC 0x57494e45") +cpp_quote("#define SERVICE_CONTROL_START 0") typedef struct service_start_info_t { - enum service_pipe_command cmd; /* request code */ + DWORD magic; /* protocol magic */ DWORD total_size; /* total request size */ DWORD name_size; /* size of name in data buffer */ DWORD control; /* control code */ diff --git a/programs/services/rpc.c b/programs/services/rpc.c index bd6af95c0e2..468b380cb74 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -979,7 +979,7 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d /****************************************************************************** * process_send_command */ -BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result) +static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result) { OVERLAPPED overlapped; DWORD count, ret; @@ -1030,8 +1030,8 @@ BOOL process_send_command(struct process_entry *process, const void *data, DWORD /****************************************************************************** * process_send_control */ -static BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control, - const BYTE *data, DWORD data_size, DWORD *result) +BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control, + const BYTE *data, DWORD data_size, DWORD *result) { service_start_info *ssi; DWORD len; @@ -1041,7 +1041,7 @@ static BOOL process_send_control(struct process_entry *process, const WCHAR *nam len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size; ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len])); - ssi->cmd = WINESERV_SENDCONTROL; + ssi->magic = SERVICE_PROTOCOL_MAGIC; ssi->control = control; ssi->total_size = FIELD_OFFSET(service_start_info, data[len]); ssi->name_size = strlenW(name) + 1; diff --git a/programs/services/services.c b/programs/services/services.c index cf5cb903646..e7610bd2934 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -844,8 +844,7 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH { OVERLAPPED overlapped; DWORD i, len, result; - service_start_info *ssi; - LPWSTR p; + WCHAR *str, *p; WINE_TRACE("%p %s %p %d\n", process, wine_dbgstr_w(name), argv, argc); @@ -872,32 +871,28 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH } } - /* calculate how much space do we need to send the startup info */ len = strlenW(name) + 1; - for (i=0; icmd = WINESERV_STARTINFO; - ssi->control = 0; - ssi->total_size = FIELD_OFFSET(service_start_info, data[len]); - ssi->name_size = strlenW(name) + 1; - strcpyW((WCHAR *)ssi->data, name); + if (!(str = HeapAlloc(GetProcessHeap(), 0, len))) + return ERROR_NOT_ENOUGH_SERVER_MEMORY; - /* copy service args into a single buffer*/ - p = (WCHAR *)&ssi->data[ssi->name_size * sizeof(WCHAR)]; - for (i=0; itotal_size, &result)) + if (!process_send_control(process, name, SERVICE_CONTROL_START, (const BYTE *)str, len, &result)) result = ERROR_SERVICE_REQUEST_TIMEOUT; - HeapFree(GetProcessHeap(), 0, ssi); + HeapFree(GetProcessHeap(), 0, str); return result; } diff --git a/programs/services/services.h b/programs/services/services.h index b03a157b818..126ef2698e8 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -95,7 +95,8 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR * struct process_entry *grab_process(struct process_entry *process); void release_process(struct process_entry *process); -BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result); +BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control, + const BYTE *data, DWORD data_size, DWORD *result); void process_terminate(struct process_entry *process); extern DWORD service_pipe_timeout;