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(struct service_entry
*service
, HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
713 service_start_info
*ssi
;
714 DWORD len
, count
= 0;
717 /* calculate how much space we need to send the startup info */
718 len
= strlenW(service
->name
) + 1;
720 ssi
= HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info
, data
[len
]));
721 ssi
->cmd
= WINESERV_SENDCONTROL
;
722 ssi
->control
= dwControl
;
723 ssi
->total_size
= FIELD_OFFSET(service_start_info
, data
[len
]);
724 ssi
->name_size
= strlenW(service
->name
) + 1;
725 strcpyW( ssi
->data
, service
->name
);
727 r
= WriteFile(pipe
, ssi
, ssi
->total_size
, &count
, NULL
);
728 if (!r
|| count
!= ssi
->total_size
)
730 WINE_ERR("service protocol error - failed to write pipe!\n");
733 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
734 if (!r
|| count
!= sizeof *result
)
735 WINE_ERR("service protocol error - failed to read pipe "
736 "r = %d count = %d!\n", r
, count
);
740 DWORD
svcctl_StartServiceW(
741 SC_RPC_HANDLE hService
,
742 DWORD dwNumServiceArgs
,
743 LPCWSTR
*lpServiceArgVectors
)
745 struct sc_service_handle
*service
;
748 WINE_TRACE("(%p, %d, %p)\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
750 if ((err
= validate_service_handle(hService
, SERVICE_START
, &service
)) != 0)
753 err
= service_start(service
->service_entry
, dwNumServiceArgs
, lpServiceArgVectors
);
758 DWORD
svcctl_ControlService(
759 SC_RPC_HANDLE hService
,
761 SERVICE_STATUS
*lpServiceStatus
)
763 DWORD access_required
;
764 struct sc_service_handle
*service
;
767 HANDLE control_mutex
;
770 WINE_TRACE("(%p, %d, %p)\n", hService
, dwControl
, lpServiceStatus
);
774 case SERVICE_CONTROL_CONTINUE
:
775 case SERVICE_CONTROL_NETBINDADD
:
776 case SERVICE_CONTROL_NETBINDDISABLE
:
777 case SERVICE_CONTROL_NETBINDENABLE
:
778 case SERVICE_CONTROL_NETBINDREMOVE
:
779 case SERVICE_CONTROL_PARAMCHANGE
:
780 case SERVICE_CONTROL_PAUSE
:
781 access_required
= SERVICE_PAUSE_CONTINUE
;
783 case SERVICE_CONTROL_INTERROGATE
:
784 access_required
= SERVICE_INTERROGATE
;
786 case SERVICE_CONTROL_STOP
:
787 access_required
= SERVICE_STOP
;
790 if (dwControl
>= 128 && dwControl
<= 255)
791 access_required
= SERVICE_USER_DEFINED_CONTROL
;
793 return ERROR_INVALID_PARAMETER
;
796 if ((err
= validate_service_handle(hService
, access_required
, &service
)) != 0)
799 service_lock_exclusive(service
->service_entry
);
803 lpServiceStatus
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
804 lpServiceStatus
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
805 lpServiceStatus
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
806 lpServiceStatus
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
807 lpServiceStatus
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
808 lpServiceStatus
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
809 lpServiceStatus
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
812 if (!service_accepts_control(service
->service_entry
, dwControl
))
814 service_unlock(service
->service_entry
);
815 return ERROR_INVALID_SERVICE_CONTROL
;
818 switch (service
->service_entry
->status
.dwCurrentState
)
820 case SERVICE_STOPPED
:
821 service_unlock(service
->service_entry
);
822 return ERROR_SERVICE_NOT_ACTIVE
;
823 case SERVICE_START_PENDING
:
824 if (dwControl
==SERVICE_CONTROL_STOP
)
827 case SERVICE_STOP_PENDING
:
828 service_unlock(service
->service_entry
);
829 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
832 /* prevent races by caching these variables and clearing them on
833 * stop here instead of outside the services lock */
834 control_mutex
= service
->service_entry
->control_mutex
;
835 control_pipe
= service
->service_entry
->control_pipe
;
836 if (dwControl
== SERVICE_CONTROL_STOP
)
838 service
->service_entry
->control_mutex
= NULL
;
839 service
->service_entry
->control_pipe
= INVALID_HANDLE_VALUE
;
842 service_unlock(service
->service_entry
);
844 ret
= WaitForSingleObject(control_mutex
, 30000);
845 if (ret
== WAIT_OBJECT_0
)
847 DWORD result
= ERROR_SUCCESS
;
849 ret
= service_send_control(service
->service_entry
, control_pipe
, dwControl
, &result
);
851 if (dwControl
== SERVICE_CONTROL_STOP
)
853 CloseHandle(control_mutex
);
854 CloseHandle(control_pipe
);
857 ReleaseMutex(control_mutex
);
863 if (dwControl
== SERVICE_CONTROL_STOP
)
865 CloseHandle(control_mutex
);
866 CloseHandle(control_pipe
);
868 return ERROR_SERVICE_REQUEST_TIMEOUT
;
872 DWORD
svcctl_CloseServiceHandle(
873 SC_RPC_HANDLE
*handle
)
875 WINE_TRACE("(&%p)\n", *handle
);
877 SC_RPC_HANDLE_destroy(*handle
);
880 return ERROR_SUCCESS
;
883 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock
)
885 struct sc_lock
*lock
= hLock
;
886 scmdatabase_unlock_startup(lock
->db
);
887 HeapFree(GetProcessHeap(), 0, lock
);
890 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock
)
892 SC_RPC_LOCK_destroy(hLock
);
895 DWORD
svcctl_LockServiceDatabase(
896 SC_RPC_HANDLE hSCManager
,
899 struct sc_manager_handle
*manager
;
900 struct sc_lock
*lock
;
903 WINE_TRACE("(%p, %p)\n", hSCManager
, phLock
);
905 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_LOCK
, &manager
)) != ERROR_SUCCESS
)
908 err
= scmdatabase_lock_startup(manager
->db
);
909 if (err
!= ERROR_SUCCESS
)
912 lock
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock
));
915 scmdatabase_unlock_startup(manager
->db
);
916 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
919 lock
->db
= manager
->db
;
922 return ERROR_SUCCESS
;
925 DWORD
svcctl_UnlockServiceDatabase(
928 WINE_TRACE("(&%p)\n", *phLock
);
930 SC_RPC_LOCK_destroy(*phLock
);
933 return ERROR_SUCCESS
;
936 DWORD
svcctl_QueryServiceObjectSecurity(
940 return ERROR_CALL_NOT_IMPLEMENTED
;
943 DWORD
svcctl_SetServiceObjectSecurity(
947 return ERROR_CALL_NOT_IMPLEMENTED
;
950 DWORD
svcctl_QueryServiceStatus(
954 return ERROR_CALL_NOT_IMPLEMENTED
;
958 DWORD
svcctl_NotifyBootConfigStatus(
962 return ERROR_CALL_NOT_IMPLEMENTED
;
965 DWORD
svcctl_SCSetServiceBitsW(
969 return ERROR_CALL_NOT_IMPLEMENTED
;
973 DWORD
svcctl_EnumDependentServicesW(
977 return ERROR_CALL_NOT_IMPLEMENTED
;
980 DWORD
svcctl_EnumServicesStatusW(
984 return ERROR_CALL_NOT_IMPLEMENTED
;
988 DWORD
svcctl_QueryServiceLockStatusW(
992 return ERROR_CALL_NOT_IMPLEMENTED
;
995 DWORD
svcctl_SCSetServiceBitsA(
999 return ERROR_CALL_NOT_IMPLEMENTED
;
1002 DWORD
svcctl_ChangeServiceConfigA(
1006 return ERROR_CALL_NOT_IMPLEMENTED
;
1009 DWORD
svcctl_CreateServiceA(
1013 return ERROR_CALL_NOT_IMPLEMENTED
;
1016 DWORD
svcctl_EnumDependentServicesA(
1020 return ERROR_CALL_NOT_IMPLEMENTED
;
1023 DWORD
svcctl_EnumServicesStatusA(
1027 return ERROR_CALL_NOT_IMPLEMENTED
;
1030 DWORD
svcctl_OpenSCManagerA(
1034 return ERROR_CALL_NOT_IMPLEMENTED
;
1037 DWORD
svcctl_OpenServiceA(
1041 return ERROR_CALL_NOT_IMPLEMENTED
;
1044 DWORD
svcctl_QueryServiceConfigA(
1048 return ERROR_CALL_NOT_IMPLEMENTED
;
1051 DWORD
svcctl_QueryServiceLockStatusA(
1055 return ERROR_CALL_NOT_IMPLEMENTED
;
1058 DWORD
svcctl_StartServiceA(
1062 return ERROR_CALL_NOT_IMPLEMENTED
;
1065 DWORD
svcctl_GetServiceDisplayNameA(
1069 return ERROR_CALL_NOT_IMPLEMENTED
;
1072 DWORD
svcctl_GetServiceKeyNameA(
1076 return ERROR_CALL_NOT_IMPLEMENTED
;
1079 DWORD
svcctl_GetCurrentGroupStateW(
1083 return ERROR_CALL_NOT_IMPLEMENTED
;
1086 DWORD
svcctl_EnumServiceGroupW(
1090 return ERROR_CALL_NOT_IMPLEMENTED
;
1093 DWORD
svcctl_ChangeServiceConfig2A(
1097 return ERROR_CALL_NOT_IMPLEMENTED
;
1100 DWORD
svcctl_ChangeServiceConfig2W(
1104 return ERROR_CALL_NOT_IMPLEMENTED
;
1107 DWORD
svcctl_QueryServiceConfig2A(
1111 return ERROR_CALL_NOT_IMPLEMENTED
;
1114 DWORD
svcctl_QueryServiceConfig2W(
1118 return ERROR_CALL_NOT_IMPLEMENTED
;
1122 DWORD
RPC_Init(void)
1124 WCHAR transport
[] = SVCCTL_TRANSPORT
;
1125 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
1128 if ((err
= RpcServerUseProtseqEpW(transport
, 0, endpoint
, NULL
)) != ERROR_SUCCESS
)
1130 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err
);
1134 if ((err
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
, 0, 0)) != ERROR_SUCCESS
)
1136 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err
);
1140 if ((err
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)) != ERROR_SUCCESS
)
1142 WINE_ERR("RpcServerListen failed with error %u\n", err
);
1145 return ERROR_SUCCESS
;
1148 DWORD
RPC_MainLoop(void)
1151 HANDLE hExitEvent
= __wine_make_process_system();
1153 SetEvent(g_hStartedEvent
);
1155 WINE_TRACE("Entered main loop\n");
1159 err
= WaitForSingleObjectEx(hExitEvent
, INFINITE
, TRUE
);
1160 WINE_TRACE("Wait returned %d\n", err
);
1161 } while (err
!= WAIT_OBJECT_0
);
1163 WINE_TRACE("Object signaled - wine shutdown\n");
1164 CloseHandle(hExitEvent
);
1165 return ERROR_SUCCESS
;
1168 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle
)
1170 SC_RPC_HANDLE_destroy(handle
);
1173 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
1175 return HeapAlloc(GetProcessHeap(), 0, len
);
1178 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
1180 HeapFree(GetProcessHeap(), 0, ptr
);