742c09317851e86ffad772dbea9ffa92b7cb9634
[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 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 */