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