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
= entry
->status
.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_ChangeServiceConfig2W( SC_RPC_HANDLE hService
, DWORD level
, SERVICE_CONFIG2W
*config
)
614 struct sc_service_handle
*service
;
617 if ((err
= validate_service_handle(hService
, SERVICE_CHANGE_CONFIG
, &service
)) != 0)
622 case SERVICE_CONFIG_DESCRIPTION
:
626 if (config
->descr
.lpDescription
[0])
628 if (!(descr
= strdupW( config
->descr
.lpDescription
)))
629 return ERROR_NOT_ENOUGH_MEMORY
;
632 WINE_TRACE( "changing service %p descr to %s\n", service
, wine_dbgstr_w(descr
) );
633 service_lock_exclusive( service
->service_entry
);
634 HeapFree( GetProcessHeap(), 0, service
->service_entry
->description
);
635 service
->service_entry
->description
= descr
;
636 save_service_config( service
->service_entry
);
637 service_unlock( service
->service_entry
);
642 WINE_FIXME("level %u not implemented\n", level
);
643 err
= ERROR_INVALID_LEVEL
;
649 DWORD
svcctl_QueryServiceStatusEx(
650 SC_RPC_HANDLE hService
,
651 SC_STATUS_TYPE InfoLevel
,
654 LPDWORD pcbBytesNeeded
)
656 struct sc_service_handle
*service
;
658 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
660 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_STATUS
, &service
)) != 0)
663 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
664 return ERROR_INVALID_LEVEL
;
666 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
667 if (pSvcStatusData
== NULL
)
668 return ERROR_INVALID_PARAMETER
;
670 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
672 if( pcbBytesNeeded
!= NULL
)
673 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
675 return ERROR_INSUFFICIENT_BUFFER
;
678 service_lock_shared(service
->service_entry
);
680 pSvcStatusData
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
681 pSvcStatusData
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
682 pSvcStatusData
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
683 pSvcStatusData
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
684 pSvcStatusData
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
685 pSvcStatusData
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
686 pSvcStatusData
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
687 pSvcStatusData
->dwProcessId
= service
->service_entry
->status
.dwProcessId
;
688 pSvcStatusData
->dwServiceFlags
= service
->service_entry
->status
.dwServiceFlags
;
690 service_unlock(service
->service_entry
);
692 return ERROR_SUCCESS
;
695 /******************************************************************************
696 * service_accepts_control
698 static BOOL
service_accepts_control(const struct service_entry
*service
, DWORD dwControl
)
700 DWORD a
= service
->status
.dwControlsAccepted
;
704 case SERVICE_CONTROL_INTERROGATE
:
706 case SERVICE_CONTROL_STOP
:
707 if (a
&SERVICE_ACCEPT_STOP
)
710 case SERVICE_CONTROL_SHUTDOWN
:
711 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
714 case SERVICE_CONTROL_PAUSE
:
715 case SERVICE_CONTROL_CONTINUE
:
716 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
719 case SERVICE_CONTROL_PARAMCHANGE
:
720 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
723 case SERVICE_CONTROL_NETBINDADD
:
724 case SERVICE_CONTROL_NETBINDREMOVE
:
725 case SERVICE_CONTROL_NETBINDENABLE
:
726 case SERVICE_CONTROL_NETBINDDISABLE
:
727 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
729 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
730 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
733 case SERVICE_CONTROL_POWEREVENT
:
734 if (a
&SERVICE_ACCEPT_POWEREVENT
)
737 case SERVICE_CONTROL_SESSIONCHANGE
:
738 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
745 /******************************************************************************
746 * service_send_control
748 static BOOL
service_send_control(struct service_entry
*service
, HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
750 service_start_info
*ssi
;
751 DWORD len
, count
= 0;
754 /* calculate how much space we need to send the startup info */
755 len
= strlenW(service
->name
) + 1;
757 ssi
= HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info
, data
[len
]));
758 ssi
->cmd
= WINESERV_SENDCONTROL
;
759 ssi
->control
= dwControl
;
760 ssi
->total_size
= FIELD_OFFSET(service_start_info
, data
[len
]);
761 ssi
->name_size
= strlenW(service
->name
) + 1;
762 strcpyW( ssi
->data
, service
->name
);
764 r
= WriteFile(pipe
, ssi
, ssi
->total_size
, &count
, NULL
);
765 if (!r
|| count
!= ssi
->total_size
)
767 WINE_ERR("service protocol error - failed to write pipe!\n");
770 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
771 if (!r
|| count
!= sizeof *result
)
772 WINE_ERR("service protocol error - failed to read pipe "
773 "r = %d count = %d!\n", r
, count
);
777 DWORD
svcctl_StartServiceW(
778 SC_RPC_HANDLE hService
,
779 DWORD dwNumServiceArgs
,
780 LPCWSTR
*lpServiceArgVectors
)
782 struct sc_service_handle
*service
;
785 WINE_TRACE("(%p, %d, %p)\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
787 if ((err
= validate_service_handle(hService
, SERVICE_START
, &service
)) != 0)
790 err
= service_start(service
->service_entry
, dwNumServiceArgs
, lpServiceArgVectors
);
795 DWORD
svcctl_ControlService(
796 SC_RPC_HANDLE hService
,
798 SERVICE_STATUS
*lpServiceStatus
)
800 DWORD access_required
;
801 struct sc_service_handle
*service
;
804 HANDLE control_mutex
;
807 WINE_TRACE("(%p, %d, %p)\n", hService
, dwControl
, lpServiceStatus
);
811 case SERVICE_CONTROL_CONTINUE
:
812 case SERVICE_CONTROL_NETBINDADD
:
813 case SERVICE_CONTROL_NETBINDDISABLE
:
814 case SERVICE_CONTROL_NETBINDENABLE
:
815 case SERVICE_CONTROL_NETBINDREMOVE
:
816 case SERVICE_CONTROL_PARAMCHANGE
:
817 case SERVICE_CONTROL_PAUSE
:
818 access_required
= SERVICE_PAUSE_CONTINUE
;
820 case SERVICE_CONTROL_INTERROGATE
:
821 access_required
= SERVICE_INTERROGATE
;
823 case SERVICE_CONTROL_STOP
:
824 access_required
= SERVICE_STOP
;
827 if (dwControl
>= 128 && dwControl
<= 255)
828 access_required
= SERVICE_USER_DEFINED_CONTROL
;
830 return ERROR_INVALID_PARAMETER
;
833 if ((err
= validate_service_handle(hService
, access_required
, &service
)) != 0)
836 service_lock_exclusive(service
->service_entry
);
840 lpServiceStatus
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
841 lpServiceStatus
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
842 lpServiceStatus
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
843 lpServiceStatus
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
844 lpServiceStatus
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
845 lpServiceStatus
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
846 lpServiceStatus
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
849 if (!service_accepts_control(service
->service_entry
, dwControl
))
851 service_unlock(service
->service_entry
);
852 return ERROR_INVALID_SERVICE_CONTROL
;
855 switch (service
->service_entry
->status
.dwCurrentState
)
857 case SERVICE_STOPPED
:
858 service_unlock(service
->service_entry
);
859 return ERROR_SERVICE_NOT_ACTIVE
;
860 case SERVICE_START_PENDING
:
861 if (dwControl
==SERVICE_CONTROL_STOP
)
864 case SERVICE_STOP_PENDING
:
865 service_unlock(service
->service_entry
);
866 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
869 /* prevent races by caching these variables and clearing them on
870 * stop here instead of outside the services lock */
871 control_mutex
= service
->service_entry
->control_mutex
;
872 control_pipe
= service
->service_entry
->control_pipe
;
873 if (dwControl
== SERVICE_CONTROL_STOP
)
875 service
->service_entry
->control_mutex
= NULL
;
876 service
->service_entry
->control_pipe
= INVALID_HANDLE_VALUE
;
879 service_unlock(service
->service_entry
);
881 ret
= WaitForSingleObject(control_mutex
, 30000);
882 if (ret
== WAIT_OBJECT_0
)
884 DWORD result
= ERROR_SUCCESS
;
886 ret
= service_send_control(service
->service_entry
, control_pipe
, dwControl
, &result
);
888 if (dwControl
== SERVICE_CONTROL_STOP
)
890 CloseHandle(control_mutex
);
891 CloseHandle(control_pipe
);
894 ReleaseMutex(control_mutex
);
900 if (dwControl
== SERVICE_CONTROL_STOP
)
902 CloseHandle(control_mutex
);
903 CloseHandle(control_pipe
);
905 return ERROR_SERVICE_REQUEST_TIMEOUT
;
909 DWORD
svcctl_CloseServiceHandle(
910 SC_RPC_HANDLE
*handle
)
912 WINE_TRACE("(&%p)\n", *handle
);
914 SC_RPC_HANDLE_destroy(*handle
);
917 return ERROR_SUCCESS
;
920 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock
)
922 struct sc_lock
*lock
= hLock
;
923 scmdatabase_unlock_startup(lock
->db
);
924 HeapFree(GetProcessHeap(), 0, lock
);
927 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock
)
929 SC_RPC_LOCK_destroy(hLock
);
932 DWORD
svcctl_LockServiceDatabase(
933 SC_RPC_HANDLE hSCManager
,
936 struct sc_manager_handle
*manager
;
937 struct sc_lock
*lock
;
940 WINE_TRACE("(%p, %p)\n", hSCManager
, phLock
);
942 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_LOCK
, &manager
)) != ERROR_SUCCESS
)
945 err
= scmdatabase_lock_startup(manager
->db
);
946 if (err
!= ERROR_SUCCESS
)
949 lock
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock
));
952 scmdatabase_unlock_startup(manager
->db
);
953 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
956 lock
->db
= manager
->db
;
959 return ERROR_SUCCESS
;
962 DWORD
svcctl_UnlockServiceDatabase(
965 WINE_TRACE("(&%p)\n", *phLock
);
967 SC_RPC_LOCK_destroy(*phLock
);
970 return ERROR_SUCCESS
;
973 DWORD
svcctl_QueryServiceObjectSecurity(
977 return ERROR_CALL_NOT_IMPLEMENTED
;
980 DWORD
svcctl_SetServiceObjectSecurity(
984 return ERROR_CALL_NOT_IMPLEMENTED
;
987 DWORD
svcctl_QueryServiceStatus(
991 return ERROR_CALL_NOT_IMPLEMENTED
;
995 DWORD
svcctl_NotifyBootConfigStatus(
999 return ERROR_CALL_NOT_IMPLEMENTED
;
1002 DWORD
svcctl_SCSetServiceBitsW(
1006 return ERROR_CALL_NOT_IMPLEMENTED
;
1010 DWORD
svcctl_EnumDependentServicesW(
1014 return ERROR_CALL_NOT_IMPLEMENTED
;
1017 DWORD
svcctl_EnumServicesStatusW(
1021 return ERROR_CALL_NOT_IMPLEMENTED
;
1025 DWORD
svcctl_QueryServiceLockStatusW(
1029 return ERROR_CALL_NOT_IMPLEMENTED
;
1032 DWORD
svcctl_SCSetServiceBitsA(
1036 return ERROR_CALL_NOT_IMPLEMENTED
;
1039 DWORD
svcctl_ChangeServiceConfigA(
1043 return ERROR_CALL_NOT_IMPLEMENTED
;
1046 DWORD
svcctl_CreateServiceA(
1050 return ERROR_CALL_NOT_IMPLEMENTED
;
1053 DWORD
svcctl_EnumDependentServicesA(
1057 return ERROR_CALL_NOT_IMPLEMENTED
;
1060 DWORD
svcctl_EnumServicesStatusA(
1064 return ERROR_CALL_NOT_IMPLEMENTED
;
1067 DWORD
svcctl_OpenSCManagerA(
1071 return ERROR_CALL_NOT_IMPLEMENTED
;
1074 DWORD
svcctl_OpenServiceA(
1078 return ERROR_CALL_NOT_IMPLEMENTED
;
1081 DWORD
svcctl_QueryServiceConfigA(
1085 return ERROR_CALL_NOT_IMPLEMENTED
;
1088 DWORD
svcctl_QueryServiceLockStatusA(
1092 return ERROR_CALL_NOT_IMPLEMENTED
;
1095 DWORD
svcctl_StartServiceA(
1099 return ERROR_CALL_NOT_IMPLEMENTED
;
1102 DWORD
svcctl_GetServiceDisplayNameA(
1106 return ERROR_CALL_NOT_IMPLEMENTED
;
1109 DWORD
svcctl_GetServiceKeyNameA(
1113 return ERROR_CALL_NOT_IMPLEMENTED
;
1116 DWORD
svcctl_GetCurrentGroupStateW(
1120 return ERROR_CALL_NOT_IMPLEMENTED
;
1123 DWORD
svcctl_EnumServiceGroupW(
1127 return ERROR_CALL_NOT_IMPLEMENTED
;
1130 DWORD
svcctl_ChangeServiceConfig2A(
1134 return ERROR_CALL_NOT_IMPLEMENTED
;
1137 DWORD
svcctl_QueryServiceConfig2A(
1141 return ERROR_CALL_NOT_IMPLEMENTED
;
1144 DWORD
svcctl_QueryServiceConfig2W(
1148 return ERROR_CALL_NOT_IMPLEMENTED
;
1152 DWORD
RPC_Init(void)
1154 WCHAR transport
[] = SVCCTL_TRANSPORT
;
1155 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
1158 if ((err
= RpcServerUseProtseqEpW(transport
, 0, endpoint
, NULL
)) != ERROR_SUCCESS
)
1160 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err
);
1164 if ((err
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
, 0, 0)) != ERROR_SUCCESS
)
1166 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err
);
1170 if ((err
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)) != ERROR_SUCCESS
)
1172 WINE_ERR("RpcServerListen failed with error %u\n", err
);
1175 return ERROR_SUCCESS
;
1178 DWORD
RPC_MainLoop(void)
1181 HANDLE hExitEvent
= __wine_make_process_system();
1183 SetEvent(g_hStartedEvent
);
1185 WINE_TRACE("Entered main loop\n");
1189 err
= WaitForSingleObjectEx(hExitEvent
, INFINITE
, TRUE
);
1190 WINE_TRACE("Wait returned %d\n", err
);
1191 } while (err
!= WAIT_OBJECT_0
);
1193 WINE_TRACE("Object signaled - wine shutdown\n");
1194 CloseHandle(hExitEvent
);
1195 return ERROR_SUCCESS
;
1198 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle
)
1200 SC_RPC_HANDLE_destroy(handle
);
1203 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
1205 return HeapAlloc(GetProcessHeap(), 0, len
);
1208 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
1210 HeapFree(GetProcessHeap(), 0, ptr
);