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