xref: /reactos/base/system/smss/smsbapi.c (revision 1de09c47)
1 /*
2  * PROJECT:         ReactOS Windows-Compatible Session Manager
3  * LICENSE:         BSD 2-Clause License
4  * FILE:            base/system/smss/smsbapi.c
5  * PURPOSE:         Main SMSS Code
6  * PROGRAMMERS:     Alex Ionescu
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "smss.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 #if DBG
19 const PCSTR SmpSubSystemNames[] =
20 {
21     "Unknown",
22     "Native",
23     "Windows GUI",
24     "Windows CUI",
25     NULL,
26     "OS/2 CUI",
27     NULL,
28     "Posix CUI"
29 };
30 #endif
31 
32 /* FUNCTIONS ******************************************************************/
33 
34 NTSTATUS
35 NTAPI
36 SmpSbCreateSession(IN PVOID Reserved,
37                    IN PSMP_SUBSYSTEM OtherSubsystem,
38                    IN PRTL_USER_PROCESS_INFORMATION ProcessInformation,
39                    IN ULONG DbgSessionId,
40                    IN PCLIENT_ID DbgUiClientId)
41 {
42     NTSTATUS Status;
43     ULONG SubSystemType = ProcessInformation->ImageInformation.SubSystemType;
44     ULONG MuSessionId;
45     ULONG SessionId;
46     PSMP_SUBSYSTEM KnownSubsys;
47     SB_API_MSG SbApiMsg = {0};
48     PSB_CREATE_SESSION_MSG CreateSessionMsg = &SbApiMsg.u.CreateSession;
49 
50     /* Write out the create session message including its initial process */
51     CreateSessionMsg->ProcessInfo = *ProcessInformation;
52     CreateSessionMsg->DbgSessionId = DbgSessionId;
53     if (DbgUiClientId)
54     {
55         CreateSessionMsg->DbgUiClientId = *DbgUiClientId;
56     }
57     else
58     {
59         CreateSessionMsg->DbgUiClientId.UniqueThread = NULL;
60         CreateSessionMsg->DbgUiClientId.UniqueProcess = NULL;
61     }
62 
63     /* Find a subsystem responsible for this session */
64     SmpGetProcessMuSessionId(ProcessInformation->ProcessHandle, &MuSessionId);
65     if (!SmpCheckDuplicateMuSessionId(MuSessionId))
66     {
67         NtClose(ProcessInformation->ProcessHandle);
68         NtClose(ProcessInformation->ThreadHandle);
69         DPRINT1("SMSS: CreateSession status=%x\n", STATUS_OBJECT_NAME_NOT_FOUND);
70         return STATUS_OBJECT_NAME_NOT_FOUND;
71     }
72 
73     /* Find the subsystem suitable for this initial process */
74     KnownSubsys = SmpLocateKnownSubSysByType(MuSessionId, SubSystemType);
75     if (KnownSubsys)
76     {
77         /* Duplicate the process handle into the message */
78         Status = NtDuplicateObject(NtCurrentProcess(),
79                                    ProcessInformation->ProcessHandle,
80                                    KnownSubsys->ProcessHandle,
81                                    &CreateSessionMsg->ProcessInfo.ProcessHandle,
82                                    PROCESS_ALL_ACCESS,
83                                    0,
84                                    0);
85         if (NT_SUCCESS(Status))
86         {
87             /* Duplicate the thread handle into the message */
88             Status = NtDuplicateObject(NtCurrentProcess(),
89                                        ProcessInformation->ThreadHandle,
90                                        KnownSubsys->ProcessHandle,
91                                        &CreateSessionMsg->ProcessInfo.ThreadHandle,
92                                        THREAD_ALL_ACCESS,
93                                        0,
94                                        0);
95             if (!NT_SUCCESS(Status))
96             {
97                 /* Close everything on failure */
98                 NtClose(ProcessInformation->ProcessHandle);
99                 NtClose(ProcessInformation->ThreadHandle);
100                 SmpDereferenceSubsystem(KnownSubsys);
101                 DPRINT1("SmpSbCreateSession: NtDuplicateObject (Thread) Failed %lx\n", Status);
102                 return Status;
103             }
104 
105             /* Close the original handles as they are no longer needed */
106             NtClose(ProcessInformation->ProcessHandle);
107             NtClose(ProcessInformation->ThreadHandle);
108 
109             /* Finally, allocate a new SMSS session ID for this session */
110             SessionId = SmpAllocateSessionId(KnownSubsys, OtherSubsystem);
111             CreateSessionMsg->SessionId = SessionId;
112 
113             /* Fill out the LPC message header and send it to the client! */
114             SbApiMsg.ApiNumber = SbpCreateSession;
115             SbApiMsg.h.u2.ZeroInit = 0;
116             SbApiMsg.h.u1.s1.DataLength = sizeof(SB_CREATE_SESSION_MSG) + 8;
117             SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg);
118             Status = NtRequestWaitReplyPort(KnownSubsys->SbApiPort,
119                                             &SbApiMsg.h,
120                                             &SbApiMsg.h);
121             if (!NT_SUCCESS(Status))
122             {
123                 /* Bail out */
124                 DPRINT1("SmpSbCreateSession: NtRequestWaitReply Failed %lx\n", Status);
125             }
126             else
127             {
128                 /* If the API succeeded, get the result value from the LPC */
129                 Status = SbApiMsg.ReturnValue;
130             }
131 
132             /* Delete the session on any kind of failure */
133             if (!NT_SUCCESS(Status)) SmpDeleteSession(SessionId);
134         }
135         else
136         {
137             /* Close the handles on failure */
138             DPRINT1("SmpSbCreateSession: NtDuplicateObject (Process) Failed %lx\n", Status);
139             NtClose(ProcessInformation->ProcessHandle);
140             NtClose(ProcessInformation->ThreadHandle);
141         }
142 
143         /* Dereference the subsystem and return the status of the LPC call */
144         SmpDereferenceSubsystem(KnownSubsys);
145         return Status;
146     }
147 
148     /* If we don't yet have a subsystem, only native images can be launched */
149     if (SubSystemType != IMAGE_SUBSYSTEM_NATIVE)
150     {
151         /* Fail */
152 #if DBG
153         PCSTR SubSysName = NULL;
154         CHAR SubSysTypeName[sizeof("Type 0x")+8];
155 
156         if (SubSystemType < RTL_NUMBER_OF(SmpSubSystemNames))
157             SubSysName = SmpSubSystemNames[SubSystemType];
158         if (!SubSysName)
159         {
160             SubSysName = SubSysTypeName;
161             sprintf(SubSysTypeName, "Type 0x%08lx", SubSystemType);
162         }
163         DPRINT1("SMSS: %s SubSystem not found (either not started or destroyed).\n", SubSysName);
164 #endif
165         Status = STATUS_UNSUCCESSFUL;
166         NtClose(ProcessInformation->ProcessHandle);
167         NtClose(ProcessInformation->ThreadHandle);
168         return Status;
169     }
170 
171 #if 0
172     /*
173      * This code is part of the LPC-based legacy debugging support for native
174      * applications, implemented with the debug client interface (DbgUi) and
175      * debug subsystem (DbgSs). It is now vestigial since WinXP+ and is here
176      * for informational purposes only.
177      */
178     if ((*(ULONGLONG)&CreateSessionMsg.DbgUiClientId) && SmpDbgSsLoaded)
179     {
180         Process = RtlAllocateHeap(SmpHeap, SmBaseTag, sizeof(SMP_PROCESS));
181         if (!Process)
182         {
183             DPRINT1("Unable to initialize debugging for Native App %lx.%lx -- out of memory\n",
184                     ProcessInformation->ClientId.UniqueProcess,
185                     ProcessInformation->ClientId.UniqueThread);
186             NtClose(ProcessInformation->ProcessHandle);
187             NtClose(ProcessInformation->ThreadHandle);
188             return STATUS_NO_MEMORY;
189         }
190 
191         Process->DbgUiClientId = CreateSessionMsg->DbgUiClientId;
192         Process->ClientId = ProcessInformation->ClientId;
193         InsertHeadList(&NativeProcessList, &Process->Entry);
194         DPRINT1("Native Debug App %lx.%lx\n",
195                 Process->ClientId.UniqueProcess,
196                 Process->ClientId.UniqueThread);
197 
198         Status = NtSetInformationProcess(ProcessInformation->ProcessHandle,
199                                          ProcessDebugPort,
200                                          &SmpDebugPort,
201                                          sizeof(SmpDebugPort));
202         ASSERT(NT_SUCCESS(Status));
203     }
204 #endif
205 
206     /* This is a native application being started as the initial command */
207     DPRINT("Subsystem active, starting thread\n");
208     NtClose(ProcessInformation->ProcessHandle);
209     NtResumeThread(ProcessInformation->ThreadHandle, NULL);
210     NtClose(ProcessInformation->ThreadHandle);
211     return STATUS_SUCCESS;
212 }
213