http://bugs.winehq.org/show_bug.cgi?id=11420
Summary: service control manager API problem: name of named objects might differ (client vs. service process) Product: Wine Version: 0.9.54. Platform: PC OS/Version: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: advapi32 AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net
Created an attachment (id=10552) --> (http://bugs.winehq.org/attachment.cgi?id=10552) patch which fixes client vs. service SCM API when using named objects
Hello,
there seems to be a misconception in usage of names for named objects in service control manager API. Some people might have experienced such situation: wine hangs for several seconds on startup (when starting services). I usually disabled autostart type services (except for builtin ones) and the problems went away.
Lately while fixing Microsoft Visual Studio .NET installers (2002/2003/2005) this problem became more and more annoying because the installers and VS.NET depend on some services, namely "debug manager" (service has to be running).
Consider the following snippet with "service_get_event_handle" trace message added by me to highlight the problem:
0x9: client (net.exe) 0x11: service process (mdm.exe) 0x12: dispatcher thread
--- snip trace --- .. 0009:trace:advapi:OpenSCManagerW ((null),(null),0x000f003f) 0009:trace:advapi:sc_handle_alloc sc_handle type=0 -> 0x121450 0009:trace:advapi:OpenSCManagerW returning 0x121450 (access : 0x000f003f) 0009:trace:advapi:OpenServiceA 0x121450 "mdm" 983103 0009:trace:advapi:OpenServiceW 0x121450 L"mdm" 983103 0009:trace:advapi:sc_handle_alloc sc_handle type=1 -> 0x121488 0009:trace:advapi:OpenServiceW returning 0x121488 0009:trace:advapi:GetServiceDisplayNameA 0x121450 "mdm" 0x34ee48 0x34fe48 0009:trace:advapi:GetServiceDisplayNameW 0x121450 L"mdm" 0x1214b8 0x34ee08 The Machine Debug Manager service is starting. 0009:trace:advapi:StartServiceA (0x121488,0,(nil)) 0009:trace:advapi:StartServiceW 0x121488 0 (nil) 0009:trace:advapi:LockServiceDatabase 0x121450 0009:trace:advapi:LockServiceDatabase returning 0x3c 0009:trace:advapi:service_start_process service_get_event_handle(L"mdm"): 0x40 0011:trace:advapi:LookupPrivilegeValueW L"",L"SeDebugPrivilege",0x34fc80 0011:trace:advapi:LookupPrivilegeValueW L"" -> 00000000-00000014 0011:trace:advapi:AdjustTokenPrivileges 0011:trace:advapi:StartServiceCtrlDispatcherA 0x34fc9c 0011:trace:advapi:service_run_threads Starting 1 pipe listener threads. Services running as process 16 0012:trace:advapi:service_control_dispatcher 0x121ea8 L"Machine Debug Manager" 0012:trace:advapi:service_control_dispatcher service_get_event_handle(L"Machine Debug Manager"): 0x48 0009:trace:advapi:UnlockServiceDatabase 0x3c 0009:trace:advapi:StartServiceW returning 0 The Machine Debug Manager service failed to start. 0009:trace:advapi:CloseServiceHandle 0x121488 0009:trace:advapi:sc_handle_destroy_service destroying service 0x121488 0009:trace:advapi:CloseServiceHandle 0x121450 0009:trace:advapi:sc_handle_destroy_manager destroying SC Manager 0x121450 000d:trace:advapi:service_run_threads last user process exited, shutting down 0011:trace:advapi:service_run_threads last user process exited, shutting down --- snip trace ---
When a service is started, named objects are created to internally communicate data/events from the service process (dispatcher) to client side SCM API and vice versa. Unfortunately there exist service proccesses which pass service names to dispatcher table (StartServiceCtrlDispatcher) not matching the service name on the client side (registry "Services" key).
--- snip dlls/advapi32/service.c --- static DWORD WINAPI service_control_dispatcher(LPVOID arg) { service_data *service = arg; LPWSTR name; HANDLE pipe, event;
TRACE("%p %s\n", service, debugstr_w(service->name));
/* create a pipe to talk to the rest of the world with */ name = service_get_pipe_name(service->name); <--------- *problem*! pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
if (pipe==INVALID_HANDLE_VALUE) ERR("failed to create pipe for %s, error = %d\n", debugstr_w(service->name), GetLastError());
HeapFree(GetProcessHeap(), 0, name);
/* let the process who started us know we've tried to create a pipe */ event = service_get_event_handle(service->name); <--------- *problem*! SetEvent(event); CloseHandle(event); .. --- snip dlls/advapi32/service.c ---
As result, different named objects are created and signaled so the client side can't communicate with the service side using named pipe and events. This leads to infamous timeout problem (30 sec) and service startup failing.
In case of Microsoft Debug Manager the service is called "mdm" (registry). The service process itself passes "Microsoft Debug Manager" as name to dispatch table (see first trace).
Problem: how can both sides communicate a "common" name for named objects? The service dispatcher part on the service side has only dispatch table data available which doesn't help much.
I thought about this problem and found a feasible solution ... well call it "hack" whatever. If the client side API passes the service name in one of the process startup parameter members before process creation, the service process' dispatcher routine is able to access this data and create the named objects used for communication. I (ab)used startupinfo "title" member because only wine itself make exclusive use of most service process startup parameters. If not considered safe, use reserved/undoc fields...
With that patch applied the services in question start fine and can be controlled using "net" commands. No more hangs ;-)
Regards