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 CRITICAL_SECTION g_handle_table_cs
;
42 static CRITICAL_SECTION_DEBUG g_handle_table_cs_debug
=
44 0, 0, &g_handle_table_cs
,
45 { &g_handle_table_cs_debug
.ProcessLocksList
,
46 &g_handle_table_cs_debug
.ProcessLocksList
},
47 0, 0, { (DWORD_PTR
)(__FILE__
": g_handle_table_cs") }
49 static CRITICAL_SECTION g_handle_table_cs
= { &g_handle_table_cs_debug
, -1, 0, 0, 0, 0 };
51 static const GENERIC_MAPPING g_scm_generic
=
53 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
54 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
55 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
59 static const GENERIC_MAPPING g_svc_generic
=
61 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
62 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
63 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
69 SC_HTYPE_DONT_CARE
= 0,
80 struct sc_manager
/* service control manager handle */
85 struct sc_service
/* service handle */
88 struct service_entry
*service_entry
;
91 /* Check if the given handle is of the required type and allows the requested access. */
92 static DWORD
validate_context_handle(SC_RPC_HANDLE handle
, DWORD type
, DWORD needed_access
, struct sc_handle
**out_hdr
)
94 struct sc_handle
*hdr
= (struct sc_handle
*)handle
;
96 if (type
!= SC_HTYPE_DONT_CARE
&& hdr
->type
!= type
)
98 WINE_ERR("Handle is of an invalid type (%d, %d)\n", hdr
->type
, type
);
99 return ERROR_INVALID_HANDLE
;
102 if ((needed_access
& hdr
->access
) != needed_access
)
104 WINE_ERR("Access denied - handle created with access %x, needed %x\n", hdr
->access
, needed_access
);
105 return ERROR_ACCESS_DENIED
;
109 return ERROR_SUCCESS
;
112 static DWORD
validate_scm_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_manager
**manager
)
114 struct sc_handle
*hdr
;
115 DWORD err
= validate_context_handle(handle
, SC_HTYPE_MANAGER
, needed_access
, &hdr
);
116 if (err
== ERROR_SUCCESS
)
117 *manager
= (struct sc_manager
*)hdr
;
121 static DWORD
validate_service_handle(SC_RPC_HANDLE handle
, DWORD needed_access
, struct sc_service
**service
)
123 struct sc_handle
*hdr
;
124 DWORD err
= validate_context_handle(handle
, SC_HTYPE_SERVICE
, needed_access
, &hdr
);
125 if (err
== ERROR_SUCCESS
)
126 *service
= (struct sc_service
*)hdr
;
130 DWORD
svcctl_OpenSCManagerW(
131 MACHINE_HANDLEW MachineName
, /* Note: this parameter is ignored */
132 LPCWSTR DatabaseName
,
134 SC_RPC_HANDLE
*handle
)
136 struct sc_manager
*manager
;
138 WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName
), wine_dbgstr_w(DatabaseName
), dwAccessMask
);
140 if (DatabaseName
!= NULL
&& DatabaseName
[0])
142 if (strcmpW(DatabaseName
, SERVICES_FAILED_DATABASEW
) == 0)
143 return ERROR_DATABASE_DOES_NOT_EXIST
;
144 if (strcmpW(DatabaseName
, SERVICES_ACTIVE_DATABASEW
) != 0)
145 return ERROR_INVALID_NAME
;
148 if (!(manager
= HeapAlloc(GetProcessHeap(), 0, sizeof(*manager
))))
149 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
151 manager
->hdr
.type
= SC_HTYPE_MANAGER
;
153 if (dwAccessMask
& MAXIMUM_ALLOWED
)
154 dwAccessMask
|= SC_MANAGER_ALL_ACCESS
;
155 manager
->hdr
.access
= dwAccessMask
;
156 RtlMapGenericMask(&manager
->hdr
.access
, &g_scm_generic
);
157 *handle
= &manager
->hdr
;
159 return ERROR_SUCCESS
;
162 static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle
)
164 struct sc_handle
*hdr
= (struct sc_handle
*)handle
;
167 case SC_HTYPE_MANAGER
:
169 struct sc_manager
*manager
= (struct sc_manager
*)hdr
;
170 HeapFree(GetProcessHeap(), 0, manager
);
173 case SC_HTYPE_SERVICE
:
175 struct sc_service
*service
= (struct sc_service
*)hdr
;
176 release_service(service
->service_entry
);
177 HeapFree(GetProcessHeap(), 0, service
);
181 WINE_ERR("invalid handle type %d\n", hdr
->type
);
182 RpcRaiseException(ERROR_INVALID_HANDLE
);
186 static DWORD
create_handle_for_service(struct service_entry
*entry
, DWORD dwDesiredAccess
, SC_RPC_HANDLE
*phService
)
188 struct sc_service
*service
;
190 if (!(service
= HeapAlloc(GetProcessHeap(), 0, sizeof(*service
))))
192 release_service(entry
);
193 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
196 service
->hdr
.type
= SC_HTYPE_SERVICE
;
197 service
->hdr
.access
= dwDesiredAccess
;
198 RtlMapGenericMask(&service
->hdr
.access
, &g_svc_generic
);
199 service
->service_entry
= entry
;
200 if (dwDesiredAccess
& MAXIMUM_ALLOWED
)
201 dwDesiredAccess
|= SERVICE_ALL_ACCESS
;
203 *phService
= &service
->hdr
;
204 return ERROR_SUCCESS
;
207 DWORD
svcctl_OpenServiceW(
208 SC_RPC_HANDLE hSCManager
,
209 LPCWSTR lpServiceName
,
210 DWORD dwDesiredAccess
,
211 SC_RPC_HANDLE
*phService
)
213 struct sc_manager
*manager
;
214 struct service_entry
*entry
;
217 WINE_TRACE("(%s, 0x%x)\n", wine_dbgstr_w(lpServiceName
), dwDesiredAccess
);
219 if ((err
= validate_scm_handle(hSCManager
, 0, &manager
)) != ERROR_SUCCESS
)
221 if (!validate_service_name(lpServiceName
))
222 return ERROR_INVALID_NAME
;
225 entry
= find_service(lpServiceName
);
231 return ERROR_SERVICE_DOES_NOT_EXIST
;
233 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
236 DWORD
svcctl_CreateServiceW(
237 SC_RPC_HANDLE hSCManager
,
238 LPCWSTR lpServiceName
,
239 LPCWSTR lpDisplayName
,
240 DWORD dwDesiredAccess
,
243 DWORD dwErrorControl
,
244 LPCWSTR lpBinaryPathName
,
245 LPCWSTR lpLoadOrderGroup
,
247 const BYTE
*lpDependencies
,
248 DWORD dwDependenciesSize
,
249 LPCWSTR lpServiceStartName
,
250 const BYTE
*lpPassword
,
251 DWORD dwPasswordSize
,
252 SC_RPC_HANDLE
*phService
)
254 struct sc_manager
*manager
;
255 struct service_entry
*entry
;
258 WINE_TRACE("(%s, %s, 0x%x, %s)\n", wine_dbgstr_w(lpServiceName
), wine_dbgstr_w(lpDisplayName
), dwDesiredAccess
, wine_dbgstr_w(lpBinaryPathName
));
260 if ((err
= validate_scm_handle(hSCManager
, SC_MANAGER_CREATE_SERVICE
, &manager
)) != ERROR_SUCCESS
)
263 if (!validate_service_name(lpServiceName
))
264 return ERROR_INVALID_NAME
;
265 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
) || !lpServiceName
[0] || !lpBinaryPathName
[0])
266 return ERROR_INVALID_PARAMETER
;
269 WINE_FIXME("Don't know how to add a password\n"); /* I always get ERROR_GEN_FAILURE */
271 WINE_FIXME("Dependencies not supported yet\n");
273 entry
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*entry
));
274 entry
->name
= strdupW(lpServiceName
);
275 entry
->config
.dwServiceType
= dwServiceType
;
276 entry
->config
.dwStartType
= dwStartType
;
277 entry
->config
.dwErrorControl
= dwErrorControl
;
278 entry
->config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
279 entry
->config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
280 entry
->config
.lpServiceStartName
= strdupW(lpServiceStartName
);
281 entry
->config
.lpDisplayName
= strdupW(lpDisplayName
);
283 if (lpdwTagId
) /* TODO: in most situations a non-NULL tagid will generate a ERROR_INVALID_PARAMETER */
284 entry
->config
.dwTagId
= *lpdwTagId
;
286 entry
->config
.dwTagId
= 0;
288 /* other fields NULL*/
290 if (!validate_service_config(entry
))
292 WINE_ERR("Invalid data while trying to create service\n");
293 free_service_entry(entry
);
294 return ERROR_INVALID_PARAMETER
;
299 if (find_service(lpServiceName
))
302 free_service_entry(entry
);
303 return ERROR_SERVICE_EXISTS
;
306 if (find_service_by_displayname(get_display_name(entry
)))
309 free_service_entry(entry
);
310 return ERROR_DUPLICATE_SERVICE_NAME
;
313 err
= add_service(entry
);
314 if (err
!= ERROR_SUCCESS
)
317 free_service_entry(entry
);
322 return create_handle_for_service(entry
, dwDesiredAccess
, phService
);
325 DWORD
svcctl_DeleteService(
326 SC_RPC_HANDLE hService
)
328 struct sc_service
*service
;
331 if ((err
= validate_service_handle(hService
, DELETE
, &service
)) != ERROR_SUCCESS
)
336 if (!is_marked_for_delete(service
->service_entry
))
337 err
= remove_service(service
->service_entry
);
339 err
= ERROR_SERVICE_MARKED_FOR_DELETE
;
346 DWORD
svcctl_QueryServiceConfigW(
347 SC_RPC_HANDLE hService
,
348 QUERY_SERVICE_CONFIGW
*config
)
350 struct sc_service
*service
;
353 WINE_TRACE("(%p)\n", config
);
355 if ((err
= validate_service_handle(hService
, SERVICE_QUERY_CONFIG
, &service
)) != 0)
359 config
->dwServiceType
= service
->service_entry
->config
.dwServiceType
;
360 config
->dwStartType
= service
->service_entry
->config
.dwStartType
;
361 config
->dwErrorControl
= service
->service_entry
->config
.dwErrorControl
;
362 config
->lpBinaryPathName
= strdupW(service
->service_entry
->config
.lpBinaryPathName
);
363 config
->lpLoadOrderGroup
= strdupW(service
->service_entry
->config
.lpLoadOrderGroup
);
364 config
->dwTagId
= service
->service_entry
->config
.dwTagId
;
365 config
->lpDependencies
= NULL
; /* TODO */
366 config
->lpServiceStartName
= strdupW(service
->service_entry
->config
.lpServiceStartName
);
367 config
->lpDisplayName
= strdupW(service
->service_entry
->config
.lpDisplayName
);
370 return ERROR_SUCCESS
;
373 DWORD
svcctl_ChangeServiceConfigW(
374 SC_RPC_HANDLE hService
,
377 DWORD dwErrorControl
,
378 LPCWSTR lpBinaryPathName
,
379 LPCWSTR lpLoadOrderGroup
,
381 const BYTE
*lpDependencies
,
382 DWORD dwDependenciesSize
,
383 LPCWSTR lpServiceStartName
,
384 const BYTE
*lpPassword
,
385 DWORD dwPasswordSize
,
386 LPCWSTR lpDisplayName
)
388 struct service_entry new_entry
;
389 struct sc_service
*service
;
394 if ((err
= validate_service_handle(hService
, SERVICE_CHANGE_CONFIG
, &service
)) != 0)
397 if (!check_multisz((LPCWSTR
)lpDependencies
, dwDependenciesSize
))
398 return ERROR_INVALID_PARAMETER
;
400 /* first check if the new configuration is correct */
403 if (is_marked_for_delete(service
->service_entry
))
406 return ERROR_SERVICE_MARKED_FOR_DELETE
;
409 if (lpDisplayName
!= NULL
&& find_service_by_displayname(lpDisplayName
))
412 return ERROR_DUPLICATE_SERVICE_NAME
;
415 new_entry
= *service
->service_entry
;
417 if (dwServiceType
!= SERVICE_NO_CHANGE
)
418 new_entry
.config
.dwServiceType
= dwServiceType
;
420 if (dwStartType
!= SERVICE_NO_CHANGE
)
421 new_entry
.config
.dwStartType
= dwStartType
;
423 if (dwErrorControl
!= SERVICE_NO_CHANGE
)
424 new_entry
.config
.dwErrorControl
= dwErrorControl
;
426 if (lpBinaryPathName
!= NULL
)
427 new_entry
.config
.lpBinaryPathName
= (LPWSTR
)lpBinaryPathName
;
429 if (lpLoadOrderGroup
!= NULL
)
430 new_entry
.config
.lpLoadOrderGroup
= (LPWSTR
)lpLoadOrderGroup
;
432 if (lpdwTagId
!= NULL
)
433 WINE_FIXME("Changing tag id not supported\n");
435 if (lpDependencies
!= NULL
)
436 WINE_FIXME("Chainging dependencies not supported\n");
438 if (lpServiceStartName
!= NULL
)
439 new_entry
.config
.lpServiceStartName
= (LPWSTR
)lpServiceStartName
;
441 if (lpPassword
!= NULL
)
442 WINE_FIXME("Setting password not supported\n");
444 if (lpDisplayName
!= NULL
)
445 new_entry
.config
.lpDisplayName
= (LPWSTR
)lpDisplayName
;
447 if (!validate_service_config(&new_entry
))
449 WINE_ERR("The configuration after the change wouldn't be valid");
451 return ERROR_INVALID_PARAMETER
;
454 /* configuration OK. The strings needs to be duplicated */
455 if (lpBinaryPathName
!= NULL
)
457 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpBinaryPathName
);
458 new_entry
.config
.lpBinaryPathName
= strdupW(lpBinaryPathName
);
461 if (lpLoadOrderGroup
!= NULL
)
463 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpLoadOrderGroup
);
464 new_entry
.config
.lpLoadOrderGroup
= strdupW(lpLoadOrderGroup
);
467 if (lpServiceStartName
!= NULL
)
469 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpServiceStartName
);
470 new_entry
.config
.lpServiceStartName
= strdupW(lpServiceStartName
);
473 if (lpDisplayName
!= NULL
)
475 HeapFree(GetProcessHeap(), 0, service
->service_entry
->config
.lpDisplayName
);
476 new_entry
.config
.lpDisplayName
= strdupW(lpDisplayName
);
479 *service
->service_entry
= new_entry
;
480 save_service_config(service
->service_entry
);
483 return ERROR_SUCCESS
;
486 DWORD
svcctl_CloseServiceHandle(
487 SC_RPC_HANDLE
*handle
)
489 WINE_TRACE("(&%p)\n", *handle
);
491 SC_RPC_HANDLE_destroy(*handle
);
494 return ERROR_SUCCESS
;
497 DWORD
RPC_MainLoop(void)
499 WCHAR transport
[] = SVCCTL_TRANSPORT
;
500 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
504 if ((err
= RpcServerUseProtseqEpW(transport
, 0, endpoint
, NULL
)) != ERROR_SUCCESS
)
506 WINE_ERR("RpcServerUseProtseq failed with error %u\n", err
);
510 if ((err
= RpcServerRegisterIf(svcctl_v2_0_s_ifspec
, 0, 0)) != ERROR_SUCCESS
)
512 WINE_ERR("RpcServerRegisterIf failed with error %u", err
);
516 if ((err
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
)) != ERROR_SUCCESS
)
518 WINE_ERR("RpcServerListen failed with error %u\n", err
);
522 WINE_TRACE("Entered main loop\n");
523 hSleepHandle
= __wine_make_process_system();
524 SetEvent(g_hStartedEvent
);
527 err
= WaitForSingleObjectEx(hSleepHandle
, INFINITE
, TRUE
);
528 WINE_TRACE("Wait returned %d\n", err
);
529 } while (err
!= WAIT_OBJECT_0
);
531 WINE_TRACE("Object signaled - wine shutdown\n");
532 return ERROR_SUCCESS
;
535 void __RPC_USER
SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle
)
537 SC_RPC_HANDLE_destroy(handle
);
540 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
542 return HeapAlloc(GetProcessHeap(), 0, len
);
545 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
547 HeapFree(GetProcessHeap(), 0, ptr
);