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