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
30 #include "wine/list.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
37 extern HANDLE
__wine_make_process_system(void);
39 WINE_DEFAULT_DEBUG_CHANNEL(service
);
41 static const GENERIC_MAPPING g_scm_generic
=
43 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
44 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
45 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
49 static const GENERIC_MAPPING g_svc_generic
=
51 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
52 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
53 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
59 SC_HTYPE_DONT_CARE
= 0,
70 struct sc_manager_handle
/* service control manager handle */
73 struct scmdatabase
*db
;
76 struct sc_service_handle
/* service handle */
79 struct service_entry
*service_entry
;
84 struct scmdatabase
*db
;
87 /* Check if the given handle is of the required type and allows the requested access. */
88 static DWORD
validate_context_handle(SC_RPC_HANDLE handle
, DWORD type
, DWORD needed_access
, struct sc_handle
**out_hdr
)
90 struct sc_handle
*hdr
= (struct sc_handle
*)handle
;
92 if (type
!= SC_HTYPE_DONT_CARE
&& hdr
->type
!= type
)
94 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr
->type
, type
);
95 return ERROR_INVALID_HANDLE
;
98 if ((needed_access
& hdr
->access
) != needed_access
)
100 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr
->access
, needed_access
);
101 return ERROR_ACCESS_DENIED
;
105 return ERROR_SUCCESS
;
108 static DWORD
validate_scm_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_manager_handle
**manager
)
110 struct sc_handle
*hdr
;
111 DWORD err
= validate_context_handle(handle
, SC_HTYPE_MANAGER
, needed_access
, &hdr
);
112 if (err
== ERROR_SUCCESS
)
113 *manager
= (struct sc_manager_handle
*)hdr
;
117 static DWORD
validate_service_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_service_handle
**service
)
119 struct sc_handle
*hdr
;
120 DWORD err
= validate_context_handle(handle
, SC_HTYPE_SERVICE
, needed_access
, &hdr
);
121 if (err
== ERROR_SUCCESS
)
122 *service
= (struct sc_service_handle
*)hdr
;
126 DWORD
svcctl_OpenSCManagerW(
127 MACHINE_HANDLEW MachineName
, /* Note: this parameter is ignored */
128 LPCWSTR DatabaseName
,
130 SC_RPC_HANDLE
*handle
)
132 struct sc_manager_handle
*manager
;
134 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName
), wine_dbgstr_w(DatabaseName
), dwAccessMask
);
136 if (DatabaseName
!= NULL
&& DatabaseName
[0])
138 if (strcmpW(DatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
139 return ERROR_DATABASE_DOES_NOT_EXIST
;
140 if (strcmpW(DatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
141 return ERROR_INVALID_NAME
;
144 if (!(manager
= HeapAlloc(GetProcessHeap(), 0, sizeof(*manager
))))
145 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
147 manager
->hdr
.type
= SC_HTYPE_MANAGER
;
149 if (dwAccessMask
& MAXIMUM_ALLOWED
)
150 dwAccessMask
|= SC_MANAGER_ALL_ACCESS
;
151 manager
->hdr
.access
= dwAccessMask
;
152 RtlMapGenericMask(&manager
->hdr
.access
, &g_scm_generic
);
153 manager
->db
= active_database
;
154 *handle
= &manager
->hdr
;
156 return ERROR_SUCCESS
;
159 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle
)
161 struct sc_handle
*hdr
= (struct sc_handle
*)handle
;
164 case SC_HTYPE_MANAGER
:
166 struct sc_manager_handle
*manager
= (struct sc_manager_handle
*)hdr
;
167 HeapFree(GetProcessHeap(), 0, manager
);
170 case SC_HTYPE_SERVICE
:
172 struct sc_service_handle
*service
= (struct sc_service_handle
*)hdr
;
173 release_service(service
->service_entry
);
174 HeapFree(GetProcessHeap(), 0, service
);
178 WINE_ERR("invalid handle type %d\n", hdr
->type
);
179 RpcRaiseException(ERROR_INVALID_HANDLE
);
183 DWORD
svcctl_GetServiceDisplayNameW(
184 SC_RPC_HANDLE hSCManager
,
185 LPCWSTR lpServiceName
,
190 struct sc_manager_handle
*manager
;
191 struct service_entry
*entry
;
194 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName
), cchBufSize
);
196 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
199 scmdatabase_lock_shared(manager
->db
);
201 entry
= scmdatabase_find_service(manager
->db
, lpServiceName
);
205 service_lock_shared(entry
);
206 name
= get_display_name(entry
);
207 *cchLength
= strlenW(name
);
208 if (*cchLength
< cchBufSize
)
211 lstrcpyW(lpBuffer
, name
);
214 err
= ERROR_INSUFFICIENT_BUFFER
;
215 service_unlock(entry
);
220 err
= ERROR_SERVICE_DOES_NOT_EXIST
;
223 scmdatabase_unlock(manager
->db
);
225 if (err
!= ERROR_SUCCESS
&& cchBufSize
> 0)
231 DWORD
svcctl_GetServiceKeyNameW(
232 SC_RPC_HANDLE hSCManager
,
233 LPCWSTR lpServiceDisplayName
,
238 struct service_entry
*entry
;
239 struct sc_manager_handle
*manager
;
242 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName
), cchBufSize
);
244 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
247 scmdatabase_lock_shared(manager
->db
);
249 entry
= scmdatabase_find_service_by_displayname(manager
->db
, lpServiceDisplayName
);
252 service_lock_shared(entry
);
253 *cchLength
= strlenW(entry
->name
);
254 if (*cchLength
< cchBufSize
)
257 lstrcpyW(lpBuffer
, entry
->name
);
260 err
= ERROR_INSUFFICIENT_BUFFER
;
261 service_unlock(entry
);
266 err
= ERROR_SERVICE_DOES_NOT_EXIST
;
269 scmdatabase_unlock(manager
->db
);
271 if (err
!= ERROR_SUCCESS
&& cchBufSize
> 0)
277 static DWORD
create_handle_for_service(struct service_entry
*entry
, DWORD dwDesiredAccess
, SC_RPC_HANDLE
*phService
)
279 struct sc_service_handle
*service
;
281 if (!(service
= HeapAlloc(GetProcessHeap(), 0, sizeof(*service
))))
283 release_service(entry
);
284 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
287 service
->hdr
.type
= SC_HTYPE_SERVICE
;
288 service
->hdr
.access
= dwDesiredAccess
;
289 RtlMapGenericMask(&service
->hdr
.access
, &g_svc_generic
);
290 service
->service_entry
= entry
;
291 if (dwDesiredAccess
& MAXIMUM_ALLOWED
)
292 dwDesiredAccess
|= SERVICE_ALL_ACCESS
;
294 *phService
= &service
->hdr
;
295 return ERROR_SUCCESS
;
298 DWORD
svcctl_OpenServiceW(
299 SC_RPC_HANDLE hSCManager
,
300 LPCWSTR lpServiceName
,
301 DWORD dwDesiredAccess
,
302 SC_RPC_HANDLE
*phService
)
304 struct sc_manager_handle
*manager
;
305 struct service_entry
*entry
;
308 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName
), dwDesiredAccess
);
310 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
312 if (!validate_service_name(lpServiceName
))
313 return ERROR_INVALID_NAME
;
315 scmdatabase_lock_shared(manager
->db
);
316 entry
= scmdatabase_find_service(manager
->db
, lpServiceName
);
319 scmdatabase_unlock(manager
->db
);
322 return ERROR_SERVICE_DOES_NOT_EXIST
;
324 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
327 DWORD
svcctl_CreateServiceW(
328 SC_RPC_HANDLE hSCManager
,
329 LPCWSTR lpServiceName
,
330 LPCWSTR lpDisplayName
,
331 DWORD dwDesiredAccess
,
334 DWORD dwErrorControl
,
335 LPCWSTR lpBinaryPathName
,
336 LPCWSTR lpLoadOrderGroup
,
338 const BYTE
*lpDependencies
,
339 DWORD dwDependenciesSize
,
340 LPCWSTR lpServiceStartName
,
341 const BYTE
*lpPassword
,
342 DWORD dwPasswordSize
,
343 SC_RPC_HANDLE
*phService
)
345 struct sc_manager_handle
*manager
;
346 struct service_entry
*entry
;
349 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName
), wine_dbgstr_w(lpDisplayName
), dwDesiredAccess
, wine_dbgstr_w(lpBinaryPathName
));
351 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_CREATE_SERVICE
, &manager
)) != ERROR_SUCCESS
)
354 if (!validate_service_name(lpServiceName
))
355 return ERROR_INVALID_NAME
;
356 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
) || !lpServiceName
[0] || !lpBinaryPathName
[0])
357 return ERROR_INVALID_PARAMETER
;
360 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
362 WINE_FIXME("Dependencies not supported yet\n");
364 err
= service_create(lpServiceName
, &entry
);
365 if (err
!= ERROR_SUCCESS
)
367 entry
->config
.dwServiceType
= dwServiceType
;
368 entry
->config
.dwStartType
= dwStartType
;
369 entry
->config
.dwErrorControl
= dwErrorControl
;
370 entry
->config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
371 entry
->config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
372 entry
->config
.lpServiceStartName
= strdupW(lpServiceStartName
);
373 entry
->config
.lpDisplayName
= strdupW(lpDisplayName
);
375 if (lpdwTagId
) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
376 entry
->config
.dwTagId
= *lpdwTagId
;
378 entry
->config
.dwTagId
= 0;
380 /* other fields NULL*/
382 if (!validate_service_config(entry
))
384 WINE_ERR("Invalid data while trying to create service\n");
385 free_service_entry(entry
);
386 return ERROR_INVALID_PARAMETER
;
389 scmdatabase_lock_exclusive(manager
->db
);
391 if (scmdatabase_find_service(manager
->db
, lpServiceName
))
393 scmdatabase_unlock(manager
->db
);
394 free_service_entry(entry
);
395 return ERROR_SERVICE_EXISTS
;
398 if (scmdatabase_find_service_by_displayname(manager
->db
, get_display_name(entry
)))
400 scmdatabase_unlock(manager
->db
);
401 free_service_entry(entry
);
402 return ERROR_DUPLICATE_SERVICE_NAME
;
405 err
= scmdatabase_add_service(manager
->db
, entry
);
406 if (err
!= ERROR_SUCCESS
)
408 scmdatabase_unlock(manager
->db
);
409 free_service_entry(entry
);
412 scmdatabase_unlock(manager
->db
);
414 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
417 DWORD
svcctl_DeleteService(
418 SC_RPC_HANDLE hService
)
420 struct sc_service_handle
*service
;
423 if ((err
= validate_service_handle(hService
, DELETE
, &service
)) != ERROR_SUCCESS
)
426 scmdatabase_lock_exclusive(service
->service_entry
->db
);
427 service_lock_exclusive(service
->service_entry
);
429 if (!is_marked_for_delete(service
->service_entry
))
430 err
= scmdatabase_remove_service(service
->service_entry
->db
, service
->service_entry
);
432 err
= ERROR_SERVICE_MARKED_FOR_DELETE
;
434 service_unlock(service
->service_entry
);
435 scmdatabase_unlock(service
->service_entry
->db
);
440 DWORD
svcctl_QueryServiceConfigW(
441 SC_RPC_HANDLE hService
,
442 QUERY_SERVICE_CONFIGW
*config
)
444 struct sc_service_handle
*service
;
447 WINE_TRACE("(%p)\n", config
);
449 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_CONFIG
, &service
)) != 0)
452 service_lock_shared(service
->service_entry
);
453 config
->dwServiceType
= service
->service_entry
->config
.dwServiceType
;
454 config
->dwStartType
= service
->service_entry
->config
.dwStartType
;
455 config
->dwErrorControl
= service
->service_entry
->config
.dwErrorControl
;
456 config
->lpBinaryPathName
= strdupW(service
->service_entry
->config
.lpBinaryPathName
);
457 config
->lpLoadOrderGroup
= strdupW(service
->service_entry
->config
.lpLoadOrderGroup
);
458 config
->dwTagId
= service
->service_entry
->config
.dwTagId
;
459 config
->lpDependencies
= NULL
; /* TODO */
460 config
->lpServiceStartName
= strdupW(service
->service_entry
->config
.lpServiceStartName
);
461 config
->lpDisplayName
= strdupW(service
->service_entry
->config
.lpDisplayName
);
462 service_unlock(service
->service_entry
);
464 return ERROR_SUCCESS
;
467 DWORD
svcctl_ChangeServiceConfigW(
468 SC_RPC_HANDLE hService
,
471 DWORD dwErrorControl
,
472 LPCWSTR lpBinaryPathName
,
473 LPCWSTR lpLoadOrderGroup
,
475 const BYTE
*lpDependencies
,
476 DWORD dwDependenciesSize
,
477 LPCWSTR lpServiceStartName
,
478 const BYTE
*lpPassword
,
479 DWORD dwPasswordSize
,
480 LPCWSTR lpDisplayName
)
482 struct service_entry new_entry
, *entry
;
483 struct sc_service_handle
*service
;
488 if ((err
= validate_service_handle(hService
, SERVICE_CHANGE_CONFIG
, &service
)) != 0)
491 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
))
492 return ERROR_INVALID_PARAMETER
;
494 /* first check if the new configuration is correct */
495 service_lock_exclusive(service
->service_entry
);
497 if (is_marked_for_delete(service
->service_entry
))
499 service_unlock(service
->service_entry
);
500 return ERROR_SERVICE_MARKED_FOR_DELETE
;
503 if (lpDisplayName
!= NULL
&&
504 (entry
= scmdatabase_find_service_by_displayname(service
->service_entry
->db
, lpDisplayName
)) &&
505 (entry
!= service
->service_entry
))
507 service_unlock(service
->service_entry
);
508 return ERROR_DUPLICATE_SERVICE_NAME
;
511 new_entry
= *service
->service_entry
;
513 if (dwServiceType
!= SERVICE_NO_CHANGE
)
514 new_entry
.config
.dwServiceType
= dwServiceType
;
516 if (dwStartType
!= SERVICE_NO_CHANGE
)
517 new_entry
.config
.dwStartType
= dwStartType
;
519 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
520 new_entry
.config
.dwErrorControl
= dwErrorControl
;
522 if (lpBinaryPathName
!= NULL
)
523 new_entry
.config
.lpBinaryPathName
= (LPWSTR
)lpBinaryPathName
;
525 if (lpLoadOrderGroup
!= NULL
)
526 new_entry
.config
.lpLoadOrderGroup
= (LPWSTR
)lpLoadOrderGroup
;
528 if (lpdwTagId
!= NULL
)
529 WINE_FIXME("Changing tag id not supported\n");
531 if (lpDependencies
!= NULL
)
532 WINE_FIXME("Chainging dependencies not supported\n");
534 if (lpServiceStartName
!= NULL
)
535 new_entry
.config
.lpServiceStartName
= (LPWSTR
)lpServiceStartName
;
537 if (lpPassword
!= NULL
)
538 WINE_FIXME("Setting password not supported\n");
540 if (lpDisplayName
!= NULL
)
541 new_entry
.config
.lpDisplayName
= (LPWSTR
)lpDisplayName
;
543 if (!validate_service_config(&new_entry
))
545 WINE_ERR("The configuration after the change wouldn't be valid\n");
546 service_unlock(service
->service_entry
);
547 return ERROR_INVALID_PARAMETER
;
550 /* configuration OK. The strings needs to be duplicated */
551 if (lpBinaryPathName
!= NULL
)
553 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpBinaryPathName
);
554 new_entry
.config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
557 if (lpLoadOrderGroup
!= NULL
)
559 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpLoadOrderGroup
);
560 new_entry
.config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
563 if (lpServiceStartName
!= NULL
)
565 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpServiceStartName
);
566 new_entry
.config
.lpServiceStartName
= strdupW(lpServiceStartName
);
569 if (lpDisplayName
!= NULL
)
571 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpDisplayName
);
572 new_entry
.config
.lpDisplayName
= strdupW(lpDisplayName
);
575 *service
->service_entry
= new_entry
;
576 save_service_config(service
->service_entry
);
577 service_unlock(service
->service_entry
);
579 return ERROR_SUCCESS
;
582 DWORD
svcctl_SetServiceStatus(
583 SC_RPC_HANDLE hServiceStatus
,
584 LPSERVICE_STATUS lpServiceStatus
)
586 struct sc_service_handle
*service
;
589 WINE_TRACE("(%p, %p)\n", hServiceStatus
, lpServiceStatus
);
591 if ((err
= validate_service_handle(hServiceStatus
, SERVICE_SET_STATUS
, &service
)) != 0)
594 service_lock_exclusive(service
->service_entry
);
595 /* FIXME: be a bit more discriminant about what parts of the status we set
596 * and check that fields are valid */
597 service
->service_entry
->status
.dwServiceType
= lpServiceStatus
->dwServiceType
;
598 service
->service_entry
->status
.dwCurrentState
= lpServiceStatus
->dwCurrentState
;
599 service
->service_entry
->status
.dwControlsAccepted
= lpServiceStatus
->dwControlsAccepted
;
600 service
->service_entry
->status
.dwWin32ExitCode
= lpServiceStatus
->dwWin32ExitCode
;
601 service
->service_entry
->status
.dwServiceSpecificExitCode
= lpServiceStatus
->dwServiceSpecificExitCode
;
602 service
->service_entry
->status
.dwCheckPoint
= lpServiceStatus
->dwCheckPoint
;
603 service
->service_entry
->status
.dwWaitHint
= lpServiceStatus
->dwWaitHint
;
604 service_unlock(service
->service_entry
);
606 if (service
->service_entry
->status_changed_event
)
607 SetEvent(service
->service_entry
->status_changed_event
);
609 return ERROR_SUCCESS
;
612 DWORD
svcctl_QueryServiceStatusEx(
613 SC_RPC_HANDLE hService
,
614 SC_STATUS_TYPE InfoLevel
,
617 LPDWORD pcbBytesNeeded
)
619 struct sc_service_handle
*service
;
621 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
623 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_STATUS
, &service
)) != 0)
626 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
627 return ERROR_INVALID_LEVEL
;
629 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
630 if (pSvcStatusData
== NULL
)
631 return ERROR_INVALID_PARAMETER
;
633 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
635 if( pcbBytesNeeded
!= NULL
)
636 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
638 return ERROR_INSUFFICIENT_BUFFER
;
641 service_lock_shared(service
->service_entry
);
643 pSvcStatusData
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
644 pSvcStatusData
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
645 pSvcStatusData
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
646 pSvcStatusData
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
647 pSvcStatusData
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
648 pSvcStatusData
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
649 pSvcStatusData
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
650 pSvcStatusData
->dwProcessId
= service
->service_entry
->status
.dwProcessId
;
651 pSvcStatusData
->dwServiceFlags
= service
->service_entry
->status
.dwServiceFlags
;
653 service_unlock(service
->service_entry
);
655 return ERROR_SUCCESS
;
658 /******************************************************************************
659 * service_accepts_control
661 static BOOL
service_accepts_control(const struct service_entry
*service
, DWORD dwControl
)
663 DWORD a
= service
->status
.dwControlsAccepted
;
667 case SERVICE_CONTROL_INTERROGATE
:
669 case SERVICE_CONTROL_STOP
:
670 if (a
&SERVICE_ACCEPT_STOP
)
673 case SERVICE_CONTROL_SHUTDOWN
:
674 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
677 case SERVICE_CONTROL_PAUSE
:
678 case SERVICE_CONTROL_CONTINUE
:
679 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
682 case SERVICE_CONTROL_PARAMCHANGE
:
683 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
686 case SERVICE_CONTROL_NETBINDADD
:
687 case SERVICE_CONTROL_NETBINDREMOVE
:
688 case SERVICE_CONTROL_NETBINDENABLE
:
689 case SERVICE_CONTROL_NETBINDDISABLE
:
690 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
692 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
693 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
696 case SERVICE_CONTROL_POWEREVENT
:
697 if (a
&SERVICE_ACCEPT_POWEREVENT
)
700 case SERVICE_CONTROL_SESSIONCHANGE
:
701 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
708 /******************************************************************************
709 * service_send_control
711 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
713 DWORD cmd
[2], count
= 0;
716 cmd
[0] = WINESERV_SENDCONTROL
;
718 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
719 if (!r
|| count
!= sizeof cmd
)
721 WINE_ERR("service protocol error - failed to write pipe!\n");
724 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
725 if (!r
|| count
!= sizeof *result
)
726 WINE_ERR("service protocol error - failed to read pipe "
727 "r = %d count = %d!\n", r
, count
);
731 DWORD
svcctl_StartServiceW(
732 SC_RPC_HANDLE hService
,
733 DWORD dwNumServiceArgs
,
734 LPCWSTR
*lpServiceArgVectors
)
736 struct sc_service_handle
*service
;
739 WINE_TRACE("(%p, %d, %p)\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
741 if ((err
= validate_service_handle(hService
, SERVICE_START
, &service
)) != 0)
744 err
= service_start(service
->service_entry
, dwNumServiceArgs
, lpServiceArgVectors
);
749 DWORD
svcctl_ControlService(
750 SC_RPC_HANDLE hService
,
752 SERVICE_STATUS
*lpServiceStatus
)
754 DWORD access_required
;
755 struct sc_service_handle
*service
;
758 HANDLE control_mutex
;
761 WINE_TRACE("(%p, %d, %p)\n", hService
, dwControl
, lpServiceStatus
);
765 case SERVICE_CONTROL_CONTINUE
:
766 case SERVICE_CONTROL_NETBINDADD
:
767 case SERVICE_CONTROL_NETBINDDISABLE
:
768 case SERVICE_CONTROL_NETBINDENABLE
:
769 case SERVICE_CONTROL_NETBINDREMOVE
:
770 case SERVICE_CONTROL_PARAMCHANGE
:
771 case SERVICE_CONTROL_PAUSE
:
772 access_required
= SERVICE_PAUSE_CONTINUE
;
774 case SERVICE_CONTROL_INTERROGATE
:
775 access_required
= SERVICE_INTERROGATE
;
777 case SERVICE_CONTROL_STOP
:
778 access_required
= SERVICE_STOP
;
781 if (dwControl
>= 128 && dwControl
<= 255)
782 access_required
= SERVICE_USER_DEFINED_CONTROL
;
784 return ERROR_INVALID_PARAMETER
;
787 if ((err
= validate_service_handle(hService
, access_required
, &service
)) != 0)
790 service_lock_exclusive(service
->service_entry
);
794 lpServiceStatus
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
795 lpServiceStatus
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
796 lpServiceStatus
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
797 lpServiceStatus
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
798 lpServiceStatus
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
799 lpServiceStatus
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
800 lpServiceStatus
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
803 if (!service_accepts_control(service
->service_entry
, dwControl
))
805 service_unlock(service
->service_entry
);
806 return ERROR_INVALID_SERVICE_CONTROL
;
809 switch (service
->service_entry
->status
.dwCurrentState
)
811 case SERVICE_STOPPED
:
812 service_unlock(service
->service_entry
);
813 return ERROR_SERVICE_NOT_ACTIVE
;
814 case SERVICE_START_PENDING
:
815 if (dwControl
==SERVICE_CONTROL_STOP
)
818 case SERVICE_STOP_PENDING
:
819 service_unlock(service
->service_entry
);
820 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
823 /* prevent races by caching these variables and clearing them on
824 * stop here instead of outside the services lock */
825 control_mutex
= service
->service_entry
->control_mutex
;
826 control_pipe
= service
->service_entry
->control_pipe
;
827 if (dwControl
== SERVICE_CONTROL_STOP
)
829 service
->service_entry
->control_mutex
= NULL
;
830 service
->service_entry
->control_pipe
= NULL
;
833 service_unlock(service
->service_entry
);
835 ret
= WaitForSingleObject(control_mutex
, 30000);
838 DWORD result
= ERROR_SUCCESS
;
840 ret
= service_send_control(control_pipe
, dwControl
, &result
);
842 if (dwControl
== SERVICE_CONTROL_STOP
)
844 CloseHandle(control_mutex
);
845 CloseHandle(control_pipe
);
848 ReleaseMutex(control_mutex
);
854 if (dwControl
== SERVICE_CONTROL_STOP
)
856 CloseHandle(control_mutex
);
857 CloseHandle(control_pipe
);
859 return ERROR_SERVICE_REQUEST_TIMEOUT
;
863 DWORD
svcctl_CloseServiceHandle(
864 SC_RPC_HANDLE
*handle
)
866 WINE_TRACE("(&%p)\n", *handle
);
868 SC_RPC_HANDLE_destroy(*handle
);
871 return ERROR_SUCCESS
;
874 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock
)
876 struct sc_lock
*lock
= hLock
;
877 scmdatabase_unlock_startup(lock
->db
);
878 HeapFree(GetProcessHeap(), 0, lock
);
881 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock
)
883 SC_RPC_LOCK_destroy(hLock
);
886 DWORD
svcctl_LockServiceDatabase(
887 SC_RPC_HANDLE hSCManager
,
890 struct sc_manager_handle
*manager
;
893 WINE_TRACE("(%p, %p)\n", hSCManager
, phLock
);
895 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_LOCK
, &manager
)) != ERROR_SUCCESS
)
898 err
= scmdatabase_lock_startup(manager
->db
);
899 if (err
!= ERROR_SUCCESS
)
902 *phLock
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock
));
905 scmdatabase_unlock_startup(manager
->db
);
906 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
909 return ERROR_SUCCESS
;
912 DWORD
svcctl_UnlockServiceDatabase(
915 WINE_TRACE("(&%p)\n", *phLock
);
917 SC_RPC_LOCK_destroy(*phLock
);
920 return ERROR_SUCCESS
;
923 DWORD
svcctl_QueryServiceObjectSecurity(
927 return ERROR_CALL_NOT_IMPLEMENTED
;
930 DWORD
svcctl_SetServiceObjectSecurity(
934 return ERROR_CALL_NOT_IMPLEMENTED
;
937 DWORD
svcctl_QueryServiceStatus(
941 return ERROR_CALL_NOT_IMPLEMENTED
;
945 DWORD
svcctl_NotifyBootConfigStatus(
949 return ERROR_CALL_NOT_IMPLEMENTED
;
952 DWORD
svcctl_SCSetServiceBitsW(
956 return ERROR_CALL_NOT_IMPLEMENTED
;
960 DWORD
svcctl_EnumDependentServicesW(
964 return ERROR_CALL_NOT_IMPLEMENTED
;
967 DWORD
svcctl_EnumServicesStatusW(
971 return ERROR_CALL_NOT_IMPLEMENTED
;
975 DWORD
svcctl_QueryServiceLockStatusW(
979 return ERROR_CALL_NOT_IMPLEMENTED
;
982 DWORD
svcctl_SCSetServiceBitsA(
986 return ERROR_CALL_NOT_IMPLEMENTED
;
989 DWORD
svcctl_ChangeServiceConfigA(
993 return ERROR_CALL_NOT_IMPLEMENTED
;
996 DWORD
svcctl_CreateServiceA(
1000 return ERROR_CALL_NOT_IMPLEMENTED
;
1003 DWORD
svcctl_EnumDependentServicesA(
1007 return ERROR_CALL_NOT_IMPLEMENTED
;
1010 DWORD
svcctl_EnumServicesStatusA(
1014 return ERROR_CALL_NOT_IMPLEMENTED
;
1017 DWORD
svcctl_OpenSCManagerA(
1021 return ERROR_CALL_NOT_IMPLEMENTED
;
1024 DWORD
svcctl_OpenServiceA(
1028 return ERROR_CALL_NOT_IMPLEMENTED
;
1031 DWORD
svcctl_QueryServiceConfigA(
1035 return ERROR_CALL_NOT_IMPLEMENTED
;
1038 DWORD
svcctl_QueryServiceLockStatusA(
1042 return ERROR_CALL_NOT_IMPLEMENTED
;
1045 DWORD
svcctl_StartServiceA(
1049 return ERROR_CALL_NOT_IMPLEMENTED
;
1052 DWORD
svcctl_GetServiceDisplayNameA(
1056 return ERROR_CALL_NOT_IMPLEMENTED
;
1059 DWORD
svcctl_GetServiceKeyNameA(
1063 return ERROR_CALL_NOT_IMPLEMENTED
;
1066 DWORD
svcctl_GetCurrentGroupStateW(
1070 return ERROR_CALL_NOT_IMPLEMENTED
;
1073 DWORD
svcctl_EnumServiceGroupW(
1077 return ERROR_CALL_NOT_IMPLEMENTED
;
1080 DWORD
svcctl_ChangeServiceConfig2A(
1084 return ERROR_CALL_NOT_IMPLEMENTED
;
1087 DWORD
svcctl_ChangeServiceConfig2W(
1091 return ERROR_CALL_NOT_IMPLEMENTED
;
1094 DWORD
svcctl_QueryServiceConfig2A(
1098 return ERROR_CALL_NOT_IMPLEMENTED
;
1101 DWORD
svcctl_QueryServiceConfig2W(
1105 return ERROR_CALL_NOT_IMPLEMENTED
;
1109 DWORD
RPC_Init(void)
1111 WCHAR transport
[] = SVCCTL_TRANSPORT
;
1112 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
1115 if ((err
= RpcServerUseProtseqEpW(transport
, 0, endpoint
, NULL
)) != ERROR_SUCCESS
)
1117 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err
);
1121 if ((err
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
, 0, 0)) != ERROR_SUCCESS
)
1123 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err
);
1127 if ((err
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)) != ERROR_SUCCESS
)
1129 WINE_ERR("RpcServerListen failed with error %u\n", err
);
1132 return ERROR_SUCCESS
;
1135 DWORD
RPC_MainLoop(void)
1138 HANDLE hExitEvent
= __wine_make_process_system();
1140 SetEvent(g_hStartedEvent
);
1142 WINE_TRACE("Entered main loop\n");
1146 err
= WaitForSingleObjectEx(hExitEvent
, INFINITE
, TRUE
);
1147 WINE_TRACE("Wait returned %d\n", err
);
1148 } while (err
!= WAIT_OBJECT_0
);
1150 WINE_TRACE("Object signaled - wine shutdown\n");
1151 CloseHandle(hExitEvent
);
1152 return ERROR_SUCCESS
;
1155 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle
)
1157 SC_RPC_HANDLE_destroy(handle
);
1160 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
1162 return HeapAlloc(GetProcessHeap(), 0, len
);
1165 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
1167 HeapFree(GetProcessHeap(), 0, ptr
);