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