~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/advapi32/service.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Win32 advapi functions
  3  *
  4  * Copyright 1995 Sven Verdoolaege
  5  * Copyright 2005 Mike McCormack
  6  * Copyright 2007 Rolf Kalbermatter
  7  *
  8  * This library is free software; you can redistribute it and/or
  9  * modify it under the terms of the GNU Lesser General Public
 10  * License as published by the Free Software Foundation; either
 11  * version 2.1 of the License, or (at your option) any later version.
 12  *
 13  * This library is distributed in the hope that it will be useful,
 14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 16  * Lesser General Public License for more details.
 17  *
 18  * You should have received a copy of the GNU Lesser General Public
 19  * License along with this library; if not, write to the Free Software
 20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 21  */
 22 
 23 #include "config.h"
 24 #include "wine/port.h"
 25 
 26 #include <stdarg.h>
 27 #include <string.h>
 28 #include <time.h>
 29 #include <assert.h>
 30 
 31 #include "windef.h"
 32 #include "winbase.h"
 33 #include "winsvc.h"
 34 #include "winerror.h"
 35 #include "winreg.h"
 36 #include "wine/unicode.h"
 37 #include "wine/debug.h"
 38 #include "winternl.h"
 39 #include "lmcons.h"
 40 #include "lmserver.h"
 41 
 42 #include "svcctl.h"
 43 
 44 #include "wine/exception.h"
 45 
 46 WINE_DEFAULT_DEBUG_CHANNEL(service);
 47 
 48 static const WCHAR szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
 49 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
 50       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
 51       'S','e','r','v','i','c','e','s',0 };
 52 static const WCHAR  szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
 53                                    'L','O','C','K',0};
 54 
 55 void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
 56 {
 57     return HeapAlloc(GetProcessHeap(), 0, len);
 58 }
 59 
 60 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
 61 {
 62     HeapFree(GetProcessHeap(), 0, ptr);
 63 }
 64 
 65 static const GENERIC_MAPPING scm_generic = {
 66     (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
 67     (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
 68     (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
 69     SC_MANAGER_ALL_ACCESS
 70 };
 71 
 72 static const GENERIC_MAPPING svc_generic = {
 73     (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
 74     (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
 75     (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
 76     SERVICE_ALL_ACCESS
 77 };
 78 
 79 typedef struct service_data_t
 80 {
 81     LPHANDLER_FUNCTION_EX handler;
 82     LPVOID context;
 83     HANDLE thread;
 84     SC_HANDLE handle;
 85     BOOL unicode : 1;
 86     union {
 87         LPSERVICE_MAIN_FUNCTIONA a;
 88         LPSERVICE_MAIN_FUNCTIONW w;
 89     } proc;
 90     LPWSTR args;
 91     WCHAR name[1];
 92 } service_data;
 93 
 94 static CRITICAL_SECTION service_cs;
 95 static CRITICAL_SECTION_DEBUG service_cs_debug =
 96 {
 97     0, 0, &service_cs,
 98     { &service_cs_debug.ProcessLocksList, 
 99       &service_cs_debug.ProcessLocksList },
100       0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
101 };
102 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
103 
104 static service_data **services;
105 static unsigned int nb_services;
106 static HANDLE service_event;
107 
108 extern HANDLE __wine_make_process_system(void);
109 
110 /******************************************************************************
111  * SC_HANDLEs
112  */
113 
114 #define MAX_SERVICE_NAME 256
115 
116 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
117 
118 struct sc_handle;
119 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
120 
121 struct sc_handle
122 {
123     SC_HANDLE_TYPE htype;
124     DWORD ref_count;
125     sc_handle_destructor destroy;
126     SC_RPC_HANDLE server_handle;     /* server-side handle */
127 };
128 
129 struct sc_manager       /* service control manager handle */
130 {
131     struct sc_handle hdr;
132     HKEY   hkey;   /* handle to services database in the registry */
133     DWORD  dwAccess;
134 };
135 
136 struct sc_service       /* service handle */
137 {
138     struct sc_handle hdr;
139     HKEY   hkey;          /* handle to service entry in the registry (under hkey) */
140     DWORD  dwAccess;
141     struct sc_manager *scm;  /* pointer to SCM handle */
142     WCHAR  name[1];
143 };
144 
145 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
146                              sc_handle_destructor destroy)
147 {
148     struct sc_handle *hdr;
149 
150     hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
151     if (hdr)
152     {
153         hdr->htype = htype;
154         hdr->ref_count = 1;
155         hdr->destroy = destroy;
156     }
157     TRACE("sc_handle type=%d -> %p\n", htype, hdr);
158     return hdr;
159 }
160 
161 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
162 {
163     struct sc_handle *hdr = (struct sc_handle *) handle;
164 
165     if (!hdr)
166         return NULL;
167     if (hdr->htype != htype)
168         return NULL;
169     return hdr;
170 }
171 
172 static void sc_handle_free(struct sc_handle* hdr)
173 {
174     if (!hdr)
175         return;
176     if (--hdr->ref_count)
177         return;
178     hdr->destroy(hdr);
179     HeapFree(GetProcessHeap(), 0, hdr);
180 }
181 
182 static void sc_handle_destroy_manager(struct sc_handle *handle)
183 {
184     struct sc_manager *mgr = (struct sc_manager*) handle;
185 
186     TRACE("destroying SC Manager %p\n", mgr);
187     if (mgr->hkey)
188         RegCloseKey(mgr->hkey);
189 }
190 
191 static void sc_handle_destroy_service(struct sc_handle *handle)
192 {
193     struct sc_service *svc = (struct sc_service*) handle;
194     
195     TRACE("destroying service %p\n", svc);
196     if (svc->hkey)
197         RegCloseKey(svc->hkey);
198     svc->hkey = NULL;
199     sc_handle_free(&svc->scm->hdr);
200     svc->scm = NULL;
201 }
202 
203 /******************************************************************************
204  * String management functions (same behaviour as strdup)
205  * NOTE: the caller of those functions is responsible for calling HeapFree
206  * in order to release the memory allocated by those functions.
207  */
208 static inline LPWSTR SERV_dup( LPCSTR str )
209 {
210     UINT len;
211     LPWSTR wstr;
212 
213     if( !str )
214         return NULL;
215     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
216     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
217     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
218     return wstr;
219 }
220 
221 static inline LPWSTR SERV_dupmulti(LPCSTR str)
222 {
223     UINT len = 0, n = 0;
224     LPWSTR wstr;
225 
226     if( !str )
227         return NULL;
228     do {
229         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
230         n += (strlen( &str[n] ) + 1);
231     } while (str[n]);
232     len++;
233     n++;
234 
235     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
236     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
237     return wstr;
238 }
239 
240 static inline DWORD multisz_cb(LPCWSTR wmultisz)
241 {
242     const WCHAR *wptr = wmultisz;
243 
244     if (wmultisz == NULL)
245         return 0;
246 
247     while (*wptr)
248         wptr += lstrlenW(wptr)+1;
249     return (wptr - wmultisz + 1)*sizeof(WCHAR);
250 }
251 
252 /******************************************************************************
253  * RPC connection with services.exe
254  */
255 
256 handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
257 {
258     WCHAR transport[] = SVCCTL_TRANSPORT;
259     WCHAR endpoint[] = SVCCTL_ENDPOINT;
260     RPC_WSTR binding_str;
261     RPC_STATUS status;
262     handle_t rpc_handle;
263 
264     status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
265     if (status != RPC_S_OK)
266     {
267         ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
268         return NULL;
269     }
270 
271     status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
272     RpcStringFreeW(&binding_str);
273 
274     if (status != RPC_S_OK)
275     {
276         ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
277         return NULL;
278     }
279 
280     return rpc_handle;
281 }
282 
283 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
284 {
285     RpcBindingFree(&h);
286 }
287 
288 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
289 {
290     return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
291 }
292 
293 static DWORD map_exception_code(DWORD exception_code)
294 {
295     switch (exception_code)
296     {
297     case RPC_X_NULL_REF_POINTER:
298     case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
299     case RPC_X_BYTE_COUNT_TOO_SMALL:
300         return ERROR_INVALID_PARAMETER;
301     default:
302         return exception_code;
303     }
304 }
305 
306 /******************************************************************************
307  * Service IPC functions
308  */
309 static LPWSTR service_get_pipe_name(void)
310 {
311     static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
312         'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
313     static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
314         'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
315         'C','o','n','t','r','o','l','\\',
316         'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
317     LPWSTR name;
318     DWORD len;
319     HKEY service_current_key;
320     DWORD service_current;
321     LONG ret;
322     DWORD type;
323 
324     ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
325         KEY_QUERY_VALUE, &service_current_key);
326     if (ret != ERROR_SUCCESS)
327         return NULL;
328     len = sizeof(service_current);
329     ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
330         (BYTE *)&service_current, &len);
331     RegCloseKey(service_current_key);
332     if (ret != ERROR_SUCCESS || type != REG_DWORD)
333         return NULL;
334     len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
335     name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
336     if (!name)
337         return NULL;
338     snprintfW(name, len, format, service_current);
339     return name;
340 }
341 
342 static HANDLE service_open_pipe(void)
343 {
344     LPWSTR szPipe = service_get_pipe_name();
345     HANDLE handle = INVALID_HANDLE_VALUE;
346 
347     do {
348         handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
349                          0, NULL, OPEN_ALWAYS, 0, NULL);
350         if (handle != INVALID_HANDLE_VALUE)
351             break;
352         if (GetLastError() != ERROR_PIPE_BUSY)
353             break;
354     } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
355     HeapFree(GetProcessHeap(), 0, szPipe);
356 
357     return handle;
358 }
359 
360 static service_data *find_service_by_name( const WCHAR *name )
361 {
362     unsigned int i;
363 
364     if (nb_services == 1)  /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
365         return services[0];
366     for (i = 0; i < nb_services; i++)
367         if (!strcmpiW( name, services[i]->name )) return services[i];
368     return NULL;
369 }
370 
371 /******************************************************************************
372  * service_thread
373  *
374  * Call into the main service routine provided by StartServiceCtrlDispatcher.
375  */
376 static DWORD WINAPI service_thread(LPVOID arg)
377 {
378     service_data *info = arg;
379     LPWSTR str = info->args;
380     DWORD argc = 0, len = 0;
381 
382     TRACE("%p\n", arg);
383 
384     while (str[len])
385     {
386         len += strlenW(&str[len]) + 1;
387         argc++;
388     }
389 
390     if (!argc)
391     {
392         if (info->unicode)
393             info->proc.w(0, NULL);
394         else
395             info->proc.a(0, NULL);
396         return 0;
397     }
398     
399     if (info->unicode)
400     {
401         LPWSTR *argv, p;
402 
403         argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
404         for (argc=0, p=str; *p; p += strlenW(p) + 1)
405             argv[argc++] = p;
406         argv[argc] = NULL;
407 
408         info->proc.w(argc, argv);
409         HeapFree(GetProcessHeap(), 0, argv);
410     }
411     else
412     {
413         LPSTR strA, *argv, p;
414         DWORD lenA;
415         
416         lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
417         strA = HeapAlloc(GetProcessHeap(), 0, lenA);
418         WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
419 
420         argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
421         for (argc=0, p=strA; *p; p += strlen(p) + 1)
422             argv[argc++] = p;
423         argv[argc] = NULL;
424 
425         info->proc.a(argc, argv);
426         HeapFree(GetProcessHeap(), 0, argv);
427         HeapFree(GetProcessHeap(), 0, strA);
428     }
429     return 0;
430 }
431 
432 /******************************************************************************
433  * service_handle_start
434  */
435 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
436 {
437     TRACE("%s argsize %u\n", debugstr_w(service->name), count);
438 
439     if (service->thread)
440     {
441         WARN("service is not stopped\n");
442         return ERROR_SERVICE_ALREADY_RUNNING;
443     }
444 
445     HeapFree(GetProcessHeap(), 0, service->args);
446     service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
447     memcpy( service->args, data, count * sizeof(WCHAR) );
448     service->thread = CreateThread( NULL, 0, service_thread,
449                                     service, 0, NULL );
450     SetEvent( service_event );  /* notify the main loop */
451     return 0;
452 }
453 
454 /******************************************************************************
455  * service_handle_control
456  */
457 static DWORD service_handle_control(service_data *service, DWORD dwControl)
458 {
459     DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
460 
461     TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
462 
463     if (service->handler)
464         ret = service->handler(dwControl, 0, NULL, service->context);
465     return ret;
466 }
467 
468 /******************************************************************************
469  * service_control_dispatcher
470  */
471 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
472 {
473     SC_HANDLE manager;
474     HANDLE pipe;
475 
476     if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
477     {
478         ERR("failed to open service manager error %u\n", GetLastError());
479         return 0;
480     }
481 
482     pipe = service_open_pipe();
483 
484     if (pipe==INVALID_HANDLE_VALUE)
485     {
486         ERR("failed to create control pipe error = %d\n", GetLastError());
487         return 0;
488     }
489 
490     /* dispatcher loop */
491     while (1)
492     {
493         service_data *service;
494         service_start_info info;
495         WCHAR *data = NULL;
496         BOOL r;
497         DWORD data_size = 0, count, result;
498 
499         r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
500         if (!r)
501         {
502             if (GetLastError() != ERROR_BROKEN_PIPE)
503                 ERR( "pipe read failed error %u\n", GetLastError() );
504             break;
505         }
506         if (count != FIELD_OFFSET(service_start_info,data))
507         {
508             ERR( "partial pipe read %u\n", count );
509             break;
510         }
511         if (count < info.total_size)
512         {
513             data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
514             data = HeapAlloc( GetProcessHeap(), 0, data_size );
515             r = ReadFile( pipe, data, data_size, &count, NULL );
516             if (!r)
517             {
518                 if (GetLastError() != ERROR_BROKEN_PIPE)
519                     ERR( "pipe read failed error %u\n", GetLastError() );
520                 break;
521             }
522             if (count != data_size)
523             {
524                 ERR( "partial pipe read %u/%u\n", count, data_size );
525                 break;
526             }
527         }
528 
529         /* find the service */
530 
531         if (!(service = find_service_by_name( data )))
532         {
533             FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
534             result = ERROR_INVALID_PARAMETER;
535             goto done;
536         }
537 
538         TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
539 
540         /* handle the request */
541         switch (info.cmd)
542         {
543         case WINESERV_STARTINFO:
544             if (!service->handle)
545             {
546                 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
547                     FIXME( "failed to open service %s\n", debugstr_w(data) );
548             }
549             result = service_handle_start(service, data + info.name_size,
550                                           data_size / sizeof(WCHAR) - info.name_size );
551             break;
552         case WINESERV_SENDCONTROL:
553             result = service_handle_control(service, info.control);
554             break;
555         default:
556             ERR("received invalid command %u\n", info.cmd);
557             result = ERROR_INVALID_PARAMETER;
558             break;
559         }
560 
561     done:
562         WriteFile(pipe, &result, sizeof(result), &count, NULL);
563         HeapFree( GetProcessHeap(), 0, data );
564     }
565 
566     CloseHandle(pipe);
567     CloseServiceHandle( manager );
568     return 1;
569 }
570 
571 /******************************************************************************
572  * service_run_main_thread
573  */
574 static BOOL service_run_main_thread(void)
575 {
576     DWORD i, n, ret;
577     HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
578     UINT wait_services[MAXIMUM_WAIT_OBJECTS];
579 
580     service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
581 
582     /* FIXME: service_control_dispatcher should be merged into the main thread */
583     wait_handles[0] = __wine_make_process_system();
584     wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
585     wait_handles[2] = service_event;
586 
587     TRACE("Starting %d services running as process %d\n",
588           nb_services, GetCurrentProcessId());
589 
590     /* wait for all the threads to pack up and exit */
591     for (;;)
592     {
593         EnterCriticalSection( &service_cs );
594         for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
595         {
596             if (!services[i]->thread) continue;
597             wait_services[n] = i;
598             wait_handles[n++] = services[i]->thread;
599         }
600         LeaveCriticalSection( &service_cs );
601 
602         ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
603         if (!ret)  /* system process event */
604         {
605             TRACE( "last user process exited, shutting down\n" );
606             /* FIXME: we should maybe send a shutdown control to running services */
607             ExitProcess(0);
608         }
609         else if (ret == 1)
610         {
611             TRACE( "control dispatcher exited, shutting down\n" );
612             /* FIXME: we should maybe send a shutdown control to running services */
613             ExitProcess(0);
614         }
615         else if (ret == 2)
616         {
617             continue;  /* rebuild the list */
618         }
619         else if (ret < n)
620         {
621             services[wait_services[ret]]->thread = 0;
622             CloseHandle( wait_handles[ret] );
623             if (n == 4) return TRUE; /* it was the last running thread */
624         }
625         else return FALSE;
626     }
627 }
628 
629 /******************************************************************************
630  * StartServiceCtrlDispatcherA [ADVAPI32.@]
631  *
632  * See StartServiceCtrlDispatcherW.
633  */
634 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
635 {
636     service_data *info;
637     unsigned int i;
638     BOOL ret = TRUE;
639 
640     TRACE("%p\n", servent);
641 
642     if (nb_services)
643     {
644         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
645         return FALSE;
646     }
647     while (servent[nb_services].lpServiceName) nb_services++;
648     services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
649 
650     for (i = 0; i < nb_services; i++)
651     {
652         DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
653         DWORD sz = FIELD_OFFSET( service_data, name[len] );
654         info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
655         MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
656         info->proc.a = servent[i].lpServiceProc;
657         info->unicode = FALSE;
658         services[i] = info;
659     }
660 
661     service_run_main_thread();
662 
663     return ret;
664 }
665 
666 /******************************************************************************
667  * StartServiceCtrlDispatcherW [ADVAPI32.@]
668  *
669  *  Connects a process containing one or more services to the service control
670  * manager.
671  *
672  * PARAMS
673  *   servent [I]  A list of the service names and service procedures
674  *
675  * RETURNS
676  *  Success: TRUE.
677  *  Failure: FALSE.
678  */
679 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
680 {
681     service_data *info;
682     unsigned int i;
683     BOOL ret = TRUE;
684 
685     TRACE("%p\n", servent);
686 
687     if (nb_services)
688     {
689         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
690         return FALSE;
691     }
692     while (servent[nb_services].lpServiceName) nb_services++;
693     services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
694 
695     for (i = 0; i < nb_services; i++)
696     {
697         DWORD len = strlenW(servent[i].lpServiceName) + 1;
698         DWORD sz = FIELD_OFFSET( service_data, name[len] );
699         info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
700         strcpyW(info->name, servent[i].lpServiceName);
701         info->proc.w = servent[i].lpServiceProc;
702         info->unicode = TRUE;
703         services[i] = info;
704     }
705 
706     service_run_main_thread();
707 
708     return ret;
709 }
710 
711 /******************************************************************************
712  * LockServiceDatabase  [ADVAPI32.@]
713  */
714 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
715 {
716     struct sc_manager *hscm;
717     SC_RPC_LOCK hLock = NULL;
718     DWORD err;
719 
720     TRACE("%p\n",hSCManager);
721 
722     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
723     if (!hscm)
724     {
725         SetLastError( ERROR_INVALID_HANDLE );
726         return NULL;
727     }
728 
729     __TRY
730     {
731         err = svcctl_LockServiceDatabase(hscm->hdr.server_handle, &hLock);
732     }
733     __EXCEPT(rpc_filter)
734     {
735         err = map_exception_code(GetExceptionCode());
736     }
737     __ENDTRY
738     if (err != ERROR_SUCCESS)
739     {
740         SetLastError(err);
741         return NULL;
742     }
743     return hLock;
744 }
745 
746 /******************************************************************************
747  * UnlockServiceDatabase  [ADVAPI32.@]
748  */
749 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
750 {
751     DWORD err;
752     SC_RPC_LOCK hRpcLock = ScLock;
753 
754     TRACE("%p\n",ScLock);
755 
756     __TRY
757     {
758         err = svcctl_UnlockServiceDatabase(&hRpcLock);
759     }
760     __EXCEPT(rpc_filter)
761     {
762         err = map_exception_code(GetExceptionCode());
763     }
764     __ENDTRY
765     if (err != ERROR_SUCCESS)
766     {
767         SetLastError(err);
768         return FALSE;
769     }
770     return TRUE;
771 }
772 
773 /******************************************************************************
774  * SetServiceStatus [ADVAPI32.@]
775  *
776  * PARAMS
777  *   hService []
778  *   lpStatus []
779  */
780 BOOL WINAPI
781 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
782 {
783     struct sc_service *hsvc;
784     DWORD err;
785 
786     TRACE("%p %x %x %x %x %x %x %x\n", hService,
787           lpStatus->dwServiceType, lpStatus->dwCurrentState,
788           lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
789           lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
790           lpStatus->dwWaitHint);
791 
792     hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
793     if (!hsvc)
794     {
795         SetLastError( ERROR_INVALID_HANDLE );
796         return FALSE;
797     }
798 
799     __TRY
800     {
801         err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
802     }
803     __EXCEPT(rpc_filter)
804     {
805         err = map_exception_code(GetExceptionCode());
806     }
807     __ENDTRY
808     if (err != ERROR_SUCCESS)
809     {
810         SetLastError(err);
811         return FALSE;
812     }
813 
814     if (lpStatus->dwCurrentState == SERVICE_STOPPED)
815         CloseServiceHandle((SC_HANDLE)hService);
816 
817     return TRUE;
818 }
819 
820 
821 /******************************************************************************
822  * OpenSCManagerA [ADVAPI32.@]
823  *
824  * Establish a connection to the service control manager and open its database.
825  *
826  * PARAMS
827  *   lpMachineName   [I] Pointer to machine name string
828  *   lpDatabaseName  [I] Pointer to database name string
829  *   dwDesiredAccess [I] Type of access
830  *
831  * RETURNS
832  *   Success: A Handle to the service control manager database
833  *   Failure: NULL
834  */
835 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
836                                  DWORD dwDesiredAccess )
837 {
838     LPWSTR lpMachineNameW, lpDatabaseNameW;
839     SC_HANDLE ret;
840 
841     lpMachineNameW = SERV_dup(lpMachineName);
842     lpDatabaseNameW = SERV_dup(lpDatabaseName);
843     ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
844     HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
845     HeapFree(GetProcessHeap(), 0, lpMachineNameW);
846     return ret;
847 }
848 
849 /******************************************************************************
850  * OpenSCManagerW [ADVAPI32.@]
851  *
852  * See OpenSCManagerA.
853  */
854 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
855                                  DWORD dwDesiredAccess )
856 {
857     struct sc_manager *manager;
858     HKEY hReg;
859     LONG r;
860     DWORD new_mask = dwDesiredAccess;
861 
862     TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
863           debugstr_w(lpDatabaseName), dwDesiredAccess);
864 
865     manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
866                                sc_handle_destroy_manager );
867     if (!manager)
868          return NULL;
869 
870     __TRY
871     {
872         r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
873     }
874     __EXCEPT(rpc_filter)
875     {
876         r = map_exception_code(GetExceptionCode());
877     }
878     __ENDTRY
879     if (r!=ERROR_SUCCESS)
880         goto error;
881 
882     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
883     if (r!=ERROR_SUCCESS)
884         goto error;
885 
886     r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
887     RegCloseKey( hReg );
888     if (r!=ERROR_SUCCESS)
889         goto error;
890 
891     RtlMapGenericMask(&new_mask, &scm_generic);
892     manager->dwAccess = new_mask;
893     TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
894 
895     return (SC_HANDLE) &manager->hdr;
896 
897 error:
898     sc_handle_free( &manager->hdr );
899     SetLastError( r);
900     return NULL;
901 }
902 
903 /******************************************************************************
904  * ControlService [ADVAPI32.@]
905  *
906  * Send a control code to a service.
907  *
908  * PARAMS
909  *   hService        [I] Handle of the service control manager database
910  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
911  *   lpServiceStatus [O] Destination for the status of the service, if available
912  *
913  * RETURNS
914  *   Success: TRUE.
915  *   Failure: FALSE.
916  *
917  * BUGS
918  *   Unlike M$' implementation, control requests are not serialized and may be
919  *   processed asynchronously.
920  */
921 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
922                             LPSERVICE_STATUS lpServiceStatus )
923 {
924     struct sc_service *hsvc;
925     DWORD err;
926 
927     TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
928 
929     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
930     if (!hsvc)
931     {
932         SetLastError( ERROR_INVALID_HANDLE );
933         return FALSE;
934     }
935 
936     __TRY
937     {
938         err = svcctl_ControlService(hsvc->hdr.server_handle, dwControl, lpServiceStatus);
939     }
940     __EXCEPT(rpc_filter)
941     {