services: Initialize service ref_count directly in service_create.
[wine.git] / programs / services / rpc.c
blobcdac9484555535c608d85df38ec98762feffa9a4
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 HANDLE timeout_queue_event;
89 static CRITICAL_SECTION timeout_queue_cs;
90 static CRITICAL_SECTION_DEBUG timeout_queue_cs_debug =
92 0, 0, &timeout_queue_cs,
93 { &timeout_queue_cs_debug.ProcessLocksList, &timeout_queue_cs_debug.ProcessLocksList },
94 0, 0, { (DWORD_PTR)(__FILE__ ": timeout_queue_cs") }
96 static CRITICAL_SECTION timeout_queue_cs = { &timeout_queue_cs_debug, -1, 0, 0, 0, 0 };
97 static struct list timeout_queue = LIST_INIT(timeout_queue);
98 struct timeout_queue_elem
100 struct list entry;
102 FILETIME time;
103 void (*func)(struct service_entry*);
104 struct service_entry *service_entry;
107 static void run_after_timeout(void (*func)(struct service_entry*), struct service_entry *service, DWORD timeout)
109 struct timeout_queue_elem *elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct timeout_queue_elem));
110 ULARGE_INTEGER time;
112 if(!elem) {
113 func(service);
114 return;
117 InterlockedIncrement(&service->ref_count);
118 elem->func = func;
119 elem->service_entry = service;
121 GetSystemTimeAsFileTime(&elem->time);
122 time.u.LowPart = elem->time.dwLowDateTime;
123 time.u.HighPart = elem->time.dwHighDateTime;
124 time.QuadPart += (ULONGLONG)timeout * 10000;
125 elem->time.dwLowDateTime = time.u.LowPart;
126 elem->time.dwHighDateTime = time.u.HighPart;
128 EnterCriticalSection(&timeout_queue_cs);
129 list_add_head(&timeout_queue, &elem->entry);
130 LeaveCriticalSection(&timeout_queue_cs);
132 SetEvent(timeout_queue_event);
135 static void free_service_strings(struct service_entry *old, struct service_entry *new)
137 QUERY_SERVICE_CONFIGW *old_cfg = &old->config;
138 QUERY_SERVICE_CONFIGW *new_cfg = &new->config;
140 if (old_cfg->lpBinaryPathName != new_cfg->lpBinaryPathName)
141 HeapFree(GetProcessHeap(), 0, old_cfg->lpBinaryPathName);
143 if (old_cfg->lpLoadOrderGroup != new_cfg->lpLoadOrderGroup)
144 HeapFree(GetProcessHeap(), 0, old_cfg->lpLoadOrderGroup);
146 if (old_cfg->lpServiceStartName != new_cfg->lpServiceStartName)
147 HeapFree(GetProcessHeap(), 0, old_cfg->lpServiceStartName);
149 if (old_cfg->lpDisplayName != new_cfg->lpDisplayName)
150 HeapFree(GetProcessHeap(), 0, old_cfg->lpDisplayName);
152 if (old->dependOnServices != new->dependOnServices)
153 HeapFree(GetProcessHeap(), 0, old->dependOnServices);
155 if (old->dependOnGroups != new->dependOnGroups)
156 HeapFree(GetProcessHeap(), 0, old->dependOnGroups);
159 /* Check if the given handle is of the required type and allows the requested access. */
160 static DWORD validate_context_handle(SC_RPC_HANDLE handle, DWORD type, DWORD needed_access, struct sc_handle **out_hdr)
162 struct sc_handle *hdr = handle;
164 if (type != SC_HTYPE_DONT_CARE && hdr->type != type)
166 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr->type, type);
167 return ERROR_INVALID_HANDLE;
170 if ((needed_access & hdr->access) != needed_access)
172 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr->access, needed_access);
173 return ERROR_ACCESS_DENIED;
176 *out_hdr = hdr;
177 return ERROR_SUCCESS;
180 static DWORD validate_scm_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_manager_handle **manager)
182 struct sc_handle *hdr;
183 DWORD err = validate_context_handle(handle, SC_HTYPE_MANAGER, needed_access, &hdr);
184 if (err == ERROR_SUCCESS)
185 *manager = (struct sc_manager_handle *)hdr;
186 return err;
189 static DWORD validate_service_handle(SC_RPC_HANDLE handle, DWORD needed_access, struct sc_service_handle **service)
191 struct sc_handle *hdr;
192 DWORD err = validate_context_handle(handle, SC_HTYPE_SERVICE, needed_access, &hdr);
193 if (err == ERROR_SUCCESS)
194 *service = (struct sc_service_handle *)hdr;
195 return err;
198 DWORD __cdecl svcctl_OpenSCManagerW(
199 MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
200 LPCWSTR DatabaseName,
201 DWORD dwAccessMask,
202 SC_RPC_HANDLE *handle)
204 struct sc_manager_handle *manager;
206 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
208 if (DatabaseName != NULL && DatabaseName[0])
210 if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
211 return ERROR_DATABASE_DOES_NOT_EXIST;
212 if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
213 return ERROR_INVALID_NAME;
216 if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
217 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
219 manager->hdr.type = SC_HTYPE_MANAGER;
221 if (dwAccessMask & MAXIMUM_ALLOWED)
222 dwAccessMask |= SC_MANAGER_ALL_ACCESS;
223 manager->hdr.access = dwAccessMask;
224 RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
225 manager->db = active_database;
226 *handle = &manager->hdr;
228 return ERROR_SUCCESS;
231 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
233 struct sc_handle *hdr = handle;
234 switch (hdr->type)
236 case SC_HTYPE_MANAGER:
238 struct sc_manager_handle *manager = (struct sc_manager_handle *)hdr;
239 HeapFree(GetProcessHeap(), 0, manager);
240 break;
242 case SC_HTYPE_SERVICE:
244 struct sc_service_handle *service = (struct sc_service_handle *)hdr;
245 release_service(service->service_entry);
246 HeapFree(GetProcessHeap(), 0, service);
247 break;
249 default:
250 WINE_ERR("invalid handle type %d\n", hdr->type);
251 RpcRaiseException(ERROR_INVALID_HANDLE);
255 DWORD __cdecl svcctl_GetServiceDisplayNameW(
256 SC_RPC_HANDLE hSCManager,
257 LPCWSTR lpServiceName,
258 WCHAR *lpBuffer,
259 DWORD *cchBufSize)
261 struct sc_manager_handle *manager;
262 struct service_entry *entry;
263 DWORD err;
265 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), *cchBufSize);
267 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
268 return err;
270 scmdatabase_lock(manager->db);
272 entry = scmdatabase_find_service(manager->db, lpServiceName);
273 if (entry != NULL)
275 LPCWSTR name;
276 int len;
277 name = get_display_name(entry);
278 len = strlenW(name);
279 if (len <= *cchBufSize)
281 err = ERROR_SUCCESS;
282 memcpy(lpBuffer, name, (len + 1)*sizeof(*name));
284 else
285 err = ERROR_INSUFFICIENT_BUFFER;
286 *cchBufSize = len;
288 else
289 err = ERROR_SERVICE_DOES_NOT_EXIST;
291 scmdatabase_unlock(manager->db);
293 if (err != ERROR_SUCCESS)
294 lpBuffer[0] = 0;
296 return err;
299 DWORD __cdecl svcctl_GetServiceKeyNameW(
300 SC_RPC_HANDLE hSCManager,
301 LPCWSTR lpServiceDisplayName,
302 WCHAR *lpBuffer,
303 DWORD *cchBufSize)
305 struct service_entry *entry;
306 struct sc_manager_handle *manager;
307 DWORD err;
309 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), *cchBufSize);
311 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
312 return err;
314 scmdatabase_lock(manager->db);
316 entry = scmdatabase_find_service_by_displayname(manager->db, lpServiceDisplayName);
317 if (entry != NULL)
319 int len;
320 len = strlenW(entry->name);
321 if (len <= *cchBufSize)
323 err = ERROR_SUCCESS;
324 memcpy(lpBuffer, entry->name, (len + 1)*sizeof(*entry->name));
326 else
327 err = ERROR_INSUFFICIENT_BUFFER;
328 *cchBufSize = len;
330 else
331 err = ERROR_SERVICE_DOES_NOT_EXIST;
333 scmdatabase_unlock(manager->db);
335 if (err != ERROR_SUCCESS)
336 lpBuffer[0] = 0;
338 return err;
341 static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
343 struct sc_service_handle *service;
345 if (!(service = HeapAlloc(GetProcessHeap(), 0, sizeof(*service))))
347 release_service(entry);
348 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
351 if (dwDesiredAccess & MAXIMUM_ALLOWED)
352 dwDesiredAccess |= SERVICE_ALL_ACCESS;
354 service->hdr.type = SC_HTYPE_SERVICE;
355 service->hdr.access = dwDesiredAccess;
356 RtlMapGenericMask(&service->hdr.access, &g_svc_generic);
357 service->service_entry = entry;
359 *phService = &service->hdr;
360 return ERROR_SUCCESS;
363 DWORD __cdecl svcctl_OpenServiceW(
364 SC_RPC_HANDLE hSCManager,
365 LPCWSTR lpServiceName,
366 DWORD dwDesiredAccess,
367 SC_RPC_HANDLE *phService)
369 struct sc_manager_handle *manager;
370 struct service_entry *entry;
371 DWORD err;
373 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName), dwDesiredAccess);
375 if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
376 return err;
377 if (!validate_service_name(lpServiceName))
378 return ERROR_INVALID_NAME;
380 scmdatabase_lock(manager->db);
381 entry = scmdatabase_find_service(manager->db, lpServiceName);
382 if (entry != NULL)
383 InterlockedIncrement(&entry->ref_count);
384 scmdatabase_unlock(manager->db);
386 if (entry == NULL)
387 return ERROR_SERVICE_DOES_NOT_EXIST;
389 return create_handle_for_service(entry, dwDesiredAccess, phService);
392 static DWORD parse_dependencies(const WCHAR *dependencies, struct service_entry *entry)
394 WCHAR *services = NULL, *groups, *s;
395 DWORD len, len_services = 0, len_groups = 0;
396 const WCHAR *ptr = dependencies;
398 if (!dependencies || !dependencies[0])
400 entry->dependOnServices = NULL;
401 entry->dependOnGroups = NULL;
402 return ERROR_SUCCESS;
405 while (*ptr)
407 len = strlenW(ptr) + 1;
408 if (ptr[0] == '+' && ptr[1])
409 len_groups += len - 1;
410 else
411 len_services += len;
412 ptr += len;
414 if (!len_services) entry->dependOnServices = NULL;
415 else
417 services = HeapAlloc(GetProcessHeap(), 0, (len_services + 1) * sizeof(WCHAR));
418 if (!services)
419 return ERROR_OUTOFMEMORY;
421 s = services;
422 ptr = dependencies;
423 while (*ptr)
425 len = strlenW(ptr) + 1;
426 if (*ptr != '+')
428 strcpyW(s, ptr);
429 s += len;
431 ptr += len;
433 *s = 0;
434 entry->dependOnServices = services;
436 if (!len_groups) entry->dependOnGroups = NULL;
437 else
439 groups = HeapAlloc(GetProcessHeap(), 0, (len_groups + 1) * sizeof(WCHAR));
440 if (!groups)
442 HeapFree(GetProcessHeap(), 0, services);
443 return ERROR_OUTOFMEMORY;
445 s = groups;
446 ptr = dependencies;
447 while (*ptr)
449 len = strlenW(ptr) + 1;
450 if (ptr[0] == '+' && ptr[1])
452 strcpyW(s, ptr + 1);
453 s += len - 1;
455 ptr += len;
457 *s = 0;
458 entry->dependOnGroups = groups;
461 return ERROR_SUCCESS;
464 static DWORD create_serviceW(
465 SC_RPC_HANDLE hSCManager,
466 LPCWSTR lpServiceName,
467 LPCWSTR lpDisplayName,
468 DWORD dwDesiredAccess,
469 DWORD dwServiceType,
470 DWORD dwStartType,
471 DWORD dwErrorControl,
472 LPCWSTR lpBinaryPathName,
473 LPCWSTR lpLoadOrderGroup,
474 DWORD *lpdwTagId,
475 const BYTE *lpDependencies,
476 DWORD dwDependenciesSize,
477 LPCWSTR lpServiceStartName,
478 const BYTE *lpPassword,
479 DWORD dwPasswordSize,
480 SC_RPC_HANDLE *phService,
481 BOOL is_wow64)
483 struct service_entry *entry, *found;
484 struct sc_manager_handle *manager;
485 DWORD err;
487 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
489 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_CREATE_SERVICE, &manager)) != ERROR_SUCCESS)
490 return err;
492 if (!validate_service_name(lpServiceName))
493 return ERROR_INVALID_NAME;
494 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize) || !lpServiceName[0] || !lpBinaryPathName[0])
495 return ERROR_INVALID_PARAMETER;
497 if (lpPassword)
498 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
500 err = service_create(lpServiceName, &entry);
501 if (err != ERROR_SUCCESS)
502 return err;
504 err = parse_dependencies((LPCWSTR)lpDependencies, entry);
505 if (err != ERROR_SUCCESS) {
506 free_service_entry(entry);
507 return err;
510 entry->is_wow64 = is_wow64;
511 entry->config.dwServiceType = entry->status.dwServiceType = dwServiceType;
512 entry->config.dwStartType = dwStartType;
513 entry->config.dwErrorControl = dwErrorControl;
514 entry->config.lpBinaryPathName = strdupW(lpBinaryPathName);
515 entry->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
516 entry->config.lpServiceStartName = strdupW(lpServiceStartName);
517 entry->config.lpDisplayName = strdupW(lpDisplayName);
519 if (lpdwTagId) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
520 entry->config.dwTagId = *lpdwTagId;
521 else
522 entry->config.dwTagId = 0;
524 /* other fields NULL*/
526 if (!validate_service_config(entry))
528 WINE_ERR("Invalid data while trying to create service\n");
529 free_service_entry(entry);
530 return ERROR_INVALID_PARAMETER;
533 scmdatabase_lock(manager->db);
535 if ((found = scmdatabase_find_service(manager->db, lpServiceName)))
537 err = is_marked_for_delete(found) ? ERROR_SERVICE_MARKED_FOR_DELETE : ERROR_SERVICE_EXISTS;
538 scmdatabase_unlock(manager->db);
539 free_service_entry(entry);
540 return err;
543 if (scmdatabase_find_service_by_displayname(manager->db, get_display_name(entry)))
545 scmdatabase_unlock(manager->db);
546 free_service_entry(entry);
547 return ERROR_DUPLICATE_SERVICE_NAME;
550 err = scmdatabase_add_service(manager->db, entry);
551 if (err != ERROR_SUCCESS)
553 scmdatabase_unlock(manager->db);
554 free_service_entry(entry);
555 return err;
557 scmdatabase_unlock(manager->db);
559 return create_handle_for_service(entry, dwDesiredAccess, phService);
562 DWORD __cdecl svcctl_CreateServiceW(
563 SC_RPC_HANDLE hSCManager,
564 LPCWSTR lpServiceName,
565 LPCWSTR lpDisplayName,
566 DWORD dwDesiredAccess,
567 DWORD dwServiceType,
568 DWORD dwStartType,
569 DWORD dwErrorControl,
570 LPCWSTR lpBinaryPathName,
571 LPCWSTR lpLoadOrderGroup,
572 DWORD *lpdwTagId,
573 const BYTE *lpDependencies,
574 DWORD dwDependenciesSize,
575 LPCWSTR lpServiceStartName,
576 const BYTE *lpPassword,
577 DWORD dwPasswordSize,
578 SC_RPC_HANDLE *phService)
580 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName), wine_dbgstr_w(lpDisplayName), dwDesiredAccess, wine_dbgstr_w(lpBinaryPathName));
581 return create_serviceW(hSCManager, lpServiceName, lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType,
582 dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, lpDependencies, dwDependenciesSize, lpServiceStartName,
583 lpPassword, dwPasswordSize, phService, FALSE);
586 DWORD __cdecl svcctl_DeleteService(
587 SC_RPC_HANDLE hService)
589 struct sc_service_handle *service;
590 DWORD err;
592 if ((err = validate_service_handle(hService, DELETE, &service)) != ERROR_SUCCESS)
593 return err;
595 service_lock(service->service_entry);
597 if (!is_marked_for_delete(service->service_entry))
598 err = mark_for_delete(service->service_entry);
599 else
600 err = ERROR_SERVICE_MARKED_FOR_DELETE;
602 service_unlock(service->service_entry);
604 return err;
607 DWORD __cdecl svcctl_QueryServiceConfigW(
608 SC_RPC_HANDLE hService,
609 QUERY_SERVICE_CONFIGW *config,
610 DWORD buf_size,
611 DWORD *needed_size)
613 struct sc_service_handle *service;
614 DWORD err;
616 WINE_TRACE("(%p)\n", config);
618 if ((err = validate_service_handle(hService, SERVICE_QUERY_CONFIG, &service)) != 0)
619 return err;
621 service_lock(service->service_entry);
622 config->dwServiceType = service->service_entry->config.dwServiceType;
623 config->dwStartType = service->service_entry->config.dwStartType;
624 config->dwErrorControl = service->service_entry->config.dwErrorControl;
625 config->lpBinaryPathName = strdupW(service->service_entry->config.lpBinaryPathName);
626 config->lpLoadOrderGroup = strdupW(service->service_entry->config.lpLoadOrderGroup);
627 config->dwTagId = service->service_entry->config.dwTagId;
628 config->lpDependencies = NULL; /* TODO */
629 config->lpServiceStartName = strdupW(service->service_entry->config.lpServiceStartName);
630 config->lpDisplayName = strdupW(service->service_entry->config.lpDisplayName);
631 service_unlock(service->service_entry);
633 return ERROR_SUCCESS;
636 DWORD __cdecl svcctl_ChangeServiceConfigW(
637 SC_RPC_HANDLE hService,
638 DWORD dwServiceType,
639 DWORD dwStartType,
640 DWORD dwErrorControl,
641 LPCWSTR lpBinaryPathName,
642 LPCWSTR lpLoadOrderGroup,
643 DWORD *lpdwTagId,
644 const BYTE *lpDependencies,
645 DWORD dwDependenciesSize,
646 LPCWSTR lpServiceStartName,
647 const BYTE *lpPassword,
648 DWORD dwPasswordSize,
649 LPCWSTR lpDisplayName)
651 struct service_entry new_entry, *entry;
652 struct sc_service_handle *service;
653 DWORD err;
655 WINE_TRACE("\n");
657 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
658 return err;
660 if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
661 return ERROR_INVALID_PARAMETER;
663 /* first check if the new configuration is correct */
664 service_lock(service->service_entry);
666 if (is_marked_for_delete(service->service_entry))
668 service_unlock(service->service_entry);
669 return ERROR_SERVICE_MARKED_FOR_DELETE;
672 if (lpDisplayName != NULL &&
673 (entry = scmdatabase_find_service_by_displayname(service->service_entry->db, lpDisplayName)) &&
674 (entry != service->service_entry))
676 service_unlock(service->service_entry);
677 return ERROR_DUPLICATE_SERVICE_NAME;
680 new_entry = *service->service_entry;
682 if (dwServiceType != SERVICE_NO_CHANGE)
683 new_entry.config.dwServiceType = dwServiceType;
685 if (dwStartType != SERVICE_NO_CHANGE)
686 new_entry.config.dwStartType = dwStartType;
688 if (dwErrorControl != SERVICE_NO_CHANGE)
689 new_entry.config.dwErrorControl = dwErrorControl;
691 if (lpBinaryPathName != NULL)
692 new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
694 if (lpLoadOrderGroup != NULL)
695 new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
697 if (lpdwTagId != NULL)
698 WINE_FIXME("Changing tag id not supported\n");
700 if (lpServiceStartName != NULL)
701 new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
703 if (lpPassword != NULL)
704 WINE_FIXME("Setting password not supported\n");
706 if (lpDisplayName != NULL)
707 new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
709 err = parse_dependencies((LPCWSTR)lpDependencies, &new_entry);
710 if (err != ERROR_SUCCESS)
712 service_unlock(service->service_entry);
713 return err;
716 if (!validate_service_config(&new_entry))
718 WINE_ERR("The configuration after the change wouldn't be valid\n");
719 service_unlock(service->service_entry);
720 return ERROR_INVALID_PARAMETER;
723 /* configuration OK. The strings needs to be duplicated */
724 if (lpBinaryPathName != NULL)
725 new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
727 if (lpLoadOrderGroup != NULL)
728 new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
730 if (lpServiceStartName != NULL)
731 new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
733 if (lpDisplayName != NULL)
734 new_entry.config.lpDisplayName = strdupW(lpDisplayName);
736 /* try to save to Registry, commit or rollback depending on success */
737 err = save_service_config(&new_entry);
738 if (ERROR_SUCCESS == err)
740 free_service_strings(service->service_entry, &new_entry);
741 *service->service_entry = new_entry;
743 else free_service_strings(&new_entry, service->service_entry);
744 service_unlock(service->service_entry);
746 return err;
749 DWORD __cdecl svcctl_SetServiceStatus(
750 SC_RPC_HANDLE hServiceStatus,
751 LPSERVICE_STATUS lpServiceStatus)
753 struct sc_service_handle *service;
754 DWORD err;
756 WINE_TRACE("(%p, %p)\n", hServiceStatus, lpServiceStatus);
758 if ((err = validate_service_handle(hServiceStatus, SERVICE_SET_STATUS, &service)) != 0)
759 return err;
761 service_lock(service->service_entry);
762 /* FIXME: be a bit more discriminant about what parts of the status we set
763 * and check that fields are valid */
764 service->service_entry->status.dwServiceType = lpServiceStatus->dwServiceType;
765 service->service_entry->status.dwCurrentState = lpServiceStatus->dwCurrentState;
766 service->service_entry->status.dwControlsAccepted = lpServiceStatus->dwControlsAccepted;
767 service->service_entry->status.dwWin32ExitCode = lpServiceStatus->dwWin32ExitCode;
768 service->service_entry->status.dwServiceSpecificExitCode = lpServiceStatus->dwServiceSpecificExitCode;
769 service->service_entry->status.dwCheckPoint = lpServiceStatus->dwCheckPoint;
770 service->service_entry->status.dwWaitHint = lpServiceStatus->dwWaitHint;
771 service_unlock(service->service_entry);
773 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
774 run_after_timeout(service_terminate, service->service_entry, service_kill_timeout);
775 else if (service->service_entry->process->status_changed_event)
776 SetEvent(service->service_entry->process->status_changed_event);
778 return ERROR_SUCCESS;
781 DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, SC_RPC_CONFIG_INFOW config )
783 struct sc_service_handle *service;
784 DWORD err;
786 if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
787 return err;
789 switch (config.dwInfoLevel)
791 case SERVICE_CONFIG_DESCRIPTION:
793 WCHAR *descr = NULL;
795 if (config.u.descr->lpDescription[0])
797 if (!(descr = strdupW( config.u.descr->lpDescription )))
798 return ERROR_NOT_ENOUGH_MEMORY;
801 WINE_TRACE( "changing service %p descr to %s\n", service, wine_dbgstr_w(descr) );
802 service_lock( service->service_entry );
803 HeapFree( GetProcessHeap(), 0, service->service_entry->description );
804 service->service_entry->description = descr;
805 save_service_config( service->service_entry );
806 service_unlock( service->service_entry );
808 break;
809 case SERVICE_CONFIG_FAILURE_ACTIONS:
810 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
811 config.u.actions->dwResetPeriod,
812 wine_dbgstr_w(config.u.actions->lpRebootMsg),
813 wine_dbgstr_w(config.u.actions->lpCommand) );
814 break;
815 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
816 WINE_TRACE( "changing service %p preshutdown timeout to %d\n",
817 service, config.u.preshutdown->dwPreshutdownTimeout );
818 service_lock( service->service_entry );
819 service->service_entry->preshutdown_timeout = config.u.preshutdown->dwPreshutdownTimeout;
820 save_service_config( service->service_entry );
821 service_unlock( service->service_entry );
822 break;
823 default:
824 WINE_FIXME("level %u not implemented\n", config.dwInfoLevel);
825 err = ERROR_INVALID_LEVEL;
826 break;
828 return err;
831 DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level,
832 BYTE *buffer, DWORD size, LPDWORD needed )
834 struct sc_service_handle *service;
835 DWORD err;
837 memset(buffer, 0, size);
839 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
840 return err;
842 switch (level)
844 case SERVICE_CONFIG_DESCRIPTION:
846 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
848 service_lock(service->service_entry);
849 *needed = sizeof(*descr);
850 if (service->service_entry->description)
851 *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR);
852 if (size >= *needed)
854 if (service->service_entry->description)
856 /* store a buffer offset instead of a pointer */
857 descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer);
858 strcpyW( (WCHAR *)(descr + 1), service->service_entry->description );
860 else descr->lpDescription = NULL;
862 else err = ERROR_INSUFFICIENT_BUFFER;
863 service_unlock(service->service_entry);
865 break;
867 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
868 service_lock(service->service_entry);
870 *needed = sizeof(SERVICE_PRESHUTDOWN_INFO);
871 if (size >= *needed)
872 ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout =
873 service->service_entry->preshutdown_timeout;
874 else err = ERROR_INSUFFICIENT_BUFFER;
876 service_unlock(service->service_entry);
877 break;
879 default:
880 WINE_FIXME("level %u not implemented\n", level);
881 err = ERROR_INVALID_LEVEL;
882 break;
884 return err;
887 DWORD __cdecl svcctl_QueryServiceStatusEx(
888 SC_RPC_HANDLE hService,
889 SC_STATUS_TYPE InfoLevel,
890 BYTE *lpBuffer,
891 DWORD cbBufSize,
892 LPDWORD pcbBytesNeeded)
894 struct sc_service_handle *service;
895 DWORD err;
896 LPSERVICE_STATUS_PROCESS pSvcStatusData;
898 memset(lpBuffer, 0, cbBufSize);
900 if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0)
901 return err;
903 if (InfoLevel != SC_STATUS_PROCESS_INFO)
904 return ERROR_INVALID_LEVEL;
906 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
907 if (pSvcStatusData == NULL)
908 return ERROR_INVALID_PARAMETER;
910 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
912 if( pcbBytesNeeded != NULL)
913 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
915 return ERROR_INSUFFICIENT_BUFFER;
918 service_lock(service->service_entry);
920 pSvcStatusData->dwServiceType = service->service_entry->status.dwServiceType;
921 pSvcStatusData->dwCurrentState = service->service_entry->status.dwCurrentState;
922 pSvcStatusData->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
923 pSvcStatusData->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
924 pSvcStatusData->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
925 pSvcStatusData->dwCheckPoint = service->service_entry->status.dwCheckPoint;
926 pSvcStatusData->dwWaitHint = service->service_entry->status.dwWaitHint;
927 pSvcStatusData->dwProcessId = service->service_entry->status.dwProcessId;
928 pSvcStatusData->dwServiceFlags = service->service_entry->status.dwServiceFlags;
930 service_unlock(service->service_entry);
932 return ERROR_SUCCESS;
935 /******************************************************************************
936 * service_accepts_control
938 static BOOL service_accepts_control(const struct service_entry *service, DWORD dwControl)
940 DWORD a = service->status.dwControlsAccepted;
942 switch (dwControl)
944 case SERVICE_CONTROL_INTERROGATE:
945 return TRUE;
946 case SERVICE_CONTROL_STOP:
947 if (a&SERVICE_ACCEPT_STOP)
948 return TRUE;
949 break;
950 case SERVICE_CONTROL_SHUTDOWN:
951 if (a&SERVICE_ACCEPT_SHUTDOWN)
952 return TRUE;
953 break;
954 case SERVICE_CONTROL_PAUSE:
955 case SERVICE_CONTROL_CONTINUE:
956 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
957 return TRUE;
958 break;
959 case SERVICE_CONTROL_PARAMCHANGE:
960 if (a&SERVICE_ACCEPT_PARAMCHANGE)
961 return TRUE;
962 break;
963 case SERVICE_CONTROL_NETBINDADD:
964 case SERVICE_CONTROL_NETBINDREMOVE:
965 case SERVICE_CONTROL_NETBINDENABLE:
966 case SERVICE_CONTROL_NETBINDDISABLE:
967 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
968 return TRUE;
969 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
970 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
971 return TRUE;
972 break;
973 case SERVICE_CONTROL_POWEREVENT:
974 if (a&SERVICE_ACCEPT_POWEREVENT)
975 return TRUE;
976 break;
977 case SERVICE_CONTROL_SESSIONCHANGE:
978 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
979 return TRUE;
980 break;
982 return FALSE;
985 /******************************************************************************
986 * process_send_command
988 BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
990 OVERLAPPED overlapped;
991 DWORD count, ret;
992 BOOL r;
994 overlapped.hEvent = process->overlapped_event;
995 r = WriteFile(process->control_pipe, data, size, &count, &overlapped);
996 if (!r && GetLastError() == ERROR_IO_PENDING)
998 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
999 if (ret == WAIT_TIMEOUT)
1001 WINE_ERR("sending command timed out\n");
1002 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1003 return FALSE;
1005 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1007 if (!r || count != size)
1009 WINE_ERR("service protocol error - failed to write pipe!\n");
1010 *result = (!r ? GetLastError() : ERROR_WRITE_FAULT);
1011 return FALSE;
1013 r = ReadFile(process->control_pipe, result, sizeof *result, &count, &overlapped);
1014 if (!r && GetLastError() == ERROR_IO_PENDING)
1016 ret = WaitForSingleObject(process->overlapped_event, service_pipe_timeout);
1017 if (ret == WAIT_TIMEOUT)
1019 WINE_ERR("receiving command result timed out\n");
1020 *result = ERROR_SERVICE_REQUEST_TIMEOUT;
1021 return FALSE;
1023 r = GetOverlappedResult(process->control_pipe, &overlapped, &count, FALSE);
1025 if (!r || count != sizeof *result)
1027 WINE_ERR("service protocol error - failed to read pipe "
1028 "r = %d count = %d!\n", r, count);
1029 *result = (!r ? GetLastError() : ERROR_READ_FAULT);
1030 return FALSE;
1033 *result = ERROR_SUCCESS;
1034 return TRUE;
1037 /******************************************************************************
1038 * service_send_control
1040 static BOOL service_send_control(struct service_entry *service, DWORD dwControl, DWORD *result)
1042 service_start_info *ssi;
1043 DWORD len;
1044 BOOL r;
1046 /* calculate how much space we need to send the startup info */
1047 len = strlenW(service->name) + 1;
1049 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
1050 ssi->cmd = WINESERV_SENDCONTROL;
1051 ssi->control = dwControl;
1052 ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
1053 ssi->name_size = strlenW(service->name) + 1;
1054 strcpyW( ssi->data, service->name );
1056 r = process_send_command(service->process, ssi, ssi->total_size, result);
1057 HeapFree( GetProcessHeap(), 0, ssi );
1058 return r;
1061 DWORD __cdecl svcctl_StartServiceW(
1062 SC_RPC_HANDLE hService,
1063 DWORD dwNumServiceArgs,
1064 LPCWSTR *lpServiceArgVectors)
1066 struct sc_service_handle *service;
1067 DWORD err;
1069 WINE_TRACE("(%p, %d, %p)\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1071 if ((err = validate_service_handle(hService, SERVICE_START, &service)) != 0)
1072 return err;
1074 if (service->service_entry->config.dwStartType == SERVICE_DISABLED)
1075 return ERROR_SERVICE_DISABLED;
1077 err = service_start(service->service_entry, dwNumServiceArgs, lpServiceArgVectors);
1079 return err;
1082 DWORD __cdecl svcctl_ControlService(
1083 SC_RPC_HANDLE hService,
1084 DWORD dwControl,
1085 SERVICE_STATUS *lpServiceStatus)
1087 DWORD access_required;
1088 struct sc_service_handle *service;
1089 DWORD result;
1090 BOOL ret;
1091 HANDLE control_mutex;
1093 WINE_TRACE("(%p, %d, %p)\n", hService, dwControl, lpServiceStatus);
1095 switch (dwControl)
1097 case SERVICE_CONTROL_CONTINUE:
1098 case SERVICE_CONTROL_NETBINDADD:
1099 case SERVICE_CONTROL_NETBINDDISABLE:
1100 case SERVICE_CONTROL_NETBINDENABLE:
1101 case SERVICE_CONTROL_NETBINDREMOVE:
1102 case SERVICE_CONTROL_PARAMCHANGE:
1103 case SERVICE_CONTROL_PAUSE:
1104 access_required = SERVICE_PAUSE_CONTINUE;
1105 break;
1106 case SERVICE_CONTROL_INTERROGATE:
1107 access_required = SERVICE_INTERROGATE;
1108 break;
1109 case SERVICE_CONTROL_STOP:
1110 access_required = SERVICE_STOP;
1111 break;
1112 default:
1113 if (dwControl >= 128 && dwControl <= 255)
1114 access_required = SERVICE_USER_DEFINED_CONTROL;
1115 else
1116 return ERROR_INVALID_PARAMETER;
1119 if ((result = validate_service_handle(hService, access_required, &service)) != 0)
1120 return result;
1122 service_lock(service->service_entry);
1124 result = ERROR_SUCCESS;
1125 switch (service->service_entry->status.dwCurrentState)
1127 case SERVICE_STOPPED:
1128 result = ERROR_SERVICE_NOT_ACTIVE;
1129 break;
1130 case SERVICE_START_PENDING:
1131 if (dwControl==SERVICE_CONTROL_STOP)
1132 break;
1133 /* fall through */
1134 case SERVICE_STOP_PENDING:
1135 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1136 break;
1139 if (result == ERROR_SUCCESS && service->service_entry->force_shutdown)
1141 result = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1142 service_terminate(service->service_entry);
1145 if (result != ERROR_SUCCESS)
1147 if (lpServiceStatus)
1149 lpServiceStatus->dwServiceType = service->service_entry->status.dwServiceType;
1150 lpServiceStatus->dwCurrentState = service->service_entry->status.dwCurrentState;
1151 lpServiceStatus->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
1152 lpServiceStatus->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
1153 lpServiceStatus->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
1154 lpServiceStatus->dwCheckPoint = service->service_entry->status.dwCheckPoint;
1155 lpServiceStatus->dwWaitHint = service->service_entry->status.dwWaitHint;
1157 service_unlock(service->service_entry);
1158 return result;
1161 if (!service_accepts_control(service->service_entry, dwControl))
1163 service_unlock(service->service_entry);
1164 return ERROR_INVALID_SERVICE_CONTROL;
1167 /* Remember that we tried to shutdown this service. When the service is
1168 * still running on the second invocation, it will be forcefully killed. */
1169 if (dwControl == SERVICE_CONTROL_STOP)
1170 service->service_entry->force_shutdown = TRUE;
1172 control_mutex = service->service_entry->process->control_mutex;
1173 service_unlock(service->service_entry);
1175 ret = WaitForSingleObject(control_mutex, 30000);
1176 if (ret != WAIT_OBJECT_0)
1177 return ERROR_SERVICE_REQUEST_TIMEOUT;
1179 service_send_control(service->service_entry, dwControl, &result);
1181 if (lpServiceStatus)
1183 service_lock(service->service_entry);
1184 lpServiceStatus->dwServiceType = service->service_entry->status.dwServiceType;
1185 lpServiceStatus->dwCurrentState = service->service_entry->status.dwCurrentState;
1186 lpServiceStatus->dwControlsAccepted = service->service_entry->status.dwControlsAccepted;
1187 lpServiceStatus->dwWin32ExitCode = service->service_entry->status.dwWin32ExitCode;
1188 lpServiceStatus->dwServiceSpecificExitCode = service->service_entry->status.dwServiceSpecificExitCode;
1189 lpServiceStatus->dwCheckPoint = service->service_entry->status.dwCheckPoint;
1190 lpServiceStatus->dwWaitHint = service->service_entry->status.dwWaitHint;
1191 service_unlock(service->service_entry);
1194 ReleaseMutex(control_mutex);
1195 return result;
1198 DWORD __cdecl svcctl_CloseServiceHandle(
1199 SC_RPC_HANDLE *handle)
1201 WINE_TRACE("(&%p)\n", *handle);
1203 SC_RPC_HANDLE_destroy(*handle);
1204 *handle = NULL;
1206 return ERROR_SUCCESS;
1209 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock)
1211 struct sc_lock *lock = hLock;
1212 scmdatabase_unlock_startup(lock->db);
1213 HeapFree(GetProcessHeap(), 0, lock);
1216 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
1218 SC_RPC_LOCK_destroy(hLock);
1221 DWORD __cdecl svcctl_LockServiceDatabase(
1222 SC_RPC_HANDLE hSCManager,
1223 SC_RPC_LOCK *phLock)
1225 struct sc_manager_handle *manager;
1226 struct sc_lock *lock;
1227 DWORD err;
1229 WINE_TRACE("(%p, %p)\n", hSCManager, phLock);
1231 if ((err = validate_scm_handle(hSCManager, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
1232 return err;
1234 err = scmdatabase_lock_startup(manager->db);
1235 if (err != ERROR_SUCCESS)
1236 return err;
1238 lock = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock));
1239 if (!lock)
1241 scmdatabase_unlock_startup(manager->db);
1242 return ERROR_NOT_ENOUGH_SERVER_MEMORY;
1245 lock->db = manager->db;
1246 *phLock = lock;
1248 return ERROR_SUCCESS;
1251 DWORD __cdecl svcctl_UnlockServiceDatabase(
1252 SC_RPC_LOCK *phLock)
1254 WINE_TRACE("(&%p)\n", *phLock);
1256 SC_RPC_LOCK_destroy(*phLock);
1257 *phLock = NULL;
1259 return ERROR_SUCCESS;
1262 static BOOL map_state(DWORD state, DWORD mask)
1264 switch (state)
1266 case SERVICE_START_PENDING:
1267 case SERVICE_STOP_PENDING:
1268 case SERVICE_RUNNING:
1269 case SERVICE_CONTINUE_PENDING:
1270 case SERVICE_PAUSE_PENDING:
1271 case SERVICE_PAUSED:
1272 if (SERVICE_ACTIVE & mask) return TRUE;
1273 break;
1274 case SERVICE_STOPPED:
1275 if (SERVICE_INACTIVE & mask) return TRUE;
1276 break;
1277 default:
1278 WINE_ERR("unknown state %u\n", state);
1279 break;
1281 return FALSE;
1284 DWORD __cdecl svcctl_EnumServicesStatusW(
1285 SC_RPC_HANDLE hmngr,
1286 DWORD type,
1287 DWORD state,
1288 BYTE *buffer,
1289 DWORD size,
1290 LPDWORD needed,
1291 LPDWORD returned,
1292 LPDWORD resume)
1294 DWORD err, sz, total_size, num_services;
1295 DWORD_PTR offset;
1296 struct sc_manager_handle *manager;
1297 struct service_entry *service;
1298 ENUM_SERVICE_STATUSW *s;
1300 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned, resume);
1302 if (!type || !state)
1303 return ERROR_INVALID_PARAMETER;
1305 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1306 return err;
1308 if (resume)
1309 WINE_FIXME("resume index not supported\n");
1311 scmdatabase_lock(manager->db);
1313 total_size = num_services = 0;
1314 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1316 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1318 total_size += sizeof(ENUM_SERVICE_STATUSW);
1319 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1320 if (service->config.lpDisplayName)
1322 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1324 num_services++;
1327 *returned = 0;
1328 *needed = total_size;
1329 if (total_size > size)
1331 scmdatabase_unlock(manager->db);
1332 return ERROR_MORE_DATA;
1334 s = (ENUM_SERVICE_STATUSW *)buffer;
1335 offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
1336 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1338 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
1340 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1341 memcpy(buffer + offset, service->name, sz);
1342 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1343 offset += sz;
1345 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1346 else
1348 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1349 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1350 s->lpDisplayName = (WCHAR *)offset;
1351 offset += sz;
1353 memcpy(&s->ServiceStatus, &service->status, sizeof(SERVICE_STATUS));
1354 s++;
1357 *returned = num_services;
1358 *needed = 0;
1359 scmdatabase_unlock(manager->db);
1360 return ERROR_SUCCESS;
1363 static struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
1365 struct service_entry *service;
1366 LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
1368 if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
1369 return service;
1371 return NULL;
1374 static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
1376 if (!g2) return TRUE;
1377 if (!g2[0] && (!g1 || !g1[0])) return TRUE;
1378 if (g1 && !strcmpW(g1, g2)) return TRUE;
1379 return FALSE;
1382 DWORD __cdecl svcctl_EnumServicesStatusExA(
1383 SC_RPC_HANDLE scmanager,
1384 SC_ENUM_TYPE info_level,
1385 DWORD service_type,
1386 DWORD service_state,
1387 BYTE *buffer,
1388 DWORD buf_size,
1389 DWORD *needed_size,
1390 DWORD *services_count,
1391 DWORD *resume_index,
1392 LPCSTR groupname)
1394 WINE_FIXME("\n");
1395 return ERROR_CALL_NOT_IMPLEMENTED;
1398 DWORD __cdecl svcctl_EnumServicesStatusExW(
1399 SC_RPC_HANDLE hmngr,
1400 SC_ENUM_TYPE info_level,
1401 DWORD type,
1402 DWORD state,
1403 BYTE *buffer,
1404 DWORD size,
1405 LPDWORD needed,
1406 LPDWORD returned,
1407 DWORD *resume_handle,
1408 LPCWSTR group)
1410 DWORD err, sz, total_size, num_services;
1411 DWORD_PTR offset;
1412 struct sc_manager_handle *manager;
1413 struct service_entry *service;
1414 ENUM_SERVICE_STATUS_PROCESSW *s;
1416 WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
1417 needed, returned, wine_dbgstr_w(group));
1419 if (resume_handle)
1420 FIXME("resume handle not supported\n");
1422 if (!type || !state)
1423 return ERROR_INVALID_PARAMETER;
1425 if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
1426 return err;
1428 scmdatabase_lock(manager->db);
1430 if (group && !find_service_by_group(manager->db, group))
1432 scmdatabase_unlock(manager->db);
1433 return ERROR_SERVICE_DOES_NOT_EXIST;
1436 total_size = num_services = 0;
1437 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1439 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1440 && match_group(service->config.lpLoadOrderGroup, group))
1442 total_size += sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1443 total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
1444 if (service->config.lpDisplayName)
1446 total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1448 num_services++;
1451 *returned = 0;
1452 *needed = total_size;
1453 if (total_size > size)
1455 scmdatabase_unlock(manager->db);
1456 return ERROR_MORE_DATA;
1458 s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1459 offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
1460 LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
1462 if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
1463 && match_group(service->config.lpLoadOrderGroup, group))
1465 sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
1466 memcpy(buffer + offset, service->name, sz);
1467 s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
1468 offset += sz;
1470 if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
1471 else
1473 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
1474 memcpy(buffer + offset, service->config.lpDisplayName, sz);
1475 s->lpDisplayName = (WCHAR *)offset;
1476 offset += sz;
1478 s->ServiceStatusProcess = service->status;
1479 s++;
1482 *returned = num_services;
1483 *needed = 0;
1484 scmdatabase_unlock(manager->db);
1485 return ERROR_SUCCESS;
1488 DWORD __cdecl svcctl_unknown43(void)
1490 WINE_FIXME("\n");
1491 return ERROR_CALL_NOT_IMPLEMENTED;
1494 DWORD __cdecl svcctl_CreateServiceWOW64A(
1495 SC_RPC_HANDLE scmanager,
1496 LPCSTR servicename,
1497 LPCSTR displayname,
1498 DWORD accessmask,
1499 DWORD service_type,
1500 DWORD start_type,
1501 DWORD error_control,
1502 LPCSTR imagepath,
1503 LPCSTR loadordergroup,
1504 DWORD *tagid,
1505 const BYTE *dependencies,
1506 DWORD depend_size,
1507 LPCSTR start_name,
1508 const BYTE *password,
1509 DWORD password_size,
1510 SC_RPC_HANDLE *service)
1512 WINE_FIXME("\n");
1513 return ERROR_CALL_NOT_IMPLEMENTED;
1516 DWORD __cdecl svcctl_CreateServiceWOW64W(
1517 SC_RPC_HANDLE scmanager,
1518 LPCWSTR servicename,
1519 LPCWSTR displayname,
1520 DWORD accessmask,
1521 DWORD service_type,
1522 DWORD start_type,
1523 DWORD error_control,
1524 LPCWSTR imagepath,
1525 LPCWSTR loadordergroup,
1526 DWORD *tagid,
1527 const BYTE *dependencies,
1528 DWORD depend_size,
1529 LPCWSTR start_name,
1530 const BYTE *password,
1531 DWORD password_size,
1532 SC_RPC_HANDLE *service)
1534 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(servicename), wine_dbgstr_w(displayname), accessmask, wine_dbgstr_w(imagepath));
1535 return create_serviceW(scmanager, servicename, displayname, accessmask, service_type, start_type, error_control, imagepath,
1536 loadordergroup, tagid, dependencies, depend_size, start_name, password, password_size, service, TRUE);
1539 DWORD __cdecl svcctl_unknown46(void)
1541 WINE_FIXME("\n");
1542 return ERROR_CALL_NOT_IMPLEMENTED;
1545 DWORD __cdecl svcctl_NotifyServiceStatusChange(
1546 SC_RPC_HANDLE service,
1547 SC_RPC_NOTIFY_PARAMS params,
1548 GUID *clientprocessguid,
1549 GUID *scmprocessguid,
1550 BOOL *createremotequeue,
1551 SC_NOTIFY_RPC_HANDLE *notify)
1553 WINE_FIXME("\n");
1554 return ERROR_CALL_NOT_IMPLEMENTED;
1557 DWORD __cdecl svcctl_GetNotifyResults(
1558 SC_NOTIFY_RPC_HANDLE notify,
1559 SC_RPC_NOTIFY_PARAMS_LIST **params)
1561 WINE_FIXME("\n");
1562 return ERROR_CALL_NOT_IMPLEMENTED;
1565 DWORD __cdecl svcctl_CloseNotifyHandle(
1566 SC_NOTIFY_RPC_HANDLE *notify,
1567 BOOL *apc_fired)
1569 WINE_FIXME("\n");
1570 return ERROR_CALL_NOT_IMPLEMENTED;
1573 DWORD __cdecl svcctl_ControlServiceExA(
1574 SC_RPC_HANDLE service,
1575 DWORD control,
1576 DWORD info_level,
1577 SC_RPC_SERVICE_CONTROL_IN_PARAMSA *in_params,
1578 SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *out_params)
1580 WINE_FIXME("\n");
1581 return ERROR_CALL_NOT_IMPLEMENTED;
1584 DWORD __cdecl svcctl_ControlServiceExW(
1585 SC_RPC_HANDLE service,
1586 DWORD control,
1587 DWORD info_level,
1588 SC_RPC_SERVICE_CONTROL_IN_PARAMSW *in_params,
1589 SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *out_params)
1591 WINE_FIXME("\n");
1592 return ERROR_CALL_NOT_IMPLEMENTED;
1595 DWORD __cdecl svcctl_unknown52(void)
1597 WINE_FIXME("\n");
1598 return ERROR_CALL_NOT_IMPLEMENTED;
1601 DWORD __cdecl svcctl_unknown53(void)
1603 WINE_FIXME("\n");
1604 return ERROR_CALL_NOT_IMPLEMENTED;
1607 DWORD __cdecl svcctl_unknown54(void)
1609 WINE_FIXME("\n");
1610 return ERROR_CALL_NOT_IMPLEMENTED;
1613 DWORD __cdecl svcctl_unknown55(void)
1615 WINE_FIXME("\n");
1616 return ERROR_CALL_NOT_IMPLEMENTED;
1619 DWORD __cdecl svcctl_QueryServiceConfigEx(
1620 SC_RPC_HANDLE service,
1621 DWORD info_level,
1622 SC_RPC_CONFIG_INFOW *info)
1624 WINE_FIXME("\n");
1625 return ERROR_CALL_NOT_IMPLEMENTED;
1628 DWORD __cdecl svcctl_QueryServiceObjectSecurity(
1629 SC_RPC_HANDLE service,
1630 SECURITY_INFORMATION info,
1631 BYTE *descriptor,
1632 DWORD buf_size,
1633 DWORD *needed_size)
1635 WINE_FIXME("\n");
1636 return ERROR_CALL_NOT_IMPLEMENTED;
1639 DWORD __cdecl svcctl_SetServiceObjectSecurity(
1640 SC_RPC_HANDLE service,
1641 SECURITY_INFORMATION info,
1642 BYTE *descriptor,
1643 DWORD buf_size)
1645 WINE_FIXME("\n");
1646 return ERROR_CALL_NOT_IMPLEMENTED;
1649 DWORD __cdecl svcctl_QueryServiceStatus(
1650 SC_RPC_HANDLE service,
1651 SERVICE_STATUS *status)
1653 WINE_FIXME("\n");
1654 return ERROR_CALL_NOT_IMPLEMENTED;
1657 DWORD __cdecl svcctl_NotifyBootConfigStatus(
1658 SVCCTL_HANDLEW machinename,
1659 DWORD boot_acceptable)
1661 WINE_FIXME("\n");
1662 return ERROR_CALL_NOT_IMPLEMENTED;
1665 DWORD __cdecl svcctl_SCSetServiceBitsW(void)
1667 WINE_FIXME("\n");
1668 return ERROR_CALL_NOT_IMPLEMENTED;
1671 DWORD __cdecl svcctl_EnumDependentServicesW(
1672 SC_RPC_HANDLE service,
1673 DWORD state,
1674 BYTE *services,
1675 DWORD buf_size,
1676 DWORD *needed_size,
1677 DWORD *services_ret)
1679 WINE_FIXME("\n");
1680 return ERROR_CALL_NOT_IMPLEMENTED;
1683 DWORD __cdecl svcctl_QueryServiceLockStatusW(
1684 SC_RPC_HANDLE scmanager,
1685 QUERY_SERVICE_LOCK_STATUSW *status,
1686 DWORD buf_size,
1687 DWORD *needed_size)
1689 WINE_FIXME("\n");
1690 return ERROR_CALL_NOT_IMPLEMENTED;
1693 DWORD __cdecl svcctl_SCSetServiceBitsA(void)
1695 WINE_FIXME("\n");
1696 return ERROR_CALL_NOT_IMPLEMENTED;
1699 DWORD __cdecl svcctl_ChangeServiceConfigA(
1700 SC_RPC_HANDLE service,
1701 DWORD service_type,
1702 DWORD start_type,
1703 DWORD error_control,
1704 LPSTR binarypath,
1705 LPSTR loadordergroup,
1706 DWORD *tagid,
1707 BYTE *dependencies,
1708 DWORD depend_size,
1709 LPSTR startname,
1710 BYTE *password,
1711 DWORD password_size,
1712 LPSTR displayname)
1714 WINE_FIXME("\n");
1715 return ERROR_CALL_NOT_IMPLEMENTED;
1718 DWORD __cdecl svcctl_CreateServiceA(
1719 SC_RPC_HANDLE scmanager,
1720 LPCSTR servicename,
1721 LPCSTR displayname,
1722 DWORD desiredaccess,
1723 DWORD service_type,
1724 DWORD start_type,
1725 DWORD error_control,
1726 LPCSTR binarypath,
1727 LPCSTR loadordergroup,
1728 DWORD *tagid,
1729 const BYTE *dependencies,
1730 DWORD depend_size,
1731 LPCSTR startname,
1732 const BYTE *password,
1733 DWORD password_size,
1734 SC_RPC_HANDLE *service)
1736 WINE_FIXME("\n");
1737 return ERROR_CALL_NOT_IMPLEMENTED;
1740 DWORD __cdecl svcctl_EnumDependentServicesA(
1741 SC_RPC_HANDLE service,
1742 DWORD state,
1743 BYTE *services,
1744 DWORD buf_size,
1745 DWORD *needed_size,
1746 DWORD *services_ret)
1748 WINE_FIXME("\n");
1749 return ERROR_CALL_NOT_IMPLEMENTED;
1752 DWORD __cdecl svcctl_EnumServicesStatusA(
1753 SC_RPC_HANDLE hmngr,
1754 DWORD type,
1755 DWORD state,
1756 BYTE *buffer,
1757 DWORD size,
1758 DWORD *needed,
1759 DWORD *returned,
1760 DWORD *resume)
1762 WINE_FIXME("\n");
1763 return ERROR_CALL_NOT_IMPLEMENTED;
1766 DWORD __cdecl svcctl_OpenSCManagerA(
1767 MACHINE_HANDLEA MachineName,
1768 LPCSTR DatabaseName,
1769 DWORD dwAccessMask,
1770 SC_RPC_HANDLE *handle)
1772 WINE_FIXME("\n");
1773 return ERROR_CALL_NOT_IMPLEMENTED;
1776 DWORD __cdecl svcctl_OpenServiceA(
1777 SC_RPC_HANDLE hSCManager,
1778 LPCSTR lpServiceName,
1779 DWORD dwDesiredAccess,
1780 SC_RPC_HANDLE *phService)
1782 WINE_FIXME("\n");
1783 return ERROR_CALL_NOT_IMPLEMENTED;
1786 DWORD __cdecl svcctl_QueryServiceConfigA(
1787 SC_RPC_HANDLE hService,
1788 QUERY_SERVICE_CONFIGA *config,
1789 DWORD buf_size,
1790 DWORD *needed_size)
1792 WINE_FIXME("\n");
1793 return ERROR_CALL_NOT_IMPLEMENTED;
1796 DWORD __cdecl svcctl_QueryServiceLockStatusA(
1797 SC_RPC_HANDLE scmanager,
1798 QUERY_SERVICE_LOCK_STATUSA *status,
1799 DWORD buf_size,
1800 DWORD *needed_size)
1802 WINE_FIXME("\n");
1803 return ERROR_CALL_NOT_IMPLEMENTED;
1806 DWORD __cdecl svcctl_StartServiceA(
1807 SC_RPC_HANDLE service,
1808 DWORD argc,
1809 LPCSTR *args)
1811 WINE_FIXME("\n");
1812 return ERROR_CALL_NOT_IMPLEMENTED;
1815 DWORD __cdecl svcctl_GetServiceDisplayNameA(
1816 SC_RPC_HANDLE hSCManager,
1817 LPCSTR servicename,
1818 CHAR buffer[],
1819 DWORD *buf_size)
1821 WINE_FIXME("\n");
1822 return ERROR_CALL_NOT_IMPLEMENTED;
1825 DWORD __cdecl svcctl_GetServiceKeyNameA(
1826 SC_RPC_HANDLE hSCManager,
1827 LPCSTR servicename,
1828 CHAR buffer[],
1829 DWORD *buf_size)
1831 WINE_FIXME("\n");
1832 return ERROR_CALL_NOT_IMPLEMENTED;
1835 DWORD __cdecl svcctl_GetCurrentGroupStateW(void)
1837 WINE_FIXME("\n");
1838 return ERROR_CALL_NOT_IMPLEMENTED;
1841 DWORD __cdecl svcctl_EnumServiceGroupW(
1842 SC_RPC_HANDLE scmanager,
1843 DWORD service_type,
1844 DWORD service_state,
1845 BYTE *buffer,
1846 DWORD buf_size,
1847 DWORD *needed_size,
1848 DWORD *returned_size,
1849 DWORD *resume_index,
1850 LPCWSTR groupname)
1852 WINE_FIXME("\n");
1853 return ERROR_CALL_NOT_IMPLEMENTED;
1856 DWORD __cdecl svcctl_ChangeServiceConfig2A(
1857 SC_RPC_HANDLE service,
1858 SC_RPC_CONFIG_INFOA info)
1860 WINE_FIXME("\n");
1861 return ERROR_CALL_NOT_IMPLEMENTED;
1864 DWORD __cdecl svcctl_QueryServiceConfig2A(
1865 SC_RPC_HANDLE service,
1866 DWORD info_level,
1867 BYTE *buffer,
1868 DWORD buf_size,
1869 DWORD *needed_size)
1871 WINE_FIXME("\n");
1872 return ERROR_CALL_NOT_IMPLEMENTED;
1875 DWORD RPC_Init(void)
1877 WCHAR transport[] = SVCCTL_TRANSPORT;
1878 WCHAR endpoint[] = SVCCTL_ENDPOINT;
1879 DWORD err;
1881 if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
1883 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
1884 return err;
1887 if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
1889 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err);
1890 return err;
1893 if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
1895 WINE_ERR("RpcServerListen failed with error %u\n", err);
1896 return err;
1898 return ERROR_SUCCESS;
1901 DWORD events_loop(void)
1903 struct timeout_queue_elem *iter, *iter_safe;
1904 DWORD err;
1905 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1906 DWORD timeout = INFINITE;
1908 wait_handles[0] = __wine_make_process_system();
1909 wait_handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
1910 timeout_queue_event = wait_handles[1];
1912 SetEvent(g_hStartedEvent);
1914 WINE_TRACE("Entered main loop\n");
1918 DWORD num_handles = 2;
1920 /* monitor tracked process handles for process end */
1921 EnterCriticalSection(&timeout_queue_cs);
1922 LIST_FOR_EACH_ENTRY(iter, &timeout_queue, struct timeout_queue_elem, entry)
1924 if(num_handles == MAXIMUM_WAIT_OBJECTS){
1925 WINE_TRACE("Exceeded maximum wait object count\n");
1926 break;
1928 wait_handles[num_handles] = iter->service_entry->process->process;
1929 num_handles++;
1931 LeaveCriticalSection(&timeout_queue_cs);
1933 err = WaitForMultipleObjects(num_handles, wait_handles, FALSE, timeout);
1934 WINE_TRACE("Wait returned %d\n", err);
1936 if(err > WAIT_OBJECT_0 || err == WAIT_TIMEOUT)
1938 FILETIME cur_time;
1939 ULARGE_INTEGER time;
1940 DWORD idx = 0;
1942 GetSystemTimeAsFileTime(&cur_time);
1943 time.u.LowPart = cur_time.dwLowDateTime;
1944 time.u.HighPart = cur_time.dwHighDateTime;
1946 EnterCriticalSection(&timeout_queue_cs);
1947 timeout = INFINITE;
1948 LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
1950 if(CompareFileTime(&cur_time, &iter->time) >= 0 ||
1951 (err > WAIT_OBJECT_0 + 1 && idx == err - WAIT_OBJECT_0 - 2))
1953 LeaveCriticalSection(&timeout_queue_cs);
1954 iter->func(iter->service_entry);
1955 EnterCriticalSection(&timeout_queue_cs);
1957 release_service(iter->service_entry);
1958 list_remove(&iter->entry);
1959 HeapFree(GetProcessHeap(), 0, iter);
1961 else
1963 ULARGE_INTEGER time_diff;
1965 time_diff.u.LowPart = iter->time.dwLowDateTime;
1966 time_diff.u.HighPart = iter->time.dwHighDateTime;
1967 time_diff.QuadPart = (time_diff.QuadPart-time.QuadPart)/10000;
1969 if(time_diff.QuadPart < timeout)
1970 timeout = time_diff.QuadPart;
1972 idx++;
1974 LeaveCriticalSection(&timeout_queue_cs);
1976 if(timeout != INFINITE)
1977 timeout += 1000;
1979 } while (err != WAIT_OBJECT_0);
1981 WINE_TRACE("Object signaled - wine shutdown\n");
1982 EnterCriticalSection(&timeout_queue_cs);
1983 LIST_FOR_EACH_ENTRY_SAFE(iter, iter_safe, &timeout_queue, struct timeout_queue_elem, entry)
1985 LeaveCriticalSection(&timeout_queue_cs);
1986 iter->func(iter->service_entry);
1987 EnterCriticalSection(&timeout_queue_cs);
1989 release_service(iter->service_entry);
1990 list_remove(&iter->entry);
1991 HeapFree(GetProcessHeap(), 0, iter);
1993 LeaveCriticalSection(&timeout_queue_cs);
1995 CloseHandle(wait_handles[0]);
1996 CloseHandle(wait_handles[1]);
1997 return ERROR_SUCCESS;
2000 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
2002 SC_RPC_HANDLE_destroy(handle);
2005 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE handle)
2009 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
2011 return HeapAlloc(GetProcessHeap(), 0, len);
2014 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
2016 HeapFree(GetProcessHeap(), 0, ptr);