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