Based on a patch by Micah N Gorrell.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/advapi32/Makefile.in | 1 - dlls/advapi32/advapi32.spec | 70 +- dlls/advapi32/service.c | 2370 +------------------------ dlls/sechost/Makefile.in | 5 + dlls/sechost/sechost.spec | 70 +- dlls/sechost/service.c | 1969 ++++++++++++++++++++ dlls/{advapi32 => sechost}/svcctl.idl | 0 7 files changed, 2089 insertions(+), 2396 deletions(-) create mode 100644 dlls/sechost/service.c rename dlls/{advapi32 => sechost}/svcctl.idl (100%)
diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in index 33dbe851c9f..e70b1a7a07a 100644 --- a/dlls/advapi32/Makefile.in +++ b/dlls/advapi32/Makefile.in @@ -19,6 +19,5 @@ C_SRCS = \ service.c \ wmi.c
-IDL_SRCS = svcctl.idl
RC_SRCS = version.rc diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index cb3e856ce98..cd4dedac74d 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -89,10 +89,10 @@ @ stdcall BuildTrusteeWithSidA(ptr ptr) @ stdcall BuildTrusteeWithSidW(ptr ptr) # @ stub CancelOverlappedAccess -@ stdcall ChangeServiceConfig2A(long long ptr) -@ stdcall ChangeServiceConfig2W(long long ptr) -@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) -@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) +@ stdcall -import ChangeServiceConfig2A(long long ptr) +@ stdcall -import ChangeServiceConfig2W(long long ptr) +@ stdcall -import ChangeServiceConfigA(long long long long wstr str ptr str str str str) +@ stdcall -import ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) # @ stub CheckForHiberboot @ stdcall -import CheckTokenMembership(long ptr ptr) @ stdcall ClearEventLogA (long str) @@ -100,12 +100,12 @@ # @ stub CloseCodeAuthzLevel @ stdcall CloseEncryptedFileRaw(ptr) @ stdcall CloseEventLog (long) -@ stdcall CloseServiceHandle(long) +@ stdcall -import CloseServiceHandle(long) # @ stub CloseThreadWaitChainSession @ stdcall -import CloseTrace(int64) @ stdcall CommandLineFromMsiDescriptor(wstr ptr ptr) # @ stub ComputeAccessTokenFromCodeAuthzLevel -@ stdcall ControlService(long long ptr) +@ stdcall -import ControlService(long long ptr) # @ stub ControlServiceExA # @ stub ControlServiceExW @ stdcall -import ControlTraceA(int64 str ptr long) @@ -143,8 +143,8 @@ @ stdcall CreateProcessWithLogonW(wstr wstr wstr long wstr wstr long ptr wstr ptr ptr) @ stdcall CreateProcessWithTokenW(long long wstr wstr long ptr wstr ptr ptr) @ stdcall -import CreateRestrictedToken(long long long ptr long ptr long ptr ptr) -@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) -@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) +@ stdcall -import CreateServiceA(long str str long long long long str str ptr str str str) +@ stdcall -import CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) # @ stub CreateTraceInstanceId @ stdcall -import CreateWellKnownSid(long ptr ptr ptr) # @ stub CredBackupCredentials @@ -235,7 +235,7 @@ @ stdcall DecryptFileA(str long) @ stdcall DecryptFileW(wstr long) @ stdcall -import DeleteAce(ptr long) -@ stdcall DeleteService(long) +@ stdcall -import DeleteService(long) @ stdcall DeregisterEventSource(long) @ stdcall -import DestroyPrivateObjectSecurity(ptr) # @ stub DuplicateEncryptionInfoFile @@ -271,13 +271,13 @@ # @ stub EncryptedFileKeyInfo # @ stub EncryptionDisable @ stdcall EnumDependentServicesA(long long ptr long ptr ptr) -@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) +@ stdcall -import EnumDependentServicesW(long long ptr long ptr ptr) @ stdcall -import EnumDynamicTimeZoneInformation(long ptr) @ stub EnumServiceGroupA @ stub EnumServiceGroupW @ stdcall EnumServicesStatusA (long long long ptr long ptr ptr ptr) @ stdcall EnumServicesStatusExA(long long long long ptr long ptr ptr ptr str) -@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) +@ stdcall -import EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) @ stdcall EnumServicesStatusW (long long long ptr long ptr ptr ptr) @ stdcall EnumerateTraceGuids(ptr long ptr) # @ stub EnumerateTraceGuidsEx @@ -361,9 +361,9 @@ @ stdcall GetSecurityInfoExA (long long long str str ptr ptr ptr ptr) @ stdcall GetSecurityInfoExW (long long long wstr wstr ptr ptr ptr ptr) @ stdcall GetServiceDisplayNameA(ptr str ptr ptr) -@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) +@ stdcall -import GetServiceDisplayNameW(ptr wstr ptr ptr) @ stdcall GetServiceKeyNameA(long str ptr ptr) -@ stdcall GetServiceKeyNameW(long wstr ptr ptr) +@ stdcall -import GetServiceKeyNameW(long wstr ptr ptr) @ stdcall -import GetSidIdentifierAuthority(ptr) @ stdcall -import GetSidLengthRequired(long) @ stdcall -import GetSidSubAuthority(ptr long) @@ -526,7 +526,7 @@ @ stdcall NotifyChangeEventLog (long long) # @ stub NotifyServiceStatusChange # @ stub NotifyServiceStatusChangeA -@ stdcall NotifyServiceStatusChangeW(ptr long ptr) +@ stdcall -import NotifyServiceStatusChangeW(ptr long ptr) # @ stub NpGetUserName @ stdcall ObjectCloseAuditAlarmA(str ptr long) @ stdcall -import ObjectCloseAuditAlarmW(wstr ptr long) @@ -543,10 +543,10 @@ @ stdcall OpenEventLogA (str str) @ stdcall OpenEventLogW (wstr wstr) @ stdcall -import OpenProcessToken(long long ptr) -@ stdcall OpenSCManagerA(str str long) -@ stdcall OpenSCManagerW(wstr wstr long) -@ stdcall OpenServiceA(long str long) -@ stdcall OpenServiceW(long wstr long) +@ stdcall -import OpenSCManagerA(str str long) +@ stdcall -import OpenSCManagerW(wstr wstr long) +@ stdcall -import OpenServiceA(long str long) +@ stdcall -import OpenServiceW(long wstr long) @ stdcall -import OpenThreadToken(long long long ptr) # @ stub OpenThreadWaitChainSession @ stdcall -ret64 OpenTraceA(ptr) @@ -593,16 +593,16 @@ # @ stub QueryLocalUserServiceName # @ stub QueryRecoveryAgentsOnEncryptedFile # @ stub QuerySecurityAccessMask -@ stdcall QueryServiceConfig2A(long long ptr long ptr) -@ stdcall QueryServiceConfig2W(long long ptr long ptr) -@ stdcall QueryServiceConfigA(long ptr long ptr) -@ stdcall QueryServiceConfigW(long ptr long ptr) +@ stdcall -import QueryServiceConfig2A(long long ptr long ptr) +@ stdcall -import QueryServiceConfig2W(long long ptr long ptr) +@ stdcall -import QueryServiceConfigA(long ptr long ptr) +@ stdcall -import QueryServiceConfigW(long ptr long ptr) # @ stub QueryServiceDynamicInformation @ stdcall QueryServiceLockStatusA(long ptr long ptr) @ stdcall QueryServiceLockStatusW(long ptr long ptr) -@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) -@ stdcall QueryServiceStatus(long ptr) -@ stdcall QueryServiceStatusEx (long long ptr long ptr) +@ stdcall -import QueryServiceObjectSecurity(long long ptr long ptr) +@ stdcall -import QueryServiceStatus(long ptr) +@ stdcall -import QueryServiceStatusEx (long long ptr long ptr) # @ stub QueryTraceA @ stdcall QueryTraceW(int64 wstr ptr) # @ stub QueryUserServiceName @@ -697,10 +697,10 @@ @ stdcall RegisterEventSourceA(str str) @ stdcall RegisterEventSourceW(wstr wstr) # @ stub RegisterIdleTask -@ stdcall RegisterServiceCtrlHandlerA(str ptr) -@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) -@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) -@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) +@ stdcall -import RegisterServiceCtrlHandlerA(str ptr) +@ stdcall -import RegisterServiceCtrlHandlerExA(str ptr ptr) +@ stdcall -import RegisterServiceCtrlHandlerExW(wstr ptr ptr) +@ stdcall -import RegisterServiceCtrlHandlerW(wstr ptr) @ stdcall RegisterTraceGuidsA(ptr ptr ptr long ptr str str ptr) ntdll.EtwRegisterTraceGuidsA @ stdcall RegisterTraceGuidsW(ptr ptr ptr long ptr wstr wstr ptr) ntdll.EtwRegisterTraceGuidsW @ stdcall RegisterWaitChainCOMCallback(ptr ptr) @@ -761,17 +761,17 @@ # @ stub SetSecurityInfoExA # @ stub SetSecurityInfoExW @ stdcall SetServiceBits(long long long long) -@ stdcall SetServiceObjectSecurity(long long ptr) -@ stdcall SetServiceStatus(long ptr) +@ stdcall -import SetServiceObjectSecurity(long long ptr) +@ stdcall -import SetServiceStatus(long ptr) @ stdcall -import SetThreadToken(ptr ptr) @ stdcall -import SetTokenInformation(long long ptr long) # @ stub SetTraceCallback # @ stub SetUserFileEncryptionKey # @ stub SetUserFileEncryptionKeyEx -@ stdcall StartServiceA(long long ptr) -@ stdcall StartServiceCtrlDispatcherA(ptr) -@ stdcall StartServiceCtrlDispatcherW(ptr) -@ stdcall StartServiceW(long long ptr) +@ stdcall -import StartServiceA(long long ptr) +@ stdcall -import StartServiceCtrlDispatcherA(ptr) +@ stdcall -import StartServiceCtrlDispatcherW(ptr) +@ stdcall -import StartServiceW(long long ptr) @ stdcall -import StartTraceA(ptr str ptr) @ stdcall -import StartTraceW(ptr wstr ptr) @ stdcall StopTraceA(int64 str ptr) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index eb195d84d05..2146ddfb186 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -20,1661 +20,34 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <string.h> -#include <time.h> -#include <assert.h> - -#define NONAMELESSUNION - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winsvc.h" -#include "winerror.h" -#include "winreg.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "winternl.h" -#include "lmcons.h" -#include "lmserver.h" - -#include "svcctl.h" - -#include "advapi32_misc.h" - -#include "wine/exception.h" -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(service); - -void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len) -{ - return heap_alloc(len); -} - -void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) -{ - heap_free(ptr); -} - -typedef struct service_data_t -{ - LPHANDLER_FUNCTION_EX handler; - LPVOID context; - HANDLE thread; - SC_HANDLE handle; - SC_HANDLE full_access_handle; - BOOL unicode : 1; - union { - LPSERVICE_MAIN_FUNCTIONA a; - LPSERVICE_MAIN_FUNCTIONW w; - } proc; - LPWSTR args; - WCHAR name[1]; -} service_data; - -typedef struct dispatcher_data_t -{ - SC_HANDLE manager; - HANDLE pipe; -} dispatcher_data; - -typedef struct notify_data_t { - SC_HANDLE service; - SC_RPC_NOTIFY_PARAMS params; - SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams; - SC_NOTIFY_RPC_HANDLE notify_handle; - SERVICE_NOTIFYW *notify_buffer; - HANDLE calling_thread, ready_evt; - struct list entry; -} notify_data; - -static struct list notify_list = LIST_INIT(notify_list); - -static CRITICAL_SECTION service_cs; -static CRITICAL_SECTION_DEBUG service_cs_debug = -{ - 0, 0, &service_cs, - { &service_cs_debug.ProcessLocksList, - &service_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") } -}; -static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 }; - -static service_data **services; -static unsigned int nb_services; -static HANDLE service_event; -static BOOL stop_service; - -extern HANDLE CDECL __wine_make_process_system(void); - -static inline LPWSTR SERV_dupmulti(LPCSTR str) -{ - UINT len = 0, n = 0; - LPWSTR wstr; - - if( !str ) - return NULL; - do { - len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 ); - n += (strlen( &str[n] ) + 1); - } while (str[n]); - len++; - n++; - - wstr = heap_alloc( len*sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len ); - return wstr; -} - -static inline DWORD multisz_cb(LPCWSTR wmultisz) -{ - const WCHAR *wptr = wmultisz; - - if (wmultisz == NULL) - return 0; - - while (*wptr) - wptr += lstrlenW(wptr)+1; - return (wptr - wmultisz + 1)*sizeof(WCHAR); -} - -/****************************************************************************** - * RPC connection with services.exe - */ -static handle_t rpc_wstr_bind(RPC_WSTR str) -{ - WCHAR transport[] = SVCCTL_TRANSPORT; - WCHAR endpoint[] = SVCCTL_ENDPOINT; - RPC_WSTR binding_str; - RPC_STATUS status; - handle_t rpc_handle; - - status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status); - return NULL; - } - - status = RpcBindingFromStringBindingW(binding_str, &rpc_handle); - RpcStringFreeW(&binding_str); - - if (status != RPC_S_OK) - { - ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status); - return NULL; - } - - return rpc_handle; -} - -static handle_t rpc_cstr_bind(RPC_CSTR str) -{ - RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA; - RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA; - RPC_CSTR binding_str; - RPC_STATUS status; - handle_t rpc_handle; - - status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str); - if (status != RPC_S_OK) - { - ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status); - return NULL; - } - - status = RpcBindingFromStringBindingA(binding_str, &rpc_handle); - RpcStringFreeA(&binding_str); - - if (status != RPC_S_OK) - { - ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status); - return NULL; - } - - return rpc_handle; -} - -DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName) -{ - return rpc_cstr_bind((RPC_CSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName) -{ - return rpc_wstr_bind((RPC_WSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName) -{ - return rpc_wstr_bind((RPC_WSTR)MachineName); -} - -DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h) -{ - RpcBindingFree(&h); -} - -static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr) -{ - return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode); -} - -static DWORD map_exception_code(DWORD exception_code) -{ - switch (exception_code) - { - case RPC_X_NULL_REF_POINTER: - return ERROR_INVALID_ADDRESS; - case RPC_X_ENUM_VALUE_OUT_OF_RANGE: - case RPC_X_BYTE_COUNT_TOO_SMALL: - return ERROR_INVALID_PARAMETER; - case RPC_S_INVALID_BINDING: - case RPC_X_SS_IN_NULL_CONTEXT: - return ERROR_INVALID_HANDLE; - default: - return exception_code; - } -} - -/****************************************************************************** - * Service IPC functions - */ -static LPWSTR service_get_pipe_name(void) -{ - static const WCHAR format[] = { '\','\','.','\','p','i','p','e','\', - 'n','e','t','\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0}; - static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\', - 'C','o','n','t','r','o','l','\', - 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0}; - LPWSTR name; - DWORD len; - HKEY service_current_key; - DWORD service_current; - LONG ret; - DWORD type; - - ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0, - KEY_QUERY_VALUE, &service_current_key); - if (ret != ERROR_SUCCESS) - return NULL; - len = sizeof(service_current); - ret = RegQueryValueExW(service_current_key, NULL, NULL, &type, - (BYTE *)&service_current, &len); - RegCloseKey(service_current_key); - if (ret != ERROR_SUCCESS || type != REG_DWORD) - return NULL; - len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */; - name = heap_alloc(len * sizeof(WCHAR)); - if (!name) - return NULL; - snprintfW(name, len, format, service_current); - return name; -} - -static HANDLE service_open_pipe(void) -{ - LPWSTR szPipe = service_get_pipe_name(); - HANDLE handle = INVALID_HANDLE_VALUE; - - do { - handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE, - 0, NULL, OPEN_ALWAYS, 0, NULL); - if (handle != INVALID_HANDLE_VALUE) - break; - if (GetLastError() != ERROR_PIPE_BUSY) - break; - } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT)); - heap_free(szPipe); - - return handle; -} - -static service_data *find_service_by_name( const WCHAR *name ) -{ - unsigned int i; - - if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */ - return services[0]; - for (i = 0; i < nb_services; i++) - if (!strcmpiW( name, services[i]->name )) return services[i]; - return NULL; -} - -/****************************************************************************** - * service_thread - * - * Call into the main service routine provided by StartServiceCtrlDispatcher. - */ -static DWORD WINAPI service_thread(LPVOID arg) -{ - service_data *info = arg; - LPWSTR str = info->args; - DWORD argc = 0, len = 0; - - TRACE("%p\n", arg); - - while (str[len]) - { - len += strlenW(&str[len]) + 1; - argc++; - } - len++; - - if (info->unicode) - { - LPWSTR *argv, p; - - argv = heap_alloc((argc+1)*sizeof(LPWSTR)); - for (argc=0, p=str; *p; p += strlenW(p) + 1) - argv[argc++] = p; - argv[argc] = NULL; - - info->proc.w(argc, argv); - heap_free(argv); - } - else - { - LPSTR strA, *argv, p; - DWORD lenA; - - lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL); - strA = heap_alloc(lenA); - WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL); - - argv = heap_alloc((argc+1)*sizeof(LPSTR)); - for (argc=0, p=strA; *p; p += strlen(p) + 1) - argv[argc++] = p; - argv[argc] = NULL; - - info->proc.a(argc, argv); - heap_free(argv); - heap_free(strA); - } - return 0; -} - -/****************************************************************************** - * service_handle_start - */ -static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size) -{ - DWORD count = data_size / sizeof(WCHAR); - - if (service->thread) - { - WARN("service is not stopped\n"); - return ERROR_SERVICE_ALREADY_RUNNING; - } - - heap_free(service->args); - 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 */ - return 0; -} - -/****************************************************************************** - * service_handle_control - */ -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 data_size %u\n", debugstr_w(service->name), control, data, data_size); - - 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; -} - -/****************************************************************************** - * service_control_dispatcher - */ -static DWORD WINAPI service_control_dispatcher(LPVOID arg) -{ - dispatcher_data *disp = arg; - - /* dispatcher loop */ - while (1) - { - service_data *service; - service_start_info info; - BYTE *data = NULL; - WCHAR *name; - BOOL r; - DWORD data_size = 0, count, result; - - r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL ); - if (!r) - { - if (GetLastError() != ERROR_BROKEN_PIPE) - ERR( "pipe read failed error %u\n", GetLastError() ); - break; - } - if (count != FIELD_OFFSET(service_start_info,data)) - { - ERR( "partial pipe read %u\n", count ); - break; - } - if (count < info.total_size) - { - data_size = info.total_size - FIELD_OFFSET(service_start_info,data); - data = heap_alloc( data_size ); - r = ReadFile( disp->pipe, data, data_size, &count, NULL ); - if (!r) - { - if (GetLastError() != ERROR_BROKEN_PIPE) - ERR( "pipe read failed error %u\n", GetLastError() ); - heap_free( data ); - break; - } - if (count != data_size) - { - ERR( "partial pipe read %u/%u\n", count, data_size ); - heap_free( data ); - break; - } - } - - EnterCriticalSection( &service_cs ); - - /* validate service name */ - name = (WCHAR *)data; - if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1]) - { - ERR( "got request without valid service name\n" ); - result = ERROR_INVALID_PARAMETER; - goto done; - } - - if (info.magic != SERVICE_PROTOCOL_MAGIC) - { - ERR( "received invalid request for service %s\n", debugstr_w(name) ); - result = ERROR_INVALID_PARAMETER; - goto done; - } - - /* find the service */ - if (!(service = find_service_by_name( name ))) - { - FIXME( "got request for unknown service %s\n", debugstr_w(name) ); - result = ERROR_INVALID_PARAMETER; - 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 ); - heap_free( data ); - } - - CloseHandle( disp->pipe ); - CloseServiceHandle( disp->manager ); - heap_free( disp ); - return 1; -} - -/* wait for services which accept this type of message to become STOPPED */ -static void handle_shutdown_msg(DWORD msg, DWORD accept) -{ - SERVICE_STATUS st; - SERVICE_PRESHUTDOWN_INFO spi; - DWORD i, n = 0, sz, timeout = 2000; - ULONGLONG stop_time; - BOOL res, done = TRUE; - SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services ); - - EnterCriticalSection( &service_cs ); - for (i = 0; i < nb_services; i++) - { - res = QueryServiceStatus( services[i]->full_access_handle, &st ); - if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept)) - continue; - - done = FALSE; - - if (accept == SERVICE_ACCEPT_PRESHUTDOWN) - { - res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO, - (LPBYTE)&spi, sizeof(spi), &sz ); - if (res) - { - FIXME( "service should be able to delay shutdown\n" ); - timeout = max( spi.dwPreshutdownTimeout, timeout ); - } - } - - service_handle_control( services[i], msg, NULL, 0 ); - wait_handles[n++] = services[i]->full_access_handle; - } - LeaveCriticalSection( &service_cs ); - - /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */ - timeout = min( timeout, 3000 ); - stop_time = GetTickCount64() + timeout; - - while (!done && GetTickCount64() < stop_time) - { - done = TRUE; - for (i = 0; i < n; i++) - { - res = QueryServiceStatus( wait_handles[i], &st ); - if (!res || st.dwCurrentState == SERVICE_STOPPED) - continue; - - done = FALSE; - Sleep( 100 ); - break; - } - } - - HeapFree( GetProcessHeap(), 0, wait_handles ); -} - -/****************************************************************************** - * service_run_main_thread - */ -static BOOL service_run_main_thread(void) -{ - DWORD i, n, ret; - HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; - UINT wait_services[MAXIMUM_WAIT_OBJECTS]; - dispatcher_data *disp = heap_alloc( sizeof(*disp) ); - - disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); - if (!disp->manager) - { - ERR("failed to open service manager error %u\n", GetLastError()); - heap_free( disp ); - return FALSE; - } - - disp->pipe = service_open_pipe(); - if (disp->pipe == INVALID_HANDLE_VALUE) - { - WARN("failed to create control pipe error %u\n", GetLastError()); - CloseServiceHandle( disp->manager ); - heap_free( disp ); - SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ); - return FALSE; - } - - service_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - stop_service = FALSE; - - /* FIXME: service_control_dispatcher should be merged into the main thread */ - wait_handles[0] = __wine_make_process_system(); - wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL ); - wait_handles[2] = service_event; - - TRACE("Starting %d services running as process %d\n", - nb_services, GetCurrentProcessId()); - - /* wait for all the threads to pack up and exit */ - while (!stop_service) - { - EnterCriticalSection( &service_cs ); - for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++) - { - if (!services[i]->thread) continue; - wait_services[n] = i; - wait_handles[n++] = services[i]->thread; - } - LeaveCriticalSection( &service_cs ); - - ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE ); - if (!ret) /* system process event */ - { - handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN); - handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN); - ExitProcess(0); - } - else if (ret == 1) - { - TRACE( "control dispatcher exited, shutting down\n" ); - /* FIXME: we should maybe send a shutdown control to running services */ - ExitProcess(0); - } - else if (ret == 2) - { - continue; /* rebuild the list */ - } - else if (ret < n) - { - i = wait_services[ret]; - EnterCriticalSection( &service_cs ); - CloseHandle( services[i]->thread ); - services[i]->thread = NULL; - LeaveCriticalSection( &service_cs ); - } - else return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * StartServiceCtrlDispatcherA [ADVAPI32.@] - * - * See StartServiceCtrlDispatcherW. - */ -BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent ) -{ - service_data *info; - unsigned int i; - - TRACE("%p\n", servent); - - if (nb_services) - { - SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); - return FALSE; - } - while (servent[nb_services].lpServiceName) nb_services++; - if (!nb_services) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - services = heap_alloc( nb_services * sizeof(*services) ); - - for (i = 0; i < nb_services; i++) - { - DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0); - DWORD sz = FIELD_OFFSET( service_data, name[len] ); - info = heap_alloc_zero( sz ); - MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len); - info->proc.a = servent[i].lpServiceProc; - info->unicode = FALSE; - services[i] = info; - } - - return service_run_main_thread(); -} - -/****************************************************************************** - * StartServiceCtrlDispatcherW [ADVAPI32.@] - * - * Connects a process containing one or more services to the service control - * manager. - * - * PARAMS - * servent [I] A list of the service names and service procedures - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - */ -BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent ) -{ - service_data *info; - unsigned int i; - - TRACE("%p\n", servent); - - if (nb_services) - { - SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); - return FALSE; - } - while (servent[nb_services].lpServiceName) nb_services++; - if (!nb_services) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return FALSE; - } - - services = heap_alloc( nb_services * sizeof(*services) ); - - for (i = 0; i < nb_services; i++) - { - DWORD len = strlenW(servent[i].lpServiceName) + 1; - DWORD sz = FIELD_OFFSET( service_data, name[len] ); - info = heap_alloc_zero( sz ); - strcpyW(info->name, servent[i].lpServiceName); - info->proc.w = servent[i].lpServiceProc; - info->unicode = TRUE; - services[i] = info; - } - - return service_run_main_thread(); -} - -/****************************************************************************** - * LockServiceDatabase [ADVAPI32.@] - */ -SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) -{ - /* this function is a no-op in Vista and above */ - TRACE("%p\n", manager); - return (SC_LOCK)0xdeadbeef; -} - -/****************************************************************************** - * UnlockServiceDatabase [ADVAPI32.@] - */ -BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock ) -{ - /* this function is a no-op in Vista and above */ - TRACE("%p\n", lock); - return TRUE; -} - -/****************************************************************************** - * SetServiceStatus [ADVAPI32.@] - * - * PARAMS - * hService [] - * lpStatus [] - */ -BOOL WINAPI -SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus ) -{ - DWORD err; - - TRACE("%p %x %x %x %x %x %x %x\n", hService, - lpStatus->dwServiceType, lpStatus->dwCurrentState, - lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode, - lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint, - lpStatus->dwWaitHint); - - __TRY - { - err = svcctl_SetServiceStatus( hService, lpStatus ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - if (lpStatus->dwCurrentState == SERVICE_STOPPED) - { - unsigned int i, count = 0; - EnterCriticalSection( &service_cs ); - for (i = 0; i < nb_services; i++) - { - if (services[i]->handle == (SC_HANDLE)hService) continue; - if (services[i]->thread) count++; - } - if (!count) - { - stop_service = TRUE; - SetEvent( service_event ); /* notify the main loop */ - } - LeaveCriticalSection( &service_cs ); - } - - return TRUE; -} - - -/****************************************************************************** - * OpenSCManagerA [ADVAPI32.@] - * - * Establish a connection to the service control manager and open its database. - * - * PARAMS - * lpMachineName [I] Pointer to machine name string - * lpDatabaseName [I] Pointer to database name string - * dwDesiredAccess [I] Type of access - * - * RETURNS - * Success: A Handle to the service control manager database - * Failure: NULL - */ -SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName, - DWORD dwDesiredAccess ) -{ - LPWSTR machineW, databaseW; - SC_HANDLE ret; - - machineW = strdupAW(lpMachineName); - databaseW = strdupAW(lpDatabaseName); - ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess); - heap_free(databaseW); - heap_free(machineW); - return ret; -} - -/****************************************************************************** - * OpenSCManagerW [ADVAPI32.@] - * - * See OpenSCManagerA. - */ -static DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, - DWORD dwDesiredAccess, SC_HANDLE *handle ) -{ - DWORD r; - - TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName), - debugstr_w(lpDatabaseName), dwDesiredAccess); - - __TRY - { - r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle); - } - __EXCEPT(rpc_filter) - { - r = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (r!=ERROR_SUCCESS) - *handle = 0; - - TRACE("returning %p\n", *handle); - return r; -} - -SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, - DWORD dwDesiredAccess ) -{ - SC_HANDLE handle = 0; - DWORD r; - - r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle); - if (r!=ERROR_SUCCESS) - SetLastError(r); - return handle; -} - -/****************************************************************************** - * ControlService [ADVAPI32.@] - * - * Send a control code to a service. - * - * PARAMS - * hService [I] Handle of the service control manager database - * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h") - * lpServiceStatus [O] Destination for the status of the service, if available - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - * - * BUGS - * Unlike M$' implementation, control requests are not serialized and may be - * processed asynchronously. - */ -BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl, - LPSERVICE_STATUS lpServiceStatus ) -{ - DWORD err; - - TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus); - - __TRY - { - err = svcctl_ControlService(hService, dwControl, lpServiceStatus); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * CloseServiceHandle [ADVAPI32.@] - * - * Close a handle to a service or the service control manager database. - * - * PARAMS - * hSCObject [I] Handle to service or service control manager database - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI -CloseServiceHandle( SC_HANDLE hSCObject ) -{ - DWORD err; - - TRACE("%p\n", hSCObject); - - __TRY - { - err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - return TRUE; -} - - -/****************************************************************************** - * OpenServiceA [ADVAPI32.@] - * - * Open a handle to a service. - * - * PARAMS - * hSCManager [I] Handle of the service control manager database - * lpServiceName [I] Name of the service to open - * dwDesiredAccess [I] Access required to the service - * - * RETURNS - * Success: Handle to the service - * Failure: NULL - */ -SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, - DWORD dwDesiredAccess ) -{ - LPWSTR lpServiceNameW; - SC_HANDLE ret; - - TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess); - - lpServiceNameW = strdupAW(lpServiceName); - ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess); - heap_free(lpServiceNameW); - return ret; -} - - -/****************************************************************************** - * OpenServiceW [ADVAPI32.@] - * - * See OpenServiceA. - */ -static DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - DWORD dwDesiredAccess, SC_HANDLE *handle ) -{ - DWORD err; - - TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess); - - if (!hSCManager) - return ERROR_INVALID_HANDLE; - - __TRY - { - err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - *handle = 0; - - TRACE("returning %p\n", *handle); - return err; -} - -SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - DWORD dwDesiredAccess) -{ - SC_HANDLE handle = 0; - DWORD err; - - err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle); - if (err != ERROR_SUCCESS) - SetLastError(err); - return handle; -} - -/****************************************************************************** - * CreateServiceW [ADVAPI32.@] - */ -SC_HANDLE WINAPI -CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - LPCWSTR lpDisplayName, DWORD dwDesiredAccess, - DWORD dwServiceType, DWORD dwStartType, - DWORD dwErrorControl, LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, - LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, - LPCWSTR lpPassword ) -{ - SC_HANDLE handle = 0; - DWORD err; - SIZE_T passwdlen; - - TRACE("%p %s %s\n", hSCManager, - debugstr_w(lpServiceName), debugstr_w(lpDisplayName)); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return 0; - } - - if (lpPassword) - passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR); - else - passwdlen = 0; - - __TRY - { - BOOL is_wow64; - - IsWow64Process(GetCurrentProcess(), &is_wow64); - - if (is_wow64) - err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName, - lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies, - multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen, - (SC_RPC_HANDLE *)&handle); - else - err = svcctl_CreateServiceW(hSCManager, lpServiceName, - lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies, - multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen, - (SC_RPC_HANDLE *)&handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - SetLastError(err); - handle = 0; - } - return handle; -} - - -/****************************************************************************** - * CreateServiceA [ADVAPI32.@] - */ -SC_HANDLE WINAPI -CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, - LPCSTR lpDisplayName, DWORD dwDesiredAccess, - DWORD dwServiceType, DWORD dwStartType, - DWORD dwErrorControl, LPCSTR lpBinaryPathName, - LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, - LPCSTR lpDependencies, LPCSTR lpServiceStartName, - LPCSTR lpPassword ) -{ - LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW, - lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW; - SC_HANDLE r; - - TRACE("%p %s %s\n", hSCManager, - debugstr_a(lpServiceName), debugstr_a(lpDisplayName)); - - lpServiceNameW = strdupAW( lpServiceName ); - lpDisplayNameW = strdupAW( lpDisplayName ); - lpBinaryPathNameW = strdupAW( lpBinaryPathName ); - lpLoadOrderGroupW = strdupAW( lpLoadOrderGroup ); - lpDependenciesW = SERV_dupmulti( lpDependencies ); - lpServiceStartNameW = strdupAW( lpServiceStartName ); - lpPasswordW = strdupAW( lpPassword ); - - r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW, - dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, - lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId, - lpDependenciesW, lpServiceStartNameW, lpPasswordW ); - - heap_free( lpServiceNameW ); - heap_free( lpDisplayNameW ); - heap_free( lpBinaryPathNameW ); - heap_free( lpLoadOrderGroupW ); - heap_free( lpDependenciesW ); - heap_free( lpServiceStartNameW ); - heap_free( lpPasswordW ); - - return r; -} - - -/****************************************************************************** - * DeleteService [ADVAPI32.@] - * - * Delete a service from the service control manager database. - * - * PARAMS - * hService [I] Handle of the service to delete - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DeleteService( SC_HANDLE hService ) -{ - DWORD err; - - TRACE("%p\n", hService); - - __TRY - { - err = svcctl_DeleteService(hService); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != 0) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - - -/****************************************************************************** - * StartServiceA [ADVAPI32.@] - * - * Start a service - * - * PARAMS - * hService [I] Handle of service - * dwNumServiceArgs [I] Number of arguments - * lpServiceArgVectors [I] Address of array of argument strings - * - * NOTES - * - NT implements this function using an obscure RPC call. - * - You might need to do a "setenv SystemRoot \WINNT" in your .cshrc - * to get things like "%SystemRoot%\System32\service.exe" to load. - * - This will only work for shared address space. How should the service - * args be transferred when address spaces are separated? - * - Can only start one service at a time. - * - Has no concept of privilege. - * - * RETURNS - * Success: TRUE. - * Failure: FALSE - */ -BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs, - LPCSTR *lpServiceArgVectors ) -{ - LPWSTR *lpwstr=NULL; - unsigned int i; - BOOL r; - - TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors); - - if (dwNumServiceArgs) - lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) ); - - for(i=0; i<dwNumServiceArgs; i++) - lpwstr[i]=strdupAW(lpServiceArgVectors[i]); - - r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr); - - if (dwNumServiceArgs) - { - for(i=0; i<dwNumServiceArgs; i++) - heap_free(lpwstr[i]); - heap_free(lpwstr); - } - - return r; -} - - -/****************************************************************************** - * StartServiceW [ADVAPI32.@] - * - * See StartServiceA. - */ -BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs, - LPCWSTR *lpServiceArgVectors) -{ - DWORD err; - - TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors); - - __TRY - { - err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * QueryServiceStatus [ADVAPI32.@] - * - * PARAMS - * hService [I] Handle to service to get information about - * lpservicestatus [O] buffer to receive the status information for the service - * - */ -BOOL WINAPI QueryServiceStatus(SC_HANDLE hService, - LPSERVICE_STATUS lpservicestatus) -{ - SERVICE_STATUS_PROCESS SvcStatusData; - BOOL ret; - DWORD dummy; - - TRACE("%p %p\n", hService, lpservicestatus); - - if (!hService) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - if (!lpservicestatus) - { - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData, - sizeof(SERVICE_STATUS_PROCESS), &dummy); - if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ; - return ret; -} - - -/****************************************************************************** - * QueryServiceStatusEx [ADVAPI32.@] - * - * Get information about a service. - * - * PARAMS - * hService [I] Handle to service to get information about - * InfoLevel [I] Level of information to get - * lpBuffer [O] Destination for requested information - * cbBufSize [I] Size of lpBuffer in bytes - * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small - * - * RETURNS - * Success: TRUE - * FAILURE: FALSE - */ -BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel, - LPBYTE lpBuffer, DWORD cbBufSize, - LPDWORD pcbBytesNeeded) -{ - DWORD err; - - TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); - - if (InfoLevel != SC_STATUS_PROCESS_INFO) - { - err = ERROR_INVALID_LEVEL; - } - else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) - { - *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); - err = ERROR_INSUFFICIENT_BUFFER; - } - else - { - __TRY - { - err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - } - if (err != ERROR_SUCCESS) - { - SetLastError(err); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * QueryServiceConfigA [ADVAPI32.@] - */ -BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config, - DWORD size, LPDWORD needed ) -{ - DWORD n; - LPSTR p, buffer; - BOOL ret; - QUERY_SERVICE_CONFIGW *configW; - - TRACE("%p %p %d %p\n", hService, config, size, needed); - - if (!(buffer = heap_alloc( 2 * size ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - configW = (QUERY_SERVICE_CONFIGW *)buffer; - ret = QueryServiceConfigW( hService, configW, 2 * size, needed ); - if (!ret) goto done; - - config->dwServiceType = configW->dwServiceType; - config->dwStartType = configW->dwStartType; - config->dwErrorControl = configW->dwErrorControl; - config->lpBinaryPathName = NULL; - config->lpLoadOrderGroup = NULL; - config->dwTagId = configW->dwTagId; - config->lpDependencies = NULL; - config->lpServiceStartName = NULL; - config->lpDisplayName = NULL; - - p = (LPSTR)(config + 1); - n = size - sizeof(*config); - ret = FALSE; - -#define MAP_STR(str) \ - do { \ - if (configW->str) \ - { \ - DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \ - if (!sz) goto done; \ - config->str = p; \ - p += sz; \ - n -= sz; \ - } \ - } while (0) - - MAP_STR( lpBinaryPathName ); - MAP_STR( lpLoadOrderGroup ); - MAP_STR( lpDependencies ); - MAP_STR( lpServiceStartName ); - MAP_STR( lpDisplayName ); -#undef MAP_STR - - *needed = p - (LPSTR)config; - ret = TRUE; - -done: - heap_free( buffer ); - return ret; -} - -static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr) -{ - DWORD cb; - - if (!*string_ptr) - { - cb = sizeof(WCHAR); - memset(*buf, 0, cb); - } - else - { - cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR); - memcpy(*buf, *string_ptr, cb); - MIDL_user_free(*string_ptr); - } - - *string_ptr = (LPWSTR)*buf; - *buf += cb; - - return cb; -} - -static DWORD size_string(LPCWSTR string) -{ - return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR)); -} - -/****************************************************************************** - * QueryServiceConfigW [ADVAPI32.@] - */ -BOOL WINAPI -QueryServiceConfigW( SC_HANDLE hService, - LPQUERY_SERVICE_CONFIGW lpServiceConfig, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - QUERY_SERVICE_CONFIGW config; - DWORD total; - DWORD err; - BYTE *bufpos; - - TRACE("%p %p %d %p\n", hService, lpServiceConfig, - cbBufSize, pcbBytesNeeded); - - memset(&config, 0, sizeof(config)); - - __TRY - { - err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - TRACE("services.exe: error %u\n", err); - SetLastError(err); - return FALSE; - } - - /* calculate the size required first */ - total = sizeof (QUERY_SERVICE_CONFIGW); - total += size_string(config.lpBinaryPathName); - total += size_string(config.lpLoadOrderGroup); - total += size_string(config.lpDependencies); - total += size_string(config.lpServiceStartName); - total += size_string(config.lpDisplayName); - - *pcbBytesNeeded = total; - - /* if there's not enough memory, return an error */ - if( total > cbBufSize ) - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - MIDL_user_free(config.lpBinaryPathName); - MIDL_user_free(config.lpLoadOrderGroup); - MIDL_user_free(config.lpDependencies); - MIDL_user_free(config.lpServiceStartName); - MIDL_user_free(config.lpDisplayName); - return FALSE; - } - - *lpServiceConfig = config; - bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName); - move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName); +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "wine/unicode.h" +#include "wine/debug.h"
- TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) ); - TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) ); - TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) ); - TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) ); - TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) ); +#include "advapi32_misc.h"
- return TRUE; -} +WINE_DEFAULT_DEBUG_CHANNEL(service);
/****************************************************************************** - * QueryServiceConfig2A [ADVAPI32.@] - * - * Note - * observed under win2k: - * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same - * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION + * LockServiceDatabase [ADVAPI32.@] */ -BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, - DWORD size, LPDWORD needed) +SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager ) { - BOOL ret; - LPBYTE bufferW = NULL; - - TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed); - - if(buffer && size) - bufferW = heap_alloc(size); - - ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed); - if(!ret) goto cleanup; - - switch(dwLevel) { - case SERVICE_CONFIG_DESCRIPTION: - if (buffer && bufferW) { - LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer; - LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW; - if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) { - DWORD sz; - configA->lpDescription = (LPSTR)(configA + 1); - sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, - configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL ); - if (!sz) { - FIXME("WideCharToMultiByte failed for configW->lpDescription\n"); - ret = FALSE; - configA->lpDescription = NULL; - } - } - else configA->lpDescription = NULL; - } - break; - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - if (buffer && bufferW && *needed<=size) - memcpy(buffer, bufferW, *needed); - break; - default: - FIXME("conversation W->A not implemented for level %d\n", dwLevel); - ret = FALSE; - break; - } - -cleanup: - heap_free( bufferW); - return ret; + /* this function is a no-op in Vista and above */ + TRACE("%p\n", manager); + return (SC_LOCK)0xdeadbeef; }
/****************************************************************************** - * QueryServiceConfig2W [ADVAPI32.@] - * - * See QueryServiceConfig2A. + * UnlockServiceDatabase [ADVAPI32.@] */ -BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, - DWORD size, LPDWORD needed) +BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock ) { - BYTE *bufptr; - DWORD err; - - TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed); - - if (!buffer && size) - { - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - switch (dwLevel) - { - case SERVICE_CONFIG_DESCRIPTION: - if (!(bufptr = heap_alloc( size ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - break; - - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - bufptr = buffer; - break; - - default: - FIXME("Level %d not implemented\n", dwLevel); - SetLastError(ERROR_INVALID_LEVEL); - return FALSE; - } - - if (!needed) - { - if (dwLevel == SERVICE_CONFIG_DESCRIPTION) heap_free(bufptr); - SetLastError(ERROR_INVALID_ADDRESS); - return FALSE; - } - - __TRY - { - err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - switch (dwLevel) - { - case SERVICE_CONFIG_DESCRIPTION: - { - SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer; - struct service_description *s = (struct service_description *)bufptr; - - if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER) - { - heap_free( bufptr ); - SetLastError( err ); - return FALSE; - } - - /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */ - if (*needed == sizeof(*s)) *needed = sizeof(*desc); - else - *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc); - - if (size < *needed) - { - heap_free( bufptr ); - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return FALSE; - } - if (desc) - { - if (!s->size) desc->lpDescription = NULL; - else - { - desc->lpDescription = (WCHAR *)(desc + 1); - memcpy( desc->lpDescription, s->description, s->size ); - } - } - heap_free( bufptr ); - break; - } - case SERVICE_CONFIG_PRESHUTDOWN_INFO: - if (err != ERROR_SUCCESS) - { - SetLastError( err ); - return FALSE; - } - break; - - default: - break; - } - + /* this function is a no-op in Vista and above */ + TRACE("%p\n", lock); return TRUE; }
@@ -1871,158 +244,41 @@ EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st heap_free( servicesW ); return FALSE; } - MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) ); - } - - ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz, - needed, returned, resume_handle, groupW ); - if (!ret) goto done; - - p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA); - n = size - (p - (char *)services); - ret = FALSE; - for (i = 0; i < *returned; i++) - { - sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL ); - if (!sz) goto done; - services[i].lpServiceName = p; - p += sz; - n -= sz; - if (servicesW[i].lpDisplayName) - { - sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL ); - if (!sz) goto done; - services[i].lpDisplayName = p; - p += sz; - n -= sz; - } - else services[i].lpDisplayName = NULL; - services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess; - } - - ret = TRUE; - -done: - heap_free( servicesW ); - heap_free( groupW ); - return ret; -} - -/****************************************************************************** - * EnumServicesStatusExW [ADVAPI32.@] - */ -BOOL WINAPI -EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state, - LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned, - LPDWORD resume_handle, LPCWSTR group ) -{ - DWORD err, i, offset, buflen, count, total_size = 0; - ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer; - struct enum_service_status_process *entry; - const WCHAR *str; - BYTE *buf; - - TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer, - size, needed, returned, resume_handle, debugstr_w(group)); - - if (level != SC_ENUM_PROCESS_INFO) - { - SetLastError( ERROR_INVALID_LEVEL ); - return FALSE; - } - if (!hmngr) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - if (!needed || !returned) - { - SetLastError( ERROR_INVALID_ADDRESS ); - return FALSE; - } - - /* make sure we pass a valid pointer */ - buflen = max( size, sizeof(*services) ); - if (!(buf = heap_alloc( buflen ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return FALSE; - } - - __TRY - { - err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed, - &count, resume_handle, group ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code( GetExceptionCode() ); - } - __ENDTRY - - *returned = 0; - if (err != ERROR_SUCCESS) - { - /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */ - if (err == ERROR_MORE_DATA) *needed *= 2; - heap_free( buf ); - SetLastError( err ); - return FALSE; - } - - entry = (struct enum_service_status_process *)buf; - for (i = 0; i < count; i++) - { - total_size += sizeof(*services); - if (entry->service_name) - { - str = (const WCHAR *)(buf + entry->service_name); - total_size += (strlenW( str ) + 1) * sizeof(WCHAR); - } - if (entry->display_name) - { - str = (const WCHAR *)(buf + entry->display_name); - total_size += (strlenW( str ) + 1) * sizeof(WCHAR); - } - entry++; - } - - if (total_size > size) - { - heap_free( buf ); - *needed = total_size; - SetLastError( ERROR_MORE_DATA ); - return FALSE; + MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) ); }
- offset = count * sizeof(*services); - entry = (struct enum_service_status_process *)buf; - for (i = 0; i < count; i++) - { - DWORD str_size; - str = (const WCHAR *)(buf + entry->service_name); - str_size = (strlenW( str ) + 1) * sizeof(WCHAR); - services[i].lpServiceName = (WCHAR *)((char *)services + offset); - memcpy( services[i].lpServiceName, str, str_size ); - offset += str_size; + ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz, + needed, returned, resume_handle, groupW ); + if (!ret) goto done;
- if (!entry->display_name) services[i].lpDisplayName = NULL; - else + p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA); + n = size - (p - (char *)services); + ret = FALSE; + for (i = 0; i < *returned; i++) + { + sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL ); + if (!sz) goto done; + services[i].lpServiceName = p; + p += sz; + n -= sz; + if (servicesW[i].lpDisplayName) { - str = (const WCHAR *)(buf + entry->display_name); - str_size = (strlenW( str ) + 1) * sizeof(WCHAR); - services[i].lpDisplayName = (WCHAR *)((char *)services + offset); - memcpy( services[i].lpDisplayName, str, str_size ); - offset += str_size; + sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL ); + if (!sz) goto done; + services[i].lpDisplayName = p; + p += sz; + n -= sz; } - services[i].ServiceStatusProcess = entry->service_status_process; - entry++; + else services[i].lpDisplayName = NULL; + services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess; }
- heap_free( buf ); - *needed = 0; - *returned = count; - return TRUE; + ret = TRUE; + +done: + heap_free( servicesW ); + heap_free( groupW ); + return ret; }
/****************************************************************************** @@ -2071,59 +327,6 @@ cleanup: return ret; }
-/****************************************************************************** - * GetServiceKeyNameW [ADVAPI32.@] - */ -BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, - LPWSTR lpServiceName, LPDWORD lpcchBuffer ) -{ - DWORD err; - WCHAR buffer[2]; - DWORD size; - - TRACE("%p %s %p %p\n", hSCManager, - debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - - /* provide a buffer if the caller didn't */ - if (!lpServiceName || *lpcchBuffer < 2) - { - lpServiceName = buffer; - /* A size of 1 would be enough, but tests show that Windows returns 2, - * probably because of a WCHAR/bytes mismatch in their code. - */ - *lpcchBuffer = 2; - } - - /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer - * includes the nul-terminator on input. */ - size = *lpcchBuffer - 1; - - __TRY - { - err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName, - &size); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - /* The value of *lpcchBuffer excludes nul-terminator on output. */ - if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) - *lpcchBuffer = size; - - if (err) - SetLastError(err); - return err == ERROR_SUCCESS; -} - /****************************************************************************** * QueryServiceLockStatusA [ADVAPI32.@] */ @@ -2195,284 +398,6 @@ cleanup: return ret; }
-/****************************************************************************** - * GetServiceDisplayNameW [ADVAPI32.@] - */ -BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, - LPWSTR lpDisplayName, LPDWORD lpcchBuffer) -{ - DWORD err; - DWORD size; - WCHAR buffer[2]; - - TRACE("%p %s %p %p\n", hSCManager, - debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer); - - if (!hSCManager) - { - SetLastError( ERROR_INVALID_HANDLE ); - return FALSE; - } - - /* provide a buffer if the caller didn't */ - if (!lpDisplayName || *lpcchBuffer < 2) - { - lpDisplayName = buffer; - /* A size of 1 would be enough, but tests show that Windows returns 2, - * probably because of a WCHAR/bytes mismatch in their code. - */ - *lpcchBuffer = 2; - } - - /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer - * includes the nul-terminator on input. */ - size = *lpcchBuffer - 1; - - __TRY - { - err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName, - &size); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - /* The value of *lpcchBuffer excludes nul-terminator on output. */ - if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) - *lpcchBuffer = size; - - if (err) - SetLastError(err); - return err == ERROR_SUCCESS; -} - -/****************************************************************************** - * ChangeServiceConfigW [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType, - DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName, - LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies, - LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName) -{ - DWORD cb_pwd; - DWORD err; - - TRACE("%p %d %d %d %s %s %p %p %s %s %s\n", - hService, dwServiceType, dwStartType, dwErrorControl, - debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), - lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName), - debugstr_w(lpPassword), debugstr_w(lpDisplayName) ); - - cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0; - - __TRY - { - err = svcctl_ChangeServiceConfigW(hService, dwServiceType, - dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, - (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName, - (const BYTE *)lpPassword, cb_pwd, lpDisplayName); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - SetLastError(err); - - return err == ERROR_SUCCESS; -} - -/****************************************************************************** - * ChangeServiceConfigA [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType, - DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName, - LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies, - LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName) -{ - LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies; - LPWSTR wServiceStartName, wPassword, wDisplayName; - BOOL r; - - TRACE("%p %d %d %d %s %s %p %p %s %s %s\n", - hService, dwServiceType, dwStartType, dwErrorControl, - debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), - lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName), - debugstr_a(lpPassword), debugstr_a(lpDisplayName) ); - - wBinaryPathName = strdupAW( lpBinaryPathName ); - wLoadOrderGroup = strdupAW( lpLoadOrderGroup ); - wDependencies = SERV_dupmulti( lpDependencies ); - wServiceStartName = strdupAW( lpServiceStartName ); - wPassword = strdupAW( lpPassword ); - wDisplayName = strdupAW( lpDisplayName ); - - r = ChangeServiceConfigW( hService, dwServiceType, - dwStartType, dwErrorControl, wBinaryPathName, - wLoadOrderGroup, lpdwTagId, wDependencies, - wServiceStartName, wPassword, wDisplayName); - - heap_free( wBinaryPathName ); - heap_free( wLoadOrderGroup ); - heap_free( wDependencies ); - heap_free( wServiceStartName ); - heap_free( wPassword ); - heap_free( wDisplayName ); - - return r; -} - -/****************************************************************************** - * ChangeServiceConfig2A [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, - LPVOID lpInfo) -{ - BOOL r = FALSE; - - TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo); - - if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) - { - LPSERVICE_DESCRIPTIONA sd = lpInfo; - SERVICE_DESCRIPTIONW sdw; - - sdw.lpDescription = strdupAW( sd->lpDescription ); - - r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw ); - - heap_free( sdw.lpDescription ); - } - else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) - { - LPSERVICE_FAILURE_ACTIONSA fa = lpInfo; - SERVICE_FAILURE_ACTIONSW faw; - - faw.dwResetPeriod = fa->dwResetPeriod; - faw.lpRebootMsg = strdupAW( fa->lpRebootMsg ); - faw.lpCommand = strdupAW( fa->lpCommand ); - faw.cActions = fa->cActions; - faw.lpsaActions = fa->lpsaActions; - - r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw ); - - heap_free( faw.lpRebootMsg ); - heap_free( faw.lpCommand ); - } - else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) - { - r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo); - } - else - SetLastError( ERROR_INVALID_PARAMETER ); - - return r; -} - -/****************************************************************************** - * ChangeServiceConfig2W [ADVAPI32.@] - */ -BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, - LPVOID lpInfo) -{ - SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo; - DWORD err; - - __TRY - { - SC_RPC_CONFIG_INFOW info; - - info.dwInfoLevel = dwInfoLevel; - if (dwInfoLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) - { - SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = lpInfo; - WCHAR *p; - - for (p = privinfo->pmszRequiredPrivileges; *p; p += strlenW(p) + 1); - rpc_privinfo.cbRequiredPrivileges = - (p - privinfo->pmszRequiredPrivileges + 1) * sizeof(WCHAR); - rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges; - info.u.privinfo = &rpc_privinfo; - } - else - info.u.descr = lpInfo; - err = svcctl_ChangeServiceConfig2W( hService, info ); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - SetLastError(err); - - return err == ERROR_SUCCESS; -} - -static NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - SECURITY_DESCRIPTOR descriptor; - NTSTATUS status; - DWORD size; - ACL acl; - - FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation, - lpSecurityDescriptor, cbBufSize, pcbBytesNeeded); - - if (dwSecurityInformation != DACL_SECURITY_INFORMATION) - FIXME("information %d not supported\n", dwSecurityInformation); - - InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION); - - InitializeAcl(&acl, sizeof(ACL), ACL_REVISION); - SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE); - - size = cbBufSize; - status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size); - *pcbBytesNeeded = size; - return status; -} - -/****************************************************************************** - * QueryServiceObjectSecurity [ADVAPI32.@] - */ -BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor, - DWORD cbBufSize, LPDWORD pcbBytesNeeded) -{ - NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor, - cbBufSize, pcbBytesNeeded); - if (status != STATUS_SUCCESS) - { - SetLastError(RtlNtStatusToDosError(status)); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * SetServiceObjectSecurity [ADVAPI32.@] - * - * NOTES - * - SetSecurityInfo should be updated to call this function once it's implemented. - */ -BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService, - SECURITY_INFORMATION dwSecurityInformation, - PSECURITY_DESCRIPTOR lpSecurityDescriptor) -{ - FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor); - return TRUE; -} - /****************************************************************************** * SetServiceBits [ADVAPI32.@] */ @@ -2486,69 +411,6 @@ BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus, return TRUE; }
-/* thunk for calling the RegisterServiceCtrlHandler handler function */ -static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context ) -{ - LPHANDLER_FUNCTION func = context; - - func( control ); - return ERROR_SUCCESS; -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerA [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler ) -{ - return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler ); -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerW [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler ) -{ - return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler ); -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerExA [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context ) -{ - LPWSTR nameW; - SERVICE_STATUS_HANDLE ret; - - nameW = strdupAW(name); - ret = RegisterServiceCtrlHandlerExW( nameW, handler, context ); - heap_free( nameW ); - return ret; -} - -/****************************************************************************** - * RegisterServiceCtrlHandlerExW [ADVAPI32.@] - */ -SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName, - LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext ) -{ - service_data *service; - SC_HANDLE hService = 0; - - TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext); - - EnterCriticalSection( &service_cs ); - if ((service = find_service_by_name( lpServiceName ))) - { - service->handler = lpHandlerProc; - service->context = lpContext; - hService = service->handle; - } - LeaveCriticalSection( &service_cs ); - - if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST ); - return (SERVICE_STATUS_HANDLE)hService; -} - /****************************************************************************** * EnumDependentServicesA [ADVAPI32.@] */ @@ -2562,145 +424,3 @@ BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState, *lpServicesReturned = 0; return TRUE; } - -/****************************************************************************** - * EnumDependentServicesW [ADVAPI32.@] - */ -BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState, - LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize, - LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned ) -{ - FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState, - lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned); - - *lpServicesReturned = 0; - return TRUE; -} - -static DWORD WINAPI notify_thread(void *user) -{ - DWORD err; - notify_data *data = user; - SC_RPC_NOTIFY_PARAMS_LIST *list = NULL; - SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; - BOOL dummy; - - __TRY - { - /* GetNotifyResults blocks until there is an event */ - err = svcctl_GetNotifyResults(data->notify_handle, &list); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - EnterCriticalSection( &service_cs ); - - list_remove(&data->entry); - - LeaveCriticalSection( &service_cs ); - - if (err == ERROR_SUCCESS && list) - { - cparams = list->NotifyParamsArray[0].u.params; - - data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus; - memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus, - sizeof(SERVICE_STATUS_PROCESS)); - data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered; - data->notify_buffer->pszServiceNames = NULL; - - QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback, - data->calling_thread, (ULONG_PTR)data->notify_buffer); - - HeapFree(GetProcessHeap(), 0, list); - } - else - WARN("GetNotifyResults server call failed: %u\n", err); - - - __TRY - { - err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - WARN("CloseNotifyHandle server call failed: %u\n", err); - - CloseHandle(data->calling_thread); - HeapFree(GetProcessHeap(), 0, data); - - return 0; -} - -/****************************************************************************** - * NotifyServiceStatusChangeW [ADVAPI32.@] - */ -DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask, - SERVICE_NOTIFYW *pNotifyBuffer) -{ - DWORD err; - BOOL b_dummy = FALSE; - GUID g_dummy = {0}; - notify_data *data; - - TRACE("%p 0x%x %p\n", hService, dwNotifyMask, pNotifyBuffer); - - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); - if (!data) - return ERROR_NOT_ENOUGH_MEMORY; - - data->service = hService; - data->notify_buffer = pNotifyBuffer; - if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &data->calling_thread, 0, FALSE, - DUPLICATE_SAME_ACCESS)) - { - ERR("DuplicateHandle failed: %u\n", GetLastError()); - HeapFree(GetProcessHeap(), 0, data); - return ERROR_NOT_ENOUGH_MEMORY; - } - - data->params.dwInfoLevel = 2; - data->params.u.params = &data->cparams; - - data->cparams.dwNotifyMask = dwNotifyMask; - - EnterCriticalSection( &service_cs ); - - __TRY - { - err = svcctl_NotifyServiceStatusChange(hService, data->params, - &g_dummy, &g_dummy, &b_dummy, &data->notify_handle); - } - __EXCEPT(rpc_filter) - { - err = map_exception_code(GetExceptionCode()); - } - __ENDTRY - - if (err != ERROR_SUCCESS) - { - WARN("NotifyServiceStatusChange server call failed: %u\n", err); - LeaveCriticalSection( &service_cs ); - CloseHandle(data->calling_thread); - CloseHandle(data->ready_evt); - HeapFree(GetProcessHeap(), 0, data); - return err; - } - - CloseHandle(CreateThread(NULL, 0, ¬ify_thread, data, 0, NULL)); - - list_add_tail(¬ify_list, &data->entry); - - LeaveCriticalSection( &service_cs ); - - return ERROR_SUCCESS; -} diff --git a/dlls/sechost/Makefile.in b/dlls/sechost/Makefile.in index 9f573ccc2f9..eb98d04859c 100644 --- a/dlls/sechost/Makefile.in +++ b/dlls/sechost/Makefile.in @@ -1,8 +1,13 @@ MODULE = sechost.dll IMPORTLIB = sechost IMPORTS = kernelbase +DELAYIMPORTS = rpcrt4
EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + service.c \ trace.c + +IDL_SRCS = \ + svcctl.idl diff --git a/dlls/sechost/sechost.spec b/dlls/sechost/sechost.spec index f54de38c289..df6af1646df 100644 --- a/dlls/sechost/sechost.spec +++ b/dlls/sechost/sechost.spec @@ -19,13 +19,13 @@ @ stub BuildSecurityDescriptorForSharingAccessEx @ stub CapabilityCheck @ stub CapabilityCheckForSingleSessionSku -@ stdcall ChangeServiceConfig2A(long long ptr) advapi32.ChangeServiceConfig2A -@ stdcall ChangeServiceConfig2W(long long ptr) advapi32.ChangeServiceConfig2W -@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) advapi32.ChangeServiceConfigA -@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) advapi32.ChangeServiceConfigW -@ stdcall CloseServiceHandle(long) advapi32.CloseServiceHandle +@ stdcall ChangeServiceConfig2A(long long ptr) +@ stdcall ChangeServiceConfig2W(long long ptr) +@ stdcall ChangeServiceConfigA(long long long long wstr str ptr str str str str) +@ stdcall ChangeServiceConfigW(long long long long wstr wstr ptr wstr wstr wstr wstr) +@ stdcall CloseServiceHandle(long) @ stdcall CloseTrace(int64) -@ stdcall ControlService(long long ptr) advapi32.ControlService +@ stdcall ControlService(long long ptr) @ stub ControlServiceExA @ stub ControlServiceExW @ stdcall ControlTraceA(int64 str ptr long) @@ -38,9 +38,9 @@ @ stub ConvertStringSDToSDRootDomainW @ stdcall ConvertStringSecurityDescriptorToSecurityDescriptorW(wstr long ptr ptr) advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW @ stdcall ConvertStringSidToSidW(ptr ptr) advapi32.ConvertStringSidToSidW -@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) advapi32.CreateServiceA +@ stdcall CreateServiceA(long str str long long long long str str ptr str str str) @ stub CreateServiceEx -@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) advapi32.CreateServiceW +@ stdcall CreateServiceW(long wstr wstr long long long long wstr wstr ptr wstr wstr wstr) @ stub CredBackupCredentials @ stdcall CredDeleteA(str long long) advapi32.CredDeleteA @ stdcall CredDeleteW(wstr long long) advapi32.CredDeleteW @@ -84,10 +84,10 @@ @ stub CredpDecodeCredential @ stub CredpEncodeCredential @ stub CredpEncodeSecret -@ stdcall DeleteService(long) advapi32.DeleteService +@ stdcall DeleteService(long) @ stdcall EnableTraceEx2(int64 ptr long long int64 int64 long ptr) -@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) advapi32.EnumDependentServicesW -@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) advapi32.EnumServicesStatusExW +@ stdcall EnumDependentServicesW(long long ptr long ptr ptr) +@ stdcall EnumServicesStatusExW(long long long long ptr long ptr ptr ptr wstr) @ stub EnumerateIdentityProviders @ stub EnumerateTraceGuidsEx @ stub EtwQueryRealtimeConsumer @@ -99,8 +99,8 @@ @ stub GetIdentityProviderInfoByGUID @ stub GetIdentityProviderInfoByName @ stub GetServiceDirectory -@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) advapi32.GetServiceDisplayNameW -@ stdcall GetServiceKeyNameW(long wstr ptr ptr) advapi32.GetServiceKeyNameW +@ stdcall GetServiceDisplayNameW(ptr wstr ptr ptr) +@ stdcall GetServiceKeyNameW(long wstr ptr ptr) @ stub GetServiceRegistryStateKey @ stub I_QueryTagInformation @ stub I_RegisterSvchostNotificationCallback @@ -159,45 +159,45 @@ @ stdcall LsaStorePrivateData(ptr ptr ptr) advapi32.LsaStorePrivateData @ stub NotifyServiceStatusChange @ stub NotifyServiceStatusChangeA -@ stdcall NotifyServiceStatusChangeW(ptr long ptr) advapi32.NotifyServiceStatusChangeW -@ stdcall OpenSCManagerA(str str long) advapi32.OpenSCManagerA -@ stdcall OpenSCManagerW(wstr wstr long) advapi32.OpenSCManagerW -@ stdcall OpenServiceA(long str long) advapi32.OpenServiceA -@ stdcall OpenServiceW(long wstr long) advapi32.OpenServiceW +@ stdcall NotifyServiceStatusChangeW(ptr long ptr) +@ stdcall OpenSCManagerA(str str long) +@ stdcall OpenSCManagerW(wstr wstr long) +@ stdcall OpenServiceA(long str long) +@ stdcall OpenServiceW(long wstr long) @ stdcall -ret64 OpenTraceW(ptr) @ stdcall ProcessTrace(ptr long ptr ptr) @ stdcall QueryAllTracesA(ptr long ptr) @ stdcall QueryAllTracesW(ptr long ptr) @ stub QueryLocalUserServiceName -@ stdcall QueryServiceConfig2A(long long ptr long ptr) advapi32.QueryServiceConfig2A -@ stdcall QueryServiceConfig2W(long long ptr long ptr) advapi32.QueryServiceConfig2W -@ stdcall QueryServiceConfigA(long ptr long ptr) advapi32.QueryServiceConfigA -@ stdcall QueryServiceConfigW(long ptr long ptr) advapi32.QueryServiceConfigW +@ stdcall QueryServiceConfig2A(long long ptr long ptr) +@ stdcall QueryServiceConfig2W(long long ptr long ptr) +@ stdcall QueryServiceConfigA(long ptr long ptr) +@ stdcall QueryServiceConfigW(long ptr long ptr) @ stub QueryServiceDynamicInformation -@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) advapi32.QueryServiceObjectSecurity -@ stdcall QueryServiceStatus(long ptr) advapi32.QueryServiceStatus -@ stdcall QueryServiceStatusEx(long long ptr long ptr) advapi32.QueryServiceStatusEx +@ stdcall QueryServiceObjectSecurity(long long ptr long ptr) +@ stdcall QueryServiceStatus(long ptr) +@ stdcall QueryServiceStatusEx(long long ptr long ptr) @ stub QueryTraceProcessingHandle @ stub QueryTransientObjectSecurityDescriptor @ stub QueryUserServiceName @ stub QueryUserServiceNameForContext -@ stdcall RegisterServiceCtrlHandlerA(str ptr) advapi32.RegisterServiceCtrlHandlerA -@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) advapi32.RegisterServiceCtrlHandlerExA -@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) advapi32.RegisterServiceCtrlHandlerExW -@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) advapi32.RegisterServiceCtrlHandlerW +@ stdcall RegisterServiceCtrlHandlerA(str ptr) +@ stdcall RegisterServiceCtrlHandlerExA(str ptr ptr) +@ stdcall RegisterServiceCtrlHandlerExW(wstr ptr ptr) +@ stdcall RegisterServiceCtrlHandlerW(wstr ptr) @ stdcall RegisterTraceGuidsA(ptr ptr ptr long ptr str str ptr) advapi32.RegisterTraceGuidsA @ stub ReleaseIdentityProviderEnumContext @ stub RemoveTraceCallback @ stub RpcClientCapabilityCheck @ stub SetLocalRpcServerInterfaceSecurity @ stub SetLocalRpcServerProtseqSecurity -@ stdcall SetServiceObjectSecurity(long long ptr) advapi32.SetServiceObjectSecurity -@ stdcall SetServiceStatus(long ptr) advapi32.SetServiceStatus +@ stdcall SetServiceObjectSecurity(long long ptr) +@ stdcall SetServiceStatus(long ptr) @ stub SetTraceCallback -@ stdcall StartServiceA(long long ptr) advapi32.StartServiceA -@ stdcall StartServiceCtrlDispatcherA(ptr) advapi32.StartServiceCtrlDispatcherA -@ stdcall StartServiceCtrlDispatcherW(ptr) advapi32.StartServiceCtrlDispatcherW -@ stdcall StartServiceW(long long ptr) advapi32.StartServiceW +@ stdcall StartServiceA(long long ptr) +@ stdcall StartServiceCtrlDispatcherA(ptr) +@ stdcall StartServiceCtrlDispatcherW(ptr) +@ stdcall StartServiceW(long long ptr) @ stdcall StartTraceA(ptr str ptr) @ stdcall StartTraceW(ptr wstr ptr) @ stdcall StopTraceW(int64 wstr ptr) diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c new file mode 100644 index 00000000000..7a4211631e2 --- /dev/null +++ b/dlls/sechost/service.c @@ -0,0 +1,1969 @@ +/* + * Service control API + * + * Copyright 1995 Sven Verdoolaege + * Copyright 2005 Mike McCormack + * Copyright 2007 Rolf Kalbermatter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define NONAMELESSUNION +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "winternl.h" + +#include "wine/debug.h" +#include "wine/exception.h" +#include "wine/heap.h" +#include "wine/list.h" + +#include "svcctl.h" + +WINE_DEFAULT_DEBUG_CHANNEL(service); + +struct notify_data +{ + SC_HANDLE service; + SC_RPC_NOTIFY_PARAMS params; + SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams; + SC_NOTIFY_RPC_HANDLE notify_handle; + SERVICE_NOTIFYW *notify_buffer; + HANDLE calling_thread, ready_evt; + struct list entry; +}; + +static struct list notify_list = LIST_INIT(notify_list); + +static CRITICAL_SECTION service_cs; +static CRITICAL_SECTION_DEBUG service_cs_debug = +{ + 0, 0, &service_cs, + { &service_cs_debug.ProcessLocksList, + &service_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") } +}; +static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 }; + +struct service_data +{ + LPHANDLER_FUNCTION_EX handler; + void *context; + HANDLE thread; + SC_HANDLE handle; + SC_HANDLE full_access_handle; + unsigned int unicode : 1; + union + { + LPSERVICE_MAIN_FUNCTIONA a; + LPSERVICE_MAIN_FUNCTIONW w; + } proc; + WCHAR *args; + WCHAR name[1]; +}; + +struct dispatcher_data +{ + SC_HANDLE manager; + HANDLE pipe; +}; + +static struct service_data **services; +static unsigned int nb_services; +static HANDLE service_event; +static BOOL stop_service; + +extern HANDLE CDECL __wine_make_process_system(void); + +static WCHAR *heap_strdupAtoW( const char *src ) +{ + WCHAR *dst = NULL; + if (src) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 ); + if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len ); + } + return dst; +} + +static WCHAR *heap_strdup_multi_AtoW( const char *src ) +{ + WCHAR *dst = NULL; + const char *p = src; + DWORD len; + + if (!src) return NULL; + + while (*p) p += strlen(p) + 1; + for (p = src; *p; p += strlen(p) + 1); + p++; /* final null */ + len = MultiByteToWideChar( CP_ACP, 0, src, p - src, NULL, 0 ); + if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, p - src, dst, len ); + return dst; +} + +static inline DWORD multisz_size( const WCHAR *str ) +{ + const WCHAR *p = str; + + if (!str) return 0; + + while (*p) p += wcslen(p) + 1; + return (p - str + 1) * sizeof(WCHAR); +} + +void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len ) +{ + return heap_alloc(len); +} + +void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr ) +{ + heap_free(ptr); +} + +static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr ) +{ + return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode ); +} + +static DWORD map_exception_code( DWORD exception_code ) +{ + switch (exception_code) + { + case RPC_X_NULL_REF_POINTER: + return ERROR_INVALID_ADDRESS; + case RPC_X_ENUM_VALUE_OUT_OF_RANGE: + case RPC_X_BYTE_COUNT_TOO_SMALL: + return ERROR_INVALID_PARAMETER; + case RPC_S_INVALID_BINDING: + case RPC_X_SS_IN_NULL_CONTEXT: + return ERROR_INVALID_HANDLE; + default: + return exception_code; + } +} + +static handle_t rpc_wstr_bind( RPC_WSTR str ) +{ + WCHAR transport[] = SVCCTL_TRANSPORT; + WCHAR endpoint[] = SVCCTL_ENDPOINT; + RPC_WSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeW failed, error %d\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingW( binding_str, &rpc_handle ); + RpcStringFreeW( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %d\n", status); + return NULL; + } + + return rpc_handle; +} + +static handle_t rpc_cstr_bind(RPC_CSTR str) +{ + RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA; + RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA; + RPC_CSTR binding_str; + RPC_STATUS status; + handle_t rpc_handle; + + status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str ); + if (status != RPC_S_OK) + { + ERR("RpcStringBindingComposeA failed, error %d\n", status); + return NULL; + } + + status = RpcBindingFromStringBindingA( binding_str, &rpc_handle ); + RpcStringFreeA( &binding_str ); + + if (status != RPC_S_OK) + { + ERR("Couldn't connect to services.exe, error %d\n", status); + return NULL; + } + + return rpc_handle; +} + +DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name ) +{ + return rpc_cstr_bind( (RPC_CSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name ) +{ + return rpc_wstr_bind( (RPC_WSTR)name ); +} + +DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h ) +{ + RpcBindingFree( &h ); +} + +static BOOL set_error( DWORD err ) +{ + if (err) SetLastError( err ); + return !err; +} + +/****************************************************************************** + * OpenSCManagerA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access ) +{ + WCHAR *machineW, *databaseW; + SC_HANDLE ret; + + machineW = heap_strdupAtoW( machine ); + databaseW = heap_strdupAtoW( database ); + ret = OpenSCManagerW( machineW, databaseW, access ); + heap_free( databaseW ); + heap_free( machineW ); + return ret; +} + +/****************************************************************************** + * OpenSCManagerW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerW( const WCHAR *machine, const WCHAR *database, DWORD access ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + + TRACE( "%s %s %#x\n", debugstr_w(machine), debugstr_w(database), access ); + + __TRY + { + err = svcctl_OpenSCManagerW( machine, database, access, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return NULL; +} + +/****************************************************************************** + * OpenServiceA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access ) +{ + WCHAR *nameW; + SC_HANDLE ret; + + TRACE( "%p %s %#x\n", manager, debugstr_a(name), access ); + + nameW = heap_strdupAtoW( name ); + ret = OpenServiceW( manager, nameW, access ); + heap_free( nameW ); + return ret; +} + +/****************************************************************************** + * OpenServiceW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR *name, DWORD access ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + + TRACE( "%p %s %#x\n", manager, debugstr_w(name), access ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } + + __TRY + { + err = svcctl_OpenServiceW( manager, name, access, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return 0; +} + +/****************************************************************************** + * CreateServiceA (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char *name, const char *display_name, + DWORD access, DWORD service_type, DWORD start_type, + DWORD error_control, const char *path, const char *group, + DWORD *tag, const char *dependencies, const char *username, + const char *password ) +{ + WCHAR *nameW, *display_nameW, *pathW, *groupW, *dependenciesW, *usernameW, *passwordW; + SC_HANDLE handle; + + TRACE( "%p %s %s\n", manager, debugstr_a(name), debugstr_a(display_name) ); + + nameW = heap_strdupAtoW( name ); + display_nameW = heap_strdupAtoW( display_name ); + pathW = heap_strdupAtoW( path ); + groupW = heap_strdupAtoW( group ); + dependenciesW = heap_strdupAtoW( dependencies ); + usernameW = heap_strdupAtoW( username ); + passwordW = heap_strdupAtoW( password ); + + handle = CreateServiceW( manager, nameW, display_nameW, access, service_type, start_type, error_control, + pathW, groupW, tag, dependenciesW, usernameW, passwordW ); + + heap_free( nameW ); + heap_free( display_nameW ); + heap_free( pathW ); + heap_free( groupW ); + heap_free( dependenciesW ); + heap_free( usernameW ); + heap_free( passwordW ); + + return handle; +} + +/****************************************************************************** + * CreateServiceW (sechost.@) + */ +SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceW( SC_HANDLE manager, const WCHAR *name, const WCHAR *display_name, + DWORD access, DWORD service_type, DWORD start_type, + DWORD error_control, const WCHAR *path, const WCHAR *group, + DWORD *tag, const WCHAR *dependencies, const WCHAR *username, + const WCHAR *password ) +{ + SC_RPC_HANDLE handle = NULL; + DWORD err; + SIZE_T password_size = 0; + + TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return 0; + } + + if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR); + + __TRY + { + BOOL is_wow64; + + if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) + err = svcctl_CreateServiceWOW64W( manager, name, display_name, access, service_type, start_type, + error_control, path, group, tag, (const BYTE *)dependencies, + multisz_size( dependencies ), username, (const BYTE *)password, + password_size, &handle ); + else + err = svcctl_CreateServiceW( manager, name, display_name, access, service_type, start_type, + error_control, path, group, tag, (const BYTE *)dependencies, + multisz_size( dependencies ), username, (const BYTE *)password, + password_size, &handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!err) return handle; + SetLastError( err ); + return NULL; +} + +/****************************************************************************** + * DeleteService (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service ) +{ + DWORD err; + + TRACE( "%p\n", service ); + + __TRY + { + err = svcctl_DeleteService( service ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * CloseServiceHandle (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle ) +{ + DWORD err; + + TRACE( "%p\n", handle ); + + __TRY + { + err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ChangeServiceConfig2A (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info) +{ + BOOL r = FALSE; + + TRACE( "%p %d %p\n", service, level, info ); + + if (level == SERVICE_CONFIG_DESCRIPTION) + { + SERVICE_DESCRIPTIONA *sd = info; + SERVICE_DESCRIPTIONW sdw; + + sdw.lpDescription = heap_strdupAtoW( sd->lpDescription ); + + r = ChangeServiceConfig2W( service, level, &sdw ); + + heap_free( sdw.lpDescription ); + } + else if (level == SERVICE_CONFIG_FAILURE_ACTIONS) + { + SERVICE_FAILURE_ACTIONSA *fa = info; + SERVICE_FAILURE_ACTIONSW faw; + + faw.dwResetPeriod = fa->dwResetPeriod; + faw.lpRebootMsg = heap_strdupAtoW( fa->lpRebootMsg ); + faw.lpCommand = heap_strdupAtoW( fa->lpCommand ); + faw.cActions = fa->cActions; + faw.lpsaActions = fa->lpsaActions; + + r = ChangeServiceConfig2W( service, level, &faw ); + + heap_free( faw.lpRebootMsg ); + heap_free( faw.lpCommand ); + } + else if (level == SERVICE_CONFIG_PRESHUTDOWN_INFO) + { + r = ChangeServiceConfig2W( service, level, info ); + } + else + SetLastError( ERROR_INVALID_PARAMETER ); + + return r; +} + +/****************************************************************************** + * ChangeServiceConfig2W (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2W( SC_HANDLE service, DWORD level, void *info ) +{ + SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo; + DWORD err; + + __TRY + { + SC_RPC_CONFIG_INFOW rpc_info; + + rpc_info.dwInfoLevel = level; + if (level == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) + { + SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = info; + + rpc_privinfo.cbRequiredPrivileges = multisz_size( privinfo->pmszRequiredPrivileges ); + rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges; + rpc_info.u.privinfo = &rpc_privinfo; + } + else + rpc_info.u.descr = info; + err = svcctl_ChangeServiceConfig2W( service, rpc_info ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ChangeServiceConfigA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigA( SC_HANDLE service, DWORD service_type, DWORD start_type, + DWORD error_control, const char *path, const char *group, + DWORD *tag, const char *dependencies, const char *username, + const char *password, const char *display_name ) +{ + WCHAR *pathW, *groupW, *dependenciesW, *usernameW, *passwordW, *display_nameW; + BOOL r; + + TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type, + error_control, debugstr_a(path), debugstr_a(group), tag, dependencies, + debugstr_a(username), debugstr_a(password), debugstr_a(display_name) ); + + pathW = heap_strdupAtoW( path ); + groupW = heap_strdupAtoW( group ); + dependenciesW = heap_strdup_multi_AtoW( dependencies ); + usernameW = heap_strdupAtoW( username ); + passwordW = heap_strdupAtoW( password ); + display_nameW = heap_strdupAtoW( display_name ); + + r = ChangeServiceConfigW( service, service_type, start_type, error_control, pathW, + groupW, tag, dependenciesW, usernameW, passwordW, display_nameW ); + + heap_free( pathW ); + heap_free( groupW ); + heap_free( dependenciesW ); + heap_free( usernameW ); + heap_free( passwordW ); + heap_free( display_nameW ); + + return r; +} + +/****************************************************************************** + * ChangeServiceConfigW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigW( SC_HANDLE service, DWORD service_type, DWORD start_type, + DWORD error_control, const WCHAR *path, const WCHAR *group, + DWORD *tag, const WCHAR *dependencies, const WCHAR *username, + const WCHAR *password, const WCHAR *display_name ) +{ + DWORD password_size; + DWORD err; + + TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type, + error_control, debugstr_w(path), debugstr_w(group), tag, dependencies, + debugstr_w(username), debugstr_w(password), debugstr_w(display_name) ); + + password_size = password ? (wcslen(password) + 1) * sizeof(WCHAR) : 0; + + __TRY + { + err = svcctl_ChangeServiceConfigW( service, service_type, start_type, error_control, path, group, tag, + (const BYTE *)dependencies, multisz_size(dependencies), username, + (const BYTE *)password, password_size, display_name ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * QueryServiceConfigA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigA( SC_HANDLE service, QUERY_SERVICE_CONFIGA *config, + DWORD size, DWORD *ret_size ) +{ + DWORD n; + char *p, *buffer; + BOOL ret; + QUERY_SERVICE_CONFIGW *configW; + + TRACE( "%p %p %d %p\n", service, config, size, ret_size ); + + if (!(buffer = heap_alloc( 2 * size ))) return set_error( ERROR_NOT_ENOUGH_MEMORY ); + configW = (QUERY_SERVICE_CONFIGW *)buffer; + ret = QueryServiceConfigW( service, configW, 2 * size, ret_size ); + if (!ret) goto done; + + config->dwServiceType = configW->dwServiceType; + config->dwStartType = configW->dwStartType; + config->dwErrorControl = configW->dwErrorControl; + config->lpBinaryPathName = NULL; + config->lpLoadOrderGroup = NULL; + config->dwTagId = configW->dwTagId; + config->lpDependencies = NULL; + config->lpServiceStartName = NULL; + config->lpDisplayName = NULL; + + p = (char *)(config + 1); + n = size - sizeof(*config); + ret = FALSE; + +#define MAP_STR(str) \ + do { \ + if (configW->str) \ + { \ + DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \ + if (!sz) goto done; \ + config->str = p; \ + p += sz; \ + n -= sz; \ + } \ + } while (0) + + MAP_STR( lpBinaryPathName ); + MAP_STR( lpLoadOrderGroup ); + MAP_STR( lpDependencies ); + MAP_STR( lpServiceStartName ); + MAP_STR( lpDisplayName ); +#undef MAP_STR + + *ret_size = p - (char *)config; + ret = TRUE; + +done: + heap_free( buffer ); + return ret; +} + +static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr) +{ + DWORD cb; + + if (!*string_ptr) + { + cb = sizeof(WCHAR); + memset(*buf, 0, cb); + } + else + { + cb = (wcslen( *string_ptr ) + 1) * sizeof(WCHAR); + memcpy(*buf, *string_ptr, cb); + MIDL_user_free( *string_ptr ); + } + + *string_ptr = (WCHAR *)*buf; + *buf += cb; + + return cb; +} + +static DWORD size_string( const WCHAR *string ) +{ + return (string ? (wcslen( string ) + 1) * sizeof(WCHAR) : sizeof(WCHAR)); +} + +/****************************************************************************** + * QueryServiceConfigW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigW( SC_HANDLE service, QUERY_SERVICE_CONFIGW *ret_config, + DWORD size, DWORD *ret_size ) +{ + QUERY_SERVICE_CONFIGW config; + DWORD total; + DWORD err; + BYTE *bufpos; + + TRACE( "%p %p %d %p\n", service, ret_config, size, ret_size ); + + memset(&config, 0, sizeof(config)); + + __TRY + { + err = svcctl_QueryServiceConfigW( service, &config, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (err) return set_error( err ); + + /* calculate the size required first */ + total = sizeof(QUERY_SERVICE_CONFIGW); + total += size_string( config.lpBinaryPathName ); + total += size_string( config.lpLoadOrderGroup ); + total += size_string( config.lpDependencies ); + total += size_string( config.lpServiceStartName ); + total += size_string( config.lpDisplayName ); + + *ret_size = total; + + /* if there's not enough memory, return an error */ + if (size < total) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + MIDL_user_free( config.lpBinaryPathName ); + MIDL_user_free( config.lpLoadOrderGroup ); + MIDL_user_free( config.lpDependencies ); + MIDL_user_free( config.lpServiceStartName ); + MIDL_user_free( config.lpDisplayName ); + return FALSE; + } + + *ret_config = config; + bufpos = ((BYTE *)ret_config) + sizeof(QUERY_SERVICE_CONFIGW); + move_string_to_buffer( &bufpos, &ret_config->lpBinaryPathName ); + move_string_to_buffer( &bufpos, &ret_config->lpLoadOrderGroup ); + move_string_to_buffer( &bufpos, &ret_config->lpDependencies ); + move_string_to_buffer( &bufpos, &ret_config->lpServiceStartName ); + move_string_to_buffer( &bufpos, &ret_config->lpDisplayName ); + + TRACE( "Image path = %s\n", debugstr_w( ret_config->lpBinaryPathName ) ); + TRACE( "Group = %s\n", debugstr_w( ret_config->lpLoadOrderGroup ) ); + TRACE( "Dependencies = %s\n", debugstr_w( ret_config->lpDependencies ) ); + TRACE( "Service account name = %s\n", debugstr_w( ret_config->lpServiceStartName ) ); + TRACE( "Display name = %s\n", debugstr_w( ret_config->lpDisplayName ) ); + + return TRUE; +} + +/****************************************************************************** + * QueryServiceConfig2A (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2A( SC_HANDLE service, DWORD level, BYTE *buffer, + DWORD size, DWORD *ret_size ) +{ + BYTE *bufferW = NULL; + + TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size ); + + if (buffer && size) + bufferW = heap_alloc( size ); + + if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size )) + { + heap_free( bufferW ); + return FALSE; + } + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + if (buffer && bufferW) { + SERVICE_DESCRIPTIONA *configA = (SERVICE_DESCRIPTIONA *)buffer; + SERVICE_DESCRIPTIONW *configW = (SERVICE_DESCRIPTIONW *)bufferW; + if (configW->lpDescription && size > sizeof(SERVICE_DESCRIPTIONA)) + { + configA->lpDescription = (char *)(configA + 1); + WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, configA->lpDescription, + size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL ); + } + else configA->lpDescription = NULL; + } + break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + if (buffer && bufferW && *ret_size <= size) + memcpy(buffer, bufferW, *ret_size); + break; + default: + FIXME("conversion W->A not implemented for level %d\n", level); + heap_free( bufferW ); + return FALSE; + } + + heap_free( bufferW ); + return TRUE; +} + +/****************************************************************************** + * QueryServiceConfig2W (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer, + DWORD size, DWORD *ret_size ) +{ + BYTE *bufptr; + DWORD err; + + TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size ); + + if (!buffer && size) + { + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + if (!(bufptr = heap_alloc( size ))) + { + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); + return FALSE; + } + break; + + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + bufptr = buffer; + break; + + default: + FIXME("Level %d not implemented\n", level); + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + + if (!ret_size) + { + if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr ); + SetLastError(ERROR_INVALID_ADDRESS); + return FALSE; + } + + __TRY + { + err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + { + SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer; + struct service_description *s = (struct service_description *)bufptr; + + if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER) + { + heap_free( bufptr ); + SetLastError( err ); + return FALSE; + } + + /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */ + if (*ret_size == sizeof(*s)) + *ret_size = sizeof(*desc); + else + *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc); + + if (size < *ret_size) + { + heap_free( bufptr ); + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return FALSE; + } + if (desc) + { + if (!s->size) desc->lpDescription = NULL; + else + { + desc->lpDescription = (WCHAR *)(desc + 1); + memcpy( desc->lpDescription, s->description, s->size ); + } + } + heap_free( bufptr ); + break; + } + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + return set_error( err ); + + default: + break; + } + + return TRUE; +} + +/****************************************************************************** + * GetServiceDisplayNameW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service, + WCHAR *display_name, DWORD *len ) +{ + DWORD err; + DWORD size; + WCHAR buffer[2]; + + TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + + /* provide a buffer if the caller didn't */ + if (!display_name || *len < sizeof(WCHAR)) + { + display_name = buffer; + /* A size of 1 would be enough, but tests show that Windows returns 2, + * probably because of a WCHAR/bytes mismatch in their code. */ + *len = 2; + } + + /* RPC call takes size excluding nul-terminator, whereas *len + * includes the nul-terminator on input. */ + size = *len - 1; + + __TRY + { + err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + /* The value of *len excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *len = size; + return set_error( err ); +} + +/****************************************************************************** + * GetServiceKeyNameW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH GetServiceKeyNameW( SC_HANDLE manager, const WCHAR *display_name, + WCHAR *key_name, DWORD *len ) +{ + DWORD err; + WCHAR buffer[2]; + DWORD size; + + TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len ); + + if (!manager) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + + /* provide a buffer if the caller didn't */ + if (!key_name || *len < 2) + { + key_name = buffer; + /* A size of 1 would be enough, but tests show that Windows returns 2, + * probably because of a WCHAR/bytes mismatch in their code. + */ + *len = 2; + } + + /* RPC call takes size excluding nul-terminator, whereas *len + * includes the nul-terminator on input. */ + size = *len - 1; + + __TRY + { + err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + /* The value of *lpcchBuffer excludes nul-terminator on output. */ + if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER) + *len = size; + return set_error( err ); +} + +/****************************************************************************** + * StartServiceA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceA( SC_HANDLE service, DWORD argc, const char **argv ) +{ + WCHAR **argvW = NULL; + DWORD i; + BOOL r; + + if (argc) + argvW = heap_alloc( argc * sizeof(WCHAR) ); + + for (i = 0; i < argc; i++) + argvW[i] = heap_strdupAtoW( argv[i] ); + + r = StartServiceW( service, argc, (const WCHAR **)argvW ); + + for (i = 0; i < argc; i++) + heap_free( argvW[i] ); + heap_free( argv ); + return r; +} + + +/****************************************************************************** + * StartServiceW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv ) +{ + DWORD err; + + TRACE( "%p %u %p\n", service, argc, argv ); + + __TRY + { + err = svcctl_StartServiceW( service, argc, argv ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * ControlService (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status ) +{ + DWORD err; + + TRACE( "%p %d %p\n", service, control, status ); + + __TRY + { + err = svcctl_ControlService( service, control, status ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * QueryServiceStatus (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatus( SC_HANDLE service, SERVICE_STATUS *status ) +{ + SERVICE_STATUS_PROCESS process_status; + BOOL ret; + DWORD size; + + TRACE( "%p %p\n", service, status ); + + if (!service) return set_error( ERROR_INVALID_HANDLE ); + if (!status) return set_error( ERROR_INVALID_ADDRESS ); + + ret = QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&process_status, + sizeof(SERVICE_STATUS_PROCESS), &size ); + if (ret) memcpy(status, &process_status, sizeof(SERVICE_STATUS) ); + return ret; +} + +/****************************************************************************** + * QueryServiceStatusEx (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS_TYPE level, + BYTE *buffer, DWORD size, DWORD *ret_size ) +{ + DWORD err; + + TRACE( "%p %d %p %d %p\n", service, level, buffer, size, ret_size ); + + if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); + + if (size < sizeof(SERVICE_STATUS_PROCESS)) + { + *ret_size = sizeof(SERVICE_STATUS_PROCESS); + return set_error( ERROR_INSUFFICIENT_BUFFER ); + } + + __TRY + { + err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + return set_error( err ); +} + +/****************************************************************************** + * EnumServicesStatusExW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH EnumServicesStatusExW( SC_HANDLE manager, SC_ENUM_TYPE level, DWORD type, DWORD state, + BYTE *buffer, DWORD size, DWORD *needed, DWORD *returned, + DWORD *resume_handle, const WCHAR *group ) +{ + DWORD err, i, offset, buflen, count, total_size = 0; + ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer; + struct enum_service_status_process *entry; + const WCHAR *str; + BYTE *buf; + + TRACE( "%p %u 0x%x 0x%x %p %u %p %p %p %s\n", manager, level, type, state, buffer, + size, needed, returned, resume_handle, debugstr_w(group) ); + + if (level != SC_ENUM_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); + if (!manager) return set_error( ERROR_INVALID_HANDLE ); + if (!needed || !returned) return set_error( ERROR_INVALID_ADDRESS ); + + /* make sure we pass a valid pointer */ + buflen = max( size, sizeof(*services) ); + if (!(buf = heap_alloc( buflen ))) return set_error( ERROR_NOT_ENOUGH_MEMORY ); + + __TRY + { + err = svcctl_EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed, + &count, resume_handle, group ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + *returned = 0; + if (err != ERROR_SUCCESS) + { + /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */ + if (err == ERROR_MORE_DATA) *needed *= 2; + heap_free( buf ); + SetLastError( err ); + return FALSE; + } + + entry = (struct enum_service_status_process *)buf; + for (i = 0; i < count; i++) + { + total_size += sizeof(*services); + if (entry->service_name) + { + str = (const WCHAR *)(buf + entry->service_name); + total_size += (wcslen( str ) + 1) * sizeof(WCHAR); + } + if (entry->display_name) + { + str = (const WCHAR *)(buf + entry->display_name); + total_size += (wcslen( str ) + 1) * sizeof(WCHAR); + } + entry++; + } + + if (total_size > size) + { + heap_free( buf ); + *needed = total_size; + SetLastError( ERROR_MORE_DATA ); + return FALSE; + } + + offset = count * sizeof(*services); + entry = (struct enum_service_status_process *)buf; + for (i = 0; i < count; i++) + { + DWORD str_size; + str = (const WCHAR *)(buf + entry->service_name); + str_size = (wcslen( str ) + 1) * sizeof(WCHAR); + services[i].lpServiceName = (WCHAR *)((char *)services + offset); + memcpy( services[i].lpServiceName, str, str_size ); + offset += str_size; + + if (!entry->display_name) services[i].lpDisplayName = NULL; + else + { + str = (const WCHAR *)(buf + entry->display_name); + str_size = (wcslen( str ) + 1) * sizeof(WCHAR); + services[i].lpDisplayName = (WCHAR *)((char *)services + offset); + memcpy( services[i].lpDisplayName, str, str_size ); + offset += str_size; + } + services[i].ServiceStatusProcess = entry->service_status_process; + entry++; + } + + heap_free( buf ); + *needed = 0; + *returned = count; + return TRUE; +} + +/****************************************************************************** + * EnumDependentServicesW (sechost.@) + */ +BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState, + LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize, + LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned ) +{ + FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState, + lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned); + + *lpServicesReturned = 0; + return TRUE; +} + +/****************************************************************************** + * QueryServiceObjectSecurity (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceObjectSecurity( SC_HANDLE service, SECURITY_INFORMATION type, + PSECURITY_DESCRIPTOR ret_descriptor, DWORD size, DWORD *ret_size ) +{ + SECURITY_DESCRIPTOR descriptor; + NTSTATUS status; + ACL acl; + + FIXME( "%p %d %p %u %p - semi-stub\n", service, type, ret_descriptor, size, ret_size ); + + if (type != DACL_SECURITY_INFORMATION) + FIXME("information %d not supported\n", type); + + InitializeSecurityDescriptor( &descriptor, SECURITY_DESCRIPTOR_REVISION ); + + InitializeAcl( &acl, sizeof(ACL), ACL_REVISION ); + SetSecurityDescriptorDacl( &descriptor, TRUE, &acl, TRUE ); + + status = RtlMakeSelfRelativeSD( &descriptor, ret_descriptor, &size ); + *ret_size = size; + + return set_error( RtlNtStatusToDosError( status ) ); +} + +/****************************************************************************** + * SetServiceObjectSecurity (sechost.@) + */ +BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService, + SECURITY_INFORMATION dwSecurityInformation, + PSECURITY_DESCRIPTOR lpSecurityDescriptor) +{ + FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor); + return TRUE; +} + +static DWORD WINAPI notify_thread(void *user) +{ + DWORD err; + struct notify_data *data = user; + SC_RPC_NOTIFY_PARAMS_LIST *list = NULL; + SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; + BOOL dummy; + + __TRY + { + /* GetNotifyResults blocks until there is an event */ + err = svcctl_GetNotifyResults(data->notify_handle, &list); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code(GetExceptionCode()); + } + __ENDTRY + + EnterCriticalSection( &service_cs ); + + list_remove(&data->entry); + + LeaveCriticalSection( &service_cs ); + + if (err == ERROR_SUCCESS && list) + { + cparams = list->NotifyParamsArray[0].u.params; + + data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus; + memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus, + sizeof(SERVICE_STATUS_PROCESS)); + data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered; + data->notify_buffer->pszServiceNames = NULL; + + QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback, + data->calling_thread, (ULONG_PTR)data->notify_buffer); + + HeapFree(GetProcessHeap(), 0, list); + } + else + WARN("GetNotifyResults server call failed: %u\n", err); + + + __TRY + { + err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code(GetExceptionCode()); + } + __ENDTRY + + if (err != ERROR_SUCCESS) + WARN("CloseNotifyHandle server call failed: %u\n", err); + + CloseHandle(data->calling_thread); + HeapFree(GetProcessHeap(), 0, data); + + return 0; +} + +/****************************************************************************** + * NotifyServiceStatusChangeW (sechost.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask, + SERVICE_NOTIFYW *notify_buffer ) +{ + DWORD err; + BOOL b_dummy = FALSE; + GUID g_dummy = {0}; + struct notify_data *data; + + TRACE( "%p 0x%x %p\n", service, mask, notify_buffer ); + + if (!(data = heap_alloc_zero( sizeof(*data) ))) + return ERROR_NOT_ENOUGH_MEMORY; + + data->service = service; + data->notify_buffer = notify_buffer; + if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &data->calling_thread, 0, FALSE, DUPLICATE_SAME_ACCESS )) + { + ERR("DuplicateHandle failed: %u\n", GetLastError()); + heap_free( data ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + data->params.dwInfoLevel = 2; + data->params.u.params = &data->cparams; + + data->cparams.dwNotifyMask = mask; + + EnterCriticalSection( &service_cs ); + + __TRY + { + err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy, + &g_dummy, &b_dummy, &data->notify_handle ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (err != ERROR_SUCCESS) + { + WARN("NotifyServiceStatusChange server call failed: %u\n", err); + LeaveCriticalSection( &service_cs ); + CloseHandle( data->calling_thread ); + CloseHandle( data->ready_evt ); + heap_free( data ); + return err; + } + + CloseHandle( CreateThread( NULL, 0, ¬ify_thread, data, 0, NULL ) ); + + list_add_tail( ¬ify_list, &data->entry ); + + LeaveCriticalSection( &service_cs ); + + return ERROR_SUCCESS; +} + +/* thunk for calling the RegisterServiceCtrlHandler handler function */ +static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context ) +{ + LPHANDLER_FUNCTION func = context; + + func( control ); + return ERROR_SUCCESS; +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerA (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA( + const char *name, LPHANDLER_FUNCTION handler ) +{ + return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler ); +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerW (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW( + const WCHAR *name, LPHANDLER_FUNCTION handler ) +{ + return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler ); +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerExA (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA( + const char *name, LPHANDLER_FUNCTION_EX handler, void *context ) +{ + WCHAR *nameW; + SERVICE_STATUS_HANDLE ret; + + nameW = heap_strdupAtoW( name ); + ret = RegisterServiceCtrlHandlerExW( nameW, handler, context ); + heap_free( nameW ); + return ret; +} + +static struct service_data *find_service_by_name( const WCHAR *name ) +{ + unsigned int i; + + if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */ + return services[0]; + for (i = 0; i < nb_services; i++) + if (!wcsicmp( name, services[i]->name )) return services[i]; + return NULL; +} + +/****************************************************************************** + * RegisterServiceCtrlHandlerExW (sechost.@) + */ +SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW( + const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context ) +{ + struct service_data *service; + SC_HANDLE handle = 0; + + TRACE( "%s %p %p\n", debugstr_w(name), handler, context ); + + EnterCriticalSection( &service_cs ); + if ((service = find_service_by_name( name ))) + { + service->handler = handler; + service->context = context; + handle = service->handle; + } + LeaveCriticalSection( &service_cs ); + + if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST ); + return (SERVICE_STATUS_HANDLE)handle; +} + +/****************************************************************************** + * SetServiceStatus (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status ) +{ + DWORD err; + + TRACE( "%p %#x %#x %#x %#x %#x %#x %#x\n", service, status->dwServiceType, + status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode, + status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint ); + + __TRY + { + err = svcctl_SetServiceStatus( service, status ); + } + __EXCEPT(rpc_filter) + { + err = map_exception_code( GetExceptionCode() ); + } + __ENDTRY + + if (!set_error( err )) + return FALSE; + + if (status->dwCurrentState == SERVICE_STOPPED) + { + unsigned int i, count = 0; + EnterCriticalSection( &service_cs ); + for (i = 0; i < nb_services; i++) + { + if (services[i]->handle == (SC_HANDLE)service) continue; + if (services[i]->thread) count++; + } + if (!count) + { + stop_service = TRUE; + SetEvent( service_event ); /* notify the main loop */ + } + LeaveCriticalSection( &service_cs ); + } + + return TRUE; +} + +static WCHAR *service_get_pipe_name(void) +{ + static const WCHAR format[] = L"\\.\pipe\net\NtControlPipe%u"; + WCHAR *name; + DWORD len; + HKEY service_current_key; + DWORD service_current; + LONG ret; + DWORD type; + + ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, + L"SYSTEM\CurrentControlSet\Control\ServiceCurrent", + 0, KEY_QUERY_VALUE, &service_current_key ); + if (ret != ERROR_SUCCESS) + return NULL; + + len = sizeof(service_current); + ret = RegQueryValueExW( service_current_key, NULL, NULL, &type, + (BYTE *)&service_current, &len ); + RegCloseKey(service_current_key); + if (ret != ERROR_SUCCESS || type != REG_DWORD) + return NULL; + + len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */; + name = heap_alloc(len * sizeof(WCHAR)); + if (!name) + return NULL; + + swprintf( name, len, format, service_current ); + return name; +} + +static HANDLE service_open_pipe(void) +{ + WCHAR *pipe_name = service_get_pipe_name(); + HANDLE handle = INVALID_HANDLE_VALUE; + + do + { + handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_ALWAYS, 0, NULL ); + if (handle != INVALID_HANDLE_VALUE) + break; + if (GetLastError() != ERROR_PIPE_BUSY) + break; + } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT )); + heap_free(pipe_name); + + return handle; +} + +static DWORD WINAPI service_thread( void *arg ) +{ + struct service_data *info = arg; + WCHAR *str = info->args; + DWORD argc = 0, len = 0; + + TRACE("%p\n", arg); + + while (str[len]) + { + len += wcslen( &str[len] ) + 1; + argc++; + } + len++; + + if (info->unicode) + { + WCHAR **argv, *p; + + argv = heap_alloc( (argc+1)*sizeof(*argv) ); + for (argc = 0, p = str; *p; p += wcslen( p ) + 1) + argv[argc++] = p; + argv[argc] = NULL; + + info->proc.w( argc, argv ); + heap_free( argv ); + } + else + { + char *strA, **argv, *p; + DWORD lenA; + + lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL ); + strA = heap_alloc(lenA); + WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL); + + argv = heap_alloc( (argc+1)*sizeof(*argv) ); + for (argc = 0, p = strA; *p; p += strlen( p ) + 1) + argv[argc++] = p; + argv[argc] = NULL; + + info->proc.a( argc, argv ); + heap_free( argv ); + heap_free( strA ); + } + return 0; +} + +static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size ) +{ + DWORD count = data_size / sizeof(WCHAR); + + if (service->thread) + { + WARN("service is not stopped\n"); + return ERROR_SERVICE_ALREADY_RUNNING; + } + + heap_free( service->args ); + 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 */ + return 0; +} + +static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size ) +{ + DWORD ret = ERROR_INVALID_SERVICE_CONTROL; + + TRACE( "%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size ); + + 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; +} + +static DWORD WINAPI service_control_dispatcher( void *arg ) +{ + struct dispatcher_data *disp = arg; + + /* dispatcher loop */ + while (1) + { + struct service_data *service; + service_start_info info; + BYTE *data = NULL; + WCHAR *name; + BOOL r; + DWORD data_size = 0, count, result; + + r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL ); + if (!r) + { + if (GetLastError() != ERROR_BROKEN_PIPE) + ERR( "pipe read failed error %u\n", GetLastError() ); + break; + } + if (count != FIELD_OFFSET(service_start_info,data)) + { + ERR( "partial pipe read %u\n", count ); + break; + } + if (count < info.total_size) + { + data_size = info.total_size - FIELD_OFFSET(service_start_info,data); + data = heap_alloc( data_size ); + r = ReadFile( disp->pipe, data, data_size, &count, NULL ); + if (!r) + { + if (GetLastError() != ERROR_BROKEN_PIPE) + ERR( "pipe read failed error %u\n", GetLastError() ); + heap_free( data ); + break; + } + if (count != data_size) + { + ERR( "partial pipe read %u/%u\n", count, data_size ); + heap_free( data ); + break; + } + } + + EnterCriticalSection( &service_cs ); + + /* validate service name */ + name = (WCHAR *)data; + if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1]) + { + ERR( "got request without valid service name\n" ); + result = ERROR_INVALID_PARAMETER; + goto done; + } + + if (info.magic != SERVICE_PROTOCOL_MAGIC) + { + ERR( "received invalid request for service %s\n", debugstr_w(name) ); + result = ERROR_INVALID_PARAMETER; + goto done; + } + + /* find the service */ + if (!(service = find_service_by_name( name ))) + { + FIXME( "got request for unknown service %s\n", debugstr_w(name) ); + result = ERROR_INVALID_PARAMETER; + 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 ); + heap_free( data ); + } + + CloseHandle( disp->pipe ); + CloseServiceHandle( disp->manager ); + heap_free( disp ); + return 1; +} + +/* wait for services which accept this type of message to become STOPPED */ +static void handle_shutdown_msg(DWORD msg, DWORD accept) +{ + SERVICE_STATUS st; + SERVICE_PRESHUTDOWN_INFO spi; + DWORD i, n = 0, sz, timeout = 2000; + ULONGLONG stop_time; + BOOL res, done = TRUE; + SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services ); + + EnterCriticalSection( &service_cs ); + for (i = 0; i < nb_services; i++) + { + res = QueryServiceStatus( services[i]->full_access_handle, &st ); + if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept)) + continue; + + done = FALSE; + + if (accept == SERVICE_ACCEPT_PRESHUTDOWN) + { + res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO, + (BYTE *)&spi, sizeof(spi), &sz ); + if (res) + { + FIXME( "service should be able to delay shutdown\n" ); + timeout = max( spi.dwPreshutdownTimeout, timeout ); + } + } + + service_handle_control( services[i], msg, NULL, 0 ); + wait_handles[n++] = services[i]->full_access_handle; + } + LeaveCriticalSection( &service_cs ); + + /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */ + timeout = min( timeout, 3000 ); + stop_time = GetTickCount64() + timeout; + + while (!done && GetTickCount64() < stop_time) + { + done = TRUE; + for (i = 0; i < n; i++) + { + res = QueryServiceStatus( wait_handles[i], &st ); + if (!res || st.dwCurrentState == SERVICE_STOPPED) + continue; + + done = FALSE; + Sleep( 100 ); + break; + } + } + + HeapFree( GetProcessHeap(), 0, wait_handles ); +} + +static BOOL service_run_main_thread(void) +{ + DWORD i, n, ret; + HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; + UINT wait_services[MAXIMUM_WAIT_OBJECTS]; + struct dispatcher_data *disp = heap_alloc( sizeof(*disp) ); + + disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); + if (!disp->manager) + { + ERR("failed to open service manager error %u\n", GetLastError()); + heap_free( disp ); + return FALSE; + } + + disp->pipe = service_open_pipe(); + if (disp->pipe == INVALID_HANDLE_VALUE) + { + WARN("failed to create control pipe error %u\n", GetLastError()); + CloseServiceHandle( disp->manager ); + heap_free( disp ); + SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ); + return FALSE; + } + + service_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + stop_service = FALSE; + + /* FIXME: service_control_dispatcher should be merged into the main thread */ + wait_handles[0] = __wine_make_process_system(); + wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL ); + wait_handles[2] = service_event; + + TRACE("Starting %d services running as process %d\n", + nb_services, GetCurrentProcessId()); + + /* wait for all the threads to pack up and exit */ + while (!stop_service) + { + EnterCriticalSection( &service_cs ); + for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++) + { + if (!services[i]->thread) continue; + wait_services[n] = i; + wait_handles[n++] = services[i]->thread; + } + LeaveCriticalSection( &service_cs ); + + ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE ); + if (!ret) /* system process event */ + { + handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN); + handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN); + ExitProcess(0); + } + else if (ret == 1) + { + TRACE( "control dispatcher exited, shutting down\n" ); + /* FIXME: we should maybe send a shutdown control to running services */ + ExitProcess(0); + } + else if (ret == 2) + { + continue; /* rebuild the list */ + } + else if (ret < n) + { + i = wait_services[ret]; + EnterCriticalSection( &service_cs ); + CloseHandle( services[i]->thread ); + services[i]->thread = NULL; + LeaveCriticalSection( &service_cs ); + } + else return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * StartServiceCtrlDispatcherA (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent ) +{ + struct service_data *info; + unsigned int i; + + TRACE("%p\n", servent); + + if (nb_services) + { + SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); + return FALSE; + } + while (servent[nb_services].lpServiceName) nb_services++; + if (!nb_services) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + services = heap_alloc( nb_services * sizeof(*services) ); + + for (i = 0; i < nb_services; i++) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 ); + DWORD sz = FIELD_OFFSET( struct service_data, name[len] ); + info = heap_alloc_zero( sz ); + MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len ); + info->proc.a = servent[i].lpServiceProc; + info->unicode = FALSE; + services[i] = info; + } + + return service_run_main_thread(); +} + +/****************************************************************************** + * StartServiceCtrlDispatcherW (sechost.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent ) +{ + struct service_data *info; + unsigned int i; + + TRACE("%p\n", servent); + + if (nb_services) + { + SetLastError( ERROR_SERVICE_ALREADY_RUNNING ); + return FALSE; + } + while (servent[nb_services].lpServiceName) nb_services++; + if (!nb_services) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + services = heap_alloc( nb_services * sizeof(*services) ); + + for (i = 0; i < nb_services; i++) + { + DWORD len = wcslen( servent[i].lpServiceName ) + 1; + DWORD sz = FIELD_OFFSET( struct service_data, name[len] ); + info = heap_alloc_zero( sz ); + wcscpy( info->name, servent[i].lpServiceName ); + info->proc.w = servent[i].lpServiceProc; + info->unicode = TRUE; + services[i] = info; + } + + return service_run_main_thread(); +} diff --git a/dlls/advapi32/svcctl.idl b/dlls/sechost/svcctl.idl similarity index 100% rename from dlls/advapi32/svcctl.idl rename to dlls/sechost/svcctl.idl