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