[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().
This commit is contained in:
Hermès Bélusca-Maïto 2022-10-20 20:03:56 +02:00
parent 9f36a9d4a7
commit 0e14378d3e
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
33 changed files with 1033 additions and 1002 deletions

View file

@ -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)

View file

@ -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()

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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 */

View file

@ -1,10 +0,0 @@
#ifndef _SMDLL_PCH_
#define _SMDLL_PCH_
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <windef.h>
#endif /* _SMDLL_PCH_ */

View file

@ -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 <ndk/lpctypes.h>
#include <ndk/lpcfuncs.h>
#include <sm/helper.h>
#define NDEBUG
#include <debug.h>
/**********************************************************************
* 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 */

View file

@ -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.

View file

@ -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 <reactos/version.rc>

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -1,153 +0,0 @@
#ifndef __SM_API_H
#define __SM_API_H
#include <sm/ns.h>
/*** DATA TYPES ******************************************************/
#define SM_SB_NAME_MAX_LENGTH 120
#include <pshpack4.h>
/* 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 <poppack.h>
/*** 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 */

View file

@ -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 <ea@reactos.com>
* Copyright 2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#if !defined(__SM_API_H)
#include <sm/api.h>
#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_

View file

@ -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_

View file

@ -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 <alex.ionescu@reactos.org>
* Copyright 2021 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#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_

View file

@ -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 <ea@reactos.com>
* Copyright 2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#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_

View file

@ -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)

View file

@ -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 <debug.h>
/**********************************************************************
* 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 */

View file

@ -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 <debug.h>
/**********************************************************************
* 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 */

View file

@ -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 <debug.h>
/**********************************************************************
* 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 */

View file

@ -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 <debug.h>
/**********************************************************************
* 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 */

View file

@ -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 <alex.ionescu@reactos.org>
*/
#ifndef _SMLIB_PCH_
#define _SMLIB_PCH_
#define WIN32_NO_STATUS
#include <windef.h>
#include <winreg.h>
#define NTOS_MODE_USER
#include <ndk/cmfuncs.h>
#include <ndk/lpctypes.h>
#include <ndk/lpcfuncs.h>
#include <ndk/obfuncs.h>
#include <ndk/rtlfuncs.h>
#include <sm/helper.h>
#include <sm/ns.h>
#include <sm/smmsg.h>
#endif /* _SMLIB_PCH_ */

67
sdk/lib/smlib/readme.txt Normal file
View file

@ -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.

View file

@ -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 <alex.ionescu@reactos.org>
* Copyright 2021 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
/* INCLUDES *******************************************************************/
#include "precomp.h"
#include <sm/smmsg.h> // To go in precomp.h after
#define NDEBUG
#include <debug.h>
/* 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);
}

16
sdk/lib/smlib/smdll.spec Normal file
View file

@ -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)

452
sdk/lib/smlib/smutils.c Normal file
View file

@ -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 <ea@reactos.com>
* Copyright 2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
#include "precomp.h"
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <windef.h>
#include <winreg.h>
#define NTOS_MODE_USER
#include <ndk/cmfuncs.h>
#include <sm/helper.h>
#define NDEBUG
#include <debug.h>
#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 */

View file

@ -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)

View file

@ -77,7 +77,6 @@ PRIORITIES = (
'glu32.dll',
'opengl32.dll',
'riched20.dll',
'smdll.dll',
'userenv.dll',
'uxtheme.dll',
'cryptui.dll',

View file

@ -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