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