xref: /reactos/dll/win32/msv1_0/msv1_0.c (revision e1338178)
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 PWSTR ComputerName,
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                    ((wcslen(ComputerName) + 3) * 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 = (wcslen(ComputerName) + 2) * sizeof(WCHAR);
208     LocalBuffer->LogonServer.MaximumLength = LocalBuffer->LogonServer.Length + sizeof(WCHAR);
209     LocalBuffer->LogonServer.Buffer = (LPWSTR)((ULONG_PTR)ClientBaseAddress + (ULONG_PTR)Ptr - (ULONG_PTR)LocalBuffer);
210     wcscpy(Ptr, L"\\");
211     wcscat(Ptr, ComputerName);
212 
213     LocalBuffer->UserFlags = 0;
214 
215     Status = DispatchTable.CopyToClientBuffer(ClientRequest,
216                                               BufferLength,
217                                               ClientBaseAddress,
218                                               LocalBuffer);
219     if (!NT_SUCCESS(Status))
220     {
221         TRACE("DispatchTable.CopyToClientBuffer failed (Status 0x%08lx)\n", Status);
222         goto done;
223     }
224 
225     *ProfileBuffer = (PMSV1_0_INTERACTIVE_PROFILE)ClientBaseAddress;
226     *ProfileBufferLength = BufferLength;
227 
228 done:
229     if (LocalBuffer != NULL)
230         DispatchTable.FreeLsaHeap(LocalBuffer);
231 
232     if (!NT_SUCCESS(Status))
233     {
234         if (ClientBaseAddress != NULL)
235             DispatchTable.FreeClientBuffer(ClientRequest,
236                                            ClientBaseAddress);
237     }
238 
239     return Status;
240 }
241 
242 
243 static
244 PSID
245 AppendRidToSid(PSID SrcSid,
246                ULONG Rid)
247 {
248     PSID DstSid = NULL;
249     UCHAR RidCount;
250 
251     RidCount = *RtlSubAuthorityCountSid(SrcSid);
252     if (RidCount >= 8)
253         return NULL;
254 
255     DstSid = DispatchTable.AllocateLsaHeap(RtlLengthRequiredSid(RidCount + 1));
256     if (DstSid == NULL)
257         return NULL;
258 
259     RtlCopyMemory(DstSid,
260                   SrcSid,
261                   RtlLengthRequiredSid(RidCount));
262 
263     *RtlSubAuthorityCountSid(DstSid) = RidCount + 1;
264     *RtlSubAuthoritySid(DstSid, RidCount) = Rid;
265 
266     return DstSid;
267 }
268 
269 
270 static
271 NTSTATUS
272 BuildTokenUser(OUT PTOKEN_USER User,
273                IN PSID AccountDomainSid,
274                IN ULONG RelativeId)
275 {
276     User->User.Sid = AppendRidToSid(AccountDomainSid,
277                                     RelativeId);
278     if (User->User.Sid == NULL)
279     {
280         ERR("Could not create the user SID\n");
281         return STATUS_INSUFFICIENT_RESOURCES;
282     }
283 
284     User->User.Attributes = 0;
285 
286     return STATUS_SUCCESS;
287 }
288 
289 
290 static
291 NTSTATUS
292 BuildTokenPrimaryGroup(OUT PTOKEN_PRIMARY_GROUP PrimaryGroup,
293                        IN PSID AccountDomainSid,
294                        IN ULONG RelativeId)
295 {
296     PrimaryGroup->PrimaryGroup = AppendRidToSid(AccountDomainSid,
297                                                 RelativeId);
298     if (PrimaryGroup->PrimaryGroup == NULL)
299     {
300         ERR("Could not create the primary group SID\n");
301         return STATUS_INSUFFICIENT_RESOURCES;
302     }
303 
304     return STATUS_SUCCESS;
305 }
306 
307 
308 static
309 NTSTATUS
310 BuildTokenGroups(OUT PTOKEN_GROUPS *Groups,
311                  IN PSID AccountDomainSid,
312                  IN ULONG RelativeId,
313                  IN BOOL SpecialAccount)
314 {
315     SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
316     PTOKEN_GROUPS TokenGroups;
317     DWORD GroupCount = 0;
318     DWORD MaxGroups = 2;
319     PSID Sid;
320     NTSTATUS Status = STATUS_SUCCESS;
321 
322     if (SpecialAccount)
323         MaxGroups++;
324 
325     TokenGroups = DispatchTable.AllocateLsaHeap(sizeof(TOKEN_GROUPS) +
326                                                 MaxGroups * sizeof(SID_AND_ATTRIBUTES));
327     if (TokenGroups == NULL)
328     {
329         return STATUS_INSUFFICIENT_RESOURCES;
330     }
331 
332     if (SpecialAccount)
333     {
334         /* Self */
335         Sid = AppendRidToSid(AccountDomainSid, RelativeId);
336         if (Sid == NULL)
337         {
338 
339         }
340 
341         TokenGroups->Groups[GroupCount].Sid = Sid;
342         TokenGroups->Groups[GroupCount].Attributes =
343             SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
344         GroupCount++;
345 
346         /* Member of 'Users' alias */
347         RtlAllocateAndInitializeSid(&SystemAuthority,
348                                     2,
349                                     SECURITY_BUILTIN_DOMAIN_RID,
350                                     DOMAIN_ALIAS_RID_USERS,
351                                     SECURITY_NULL_RID,
352                                     SECURITY_NULL_RID,
353                                     SECURITY_NULL_RID,
354                                     SECURITY_NULL_RID,
355                                     SECURITY_NULL_RID,
356                                     SECURITY_NULL_RID,
357                                     &Sid);
358         TokenGroups->Groups[GroupCount].Sid = Sid;
359         TokenGroups->Groups[GroupCount].Attributes =
360             SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
361         GroupCount++;
362     }
363     else
364     {
365         /* Member of the domains users group */
366         Sid = AppendRidToSid(AccountDomainSid, DOMAIN_GROUP_RID_USERS);
367         if (Sid == NULL)
368         {
369 
370         }
371 
372         TokenGroups->Groups[GroupCount].Sid = Sid;
373         TokenGroups->Groups[GroupCount].Attributes =
374             SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
375         GroupCount++;
376     }
377 
378     /* Member of 'Authenticated users' */
379     RtlAllocateAndInitializeSid(&SystemAuthority,
380                                 1,
381                                 SECURITY_AUTHENTICATED_USER_RID,
382                                 SECURITY_NULL_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                                 &Sid);
390     TokenGroups->Groups[GroupCount].Sid = Sid;
391     TokenGroups->Groups[GroupCount].Attributes =
392         SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY;
393     GroupCount++;
394 
395     TokenGroups->GroupCount = GroupCount;
396     ASSERT(TokenGroups->GroupCount <= MaxGroups);
397 
398     *Groups = TokenGroups;
399 
400     return Status;
401 }
402 
403 
404 static
405 NTSTATUS
406 BuildTokenInformationBuffer(PLSA_TOKEN_INFORMATION_V1 *TokenInformation,
407                             PRPC_SID AccountDomainSid,
408                             PSAMPR_USER_INFO_BUFFER UserInfo,
409                             BOOL SpecialAccount)
410 {
411     PLSA_TOKEN_INFORMATION_V1 Buffer = NULL;
412     ULONG i;
413     NTSTATUS Status = STATUS_SUCCESS;
414 
415     Buffer = DispatchTable.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1));
416     if (Buffer == NULL)
417     {
418         WARN("Failed to allocate the local buffer!\n");
419         Status = STATUS_INSUFFICIENT_RESOURCES;
420         goto done;
421     }
422 
423     Buffer->ExpirationTime.LowPart = UserInfo->All.AccountExpires.LowPart;
424     Buffer->ExpirationTime.HighPart = UserInfo->All.AccountExpires.HighPart;
425 
426     Status = BuildTokenUser(&Buffer->User,
427                             (PSID)AccountDomainSid,
428                             UserInfo->All.UserId);
429     if (!NT_SUCCESS(Status))
430     {
431         WARN("BuildTokenUser() failed (Status 0x%08lx)\n", Status);
432         goto done;
433     }
434 
435     Status = BuildTokenPrimaryGroup(&Buffer->PrimaryGroup,
436                                     (PSID)AccountDomainSid,
437                                     UserInfo->All.PrimaryGroupId);
438     if (!NT_SUCCESS(Status))
439     {
440         WARN("BuildTokenPrimaryGroup() failed (Status 0x%08lx)\n", Status);
441         goto done;
442     }
443 
444     Status = BuildTokenGroups(&Buffer->Groups,
445                               (PSID)AccountDomainSid,
446                               UserInfo->All.UserId,
447                               SpecialAccount);
448     if (!NT_SUCCESS(Status))
449     {
450         WARN("BuildTokenGroups() failed (Status 0x%08lx)\n", Status);
451         goto done;
452     }
453 
454     *TokenInformation = Buffer;
455 
456 done:
457     if (!NT_SUCCESS(Status))
458     {
459         if (Buffer != NULL)
460         {
461             if (Buffer->User.User.Sid != NULL)
462                 DispatchTable.FreeLsaHeap(Buffer->User.User.Sid);
463 
464             if (Buffer->Groups != NULL)
465             {
466                 for (i = 0; i < Buffer->Groups->GroupCount; i++)
467                 {
468                     if (Buffer->Groups->Groups[i].Sid != NULL)
469                         DispatchTable.FreeLsaHeap(Buffer->Groups->Groups[i].Sid);
470                 }
471 
472                 DispatchTable.FreeLsaHeap(Buffer->Groups);
473             }
474 
475             if (Buffer->PrimaryGroup.PrimaryGroup != NULL)
476                 DispatchTable.FreeLsaHeap(Buffer->PrimaryGroup.PrimaryGroup);
477 
478             if (Buffer->DefaultDacl.DefaultDacl != NULL)
479                 DispatchTable.FreeLsaHeap(Buffer->DefaultDacl.DefaultDacl);
480 
481             DispatchTable.FreeLsaHeap(Buffer);
482         }
483     }
484 
485     return Status;
486 }
487 
488 
489 static
490 NTSTATUS
491 MsvpChangePassword(IN PLSA_CLIENT_REQUEST ClientRequest,
492                    IN PVOID ProtocolSubmitBuffer,
493                    IN PVOID ClientBufferBase,
494                    IN ULONG SubmitBufferLength,
495                    OUT PVOID *ProtocolReturnBuffer,
496                    OUT PULONG ReturnBufferLength,
497                    OUT PNTSTATUS ProtocolStatus)
498 {
499     PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer;
500     ULONG_PTR PtrOffset;
501 
502     SAMPR_HANDLE ServerHandle = NULL;
503     SAMPR_HANDLE DomainHandle = NULL;
504     SAMPR_HANDLE UserHandle = NULL;
505     PRPC_SID DomainSid = NULL;
506     RPC_UNICODE_STRING Names[1];
507     SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
508     SAMPR_ULONG_ARRAY Use = {0, NULL};
509     NTSTATUS Status;
510 
511     ENCRYPTED_NT_OWF_PASSWORD OldNtPassword;
512     ENCRYPTED_NT_OWF_PASSWORD NewNtPassword;
513     ENCRYPTED_LM_OWF_PASSWORD OldLmPassword;
514     ENCRYPTED_LM_OWF_PASSWORD NewLmPassword;
515     OEM_STRING LmPwdString;
516     CHAR LmPwdBuffer[15];
517     BOOLEAN OldLmPasswordPresent = FALSE;
518     BOOLEAN NewLmPasswordPresent = FALSE;
519 
520     ENCRYPTED_LM_OWF_PASSWORD OldLmEncryptedWithNewLm;
521     ENCRYPTED_LM_OWF_PASSWORD NewLmEncryptedWithOldLm;
522     ENCRYPTED_LM_OWF_PASSWORD OldNtEncryptedWithNewNt;
523     ENCRYPTED_LM_OWF_PASSWORD NewNtEncryptedWithOldNt;
524     PENCRYPTED_LM_OWF_PASSWORD pOldLmEncryptedWithNewLm = NULL;
525     PENCRYPTED_LM_OWF_PASSWORD pNewLmEncryptedWithOldLm = NULL;
526 
527     TRACE("()\n");
528 
529     RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
530 
531     /* Fix-up pointers in the request buffer info */
532     PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
533 
534     RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
535     RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
536     RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
537     RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
538 
539     TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
540     TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
541     TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
542     TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);
543 
544     /* Connect to the SAM server */
545     Status = SamIConnect(NULL,
546                          &ServerHandle,
547                          SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
548                          TRUE);
549     if (!NT_SUCCESS(Status))
550     {
551         TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
552         goto done;
553     }
554 
555     /* Get the domain SID */
556     Status = SamrLookupDomainInSamServer(ServerHandle,
557                                          (PRPC_UNICODE_STRING)&RequestBuffer->DomainName,
558                                          &DomainSid);
559     if (!NT_SUCCESS(Status))
560     {
561         TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status);
562         goto done;
563     }
564 
565     /* Open the domain */
566     Status = SamrOpenDomain(ServerHandle,
567                             DOMAIN_LOOKUP,
568                             DomainSid,
569                             &DomainHandle);
570     if (!NT_SUCCESS(Status))
571     {
572         TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
573         goto done;
574     }
575 
576     Names[0].Length = RequestBuffer->AccountName.Length;
577     Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
578     Names[0].Buffer = RequestBuffer->AccountName.Buffer;
579 
580     /* Try to get the RID for the user name */
581     Status = SamrLookupNamesInDomain(DomainHandle,
582                                      1,
583                                      Names,
584                                      &RelativeIds,
585                                      &Use);
586     if (!NT_SUCCESS(Status))
587     {
588         TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
589         Status = STATUS_NO_SUCH_USER;
590         goto done;
591     }
592 
593     /* Fail, if it is not a user account */
594     if (Use.Element[0] != SidTypeUser)
595     {
596         TRACE("Account is not a user account!\n");
597         Status = STATUS_NO_SUCH_USER;
598         goto done;
599     }
600 
601     /* Open the user object */
602     Status = SamrOpenUser(DomainHandle,
603                           USER_CHANGE_PASSWORD,
604                           RelativeIds.Element[0],
605                           &UserHandle);
606     if (!NT_SUCCESS(Status))
607     {
608         TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
609         goto done;
610     }
611 
612 
613     /* Calculate the NT hash for the old password */
614     Status = SystemFunction007(&RequestBuffer->OldPassword,
615                                (LPBYTE)&OldNtPassword);
616     if (!NT_SUCCESS(Status))
617     {
618         TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
619         goto done;
620     }
621 
622     /* Calculate the NT hash for the new password */
623     Status = SystemFunction007(&RequestBuffer->NewPassword,
624                                (LPBYTE)&NewNtPassword);
625     if (!NT_SUCCESS(Status))
626     {
627         TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
628         goto done;
629     }
630 
631     /* Calculate the LM password and hash for the old password */
632     LmPwdString.Length = 15;
633     LmPwdString.MaximumLength = 15;
634     LmPwdString.Buffer = LmPwdBuffer;
635     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
636 
637     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
638                                                &RequestBuffer->OldPassword,
639                                                FALSE);
640     if (NT_SUCCESS(Status))
641     {
642         /* Calculate the LM hash value of the password */
643         Status = SystemFunction006(LmPwdString.Buffer,
644                                    (LPSTR)&OldLmPassword);
645         if (NT_SUCCESS(Status))
646         {
647             OldLmPasswordPresent = TRUE;
648         }
649     }
650 
651     /* Calculate the LM password and hash for the new password */
652     LmPwdString.Length = 15;
653     LmPwdString.MaximumLength = 15;
654     LmPwdString.Buffer = LmPwdBuffer;
655     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
656 
657     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
658                                                &RequestBuffer->NewPassword,
659                                                FALSE);
660     if (NT_SUCCESS(Status))
661     {
662         /* Calculate the LM hash value of the password */
663         Status = SystemFunction006(LmPwdString.Buffer,
664                                    (LPSTR)&NewLmPassword);
665         if (NT_SUCCESS(Status))
666         {
667             NewLmPasswordPresent = TRUE;
668         }
669     }
670 
671     /* Encrypt the old and new LM passwords, if they exist */
672     if (OldLmPasswordPresent && NewLmPasswordPresent)
673     {
674         /* Encrypt the old LM password */
675         Status = SystemFunction012((const BYTE *)&OldLmPassword,
676                                    (const BYTE *)&NewLmPassword,
677                                    (LPBYTE)&OldLmEncryptedWithNewLm);
678         if (!NT_SUCCESS(Status))
679         {
680             TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
681             goto done;
682         }
683 
684         /* Encrypt the new LM password */
685         Status = SystemFunction012((const BYTE *)&NewLmPassword,
686                                    (const BYTE *)&OldLmPassword,
687                                    (LPBYTE)&NewLmEncryptedWithOldLm);
688         if (!NT_SUCCESS(Status))
689         {
690             TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
691             goto done;
692         }
693 
694         pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm;
695         pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm;
696     }
697 
698     /* Encrypt the old NT password */
699     Status = SystemFunction012((const BYTE *)&OldNtPassword,
700                                (const BYTE *)&NewNtPassword,
701                                (LPBYTE)&OldNtEncryptedWithNewNt);
702     if (!NT_SUCCESS(Status))
703     {
704         TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
705         goto done;
706     }
707 
708     /* Encrypt the new NT password */
709     Status = SystemFunction012((const BYTE *)&NewNtPassword,
710                                (const BYTE *)&OldNtPassword,
711                                (LPBYTE)&NewNtEncryptedWithOldNt);
712     if (!NT_SUCCESS(Status))
713     {
714         TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
715         goto done;
716     }
717 
718     /* Change the password */
719     Status = SamrChangePasswordUser(UserHandle,
720                                     OldLmPasswordPresent && NewLmPasswordPresent,
721                                     pOldLmEncryptedWithNewLm,
722                                     pNewLmEncryptedWithOldLm,
723                                     TRUE,
724                                     &OldNtEncryptedWithNewNt,
725                                     &NewNtEncryptedWithOldNt,
726                                     FALSE,
727                                     NULL,
728                                     FALSE,
729                                     NULL);
730     if (!NT_SUCCESS(Status))
731     {
732         TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status);
733         goto done;
734     }
735 
736 done:
737     if (UserHandle != NULL)
738         SamrCloseHandle(&UserHandle);
739 
740     SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
741     SamIFree_SAMPR_ULONG_ARRAY(&Use);
742 
743     if (DomainHandle != NULL)
744         SamrCloseHandle(&DomainHandle);
745 
746     if (DomainSid != NULL)
747         SamIFreeVoid(DomainSid);
748 
749     if (ServerHandle != NULL)
750         SamrCloseHandle(&ServerHandle);
751 
752     return Status;
753 }
754 
755 
756 static
757 NTSTATUS
758 MsvpCheckPassword(PUNICODE_STRING UserPassword,
759                   PSAMPR_USER_INFO_BUFFER UserInfo)
760 {
761     ENCRYPTED_NT_OWF_PASSWORD UserNtPassword;
762     ENCRYPTED_LM_OWF_PASSWORD UserLmPassword;
763     BOOLEAN UserLmPasswordPresent = FALSE;
764     BOOLEAN UserNtPasswordPresent = FALSE;
765     OEM_STRING LmPwdString;
766     CHAR LmPwdBuffer[15];
767     NTSTATUS Status;
768 
769     TRACE("(%p %p)\n", UserPassword, UserInfo);
770 
771     /* Calculate the LM password and hash for the users password */
772     LmPwdString.Length = 15;
773     LmPwdString.MaximumLength = 15;
774     LmPwdString.Buffer = LmPwdBuffer;
775     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
776 
777     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
778                                                UserPassword,
779                                                FALSE);
780     if (NT_SUCCESS(Status))
781     {
782         /* Calculate the LM hash value of the users password */
783         Status = SystemFunction006(LmPwdString.Buffer,
784                                    (LPSTR)&UserLmPassword);
785         if (NT_SUCCESS(Status))
786         {
787             UserLmPasswordPresent = TRUE;
788         }
789     }
790 
791     /* Calculate the NT hash of the users password */
792     Status = SystemFunction007(UserPassword,
793                                (LPBYTE)&UserNtPassword);
794     if (NT_SUCCESS(Status))
795     {
796         UserNtPasswordPresent = TRUE;
797     }
798 
799     Status = STATUS_WRONG_PASSWORD;
800 
801     /* Succeed, if no password has been set */
802     if (UserInfo->All.NtPasswordPresent == FALSE &&
803         UserInfo->All.LmPasswordPresent == FALSE)
804     {
805         TRACE("No password check!\n");
806         Status = STATUS_SUCCESS;
807         goto done;
808     }
809 
810     /* Succeed, if NT password matches */
811     if (UserNtPasswordPresent && UserInfo->All.NtPasswordPresent)
812     {
813         TRACE("Check NT password hashes:\n");
814         if (RtlEqualMemory(&UserNtPassword,
815                            UserInfo->All.NtOwfPassword.Buffer,
816                            sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
817         {
818             TRACE("  success!\n");
819             Status = STATUS_SUCCESS;
820             goto done;
821         }
822 
823         TRACE("  failed!\n");
824     }
825 
826     /* Succeed, if LM password matches */
827     if (UserLmPasswordPresent && UserInfo->All.LmPasswordPresent)
828     {
829         TRACE("Check LM password hashes:\n");
830         if (RtlEqualMemory(&UserLmPassword,
831                            UserInfo->All.LmOwfPassword.Buffer,
832                            sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
833         {
834             TRACE("  success!\n");
835             Status = STATUS_SUCCESS;
836             goto done;
837         }
838         TRACE("  failed!\n");
839     }
840 
841 done:
842     return Status;
843 }
844 
845 
846 static
847 BOOL
848 MsvpCheckLogonHours(
849     _In_ PSAMPR_LOGON_HOURS LogonHours,
850     _In_ PLARGE_INTEGER LogonTime)
851 {
852 #if 0
853     LARGE_INTEGER LocalLogonTime;
854     TIME_FIELDS TimeFields;
855     USHORT MinutesPerUnit, Offset;
856     BOOL bFound;
857 
858     FIXME("MsvpCheckLogonHours(%p %p)\n", LogonHours, LogonTime);
859 
860     if (LogonHours->UnitsPerWeek == 0 || LogonHours->LogonHours == NULL)
861     {
862         FIXME("No logon hours!\n");
863         return TRUE;
864     }
865 
866     RtlSystemTimeToLocalTime(LogonTime, &LocalLogonTime);
867     RtlTimeToTimeFields(&LocalLogonTime, &TimeFields);
868 
869     FIXME("UnitsPerWeek: %u\n", LogonHours->UnitsPerWeek);
870     MinutesPerUnit = 10080 / LogonHours->UnitsPerWeek;
871 
872     Offset = ((TimeFields.Weekday * 24 + TimeFields.Hour) * 60 + TimeFields.Minute) / MinutesPerUnit;
873     FIXME("Offset: %us\n", Offset);
874 
875     bFound = (BOOL)(LogonHours->LogonHours[Offset / 8] & (1 << (Offset % 8)));
876     FIXME("Logon permitted: %s\n", bFound ? "Yes" : "No");
877 
878     return bFound;
879 #endif
880     return TRUE;
881 }
882 
883 
884 static
885 BOOL
886 MsvpCheckWorkstations(
887     _In_ PRPC_UNICODE_STRING WorkStations,
888     _In_ PWSTR ComputerName)
889 {
890     PWSTR pStart, pEnd;
891     BOOL bFound = FALSE;
892 
893     TRACE("MsvpCheckWorkstations(%p %S)\n", WorkStations, ComputerName);
894 
895     if (WorkStations->Length == 0 || WorkStations->Buffer == NULL)
896     {
897         TRACE("No workstations!\n");
898         return TRUE;
899     }
900 
901     TRACE("Workstations: %wZ\n", WorkStations);
902 
903     pStart = WorkStations->Buffer;
904     for (;;)
905     {
906         pEnd = wcschr(pStart, L',');
907         if (pEnd != NULL)
908             *pEnd = UNICODE_NULL;
909 
910         TRACE("Comparing '%S' and '%S'\n", ComputerName, pStart);
911         if (_wcsicmp(ComputerName, pStart) == 0)
912         {
913             bFound = TRUE;
914             if (pEnd != NULL)
915                 *pEnd = L',';
916             break;
917         }
918 
919         if (pEnd == NULL)
920             break;
921 
922         *pEnd = L',';
923         pStart = pEnd + 1;
924     }
925 
926     TRACE("Found allowed workstation: %s\n", (bFound) ? "Yes" : "No");
927 
928     return bFound;
929 }
930 
931 
932 /*
933  * @unimplemented
934  */
935 NTSTATUS
936 NTAPI
937 LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest,
938                  IN PVOID ProtocolSubmitBuffer,
939                  IN PVOID ClientBufferBase,
940                  IN ULONG SubmitBufferLength,
941                  OUT PVOID *ProtocolReturnBuffer,
942                  OUT PULONG ReturnBufferLength,
943                  OUT PNTSTATUS ProtocolStatus)
944 {
945     ULONG MessageType;
946     NTSTATUS Status;
947 
948     TRACE("LsaApCallPackage()\n");
949 
950     if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
951         return STATUS_INVALID_PARAMETER;
952 
953     MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
954 
955     *ProtocolReturnBuffer = NULL;
956     *ReturnBufferLength = 0;
957 
958     switch (MessageType)
959     {
960         case MsV1_0Lm20ChallengeRequest:
961         case MsV1_0Lm20GetChallengeResponse:
962             Status = STATUS_NOT_IMPLEMENTED;
963             break;
964 
965         case MsV1_0EnumerateUsers:
966         case MsV1_0GetUserInfo:
967         case MsV1_0ReLogonUsers:
968             Status = STATUS_INVALID_PARAMETER;
969             break;
970 
971         case MsV1_0ChangePassword:
972             Status = MsvpChangePassword(ClientRequest,
973                                         ProtocolSubmitBuffer,
974                                         ClientBufferBase,
975                                         SubmitBufferLength,
976                                         ProtocolReturnBuffer,
977                                         ReturnBufferLength,
978                                         ProtocolStatus);
979             break;
980 
981         case MsV1_0ChangeCachedPassword:
982         case MsV1_0GenericPassthrough:
983         case MsV1_0CacheLogon:
984         case MsV1_0SubAuth:
985         case MsV1_0DeriveCredential:
986         case MsV1_0CacheLookup:
987             Status = STATUS_NOT_IMPLEMENTED;
988             break;
989 
990         default:
991             return STATUS_INVALID_PARAMETER;
992     }
993 
994     return Status;
995 }
996 
997 
998 /*
999  * @unimplemented
1000  */
1001 NTSTATUS
1002 NTAPI
1003 LsaApCallPackagePassthrough(IN PLSA_CLIENT_REQUEST ClientRequest,
1004                             IN PVOID ProtocolSubmitBuffer,
1005                             IN PVOID ClientBufferBase,
1006                             IN ULONG SubmitBufferLength,
1007                             OUT PVOID *ProtocolReturnBuffer,
1008                             OUT PULONG ReturnBufferLength,
1009                             OUT PNTSTATUS ProtocolStatus)
1010 {
1011     TRACE("LsaApCallPackagePassthrough()\n");
1012     return STATUS_NOT_IMPLEMENTED;
1013 }
1014 
1015 
1016 /*
1017  * @implemented
1018  */
1019 NTSTATUS
1020 NTAPI
1021 LsaApCallPackageUntrusted(IN PLSA_CLIENT_REQUEST ClientRequest,
1022                           IN PVOID ProtocolSubmitBuffer,
1023                           IN PVOID ClientBufferBase,
1024                           IN ULONG SubmitBufferLength,
1025                           OUT PVOID *ProtocolReturnBuffer,
1026                           OUT PULONG ReturnBufferLength,
1027                           OUT PNTSTATUS ProtocolStatus)
1028 {
1029     ULONG MessageType;
1030     NTSTATUS Status;
1031 
1032     TRACE("LsaApCallPackageUntrusted()\n");
1033 
1034     if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
1035         return STATUS_INVALID_PARAMETER;
1036 
1037     MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
1038 
1039     *ProtocolReturnBuffer = NULL;
1040     *ReturnBufferLength = 0;
1041 
1042     if (MessageType == MsV1_0ChangePassword)
1043         Status = MsvpChangePassword(ClientRequest,
1044                                     ProtocolSubmitBuffer,
1045                                     ClientBufferBase,
1046                                     SubmitBufferLength,
1047                                     ProtocolReturnBuffer,
1048                                     ReturnBufferLength,
1049                                     ProtocolStatus);
1050     else
1051         Status = STATUS_ACCESS_DENIED;
1052 
1053     return Status;
1054 }
1055 
1056 
1057 /*
1058  * @implemented
1059  */
1060 NTSTATUS
1061 NTAPI
1062 LsaApInitializePackage(IN ULONG AuthenticationPackageId,
1063                        IN PLSA_DISPATCH_TABLE LsaDispatchTable,
1064                        IN PLSA_STRING Database OPTIONAL,
1065                        IN PLSA_STRING Confidentiality OPTIONAL,
1066                        OUT PLSA_STRING *AuthenticationPackageName)
1067 {
1068     PANSI_STRING NameString;
1069     PCHAR NameBuffer;
1070 
1071     TRACE("LsaApInitializePackage(%lu %p %p %p %p)\n",
1072           AuthenticationPackageId, LsaDispatchTable, Database,
1073           Confidentiality, AuthenticationPackageName);
1074 
1075     /* Get the dispatch table entries */
1076     DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession;
1077     DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession;
1078     DispatchTable.AddCredential = LsaDispatchTable->AddCredential;
1079     DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials;
1080     DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential;
1081     DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap;
1082     DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap;
1083     DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer;
1084     DispatchTable.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer;
1085     DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer;
1086     DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer;
1087 
1088     /* Return the package name */
1089     NameString = DispatchTable.AllocateLsaHeap(sizeof(LSA_STRING));
1090     if (NameString == NULL)
1091         return STATUS_INSUFFICIENT_RESOURCES;
1092 
1093     NameBuffer = DispatchTable.AllocateLsaHeap(sizeof(MSV1_0_PACKAGE_NAME));
1094     if (NameBuffer == NULL)
1095     {
1096         DispatchTable.FreeLsaHeap(NameString);
1097         return STATUS_INSUFFICIENT_RESOURCES;
1098     }
1099 
1100     strcpy(NameBuffer, MSV1_0_PACKAGE_NAME);
1101 
1102     RtlInitAnsiString(NameString, NameBuffer);
1103 
1104     *AuthenticationPackageName = (PLSA_STRING)NameString;
1105 
1106     return STATUS_SUCCESS;
1107 }
1108 
1109 
1110 /*
1111  * @unimplemented
1112  */
1113 VOID
1114 NTAPI
1115 LsaApLogonTerminated(IN PLUID LogonId)
1116 {
1117     TRACE("LsaApLogonTerminated()\n");
1118 }
1119 
1120 
1121 /*
1122  * @implemented
1123  */
1124 NTSTATUS
1125 NTAPI
1126 LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
1127                   IN SECURITY_LOGON_TYPE LogonType,
1128                   IN PVOID ProtocolSubmitBuffer,
1129                   IN PVOID ClientBufferBase,
1130                   IN ULONG SubmitBufferSize,
1131                   OUT PVOID *ProfileBuffer,
1132                   OUT PULONG ProfileBufferSize,
1133                   OUT PLUID LogonId,
1134                   OUT PNTSTATUS SubStatus,
1135                   OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
1136                   OUT PVOID *TokenInformation,
1137                   OUT PUNICODE_STRING *AccountName,
1138                   OUT PUNICODE_STRING *AuthenticatingAuthority,
1139                   OUT PUNICODE_STRING *MachineName,
1140                   OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
1141                   OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */
1142 {
1143     PMSV1_0_INTERACTIVE_LOGON LogonInfo;
1144     WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1145     SAMPR_HANDLE ServerHandle = NULL;
1146     SAMPR_HANDLE DomainHandle = NULL;
1147     SAMPR_HANDLE UserHandle = NULL;
1148     PRPC_SID AccountDomainSid = NULL;
1149     RPC_UNICODE_STRING Names[1];
1150     SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
1151     SAMPR_ULONG_ARRAY Use = {0, NULL};
1152     PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
1153     BOOLEAN SessionCreated = FALSE;
1154     LARGE_INTEGER LogonTime;
1155     LARGE_INTEGER AccountExpires;
1156     LARGE_INTEGER PasswordMustChange;
1157     LARGE_INTEGER PasswordLastSet;
1158     DWORD ComputerNameSize;
1159     BOOL SpecialAccount = FALSE;
1160     NTSTATUS Status;
1161 
1162     TRACE("LsaApLogonUser()\n");
1163 
1164     TRACE("LogonType: %lu\n", LogonType);
1165     TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
1166     TRACE("SubmitBufferSize: %lu\n", SubmitBufferSize);
1167 
1168     *ProfileBuffer = NULL;
1169     *ProfileBufferSize = 0;
1170     *SubStatus = STATUS_SUCCESS;
1171     *AccountName = NULL;
1172     *AuthenticatingAuthority = NULL;
1173 
1174     if (LogonType == Interactive ||
1175         LogonType == Batch ||
1176         LogonType == Service)
1177     {
1178         ULONG_PTR PtrOffset;
1179 
1180         LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)ProtocolSubmitBuffer;
1181 
1182         /* Fix-up pointers in the authentication info */
1183         PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
1184 
1185         LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
1186         LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
1187         LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);
1188 
1189         TRACE("Domain: %S\n", LogonInfo->LogonDomainName.Buffer);
1190         TRACE("User: %S\n", LogonInfo->UserName.Buffer);
1191         TRACE("Password: %S\n", LogonInfo->Password.Buffer);
1192     }
1193     else
1194     {
1195         FIXME("LogonType %lu is not supported yet!\n", LogonType);
1196         return STATUS_NOT_IMPLEMENTED;
1197     }
1198 
1199     /* Get the logon time */
1200     NtQuerySystemTime(&LogonTime);
1201 
1202     /* Get the computer name */
1203     ComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
1204     GetComputerNameW(ComputerName, &ComputerNameSize);
1205 
1206     /* Check for special accounts */
1207     if (_wcsicmp(LogonInfo->LogonDomainName.Buffer, L"NT AUTHORITY") == 0)
1208     {
1209         SpecialAccount = TRUE;
1210 
1211         /* Get the authority domain SID */
1212         Status = GetNtAuthorityDomainSid(&AccountDomainSid);
1213         if (!NT_SUCCESS(Status))
1214         {
1215             ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n", Status);
1216             return Status;
1217         }
1218 
1219         if (_wcsicmp(LogonInfo->UserName.Buffer, L"LocalService") == 0)
1220         {
1221             TRACE("SpecialAccount: LocalService\n");
1222 
1223             if (LogonType != Service)
1224                 return STATUS_LOGON_FAILURE;
1225 
1226             UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1227                                        HEAP_ZERO_MEMORY,
1228                                        sizeof(SAMPR_USER_ALL_INFORMATION));
1229             if (UserInfo == NULL)
1230             {
1231                 Status = STATUS_INSUFFICIENT_RESOURCES;
1232                 goto done;
1233             }
1234 
1235             UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
1236             UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
1237         }
1238         else if (_wcsicmp(LogonInfo->UserName.Buffer, L"NetworkService") == 0)
1239         {
1240             TRACE("SpecialAccount: NetworkService\n");
1241 
1242             if (LogonType != Service)
1243                 return STATUS_LOGON_FAILURE;
1244 
1245             UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1246                                        HEAP_ZERO_MEMORY,
1247                                        sizeof(SAMPR_USER_ALL_INFORMATION));
1248             if (UserInfo == NULL)
1249             {
1250                 Status = STATUS_INSUFFICIENT_RESOURCES;
1251                 goto done;
1252             }
1253 
1254             UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID;
1255             UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID;
1256         }
1257         else
1258         {
1259             Status = STATUS_NO_SUCH_USER;
1260             goto done;
1261         }
1262     }
1263     else
1264     {
1265         TRACE("NormalAccount\n");
1266 
1267         /* Get the account domain SID */
1268         Status = GetAccountDomainSid(&AccountDomainSid);
1269         if (!NT_SUCCESS(Status))
1270         {
1271             ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status);
1272             return Status;
1273         }
1274 
1275         /* Connect to the SAM server */
1276         Status = SamIConnect(NULL,
1277                              &ServerHandle,
1278                              SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1279                              TRUE);
1280         if (!NT_SUCCESS(Status))
1281         {
1282             TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
1283             goto done;
1284         }
1285 
1286         /* Open the account domain */
1287         Status = SamrOpenDomain(ServerHandle,
1288                                 DOMAIN_LOOKUP,
1289                                 AccountDomainSid,
1290                                 &DomainHandle);
1291         if (!NT_SUCCESS(Status))
1292         {
1293             ERR("SamrOpenDomain failed (Status %08lx)\n", Status);
1294             goto done;
1295         }
1296 
1297         Names[0].Length = LogonInfo->UserName.Length;
1298         Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
1299         Names[0].Buffer = LogonInfo->UserName.Buffer;
1300 
1301         /* Try to get the RID for the user name */
1302         Status = SamrLookupNamesInDomain(DomainHandle,
1303                                          1,
1304                                          Names,
1305                                          &RelativeIds,
1306                                          &Use);
1307         if (!NT_SUCCESS(Status))
1308         {
1309             ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
1310             Status = STATUS_NO_SUCH_USER;
1311             goto done;
1312         }
1313 
1314         /* Fail, if it is not a user account */
1315         if (Use.Element[0] != SidTypeUser)
1316         {
1317             ERR("Account is not a user account!\n");
1318             Status = STATUS_NO_SUCH_USER;
1319             goto done;
1320         }
1321 
1322         /* Open the user object */
1323         Status = SamrOpenUser(DomainHandle,
1324                               USER_READ_GENERAL | USER_READ_LOGON |
1325                               USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
1326                               RelativeIds.Element[0],
1327                               &UserHandle);
1328         if (!NT_SUCCESS(Status))
1329         {
1330             ERR("SamrOpenUser failed (Status %08lx)\n", Status);
1331             goto done;
1332         }
1333 
1334         Status = SamrQueryInformationUser(UserHandle,
1335                                           UserAllInformation,
1336                                           &UserInfo);
1337         if (!NT_SUCCESS(Status))
1338         {
1339             ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status);
1340             goto done;
1341         }
1342 
1343         TRACE("UserName: %S\n", UserInfo->All.UserName.Buffer);
1344 
1345         /* Check the password */
1346         if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
1347         {
1348             Status = MsvpCheckPassword(&(LogonInfo->Password),
1349                                        UserInfo);
1350             if (!NT_SUCCESS(Status))
1351             {
1352                 ERR("MsvpCheckPassword failed (Status %08lx)\n", Status);
1353                 goto done;
1354             }
1355         }
1356 
1357         /* Check account restrictions for non-administrator accounts */
1358         if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
1359         {
1360             /* Check if the account has been disabled */
1361             if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
1362             {
1363                 ERR("Account disabled!\n");
1364                 *SubStatus = STATUS_ACCOUNT_DISABLED;
1365                 Status = STATUS_ACCOUNT_RESTRICTION;
1366                 goto done;
1367             }
1368 
1369             /* Check if the account has been locked */
1370             if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
1371             {
1372                 ERR("Account locked!\n");
1373                 *SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
1374                 Status = STATUS_ACCOUNT_RESTRICTION;
1375                 goto done;
1376             }
1377 
1378             /* Check if the account expired */
1379             AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
1380             AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;
1381             if (LogonTime.QuadPart >= AccountExpires.QuadPart)
1382             {
1383                 ERR("Account expired!\n");
1384                 *SubStatus = STATUS_ACCOUNT_EXPIRED;
1385                 Status = STATUS_ACCOUNT_RESTRICTION;
1386                 goto done;
1387             }
1388 
1389             /* Check if the password expired */
1390             PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
1391             PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
1392             PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
1393             PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;
1394 
1395             if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
1396             {
1397                 ERR("Password expired!\n");
1398                 if (PasswordLastSet.QuadPart == 0)
1399                     *SubStatus = STATUS_PASSWORD_MUST_CHANGE;
1400                 else
1401                     *SubStatus = STATUS_PASSWORD_EXPIRED;
1402 
1403                 Status = STATUS_ACCOUNT_RESTRICTION;
1404                 goto done;
1405             }
1406 
1407             /* Check logon hours */
1408             if (!MsvpCheckLogonHours(&UserInfo->All.LogonHours, &LogonTime))
1409             {
1410                 ERR("Invalid logon hours!\n");
1411                 *SubStatus = STATUS_INVALID_LOGON_HOURS;
1412                 Status = STATUS_ACCOUNT_RESTRICTION;
1413                 goto done;
1414             }
1415 
1416             /* Check workstations */
1417             if (!MsvpCheckWorkstations(&UserInfo->All.WorkStations, ComputerName))
1418             {
1419                 ERR("Invalid workstation!\n");
1420                 *SubStatus = STATUS_INVALID_WORKSTATION;
1421                 Status = STATUS_ACCOUNT_RESTRICTION;
1422                 goto done;
1423             }
1424         }
1425     }
1426 
1427     /* Return logon information */
1428 
1429     /* Create and return a new logon id */
1430     Status = NtAllocateLocallyUniqueId(LogonId);
1431     if (!NT_SUCCESS(Status))
1432     {
1433         TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status);
1434         goto done;
1435     }
1436 
1437     /* Create the logon session */
1438     Status = DispatchTable.CreateLogonSession(LogonId);
1439     if (!NT_SUCCESS(Status))
1440     {
1441         TRACE("CreateLogonSession failed (Status %08lx)\n", Status);
1442         goto done;
1443     }
1444 
1445     SessionCreated = TRUE;
1446 
1447     /* Build and fill the interactive profile buffer */
1448     Status = BuildInteractiveProfileBuffer(ClientRequest,
1449                                            UserInfo,
1450                                            ComputerName,
1451                                            (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
1452                                            ProfileBufferSize);
1453     if (!NT_SUCCESS(Status))
1454     {
1455         TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status);
1456         goto done;
1457     }
1458 
1459     /* Return the token information type */
1460     *TokenInformationType = LsaTokenInformationV1;
1461 
1462     /* Build and fill the token information buffer */
1463     Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
1464                                          AccountDomainSid,
1465                                          UserInfo,
1466                                          SpecialAccount);
1467     if (!NT_SUCCESS(Status))
1468     {
1469         TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
1470         goto done;
1471     }
1472 
1473 done:
1474     /* Update the logon time/count or the bad password time/count */
1475     if ((UserHandle != NULL) &&
1476         (Status == STATUS_SUCCESS || Status == STATUS_WRONG_PASSWORD))
1477     {
1478         SAMPR_USER_INFO_BUFFER InternalInfo;
1479 
1480         RtlZeroMemory(&InternalInfo, sizeof(InternalInfo));
1481 
1482         if (Status == STATUS_SUCCESS)
1483             InternalInfo.Internal2.Flags = USER_LOGON_SUCCESS;
1484         else
1485             InternalInfo.Internal2.Flags = USER_LOGON_BAD_PASSWORD;
1486 
1487         SamrSetInformationUser(UserHandle,
1488                                UserInternal2Information,
1489                                &InternalInfo);
1490     }
1491 
1492     /* Return the account name */
1493     *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1494     if (*AccountName != NULL)
1495     {
1496         (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length +
1497                                                                sizeof(UNICODE_NULL));
1498         if ((*AccountName)->Buffer != NULL)
1499         {
1500             (*AccountName)->MaximumLength = LogonInfo->UserName.Length +
1501                                             sizeof(UNICODE_NULL);
1502             RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName);
1503         }
1504     }
1505 
1506     /* Return the authenticating authority */
1507     *AuthenticatingAuthority = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1508     if (*AuthenticatingAuthority != NULL)
1509     {
1510         (*AuthenticatingAuthority)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->LogonDomainName.Length +
1511                                                                            sizeof(UNICODE_NULL));
1512         if ((*AuthenticatingAuthority)->Buffer != NULL)
1513         {
1514             (*AuthenticatingAuthority)->MaximumLength = LogonInfo->LogonDomainName.Length +
1515                                                         sizeof(UNICODE_NULL);
1516             RtlCopyUnicodeString(*AuthenticatingAuthority, &LogonInfo->LogonDomainName);
1517         }
1518     }
1519 
1520     /* Return the machine name */
1521     *MachineName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1522     if (*MachineName != NULL)
1523     {
1524         (*MachineName)->Buffer = DispatchTable.AllocateLsaHeap((ComputerNameSize + 1) * sizeof(WCHAR));
1525         if ((*MachineName)->Buffer != NULL)
1526         {
1527             (*MachineName)->MaximumLength = (ComputerNameSize + 1) * sizeof(WCHAR);
1528             (*MachineName)->Length = ComputerNameSize * sizeof(WCHAR);
1529             RtlCopyMemory((*MachineName)->Buffer, ComputerName, (*MachineName)->MaximumLength);
1530         }
1531     }
1532 
1533     if (!NT_SUCCESS(Status))
1534     {
1535         if (SessionCreated != FALSE)
1536             DispatchTable.DeleteLogonSession(LogonId);
1537 
1538         if (*ProfileBuffer != NULL)
1539         {
1540             DispatchTable.FreeClientBuffer(ClientRequest,
1541                                            *ProfileBuffer);
1542             *ProfileBuffer = NULL;
1543         }
1544     }
1545 
1546     if (UserHandle != NULL)
1547         SamrCloseHandle(&UserHandle);
1548 
1549     SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo,
1550                                     UserAllInformation);
1551     SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
1552     SamIFree_SAMPR_ULONG_ARRAY(&Use);
1553 
1554     if (DomainHandle != NULL)
1555         SamrCloseHandle(&DomainHandle);
1556 
1557     if (ServerHandle != NULL)
1558         SamrCloseHandle(&ServerHandle);
1559 
1560     if (AccountDomainSid != NULL)
1561         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
1562 
1563     if (Status == STATUS_NO_SUCH_USER ||
1564         Status == STATUS_WRONG_PASSWORD)
1565     {
1566         *SubStatus = Status;
1567         Status = STATUS_LOGON_FAILURE;
1568     }
1569 
1570     TRACE("LsaApLogonUser done (Status 0x%08lx  SubStatus 0x%08lx)\n", Status, *SubStatus);
1571 
1572     return Status;
1573 }
1574 
1575 
1576 /*
1577  * @unimplemented
1578  */
1579 NTSTATUS
1580 NTAPI
1581 SpLsaModeInitialize(
1582     _In_ ULONG LsaVersion,
1583     _Out_ PULONG PackageVersion,
1584     _Out_ PSECPKG_FUNCTION_TABLE *ppTables,
1585     _Out_ PULONG pcTables)
1586 {
1587     SECPKG_FUNCTION_TABLE Tables[1];
1588 
1589     TRACE("SpLsaModeInitialize(0x%lx %p %p %p)\n",
1590           LsaVersion, PackageVersion, ppTables, pcTables);
1591 
1592     if (LsaVersion != SECPKG_INTERFACE_VERSION)
1593         return STATUS_INVALID_PARAMETER;
1594 
1595     *PackageVersion = SECPKG_INTERFACE_VERSION;
1596 
1597     RtlZeroMemory(&Tables, sizeof(Tables));
1598 
1599     Tables[0].InitializePackage = LsaApInitializePackage;
1600 //    Tables[0].LogonUser = NULL;
1601     Tables[0].CallPackage = (PLSA_AP_CALL_PACKAGE)LsaApCallPackage;
1602     Tables[0].LogonTerminated = LsaApLogonTerminated;
1603     Tables[0].CallPackageUntrusted = LsaApCallPackageUntrusted;
1604     Tables[0].CallPackagePassthrough = (PLSA_AP_CALL_PACKAGE_PASSTHROUGH)LsaApCallPackagePassthrough;
1605 //    Tables[0].LogonUserEx = NULL;
1606     Tables[0].LogonUserEx2 = LsaApLogonUserEx2;
1607 //    Tables[0].Initialize = SpInitialize;
1608 //    Tables[0].Shutdown = NULL;
1609 //    Tables[0].GetInfo = NULL;
1610 //    Tables[0].AcceptCredentials = NULL;
1611 //    Tables[0].SpAcquireCredentialsHandle = NULL;
1612 //    Tables[0].SpQueryCredentialsAttributes = NULL;
1613 //    Tables[0].FreeCredentialsHandle = NULL;
1614 //    Tables[0].SaveCredentials = NULL;
1615 //    Tables[0].GetCredentials = NULL;
1616 //    Tables[0].DeleteCredentials = NULL;
1617 //    Tables[0].InitLsaModeContext = NULL;
1618 //    Tables[0].AcceptLsaModeContext = NULL;
1619 //    Tables[0].DeleteContext = NULL;
1620 //    Tables[0].ApplyControlToken = NULL;
1621 //    Tables[0].GetUserInfo = NULL;
1622 //    Tables[0].GetExtendedInformation = NULL;
1623 //    Tables[0].SpQueryContextAttributes = NULL;
1624 //    Tables[0].SpAddCredentials = NULL;
1625 //    Tables[0].SetExtendedInformation = NULL;
1626 
1627     *ppTables = Tables;
1628     *pcTables = 1;
1629 
1630     return STATUS_SUCCESS;
1631 }
1632 
1633 
1634 /*
1635  * @unimplemented
1636  */
1637 NTSTATUS
1638 WINAPI
1639 SpUserModeInitialize(
1640     _In_ ULONG LsaVersion,
1641     _Out_ PULONG PackageVersion,
1642     _Out_ PSECPKG_USER_FUNCTION_TABLE *ppTables,
1643     _Out_ PULONG pcTables)
1644 {
1645     SECPKG_USER_FUNCTION_TABLE Tables[1];
1646 
1647     TRACE("SpUserModeInitialize(0x%lx %p %p %p)\n",
1648           LsaVersion, PackageVersion, ppTables, pcTables);
1649 
1650     if (LsaVersion != SECPKG_INTERFACE_VERSION)
1651         return STATUS_INVALID_PARAMETER;
1652 
1653     *PackageVersion = SECPKG_INTERFACE_VERSION;
1654 
1655     RtlZeroMemory(&Tables, sizeof(Tables));
1656 
1657 //    Tables[0].InstanceInit = SpInstanceInit;
1658 //    Tables[0].InitUserModeContext = NULL;
1659 //    Tables[0].MakeSignature = NULL;
1660 //    Tables[0].VerifySignature = NULL;
1661 //    Tables[0].SealMessage = NULL;
1662 //    Tables[0].UnsealMessage = NULL;
1663 //    Tables[0].GetContextToken = NULL;
1664 //    Tables[0].SpQueryContextAttributes = NULL;
1665 //    Tables[0].CompleteAuthToken = NULL;
1666 //    Tables[0].DeleteUserModeContext = NULL;
1667 //    Tables[0].FormatCredentials = NULL;
1668 //    Tables[0].MarshallSupplementalCreds = NULL;
1669 //    Tables[0].ExportContext = NULL;
1670 //    Tables[0].ImportContext = NULL;
1671 
1672     *ppTables = Tables;
1673     *pcTables = 1;
1674 
1675     return STATUS_SUCCESS;
1676 }
1677 
1678 /* EOF */
1679