1 /* 2 * PROJECT: Authentication Package DLL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/msv1_0/msv1_0.c 5 * PURPOSE: Main file 6 * COPYRIGHT: Copyright 2013 Eric Kohl 7 */ 8 9 /* INCLUDES ****************************************************************/ 10 11 #include "precomp.h" 12 13 WINE_DEFAULT_DEBUG_CHANNEL(msv1_0); 14 15 16 /* FUNCTIONS ***************************************************************/ 17 18 static 19 NTSTATUS 20 BuildInteractiveProfileBuffer(IN PLSA_CLIENT_REQUEST ClientRequest, 21 IN PSAMPR_USER_INFO_BUFFER UserInfo, 22 IN PWSTR ComputerName, 23 OUT PMSV1_0_INTERACTIVE_PROFILE *ProfileBuffer, 24 OUT PULONG ProfileBufferLength) 25 { 26 PMSV1_0_INTERACTIVE_PROFILE LocalBuffer = NULL; 27 PVOID ClientBaseAddress = NULL; 28 LPWSTR Ptr; 29 ULONG BufferLength; 30 USHORT ComputerNameLength; 31 NTSTATUS Status = STATUS_SUCCESS; 32 33 *ProfileBuffer = NULL; 34 *ProfileBufferLength = 0; 35 36 if (UIntPtrToUShort(wcslen(ComputerName), &ComputerNameLength) != S_OK) 37 { 38 return STATUS_INVALID_PARAMETER; 39 } 40 41 BufferLength = sizeof(MSV1_0_INTERACTIVE_PROFILE) + 42 UserInfo->All.FullName.Length + sizeof(WCHAR) + 43 UserInfo->All.HomeDirectory.Length + sizeof(WCHAR) + 44 UserInfo->All.HomeDirectoryDrive.Length + sizeof(WCHAR) + 45 UserInfo->All.ScriptPath.Length + sizeof(WCHAR) + 46 UserInfo->All.ProfilePath.Length + sizeof(WCHAR) + 47 ((ComputerNameLength + 3) * sizeof(WCHAR)); 48 49 LocalBuffer = DispatchTable.AllocateLsaHeap(BufferLength); 50 if (LocalBuffer == NULL) 51 { 52 TRACE("Failed to allocate the local buffer!\n"); 53 Status = STATUS_INSUFFICIENT_RESOURCES; 54 goto done; 55 } 56 57 Status = DispatchTable.AllocateClientBuffer(ClientRequest, 58 BufferLength, 59 &ClientBaseAddress); 60 if (!NT_SUCCESS(Status)) 61 { 62 TRACE("DispatchTable.AllocateClientBuffer failed (Status 0x%08lx)\n", Status); 63 goto done; 64 } 65 66 TRACE("ClientBaseAddress: %p\n", ClientBaseAddress); 67 68 Ptr = (LPWSTR)((ULONG_PTR)LocalBuffer + sizeof(MSV1_0_INTERACTIVE_PROFILE)); 69 70 LocalBuffer->MessageType = MsV1_0InteractiveProfile; 71 LocalBuffer->LogonCount = UserInfo->All.LogonCount; 72 LocalBuffer->BadPasswordCount = UserInfo->All.BadPasswordCount; 73 74 LocalBuffer->LogonTime.LowPart = UserInfo->All.LastLogon.LowPart; 75 LocalBuffer->LogonTime.HighPart = UserInfo->All.LastLogon.HighPart; 76 77 LocalBuffer->LogoffTime.LowPart = UserInfo->All.AccountExpires.LowPart; 78 LocalBuffer->LogoffTime.HighPart = UserInfo->All.AccountExpires.HighPart; 79 80 LocalBuffer->KickOffTime.LowPart = UserInfo->All.AccountExpires.LowPart; 81 LocalBuffer->KickOffTime.HighPart = UserInfo->All.AccountExpires.HighPart; 82 83 LocalBuffer->PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart; 84 LocalBuffer->PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart; 85 86 LocalBuffer->PasswordCanChange.LowPart = UserInfo->All.PasswordCanChange.LowPart; 87 LocalBuffer->PasswordCanChange.HighPart = UserInfo->All.PasswordCanChange.HighPart; 88 89 LocalBuffer->PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart; 90 LocalBuffer->PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart; 91 92 LocalBuffer->LogonScript.Length = UserInfo->All.ScriptPath.Length; 93 LocalBuffer->LogonScript.MaximumLength = UserInfo->All.ScriptPath.Length + sizeof(WCHAR); 94 LocalBuffer->LogonScript.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 95 memcpy(Ptr, 96 UserInfo->All.ScriptPath.Buffer, 97 UserInfo->All.ScriptPath.Length); 98 99 Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->LogonScript.MaximumLength); 100 101 LocalBuffer->HomeDirectory.Length = UserInfo->All.HomeDirectory.Length; 102 LocalBuffer->HomeDirectory.MaximumLength = UserInfo->All.HomeDirectory.Length + sizeof(WCHAR); 103 LocalBuffer->HomeDirectory.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 104 memcpy(Ptr, 105 UserInfo->All.HomeDirectory.Buffer, 106 UserInfo->All.HomeDirectory.Length); 107 108 Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->HomeDirectory.MaximumLength); 109 110 LocalBuffer->FullName.Length = UserInfo->All.FullName.Length; 111 LocalBuffer->FullName.MaximumLength = UserInfo->All.FullName.Length + sizeof(WCHAR); 112 LocalBuffer->FullName.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 113 memcpy(Ptr, 114 UserInfo->All.FullName.Buffer, 115 UserInfo->All.FullName.Length); 116 TRACE("FullName.Buffer: %p\n", LocalBuffer->FullName.Buffer); 117 118 Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->FullName.MaximumLength); 119 120 LocalBuffer->ProfilePath.Length = UserInfo->All.ProfilePath.Length; 121 LocalBuffer->ProfilePath.MaximumLength = UserInfo->All.ProfilePath.Length + sizeof(WCHAR); 122 LocalBuffer->ProfilePath.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 123 memcpy(Ptr, 124 UserInfo->All.ProfilePath.Buffer, 125 UserInfo->All.ProfilePath.Length); 126 127 Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->ProfilePath.MaximumLength); 128 129 LocalBuffer->HomeDirectoryDrive.Length = UserInfo->All.HomeDirectoryDrive.Length; 130 LocalBuffer->HomeDirectoryDrive.MaximumLength = UserInfo->All.HomeDirectoryDrive.Length + sizeof(WCHAR); 131 LocalBuffer->HomeDirectoryDrive.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 132 memcpy(Ptr, 133 UserInfo->All.HomeDirectoryDrive.Buffer, 134 UserInfo->All.HomeDirectoryDrive.Length); 135 136 Ptr = (LPWSTR)((ULONG_PTR)Ptr + LocalBuffer->HomeDirectoryDrive.MaximumLength); 137 138 LocalBuffer->LogonServer.Length = (ComputerNameLength + 2) * sizeof(WCHAR); 139 LocalBuffer->LogonServer.MaximumLength = LocalBuffer->LogonServer.Length + sizeof(WCHAR); 140 LocalBuffer->LogonServer.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer); 141 wcscpy(Ptr, L"\\"); 142 wcscat(Ptr, ComputerName); 143 144 LocalBuffer->UserFlags = 0; 145 146 Status = DispatchTable.CopyToClientBuffer(ClientRequest, 147 BufferLength, 148 ClientBaseAddress, 149 LocalBuffer); 150 if (!NT_SUCCESS(Status)) 151 { 152 TRACE("DispatchTable.CopyToClientBuffer failed (Status 0x%08lx)\n", Status); 153 goto done; 154 } 155 156 *ProfileBuffer = (PMSV1_0_INTERACTIVE_PROFILE)ClientBaseAddress; 157 *ProfileBufferLength = BufferLength; 158 159 done: 160 if (LocalBuffer != NULL) 161 DispatchTable.FreeLsaHeap(LocalBuffer); 162 163 if (!NT_SUCCESS(Status)) 164 { 165 if (ClientBaseAddress != NULL) 166 DispatchTable.FreeClientBuffer(ClientRequest, 167 ClientBaseAddress); 168 } 169 170 return Status; 171 } 172 173 174 static 175 NTSTATUS 176 BuildLm20LogonProfileBuffer( 177 _In_ PLSA_CLIENT_REQUEST ClientRequest, 178 _In_ PSAMPR_USER_INFO_BUFFER UserInfo, 179 _In_ PLSA_SAM_PWD_DATA LogonPwdData, 180 _Out_ PMSV1_0_LM20_LOGON_PROFILE *ProfileBuffer, 181 _Out_ PULONG ProfileBufferLength) 182 { 183 PMSV1_0_LM20_LOGON_PROFILE LocalBuffer; 184 NTLM_CLIENT_BUFFER Buffer; 185 PBYTE PtrOffset; 186 ULONG BufferLength; 187 NTSTATUS Status = STATUS_SUCCESS; 188 UNICODE_STRING ComputerNameUCS; 189 190 *ProfileBuffer = NULL; 191 *ProfileBufferLength = 0; 192 193 if (!NtlmUStrAlloc(&ComputerNameUCS, LogonPwdData->ComputerName->Length + sizeof(WCHAR) * 3, 0)) 194 { 195 Status = STATUS_INSUFFICIENT_RESOURCES; 196 goto done; 197 } 198 Status = RtlAppendUnicodeToString(&ComputerNameUCS, L"\\\\"); 199 if (!NT_SUCCESS(Status)) 200 { 201 ERR("RtlAppendUnicodeToString failed 0x%lx\n", Status); 202 goto done; 203 } 204 Status = RtlAppendUnicodeStringToString(&ComputerNameUCS, LogonPwdData->ComputerName); 205 if (!NT_SUCCESS(Status)) 206 { 207 ERR("RtlAppendUnicodeStringToString failed 0x%lx\n", Status); 208 goto done; 209 } 210 211 BufferLength = sizeof(MSV1_0_LM20_LOGON_PROFILE) + ComputerNameUCS.Length + sizeof(WCHAR); 212 213 Status = NtlmAllocateClientBuffer(ClientRequest, BufferLength, &Buffer); 214 if (!NT_SUCCESS(Status)) 215 { 216 TRACE("DispatchTable.AllocateClientBuffer failed (Status 0x%08lx)\n", Status); 217 goto done; 218 } 219 220 TRACE("ClientBaseAddress: %p\n", Buffer.ClientBaseAddress); 221 222 LocalBuffer = (PMSV1_0_LM20_LOGON_PROFILE)Buffer.LocalBuffer; 223 PtrOffset = (PBYTE)(LocalBuffer + 1); 224 225 LocalBuffer->MessageType = MsV1_0Lm20LogonProfile; 226 LocalBuffer->KickOffTime.LowPart = UserInfo->All.AccountExpires.LowPart; 227 LocalBuffer->KickOffTime.HighPart = UserInfo->All.AccountExpires.HighPart; 228 LocalBuffer->LogoffTime.LowPart = UserInfo->All.AccountExpires.LowPart; 229 LocalBuffer->LogoffTime.HighPart = UserInfo->All.AccountExpires.HighPart; 230 231 memcpy(LocalBuffer->UserSessionKey, 232 &LogonPwdData->UserSessionKey, 233 MSV1_0_USER_SESSION_KEY_LENGTH); 234 235 //FIXME: Set Domainname if we domain joined 236 // what to do if not? WORKGROUP 237 RtlInitUnicodeString(&LocalBuffer->LogonDomainName, NULL); 238 239 memcpy(LocalBuffer->LanmanSessionKey, 240 &LogonPwdData->LanmanSessionKey, 241 MSV1_0_LANMAN_SESSION_KEY_LENGTH); 242 243 if (!NtlmUStrWriteToStruct(LocalBuffer, 244 BufferLength, 245 &LocalBuffer->LogonServer, 246 &ComputerNameUCS, 247 &PtrOffset, 248 TRUE)) 249 { 250 ERR("NtlmStructWriteUCS failed.\n"); 251 Status = ERROR_INTERNAL_ERROR; 252 goto done; 253 } 254 /* not supported */ 255 RtlInitUnicodeString(&LocalBuffer->UserParameters, NULL); 256 /* Build user flags */ 257 LocalBuffer->UserFlags = 0x0; 258 if (LogonPwdData->LogonType == NetLogonLmKey) 259 LocalBuffer->UserFlags |= LOGON_USED_LM_PASSWORD; 260 261 /* copy data to client buffer */ 262 Status = NtlmCopyToClientBuffer(ClientRequest, BufferLength, &Buffer); 263 if (!NT_SUCCESS(Status)) 264 { 265 TRACE("DispatchTable.CopyToClientBuffer failed (Status 0x%08lx)\n", Status); 266 goto done; 267 } 268 269 *ProfileBuffer = (PMSV1_0_LM20_LOGON_PROFILE)Buffer.ClientBaseAddress; 270 *ProfileBufferLength = BufferLength; 271 done: 272 /* On success Buffer.ClientBaseAddress will not be free */ 273 NtlmFreeClientBuffer(ClientRequest, !NT_SUCCESS(Status), &Buffer); 274 NtlmUStrFree(&ComputerNameUCS); 275 return Status; 276 } 277 278 static 279 PSID 280 AppendRidToSid(PSID SrcSid, 281 ULONG Rid) 282 { 283 PSID DstSid = NULL; 284 UCHAR RidCount; 285 286 RidCount = *RtlSubAuthorityCountSid(SrcSid); 287 if (RidCount >= 8) 288 return NULL; 289 290 DstSid = DispatchTable.AllocateLsaHeap(RtlLengthRequiredSid(RidCount + 1)); 291 if (DstSid == NULL) 292 return NULL; 293 294 RtlCopyMemory(DstSid, 295 SrcSid, 296 RtlLengthRequiredSid(RidCount)); 297 298 *RtlSubAuthorityCountSid(DstSid) = RidCount + 1; 299 *RtlSubAuthoritySid(DstSid, RidCount) = Rid; 300 301 return DstSid; 302 } 303 304 305 static 306 NTSTATUS 307 BuildTokenUser(OUT PTOKEN_USER User, 308 IN PSID AccountDomainSid, 309 IN ULONG RelativeId) 310 { 311 User->User.Sid = AppendRidToSid(AccountDomainSid, 312 RelativeId); 313 if (User->User.Sid == NULL) 314 { 315 ERR("Could not create the user SID\n"); 316 return STATUS_INSUFFICIENT_RESOURCES; 317 } 318 319 User->User.Attributes = 0; 320 321 return STATUS_SUCCESS; 322 } 323 324 325 static 326 NTSTATUS 327 BuildTokenPrimaryGroup(OUT PTOKEN_PRIMARY_GROUP PrimaryGroup, 328 IN PSID AccountDomainSid, 329 IN ULONG RelativeId) 330 { 331 PrimaryGroup->PrimaryGroup = AppendRidToSid(AccountDomainSid, 332 RelativeId); 333 if (PrimaryGroup->PrimaryGroup == NULL) 334 { 335 ERR("Could not create the primary group SID\n"); 336 return STATUS_INSUFFICIENT_RESOURCES; 337 } 338 339 return STATUS_SUCCESS; 340 } 341 342 343 static 344 NTSTATUS 345 BuildTokenGroups(OUT PTOKEN_GROUPS *Groups, 346 IN PSID AccountDomainSid, 347 IN ULONG RelativeId, 348 IN BOOL SpecialAccount) 349 { 350 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; 351 PTOKEN_GROUPS TokenGroups; 352 DWORD GroupCount = 0; 353 DWORD MaxGroups = 2; 354 PSID Sid; 355 NTSTATUS Status = STATUS_SUCCESS; 356 357 if (SpecialAccount) 358 MaxGroups++; 359 360 TokenGroups = DispatchTable.AllocateLsaHeap(sizeof(TOKEN_GROUPS) + 361 MaxGroups * sizeof(SID_AND_ATTRIBUTES)); 362 if (TokenGroups == NULL) 363 { 364 return STATUS_INSUFFICIENT_RESOURCES; 365 } 366 367 if (SpecialAccount) 368 { 369 /* Self */ 370 Sid = AppendRidToSid(AccountDomainSid, RelativeId); 371 if (Sid == NULL) 372 { 373 374 } 375 376 TokenGroups->Groups[GroupCount].Sid = Sid; 377 TokenGroups->Groups[GroupCount].Attributes = 378 SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; 379 GroupCount++; 380 381 /* Member of 'Users' alias */ 382 RtlAllocateAndInitializeSid(&SystemAuthority, 383 2, 384 SECURITY_BUILTIN_DOMAIN_RID, 385 DOMAIN_ALIAS_RID_USERS, 386 SECURITY_NULL_RID, 387 SECURITY_NULL_RID, 388 SECURITY_NULL_RID, 389 SECURITY_NULL_RID, 390 SECURITY_NULL_RID, 391 SECURITY_NULL_RID, 392 &Sid); 393 TokenGroups->Groups[GroupCount].Sid = Sid; 394 TokenGroups->Groups[GroupCount].Attributes = 395 SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; 396 GroupCount++; 397 } 398 else 399 { 400 /* Member of the domains users group */ 401 Sid = AppendRidToSid(AccountDomainSid, DOMAIN_GROUP_RID_USERS); 402 if (Sid == NULL) 403 { 404 405 } 406 407 TokenGroups->Groups[GroupCount].Sid = Sid; 408 TokenGroups->Groups[GroupCount].Attributes = 409 SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; 410 GroupCount++; 411 } 412 413 /* Member of 'Authenticated users' */ 414 RtlAllocateAndInitializeSid(&SystemAuthority, 415 1, 416 SECURITY_AUTHENTICATED_USER_RID, 417 SECURITY_NULL_RID, 418 SECURITY_NULL_RID, 419 SECURITY_NULL_RID, 420 SECURITY_NULL_RID, 421 SECURITY_NULL_RID, 422 SECURITY_NULL_RID, 423 SECURITY_NULL_RID, 424 &Sid); 425 TokenGroups->Groups[GroupCount].Sid = Sid; 426 TokenGroups->Groups[GroupCount].Attributes = 427 SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY; 428 GroupCount++; 429 430 TokenGroups->GroupCount = GroupCount; 431 ASSERT(TokenGroups->GroupCount <= MaxGroups); 432 433 *Groups = TokenGroups; 434 435 return Status; 436 } 437 438 439 static 440 NTSTATUS 441 BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation, 442 PRPC_SID AccountDomainSid, 443 PSAMPR_USER_INFO_BUFFER UserInfo, 444 BOOL SpecialAccount) 445 { 446 PLSA_TOKEN_INFORMATION_V1 Buffer = NULL; 447 ULONG i; 448 NTSTATUS Status = STATUS_SUCCESS; 449 450 Buffer = DispatchTable.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1)); 451 if (Buffer == NULL) 452 { 453 WARN("Failed to allocate the local buffer!\n"); 454 Status = STATUS_INSUFFICIENT_RESOURCES; 455 goto done; 456 } 457 458 Buffer->ExpirationTime.LowPart = UserInfo->All.AccountExpires.LowPart; 459 Buffer->ExpirationTime.HighPart = UserInfo->All.AccountExpires.HighPart; 460 461 Status = BuildTokenUser(&Buffer->User, 462 (PSID)AccountDomainSid, 463 UserInfo->All.UserId); 464 if (!NT_SUCCESS(Status)) 465 { 466 WARN("BuildTokenUser() failed (Status 0x%08lx)\n", Status); 467 goto done; 468 } 469 470 Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup, 471 (PSID)AccountDomainSid, 472 UserInfo->All.PrimaryGroupId); 473 if (!NT_SUCCESS(Status)) 474 { 475 WARN("BuildTokenPrimaryGroup() failed (Status 0x%08lx)\n", Status); 476 goto done; 477 } 478 479 Status = BuildTokenGroups(&Buffer->Groups, 480 (PSID)AccountDomainSid, 481 UserInfo->All.UserId, 482 SpecialAccount); 483 if (!NT_SUCCESS(Status)) 484 { 485 WARN("BuildTokenGroups() failed (Status 0x%08lx)\n", Status); 486 goto done; 487 } 488 489 *TokenInformation = Buffer; 490 491 done: 492 if (!NT_SUCCESS(Status)) 493 { 494 if (Buffer != NULL) 495 { 496 if (Buffer->User.User.Sid != NULL) 497 DispatchTable.FreeLsaHeap(Buffer->User.User.Sid); 498 499 if (Buffer->Groups != NULL) 500 { 501 for (i = 0; i < Buffer->Groups->GroupCount; i++) 502 { 503 if (Buffer->Groups->Groups[i].Sid != NULL) 504 DispatchTable.FreeLsaHeap(Buffer->Groups->Groups[i].Sid); 505 } 506 507 DispatchTable.FreeLsaHeap(Buffer->Groups); 508 } 509 510 if (Buffer->PrimaryGroup.PrimaryGroup != NULL) 511 DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup); 512 513 if (Buffer->DefaultDacl.DefaultDacl != NULL) 514 DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl); 515 516 DispatchTable.FreeLsaHeap(Buffer); 517 } 518 } 519 520 return Status; 521 } 522 523 524 static 525 NTSTATUS 526 MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest, 527 IN PVOID ProtocolSubmitBuffer, 528 IN PVOID ClientBufferBase, 529 IN ULONG SubmitBufferLength, 530 OUT PVOID *ProtocolReturnBuffer, 531 OUT PULONG ReturnBufferLength, 532 OUT PNTSTATUS ProtocolStatus) 533 { 534 NTSTATUS Status; 535 PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer; 536 ULONG_PTR PtrOffset; 537 538 SAMPR_HANDLE ServerHandle = NULL; 539 SAMPR_HANDLE DomainHandle = NULL; 540 SAMPR_HANDLE UserHandle = NULL; 541 PRPC_SID DomainSid = NULL; 542 RPC_UNICODE_STRING Names[1]; 543 SAMPR_ULONG_ARRAY RelativeIds = {0, NULL}; 544 SAMPR_ULONG_ARRAY Use = {0, NULL}; 545 546 ENCRYPTED_NT_OWF_PASSWORD OldNtPassword; 547 ENCRYPTED_NT_OWF_PASSWORD NewNtPassword; 548 ENCRYPTED_LM_OWF_PASSWORD OldLmPassword; 549 ENCRYPTED_LM_OWF_PASSWORD NewLmPassword; 550 OEM_STRING LmPwdString; 551 CHAR LmPwdBuffer[15]; 552 BOOLEAN OldLmPasswordPresent = FALSE; 553 BOOLEAN NewLmPasswordPresent = FALSE; 554 555 ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm; 556 ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm; 557 ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt; 558 ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt; 559 PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL; 560 PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL; 561 562 TRACE("MsvpChangePassword()\n"); 563 564 /* Parameters validation */ 565 566 if (SubmitBufferLength < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST)) 567 { 568 ERR("Invalid SubmitBufferLength %lu\n", SubmitBufferLength); 569 return STATUS_INVALID_PARAMETER; 570 } 571 572 RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer; 573 574 /* Fix-up pointers in the request buffer info */ 575 PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase; 576 577 Status = RtlValidateUnicodeString(0, &RequestBuffer->DomainName); 578 if (!NT_SUCCESS(Status)) 579 return STATUS_INVALID_PARAMETER; 580 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 581 RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset); 582 RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length; 583 584 Status = RtlValidateUnicodeString(0, &RequestBuffer->AccountName); 585 if (!NT_SUCCESS(Status)) 586 return STATUS_INVALID_PARAMETER; 587 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 588 RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset); 589 RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length; 590 591 Status = RtlValidateUnicodeString(0, &RequestBuffer->OldPassword); 592 if (!NT_SUCCESS(Status)) 593 return STATUS_INVALID_PARAMETER; 594 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 595 RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset); 596 RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length; 597 598 Status = RtlValidateUnicodeString(0, &RequestBuffer->NewPassword); 599 if (!NT_SUCCESS(Status)) 600 return STATUS_INVALID_PARAMETER; 601 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 602 RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset); 603 RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length; 604 605 TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer); 606 TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer); 607 TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer); 608 TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer); 609 610 /* Connect to the SAM server */ 611 Status = SamIConnect(NULL, 612 &ServerHandle, 613 SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN, 614 TRUE); 615 if (!NT_SUCCESS(Status)) 616 { 617 TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status); 618 goto done; 619 } 620 621 /* Get the domain SID */ 622 Status = SamrLookupDomainInSamServer(ServerHandle, 623 (PRPC_UNICODE_STRING)&RequestBuffer->DomainName, 624 &DomainSid); 625 if (!NT_SUCCESS(Status)) 626 { 627 TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status); 628 goto done; 629 } 630 631 /* Open the domain */ 632 Status = SamrOpenDomain(ServerHandle, 633 DOMAIN_LOOKUP, 634 DomainSid, 635 &DomainHandle); 636 if (!NT_SUCCESS(Status)) 637 { 638 TRACE("SamrOpenDomain failed (Status %08lx)\n", Status); 639 goto done; 640 } 641 642 Names[0].Length = RequestBuffer->AccountName.Length; 643 Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength; 644 Names[0].Buffer = RequestBuffer->AccountName.Buffer; 645 646 /* Try to get the RID for the user name */ 647 Status = SamrLookupNamesInDomain(DomainHandle, 648 1, 649 Names, 650 &RelativeIds, 651 &Use); 652 if (!NT_SUCCESS(Status)) 653 { 654 TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status); 655 Status = STATUS_NO_SUCH_USER; 656 goto done; 657 } 658 659 /* Fail, if it is not a user account */ 660 if (Use.Element[0] != SidTypeUser) 661 { 662 TRACE("Account is not a user account!\n"); 663 Status = STATUS_NO_SUCH_USER; 664 goto done; 665 } 666 667 /* Open the user object */ 668 Status = SamrOpenUser(DomainHandle, 669 USER_CHANGE_PASSWORD, 670 RelativeIds.Element[0], 671 &UserHandle); 672 if (!NT_SUCCESS(Status)) 673 { 674 TRACE("SamrOpenUser failed (Status %08lx)\n", Status); 675 goto done; 676 } 677 678 679 /* Calculate the NT hash for the old password */ 680 Status = SystemFunction007(&RequestBuffer->OldPassword, 681 (LPBYTE)&OldNtPassword); 682 if (!NT_SUCCESS(Status)) 683 { 684 TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status); 685 goto done; 686 } 687 688 /* Calculate the NT hash for the new password */ 689 Status = SystemFunction007(&RequestBuffer->NewPassword, 690 (LPBYTE)&NewNtPassword); 691 if (!NT_SUCCESS(Status)) 692 { 693 TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status); 694 goto done; 695 } 696 697 /* Calculate the LM password and hash for the old password */ 698 LmPwdString.Length = 15; 699 LmPwdString.MaximumLength = 15; 700 LmPwdString.Buffer = LmPwdBuffer; 701 ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength); 702 703 Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString, 704 &RequestBuffer->OldPassword, 705 FALSE); 706 if (NT_SUCCESS(Status)) 707 { 708 /* Calculate the LM hash value of the password */ 709 Status = SystemFunction006(LmPwdString.Buffer, 710 (LPSTR)&OldLmPassword); 711 if (NT_SUCCESS(Status)) 712 { 713 OldLmPasswordPresent = TRUE; 714 } 715 } 716 717 /* Calculate the LM password and hash for the new password */ 718 LmPwdString.Length = 15; 719 LmPwdString.MaximumLength = 15; 720 LmPwdString.Buffer = LmPwdBuffer; 721 ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength); 722 723 Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString, 724 &RequestBuffer->NewPassword, 725 FALSE); 726 if (NT_SUCCESS(Status)) 727 { 728 /* Calculate the LM hash value of the password */ 729 Status = SystemFunction006(LmPwdString.Buffer, 730 (LPSTR)&NewLmPassword); 731 if (NT_SUCCESS(Status)) 732 { 733 NewLmPasswordPresent = TRUE; 734 } 735 } 736 737 /* Encrypt the old and new LM passwords, if they exist */ 738 if (OldLmPasswordPresent && NewLmPasswordPresent) 739 { 740 /* Encrypt the old LM password */ 741 Status = SystemFunction012((const BYTE *)&OldLmPassword, 742 (const BYTE *)&NewLmPassword, 743 (LPBYTE)&OldLmEncryptedWithNewLm); 744 if (!NT_SUCCESS(Status)) 745 { 746 TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); 747 goto done; 748 } 749 750 /* Encrypt the new LM password */ 751 Status = SystemFunction012((const BYTE *)&NewLmPassword, 752 (const BYTE *)&OldLmPassword, 753 (LPBYTE)&NewLmEncryptedWithOldLm); 754 if (!NT_SUCCESS(Status)) 755 { 756 TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); 757 goto done; 758 } 759 760 pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm; 761 pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm; 762 } 763 764 /* Encrypt the old NT password */ 765 Status = SystemFunction012((const BYTE *)&OldNtPassword, 766 (const BYTE *)&NewNtPassword, 767 (LPBYTE)&OldNtEncryptedWithNewNt); 768 if (!NT_SUCCESS(Status)) 769 { 770 TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); 771 goto done; 772 } 773 774 /* Encrypt the new NT password */ 775 Status = SystemFunction012((const BYTE *)&NewNtPassword, 776 (const BYTE *)&OldNtPassword, 777 (LPBYTE)&NewNtEncryptedWithOldNt); 778 if (!NT_SUCCESS(Status)) 779 { 780 TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status); 781 goto done; 782 } 783 784 /* Change the password */ 785 Status = SamrChangePasswordUser(UserHandle, 786 OldLmPasswordPresent && NewLmPasswordPresent, 787 pOldLmEncryptedWithNewLm, 788 pNewLmEncryptedWithOldLm, 789 TRUE, 790 &OldNtEncryptedWithNewNt, 791 &NewNtEncryptedWithOldNt, 792 FALSE, 793 NULL, 794 FALSE, 795 NULL); 796 if (!NT_SUCCESS(Status)) 797 { 798 TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status); 799 goto done; 800 } 801 802 done: 803 if (UserHandle != NULL) 804 SamrCloseHandle(&UserHandle); 805 806 SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds); 807 SamIFree_SAMPR_ULONG_ARRAY(&Use); 808 809 if (DomainHandle != NULL) 810 SamrCloseHandle(&DomainHandle); 811 812 if (DomainSid != NULL) 813 SamIFreeVoid(DomainSid); 814 815 if (ServerHandle != NULL) 816 SamrCloseHandle(&ServerHandle); 817 818 return Status; 819 } 820 821 822 /* 823 * @unimplemented 824 */ 825 NTSTATUS 826 NTAPI 827 LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest, 828 IN PVOID ProtocolSubmitBuffer, 829 IN PVOID ClientBufferBase, 830 IN ULONG SubmitBufferLength, 831 OUT PVOID *ProtocolReturnBuffer, 832 OUT PULONG ReturnBufferLength, 833 OUT PNTSTATUS ProtocolStatus) 834 { 835 NTSTATUS Status; 836 MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType; 837 838 TRACE("LsaApCallPackage()\n"); 839 840 if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE)) 841 return STATUS_INVALID_PARAMETER; 842 843 MessageType = *((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer); 844 845 *ProtocolReturnBuffer = NULL; 846 *ReturnBufferLength = 0; 847 848 switch (MessageType) 849 { 850 case MsV1_0Lm20ChallengeRequest: 851 case MsV1_0Lm20GetChallengeResponse: 852 Status = STATUS_NOT_IMPLEMENTED; 853 break; 854 855 case MsV1_0EnumerateUsers: 856 case MsV1_0GetUserInfo: 857 case MsV1_0ReLogonUsers: 858 Status = STATUS_INVALID_PARAMETER; 859 break; 860 861 case MsV1_0ChangePassword: 862 Status = MsvpChangePassword(ClientRequest, 863 ProtocolSubmitBuffer, 864 ClientBufferBase, 865 SubmitBufferLength, 866 ProtocolReturnBuffer, 867 ReturnBufferLength, 868 ProtocolStatus); 869 break; 870 871 case MsV1_0ChangeCachedPassword: 872 case MsV1_0GenericPassthrough: 873 case MsV1_0CacheLogon: 874 case MsV1_0SubAuth: 875 case MsV1_0DeriveCredential: 876 case MsV1_0CacheLookup: 877 Status = STATUS_NOT_IMPLEMENTED; 878 break; 879 880 default: 881 return STATUS_INVALID_PARAMETER; 882 } 883 884 return Status; 885 } 886 887 888 /* 889 * @unimplemented 890 */ 891 NTSTATUS 892 NTAPI 893 LsaApCallPackagePassthrough(IN PLSA_CLIENT_REQUEST ClientRequest, 894 IN PVOID ProtocolSubmitBuffer, 895 IN PVOID ClientBufferBase, 896 IN ULONG SubmitBufferLength, 897 OUT PVOID *ProtocolReturnBuffer, 898 OUT PULONG ReturnBufferLength, 899 OUT PNTSTATUS ProtocolStatus) 900 { 901 TRACE("LsaApCallPackagePassthrough()\n"); 902 return STATUS_NOT_IMPLEMENTED; 903 } 904 905 906 /* 907 * @implemented 908 */ 909 NTSTATUS 910 NTAPI 911 LsaApCallPackageUntrusted(IN PLSA_CLIENT_REQUEST ClientRequest, 912 IN PVOID ProtocolSubmitBuffer, 913 IN PVOID ClientBufferBase, 914 IN ULONG SubmitBufferLength, 915 OUT PVOID *ProtocolReturnBuffer, 916 OUT PULONG ReturnBufferLength, 917 OUT PNTSTATUS ProtocolStatus) 918 { 919 ULONG MessageType; 920 NTSTATUS Status; 921 922 TRACE("LsaApCallPackageUntrusted()\n"); 923 924 if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE)) 925 return STATUS_INVALID_PARAMETER; 926 927 MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer); 928 929 *ProtocolReturnBuffer = NULL; 930 *ReturnBufferLength = 0; 931 932 if (MessageType == MsV1_0ChangePassword) 933 Status = MsvpChangePassword(ClientRequest, 934 ProtocolSubmitBuffer, 935 ClientBufferBase, 936 SubmitBufferLength, 937 ProtocolReturnBuffer, 938 ReturnBufferLength, 939 ProtocolStatus); 940 else 941 Status = STATUS_ACCESS_DENIED; 942 943 return Status; 944 } 945 946 947 /* 948 * @implemented 949 */ 950 NTSTATUS 951 NTAPI 952 LsaApInitializePackage(IN ULONG AuthenticationPackageId, 953 IN PLSA_DISPATCH_TABLE LsaDispatchTable, 954 IN PLSA_STRING Database OPTIONAL, 955 IN PLSA_STRING Confidentiality OPTIONAL, 956 OUT PLSA_STRING *AuthenticationPackageName) 957 { 958 PANSI_STRING NameString; 959 PCHAR NameBuffer; 960 961 TRACE("LsaApInitializePackage(%lu %p %p %p %p)\n", 962 AuthenticationPackageId, LsaDispatchTable, Database, 963 Confidentiality, AuthenticationPackageName); 964 965 /* Get the dispatch table entries */ 966 DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession; 967 DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession; 968 DispatchTable.AddCredential = LsaDispatchTable->AddCredential; 969 DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials; 970 DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential; 971 DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap; 972 DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap; 973 DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer; 974 DispatchTable.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer; 975 DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer; 976 DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer; 977 978 /* Return the package name */ 979 NameString = DispatchTable.AllocateLsaHeap(sizeof(LSA_STRING)); 980 if (NameString == NULL) 981 return STATUS_INSUFFICIENT_RESOURCES; 982 983 NameBuffer = DispatchTable.AllocateLsaHeap(sizeof(MSV1_0_PACKAGE_NAME)); 984 if (NameBuffer == NULL) 985 { 986 DispatchTable.FreeLsaHeap(NameString); 987 return STATUS_INSUFFICIENT_RESOURCES; 988 } 989 990 strcpy(NameBuffer, MSV1_0_PACKAGE_NAME); 991 992 RtlInitAnsiString(NameString, NameBuffer); 993 994 *AuthenticationPackageName = (PLSA_STRING)NameString; 995 996 return STATUS_SUCCESS; 997 } 998 999 1000 /* 1001 * @unimplemented 1002 */ 1003 VOID 1004 NTAPI 1005 LsaApLogonTerminated(IN PLUID LogonId) 1006 { 1007 TRACE("LsaApLogonTerminated()\n"); 1008 } 1009 1010 1011 /* 1012 * Handle Network logon 1013 */ 1014 static 1015 NTSTATUS 1016 LsaApLogonUserEx2_Network( 1017 _In_ PLSA_CLIENT_REQUEST ClientRequest, 1018 _In_ PVOID ProtocolSubmitBuffer, 1019 _In_ PVOID ClientBufferBase, 1020 _In_ ULONG SubmitBufferSize, 1021 _In_ PUNICODE_STRING ComputerName, 1022 _Out_ PUNICODE_STRING* LogonUserRef, 1023 _Out_ PUNICODE_STRING* LogonDomainRef, 1024 _Inout_ PLSA_SAM_PWD_DATA LogonPwdData, 1025 _Out_ SAMPR_HANDLE* UserHandlePtr, 1026 _Out_ PSAMPR_USER_INFO_BUFFER* UserInfoPtr, 1027 _Out_ PRPC_SID* AccountDomainSidPtr, 1028 _Out_ PBOOL SpecialAccount, 1029 _Out_ PMSV1_0_LM20_LOGON_PROFILE *LogonProfile, 1030 _Out_ PULONG LogonProfileSize, 1031 _Out_ PNTSTATUS SubStatus) 1032 { 1033 NTSTATUS Status; 1034 PMSV1_0_LM20_LOGON LogonInfo; 1035 ULONG_PTR PtrOffset; 1036 1037 *LogonProfile = NULL; 1038 *LogonProfileSize = 0; 1039 *UserInfoPtr = NULL; 1040 *AccountDomainSidPtr = NULL; 1041 *SpecialAccount = FALSE; 1042 LogonInfo = ProtocolSubmitBuffer; 1043 1044 if (SubmitBufferSize < sizeof(MSV1_0_LM20_LOGON)) 1045 { 1046 ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize); 1047 return STATUS_INVALID_PARAMETER; 1048 } 1049 1050 /* Fix-up pointers in the authentication info */ 1051 PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase; 1052 1053 if ((!NtlmFixupAndValidateUStr(&LogonInfo->LogonDomainName, PtrOffset)) || 1054 (!NtlmFixupAndValidateUStr(&LogonInfo->UserName, PtrOffset)) || 1055 (!NtlmFixupAndValidateUStr(&LogonInfo->Workstation, PtrOffset)) || 1056 (!NtlmFixupAStr(&LogonInfo->CaseSensitiveChallengeResponse, PtrOffset)) || 1057 (!NtlmFixupAStr(&LogonInfo->CaseInsensitiveChallengeResponse, PtrOffset))) 1058 { 1059 return STATUS_INVALID_PARAMETER; 1060 } 1061 1062 LogonPwdData->IsNetwork = TRUE; 1063 LogonPwdData->LogonInfo = LogonInfo; 1064 LogonPwdData->ComputerName = ComputerName; 1065 Status = SamValidateUser(Network, 1066 &LogonInfo->UserName, 1067 &LogonInfo->LogonDomainName, 1068 LogonPwdData, 1069 ComputerName, 1070 SpecialAccount, 1071 AccountDomainSidPtr, 1072 UserHandlePtr, 1073 UserInfoPtr, 1074 SubStatus); 1075 if (!NT_SUCCESS(Status)) 1076 { 1077 ERR("SamValidateUser failed with 0x%lx\n", Status); 1078 return Status; 1079 } 1080 1081 if (LogonInfo->ParameterControl & MSV1_0_RETURN_PROFILE_PATH) 1082 { 1083 Status = BuildLm20LogonProfileBuffer(ClientRequest, 1084 *UserInfoPtr, 1085 LogonPwdData, 1086 LogonProfile, 1087 LogonProfileSize); 1088 if (!NT_SUCCESS(Status)) 1089 { 1090 ERR("BuildLm20LogonProfileBuffer failed with 0x%lx\n", Status); 1091 return Status; 1092 } 1093 } 1094 1095 *LogonUserRef = &LogonInfo->UserName; 1096 *LogonDomainRef = &LogonInfo->LogonDomainName; 1097 1098 return Status; 1099 } 1100 1101 /* 1102 * @implemented 1103 */ 1104 NTSTATUS 1105 NTAPI 1106 LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest, 1107 IN SECURITY_LOGON_TYPE LogonType, 1108 IN PVOID ProtocolSubmitBuffer, 1109 IN PVOID ClientBufferBase, 1110 IN ULONG SubmitBufferSize, 1111 OUT PVOID *ProfileBuffer, 1112 OUT PULONG ProfileBufferSize, 1113 OUT PLUID LogonId, 1114 OUT PNTSTATUS SubStatus, 1115 OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType, 1116 OUT PVOID *TokenInformation, 1117 OUT PUNICODE_STRING *AccountName, 1118 OUT PUNICODE_STRING *AuthenticatingAuthority, 1119 OUT PUNICODE_STRING *MachineName, 1120 OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */ 1121 OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */ 1122 { 1123 NTSTATUS Status; 1124 UNICODE_STRING ComputerName; 1125 WCHAR ComputerNameData[MAX_COMPUTERNAME_LENGTH + 1]; 1126 PUNICODE_STRING LogonUserName = NULL; 1127 LSA_SAM_PWD_DATA LogonPwdData = { FALSE, NULL }; 1128 PUNICODE_STRING LogonDomain = NULL; 1129 SAMPR_HANDLE UserHandle = NULL; 1130 PRPC_SID AccountDomainSid = NULL; 1131 PSAMPR_USER_INFO_BUFFER UserInfo = NULL; 1132 BOOLEAN SessionCreated = FALSE; 1133 DWORD ComputerNameSize; 1134 BOOL SpecialAccount = FALSE; 1135 UCHAR LogonPassHash; 1136 PUNICODE_STRING ErasePassword = NULL; 1137 1138 TRACE("LsaApLogonUserEx2()\n"); 1139 1140 TRACE("LogonType: %lu\n", LogonType); 1141 TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer); 1142 TRACE("SubmitBufferSize: %lu\n", SubmitBufferSize); 1143 1144 *ProfileBuffer = NULL; 1145 *ProfileBufferSize = 0; 1146 *SubStatus = STATUS_SUCCESS; 1147 *AccountName = NULL; 1148 *AuthenticatingAuthority = NULL; 1149 1150 /* Get the computer name */ 1151 ComputerNameSize = ARRAYSIZE(ComputerNameData); 1152 if (!GetComputerNameW(ComputerNameData, &ComputerNameSize)) 1153 { 1154 ERR("Failed to get Computername.\n"); 1155 return STATUS_INTERNAL_ERROR; 1156 } 1157 RtlInitUnicodeString(&ComputerName, ComputerNameData); 1158 1159 /* Parameters validation */ 1160 if (LogonType == Interactive || 1161 LogonType == Batch || 1162 LogonType == Service) 1163 { 1164 PMSV1_0_INTERACTIVE_LOGON LogonInfo; 1165 ULONG_PTR PtrOffset; 1166 1167 if (SubmitBufferSize < sizeof(MSV1_0_INTERACTIVE_LOGON)) 1168 { 1169 ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize); 1170 return STATUS_INVALID_PARAMETER; 1171 } 1172 1173 LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)ProtocolSubmitBuffer; 1174 1175 if (LogonInfo->MessageType != MsV1_0InteractiveLogon && 1176 LogonInfo->MessageType != MsV1_0WorkstationUnlockLogon) 1177 { 1178 ERR("Invalid MessageType %lu\n", LogonInfo->MessageType); 1179 return STATUS_BAD_VALIDATION_CLASS; 1180 } 1181 1182 #if 0 // FIXME: These checks happen to be done on Windows. We however keep them general on ReactOS for now... 1183 if (LogonInfo->UserName.Length > 512) // CRED_MAX_STRING_LENGTH * sizeof(WCHAR) or (CREDUI_MAX_USERNAME_LENGTH (== CRED_MAX_USERNAME_LENGTH) - 1) * sizeof(WCHAR) 1184 { 1185 ERR("UserName too long (%lu, maximum 512)\n", LogonInfo->UserName.Length); 1186 return STATUS_NAME_TOO_LONG; 1187 } 1188 if (LogonInfo->Password.Length > 512) // CREDUI_MAX_PASSWORD_LENGTH * sizeof(WCHAR) 1189 { 1190 ERR("Password too long (%lu, maximum 512)\n", LogonInfo->Password.Length); 1191 return STATUS_NAME_TOO_LONG; 1192 } 1193 #endif 1194 1195 /* Fix-up pointers in the authentication info */ 1196 PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase; 1197 1198 /* LogonDomainName is optional and can be an empty string */ 1199 if (LogonInfo->LogonDomainName.Length) 1200 { 1201 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 1202 LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset); 1203 LogonInfo->LogonDomainName.MaximumLength = LogonInfo->LogonDomainName.Length; 1204 } 1205 else 1206 { 1207 LogonInfo->LogonDomainName.Buffer = NULL; 1208 LogonInfo->LogonDomainName.MaximumLength = 0; 1209 } 1210 Status = RtlValidateUnicodeString(0, &LogonInfo->LogonDomainName); 1211 if (!NT_SUCCESS(Status)) 1212 return STATUS_INVALID_PARAMETER; 1213 1214 /* UserName is mandatory and cannot be an empty string */ 1215 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 1216 LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset); 1217 LogonInfo->UserName.MaximumLength = LogonInfo->UserName.Length; 1218 1219 Status = RtlValidateUnicodeString(0, &LogonInfo->UserName); 1220 if (!NT_SUCCESS(Status)) 1221 return STATUS_INVALID_PARAMETER; 1222 1223 /* MS docs says max length is 0xFF bytes. But thats not the full story: 1224 * 1225 * A Quote from https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.kernel/eFGcCo_ZObk: 1226 * "... At least on my WinXP SP2. Domain and UserName are passed 1227 * in clear text, but the Password is NOT. ..." 1228 * 1229 * If the higher byte of length != 0 we have to use RtlRunDecodeUnicodeString. 1230 */ 1231 LogonPassHash = (LogonInfo->Password.Length >> 8) & 0xFF; 1232 LogonInfo->Password.Length = LogonInfo->Password.Length & 0xFF; 1233 1234 /* Password is optional and can be an empty string */ 1235 if (LogonInfo->Password.Length) 1236 { 1237 // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment. 1238 LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset); 1239 LogonInfo->Password.MaximumLength = LogonInfo->Password.Length; 1240 } 1241 else 1242 { 1243 LogonInfo->Password.Buffer = NULL; 1244 LogonInfo->Password.MaximumLength = 0; 1245 } 1246 1247 /* Decode password */ 1248 if (LogonPassHash > 0) 1249 { 1250 RtlRunDecodeUnicodeString(LogonPassHash, &LogonInfo->Password); 1251 } 1252 1253 /* ErasePassword will be "erased" before we return */ 1254 ErasePassword = &LogonInfo->Password; 1255 1256 Status = RtlValidateUnicodeString(0, &LogonInfo->Password); 1257 if (!NT_SUCCESS(Status)) 1258 return STATUS_INVALID_PARAMETER; 1259 1260 LogonUserName = &LogonInfo->UserName; 1261 LogonDomain = &LogonInfo->LogonDomainName; 1262 LogonPwdData.IsNetwork = FALSE; 1263 LogonPwdData.PlainPwd = &LogonInfo->Password; 1264 LogonPwdData.ComputerName = &ComputerName; 1265 1266 TRACE("Domain: %wZ\n", &LogonInfo->LogonDomainName); 1267 TRACE("User: %wZ\n", &LogonInfo->UserName); 1268 TRACE("Password: %wZ\n", &LogonInfo->Password); 1269 1270 // TODO: If LogonType == Service, do some extra work using LogonInfo->Password. 1271 } 1272 else if (LogonType == Network) 1273 { 1274 Status = LsaApLogonUserEx2_Network(ClientRequest, 1275 ProtocolSubmitBuffer, 1276 ClientBufferBase, 1277 SubmitBufferSize, 1278 &ComputerName, 1279 &LogonUserName, 1280 &LogonDomain, 1281 &LogonPwdData, 1282 &UserHandle, 1283 &UserInfo, 1284 &AccountDomainSid, 1285 &SpecialAccount, 1286 (PMSV1_0_LM20_LOGON_PROFILE*)ProfileBuffer, 1287 ProfileBufferSize, 1288 SubStatus); 1289 if (!NT_SUCCESS(Status)) 1290 goto done; 1291 } 1292 else 1293 { 1294 FIXME("LogonType %lu is not supported yet!\n", LogonType); 1295 return STATUS_NOT_IMPLEMENTED; 1296 } 1297 // TODO: Add other LogonType validity checks. 1298 1299 Status = SamValidateUser(LogonType, 1300 LogonUserName, 1301 LogonDomain, 1302 &LogonPwdData, 1303 &ComputerName, 1304 &SpecialAccount, 1305 &AccountDomainSid, 1306 &UserHandle, 1307 &UserInfo, 1308 SubStatus); 1309 if (!NT_SUCCESS(Status)) 1310 goto done; 1311 1312 /* Return logon information */ 1313 1314 /* Create and return a new logon id */ 1315 Status = NtAllocateLocallyUniqueId(LogonId); 1316 if (!NT_SUCCESS(Status)) 1317 { 1318 TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status); 1319 goto done; 1320 } 1321 1322 /* Create the logon session */ 1323 Status = DispatchTable.CreateLogonSession(LogonId); 1324 if (!NT_SUCCESS(Status)) 1325 { 1326 TRACE("CreateLogonSession failed (Status %08lx)\n", Status); 1327 goto done; 1328 } 1329 1330 SessionCreated = TRUE; 1331 1332 if (LogonType == Interactive || LogonType == Batch || LogonType == Service) 1333 { 1334 /* Build and fill the interactive profile buffer */ 1335 Status = BuildInteractiveProfileBuffer(ClientRequest, 1336 UserInfo, 1337 ComputerName.Buffer, 1338 (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer, 1339 ProfileBufferSize); 1340 if (!NT_SUCCESS(Status)) 1341 { 1342 TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status); 1343 goto done; 1344 } 1345 } 1346 else if (LogonType == Network) 1347 { 1348 //FIXME: no need to do anything, its already done ... 1349 } 1350 1351 /* Return the token information type */ 1352 *TokenInformationType = LsaTokenInformationV1; 1353 1354 /* Build and fill the token information buffer */ 1355 Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation, 1356 AccountDomainSid, 1357 UserInfo, 1358 SpecialAccount); 1359 if (!NT_SUCCESS(Status)) 1360 { 1361 TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status); 1362 goto done; 1363 } 1364 1365 done: 1366 /* Erase password */ 1367 if (ErasePassword) 1368 { 1369 RtlEraseUnicodeString(ErasePassword); 1370 } 1371 1372 /* Update the logon time/count or the bad password time/count */ 1373 if ((UserHandle != NULL) && 1374 (Status == STATUS_SUCCESS || Status == STATUS_WRONG_PASSWORD)) 1375 { 1376 SAMPR_USER_INFO_BUFFER InternalInfo; 1377 1378 RtlZeroMemory(&InternalInfo, sizeof(InternalInfo)); 1379 1380 if (Status == STATUS_SUCCESS) 1381 InternalInfo.Internal2.Flags = USER_LOGON_SUCCESS; 1382 else 1383 InternalInfo.Internal2.Flags = USER_LOGON_BAD_PASSWORD; 1384 1385 SamrSetInformationUser(UserHandle, 1386 UserInternal2Information, 1387 &InternalInfo); 1388 } 1389 1390 if (NT_SUCCESS(Status)) 1391 { 1392 /* Return the account name */ 1393 *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING)); 1394 if ((LogonUserName != NULL) && 1395 (*AccountName != NULL)) 1396 { 1397 (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonUserName->Length + 1398 sizeof(UNICODE_NULL)); 1399 if ((*AccountName)->Buffer != NULL) 1400 { 1401 (*AccountName)->MaximumLength = LogonUserName->Length + 1402 sizeof(UNICODE_NULL); 1403 RtlCopyUnicodeString(*AccountName, LogonUserName); 1404 } 1405 } 1406 1407 /* Return the authenticating authority */ 1408 *AuthenticatingAuthority = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING)); 1409 if ((LogonDomain != NULL) && 1410 (*AuthenticatingAuthority != NULL)) 1411 { 1412 (*AuthenticatingAuthority)->Buffer = DispatchTable.AllocateLsaHeap(LogonDomain->Length + 1413 sizeof(UNICODE_NULL)); 1414 if ((*AuthenticatingAuthority)->Buffer != NULL) 1415 { 1416 (*AuthenticatingAuthority)->MaximumLength = LogonDomain->Length + 1417 sizeof(UNICODE_NULL); 1418 RtlCopyUnicodeString(*AuthenticatingAuthority, LogonDomain); 1419 } 1420 } 1421 1422 /* Return the machine name */ 1423 *MachineName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING)); 1424 if (*MachineName != NULL) 1425 { 1426 (*MachineName)->Buffer = DispatchTable.AllocateLsaHeap(ComputerName.MaximumLength); 1427 if ((*MachineName)->Buffer != NULL) 1428 { 1429 (*MachineName)->MaximumLength = ComputerName.MaximumLength; 1430 (*MachineName)->Length = ComputerName.Length; 1431 RtlCopyMemory((*MachineName)->Buffer, 1432 ComputerName.Buffer, 1433 ComputerName.MaximumLength); 1434 } 1435 } 1436 } 1437 1438 if (!NT_SUCCESS(Status)) 1439 { 1440 if (SessionCreated != FALSE) 1441 DispatchTable.DeleteLogonSession(LogonId); 1442 1443 if (*ProfileBuffer != NULL) 1444 { 1445 DispatchTable.FreeClientBuffer(ClientRequest, 1446 *ProfileBuffer); 1447 *ProfileBuffer = NULL; 1448 } 1449 } 1450 1451 if (UserHandle != NULL) 1452 SamrCloseHandle(&UserHandle); 1453 1454 SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo, 1455 UserAllInformation); 1456 1457 if (AccountDomainSid != NULL) 1458 RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid); 1459 1460 if (Status == STATUS_NO_SUCH_USER || 1461 Status == STATUS_WRONG_PASSWORD) 1462 { 1463 *SubStatus = Status; 1464 Status = STATUS_LOGON_FAILURE; 1465 } 1466 1467 TRACE("LsaApLogonUserEx2 done (Status 0x%08lx, SubStatus 0x%08lx)\n", Status, *SubStatus); 1468 1469 return Status; 1470 } 1471 1472 1473 /* 1474 * @unimplemented 1475 */ 1476 NTSTATUS 1477 NTAPI 1478 SpLsaModeInitialize( 1479 _In_ ULONG LsaVersion, 1480 _Out_ PULONG PackageVersion, 1481 _Out_ PSECPKG_FUNCTION_TABLE *ppTables, 1482 _Out_ PULONG pcTables) 1483 { 1484 TRACE("SpLsaModeInitialize(0x%lx %p %p %p)\n", 1485 LsaVersion, PackageVersion, ppTables, pcTables); 1486 1487 if (LsaVersion != SECPKG_INTERFACE_VERSION) 1488 return STATUS_INVALID_PARAMETER; 1489 1490 *PackageVersion = SECPKG_INTERFACE_VERSION; 1491 1492 *ppTables = NtlmLsaFn; 1493 *pcTables = 1; 1494 1495 return STATUS_SUCCESS; 1496 } 1497 1498 /* 1499 * @unimplemented 1500 */ 1501 NTSTATUS 1502 WINAPI 1503 SpUserModeInitialize( 1504 _In_ ULONG LsaVersion, 1505 _Out_ PULONG PackageVersion, 1506 _Out_ PSECPKG_USER_FUNCTION_TABLE *ppTables, 1507 _Out_ PULONG pcTables) 1508 { 1509 TRACE("SpUserModeInitialize(0x%lx %p %p %p)\n", 1510 LsaVersion, PackageVersion, ppTables, pcTables); 1511 1512 if (LsaVersion != SECPKG_INTERFACE_VERSION) 1513 return STATUS_INVALID_PARAMETER; 1514 1515 *PackageVersion = SECPKG_INTERFACE_VERSION; 1516 1517 *ppTables = NtlmUsrFn; 1518 *pcTables = 1; 1519 1520 return STATUS_SUCCESS; 1521 } 1522 1523 /* EOF */ 1524