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