msvcirt/tests: Silence a compiler warning.
[wine.git] / programs / services / rpc.c
blob08b5776aebdd63785df5102343dafca2522b198e
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 const WCHAR emptyW[] = {0};
89 static PTP_CLEANUP_GROUP cleanup_group;
90 HANDLE exit_event;
92 static void CALLBACK group_cancel_callback(void *object, void *userdata)
94 struct process_entry *process = object;
95 release_process(process);
98 static void CALLBACK terminate_callback(TP_CALLBACK_INSTANCE *instance, void *context,
99 TP_WAIT *wait, TP_WAIT_RESULT result)
101 struct process_entry *process = context;
102 if (result == WAIT_TIMEOUT) process_terminate(process);
103 release_process(process);
104 CloseThreadpoolWait(wait);
107 static void terminate_after_timeout(struct process_entry *process, DWORD timeout)
109 TP_CALLBACK_ENVIRON environment;
110 LARGE_INTEGER timestamp;
111 TP_WAIT *wait;
112 FILETIME ft;
114 memset(&environment, 0, sizeof(environment));
115 environment.Version = 1;
116 environment.CleanupGroup = cleanup_group;
117 environment.CleanupGroupCancelCallback = group_cancel_callback;
119 timestamp.QuadPart = (ULONGLONG)timeout * -10000;
120 ft.dwLowDateTime = timestamp.u.LowPart;
121 ft.dwHighDateTime = timestamp.u.HighPart;
123 if ((wait = CreateThreadpoolWait(terminate_callback, grab_process(process), &environment)))
124 SetThreadpoolWait(wait, process->process, &ft);
125 else
126 release_process(process);
129 static void CALLBACK shutdown_callback(TP_CALLBACK_INSTANCE *instance, void *context)
131 struct process_entry *process = context;
132 DWORD result;
134 result = WaitForSingleObject(process->control_mutex, 30000);
135 if (result == WAIT_OBJECT_0)
137 process_send_control(process, FALSE, emptyW, SERVICE_CONTROL_STOP, NULL, 0, &result);
138 ReleaseMutex(process->control_mutex);
141 release_process(process);
144 static void shutdown_shared_process(struct process_entry *process)
146 TP_CALLBACK_ENVIRON environment;
147 struct service_entry *service;
148 struct scmdatabase *db = process->db;
150 scmdatabase_lock(db);
151 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
153 if (service->process != process) continue;
154 service->status.dwCurrentState = SERVICE_STOP_PENDING;
156 scmdatabase_unlock(db);
158 memset(&environment, 0, sizeof(environment));
159 environment.Version = 1;
160 environment.CleanupGroup = cleanup_group;
161 environment.CleanupGroupCancelCallback = group_cancel_callback;
163 if (!TrySubmitThreadpoolCallback(shutdown_callback, grab_process(process), &environment))
164 release_process(process);
167 static void free_service_strings(struct service_entry *old, struct service_entry *new)
169 QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
170 QUERY_SERVICE_CONFIGW *new_cfg = &new->config;
172 if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName)
173 HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName);
175 if (old_cfg->lpLoadOrderGroup != new_cfg->lpLoadOrderGroup)
176 HeapFree(GetProcessHeap(), 0, old_cfg->lpLoadOrderGroup);
178 if (old_cfg->lpServiceStartName != new_cfg->lpServiceStartName)
179 HeapFree(GetProcessHeap(), 0, old_cfg->lpServiceStartName);
181 if (old_cfg->lpDisplayName != new_cfg->lpDisplayName)
182 HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName);
184 if (old->dependOnServices != new->dependOnServices)
185 HeapFree(GetProcessHeap(), 0, old->dependOnServices);
187 if (old->dependOnGroups != new->dependOnGroups)
188 HeapFree(GetProcessHeap(), 0, old->dependOnGroups);
191 /* Check if the given handle is of the required type and allows the requested access. */
192 static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
194 struct sc_handle *hdr = handle;
196 if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
198 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
199 return ERROR_INVALID_HANDLE;
202 if ((needed_access & hdr->access) != needed_access)
204 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
205 return ERROR_ACCESS_DENIED;
208 *out_hdr = hdr;
209 return ERROR_SUCCESS;
212 static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
214 struct sc_handle *hdr;
215 DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
216 if (err == ERROR_SUCCESS)
217 *manager = (struct sc_manager_handle *)hdr;
218 return err;
221 static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
223 struct sc_handle *hdr;
224 DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
225 if (err == ERROR_SUCCESS)
226 *service = (struct sc_service_handle *)hdr;
227 return err;
230 DWORD __cdecl svcctl_OpenSCManagerW(
231 MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
232 LPCWSTR DatabaseName,
233 DWORD dwAccessMask,
234 SC_RPC_HANDLE *handle)
236 struct sc_manager_handle *manager;
238 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
240 if (DatabaseName != NULL && DatabaseName[0])
242 if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
243 return ERROR_DATABASE_DOES_NOT_EXIST;
244 if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
245 return ERROR_INVALID_NAME;
248 if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
249 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
251 manager->hdr.type = SC_HTYPE_MANAGER;
253 if (dwAccessMask & MAXIMUM_ALLOWED)
254 dwAccessMask |= SC_MANAGER_ALL_ACCESS;
255 manager->hdr.access = dwAccessMask;
256 RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
257 manager->db = active_database;
258 *handle = &manager->hdr;
260 return ERROR_SUCCESS;
263 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
265 struct sc_handle *hdr = handle;
266 switch (hdr->type)
268 case SC_HTYPE_MANAGER:
270 struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
271 HeapFree(GetProcessHeap(), 0, manager);
272 break;
274 case SC_HTYPE_SERVICE:
276 struct sc_service_handle *service = (struct sc_service_handle *)hdr;
277 release_service(service->service_entry);
278 HeapFree(GetProcessHeap(), 0, service);
279 break;
281 default:
282 WINE_ERR("invalid handle type %d\n", hdr->type);
283 RpcRaiseException(ERROR_INVALID_HANDLE);
287 DWORD __cdecl svcctl_GetServiceDisplayNameW(
288 SC_RPC_HANDLE hSCManager,
289 LPCWSTR lpServiceName,
290 WCHAR *lpBuffer,
291 DWORD *cchBufSize)
293 struct sc_manager_handle *manager;
294 struct service_entry *entry;
295 DWORD err;
297 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize);
299 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
300 return err;
302 scmdatabase_lock(manager->db);
304 entry = scmdatabase_find_service(manager->db, lpServiceName);
305 if (entry != NULL)
307 LPCWSTR name;
308 int len;
309 name = get_display_name(entry);
310 len = strlenW(name);
311 if (len <= *cchBufSize)
313 err = ERROR_SUCCESS;
314 memcpy(lpBuffer, name, (len + 1)*sizeof(*name));
316 else
317 err = ERROR_INSUFFICIENT_BUFFER;
318 *cchBufSize = len;
320 else
321 err = ERROR_SERVICE_DOES_NOT_EXIST;
323 scmdatabase_unlock(manager->db);
325 if (err != ERROR_SUCCESS)
326 lpBuffer[0] = 0;
328 return err;
331 DWORD __cdecl svcctl_GetServiceKeyNameW(
332 SC_RPC_HANDLE hSCManager,
333 LPCWSTR lpServiceDisplayName,
334 WCHAR *lpBuffer,
335 DWORD *cchBufSize)
337 struct service_entry *entry;
338 struct sc_manager_handle *manager;
339 DWORD err;
341 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize);
343 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
344 return err;
346 scmdatabase_lock(manager->db);
348 entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
349 if (entry != NULL)
351 int len;
352 len = strlenW(entry->name);
353 if (len <= *cchBufSize)
355 err = ERROR_SUCCESS;
356 memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name));
358 else
359 err = ERROR_INSUFFICIENT_BUFFER;
360 *cchBufSize = len;
362 else
363 err = ERROR_SERVICE_DOES_NOT_EXIST;
365 scmdatabase_unlock(manager->db);
367 if (err != ERROR_SUCCESS)
368 lpBuffer[0] = 0;
370 return err;
373 static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
375 struct sc_service_handle *service;
377 if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
379 release_service(entry);
380 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
383 if (dwDesiredAccess & MAXIMUM_ALLOWED)
384 dwDesiredAccess |= SERVICE_ALL_ACCESS;
386 service->hdr.type = SC_HTYPE_SERVICE;
387 service->hdr.access = dwDesiredAccess;
388 RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
389 service->service_entry = entry;
391 *phService = &service->hdr;
392 return ERROR_SUCCESS;
395 DWORD __cdecl svcctl_OpenServiceW(
396 SC_RPC_HANDLE hSCManager,
397 LPCWSTR lpServiceName,
398 DWORD dwDesiredAccess,
399 SC_RPC_HANDLE *phService)
401 struct sc_manager_handle *manager;
402 struct service_entry *entry;
403 DWORD err;
405 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
407 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
408 return err;
409 if (!validate_service_name(lpServiceName))
410 return ERROR_INVALID_NAME;
412 scmdatabase_lock(manager->db);
413 entry = grab_service(scmdatabase_find_service(manager->db, lpServiceName));
414 scmdatabase_unlock(manager->db);
416 if (entry == NULL)
417 return ERROR_SERVICE_DOES_NOT_EXIST;
419 return create_handle_for_service(entry, dwDesiredAccess, phService);
422 static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry)
424 WCHAR *services = NULL, *groups, *s;
425 DWORD len, len_services = 0, len_groups = 0;
426 const WCHAR *ptr = dependencies;
428 if (!dependencies || !dependencies[0])
430 entry->dependOnServices = NULL;
431 entry->dependOnGroups = NULL;
432 return ERROR_SUCCESS;
435 while (*ptr)
437 len = strlenW(ptr) + 1;
438 if (ptr[0] == '+' && ptr[1])
439 len_groups += len - 1;
440 else
441 len_services += len;
442 ptr += len;
444 if (!len_services) entry->dependOnServices = NULL;
445 else
447 services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR));
448 if (!services)
449 return ERROR_OUTOFMEMORY;
451 s = services;
452 ptr = dependencies;
453 while (*ptr)
455 len = strlenW(ptr) + 1;
456 if (*ptr != '+')
458 strcpyW(s, ptr);
459 s += len;
461 ptr += len;
463 *s = 0;
464 entry->dependOnServices = services;
466 if (!len_groups) entry->dependOnGroups = NULL;
467 else
469 groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR));
470 if (!groups)
472 HeapFree(GetProcessHeap(), 0, services);
473 return ERROR_OUTOFMEMORY;
475 s = groups;
476 ptr = dependencies;
477 while (*ptr)
479 len = strlenW(ptr) + 1;
480 if (ptr[0] == '+' && ptr[1])
482 strcpyW(s, ptr + 1);
483 s += len - 1;
485 ptr += len;
487 *s = 0;
488 entry->dependOnGroups = groups;
491 return ERROR_SUCCESS;
494 static DWORD create_serviceW(
495 SC_RPC_HANDLE hSCManager,
496 LPCWSTR lpServiceName,
497 LPCWSTR lpDisplayName,
498 DWORD dwDesiredAccess,
499 DWORD dwServiceType,
500 DWORD dwStartType,
501 DWORD dwErrorControl,
502 LPCWSTR lpBinaryPathName,
503 LPCWSTR lpLoadOrderGroup,
504 DWORD *lpdwTagId,
505 const BYTE *lpDependencies,
506 DWORD dwDependenciesSize,
507 LPCWSTR lpServiceStartName,
508 const BYTE *lpPassword,
509 DWORD dwPasswordSize,
510 SC_RPC_HANDLE *phService,
511 BOOL is_wow64)
513 struct service_entry *entry, *found;
514 struct sc_manager_handle *manager;
515 DWORD err;
517 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
519 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
520 return err;
522 if (!validate_service_name(lpServiceName))
523 return ERROR_INVALID_NAME;
524 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
525 return ERROR_INVALID_PARAMETER;
527 if (lpPassword)
528 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
530 err = service_create(lpServiceName, &entry);
531 if (err != ERROR_SUCCESS)
532 return err;
534 err = parse_dependencies((LPCWSTR)lpDependencies, entry);
535 if (err != ERROR_SUCCESS) {
536 free_service_entry(entry);
537 return err;
540 entry->is_wow64 = is_wow64;
541 entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType;
542 entry->config.dwStartType = dwStartType;
543 entry->config.dwErrorControl = dwErrorControl;
544 entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
545 entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
546 entry->config.lpServiceStartName = strdupW(lpServiceStartName);
547 entry->config.lpDisplayName = strdupW(lpDisplayName);
549 if (lpdwTagId) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
550 entry->config.dwTagId = *lpdwTagId;
551 else
552 entry->config.dwTagId = 0;
554 /* other fields NULL*/
556 if (!validate_service_config(entry))
558 WINE_ERR("Invalid data while trying to create service\n");
559 free_service_entry(entry);
560 return ERROR_INVALID_PARAMETER;
563 scmdatabase_lock(manager->db);
565 if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
567 err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
568 scmdatabase_unlock(manager->db);
569 free_service_entry(entry);
570 return err;
573 if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
575 scmdatabase_unlock(manager->db);
576 free_service_entry(entry);
577 return ERROR_DUPLICATE_SERVICE_NAME;
580 err = scmdatabase_add_service(manager->db, entry);
581 if (err != ERROR_SUCCESS)
583 scmdatabase_unlock(manager->db);
584 free_service_entry(entry);
585 return err;
587 scmdatabase_unlock(manager->db);
589 return create_handle_for_service(entry, dwDesiredAccess, phService);
592 DWORD __cdecl svcctl_CreateServiceW(
593 SC_RPC_HANDLE hSCManager,
594 LPCWSTR lpServiceName,
595 LPCWSTR lpDisplayName,
596 DWORD dwDesiredAccess,
597 DWORD dwServiceType,
598 DWORD dwStartType,
599 DWORD dwErrorControl,
600 LPCWSTR lpBinaryPathName,
601 LPCWSTR lpLoadOrderGroup,
602 DWORD *lpdwTagId,
603 const BYTE *lpDependencies,
604 DWORD dwDependenciesSize,
605 LPCWSTR lpServiceStartName,
606 const BYTE *lpPassword,
607 DWORD dwPasswordSize,
608 SC_RPC_HANDLE *phService)
610 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
611 return create_serviceW(hSCManager, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType,
612 dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, dwDependenciesSize, lpServiceStartName,
613 lpPassword, dwPasswordSize, phService, FALSE);
616 DWORD __cdecl svcctl_DeleteService(
617 SC_RPC_HANDLE hService)
619 struct sc_service_handle *service;
620 DWORD err;
622 if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
623 return err;
625 service_lock(service->service_entry);
627 if (!is_marked_for_delete(service->service_entry))
628 err = mark_for_delete(service->service_entry);
629 else
630 err = ERROR_SERVICE_MARKED_FOR_DELETE;
632 service_unlock(service->service_entry);
634 return err;
637 DWORD __cdecl svcctl_QueryServiceConfigW(
638 SC_RPC_HANDLE hService,
639 QUERY_SERVICE_CONFIGW *config,
640 DWORD buf_size,
641 DWORD *needed_size)
643 struct sc_service_handle *service;
644 DWORD err;
646 WINE_TRACE("(%p)\n", config);
648 if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
649 return err;
651 service_lock(service->service_entry);
652 config->dwServiceType = service->service_entry->config.dwServiceType;
653 config->dwStartType = service->service_entry->config.dwStartType;
654 config->dwErrorControl = service->service_entry->config.dwErrorControl;
655 config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
656 config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
657 config->dwTagId = service->service_entry->config.dwTagId;
658 config->lpDependencies = NULL; /* TODO */
659 config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
660 config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
661 service_unlock(service->service_entry);
663 return ERROR_SUCCESS;
666 DWORD __cdecl svcctl_ChangeServiceConfigW(
667 SC_RPC_HANDLE hService,
668 DWORD dwServiceType,
669 DWORD dwStartType,
670 DWORD dwErrorControl,
671 LPCWSTR lpBinaryPathName,
672 LPCWSTR lpLoadOrderGroup,
673 DWORD *lpdwTagId,
674 const BYTE *lpDependencies,
675 DWORD dwDependenciesSize,
676 LPCWSTR lpServiceStartName,
677 const BYTE *lpPassword,
678 DWORD dwPasswordSize,
679 LPCWSTR lpDisplayName)
681 struct service_entry new_entry, *entry;
682 struct sc_service_handle *service;
683 DWORD err;
685 WINE_TRACE("\n");
687 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
688 return err;
690 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
691 return ERROR_INVALID_PARAMETER;
693 /* first check if the new configuration is correct */
694 service_lock(service->service_entry);
696 if (is_marked_for_delete(service->service_entry))
698 service_unlock(service->service_entry);
699 return ERROR_SERVICE_MARKED_FOR_DELETE;
702 if (lpDisplayName != NULL &&
703 (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
704 (entry != service->service_entry))
706 service_unlock(service->service_entry);
707 return ERROR_DUPLICATE_SERVICE_NAME;
710 new_entry = *service->service_entry;
712 if (dwServiceType != SERVICE_NO_CHANGE)
713 new_entry.config.dwServiceType = dwServiceType;
715 if (dwStartType != SERVICE_NO_CHANGE)
716 new_entry.config.dwStartType = dwStartType;
718 if (dwErrorControl != SERVICE_NO_CHANGE)
719 new_entry.config.dwErrorControl = dwErrorControl;
721 if (lpBinaryPathName != NULL)
722 new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
724 if (lpLoadOrderGroup != NULL)
725 new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
727 if (lpdwTagId != NULL)
728 WINE_FIXME("Changing tag id not supported\n");
730 if (lpServiceStartName != NULL)
731 new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
733 if (lpPassword != NULL)
734 WINE_FIXME("Setting password not supported\n");
736 if (lpDisplayName != NULL)
737 new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
739 err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry);
740 if (err != ERROR_SUCCESS)
742 service_unlock(service->service_entry);
743 return err;
746 if (!validate_service_config(&new_entry))
748 WINE_ERR("The configuration after the change wouldn't be valid\n");
749 service_unlock(service->service_entry);
750 return ERROR_INVALID_PARAMETER;
753 /* configuration OK. The strings needs to be duplicated */
754 if (lpBinaryPathName != NULL)
755 new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
757 if (lpLoadOrderGroup != NULL)
758 new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
760 if (lpServiceStartName != NULL)
761 new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
763 if (lpDisplayName != NULL)
764 new_entry.config.lpDisplayName = strdupW(lpDisplayName);
766 /* try to save to Registry, commit or rollback depending on success */
767 err = save_service_config(&new_entry);
768 if (ERROR_SUCCESS == err)
770 free_service_strings(service->service_entry, &new_entry);
771 *service->service_entry = new_entry;
773 else free_service_strings(&new_entry, service->service_entry);
774 service_unlock(service->service_entry);
776 return err;
779 DWORD __cdecl svcctl_SetServiceStatus(
780 SC_RPC_HANDLE hServiceStatus,
781 LPSERVICE_STATUS lpServiceStatus)
783 struct sc_service_handle *service;
784 struct process_entry *process;
785 DWORD err;
787 WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
789 if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
790 return err;
792 service_lock(service->service_entry);
794 /* FIXME: be a bit more discriminant about what parts of the status we set
795 * and check that fields are valid */
796 service->service_entry->status = *lpServiceStatus;
797 SetEvent(service->service_entry->status_changed_event);
799 if ((process = service->service_entry->process) &&
800 lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
802 service->service_entry->process = NULL;
803 if (!--process->use_count)
804 terminate_after_timeout(process, service_kill_timeout);
805 if (service->service_entry->shared_process && process->use_count <= 1)
806 shutdown_shared_process(process);
807 release_process(process);
810 service_unlock(service->service_entry);
812 return ERROR_SUCCESS;
815 DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFIG_INFOW config )
817 struct sc_service_handle *service;
818 DWORD err;
820 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
821 return err;
823 switch (config.dwInfoLevel)
825 case SERVICE_CONFIG_DESCRIPTION:
827 WCHAR *descr = NULL;
829 if (config.u.descr->lpDescription[0])
831 if (!(descr = strdupW( config.u.descr->lpDescription )))
832 return ERROR_NOT_ENOUGH_MEMORY;
835 WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
836 service_lock( service->service_entry );
837 HeapFree( GetProcessHeap(), 0, service->service_entry->description );
838 service->service_entry->description = descr;
839 save_service_config( service->service_entry );
840 service_unlock( service->service_entry );
842 break;
843 case SERVICE_CONFIG_FAILURE_ACTIONS:
844 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
845 config.u.actions->dwResetPeriod,
846 wine_dbgstr_w(config.u.actions->lpRebootMsg),
847 wine_dbgstr_w(config.u.actions->lpCommand) );
848 break;
849 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
850 WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
851 service, config.u.preshutdown->dwPreshutdownTimeout );
852 service_lock( service->service_entry );
853 service->service_entry->preshutdown_timeout = config.u.preshutdown->dwPreshutdownTimeout;
854 save_service_config( service->service_entry );
855 service_unlock( service->service_entry );
856 break;
857 default:
858 WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
859 err = ERROR_INVALID_LEVEL;
860 break;
862 return err;
865 DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
866 BYTE *buffer, DWORD size, LPDWORD needed )
868 struct sc_service_handle *service;
869 DWORD err;
871 memset(buffer, 0, size);
873 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
874 return err;
876 switch (level)
878 case SERVICE_CONFIG_DESCRIPTION:
880 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
882 service_lock(service->service_entry);
883 *needed = sizeof(*descr);
884 if (service->service_entry->description)
885 *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
886 if (size >= *needed)
888 if (service->service_entry->description)
890 /* store a buffer offset instead of a pointer */
891 descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer);
892 strcpyW( (WCHAR *)(descr + 1), service->service_entry->description );
894 else descr->lpDescription = NULL;
896 else err = ERROR_INSUFFICIENT_BUFFER;
897 service_unlock(service->service_entry);
899 break;
901 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
902 service_lock(service->service_entry);
904 *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
905 if (size >= *needed)
906 ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
907 service->service_entry->preshutdown_timeout;
908 else err = ERROR_INSUFFICIENT_BUFFER;
910 service_unlock(service->service_entry);
911 break;
913 default:
914 WINE_FIXME("level %u not implemented\n", level);
915 err = ERROR_INVALID_LEVEL;
916 break;
918 return err;
921 static void fill_status_process(SERVICE_STATUS_PROCESS *status, struct service_entry *service)
923 struct process_entry *process = service->process;
924 memcpy(status, &service->status, sizeof(service->status));
925 status->dwProcessId = process ? process->process_id : 0;
926 status->dwServiceFlags = 0;
929 DWORD __cdecl svcctl_QueryServiceStatusEx(
930 SC_RPC_HANDLE hService,
931 SC_STATUS_TYPE InfoLevel,
932 BYTE *lpBuffer,
933 DWORD cbBufSize,
934 LPDWORD pcbBytesNeeded)
936 struct sc_service_handle *service;
937 DWORD err;
938 LPSERVICE_STATUS_PROCESS pSvcStatusData;
940 memset(lpBuffer, 0, cbBufSize);
942 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
943 return err;
945 if (InfoLevel != SC_STATUS_PROCESS_INFO)
946 return ERROR_INVALID_LEVEL;
948 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
949 if (pSvcStatusData == NULL)
950 return ERROR_INVALID_PARAMETER;
952 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
954 if( pcbBytesNeeded != NULL)
955 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
957 return ERROR_INSUFFICIENT_BUFFER;
960 service_lock(service->service_entry);
961 fill_status_process(pSvcStatusData, service->service_entry);
962 service_unlock(service->service_entry);
964 return ERROR_SUCCESS;
967 /******************************************************************************
968 * service_accepts_control
970 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
972 DWORD a = service->status.dwControlsAccepted;
974 if (dwControl >= 128 && dwControl <= 255)
975 return TRUE;
977 switch (dwControl)
979 case SERVICE_CONTROL_INTERROGATE:
980 return TRUE;
981 case SERVICE_CONTROL_STOP:
982 if (a&SERVICE_ACCEPT_STOP)
983 return TRUE;
984 break;
985 case SERVICE_CONTROL_SHUTDOWN:
986 if (a&SERVICE_ACCEPT_SHUTDOWN)
987 return TRUE;
988 break;
989 case SERVICE_CONTROL_PAUSE:
990 case SERVICE_CONTROL_CONTINUE:
991 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
992 return TRUE;
993 break;
994 case SERVICE_CONTROL_PARAMCHANGE:
995 if (a&SERVICE_ACCEPT_PARAMCHANGE)
996 return TRUE;
997 break;
998 case SERVICE_CONTROL_NETBINDADD:
999 case SERVICE_CONTROL_NETBINDREMOVE:
1000 case SERVICE_CONTROL_NETBINDENABLE:
1001 case SERVICE_CONTROL_NETBINDDISABLE:
1002 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
1003 return TRUE;
1004 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
1005 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
1006 return TRUE;
1007 break;
1008 case SERVICE_CONTROL_POWEREVENT:
1009 if (a&SERVICE_ACCEPT_POWEREVENT)
1010 return TRUE;
1011 break;
1012 case SERVICE_CONTROL_SESSIONCHANGE:
1013 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
1014 return TRUE;
1015 break;
1017 return FALSE;
1020 /******************************************************************************
1021 * process_send_command
1023 static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
1025 OVERLAPPED overlapped;
1026 DWORD count, ret;
1027 BOOL r;
1029 overlapped.hEvent = process->overlapped_event;
1030 r = WriteFile(process->control_pipe, data, size, &count, &overlapped);
1031 if (!r && GetLastError() == ERROR_IO_PENDING)
1033 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1034 if (ret == WAIT_TIMEOUT)
1036 WINE_ERR("sending command timed out\n");
1037 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1038 return FALSE;
1040 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1042 if (!r || count != size)
1044 WINE_ERR("service protocol error - failed to write pipe!\n");
1045 *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
1046 return FALSE;
1048 r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped);
1049 if (!r && GetLastError() == ERROR_IO_PENDING)
1051 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1052 if (ret == WAIT_TIMEOUT)
1054 WINE_ERR("receiving command result timed out\n");
1055 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1056 return FALSE;
1058 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1060 if (!r || count != sizeof *result)
1062 WINE_ERR("service protocol error - failed to read pipe "
1063 "r = %d count = %d!\n", r, count);
1064 *result = (!r ? GetLastError() : ERROR_READ_FAULT);
1065 return FALSE;
1068 return TRUE;
1071 /******************************************************************************
1072 * process_send_control
1074 BOOL process_send_control(struct process_entry *process, BOOL shared_process, const WCHAR *name,
1075 DWORD control, const BYTE *data, DWORD data_size, DWORD *result)
1077 service_start_info *ssi;
1078 DWORD len;
1079 BOOL r;
1081 if (shared_process)
1083 control |= SERVICE_CONTROL_FORWARD_FLAG;
1084 data = (BYTE *)name;
1085 data_size = (strlenW(name) + 1) * sizeof(WCHAR);
1086 name = emptyW;
1089 /* calculate how much space we need to send the startup info */
1090 len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size;
1092 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
1093 ssi->magic = SERVICE_PROTOCOL_MAGIC;
1094 ssi->control = control;
1095 ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
1096 ssi->name_size = strlenW(name) + 1;
1097 strcpyW((WCHAR *)ssi->data, name);
1098 if (data_size) memcpy(&ssi->data[ssi->name_size * sizeof(WCHAR)], data, data_size);
1100 r = process_send_command(process, ssi, ssi->total_size, result);
1101 HeapFree( GetProcessHeap(), 0, ssi );
1102 return r;
1105 DWORD __cdecl svcctl_StartServiceW(
1106 SC_RPC_HANDLE hService,
1107 DWORD dwNumServiceArgs,
1108 LPCWSTR *lpServiceArgVectors)
1110 struct sc_service_handle *service;
1111 DWORD err;
1113 WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1115 if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
1116 return err;
1118 if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
1119 return ERROR_SERVICE_DISABLED;
1121 if (!scmdatabase_lock_startup(service->service_entry->db))
1122 return ERROR_SERVICE_DATABASE_LOCKED;
1124 err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
1126 scmdatabase_unlock_startup(service->service_entry->db);
1127 return err;
1130 DWORD __cdecl svcctl_ControlService(
1131 SC_RPC_HANDLE hService,
1132 DWORD dwControl,
1133 SERVICE_STATUS *lpServiceStatus)
1135 DWORD access_required;
1136 struct sc_service_handle *service;
1137 struct process_entry *process;
1138 BOOL shared_process;
1139 DWORD result;
1141 WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
1143 switch (dwControl)
1145 case SERVICE_CONTROL_CONTINUE:
1146 case SERVICE_CONTROL_NETBINDADD:
1147 case SERVICE_CONTROL_NETBINDDISABLE:
1148 case SERVICE_CONTROL_NETBINDENABLE:
1149 case SERVICE_CONTROL_NETBINDREMOVE:
1150 case SERVICE_CONTROL_PARAMCHANGE:
1151 case SERVICE_CONTROL_PAUSE:
1152 access_required = SERVICE_PAUSE_CONTINUE;
1153 break;
1154 case SERVICE_CONTROL_INTERROGATE:
1155 access_required = SERVICE_INTERROGATE;
1156 break;
1157 case SERVICE_CONTROL_STOP:
1158 access_required = SERVICE_STOP;
1159 break;
1160 default:
1161 if (dwControl >= 128 && dwControl <= 255)
1162 access_required = SERVICE_USER_DEFINED_CONTROL;
1163 else
1164 return ERROR_INVALID_PARAMETER;
1167 if ((result = validate_service_handle(hService, access_required, &service)) != 0)
1168 return result;
1170 service_lock(service->service_entry);
1172 result = ERROR_SUCCESS;
1173 switch (service->service_entry->status.dwCurrentState)
1175 case SERVICE_STOPPED:
1176 result = ERROR_SERVICE_NOT_ACTIVE;
1177 break;
1178 case SERVICE_START_PENDING:
1179 if (dwControl==SERVICE_CONTROL_STOP)
1180 break;
1181 /* fall through */
1182 case SERVICE_STOP_PENDING:
1183 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1184 break;
1187 if (result == ERROR_SUCCESS && service->service_entry->force_shutdown)
1189 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1190 if ((process = service->service_entry->process))
1192 service->service_entry->process = NULL;
1193 if (!--process->use_count) process_terminate(process);
1194 release_process(process);
1198 if (result != ERROR_SUCCESS)
1200 if (lpServiceStatus) *lpServiceStatus = service->service_entry->status;
1201 service_unlock(service->service_entry);
1202 return result;
1205 if (!service_accepts_control(service->service_entry, dwControl))
1207 service_unlock(service->service_entry);
1208 return ERROR_INVALID_SERVICE_CONTROL;
1211 /* Remember that we tried to shutdown this service. When the service is
1212 * still running on the second invocation, it will be forcefully killed. */
1213 if (dwControl == SERVICE_CONTROL_STOP)
1214 service->service_entry->force_shutdown = TRUE;
1216 /* Hold a reference to the process while sending the command. */
1217 process = grab_process(service->service_entry->process);
1218 shared_process = service->service_entry->shared_process;
1219 service_unlock(service->service_entry);
1221 if (!process)
1222 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1224 result = WaitForSingleObject(process->control_mutex, 30000);
1225 if (result != WAIT_OBJECT_0)
1227 release_process(process);
1228 return ERROR_SERVICE_REQUEST_TIMEOUT;
1231 if (process_send_control(process, shared_process, service->service_entry->name,
1232 dwControl, NULL, 0, &result))
1233 result = ERROR_SUCCESS;
1235 if (lpServiceStatus)
1237 service_lock(service->service_entry);
1238 *lpServiceStatus = service->service_entry->status;
1239 service_unlock(service->service_entry);
1242 ReleaseMutex(process->control_mutex);
1243 release_process(process);
1244 return result;
1247 DWORD __cdecl svcctl_CloseServiceHandle(
1248 SC_RPC_HANDLE *handle)
1250 WINE_TRACE("(&%p)\n", *handle);
1252 SC_RPC_HANDLE_destroy(*handle);
1253 *handle = NULL;
1255 return ERROR_SUCCESS;
1258 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
1260 struct sc_lock *lock = hLock;
1261 scmdatabase_unlock_startup(lock->db);
1262 HeapFree(GetProcessHeap(), 0, lock);
1265 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
1267 SC_RPC_LOCK_destroy(hLock);
1270 DWORD __cdecl svcctl_LockServiceDatabase(
1271 SC_RPC_HANDLE hSCManager,
1272 SC_RPC_LOCK *phLock)
1274 struct sc_manager_handle *manager;
1275 struct sc_lock *lock;
1276 DWORD err;
1278 WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
1280 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
1281 return err;
1283 if (!scmdatabase_lock_startup(manager->db))
1284 return ERROR_SERVICE_DATABASE_LOCKED;
1286 lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
1287 if (!lock)
1289 scmdatabase_unlock_startup(manager->db);
1290 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
1293 lock->db = manager->db;
1294 *phLock = lock;
1296 return ERROR_SUCCESS;
1299 DWORD __cdecl svcctl_UnlockServiceDatabase(
1300 SC_RPC_LOCK *phLock)
1302 WINE_TRACE("(&%p)\n", *phLock);
1304 SC_RPC_LOCK_destroy(*phLock);
1305 *phLock = NULL;
1307 return ERROR_SUCCESS;
1310 static BOOL map_state(DWORD state, DWORD mask)
1312 switch (state)
1314 case SERVICE_START_PENDING:
1315 case SERVICE_STOP_PENDING:
1316 case SERVICE_RUNNING:
1317 case SERVICE_CONTINUE_PENDING:
1318 case SERVICE_PAUSE_PENDING:
1319 case SERVICE_PAUSED:
1320 if (SERVICE_ACTIVE & mask) return TRUE;
1321 break;
1322 case SERVICE_STOPPED:
1323 if (SERVICE_INACTIVE & mask) return TRUE;
1324 break;
1325 default:
1326 WINE_ERR("unknown state %u\n", state);
1327 break;
1329 return FALSE;
1332 DWORD __cdecl svcctl_EnumServicesStatusW(
1333 SC_RPC_HANDLE hmngr,
1334 DWORD type,
1335 DWORD state,
1336 BYTE *buffer,
1337 DWORD size,
1338 LPDWORD needed,
1339 LPDWORD returned,
1340 LPDWORD resume)
1342 DWORD err, sz, total_size, num_services;
1343 DWORD_PTR offset;
1344 struct sc_manager_handle *manager;
1345 struct service_entry *service;
1346 ENUM_SERVICE_STATUSW *s;
1348 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
1350 if (!type || !state)
1351 return ERROR_INVALID_PARAMETER;
1353 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1354 return err;
1356 if (resume)
1357 WINE_FIXME("resume index not supported\n");
1359 scmdatabase_lock(manager->db);
1361 total_size = num_services = 0;
1362 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1364 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1366 total_size += sizeof(ENUM_SERVICE_STATUSW);
1367 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1368 if (service->config.lpDisplayName)
1370 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1372 num_services++;
1375 *returned = 0;
1376 *needed = total_size;
1377 if (total_size > size)
1379 scmdatabase_unlock(manager->db);
1380 return ERROR_MORE_DATA;
1382 s = (ENUM_SERVICE_STATUSW *)buffer;
1383 offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
1384 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1386 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1388 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1389 memcpy(buffer + offset, service->name, sz);
1390 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1391 offset += sz;
1393 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1394 else
1396 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1397 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1398 s->lpDisplayName = (WCHAR *)offset;
1399 offset += sz;
1401 s->ServiceStatus = service->status;
1402 s++;
1405 *returned = num_services;
1406 *needed = 0;
1407 scmdatabase_unlock(manager->db);
1408 return ERROR_SUCCESS;
1411 static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
1413 struct service_entry *service;
1414 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
1416 if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
1417 return service;
1419 return NULL;
1422 static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
1424 if (!g2) return TRUE;
1425 if (!g2[0] && (!g1 || !g1[0])) return TRUE;
1426 if (g1 && !strcmpW(g1, g2)) return TRUE;
1427 return FALSE;
1430 DWORD __cdecl svcctl_EnumServicesStatusExA(
1431 SC_RPC_HANDLE scmanager,
1432 SC_ENUM_TYPE info_level,
1433 DWORD service_type,
1434 DWORD service_state,
1435 BYTE *buffer,
1436 DWORD buf_size,
1437 DWORD *needed_size,
1438 DWORD *services_count,
1439 DWORD *resume_index,
1440 LPCSTR groupname)
1442 WINE_FIXME("\n");
1443 return ERROR_CALL_NOT_IMPLEMENTED;
1446 DWORD __cdecl svcctl_EnumServicesStatusExW(
1447 SC_RPC_HANDLE hmngr,
1448 SC_ENUM_TYPE info_level,
1449 DWORD type,
1450 DWORD state,
1451 BYTE *buffer,
1452 DWORD size,
1453 LPDWORD needed,
1454 LPDWORD returned,
1455 DWORD *resume_handle,
1456 LPCWSTR group)
1458 DWORD err, sz, total_size, num_services;
1459 DWORD_PTR offset;
1460 struct sc_manager_handle *manager;
1461 struct service_entry *service;
1462 ENUM_SERVICE_STATUS_PROCESSW *s;
1464 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
1465 needed, returned, wine_dbgstr_w(group));
1467 if (resume_handle)
1468 FIXME("resume handle not supported\n");
1470 if (!type || !state)
1471 return ERROR_INVALID_PARAMETER;
1473 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1474 return err;
1476 scmdatabase_lock(manager->db);
1478 if (group && !find_service_by_group(manager->db, group))
1480 scmdatabase_unlock(manager->db);
1481 return ERROR_SERVICE_DOES_NOT_EXIST;
1484 total_size = num_services = 0;
1485 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1487 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1488 && match_group(service->config.lpLoadOrderGroup, group))
1490 total_size += sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1491 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1492 if (service->config.lpDisplayName)
1494 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1496 num_services++;
1499 *returned = 0;
1500 *needed = total_size;
1501 if (total_size > size)
1503 scmdatabase_unlock(manager->db);
1504 return ERROR_MORE_DATA;
1506 s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1507 offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1508 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1510 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1511 && match_group(service->config.lpLoadOrderGroup, group))
1513 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1514 memcpy(buffer + offset, service->name, sz);
1515 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1516 offset += sz;
1518 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1519 else
1521 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1522 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1523 s->lpDisplayName = (WCHAR *)offset;
1524 offset += sz;
1526 fill_status_process(&s->ServiceStatusProcess, service);
1527 s++;
1530 *returned = num_services;
1531 *needed = 0;
1532 scmdatabase_unlock(manager->db);
1533 return ERROR_SUCCESS;
1536 DWORD __cdecl svcctl_unknown43(void)
1538 WINE_FIXME("\n");
1539 return ERROR_CALL_NOT_IMPLEMENTED;
1542 DWORD __cdecl svcctl_CreateServiceWOW64A(
1543 SC_RPC_HANDLE scmanager,
1544 LPCSTR servicename,
1545 LPCSTR displayname,
1546 DWORD accessmask,
1547 DWORD service_type,
1548 DWORD start_type,
1549 DWORD error_control,
1550 LPCSTR imagepath,
1551 LPCSTR loadordergroup,
1552 DWORD *tagid,
1553 const BYTE *dependencies,
1554 DWORD depend_size,
1555 LPCSTR start_name,
1556 const BYTE *password,
1557 DWORD password_size,
1558 SC_RPC_HANDLE *service)
1560 WINE_FIXME("\n");
1561 return ERROR_CALL_NOT_IMPLEMENTED;
1564 DWORD __cdecl svcctl_CreateServiceWOW64W(
1565 SC_RPC_HANDLE scmanager,
1566 LPCWSTR servicename,
1567 LPCWSTR displayname,
1568 DWORD accessmask,
1569 DWORD service_type,
1570 DWORD start_type,
1571 DWORD error_control,
1572 LPCWSTR imagepath,
1573 LPCWSTR loadordergroup,
1574 DWORD *tagid,
1575 const BYTE *dependencies,
1576 DWORD depend_size,
1577 LPCWSTR start_name,
1578 const BYTE *password,
1579 DWORD password_size,
1580 SC_RPC_HANDLE *service)
1582 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
1583 return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
1584 loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
1587 DWORD __cdecl svcctl_unknown46(void)
1589 WINE_FIXME("\n");
1590 return ERROR_CALL_NOT_IMPLEMENTED;
1593 DWORD __cdecl svcctl_NotifyServiceStatusChange(
1594 SC_RPC_HANDLE service,
1595 SC_RPC_NOTIFY_PARAMS params,
1596 GUID *clientprocessguid,
1597 GUID *scmprocessguid,
1598 BOOL *createremotequeue,
1599 SC_NOTIFY_RPC_HANDLE *notify)
1601 WINE_FIXME("\n");
1602 return ERROR_CALL_NOT_IMPLEMENTED;
1605 DWORD __cdecl svcctl_GetNotifyResults(
1606 SC_NOTIFY_RPC_HANDLE notify,
1607 SC_RPC_NOTIFY_PARAMS_LIST **params)
1609 WINE_FIXME("\n");
1610 return ERROR_CALL_NOT_IMPLEMENTED;
1613 DWORD __cdecl svcctl_CloseNotifyHandle(
1614 SC_NOTIFY_RPC_HANDLE *notify,
1615 BOOL *apc_fired)
1617 WINE_FIXME("\n");
1618 return ERROR_CALL_NOT_IMPLEMENTED;
1621 DWORD __cdecl svcctl_ControlServiceExA(
1622 SC_RPC_HANDLE service,
1623 DWORD control,
1624 DWORD info_level,
1625 SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
1626 SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
1628 WINE_FIXME("\n");
1629 return ERROR_CALL_NOT_IMPLEMENTED;
1632 DWORD __cdecl svcctl_ControlServiceExW(
1633 SC_RPC_HANDLE service,
1634 DWORD control,
1635 DWORD info_level,
1636 SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
1637 SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
1639 WINE_FIXME("\n");
1640 return ERROR_CALL_NOT_IMPLEMENTED;
1643 DWORD __cdecl svcctl_unknown52(void)
1645 WINE_FIXME("\n");
1646 return ERROR_CALL_NOT_IMPLEMENTED;
1649 DWORD __cdecl svcctl_unknown53(void)
1651 WINE_FIXME("\n");
1652 return ERROR_CALL_NOT_IMPLEMENTED;
1655 DWORD __cdecl svcctl_unknown54(void)
1657 WINE_FIXME("\n");
1658 return ERROR_CALL_NOT_IMPLEMENTED;
1661 DWORD __cdecl svcctl_unknown55(void)
1663 WINE_FIXME("\n");
1664 return ERROR_CALL_NOT_IMPLEMENTED;
1667 DWORD __cdecl svcctl_QueryServiceConfigEx(
1668 SC_RPC_HANDLE service,
1669 DWORD info_level,
1670 SC_RPC_CONFIG_INFOW *info)
1672 WINE_FIXME("\n");
1673 return ERROR_CALL_NOT_IMPLEMENTED;
1676 DWORD __cdecl svcctl_QueryServiceObjectSecurity(
1677 SC_RPC_HANDLE service,
1678 SECURITY_INFORMATION info,
1679 BYTE *descriptor,
1680 DWORD buf_size,
1681 DWORD *needed_size)
1683 WINE_FIXME("\n");
1684 return ERROR_CALL_NOT_IMPLEMENTED;
1687 DWORD __cdecl svcctl_SetServiceObjectSecurity(
1688 SC_RPC_HANDLE service,
1689 SECURITY_INFORMATION info,
1690 BYTE *descriptor,
1691 DWORD buf_size)
1693 WINE_FIXME("\n");
1694 return ERROR_CALL_NOT_IMPLEMENTED;
1697 DWORD __cdecl svcctl_QueryServiceStatus(
1698 SC_RPC_HANDLE service,
1699 SERVICE_STATUS *status)
1701 WINE_FIXME("\n");
1702 return ERROR_CALL_NOT_IMPLEMENTED;
1705 DWORD __cdecl svcctl_NotifyBootConfigStatus(
1706 SVCCTL_HANDLEW machinename,
1707 DWORD boot_acceptable)
1709 WINE_FIXME("\n");
1710 return ERROR_CALL_NOT_IMPLEMENTED;
1713 DWORD __cdecl svcctl_SCSetServiceBitsW(void)
1715 WINE_FIXME("\n");
1716 return ERROR_CALL_NOT_IMPLEMENTED;
1719 DWORD __cdecl svcctl_EnumDependentServicesW(
1720 SC_RPC_HANDLE service,
1721 DWORD state,
1722 BYTE *services,
1723 DWORD buf_size,
1724 DWORD *needed_size,
1725 DWORD *services_ret)
1727 WINE_FIXME("\n");
1728 return ERROR_CALL_NOT_IMPLEMENTED;
1731 DWORD __cdecl svcctl_QueryServiceLockStatusW(
1732 SC_RPC_HANDLE scmanager,
1733 QUERY_SERVICE_LOCK_STATUSW *status,
1734 DWORD buf_size,
1735 DWORD *needed_size)
1737 WINE_FIXME("\n");
1738 return ERROR_CALL_NOT_IMPLEMENTED;
1741 DWORD __cdecl svcctl_SCSetServiceBitsA(void)
1743 WINE_FIXME("\n");
1744 return ERROR_CALL_NOT_IMPLEMENTED;
1747 DWORD __cdecl svcctl_ChangeServiceConfigA(
1748 SC_RPC_HANDLE service,
1749 DWORD service_type,
1750 DWORD start_type,
1751 DWORD error_control,
1752 LPSTR binarypath,
1753 LPSTR loadordergroup,
1754 DWORD *tagid,
1755 BYTE *dependencies,
1756 DWORD depend_size,
1757 LPSTR startname,
1758 BYTE *password,
1759 DWORD password_size,
1760 LPSTR displayname)
1762 WINE_FIXME("\n");
1763 return ERROR_CALL_NOT_IMPLEMENTED;
1766 DWORD __cdecl svcctl_CreateServiceA(
1767 SC_RPC_HANDLE scmanager,
1768 LPCSTR servicename,
1769 LPCSTR displayname,
1770 DWORD desiredaccess,
1771 DWORD service_type,
1772 DWORD start_type,
1773 DWORD error_control,
1774 LPCSTR binarypath,
1775 LPCSTR loadordergroup,
1776 DWORD *tagid,
1777 const BYTE *dependencies,
1778 DWORD depend_size,
1779 LPCSTR startname,
1780 const BYTE *password,
1781 DWORD password_size,
1782 SC_RPC_HANDLE *service)
1784 WINE_FIXME("\n");
1785 return ERROR_CALL_NOT_IMPLEMENTED;
1788 DWORD __cdecl svcctl_EnumDependentServicesA(
1789 SC_RPC_HANDLE service,
1790 DWORD state,
1791 BYTE *services,
1792 DWORD buf_size,
1793 DWORD *needed_size,
1794 DWORD *services_ret)
1796 WINE_FIXME("\n");
1797 return ERROR_CALL_NOT_IMPLEMENTED;
1800 DWORD __cdecl svcctl_EnumServicesStatusA(
1801 SC_RPC_HANDLE hmngr,
1802 DWORD type,
1803 DWORD state,
1804 BYTE *buffer,
1805 DWORD size,
1806 DWORD *needed,
1807 DWORD *returned,
1808 DWORD *resume)
1810 WINE_FIXME("\n");
1811 return ERROR_CALL_NOT_IMPLEMENTED;
1814 DWORD __cdecl svcctl_OpenSCManagerA(
1815 MACHINE_HANDLEA MachineName,
1816 LPCSTR DatabaseName,
1817 DWORD dwAccessMask,
1818 SC_RPC_HANDLE *handle)
1820 WINE_FIXME("\n");
1821 return ERROR_CALL_NOT_IMPLEMENTED;
1824 DWORD __cdecl svcctl_OpenServiceA(
1825 SC_RPC_HANDLE hSCManager,
1826 LPCSTR lpServiceName,
1827 DWORD dwDesiredAccess,
1828 SC_RPC_HANDLE *phService)
1830 WINE_FIXME("\n");
1831 return ERROR_CALL_NOT_IMPLEMENTED;
1834 DWORD __cdecl svcctl_QueryServiceConfigA(
1835 SC_RPC_HANDLE hService,
1836 QUERY_SERVICE_CONFIGA *config,
1837 DWORD buf_size,
1838 DWORD *needed_size)
1840 WINE_FIXME("\n");
1841 return ERROR_CALL_NOT_IMPLEMENTED;
1844 DWORD __cdecl svcctl_QueryServiceLockStatusA(
1845 SC_RPC_HANDLE scmanager,
1846 QUERY_SERVICE_LOCK_STATUSA *status,
1847 DWORD buf_size,
1848 DWORD *needed_size)
1850 WINE_FIXME("\n");
1851 return ERROR_CALL_NOT_IMPLEMENTED;
1854 DWORD __cdecl svcctl_StartServiceA(
1855 SC_RPC_HANDLE service,
1856 DWORD argc,
1857 LPCSTR *args)
1859 WINE_FIXME("\n");
1860 return ERROR_CALL_NOT_IMPLEMENTED;
1863 DWORD __cdecl svcctl_GetServiceDisplayNameA(
1864 SC_RPC_HANDLE hSCManager,
1865 LPCSTR servicename,
1866 CHAR buffer[],
1867 DWORD *buf_size)
1869 WINE_FIXME("\n");
1870 return ERROR_CALL_NOT_IMPLEMENTED;
1873 DWORD __cdecl svcctl_GetServiceKeyNameA(
1874 SC_RPC_HANDLE hSCManager,
1875 LPCSTR servicename,
1876 CHAR buffer[],
1877 DWORD *buf_size)
1879 WINE_FIXME("\n");
1880 return ERROR_CALL_NOT_IMPLEMENTED;
1883 DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
1885 WINE_FIXME("\n");
1886 return ERROR_CALL_NOT_IMPLEMENTED;
1889 DWORD __cdecl svcctl_EnumServiceGroupW(
1890 SC_RPC_HANDLE scmanager,
1891 DWORD service_type,
1892 DWORD service_state,
1893 BYTE *buffer,
1894 DWORD buf_size,
1895 DWORD *needed_size,
1896 DWORD *returned_size,
1897 DWORD *resume_index,
1898 LPCWSTR groupname)
1900 WINE_FIXME("\n");
1901 return ERROR_CALL_NOT_IMPLEMENTED;
1904 DWORD __cdecl svcctl_ChangeServiceConfig2A(
1905 SC_RPC_HANDLE service,
1906 SC_RPC_CONFIG_INFOA info)
1908 WINE_FIXME("\n");
1909 return ERROR_CALL_NOT_IMPLEMENTED;
1912 DWORD __cdecl svcctl_QueryServiceConfig2A(
1913 SC_RPC_HANDLE service,
1914 DWORD info_level,
1915 BYTE *buffer,
1916 DWORD buf_size,
1917 DWORD *needed_size)
1919 WINE_FIXME("\n");
1920 return ERROR_CALL_NOT_IMPLEMENTED;
1923 DWORD RPC_Init(void)
1925 WCHAR transport[] = SVCCTL_TRANSPORT;
1926 WCHAR endpoint[] = SVCCTL_ENDPOINT;
1927 DWORD err;
1929 if (!(cleanup_group = CreateThreadpoolCleanupGroup()))
1931 WINE_ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
1932 return GetLastError();
1935 if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1937 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1938 return err;
1941 if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1943 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1944 return err;
1947 if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1949 WINE_ERR("RpcServerListen failed with error %u\n", err);
1950 return err;
1953 exit_event = __wine_make_process_system();
1954 return ERROR_SUCCESS;
1957 void RPC_Stop(void)
1959 RpcMgmtStopServerListening(NULL);
1960 RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
1962 CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
1963 CloseThreadpoolCleanupGroup(cleanup_group);
1964 CloseHandle(exit_event);
1967 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
1969 SC_RPC_HANDLE_destroy(handle);
1972 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
1976 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
1978 return HeapAlloc(GetProcessHeap(), 0, len);
1981 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
1983 HeapFree(GetProcessHeap(), 0, ptr);