libport: Add a replacement implementation for strnlen.
[wine.git] / programs / services / rpc.c
blob20c5a2761f3cc0b5cc54b784514705d9bd477bfa
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)
830 break;
832 if (config.u.descr->lpDescription[0])
834 if (!(descr = strdupW( config.u.descr->lpDescription )))
835 return ERROR_NOT_ENOUGH_MEMORY;
838 WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
839 service_lock( service->service_entry );
840 HeapFree( GetProcessHeap(), 0, service->service_entry->description );
841 service->service_entry->description = descr;
842 save_service_config( service->service_entry );
843 service_unlock( service->service_entry );
845 break;
846 case SERVICE_CONFIG_FAILURE_ACTIONS:
847 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
848 config.u.actions->dwResetPeriod,
849 wine_dbgstr_w(config.u.actions->lpRebootMsg),
850 wine_dbgstr_w(config.u.actions->lpCommand) );
851 break;
852 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
853 WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
854 service, config.u.preshutdown->dwPreshutdownTimeout );
855 service_lock( service->service_entry );
856 service->service_entry->preshutdown_timeout = config.u.preshutdown->dwPreshutdownTimeout;
857 save_service_config( service->service_entry );
858 service_unlock( service->service_entry );
859 break;
860 default:
861 WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
862 err = ERROR_INVALID_LEVEL;
863 break;
865 return err;
868 DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
869 BYTE *buffer, DWORD size, LPDWORD needed )
871 struct sc_service_handle *service;
872 DWORD err;
874 memset(buffer, 0, size);
876 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
877 return err;
879 switch (level)
881 case SERVICE_CONFIG_DESCRIPTION:
883 struct service_description *desc = (struct service_description *)buffer;
884 DWORD total_size = sizeof(*desc);
886 service_lock(service->service_entry);
887 if (service->service_entry->description)
888 total_size += strlenW(service->service_entry->description) * sizeof(WCHAR);
890 *needed = total_size;
891 if (size >= total_size)
893 if (service->service_entry->description)
895 strcpyW( desc->description, service->service_entry->description );
896 desc->size = total_size - FIELD_OFFSET(struct service_description, description);
898 else
900 desc->description[0] = 0;
901 desc->size = 0;
904 else err = ERROR_INSUFFICIENT_BUFFER;
905 service_unlock(service->service_entry);
907 break;
909 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
910 service_lock(service->service_entry);
912 *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
913 if (size >= *needed)
914 ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
915 service->service_entry->preshutdown_timeout;
916 else err = ERROR_INSUFFICIENT_BUFFER;
918 service_unlock(service->service_entry);
919 break;
921 default:
922 WINE_FIXME("level %u not implemented\n", level);
923 err = ERROR_INVALID_LEVEL;
924 break;
926 return err;
929 static void fill_status_process(SERVICE_STATUS_PROCESS *status, struct service_entry *service)
931 struct process_entry *process = service->process;
932 memcpy(status, &service->status, sizeof(service->status));
933 status->dwProcessId = process ? process->process_id : 0;
934 status->dwServiceFlags = 0;
937 DWORD __cdecl svcctl_QueryServiceStatusEx(
938 SC_RPC_HANDLE hService,
939 SC_STATUS_TYPE InfoLevel,
940 BYTE *lpBuffer,
941 DWORD cbBufSize,
942 LPDWORD pcbBytesNeeded)
944 struct sc_service_handle *service;
945 DWORD err;
946 LPSERVICE_STATUS_PROCESS pSvcStatusData;
948 memset(lpBuffer, 0, cbBufSize);
950 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
951 return err;
953 if (InfoLevel != SC_STATUS_PROCESS_INFO)
954 return ERROR_INVALID_LEVEL;
956 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
957 if (pSvcStatusData == NULL)
958 return ERROR_INVALID_PARAMETER;
960 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
962 if( pcbBytesNeeded != NULL)
963 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
965 return ERROR_INSUFFICIENT_BUFFER;
968 service_lock(service->service_entry);
969 fill_status_process(pSvcStatusData, service->service_entry);
970 service_unlock(service->service_entry);
972 return ERROR_SUCCESS;
975 /******************************************************************************
976 * service_accepts_control
978 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
980 DWORD a = service->status.dwControlsAccepted;
982 if (dwControl >= 128 && dwControl <= 255)
983 return TRUE;
985 switch (dwControl)
987 case SERVICE_CONTROL_INTERROGATE:
988 return TRUE;
989 case SERVICE_CONTROL_STOP:
990 if (a&SERVICE_ACCEPT_STOP)
991 return TRUE;
992 break;
993 case SERVICE_CONTROL_SHUTDOWN:
994 if (a&SERVICE_ACCEPT_SHUTDOWN)
995 return TRUE;
996 break;
997 case SERVICE_CONTROL_PAUSE:
998 case SERVICE_CONTROL_CONTINUE:
999 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
1000 return TRUE;
1001 break;
1002 case SERVICE_CONTROL_PARAMCHANGE:
1003 if (a&SERVICE_ACCEPT_PARAMCHANGE)
1004 return TRUE;
1005 break;
1006 case SERVICE_CONTROL_NETBINDADD:
1007 case SERVICE_CONTROL_NETBINDREMOVE:
1008 case SERVICE_CONTROL_NETBINDENABLE:
1009 case SERVICE_CONTROL_NETBINDDISABLE:
1010 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
1011 return TRUE;
1012 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
1013 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
1014 return TRUE;
1015 break;
1016 case SERVICE_CONTROL_POWEREVENT:
1017 if (a&SERVICE_ACCEPT_POWEREVENT)
1018 return TRUE;
1019 break;
1020 case SERVICE_CONTROL_SESSIONCHANGE:
1021 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
1022 return TRUE;
1023 break;
1025 return FALSE;
1028 /******************************************************************************
1029 * process_send_command
1031 static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
1033 OVERLAPPED overlapped;
1034 DWORD count, ret;
1035 BOOL r;
1037 overlapped.hEvent = process->overlapped_event;
1038 r = WriteFile(process->control_pipe, data, size, &count, &overlapped);
1039 if (!r && GetLastError() == ERROR_IO_PENDING)
1041 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1042 if (ret == WAIT_TIMEOUT)
1044 WINE_ERR("sending command timed out\n");
1045 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1046 return FALSE;
1048 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1050 if (!r || count != size)
1052 WINE_ERR("service protocol error - failed to write pipe!\n");
1053 *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
1054 return FALSE;
1056 r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped);
1057 if (!r && GetLastError() == ERROR_IO_PENDING)
1059 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1060 if (ret == WAIT_TIMEOUT)
1062 WINE_ERR("receiving command result timed out\n");
1063 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1064 return FALSE;
1066 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1068 if (!r || count != sizeof *result)
1070 WINE_ERR("service protocol error - failed to read pipe "
1071 "r = %d count = %d!\n", r, count);
1072 *result = (!r ? GetLastError() : ERROR_READ_FAULT);
1073 return FALSE;
1076 return TRUE;
1079 /******************************************************************************
1080 * process_send_control
1082 BOOL process_send_control(struct process_entry *process, BOOL shared_process, const WCHAR *name,
1083 DWORD control, const BYTE *data, DWORD data_size, DWORD *result)
1085 service_start_info *ssi;
1086 DWORD len;
1087 BOOL r;
1089 if (shared_process)
1091 control |= SERVICE_CONTROL_FORWARD_FLAG;
1092 data = (BYTE *)name;
1093 data_size = (strlenW(name) + 1) * sizeof(WCHAR);
1094 name = emptyW;
1097 /* calculate how much space we need to send the startup info */
1098 len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size;
1100 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
1101 ssi->magic = SERVICE_PROTOCOL_MAGIC;
1102 ssi->control = control;
1103 ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
1104 ssi->name_size = strlenW(name) + 1;
1105 strcpyW((WCHAR *)ssi->data, name);
1106 if (data_size) memcpy(&ssi->data[ssi->name_size * sizeof(WCHAR)], data, data_size);
1108 r = process_send_command(process, ssi, ssi->total_size, result);
1109 HeapFree( GetProcessHeap(), 0, ssi );
1110 return r;
1113 DWORD __cdecl svcctl_StartServiceW(
1114 SC_RPC_HANDLE hService,
1115 DWORD dwNumServiceArgs,
1116 LPCWSTR *lpServiceArgVectors)
1118 struct sc_service_handle *service;
1119 DWORD err;
1121 WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1123 if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
1124 return err;
1126 if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
1127 return ERROR_SERVICE_DISABLED;
1129 if (!scmdatabase_lock_startup(service->service_entry->db))
1130 return ERROR_SERVICE_DATABASE_LOCKED;
1132 err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
1134 scmdatabase_unlock_startup(service->service_entry->db);
1135 return err;
1138 DWORD __cdecl svcctl_ControlService(
1139 SC_RPC_HANDLE hService,
1140 DWORD dwControl,
1141 SERVICE_STATUS *lpServiceStatus)
1143 DWORD access_required;
1144 struct sc_service_handle *service;
1145 struct process_entry *process;
1146 BOOL shared_process;
1147 DWORD result;
1149 WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
1151 switch (dwControl)
1153 case SERVICE_CONTROL_CONTINUE:
1154 case SERVICE_CONTROL_NETBINDADD:
1155 case SERVICE_CONTROL_NETBINDDISABLE:
1156 case SERVICE_CONTROL_NETBINDENABLE:
1157 case SERVICE_CONTROL_NETBINDREMOVE:
1158 case SERVICE_CONTROL_PARAMCHANGE:
1159 case SERVICE_CONTROL_PAUSE:
1160 access_required = SERVICE_PAUSE_CONTINUE;
1161 break;
1162 case SERVICE_CONTROL_INTERROGATE:
1163 access_required = SERVICE_INTERROGATE;
1164 break;
1165 case SERVICE_CONTROL_STOP:
1166 access_required = SERVICE_STOP;
1167 break;
1168 default:
1169 if (dwControl >= 128 && dwControl <= 255)
1170 access_required = SERVICE_USER_DEFINED_CONTROL;
1171 else
1172 return ERROR_INVALID_PARAMETER;
1175 if ((result = validate_service_handle(hService, access_required, &service)) != 0)
1176 return result;
1178 service_lock(service->service_entry);
1180 result = ERROR_SUCCESS;
1181 switch (service->service_entry->status.dwCurrentState)
1183 case SERVICE_STOPPED:
1184 result = ERROR_SERVICE_NOT_ACTIVE;
1185 break;
1186 case SERVICE_START_PENDING:
1187 if (dwControl==SERVICE_CONTROL_STOP)
1188 break;
1189 /* fall through */
1190 case SERVICE_STOP_PENDING:
1191 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1192 break;
1195 if (result == ERROR_SUCCESS && service->service_entry->force_shutdown)
1197 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1198 if ((process = service->service_entry->process))
1200 service->service_entry->process = NULL;
1201 if (!--process->use_count) process_terminate(process);
1202 release_process(process);
1206 if (result != ERROR_SUCCESS)
1208 if (lpServiceStatus) *lpServiceStatus = service->service_entry->status;
1209 service_unlock(service->service_entry);
1210 return result;
1213 if (!service_accepts_control(service->service_entry, dwControl))
1215 service_unlock(service->service_entry);
1216 return ERROR_INVALID_SERVICE_CONTROL;
1219 /* Remember that we tried to shutdown this service. When the service is
1220 * still running on the second invocation, it will be forcefully killed. */
1221 if (dwControl == SERVICE_CONTROL_STOP)
1222 service->service_entry->force_shutdown = TRUE;
1224 /* Hold a reference to the process while sending the command. */
1225 process = grab_process(service->service_entry->process);
1226 shared_process = service->service_entry->shared_process;
1227 service_unlock(service->service_entry);
1229 if (!process)
1230 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1232 result = WaitForSingleObject(process->control_mutex, 30000);
1233 if (result != WAIT_OBJECT_0)
1235 release_process(process);
1236 return ERROR_SERVICE_REQUEST_TIMEOUT;
1239 if (process_send_control(process, shared_process, service->service_entry->name,
1240 dwControl, NULL, 0, &result))
1241 result = ERROR_SUCCESS;
1243 if (lpServiceStatus)
1245 service_lock(service->service_entry);
1246 *lpServiceStatus = service->service_entry->status;
1247 service_unlock(service->service_entry);
1250 ReleaseMutex(process->control_mutex);
1251 release_process(process);
1252 return result;
1255 DWORD __cdecl svcctl_CloseServiceHandle(
1256 SC_RPC_HANDLE *handle)
1258 WINE_TRACE("(&%p)\n", *handle);
1260 SC_RPC_HANDLE_destroy(*handle);
1261 *handle = NULL;
1263 return ERROR_SUCCESS;
1266 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
1268 struct sc_lock *lock = hLock;
1269 scmdatabase_unlock_startup(lock->db);
1270 HeapFree(GetProcessHeap(), 0, lock);
1273 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
1275 SC_RPC_LOCK_destroy(hLock);
1278 DWORD __cdecl svcctl_LockServiceDatabase(
1279 SC_RPC_HANDLE hSCManager,
1280 SC_RPC_LOCK *phLock)
1282 struct sc_manager_handle *manager;
1283 struct sc_lock *lock;
1284 DWORD err;
1286 WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
1288 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
1289 return err;
1291 if (!scmdatabase_lock_startup(manager->db))
1292 return ERROR_SERVICE_DATABASE_LOCKED;
1294 lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
1295 if (!lock)
1297 scmdatabase_unlock_startup(manager->db);
1298 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
1301 lock->db = manager->db;
1302 *phLock = lock;
1304 return ERROR_SUCCESS;
1307 DWORD __cdecl svcctl_UnlockServiceDatabase(
1308 SC_RPC_LOCK *phLock)
1310 WINE_TRACE("(&%p)\n", *phLock);
1312 SC_RPC_LOCK_destroy(*phLock);
1313 *phLock = NULL;
1315 return ERROR_SUCCESS;
1318 static BOOL map_state(DWORD state, DWORD mask)
1320 switch (state)
1322 case SERVICE_START_PENDING:
1323 case SERVICE_STOP_PENDING:
1324 case SERVICE_RUNNING:
1325 case SERVICE_CONTINUE_PENDING:
1326 case SERVICE_PAUSE_PENDING:
1327 case SERVICE_PAUSED:
1328 if (SERVICE_ACTIVE & mask) return TRUE;
1329 break;
1330 case SERVICE_STOPPED:
1331 if (SERVICE_INACTIVE & mask) return TRUE;
1332 break;
1333 default:
1334 WINE_ERR("unknown state %u\n", state);
1335 break;
1337 return FALSE;
1340 DWORD __cdecl svcctl_EnumServicesStatusW(
1341 SC_RPC_HANDLE hmngr,
1342 DWORD type,
1343 DWORD state,
1344 BYTE *buffer,
1345 DWORD size,
1346 LPDWORD needed,
1347 LPDWORD returned,
1348 LPDWORD resume)
1350 DWORD err, sz, total_size, num_services, offset;
1351 struct sc_manager_handle *manager;
1352 struct service_entry *service;
1353 struct enum_service_status *s;
1355 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
1357 if (!type || !state)
1358 return ERROR_INVALID_PARAMETER;
1360 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1361 return err;
1363 if (resume)
1364 WINE_FIXME("resume index not supported\n");
1366 scmdatabase_lock(manager->db);
1368 total_size = num_services = 0;
1369 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1371 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1373 total_size += sizeof(*s);
1374 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1375 if (service->config.lpDisplayName)
1377 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1379 num_services++;
1382 *returned = 0;
1383 *needed = total_size;
1384 if (total_size > size)
1386 scmdatabase_unlock(manager->db);
1387 return ERROR_MORE_DATA;
1389 s = (struct enum_service_status *)buffer;
1390 offset = num_services * sizeof(struct enum_service_status);
1391 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1393 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1395 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1396 memcpy(buffer + offset, service->name, sz);
1397 s->service_name = offset;
1398 offset += sz;
1400 if (!service->config.lpDisplayName) s->display_name = 0;
1401 else
1403 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1404 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1405 s->display_name = offset;
1406 offset += sz;
1408 s->service_status = service->status;
1409 s++;
1412 *returned = num_services;
1413 *needed = 0;
1414 scmdatabase_unlock(manager->db);
1415 return ERROR_SUCCESS;
1418 static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
1420 struct service_entry *service;
1421 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
1423 if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
1424 return service;
1426 return NULL;
1429 static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
1431 if (!g2) return TRUE;
1432 if (!g2[0] && (!g1 || !g1[0])) return TRUE;
1433 if (g1 && !strcmpW(g1, g2)) return TRUE;
1434 return FALSE;
1437 DWORD __cdecl svcctl_EnumServicesStatusExA(
1438 SC_RPC_HANDLE scmanager,
1439 SC_ENUM_TYPE info_level,
1440 DWORD service_type,
1441 DWORD service_state,
1442 BYTE *buffer,
1443 DWORD buf_size,
1444 DWORD *needed_size,
1445 DWORD *services_count,
1446 DWORD *resume_index,
1447 LPCSTR groupname)
1449 WINE_FIXME("\n");
1450 return ERROR_CALL_NOT_IMPLEMENTED;
1453 DWORD __cdecl svcctl_EnumServicesStatusExW(
1454 SC_RPC_HANDLE hmngr,
1455 SC_ENUM_TYPE info_level,
1456 DWORD type,
1457 DWORD state,
1458 BYTE *buffer,
1459 DWORD size,
1460 LPDWORD needed,
1461 LPDWORD returned,
1462 DWORD *resume_handle,
1463 LPCWSTR group)
1465 DWORD err, sz, total_size, num_services;
1466 DWORD_PTR offset;
1467 struct sc_manager_handle *manager;
1468 struct service_entry *service;
1469 struct enum_service_status_process *s;
1471 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
1472 needed, returned, wine_dbgstr_w(group));
1474 if (resume_handle)
1475 FIXME("resume handle not supported\n");
1477 if (!type || !state)
1478 return ERROR_INVALID_PARAMETER;
1480 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1481 return err;
1483 scmdatabase_lock(manager->db);
1485 if (group && !find_service_by_group(manager->db, group))
1487 scmdatabase_unlock(manager->db);
1488 return ERROR_SERVICE_DOES_NOT_EXIST;
1491 total_size = num_services = 0;
1492 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1494 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1495 && match_group(service->config.lpLoadOrderGroup, group))
1497 total_size += sizeof(*s);
1498 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1499 if (service->config.lpDisplayName)
1501 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1503 num_services++;
1506 *returned = 0;
1507 *needed = total_size;
1508 if (total_size > size)
1510 scmdatabase_unlock(manager->db);
1511 return ERROR_MORE_DATA;
1513 s = (struct enum_service_status_process *)buffer;
1514 offset = num_services * sizeof(*s);
1515 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1517 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1518 && match_group(service->config.lpLoadOrderGroup, group))
1520 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1521 memcpy(buffer + offset, service->name, sz);
1522 s->service_name = offset;
1523 offset += sz;
1525 if (!service->config.lpDisplayName) s->display_name = 0;
1526 else
1528 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1529 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1530 s->display_name = offset;
1531 offset += sz;
1533 fill_status_process(&s->service_status_process, service);
1534 s++;
1537 *returned = num_services;
1538 *needed = 0;
1539 scmdatabase_unlock(manager->db);
1540 return ERROR_SUCCESS;
1543 DWORD __cdecl svcctl_unknown43(void)
1545 WINE_FIXME("\n");
1546 return ERROR_CALL_NOT_IMPLEMENTED;
1549 DWORD __cdecl svcctl_CreateServiceWOW64A(
1550 SC_RPC_HANDLE scmanager,
1551 LPCSTR servicename,
1552 LPCSTR displayname,
1553 DWORD accessmask,
1554 DWORD service_type,
1555 DWORD start_type,
1556 DWORD error_control,
1557 LPCSTR imagepath,
1558 LPCSTR loadordergroup,
1559 DWORD *tagid,
1560 const BYTE *dependencies,
1561 DWORD depend_size,
1562 LPCSTR start_name,
1563 const BYTE *password,
1564 DWORD password_size,
1565 SC_RPC_HANDLE *service)
1567 WINE_FIXME("\n");
1568 return ERROR_CALL_NOT_IMPLEMENTED;
1571 DWORD __cdecl svcctl_CreateServiceWOW64W(
1572 SC_RPC_HANDLE scmanager,
1573 LPCWSTR servicename,
1574 LPCWSTR displayname,
1575 DWORD accessmask,
1576 DWORD service_type,
1577 DWORD start_type,
1578 DWORD error_control,
1579 LPCWSTR imagepath,
1580 LPCWSTR loadordergroup,
1581 DWORD *tagid,
1582 const BYTE *dependencies,
1583 DWORD depend_size,
1584 LPCWSTR start_name,
1585 const BYTE *password,
1586 DWORD password_size,
1587 SC_RPC_HANDLE *service)
1589 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
1590 return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
1591 loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
1594 DWORD __cdecl svcctl_unknown46(void)
1596 WINE_FIXME("\n");
1597 return ERROR_CALL_NOT_IMPLEMENTED;
1600 DWORD __cdecl svcctl_NotifyServiceStatusChange(
1601 SC_RPC_HANDLE service,
1602 SC_RPC_NOTIFY_PARAMS params,
1603 GUID *clientprocessguid,
1604 GUID *scmprocessguid,
1605 BOOL *createremotequeue,
1606 SC_NOTIFY_RPC_HANDLE *notify)
1608 WINE_FIXME("\n");
1609 return ERROR_CALL_NOT_IMPLEMENTED;
1612 DWORD __cdecl svcctl_GetNotifyResults(
1613 SC_NOTIFY_RPC_HANDLE notify,
1614 SC_RPC_NOTIFY_PARAMS_LIST **params)
1616 WINE_FIXME("\n");
1617 return ERROR_CALL_NOT_IMPLEMENTED;
1620 DWORD __cdecl svcctl_CloseNotifyHandle(
1621 SC_NOTIFY_RPC_HANDLE *notify,
1622 BOOL *apc_fired)
1624 WINE_FIXME("\n");
1625 return ERROR_CALL_NOT_IMPLEMENTED;
1628 DWORD __cdecl svcctl_ControlServiceExA(
1629 SC_RPC_HANDLE service,
1630 DWORD control,
1631 DWORD info_level,
1632 SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
1633 SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
1635 WINE_FIXME("\n");
1636 return ERROR_CALL_NOT_IMPLEMENTED;
1639 DWORD __cdecl svcctl_ControlServiceExW(
1640 SC_RPC_HANDLE service,
1641 DWORD control,
1642 DWORD info_level,
1643 SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
1644 SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
1646 WINE_FIXME("\n");
1647 return ERROR_CALL_NOT_IMPLEMENTED;
1650 DWORD __cdecl svcctl_unknown52(void)
1652 WINE_FIXME("\n");
1653 return ERROR_CALL_NOT_IMPLEMENTED;
1656 DWORD __cdecl svcctl_unknown53(void)
1658 WINE_FIXME("\n");
1659 return ERROR_CALL_NOT_IMPLEMENTED;
1662 DWORD __cdecl svcctl_unknown54(void)
1664 WINE_FIXME("\n");
1665 return ERROR_CALL_NOT_IMPLEMENTED;
1668 DWORD __cdecl svcctl_unknown55(void)
1670 WINE_FIXME("\n");
1671 return ERROR_CALL_NOT_IMPLEMENTED;
1674 DWORD __cdecl svcctl_QueryServiceConfigEx(
1675 SC_RPC_HANDLE service,
1676 DWORD info_level,
1677 SC_RPC_CONFIG_INFOW *info)
1679 WINE_FIXME("\n");
1680 return ERROR_CALL_NOT_IMPLEMENTED;
1683 DWORD __cdecl svcctl_QueryServiceObjectSecurity(
1684 SC_RPC_HANDLE service,
1685 SECURITY_INFORMATION info,
1686 BYTE *descriptor,
1687 DWORD buf_size,
1688 DWORD *needed_size)
1690 WINE_FIXME("\n");
1691 return ERROR_CALL_NOT_IMPLEMENTED;
1694 DWORD __cdecl svcctl_SetServiceObjectSecurity(
1695 SC_RPC_HANDLE service,
1696 SECURITY_INFORMATION info,
1697 BYTE *descriptor,
1698 DWORD buf_size)
1700 WINE_FIXME("\n");
1701 return ERROR_CALL_NOT_IMPLEMENTED;
1704 DWORD __cdecl svcctl_QueryServiceStatus(
1705 SC_RPC_HANDLE service,
1706 SERVICE_STATUS *status)
1708 WINE_FIXME("\n");
1709 return ERROR_CALL_NOT_IMPLEMENTED;
1712 DWORD __cdecl svcctl_NotifyBootConfigStatus(
1713 SVCCTL_HANDLEW machinename,
1714 DWORD boot_acceptable)
1716 WINE_FIXME("\n");
1717 return ERROR_CALL_NOT_IMPLEMENTED;
1720 DWORD __cdecl svcctl_SCSetServiceBitsW(void)
1722 WINE_FIXME("\n");
1723 return ERROR_CALL_NOT_IMPLEMENTED;
1726 DWORD __cdecl svcctl_EnumDependentServicesW(
1727 SC_RPC_HANDLE service,
1728 DWORD state,
1729 BYTE *services,
1730 DWORD buf_size,
1731 DWORD *needed_size,
1732 DWORD *services_ret)
1734 WINE_FIXME("\n");
1735 return ERROR_CALL_NOT_IMPLEMENTED;
1738 DWORD __cdecl svcctl_QueryServiceLockStatusW(
1739 SC_RPC_HANDLE scmanager,
1740 QUERY_SERVICE_LOCK_STATUSW *status,
1741 DWORD buf_size,
1742 DWORD *needed_size)
1744 WINE_FIXME("\n");
1745 return ERROR_CALL_NOT_IMPLEMENTED;
1748 DWORD __cdecl svcctl_SCSetServiceBitsA(void)
1750 WINE_FIXME("\n");
1751 return ERROR_CALL_NOT_IMPLEMENTED;
1754 DWORD __cdecl svcctl_ChangeServiceConfigA(
1755 SC_RPC_HANDLE service,
1756 DWORD service_type,
1757 DWORD start_type,
1758 DWORD error_control,
1759 LPSTR binarypath,
1760 LPSTR loadordergroup,
1761 DWORD *tagid,
1762 BYTE *dependencies,
1763 DWORD depend_size,
1764 LPSTR startname,
1765 BYTE *password,
1766 DWORD password_size,
1767 LPSTR displayname)
1769 WINE_FIXME("\n");
1770 return ERROR_CALL_NOT_IMPLEMENTED;
1773 DWORD __cdecl svcctl_CreateServiceA(
1774 SC_RPC_HANDLE scmanager,
1775 LPCSTR servicename,
1776 LPCSTR displayname,
1777 DWORD desiredaccess,
1778 DWORD service_type,
1779 DWORD start_type,
1780 DWORD error_control,
1781 LPCSTR binarypath,
1782 LPCSTR loadordergroup,
1783 DWORD *tagid,
1784 const BYTE *dependencies,
1785 DWORD depend_size,
1786 LPCSTR startname,
1787 const BYTE *password,
1788 DWORD password_size,
1789 SC_RPC_HANDLE *service)
1791 WINE_FIXME("\n");
1792 return ERROR_CALL_NOT_IMPLEMENTED;
1795 DWORD __cdecl svcctl_EnumDependentServicesA(
1796 SC_RPC_HANDLE service,
1797 DWORD state,
1798 BYTE *services,
1799 DWORD buf_size,
1800 DWORD *needed_size,
1801 DWORD *services_ret)
1803 WINE_FIXME("\n");
1804 return ERROR_CALL_NOT_IMPLEMENTED;
1807 DWORD __cdecl svcctl_EnumServicesStatusA(
1808 SC_RPC_HANDLE hmngr,
1809 DWORD type,
1810 DWORD state,
1811 BYTE *buffer,
1812 DWORD size,
1813 DWORD *needed,
1814 DWORD *returned,
1815 DWORD *resume)
1817 WINE_FIXME("\n");
1818 return ERROR_CALL_NOT_IMPLEMENTED;
1821 DWORD __cdecl svcctl_OpenSCManagerA(
1822 MACHINE_HANDLEA MachineName,
1823 LPCSTR DatabaseName,
1824 DWORD dwAccessMask,
1825 SC_RPC_HANDLE *handle)
1827 WINE_FIXME("\n");
1828 return ERROR_CALL_NOT_IMPLEMENTED;
1831 DWORD __cdecl svcctl_OpenServiceA(
1832 SC_RPC_HANDLE hSCManager,
1833 LPCSTR lpServiceName,
1834 DWORD dwDesiredAccess,
1835 SC_RPC_HANDLE *phService)
1837 WINE_FIXME("\n");
1838 return ERROR_CALL_NOT_IMPLEMENTED;
1841 DWORD __cdecl svcctl_QueryServiceConfigA(
1842 SC_RPC_HANDLE hService,
1843 QUERY_SERVICE_CONFIGA *config,
1844 DWORD buf_size,
1845 DWORD *needed_size)
1847 WINE_FIXME("\n");
1848 return ERROR_CALL_NOT_IMPLEMENTED;
1851 DWORD __cdecl svcctl_QueryServiceLockStatusA(
1852 SC_RPC_HANDLE scmanager,
1853 QUERY_SERVICE_LOCK_STATUSA *status,
1854 DWORD buf_size,
1855 DWORD *needed_size)
1857 WINE_FIXME("\n");
1858 return ERROR_CALL_NOT_IMPLEMENTED;
1861 DWORD __cdecl svcctl_StartServiceA(
1862 SC_RPC_HANDLE service,
1863 DWORD argc,
1864 LPCSTR *args)
1866 WINE_FIXME("\n");
1867 return ERROR_CALL_NOT_IMPLEMENTED;
1870 DWORD __cdecl svcctl_GetServiceDisplayNameA(
1871 SC_RPC_HANDLE hSCManager,
1872 LPCSTR servicename,
1873 CHAR buffer[],
1874 DWORD *buf_size)
1876 WINE_FIXME("\n");
1877 return ERROR_CALL_NOT_IMPLEMENTED;
1880 DWORD __cdecl svcctl_GetServiceKeyNameA(
1881 SC_RPC_HANDLE hSCManager,
1882 LPCSTR servicename,
1883 CHAR buffer[],
1884 DWORD *buf_size)
1886 WINE_FIXME("\n");
1887 return ERROR_CALL_NOT_IMPLEMENTED;
1890 DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
1892 WINE_FIXME("\n");
1893 return ERROR_CALL_NOT_IMPLEMENTED;
1896 DWORD __cdecl svcctl_EnumServiceGroupW(
1897 SC_RPC_HANDLE scmanager,
1898 DWORD service_type,
1899 DWORD service_state,
1900 BYTE *buffer,
1901 DWORD buf_size,
1902 DWORD *needed_size,
1903 DWORD *returned_size,
1904 DWORD *resume_index,
1905 LPCWSTR groupname)
1907 WINE_FIXME("\n");
1908 return ERROR_CALL_NOT_IMPLEMENTED;
1911 DWORD __cdecl svcctl_ChangeServiceConfig2A(
1912 SC_RPC_HANDLE service,
1913 SC_RPC_CONFIG_INFOA info)
1915 WINE_FIXME("\n");
1916 return ERROR_CALL_NOT_IMPLEMENTED;
1919 DWORD __cdecl svcctl_QueryServiceConfig2A(
1920 SC_RPC_HANDLE service,
1921 DWORD info_level,
1922 BYTE *buffer,
1923 DWORD buf_size,
1924 DWORD *needed_size)
1926 WINE_FIXME("\n");
1927 return ERROR_CALL_NOT_IMPLEMENTED;
1930 DWORD RPC_Init(void)
1932 WCHAR transport[] = SVCCTL_TRANSPORT;
1933 WCHAR endpoint[] = SVCCTL_ENDPOINT;
1934 DWORD err;
1936 if (!(cleanup_group = CreateThreadpoolCleanupGroup()))
1938 WINE_ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
1939 return GetLastError();
1942 if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1944 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1945 return err;
1948 if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1950 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1951 return err;
1954 if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1956 WINE_ERR("RpcServerListen failed with error %u\n", err);
1957 return err;
1960 exit_event = __wine_make_process_system();
1961 return ERROR_SUCCESS;
1964 void RPC_Stop(void)
1966 RpcMgmtStopServerListening(NULL);
1967 RpcServerUnregisterIf(svcctl_v2_0_s_ifspec, NULL, TRUE);
1968 RpcMgmtWaitServerListen();
1970 CloseThreadpoolCleanupGroupMembers(cleanup_group, TRUE, NULL);
1971 CloseThreadpoolCleanupGroup(cleanup_group);
1972 CloseHandle(exit_event);
1975 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
1977 SC_RPC_HANDLE_destroy(handle);
1980 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
1984 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
1986 return HeapAlloc(GetProcessHeap(), 0, len);
1989 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
1991 HeapFree(GetProcessHeap(), 0, ptr);