xref: /reactos/dll/win32/lsasrv/session.c (revision f7cab5a1)
1 /*
2  * PROJECT:     Local Security Authority Server DLL
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        dll/win32/lsasrv/session.c
5  * PURPOSE:     Logon session management routines
6  * COPYRIGHT:   Copyright 2013 Eric Kohl
7  */
8 
9 #include "lsasrv.h"
10 
11 typedef struct _LSAP_LOGON_SESSION
12 {
13     LIST_ENTRY Entry;
14     LUID LogonId;
15     ULONG LogonType;
16     ULONG Session;
17     LARGE_INTEGER LogonTime;
18     PSID Sid;
19     UNICODE_STRING UserName;
20     UNICODE_STRING LogonDomain;
21     UNICODE_STRING AuthenticationPackage;
22     UNICODE_STRING LogonServer;
23     UNICODE_STRING DnsDomainName;
24     UNICODE_STRING Upn;
25 } LSAP_LOGON_SESSION, *PLSAP_LOGON_SESSION;
26 
27 
28 /* GLOBALS *****************************************************************/
29 
30 LIST_ENTRY SessionListHead;
31 ULONG SessionCount;
32 
33 /* FUNCTIONS ***************************************************************/
34 
35 VOID
36 LsapInitLogonSessions(VOID)
37 {
38     InitializeListHead(&SessionListHead);
39     SessionCount = 0;
40 }
41 
42 
43 static
44 PLSAP_LOGON_SESSION
45 LsapGetLogonSession(IN PLUID LogonId)
46 {
47     PLIST_ENTRY SessionEntry;
48     PLSAP_LOGON_SESSION CurrentSession;
49 
50     SessionEntry = SessionListHead.Flink;
51     while (SessionEntry != &SessionListHead)
52     {
53         CurrentSession = CONTAINING_RECORD(SessionEntry,
54                                            LSAP_LOGON_SESSION,
55                                            Entry);
56         if (RtlEqualLuid(&CurrentSession->LogonId, LogonId))
57             return CurrentSession;
58 
59         SessionEntry = SessionEntry->Flink;
60     }
61 
62     return NULL;
63 }
64 
65 
66 NTSTATUS
67 LsapSetLogonSessionData(
68     _In_ PLUID LogonId,
69     _In_ ULONG LogonType,
70     _In_ PUNICODE_STRING UserName,
71     _In_ PUNICODE_STRING LogonDomain,
72     _In_ PSID Sid)
73 {
74     NTSTATUS Status;
75     PLSAP_LOGON_SESSION Session;
76     ULONG Length;
77 
78     TRACE("LsapSetLogonSessionData(%p)\n", LogonId);
79 
80     Session = LsapGetLogonSession(LogonId);
81     if (Session == NULL)
82         return STATUS_NO_SUCH_LOGON_SESSION;
83 
84     TRACE("LogonType %lu\n", LogonType);
85     Session->LogonType = LogonType;
86 
87     Status = RtlValidateUnicodeString(0, UserName);
88     if (!NT_SUCCESS(Status))
89         return STATUS_INVALID_PARAMETER;
90 
91     /* UserName is mandatory and cannot be an empty string */
92     TRACE("UserName %wZ\n", UserName);
93     Session->UserName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
94                                                HEAP_ZERO_MEMORY,
95                                                UserName->MaximumLength);
96     if (Session->UserName.Buffer == NULL)
97         return STATUS_INSUFFICIENT_RESOURCES;
98 
99     Session->UserName.Length = UserName->Length;
100     Session->UserName.MaximumLength = UserName->MaximumLength;
101     RtlCopyMemory(Session->UserName.Buffer, UserName->Buffer, UserName->MaximumLength);
102 
103     Status = RtlValidateUnicodeString(0, LogonDomain);
104     if (!NT_SUCCESS(Status))
105     {
106         /* Cleanup and fail */
107         if (Session->UserName.Buffer != NULL)
108             RtlFreeHeap(RtlGetProcessHeap(), 0, Session->UserName.Buffer);
109 
110         return STATUS_INVALID_PARAMETER;
111     }
112 
113     /* LogonDomain is optional and can be an empty string */
114     TRACE("LogonDomain %wZ\n", LogonDomain);
115     if (LogonDomain->Length)
116     {
117         Session->LogonDomain.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
118                                                       HEAP_ZERO_MEMORY,
119                                                       LogonDomain->MaximumLength);
120         if (Session->LogonDomain.Buffer == NULL)
121         {
122             /* Cleanup and fail */
123             if (Session->UserName.Buffer != NULL)
124                 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->UserName.Buffer);
125 
126             return STATUS_INSUFFICIENT_RESOURCES;
127         }
128 
129         Session->LogonDomain.Length = LogonDomain->Length;
130         Session->LogonDomain.MaximumLength = LogonDomain->MaximumLength;
131         RtlCopyMemory(Session->LogonDomain.Buffer, LogonDomain->Buffer, LogonDomain->MaximumLength);
132     }
133     else
134     {
135         RtlInitEmptyUnicodeString(&Session->LogonDomain, NULL, 0);
136     }
137 
138     Length = RtlLengthSid(Sid);
139     Session->Sid = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Length);
140     if (Session->Sid == NULL)
141     {
142         /* Cleanup and fail */
143         if (Session->LogonDomain.Buffer != NULL)
144             RtlFreeHeap(RtlGetProcessHeap(), 0, Session->LogonDomain.Buffer);
145         if (Session->UserName.Buffer != NULL)
146             RtlFreeHeap(RtlGetProcessHeap(), 0, Session->UserName.Buffer);
147 
148         return STATUS_INSUFFICIENT_RESOURCES;
149     }
150 
151     RtlCopyMemory(Session->Sid, Sid, Length);
152 
153     return STATUS_SUCCESS;
154 }
155 
156 
157 NTSTATUS
158 NTAPI
159 LsapCreateLogonSession(IN PLUID LogonId)
160 {
161     PLSAP_LOGON_SESSION Session;
162     NTSTATUS Status;
163 
164     TRACE("LsapCreateLogonSession(%p)\n", LogonId);
165 
166     /* Fail, if a session already exists */
167     if (LsapGetLogonSession(LogonId) != NULL)
168         return STATUS_LOGON_SESSION_COLLISION;
169 
170     /* Allocate a new session entry */
171     Session = RtlAllocateHeap(RtlGetProcessHeap(),
172                               HEAP_ZERO_MEMORY,
173                               sizeof(LSAP_LOGON_SESSION));
174     if (Session == NULL)
175         return STATUS_INSUFFICIENT_RESOURCES;
176 
177     /* Initialize the session entry */
178     RtlCopyLuid(&Session->LogonId, LogonId);
179 
180     TRACE("LsapCreateLogonSession(<0x%lx,0x%lx>)\n",
181           LogonId->HighPart, LogonId->LowPart);
182 
183     /* Tell ntoskrnl to create a new logon session */
184     Status = LsapRmCreateLogonSession(LogonId);
185     if (!NT_SUCCESS(Status))
186     {
187         RtlFreeHeap(RtlGetProcessHeap(), 0, Session);
188         return Status;
189     }
190 
191     /* Insert the new session into the session list */
192     InsertHeadList(&SessionListHead, &Session->Entry);
193     SessionCount++;
194 
195     return STATUS_SUCCESS;
196 }
197 
198 
199 NTSTATUS
200 NTAPI
201 LsapDeleteLogonSession(IN PLUID LogonId)
202 {
203     PLSAP_LOGON_SESSION Session;
204     NTSTATUS Status;
205 
206     TRACE("LsapDeleteLogonSession(%p)\n", LogonId);
207 
208     /* Fail, if the session does not exist */
209     Session = LsapGetLogonSession(LogonId);
210     if (Session == NULL)
211         return STATUS_NO_SUCH_LOGON_SESSION;
212 
213     TRACE("LsapDeleteLogonSession(<0x%lx,0x%lx>)\n",
214           LogonId->HighPart, LogonId->LowPart);
215 
216     /* Tell ntoskrnl to delete the logon session */
217     Status = LsapRmDeleteLogonSession(LogonId);
218     if (!NT_SUCCESS(Status))
219         return Status;
220 
221     /* Remove the session entry from the list */
222     RemoveEntryList(&Session->Entry);
223     SessionCount--;
224 
225     /* Free the session data */
226     if (Session->Sid != NULL)
227         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->Sid);
228 
229     if (Session->UserName.Buffer != NULL)
230         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->UserName.Buffer);
231 
232     if (Session->LogonDomain.Buffer != NULL)
233         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->LogonDomain.Buffer);
234 
235     if (Session->AuthenticationPackage.Buffer != NULL)
236         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->AuthenticationPackage.Buffer);
237 
238     if (Session->LogonServer.Buffer != NULL)
239         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->LogonServer.Buffer);
240 
241     if (Session->DnsDomainName.Buffer != NULL)
242         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->DnsDomainName.Buffer);
243 
244     if (Session->Upn.Buffer != NULL)
245         RtlFreeHeap(RtlGetProcessHeap(), 0, Session->Upn.Buffer);
246 
247     /* Free the session entry */
248     RtlFreeHeap(RtlGetProcessHeap(), 0, Session);
249 
250     return STATUS_SUCCESS;
251 }
252 
253 
254 NTSTATUS
255 NTAPI
256 LsapAddCredential(
257     _In_ PLUID LogonId,
258     _In_ ULONG AuthenticationPackage,
259     _In_ PLSA_STRING PrimaryKeyValue,
260     _In_ PLSA_STRING Credential)
261 {
262 
263     return STATUS_SUCCESS;
264 }
265 
266 
267 NTSTATUS
268 NTAPI
269 LsapGetCredentials(
270     _In_ PLUID LogonId,
271     _In_ ULONG AuthenticationPackage,
272     _Inout_ PULONG QueryContext,
273     _In_ BOOLEAN RetrieveAllCredentials,
274     _Inout_ PLSA_STRING PrimaryKeyValue,
275     _Out_ PULONG PrimaryKeyLength,
276     _Out_ PLSA_STRING Credentials)
277 {
278 
279     return STATUS_SUCCESS;
280 }
281 
282 
283 NTSTATUS
284 NTAPI
285 LsapDeleteCredential(
286     _In_ PLUID LogonId,
287     _In_ ULONG AuthenticationPackage,
288     _In_ PLSA_STRING PrimaryKeyValue)
289 {
290 
291     return STATUS_SUCCESS;
292 }
293 
294 
295 NTSTATUS
296 LsapEnumLogonSessions(IN OUT PLSA_API_MSG RequestMsg)
297 {
298     OBJECT_ATTRIBUTES ObjectAttributes;
299     HANDLE ProcessHandle = NULL;
300     PLIST_ENTRY SessionEntry;
301     PLSAP_LOGON_SESSION CurrentSession;
302     PLUID SessionList;
303     ULONG i, Length;
304     SIZE_T MemSize;
305     PVOID ClientBaseAddress = NULL;
306     NTSTATUS Status;
307 
308     TRACE("LsapEnumLogonSessions(%p)\n", RequestMsg);
309 
310     Length = SessionCount * sizeof(LUID);
311     SessionList = RtlAllocateHeap(RtlGetProcessHeap(),
312                                   HEAP_ZERO_MEMORY,
313                                   Length);
314     if (SessionList == NULL)
315         return STATUS_INSUFFICIENT_RESOURCES;
316 
317     i = 0;
318     SessionEntry = SessionListHead.Flink;
319     while (SessionEntry != &SessionListHead)
320     {
321         CurrentSession = CONTAINING_RECORD(SessionEntry,
322                                            LSAP_LOGON_SESSION,
323                                            Entry);
324 
325         RtlCopyLuid(&SessionList[i],
326                     &CurrentSession->LogonId);
327 
328         SessionEntry = SessionEntry->Flink;
329         i++;
330     }
331 
332     InitializeObjectAttributes(&ObjectAttributes,
333                                NULL,
334                                0,
335                                NULL,
336                                NULL);
337 
338     Status = NtOpenProcess(&ProcessHandle,
339                            PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
340                            &ObjectAttributes,
341                            &RequestMsg->h.ClientId);
342     if (!NT_SUCCESS(Status))
343     {
344         TRACE("NtOpenProcess() failed (Status %lx)\n", Status);
345         goto done;
346     }
347 
348     TRACE("Length: %lu\n", Length);
349 
350     MemSize = Length;
351     Status = NtAllocateVirtualMemory(ProcessHandle,
352                                      &ClientBaseAddress,
353                                      0,
354                                      &MemSize,
355                                      MEM_COMMIT,
356                                      PAGE_READWRITE);
357     if (!NT_SUCCESS(Status))
358     {
359         TRACE("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
360         goto done;
361     }
362 
363     TRACE("MemSize: %lu\n", MemSize);
364     TRACE("ClientBaseAddress: %p\n", ClientBaseAddress);
365 
366     Status = NtWriteVirtualMemory(ProcessHandle,
367                                   ClientBaseAddress,
368                                   SessionList,
369                                   Length,
370                                   NULL);
371     if (!NT_SUCCESS(Status))
372     {
373         TRACE("NtWriteVirtualMemory() failed (Status %lx)\n", Status);
374         goto done;
375     }
376 
377     RequestMsg->EnumLogonSessions.Reply.LogonSessionCount = SessionCount;
378     RequestMsg->EnumLogonSessions.Reply.LogonSessionBuffer = ClientBaseAddress;
379 
380 done:
381     if (ProcessHandle != NULL)
382         NtClose(ProcessHandle);
383 
384     if (SessionList != NULL)
385         RtlFreeHeap(RtlGetProcessHeap(), 0, SessionList);
386 
387     return Status;
388 }
389 
390 
391 NTSTATUS
392 LsapGetLogonSessionData(IN OUT PLSA_API_MSG RequestMsg)
393 {
394     OBJECT_ATTRIBUTES ObjectAttributes;
395     HANDLE ProcessHandle = NULL;
396     PLSAP_LOGON_SESSION Session;
397     PSECURITY_LOGON_SESSION_DATA LocalSessionData;
398     PVOID ClientBaseAddress = NULL;
399     ULONG TotalLength, SidLength = 0;
400     SIZE_T MemSize;
401     PUCHAR Ptr;
402     NTSTATUS Status;
403 
404     TRACE("LsapGetLogonSessionData(%p)\n", RequestMsg);
405 
406     TRACE("LogonId: %lx\n", RequestMsg->GetLogonSessionData.Request.LogonId.LowPart);
407     Session = LsapGetLogonSession(&RequestMsg->GetLogonSessionData.Request.LogonId);
408     if (Session == NULL)
409         return STATUS_NO_SUCH_LOGON_SESSION;
410 
411     /* Calculate the required buffer size */
412     TotalLength = sizeof(SECURITY_LOGON_SESSION_DATA) +
413                   Session->UserName.MaximumLength +
414                   Session->LogonDomain.MaximumLength +
415                   Session->AuthenticationPackage.MaximumLength +
416                   Session->LogonServer.MaximumLength +
417                   Session->DnsDomainName.MaximumLength +
418                   Session->Upn.MaximumLength;
419     if (Session->Sid != NULL)
420     {
421         SidLength = RtlLengthSid(Session->Sid);
422         TotalLength += SidLength;
423     }
424     TRACE("TotalLength: %lu\n", TotalLength);
425 
426     /* Allocate the buffer */
427     LocalSessionData = RtlAllocateHeap(RtlGetProcessHeap(),
428                                        HEAP_ZERO_MEMORY,
429                                        TotalLength);
430     if (LocalSessionData == NULL)
431         return STATUS_INSUFFICIENT_RESOURCES;
432 
433     Ptr = (PUCHAR)((ULONG_PTR)LocalSessionData + sizeof(SECURITY_LOGON_SESSION_DATA));
434     TRACE("LocalSessionData: %p  Ptr: %p\n", LocalSessionData, Ptr);
435 
436     LocalSessionData->Size = sizeof(SECURITY_LOGON_SESSION_DATA);
437 
438     /* Copy the LogonId */
439     RtlCopyLuid(&LocalSessionData->LogonId,
440                 &RequestMsg->GetLogonSessionData.Request.LogonId);
441 
442     /* Copy the UserName string */
443     LocalSessionData->UserName.Length = Session->UserName.Length;
444     LocalSessionData->UserName.MaximumLength = Session->UserName.MaximumLength;
445     if (Session->UserName.MaximumLength != 0)
446     {
447         RtlCopyMemory(Ptr, Session->UserName.Buffer, Session->UserName.MaximumLength);
448         LocalSessionData->UserName.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
449 
450         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->UserName.MaximumLength);
451     }
452 
453     /* Copy the LogonDomain string */
454     LocalSessionData->LogonDomain.Length = Session->LogonDomain.Length;
455     LocalSessionData->LogonDomain.MaximumLength = Session->LogonDomain.MaximumLength;
456     if (Session->LogonDomain.MaximumLength != 0)
457     {
458         RtlCopyMemory(Ptr, Session->LogonDomain.Buffer, Session->LogonDomain.MaximumLength);
459         LocalSessionData->LogonDomain.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
460 
461         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->LogonDomain.MaximumLength);
462     }
463 
464     /* Copy the AuthenticationPackage string */
465     LocalSessionData->AuthenticationPackage.Length = Session->AuthenticationPackage.Length;
466     LocalSessionData->AuthenticationPackage.MaximumLength = Session->AuthenticationPackage.MaximumLength;
467     if (Session->AuthenticationPackage.MaximumLength != 0)
468     {
469         RtlCopyMemory(Ptr, Session->AuthenticationPackage.Buffer, Session->AuthenticationPackage.MaximumLength);
470         LocalSessionData->AuthenticationPackage.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
471 
472         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->AuthenticationPackage.MaximumLength);
473     }
474 
475     LocalSessionData->LogonType = Session->LogonType;
476     LocalSessionData->Session = 0;
477 
478     /* Sid */
479     if (Session->Sid != NULL)
480     {
481         RtlCopyMemory(Ptr, Session->Sid, SidLength);
482         LocalSessionData->Sid = (PSID)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
483 
484         Ptr = (PUCHAR)((ULONG_PTR)Ptr + SidLength);
485     }
486 
487     /* LogonTime */
488     LocalSessionData->LogonTime.QuadPart = Session->LogonTime.QuadPart;
489 
490     /* Copy the LogonServer string */
491     LocalSessionData->LogonServer.Length = Session->LogonServer.Length;
492     LocalSessionData->LogonServer.MaximumLength = Session->LogonServer.MaximumLength;
493     if (Session->LogonServer.MaximumLength != 0)
494     {
495         RtlCopyMemory(Ptr, Session->LogonServer.Buffer, Session->LogonServer.MaximumLength);
496         LocalSessionData->LogonServer.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
497 
498         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->LogonServer.MaximumLength);
499     }
500 
501     /* Copy the DnsDomainName string */
502     LocalSessionData->DnsDomainName.Length = Session->DnsDomainName.Length;
503     LocalSessionData->DnsDomainName.MaximumLength = Session->DnsDomainName.MaximumLength;
504     if (Session->DnsDomainName.MaximumLength != 0)
505     {
506         RtlCopyMemory(Ptr, Session->DnsDomainName.Buffer, Session->DnsDomainName.MaximumLength);
507         LocalSessionData->DnsDomainName.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
508 
509         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->DnsDomainName.MaximumLength);
510     }
511 
512     /* Copy the Upn string */
513     LocalSessionData->Upn.Length = Session->Upn.Length;
514     LocalSessionData->Upn.MaximumLength = Session->Upn.MaximumLength;
515     if (Session->Upn.MaximumLength != 0)
516     {
517         RtlCopyMemory(Ptr, Session->Upn.Buffer, Session->Upn.MaximumLength);
518         LocalSessionData->Upn.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
519 
520         Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->Upn.MaximumLength);
521     }
522 
523     InitializeObjectAttributes(&ObjectAttributes,
524                                NULL,
525                                0,
526                                NULL,
527                                NULL);
528 
529     Status = NtOpenProcess(&ProcessHandle,
530                            PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
531                            &ObjectAttributes,
532                            &RequestMsg->h.ClientId);
533     if (!NT_SUCCESS(Status))
534     {
535         TRACE("NtOpenProcess() failed (Status %lx)\n", Status);
536         goto done;
537     }
538 
539     MemSize = TotalLength;
540     Status = NtAllocateVirtualMemory(ProcessHandle,
541                                      &ClientBaseAddress,
542                                      0,
543                                      &MemSize,
544                                      MEM_COMMIT,
545                                      PAGE_READWRITE);
546     if (!NT_SUCCESS(Status))
547     {
548         TRACE("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
549         goto done;
550     }
551 
552     TRACE("MemSize: %lu\n", MemSize);
553     TRACE("ClientBaseAddress: %p\n", ClientBaseAddress);
554 
555     Status = NtWriteVirtualMemory(ProcessHandle,
556                                   ClientBaseAddress,
557                                   LocalSessionData,
558                                   TotalLength,
559                                   NULL);
560     if (!NT_SUCCESS(Status))
561     {
562         TRACE("NtWriteVirtualMemory() failed (Status %lx)\n", Status);
563         goto done;
564     }
565 
566     RequestMsg->GetLogonSessionData.Reply.SessionDataBuffer = ClientBaseAddress;
567 
568 done:
569     if (ProcessHandle != NULL)
570         NtClose(ProcessHandle);
571 
572     if (LocalSessionData != NULL)
573         RtlFreeHeap(RtlGetProcessHeap(), 0, LocalSessionData);
574 
575     return Status;
576 }
577 
578 /* EOF */
579