services: Use threadpool API instead of custom wait implementation.
[wine.git] / programs / services / rpc.c
blob4c6301c5e60ac38110dcff14a7b3debb691ca97f
1 /*
2 * Services.exe - RPC functions
4 * Copyright 2007 Google (Mikolaj Zalewski)
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.
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.
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
21 #define WIN32_LEAN_AND_MEAN
22 #define NONAMELESSUNION
24 #include <stdarg.h>
25 #include <windows.h>
26 #include <winternl.h>
27 #include <winsvc.h>
28 #include <ntsecapi.h>
29 #include <rpc.h>
31 #include "wine/list.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
35 #include "services.h"
36 #include "svcctl.h"
38 extern HANDLE CDECL __wine_make_process_system(void);
40 WINE_DEFAULT_DEBUG_CHANNEL(service);
42 static const GENERIC_MAPPING g_scm_generic =
44 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
45 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
46 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
47 SC_MANAGER_ALL_ACCESS
50 static const GENERIC_MAPPING g_svc_generic =
52 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
53 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
54 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
55 SERVICE_ALL_ACCESS
58 typedef enum
60 SC_HTYPE_DONT_CARE = 0,
61 SC_HTYPE_MANAGER,
62 SC_HTYPE_SERVICE
63 } SC_HANDLE_TYPE;
65 struct sc_handle
67 SC_HANDLE_TYPE type;
68 DWORD access;
71 struct sc_manager_handle /* service control manager handle */
73 struct sc_handle hdr;
74 struct scmdatabase *db;
77 struct sc_service_handle /* service handle */
79 struct sc_handle hdr;
80 struct service_entry *service_entry;
83 struct sc_lock
85 struct scmdatabase *db;
88 static CRITICAL_SECTION shutdown_cs;
89 static CRITICAL_SECTION_DEBUG critsect_debug =
91 0, 0, &shutdown_cs,
92 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": shutdown_cs") }
95 static CRITICAL_SECTION shutdown_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
96 static BOOL service_shutdown;
98 static PTP_CLEANUP_GROUP cleanup_group;
99 HANDLE exit_event;
101 static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
102 TP_WAIT *wait, TP_WAIT_RESULT result)
104 struct process_entry *process = context;
105 if (result == WAIT_TIMEOUT) process_terminate(process);
106 release_process(process);
108 /* synchronize with CloseThreadpoolCleanupGroupMembers */
109 EnterCriticalSection(&shutdown_cs);
110 if (!service_shutdown) CloseThreadpoolWait(wait);
111 LeaveCriticalSection(&shutdown_cs);
114 static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
116 TP_CALLBACK_ENVIRON environment;
117 LARGE_INTEGER timestamp;
118 TP_WAIT *wait;
119 FILETIME ft;
121 memset(&environment, 0, sizeof(environment));
122 environment.Version = 1;
123 environment.CleanupGroup = cleanup_group;
125 timestamp.QuadPart = (ULONGLONG)timeout * -10000;
126 ft.dwLowDateTime = timestamp.u.LowPart;
127 ft.dwHighDateTime = timestamp.u.HighPart;
129 if ((wait = CreateThreadpoolWait(terminate_callback, grab_process(process), &environment)))
130 SetThreadpoolWait(wait, process->process, &ft);
131 else
132 release_process(process);
135 static void free_service_strings(struct service_entry *old, struct service_entry *new)
137 QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
138 QUERY_SERVICE_CONFIGW *new_cfg = &new->config;
140 if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName)
141 HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName);
143 if (old_cfg->lpLoadOrderGroup != new_cfg->lpLoadOrderGroup)
144 HeapFree(GetProcessHeap(), 0, old_cfg->lpLoadOrderGroup);
146 if (old_cfg->lpServiceStartName != new_cfg->lpServiceStartName)
147 HeapFree(GetProcessHeap(), 0, old_cfg->lpServiceStartName);
149 if (old_cfg->lpDisplayName != new_cfg->lpDisplayName)
150 HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName);
152 if (old->dependOnServices != new->dependOnServices)
153 HeapFree(GetProcessHeap(), 0, old->dependOnServices);
155 if (old->dependOnGroups != new->dependOnGroups)
156 HeapFree(GetProcessHeap(), 0, old->dependOnGroups);
159 /* Check if the given handle is of the required type and allows the requested access. */
160 static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
162 struct sc_handle *hdr = handle;
164 if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
166 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
167 return ERROR_INVALID_HANDLE;
170 if ((needed_access & hdr->access) != needed_access)
172 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
173 return ERROR_ACCESS_DENIED;
176 *out_hdr = hdr;
177 return ERROR_SUCCESS;
180 static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
182 struct sc_handle *hdr;
183 DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
184 if (err == ERROR_SUCCESS)
185 *manager = (struct sc_manager_handle *)hdr;
186 return err;
189 static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
191 struct sc_handle *hdr;
192 DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
193 if (err == ERROR_SUCCESS)
194 *service = (struct sc_service_handle *)hdr;
195 return err;
198 DWORD __cdecl svcctl_OpenSCManagerW(
199 MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
200 LPCWSTR DatabaseName,
201 DWORD dwAccessMask,
202 SC_RPC_HANDLE *handle)
204 struct sc_manager_handle *manager;
206 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
208 if (DatabaseName != NULL && DatabaseName[0])
210 if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
211 return ERROR_DATABASE_DOES_NOT_EXIST;
212 if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
213 return ERROR_INVALID_NAME;
216 if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
217 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
219 manager->hdr.type = SC_HTYPE_MANAGER;
221 if (dwAccessMask & MAXIMUM_ALLOWED)
222 dwAccessMask |= SC_MANAGER_ALL_ACCESS;
223 manager->hdr.access = dwAccessMask;
224 RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
225 manager->db = active_database;
226 *handle = &manager->hdr;
228 return ERROR_SUCCESS;
231 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
233 struct sc_handle *hdr = handle;
234 switch (hdr->type)
236 case SC_HTYPE_MANAGER:
238 struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
239 HeapFree(GetProcessHeap(), 0, manager);
240 break;
242 case SC_HTYPE_SERVICE:
244 struct sc_service_handle *service = (struct sc_service_handle *)hdr;
245 release_service(service->service_entry);
246 HeapFree(GetProcessHeap(), 0, service);
247 break;
249 default:
250 WINE_ERR("invalid handle type %d\n", hdr->type);
251 RpcRaiseException(ERROR_INVALID_HANDLE);
255 DWORD __cdecl svcctl_GetServiceDisplayNameW(
256 SC_RPC_HANDLE hSCManager,
257 LPCWSTR lpServiceName,
258 WCHAR *lpBuffer,
259 DWORD *cchBufSize)
261 struct sc_manager_handle *manager;
262 struct service_entry *entry;
263 DWORD err;
265 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize);
267 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
268 return err;
270 scmdatabase_lock(manager->db);
272 entry = scmdatabase_find_service(manager->db, lpServiceName);
273 if (entry != NULL)
275 LPCWSTR name;
276 int len;
277 name = get_display_name(entry);
278 len = strlenW(name);
279 if (len <= *cchBufSize)
281 err = ERROR_SUCCESS;
282 memcpy(lpBuffer, name, (len + 1)*sizeof(*name));
284 else
285 err = ERROR_INSUFFICIENT_BUFFER;
286 *cchBufSize = len;
288 else
289 err = ERROR_SERVICE_DOES_NOT_EXIST;
291 scmdatabase_unlock(manager->db);
293 if (err != ERROR_SUCCESS)
294 lpBuffer[0] = 0;
296 return err;
299 DWORD __cdecl svcctl_GetServiceKeyNameW(
300 SC_RPC_HANDLE hSCManager,
301 LPCWSTR lpServiceDisplayName,
302 WCHAR *lpBuffer,
303 DWORD *cchBufSize)
305 struct service_entry *entry;
306 struct sc_manager_handle *manager;
307 DWORD err;
309 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize);
311 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
312 return err;
314 scmdatabase_lock(manager->db);
316 entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
317 if (entry != NULL)
319 int len;
320 len = strlenW(entry->name);
321 if (len <= *cchBufSize)
323 err = ERROR_SUCCESS;
324 memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name));
326 else
327 err = ERROR_INSUFFICIENT_BUFFER;
328 *cchBufSize = len;
330 else
331 err = ERROR_SERVICE_DOES_NOT_EXIST;
333 scmdatabase_unlock(manager->db);
335 if (err != ERROR_SUCCESS)
336 lpBuffer[0] = 0;
338 return err;
341 static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
343 struct sc_service_handle *service;
345 if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
347 release_service(entry);
348 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
351 if (dwDesiredAccess & MAXIMUM_ALLOWED)
352 dwDesiredAccess |= SERVICE_ALL_ACCESS;
354 service->hdr.type = SC_HTYPE_SERVICE;
355 service->hdr.access = dwDesiredAccess;
356 RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
357 service->service_entry = entry;
359 *phService = &service->hdr;
360 return ERROR_SUCCESS;
363 DWORD __cdecl svcctl_OpenServiceW(
364 SC_RPC_HANDLE hSCManager,
365 LPCWSTR lpServiceName,
366 DWORD dwDesiredAccess,
367 SC_RPC_HANDLE *phService)
369 struct sc_manager_handle *manager;
370 struct service_entry *entry;
371 DWORD err;
373 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
375 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
376 return err;
377 if (!validate_service_name(lpServiceName))
378 return ERROR_INVALID_NAME;
380 scmdatabase_lock(manager->db);
381 entry = grab_service(scmdatabase_find_service(manager->db, lpServiceName));
382 scmdatabase_unlock(manager->db);
384 if (entry == NULL)
385 return ERROR_SERVICE_DOES_NOT_EXIST;
387 return create_handle_for_service(entry, dwDesiredAccess, phService);
390 static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry)
392 WCHAR *services = NULL, *groups, *s;
393 DWORD len, len_services = 0, len_groups = 0;
394 const WCHAR *ptr = dependencies;
396 if (!dependencies || !dependencies[0])
398 entry->dependOnServices = NULL;
399 entry->dependOnGroups = NULL;
400 return ERROR_SUCCESS;
403 while (*ptr)
405 len = strlenW(ptr) + 1;
406 if (ptr[0] == '+' && ptr[1])
407 len_groups += len - 1;
408 else
409 len_services += len;
410 ptr += len;
412 if (!len_services) entry->dependOnServices = NULL;
413 else
415 services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR));
416 if (!services)
417 return ERROR_OUTOFMEMORY;
419 s = services;
420 ptr = dependencies;
421 while (*ptr)
423 len = strlenW(ptr) + 1;
424 if (*ptr != '+')
426 strcpyW(s, ptr);
427 s += len;
429 ptr += len;
431 *s = 0;
432 entry->dependOnServices = services;
434 if (!len_groups) entry->dependOnGroups = NULL;
435 else
437 groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR));
438 if (!groups)
440 HeapFree(GetProcessHeap(), 0, services);
441 return ERROR_OUTOFMEMORY;
443 s = groups;
444 ptr = dependencies;
445 while (*ptr)
447 len = strlenW(ptr) + 1;
448 if (ptr[0] == '+' && ptr[1])
450 strcpyW(s, ptr + 1);
451 s += len - 1;
453 ptr += len;
455 *s = 0;
456 entry->dependOnGroups = groups;
459 return ERROR_SUCCESS;
462 static DWORD create_serviceW(
463 SC_RPC_HANDLE hSCManager,
464 LPCWSTR lpServiceName,
465 LPCWSTR lpDisplayName,
466 DWORD dwDesiredAccess,
467 DWORD dwServiceType,
468 DWORD dwStartType,
469 DWORD dwErrorControl,
470 LPCWSTR lpBinaryPathName,
471 LPCWSTR lpLoadOrderGroup,
472 DWORD *lpdwTagId,
473 const BYTE *lpDependencies,
474 DWORD dwDependenciesSize,
475 LPCWSTR lpServiceStartName,
476 const BYTE *lpPassword,
477 DWORD dwPasswordSize,
478 SC_RPC_HANDLE *phService,
479 BOOL is_wow64)
481 struct service_entry *entry, *found;
482 struct sc_manager_handle *manager;
483 DWORD err;
485 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
487 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
488 return err;
490 if (!validate_service_name(lpServiceName))
491 return ERROR_INVALID_NAME;
492 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
493 return ERROR_INVALID_PARAMETER;
495 if (lpPassword)
496 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
498 err = service_create(lpServiceName, &entry);
499 if (err != ERROR_SUCCESS)
500 return err;
502 err = parse_dependencies((LPCWSTR)lpDependencies, entry);
503 if (err != ERROR_SUCCESS) {
504 free_service_entry(entry);
505 return err;
508 entry->is_wow64 = is_wow64;
509 entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType;
510 entry->config.dwStartType = dwStartType;
511 entry->config.dwErrorControl = dwErrorControl;
512 entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
513 entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
514 entry->config.lpServiceStartName = strdupW(lpServiceStartName);
515 entry->config.lpDisplayName = strdupW(lpDisplayName);
517 if (lpdwTagId) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
518 entry->config.dwTagId = *lpdwTagId;
519 else
520 entry->config.dwTagId = 0;
522 /* other fields NULL*/
524 if (!validate_service_config(entry))
526 WINE_ERR("Invalid data while trying to create service\n");
527 free_service_entry(entry);
528 return ERROR_INVALID_PARAMETER;
531 scmdatabase_lock(manager->db);
533 if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
535 err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
536 scmdatabase_unlock(manager->db);
537 free_service_entry(entry);
538 return err;
541 if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
543 scmdatabase_unlock(manager->db);
544 free_service_entry(entry);
545 return ERROR_DUPLICATE_SERVICE_NAME;
548 err = scmdatabase_add_service(manager->db, entry);
549 if (err != ERROR_SUCCESS)
551 scmdatabase_unlock(manager->db);
552 free_service_entry(entry);
553 return err;
555 scmdatabase_unlock(manager->db);
557 return create_handle_for_service(entry, dwDesiredAccess, phService);
560 DWORD __cdecl svcctl_CreateServiceW(
561 SC_RPC_HANDLE hSCManager,
562 LPCWSTR lpServiceName,
563 LPCWSTR lpDisplayName,
564 DWORD dwDesiredAccess,
565 DWORD dwServiceType,
566 DWORD dwStartType,
567 DWORD dwErrorControl,
568 LPCWSTR lpBinaryPathName,
569 LPCWSTR lpLoadOrderGroup,
570 DWORD *lpdwTagId,
571 const BYTE *lpDependencies,
572 DWORD dwDependenciesSize,
573 LPCWSTR lpServiceStartName,
574 const BYTE *lpPassword,
575 DWORD dwPasswordSize,
576 SC_RPC_HANDLE *phService)
578 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
579 return create_serviceW(hSCManager, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType,
580 dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, dwDependenciesSize, lpServiceStartName,
581 lpPassword, dwPasswordSize, phService, FALSE);
584 DWORD __cdecl svcctl_DeleteService(
585 SC_RPC_HANDLE hService)
587 struct sc_service_handle *service;
588 DWORD err;
590 if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
591 return err;
593 service_lock(service->service_entry);
595 if (!is_marked_for_delete(service->service_entry))
596 err = mark_for_delete(service->service_entry);
597 else
598 err = ERROR_SERVICE_MARKED_FOR_DELETE;
600 service_unlock(service->service_entry);
602 return err;
605 DWORD __cdecl svcctl_QueryServiceConfigW(
606 SC_RPC_HANDLE hService,
607 QUERY_SERVICE_CONFIGW *config,
608 DWORD buf_size,
609 DWORD *needed_size)
611 struct sc_service_handle *service;
612 DWORD err;
614 WINE_TRACE("(%p)\n", config);
616 if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
617 return err;
619 service_lock(service->service_entry);
620 config->dwServiceType = service->service_entry->config.dwServiceType;
621 config->dwStartType = service->service_entry->config.dwStartType;
622 config->dwErrorControl = service->service_entry->config.dwErrorControl;
623 config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
624 config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
625 config->dwTagId = service->service_entry->config.dwTagId;
626 config->lpDependencies = NULL; /* TODO */
627 config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
628 config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
629 service_unlock(service->service_entry);
631 return ERROR_SUCCESS;
634 DWORD __cdecl svcctl_ChangeServiceConfigW(
635 SC_RPC_HANDLE hService,
636 DWORD dwServiceType,
637 DWORD dwStartType,
638 DWORD dwErrorControl,
639 LPCWSTR lpBinaryPathName,
640 LPCWSTR lpLoadOrderGroup,
641 DWORD *lpdwTagId,
642 const BYTE *lpDependencies,
643 DWORD dwDependenciesSize,
644 LPCWSTR lpServiceStartName,
645 const BYTE *lpPassword,
646 DWORD dwPasswordSize,
647 LPCWSTR lpDisplayName)
649 struct service_entry new_entry, *entry;
650 struct sc_service_handle *service;
651 DWORD err;
653 WINE_TRACE("\n");
655 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
656 return err;
658 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
659 return ERROR_INVALID_PARAMETER;
661 /* first check if the new configuration is correct */
662 service_lock(service->service_entry);
664 if (is_marked_for_delete(service->service_entry))
666 service_unlock(service->service_entry);
667 return ERROR_SERVICE_MARKED_FOR_DELETE;
670 if (lpDisplayName != NULL &&
671 (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
672 (entry != service->service_entry))
674 service_unlock(service->service_entry);
675 return ERROR_DUPLICATE_SERVICE_NAME;
678 new_entry = *service->service_entry;
680 if (dwServiceType != SERVICE_NO_CHANGE)
681 new_entry.config.dwServiceType = dwServiceType;
683 if (dwStartType != SERVICE_NO_CHANGE)
684 new_entry.config.dwStartType = dwStartType;
686 if (dwErrorControl != SERVICE_NO_CHANGE)
687 new_entry.config.dwErrorControl = dwErrorControl;
689 if (lpBinaryPathName != NULL)
690 new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
692 if (lpLoadOrderGroup != NULL)
693 new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
695 if (lpdwTagId != NULL)
696 WINE_FIXME("Changing tag id not supported\n");
698 if (lpServiceStartName != NULL)
699 new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
701 if (lpPassword != NULL)
702 WINE_FIXME("Setting password not supported\n");
704 if (lpDisplayName != NULL)
705 new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
707 err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry);
708 if (err != ERROR_SUCCESS)
710 service_unlock(service->service_entry);
711 return err;
714 if (!validate_service_config(&new_entry))
716 WINE_ERR("The configuration after the change wouldn't be valid\n");
717 service_unlock(service->service_entry);
718 return ERROR_INVALID_PARAMETER;
721 /* configuration OK. The strings needs to be duplicated */
722 if (lpBinaryPathName != NULL)
723 new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
725 if (lpLoadOrderGroup != NULL)
726 new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
728 if (lpServiceStartName != NULL)
729 new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
731 if (lpDisplayName != NULL)
732 new_entry.config.lpDisplayName = strdupW(lpDisplayName);
734 /* try to save to Registry, commit or rollback depending on success */
735 err = save_service_config(&new_entry);
736 if (ERROR_SUCCESS == err)
738 free_service_strings(service->service_entry, &new_entry);
739 *service->service_entry = new_entry;
741 else free_service_strings(&new_entry, service->service_entry);
742 service_unlock(service->service_entry);
744 return err;
747 DWORD __cdecl svcctl_SetServiceStatus(
748 SC_RPC_HANDLE hServiceStatus,
749 LPSERVICE_STATUS lpServiceStatus)
751 struct sc_service_handle *service;
752 struct process_entry *process;
753 DWORD err;
755 WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
757 if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
758 return err;
760 service_lock(service->service_entry);
761 /* FIXME: be a bit more discriminant about what parts of the status we set
762 * and check that fields are valid */
763 service->service_entry->status = *lpServiceStatus;
764 if ((process = service->service_entry->process))
766 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
768 service->service_entry->process = NULL;
769 if (!--process->use_count)
770 terminate_after_timeout(process, service_kill_timeout);
771 release_process(process);
773 else
774 SetEvent(process->status_changed_event);
776 service_unlock(service->service_entry);
778 return ERROR_SUCCESS;
781 DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFIG_INFOW config )
783 struct sc_service_handle *service;
784 DWORD err;
786 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
787 return err;
789 switch (config.dwInfoLevel)
791 case SERVICE_CONFIG_DESCRIPTION:
793 WCHAR *descr = NULL;
795 if (config.u.descr->lpDescription[0])
797 if (!(descr = strdupW( config.u.descr->lpDescription )))
798 return ERROR_NOT_ENOUGH_MEMORY;
801 WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
802 service_lock( service->service_entry );
803 HeapFree( GetProcessHeap(), 0, service->service_entry->description );
804 service->service_entry->description = descr;
805 save_service_config( service->service_entry );
806 service_unlock( service->service_entry );
808 break;
809 case SERVICE_CONFIG_FAILURE_ACTIONS:
810 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
811 config.u.actions->dwResetPeriod,
812 wine_dbgstr_w(config.u.actions->lpRebootMsg),
813 wine_dbgstr_w(config.u.actions->lpCommand) );
814 break;
815 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
816 WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
817 service, config.u.preshutdown->dwPreshutdownTimeout );
818 service_lock( service->service_entry );
819 service->service_entry->preshutdown_timeout = config.u.preshutdown->dwPreshutdownTimeout;
820 save_service_config( service->service_entry );
821 service_unlock( service->service_entry );
822 break;
823 default:
824 WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
825 err = ERROR_INVALID_LEVEL;
826 break;
828 return err;
831 DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
832 BYTE *buffer, DWORD size, LPDWORD needed )
834 struct sc_service_handle *service;
835 DWORD err;
837 memset(buffer, 0, size);
839 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
840 return err;
842 switch (level)
844 case SERVICE_CONFIG_DESCRIPTION:
846 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
848 service_lock(service->service_entry);
849 *needed = sizeof(*descr);
850 if (service->service_entry->description)
851 *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
852 if (size >= *needed)
854 if (service->service_entry->description)
856 /* store a buffer offset instead of a pointer */
857 descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer);
858 strcpyW( (WCHAR *)(descr + 1), service->service_entry->description );
860 else descr->lpDescription = NULL;
862 else err = ERROR_INSUFFICIENT_BUFFER;
863 service_unlock(service->service_entry);
865 break;
867 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
868 service_lock(service->service_entry);
870 *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
871 if (size >= *needed)
872 ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
873 service->service_entry->preshutdown_timeout;
874 else err = ERROR_INSUFFICIENT_BUFFER;
876 service_unlock(service->service_entry);
877 break;
879 default:
880 WINE_FIXME("level %u not implemented\n", level);
881 err = ERROR_INVALID_LEVEL;
882 break;
884 return err;
887 static void fill_status_process(SERVICE_STATUS_PROCESS *status, struct service_entry *service)
889 struct process_entry *process = service->process;
890 memcpy(status, &service->status, sizeof(service->status));
891 status->dwProcessId = process ? process->process_id : 0;
892 status->dwServiceFlags = 0;
895 DWORD __cdecl svcctl_QueryServiceStatusEx(
896 SC_RPC_HANDLE hService,
897 SC_STATUS_TYPE InfoLevel,
898 BYTE *lpBuffer,
899 DWORD cbBufSize,
900 LPDWORD pcbBytesNeeded)
902 struct sc_service_handle *service;
903 DWORD err;
904 LPSERVICE_STATUS_PROCESS pSvcStatusData;
906 memset(lpBuffer, 0, cbBufSize);
908 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
909 return err;
911 if (InfoLevel != SC_STATUS_PROCESS_INFO)
912 return ERROR_INVALID_LEVEL;
914 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
915 if (pSvcStatusData == NULL)
916 return ERROR_INVALID_PARAMETER;
918 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
920 if( pcbBytesNeeded != NULL)
921 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
923 return ERROR_INSUFFICIENT_BUFFER;
926 service_lock(service->service_entry);
927 fill_status_process(pSvcStatusData, service->service_entry);
928 service_unlock(service->service_entry);
930 return ERROR_SUCCESS;
933 /******************************************************************************
934 * service_accepts_control
936 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
938 DWORD a = service->status.dwControlsAccepted;
940 if (dwControl >= 128 && dwControl <= 255)
941 return TRUE;
943 switch (dwControl)
945 case SERVICE_CONTROL_INTERROGATE:
946 return TRUE;
947 case SERVICE_CONTROL_STOP:
948 if (a&SERVICE_ACCEPT_STOP)
949 return TRUE;
950 break;
951 case SERVICE_CONTROL_SHUTDOWN:
952 if (a&SERVICE_ACCEPT_SHUTDOWN)
953 return TRUE;
954 break;
955 case SERVICE_CONTROL_PAUSE:
956 case SERVICE_CONTROL_CONTINUE:
957 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
958 return TRUE;
959 break;
960 case SERVICE_CONTROL_PARAMCHANGE:
961 if (a&SERVICE_ACCEPT_PARAMCHANGE)
962 return TRUE;
963 break;
964 case SERVICE_CONTROL_NETBINDADD:
965 case SERVICE_CONTROL_NETBINDREMOVE:
966 case SERVICE_CONTROL_NETBINDENABLE:
967 case SERVICE_CONTROL_NETBINDDISABLE:
968 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
969 return TRUE;
970 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
971 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
972 return TRUE;
973 break;
974 case SERVICE_CONTROL_POWEREVENT:
975 if (a&SERVICE_ACCEPT_POWEREVENT)
976 return TRUE;
977 break;
978 case SERVICE_CONTROL_SESSIONCHANGE:
979 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
980 return TRUE;
981 break;
983 return FALSE;
986 /******************************************************************************
987 * process_send_command
989 BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
991 OVERLAPPED overlapped;
992 DWORD count, ret;
993 BOOL r;
995 overlapped.hEvent = process->overlapped_event;
996 r = WriteFile(process->control_pipe, data, size, &count, &overlapped);
997 if (!r && GetLastError() == ERROR_IO_PENDING)
999 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1000 if (ret == WAIT_TIMEOUT)
1002 WINE_ERR("sending command timed out\n");
1003 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1004 return FALSE;
1006 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1008 if (!r || count != size)
1010 WINE_ERR("service protocol error - failed to write pipe!\n");
1011 *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
1012 return FALSE;
1014 r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped);
1015 if (!r && GetLastError() == ERROR_IO_PENDING)
1017 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1018 if (ret == WAIT_TIMEOUT)
1020 WINE_ERR("receiving command result timed out\n");
1021 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1022 return FALSE;
1024 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1026 if (!r || count != sizeof *result)
1028 WINE_ERR("service protocol error - failed to read pipe "
1029 "r = %d count = %d!\n", r, count);
1030 *result = (!r ? GetLastError() : ERROR_READ_FAULT);
1031 return FALSE;
1034 return TRUE;
1037 /******************************************************************************
1038 * process_send_control
1040 static BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
1041 const BYTE *data, DWORD data_size, DWORD *result)
1043 service_start_info *ssi;
1044 DWORD len;
1045 BOOL r;
1047 /* calculate how much space we need to send the startup info */
1048 len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size;
1050 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
1051 ssi->cmd = WINESERV_SENDCONTROL;
1052 ssi->control = control;
1053 ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
1054 ssi->name_size = strlenW(name) + 1;
1055 strcpyW((WCHAR *)ssi->data, name);
1056 if (data_size) memcpy(&ssi->data[ssi->name_size * sizeof(WCHAR)], data, data_size);
1058 r = process_send_command(process, ssi, ssi->total_size, result);
1059 HeapFree( GetProcessHeap(), 0, ssi );
1060 return r;
1063 DWORD __cdecl svcctl_StartServiceW(
1064 SC_RPC_HANDLE hService,
1065 DWORD dwNumServiceArgs,
1066 LPCWSTR *lpServiceArgVectors)
1068 struct sc_service_handle *service;
1069 DWORD err;
1071 WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1073 if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
1074 return err;
1076 if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
1077 return ERROR_SERVICE_DISABLED;
1079 if (!scmdatabase_lock_startup(service->service_entry->db))
1080 return ERROR_SERVICE_DATABASE_LOCKED;
1082 err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
1084 scmdatabase_unlock_startup(service->service_entry->db);
1085 return err;
1088 DWORD __cdecl svcctl_ControlService(
1089 SC_RPC_HANDLE hService,
1090 DWORD dwControl,
1091 SERVICE_STATUS *lpServiceStatus)
1093 DWORD access_required;
1094 struct sc_service_handle *service;
1095 struct process_entry *process;
1096 DWORD result;
1098 WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
1100 switch (dwControl)
1102 case SERVICE_CONTROL_CONTINUE:
1103 case SERVICE_CONTROL_NETBINDADD:
1104 case SERVICE_CONTROL_NETBINDDISABLE:
1105 case SERVICE_CONTROL_NETBINDENABLE:
1106 case SERVICE_CONTROL_NETBINDREMOVE:
1107 case SERVICE_CONTROL_PARAMCHANGE:
1108 case SERVICE_CONTROL_PAUSE:
1109 access_required = SERVICE_PAUSE_CONTINUE;
1110 break;
1111 case SERVICE_CONTROL_INTERROGATE:
1112 access_required = SERVICE_INTERROGATE;
1113 break;
1114 case SERVICE_CONTROL_STOP:
1115 access_required = SERVICE_STOP;
1116 break;
1117 default:
1118 if (dwControl >= 128 && dwControl <= 255)
1119 access_required = SERVICE_USER_DEFINED_CONTROL;
1120 else
1121 return ERROR_INVALID_PARAMETER;
1124 if ((result = validate_service_handle(hService, access_required, &service)) != 0)
1125 return result;
1127 service_lock(service->service_entry);
1129 result = ERROR_SUCCESS;
1130 switch (service->service_entry->status.dwCurrentState)
1132 case SERVICE_STOPPED:
1133 result = ERROR_SERVICE_NOT_ACTIVE;
1134 break;
1135 case SERVICE_START_PENDING:
1136 if (dwControl==SERVICE_CONTROL_STOP)
1137 break;
1138 /* fall through */
1139 case SERVICE_STOP_PENDING:
1140 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1141 break;
1144 if (result == ERROR_SUCCESS && service->service_entry->force_shutdown)
1146 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1147 if ((process = service->service_entry->process))
1149 service->service_entry->process = NULL;
1150 if (!--process->use_count) process_terminate(process);
1151 release_process(process);
1155 if (result != ERROR_SUCCESS)
1157 if (lpServiceStatus) *lpServiceStatus = service->service_entry->status;
1158 service_unlock(service->service_entry);
1159 return result;
1162 if (!service_accepts_control(service->service_entry, dwControl))
1164 service_unlock(service->service_entry);
1165 return ERROR_INVALID_SERVICE_CONTROL;
1168 /* Remember that we tried to shutdown this service. When the service is
1169 * still running on the second invocation, it will be forcefully killed. */
1170 if (dwControl == SERVICE_CONTROL_STOP)
1171 service->service_entry->force_shutdown = TRUE;
1173 /* Hold a reference to the process while sending the command. */
1174 process = grab_process(service->service_entry->process);
1175 service_unlock(service->service_entry);
1177 if (!process)
1178 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1180 result = WaitForSingleObject(process->control_mutex, 30000);
1181 if (result != WAIT_OBJECT_0)
1183 release_process(process);
1184 return ERROR_SERVICE_REQUEST_TIMEOUT;
1187 if (process_send_control(process, service->service_entry->name, dwControl, NULL, 0, &result))
1188 result = ERROR_SUCCESS;
1190 if (lpServiceStatus)
1192 service_lock(service->service_entry);
1193 *lpServiceStatus = service->service_entry->status;
1194 service_unlock(service->service_entry);
1197 ReleaseMutex(process->control_mutex);
1198 release_process(process);
1199 return result;
1202 DWORD __cdecl svcctl_CloseServiceHandle(
1203 SC_RPC_HANDLE *handle)
1205 WINE_TRACE("(&%p)\n", *handle);
1207 SC_RPC_HANDLE_destroy(*handle);
1208 *handle = NULL;
1210 return ERROR_SUCCESS;
1213 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
1215 struct sc_lock *lock = hLock;
1216 scmdatabase_unlock_startup(lock->db);
1217 HeapFree(GetProcessHeap(), 0, lock);
1220 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
1222 SC_RPC_LOCK_destroy(hLock);
1225 DWORD __cdecl svcctl_LockServiceDatabase(
1226 SC_RPC_HANDLE hSCManager,
1227 SC_RPC_LOCK *phLock)
1229 struct sc_manager_handle *manager;
1230 struct sc_lock *lock;
1231 DWORD err;
1233 WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
1235 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
1236 return err;
1238 if (!scmdatabase_lock_startup(manager->db))
1239 return ERROR_SERVICE_DATABASE_LOCKED;
1241 lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
1242 if (!lock)
1244 scmdatabase_unlock_startup(manager->db);
1245 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
1248 lock->db = manager->db;
1249 *phLock = lock;
1251 return ERROR_SUCCESS;
1254 DWORD __cdecl svcctl_UnlockServiceDatabase(
1255 SC_RPC_LOCK *phLock)
1257 WINE_TRACE("(&%p)\n", *phLock);
1259 SC_RPC_LOCK_destroy(*phLock);
1260 *phLock = NULL;
1262 return ERROR_SUCCESS;
1265 static BOOL map_state(DWORD state, DWORD mask)
1267 switch (state)
1269 case SERVICE_START_PENDING:
1270 case SERVICE_STOP_PENDING:
1271 case SERVICE_RUNNING:
1272 case SERVICE_CONTINUE_PENDING:
1273 case SERVICE_PAUSE_PENDING:
1274 case SERVICE_PAUSED:
1275 if (SERVICE_ACTIVE & mask) return TRUE;
1276 break;
1277 case SERVICE_STOPPED:
1278 if (SERVICE_INACTIVE & mask) return TRUE;
1279 break;
1280 default:
1281 WINE_ERR("unknown state %u\n", state);
1282 break;
1284 return FALSE;
1287 DWORD __cdecl svcctl_EnumServicesStatusW(
1288 SC_RPC_HANDLE hmngr,
1289 DWORD type,
1290 DWORD state,
1291 BYTE *buffer,
1292 DWORD size,
1293 LPDWORD needed,
1294 LPDWORD returned,
1295 LPDWORD resume)
1297 DWORD err, sz, total_size, num_services;
1298 DWORD_PTR offset;
1299 struct sc_manager_handle *manager;
1300 struct service_entry *service;
1301 ENUM_SERVICE_STATUSW *s;
1303 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
1305 if (!type || !state)
1306 return ERROR_INVALID_PARAMETER;
1308 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1309 return err;
1311 if (resume)
1312 WINE_FIXME("resume index not supported\n");
1314 scmdatabase_lock(manager->db);
1316 total_size = num_services = 0;
1317 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1319 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1321 total_size += sizeof(ENUM_SERVICE_STATUSW);
1322 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1323 if (service->config.lpDisplayName)
1325 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1327 num_services++;
1330 *returned = 0;
1331 *needed = total_size;
1332 if (total_size > size)
1334 scmdatabase_unlock(manager->db);
1335 return ERROR_MORE_DATA;
1337 s = (ENUM_SERVICE_STATUSW *)buffer;
1338 offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
1339 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1341 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1343 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1344 memcpy(buffer + offset, service->name, sz);
1345 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1346 offset += sz;
1348 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1349 else
1351 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1352 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1353 s->lpDisplayName = (WCHAR *)offset;
1354 offset += sz;
1356 s->ServiceStatus = service->status;
1357 s++;
1360 *returned = num_services;
1361 *needed = 0;
1362 scmdatabase_unlock(manager->db);
1363 return ERROR_SUCCESS;
1366 static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
1368 struct service_entry *service;
1369 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
1371 if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
1372 return service;
1374 return NULL;
1377 static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
1379 if (!g2) return TRUE;
1380 if (!g2[0] && (!g1 || !g1[0])) return TRUE;
1381 if (g1 && !strcmpW(g1, g2)) return TRUE;
1382 return FALSE;
1385 DWORD __cdecl svcctl_EnumServicesStatusExA(
1386 SC_RPC_HANDLE scmanager,
1387 SC_ENUM_TYPE info_level,
1388 DWORD service_type,
1389 DWORD service_state,
1390 BYTE *buffer,
1391 DWORD buf_size,
1392 DWORD *needed_size,
1393 DWORD *services_count,
1394 DWORD *resume_index,
1395 LPCSTR groupname)
1397 WINE_FIXME("\n");
1398 return ERROR_CALL_NOT_IMPLEMENTED;
1401 DWORD __cdecl svcctl_EnumServicesStatusExW(
1402 SC_RPC_HANDLE hmngr,
1403 SC_ENUM_TYPE info_level,
1404 DWORD type,
1405 DWORD state,
1406 BYTE *buffer,
1407 DWORD size,
1408 LPDWORD needed,
1409 LPDWORD returned,
1410 DWORD *resume_handle,
1411 LPCWSTR group)
1413 DWORD err, sz, total_size, num_services;
1414 DWORD_PTR offset;
1415 struct sc_manager_handle *manager;
1416 struct service_entry *service;
1417 ENUM_SERVICE_STATUS_PROCESSW *s;
1419 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
1420 needed, returned, wine_dbgstr_w(group));
1422 if (resume_handle)
1423 FIXME("resume handle not supported\n");
1425 if (!type || !state)
1426 return ERROR_INVALID_PARAMETER;
1428 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1429 return err;
1431 scmdatabase_lock(manager->db);
1433 if (group && !find_service_by_group(manager->db, group))
1435 scmdatabase_unlock(manager->db);
1436 return ERROR_SERVICE_DOES_NOT_EXIST;
1439 total_size = num_services = 0;
1440 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1442 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1443 && match_group(service->config.lpLoadOrderGroup, group))
1445 total_size += sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1446 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1447 if (service->config.lpDisplayName)
1449 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1451 num_services++;
1454 *returned = 0;
1455 *needed = total_size;
1456 if (total_size > size)
1458 scmdatabase_unlock(manager->db);
1459 return ERROR_MORE_DATA;
1461 s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1462 offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1463 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1465 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1466 && match_group(service->config.lpLoadOrderGroup, group))
1468 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1469 memcpy(buffer + offset, service->name, sz);
1470 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1471 offset += sz;
1473 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1474 else
1476 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1477 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1478 s->lpDisplayName = (WCHAR *)offset;
1479 offset += sz;
1481 fill_status_process(&s->ServiceStatusProcess, service);
1482 s++;
1485 *returned = num_services;
1486 *needed = 0;
1487 scmdatabase_unlock(manager->db);
1488 return ERROR_SUCCESS;
1491 DWORD __cdecl svcctl_unknown43(void)
1493 WINE_FIXME("\n");
1494 return ERROR_CALL_NOT_IMPLEMENTED;
1497 DWORD __cdecl svcctl_CreateServiceWOW64A(
1498 SC_RPC_HANDLE scmanager,
1499 LPCSTR servicename,
1500 LPCSTR displayname,
1501 DWORD accessmask,
1502 DWORD service_type,
1503 DWORD start_type,
1504 DWORD error_control,
1505 LPCSTR imagepath,
1506 LPCSTR loadordergroup,
1507 DWORD *tagid,
1508 const BYTE *dependencies,
1509 DWORD depend_size,
1510 LPCSTR start_name,
1511 const BYTE *password,
1512 DWORD password_size,
1513 SC_RPC_HANDLE *service)
1515 WINE_FIXME("\n");
1516 return ERROR_CALL_NOT_IMPLEMENTED;
1519 DWORD __cdecl svcctl_CreateServiceWOW64W(
1520 SC_RPC_HANDLE scmanager,
1521 LPCWSTR servicename,
1522 LPCWSTR displayname,
1523 DWORD accessmask,
1524 DWORD service_type,
1525 DWORD start_type,
1526 DWORD error_control,
1527 LPCWSTR imagepath,
1528 LPCWSTR loadordergroup,
1529 DWORD *tagid,
1530 const BYTE *dependencies,
1531 DWORD depend_size,
1532 LPCWSTR start_name,
1533 const BYTE *password,
1534 DWORD password_size,
1535 SC_RPC_HANDLE *service)
1537 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
1538 return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
1539 loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
1542 DWORD __cdecl svcctl_unknown46(void)
1544 WINE_FIXME("\n");
1545 return ERROR_CALL_NOT_IMPLEMENTED;
1548 DWORD __cdecl svcctl_NotifyServiceStatusChange(
1549 SC_RPC_HANDLE service,
1550 SC_RPC_NOTIFY_PARAMS params,
1551 GUID *clientprocessguid,
1552 GUID *scmprocessguid,
1553 BOOL *createremotequeue,
1554 SC_NOTIFY_RPC_HANDLE *notify)
1556 WINE_FIXME("\n");
1557 return ERROR_CALL_NOT_IMPLEMENTED;
1560 DWORD __cdecl svcctl_GetNotifyResults(
1561 SC_NOTIFY_RPC_HANDLE notify,
1562 SC_RPC_NOTIFY_PARAMS_LIST **params)
1564 WINE_FIXME("\n");
1565 return ERROR_CALL_NOT_IMPLEMENTED;
1568 DWORD __cdecl svcctl_CloseNotifyHandle(
1569 SC_NOTIFY_RPC_HANDLE *notify,
1570 BOOL *apc_fired)
1572 WINE_FIXME("\n");
1573 return ERROR_CALL_NOT_IMPLEMENTED;
1576 DWORD __cdecl svcctl_ControlServiceExA(
1577 SC_RPC_HANDLE service,
1578 DWORD control,
1579 DWORD info_level,
1580 SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
1581 SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
1583 WINE_FIXME("\n");
1584 return ERROR_CALL_NOT_IMPLEMENTED;
1587 DWORD __cdecl svcctl_ControlServiceExW(
1588 SC_RPC_HANDLE service,
1589 DWORD control,
1590 DWORD info_level,
1591 SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
1592 SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
1594 WINE_FIXME("\n");
1595 return ERROR_CALL_NOT_IMPLEMENTED;
1598 DWORD __cdecl svcctl_unknown52(void)
1600 WINE_FIXME("\n");
1601 return ERROR_CALL_NOT_IMPLEMENTED;
1604 DWORD __cdecl svcctl_unknown53(void)
1606 WINE_FIXME("\n");
1607 return ERROR_CALL_NOT_IMPLEMENTED;
1610 DWORD __cdecl svcctl_unknown54(void)
1612 WINE_FIXME("\n");
1613 return ERROR_CALL_NOT_IMPLEMENTED;
1616 DWORD __cdecl svcctl_unknown55(void)
1618 WINE_FIXME("\n");
1619 return ERROR_CALL_NOT_IMPLEMENTED;
1622 DWORD __cdecl svcctl_QueryServiceConfigEx(
1623 SC_RPC_HANDLE service,
1624 DWORD info_level,
1625 SC_RPC_CONFIG_INFOW *info)
1627 WINE_FIXME("\n");
1628 return ERROR_CALL_NOT_IMPLEMENTED;
1631 DWORD __cdecl svcctl_QueryServiceObjectSecurity(
1632 SC_RPC_HANDLE service,
1633 SECURITY_INFORMATION info,
1634 BYTE *descriptor,
1635 DWORD buf_size,
1636 DWORD *needed_size)
1638 WINE_FIXME("\n");
1639 return ERROR_CALL_NOT_IMPLEMENTED;
1642 DWORD __cdecl svcctl_SetServiceObjectSecurity(
1643 SC_RPC_HANDLE service,
1644 SECURITY_INFORMATION info,
1645 BYTE *descriptor,
1646 DWORD buf_size)
1648 WINE_FIXME("\n");
1649 return ERROR_CALL_NOT_IMPLEMENTED;
1652 DWORD __cdecl svcctl_QueryServiceStatus(
1653 SC_RPC_HANDLE service,
1654 SERVICE_STATUS *status)
1656 WINE_FIXME("\n");
1657 return ERROR_CALL_NOT_IMPLEMENTED;
1660 DWORD __cdecl svcctl_NotifyBootConfigStatus(
1661 SVCCTL_HANDLEW machinename,
1662 DWORD boot_acceptable)
1664 WINE_FIXME("\n");
1665 return ERROR_CALL_NOT_IMPLEMENTED;
1668 DWORD __cdecl svcctl_SCSetServiceBitsW(void)
1670 WINE_FIXME("\n");
1671 return ERROR_CALL_NOT_IMPLEMENTED;
1674 DWORD __cdecl svcctl_EnumDependentServicesW(
1675 SC_RPC_HANDLE service,
1676 DWORD state,
1677 BYTE *services,
1678 DWORD buf_size,
1679 DWORD *needed_size,
1680 DWORD *services_ret)
1682 WINE_FIXME("\n");
1683 return ERROR_CALL_NOT_IMPLEMENTED;
1686 DWORD __cdecl svcctl_QueryServiceLockStatusW(
1687 SC_RPC_HANDLE scmanager,
1688 QUERY_SERVICE_LOCK_STATUSW *status,
1689 DWORD buf_size,
1690 DWORD *needed_size)
1692 WINE_FIXME("\n");
1693 return ERROR_CALL_NOT_IMPLEMENTED;
1696 DWORD __cdecl svcctl_SCSetServiceBitsA(void)
1698 WINE_FIXME("\n");
1699 return ERROR_CALL_NOT_IMPLEMENTED;
1702 DWORD __cdecl svcctl_ChangeServiceConfigA(
1703 SC_RPC_HANDLE service,
1704 DWORD service_type,
1705 DWORD start_type,
1706 DWORD error_control,
1707 LPSTR binarypath,
1708 LPSTR loadordergroup,
1709 DWORD *tagid,
1710 BYTE *dependencies,
1711 DWORD depend_size,
1712 LPSTR startname,
1713 BYTE *password,
1714 DWORD password_size,
1715 LPSTR displayname)
1717 WINE_FIXME("\n");
1718 return ERROR_CALL_NOT_IMPLEMENTED;
1721 DWORD __cdecl svcctl_CreateServiceA(
1722 SC_RPC_HANDLE scmanager,
1723 LPCSTR servicename,
1724 LPCSTR displayname,
1725 DWORD desiredaccess,
1726 DWORD service_type,
1727 DWORD start_type,
1728 DWORD error_control,
1729 LPCSTR binarypath,
1730 LPCSTR loadordergroup,
1731 DWORD *tagid,
1732 const BYTE *dependencies,
1733 DWORD depend_size,
1734 LPCSTR startname,
1735 const BYTE *password,
1736 DWORD password_size,
1737 SC_RPC_HANDLE *service)
1739 WINE_FIXME("\n");
1740 return ERROR_CALL_NOT_IMPLEMENTED;
1743 DWORD __cdecl svcctl_EnumDependentServicesA(
1744 SC_RPC_HANDLE service,
1745 DWORD state,
1746 BYTE *services,
1747 DWORD buf_size,
1748 DWORD *needed_size,
1749 DWORD *services_ret)
1751 WINE_FIXME("\n");
1752 return ERROR_CALL_NOT_IMPLEMENTED;
1755 DWORD __cdecl svcctl_EnumServicesStatusA(
1756 SC_RPC_HANDLE hmngr,
1757 DWORD type,
1758 DWORD state,
1759 BYTE *buffer,
1760 DWORD size,
1761 DWORD *needed,
1762 DWORD *returned,
1763 DWORD *resume)
1765 WINE_FIXME("\n");
1766 return ERROR_CALL_NOT_IMPLEMENTED;
1769 DWORD __cdecl svcctl_OpenSCManagerA(
1770 MACHINE_HANDLEA MachineName,
1771 LPCSTR DatabaseName,
1772 DWORD dwAccessMask,
1773 SC_RPC_HANDLE *handle)
1775 WINE_FIXME("\n");
1776 return ERROR_CALL_NOT_IMPLEMENTED;
1779 DWORD __cdecl svcctl_OpenServiceA(
1780 SC_RPC_HANDLE hSCManager,
1781 LPCSTR lpServiceName,
1782 DWORD dwDesiredAccess,
1783 SC_RPC_HANDLE *phService)
1785 WINE_FIXME("\n");
1786 return ERROR_CALL_NOT_IMPLEMENTED;
1789 DWORD __cdecl svcctl_QueryServiceConfigA(
1790 SC_RPC_HANDLE hService,
1791 QUERY_SERVICE_CONFIGA *config,
1792 DWORD buf_size,
1793 DWORD *needed_size)
1795 WINE_FIXME("\n");
1796 return ERROR_CALL_NOT_IMPLEMENTED;
1799 DWORD __cdecl svcctl_QueryServiceLockStatusA(
1800 SC_RPC_HANDLE scmanager,
1801 QUERY_SERVICE_LOCK_STATUSA *status,
1802 DWORD buf_size,
1803 DWORD *needed_size)
1805 WINE_FIXME("\n");
1806 return ERROR_CALL_NOT_IMPLEMENTED;
1809 DWORD __cdecl svcctl_StartServiceA(
1810 SC_RPC_HANDLE service,
1811 DWORD argc,
1812 LPCSTR *args)
1814 WINE_FIXME("\n");
1815 return ERROR_CALL_NOT_IMPLEMENTED;
1818 DWORD __cdecl svcctl_GetServiceDisplayNameA(
1819 SC_RPC_HANDLE hSCManager,
1820 LPCSTR servicename,
1821 CHAR buffer[],
1822 DWORD *buf_size)
1824 WINE_FIXME("\n");
1825 return ERROR_CALL_NOT_IMPLEMENTED;
1828 DWORD __cdecl svcctl_GetServiceKeyNameA(
1829 SC_RPC_HANDLE hSCManager,
1830 LPCSTR servicename,
1831 CHAR buffer[],
1832 DWORD *buf_size)
1834 WINE_FIXME("\n");
1835 return ERROR_CALL_NOT_IMPLEMENTED;
1838 DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
1840 WINE_FIXME("\n");
1841 return ERROR_CALL_NOT_IMPLEMENTED;
1844 DWORD __cdecl svcctl_EnumServiceGroupW(
1845 SC_RPC_HANDLE scmanager,
1846 DWORD service_type,
1847 DWORD service_state,
1848 BYTE *buffer,
1849 DWORD buf_size,
1850 DWORD *needed_size,
1851 DWORD *returned_size,
1852 DWORD *resume_index,
1853 LPCWSTR groupname)
1855 WINE_FIXME("\n");
1856 return ERROR_CALL_NOT_IMPLEMENTED;
1859 DWORD __cdecl svcctl_ChangeServiceConfig2A(
1860 SC_RPC_HANDLE service,
1861 SC_RPC_CONFIG_INFOA info)
1863 WINE_FIXME("\n");
1864 return ERROR_CALL_NOT_IMPLEMENTED;
1867 DWORD __cdecl svcctl_QueryServiceConfig2A(
1868 SC_RPC_HANDLE service,
1869 DWORD info_level,
1870 BYTE *buffer,
1871 DWORD buf_size,
1872 DWORD *needed_size)
1874 WINE_FIXME("\n");
1875 return ERROR_CALL_NOT_IMPLEMENTED;
1878 DWORD RPC_Init(void)
1880 WCHAR transport[] = SVCCTL_TRANSPORT;
1881 WCHAR endpoint[] = SVCCTL_ENDPOINT;
1882 DWORD err;
1884 if (!(cleanup_group = CreateThreadpoolCleanupGroup()))
1886 WINE_ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
1887 return GetLastError();
1890 if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1892 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1893 return err;
1896 if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1898 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1899 return err;
1902 if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1904 WINE_ERR("RpcServerListen failed with error %u\n", err);
1905 return err;
1908 exit_event = __wine_make_process_system();
1909 return ERROR_SUCCESS;
1912 void RPC_Stop(void)
1914 RpcMgmtStopServerListening(NULL);
1915 RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
1917 /* synchronize with CloseThreadpoolWait */
1918 EnterCriticalSection(&shutdown_cs);
1919 service_shutdown = TRUE;
1920 LeaveCriticalSection(&shutdown_cs);
1922 CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
1923 CloseThreadpoolCleanupGroup(cleanup_group);
1924 CloseHandle(exit_event);
1927 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
1929 SC_RPC_HANDLE_destroy(handle);
1932 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
1936 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
1938 return HeapAlloc(GetProcessHeap(), 0, len);
1941 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
1943 HeapFree(GetProcessHeap(), 0, ptr);