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