xref: /reactos/dll/win32/advapi32/misc/logon.c (revision f2df3bf0)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS system libraries
4  * FILE:        lib/advapi32/misc/logon.c
5  * PURPOSE:     Logon functions
6  * PROGRAMMER:  Eric Kohl
7  */
8 
9 #include <advapi32.h>
10 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
11 
12 /* GLOBALS *****************************************************************/
13 
14 HANDLE LsaHandle = NULL;
15 ULONG AuthenticationPackage = 0;
16 
17 /* FUNCTIONS ***************************************************************/
18 
19 static
20 NTSTATUS
21 OpenLogonLsaHandle(VOID)
22 {
23     LSA_STRING LogonProcessName;
24     LSA_STRING PackageName;
25     LSA_OPERATIONAL_MODE SecurityMode = 0;
26     NTSTATUS Status;
27 
28     RtlInitAnsiString((PANSI_STRING)&LogonProcessName,
29                       "User32LogonProcess");
30 
31     Status = LsaRegisterLogonProcess(&LogonProcessName,
32                                      &LsaHandle,
33                                      &SecurityMode);
34     if (!NT_SUCCESS(Status))
35     {
36         TRACE("LsaRegisterLogonProcess failed (Status 0x%08lx)\n", Status);
37         goto done;
38     }
39 
40     RtlInitAnsiString((PANSI_STRING)&PackageName,
41                       MSV1_0_PACKAGE_NAME);
42 
43     Status = LsaLookupAuthenticationPackage(LsaHandle,
44                                             &PackageName,
45                                             &AuthenticationPackage);
46     if (!NT_SUCCESS(Status))
47     {
48         TRACE("LsaLookupAuthenticationPackage failed (Status 0x%08lx)\n", Status);
49         goto done;
50     }
51 
52     TRACE("AuthenticationPackage: 0x%08lx\n", AuthenticationPackage);
53 
54 done:
55     if (!NT_SUCCESS(Status))
56     {
57         if (LsaHandle != NULL)
58         {
59             Status = LsaDeregisterLogonProcess(LsaHandle);
60             if (!NT_SUCCESS(Status))
61             {
62                 TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
63             }
64         }
65     }
66 
67     return Status;
68 }
69 
70 
71 NTSTATUS
72 CloseLogonLsaHandle(VOID)
73 {
74     NTSTATUS Status = STATUS_SUCCESS;
75 
76     if (LsaHandle != NULL)
77     {
78         Status = LsaDeregisterLogonProcess(LsaHandle);
79         if (!NT_SUCCESS(Status))
80         {
81             TRACE("LsaDeregisterLogonProcess failed (Status 0x%08lx)\n", Status);
82         }
83     }
84 
85     return Status;
86 }
87 
88 
89 static
90 BOOL
91 CreateProcessAsUserCommon(
92     _In_ BOOL bUnicode,
93     _In_opt_ HANDLE hToken,
94     _In_opt_ LPCVOID lpApplicationName,
95     _Inout_opt_ LPVOID lpCommandLine,
96     _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
97     _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
98     _In_ BOOL bInheritHandles,
99     _In_ DWORD dwCreationFlags,
100     _In_opt_ LPVOID lpEnvironment,
101     _In_opt_ LPCVOID lpCurrentDirectory,
102     _In_ LPVOID lpStartupInfo,
103     _Out_ LPPROCESS_INFORMATION lpProcessInformation)
104 {
105     NTSTATUS Status;
106     PROCESS_ACCESS_TOKEN AccessToken;
107 
108     /* Create the process with a suspended main thread */
109     if (bUnicode)
110     {
111         /* Call the UNICODE version */
112         if (!CreateProcessW((LPCWSTR)lpApplicationName,
113                             (LPWSTR)lpCommandLine,
114                             lpProcessAttributes,
115                             lpThreadAttributes,
116                             bInheritHandles,
117                             dwCreationFlags | CREATE_SUSPENDED,
118                             lpEnvironment,
119                             (LPCWSTR)lpCurrentDirectory,
120                             (LPSTARTUPINFOW)lpStartupInfo,
121                             lpProcessInformation))
122         {
123             ERR("CreateProcessW failed, last error: %d\n", GetLastError());
124             return FALSE;
125         }
126     }
127     else
128     {
129         /* Call the ANSI version */
130         if (!CreateProcessA((LPCSTR)lpApplicationName,
131                             (LPSTR)lpCommandLine,
132                             lpProcessAttributes,
133                             lpThreadAttributes,
134                             bInheritHandles,
135                             dwCreationFlags | CREATE_SUSPENDED,
136                             lpEnvironment,
137                             (LPCSTR)lpCurrentDirectory,
138                             (LPSTARTUPINFOA)lpStartupInfo,
139                             lpProcessInformation))
140         {
141             ERR("CreateProcessA failed, last error: %d\n", GetLastError());
142             return FALSE;
143         }
144     }
145 
146     if (hToken != NULL)
147     {
148         TOKEN_TYPE Type;
149         ULONG ReturnLength;
150         OBJECT_ATTRIBUTES ObjectAttributes;
151         HANDLE hTokenDup;
152         BOOLEAN PrivilegeSet = FALSE, HavePrivilege;
153 
154         /* Check whether the user-provided token is a primary token */
155         // GetTokenInformation();
156         Status = NtQueryInformationToken(hToken,
157                                          TokenType,
158                                          &Type,
159                                          sizeof(Type),
160                                          &ReturnLength);
161         if (!NT_SUCCESS(Status))
162         {
163             ERR("NtQueryInformationToken() failed, Status 0x%08x\n", Status);
164             goto Quit;
165         }
166         if (Type != TokenPrimary)
167         {
168             ERR("Wrong token type for token 0x%p, expected TokenPrimary, got %ld\n", hToken, Type);
169             Status = STATUS_BAD_TOKEN_TYPE;
170             goto Quit;
171         }
172 
173         /* Duplicate the token for this new process */
174         InitializeObjectAttributes(&ObjectAttributes,
175                                    NULL,
176                                    0,
177                                    NULL,
178                                    NULL); // FIXME: Use a valid SecurityDescriptor!
179         Status = NtDuplicateToken(hToken,
180                                   0,
181                                   &ObjectAttributes,
182                                   FALSE,
183                                   TokenPrimary,
184                                   &hTokenDup);
185         if (!NT_SUCCESS(Status))
186         {
187             ERR("NtDuplicateToken() failed, Status 0x%08x\n", Status);
188             goto Quit;
189         }
190 
191         // FIXME: Do we always need SecurityImpersonation?
192         Status = RtlImpersonateSelf(SecurityImpersonation);
193         if (!NT_SUCCESS(Status))
194         {
195             ERR("RtlImpersonateSelf(SecurityImpersonation) failed, Status 0x%08x\n", Status);
196             NtClose(hTokenDup);
197             goto Quit;
198         }
199 
200         /*
201          * Attempt to acquire the process primary token assignment privilege
202          * in case we actually need it.
203          * The call will either succeed or fail when the caller has (or has not)
204          * enough rights.
205          * The last situation may not be dramatic for us. Indeed it may happen
206          * that the user-provided token is a restricted version of the caller's
207          * primary token (aka. a "child" token), or both tokens inherit (i.e. are
208          * children, and are together "siblings") from a common parent token.
209          * In this case the NT kernel allows us to assign the token to the child
210          * process without the need for the assignment privilege, which is fine.
211          * On the contrary, if the user-provided token is completely arbitrary,
212          * then the NT kernel will enforce the presence of the assignment privilege:
213          * because we failed (by assumption) to assign the privilege, the process
214          * token assignment will fail as required. It is then the job of the
215          * caller to manually acquire the necessary privileges.
216          */
217         Status = RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
218                                     TRUE, TRUE, &PrivilegeSet);
219         HavePrivilege = NT_SUCCESS(Status);
220         if (!HavePrivilege)
221         {
222             ERR("RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE) failed, Status 0x%08lx, "
223                 "attempting to continue without it...\n", Status);
224         }
225 
226         AccessToken.Token  = hTokenDup;
227         AccessToken.Thread = lpProcessInformation->hThread;
228 
229         /* Set the new process token */
230         Status = NtSetInformationProcess(lpProcessInformation->hProcess,
231                                          ProcessAccessToken,
232                                          (PVOID)&AccessToken,
233                                          sizeof(AccessToken));
234 
235         /* Restore the privilege */
236         if (HavePrivilege)
237         {
238             RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
239                                PrivilegeSet, TRUE, &PrivilegeSet);
240         }
241 
242         RevertToSelf();
243 
244         /* Close the duplicated token */
245         NtClose(hTokenDup);
246 
247         /* Check whether NtSetInformationProcess() failed */
248         if (!NT_SUCCESS(Status))
249         {
250             ERR("NtSetInformationProcess() failed, Status 0x%08x\n", Status);
251             goto Quit;
252         }
253 
254         if (!NT_SUCCESS(Status))
255         {
256 Quit:
257             TerminateProcess(lpProcessInformation->hProcess, Status);
258             SetLastError(RtlNtStatusToDosError(Status));
259             return FALSE;
260         }
261     }
262 
263     /* Resume the main thread */
264     if (!(dwCreationFlags & CREATE_SUSPENDED))
265     {
266         ResumeThread(lpProcessInformation->hThread);
267     }
268 
269     return TRUE;
270 }
271 
272 
273 /*
274  * @implemented
275  */
276 BOOL
277 WINAPI
278 DECLSPEC_HOTPATCH
279 CreateProcessAsUserA(
280     _In_opt_ HANDLE hToken,
281     _In_opt_ LPCSTR lpApplicationName,
282     _Inout_opt_ LPSTR lpCommandLine,
283     _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
284     _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
285     _In_ BOOL bInheritHandles,
286     _In_ DWORD dwCreationFlags,
287     _In_opt_ LPVOID lpEnvironment,
288     _In_opt_ LPCSTR lpCurrentDirectory,
289     _In_ LPSTARTUPINFOA lpStartupInfo,
290     _Out_ LPPROCESS_INFORMATION lpProcessInformation)
291 {
292     TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_a(lpApplicationName),
293         debugstr_a(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles,
294         dwCreationFlags, lpEnvironment, debugstr_a(lpCurrentDirectory), lpStartupInfo, lpProcessInformation);
295 
296     /* Call the helper function */
297     return CreateProcessAsUserCommon(FALSE,
298                                      hToken,
299                                      lpApplicationName,
300                                      lpCommandLine,
301                                      lpProcessAttributes,
302                                      lpThreadAttributes,
303                                      bInheritHandles,
304                                      dwCreationFlags,
305                                      lpEnvironment,
306                                      lpCurrentDirectory,
307                                      lpStartupInfo,
308                                      lpProcessInformation);
309 }
310 
311 
312 /*
313  * @implemented
314  */
315 BOOL
316 WINAPI
317 DECLSPEC_HOTPATCH
318 CreateProcessAsUserW(
319     _In_opt_ HANDLE hToken,
320     _In_opt_ LPCWSTR lpApplicationName,
321     _Inout_opt_ LPWSTR lpCommandLine,
322     _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
323     _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
324     _In_ BOOL bInheritHandles,
325     _In_ DWORD dwCreationFlags,
326     _In_opt_ LPVOID lpEnvironment,
327     _In_opt_ LPCWSTR lpCurrentDirectory,
328     _In_ LPSTARTUPINFOW lpStartupInfo,
329     _Out_ LPPROCESS_INFORMATION lpProcessInformation)
330 {
331     TRACE("%p %s %s %p %p %d 0x%08x %p %s %p %p\n", hToken, debugstr_w(lpApplicationName),
332         debugstr_w(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles,
333         dwCreationFlags, lpEnvironment, debugstr_w(lpCurrentDirectory), lpStartupInfo, lpProcessInformation);
334 
335     /* Call the helper function */
336     return CreateProcessAsUserCommon(TRUE,
337                                      hToken,
338                                      lpApplicationName,
339                                      lpCommandLine,
340                                      lpProcessAttributes,
341                                      lpThreadAttributes,
342                                      bInheritHandles,
343                                      dwCreationFlags,
344                                      lpEnvironment,
345                                      lpCurrentDirectory,
346                                      lpStartupInfo,
347                                      lpProcessInformation);
348 }
349 
350 
351 /*
352  * @implemented
353  */
354 BOOL
355 WINAPI
356 LogonUserA(
357     _In_ LPSTR lpszUsername,
358     _In_opt_ LPSTR lpszDomain,
359     _In_opt_ LPSTR lpszPassword,
360     _In_ DWORD dwLogonType,
361     _In_ DWORD dwLogonProvider,
362     _Out_opt_ PHANDLE phToken)
363 {
364     return LogonUserExA(lpszUsername,
365                         lpszDomain,
366                         lpszPassword,
367                         dwLogonType,
368                         dwLogonProvider,
369                         phToken,
370                         NULL,
371                         NULL,
372                         NULL,
373                         NULL);
374 }
375 
376 
377 /*
378  * @implemented
379  */
380 BOOL
381 WINAPI
382 LogonUserExA(
383     _In_ LPSTR lpszUsername,
384     _In_opt_ LPSTR lpszDomain,
385     _In_opt_ LPSTR lpszPassword,
386     _In_ DWORD dwLogonType,
387     _In_ DWORD dwLogonProvider,
388     _Out_opt_ PHANDLE phToken,
389     _Out_opt_ PSID *ppLogonSid,
390     _Out_opt_ PVOID *ppProfileBuffer,
391     _Out_opt_ LPDWORD pdwProfileLength,
392     _Out_opt_ PQUOTA_LIMITS pQuotaLimits)
393 {
394     UNICODE_STRING UserName;
395     UNICODE_STRING Domain;
396     UNICODE_STRING Password;
397     BOOL ret = FALSE;
398 
399     UserName.Buffer = NULL;
400     Domain.Buffer = NULL;
401     Password.Buffer = NULL;
402 
403     if (!RtlCreateUnicodeStringFromAsciiz(&UserName, lpszUsername))
404     {
405         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
406         goto UsernameDone;
407     }
408 
409     if (!RtlCreateUnicodeStringFromAsciiz(&Domain, lpszDomain))
410     {
411         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
412         goto DomainDone;
413     }
414 
415     if (!RtlCreateUnicodeStringFromAsciiz(&Password, lpszPassword))
416     {
417         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
418         goto PasswordDone;
419     }
420 
421     ret = LogonUserExW(UserName.Buffer,
422                        Domain.Buffer,
423                        Password.Buffer,
424                        dwLogonType,
425                        dwLogonProvider,
426                        phToken,
427                        ppLogonSid,
428                        ppProfileBuffer,
429                        pdwProfileLength,
430                        pQuotaLimits);
431 
432     if (Password.Buffer != NULL)
433         RtlFreeUnicodeString(&Password);
434 
435 PasswordDone:
436     if (Domain.Buffer != NULL)
437         RtlFreeUnicodeString(&Domain);
438 
439 DomainDone:
440     if (UserName.Buffer != NULL)
441         RtlFreeUnicodeString(&UserName);
442 
443 UsernameDone:
444     return ret;
445 }
446 
447 
448 /*
449  * @implemented
450  */
451 BOOL
452 WINAPI
453 LogonUserW(
454     _In_ LPWSTR lpszUsername,
455     _In_opt_ LPWSTR lpszDomain,
456     _In_opt_ LPWSTR lpszPassword,
457     _In_ DWORD dwLogonType,
458     _In_ DWORD dwLogonProvider,
459     _Out_opt_ PHANDLE phToken)
460 {
461     return LogonUserExW(lpszUsername,
462                         lpszDomain,
463                         lpszPassword,
464                         dwLogonType,
465                         dwLogonProvider,
466                         phToken,
467                         NULL,
468                         NULL,
469                         NULL,
470                         NULL);
471 }
472 
473 
474 /*
475  * @implemented
476  */
477 BOOL
478 WINAPI
479 LogonUserExW(
480     _In_ LPWSTR lpszUsername,
481     _In_opt_ LPWSTR lpszDomain,
482     _In_opt_ LPWSTR lpszPassword,
483     _In_ DWORD dwLogonType,
484     _In_ DWORD dwLogonProvider,
485     _Out_opt_ PHANDLE phToken,
486     _Out_opt_ PSID *ppLogonSid,
487     _Out_opt_ PVOID *ppProfileBuffer,
488     _Out_opt_ LPDWORD pdwProfileLength,
489     _Out_opt_ PQUOTA_LIMITS pQuotaLimits)
490 {
491     SID_IDENTIFIER_AUTHORITY LocalAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
492     SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
493     PSID LogonSid = NULL;
494     PSID LocalSid = NULL;
495     LSA_STRING OriginName;
496     UNICODE_STRING DomainName;
497     UNICODE_STRING UserName;
498     UNICODE_STRING Password;
499     PMSV1_0_INTERACTIVE_LOGON AuthInfo = NULL;
500     ULONG AuthInfoLength;
501     ULONG_PTR Ptr;
502     TOKEN_SOURCE TokenSource;
503     PTOKEN_GROUPS TokenGroups = NULL;
504     PMSV1_0_INTERACTIVE_PROFILE ProfileBuffer = NULL;
505     ULONG ProfileBufferLength = 0;
506     LUID Luid = {0, 0};
507     LUID LogonId = {0, 0};
508     HANDLE TokenHandle = NULL;
509     QUOTA_LIMITS QuotaLimits;
510     SECURITY_LOGON_TYPE LogonType;
511     NTSTATUS SubStatus = STATUS_SUCCESS;
512     NTSTATUS Status;
513 
514     if ((ppProfileBuffer != NULL && pdwProfileLength == NULL) ||
515         (ppProfileBuffer == NULL && pdwProfileLength != NULL))
516     {
517         SetLastError(ERROR_INVALID_PARAMETER);
518         return FALSE;
519     }
520 
521     if (ppProfileBuffer != NULL && pdwProfileLength != NULL)
522     {
523         *ppProfileBuffer = NULL;
524         *pdwProfileLength = 0;
525     }
526 
527     if (phToken != NULL)
528         *phToken = NULL;
529 
530     switch (dwLogonType)
531     {
532         case LOGON32_LOGON_INTERACTIVE:
533             LogonType = Interactive;
534             break;
535 
536         case LOGON32_LOGON_NETWORK:
537             LogonType = Network;
538             break;
539 
540         case LOGON32_LOGON_BATCH:
541             LogonType = Batch;
542             break;
543 
544         case LOGON32_LOGON_SERVICE:
545             LogonType = Service;
546             break;
547 
548        default:
549             ERR("Invalid logon type: %ul\n", dwLogonType);
550             Status = STATUS_INVALID_PARAMETER;
551             goto done;
552     }
553 
554     if (LsaHandle == NULL)
555     {
556         Status = OpenLogonLsaHandle();
557         if (!NT_SUCCESS(Status))
558             goto done;
559     }
560 
561     RtlInitAnsiString((PANSI_STRING)&OriginName,
562                       "Advapi32 Logon");
563 
564     RtlInitUnicodeString(&DomainName,
565                          lpszDomain);
566 
567     RtlInitUnicodeString(&UserName,
568                          lpszUsername);
569 
570     RtlInitUnicodeString(&Password,
571                          lpszPassword);
572 
573     AuthInfoLength = sizeof(MSV1_0_INTERACTIVE_LOGON)+
574                      DomainName.MaximumLength +
575                      UserName.MaximumLength +
576                      Password.MaximumLength;
577 
578     AuthInfo = RtlAllocateHeap(RtlGetProcessHeap(),
579                                HEAP_ZERO_MEMORY,
580                                AuthInfoLength);
581     if (AuthInfo == NULL)
582     {
583         Status = STATUS_INSUFFICIENT_RESOURCES;
584         goto done;
585     }
586 
587     AuthInfo->MessageType = MsV1_0InteractiveLogon;
588 
589     Ptr = (ULONG_PTR)AuthInfo + sizeof(MSV1_0_INTERACTIVE_LOGON);
590 
591     AuthInfo->LogonDomainName.Length = DomainName.Length;
592     AuthInfo->LogonDomainName.MaximumLength = DomainName.MaximumLength;
593     AuthInfo->LogonDomainName.Buffer = (DomainName.Buffer == NULL) ? NULL : (PWCHAR)Ptr;
594     if (DomainName.MaximumLength > 0)
595     {
596         RtlCopyMemory(AuthInfo->LogonDomainName.Buffer,
597                       DomainName.Buffer,
598                       DomainName.MaximumLength);
599 
600         Ptr += DomainName.MaximumLength;
601     }
602 
603     AuthInfo->UserName.Length = UserName.Length;
604     AuthInfo->UserName.MaximumLength = UserName.MaximumLength;
605     AuthInfo->UserName.Buffer = (PWCHAR)Ptr;
606     if (UserName.MaximumLength > 0)
607         RtlCopyMemory(AuthInfo->UserName.Buffer,
608                       UserName.Buffer,
609                       UserName.MaximumLength);
610 
611     Ptr += UserName.MaximumLength;
612 
613     AuthInfo->Password.Length = Password.Length;
614     AuthInfo->Password.MaximumLength = Password.MaximumLength;
615     AuthInfo->Password.Buffer = (PWCHAR)Ptr;
616     if (Password.MaximumLength > 0)
617         RtlCopyMemory(AuthInfo->Password.Buffer,
618                       Password.Buffer,
619                       Password.MaximumLength);
620 
621     /* Create the Logon SID */
622     AllocateLocallyUniqueId(&LogonId);
623     Status = RtlAllocateAndInitializeSid(&SystemAuthority,
624                                          SECURITY_LOGON_IDS_RID_COUNT,
625                                          SECURITY_LOGON_IDS_RID,
626                                          LogonId.HighPart,
627                                          LogonId.LowPart,
628                                          SECURITY_NULL_RID,
629                                          SECURITY_NULL_RID,
630                                          SECURITY_NULL_RID,
631                                          SECURITY_NULL_RID,
632                                          SECURITY_NULL_RID,
633                                          &LogonSid);
634     if (!NT_SUCCESS(Status))
635         goto done;
636 
637     /* Create the Local SID */
638     Status = RtlAllocateAndInitializeSid(&LocalAuthority,
639                                          1,
640                                          SECURITY_LOCAL_RID,
641                                          SECURITY_NULL_RID,
642                                          SECURITY_NULL_RID,
643                                          SECURITY_NULL_RID,
644                                          SECURITY_NULL_RID,
645                                          SECURITY_NULL_RID,
646                                          SECURITY_NULL_RID,
647                                          SECURITY_NULL_RID,
648                                          &LocalSid);
649     if (!NT_SUCCESS(Status))
650         goto done;
651 
652     /* Allocate and set the token groups */
653     TokenGroups = RtlAllocateHeap(RtlGetProcessHeap(),
654                                   HEAP_ZERO_MEMORY,
655                                   sizeof(TOKEN_GROUPS) + ((2 - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES)));
656     if (TokenGroups == NULL)
657     {
658         Status = STATUS_INSUFFICIENT_RESOURCES;
659         goto done;
660     }
661 
662     TokenGroups->GroupCount = 2;
663     TokenGroups->Groups[0].Sid = LogonSid;
664     TokenGroups->Groups[0].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
665                                         SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_LOGON_ID;
666     TokenGroups->Groups[1].Sid = LocalSid;
667     TokenGroups->Groups[1].Attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
668                                         SE_GROUP_ENABLED_BY_DEFAULT;
669 
670     /* Set the token source */
671     strncpy(TokenSource.SourceName, "Advapi  ", sizeof(TokenSource.SourceName));
672     AllocateLocallyUniqueId(&TokenSource.SourceIdentifier);
673 
674     Status = LsaLogonUser(LsaHandle,
675                           &OriginName,
676                           LogonType,
677                           AuthenticationPackage,
678                           (PVOID)AuthInfo,
679                           AuthInfoLength,
680                           TokenGroups,
681                           &TokenSource,
682                           (PVOID*)&ProfileBuffer,
683                           &ProfileBufferLength,
684                           &Luid,
685                           &TokenHandle,
686                           &QuotaLimits,
687                           &SubStatus);
688     if (!NT_SUCCESS(Status))
689     {
690         ERR("LsaLogonUser failed (Status 0x%08lx)\n", Status);
691         goto done;
692     }
693 
694     if (ProfileBuffer != NULL)
695     {
696         TRACE("ProfileBuffer: %p\n", ProfileBuffer);
697         TRACE("MessageType: %u\n", ProfileBuffer->MessageType);
698 
699         TRACE("FullName: %p\n", ProfileBuffer->FullName.Buffer);
700         TRACE("FullName: %S\n", ProfileBuffer->FullName.Buffer);
701 
702         TRACE("LogonServer: %p\n", ProfileBuffer->LogonServer.Buffer);
703         TRACE("LogonServer: %S\n", ProfileBuffer->LogonServer.Buffer);
704     }
705 
706     TRACE("Luid: 0x%08lx%08lx\n", Luid.HighPart, Luid.LowPart);
707 
708     if (TokenHandle != NULL)
709     {
710         TRACE("TokenHandle: %p\n", TokenHandle);
711     }
712 
713     if (phToken != NULL)
714         *phToken = TokenHandle;
715 
716     /* FIXME: return ppLogonSid and pQuotaLimits */
717 
718 done:
719     if (ProfileBuffer != NULL)
720         LsaFreeReturnBuffer(ProfileBuffer);
721 
722     if (!NT_SUCCESS(Status))
723     {
724         if (TokenHandle != NULL)
725             CloseHandle(TokenHandle);
726     }
727 
728     if (TokenGroups != NULL)
729         RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroups);
730 
731     if (LocalSid != NULL)
732         RtlFreeSid(LocalSid);
733 
734     if (LogonSid != NULL)
735         RtlFreeSid(LogonSid);
736 
737     if (AuthInfo != NULL)
738         RtlFreeHeap(RtlGetProcessHeap(), 0, AuthInfo);
739 
740     if (!NT_SUCCESS(Status))
741     {
742         SetLastError(RtlNtStatusToDosError(Status));
743         return FALSE;
744     }
745 
746     return TRUE;
747 }
748 
749 /* EOF */
750