No longer directly accessing debuggee memory.
[wine] / dlls / advapi32 / service.c
1 /*
2  * Win32 advapi functions
3  *
4  * Copyright 1995 Sven Verdoolaege
5  */
6
7 #include <time.h>
8
9 #include "windef.h"
10 #include "winsvc.h"
11 #include "winerror.h"
12 #include "winreg.h"
13 #include "heap.h"
14 #include "debugtools.h"
15
16 DEFAULT_DEBUG_CHANNEL(advapi)
17
18 static DWORD   start_dwNumServiceArgs;
19 static LPWSTR *start_lpServiceArgVectors;
20
21 /******************************************************************************
22  * EnumServicesStatusA [ADVAPI32.38]
23  */
24 BOOL WINAPI
25 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
26                        DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
27                        DWORD cbBufSize, LPDWORD pcbBytesNeeded,
28                        LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
29 {       FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager, 
30                 dwServiceType, dwServiceState, lpServices, cbBufSize,
31                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
32         SetLastError (ERROR_ACCESS_DENIED);
33         return 0;
34 }
35
36 /******************************************************************************
37  * StartServiceCtrlDispatcherA [ADVAPI32.196]
38  */
39 BOOL WINAPI
40 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
41 {       
42     LPSERVICE_MAIN_FUNCTIONA fpMain;
43     HANDLE wait;
44     DWORD  dwNumServiceArgs ;
45     LPWSTR *lpArgVecW;
46     LPSTR  *lpArgVecA;
47     int i;
48         
49     TRACE("(%p)\n", servent);
50     wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
51     if(wait == 0)
52     {
53         ERR("Couldn't find wait semaphore\n");
54         ERR("perhaps you need to start services using StartService\n");
55         return FALSE;
56     }
57
58     dwNumServiceArgs = start_dwNumServiceArgs;
59     lpArgVecW        = start_lpServiceArgVectors;
60
61     ReleaseSemaphore(wait, 1, NULL);
62
63     /* Convert the Unicode arg vectors back to ASCII */
64     if(dwNumServiceArgs)
65         lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0, 
66                                    dwNumServiceArgs*sizeof(LPSTR) );
67     else
68         lpArgVecA = NULL;
69
70     for(i=0; i<dwNumServiceArgs; i++)
71         lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
72
73     /* FIXME: should we blindly start all services? */
74     while (servent->lpServiceName) { 
75         TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
76         fpMain = servent->lpServiceProc;
77
78         /* try to start the service */
79         fpMain( dwNumServiceArgs, lpArgVecA);
80
81         servent++;
82     }
83
84     if(dwNumServiceArgs)
85     {
86         /* free arg strings */
87         for(i=0; i<dwNumServiceArgs; i++)
88             HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
89         HeapFree(GetProcessHeap(), 0, lpArgVecA);
90     }
91
92     return TRUE;
93 }
94
95 /******************************************************************************
96  * StartServiceCtrlDispatcherW [ADVAPI32.197]
97  *
98  * PARAMS
99  *   servent []
100  */
101 BOOL WINAPI
102 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
103 {       
104     LPSERVICE_MAIN_FUNCTIONW fpMain;
105     HANDLE wait;
106     DWORD  dwNumServiceArgs ;
107     LPWSTR *lpServiceArgVectors ;
108         
109     TRACE("(%p)\n", servent);
110     wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
111     if(wait == 0)
112     {
113         ERR("Couldn't find wait semaphore\n");
114         ERR("perhaps you need to start services using StartService\n");
115         return FALSE;
116     }
117
118     dwNumServiceArgs    = start_dwNumServiceArgs;
119     lpServiceArgVectors = start_lpServiceArgVectors;
120
121     ReleaseSemaphore(wait, 1, NULL);
122
123     /* FIXME: should we blindly start all services? */
124     while (servent->lpServiceName) { 
125         TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
126         fpMain = servent->lpServiceProc;
127
128         /* try to start the service */
129         fpMain( dwNumServiceArgs, lpServiceArgVectors);
130
131         servent++;
132     }
133
134     return TRUE;
135 }
136
137 /******************************************************************************
138  * RegisterServiceCtrlHandlerA [ADVAPI32.176]
139  */
140 SERVICE_STATUS_HANDLE WINAPI
141 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
142                              LPHANDLER_FUNCTION lpfHandler )
143 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
144         return 0xcacacafe;      
145 }
146
147 /******************************************************************************
148  * RegisterServiceCtrlHandlerW [ADVAPI32.177]
149  *
150  * PARAMS
151  *   lpServiceName []
152  *   lpfHandler    []
153  */
154 SERVICE_STATUS_HANDLE WINAPI
155 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName, 
156                              LPHANDLER_FUNCTION lpfHandler )
157 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
158         return 0xcacacafe;      
159 }
160
161 /******************************************************************************
162  * SetServiceStatus [ADVAPI32.192]
163  *
164  * PARAMS
165  *   hService []
166  *   lpStatus []
167  */
168 BOOL WINAPI
169 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
170 {       FIXME("%lx %p\n",hService, lpStatus);
171         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
172         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
173         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
174         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
175         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
176         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
177         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
178         return TRUE;
179 }
180
181 /******************************************************************************
182  * OpenSCManagerA [ADVAPI32.110]
183  */
184 SC_HANDLE WINAPI
185 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
186                   DWORD dwDesiredAccess )
187 {   
188     LPWSTR lpMachineNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpMachineName);
189     LPWSTR lpDatabaseNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpDatabaseName);
190     DWORD ret = OpenSCManagerW(lpMachineNameW,lpDatabaseNameW,
191                                  dwDesiredAccess);
192     HeapFree(GetProcessHeap(),0,lpDatabaseNameW);
193     HeapFree(GetProcessHeap(),0,lpMachineNameW);
194     return ret;
195 }
196
197 /******************************************************************************
198  * OpenSCManagerW [ADVAPI32.111]
199  * Establishes a connection to the service control manager and opens database
200  *
201  * NOTES
202  *   This should return a SC_HANDLE
203  *
204  * PARAMS
205  *   lpMachineName   [I] Pointer to machine name string
206  *   lpDatabaseName  [I] Pointer to database name string
207  *   dwDesiredAccess [I] Type of access
208  *
209  * RETURNS
210  *   Success: Handle to service control manager database
211  *   Failure: NULL
212  */
213 SC_HANDLE WINAPI
214 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
215                   DWORD dwDesiredAccess )
216 {
217     HKEY hKey;
218     LONG r;
219
220     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName), 
221           debugstr_w(lpDatabaseName), dwDesiredAccess);
222
223     /*
224      * FIXME: what is lpDatabaseName?
225      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
226      * docs, but what if it isn't?
227      */
228
229     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
230     if (r!=ERROR_SUCCESS)
231         return 0;
232
233     TRACE("returning %x\n",hKey);
234
235     return hKey;
236 }
237
238
239 /******************************************************************************
240  * AllocateLocallyUniqueId [ADVAPI32.12]
241  *
242  * PARAMS
243  *   lpluid []
244  */
245 BOOL WINAPI
246 AllocateLocallyUniqueId( PLUID lpluid )
247 {
248         lpluid->s.LowPart = time(NULL);
249         lpluid->s.HighPart = 0;
250         return TRUE;
251 }
252
253
254 /******************************************************************************
255  * ControlService [ADVAPI32.23]
256  * Sends a control code to a Win32-based service.
257  *
258  * PARAMS
259  *   hService        []
260  *   dwControl       []
261  *   lpServiceStatus []
262  *
263  * RETURNS STD
264  */
265 BOOL WINAPI
266 ControlService( SC_HANDLE hService, DWORD dwControl, 
267                 LPSERVICE_STATUS lpServiceStatus )
268 {
269     FIXME("(%d,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
270     return TRUE;
271 }
272
273
274 /******************************************************************************
275  * CloseServiceHandle [ADVAPI32.22]
276  * Close handle to service or service control manager
277  *
278  * PARAMS
279  *   hSCObject [I] Handle to service or service control manager database
280  *
281  * RETURNS STD
282  */
283 BOOL WINAPI
284 CloseServiceHandle( SC_HANDLE hSCObject )
285 {
286     TRACE("(%x)\n", hSCObject);
287
288     RegCloseKey(hSCObject);
289     
290     return TRUE;
291 }
292
293
294 /******************************************************************************
295  * OpenServiceA [ADVAPI32.112]
296  */
297 SC_HANDLE WINAPI
298 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, 
299                 DWORD dwDesiredAccess )
300 {
301     LPWSTR lpServiceNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpServiceName);
302     DWORD ret;
303
304     if(lpServiceName)
305         TRACE("Request for service %s\n",lpServiceName);
306     else
307         return FALSE;
308     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
309     HeapFree(GetProcessHeap(),0,lpServiceNameW);
310     return ret;
311 }
312
313
314 /******************************************************************************
315  * OpenServiceW [ADVAPI32.113]
316  * Opens a handle to an existing service
317  *
318  * PARAMS
319  *   hSCManager      []
320  *   lpServiceName   []
321  *   dwDesiredAccess []
322  *
323  * RETURNS
324  *    Success: Handle to the service
325  *    Failure: NULL
326  */
327 SC_HANDLE WINAPI
328 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
329                DWORD dwDesiredAccess)
330 {
331     const char *str = "System\\CurrentControlSet\\Services\\";
332     WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
333     HKEY hKey;
334     long r;
335
336     TRACE("(%d,%p,%ld)\n",hSCManager, lpServiceName,
337           dwDesiredAccess);
338
339     lstrcpyAtoW(lpServiceKey,str);
340     lstrcatW(lpServiceKey,lpServiceName);
341
342     TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
343
344     /* FIXME: dwDesiredAccess may need some processing */
345     r = RegOpenKeyExW(hSCManager, lpServiceKey, 0, dwDesiredAccess, &hKey );
346     if (r!=ERROR_SUCCESS)
347         return 0;
348
349     TRACE("returning %x\n",hKey);
350
351     return hKey;
352 }
353
354 /******************************************************************************
355  * CreateServiceW [ADVAPI32.29]
356  */
357 SC_HANDLE WINAPI
358 CreateServiceW( DWORD hSCManager, LPCWSTR lpServiceName,
359                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess, 
360                   DWORD dwServiceType, DWORD dwStartType, 
361                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
362                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, 
363                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName, 
364                   LPCWSTR lpPassword )
365 {
366     FIXME("(%ld,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
367     return FALSE;
368 }
369
370
371 /******************************************************************************
372  * CreateServiceA [ADVAPI32.28]
373  */
374 SC_HANDLE WINAPI
375 CreateServiceA( DWORD hSCManager, LPCSTR lpServiceName,
376                   LPCSTR lpDisplayName, DWORD dwDesiredAccess, 
377                   DWORD dwServiceType, DWORD dwStartType, 
378                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
379                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, 
380                   LPCSTR lpDependencies, LPCSTR lpServiceStartName, 
381                   LPCSTR lpPassword )
382 {
383     HKEY hKey;
384     LONG r;
385     DWORD dp;
386
387     TRACE("(%ld,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
388
389     r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL, 
390                        REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
391     if (r!=ERROR_SUCCESS)
392         return 0;
393     if (dp != REG_CREATED_NEW_KEY)
394         return 0;
395
396     if(lpDisplayName)
397     {
398         r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, lstrlenA(lpDisplayName) );
399         if (r!=ERROR_SUCCESS)
400             return 0;
401     }
402
403     r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
404     if (r!=ERROR_SUCCESS)
405         return 0;
406
407     r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
408     if (r!=ERROR_SUCCESS)
409         return 0;
410
411     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD, 
412                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
413     if (r!=ERROR_SUCCESS)
414         return 0;
415
416     if(lpBinaryPathName)
417     {
418         r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ, 
419                            lpBinaryPathName,lstrlenA(lpBinaryPathName)+1 );
420         if (r!=ERROR_SUCCESS)
421             return 0;
422     }
423
424     if(lpLoadOrderGroup)
425     {
426         r = RegSetValueExA(hKey, "Group", 0, REG_SZ, 
427                            lpLoadOrderGroup, lstrlenA(lpLoadOrderGroup)+1 );
428         if (r!=ERROR_SUCCESS)
429             return 0;
430     }
431
432     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD, 
433                        (LPVOID)&dwErrorControl, sizeof (DWORD) );
434     if (r!=ERROR_SUCCESS)
435         return 0;
436
437     if(lpDependencies)
438     {
439         DWORD len = 0; 
440
441         /* determine the length of a double null terminated multi string */
442         do {
443             len += (lstrlenA(&lpDependencies[len])+1);
444         } while (lpDependencies[len++]); 
445         
446         /* fixme: this should be unicode */
447         r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ, 
448                            lpDependencies, len );
449         if (r!=ERROR_SUCCESS)
450             return 0;
451     }
452
453     if(lpPassword)
454     {
455         FIXME("Don't know how to add a Password for a service.\n");
456     }
457
458     if(lpServiceStartName)
459     {
460         FIXME("Don't know how to add a ServiceStartName for a service.\n");
461     }
462
463     return hKey;
464 }
465
466
467 /******************************************************************************
468  * DeleteService [ADVAPI32.31]
469  *
470  * PARAMS
471  *    hService [I] Handle to service
472  *
473  * RETURNS STD
474  *
475  */
476 BOOL WINAPI
477 DeleteService( SC_HANDLE hService )
478 {
479     FIXME("(%d): stub\n",hService);
480     return TRUE;
481 }
482
483
484 /******************************************************************************
485  * StartServiceA [ADVAPI32.195]
486  *
487  */
488 BOOL WINAPI
489 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
490                  LPCSTR *lpServiceArgVectors )
491 {
492     LPWSTR *lpwstr=NULL;
493     int i;
494
495     TRACE("(%d,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
496
497     if(dwNumServiceArgs)
498         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0, 
499                                    dwNumServiceArgs*sizeof(LPWSTR) );
500     else
501         lpwstr = NULL;
502
503     for(i=0; i<dwNumServiceArgs; i++)
504         lpwstr[i]=HEAP_strdupAtoW(GetProcessHeap(), 0, lpServiceArgVectors[i]);
505
506     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
507
508     if(dwNumServiceArgs)
509     {
510         for(i=0; i<dwNumServiceArgs; i++)
511             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
512         HeapFree(GetProcessHeap(), 0, lpwstr);
513     }
514
515     return TRUE;
516 }
517
518
519 /******************************************************************************
520  * StartServiceW [ADVAPI32.198]
521  * Starts a service
522  *
523  * PARAMS
524  *   hService            [I] Handle of service
525  *   dwNumServiceArgs    [I] Number of arguments
526  *   lpServiceArgVectors [I] Address of array of argument string pointers
527  *
528  * NOTES
529  *
530  * NT implements this function using an obscure RPC call...
531  *
532  * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
533  *   to get things like %SystemRoot%\\System32\\service.exe to load.
534  *
535  * Will only work for shared address space. How should the service
536  *  args be transferred when address spaces are separated?
537  *
538  * Can only start one service at a time.
539  *
540  * Has no concept of priviledge.
541  *
542  * RETURNS STD
543  *
544  */
545 BOOL WINAPI
546 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
547                  LPCWSTR *lpServiceArgVectors )
548 {
549     CHAR path[MAX_PATH],str[MAX_PATH];
550     DWORD type,size;
551     long r;
552     HANDLE data,wait;
553     PROCESS_INFORMATION procinfo;
554     STARTUPINFOA startupinfo;
555
556     TRACE("(%d,%ld,%p)\n",hService,dwNumServiceArgs,
557           lpServiceArgVectors);
558
559     size = sizeof str;
560     r = RegQueryValueExA(hService, "ImagePath", NULL, &type, (LPVOID)str, &size);
561     if (r!=ERROR_SUCCESS)
562         return FALSE;
563     ExpandEnvironmentStringsA(str,path,sizeof path);
564
565     TRACE("Starting service %s\n", debugstr_a(path) );
566
567     data = CreateSemaphoreA(NULL,1,1,"ADVAPI32_ServiceStartData");
568     if(data == ERROR_INVALID_HANDLE)
569     {
570         data = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
571         if(data == 0)
572         {
573             ERR("Couldn't create data semaphore\n");
574             return FALSE;
575         }
576     }
577     wait = CreateSemaphoreA(NULL,0,1,"ADVAPI32_WaitServiceStart");
578     {
579         wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
580         if(wait == 0)
581         {
582             ERR("Couldn't create wait semaphore\n");
583             return FALSE;
584         }
585     }
586
587     /* 
588      * FIXME: lpServiceArgsVectors need to be stored and returned to
589      *        the service when it calls StartServiceCtrlDispatcher
590      *
591      * Chuck these in a global (yuk) so we can pass them to
592      * another process - address space separation will break this.
593      */
594     
595     r = WaitForSingleObject(data,INFINITE);
596
597     if( r == WAIT_FAILED)
598         return FALSE;
599
600     start_dwNumServiceArgs    = dwNumServiceArgs;
601     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
602
603     ZeroMemory(&startupinfo,sizeof(STARTUPINFOA));
604     startupinfo.cb = sizeof(STARTUPINFOA);
605
606     r = CreateProcessA(path, 
607                    NULL, 
608                    NULL,  /* process security attribs */
609                    NULL,  /* thread security attribs */
610                    FALSE, /* inherit handles */
611                    0,     /* creation flags */
612                    NULL,  /* environment */
613                    NULL,  /* current directory */
614                    &startupinfo,  /* startup info */
615                    &procinfo); /* process info */
616
617     if(r == FALSE)
618     {
619         ERR("Couldn't start process\n");
620         /* ReleaseSemaphore(data, 1, NULL);
621         return FALSE; */
622     }
623
624     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
625     r = WaitForSingleObject(wait,30000);
626     
627     ReleaseSemaphore(data, 1, NULL);
628
629     if( r == WAIT_FAILED)
630         return FALSE;
631
632     return TRUE;
633 }
634
635 /******************************************************************************
636  * QueryServiceStatus [ADVAPI32.123]
637  *
638  * PARAMS
639  *   hService        []
640  *   lpservicestatus []
641  *   
642  */
643 BOOL WINAPI
644 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
645 {
646     LONG r;
647     DWORD type, val, size;
648
649     FIXME("(%x,%p) partial\n",hService,lpservicestatus);
650
651     /* read the service type from the registry */
652     size = sizeof val;
653     r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
654     if(type!=REG_DWORD)
655     {
656         ERR("invalid Type\n");
657         return FALSE;
658     }
659     lpservicestatus->dwServiceType = val;
660     /* FIXME: how are these determined or read from the registry? */
661     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
662     lpservicestatus->dwCurrentState            = 1;
663     lpservicestatus->dwControlsAccepted        = 0;
664     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
665     lpservicestatus->dwServiceSpecificExitCode = 0;
666     lpservicestatus->dwCheckPoint              = 0;
667     lpservicestatus->dwWaitHint                = 0;
668
669     return TRUE;
670 }
671