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 CDECL
__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 static void free_config_strings(QUERY_SERVICE_CONFIGW
*old_cfg
, QUERY_SERVICE_CONFIGW
*new_cfg
)
89 if (old_cfg
->lpBinaryPathName
!= new_cfg
->lpBinaryPathName
)
90 HeapFree(GetProcessHeap(), 0, old_cfg
->lpBinaryPathName
);
92 if (old_cfg
->lpLoadOrderGroup
!= new_cfg
->lpLoadOrderGroup
)
93 HeapFree(GetProcessHeap(), 0, old_cfg
->lpLoadOrderGroup
);
95 if (old_cfg
->lpServiceStartName
!= new_cfg
->lpServiceStartName
)
96 HeapFree(GetProcessHeap(), 0, old_cfg
->lpServiceStartName
);
98 if (old_cfg
->lpDisplayName
!= new_cfg
->lpDisplayName
)
99 HeapFree(GetProcessHeap(), 0, old_cfg
->lpDisplayName
);
102 /* Check if the given handle is of the required type and allows the requested access. */
103 static DWORD
validate_context_handle(SC_RPC_HANDLE handle
, DWORD type
, DWORD needed_access
, struct sc_handle
**out_hdr
)
105 struct sc_handle
*hdr
= handle
;
107 if (type
!= SC_HTYPE_DONT_CARE
&& hdr
->type
!= type
)
109 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr
->type
, type
);
110 return ERROR_INVALID_HANDLE
;
113 if ((needed_access
& hdr
->access
) != needed_access
)
115 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr
->access
, needed_access
);
116 return ERROR_ACCESS_DENIED
;
120 return ERROR_SUCCESS
;
123 static DWORD
validate_scm_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_manager_handle
**manager
)
125 struct sc_handle
*hdr
;
126 DWORD err
= validate_context_handle(handle
, SC_HTYPE_MANAGER
, needed_access
, &hdr
);
127 if (err
== ERROR_SUCCESS
)
128 *manager
= (struct sc_manager_handle
*)hdr
;
132 static DWORD
validate_service_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_service_handle
**service
)
134 struct sc_handle
*hdr
;
135 DWORD err
= validate_context_handle(handle
, SC_HTYPE_SERVICE
, needed_access
, &hdr
);
136 if (err
== ERROR_SUCCESS
)
137 *service
= (struct sc_service_handle
*)hdr
;
141 DWORD
svcctl_OpenSCManagerW(
142 MACHINE_HANDLEW MachineName
, /* Note: this parameter is ignored */
143 LPCWSTR DatabaseName
,
145 SC_RPC_HANDLE
*handle
)
147 struct sc_manager_handle
*manager
;
149 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName
), wine_dbgstr_w(DatabaseName
), dwAccessMask
);
151 if (DatabaseName
!= NULL
&& DatabaseName
[0])
153 if (strcmpW(DatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
154 return ERROR_DATABASE_DOES_NOT_EXIST
;
155 if (strcmpW(DatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
156 return ERROR_INVALID_NAME
;
159 if (!(manager
= HeapAlloc(GetProcessHeap(), 0, sizeof(*manager
))))
160 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
162 manager
->hdr
.type
= SC_HTYPE_MANAGER
;
164 if (dwAccessMask
& MAXIMUM_ALLOWED
)
165 dwAccessMask
|= SC_MANAGER_ALL_ACCESS
;
166 manager
->hdr
.access
= dwAccessMask
;
167 RtlMapGenericMask(&manager
->hdr
.access
, &g_scm_generic
);
168 manager
->db
= active_database
;
169 *handle
= &manager
->hdr
;
171 return ERROR_SUCCESS
;
174 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle
)
176 struct sc_handle
*hdr
= handle
;
179 case SC_HTYPE_MANAGER
:
181 struct sc_manager_handle
*manager
= (struct sc_manager_handle
*)hdr
;
182 HeapFree(GetProcessHeap(), 0, manager
);
185 case SC_HTYPE_SERVICE
:
187 struct sc_service_handle
*service
= (struct sc_service_handle
*)hdr
;
188 release_service(service
->service_entry
);
189 HeapFree(GetProcessHeap(), 0, service
);
193 WINE_ERR("invalid handle type %d\n", hdr
->type
);
194 RpcRaiseException(ERROR_INVALID_HANDLE
);
198 DWORD
svcctl_GetServiceDisplayNameW(
199 SC_RPC_HANDLE hSCManager
,
200 LPCWSTR lpServiceName
,
204 struct sc_manager_handle
*manager
;
205 struct service_entry
*entry
;
208 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName
), *cchBufSize
);
210 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
213 scmdatabase_lock_shared(manager
->db
);
215 entry
= scmdatabase_find_service(manager
->db
, lpServiceName
);
220 service_lock_shared(entry
);
221 name
= get_display_name(entry
);
223 if (len
<= *cchBufSize
)
226 memcpy(lpBuffer
, name
, (len
+ 1)*sizeof(*name
));
229 err
= ERROR_INSUFFICIENT_BUFFER
;
231 service_unlock(entry
);
234 err
= ERROR_SERVICE_DOES_NOT_EXIST
;
236 scmdatabase_unlock(manager
->db
);
238 if (err
!= ERROR_SUCCESS
)
244 DWORD
svcctl_GetServiceKeyNameW(
245 SC_RPC_HANDLE hSCManager
,
246 LPCWSTR lpServiceDisplayName
,
250 struct service_entry
*entry
;
251 struct sc_manager_handle
*manager
;
254 WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName
), *cchBufSize
);
256 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
259 scmdatabase_lock_shared(manager
->db
);
261 entry
= scmdatabase_find_service_by_displayname(manager
->db
, lpServiceDisplayName
);
265 service_lock_shared(entry
);
266 len
= strlenW(entry
->name
);
267 if (len
<= *cchBufSize
)
270 memcpy(lpBuffer
, entry
->name
, (len
+ 1)*sizeof(*entry
->name
));
273 err
= ERROR_INSUFFICIENT_BUFFER
;
275 service_unlock(entry
);
278 err
= ERROR_SERVICE_DOES_NOT_EXIST
;
280 scmdatabase_unlock(manager
->db
);
282 if (err
!= ERROR_SUCCESS
)
288 static DWORD
create_handle_for_service(struct service_entry
*entry
, DWORD dwDesiredAccess
, SC_RPC_HANDLE
*phService
)
290 struct sc_service_handle
*service
;
292 if (!(service
= HeapAlloc(GetProcessHeap(), 0, sizeof(*service
))))
294 release_service(entry
);
295 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
298 service
->hdr
.type
= SC_HTYPE_SERVICE
;
299 service
->hdr
.access
= dwDesiredAccess
;
300 RtlMapGenericMask(&service
->hdr
.access
, &g_svc_generic
);
301 service
->service_entry
= entry
;
302 if (dwDesiredAccess
& MAXIMUM_ALLOWED
)
303 dwDesiredAccess
|= SERVICE_ALL_ACCESS
;
305 *phService
= &service
->hdr
;
306 return ERROR_SUCCESS
;
309 DWORD
svcctl_OpenServiceW(
310 SC_RPC_HANDLE hSCManager
,
311 LPCWSTR lpServiceName
,
312 DWORD dwDesiredAccess
,
313 SC_RPC_HANDLE
*phService
)
315 struct sc_manager_handle
*manager
;
316 struct service_entry
*entry
;
319 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName
), dwDesiredAccess
);
321 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
323 if (!validate_service_name(lpServiceName
))
324 return ERROR_INVALID_NAME
;
326 scmdatabase_lock_shared(manager
->db
);
327 entry
= scmdatabase_find_service(manager
->db
, lpServiceName
);
329 InterlockedIncrement(&entry
->ref_count
);
330 scmdatabase_unlock(manager
->db
);
333 return ERROR_SERVICE_DOES_NOT_EXIST
;
335 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
338 DWORD
svcctl_CreateServiceW(
339 SC_RPC_HANDLE hSCManager
,
340 LPCWSTR lpServiceName
,
341 LPCWSTR lpDisplayName
,
342 DWORD dwDesiredAccess
,
345 DWORD dwErrorControl
,
346 LPCWSTR lpBinaryPathName
,
347 LPCWSTR lpLoadOrderGroup
,
349 const BYTE
*lpDependencies
,
350 DWORD dwDependenciesSize
,
351 LPCWSTR lpServiceStartName
,
352 const BYTE
*lpPassword
,
353 DWORD dwPasswordSize
,
354 SC_RPC_HANDLE
*phService
)
356 struct sc_manager_handle
*manager
;
357 struct service_entry
*entry
;
360 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName
), wine_dbgstr_w(lpDisplayName
), dwDesiredAccess
, wine_dbgstr_w(lpBinaryPathName
));
362 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_CREATE_SERVICE
, &manager
)) != ERROR_SUCCESS
)
365 if (!validate_service_name(lpServiceName
))
366 return ERROR_INVALID_NAME
;
367 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
) || !lpServiceName
[0] || !lpBinaryPathName
[0])
368 return ERROR_INVALID_PARAMETER
;
371 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
373 WINE_FIXME("Dependencies not supported yet\n");
375 err
= service_create(lpServiceName
, &entry
);
376 if (err
!= ERROR_SUCCESS
)
378 entry
->ref_count
= 1;
379 entry
->config
.dwServiceType
= entry
->status
.dwServiceType
= dwServiceType
;
380 entry
->config
.dwStartType
= dwStartType
;
381 entry
->config
.dwErrorControl
= dwErrorControl
;
382 entry
->config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
383 entry
->config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
384 entry
->config
.lpServiceStartName
= strdupW(lpServiceStartName
);
385 entry
->config
.lpDisplayName
= strdupW(lpDisplayName
);
387 if (lpdwTagId
) /* TODO: In most situations a non-NULL TagId will generate an ERROR_INVALID_PARAMETER. */
388 entry
->config
.dwTagId
= *lpdwTagId
;
390 entry
->config
.dwTagId
= 0;
392 /* other fields NULL*/
394 if (!validate_service_config(entry
))
396 WINE_ERR("Invalid data while trying to create service\n");
397 free_service_entry(entry
);
398 return ERROR_INVALID_PARAMETER
;
401 scmdatabase_lock_exclusive(manager
->db
);
403 if (scmdatabase_find_service(manager
->db
, lpServiceName
))
405 scmdatabase_unlock(manager
->db
);
406 free_service_entry(entry
);
407 return ERROR_SERVICE_EXISTS
;
410 if (scmdatabase_find_service_by_displayname(manager
->db
, get_display_name(entry
)))
412 scmdatabase_unlock(manager
->db
);
413 free_service_entry(entry
);
414 return ERROR_DUPLICATE_SERVICE_NAME
;
417 err
= scmdatabase_add_service(manager
->db
, entry
);
418 if (err
!= ERROR_SUCCESS
)
420 scmdatabase_unlock(manager
->db
);
421 free_service_entry(entry
);
424 scmdatabase_unlock(manager
->db
);
426 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
429 DWORD
svcctl_DeleteService(
430 SC_RPC_HANDLE hService
)
432 struct sc_service_handle
*service
;
435 if ((err
= validate_service_handle(hService
, DELETE
, &service
)) != ERROR_SUCCESS
)
438 scmdatabase_lock_exclusive(service
->service_entry
->db
);
439 service_lock_exclusive(service
->service_entry
);
441 if (!is_marked_for_delete(service
->service_entry
))
442 err
= scmdatabase_remove_service(service
->service_entry
->db
, service
->service_entry
);
444 err
= ERROR_SERVICE_MARKED_FOR_DELETE
;
446 service_unlock(service
->service_entry
);
447 scmdatabase_unlock(service
->service_entry
->db
);
452 DWORD
svcctl_QueryServiceConfigW(
453 SC_RPC_HANDLE hService
,
454 QUERY_SERVICE_CONFIGW
*config
)
456 struct sc_service_handle
*service
;
459 WINE_TRACE("(%p)\n", config
);
461 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_CONFIG
, &service
)) != 0)
464 service_lock_shared(service
->service_entry
);
465 config
->dwServiceType
= service
->service_entry
->config
.dwServiceType
;
466 config
->dwStartType
= service
->service_entry
->config
.dwStartType
;
467 config
->dwErrorControl
= service
->service_entry
->config
.dwErrorControl
;
468 config
->lpBinaryPathName
= strdupW(service
->service_entry
->config
.lpBinaryPathName
);
469 config
->lpLoadOrderGroup
= strdupW(service
->service_entry
->config
.lpLoadOrderGroup
);
470 config
->dwTagId
= service
->service_entry
->config
.dwTagId
;
471 config
->lpDependencies
= NULL
; /* TODO */
472 config
->lpServiceStartName
= strdupW(service
->service_entry
->config
.lpServiceStartName
);
473 config
->lpDisplayName
= strdupW(service
->service_entry
->config
.lpDisplayName
);
474 service_unlock(service
->service_entry
);
476 return ERROR_SUCCESS
;
479 DWORD
svcctl_ChangeServiceConfigW(
480 SC_RPC_HANDLE hService
,
483 DWORD dwErrorControl
,
484 LPCWSTR lpBinaryPathName
,
485 LPCWSTR lpLoadOrderGroup
,
487 const BYTE
*lpDependencies
,
488 DWORD dwDependenciesSize
,
489 LPCWSTR lpServiceStartName
,
490 const BYTE
*lpPassword
,
491 DWORD dwPasswordSize
,
492 LPCWSTR lpDisplayName
)
494 struct service_entry new_entry
, *entry
;
495 struct sc_service_handle
*service
;
500 if ((err
= validate_service_handle(hService
, SERVICE_CHANGE_CONFIG
, &service
)) != 0)
503 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
))
504 return ERROR_INVALID_PARAMETER
;
506 /* first check if the new configuration is correct */
507 service_lock_exclusive(service
->service_entry
);
509 if (is_marked_for_delete(service
->service_entry
))
511 service_unlock(service
->service_entry
);
512 return ERROR_SERVICE_MARKED_FOR_DELETE
;
515 if (lpDisplayName
!= NULL
&&
516 (entry
= scmdatabase_find_service_by_displayname(service
->service_entry
->db
, lpDisplayName
)) &&
517 (entry
!= service
->service_entry
))
519 service_unlock(service
->service_entry
);
520 return ERROR_DUPLICATE_SERVICE_NAME
;
523 new_entry
= *service
->service_entry
;
525 if (dwServiceType
!= SERVICE_NO_CHANGE
)
526 new_entry
.config
.dwServiceType
= dwServiceType
;
528 if (dwStartType
!= SERVICE_NO_CHANGE
)
529 new_entry
.config
.dwStartType
= dwStartType
;
531 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
532 new_entry
.config
.dwErrorControl
= dwErrorControl
;
534 if (lpBinaryPathName
!= NULL
)
535 new_entry
.config
.lpBinaryPathName
= (LPWSTR
)lpBinaryPathName
;
537 if (lpLoadOrderGroup
!= NULL
)
538 new_entry
.config
.lpLoadOrderGroup
= (LPWSTR
)lpLoadOrderGroup
;
540 if (lpdwTagId
!= NULL
)
541 WINE_FIXME("Changing tag id not supported\n");
543 if (lpDependencies
!= NULL
)
544 WINE_FIXME("Changing dependencies not supported\n");
546 if (lpServiceStartName
!= NULL
)
547 new_entry
.config
.lpServiceStartName
= (LPWSTR
)lpServiceStartName
;
549 if (lpPassword
!= NULL
)
550 WINE_FIXME("Setting password not supported\n");
552 if (lpDisplayName
!= NULL
)
553 new_entry
.config
.lpDisplayName
= (LPWSTR
)lpDisplayName
;
555 if (!validate_service_config(&new_entry
))
557 WINE_ERR("The configuration after the change wouldn't be valid\n");
558 service_unlock(service
->service_entry
);
559 return ERROR_INVALID_PARAMETER
;
562 /* configuration OK. The strings needs to be duplicated */
563 if (lpBinaryPathName
!= NULL
)
564 new_entry
.config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
566 if (lpLoadOrderGroup
!= NULL
)
567 new_entry
.config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
569 if (lpServiceStartName
!= NULL
)
570 new_entry
.config
.lpServiceStartName
= strdupW(lpServiceStartName
);
572 if (lpDisplayName
!= NULL
)
573 new_entry
.config
.lpDisplayName
= strdupW(lpDisplayName
);
575 /* try to save to Registry, commit or rollback depending on success */
576 err
= save_service_config(&new_entry
);
577 if (ERROR_SUCCESS
== err
)
579 free_config_strings(&service
->service_entry
->config
,&new_entry
.config
);
580 *service
->service_entry
= new_entry
;
582 else free_config_strings(&new_entry
.config
,&service
->service_entry
->config
);
583 service_unlock(service
->service_entry
);
588 DWORD
svcctl_SetServiceStatus(
589 SC_RPC_HANDLE hServiceStatus
,
590 LPSERVICE_STATUS lpServiceStatus
)
592 struct sc_service_handle
*service
;
595 WINE_TRACE("(%p, %p)\n", hServiceStatus
, lpServiceStatus
);
597 if ((err
= validate_service_handle(hServiceStatus
, SERVICE_SET_STATUS
, &service
)) != 0)
600 service_lock_exclusive(service
->service_entry
);
601 /* FIXME: be a bit more discriminant about what parts of the status we set
602 * and check that fields are valid */
603 service
->service_entry
->status
.dwServiceType
= lpServiceStatus
->dwServiceType
;
604 service
->service_entry
->status
.dwCurrentState
= lpServiceStatus
->dwCurrentState
;
605 service
->service_entry
->status
.dwControlsAccepted
= lpServiceStatus
->dwControlsAccepted
;
606 service
->service_entry
->status
.dwWin32ExitCode
= lpServiceStatus
->dwWin32ExitCode
;
607 service
->service_entry
->status
.dwServiceSpecificExitCode
= lpServiceStatus
->dwServiceSpecificExitCode
;
608 service
->service_entry
->status
.dwCheckPoint
= lpServiceStatus
->dwCheckPoint
;
609 service
->service_entry
->status
.dwWaitHint
= lpServiceStatus
->dwWaitHint
;
610 service_unlock(service
->service_entry
);
612 if (service
->service_entry
->status_changed_event
)
613 SetEvent(service
->service_entry
->status_changed_event
);
615 return ERROR_SUCCESS
;
618 DWORD
svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService
, DWORD level
, SERVICE_CONFIG2W
*config
)
620 struct sc_service_handle
*service
;
623 if ((err
= validate_service_handle(hService
, SERVICE_CHANGE_CONFIG
, &service
)) != 0)
628 case SERVICE_CONFIG_DESCRIPTION
:
632 if (config
->descr
.lpDescription
[0])
634 if (!(descr
= strdupW( config
->descr
.lpDescription
)))
635 return ERROR_NOT_ENOUGH_MEMORY
;
638 WINE_TRACE( "changing service %p descr to %s\n", service
, wine_dbgstr_w(descr
) );
639 service_lock_exclusive( service
->service_entry
);
640 HeapFree( GetProcessHeap(), 0, service
->service_entry
->description
);
641 service
->service_entry
->description
= descr
;
642 save_service_config( service
->service_entry
);
643 service_unlock( service
->service_entry
);
646 case SERVICE_CONFIG_FAILURE_ACTIONS
:
647 WINE_FIXME( "SERVICE_CONFIG_FAILURE_ACTIONS not implemented: period %u msg %s cmd %s\n",
648 config
->actions
.dwResetPeriod
,
649 wine_dbgstr_w(config
->actions
.lpRebootMsg
),
650 wine_dbgstr_w(config
->actions
.lpCommand
) );
653 WINE_FIXME("level %u not implemented\n", level
);
654 err
= ERROR_INVALID_LEVEL
;
660 DWORD
svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService
, DWORD level
,
661 BYTE
*buffer
, DWORD size
, LPDWORD needed
)
663 struct sc_service_handle
*service
;
666 memset(buffer
, 0, size
);
668 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_STATUS
, &service
)) != 0)
673 case SERVICE_CONFIG_DESCRIPTION
:
675 SERVICE_DESCRIPTIONW
*descr
= (SERVICE_DESCRIPTIONW
*)buffer
;
677 service_lock_shared(service
->service_entry
);
678 *needed
= sizeof(*descr
);
679 if (service
->service_entry
->description
)
680 *needed
+= (strlenW(service
->service_entry
->description
) + 1) * sizeof(WCHAR
);
683 if (service
->service_entry
->description
)
685 /* store a buffer offset instead of a pointer */
686 descr
->lpDescription
= (WCHAR
*)((BYTE
*)(descr
+ 1) - buffer
);
687 strcpyW( (WCHAR
*)(descr
+ 1), service
->service_entry
->description
);
689 else descr
->lpDescription
= NULL
;
691 else err
= ERROR_INSUFFICIENT_BUFFER
;
692 service_unlock(service
->service_entry
);
697 WINE_FIXME("level %u not implemented\n", level
);
698 err
= ERROR_INVALID_LEVEL
;
704 DWORD
svcctl_QueryServiceStatusEx(
705 SC_RPC_HANDLE hService
,
706 SC_STATUS_TYPE InfoLevel
,
709 LPDWORD pcbBytesNeeded
)
711 struct sc_service_handle
*service
;
713 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
715 memset(lpBuffer
, 0, cbBufSize
);
717 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_STATUS
, &service
)) != 0)
720 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
721 return ERROR_INVALID_LEVEL
;
723 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
724 if (pSvcStatusData
== NULL
)
725 return ERROR_INVALID_PARAMETER
;
727 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
729 if( pcbBytesNeeded
!= NULL
)
730 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
732 return ERROR_INSUFFICIENT_BUFFER
;
735 service_lock_shared(service
->service_entry
);
737 pSvcStatusData
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
738 pSvcStatusData
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
739 pSvcStatusData
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
740 pSvcStatusData
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
741 pSvcStatusData
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
742 pSvcStatusData
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
743 pSvcStatusData
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
744 pSvcStatusData
->dwProcessId
= service
->service_entry
->status
.dwProcessId
;
745 pSvcStatusData
->dwServiceFlags
= service
->service_entry
->status
.dwServiceFlags
;
747 service_unlock(service
->service_entry
);
749 return ERROR_SUCCESS
;
752 /******************************************************************************
753 * service_accepts_control
755 static BOOL
service_accepts_control(const struct service_entry
*service
, DWORD dwControl
)
757 DWORD a
= service
->status
.dwControlsAccepted
;
761 case SERVICE_CONTROL_INTERROGATE
:
763 case SERVICE_CONTROL_STOP
:
764 if (a
&SERVICE_ACCEPT_STOP
)
767 case SERVICE_CONTROL_SHUTDOWN
:
768 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
771 case SERVICE_CONTROL_PAUSE
:
772 case SERVICE_CONTROL_CONTINUE
:
773 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
776 case SERVICE_CONTROL_PARAMCHANGE
:
777 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
780 case SERVICE_CONTROL_NETBINDADD
:
781 case SERVICE_CONTROL_NETBINDREMOVE
:
782 case SERVICE_CONTROL_NETBINDENABLE
:
783 case SERVICE_CONTROL_NETBINDDISABLE
:
784 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
786 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
787 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
790 case SERVICE_CONTROL_POWEREVENT
:
791 if (a
&SERVICE_ACCEPT_POWEREVENT
)
794 case SERVICE_CONTROL_SESSIONCHANGE
:
795 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
802 /******************************************************************************
803 * service_send_control
805 static BOOL
service_send_control(struct service_entry
*service
, HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
807 service_start_info
*ssi
;
808 DWORD len
, count
= 0;
811 /* calculate how much space we need to send the startup info */
812 len
= strlenW(service
->name
) + 1;
814 ssi
= HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info
, data
[len
]));
815 ssi
->cmd
= WINESERV_SENDCONTROL
;
816 ssi
->control
= dwControl
;
817 ssi
->total_size
= FIELD_OFFSET(service_start_info
, data
[len
]);
818 ssi
->name_size
= strlenW(service
->name
) + 1;
819 strcpyW( ssi
->data
, service
->name
);
821 r
= WriteFile(pipe
, ssi
, ssi
->total_size
, &count
, NULL
);
822 if (!r
|| count
!= ssi
->total_size
)
824 WINE_ERR("service protocol error - failed to write pipe!\n");
827 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
828 if (!r
|| count
!= sizeof *result
)
829 WINE_ERR("service protocol error - failed to read pipe "
830 "r = %d count = %d!\n", r
, count
);
834 DWORD
svcctl_StartServiceW(
835 SC_RPC_HANDLE hService
,
836 DWORD dwNumServiceArgs
,
837 LPCWSTR
*lpServiceArgVectors
)
839 struct sc_service_handle
*service
;
842 WINE_TRACE("(%p, %d, %p)\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
844 if ((err
= validate_service_handle(hService
, SERVICE_START
, &service
)) != 0)
847 err
= service_start(service
->service_entry
, dwNumServiceArgs
, lpServiceArgVectors
);
852 DWORD
svcctl_ControlService(
853 SC_RPC_HANDLE hService
,
855 SERVICE_STATUS
*lpServiceStatus
)
857 DWORD access_required
;
858 struct sc_service_handle
*service
;
861 HANDLE control_mutex
;
864 WINE_TRACE("(%p, %d, %p)\n", hService
, dwControl
, lpServiceStatus
);
868 case SERVICE_CONTROL_CONTINUE
:
869 case SERVICE_CONTROL_NETBINDADD
:
870 case SERVICE_CONTROL_NETBINDDISABLE
:
871 case SERVICE_CONTROL_NETBINDENABLE
:
872 case SERVICE_CONTROL_NETBINDREMOVE
:
873 case SERVICE_CONTROL_PARAMCHANGE
:
874 case SERVICE_CONTROL_PAUSE
:
875 access_required
= SERVICE_PAUSE_CONTINUE
;
877 case SERVICE_CONTROL_INTERROGATE
:
878 access_required
= SERVICE_INTERROGATE
;
880 case SERVICE_CONTROL_STOP
:
881 access_required
= SERVICE_STOP
;
884 if (dwControl
>= 128 && dwControl
<= 255)
885 access_required
= SERVICE_USER_DEFINED_CONTROL
;
887 return ERROR_INVALID_PARAMETER
;
890 if ((err
= validate_service_handle(hService
, access_required
, &service
)) != 0)
893 service_lock_exclusive(service
->service_entry
);
897 lpServiceStatus
->dwServiceType
= service
->service_entry
->status
.dwServiceType
;
898 lpServiceStatus
->dwCurrentState
= service
->service_entry
->status
.dwCurrentState
;
899 lpServiceStatus
->dwControlsAccepted
= service
->service_entry
->status
.dwControlsAccepted
;
900 lpServiceStatus
->dwWin32ExitCode
= service
->service_entry
->status
.dwWin32ExitCode
;
901 lpServiceStatus
->dwServiceSpecificExitCode
= service
->service_entry
->status
.dwServiceSpecificExitCode
;
902 lpServiceStatus
->dwCheckPoint
= service
->service_entry
->status
.dwCheckPoint
;
903 lpServiceStatus
->dwWaitHint
= service
->service_entry
->status
.dwWaitHint
;
906 if (!service_accepts_control(service
->service_entry
, dwControl
))
908 service_unlock(service
->service_entry
);
909 return ERROR_INVALID_SERVICE_CONTROL
;
912 switch (service
->service_entry
->status
.dwCurrentState
)
914 case SERVICE_STOPPED
:
915 service_unlock(service
->service_entry
);
916 return ERROR_SERVICE_NOT_ACTIVE
;
917 case SERVICE_START_PENDING
:
918 if (dwControl
==SERVICE_CONTROL_STOP
)
921 case SERVICE_STOP_PENDING
:
922 service_unlock(service
->service_entry
);
923 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
926 /* prevent races by caching these variables and clearing them on
927 * stop here instead of outside the services lock */
928 control_mutex
= service
->service_entry
->control_mutex
;
929 control_pipe
= service
->service_entry
->control_pipe
;
930 if (dwControl
== SERVICE_CONTROL_STOP
)
932 service
->service_entry
->control_mutex
= NULL
;
933 service
->service_entry
->control_pipe
= INVALID_HANDLE_VALUE
;
936 service_unlock(service
->service_entry
);
938 ret
= WaitForSingleObject(control_mutex
, 30000);
939 if (ret
== WAIT_OBJECT_0
)
941 DWORD result
= ERROR_SUCCESS
;
943 ret
= service_send_control(service
->service_entry
, control_pipe
, dwControl
, &result
);
945 if (dwControl
== SERVICE_CONTROL_STOP
)
947 CloseHandle(control_mutex
);
948 CloseHandle(control_pipe
);
951 ReleaseMutex(control_mutex
);
957 if (dwControl
== SERVICE_CONTROL_STOP
)
959 CloseHandle(control_mutex
);
960 CloseHandle(control_pipe
);
962 return ERROR_SERVICE_REQUEST_TIMEOUT
;
966 DWORD
svcctl_CloseServiceHandle(
967 SC_RPC_HANDLE
*handle
)
969 WINE_TRACE("(&%p)\n", *handle
);
971 SC_RPC_HANDLE_destroy(*handle
);
974 return ERROR_SUCCESS
;
977 static void SC_RPC_LOCK_destroy(SC_RPC_LOCK hLock
)
979 struct sc_lock
*lock
= hLock
;
980 scmdatabase_unlock_startup(lock
->db
);
981 HeapFree(GetProcessHeap(), 0, lock
);
984 void __RPC_USER
SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock
)
986 SC_RPC_LOCK_destroy(hLock
);
989 DWORD
svcctl_LockServiceDatabase(
990 SC_RPC_HANDLE hSCManager
,
993 struct sc_manager_handle
*manager
;
994 struct sc_lock
*lock
;
997 WINE_TRACE("(%p, %p)\n", hSCManager
, phLock
);
999 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_LOCK
, &manager
)) != ERROR_SUCCESS
)
1002 err
= scmdatabase_lock_startup(manager
->db
);
1003 if (err
!= ERROR_SUCCESS
)
1006 lock
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct sc_lock
));
1009 scmdatabase_unlock_startup(manager
->db
);
1010 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
1013 lock
->db
= manager
->db
;
1016 return ERROR_SUCCESS
;
1019 DWORD
svcctl_UnlockServiceDatabase(
1020 SC_RPC_LOCK
*phLock
)
1022 WINE_TRACE("(&%p)\n", *phLock
);
1024 SC_RPC_LOCK_destroy(*phLock
);
1027 return ERROR_SUCCESS
;
1030 DWORD
svcctl_QueryServiceObjectSecurity(
1034 return ERROR_CALL_NOT_IMPLEMENTED
;
1037 DWORD
svcctl_SetServiceObjectSecurity(
1041 return ERROR_CALL_NOT_IMPLEMENTED
;
1044 DWORD
svcctl_QueryServiceStatus(
1048 return ERROR_CALL_NOT_IMPLEMENTED
;
1052 DWORD
svcctl_NotifyBootConfigStatus(
1056 return ERROR_CALL_NOT_IMPLEMENTED
;
1059 DWORD
svcctl_SCSetServiceBitsW(
1063 return ERROR_CALL_NOT_IMPLEMENTED
;
1067 DWORD
svcctl_EnumDependentServicesW(
1071 return ERROR_CALL_NOT_IMPLEMENTED
;
1074 DWORD
svcctl_EnumServicesStatusW(
1078 return ERROR_CALL_NOT_IMPLEMENTED
;
1082 DWORD
svcctl_QueryServiceLockStatusW(
1086 return ERROR_CALL_NOT_IMPLEMENTED
;
1089 DWORD
svcctl_SCSetServiceBitsA(
1093 return ERROR_CALL_NOT_IMPLEMENTED
;
1096 DWORD
svcctl_ChangeServiceConfigA(
1100 return ERROR_CALL_NOT_IMPLEMENTED
;
1103 DWORD
svcctl_CreateServiceA(
1107 return ERROR_CALL_NOT_IMPLEMENTED
;
1110 DWORD
svcctl_EnumDependentServicesA(
1114 return ERROR_CALL_NOT_IMPLEMENTED
;
1117 DWORD
svcctl_EnumServicesStatusA(
1121 return ERROR_CALL_NOT_IMPLEMENTED
;
1124 DWORD
svcctl_OpenSCManagerA(
1128 return ERROR_CALL_NOT_IMPLEMENTED
;
1131 DWORD
svcctl_OpenServiceA(
1135 return ERROR_CALL_NOT_IMPLEMENTED
;
1138 DWORD
svcctl_QueryServiceConfigA(
1142 return ERROR_CALL_NOT_IMPLEMENTED
;
1145 DWORD
svcctl_QueryServiceLockStatusA(
1149 return ERROR_CALL_NOT_IMPLEMENTED
;
1152 DWORD
svcctl_StartServiceA(
1156 return ERROR_CALL_NOT_IMPLEMENTED
;
1159 DWORD
svcctl_GetServiceDisplayNameA(
1163 return ERROR_CALL_NOT_IMPLEMENTED
;
1166 DWORD
svcctl_GetServiceKeyNameA(
1170 return ERROR_CALL_NOT_IMPLEMENTED
;
1173 DWORD
svcctl_GetCurrentGroupStateW(
1177 return ERROR_CALL_NOT_IMPLEMENTED
;
1180 DWORD
svcctl_EnumServiceGroupW(
1184 return ERROR_CALL_NOT_IMPLEMENTED
;
1187 DWORD
svcctl_ChangeServiceConfig2A(
1191 return ERROR_CALL_NOT_IMPLEMENTED
;
1194 DWORD
svcctl_QueryServiceConfig2A(
1198 return ERROR_CALL_NOT_IMPLEMENTED
;
1202 DWORD
RPC_Init(void)
1204 WCHAR transport
[] = SVCCTL_TRANSPORT
;
1205 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
1208 if ((err
= RpcServerUseProtseqEpW(transport
, 0, endpoint
, NULL
)) != ERROR_SUCCESS
)
1210 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err
);
1214 if ((err
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
, 0, 0)) != ERROR_SUCCESS
)
1216 WINE_ERR("RpcServerRegisterIf failed with error %u\n", err
);
1220 if ((err
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)) != ERROR_SUCCESS
)
1222 WINE_ERR("RpcServerListen failed with error %u\n", err
);
1225 return ERROR_SUCCESS
;
1228 DWORD
RPC_MainLoop(void)
1231 HANDLE hExitEvent
= __wine_make_process_system();
1233 SetEvent(g_hStartedEvent
);
1235 WINE_TRACE("Entered main loop\n");
1239 err
= WaitForSingleObjectEx(hExitEvent
, INFINITE
, TRUE
);
1240 WINE_TRACE("Wait returned %d\n", err
);
1241 } while (err
!= WAIT_OBJECT_0
);
1243 WINE_TRACE("Object signaled - wine shutdown\n");
1244 CloseHandle(hExitEvent
);
1245 return ERROR_SUCCESS
;
1248 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle
)
1250 SC_RPC_HANDLE_destroy(handle
);
1253 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
1255 return HeapAlloc(GetProcessHeap(), 0, len
);
1258 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
1260 HeapFree(GetProcessHeap(), 0, ptr
);