xref: /reactos/dll/win32/msv1_0/msv1_0.c (revision 8a978a17)
1 /*
2  * PROJECT:     Authentication Package DLL
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        dll/win32/msv1_0/msv1_0.c
5  * PURPOSE:     Main file
6  * COPYRIGHT:   Copyright 2013 Eric Kohl
7  */
8 
9 /* INCLUDES ****************************************************************/
10 
11 #include "precomp.h"
12 
13 WINE_DEFAULT_DEBUG_CHANNEL(msv1_0);
14 
15 
16 /* 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     NTSTATUS Status;
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 
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("MsvpChangePassword()\n");
528 
529     /* Parameters validation */
530 
531     if (SubmitBufferLength < sizeof(MSV1_0_CHANGEPASSWORD_REQUEST))
532     {
533         ERR("Invalid SubmitBufferLength %lu\n", SubmitBufferLength);
534         return STATUS_INVALID_PARAMETER;
535     }
536 
537     RequestBuffer = (PMSV1_0_CHANGEPASSWORD_REQUEST)ProtocolSubmitBuffer;
538 
539     /* Fix-up pointers in the request buffer info */
540     PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
541 
542     Status = RtlValidateUnicodeString(0, &RequestBuffer->DomainName);
543     if (!NT_SUCCESS(Status))
544         return STATUS_INVALID_PARAMETER;
545     // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
546     RequestBuffer->DomainName.Buffer = FIXUP_POINTER(RequestBuffer->DomainName.Buffer, PtrOffset);
547     RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length;
548 
549     Status = RtlValidateUnicodeString(0, &RequestBuffer->AccountName);
550     if (!NT_SUCCESS(Status))
551         return STATUS_INVALID_PARAMETER;
552     // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
553     RequestBuffer->AccountName.Buffer = FIXUP_POINTER(RequestBuffer->AccountName.Buffer, PtrOffset);
554     RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length;
555 
556     Status = RtlValidateUnicodeString(0, &RequestBuffer->OldPassword);
557     if (!NT_SUCCESS(Status))
558         return STATUS_INVALID_PARAMETER;
559     // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
560     RequestBuffer->OldPassword.Buffer = FIXUP_POINTER(RequestBuffer->OldPassword.Buffer, PtrOffset);
561     RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length;
562 
563     Status = RtlValidateUnicodeString(0, &RequestBuffer->NewPassword);
564     if (!NT_SUCCESS(Status))
565         return STATUS_INVALID_PARAMETER;
566     // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
567     RequestBuffer->NewPassword.Buffer = FIXUP_POINTER(RequestBuffer->NewPassword.Buffer, PtrOffset);
568     RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length;
569 
570     TRACE("Domain: %S\n", RequestBuffer->DomainName.Buffer);
571     TRACE("Account: %S\n", RequestBuffer->AccountName.Buffer);
572     TRACE("Old Password: %S\n", RequestBuffer->OldPassword.Buffer);
573     TRACE("New Password: %S\n", RequestBuffer->NewPassword.Buffer);
574 
575     /* Connect to the SAM server */
576     Status = SamIConnect(NULL,
577                          &ServerHandle,
578                          SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
579                          TRUE);
580     if (!NT_SUCCESS(Status))
581     {
582         TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
583         goto done;
584     }
585 
586     /* Get the domain SID */
587     Status = SamrLookupDomainInSamServer(ServerHandle,
588                                          (PRPC_UNICODE_STRING)&RequestBuffer->DomainName,
589                                          &DomainSid);
590     if (!NT_SUCCESS(Status))
591     {
592         TRACE("SamrLookupDomainInSamServer failed (Status %08lx)\n", Status);
593         goto done;
594     }
595 
596     /* Open the domain */
597     Status = SamrOpenDomain(ServerHandle,
598                             DOMAIN_LOOKUP,
599                             DomainSid,
600                             &DomainHandle);
601     if (!NT_SUCCESS(Status))
602     {
603         TRACE("SamrOpenDomain failed (Status %08lx)\n", Status);
604         goto done;
605     }
606 
607     Names[0].Length = RequestBuffer->AccountName.Length;
608     Names[0].MaximumLength = RequestBuffer->AccountName.MaximumLength;
609     Names[0].Buffer = RequestBuffer->AccountName.Buffer;
610 
611     /* Try to get the RID for the user name */
612     Status = SamrLookupNamesInDomain(DomainHandle,
613                                      1,
614                                      Names,
615                                      &RelativeIds,
616                                      &Use);
617     if (!NT_SUCCESS(Status))
618     {
619         TRACE("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
620         Status = STATUS_NO_SUCH_USER;
621         goto done;
622     }
623 
624     /* Fail, if it is not a user account */
625     if (Use.Element[0] != SidTypeUser)
626     {
627         TRACE("Account is not a user account!\n");
628         Status = STATUS_NO_SUCH_USER;
629         goto done;
630     }
631 
632     /* Open the user object */
633     Status = SamrOpenUser(DomainHandle,
634                           USER_CHANGE_PASSWORD,
635                           RelativeIds.Element[0],
636                           &UserHandle);
637     if (!NT_SUCCESS(Status))
638     {
639         TRACE("SamrOpenUser failed (Status %08lx)\n", Status);
640         goto done;
641     }
642 
643 
644     /* Calculate the NT hash for the old password */
645     Status = SystemFunction007(&RequestBuffer->OldPassword,
646                                (LPBYTE)&OldNtPassword);
647     if (!NT_SUCCESS(Status))
648     {
649         TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
650         goto done;
651     }
652 
653     /* Calculate the NT hash for the new password */
654     Status = SystemFunction007(&RequestBuffer->NewPassword,
655                                (LPBYTE)&NewNtPassword);
656     if (!NT_SUCCESS(Status))
657     {
658         TRACE("SystemFunction007 failed (Status 0x%08lx)\n", Status);
659         goto done;
660     }
661 
662     /* Calculate the LM password and hash for the old password */
663     LmPwdString.Length = 15;
664     LmPwdString.MaximumLength = 15;
665     LmPwdString.Buffer = LmPwdBuffer;
666     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
667 
668     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
669                                                &RequestBuffer->OldPassword,
670                                                FALSE);
671     if (NT_SUCCESS(Status))
672     {
673         /* Calculate the LM hash value of the password */
674         Status = SystemFunction006(LmPwdString.Buffer,
675                                    (LPSTR)&OldLmPassword);
676         if (NT_SUCCESS(Status))
677         {
678             OldLmPasswordPresent = TRUE;
679         }
680     }
681 
682     /* Calculate the LM password and hash for the new password */
683     LmPwdString.Length = 15;
684     LmPwdString.MaximumLength = 15;
685     LmPwdString.Buffer = LmPwdBuffer;
686     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
687 
688     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
689                                                &RequestBuffer->NewPassword,
690                                                FALSE);
691     if (NT_SUCCESS(Status))
692     {
693         /* Calculate the LM hash value of the password */
694         Status = SystemFunction006(LmPwdString.Buffer,
695                                    (LPSTR)&NewLmPassword);
696         if (NT_SUCCESS(Status))
697         {
698             NewLmPasswordPresent = TRUE;
699         }
700     }
701 
702     /* Encrypt the old and new LM passwords, if they exist */
703     if (OldLmPasswordPresent && NewLmPasswordPresent)
704     {
705         /* Encrypt the old LM password */
706         Status = SystemFunction012((const BYTE *)&OldLmPassword,
707                                    (const BYTE *)&NewLmPassword,
708                                    (LPBYTE)&OldLmEncryptedWithNewLm);
709         if (!NT_SUCCESS(Status))
710         {
711             TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
712             goto done;
713         }
714 
715         /* Encrypt the new LM password */
716         Status = SystemFunction012((const BYTE *)&NewLmPassword,
717                                    (const BYTE *)&OldLmPassword,
718                                    (LPBYTE)&NewLmEncryptedWithOldLm);
719         if (!NT_SUCCESS(Status))
720         {
721             TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
722             goto done;
723         }
724 
725         pOldLmEncryptedWithNewLm = &OldLmEncryptedWithNewLm;
726         pNewLmEncryptedWithOldLm = &NewLmEncryptedWithOldLm;
727     }
728 
729     /* Encrypt the old NT password */
730     Status = SystemFunction012((const BYTE *)&OldNtPassword,
731                                (const BYTE *)&NewNtPassword,
732                                (LPBYTE)&OldNtEncryptedWithNewNt);
733     if (!NT_SUCCESS(Status))
734     {
735         TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
736         goto done;
737     }
738 
739     /* Encrypt the new NT password */
740     Status = SystemFunction012((const BYTE *)&NewNtPassword,
741                                (const BYTE *)&OldNtPassword,
742                                (LPBYTE)&NewNtEncryptedWithOldNt);
743     if (!NT_SUCCESS(Status))
744     {
745         TRACE("SystemFunction012 failed (Status 0x%08lx)\n", Status);
746         goto done;
747     }
748 
749     /* Change the password */
750     Status = SamrChangePasswordUser(UserHandle,
751                                     OldLmPasswordPresent && NewLmPasswordPresent,
752                                     pOldLmEncryptedWithNewLm,
753                                     pNewLmEncryptedWithOldLm,
754                                     TRUE,
755                                     &OldNtEncryptedWithNewNt,
756                                     &NewNtEncryptedWithOldNt,
757                                     FALSE,
758                                     NULL,
759                                     FALSE,
760                                     NULL);
761     if (!NT_SUCCESS(Status))
762     {
763         TRACE("SamrChangePasswordUser failed (Status %08lx)\n", Status);
764         goto done;
765     }
766 
767 done:
768     if (UserHandle != NULL)
769         SamrCloseHandle(&UserHandle);
770 
771     SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
772     SamIFree_SAMPR_ULONG_ARRAY(&Use);
773 
774     if (DomainHandle != NULL)
775         SamrCloseHandle(&DomainHandle);
776 
777     if (DomainSid != NULL)
778         SamIFreeVoid(DomainSid);
779 
780     if (ServerHandle != NULL)
781         SamrCloseHandle(&ServerHandle);
782 
783     return Status;
784 }
785 
786 
787 static
788 NTSTATUS
789 MsvpCheckPassword(PUNICODE_STRING UserPassword,
790                   PSAMPR_USER_INFO_BUFFER UserInfo)
791 {
792     ENCRYPTED_NT_OWF_PASSWORD UserNtPassword;
793     ENCRYPTED_LM_OWF_PASSWORD UserLmPassword;
794     BOOLEAN UserLmPasswordPresent = FALSE;
795     BOOLEAN UserNtPasswordPresent = FALSE;
796     OEM_STRING LmPwdString;
797     CHAR LmPwdBuffer[15];
798     NTSTATUS Status;
799 
800     TRACE("(%p %p)\n", UserPassword, UserInfo);
801 
802     /* Calculate the LM password and hash for the users password */
803     LmPwdString.Length = 15;
804     LmPwdString.MaximumLength = 15;
805     LmPwdString.Buffer = LmPwdBuffer;
806     ZeroMemory(LmPwdString.Buffer, LmPwdString.MaximumLength);
807 
808     Status = RtlUpcaseUnicodeStringToOemString(&LmPwdString,
809                                                UserPassword,
810                                                FALSE);
811     if (NT_SUCCESS(Status))
812     {
813         /* Calculate the LM hash value of the users password */
814         Status = SystemFunction006(LmPwdString.Buffer,
815                                    (LPSTR)&UserLmPassword);
816         if (NT_SUCCESS(Status))
817         {
818             UserLmPasswordPresent = TRUE;
819         }
820     }
821 
822     /* Calculate the NT hash of the users password */
823     Status = SystemFunction007(UserPassword,
824                                (LPBYTE)&UserNtPassword);
825     if (NT_SUCCESS(Status))
826     {
827         UserNtPasswordPresent = TRUE;
828     }
829 
830     Status = STATUS_WRONG_PASSWORD;
831 
832     /* Succeed, if no password has been set */
833     if (UserInfo->All.NtPasswordPresent == FALSE &&
834         UserInfo->All.LmPasswordPresent == FALSE)
835     {
836         TRACE("No password check!\n");
837         Status = STATUS_SUCCESS;
838         goto done;
839     }
840 
841     /* Succeed, if NT password matches */
842     if (UserNtPasswordPresent && UserInfo->All.NtPasswordPresent)
843     {
844         TRACE("Check NT password hashes:\n");
845         if (RtlEqualMemory(&UserNtPassword,
846                            UserInfo->All.NtOwfPassword.Buffer,
847                            sizeof(ENCRYPTED_NT_OWF_PASSWORD)))
848         {
849             TRACE("  success!\n");
850             Status = STATUS_SUCCESS;
851             goto done;
852         }
853 
854         TRACE("  failed!\n");
855     }
856 
857     /* Succeed, if LM password matches */
858     if (UserLmPasswordPresent && UserInfo->All.LmPasswordPresent)
859     {
860         TRACE("Check LM password hashes:\n");
861         if (RtlEqualMemory(&UserLmPassword,
862                            UserInfo->All.LmOwfPassword.Buffer,
863                            sizeof(ENCRYPTED_LM_OWF_PASSWORD)))
864         {
865             TRACE("  success!\n");
866             Status = STATUS_SUCCESS;
867             goto done;
868         }
869         TRACE("  failed!\n");
870     }
871 
872 done:
873     return Status;
874 }
875 
876 
877 static
878 BOOL
879 MsvpCheckLogonHours(
880     _In_ PSAMPR_LOGON_HOURS LogonHours,
881     _In_ PLARGE_INTEGER LogonTime)
882 {
883 #if 0
884     LARGE_INTEGER LocalLogonTime;
885     TIME_FIELDS TimeFields;
886     USHORT MinutesPerUnit, Offset;
887     BOOL bFound;
888 
889     FIXME("MsvpCheckLogonHours(%p %p)\n", LogonHours, LogonTime);
890 
891     if (LogonHours->UnitsPerWeek == 0 || LogonHours->LogonHours == NULL)
892     {
893         FIXME("No logon hours!\n");
894         return TRUE;
895     }
896 
897     RtlSystemTimeToLocalTime(LogonTime, &LocalLogonTime);
898     RtlTimeToTimeFields(&LocalLogonTime, &TimeFields);
899 
900     FIXME("UnitsPerWeek: %u\n", LogonHours->UnitsPerWeek);
901     MinutesPerUnit = 10080 / LogonHours->UnitsPerWeek;
902 
903     Offset = ((TimeFields.Weekday * 24 + TimeFields.Hour) * 60 + TimeFields.Minute) / MinutesPerUnit;
904     FIXME("Offset: %us\n", Offset);
905 
906     bFound = (BOOL)(LogonHours->LogonHours[Offset / 8] & (1 << (Offset % 8)));
907     FIXME("Logon permitted: %s\n", bFound ? "Yes" : "No");
908 
909     return bFound;
910 #endif
911     return TRUE;
912 }
913 
914 
915 static
916 BOOL
917 MsvpCheckWorkstations(
918     _In_ PRPC_UNICODE_STRING WorkStations,
919     _In_ PWSTR ComputerName)
920 {
921     PWSTR pStart, pEnd;
922     BOOL bFound = FALSE;
923 
924     TRACE("MsvpCheckWorkstations(%p %S)\n", WorkStations, ComputerName);
925 
926     if (WorkStations->Length == 0 || WorkStations->Buffer == NULL)
927     {
928         TRACE("No workstations!\n");
929         return TRUE;
930     }
931 
932     TRACE("Workstations: %wZ\n", WorkStations);
933 
934     pStart = WorkStations->Buffer;
935     for (;;)
936     {
937         pEnd = wcschr(pStart, L',');
938         if (pEnd != NULL)
939             *pEnd = UNICODE_NULL;
940 
941         TRACE("Comparing '%S' and '%S'\n", ComputerName, pStart);
942         if (_wcsicmp(ComputerName, pStart) == 0)
943         {
944             bFound = TRUE;
945             if (pEnd != NULL)
946                 *pEnd = L',';
947             break;
948         }
949 
950         if (pEnd == NULL)
951             break;
952 
953         *pEnd = L',';
954         pStart = pEnd + 1;
955     }
956 
957     TRACE("Found allowed workstation: %s\n", (bFound) ? "Yes" : "No");
958 
959     return bFound;
960 }
961 
962 
963 /*
964  * @unimplemented
965  */
966 NTSTATUS
967 NTAPI
968 LsaApCallPackage(IN PLSA_CLIENT_REQUEST ClientRequest,
969                  IN PVOID ProtocolSubmitBuffer,
970                  IN PVOID ClientBufferBase,
971                  IN ULONG SubmitBufferLength,
972                  OUT PVOID *ProtocolReturnBuffer,
973                  OUT PULONG ReturnBufferLength,
974                  OUT PNTSTATUS ProtocolStatus)
975 {
976     NTSTATUS Status;
977     MSV1_0_PROTOCOL_MESSAGE_TYPE MessageType;
978 
979     TRACE("LsaApCallPackage()\n");
980 
981     if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
982         return STATUS_INVALID_PARAMETER;
983 
984     MessageType = *((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
985 
986     *ProtocolReturnBuffer = NULL;
987     *ReturnBufferLength = 0;
988 
989     switch (MessageType)
990     {
991         case MsV1_0Lm20ChallengeRequest:
992         case MsV1_0Lm20GetChallengeResponse:
993             Status = STATUS_NOT_IMPLEMENTED;
994             break;
995 
996         case MsV1_0EnumerateUsers:
997         case MsV1_0GetUserInfo:
998         case MsV1_0ReLogonUsers:
999             Status = STATUS_INVALID_PARAMETER;
1000             break;
1001 
1002         case MsV1_0ChangePassword:
1003             Status = MsvpChangePassword(ClientRequest,
1004                                         ProtocolSubmitBuffer,
1005                                         ClientBufferBase,
1006                                         SubmitBufferLength,
1007                                         ProtocolReturnBuffer,
1008                                         ReturnBufferLength,
1009                                         ProtocolStatus);
1010             break;
1011 
1012         case MsV1_0ChangeCachedPassword:
1013         case MsV1_0GenericPassthrough:
1014         case MsV1_0CacheLogon:
1015         case MsV1_0SubAuth:
1016         case MsV1_0DeriveCredential:
1017         case MsV1_0CacheLookup:
1018             Status = STATUS_NOT_IMPLEMENTED;
1019             break;
1020 
1021         default:
1022             return STATUS_INVALID_PARAMETER;
1023     }
1024 
1025     return Status;
1026 }
1027 
1028 
1029 /*
1030  * @unimplemented
1031  */
1032 NTSTATUS
1033 NTAPI
1034 LsaApCallPackagePassthrough(IN PLSA_CLIENT_REQUEST ClientRequest,
1035                             IN PVOID ProtocolSubmitBuffer,
1036                             IN PVOID ClientBufferBase,
1037                             IN ULONG SubmitBufferLength,
1038                             OUT PVOID *ProtocolReturnBuffer,
1039                             OUT PULONG ReturnBufferLength,
1040                             OUT PNTSTATUS ProtocolStatus)
1041 {
1042     TRACE("LsaApCallPackagePassthrough()\n");
1043     return STATUS_NOT_IMPLEMENTED;
1044 }
1045 
1046 
1047 /*
1048  * @implemented
1049  */
1050 NTSTATUS
1051 NTAPI
1052 LsaApCallPackageUntrusted(IN PLSA_CLIENT_REQUEST ClientRequest,
1053                           IN PVOID ProtocolSubmitBuffer,
1054                           IN PVOID ClientBufferBase,
1055                           IN ULONG SubmitBufferLength,
1056                           OUT PVOID *ProtocolReturnBuffer,
1057                           OUT PULONG ReturnBufferLength,
1058                           OUT PNTSTATUS ProtocolStatus)
1059 {
1060     ULONG MessageType;
1061     NTSTATUS Status;
1062 
1063     TRACE("LsaApCallPackageUntrusted()\n");
1064 
1065     if (SubmitBufferLength < sizeof(MSV1_0_PROTOCOL_MESSAGE_TYPE))
1066         return STATUS_INVALID_PARAMETER;
1067 
1068     MessageType = (ULONG)*((PMSV1_0_PROTOCOL_MESSAGE_TYPE)ProtocolSubmitBuffer);
1069 
1070     *ProtocolReturnBuffer = NULL;
1071     *ReturnBufferLength = 0;
1072 
1073     if (MessageType == MsV1_0ChangePassword)
1074         Status = MsvpChangePassword(ClientRequest,
1075                                     ProtocolSubmitBuffer,
1076                                     ClientBufferBase,
1077                                     SubmitBufferLength,
1078                                     ProtocolReturnBuffer,
1079                                     ReturnBufferLength,
1080                                     ProtocolStatus);
1081     else
1082         Status = STATUS_ACCESS_DENIED;
1083 
1084     return Status;
1085 }
1086 
1087 
1088 /*
1089  * @implemented
1090  */
1091 NTSTATUS
1092 NTAPI
1093 LsaApInitializePackage(IN ULONG AuthenticationPackageId,
1094                        IN PLSA_DISPATCH_TABLE LsaDispatchTable,
1095                        IN PLSA_STRING Database OPTIONAL,
1096                        IN PLSA_STRING Confidentiality OPTIONAL,
1097                        OUT PLSA_STRING *AuthenticationPackageName)
1098 {
1099     PANSI_STRING NameString;
1100     PCHAR NameBuffer;
1101 
1102     TRACE("LsaApInitializePackage(%lu %p %p %p %p)\n",
1103           AuthenticationPackageId, LsaDispatchTable, Database,
1104           Confidentiality, AuthenticationPackageName);
1105 
1106     /* Get the dispatch table entries */
1107     DispatchTable.CreateLogonSession = LsaDispatchTable->CreateLogonSession;
1108     DispatchTable.DeleteLogonSession = LsaDispatchTable->DeleteLogonSession;
1109     DispatchTable.AddCredential = LsaDispatchTable->AddCredential;
1110     DispatchTable.GetCredentials = LsaDispatchTable->GetCredentials;
1111     DispatchTable.DeleteCredential = LsaDispatchTable->DeleteCredential;
1112     DispatchTable.AllocateLsaHeap = LsaDispatchTable->AllocateLsaHeap;
1113     DispatchTable.FreeLsaHeap = LsaDispatchTable->FreeLsaHeap;
1114     DispatchTable.AllocateClientBuffer = LsaDispatchTable->AllocateClientBuffer;
1115     DispatchTable.FreeClientBuffer = LsaDispatchTable->FreeClientBuffer;
1116     DispatchTable.CopyToClientBuffer = LsaDispatchTable->CopyToClientBuffer;
1117     DispatchTable.CopyFromClientBuffer = LsaDispatchTable->CopyFromClientBuffer;
1118 
1119     /* Return the package name */
1120     NameString = DispatchTable.AllocateLsaHeap(sizeof(LSA_STRING));
1121     if (NameString == NULL)
1122         return STATUS_INSUFFICIENT_RESOURCES;
1123 
1124     NameBuffer = DispatchTable.AllocateLsaHeap(sizeof(MSV1_0_PACKAGE_NAME));
1125     if (NameBuffer == NULL)
1126     {
1127         DispatchTable.FreeLsaHeap(NameString);
1128         return STATUS_INSUFFICIENT_RESOURCES;
1129     }
1130 
1131     strcpy(NameBuffer, MSV1_0_PACKAGE_NAME);
1132 
1133     RtlInitAnsiString(NameString, NameBuffer);
1134 
1135     *AuthenticationPackageName = (PLSA_STRING)NameString;
1136 
1137     return STATUS_SUCCESS;
1138 }
1139 
1140 
1141 /*
1142  * @unimplemented
1143  */
1144 VOID
1145 NTAPI
1146 LsaApLogonTerminated(IN PLUID LogonId)
1147 {
1148     TRACE("LsaApLogonTerminated()\n");
1149 }
1150 
1151 
1152 /*
1153  * @implemented
1154  */
1155 NTSTATUS
1156 NTAPI
1157 LsaApLogonUserEx2(IN PLSA_CLIENT_REQUEST ClientRequest,
1158                   IN SECURITY_LOGON_TYPE LogonType,
1159                   IN PVOID ProtocolSubmitBuffer,
1160                   IN PVOID ClientBufferBase,
1161                   IN ULONG SubmitBufferSize,
1162                   OUT PVOID *ProfileBuffer,
1163                   OUT PULONG ProfileBufferSize,
1164                   OUT PLUID LogonId,
1165                   OUT PNTSTATUS SubStatus,
1166                   OUT PLSA_TOKEN_INFORMATION_TYPE TokenInformationType,
1167                   OUT PVOID *TokenInformation,
1168                   OUT PUNICODE_STRING *AccountName,
1169                   OUT PUNICODE_STRING *AuthenticatingAuthority,
1170                   OUT PUNICODE_STRING *MachineName,
1171                   OUT PSECPKG_PRIMARY_CRED PrimaryCredentials, /* Not supported yet */
1172                   OUT PSECPKG_SUPPLEMENTAL_CRED_ARRAY *SupplementalCredentials) /* Not supported yet */
1173 {
1174     static const UNICODE_STRING NtAuthorityU = RTL_CONSTANT_STRING(L"NT AUTHORITY");
1175     static const UNICODE_STRING LocalServiceU = RTL_CONSTANT_STRING(L"LocalService");
1176     static const UNICODE_STRING NetworkServiceU = RTL_CONSTANT_STRING(L"NetworkService");
1177 
1178     NTSTATUS Status;
1179     PMSV1_0_INTERACTIVE_LOGON LogonInfo;
1180     WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1181     SAMPR_HANDLE ServerHandle = NULL;
1182     SAMPR_HANDLE DomainHandle = NULL;
1183     SAMPR_HANDLE UserHandle = NULL;
1184     PRPC_SID AccountDomainSid = NULL;
1185     RPC_UNICODE_STRING Names[1];
1186     SAMPR_ULONG_ARRAY RelativeIds = {0, NULL};
1187     SAMPR_ULONG_ARRAY Use = {0, NULL};
1188     PSAMPR_USER_INFO_BUFFER UserInfo = NULL;
1189     BOOLEAN SessionCreated = FALSE;
1190     LARGE_INTEGER LogonTime;
1191     LARGE_INTEGER AccountExpires;
1192     LARGE_INTEGER PasswordMustChange;
1193     LARGE_INTEGER PasswordLastSet;
1194     DWORD ComputerNameSize;
1195     BOOL SpecialAccount = FALSE;
1196     UCHAR LogonPassHash;
1197     PUNICODE_STRING ErasePassword = NULL;
1198 
1199     TRACE("LsaApLogonUserEx2()\n");
1200 
1201     TRACE("LogonType: %lu\n", LogonType);
1202     TRACE("ProtocolSubmitBuffer: %p\n", ProtocolSubmitBuffer);
1203     TRACE("SubmitBufferSize: %lu\n", SubmitBufferSize);
1204 
1205     *ProfileBuffer = NULL;
1206     *ProfileBufferSize = 0;
1207     *SubStatus = STATUS_SUCCESS;
1208     *AccountName = NULL;
1209     *AuthenticatingAuthority = NULL;
1210 
1211     /* Parameters validation */
1212     if (LogonType == Interactive ||
1213         LogonType == Batch ||
1214         LogonType == Service)
1215     {
1216         ULONG_PTR PtrOffset;
1217 
1218         if (SubmitBufferSize < sizeof(MSV1_0_INTERACTIVE_LOGON))
1219         {
1220             ERR("Invalid SubmitBufferSize %lu\n", SubmitBufferSize);
1221             return STATUS_INVALID_PARAMETER;
1222         }
1223 
1224         LogonInfo = (PMSV1_0_INTERACTIVE_LOGON)ProtocolSubmitBuffer;
1225 
1226         if (LogonInfo->MessageType != MsV1_0InteractiveLogon &&
1227             LogonInfo->MessageType != MsV1_0WorkstationUnlockLogon)
1228         {
1229             ERR("Invalid MessageType %lu\n", LogonInfo->MessageType);
1230             return STATUS_BAD_VALIDATION_CLASS;
1231         }
1232 
1233 #if 0   // FIXME: These checks happen to be done on Windows. We however keep them general on ReactOS for now...
1234         if (LogonInfo->UserName.Length > 512) // CRED_MAX_STRING_LENGTH * sizeof(WCHAR) or (CREDUI_MAX_USERNAME_LENGTH (== CRED_MAX_USERNAME_LENGTH) - 1) * sizeof(WCHAR)
1235         {
1236             ERR("UserName too long (%lu, maximum 512)\n", LogonInfo->UserName.Length);
1237             return STATUS_NAME_TOO_LONG;
1238         }
1239         if (LogonInfo->Password.Length > 512) // CREDUI_MAX_PASSWORD_LENGTH * sizeof(WCHAR)
1240         {
1241             ERR("Password too long (%lu, maximum 512)\n", LogonInfo->Password.Length);
1242             return STATUS_NAME_TOO_LONG;
1243         }
1244 #endif
1245 
1246         /* Fix-up pointers in the authentication info */
1247         PtrOffset = (ULONG_PTR)ProtocolSubmitBuffer - (ULONG_PTR)ClientBufferBase;
1248 
1249         /* LogonDomainName is optional and can be an empty string */
1250         if (LogonInfo->LogonDomainName.Length)
1251         {
1252             // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
1253             LogonInfo->LogonDomainName.Buffer = FIXUP_POINTER(LogonInfo->LogonDomainName.Buffer, PtrOffset);
1254             LogonInfo->LogonDomainName.MaximumLength = LogonInfo->LogonDomainName.Length;
1255         }
1256         else
1257         {
1258             LogonInfo->LogonDomainName.Buffer = NULL;
1259             LogonInfo->LogonDomainName.MaximumLength = 0;
1260         }
1261         Status = RtlValidateUnicodeString(0, &LogonInfo->LogonDomainName);
1262         if (!NT_SUCCESS(Status))
1263             return STATUS_INVALID_PARAMETER;
1264 
1265         /* UserName is mandatory and cannot be an empty string */
1266         // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
1267         LogonInfo->UserName.Buffer = FIXUP_POINTER(LogonInfo->UserName.Buffer, PtrOffset);
1268         LogonInfo->UserName.MaximumLength = LogonInfo->UserName.Length;
1269 
1270         Status = RtlValidateUnicodeString(0, &LogonInfo->UserName);
1271         if (!NT_SUCCESS(Status))
1272             return STATUS_INVALID_PARAMETER;
1273 
1274         /* MS docs says max length is 0xFF bytes. But thats not the full story:
1275          *
1276          * A Quote from https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.kernel/eFGcCo_ZObk:
1277          * "... At least on my WinXP SP2. Domain and UserName are passed
1278          * in clear text, but the Password is NOT. ..."
1279          *
1280          * If the higher byte of length != 0 we have to use RtlRunDecodeUnicodeString.
1281          */
1282         LogonPassHash = (LogonInfo->Password.Length >> 8) & 0xFF;
1283         LogonInfo->Password.Length = LogonInfo->Password.Length & 0xFF;
1284 
1285         /* Password is optional and can be an empty string */
1286         if (LogonInfo->Password.Length)
1287         {
1288             // TODO: Check for Buffer limits wrt. ClientBufferBase and alignment.
1289             LogonInfo->Password.Buffer = FIXUP_POINTER(LogonInfo->Password.Buffer, PtrOffset);
1290             LogonInfo->Password.MaximumLength = LogonInfo->Password.Length;
1291         }
1292         else
1293         {
1294             LogonInfo->Password.Buffer = NULL;
1295             LogonInfo->Password.MaximumLength = 0;
1296         }
1297 
1298         /* Decode password */
1299         if (LogonPassHash > 0)
1300         {
1301             RtlRunDecodeUnicodeString(LogonPassHash, &LogonInfo->Password);
1302         }
1303 
1304         /* ErasePassword will be "erased" before we return */
1305         ErasePassword = &LogonInfo->Password;
1306 
1307         Status = RtlValidateUnicodeString(0, &LogonInfo->Password);
1308         if (!NT_SUCCESS(Status))
1309             return STATUS_INVALID_PARAMETER;
1310 
1311         TRACE("Domain: %wZ\n", &LogonInfo->LogonDomainName);
1312         TRACE("User: %wZ\n", &LogonInfo->UserName);
1313         TRACE("Password: %wZ\n", &LogonInfo->Password);
1314 
1315         // TODO: If LogonType == Service, do some extra work using LogonInfo->Password.
1316     }
1317     else
1318     {
1319         FIXME("LogonType %lu is not supported yet!\n", LogonType);
1320         return STATUS_NOT_IMPLEMENTED;
1321     }
1322     // TODO: Add other LogonType validity checks.
1323 
1324     /* Get the logon time */
1325     NtQuerySystemTime(&LogonTime);
1326 
1327     /* Get the computer name */
1328     ComputerNameSize = ARRAYSIZE(ComputerName);
1329     GetComputerNameW(ComputerName, &ComputerNameSize);
1330 
1331     /* Check for special accounts */
1332     // FIXME: Windows does not do this that way!! (msv1_0 does not contain these hardcoded values)
1333     if (RtlEqualUnicodeString(&LogonInfo->LogonDomainName, &NtAuthorityU, TRUE))
1334     {
1335         SpecialAccount = TRUE;
1336 
1337         /* Get the authority domain SID */
1338         Status = GetNtAuthorityDomainSid(&AccountDomainSid);
1339         if (!NT_SUCCESS(Status))
1340         {
1341             ERR("GetNtAuthorityDomainSid() failed (Status 0x%08lx)\n", Status);
1342             return Status;
1343         }
1344 
1345         if (RtlEqualUnicodeString(&LogonInfo->UserName, &LocalServiceU, TRUE))
1346         {
1347             TRACE("SpecialAccount: LocalService\n");
1348 
1349             if (LogonType != Service)
1350                 return STATUS_LOGON_FAILURE;
1351 
1352             UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1353                                        HEAP_ZERO_MEMORY,
1354                                        sizeof(SAMPR_USER_ALL_INFORMATION));
1355             if (UserInfo == NULL)
1356             {
1357                 Status = STATUS_INSUFFICIENT_RESOURCES;
1358                 goto done;
1359             }
1360 
1361             UserInfo->All.UserId = SECURITY_LOCAL_SERVICE_RID;
1362             UserInfo->All.PrimaryGroupId = SECURITY_LOCAL_SERVICE_RID;
1363         }
1364         else if (RtlEqualUnicodeString(&LogonInfo->UserName, &NetworkServiceU, TRUE))
1365         {
1366             TRACE("SpecialAccount: NetworkService\n");
1367 
1368             if (LogonType != Service)
1369                 return STATUS_LOGON_FAILURE;
1370 
1371             UserInfo = RtlAllocateHeap(RtlGetProcessHeap(),
1372                                        HEAP_ZERO_MEMORY,
1373                                        sizeof(SAMPR_USER_ALL_INFORMATION));
1374             if (UserInfo == NULL)
1375             {
1376                 Status = STATUS_INSUFFICIENT_RESOURCES;
1377                 goto done;
1378             }
1379 
1380             UserInfo->All.UserId = SECURITY_NETWORK_SERVICE_RID;
1381             UserInfo->All.PrimaryGroupId = SECURITY_NETWORK_SERVICE_RID;
1382         }
1383         else
1384         {
1385             Status = STATUS_NO_SUCH_USER;
1386             goto done;
1387         }
1388     }
1389     else
1390     {
1391         TRACE("NormalAccount\n");
1392 
1393         /* Get the account domain SID */
1394         Status = GetAccountDomainSid(&AccountDomainSid);
1395         if (!NT_SUCCESS(Status))
1396         {
1397             ERR("GetAccountDomainSid() failed (Status 0x%08lx)\n", Status);
1398             return Status;
1399         }
1400 
1401         /* Connect to the SAM server */
1402         Status = SamIConnect(NULL,
1403                              &ServerHandle,
1404                              SAM_SERVER_CONNECT | SAM_SERVER_LOOKUP_DOMAIN,
1405                              TRUE);
1406         if (!NT_SUCCESS(Status))
1407         {
1408             TRACE("SamIConnect() failed (Status 0x%08lx)\n", Status);
1409             goto done;
1410         }
1411 
1412         /* Open the account domain */
1413         Status = SamrOpenDomain(ServerHandle,
1414                                 DOMAIN_LOOKUP,
1415                                 AccountDomainSid,
1416                                 &DomainHandle);
1417         if (!NT_SUCCESS(Status))
1418         {
1419             ERR("SamrOpenDomain failed (Status %08lx)\n", Status);
1420             goto done;
1421         }
1422 
1423         Names[0].Length = LogonInfo->UserName.Length;
1424         Names[0].MaximumLength = LogonInfo->UserName.MaximumLength;
1425         Names[0].Buffer = LogonInfo->UserName.Buffer;
1426 
1427         /* Try to get the RID for the user name */
1428         Status = SamrLookupNamesInDomain(DomainHandle,
1429                                          1,
1430                                          Names,
1431                                          &RelativeIds,
1432                                          &Use);
1433         if (!NT_SUCCESS(Status))
1434         {
1435             ERR("SamrLookupNamesInDomain failed (Status %08lx)\n", Status);
1436             Status = STATUS_NO_SUCH_USER;
1437             goto done;
1438         }
1439 
1440         /* Fail, if it is not a user account */
1441         if (Use.Element[0] != SidTypeUser)
1442         {
1443             ERR("Account is not a user account!\n");
1444             Status = STATUS_NO_SUCH_USER;
1445             goto done;
1446         }
1447 
1448         /* Open the user object */
1449         Status = SamrOpenUser(DomainHandle,
1450                               USER_READ_GENERAL | USER_READ_LOGON |
1451                               USER_READ_ACCOUNT | USER_READ_PREFERENCES, /* FIXME */
1452                               RelativeIds.Element[0],
1453                               &UserHandle);
1454         if (!NT_SUCCESS(Status))
1455         {
1456             ERR("SamrOpenUser failed (Status %08lx)\n", Status);
1457             goto done;
1458         }
1459 
1460         Status = SamrQueryInformationUser(UserHandle,
1461                                           UserAllInformation,
1462                                           &UserInfo);
1463         if (!NT_SUCCESS(Status))
1464         {
1465             ERR("SamrQueryInformationUser failed (Status %08lx)\n", Status);
1466             goto done;
1467         }
1468 
1469         TRACE("UserName: %wZ\n", &UserInfo->All.UserName);
1470 
1471         /* Check the password */
1472         if ((UserInfo->All.UserAccountControl & USER_PASSWORD_NOT_REQUIRED) == 0)
1473         {
1474             Status = MsvpCheckPassword(&LogonInfo->Password,
1475                                        UserInfo);
1476             if (!NT_SUCCESS(Status))
1477             {
1478                 ERR("MsvpCheckPassword failed (Status %08lx)\n", Status);
1479                 goto done;
1480             }
1481         }
1482 
1483         /* Check account restrictions for non-administrator accounts */
1484         if (RelativeIds.Element[0] != DOMAIN_USER_RID_ADMIN)
1485         {
1486             /* Check if the account has been disabled */
1487             if (UserInfo->All.UserAccountControl & USER_ACCOUNT_DISABLED)
1488             {
1489                 ERR("Account disabled!\n");
1490                 *SubStatus = STATUS_ACCOUNT_DISABLED;
1491                 Status = STATUS_ACCOUNT_RESTRICTION;
1492                 goto done;
1493             }
1494 
1495             /* Check if the account has been locked */
1496             if (UserInfo->All.UserAccountControl & USER_ACCOUNT_AUTO_LOCKED)
1497             {
1498                 ERR("Account locked!\n");
1499                 *SubStatus = STATUS_ACCOUNT_LOCKED_OUT;
1500                 Status = STATUS_ACCOUNT_RESTRICTION;
1501                 goto done;
1502             }
1503 
1504             /* Check if the account expired */
1505             AccountExpires.LowPart = UserInfo->All.AccountExpires.LowPart;
1506             AccountExpires.HighPart = UserInfo->All.AccountExpires.HighPart;
1507             if (LogonTime.QuadPart >= AccountExpires.QuadPart)
1508             {
1509                 ERR("Account expired!\n");
1510                 *SubStatus = STATUS_ACCOUNT_EXPIRED;
1511                 Status = STATUS_ACCOUNT_RESTRICTION;
1512                 goto done;
1513             }
1514 
1515             /* Check if the password expired */
1516             PasswordMustChange.LowPart = UserInfo->All.PasswordMustChange.LowPart;
1517             PasswordMustChange.HighPart = UserInfo->All.PasswordMustChange.HighPart;
1518             PasswordLastSet.LowPart = UserInfo->All.PasswordLastSet.LowPart;
1519             PasswordLastSet.HighPart = UserInfo->All.PasswordLastSet.HighPart;
1520 
1521             if (LogonTime.QuadPart >= PasswordMustChange.QuadPart)
1522             {
1523                 ERR("Password expired!\n");
1524                 if (PasswordLastSet.QuadPart == 0)
1525                     *SubStatus = STATUS_PASSWORD_MUST_CHANGE;
1526                 else
1527                     *SubStatus = STATUS_PASSWORD_EXPIRED;
1528 
1529                 Status = STATUS_ACCOUNT_RESTRICTION;
1530                 goto done;
1531             }
1532 
1533             /* Check logon hours */
1534             if (!MsvpCheckLogonHours(&UserInfo->All.LogonHours, &LogonTime))
1535             {
1536                 ERR("Invalid logon hours!\n");
1537                 *SubStatus = STATUS_INVALID_LOGON_HOURS;
1538                 Status = STATUS_ACCOUNT_RESTRICTION;
1539                 goto done;
1540             }
1541 
1542             /* Check workstations */
1543             if (!MsvpCheckWorkstations(&UserInfo->All.WorkStations, ComputerName))
1544             {
1545                 ERR("Invalid workstation!\n");
1546                 *SubStatus = STATUS_INVALID_WORKSTATION;
1547                 Status = STATUS_ACCOUNT_RESTRICTION;
1548                 goto done;
1549             }
1550         }
1551     }
1552 
1553     /* Return logon information */
1554 
1555     /* Create and return a new logon id */
1556     Status = NtAllocateLocallyUniqueId(LogonId);
1557     if (!NT_SUCCESS(Status))
1558     {
1559         TRACE("NtAllocateLocallyUniqueId failed (Status %08lx)\n", Status);
1560         goto done;
1561     }
1562 
1563     /* Create the logon session */
1564     Status = DispatchTable.CreateLogonSession(LogonId);
1565     if (!NT_SUCCESS(Status))
1566     {
1567         TRACE("CreateLogonSession failed (Status %08lx)\n", Status);
1568         goto done;
1569     }
1570 
1571     SessionCreated = TRUE;
1572 
1573     /* Build and fill the interactive profile buffer */
1574     Status = BuildInteractiveProfileBuffer(ClientRequest,
1575                                            UserInfo,
1576                                            ComputerName,
1577                                            (PMSV1_0_INTERACTIVE_PROFILE*)ProfileBuffer,
1578                                            ProfileBufferSize);
1579     if (!NT_SUCCESS(Status))
1580     {
1581         TRACE("BuildInteractiveProfileBuffer failed (Status %08lx)\n", Status);
1582         goto done;
1583     }
1584 
1585     /* Return the token information type */
1586     *TokenInformationType = LsaTokenInformationV1;
1587 
1588     /* Build and fill the token information buffer */
1589     Status = BuildTokenInformationBuffer((PLSA_TOKEN_INFORMATION_V1*)TokenInformation,
1590                                          AccountDomainSid,
1591                                          UserInfo,
1592                                          SpecialAccount);
1593     if (!NT_SUCCESS(Status))
1594     {
1595         TRACE("BuildTokenInformationBuffer failed (Status %08lx)\n", Status);
1596         goto done;
1597     }
1598 
1599 done:
1600     /* Erase password */
1601     if (ErasePassword)
1602     {
1603         RtlEraseUnicodeString(ErasePassword);
1604     }
1605 
1606     /* Update the logon time/count or the bad password time/count */
1607     if ((UserHandle != NULL) &&
1608         (Status == STATUS_SUCCESS || Status == STATUS_WRONG_PASSWORD))
1609     {
1610         SAMPR_USER_INFO_BUFFER InternalInfo;
1611 
1612         RtlZeroMemory(&InternalInfo, sizeof(InternalInfo));
1613 
1614         if (Status == STATUS_SUCCESS)
1615             InternalInfo.Internal2.Flags = USER_LOGON_SUCCESS;
1616         else
1617             InternalInfo.Internal2.Flags = USER_LOGON_BAD_PASSWORD;
1618 
1619         SamrSetInformationUser(UserHandle,
1620                                UserInternal2Information,
1621                                &InternalInfo);
1622     }
1623 
1624     /* Return the account name */
1625     *AccountName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1626     if (*AccountName != NULL)
1627     {
1628         (*AccountName)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->UserName.Length +
1629                                                                sizeof(UNICODE_NULL));
1630         if ((*AccountName)->Buffer != NULL)
1631         {
1632             (*AccountName)->MaximumLength = LogonInfo->UserName.Length +
1633                                             sizeof(UNICODE_NULL);
1634             RtlCopyUnicodeString(*AccountName, &LogonInfo->UserName);
1635         }
1636     }
1637 
1638     /* Return the authenticating authority */
1639     *AuthenticatingAuthority = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1640     if (*AuthenticatingAuthority != NULL)
1641     {
1642         (*AuthenticatingAuthority)->Buffer = DispatchTable.AllocateLsaHeap(LogonInfo->LogonDomainName.Length +
1643                                                                            sizeof(UNICODE_NULL));
1644         if ((*AuthenticatingAuthority)->Buffer != NULL)
1645         {
1646             (*AuthenticatingAuthority)->MaximumLength = LogonInfo->LogonDomainName.Length +
1647                                                         sizeof(UNICODE_NULL);
1648             RtlCopyUnicodeString(*AuthenticatingAuthority, &LogonInfo->LogonDomainName);
1649         }
1650     }
1651 
1652     /* Return the machine name */
1653     *MachineName = DispatchTable.AllocateLsaHeap(sizeof(UNICODE_STRING));
1654     if (*MachineName != NULL)
1655     {
1656         (*MachineName)->Buffer = DispatchTable.AllocateLsaHeap((ComputerNameSize + 1) * sizeof(WCHAR));
1657         if ((*MachineName)->Buffer != NULL)
1658         {
1659             (*MachineName)->MaximumLength = (ComputerNameSize + 1) * sizeof(WCHAR);
1660             (*MachineName)->Length = ComputerNameSize * sizeof(WCHAR);
1661             RtlCopyMemory((*MachineName)->Buffer, ComputerName, (*MachineName)->MaximumLength);
1662         }
1663     }
1664 
1665     if (!NT_SUCCESS(Status))
1666     {
1667         if (SessionCreated != FALSE)
1668             DispatchTable.DeleteLogonSession(LogonId);
1669 
1670         if (*ProfileBuffer != NULL)
1671         {
1672             DispatchTable.FreeClientBuffer(ClientRequest,
1673                                            *ProfileBuffer);
1674             *ProfileBuffer = NULL;
1675         }
1676     }
1677 
1678     if (UserHandle != NULL)
1679         SamrCloseHandle(&UserHandle);
1680 
1681     SamIFree_SAMPR_USER_INFO_BUFFER(UserInfo,
1682                                     UserAllInformation);
1683     SamIFree_SAMPR_ULONG_ARRAY(&RelativeIds);
1684     SamIFree_SAMPR_ULONG_ARRAY(&Use);
1685 
1686     if (DomainHandle != NULL)
1687         SamrCloseHandle(&DomainHandle);
1688 
1689     if (ServerHandle != NULL)
1690         SamrCloseHandle(&ServerHandle);
1691 
1692     if (AccountDomainSid != NULL)
1693         RtlFreeHeap(RtlGetProcessHeap(), 0, AccountDomainSid);
1694 
1695     if (Status == STATUS_NO_SUCH_USER ||
1696         Status == STATUS_WRONG_PASSWORD)
1697     {
1698         *SubStatus = Status;
1699         Status = STATUS_LOGON_FAILURE;
1700     }
1701 
1702     TRACE("LsaApLogonUserEx2 done (Status 0x%08lx, SubStatus 0x%08lx)\n", Status, *SubStatus);
1703 
1704     return Status;
1705 }
1706 
1707 
1708 /*
1709  * @unimplemented
1710  */
1711 NTSTATUS
1712 NTAPI
1713 SpLsaModeInitialize(
1714     _In_ ULONG LsaVersion,
1715     _Out_ PULONG PackageVersion,
1716     _Out_ PSECPKG_FUNCTION_TABLE *ppTables,
1717     _Out_ PULONG pcTables)
1718 {
1719     TRACE("SpLsaModeInitialize(0x%lx %p %p %p)\n",
1720           LsaVersion, PackageVersion, ppTables, pcTables);
1721 
1722     if (LsaVersion != SECPKG_INTERFACE_VERSION)
1723         return STATUS_INVALID_PARAMETER;
1724 
1725     *PackageVersion = SECPKG_INTERFACE_VERSION;
1726 
1727     RtlZeroMemory(NtlmLsaFn, sizeof(NtlmLsaFn));
1728 
1729     /* msv1_0 (XP, win2k) returns NULL for
1730      * InitializePackage, LsaLogonUser,LsaLogonUserEx,
1731      * SpQueryContextAttributes and SpAddCredentials */
1732     NtlmLsaFn[0].InitializePackage = NULL;
1733     NtlmLsaFn[0].LsaLogonUser = NULL;
1734     NtlmLsaFn[0].CallPackage = LsaApCallPackage;
1735     NtlmLsaFn[0].LogonTerminated = LsaApLogonTerminated;
1736     NtlmLsaFn[0].CallPackageUntrusted = LsaApCallPackageUntrusted;
1737     NtlmLsaFn[0].CallPackagePassthrough = LsaApCallPackagePassthrough;
1738     NtlmLsaFn[0].LogonUserEx = NULL;
1739     NtlmLsaFn[0].LogonUserEx2 = LsaApLogonUserEx2;
1740     NtlmLsaFn[0].Initialize = SpInitialize;
1741     NtlmLsaFn[0].Shutdown = LsaSpShutDown;
1742     NtlmLsaFn[0].GetInfo = LsaSpGetInfoW;
1743     NtlmLsaFn[0].AcceptCredentials = SpAcceptCredentials;
1744     NtlmLsaFn[0].SpAcquireCredentialsHandle = LsaSpAcquireCredentialsHandle;
1745     NtlmLsaFn[0].SpQueryCredentialsAttributes = LsaSpQueryCredentialsAttributes;
1746     NtlmLsaFn[0].FreeCredentialsHandle = LsaSpFreeCredentialsHandle;
1747     NtlmLsaFn[0].SaveCredentials = LsaSpSaveCredentials;
1748     NtlmLsaFn[0].GetCredentials = LsaSpGetCredentials;
1749     NtlmLsaFn[0].DeleteCredentials = LsaSpDeleteCredentials;
1750     NtlmLsaFn[0].InitLsaModeContext = LsaSpInitLsaModeContext;
1751     NtlmLsaFn[0].AcceptLsaModeContext = LsaSpAcceptLsaModeContext;
1752     NtlmLsaFn[0].DeleteContext = LsaSpDeleteContext;
1753     NtlmLsaFn[0].ApplyControlToken = LsaSpApplyControlToken;
1754     NtlmLsaFn[0].GetUserInfo = LsaSpGetUserInfo;
1755     NtlmLsaFn[0].GetExtendedInformation = LsaSpGetExtendedInformation;
1756     NtlmLsaFn[0].SpQueryContextAttributes = NULL;
1757     NtlmLsaFn[0].SpAddCredentials = NULL;
1758     NtlmLsaFn[0].SetExtendedInformation = LsaSpSetExtendedInformation;
1759 
1760     *ppTables = NtlmLsaFn;
1761     *pcTables = 1;
1762 
1763     return STATUS_SUCCESS;
1764 }
1765 
1766 
1767 /*
1768  * @unimplemented
1769  */
1770 NTSTATUS
1771 WINAPI
1772 SpUserModeInitialize(
1773     _In_ ULONG LsaVersion,
1774     _Out_ PULONG PackageVersion,
1775     _Out_ PSECPKG_USER_FUNCTION_TABLE *ppTables,
1776     _Out_ PULONG pcTables)
1777 {
1778     SECPKG_USER_FUNCTION_TABLE Tables[1];
1779 
1780     TRACE("SpUserModeInitialize(0x%lx %p %p %p)\n",
1781           LsaVersion, PackageVersion, ppTables, pcTables);
1782 
1783     if (LsaVersion != SECPKG_INTERFACE_VERSION)
1784         return STATUS_INVALID_PARAMETER;
1785 
1786     *PackageVersion = SECPKG_INTERFACE_VERSION;
1787 
1788     RtlZeroMemory(&Tables, sizeof(Tables));
1789 
1790 //    Tables[0].InstanceInit = SpInstanceInit;
1791 //    Tables[0].InitUserModeContext = NULL;
1792 //    Tables[0].MakeSignature = NULL;
1793 //    Tables[0].VerifySignature = NULL;
1794 //    Tables[0].SealMessage = NULL;
1795 //    Tables[0].UnsealMessage = NULL;
1796 //    Tables[0].GetContextToken = NULL;
1797 //    Tables[0].SpQueryContextAttributes = NULL;
1798 //    Tables[0].CompleteAuthToken = NULL;
1799 //    Tables[0].DeleteUserModeContext = NULL;
1800 //    Tables[0].FormatCredentials = NULL;
1801 //    Tables[0].MarshallSupplementalCreds = NULL;
1802 //    Tables[0].ExportContext = NULL;
1803 //    Tables[0].ImportContext = NULL;
1804 
1805     *ppTables = Tables;
1806     *pcTables = 1;
1807 
1808     return STATUS_SUCCESS;
1809 }
1810 
1811 /* EOF */
1812