[ADVAPI32] Fix copying the TokenSource string
[reactos.git] / dll / win32 / advapi32 / misc / logon.c
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 */