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
LsapInitLogonSessions(VOID)36 LsapInitLogonSessions(VOID)
37 {
38 InitializeListHead(&SessionListHead);
39 SessionCount = 0;
40 }
41
42
43 static
44 PLSAP_LOGON_SESSION
LsapGetLogonSession(IN PLUID LogonId)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
LsapSetLogonSessionData(_In_ PLUID LogonId,_In_ ULONG LogonType,_In_ PUNICODE_STRING UserName,_In_ PUNICODE_STRING LogonDomain,_In_ PSID Sid)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
LsapCreateLogonSession(IN PLUID LogonId)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
LsapDeleteLogonSession(IN PLUID LogonId)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%08lx%08lx)\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 /* Notify the authentication packages */
222 LsapTerminateLogon(LogonId);
223
224 /* Remove the session entry from the list */
225 RemoveEntryList(&Session->Entry);
226 SessionCount--;
227
228 /* Free the session data */
229 if (Session->Sid != NULL)
230 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->Sid);
231
232 if (Session->UserName.Buffer != NULL)
233 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->UserName.Buffer);
234
235 if (Session->LogonDomain.Buffer != NULL)
236 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->LogonDomain.Buffer);
237
238 if (Session->AuthenticationPackage.Buffer != NULL)
239 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->AuthenticationPackage.Buffer);
240
241 if (Session->LogonServer.Buffer != NULL)
242 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->LogonServer.Buffer);
243
244 if (Session->DnsDomainName.Buffer != NULL)
245 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->DnsDomainName.Buffer);
246
247 if (Session->Upn.Buffer != NULL)
248 RtlFreeHeap(RtlGetProcessHeap(), 0, Session->Upn.Buffer);
249
250 /* Free the session entry */
251 RtlFreeHeap(RtlGetProcessHeap(), 0, Session);
252
253 return STATUS_SUCCESS;
254 }
255
256
257 NTSTATUS
258 NTAPI
LsapAddCredential(_In_ PLUID LogonId,_In_ ULONG AuthenticationPackage,_In_ PLSA_STRING PrimaryKeyValue,_In_ PLSA_STRING Credential)259 LsapAddCredential(
260 _In_ PLUID LogonId,
261 _In_ ULONG AuthenticationPackage,
262 _In_ PLSA_STRING PrimaryKeyValue,
263 _In_ PLSA_STRING Credential)
264 {
265
266 return STATUS_SUCCESS;
267 }
268
269
270 NTSTATUS
271 NTAPI
LsapGetCredentials(_In_ PLUID LogonId,_In_ ULONG AuthenticationPackage,_Inout_ PULONG QueryContext,_In_ BOOLEAN RetrieveAllCredentials,_Inout_ PLSA_STRING PrimaryKeyValue,_Out_ PULONG PrimaryKeyLength,_Out_ PLSA_STRING Credentials)272 LsapGetCredentials(
273 _In_ PLUID LogonId,
274 _In_ ULONG AuthenticationPackage,
275 _Inout_ PULONG QueryContext,
276 _In_ BOOLEAN RetrieveAllCredentials,
277 _Inout_ PLSA_STRING PrimaryKeyValue,
278 _Out_ PULONG PrimaryKeyLength,
279 _Out_ PLSA_STRING Credentials)
280 {
281
282 return STATUS_SUCCESS;
283 }
284
285
286 NTSTATUS
287 NTAPI
LsapDeleteCredential(_In_ PLUID LogonId,_In_ ULONG AuthenticationPackage,_In_ PLSA_STRING PrimaryKeyValue)288 LsapDeleteCredential(
289 _In_ PLUID LogonId,
290 _In_ ULONG AuthenticationPackage,
291 _In_ PLSA_STRING PrimaryKeyValue)
292 {
293
294 return STATUS_SUCCESS;
295 }
296
297
298 NTSTATUS
LsapEnumLogonSessions(IN OUT PLSA_API_MSG RequestMsg)299 LsapEnumLogonSessions(IN OUT PLSA_API_MSG RequestMsg)
300 {
301 OBJECT_ATTRIBUTES ObjectAttributes;
302 HANDLE ProcessHandle = NULL;
303 PLIST_ENTRY SessionEntry;
304 PLSAP_LOGON_SESSION CurrentSession;
305 PLUID SessionList;
306 ULONG i, Length;
307 SIZE_T MemSize;
308 PVOID ClientBaseAddress = NULL;
309 NTSTATUS Status;
310
311 TRACE("LsapEnumLogonSessions(%p)\n", RequestMsg);
312
313 Length = SessionCount * sizeof(LUID);
314 SessionList = RtlAllocateHeap(RtlGetProcessHeap(),
315 HEAP_ZERO_MEMORY,
316 Length);
317 if (SessionList == NULL)
318 return STATUS_INSUFFICIENT_RESOURCES;
319
320 i = 0;
321 SessionEntry = SessionListHead.Flink;
322 while (SessionEntry != &SessionListHead)
323 {
324 CurrentSession = CONTAINING_RECORD(SessionEntry,
325 LSAP_LOGON_SESSION,
326 Entry);
327
328 RtlCopyLuid(&SessionList[i],
329 &CurrentSession->LogonId);
330
331 SessionEntry = SessionEntry->Flink;
332 i++;
333 }
334
335 InitializeObjectAttributes(&ObjectAttributes,
336 NULL,
337 0,
338 NULL,
339 NULL);
340
341 Status = NtOpenProcess(&ProcessHandle,
342 PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
343 &ObjectAttributes,
344 &RequestMsg->h.ClientId);
345 if (!NT_SUCCESS(Status))
346 {
347 TRACE("NtOpenProcess() failed (Status %lx)\n", Status);
348 goto done;
349 }
350
351 TRACE("Length: %lu\n", Length);
352
353 MemSize = Length;
354 Status = NtAllocateVirtualMemory(ProcessHandle,
355 &ClientBaseAddress,
356 0,
357 &MemSize,
358 MEM_COMMIT,
359 PAGE_READWRITE);
360 if (!NT_SUCCESS(Status))
361 {
362 TRACE("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
363 goto done;
364 }
365
366 TRACE("MemSize: %lu\n", MemSize);
367 TRACE("ClientBaseAddress: %p\n", ClientBaseAddress);
368
369 Status = NtWriteVirtualMemory(ProcessHandle,
370 ClientBaseAddress,
371 SessionList,
372 Length,
373 NULL);
374 if (!NT_SUCCESS(Status))
375 {
376 TRACE("NtWriteVirtualMemory() failed (Status %lx)\n", Status);
377 goto done;
378 }
379
380 RequestMsg->EnumLogonSessions.Reply.LogonSessionCount = SessionCount;
381 RequestMsg->EnumLogonSessions.Reply.LogonSessionBuffer = ClientBaseAddress;
382
383 done:
384 if (ProcessHandle != NULL)
385 NtClose(ProcessHandle);
386
387 if (SessionList != NULL)
388 RtlFreeHeap(RtlGetProcessHeap(), 0, SessionList);
389
390 return Status;
391 }
392
393
394 NTSTATUS
LsapGetLogonSessionData(IN OUT PLSA_API_MSG RequestMsg)395 LsapGetLogonSessionData(IN OUT PLSA_API_MSG RequestMsg)
396 {
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 HANDLE ProcessHandle = NULL;
399 PLSAP_LOGON_SESSION Session;
400 PSECURITY_LOGON_SESSION_DATA LocalSessionData;
401 PVOID ClientBaseAddress = NULL;
402 ULONG TotalLength, SidLength = 0;
403 SIZE_T MemSize;
404 PUCHAR Ptr;
405 NTSTATUS Status;
406
407 TRACE("LsapGetLogonSessionData(%p)\n", RequestMsg);
408
409 TRACE("LogonId: %lx\n", RequestMsg->GetLogonSessionData.Request.LogonId.LowPart);
410 Session = LsapGetLogonSession(&RequestMsg->GetLogonSessionData.Request.LogonId);
411 if (Session == NULL)
412 return STATUS_NO_SUCH_LOGON_SESSION;
413
414 /* Calculate the required buffer size */
415 TotalLength = sizeof(SECURITY_LOGON_SESSION_DATA) +
416 Session->UserName.MaximumLength +
417 Session->LogonDomain.MaximumLength +
418 Session->AuthenticationPackage.MaximumLength +
419 Session->LogonServer.MaximumLength +
420 Session->DnsDomainName.MaximumLength +
421 Session->Upn.MaximumLength;
422 if (Session->Sid != NULL)
423 {
424 SidLength = RtlLengthSid(Session->Sid);
425 TotalLength += SidLength;
426 }
427 TRACE("TotalLength: %lu\n", TotalLength);
428
429 /* Allocate the buffer */
430 LocalSessionData = RtlAllocateHeap(RtlGetProcessHeap(),
431 HEAP_ZERO_MEMORY,
432 TotalLength);
433 if (LocalSessionData == NULL)
434 return STATUS_INSUFFICIENT_RESOURCES;
435
436 Ptr = (PUCHAR)((ULONG_PTR)LocalSessionData + sizeof(SECURITY_LOGON_SESSION_DATA));
437 TRACE("LocalSessionData: %p Ptr: %p\n", LocalSessionData, Ptr);
438
439 LocalSessionData->Size = sizeof(SECURITY_LOGON_SESSION_DATA);
440
441 /* Copy the LogonId */
442 RtlCopyLuid(&LocalSessionData->LogonId,
443 &RequestMsg->GetLogonSessionData.Request.LogonId);
444
445 /* Copy the UserName string */
446 LocalSessionData->UserName.Length = Session->UserName.Length;
447 LocalSessionData->UserName.MaximumLength = Session->UserName.MaximumLength;
448 if (Session->UserName.MaximumLength != 0)
449 {
450 RtlCopyMemory(Ptr, Session->UserName.Buffer, Session->UserName.MaximumLength);
451 LocalSessionData->UserName.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
452
453 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->UserName.MaximumLength);
454 }
455
456 /* Copy the LogonDomain string */
457 LocalSessionData->LogonDomain.Length = Session->LogonDomain.Length;
458 LocalSessionData->LogonDomain.MaximumLength = Session->LogonDomain.MaximumLength;
459 if (Session->LogonDomain.MaximumLength != 0)
460 {
461 RtlCopyMemory(Ptr, Session->LogonDomain.Buffer, Session->LogonDomain.MaximumLength);
462 LocalSessionData->LogonDomain.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
463
464 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->LogonDomain.MaximumLength);
465 }
466
467 /* Copy the AuthenticationPackage string */
468 LocalSessionData->AuthenticationPackage.Length = Session->AuthenticationPackage.Length;
469 LocalSessionData->AuthenticationPackage.MaximumLength = Session->AuthenticationPackage.MaximumLength;
470 if (Session->AuthenticationPackage.MaximumLength != 0)
471 {
472 RtlCopyMemory(Ptr, Session->AuthenticationPackage.Buffer, Session->AuthenticationPackage.MaximumLength);
473 LocalSessionData->AuthenticationPackage.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
474
475 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->AuthenticationPackage.MaximumLength);
476 }
477
478 LocalSessionData->LogonType = Session->LogonType;
479 LocalSessionData->Session = 0;
480
481 /* Sid */
482 if (Session->Sid != NULL)
483 {
484 RtlCopyMemory(Ptr, Session->Sid, SidLength);
485 LocalSessionData->Sid = (PSID)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
486
487 Ptr = (PUCHAR)((ULONG_PTR)Ptr + SidLength);
488 }
489
490 /* LogonTime */
491 LocalSessionData->LogonTime.QuadPart = Session->LogonTime.QuadPart;
492
493 /* Copy the LogonServer string */
494 LocalSessionData->LogonServer.Length = Session->LogonServer.Length;
495 LocalSessionData->LogonServer.MaximumLength = Session->LogonServer.MaximumLength;
496 if (Session->LogonServer.MaximumLength != 0)
497 {
498 RtlCopyMemory(Ptr, Session->LogonServer.Buffer, Session->LogonServer.MaximumLength);
499 LocalSessionData->LogonServer.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
500
501 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->LogonServer.MaximumLength);
502 }
503
504 /* Copy the DnsDomainName string */
505 LocalSessionData->DnsDomainName.Length = Session->DnsDomainName.Length;
506 LocalSessionData->DnsDomainName.MaximumLength = Session->DnsDomainName.MaximumLength;
507 if (Session->DnsDomainName.MaximumLength != 0)
508 {
509 RtlCopyMemory(Ptr, Session->DnsDomainName.Buffer, Session->DnsDomainName.MaximumLength);
510 LocalSessionData->DnsDomainName.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
511
512 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->DnsDomainName.MaximumLength);
513 }
514
515 /* Copy the Upn string */
516 LocalSessionData->Upn.Length = Session->Upn.Length;
517 LocalSessionData->Upn.MaximumLength = Session->Upn.MaximumLength;
518 if (Session->Upn.MaximumLength != 0)
519 {
520 RtlCopyMemory(Ptr, Session->Upn.Buffer, Session->Upn.MaximumLength);
521 LocalSessionData->Upn.Buffer = (PWSTR)((ULONG_PTR)Ptr - (ULONG_PTR)LocalSessionData);
522
523 Ptr = (PUCHAR)((ULONG_PTR)Ptr + Session->Upn.MaximumLength);
524 }
525
526 InitializeObjectAttributes(&ObjectAttributes,
527 NULL,
528 0,
529 NULL,
530 NULL);
531
532 Status = NtOpenProcess(&ProcessHandle,
533 PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION,
534 &ObjectAttributes,
535 &RequestMsg->h.ClientId);
536 if (!NT_SUCCESS(Status))
537 {
538 TRACE("NtOpenProcess() failed (Status %lx)\n", Status);
539 goto done;
540 }
541
542 MemSize = TotalLength;
543 Status = NtAllocateVirtualMemory(ProcessHandle,
544 &ClientBaseAddress,
545 0,
546 &MemSize,
547 MEM_COMMIT,
548 PAGE_READWRITE);
549 if (!NT_SUCCESS(Status))
550 {
551 TRACE("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
552 goto done;
553 }
554
555 TRACE("MemSize: %lu\n", MemSize);
556 TRACE("ClientBaseAddress: %p\n", ClientBaseAddress);
557
558 Status = NtWriteVirtualMemory(ProcessHandle,
559 ClientBaseAddress,
560 LocalSessionData,
561 TotalLength,
562 NULL);
563 if (!NT_SUCCESS(Status))
564 {
565 TRACE("NtWriteVirtualMemory() failed (Status %lx)\n", Status);
566 goto done;
567 }
568
569 RequestMsg->GetLogonSessionData.Reply.SessionDataBuffer = ClientBaseAddress;
570
571 done:
572 if (ProcessHandle != NULL)
573 NtClose(ProcessHandle);
574
575 if (LocalSessionData != NULL)
576 RtlFreeHeap(RtlGetProcessHeap(), 0, LocalSessionData);
577
578 return Status;
579 }
580
581 /* EOF */
582