quartz: Make dwSamplesProcessed a longlong.
[wine] / programs / services / rpc.c
1 /*
2  * Services.exe - RPC functions
3  *
4  * Copyright 2007 Google (Mikolaj Zalewski)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define WIN32_LEAN_AND_MEAN
22
23 #include <stdarg.h>
24 #include <windows.h>
25 #include <winternl.h>
26 #include <winsvc.h>
27 #include <ntsecapi.h>
28 #include <rpc.h>
29
30 #include "wine/list.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 #include "services.h"
35 #include "svcctl.h"
36
37 extern HANDLE __wine_make_process_system(void);
38
39 WINE_DEFAULT_DEBUG_CHANNEL(service);
40
41 static const GENERIC_MAPPING g_scm_generic =
42 {
43     (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
44     (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
45     (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
46     SC_MANAGER_ALL_ACCESS
47 };
48
49 static const GENERIC_MAPPING g_svc_generic =
50 {
51     (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
52     (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
53     (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
54     SERVICE_ALL_ACCESS
55 };
56
57 typedef enum
58 {
59     SC_HTYPE_DONT_CARE = 0,
60     SC_HTYPE_MANAGER,
61     SC_HTYPE_SERVICE
62 } SC_HANDLE_TYPE;
63
64 struct sc_handle
65 {
66     SC_HANDLE_TYPE type;
67     DWORD access;
68 };
69
70 struct sc_manager_handle       /* service control manager handle */
71 {
72     struct sc_handle hdr;
73     struct scmdatabase *db;
74 };
75
76 struct sc_service_handle       /* service handle */
77 {
78     struct sc_handle hdr;
79     struct service_entry *service_entry;
80 };
81
82 struct sc_lock
83 {
84     struct scmdatabase *db;
85 };
86
87 /* Check if the given handle is of the required type and allows the requested access. */
88 static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
89 {
90     struct sc_handle *hdr = (struct sc_handle *)handle;
91
92     if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
93     {
94         WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
95         return ERROR_INVALID_HANDLE;
96     }
97
98     if ((needed_access & hdr->access) != needed_access)
99     {
100         WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
101         return ERROR_ACCESS_DENIED;
102     }
103
104     *out_hdr = hdr;
105     return ERROR_SUCCESS;
106 }
107
108 static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
109 {
110     struct sc_handle *hdr;
111     DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
112     if (err == ERROR_SUCCESS)
113         *manager = (struct sc_manager_handle *)hdr;
114     return err;
115 }
116
117 static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
118 {
119     struct sc_handle *hdr;
120     DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
121     if (err == ERROR_SUCCESS)
122         *service = (struct sc_service_handle *)hdr;
123     return err;
124 }
125
126 DWORD svcctl_OpenSCManagerW(
127     MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
128     LPCWSTR DatabaseName,
129     DWORD dwAccessMask,
130     SC_RPC_HANDLE *handle)
131 {
132     struct sc_manager_handle *manager;
133
134     WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
135
136     if (DatabaseName != NULL && DatabaseName[0])
137     {
138         if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
139             return ERROR_DATABASE_DOES_NOT_EXIST;
140         if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
141             return ERROR_INVALID_NAME;
142     }
143
144     if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
145         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
146
147     manager->hdr.type = SC_HTYPE_MANAGER;
148
149     if (dwAccessMask & MAXIMUM_ALLOWED)
150         dwAccessMask |= SC_MANAGER_ALL_ACCESS;
151     manager->hdr.access = dwAccessMask;
152     RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
153     manager->db = active_database;
154     *handle = &manager->hdr;
155
156     return ERROR_SUCCESS;
157 }
158
159 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
160 {
161     struct sc_handle *hdr = (struct sc_handle *)handle;
162     switch (hdr->type)
163     {
164         case SC_HTYPE_MANAGER:
165         {
166             struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
167             HeapFree(GetProcessHeap(), 0, manager);
168             break;
169         }
170         case SC_HTYPE_SERVICE:
171         {
172             struct sc_service_handle *service = (struct sc_service_handle *)hdr;
173             release_service(service->service_entry);
174             HeapFree(GetProcessHeap(), 0, service);
175             break;
176         }
177         default:
178             WINE_ERR("invalid handle type %d\n", hdr->type);
179             RpcRaiseException(ERROR_INVALID_HANDLE);
180     }
181 }
182
183 DWORD svcctl_GetServiceDisplayNameW(
184     SC_RPC_HANDLE hSCManager,
185     LPCWSTR lpServiceName,
186     WCHAR *lpBuffer,
187     DWORD cchBufSize,
188     DWORD *cchLength)
189 {
190     struct sc_manager_handle *manager;
191     struct service_entry *entry;
192     DWORD err;
193
194     WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), cchBufSize);
195
196     if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
197         return err;
198
199     scmdatabase_lock_shared(manager->db);
200
201     entry = scmdatabase_find_service(manager->db, lpServiceName);
202     if (entry != NULL)
203     {
204         LPCWSTR name;
205         service_lock_shared(entry);
206         name = get_display_name(entry);
207         *cchLength = strlenW(name);
208         if (*cchLength < cchBufSize)
209         {
210             err = ERROR_SUCCESS;
211             lstrcpyW(lpBuffer, name);
212         }
213         else
214             err = ERROR_INSUFFICIENT_BUFFER;
215         service_unlock(entry);
216     }
217     else
218     {
219         *cchLength = 1;
220         err = ERROR_SERVICE_DOES_NOT_EXIST;
221     }
222
223     scmdatabase_unlock(manager->db);
224
225     if (err != ERROR_SUCCESS && cchBufSize > 0)
226         lpBuffer[0] = 0;
227
228     return err;
229 }
230
231 DWORD svcctl_GetServiceKeyNameW(
232     SC_RPC_HANDLE hSCManager,
233     LPCWSTR lpServiceDisplayName,
234     WCHAR *lpBuffer,
235     DWORD cchBufSize,
236     DWORD *cchLength)
237 {
238     struct service_entry *entry;
239     struct sc_manager_handle *manager;
240     DWORD err;
241
242     WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), cchBufSize);
243
244     if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
245         return err;
246
247     scmdatabase_lock_shared(manager->db);
248
249     entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
250     if (entry != NULL)
251     {
252         service_lock_shared(entry);
253         *cchLength = strlenW(entry->name);
254         if (*cchLength < cchBufSize)
255         {
256             err = ERROR_SUCCESS;
257             lstrcpyW(lpBuffer, entry->name);
258         }
259         else
260             err = ERROR_INSUFFICIENT_BUFFER;
261         service_unlock(entry);
262     }
263     else
264     {
265         *cchLength = 1;
266         err = ERROR_SERVICE_DOES_NOT_EXIST;
267     }
268
269     scmdatabase_unlock(manager->db);
270
271     if (err != ERROR_SUCCESS && cchBufSize > 0)
272         lpBuffer[0] = 0;
273
274     return err;
275 }
276
277 static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
278 {
279     struct sc_service_handle *service;
280
281     if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
282     {
283         release_service(entry);
284         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
285     }
286
287     service->hdr.type = SC_HTYPE_SERVICE;
288     service->hdr.access = dwDesiredAccess;
289     RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
290     service->service_entry = entry;
291     if (dwDesiredAccess & MAXIMUM_ALLOWED)
292         dwDesiredAccess |= SERVICE_ALL_ACCESS;
293
294     *phService = &service->hdr;
295     return ERROR_SUCCESS;
296 }
297
298 DWORD svcctl_OpenServiceW(
299     SC_RPC_HANDLE hSCManager,
300     LPCWSTR lpServiceName,
301     DWORD dwDesiredAccess,
302     SC_RPC_HANDLE *phService)
303 {
304     struct sc_manager_handle *manager;
305     struct service_entry *entry;
306     DWORD err;
307
308     WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
309
310     if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
311         return err;
312     if (!validate_service_name(lpServiceName))
313         return ERROR_INVALID_NAME;
314
315     scmdatabase_lock_shared(manager->db);
316     entry = scmdatabase_find_service(manager->db, lpServiceName);
317     if (entry != NULL)
318         entry->ref_count++;
319     scmdatabase_unlock(manager->db);
320
321     if (entry == NULL)
322         return ERROR_SERVICE_DOES_NOT_EXIST;
323
324     return create_handle_for_service(entry, dwDesiredAccess, phService);
325 }
326
327 DWORD svcctl_CreateServiceW(
328     SC_RPC_HANDLE hSCManager,
329     LPCWSTR lpServiceName,
330     LPCWSTR lpDisplayName,
331     DWORD dwDesiredAccess,
332     DWORD dwServiceType,
333     DWORD dwStartType,
334     DWORD dwErrorControl,
335     LPCWSTR lpBinaryPathName,
336     LPCWSTR lpLoadOrderGroup,
337     DWORD *lpdwTagId,
338     const BYTE *lpDependencies,
339     DWORD dwDependenciesSize,
340     LPCWSTR lpServiceStartName,
341     const BYTE *lpPassword,
342     DWORD dwPasswordSize,
343     SC_RPC_HANDLE *phService)
344 {
345     struct sc_manager_handle *manager;
346     struct service_entry *entry;
347     DWORD err;
348
349     WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
350
351     if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
352         return err;
353
354     if (!validate_service_name(lpServiceName))
355         return ERROR_INVALID_NAME;
356     if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
357         return ERROR_INVALID_PARAMETER;
358
359     if (lpPassword)
360         WINE_FIXME("Don't know how to add a password\n");   /* I always get ERROR_GEN_FAILURE */
361     if (lpDependencies)
362         WINE_FIXME("Dependencies not supported yet\n");
363
364     err = service_create(lpServiceName, &entry);
365     if (err != ERROR_SUCCESS)
366         return err;
367     entry->config.dwServiceType = dwServiceType;
368     entry->config.dwStartType = dwStartType;
369     entry->config.dwErrorControl = dwErrorControl;
370     entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
371     entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
372     entry->config.lpServiceStartName = strdupW(lpServiceStartName);
373     entry->config.lpDisplayName = strdupW(lpDisplayName);
374
375     if (lpdwTagId)      /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
376         entry->config.dwTagId = *lpdwTagId;
377     else
378         entry->config.dwTagId = 0;
379
380     /* other fields NULL*/
381
382     if (!validate_service_config(entry))
383     {
384         WINE_ERR("Invalid data while trying to create service\n");
385         free_service_entry(entry);
386         return ERROR_INVALID_PARAMETER;
387     }
388
389     scmdatabase_lock_exclusive(manager->db);
390
391     if (scmdatabase_find_service(manager->db, lpServiceName))
392     {
393         scmdatabase_unlock(manager->db);
394         free_service_entry(entry);
395         return ERROR_SERVICE_EXISTS;
396     }
397
398     if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
399     {
400         scmdatabase_unlock(manager->db);
401         free_service_entry(entry);
402         return ERROR_DUPLICATE_SERVICE_NAME;
403     }
404
405     err = scmdatabase_add_service(manager->db, entry);
406     if (err != ERROR_SUCCESS)
407     {
408         scmdatabase_unlock(manager->db);
409         free_service_entry(entry);
410         return err;
411     }
412     scmdatabase_unlock(manager->db);
413
414     return create_handle_for_service(entry, dwDesiredAccess, phService);
415 }
416
417 DWORD svcctl_DeleteService(
418     SC_RPC_HANDLE hService)
419 {
420     struct sc_service_handle *service;
421     DWORD err;
422
423     if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
424         return err;
425
426     scmdatabase_lock_exclusive(service->service_entry->db);
427     service_lock_exclusive(service->service_entry);
428
429     if (!is_marked_for_delete(service->service_entry))
430         err = scmdatabase_remove_service(service->service_entry->db, service->service_entry);
431     else
432         err = ERROR_SERVICE_MARKED_FOR_DELETE;
433
434     service_unlock(service->service_entry);
435     scmdatabase_unlock(service->service_entry->db);
436
437     return err;
438 }
439
440 DWORD svcctl_QueryServiceConfigW(
441         SC_RPC_HANDLE hService,
442         QUERY_SERVICE_CONFIGW *config)
443 {
444     struct sc_service_handle *service;
445     DWORD err;
446
447     WINE_TRACE("(%p)\n", config);
448
449     if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
450         return err;
451
452     service_lock_shared(service->service_entry);
453     config->dwServiceType = service->service_entry->config.dwServiceType;
454     config->dwStartType = service->service_entry->config.dwStartType;
455     config->dwErrorControl = service->service_entry->config.dwErrorControl;
456     config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
457     config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
458     config->dwTagId = service->service_entry->config.dwTagId;
459     config->lpDependencies = NULL; /* TODO */
460     config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
461     config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
462     service_unlock(service->service_entry);
463
464     return ERROR_SUCCESS;
465 }
466
467 DWORD svcctl_ChangeServiceConfigW(
468         SC_RPC_HANDLE hService,
469         DWORD dwServiceType,
470         DWORD dwStartType,
471         DWORD dwErrorControl,
472         LPCWSTR lpBinaryPathName,
473         LPCWSTR lpLoadOrderGroup,
474         DWORD *lpdwTagId,
475         const BYTE *lpDependencies,
476         DWORD dwDependenciesSize,
477         LPCWSTR lpServiceStartName,
478         const BYTE *lpPassword,
479         DWORD dwPasswordSize,
480         LPCWSTR lpDisplayName)
481 {
482     struct service_entry new_entry, *entry;
483     struct sc_service_handle *service;
484     DWORD err;
485
486     WINE_TRACE("\n");
487
488     if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
489         return err;
490
491     if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
492         return ERROR_INVALID_PARAMETER;
493
494     /* first check if the new configuration is correct */
495     service_lock_exclusive(service->service_entry);
496
497     if (is_marked_for_delete(service->service_entry))
498     {
499         service_unlock(service->service_entry);
500         return ERROR_SERVICE_MARKED_FOR_DELETE;
501     }
502
503     if (lpDisplayName != NULL &&
504         (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
505         (entry != service->service_entry))
506     {
507         service_unlock(service->service_entry);
508         return ERROR_DUPLICATE_SERVICE_NAME;
509     }
510
511     new_entry = *service->service_entry;
512
513     if (dwServiceType != SERVICE_NO_CHANGE)
514         new_entry.config.dwServiceType = dwServiceType;
515
516     if (dwStartType != SERVICE_NO_CHANGE)
517         new_entry.config.dwStartType = dwStartType;
518
519     if (dwErrorControl != SERVICE_NO_CHANGE)
520         new_entry.config.dwErrorControl = dwErrorControl;
521
522     if (lpBinaryPathName != NULL)
523         new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
524
525     if (lpLoadOrderGroup != NULL)
526         new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
527
528     if (lpdwTagId != NULL)
529         WINE_FIXME("Changing tag id not supported\n");
530
531     if (lpDependencies != NULL)
532         WINE_FIXME("Chainging dependencies not supported\n");
533
534     if (lpServiceStartName != NULL)
535         new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
536
537     if (lpPassword != NULL)
538         WINE_FIXME("Setting password not supported\n");
539
540     if (lpDisplayName != NULL)
541         new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
542
543     if (!validate_service_config(&new_entry))
544     {
545         WINE_ERR("The configuration after the change wouldn't be valid\n");
546         service_unlock(service->service_entry);
547         return ERROR_INVALID_PARAMETER;
548     }
549
550     /* configuration OK. The strings needs to be duplicated */
551     if (lpBinaryPathName != NULL)
552     {
553         HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpBinaryPathName);
554         new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
555     }
556
557     if (lpLoadOrderGroup != NULL)
558     {
559         HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpLoadOrderGroup);
560         new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
561     }
562
563     if (lpServiceStartName != NULL)
564     {
565         HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpServiceStartName);
566         new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
567     }
568
569     if (lpDisplayName != NULL)
570     {
571         HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpDisplayName);
572         new_entry.config.lpDisplayName = strdupW(lpDisplayName);
573     }
574
575     *service->service_entry = new_entry;
576     save_service_config(service->service_entry);
577     service_unlock(service->service_entry);
578
579     return ERROR_SUCCESS;
580 }
581
582 DWORD svcctl_SetServiceStatus(
583     SC_RPC_HANDLE hServiceStatus,
584     LPSERVICE_STATUS lpServiceStatus)
585 {
586     struct sc_service_handle *service;
587     DWORD err;
588
589     WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
590
591     if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
592         return err;
593
594     service_lock_exclusive(service->service_entry);
595     /* FIXME: be a bit more discriminant about what parts of the status we set
596      * and check that fields are valid */
597     service->service_entry->status.dwServiceType = lpServiceStatus->dwServiceType;
598     service->service_entry->status.dwCurrentState = lpServiceStatus->dwCurrentState;
599     service->service_entry->status.dwControlsAccepted = lpServiceStatus->dwControlsAccepted;
600     service->service_entry->status.dwWin32ExitCode = lpServiceStatus->dwWin32ExitCode;
601     service->service_entry->status.dwServiceSpecificExitCode = lpServiceStatus->dwServiceSpecificExitCode;
602     service->service_entry->status.dwCheckPoint = lpServiceStatus->dwCheckPoint;
603     service->service_entry->status.dwWaitHint = lpServiceStatus->dwWaitHint;
604     service_unlock(service->service_entry);
605
606     if (service->service_entry->status_changed_event)
607         SetEvent(service->service_entry->status_changed_event);
608
609     return ERROR_SUCCESS;
610 }
611
612 DWORD svcctl_QueryServiceStatusEx(
613     SC_RPC_HANDLE hService,
614     SC_STATUS_TYPE InfoLevel,
615     BYTE *lpBuffer,
616     DWORD cbBufSize,
617     LPDWORD pcbBytesNeeded)
618 {
619     struct sc_service_handle *service;
620     DWORD err;
621     LPSERVICE_STATUS_PROCESS pSvcStatusData;
622
623     if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
624         return err;
625
626     if (InfoLevel != SC_STATUS_PROCESS_INFO)
627         return ERROR_INVALID_LEVEL;
628
629     pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
630     if (pSvcStatusData == NULL)
631         return ERROR_INVALID_PARAMETER;
632
633     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
634     {
635         if( pcbBytesNeeded != NULL)
636             *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
637
638         return ERROR_INSUFFICIENT_BUFFER;
639     }
640
641     service_lock_shared(service->service_entry);
642
643     pSvcStatusData->dwServiceType = service->service_entry->status.dwServiceType;
644     pSvcStatusData->dwCurrentState = service->service_entry->status.dwCurrentState;
645     pSvcStatusData->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
646     pSvcStatusData->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
647     pSvcStatusData->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
648     pSvcStatusData->dwCheckPoint = service->service_entry->status.dwCheckPoint;
649     pSvcStatusData->dwWaitHint = service->service_entry->status.dwWaitHint;
650     pSvcStatusData->dwProcessId = service->service_entry->status.dwProcessId;
651     pSvcStatusData->dwServiceFlags = service->service_entry->status.dwServiceFlags;
652
653     service_unlock(service->service_entry);
654
655     return ERROR_SUCCESS;
656 }
657
658 /******************************************************************************
659  * service_accepts_control
660  */
661 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
662 {
663     DWORD a = service->status.dwControlsAccepted;
664
665     switch (dwControl)
666     {
667     case SERVICE_CONTROL_INTERROGATE:
668         return TRUE;
669     case SERVICE_CONTROL_STOP:
670         if (a&SERVICE_ACCEPT_STOP)
671             return TRUE;
672         break;
673     case SERVICE_CONTROL_SHUTDOWN:
674         if (a&SERVICE_ACCEPT_SHUTDOWN)
675             return TRUE;
676         break;
677     case SERVICE_CONTROL_PAUSE:
678     case SERVICE_CONTROL_CONTINUE:
679         if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
680             return TRUE;
681         break;
682     case SERVICE_CONTROL_PARAMCHANGE:
683         if (a&SERVICE_ACCEPT_PARAMCHANGE)
684             return TRUE;
685         break;
686     case SERVICE_CONTROL_NETBINDADD:
687     case SERVICE_CONTROL_NETBINDREMOVE:
688     case SERVICE_CONTROL_NETBINDENABLE:
689     case SERVICE_CONTROL_NETBINDDISABLE:
690         if (a&SERVICE_ACCEPT_NETBINDCHANGE)
691             return TRUE;
692     case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
693         if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
694             return TRUE;
695         break;
696     case SERVICE_CONTROL_POWEREVENT:
697         if (a&SERVICE_ACCEPT_POWEREVENT)
698             return TRUE;
699         break;
700     case SERVICE_CONTROL_SESSIONCHANGE:
701         if (a&SERVICE_ACCEPT_SESSIONCHANGE)
702             return TRUE;
703         break;
704     }
705     return FALSE;
706 }
707
708 /******************************************************************************
709  * service_send_control
710  */
711 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
712 {
713     DWORD cmd[2], count = 0;
714     BOOL r;
715
716     cmd[0] = WINESERV_SENDCONTROL;
717     cmd[1] = dwControl;
718     r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
719     if (!r || count != sizeof cmd)
720     {
721         WINE_ERR("service protocol error - failed to write pipe!\n");
722         return r;
723     }
724     r = ReadFile(pipe, result, sizeof *result, &count, NULL);
725     if (!r || count != sizeof *result)
726         WINE_ERR("service protocol error - failed to read pipe "
727             "r = %d  count = %d!\n", r, count);
728     return r;
729 }
730
731 DWORD svcctl_StartServiceW(
732     SC_RPC_HANDLE hService,
733     DWORD dwNumServiceArgs,
734     LPCWSTR *lpServiceArgVectors)
735 {
736     struct sc_service_handle *service;
737     DWORD err;
738
739     WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
740
741     if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
742         return err;
743
744     err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
745
746     return err;
747 }
748
749 DWORD svcctl_ControlService(
750     SC_RPC_HANDLE hService,
751     DWORD dwControl,
752     SERVICE_STATUS *lpServiceStatus)
753 {
754     DWORD access_required;
755     struct sc_service_handle *service;
756     DWORD err;
757     BOOL ret;
758     HANDLE control_mutex;
759     HANDLE control_pipe;
760
761     WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
762
763     switch (dwControl)
764     {
765     case SERVICE_CONTROL_CONTINUE:
766     case SERVICE_CONTROL_NETBINDADD:
767     case SERVICE_CONTROL_NETBINDDISABLE:
768     case SERVICE_CONTROL_NETBINDENABLE:
769     case SERVICE_CONTROL_NETBINDREMOVE:
770     case SERVICE_CONTROL_PARAMCHANGE:
771     case SERVICE_CONTROL_PAUSE:
772         access_required = SERVICE_PAUSE_CONTINUE;
773         break;
774     case SERVICE_CONTROL_INTERROGATE:
775         access_required = SERVICE_INTERROGATE;
776         break;
777     case SERVICE_CONTROL_STOP:
778         access_required = SERVICE_STOP;
779         break;
780     default:
781         if (dwControl >= 128 && dwControl <= 255)
782             access_required = SERVICE_USER_DEFINED_CONTROL;
783         else
784             return ERROR_INVALID_PARAMETER;
785     }
786
787     if ((err = validate_service_handle(hService, access_required, &service)) != 0)
788         return err;
789
790     service_lock_exclusive(service->service_entry);
791
792     if (lpServiceStatus)
793     {
794         lpServiceStatus->dwServiceType = service->service_entry->status.dwServiceType;
795         lpServiceStatus->dwCurrentState = service->service_entry->status.dwCurrentState;
796         lpServiceStatus->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
797         lpServiceStatus->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
798         lpServiceStatus->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
799         lpServiceStatus->dwCheckPoint = service->service_entry->status.dwCheckPoint;
800         lpServiceStatus->dwWaitHint = service->service_entry->status.dwWaitHint;
801     }
802
803     if (!service_accepts_control(service->service_entry, dwControl))
804     {
805         service_unlock(service->service_entry);
806         return ERROR_INVALID_SERVICE_CONTROL;
807     }
808
809     switch (service->service_entry->status.dwCurrentState)
810     {
811     case SERVICE_STOPPED:
812         service_unlock(service->service_entry);
813         return ERROR_SERVICE_NOT_ACTIVE;
814     case SERVICE_START_PENDING:
815         if (dwControl==SERVICE_CONTROL_STOP)
816             break;
817         /* fall thru */
818     case SERVICE_STOP_PENDING:
819         service_unlock(service->service_entry);
820         return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
821     }
822
823     /* prevent races by caching these variables and clearing them on
824      * stop here instead of outside the services lock */
825     control_mutex = service->service_entry->control_mutex;
826     control_pipe = service->service_entry->control_pipe;
827     if (dwControl == SERVICE_CONTROL_STOP)
828     {
829         service->service_entry->control_mutex = NULL;
830         service->service_entry->control_pipe = NULL;
831     }
832
833     service_unlock(service->service_entry);
834
835     ret = WaitForSingleObject(control_mutex, 30000);
836     if (ret)
837     {
838         DWORD result = ERROR_SUCCESS;
839
840         ret = service_send_control(control_pipe, dwControl, &result);
841
842         if (dwControl == SERVICE_CONTROL_STOP)
843         {
844             CloseHandle(control_mutex);
845             CloseHandle(control_pipe);
846         }
847         else
848             ReleaseMutex(control_mutex);
849
850         return result;
851     }
852     else
853     {
854         if (dwControl == SERVICE_CONTROL_STOP)
855         {
856             CloseHandle(control_mutex);
857             CloseHandle(control_pipe);
858         }
859         return ERROR_SERVICE_REQUEST_TIMEOUT;
860     }
861 }
862
863 DWORD svcctl_CloseServiceHandle(
864     SC_RPC_HANDLE *handle)
865 {
866     WINE_TRACE("(&%p)\n", *handle);
867
868     SC_RPC_HANDLE_destroy(*handle);
869     *handle = NULL;
870
871     return ERROR_SUCCESS;
872 }
873
874 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
875 {
876     struct sc_lock *lock = hLock;
877     scmdatabase_unlock_startup(lock->db);
878     HeapFree(GetProcessHeap(), 0, lock);
879 }
880
881 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
882 {
883     SC_RPC_LOCK_destroy(hLock);
884 }
885
886 DWORD svcctl_LockServiceDatabase(
887     SC_RPC_HANDLE hSCManager,
888     SC_RPC_LOCK *phLock)
889 {
890     struct sc_manager_handle *manager;
891     DWORD err;
892
893     WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
894
895     if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
896         return err;
897
898     err = scmdatabase_lock_startup(manager->db);
899     if (err != ERROR_SUCCESS)
900         return err;
901
902     *phLock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
903     if (!*phLock)
904     {
905         scmdatabase_unlock_startup(manager->db);
906         return ERROR_NOT_ENOUGH_SERVER_MEMORY;
907     }
908
909     return ERROR_SUCCESS;
910 }
911
912 DWORD svcctl_UnlockServiceDatabase(
913     SC_RPC_LOCK *phLock)
914 {
915     WINE_TRACE("(&%p)\n", *phLock);
916
917     SC_RPC_LOCK_destroy(*phLock);
918     *phLock = NULL;
919
920     return ERROR_SUCCESS;
921 }
922
923 DWORD svcctl_QueryServiceObjectSecurity(
924     void)
925 {
926     WINE_FIXME("\n");
927     return ERROR_CALL_NOT_IMPLEMENTED;
928 }
929
930 DWORD svcctl_SetServiceObjectSecurity(
931     void)
932 {
933     WINE_FIXME("\n");
934     return ERROR_CALL_NOT_IMPLEMENTED;
935 }
936
937 DWORD svcctl_QueryServiceStatus(
938     void)
939 {
940     WINE_FIXME("\n");
941     return ERROR_CALL_NOT_IMPLEMENTED;
942 }
943
944
945 DWORD svcctl_NotifyBootConfigStatus(
946     void)
947 {
948     WINE_FIXME("\n");
949     return ERROR_CALL_NOT_IMPLEMENTED;
950 }
951
952 DWORD svcctl_SCSetServiceBitsW(
953     void)
954 {
955     WINE_FIXME("\n");
956     return ERROR_CALL_NOT_IMPLEMENTED;
957 }
958
959
960 DWORD svcctl_EnumDependentServicesW(
961     void)
962 {
963     WINE_FIXME("\n");
964     return ERROR_CALL_NOT_IMPLEMENTED;
965 }
966
967 DWORD svcctl_EnumServicesStatusW(
968     void)
969 {
970     WINE_FIXME("\n");
971     return ERROR_CALL_NOT_IMPLEMENTED;
972 }
973
974
975 DWORD svcctl_QueryServiceLockStatusW(
976     void)
977 {
978     WINE_FIXME("\n");
979     return ERROR_CALL_NOT_IMPLEMENTED;
980 }
981
982 DWORD svcctl_SCSetServiceBitsA(
983     void)
984 {
985     WINE_FIXME("\n");
986     return ERROR_CALL_NOT_IMPLEMENTED;
987 }
988
989 DWORD svcctl_ChangeServiceConfigA(
990     void)
991 {
992     WINE_FIXME("\n");
993     return ERROR_CALL_NOT_IMPLEMENTED;
994 }
995
996 DWORD svcctl_CreateServiceA(
997     void)
998 {
999     WINE_FIXME("\n");
1000     return ERROR_CALL_NOT_IMPLEMENTED;
1001 }
1002
1003 DWORD svcctl_EnumDependentServicesA(
1004     void)
1005 {
1006     WINE_FIXME("\n");
1007     return ERROR_CALL_NOT_IMPLEMENTED;
1008 }
1009
1010 DWORD svcctl_EnumServicesStatusA(
1011     void)
1012 {
1013     WINE_FIXME("\n");
1014     return ERROR_CALL_NOT_IMPLEMENTED;
1015 }
1016
1017 DWORD svcctl_OpenSCManagerA(
1018     void)
1019 {
1020     WINE_FIXME("\n");
1021     return ERROR_CALL_NOT_IMPLEMENTED;
1022 }
1023
1024 DWORD svcctl_OpenServiceA(
1025     void)
1026 {
1027     WINE_FIXME("\n");
1028     return ERROR_CALL_NOT_IMPLEMENTED;
1029 }
1030
1031 DWORD svcctl_QueryServiceConfigA(
1032     void)
1033 {
1034     WINE_FIXME("\n");
1035     return ERROR_CALL_NOT_IMPLEMENTED;
1036 }
1037
1038 DWORD svcctl_QueryServiceLockStatusA(
1039     void)
1040 {
1041     WINE_FIXME("\n");
1042     return ERROR_CALL_NOT_IMPLEMENTED;
1043 }
1044
1045 DWORD svcctl_StartServiceA(
1046     void)
1047 {
1048     WINE_FIXME("\n");
1049     return ERROR_CALL_NOT_IMPLEMENTED;
1050 }
1051
1052 DWORD svcctl_GetServiceDisplayNameA(
1053     void)
1054 {
1055     WINE_FIXME("\n");
1056     return ERROR_CALL_NOT_IMPLEMENTED;
1057 }
1058
1059 DWORD svcctl_GetServiceKeyNameA(
1060     void)
1061 {
1062     WINE_FIXME("\n");
1063     return ERROR_CALL_NOT_IMPLEMENTED;
1064 }
1065
1066 DWORD svcctl_GetCurrentGroupStateW(
1067     void)
1068 {
1069     WINE_FIXME("\n");
1070     return ERROR_CALL_NOT_IMPLEMENTED;
1071 }
1072
1073 DWORD svcctl_EnumServiceGroupW(
1074     void)
1075 {
1076     WINE_FIXME("\n");
1077     return ERROR_CALL_NOT_IMPLEMENTED;
1078 }
1079
1080 DWORD svcctl_ChangeServiceConfig2A(
1081     void)
1082 {
1083     WINE_FIXME("\n");
1084     return ERROR_CALL_NOT_IMPLEMENTED;
1085 }
1086
1087 DWORD svcctl_ChangeServiceConfig2W(
1088     void)
1089 {
1090     WINE_FIXME("\n");
1091     return ERROR_CALL_NOT_IMPLEMENTED;
1092 }
1093
1094 DWORD svcctl_QueryServiceConfig2A(
1095     void)
1096 {
1097     WINE_FIXME("\n");
1098     return ERROR_CALL_NOT_IMPLEMENTED;
1099 }
1100
1101 DWORD svcctl_QueryServiceConfig2W(
1102     void)
1103 {
1104     WINE_FIXME("\n");
1105     return ERROR_CALL_NOT_IMPLEMENTED;
1106 }
1107
1108
1109 DWORD RPC_Init(void)
1110 {
1111     WCHAR transport[] = SVCCTL_TRANSPORT;
1112     WCHAR endpoint[] = SVCCTL_ENDPOINT;
1113     DWORD err;
1114
1115     if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1116     {
1117         WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1118         return err;
1119     }
1120
1121     if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1122     {
1123         WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1124         return err;
1125     }
1126
1127     if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1128     {
1129         WINE_ERR("RpcServerListen failed with error %u\n", err);
1130         return err;
1131     }
1132     return ERROR_SUCCESS;
1133 }
1134
1135 DWORD RPC_MainLoop(void)
1136 {
1137     DWORD err;
1138     HANDLE hExitEvent = __wine_make_process_system();
1139
1140     SetEvent(g_hStartedEvent);
1141
1142     WINE_TRACE("Entered main loop\n");
1143
1144     do
1145     {
1146         err = WaitForSingleObjectEx(hExitEvent, INFINITE, TRUE);
1147         WINE_TRACE("Wait returned %d\n", err);
1148     } while (err != WAIT_OBJECT_0);
1149
1150     WINE_TRACE("Object signaled - wine shutdown\n");
1151     CloseHandle(hExitEvent);
1152     return ERROR_SUCCESS;
1153 }
1154
1155 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
1156 {
1157     SC_RPC_HANDLE_destroy(handle);
1158 }
1159
1160 void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
1161 {
1162     return HeapAlloc(GetProcessHeap(), 0, len);
1163 }
1164
1165 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
1166 {
1167     HeapFree(GetProcessHeap(), 0, ptr);
1168 }