diff --git a/configure b/configure index b802bc2eff0..7a9f1dd753e 100755 --- a/configure +++ b/configure @@ -1195,6 +1195,7 @@ enable_sane_ds enable_scarddlg enable_sccbase enable_schannel +enable_schedsvc enable_scrrun enable_scsiport_sys enable_secur32 @@ -17106,6 +17107,7 @@ wine_fn_config_dll scarddlg enable_scarddlg wine_fn_config_dll sccbase enable_sccbase wine_fn_config_dll schannel enable_schannel wine_fn_config_test dlls/schannel/tests schannel_test +wine_fn_config_dll schedsvc enable_schedsvc clean wine_fn_config_dll scrrun enable_scrrun clean wine_fn_config_test dlls/scrrun/tests scrrun_test clean wine_fn_config_dll scsiport.sys enable_scsiport_sys diff --git a/configure.ac b/configure.ac index a7b90accd2c..2ff3113fad9 100644 --- a/configure.ac +++ b/configure.ac @@ -3111,6 +3111,7 @@ WINE_CONFIG_DLL(scarddlg) WINE_CONFIG_DLL(sccbase) WINE_CONFIG_DLL(schannel) WINE_CONFIG_TEST(dlls/schannel/tests) +WINE_CONFIG_DLL(schedsvc,,[clean]) WINE_CONFIG_DLL(scrrun,,[clean]) WINE_CONFIG_TEST(dlls/scrrun/tests,[clean]) WINE_CONFIG_DLL(scsiport.sys) diff --git a/dlls/schedsvc/Makefile.in b/dlls/schedsvc/Makefile.in new file mode 100644 index 00000000000..d1ee5c3ffae --- /dev/null +++ b/dlls/schedsvc/Makefile.in @@ -0,0 +1,8 @@ +MODULE = schedsvc.dll +IMPORTS = rpcrt4 advapi32 + +C_SRCS = \ + schedsvc.c \ + svc_main.c + +IDL_SRCS = schrpc.idl diff --git a/dlls/schedsvc/schedsvc.c b/dlls/schedsvc/schedsvc.c new file mode 100644 index 00000000000..9b9d7c5630f --- /dev/null +++ b/dlls/schedsvc/schedsvc.c @@ -0,0 +1,158 @@ +/* + * Task Scheduler Service + * + * Copyright 2014 Dmitry Timoshkov + * + * 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 + */ + +#include + +#include "windef.h" +#include "schrpc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(schedsvc); + +HRESULT __cdecl SchRpcHighestVersion(DWORD *version) +{ + WINE_FIXME("%p: stub\n", version); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcRegisterTask(const WCHAR *path, const WCHAR *xml, DWORD flags, const WCHAR *sddl, + DWORD task_logon_type, DWORD n_creds, const TASK_USER_CRED *creds, + WCHAR **actual_path, TASK_XML_ERROR_INFO **xml_error_info) +{ + WINE_FIXME("%s,%s,%#x,%s,%u,%u,%p,%p,%p: stub\n", wine_dbgstr_w(path), wine_dbgstr_w(xml), flags, + wine_dbgstr_w(sddl), task_logon_type, n_creds, creds, actual_path, xml_error_info); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcRetrieveTask(const WCHAR *path, const WCHAR *languages, ULONG *n_languages, WCHAR **xml) +{ + WINE_FIXME("%s,%s,%p,%p: stub\n", wine_dbgstr_w(path), wine_dbgstr_w(languages), n_languages, xml); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcCreateFolder(const WCHAR *path, const WCHAR *sddl, DWORD flags) +{ + WINE_FIXME("%s,%s,%#x: stub\n", wine_dbgstr_w(path), wine_dbgstr_w(sddl), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcSetSecurity(const WCHAR *path, const WCHAR *sddl, DWORD flags) +{ + WINE_FIXME("%s,%s,%#x: stub\n", wine_dbgstr_w(path), wine_dbgstr_w(sddl), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcGetSecurity(const WCHAR *path, DWORD flags, WCHAR **sddl) +{ + WINE_FIXME("%s,%#x,%p: stub\n", wine_dbgstr_w(path), flags, sddl); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcEnumFolders(const WCHAR *path, DWORD flags, DWORD *start_index, DWORD n_requested, + DWORD *n_names, TASK_NAMES *names) +{ + WINE_FIXME("%s,%#x,%p,%u,%p,%p: stub\n", wine_dbgstr_w(path), flags, start_index, n_requested, n_names, names); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcEnumTasks(const WCHAR *path, DWORD flags, DWORD *start_index, DWORD n_requested, + DWORD *n_names, TASK_NAMES *names) +{ + WINE_FIXME("%s,%#x,%p,%u,%p,%p: stub\n", wine_dbgstr_w(path), flags, start_index, n_requested, n_names, names); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcEnumInstances(const WCHAR *path, DWORD flags, DWORD *n_guids, GUID **guids) +{ + WINE_FIXME("%s,%#x,%p,%p: stub\n", wine_dbgstr_w(path), flags, n_guids, guids); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcGetInstanceInfo(GUID guid, WCHAR **path, DWORD *task_state, WCHAR **action, + WCHAR **info, DWORD *n_instances, GUID **instances, DWORD *pid) +{ + WINE_FIXME("%s,%p,%p,%p,%p,%p,%p,%p: stub\n", wine_dbgstr_guid(&guid), path, task_state, action, + info, n_instances, instances, pid); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcStopInstance(GUID guid, DWORD flags) +{ + WINE_FIXME("%s,%#x: stub\n", wine_dbgstr_guid(&guid), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcStop(const WCHAR *path, DWORD flags) +{ + WINE_FIXME("%s,%#x: stub\n", wine_dbgstr_w(path), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcRun(const WCHAR *path, DWORD n_args, const WCHAR **args, DWORD flags, + DWORD session_id, const WCHAR *user, GUID *guid) +{ + WINE_FIXME("%s,%u,%p,%#x,%#x,%s,%p: stub\n", wine_dbgstr_w(path), n_args, args, flags, + session_id, wine_dbgstr_w(user), guid); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcDelete(const WCHAR *path, DWORD flags) +{ + WINE_FIXME("%s,%#x: stub\n", wine_dbgstr_w(path), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcRename(const WCHAR *path, const WCHAR *name, DWORD flags) +{ + WINE_FIXME("%s,%s,%#x: stub\n", wine_dbgstr_w(path), wine_dbgstr_w(name), flags); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcScheduledRuntimes(const WCHAR *path, SYSTEMTIME *start, SYSTEMTIME *end, DWORD flags, + DWORD n_requested, DWORD *n_runtimes, SYSTEMTIME **runtimes) +{ + WINE_FIXME("%s,%p,%p,%#x,%u,%p,%p: stub\n", wine_dbgstr_w(path), start, end, flags, + n_requested, n_runtimes, runtimes); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcGetLastRunInfo(const WCHAR *path, SYSTEMTIME *last_runtime, DWORD *last_return_code) +{ + WINE_FIXME("%s,%p,%p: stub\n", wine_dbgstr_w(path), last_runtime, last_return_code); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcGetTaskInfo(const WCHAR *path, DWORD flags, DWORD *enabled, DWORD *task_state) +{ + WINE_FIXME("%s,%#x,%p,%p: stub\n", wine_dbgstr_w(path), flags, enabled, task_state); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcGetNumberOfMissedRuns(const WCHAR *path, DWORD *runs) +{ + WINE_FIXME("%s,%p: stub\n", wine_dbgstr_w(path), runs); + return E_NOTIMPL; +} + +HRESULT __cdecl SchRpcEnableTask(const WCHAR *path, DWORD enabled) +{ + WINE_FIXME("%s,%u: stub\n", wine_dbgstr_w(path), enabled); + return E_NOTIMPL; +} diff --git a/dlls/schedsvc/schedsvc.spec b/dlls/schedsvc/schedsvc.spec new file mode 100644 index 00000000000..daa88578f7f --- /dev/null +++ b/dlls/schedsvc/schedsvc.spec @@ -0,0 +1 @@ +@ stdcall -private ServiceMain(long ptr) diff --git a/dlls/schedsvc/schrpc.idl b/dlls/schedsvc/schrpc.idl new file mode 100644 index 00000000000..935a0b2fbba --- /dev/null +++ b/dlls/schedsvc/schrpc.idl @@ -0,0 +1,3 @@ +#pragma makedep server + +#include "wine/schrpc.idl" diff --git a/dlls/schedsvc/svc_main.c b/dlls/schedsvc/svc_main.c new file mode 100644 index 00000000000..fe5d4fcd63a --- /dev/null +++ b/dlls/schedsvc/svc_main.c @@ -0,0 +1,158 @@ +/* + * Task Scheduler Service + * + * Copyright 2014 Dmitry Timoshkov + * + * 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winsvc.h" +#include "rpc.h" +#include "schrpc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(schedsvc); + +static SERVICE_STATUS_HANDLE schedsvc_handle; +static HANDLE done_event; + +static void schedsvc_update_status(DWORD state) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + status.dwControlsAccepted = 0; + status.dwCurrentState = state; + + SetServiceStatus(schedsvc_handle, &status); +} + +static void WINAPI schedsvc_handler(DWORD control) +{ + WINE_TRACE("%#x\n", control); + + switch (control) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + schedsvc_update_status(SERVICE_STOP_PENDING); + SetEvent(done_event); + break; + + default: + schedsvc_update_status(SERVICE_RUNNING); + break; + } +} + +static RPC_BINDING_VECTOR *sched_bindings; + +static RPC_STATUS RPC_init(void) +{ + WCHAR transport[] = SCHEDSVC_TRANSPORT; + RPC_STATUS status; + + WINE_TRACE("using %s\n", wine_dbgstr_w(transport)); + + status = RpcServerUseProtseqEpW(transport, 0, NULL, NULL); + if (status != RPC_S_OK) + { + WINE_ERR("RpcServerUseProtseqEp error %#x\n", status); + return status; + } + + status = RpcServerRegisterIf(ITaskSchedulerService_v1_0_s_ifspec, 0, 0); + if (status != RPC_S_OK) + { + WINE_ERR("RpcServerRegisterIf error %#x\n", status); + return status; + } + + status = RpcServerInqBindings(&sched_bindings); + if (status != RPC_S_OK) + { + WINE_ERR("RpcServerInqBindings error %#x\n", status); + return status; + } + + status = RpcEpRegisterW(ITaskSchedulerService_v1_0_s_ifspec, sched_bindings, NULL, NULL); + if (status != RPC_S_OK) + { + WINE_ERR("RpcEpRegister error %#x\n", status); + return status; + } + + status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE); + if (status != RPC_S_OK) + { + WINE_ERR("RpcServerListen error %#x\n", status); + return status; + } + return RPC_S_OK; +} + +static void RPC_finish(void) +{ + RpcMgmtStopServerListening(NULL); + RpcEpUnregister(ITaskSchedulerService_v1_0_s_ifspec, sched_bindings, NULL); + RpcBindingVectorFree(&sched_bindings); + RpcServerUnregisterIf(NULL, NULL, FALSE); +} + +void WINAPI ServiceMain(DWORD argc, LPWSTR *argv) +{ + static const WCHAR scheduleW[] = {'S','c','h','e','d','u','l','e',0}; + + WINE_TRACE("starting Task Scheduler Service\n"); + + if (RPC_init() != RPC_S_OK) return; + + schedsvc_handle = RegisterServiceCtrlHandlerW(scheduleW, schedsvc_handler); + if (!schedsvc_handle) + { + WINE_ERR("RegisterServiceCtrlHandler error %d\n", GetLastError()); + return; + } + + done_event = CreateEventW(NULL, TRUE, FALSE, NULL); + + schedsvc_update_status(SERVICE_RUNNING); + + WaitForSingleObject(done_event, INFINITE); + + RPC_finish(); + schedsvc_update_status(SERVICE_STOPPED); + + WINE_TRACE("exiting Task Scheduler Service\n"); +} + +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); +} diff --git a/include/wine/schrpc.idl b/include/wine/schrpc.idl new file mode 100644 index 00000000000..c45108225fe --- /dev/null +++ b/include/wine/schrpc.idl @@ -0,0 +1,100 @@ +/* + * Task Scheduler Service definitions + * + * Copyright 2014 Dmitry Timoshkov + * + * 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 + */ + +cpp_quote("#define SCHEDSVC_TRANSPORT {'n','c','a','l','r','p','c',0}") + +import "oaidl.idl"; +import "ocidl.idl"; + +[ + uuid(86d35949-83c9-4044-b424-db363231fd0c), + implicit_handle(handle_t rpc_handle), + version(1.0), + pointer_default(unique) +] +interface ITaskSchedulerService +{ + typedef struct _TASK_USER_CRED + { + [string] const WCHAR *user; + [string] const WCHAR *password; + DWORD flags; + } TASK_USER_CRED; + + typedef struct _TASK_XML_ERROR_INFO + { + DWORD line, column; + [string] WCHAR *node; + [string] WCHAR *value; + } TASK_XML_ERROR_INFO; + + typedef [string] WCHAR **TASK_NAMES; + + HRESULT SchRpcHighestVersion([out] DWORD *version); + HRESULT SchRpcRegisterTask([in, string, unique] const WCHAR *path, + [in, string] const WCHAR *xml, [in] DWORD flags, + [in, string, unique] const WCHAR *sddl, + [in] DWORD task_logon_type, [in] DWORD n_creds, + [in, size_is(n_creds), unique] const TASK_USER_CRED *creds, + [out, string] WCHAR **actual_path, + [out] TASK_XML_ERROR_INFO **xml_error_info); + HRESULT SchRpcRetrieveTask([in, string] const WCHAR *path, + [in, string] const WCHAR *languages, + [in] unsigned long *n_languages, [out, string] WCHAR **xml); + HRESULT SchRpcCreateFolder([in, string] const WCHAR *path, + [in, string, unique] const WCHAR *sddl, [in] DWORD flags); + HRESULT SchRpcSetSecurity([in, string] const WCHAR *path, + [in, string] const WCHAR *sddl, [in] DWORD flags); + HRESULT SchRpcGetSecurity([in, string] const WCHAR *path, + [in] DWORD flags, [out, string] WCHAR **sddl); + HRESULT SchRpcEnumFolders([in, string] const WCHAR *path, + [in] DWORD flags, [in, out] DWORD *start_index, + [in] DWORD n_requested, [out] DWORD *n_names, + [out, size_is(,*n_names)] TASK_NAMES *names); + HRESULT SchRpcEnumTasks([in, string] const WCHAR *path, + [in] DWORD flags, [in, out] DWORD *start_index, + [in] DWORD n_requested, [out] DWORD *n_names, + [out, size_is(,*n_names)] TASK_NAMES *names); + HRESULT SchRpcEnumInstances([in, string, unique] const WCHAR *path, + [in] DWORD flags, [out] DWORD *n_guids, + [out, size_is(,*n_guids)] GUID **guids); + HRESULT SchRpcGetInstanceInfo([in] GUID guid, [out, string] WCHAR **path, + [out] DWORD *task_state, [out, string] WCHAR **action, + [out, string] WCHAR **info, [out] DWORD *n_instances, + [out, size_is(,*n_instances)] GUID **instances, [out] DWORD *pid); + HRESULT SchRpcStopInstance([in] GUID guid, [in] DWORD flags); + HRESULT SchRpcStop([in, string, unique] const WCHAR *path, [in] DWORD flags); + HRESULT SchRpcRun([in, string] const WCHAR *path, + [in] DWORD n_args, [in, size_is(n_args),unique] const WCHAR **args, + [in] DWORD flags, [in] DWORD session_id, + [in, unique, string] const WCHAR *user, [out] GUID *guid); + HRESULT SchRpcDelete([in, string] const WCHAR *path, [in] DWORD flags); + HRESULT SchRpcRename([in, string] const WCHAR *path, [in, string] const WCHAR *name, [in] DWORD flags); + HRESULT SchRpcScheduledRuntimes([in, string] const WCHAR *path, + [in, unique] SYSTEMTIME *start, [in, unique] SYSTEMTIME *end, + [in] DWORD flags, [in] DWORD n_requested, [out] DWORD *n_runtimes, + [out, size_is(,*n_runtimes)] SYSTEMTIME **runtimes); + HRESULT SchRpcGetLastRunInfo([in, string] const WCHAR *path, + [out] SYSTEMTIME *last_runtime, [out] DWORD *last_return_code); + HRESULT SchRpcGetTaskInfo([in, string] const WCHAR *path, [in] DWORD flags, + [out] DWORD *enabled, [out] DWORD *task_state); + HRESULT SchRpcGetNumberOfMissedRuns([in, string] const WCHAR *path, [out] DWORD *runs); + HRESULT SchRpcEnableTask([in, string] const WCHAR *path, [in] DWORD enabled); +} diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 595d4b9069a..7486cfddb23 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -124,6 +124,7 @@ AddService=PlugPlay,0,PlugPlayService AddService=FontCache3.0.0.0,0,WPFFontCacheService AddService=LanmanServer,0,LanmanServerService AddService=FontCache,0,FontCacheService +AddService=Schedule,0,TaskSchedulerService [DefaultInstall.NT.Services] AddService=BITS,0,BITSService @@ -136,6 +137,7 @@ AddService=PlugPlay,0,PlugPlayService AddService=FontCache3.0.0.0,0,WPFFontCacheService AddService=LanmanServer,0,LanmanServerService AddService=FontCache,0,FontCacheService +AddService=Schedule,0,TaskSchedulerService [DefaultInstall.ntamd64.Services] AddService=BITS,0,BITSService @@ -148,6 +150,7 @@ AddService=PlugPlay,0,PlugPlayService AddService=FontCache3.0.0.0,0,WPFFontCacheService AddService=LanmanServer,0,LanmanServerService AddService=FontCache,0,FontCacheService +AddService=Schedule,0,TaskSchedulerService [Strings] MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions" @@ -3026,6 +3029,19 @@ ErrorControl=1 HKR,Parameters,"ServiceDll",,"%11%\fntcache.dll" ;; HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"fontcache" +[TaskSchedulerService] +AddReg=TaskSchedulerServiceKeys +Description="Task Scheduler" +DisplayName="Task Scheduler" +ServiceBinary="%11%\svchost.exe -k netsvcs" +ServiceType=32 +StartType=3 +ErrorControl=1 + +[TaskSchedulerServiceKeys] +HKR,Parameters,"ServiceDll",,"%11%\schedsvc.dll" +HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"Schedule" + [Services] HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16