dlls/actxprxy/actxprxy_servprov_i.c
dlls/actxprxy/actxprxy_servprov_p.c
dlls/advapi32/libadvapi32.def
+dlls/advapi32/svcctl.h
+dlls/advapi32/svcctl_c.c
dlls/advapi32/tests/*.ok
dlls/advapi32/tests/advapi32_crosstest.exe
dlls/advapi32/tests/testlist.c
include/urlhist.h
include/urlmon.h
include/wine/itss.h
+include/wine/svcctl.h
include/wtypes.h
include/xmldom.h
include/xmldso.h
programs/rundll32/rundll32
programs/secedit/secedit
programs/services/services
+programs/services/svcctl.h
+programs/services/svcctl_s.c
programs/spoolsv/spoolsv
programs/start/start
programs/svchost/svchost
IMPORTLIB = advapi32
IMPORTS = kernel32 ntdll
EXTRALIBS = @SECURITYLIB@
+DELAYIMPORTS = rpcrt4
C_SRCS = \
advapi.c \
security.c \
service.c
+IDL_C_SRCS = svcctl.idl
+
RC_SRCS = version.rc
@MAKE_DLL_RULES@
#include "lmcons.h"
#include "lmserver.h"
+#include "svcctl.h"
+
WINE_DEFAULT_DEBUG_CHANNEL(service);
static const WCHAR szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
'L','O','C','K',0};
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
+{
+ return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
+{
+ HeapFree(GetProcessHeap(), 0, ptr);
+}
+
static const GENERIC_MAPPING scm_generic = {
(STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
(STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
SC_HANDLE_TYPE htype;
DWORD ref_count;
sc_handle_destructor destroy;
+ SC_RPC_HANDLE server_handle; /* server-side handle */
};
struct sc_manager /* service control manager handle */
return wstr;
}
+/******************************************************************************
+ * RPC connection with servies.exe
+ */
+
+static BOOL check_services_exe(void)
+{
+ static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
+ HANDLE hEvent = OpenEventW(SYNCHRONIZE, FALSE, svcctl_started_event);
+ if (hEvent == NULL) /* need to start services.exe */
+ {
+ static const WCHAR services[] = {'\\','s','e','r','v','i','c','e','s','.','e','x','e',0};
+ PROCESS_INFORMATION out;
+ STARTUPINFOW si;
+ HANDLE wait_handles[2];
+ WCHAR path[MAX_PATH];
+
+ if (!GetSystemDirectoryW(path, MAX_PATH - strlenW(services)))
+ return FALSE;
+ strcatW(path, services);
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ if (!CreateProcessW(path, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &out))
+ {
+ ERR("Couldn't start services.exe: error %u\n", GetLastError());
+ return FALSE;
+ }
+ CloseHandle(out.hThread);
+
+ hEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
+ wait_handles[0] = hEvent;
+ wait_handles[1] = out.hProcess;
+
+ /* wait for the event to become available or the process to exit */
+ if ((WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE)) == WAIT_OBJECT_0 + 1)
+ {
+ DWORD exit_code;
+ GetExitCodeProcess(out.hProcess, &exit_code);
+ ERR("Unexpected termination of services.exe - exit code %d\n", exit_code);
+ CloseHandle(out.hProcess);
+ CloseHandle(hEvent);
+ return FALSE;
+ }
+
+ TRACE("services.exe started successfully\n");
+ CloseHandle(out.hProcess);
+ CloseHandle(hEvent);
+ return TRUE;
+ }
+
+ TRACE("Waiting for services.exe to be available\n");
+ WaitForSingleObject(hEvent, INFINITE);
+ TRACE("Services.exe are available\n");
+ CloseHandle(hEvent);
+
+ return TRUE;
+}
+
+handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
+{
+ WCHAR transport[] = SVCCTL_TRANSPORT;
+ WCHAR endpoint[] = SVCCTL_ENDPOINT;
+ LPWSTR server_copy = NULL;
+ RPC_WSTR binding_str;
+ RPC_STATUS status;
+ handle_t rpc_handle;
+
+ /* unlike Windows we start services.exe on demand. We start it always as
+ * checking if this is our address can be tricky */
+ if (!check_services_exe())
+ return NULL;
+
+ status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
+ HeapFree(GetProcessHeap(), 0, server_copy);
+ if (status != RPC_S_OK)
+ {
+ ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
+ return NULL;
+ }
+
+ status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
+ RpcStringFreeW(&binding_str);
+
+ if (status != RPC_S_OK)
+ {
+ ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
+ return NULL;
+ }
+
+ return rpc_handle;
+}
+
+void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
+{
+ RpcBindingFree(&h);
+}
+
/******************************************************************************
* registry access functions and data
*/
TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
debugstr_w(lpDatabaseName), dwDesiredAccess);
- if( lpDatabaseName && lpDatabaseName[0] )
- {
- if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
- {
- /* noop, all right */
- }
- else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
- {
- SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
- return NULL;
- }
- else
- {
- SetLastError( ERROR_INVALID_NAME );
- return NULL;
- }
- }
-
manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
sc_handle_destroy_manager );
if (!manager)
return NULL;
+ r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
+ if (r!=ERROR_SUCCESS)
+ goto error;
+
r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
if (r!=ERROR_SUCCESS)
goto error;
BOOL WINAPI
CloseServiceHandle( SC_HANDLE hSCObject )
{
+ struct sc_handle *obj;
+ DWORD err;
+
TRACE("%p\n", hSCObject);
+ if (hSCObject == NULL)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- sc_handle_free( (struct sc_handle*) hSCObject );
+ obj = (struct sc_handle *)hSCObject;
+ if (obj->server_handle) /* service handles currently don't have RPC connections */
+ err = svcctl_CloseServiceHandle(&obj->server_handle);
+ else
+ err = ERROR_SUCCESS;
+ sc_handle_free( obj );
+ if (err != ERROR_SUCCESS)
+ {
+ SetLastError(err);
+ return FALSE;
+ }
return TRUE;
}
--- /dev/null
+#include "wine/svcctl.idl"
/* NULL handle */
SetLastError(0xdeadbeef);
ret = CloseServiceHandle(NULL);
- todo_wine
- {
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
- }
/* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
urlhist.idl \
urlmon.idl \
wine/itss.idl \
+ wine/svcctl.idl \
wtypes.idl \
xmldom.idl \
xmldso.idl
--- /dev/null
+/*
+ * svcctl interface definitions - exported by services.exe to access the
+ * services database
+ *
+ * Copyright 2007 Google (Mikolaj Zalewski)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "wtypes.idl";
+
+/*
+ * some defined for the C code
+ */
+cpp_quote("#define SVCCTL_TRANSPORT {'n','c','a','c','n','_','n','p',0}")
+cpp_quote("#define SVCCTL_ENDPOINT {'\\\\','p','i','p','e','\\\\','s','v','c','c','t','l',0}")
+
+/* Not the Windows event name - if needed the true one can be found in Inside Windows */
+cpp_quote("#define SVCCTL_STARTED_EVENT {'_','_','w','i','n','e','_','S','v','c','c','t','l','S','t','a','r','t','e','d',0}")
+
+
+[
+ uuid(367abb81-9844-35f1-ad32-98f038001003),
+ version(2.0),
+ pointer_default(unique),
+ endpoint("ncacn_np:[\\pipe\\svcctl]")
+]
+interface svcctl
+{
+ /* handle types */
+ typedef [handle] LPCWSTR MACHINE_HANDLEW;
+ typedef [context_handle] void *SC_RPC_HANDLE;
+
+ /* Compatible with Windows function 0x00 */
+ DWORD svcctl_CloseServiceHandle(
+ [in,out] SC_RPC_HANDLE *handle
+ );
+
+ /* Compatible with Windows function 0x0f */
+ DWORD svcctl_OpenSCManagerW(
+ [in,unique] MACHINE_HANDLEW MachineName,
+ [in,unique] LPCWSTR DatabaseName,
+ [in] DWORD dwAccessMask,
+ [out] SC_RPC_HANDLE *handle
+ );
+
+}
MODULE = services.exe
APPMODE = -mconsole
IMPORTS = kernel32
-IMPORTS = advapi32 kernel32
+IMPORTS = rpcrt4 advapi32 kernel32 ntdll
C_SRCS = \
+ rpc.c \
services.c \
utils.c
+IDL_S_SRCS = svcctl.idl
+
@MAKE_PROG_RULES@
@DEPENDENCIES@ # everything below this line is overwritten by make depend
--- /dev/null
+/*
+ * Services.exe - RPC functions
+ *
+ * Copyright 2007 Google (Mikolaj Zalewski)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <stdarg.h>
+#include <windows.h>
+#include <winternl.h>
+#include <winsvc.h>
+#include <ntsecapi.h>
+#include <rpc.h>
+
+#include "wine/list.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include "services.h"
+#include "svcctl.h"
+
+extern HANDLE __wine_make_process_system(void);
+
+WINE_DEFAULT_DEBUG_CHANNEL(service);
+
+static CRITICAL_SECTION g_handle_table_cs;
+static CRITICAL_SECTION_DEBUG g_handle_table_cs_debug =
+{
+ 0, 0, &g_handle_table_cs,
+ { &g_handle_table_cs_debug.ProcessLocksList,
+ &g_handle_table_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": g_handle_table_cs") }
+};
+static CRITICAL_SECTION g_handle_table_cs = { &g_handle_table_cs_debug, -1, 0, 0, 0, 0 };
+
+static const GENERIC_MAPPING g_scm_generic =
+{
+ (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
+ (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
+ (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
+ SC_MANAGER_ALL_ACCESS
+};
+
+typedef enum
+{
+ SC_HTYPE_DONT_CARE = 0,
+ SC_HTYPE_MANAGER,
+ SC_HTYPE_SERVICE
+} SC_HANDLE_TYPE;
+
+struct sc_handle
+{
+ SC_HANDLE_TYPE type;
+ DWORD access;
+};
+
+struct sc_manager /* service control manager handle */
+{
+ struct sc_handle hdr;
+};
+
+DWORD svcctl_OpenSCManagerW(
+ MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
+ LPCWSTR DatabaseName,
+ DWORD dwAccessMask,
+ SC_RPC_HANDLE *handle)
+{
+ struct sc_manager *manager;
+
+ WINE_TRACE("(%s, %s, %x)\n", wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
+
+ if (DatabaseName != NULL && DatabaseName[0])
+ {
+ if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
+ return ERROR_DATABASE_DOES_NOT_EXIST;
+ if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
+ return ERROR_INVALID_NAME;
+ }
+
+ if (!(manager = HeapAlloc(GetProcessHeap(), 0, sizeof(*manager))))
+ return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+
+ manager->hdr.type = SC_HTYPE_MANAGER;
+
+ if (dwAccessMask & MAXIMUM_ALLOWED)
+ dwAccessMask |= SC_MANAGER_ALL_ACCESS;
+ manager->hdr.access = dwAccessMask;
+ RtlMapGenericMask(&manager->hdr.access, &g_scm_generic);
+ *handle = &manager->hdr;
+
+ return ERROR_SUCCESS;
+}
+
+static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
+{
+ struct sc_handle *hdr = (struct sc_handle *)handle;
+ switch (hdr->type)
+ {
+ case SC_HTYPE_MANAGER:
+ {
+ struct sc_manager *manager = (struct sc_manager *)hdr;
+ HeapFree(GetProcessHeap(), 0, manager);
+ break;
+ }
+ default:
+ WINE_ERR("invalid handle type %d\n", hdr->type);
+ RpcRaiseException(ERROR_INVALID_HANDLE);
+ }
+}
+
+DWORD svcctl_CloseServiceHandle(
+ SC_RPC_HANDLE *handle)
+{
+ WINE_TRACE("(&%p)\n", *handle);
+
+ SC_RPC_HANDLE_destroy(*handle);
+ *handle = NULL;
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RPC_MainLoop(void)
+{
+ WCHAR transport[] = SVCCTL_TRANSPORT;
+ WCHAR endpoint[] = SVCCTL_ENDPOINT;
+ HANDLE hSleepHandle;
+ DWORD err;
+
+ if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
+ {
+ WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
+ return err;
+ }
+
+ if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
+ {
+ WINE_ERR("RpcServerRegisterIf failed with error %u", err);
+ return err;
+ }
+
+ if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
+ {
+ WINE_ERR("RpcServerListen failed with error %u\n", err);
+ return err;
+ }
+
+ WINE_TRACE("Entered main loop\n");
+ hSleepHandle = __wine_make_process_system();
+ SetEvent(g_hStartedEvent);
+ do
+ {
+ err = WaitForSingleObjectEx(hSleepHandle, INFINITE, TRUE);
+ WINE_TRACE("Wait returned %d\n", err);
+ } while (err != WAIT_OBJECT_0);
+
+ WINE_TRACE("Object signaled - wine shutdown\n");
+ return ERROR_SUCCESS;
+}
+
+void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE handle)
+{
+ SC_RPC_HANDLE_destroy(handle);
+}
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
+{
+ return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
+{
+ HeapFree(GetProcessHeap(), 0, ptr);
+}
#include <stdarg.h>
#include <windows.h>
#include <winsvc.h>
+#include <rpc.h>
#include "wine/list.h"
#include "wine/unicode.h"
#include "wine/debug.h"
+#include "svcctl.h"
#include "services.h"
WINE_DEFAULT_DEBUG_CHANNEL(service);
+HANDLE g_hStartedEvent;
+
static struct list g_services;
/* Registry constants */
int main(int argc, char *argv[])
{
+ static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
DWORD err;
+ g_hStartedEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
list_init(&g_services);
if ((err = load_services()) != ERROR_SUCCESS)
return err;
- return 0;
+ return RPC_MainLoop();
}
--- /dev/null
+#include "wine/svcctl.idl"