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 {