From 0e14378d3ea95e51825ce2d187fcd1f8aa5abecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Thu, 20 Oct 2022 20:03:56 +0200 Subject: [PATCH] [SMDLL][SMLIB] Deprecate the legacy ROS-specific SMDLL and improve SM client functions. (#4821) This DLL was exporting legacy NT-incompatible or ROS-specific SM client functions, that have been since 10 years now (2012) replaced by the new NT-compatible SM: - SmConnectApiPort(): was just SmConnectToSm(). - SmCompleteSession(): The legacy SMSS used it for when a subsystem initialization was finished. Now (NT-compatible) this function is called by subsystems **only** when a subsystem session **terminates**: SmSessionComplete(). - SmExecuteProgram(): was just the client side of SmLoadDeferedSubSystem() (whose server side is not implemented yet). The legacy SM "old" SmExecPgm implementation actually was "SmLoadDeferedSubSystem"... - SmLookupSubsystem(): is a utility-only function to read any registry value inside "Session Manager\SubSystems". Move SMDLL's readme into SMLIB and update its contents. Collect some residual useful functions into smutils.c (and moved in SMLIB, though not compiled yet): - SmExecuteProgram(), now implemented as a wrapper around SmExecPgm(); - SmLookupSubsystem(), described above; - SmQueryInformation(), that retrieves a list of currently-running subsystems. [SMLIB] Validate SbApiPortName's length in SmConnectToSm(). Fix CommandLine length validation in SmStartCsr(). Add documentation (+ SAL annotations) to the NT-compatible SMSS client functions. smmsg.h: Add both Win32 and Win64 struct sizes C_ASSERTs for those whose size change between these two processor architecture sizes. [SMLIB] Introduce SmSendMsgToSm() as helper to send data into the SM LPC port. + Make the other API functions use it. It should be observed that in Vista+, both functions SmConnectToSm() and this new SmSendMsgToSm() are exported by NTDLL under the names RtlConnectToSm() and RtlSendMsgToSm() (and use the same signature). See: https://www.geoffchappell.com/studies/windows/win32/ntdll/history/names60.htm [NTDLL] Correctly stub RtlConnectToSm() and RtlSendMsgToSm(). [NTDLL_VISTA] Link to SMLIB and simply export RtlConnectToSm() and RtlSendMsgToSm(). --- dll/ntdll/def/ntdll.spec | 4 +- dll/ntdll/nt_0600/CMakeLists.txt | 2 +- dll/ntdll/nt_0600/ntdll_vista.spec | 3 + dll/win32/CMakeLists.txt | 1 - dll/win32/smdll/CMakeLists.txt | 20 - dll/win32/smdll/dllmain.c | 15 - dll/win32/smdll/precomp.h | 10 - dll/win32/smdll/query.c | 108 ------ dll/win32/smdll/readme.txt | 42 --- dll/win32/smdll/smdll.rc | 4 - dll/win32/smdll/smdll.spec | 5 - sdk/cmake/baseaddress.cmake | 1 - sdk/cmake/baseaddress_dwarf.cmake | 1 - sdk/cmake/baseaddress_msvc.cmake | 1 - sdk/cmake/baseaddress_msvc_x64.cmake | 1 - sdk/include/reactos/subsys/sm/api.h | 153 -------- sdk/include/reactos/subsys/sm/helper.h | 72 ++-- sdk/include/reactos/subsys/sm/ns.h | 10 +- sdk/include/reactos/subsys/sm/smmsg.h | 110 ++++-- sdk/include/reactos/subsys/sm/smrosdbg.h | 58 +++ sdk/lib/smlib/CMakeLists.txt | 4 - sdk/lib/smlib/compses.c | 61 --- sdk/lib/smlib/connect.c | 103 ------ sdk/lib/smlib/execpgm.c | 84 ----- sdk/lib/smlib/lookupss.c | 153 -------- sdk/lib/smlib/precomp.h | 16 +- sdk/lib/smlib/readme.txt | 67 ++++ sdk/lib/smlib/smclient.c | 445 +++++++++++++++------- sdk/lib/smlib/smdll.spec | 16 + sdk/lib/smlib/smutils.c | 452 +++++++++++++++++++++++ sdk/lib/smlib/smutils.cmake | 11 + sdk/tools/gen_baseaddress.py | 1 - sdk/tools/rgenstat/module_list.txt | 1 - 33 files changed, 1033 insertions(+), 1002 deletions(-) delete mode 100644 dll/win32/smdll/CMakeLists.txt delete mode 100644 dll/win32/smdll/dllmain.c delete mode 100644 dll/win32/smdll/precomp.h delete mode 100644 dll/win32/smdll/query.c delete mode 100644 dll/win32/smdll/readme.txt delete mode 100644 dll/win32/smdll/smdll.rc delete mode 100644 dll/win32/smdll/smdll.spec delete mode 100644 sdk/include/reactos/subsys/sm/api.h create mode 100644 sdk/include/reactos/subsys/sm/smrosdbg.h delete mode 100644 sdk/lib/smlib/compses.c delete mode 100644 sdk/lib/smlib/connect.c delete mode 100644 sdk/lib/smlib/execpgm.c delete mode 100644 sdk/lib/smlib/lookupss.c create mode 100644 sdk/lib/smlib/readme.txt create mode 100644 sdk/lib/smlib/smdll.spec create mode 100644 sdk/lib/smlib/smutils.c create mode 100644 sdk/lib/smlib/smutils.cmake diff --git a/dll/ntdll/def/ntdll.spec b/dll/ntdll/def/ntdll.spec index c2b00882c2d..96200db55dc 100644 --- a/dll/ntdll/def/ntdll.spec +++ b/dll/ntdll/def/ntdll.spec @@ -688,7 +688,7 @@ @ stdcall RtlComputeCrc32(long ptr long) @ stdcall RtlComputeImportTableHash(ptr ptr long) @ stdcall RtlComputePrivatizedDllName_U(ptr ptr ptr) -@ stub -version=0x600+ RtlConnectToSm +@ stdcall -stub -version=0x600+ RtlConnectToSm(ptr ptr long ptr) @ stdcall RtlConsoleMultiByteToUnicodeN(ptr long ptr ptr long ptr) @ stdcall RtlConvertExclusiveToShared(ptr) @ stub -version=0x600+ RtlConvertLCIDToString @@ -1133,7 +1133,7 @@ @ stdcall RtlSeekMemoryStream(ptr int64 long ptr) @ stdcall RtlSelfRelativeToAbsoluteSD2(ptr ptr) @ stdcall RtlSelfRelativeToAbsoluteSD(ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr ptr) -@ stub -version=0x600+ RtlSendMsgToSm +@ stdcall -stub -version=0x600+ RtlSendMsgToSm(ptr ptr) @ stdcall RtlSetAllBits(ptr) @ stdcall RtlSetAttributesSecurityDescriptor(ptr long ptr) @ stdcall RtlSetBits(ptr long long) diff --git a/dll/ntdll/nt_0600/CMakeLists.txt b/dll/ntdll/nt_0600/CMakeLists.txt index 061502ac7f1..9cc2c32e192 100644 --- a/dll/ntdll/nt_0600/CMakeLists.txt +++ b/dll/ntdll/nt_0600/CMakeLists.txt @@ -16,7 +16,7 @@ list(APPEND SOURCE add_library(ntdll_vista MODULE ${SOURCE}) set_module_type(ntdll_vista win32dll ENTRYPOINT DllMain 12) -target_link_libraries(ntdll_vista rtl_vista) +target_link_libraries(ntdll_vista smlib rtl_vista) if(ARCH STREQUAL "arm") target_link_libraries(ntdll_vista chkstk) endif() diff --git a/dll/ntdll/nt_0600/ntdll_vista.spec b/dll/ntdll/nt_0600/ntdll_vista.spec index 1a3098dde3f..d36c6449d8e 100644 --- a/dll/ntdll/nt_0600/ntdll_vista.spec +++ b/dll/ntdll/nt_0600/ntdll_vista.spec @@ -12,3 +12,6 @@ @ stdcall RtlRunOnceBeginInitialize(ptr long ptr) @ stdcall RtlRunOnceComplete(ptr long ptr) @ stdcall RtlRunOnceExecuteOnce(ptr ptr ptr ptr) + +@ stdcall RtlConnectToSm(ptr ptr long ptr) SmConnectToSm +@ stdcall RtlSendMsgToSm(ptr ptr) SmSendMsgToSm diff --git a/dll/win32/CMakeLists.txt b/dll/win32/CMakeLists.txt index fad02b4cc03..50c4080a8ca 100644 --- a/dll/win32/CMakeLists.txt +++ b/dll/win32/CMakeLists.txt @@ -192,7 +192,6 @@ add_subdirectory(shfolder) add_subdirectory(shimgvw) add_subdirectory(shlwapi) add_subdirectory(slbcsp) -add_subdirectory(smdll) add_subdirectory(sndblst) add_subdirectory(snmpapi) add_subdirectory(softpub) diff --git a/dll/win32/smdll/CMakeLists.txt b/dll/win32/smdll/CMakeLists.txt deleted file mode 100644 index 9c38ba32b27..00000000000 --- a/dll/win32/smdll/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ - -include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys) -spec2def(smdll.dll smdll.spec ADD_IMPORTLIB) - -list(APPEND SOURCE - dllmain.c - query.c - precomp.h) - -add_library(smdll MODULE - ${SOURCE} - smdll.rc - ${CMAKE_CURRENT_BINARY_DIR}/smdll.def) - -target_link_libraries(smdll smlib) -set_module_type(smdll nativedll ENTRYPOINT DllMainCRTStartup 12) -add_importlibs(smdll ntdll) -add_pch(smdll precomp.h SOURCE) -add_dependencies(smdll psdk) -add_cd_file(TARGET smdll DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/smdll/dllmain.c b/dll/win32/smdll/dllmain.c deleted file mode 100644 index 604f8944d40..00000000000 --- a/dll/win32/smdll/dllmain.c +++ /dev/null @@ -1,15 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS - * FILE: lib/smdll/dllmain.c - * PURPOSE: SM Helper Library - */ - -#include "precomp.h" - -BOOL WINAPI DllMainCRTStartup(HANDLE hinstDll, DWORD fdwReason, LPVOID fImpLoad) -{ - return TRUE; -} - -/* EOF */ diff --git a/dll/win32/smdll/precomp.h b/dll/win32/smdll/precomp.h deleted file mode 100644 index 2caa290d549..00000000000 --- a/dll/win32/smdll/precomp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _SMDLL_PCH_ -#define _SMDLL_PCH_ - -#define WIN32_NO_STATUS -#define _INC_WINDOWS -#define COM_NO_WINDOWS_H - -#include - -#endif /* _SMDLL_PCH_ */ diff --git a/dll/win32/smdll/query.c b/dll/win32/smdll/query.c deleted file mode 100644 index d3b6e964398..00000000000 --- a/dll/win32/smdll/query.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/smdll/query.c - * PURPOSE: Call SM API SM_API_QUERY_INFORMATION (not in NT) - */ - -#include "precomp.h" - -#define NTOS_MODE_USER -#include -#include -#include - -#define NDEBUG -#include - - -/********************************************************************** - * NAME EXPORTED - * SmQueryInformation/5 - * - * DESCRIPTION - * Ask the SM to collect some data from its internal data - * structures and send it back. - * - * ARGUMENTS - * hSmApiPort: handle returned by SmConnectApiPort; - * SmInformationClass: an SM information class ID: - * SM_BASIC_INFORMATION: the number of registered subsystems - * Data: pointer to storage for the information to request; - * DataLength: length in bytes of the Data buffer; it must be - * set and must match the SmInformationClass info size; - * ReturnedDataLength: optional pointer to storage to receive - * the size of the returned data. - * - * RETURN VALUE - * STATUS_SUCCESS: OK you get what you asked for; - * STATUS_INFO_LENGTH_MISMATCH: you set DataLength to 0 or to a - * value that does not match whet the SmInformationClass - * requires; - * STATUS_INVALID_PARAMETER_2: bad information class; - * A port error. - * - */ -NTSTATUS WINAPI -SmQueryInformation (IN HANDLE hSmApiPort, - IN SM_INFORMATION_CLASS SmInformationClass, - IN OUT PVOID Data, - IN ULONG DataLength, - IN OUT PULONG ReturnedDataLength OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - SM_PORT_MESSAGE SmReqMsg; - - - if(0 == DataLength) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - /* Marshal data in the port message */ - switch (SmInformationClass) - { - case SmBasicInformation: - if(DataLength != sizeof (SM_BASIC_INFORMATION)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - SmReqMsg.Request.QryInfo.SmInformationClass = SmBasicInformation; - SmReqMsg.Request.QryInfo.DataLength = DataLength; - SmReqMsg.Request.QryInfo.BasicInformation.SubSystemCount = 0; - break; - case SmSubSystemInformation: - if(DataLength != sizeof (SM_SUBSYSTEM_INFORMATION)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - SmReqMsg.Request.QryInfo.SmInformationClass = SmSubSystemInformation; - SmReqMsg.Request.QryInfo.DataLength = DataLength; - SmReqMsg.Request.QryInfo.SubSystemInformation.SubSystemId = - ((PSM_SUBSYSTEM_INFORMATION)Data)->SubSystemId; - break; - default: - return STATUS_INVALID_PARAMETER_2; - } - /* SM API to invoke */ - SmReqMsg.SmHeader.ApiIndex = SM_API_QUERY_INFORMATION; - - /* Prepare the port request message */ - SmReqMsg.Header.u2.s2.Type = LPC_NEW_MESSAGE; - SmReqMsg.Header.u1.s1.DataLength = SM_PORT_DATA_SIZE(SmReqMsg.Request); - SmReqMsg.Header.u1.s1.TotalLength = SM_PORT_MESSAGE_SIZE; - Status = NtRequestWaitReplyPort (hSmApiPort, (PPORT_MESSAGE) & SmReqMsg, (PPORT_MESSAGE) & SmReqMsg); - if (NT_SUCCESS(Status)) - { - /* Unmarshal data */ - RtlCopyMemory (Data, & SmReqMsg.Reply.QryInfo.BasicInformation, SmReqMsg.Reply.QryInfo.DataLength); - /* Use caller provided storage to store data size */ - if(NULL != ReturnedDataLength) - { - *ReturnedDataLength = SmReqMsg.Reply.QryInfo.DataLength; - } - return SmReqMsg.SmHeader.Status; - } - DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); - return Status; -} -/* EOF */ diff --git a/dll/win32/smdll/readme.txt b/dll/win32/smdll/readme.txt deleted file mode 100644 index a85f2f10152..00000000000 --- a/dll/win32/smdll/readme.txt +++ /dev/null @@ -1,42 +0,0 @@ - -This is SMDLL: a helper library to talk to the ReactOS session manager (SM). - -It should be linked in the following components: - -a) the SM itself, because it registers for managing native processes - IMAGE_SUBSYSTEM_NATIVE; - -b) environment subsystem servers, because each one should register in - the SM its own subsystem (willing to manage those processes); - -c) terminal emulators for optional subsystems, like posixw32 and os2w32, - to ask the SM to start the optional subsystem server they need connect to; - -d) system and development utilities to debug/query the SM. - -2004-02-15 ea - - -How a subsystem uses these APIs -=============================== - -Thread #0 Thread #1 -- create your own directory (\EXAMPLE) -- create an event E0 -- create your call back API port (\EXAMPLE\SbApiPort) - and serving thread T1 - - wait connection requests on call - back port (\EXAMPLE\SbApiPort) -- SmConnectApiPort( - \EXAMPLE\SbApiPort, - hSbApiPort, - SUBSYSTEM_ID, - & hSmApiPort) -- wait for E0 - - as SM calls back, signal event E0 -- create your API port (\EXAMPLE\ApiPort) and - initialize the subsystem -- call SmCompleteSession (hSmApiPort, - hSbApiPort, - hApiPort) -- manage processes etc. diff --git a/dll/win32/smdll/smdll.rc b/dll/win32/smdll/smdll.rc deleted file mode 100644 index c2277b97fe4..00000000000 --- a/dll/win32/smdll/smdll.rc +++ /dev/null @@ -1,4 +0,0 @@ -#define REACTOS_STR_FILE_DESCRIPTION "ReactOS SM Helper" -#define REACTOS_STR_INTERNAL_NAME "smdll.dll" -#define REACTOS_STR_ORIGINAL_FILENAME "smdll.dll" -#include diff --git a/dll/win32/smdll/smdll.spec b/dll/win32/smdll/smdll.spec deleted file mode 100644 index a917bf979a7..00000000000 --- a/dll/win32/smdll/smdll.spec +++ /dev/null @@ -1,5 +0,0 @@ -@ stdcall SmCompleteSession(ptr ptr ptr) -@ stdcall SmConnectApiPort(ptr ptr long ptr) -@ stdcall SmExecuteProgram(ptr ptr) -@ stdcall SmQueryInformation(ptr long ptr long ptr) -@ stdcall SmLookupSubsystem(ptr ptr ptr ptr ptr) diff --git a/sdk/cmake/baseaddress.cmake b/sdk/cmake/baseaddress.cmake index c8a2c9a81ca..dbaad8bb9ba 100644 --- a/sdk/cmake/baseaddress.cmake +++ b/sdk/cmake/baseaddress.cmake @@ -45,7 +45,6 @@ set(baseaddress_dsound 0x7a040000) set(baseaddress_glu32 0x79f20000) set(baseaddress_opengl32 0x79dc0000) set(baseaddress_riched20 0x79cf0000) -set(baseaddress_smdll 0x79cd0000) set(baseaddress_userenv 0x79c70000) set(baseaddress_uxtheme 0x79c00000) set(baseaddress_cryptui 0x79b40000) diff --git a/sdk/cmake/baseaddress_dwarf.cmake b/sdk/cmake/baseaddress_dwarf.cmake index 8eb2eb74fbb..00b8d491251 100644 --- a/sdk/cmake/baseaddress_dwarf.cmake +++ b/sdk/cmake/baseaddress_dwarf.cmake @@ -45,7 +45,6 @@ set(baseaddress_dsound 0x79080000) set(baseaddress_glu32 0x78ee0000) set(baseaddress_opengl32 0x78d50000) set(baseaddress_riched20 0x78c10000) -set(baseaddress_smdll 0x78be0000) set(baseaddress_userenv 0x78b50000) set(baseaddress_uxtheme 0x78ac0000) set(baseaddress_cryptui 0x789f0000) diff --git a/sdk/cmake/baseaddress_msvc.cmake b/sdk/cmake/baseaddress_msvc.cmake index c56267561d9..a4dee3b4993 100644 --- a/sdk/cmake/baseaddress_msvc.cmake +++ b/sdk/cmake/baseaddress_msvc.cmake @@ -45,7 +45,6 @@ set(baseaddress_dsound 0x7ad60000) set(baseaddress_glu32 0x7ace0000) set(baseaddress_opengl32 0x7ac00000) set(baseaddress_riched20 0x7ab70000) -set(baseaddress_smdll 0x7ab50000) set(baseaddress_userenv 0x7ab10000) set(baseaddress_uxtheme 0x7aac0000) set(baseaddress_cryptui 0x7aa20000) diff --git a/sdk/cmake/baseaddress_msvc_x64.cmake b/sdk/cmake/baseaddress_msvc_x64.cmake index d49365cb457..a9a251aef1d 100644 --- a/sdk/cmake/baseaddress_msvc_x64.cmake +++ b/sdk/cmake/baseaddress_msvc_x64.cmake @@ -44,7 +44,6 @@ set(baseaddress_dsound 0x7FF8F500000) set(baseaddress_glu32 0x7FF8E500000) set(baseaddress_opengl32 0x7FF8D500000) set(baseaddress_riched20 0x7FF8C500000) -set(baseaddress_smdll 0x7FF8B500000) set(baseaddress_userenv 0x7FF8A500000) set(baseaddress_uxtheme 0x7FF89500000) set(baseaddress_cryptui 0x7FF88500000) diff --git a/sdk/include/reactos/subsys/sm/api.h b/sdk/include/reactos/subsys/sm/api.h deleted file mode 100644 index cf3b1778d60..00000000000 --- a/sdk/include/reactos/subsys/sm/api.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef __SM_API_H -#define __SM_API_H - -#include - -/*** DATA TYPES ******************************************************/ - -#define SM_SB_NAME_MAX_LENGTH 120 - -#include - -/* SmConnectApiPort (SS->SM) */ -typedef struct _SM_CONNECT_DATA -{ - USHORT SubSystemId; - WORD Unused; - WCHAR SbName [SM_SB_NAME_MAX_LENGTH]; - -} SM_CONNECT_DATA, *PSM_CONNECT_DATA; - -/* SmpConnectSbApiPort (SM->SS) */ -typedef struct _SB_CONNECT_DATA -{ - ULONG SmApiMax; -} SB_CONNECT_DATA, *PSB_CONNECT_DATA; - - -/*** SM API ***/ - -/*** 1 ****************************************************************/ - -#define SM_API_COMPLETE_SESSION 1 /* complete a session initialization */ - -typedef struct _SM_PORT_MESSAGE_COMPSES -{ - HANDLE hApiPort; - HANDLE hSbApiPort; - -} SM_PORT_MESSAGE_COMPSES, *PSM_PORT_MESSAGE_COMPSES; - -/*** 2 ****************************************************************/ - -#define SM_API_2 2 - -/* obsolete */ - -/*** 3 ****************************************************************/ - -#define SM_API_3 3 - -/* unknown */ - -/*** 4 ****************************************************************/ - -#define SM_API_EXECUTE_PROGRAMME 4 /* start a subsystem (server) */ - -#define SM_EXEXPGM_MAX_LENGTH 32 /* max count of wide string */ - -typedef struct _SM_PORT_MESSAGE_EXECPGM -{ - ULONG NameLength; - WCHAR Name [SM_EXEXPGM_MAX_LENGTH]; - -} SM_PORT_MESSAGE_EXECPGM, *PSM_PORT_MESSAGE_EXECPGM; - -/*** 5 ****************************************************************/ - -#define SM_API_QUERY_INFORMATION 5 /* ask SM to send back some data */ - /* Note: this is not in NT */ -#define SM_QRYINFO_MAX_SS_COUNT 8 -#define SM_QRYINFO_MAX_ROOT_NODE 30 - -typedef enum { - SmBasicInformation = 0, - SmSubSystemInformation = 1, -} SM_INFORMATION_CLASS; - -typedef struct _SM_BASIC_INFORMATION -{ - USHORT SubSystemCount; - WORD Unused; - struct { - WORD Id; - WORD Flags; - DWORD ProcessId; - } SubSystem [SM_QRYINFO_MAX_SS_COUNT]; -} SM_BASIC_INFORMATION, *PSM_BASIC_INFORMATION; - -typedef struct _SM_SUBSYSTEM_INFORMATION -{ - WORD SubSystemId; - WORD Flags; - DWORD ProcessId; - WCHAR NameSpaceRootNode [SM_QRYINFO_MAX_ROOT_NODE]; -} SM_SUBSYSTEM_INFORMATION, *PSM_SUBSYSTEM_INFORMATION; - -typedef struct _SM_PORT_MESSAGE_QRYINFO -{ - SM_INFORMATION_CLASS SmInformationClass; - ULONG DataLength; - union { - SM_BASIC_INFORMATION BasicInformation; - SM_SUBSYSTEM_INFORMATION SubSystemInformation; - }; -} SM_PORT_MESSAGE_QRYINFO, * PSM_PORT_MESSAGE_QRYINFO; - -/*** | ****************************************************************/ - -typedef struct _SM_PORT_MESSAGE -{ - /*** LPC common header ***/ - PORT_MESSAGE Header; - union - { - struct - { - /*** SM common header ***/ - struct - { - DWORD ApiIndex; - NTSTATUS Status; - } SmHeader; - /*** SM per API arguments ***/ - union - { - union - { - SM_PORT_MESSAGE_COMPSES CompSes; - SM_PORT_MESSAGE_EXECPGM ExecPgm; - SM_PORT_MESSAGE_QRYINFO QryInfo; - } Request; - union - { - SM_PORT_MESSAGE_COMPSES CompSes; - SM_PORT_MESSAGE_EXECPGM ExecPgm; - SM_PORT_MESSAGE_QRYINFO QryInfo; - } Reply; - }; - }; - SM_CONNECT_DATA ConnectData; - }; -} SM_PORT_MESSAGE, * PSM_PORT_MESSAGE; - -#include - -/*** MACRO ***********************************************************/ - -#define SM_CONNECT_DATA_SIZE(m) ((m).Header.u1.s1.DataLength-sizeof(USHORT)-sizeof(WORD)) -#define SM_PORT_DATA_SIZE(c) (sizeof(DWORD)+sizeof(NTSTATUS)+sizeof(c)) -#define SM_PORT_MESSAGE_SIZE (sizeof(SM_PORT_MESSAGE)) - - -#endif /* !def __SM_API_H */ diff --git a/sdk/include/reactos/subsys/sm/helper.h b/sdk/include/reactos/subsys/sm/helper.h index 82491e7f95f..4d2263e3b97 100644 --- a/sdk/include/reactos/subsys/sm/helper.h +++ b/sdk/include/reactos/subsys/sm/helper.h @@ -1,37 +1,39 @@ -#if !defined(INCLUDE_SM_HELPER_H) -#define INCLUDE_SM_HELPER_H +/* + * PROJECT: ReactOS SM Helper Library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Utility functions built around the client SM API + * COPYRIGHT: Copyright 2005 Emanuele Aliberti + * Copyright 2022 Hermès Bélusca-Maïto + */ -#if !defined(__SM_API_H) -#include -#endif +#ifndef _SM_HELPER_H_ +#define _SM_HELPER_H_ -/* smlib/connect.c */ -NTSTATUS WINAPI -SmConnectApiPort(IN PUNICODE_STRING pSbApiPortName OPTIONAL, - IN HANDLE hSbApiPort OPTIONAL, - IN WORD wSubsystem OPTIONAL, /* pe.h */ - IN OUT PHANDLE phSmApiPort); -/* smlib/compses.c */ -NTSTATUS WINAPI -SmCompleteSession(IN HANDLE hSmApiPort, - IN HANDLE hSbApiPort, - IN HANDLE hApiPort); -/* smlib/execpgm.c */ -NTSTATUS WINAPI -SmExecuteProgram(IN HANDLE hSmApiPort, - IN PUNICODE_STRING Pgm); -/* smdll/query.c */ -NTSTATUS WINAPI -SmQueryInformation(IN HANDLE SmApiPort, - IN SM_INFORMATION_CLASS SmInformationClass, - IN OUT PVOID Data, - IN ULONG DataLength, - IN OUT PULONG ReturnedDataLength OPTIONAL); -/* smlib/lookupss.c */ -NTSTATUS WINAPI -SmLookupSubsystem(IN PWSTR Name, - IN OUT PWSTR Data, - IN OUT PULONG DataLength, - IN OUT PULONG DataType, - IN PVOID Environment OPTIONAL); -#endif /* ndef INCLUDE_SM_HELPER_H */ +#include "smrosdbg.h" + +NTSTATUS +NTAPI +SmExecuteProgram( + _In_ HANDLE SmApiPort, + _In_ PUNICODE_STRING Pgm /*, + _Out_opt_ PRTL_USER_PROCESS_INFORMATION ProcessInformation*/); + +NTSTATUS +NTAPI +SmLookupSubsystem( + _In_ PWSTR Name, + _Out_ PWSTR Data, + _Inout_ PULONG DataLength, + _Out_opt_ PULONG DataType, + _In_opt_ PVOID Environment); + +NTSTATUS +NTAPI +SmQueryInformation( + _In_ HANDLE SmApiPort, + _In_ SM_INFORMATION_CLASS SmInformationClass, + _Inout_ PVOID Data, + _In_ ULONG DataLength, + _Inout_opt_ PULONG ReturnedDataLength); + +#endif // _SM_HELPER_H_ diff --git a/sdk/include/reactos/subsys/sm/ns.h b/sdk/include/reactos/subsys/sm/ns.h index 2cd37850656..74b30ce9a31 100644 --- a/sdk/include/reactos/subsys/sm/ns.h +++ b/sdk/include/reactos/subsys/sm/ns.h @@ -1,11 +1,11 @@ -#if !defined(INCLUDE_SM_NS_H) -#define INCLUDE_SM_NS_H +#ifndef _SM_NS_H_ +#define _SM_NS_H_ -#define SM_REGISTRY_ROOT_NAME L"\\Session Manager" -#define SM_REGISTRY_SUBSYSTEMS_NAME L"SubSystems" +#define SM_REGISTRY_ROOT_NAME L"\\Session Manager" +#define SM_REGISTRY_SUBSYSTEMS_NAME L"SubSystems" #define SM_API_PORT_NAME L"\\SmApiPort" #define SM_DBGSS_PORT_NAME L"\\DbgSsApiPort" #define SM_DBGUI_PORT_NAME L"\\DbgUiApiPort" -#endif /* ndef INCLUDE_SM_NS_H */ +#endif //_SM_NS_H_ diff --git a/sdk/include/reactos/subsys/sm/smmsg.h b/sdk/include/reactos/subsys/sm/smmsg.h index a5af962fed6..e8f15b5a1a1 100644 --- a/sdk/include/reactos/subsys/sm/smmsg.h +++ b/sdk/include/reactos/subsys/sm/smmsg.h @@ -1,17 +1,19 @@ /* - * PROJECT: ReactOS Windows-Compatible Session Manager - * LICENSE: BSD 2-Clause License - * FILE: include/reactos/subsys/sm/smmsg.h - * PURPOSE: SMSS (SB and SM) Message Format - * PROGRAMMERS: Alex Ionescu + * PROJECT: ReactOS NT-Compatible Session Manager + * LICENSE: BSD 2-Clause License (https://spdx.org/licenses/BSD-2-Clause) + * PURPOSE: SMSS Client (SB and SM) Message Format + * COPYRIGHT: Copyright 2012-2013 Alex Ionescu + * Copyright 2021 Hervé Poussineau + * Copyright 2022 Hermès Bélusca-Maïto */ -#pragma once + #ifndef _SM_MSG_ #define _SM_MSG_ +#pragma once + // // There are the APIs that a Client (such as CSRSS) can send to the SMSS Server. -// // These are called "SM" APIs. // // The exact names are not known, but we are basing them on the SmpApiName array @@ -21,7 +23,6 @@ // The enumeration finishes with an enumeratee holding the maximum API number. // Its name is based on BasepMaxApiNumber, UserpMaxApiNumber... // -// typedef enum _SMSRV_API_NUMBER { SmpCreateForeignSessionApi, @@ -62,6 +63,8 @@ typedef struct _SM_EXEC_PGM_MSG } SM_EXEC_PGM_MSG, *PSM_EXEC_PGM_MSG; #ifndef _WIN64 C_ASSERT(sizeof(SM_EXEC_PGM_MSG) == 0x48); +#else +C_ASSERT(sizeof(SM_EXEC_PGM_MSG) == 0x70); #endif typedef struct _SM_LOAD_DEFERED_SUBSYSTEM_MSG @@ -78,14 +81,23 @@ typedef struct _SM_START_CSR_MSG HANDLE WindowsSubSysProcessId; HANDLE SmpInitialCommandProcessId; } SM_START_CSR_MSG, *PSM_START_CSR_MSG; +#ifndef _WIN64 +C_ASSERT(sizeof(SM_START_CSR_MSG) == 0x110); +#else +C_ASSERT(sizeof(SM_START_CSR_MSG) == 0x118); +#endif typedef struct _SM_STOP_CSR_MSG { ULONG MuSessionId; } SM_STOP_CSR_MSG, *PSM_STOP_CSR_MSG; +#if defined(__REACTOS__) && DBG +#include "smrosdbg.h" +#endif + // -// This is the actual packet structure sent over LCP to the \SmApiPort +// This is the actual packet structure sent over LPC to the \SmApiPort // typedef struct _SM_API_MSG { @@ -101,6 +113,10 @@ typedef struct _SM_API_MSG SM_LOAD_DEFERED_SUBSYSTEM_MSG LoadDefered; SM_START_CSR_MSG StartCsr; SM_STOP_CSR_MSG StopCsr; + +#if defined(__REACTOS__) && DBG + SM_QUERYINFO_MSG QueryInfo; +#endif } u; } SM_API_MSG, *PSM_API_MSG; @@ -109,11 +125,12 @@ typedef struct _SM_API_MSG // #ifndef _WIN64 C_ASSERT(sizeof(SM_API_MSG) == 0x130); +#else +C_ASSERT(sizeof(SM_API_MSG) == 0x148); #endif // // There are the APIs that the SMSS Server can send to a client (such as CSRSS). -// // These are called "SB" APIs. // // The exact names are unknown but we are basing them on the CsrServerSbApiName @@ -124,7 +141,6 @@ C_ASSERT(sizeof(SM_API_MSG) == 0x130); // The enumeration finishes with an enumeratee holding the maximum API number. // Its name is based on BasepMaxApiNumber, UserpMaxApiNumber... // -// typedef enum _SB_API_NUMBER { SbpCreateSession, @@ -143,10 +159,15 @@ typedef struct _SB_CREATE_SESSION_MSG { ULONG SessionId; RTL_USER_PROCESS_INFORMATION ProcessInfo; - ULONG Unknown; + PVOID Unknown; ULONG MuSessionId; CLIENT_ID ClientId; } SB_CREATE_SESSION_MSG, *PSB_CREATE_SESSION_MSG; +#ifndef _WIN64 +C_ASSERT(sizeof(SB_CREATE_SESSION_MSG) == 0x58); +#else +C_ASSERT(sizeof(SB_CREATE_SESSION_MSG) == 0x90); +#endif typedef struct _SB_TERMINATE_SESSION_MSG { @@ -184,6 +205,11 @@ typedef struct _SB_CREATE_PROCESS_MSG } Out; }; } SB_CREATE_PROCESS_MSG, *PSB_CREATE_PROCESS_MSG; +#ifndef _WIN64 +C_ASSERT(sizeof(SB_CREATE_PROCESS_MSG) == 0x18); +#else +C_ASSERT(sizeof(SB_CREATE_PROCESS_MSG) == 0x28); +#endif // // When the server connects to a client, this structure is exchanged @@ -195,7 +221,7 @@ typedef struct _SB_CONNECTION_INFO } SB_CONNECTION_INFO, *PSB_CONNECTION_INFO; // -// This is the actual packet structure sent over LCP to the \SbApiPort +// This is the actual packet structure sent over LPC to the \SbApiPort // typedef struct _SB_API_MSG { @@ -222,8 +248,9 @@ typedef struct _SB_API_MSG // This is the size that Server 2003 SP1 SMSS expects, so make sure we conform. // #ifndef _WIN64 -C_ASSERT(sizeof(SB_CONNECTION_INFO) == 0xF4); C_ASSERT(sizeof(SB_API_MSG) == 0x110); +#else +C_ASSERT(sizeof(SB_API_MSG) == 0x120); #endif // @@ -232,52 +259,55 @@ C_ASSERT(sizeof(SB_API_MSG) == 0x110); typedef BOOLEAN (NTAPI *PSB_API_ROUTINE)( - IN PSB_API_MSG SbApiMsg + _In_ PSB_API_MSG SbApiMsg ); // -// The actual server functions that a client linking with smlib can call +// The actual server functions that a client linking with SMLIB can call. // +/* NTDLL!RtlConnectToSm */ NTSTATUS NTAPI SmConnectToSm( - IN PUNICODE_STRING SbApiPortName, - IN HANDLE SbApiPort, - IN ULONG ImageType, - OUT PHANDLE SmApiPort -); + _In_opt_ PUNICODE_STRING SbApiPortName, + _In_opt_ HANDLE SbApiPort, + _In_opt_ ULONG ImageType, + _Out_ PHANDLE SmApiPort); +/* NTDLL!RtlSendMsgToSm */ NTSTATUS NTAPI -SmExecPgm( - IN HANDLE SmApiPort, - IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, - IN BOOLEAN DebugFlag -); +SmSendMsgToSm( + _In_ HANDLE SmApiPort, + _Inout_ PSM_API_MSG SmApiMsg); NTSTATUS NTAPI SmSessionComplete( - IN HANDLE SmApiPort, - IN ULONG SessionId, - IN NTSTATUS SessionStatus -); + _In_ HANDLE SmApiPort, + _In_ ULONG SessionId, + _In_ NTSTATUS SessionStatus); + +NTSTATUS +NTAPI +SmExecPgm( + _In_ HANDLE SmApiPort, + _In_ PRTL_USER_PROCESS_INFORMATION ProcessInformation, + _In_ BOOLEAN DebugFlag); NTSTATUS NTAPI SmStartCsr( - IN HANDLE SmApiPort, - OUT PULONG pMuSessionId, - IN PUNICODE_STRING CommandLine, - OUT PHANDLE pWindowsSubSysProcessId, - OUT PHANDLE pInitialCommandProcessId -); + _In_ HANDLE SmApiPort, + _Out_ PULONG pMuSessionId, + _In_opt_ PUNICODE_STRING CommandLine, + _Out_ PHANDLE pWindowsSubSysProcessId, + _Out_ PHANDLE pInitialCommandProcessId); NTSTATUS NTAPI SmStopCsr( - IN HANDLE SmApiPort, - IN ULONG SessionId -); + _In_ HANDLE SmApiPort, + _In_ ULONG MuSessionId); -#endif +#endif // _SM_MSG_ diff --git a/sdk/include/reactos/subsys/sm/smrosdbg.h b/sdk/include/reactos/subsys/sm/smrosdbg.h new file mode 100644 index 00000000000..8a20f9afa1d --- /dev/null +++ b/sdk/include/reactos/subsys/sm/smrosdbg.h @@ -0,0 +1,58 @@ +/* + * PROJECT: ReactOS SM Helper Library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: ReactOS-specific SM Debug Utility Function: + * Querying subsystem information. + * COPYRIGHT: Copyright 2005 Emanuele Aliberti + * Copyright 2022 Hermès Bélusca-Maïto + */ + +#ifndef _SMROSDBG_H_ +#define _SMROSDBG_H_ + +#pragma once + +/* Note: this is not in NT */ +/* Ask SM to send back some data */ +#define SM_API_QUERY_INFORMATION SmpMaxApiNumber + +#define SM_QRYINFO_MAX_SS_COUNT 8 +#define SM_QRYINFO_MAX_ROOT_NODE 30 + +typedef enum { + SmBasicInformation = 0, + SmSubSystemInformation +} SM_INFORMATION_CLASS; + +typedef struct _SM_BASIC_INFORMATION +{ + USHORT SubSystemCount; + USHORT Unused; + struct + { + USHORT Id; + USHORT Flags; + ULONG ProcessId; + } SubSystem[SM_QRYINFO_MAX_SS_COUNT]; +} SM_BASIC_INFORMATION, *PSM_BASIC_INFORMATION; + +typedef struct _SM_SUBSYSTEM_INFORMATION +{ + USHORT SubSystemId; + USHORT Flags; + ULONG ProcessId; + WCHAR NameSpaceRootNode[SM_QRYINFO_MAX_ROOT_NODE]; +} SM_SUBSYSTEM_INFORMATION, *PSM_SUBSYSTEM_INFORMATION; + +typedef struct _SM_QUERYINFO_MSG +{ + SM_INFORMATION_CLASS SmInformationClass; + ULONG DataLength; + union + { + SM_BASIC_INFORMATION BasicInformation; + SM_SUBSYSTEM_INFORMATION SubSystemInformation; + }; +} SM_QUERYINFO_MSG, *PSM_QUERYINFO_MSG; + +#endif // _SMROSDBG_H_ diff --git a/sdk/lib/smlib/CMakeLists.txt b/sdk/lib/smlib/CMakeLists.txt index 41429ad3e02..00d223c7755 100644 --- a/sdk/lib/smlib/CMakeLists.txt +++ b/sdk/lib/smlib/CMakeLists.txt @@ -2,10 +2,6 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys) list(APPEND SOURCE - compses.c - connect.c - execpgm.c - lookupss.c smclient.c precomp.h) diff --git a/sdk/lib/smlib/compses.c b/sdk/lib/smlib/compses.c deleted file mode 100644 index 04f18019991..00000000000 --- a/sdk/lib/smlib/compses.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/smlib/compses.c - * PURPOSE: Call SM API SM_API_COMPLETE_SESSION - */ - -#include "precomp.h" - -#define NDEBUG -#include - -/********************************************************************** - * NAME EXPORTED - * SmCompleteSession/3 - * - * DESCRIPTION - * This function is called by an environment subsystem server to - * tell the SM it finished initialization phase and is ready to - * manage processes it registered for (SmConnectApiPort). - * - * ARGUMENTS - * hSmApiPort: port handle returned by SmConnectApiPort; - * hSbApiPort: call back API port of the subsystem (handle); - * hApiPort : API port of the subsystem (handle). - * - * RETURN VALUE - * Success status as handed by the SM reply; otherwise a failure - * status code. - */ -NTSTATUS WINAPI -SmCompleteSession (IN HANDLE hSmApiPort, - IN HANDLE hSbApiPort, - IN HANDLE hApiPort) -{ - NTSTATUS Status; - SM_PORT_MESSAGE SmReqMsg; - - DPRINT("SMLIB: %s called\n", __FUNCTION__); - - /* Marshal Ses in the LPC message */ - SmReqMsg.Request.CompSes.hApiPort = hApiPort; - SmReqMsg.Request.CompSes.hSbApiPort = hSbApiPort; - - /* SM API to invoke */ - SmReqMsg.SmHeader.ApiIndex = SM_API_COMPLETE_SESSION; - - /* Port message */ - SmReqMsg.Header.u2.s2.Type = LPC_NEW_MESSAGE; - SmReqMsg.Header.u1.s1.DataLength = SM_PORT_DATA_SIZE(SmReqMsg.Request); - SmReqMsg.Header.u1.s1.TotalLength = SM_PORT_MESSAGE_SIZE; - Status = NtRequestWaitReplyPort (hSmApiPort, (PPORT_MESSAGE) & SmReqMsg, (PPORT_MESSAGE) & SmReqMsg); - if (NT_SUCCESS(Status)) - { - return SmReqMsg.SmHeader.Status; - } - DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); - return Status; -} - -/* EOF */ diff --git a/sdk/lib/smlib/connect.c b/sdk/lib/smlib/connect.c deleted file mode 100644 index aa95d9ab4d8..00000000000 --- a/sdk/lib/smlib/connect.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: reactos/lib/smlib/connect.c - * PURPOSE: Connect to the API LPC port exposed by the SM - */ - -#include "precomp.h" - -#define NDEBUG -#include - -/********************************************************************** - * NAME EXPORTED - * SmConnectApiPort/4 - * - * DESCRIPTION - * Connect to SM API port and register a session "begin" port (Sb) - * or to issue API requests to SmApiPort. - * - * ARGUMENTS - * pSbApiPortName: name of the Sb port the calling subsystem - * server already created in the system name space; - * hSbApiPort: LPC port handle (checked, but not used: the - * subsystem is required to have already created - * the callback port before it connects to the SM); - * wSubsystem: a valid IMAGE_SUBSYSTEM_xxx value; - * phSmApiPort: a pointer to a HANDLE, which will be - * filled with a valid client-side LPC comm port. - * - * There should be only two ways to call this API: - * a) subsystems willing to register with SM will use it - * with full parameters (the function checks them); - * b) regular SM clients, will set to 0 the 1st, the 2nd, - * and the 3rd parameter. - * - * RETURN VALUE - * If all three optional values are omitted, an LPC status. - * STATUS_INVALID_PARAMETER_MIX if PortName is defined and - * both hSbApiPort and wSubsystem are 0. - */ -NTSTATUS WINAPI -SmConnectApiPort (IN PUNICODE_STRING pSbApiPortName OPTIONAL, - IN HANDLE hSbApiPort OPTIONAL, - IN WORD wSubSystemId OPTIONAL, - IN OUT PHANDLE phSmApiPort) -{ - UNICODE_STRING SmApiPortName; - SECURITY_QUALITY_OF_SERVICE SecurityQos; - NTSTATUS Status = STATUS_SUCCESS; - SM_CONNECT_DATA ConnectData = {0,0,{0}}; - ULONG ConnectDataLength = 0; - - DPRINT("SMLIB: %s called\n", __FUNCTION__); - - if (pSbApiPortName) - { - if (pSbApiPortName->Length > (sizeof pSbApiPortName->Buffer[0] * SM_SB_NAME_MAX_LENGTH)) - { - return STATUS_INVALID_PARAMETER_1; - } - if (NULL == hSbApiPort || IMAGE_SUBSYSTEM_UNKNOWN == wSubSystemId) - { - return STATUS_INVALID_PARAMETER_MIX; - } - RtlZeroMemory (& ConnectData, sizeof ConnectData); - ConnectData.Unused = 0; - ConnectData.SubSystemId = wSubSystemId; - if (pSbApiPortName->Length > 0) - { - RtlCopyMemory (& ConnectData.SbName, - pSbApiPortName->Buffer, - pSbApiPortName->Length); - } - } - ConnectDataLength = sizeof ConnectData; - - SecurityQos.Length = sizeof (SecurityQos); - SecurityQos.ImpersonationLevel = SecurityIdentification; - SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; - SecurityQos.EffectiveOnly = TRUE; - - RtlInitUnicodeString (& SmApiPortName, SM_API_PORT_NAME); - - Status = NtConnectPort ( - phSmApiPort, - & SmApiPortName, - & SecurityQos, - NULL, - NULL, - NULL, - & ConnectData, - & ConnectDataLength - ); - if (NT_SUCCESS(Status)) - { - return STATUS_SUCCESS; - } - DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); - return Status; -} - -/* EOF */ diff --git a/sdk/lib/smlib/execpgm.c b/sdk/lib/smlib/execpgm.c deleted file mode 100644 index e75b743de4c..00000000000 --- a/sdk/lib/smlib/execpgm.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/smlib/execpgm.c - * PURPOSE: Call SM API SM_API_EXECPGM - */ - -#include "precomp.h" - -#define NDEBUG -#include - -/********************************************************************** - * NAME EXPORTED - * SmExecuteProgram/2 - * - * DESCRIPTION - * This function is used to make the SM start an environment - * subsystem server process. - * - * ARGUMENTS - * hSmApiPort: port handle returned by SmConnectApiPort; - * Pgm : name of the subsystem (to be used by the SM to - * lookup the image name from the registry). - * Valid names are: DEBUG, WINDOWS, POSIX, OS2, - * and VMS. - * - * RETURN VALUE - * Success status as handed by the SM reply; otherwise a failure - * status code. - */ -NTSTATUS WINAPI -SmExecuteProgram (IN HANDLE hSmApiPort, - IN PUNICODE_STRING Pgm) -{ - NTSTATUS Status; - SM_PORT_MESSAGE SmReqMsg; - - - DPRINT("SMLIB: %s(%p,'%S') called\n", - __FUNCTION__, hSmApiPort, Pgm->Buffer); - - /* Check Pgm's length */ - if (Pgm->Length > (sizeof (Pgm->Buffer[0]) * SM_EXEXPGM_MAX_LENGTH)) - { - return STATUS_INVALID_PARAMETER; - } - /* Marshal Pgm in the LPC message */ - RtlZeroMemory (& SmReqMsg, sizeof SmReqMsg); - SmReqMsg.Request.ExecPgm.NameLength = Pgm->Length; - RtlCopyMemory (SmReqMsg.Request.ExecPgm.Name, - Pgm->Buffer, - Pgm->Length); - - /* SM API to invoke */ - SmReqMsg.SmHeader.ApiIndex = SM_API_EXECUTE_PROGRAMME; - - /* LPC message */ - SmReqMsg.Header.u2.s2.Type = LPC_NEW_MESSAGE; - SmReqMsg.Header.u1.s1.DataLength = SM_PORT_DATA_SIZE(SmReqMsg.Request); - SmReqMsg.Header.u1.s1.TotalLength = SM_PORT_MESSAGE_SIZE; - - DPRINT("SMLIB: %s:\n" - " u2.s2.Type = %d\n" - " u1.s1.DataLength = %d\n" - " u1.s1.TotalLength = %d\n" - " sizeof(PORT_MESSAGE)==%u\n", - __FUNCTION__, - SmReqMsg.Header.u2.s2.Type, - SmReqMsg.Header.u1.s1.DataLength, - SmReqMsg.Header.u1.s1.TotalLength, - sizeof(PORT_MESSAGE)); - - /* Call SM and wait for a reply */ - Status = NtRequestWaitReplyPort (hSmApiPort, (PPORT_MESSAGE) & SmReqMsg, (PPORT_MESSAGE) & SmReqMsg); - if (NT_SUCCESS(Status)) - { - return SmReqMsg.SmHeader.Status; - } - DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); - return Status; -} - -/* EOF */ diff --git a/sdk/lib/smlib/lookupss.c b/sdk/lib/smlib/lookupss.c deleted file mode 100644 index e47a47ac0ee..00000000000 --- a/sdk/lib/smlib/lookupss.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/smlib/lookupss.c - */ - -#include "precomp.h" - -#define NDEBUG -#include - -/********************************************************************** - * NAME EXPORTED - * SmLookupSubsystem/6 - * - * DESCRIPTION - * Read from the registry key - * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems - * the value which name is Name. - * - * ARGUMENTS - * Name: name of the program to run, that is a value's name in - * the SM registry key SubSystems; - * Data: what the registry gave back for Name; - * DataLength: how much Data the registry returns; - * DataType: what is Data? - * Environment: set it if you want this function to use it - * to possibly expand Data before giving it back; if set - * to NULL, no expansion will be performed. - */ -NTSTATUS WINAPI -SmLookupSubsystem (IN PWSTR Name, - IN OUT PWSTR Data, - IN OUT PULONG DataLength, - IN OUT PULONG DataType, - IN PVOID Environment OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - UNICODE_STRING usKeyName = { 0, 0, NULL }; - OBJECT_ATTRIBUTES Oa = {0}; - HANDLE hKey = (HANDLE) 0; - - DPRINT("SM: %s(Name='%S') called\n", __FUNCTION__, Name); - /* - * Prepare the key name to scan and - * related object attributes. - */ - RtlInitUnicodeString (& usKeyName, - L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems"); - - InitializeObjectAttributes (& Oa, - & usKeyName, - OBJ_CASE_INSENSITIVE, - NULL, - NULL); - /* - * Open the key. This MUST NOT fail, if the - * request is for a legitimate subsystem. - */ - Status = NtOpenKey (& hKey, - MAXIMUM_ALLOWED, - & Oa); - if(NT_SUCCESS(Status)) - { - UNICODE_STRING usValueName = { 0, 0, NULL }; - PWCHAR KeyValueInformation = NULL; - ULONG KeyValueInformationLength = 1024; - ULONG ResultLength = 0L; - PKEY_VALUE_PARTIAL_INFORMATION kvpi = NULL; - - KeyValueInformation = RtlAllocateHeap (RtlGetProcessHeap(), - 0, - KeyValueInformationLength); - if (NULL == KeyValueInformation) - { - return STATUS_NO_MEMORY; - } - kvpi = (PKEY_VALUE_PARTIAL_INFORMATION) KeyValueInformation; - RtlInitUnicodeString (& usValueName, Name); - Status = NtQueryValueKey (hKey, - & usValueName, - KeyValuePartialInformation, - KeyValueInformation, - KeyValueInformationLength, - & ResultLength); - if(NT_SUCCESS(Status)) - { - DPRINT("nkvpi.TitleIndex = %lu\n", kvpi->TitleIndex); - DPRINT("kvpi.Type = %lu\n", kvpi->Type); - DPRINT("kvpi.DataLength = %lu\n", kvpi->DataLength); - - if((NULL != Data) && (NULL != DataLength) && (NULL != DataType)) - { - *DataType = kvpi->Type; - if((NULL != Environment) && (REG_EXPAND_SZ == *DataType)) - { - UNICODE_STRING Source; - PWCHAR DestinationBuffer = NULL; - UNICODE_STRING Destination; - ULONG Length = 0; - - DPRINT("SM: %s: value will be expanded\n", __FUNCTION__); - - DestinationBuffer = RtlAllocateHeap (RtlGetProcessHeap(), - 0, - (2 * KeyValueInformationLength)); - if (NULL == DestinationBuffer) - { - Status = STATUS_NO_MEMORY; - } - else - { - Source.Length = (USHORT)kvpi->DataLength; - Source.MaximumLength = (USHORT)kvpi->DataLength; - Source.Buffer = (PWCHAR) & kvpi->Data; - - Destination.Length = 0; - Destination.MaximumLength = (USHORT)(2 * KeyValueInformationLength); - Destination.Buffer = DestinationBuffer; - - Status = RtlExpandEnvironmentStrings_U (Environment, - & Source, - & Destination, - & Length); - if(NT_SUCCESS(Status)) - { - *DataLength = min(*DataLength, Destination.Length); - RtlCopyMemory (Data, Destination.Buffer, *DataLength); - } - RtlFreeHeap (RtlGetProcessHeap(), 0, DestinationBuffer); - } - }else{ - DPRINT("SM: %s: value won't be expanded\n", __FUNCTION__); - *DataLength = min(*DataLength, kvpi->DataLength); - RtlCopyMemory (Data, & kvpi->Data, *DataLength); - } - *DataType = kvpi->Type; - }else{ - DPRINT1("SM: %s: Data or DataLength or DataType is NULL!\n", __FUNCTION__); - Status = STATUS_INVALID_PARAMETER; - } - }else{ - DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); - } - RtlFreeHeap (RtlGetProcessHeap(), 0, KeyValueInformation); - NtClose (hKey); - }else{ - DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); - } - return Status; -} - -/* EOF */ diff --git a/sdk/lib/smlib/precomp.h b/sdk/lib/smlib/precomp.h index 97f3b2bf7a2..19e69e374bd 100644 --- a/sdk/lib/smlib/precomp.h +++ b/sdk/lib/smlib/precomp.h @@ -1,24 +1,20 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS System Libraries - * FILE: lib/smlib/precomp.h - * PURPOSE: SMLIB Library Header - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * PROJECT: ReactOS NT-Compatible Session Manager + * LICENSE: BSD 2-Clause License (https://spdx.org/licenses/BSD-2-Clause) + * PURPOSE: SMSS Client Library (SMLIB) Header + * COPYRIGHT: Copyright 2012-2013 Alex Ionescu */ #ifndef _SMLIB_PCH_ #define _SMLIB_PCH_ -#define WIN32_NO_STATUS -#include -#include #define NTOS_MODE_USER -#include #include #include #include #include -#include +#include +#include #endif /* _SMLIB_PCH_ */ diff --git a/sdk/lib/smlib/readme.txt b/sdk/lib/smlib/readme.txt new file mode 100644 index 00000000000..14fa624b32a --- /dev/null +++ b/sdk/lib/smlib/readme.txt @@ -0,0 +1,67 @@ + +SMLIB: Client Library to talk to the ReactOS NT-Compatible Session Manager (SM). + +It should be linked in the following components: + +a) the SM itself, because it registers for managing native processes + IMAGE_SUBSYSTEM_NATIVE; + +b) environment subsystem servers, because each one should register in + the SM its own subsystem (willing to manage those processes); + +c) application launchers (e.g. terminal emulators) for optional subsystems, + to ask the SM to start the optional subsystem server they need to connect; + +d) system and development utilities to debug/query the SM. + +2004-02-15 ea +2022-11-03 hbelusca + + +How a subsystem uses these APIs +=============================== + +Thread #0 Thread #1 + +- Creates its own directory (\EXAMPLE) +- Initializes the main parts of the subsystem. +- Creates its main API port (\EXAMPLE\ApiPort), + and servicing thread for it. Programs running + under this subsystem will communicate with + this API port. + +- Creates its SM callback API port (\EXAMPLE\SbApiPort) + and servicing thread T1. + + - Waits connection requests on the + callback port (\EXAMPLE\SbApiPort) + +- Registers to the SM by calling + SmConnectToSm( + "\EXAMPLE\SbApiPort", + hSbApiPort, + SUBSYSTEM_ID, + &hSmApiPort); + - As the SM calls back, validates + and accepts connection. + +- The subsystem is now ready to + manage processes, etc. + +----- + +Thread #N Thread #1 + + - The SM calls back the subsystem + SbCreateSession() API, so that it + can initialize a new environment + session (with associated SessionId). + +- When no more processes to manage exist, + terminate the subsystem session by calling + SmSessionComplete( + hSmApiPort, + SessionId, + ExitStatus); + - The SM calls back the subsystem + SbTerminateSession() API. diff --git a/sdk/lib/smlib/smclient.c b/sdk/lib/smlib/smclient.c index d56c8e57d0a..58768f197bb 100644 --- a/sdk/lib/smlib/smclient.c +++ b/sdk/lib/smlib/smclient.c @@ -1,79 +1,69 @@ /* - * PROJECT: ReactOS Windows-Compatible Session Manager - * LICENSE: BSD 2-Clause License - * FILE: lib/smlib/smclient.c - * PURPOSE: SMSS Client Library Stubs for calling SM APIs from a client - * PROGRAMMERS: Alex Ionescu + * PROJECT: ReactOS NT-Compatible Session Manager + * LICENSE: BSD 2-Clause License (https://spdx.org/licenses/BSD-2-Clause) + * PURPOSE: SMSS Client Library (SMLIB) Client Stubs + * COPYRIGHT: Copyright 2012-2013 Alex Ionescu + * Copyright 2021 Hervé Poussineau + * Copyright 2022 Hermès Bélusca-Maïto */ /* INCLUDES *******************************************************************/ #include "precomp.h" -#include // To go in precomp.h after #define NDEBUG #include /* FUNCTIONS ******************************************************************/ +/** + * @brief + * Connects to the SM API port for registering a session callback port (Sb) + * associated to a subsystem, or for issuing API requests to the SM API port. + * + * There are only two ways to call this API: + * a) subsystems willing to register with SM will use it + * with full parameters (the function checks them); + * b) regular SM clients, will set to 0 the 1st, the 2nd, + * and the 3rd parameters. + * + * @param[in] SbApiPortName + * Name of the Sb port the calling subsystem server already + * created in the system namespace. + * + * @param[in] SbApiPort + * LPC port handle (checked, but not used: the subsystem is + * required to have already created the callback port before + * it connects to the SM). + * + * @param[in] ImageType + * A valid IMAGE_SUBSYSTEM_xxx value. PE images having this + * subsystem value will be handled by the current subsystem. + * + * @param[out] SmApiPort + * Pointer to a HANDLE, which will be filled with a valid + * client-side LPC communication port. + * + * @return + * If all three optional values are omitted, an LPC status. + * STATUS_INVALID_PARAMETER_MIX if PortName is defined and + * both SbApiPort and ImageType are 0. + * + * @remark + * Exported on Vista+ by NTDLL and called RtlConnectToSm(). + **/ NTSTATUS NTAPI -SmExecPgm(IN HANDLE SmApiPort, - IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, - IN BOOLEAN DebugFlag) +SmConnectToSm( + _In_opt_ PUNICODE_STRING SbApiPortName, + _In_opt_ HANDLE SbApiPort, + _In_opt_ ULONG ImageType, + _Out_ PHANDLE SmApiPort) { NTSTATUS Status; - SM_API_MSG SmApiMsg; - -#if 0 //def _WIN64 // You can take care of this Timo - /* 64-bit SMSS needs to talk to 32-bit processes so do the LPC conversion */ - if (SmpIsWow64Process()) - { - return SmpWow64ExecPgm(SmApiPort, ProcessInformation, DebugFlag); - } -#endif - - /* Initialize the generic LPC header */ - SmApiMsg.h.u2.ZeroInit = 0; - SmApiMsg.h.u1.s1.DataLength = sizeof(SM_EXEC_PGM_MSG) + 8; - SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); - - /* Initialize this specific API's parameters */ - SmApiMsg.ApiNumber = SmpExecPgmApi; - RtlCopyMemory(&SmApiMsg.u.ExecPgm.ProcessInformation, - ProcessInformation, - sizeof(SmApiMsg.u.ExecPgm.ProcessInformation)); - SmApiMsg.u.ExecPgm.DebugFlag = DebugFlag; - - /* Send the message to SMSS */ - Status = NtRequestWaitReplyPort(SmApiPort, &SmApiMsg.h, &SmApiMsg.h); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SmExecPgm: NtRequestWaitReply Failed %lx\n", Status); - } - else - { - /* Upon success, we use the API's return value */ - Status = SmApiMsg.ReturnValue; - } - - /* Close the handles that the parent passed in and return status */ - NtClose(ProcessInformation->ProcessHandle); - NtClose(ProcessInformation->ThreadHandle); - return Status; -} - -NTSTATUS -NTAPI -SmConnectToSm(IN PUNICODE_STRING SbApiPortName, - IN HANDLE SbApiPort, - IN ULONG ImageType, - OUT PHANDLE SmApiPort) -{ - NTSTATUS Status; - SB_CONNECTION_INFO ConnectInfo; - UNICODE_STRING PortName; SECURITY_QUALITY_OF_SERVICE SecurityQos; + UNICODE_STRING PortName; + SB_CONNECTION_INFO ConnectInfo = {0}; ULONG ConnectInfoLength = sizeof(ConnectInfo); /* Setup the QoS structure */ @@ -82,20 +72,24 @@ SmConnectToSm(IN PUNICODE_STRING SbApiPortName, SecurityQos.EffectiveOnly = TRUE; /* Set the SM API port name */ - RtlInitUnicodeString(&PortName, L"\\SmApiPort"); + RtlInitUnicodeString(&PortName, L"\\SmApiPort"); // SM_API_PORT_NAME /* Check if this is a client connecting to SMSS, or SMSS to itself */ if (SbApiPortName) { /* A client SB port as well as an image type must be present */ - if (!(SbApiPort) || !(ImageType)) return STATUS_INVALID_PARAMETER_MIX; + if (!SbApiPort || (ImageType == IMAGE_SUBSYSTEM_UNKNOWN)) + return STATUS_INVALID_PARAMETER_MIX; + + /* Validate SbApiPortName's length */ + if (SbApiPortName->Length >= sizeof(ConnectInfo.SbApiPortName)) + return STATUS_INVALID_PARAMETER; /* Copy the client port name, and NULL-terminate it */ RtlCopyMemory(ConnectInfo.SbApiPortName, SbApiPortName->Buffer, SbApiPortName->Length); - ConnectInfo.SbApiPortName[SbApiPortName->Length / - sizeof(WCHAR)] = UNICODE_NULL; + ConnectInfo.SbApiPortName[SbApiPortName->Length / sizeof(WCHAR)] = UNICODE_NULL; /* Save the subsystem type */ ConnectInfo.SubsystemType = ImageType; @@ -120,131 +114,302 @@ SmConnectToSm(IN PUNICODE_STRING SbApiPortName, { DPRINT1("SmConnectToSm: Connect to Sm failed %lx\n", Status); } +#if (NTDDI_VERSION < NTDDI_VISTA) else { /* Treat a warning or informational status as success */ Status = STATUS_SUCCESS; } +#endif /* Return if the connection was successful or not */ return Status; } +/** + * @brief + * Sends a message to the SM via the SM API port. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in,out] SmApiMsg + * Message to send to the SM. The API-specific data must be initialized, + * and the SmApiMsg->ApiNumber must be specified accordingly. + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + * + * @remark + * Exported on Vista+ by NTDLL and called RtlSendMsgToSm(). + **/ NTSTATUS NTAPI -SmSessionComplete(IN HANDLE SmApiPort, - IN ULONG SessionId, - IN NTSTATUS SessionStatus) +SmSendMsgToSm( + _In_ HANDLE SmApiPort, + _Inout_ PSM_API_MSG SmApiMsg) { + static ULONG RtlpSmMessageInfo[SmpMaxApiNumber] = + { + 0 /*sizeof(SM_CREATE_FOREIGN_SESSION_MSG)*/, + sizeof(SM_SESSION_COMPLETE_MSG), + 0 /*sizeof(SM_TERMINATE_FOREIGN_SESSION_MSG)*/, + sizeof(SM_EXEC_PGM_MSG), + sizeof(SM_LOAD_DEFERED_SUBSYSTEM_MSG), + sizeof(SM_START_CSR_MSG), + sizeof(SM_STOP_CSR_MSG), + }; + NTSTATUS Status; - SM_API_MSG ApiMessage; - PSM_SESSION_COMPLETE_MSG SessionComplete = &ApiMessage.u.SessionComplete; + ULONG DataLength; + + if (SmApiMsg->ApiNumber >= SmpMaxApiNumber) + return STATUS_NOT_IMPLEMENTED; + + /* Obtain the necessary data length for this API */ + DataLength = RtlpSmMessageInfo[SmApiMsg->ApiNumber]; + + /* Fill out the Port Message Header */ + // RtlZeroMemory(&SmApiMsg->h, sizeof(SmApiMsg->h)); + SmApiMsg->h.u2.ZeroInit = 0; + /* DataLength = user_data_size + anything between + * header and data, including intermediate padding */ + SmApiMsg->h.u1.s1.DataLength = (CSHORT)DataLength + + FIELD_OFFSET(SM_API_MSG, u) - sizeof(SmApiMsg->h); + /* TotalLength = sizeof(*SmApiMsg) on <= NT5.2, otherwise: + * DataLength + header_size == user_data_size + FIELD_OFFSET(SM_API_MSG, u) + * without structure trailing padding */ + SmApiMsg->h.u1.s1.TotalLength = SmApiMsg->h.u1.s1.DataLength + sizeof(SmApiMsg->h); + + /* Send the LPC message and wait for a reply */ + Status = NtRequestWaitReplyPort(SmApiPort, &SmApiMsg->h, &SmApiMsg->h); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SmSendMsgToSm: NtRequestWaitReplyPort failed, Status: 0x%08lx\n", Status); + } + else + { + /* Return the real status */ + Status = SmApiMsg->ReturnValue; + } + + return Status; +} + +/** + * @brief + * This function is called by an environment subsystem server + * to tell the SM it has terminated the session it managed. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in] SessionId + * The session ID of the session being terminated. + * + * @param[in] SessionStatus + * An NT status code for the termination. + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + **/ +NTSTATUS +NTAPI +SmSessionComplete( + _In_ HANDLE SmApiPort, + _In_ ULONG SessionId, + _In_ NTSTATUS SessionStatus) +{ + SM_API_MSG SmApiMsg = {0}; + PSM_SESSION_COMPLETE_MSG SessionComplete = &SmApiMsg.u.SessionComplete; + +#if 0 //def _WIN64 + /* 64-bit SMSS needs to talk to 32-bit processes so do the LPC conversion */ + if (SmpIsWow64Process()) + { + return SmpWow64SessionComplete(SmApiPort, SessionId, SessionStatus); + } +#endif /* Set the message data */ SessionComplete->SessionId = SessionId; SessionComplete->SessionStatus = SessionStatus; - /* Set the API Message Port Message header */ - ApiMessage.ApiNumber = SmpSessionCompleteApi; - ApiMessage.h.u1.s1.DataLength = sizeof(SM_SESSION_COMPLETE_MSG) + 8; - ApiMessage.h.u1.s1.TotalLength = sizeof(SM_API_MSG); - ApiMessage.h.u2.ZeroInit = 0; + /* Send the message and wait for a reply */ + SmApiMsg.ApiNumber = SmpSessionCompleteApi; + return SmSendMsgToSm(SmApiPort, &SmApiMsg); +} - /* Sent the message and wait for a reply */ - Status = NtRequestWaitReplyPort(SmApiPort, - &ApiMessage.h, - &ApiMessage.h); - if (NT_SUCCESS(Status)) - { - /* Return the real status */ - Status = ApiMessage.ReturnValue; - } - else - { - DPRINT1("SmCompleteSession: NtRequestWaitReply failed\n"); - } +/** + * @brief + * Requests the SM to start a process under a new environment session. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in] ProcessInformation + * A process description as returned by RtlCreateUserProcess(). + * + * @param[in] DebugFlag + * If set, indicates that the caller wants to debug this process + * and act as its debug user interface. + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + **/ +NTSTATUS +NTAPI +SmExecPgm( + _In_ HANDLE SmApiPort, + _In_ PRTL_USER_PROCESS_INFORMATION ProcessInformation, + _In_ BOOLEAN DebugFlag) +{ + NTSTATUS Status; + SM_API_MSG SmApiMsg = {0}; + PSM_EXEC_PGM_MSG ExecPgm = &SmApiMsg.u.ExecPgm; - /* Return status */ +#if 0 //def _WIN64 + /* 64-bit SMSS needs to talk to 32-bit processes so do the LPC conversion */ + if (SmpIsWow64Process()) + { + return SmpWow64ExecPgm(SmApiPort, ProcessInformation, DebugFlag); + } +#endif + + /* Set the message data */ + RtlCopyMemory(&ExecPgm->ProcessInformation, + ProcessInformation, + sizeof(ExecPgm->ProcessInformation)); + ExecPgm->DebugFlag = DebugFlag; + + /* Send the message and wait for a reply */ + SmApiMsg.ApiNumber = SmpExecPgmApi; + Status = SmSendMsgToSm(SmApiPort, &SmApiMsg); + + /* Close the handles that the parent passed in and return status */ + NtClose(ProcessInformation->ProcessHandle); + NtClose(ProcessInformation->ThreadHandle); return Status; } +/** + * @brief + * Requests the SM to create a new Terminal Services session + * and start an initial command. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[out] pMuSessionId + * Pointer to a variable that receives the session ID of the new + * Terminal Services session that has been created. + * + * @param[in] CommandLine + * Full path to the image to be used as the initial command. + * + * @param[out] pWindowsSubSysProcessId + * Pointer to a variable that receives the process ID of the environment + * subsystem that has been started in the new session. + * + * @param[out] pInitialCommandProcessId + * Pointer to a variable that receives the process ID of the initial command. + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + **/ NTSTATUS NTAPI -SmStartCsr(IN HANDLE SmApiPort, - OUT PULONG pMuSessionId, - IN PUNICODE_STRING CommandLine, - OUT PHANDLE pWindowsSubSysProcessId, - OUT PHANDLE pInitialCommandProcessId) +SmStartCsr( + _In_ HANDLE SmApiPort, + _Out_ PULONG pMuSessionId, + _In_opt_ PUNICODE_STRING CommandLine, + _Out_ PHANDLE pWindowsSubSysProcessId, + _Out_ PHANDLE pInitialCommandProcessId) { NTSTATUS Status; - SM_API_MSG SmApiMsg; + SM_API_MSG SmApiMsg = {0}; + PSM_START_CSR_MSG StartCsr = &SmApiMsg.u.StartCsr; - /* Initialize the generic LPC header */ - RtlZeroMemory(&SmApiMsg, sizeof(SmApiMsg)); - SmApiMsg.h.u1.s1.DataLength = sizeof(SM_EXEC_PGM_MSG) + 8; - SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); +#if 0 //def _WIN64 + /* 64-bit SMSS needs to talk to 32-bit processes so do the LPC conversion */ + if (SmpIsWow64Process()) + { + return SmpWow64StartCsr(SmApiPort, + pMuSessionId, + CommandLine, + pWindowsSubSysProcessId, + pInitialCommandProcessId); + } +#endif - /* Initialize this specific API's parameters */ - SmApiMsg.ApiNumber = SmpStartCsrApi; + /* Set the message data */ if (CommandLine) { - if (CommandLine->Length > ARRAYSIZE(SmApiMsg.u.StartCsr.Buffer)) - { - DPRINT1("SmStartCsr: Command line too long\n"); + /* Validate CommandLine's length */ + if (CommandLine->Length > sizeof(StartCsr->Buffer)) return STATUS_INVALID_PARAMETER; - } - RtlCopyMemory(SmApiMsg.u.StartCsr.Buffer, CommandLine->Buffer, CommandLine->Length); - SmApiMsg.u.StartCsr.Length = CommandLine->Length; - } - /* Send the message to SMSS */ - Status = NtRequestWaitReplyPort(SmApiPort, &SmApiMsg.h, &SmApiMsg.h); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SmStartCsr: NtRequestWaitReply Failed %lx\n", Status); + /* Buffer stores a counted non-NULL-terminated UNICODE string */ + StartCsr->Length = CommandLine->Length; + RtlCopyMemory(StartCsr->Buffer, + CommandLine->Buffer, + CommandLine->Length); } else { - /* Upon success, we use the API's return value */ - Status = SmApiMsg.ReturnValue; + StartCsr->Length = 0; } + /* Send the message and wait for a reply */ + SmApiMsg.ApiNumber = SmpStartCsrApi; + Status = SmSendMsgToSm(SmApiPort, &SmApiMsg); + /* Give back informations to caller */ - *pMuSessionId = SmApiMsg.u.StartCsr.MuSessionId; - *pWindowsSubSysProcessId = SmApiMsg.u.StartCsr.WindowsSubSysProcessId; - *pInitialCommandProcessId = SmApiMsg.u.StartCsr.SmpInitialCommandProcessId; + *pMuSessionId = StartCsr->MuSessionId; + *pWindowsSubSysProcessId = StartCsr->WindowsSubSysProcessId; + *pInitialCommandProcessId = StartCsr->SmpInitialCommandProcessId; return Status; } +/** + * @brief + * Requests the SM to terminate a Terminal Services session. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in] MuSessionId + * The Terminal Services session ID, returned by SmStartCsr(). + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + **/ NTSTATUS NTAPI -SmStopCsr(IN HANDLE SmApiPort, - IN ULONG SessionId) +SmStopCsr( + _In_ HANDLE SmApiPort, + _In_ ULONG MuSessionId) { - NTSTATUS Status; - SM_API_MSG SmApiMsg; + SM_API_MSG SmApiMsg = {0}; - /* Initialize the generic LPC header */ - RtlZeroMemory(&SmApiMsg, sizeof(SmApiMsg)); - SmApiMsg.h.u1.s1.DataLength = sizeof(SM_EXEC_PGM_MSG) + 8; - SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); +#if 0 //def _WIN64 + /* 64-bit SMSS needs to talk to 32-bit processes so do the LPC conversion */ + if (SmpIsWow64Process()) + { + return SmpWow64StopCsr(SmApiPort, MuSessionId); + } +#endif - /* Initialize this specific API's parameters */ + /* Set the message data */ + SmApiMsg.u.StopCsr.MuSessionId = MuSessionId; + + /* Send the message and wait for a reply */ SmApiMsg.ApiNumber = SmpStopCsrApi; - SmApiMsg.u.StopCsr.MuSessionId = SessionId; - - /* Send the message to SMSS */ - Status = NtRequestWaitReplyPort(SmApiPort, &SmApiMsg.h, &SmApiMsg.h); - if (!NT_SUCCESS(Status)) - { - DPRINT1("SmStopCsr: NtRequestWaitReply Failed %lx\n", Status); - } - else - { - /* Upon success, we use the API's return value */ - Status = SmApiMsg.ReturnValue; - } - - return Status; + return SmSendMsgToSm(SmApiPort, &SmApiMsg); } diff --git a/sdk/lib/smlib/smdll.spec b/sdk/lib/smlib/smdll.spec new file mode 100644 index 00000000000..7372353e3c7 --- /dev/null +++ b/sdk/lib/smlib/smdll.spec @@ -0,0 +1,16 @@ +@ stdcall SmConnectToSm(ptr ptr long ptr) +@ stub SmCreateForeignSession +@ stdcall SmSessionComplete(ptr long long) +@ stub SmTerminateForeignSession +@ stdcall SmExecPgm(ptr ptr long) +@ stdcall SmLoadDeferedSubsystem(ptr ptr) +@ stdcall SmStartCsr(ptr ptr ptr ptr ptr) +@ stdcall SmStopCsr(ptr long) + +@ stdcall -version=0x600+ RtlConnectToSm(ptr ptr long ptr) SmConnectToSm +@ stdcall -version=0x600+ RtlSendMsgToSm(ptr ptr) SmSendMsgToSm + +## Utilities +@ stdcall SmExecuteProgram(ptr ptr) +@ stdcall SmLookupSubsystem(ptr ptr ptr ptr ptr) +@ stdcall SmQueryInformation(ptr long ptr long ptr) diff --git a/sdk/lib/smlib/smutils.c b/sdk/lib/smlib/smutils.c new file mode 100644 index 00000000000..5dc2503133b --- /dev/null +++ b/sdk/lib/smlib/smutils.c @@ -0,0 +1,452 @@ +/* + * PROJECT: ReactOS SM Helper Library + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Utility functions built around the client SM API + * COPYRIGHT: Copyright 2005 Emanuele Aliberti + * Copyright 2022 Hermès Bélusca-Maïto + */ + +#include "precomp.h" + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H +#include +#include + +#define NTOS_MODE_USER +#include + +#include + +#define NDEBUG +#include + +#if DBG +BOOLEAN SmpDebug = TRUE; +#else +BOOLEAN SmpDebug = FALSE; +#endif + +/** + * @brief + * This function is used to make the SM start an external process + * under an already-loaded environment subsystem server. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in] Program + * Fully qualified NT name of the executable to load. + * + * @return + * Success status as handed by the SM reply; otherwise a failure + * status code. + * + * @remark + * Adapted from SMSS' SmpExecuteInitialCommand() and SmpExecuteImage(). + **/ +NTSTATUS +NTAPI +SmExecuteProgram( + _In_ HANDLE SmApiPort, + _In_ PUNICODE_STRING Program /*, + _Out_opt_ PRTL_USER_PROCESS_INFORMATION ProcessInformation*/) +{ + // ULONG MuSessionId; + + NTSTATUS Status; + RTL_USER_PROCESS_INFORMATION ProcessInfo; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + + PUNICODE_STRING FileName = Program; // FIXME! + PUNICODE_STRING Directory = NULL; // FIXME! + PUNICODE_STRING CommandLine = NULL; // FIXME! + + PVOID SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment; + // UNICODE_STRING SmpDefaultLibPath; + + DPRINT("SMLIB: %s(%p, '%wZ') called\n", + __FUNCTION__, SmApiPort, Program); + + /* Parameters validation */ + if (!SmApiPort) + return STATUS_INVALID_PARAMETER_1; + if (!Program) + return STATUS_INVALID_PARAMETER_2; + + /* Create parameters for the target process, using the current environment */ + Status = RtlCreateProcessParameters(&ProcessParameters, + FileName, + /* SmpDefaultLibPath.Length ? + &SmpDefaultLibPath : */ NULL, + Directory, + CommandLine, + SmpDefaultEnvironment, + NULL, + NULL, + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SMLIB: RtlCreateProcessParameters failed for %wZ - Status == %lx\n", + FileName, Status); + return Status; + } + + /* Set the size field as required */ + ProcessInfo.Size = sizeof(ProcessInfo); + + /* Otherwise inherit the flag that was passed to SMSS itself */ + ProcessParameters->DebugFlags = SmpDebug; + + /* And always force NX for anything that SMSS launches */ + ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_NX; + + /* Now create the process in suspended state */ + Status = RtlCreateUserProcess(FileName, + OBJ_CASE_INSENSITIVE, + ProcessParameters, + NULL, + NULL, + NULL, + FALSE, + NULL, + NULL, + &ProcessInfo); + RtlDestroyProcessParameters(ProcessParameters); + if (!NT_SUCCESS(Status)) + { + /* If we couldn't create it, fail back to the caller */ + DPRINT1("SMLIB: Failed load of %wZ - Status == %lx\n", + FileName, Status); + return Status; + } + + // /* Now duplicate the handle to this process */ + // Status = NtDuplicateObject(NtCurrentProcess(), + // ProcessInfo.ProcessHandle, + // NtCurrentProcess(), + // InitialCommandProcess, + // PROCESS_ALL_ACCESS, + // 0, + // 0); + // if (!NT_SUCCESS(Status)) + // { + // /* Kill it utterly if duplication failed */ + // DPRINT1("SMLIB: DupObject Failed. Status == %lx\n", Status); + // NtTerminateProcess(ProcessInfo.ProcessHandle, Status); + // NtResumeThread(ProcessInfo.ThreadHandle, NULL); + // NtClose(ProcessInfo.ThreadHandle); + // NtClose(ProcessInfo.ProcessHandle); + // return Status; + // } + + /* Call SM and wait for a reply */ + Status = SmExecPgm(SmApiPort, &ProcessInfo, TRUE); + + NtClose(ProcessInfo.ThreadHandle); + NtClose(ProcessInfo.ProcessHandle); + + // if (ProcessInformation) + // *ProcessInformation = ProcessInfo; + + DPRINT("SMLIB: %s returned (Status=0x%08lx)\n", __FUNCTION__, Status); + return Status; +} + +/** + * @brief + * Reads from the registry key + * \Registry\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems + * the value specified by Name. + * + * @param[in] Name + * Name of the program to run, that is a value's name in + * the SM registry key "SubSystems". + * + * @param[out] Data + * What the registry gave back for Name. + * + * @param[in,out] DataLength + * How much Data the registry returns. + * + * @param[out] DataType + * Optional pointer to a variable that receives the type of data + * stored in the specified value. + * + * @param[in] Environment + * Optional environment to be used to possibly expand Data before + * returning it back; if set to NULL, no expansion will be performed. + * + * @return + * Success status if the specified subsystem existed and its information + * has been retrieved successfully; otherwise a failure status code. + **/ +NTSTATUS +NTAPI +SmLookupSubsystem( + _In_ PWSTR Name, + _Out_ PWSTR Data, + _Inout_ PULONG DataLength, + _Out_opt_ PULONG DataType, + _In_opt_ PVOID Environment) +{ + NTSTATUS Status; + UNICODE_STRING usKeyName; + OBJECT_ATTRIBUTES Oa; + HANDLE hKey = NULL; + + UNICODE_STRING usValueName; + PWCHAR KeyValueInformation = NULL; + ULONG KeyValueInformationLength = 1024; + ULONG ResultLength = 0; + PKEY_VALUE_PARTIAL_INFORMATION kvpi; + + DPRINT("SMLIB: %s(Name='%S') called\n", __FUNCTION__, Name); + + /* + * Prepare the key name to scan and + * related object attributes. + */ + RtlInitUnicodeString(&usKeyName, + L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\SubSystems"); + + InitializeObjectAttributes(&Oa, + &usKeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + /* + * Open the key. This MUST NOT fail, if the + * request is for a legitimate subsystem. + */ + Status = NtOpenKey(&hKey, + MAXIMUM_ALLOWED, + &Oa); + if (!NT_SUCCESS(Status)) + { + DPRINT1("%s: NtOpenKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); + return Status; + } + + KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + KeyValueInformationLength); + if (!KeyValueInformation) + { + NtClose(hKey); + return STATUS_NO_MEMORY; + } + + kvpi = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueInformation; + RtlInitUnicodeString(&usValueName, Name); + Status = NtQueryValueKey(hKey, + &usValueName, + KeyValuePartialInformation, + KeyValueInformation, + KeyValueInformationLength, + &ResultLength); + if (!NT_SUCCESS(Status)) + { + DPRINT1("%s: NtQueryValueKey failed (Status=0x%08lx)\n", __FUNCTION__, Status); + + RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); + NtClose(hKey); + + return Status; + } + + DPRINT("kvpi.TitleIndex = %lu\n", kvpi->TitleIndex); + DPRINT("kvpi.Type = %lu\n", kvpi->Type); + DPRINT("kvpi.DataLength = %lu\n", kvpi->DataLength); + + if (Data && DataLength) + { + if (DataType) + *DataType = kvpi->Type; + + if (Environment && (kvpi->Type == REG_EXPAND_SZ)) + { + UNICODE_STRING Source; + UNICODE_STRING Destination; + PWCHAR DestinationBuffer = NULL; + ULONG Length; + + DPRINT("SMLIB: %s: value will be expanded\n", __FUNCTION__); + + Length = 2 * KeyValueInformationLength; + DestinationBuffer = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + Length); + if (!DestinationBuffer) + { + Status = STATUS_NO_MEMORY; + } + else + { + Source.Length = (USHORT)kvpi->DataLength; + Source.MaximumLength = Source.Length; + Source.Buffer = (PWCHAR)&kvpi->Data; + + RtlInitEmptyUnicodeString(&Destination, + DestinationBuffer, + (USHORT)Length); + + Length = 0; + Status = RtlExpandEnvironmentStrings_U(Environment, + &Source, + &Destination, + &Length); + if (NT_SUCCESS(Status)) + { + *DataLength = min(*DataLength, Destination.Length); + RtlCopyMemory(Data, Destination.Buffer, *DataLength); + } + RtlFreeHeap(RtlGetProcessHeap(), 0, DestinationBuffer); + } + } + else + { + DPRINT("SMLIB: %s: value won't be expanded\n", __FUNCTION__); + *DataLength = min(*DataLength, kvpi->DataLength); + RtlCopyMemory(Data, &kvpi->Data, *DataLength); + } + } + else + { + DPRINT1("SMLIB: %s: Data or DataLength is NULL!\n", __FUNCTION__); + Status = STATUS_INVALID_PARAMETER; + } + + RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation); + NtClose(hKey); + + return Status; +} + +/** + * @brief + * Retrieves information about subsystems registered with the SM. + * + * @param[in] SmApiPort + * Port handle returned by SmConnectToSm(). + * + * @param[in] SmInformationClass + * An SM information class ID: + * - SmBasicInformation: + * The number and list of registered subsystems. Data is returned + * in a SM_BASIC_INFORMATION structure. + * - SmSubSystemInformation: + * Information about a particular registered subsystem. Data is + * returned in a SM_SUBSYSTEM_INFORMATION structure. + * + * @param[in,out] Data + * Pointer to storage for the information to request. Either a + * SM_BASIC_INFORMATION or a SM_SUBSYSTEM_INFORMATION, depending + * on the information class. + * + * @param[in] DataLength + * Length in bytes of the Data buffer; it must be set and must + * match the SmInformationClass information size. + * + * @param[in,out] ReturnedDataLength + * Optional pointer to storage to receive the size of the returned data. + * + * @return + * STATUS_SUCCESS when the information asked for has been retrieved. + * STATUS_INVALID_PARAMETER_2 if an invalid information class has been provided. + * STATUS_INFO_LENGTH_MISMATCH in case either DataLength was set to 0 + * or to a value that does not match what the SmInformationClass requires. + * Otherwise, a success status as handed by the SM reply, or a failure + * status code. + * + * @remark + * This API is ReactOS-specific and not in NT. + */ +NTSTATUS +NTAPI +SmQueryInformation( + _In_ HANDLE SmApiPort, + _In_ SM_INFORMATION_CLASS SmInformationClass, + _Inout_ PVOID Data, + _In_ ULONG DataLength, + _Inout_opt_ PULONG ReturnedDataLength) +{ +#if defined(__REACTOS__) && DBG + NTSTATUS Status; + SM_API_MSG SmApiMsg = {0}; + PSM_QUERYINFO_MSG QueryInfo = &SmApiMsg.u.QueryInfo; + + /* Marshal data in the port message */ + switch (SmInformationClass) + { + case SmBasicInformation: + if (DataLength != sizeof(SM_BASIC_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + QueryInfo->SmInformationClass = SmBasicInformation; + QueryInfo->DataLength = DataLength; + QueryInfo->BasicInformation.SubSystemCount = 0; + break; + + case SmSubSystemInformation: + if (DataLength != sizeof(SM_SUBSYSTEM_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + QueryInfo->SmInformationClass = SmSubSystemInformation; + QueryInfo->DataLength = DataLength; + QueryInfo->SubSystemInformation.SubSystemId = + ((PSM_SUBSYSTEM_INFORMATION)Data)->SubSystemId; + break; + + default: + return STATUS_INVALID_PARAMETER_2; + } + + /* SM API to invoke */ + SmApiMsg.ApiNumber = SM_API_QUERY_INFORMATION; + + /* NOTE: Repurpose the DataLength variable */ + DataLength = sizeof(SM_QUERYINFO_MSG); + + /* Fill out the Port Message Header */ + // SmApiMsg.h.u2.s2.Type = LPC_NEW_MESSAGE; + SmApiMsg.h.u2.ZeroInit = 0; + /* DataLength = user_data_size + anything between + * header and data, including intermediate padding */ + SmApiMsg.h.u1.s1.DataLength = (CSHORT)DataLength + + FIELD_OFFSET(SM_API_MSG, u) - sizeof(SmApiMsg.h); + /* TotalLength = sizeof(SmApiMsg) on <= NT5.2, otherwise: + * DataLength + header_size == user_data_size + FIELD_OFFSET(SM_API_MSG, u) + * without structure trailing padding */ + SmApiMsg.h.u1.s1.TotalLength = SmApiMsg.h.u1.s1.DataLength + sizeof(SmApiMsg.h); + + /* Send the LPC message and wait for a reply */ + Status = NtRequestWaitReplyPort(SmApiPort, &SmApiMsg.h, &SmApiMsg.h); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SMLIB: %s: NtRequestWaitReplyPort failed, Status: 0x%08lx\n", + __FUNCTION__, Status); + return Status; + } + + /* Unmarshal data */ + RtlCopyMemory(Data, + &QueryInfo->BasicInformation, + QueryInfo->DataLength); + + /* Use caller provided storage to store data size */ + if (ReturnedDataLength) + *ReturnedDataLength = QueryInfo->DataLength; + + /* Return the real status */ + return SmApiMsg.ReturnValue; +#else + return STATUS_NOT_IMPLEMENTED; +#endif /* defined(__REACTOS__) && DBG */ +} + +/* EOF */ diff --git a/sdk/lib/smlib/smutils.cmake b/sdk/lib/smlib/smutils.cmake new file mode 100644 index 00000000000..579eecb0650 --- /dev/null +++ b/sdk/lib/smlib/smutils.cmake @@ -0,0 +1,11 @@ + +include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys) + +list(APPEND SOURCE + smutils.c + precomp.h) + +add_library(smutils ${SOURCE}) +target_link_libraries(smutils smlib) +add_pch(smutils precomp.h SOURCE) +add_dependencies(smutils psdk) diff --git a/sdk/tools/gen_baseaddress.py b/sdk/tools/gen_baseaddress.py index 0b0cc2e4739..51e89d0870d 100644 --- a/sdk/tools/gen_baseaddress.py +++ b/sdk/tools/gen_baseaddress.py @@ -77,7 +77,6 @@ PRIORITIES = ( 'glu32.dll', 'opengl32.dll', 'riched20.dll', - 'smdll.dll', 'userenv.dll', 'uxtheme.dll', 'cryptui.dll', diff --git a/sdk/tools/rgenstat/module_list.txt b/sdk/tools/rgenstat/module_list.txt index 269ab99ab9d..993c3618632 100644 --- a/sdk/tools/rgenstat/module_list.txt +++ b/sdk/tools/rgenstat/module_list.txt @@ -108,7 +108,6 @@ shdocvw dll\win32\shdocvw shell32 dll\win32\shell32 shfolder dll\win32\shfolder shlwapi dll\win32\shlwapi -smdll dll\win32\smdll snmpapi dll\win32\snmpapi syssetup dll\win32\syssetup twain_32 dll\win32\twain_32