[USERENV] UnloadUserProfile: When a profiles ref count gets 0, delete the profile...
[reactos.git] / dll / win32 / userenv / profile.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/userenv/profile.c
5 * PURPOSE: User profile code
6 * PROGRAMMERS: Eric Kohl
7 * Hervé Poussineau
8 */
9
10 #include "precomp.h"
11
12 #include <sddl.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ***************************************************************/
18
19 BOOL
20 AppendSystemPostfix(LPWSTR lpName,
21 DWORD dwMaxLength)
22 {
23 WCHAR szSystemRoot[MAX_PATH];
24 LPWSTR lpszPostfix;
25 LPWSTR lpszPtr;
26
27 /* Build profile name postfix */
28 if (!ExpandEnvironmentStringsW(L"%SystemRoot%",
29 szSystemRoot,
30 ARRAYSIZE(szSystemRoot)))
31 {
32 DPRINT1("Error: %lu\n", GetLastError());
33 return FALSE;
34 }
35
36 _wcsupr(szSystemRoot);
37
38 /* Get name postfix */
39 szSystemRoot[2] = L'.';
40 lpszPostfix = &szSystemRoot[2];
41 lpszPtr = lpszPostfix;
42 while (*lpszPtr != (WCHAR)0)
43 {
44 if (*lpszPtr == L'\\')
45 *lpszPtr = L'_';
46 lpszPtr++;
47 }
48
49 if (wcslen(lpName) + wcslen(lpszPostfix) + 1 >= dwMaxLength)
50 {
51 DPRINT1("Error: buffer overflow\n");
52 SetLastError(ERROR_BUFFER_OVERFLOW);
53 return FALSE;
54 }
55
56 wcscat(lpName, lpszPostfix);
57
58 return TRUE;
59 }
60
61
62 static
63 BOOL
64 AcquireRemoveRestorePrivilege(IN BOOL bAcquire)
65 {
66 BOOL bRet = FALSE;
67 HANDLE Token;
68 TOKEN_PRIVILEGES TokenPriv;
69
70 DPRINT("AcquireRemoveRestorePrivilege(%d)\n", bAcquire);
71
72 if (OpenProcessToken(GetCurrentProcess(),
73 TOKEN_ADJUST_PRIVILEGES,
74 &Token))
75 {
76 TokenPriv.PrivilegeCount = 1;
77 TokenPriv.Privileges[0].Attributes = (bAcquire ? SE_PRIVILEGE_ENABLED : 0);
78
79 if (LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &TokenPriv.Privileges[0].Luid))
80 {
81 bRet = AdjustTokenPrivileges(Token, FALSE, &TokenPriv, 0, NULL, NULL);
82
83 if (!bRet)
84 {
85 DPRINT1("AdjustTokenPrivileges() failed with error %lu\n", GetLastError());
86 }
87 else if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
88 {
89 DPRINT1("AdjustTokenPrivileges() succeeded, but with not all privileges assigned\n");
90 bRet = FALSE;
91 }
92 }
93 else
94 {
95 DPRINT1("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
96 }
97
98 CloseHandle(Token);
99 }
100 else
101 {
102 DPRINT1("OpenProcessToken() failed with error %lu\n", GetLastError());
103 }
104
105 return bRet;
106 }
107
108
109 static
110 BOOL
111 CheckForLoadedProfile(HANDLE hToken)
112 {
113 UNICODE_STRING SidString;
114 HKEY hKey;
115
116 DPRINT("CheckForLoadedProfile() called\n");
117
118 /* Get the user SID string */
119 if (!GetUserSidStringFromToken(hToken, &SidString))
120 {
121 DPRINT1("GetUserSidStringFromToken() failed\n");
122 return FALSE;
123 }
124
125 if (RegOpenKeyExW(HKEY_USERS,
126 SidString.Buffer,
127 0,
128 MAXIMUM_ALLOWED,
129 &hKey))
130 {
131 DPRINT("Profile not loaded\n");
132 RtlFreeUnicodeString(&SidString);
133 return FALSE;
134 }
135
136 RegCloseKey(hKey);
137
138 RtlFreeUnicodeString(&SidString);
139
140 DPRINT("Profile already loaded\n");
141
142 return TRUE;
143 }
144
145
146 static
147 HANDLE
148 CreateProfileMutex(
149 _In_ PWSTR pszSidString)
150 {
151 SECURITY_DESCRIPTOR SecurityDescriptor;
152 SECURITY_ATTRIBUTES SecurityAttributes;
153 PWSTR pszMutexName = NULL;
154 HANDLE hMutex = NULL;
155
156 pszMutexName = HeapAlloc(GetProcessHeap(),
157 0,
158 (wcslen(L"Global\\userenv: User Profile Mutex for ") + wcslen(pszSidString) + 1) * sizeof(WCHAR));
159 if (pszMutexName == NULL)
160 {
161 DPRINT("Failed to allocate the mutex name buffer!\n");
162 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
163 return NULL;
164 }
165
166 /* Build the profile mutex name */
167 wcscpy(pszMutexName, L"Global\\userenv: User Profile Mutex for ");
168 wcscat(pszMutexName, pszSidString);
169
170 /* Initialize the security descriptor */
171 InitializeSecurityDescriptor(&SecurityDescriptor,
172 SECURITY_DESCRIPTOR_REVISION);
173
174 /* Set a NULL-DACL (everyone has access) */
175 SetSecurityDescriptorDacl(&SecurityDescriptor,
176 TRUE,
177 NULL,
178 FALSE);
179
180 /* Initialize the security attributes */
181 SecurityAttributes.nLength = sizeof(SecurityAttributes);
182 SecurityAttributes.lpSecurityDescriptor = &SecurityDescriptor;
183 SecurityAttributes.bInheritHandle = FALSE;
184
185 /* Create the profile mutex */
186 hMutex = CreateMutexW(&SecurityAttributes,
187 FALSE,
188 pszMutexName);
189 if (hMutex == NULL)
190 {
191 DPRINT1("Failed to create the profile mutex (Error %lu)\n", GetLastError());
192 }
193
194 HeapFree(GetProcessHeap(), 0, pszMutexName);
195
196 return hMutex;
197 }
198
199
200 static
201 DWORD
202 IncrementRefCount(
203 PWSTR pszSidString,
204 PDWORD pdwRefCount)
205 {
206 HKEY hProfilesKey = NULL, hProfileKey = NULL;
207 DWORD dwRefCount = 0, dwLength, dwType;
208 DWORD dwError;
209
210 DPRINT1("IncrementRefCount(%S %p)\n",
211 pszSidString, pdwRefCount);
212
213 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
214 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
215 0,
216 KEY_QUERY_VALUE,
217 &hProfilesKey);
218 if (dwError != ERROR_SUCCESS)
219 {
220 DPRINT1("Error: %lu\n", dwError);
221 goto done;
222 }
223
224 dwError = RegOpenKeyExW(hProfilesKey,
225 pszSidString,
226 0,
227 KEY_QUERY_VALUE | KEY_SET_VALUE,
228 &hProfileKey);
229 if (dwError != ERROR_SUCCESS)
230 {
231 DPRINT1("Error: %lu\n", dwError);
232 goto done;
233 }
234
235 /* Get the reference counter */
236 dwLength = sizeof(dwRefCount);
237 RegQueryValueExW(hProfileKey,
238 L"RefCount",
239 NULL,
240 &dwType,
241 (PBYTE)&dwRefCount,
242 &dwLength);
243
244 dwRefCount++;
245
246 dwLength = sizeof(dwRefCount);
247 dwError = RegSetValueExW(hProfileKey,
248 L"RefCount",
249 0,
250 REG_DWORD,
251 (PBYTE)&dwRefCount,
252 dwLength);
253 if (dwError != ERROR_SUCCESS)
254 {
255 DPRINT1("Error: %lu\n", dwError);
256 goto done;
257 }
258
259 if (pdwRefCount != NULL)
260 *pdwRefCount = dwRefCount;
261
262 done:
263 if (hProfileKey != NULL)
264 RegCloseKey(hProfileKey);
265
266 if (hProfilesKey != NULL)
267 RegCloseKey(hProfilesKey);
268
269 return dwError;
270 }
271
272
273 static
274 DWORD
275 DecrementRefCount(
276 PWSTR pszSidString,
277 PDWORD pdwRefCount)
278 {
279 HKEY hProfilesKey = NULL, hProfileKey = NULL;
280 DWORD dwRefCount = 0, dwLength, dwType;
281 DWORD dwError;
282
283 DPRINT1("DecrementRefCount(%S %p)\n",
284 pszSidString, pdwRefCount);
285
286 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
287 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
288 0,
289 KEY_QUERY_VALUE,
290 &hProfilesKey);
291 if (dwError != ERROR_SUCCESS)
292 {
293 DPRINT1("Error: %lu\n", dwError);
294 goto done;
295 }
296
297 dwError = RegOpenKeyExW(hProfilesKey,
298 pszSidString,
299 0,
300 KEY_QUERY_VALUE | KEY_SET_VALUE,
301 &hProfileKey);
302 if (dwError != ERROR_SUCCESS)
303 {
304 DPRINT1("Error: %lu\n", dwError);
305 goto done;
306 }
307
308 /* Get the reference counter */
309 dwLength = sizeof(dwRefCount);
310 dwError = RegQueryValueExW(hProfileKey,
311 L"RefCount",
312 NULL,
313 &dwType,
314 (PBYTE)&dwRefCount,
315 &dwLength);
316 if (dwError != ERROR_SUCCESS)
317 {
318 DPRINT1("Error: %lu\n", dwError);
319 goto done;
320 }
321
322 dwRefCount--;
323
324 dwLength = sizeof(dwRefCount);
325 dwError = RegSetValueExW(hProfileKey,
326 L"RefCount",
327 0,
328 REG_DWORD,
329 (PBYTE)&dwRefCount,
330 dwLength);
331 if (dwError != ERROR_SUCCESS)
332 {
333 DPRINT1("Error: %lu\n", dwError);
334 goto done;
335 }
336
337 if (pdwRefCount != NULL)
338 *pdwRefCount = dwRefCount;
339
340 done:
341 if (hProfileKey != NULL)
342 RegCloseKey(hProfileKey);
343
344 if (hProfilesKey != NULL)
345 RegCloseKey(hProfilesKey);
346
347 return dwError;
348 }
349
350
351 static
352 DWORD
353 CheckForGuestsAndAdmins(
354 _In_ HANDLE hToken,
355 _Out_ PDWORD pdwState)
356 {
357 PTOKEN_GROUPS pGroupInfo = NULL;
358 PSID pAdministratorsSID = NULL;
359 PSID pGuestsSID = NULL;
360 DWORD i, dwSize;
361 DWORD dwError = ERROR_SUCCESS;
362
363 DPRINT("CheckForGuestsAndAdmins(%p %p)\n", hToken, pdwState);
364
365 /* Get the buffer size */
366 if (!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize))
367 {
368 dwError = GetLastError();
369 if (dwError != ERROR_INSUFFICIENT_BUFFER)
370 {
371 DPRINT1("GetTokenInformation() failed (Error %lu)\n", dwError);
372 return dwError;
373 }
374
375 dwError = ERROR_SUCCESS;
376 }
377
378 /* Allocate the buffer */
379 pGroupInfo = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize);
380 if (pGroupInfo == NULL)
381 {
382 dwError = ERROR_OUTOFMEMORY;
383 DPRINT1("HeapAlloc() failed (Error %lu)\n", dwError);
384 goto done;
385 }
386
387 /* Get the token groups */
388 if (!GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize))
389 {
390 dwError = GetLastError();
391 DPRINT1("GetTokenInformation() failed (Error %lu)\n", dwError);
392 goto done;
393 }
394
395 /* Build the Administrators Group SID */
396 if(!AllocateAndInitializeSid(&LocalSystemAuthority,
397 2,
398 SECURITY_BUILTIN_DOMAIN_RID,
399 DOMAIN_ALIAS_RID_ADMINS,
400 0, 0, 0, 0, 0, 0,
401 &pAdministratorsSID))
402 {
403 dwError = GetLastError();
404 DPRINT1("AllocateAndInitializeSid() failed (Error %lu)\n", dwError);
405 goto done;
406 }
407
408 /* Build the Guests Group SID */
409 if(!AllocateAndInitializeSid(&LocalSystemAuthority,
410 2,
411 SECURITY_BUILTIN_DOMAIN_RID,
412 DOMAIN_ALIAS_RID_GUESTS,
413 0, 0, 0, 0, 0, 0,
414 &pGuestsSID))
415 {
416 dwError = GetLastError();
417 DPRINT1("AllocateAndInitializeSid() failed (Error %lu)\n", dwError);
418 goto done;
419 }
420
421 /* Check for Administratos or Guests group memberships */
422 for (i = 0; i < pGroupInfo->GroupCount; i++)
423 {
424 if (EqualSid(pAdministratorsSID, pGroupInfo->Groups[i].Sid))
425 {
426 *pdwState |= 0x0100; // PROFILE_ADMIN_USER
427 }
428
429 if (EqualSid(pGuestsSID, pGroupInfo->Groups[i].Sid))
430 {
431 *pdwState |= 0x0080; // PROFILE_GUESTS_USER
432 }
433 }
434
435 dwError = ERROR_SUCCESS;
436
437 done:
438 if (pGuestsSID != NULL)
439 FreeSid(pGuestsSID);
440
441 if (pAdministratorsSID != NULL)
442 FreeSid(pAdministratorsSID);
443
444 if (pGroupInfo != NULL)
445 HeapFree(GetProcessHeap(), 0, pGroupInfo);
446
447 return dwError;
448 }
449
450
451 static
452 DWORD
453 SetProfileData(
454 _In_ PWSTR pszSidString,
455 _In_ DWORD dwFlags,
456 _In_ HANDLE hToken)
457 {
458 HKEY hProfilesKey = NULL, hProfileKey = NULL;
459 FILETIME LoadTime;
460 DWORD dwLength, dwState = 0;
461 DWORD dwError;
462
463 DPRINT("SetProfileData(%S %p)\n", pszSidString, hToken);
464
465 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
466 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
467 0,
468 KEY_QUERY_VALUE,
469 &hProfilesKey);
470 if (dwError != ERROR_SUCCESS)
471 {
472 DPRINT1("Error: %lu\n", dwError);
473 goto done;
474 }
475
476 dwError = RegOpenKeyExW(hProfilesKey,
477 pszSidString,
478 0,
479 KEY_QUERY_VALUE | KEY_SET_VALUE,
480 &hProfileKey);
481 if (dwError != ERROR_SUCCESS)
482 {
483 DPRINT1("Error: %lu\n", dwError);
484 goto done;
485 }
486
487 /* Set the profile load time */
488 GetSystemTimeAsFileTime(&LoadTime);
489
490 dwLength = sizeof(LoadTime.dwLowDateTime);
491 dwError = RegSetValueExW(hProfileKey,
492 L"ProfileLoadTimeLow",
493 0,
494 REG_DWORD,
495 (PBYTE)&LoadTime.dwLowDateTime,
496 dwLength);
497 if (dwError != ERROR_SUCCESS)
498 {
499 DPRINT1("Error: %lu\n", dwError);
500 goto done;
501 }
502
503 dwLength = sizeof(LoadTime.dwHighDateTime);
504 dwError = RegSetValueExW(hProfileKey,
505 L"ProfileLoadTimeHigh",
506 0,
507 REG_DWORD,
508 (PBYTE)&LoadTime.dwHighDateTime,
509 dwLength);
510 if (dwError != ERROR_SUCCESS)
511 {
512 DPRINT1("Error: %lu\n", dwError);
513 goto done;
514 }
515
516 dwLength = sizeof(dwFlags);
517 dwError = RegSetValueExW(hProfileKey,
518 L"Flags",
519 0,
520 REG_DWORD,
521 (PBYTE)&dwFlags,
522 dwLength);
523 if (dwError != ERROR_SUCCESS)
524 {
525 DPRINT1("Error: %lu\n", dwError);
526 goto done;
527 }
528
529 dwError = CheckForGuestsAndAdmins(hToken,
530 &dwState);
531 if (dwError != ERROR_SUCCESS)
532 {
533 DPRINT1("Error: %lu\n", dwError);
534 goto done;
535 }
536
537 dwLength = sizeof(dwState);
538 dwError = RegSetValueExW(hProfileKey,
539 L"State",
540 0,
541 REG_DWORD,
542 (PBYTE)&dwState,
543 dwLength);
544 if (dwError != ERROR_SUCCESS)
545 {
546 DPRINT1("Error: %lu\n", dwError);
547 goto done;
548 }
549
550 done:
551 if (hProfileKey != NULL)
552 RegCloseKey(hProfileKey);
553
554 if (hProfilesKey != NULL)
555 RegCloseKey(hProfilesKey);
556
557 return dwError;
558 }
559
560
561 /* PUBLIC FUNCTIONS ********************************************************/
562
563 BOOL
564 WINAPI
565 CopySystemProfile(
566 _In_ ULONG Unused)
567 {
568 WCHAR szKeyName[MAX_PATH];
569 WCHAR szRawProfilePath[MAX_PATH];
570 WCHAR szProfilePath[MAX_PATH];
571 WCHAR szDefaultProfilePath[MAX_PATH];
572 UNICODE_STRING SidString = {0, 0, NULL};
573 HANDLE hToken = NULL;
574 PSID pUserSid = NULL;
575 HKEY hProfileKey = NULL;
576 DWORD dwDisposition;
577 BOOL bResult = FALSE;
578 DWORD cchSize;
579 DWORD dwError;
580
581 DPRINT1("CopySystemProfile()\n");
582
583 if (!OpenProcessToken(GetCurrentProcess(),
584 TOKEN_QUERY | TOKEN_IMPERSONATE,
585 &hToken))
586 {
587 DPRINT1("Failed to open the process token (Error %lu)\n", GetLastError());
588 return FALSE;
589 }
590
591 pUserSid = GetUserSid(hToken);
592 if (pUserSid == NULL)
593 {
594 DPRINT1("Failed to get the users SID (Error %lu)\n", GetLastError());
595 goto done;
596 }
597
598 /* Get the user SID string */
599 if (!GetUserSidStringFromToken(hToken, &SidString))
600 {
601 DPRINT1("GetUserSidStringFromToken() failed\n");
602 goto done;
603 }
604
605 StringCbCopyW(szKeyName, sizeof(szKeyName),
606 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
607 StringCbCatW(szKeyName, sizeof(szKeyName), SidString.Buffer);
608
609 RtlFreeUnicodeString(&SidString);
610
611 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
612 szKeyName,
613 0, NULL, 0,
614 KEY_WRITE,
615 NULL,
616 &hProfileKey,
617 &dwDisposition);
618 if (dwError != ERROR_SUCCESS)
619 {
620 DPRINT1("Failed to create the profile key for the %s profile (Error %lu)\n",
621 SidString.Buffer, dwError);
622 goto done;
623 }
624
625 dwError = RegSetValueExW(hProfileKey,
626 L"Sid",
627 0,
628 REG_BINARY,
629 (PBYTE)pUserSid,
630 RtlLengthSid(pUserSid));
631 if (dwError != ERROR_SUCCESS)
632 {
633 DPRINT1("Failed to set the SID value (Error %lu)\n", dwError);
634 goto done;
635 }
636
637 wcscpy(szRawProfilePath,
638 L"%systemroot%\\system32\\config\\systemprofile");
639
640 dwError = RegSetValueExW(hProfileKey,
641 L"ProfileImagePath",
642 0,
643 REG_EXPAND_SZ,
644 (PBYTE)szRawProfilePath,
645 (wcslen(szRawProfilePath) + 1) * sizeof(WCHAR));
646 if (dwError != ERROR_SUCCESS)
647 {
648 DPRINT1("Failed to set the ProfileImagePath value (Error %lu)\n", dwError);
649 goto done;
650 }
651
652 /* Expand the raw profile path */
653 if (!ExpandEnvironmentStringsW(szRawProfilePath,
654 szProfilePath,
655 ARRAYSIZE(szProfilePath)))
656 {
657 DPRINT1("Failled to expand the raw profile path (Error %lu)\n", GetLastError());
658 goto done;
659 }
660
661 /* Create the profile directory if it does not exist yet */
662 // FIXME: Security!
663 if (!CreateDirectoryW(szProfilePath, NULL))
664 {
665 if (GetLastError() != ERROR_ALREADY_EXISTS)
666 {
667 DPRINT1("Failed to create the profile directory (Error %lu)\n", GetLastError());
668 goto done;
669 }
670 }
671
672 /* Get the path of the default profile */
673 cchSize = ARRAYSIZE(szDefaultProfilePath);
674 if (!GetDefaultUserProfileDirectoryW(szDefaultProfilePath, &cchSize))
675 {
676 DPRINT1("Failed to create the default profile path (Error %lu)\n", GetLastError());
677 goto done;
678 }
679
680 /* Copy the default profile into the new profile directory */
681 // FIXME: Security!
682 if (!CopyDirectory(szProfilePath, szDefaultProfilePath))
683 {
684 DPRINT1("Failed to copy the default profile directory (Error %lu)\n", GetLastError());
685 goto done;
686 }
687
688 bResult = TRUE;
689
690 done:
691 if (hProfileKey != NULL)
692 RegCloseKey(hProfileKey);
693
694 RtlFreeUnicodeString(&SidString);
695
696 if (pUserSid != NULL)
697 LocalFree(pUserSid);
698
699 if (hToken != NULL)
700 CloseHandle(hToken);
701
702 return bResult;
703 }
704
705
706 BOOL
707 WINAPI
708 CreateUserProfileA(
709 _In_ PSID pSid,
710 _In_ LPCSTR lpUserName)
711 {
712 LPWSTR pUserNameW = NULL;
713 INT nLength;
714 BOOL bResult;
715
716 DPRINT("CreateUserProfileA(%p %s)\n", pSid, lpUserName);
717
718 /* Convert lpUserName to Unicode */
719 nLength = MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, NULL, 0);
720 pUserNameW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
721 if (pUserNameW == NULL)
722 {
723 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
724 return FALSE;
725 }
726 MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, pUserNameW, nLength);
727
728 /* Call the Ex function */
729 bResult = CreateUserProfileExW(pSid,
730 pUserNameW,
731 NULL,
732 NULL,
733 0,
734 FALSE);
735
736 HeapFree(GetProcessHeap(), 0, pUserNameW);
737
738 return bResult;
739 }
740
741
742 BOOL
743 WINAPI
744 CreateUserProfileW(
745 _In_ PSID pSid,
746 _In_ LPCWSTR lpUserName)
747 {
748 DPRINT("CreateUserProfileW(%p %S)\n", pSid, lpUserName);
749
750 /* Call the Ex function */
751 return CreateUserProfileExW(pSid,
752 lpUserName,
753 NULL,
754 NULL,
755 0,
756 FALSE);
757 }
758
759
760 BOOL
761 WINAPI
762 CreateUserProfileExA(
763 _In_ PSID pSid,
764 _In_ LPCSTR lpUserName,
765 _In_opt_ LPCSTR lpUserHive,
766 _Out_opt_ LPSTR lpProfileDir,
767 _In_ DWORD dwDirSize,
768 _In_ BOOL bWin9xUpg)
769 {
770 LPWSTR pUserNameW = NULL;
771 LPWSTR pUserHiveW = NULL;
772 LPWSTR pProfileDirW = NULL;
773 INT nLength;
774 BOOL bResult = FALSE;
775
776 DPRINT("CreateUserProfileExA(%p %s %s %p %lu %d)\n",
777 pSid, lpUserName, lpUserHive, lpProfileDir, dwDirSize, bWin9xUpg);
778
779 /* Check the parameters */
780 if (lpProfileDir != NULL && dwDirSize == 0)
781 {
782 SetLastError(ERROR_INVALID_PARAMETER);
783 return FALSE;
784 }
785
786 /* Convert lpUserName to Unicode */
787 nLength = MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, NULL, 0);
788 pUserNameW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
789 if (pUserNameW == NULL)
790 {
791 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
792 goto done;
793 }
794 MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, pUserNameW, nLength);
795
796 /* Convert lpUserHive to Unicode */
797 if (lpUserHive != NULL)
798 {
799 nLength = MultiByteToWideChar(CP_ACP, 0, lpUserHive, -1, NULL, 0);
800 pUserHiveW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
801 if (pUserHiveW == NULL)
802 {
803 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
804 goto done;
805 }
806 MultiByteToWideChar(CP_ACP, 0, lpUserHive, -1, pUserHiveW, nLength);
807 }
808
809 /* Allocate a Unicode buffer for lpProfileDir */
810 if (lpProfileDir != NULL)
811 {
812 pProfileDirW = HeapAlloc(GetProcessHeap(), 0, dwDirSize * sizeof(WCHAR));
813 if (pProfileDirW == NULL)
814 {
815 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
816 goto done;
817 }
818 }
819
820 /* Call the Unicode function */
821 bResult = CreateUserProfileExW(pSid,
822 (LPCWSTR)pUserNameW,
823 (LPCWSTR)pUserHiveW,
824 pProfileDirW,
825 dwDirSize,
826 bWin9xUpg);
827
828 /* Convert the profile path to ANSI */
829 if (bResult && lpProfileDir != NULL)
830 {
831 WideCharToMultiByte(CP_ACP, 0, pProfileDirW, -1, lpProfileDir, dwDirSize, NULL, NULL);
832 }
833
834 done:
835 /* Free the buffers */
836 if (pProfileDirW != NULL)
837 HeapFree(GetProcessHeap(), 0, pProfileDirW);
838
839 if (pUserHiveW != NULL)
840 HeapFree(GetProcessHeap(), 0, pUserHiveW);
841
842 if (pUserNameW != NULL)
843 HeapFree(GetProcessHeap(), 0, pUserNameW);
844
845 return bResult;
846 }
847
848
849 BOOL
850 WINAPI
851 CreateUserProfileExW(
852 _In_ PSID pSid,
853 _In_ LPCWSTR lpUserName,
854 _In_opt_ LPCWSTR lpUserHive,
855 _Out_opt_ LPWSTR lpProfileDir,
856 _In_ DWORD dwDirSize,
857 _In_ BOOL bWin9xUpg)
858 {
859 WCHAR szRawProfilesPath[MAX_PATH];
860 WCHAR szProfilesPath[MAX_PATH];
861 WCHAR szUserProfilePath[MAX_PATH];
862 WCHAR szDefaultUserPath[MAX_PATH];
863 WCHAR szUserProfileName[MAX_PATH];
864 WCHAR szBuffer[MAX_PATH];
865 LPWSTR SidString;
866 DWORD dwType, dwLength;
867 DWORD dwDisposition;
868 UINT i;
869 HKEY hKey;
870 BOOL bRet = TRUE;
871 LONG Error;
872
873 DPRINT("CreateUserProfileExW(%p %S %S %p %lu %d)\n",
874 pSid, lpUserName, lpUserHive, lpProfileDir, dwDirSize, bWin9xUpg);
875
876 /* Parameters validation */
877 if (!pSid || !lpUserName)
878 {
879 SetLastError(ERROR_INVALID_PARAMETER);
880 return FALSE;
881 }
882
883 /*
884 * TODO:
885 * - Add support for lpUserHive.
886 * - bWin9xUpg is obsolete. Don't waste your time implementing this.
887 */
888
889 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
890 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
891 0,
892 KEY_QUERY_VALUE,
893 &hKey);
894 if (Error != ERROR_SUCCESS)
895 {
896 DPRINT1("Error: %lu\n", Error);
897 SetLastError((DWORD)Error);
898 return FALSE;
899 }
900
901 /* Get profiles path */
902 dwLength = sizeof(szRawProfilesPath);
903 Error = RegQueryValueExW(hKey,
904 L"ProfilesDirectory",
905 NULL,
906 &dwType,
907 (LPBYTE)szRawProfilesPath,
908 &dwLength);
909 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
910 {
911 DPRINT1("Error: %lu\n", Error);
912 RegCloseKey(hKey);
913 SetLastError((DWORD)Error);
914 return FALSE;
915 }
916
917 /* Expand it */
918 if (!ExpandEnvironmentStringsW(szRawProfilesPath,
919 szProfilesPath,
920 ARRAYSIZE(szProfilesPath)))
921 {
922 DPRINT1("Error: %lu\n", GetLastError());
923 RegCloseKey(hKey);
924 return FALSE;
925 }
926
927 /* Create the profiles directory if it does not exist yet */
928 // FIXME: Security!
929 if (!CreateDirectoryW(szProfilesPath, NULL))
930 {
931 if (GetLastError() != ERROR_ALREADY_EXISTS)
932 {
933 DPRINT1("Error: %lu\n", GetLastError());
934 return FALSE;
935 }
936 }
937
938 /* Get default user path */
939 dwLength = sizeof(szBuffer);
940 Error = RegQueryValueExW(hKey,
941 L"DefaultUserProfile",
942 NULL,
943 &dwType,
944 (LPBYTE)szBuffer,
945 &dwLength);
946 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
947 {
948 DPRINT1("Error: %lu\n", Error);
949 RegCloseKey(hKey);
950 SetLastError((DWORD)Error);
951 return FALSE;
952 }
953
954 RegCloseKey(hKey);
955
956 StringCbCopyW(szUserProfileName, sizeof(szUserProfileName), lpUserName);
957
958 /* Create user profile directory */
959
960 StringCbCopyW(szUserProfilePath, sizeof(szUserProfilePath), szProfilesPath);
961 StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), L"\\");
962 StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), szUserProfileName);
963
964 // FIXME: Security!
965 if (!CreateDirectoryW(szUserProfilePath, NULL))
966 {
967 if (GetLastError() != ERROR_ALREADY_EXISTS)
968 {
969 DPRINT1("Error: %lu\n", GetLastError());
970 return FALSE;
971 }
972
973 for (i = 0; i < 1000; i++)
974 {
975 swprintf(szUserProfileName, L"%s.%03u", lpUserName, i);
976
977 StringCbCopyW(szUserProfilePath, sizeof(szUserProfilePath), szProfilesPath);
978 StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), L"\\");
979 StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), szUserProfileName);
980
981 // FIXME: Security!
982 if (CreateDirectoryW(szUserProfilePath, NULL))
983 break;
984
985 if (GetLastError() != ERROR_ALREADY_EXISTS)
986 {
987 DPRINT1("Error: %lu\n", GetLastError());
988 return FALSE;
989 }
990 }
991 }
992
993 /* Copy default user directory */
994
995 StringCbCopyW(szDefaultUserPath, sizeof(szDefaultUserPath), szProfilesPath);
996 StringCbCatW(szDefaultUserPath, sizeof(szDefaultUserPath), L"\\");
997 StringCbCatW(szDefaultUserPath, sizeof(szDefaultUserPath), szBuffer);
998
999 // FIXME: Security!
1000 if (!CopyDirectory(szUserProfilePath, szDefaultUserPath))
1001 {
1002 DPRINT1("Error: %lu\n", GetLastError());
1003 return FALSE;
1004 }
1005
1006 /* Add profile to profile list */
1007 if (!ConvertSidToStringSidW(pSid,
1008 &SidString))
1009 {
1010 DPRINT1("Error: %lu\n", GetLastError());
1011 return FALSE;
1012 }
1013
1014 StringCbCopyW(szBuffer, sizeof(szBuffer),
1015 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
1016 StringCbCatW(szBuffer, sizeof(szBuffer), SidString);
1017
1018 /* Create user profile key */
1019 Error = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
1020 szBuffer,
1021 0,
1022 NULL,
1023 REG_OPTION_NON_VOLATILE,
1024 KEY_ALL_ACCESS,
1025 NULL,
1026 &hKey,
1027 &dwDisposition);
1028 if (Error != ERROR_SUCCESS)
1029 {
1030 DPRINT1("Error: %lu\n", Error);
1031 bRet = FALSE;
1032 goto done;
1033 }
1034
1035 /* Create non-expanded user profile path */
1036 StringCbCopyW(szBuffer, sizeof(szBuffer), szRawProfilesPath);
1037 StringCbCatW(szBuffer, sizeof(szBuffer), L"\\");
1038 StringCbCatW(szBuffer, sizeof(szBuffer), szUserProfileName);
1039
1040 /* Set 'ProfileImagePath' value (non-expanded) */
1041 Error = RegSetValueExW(hKey,
1042 L"ProfileImagePath",
1043 0,
1044 REG_EXPAND_SZ,
1045 (LPBYTE)szBuffer,
1046 (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1047 if (Error != ERROR_SUCCESS)
1048 {
1049 DPRINT1("Error: %lu\n", Error);
1050 RegCloseKey(hKey);
1051 bRet = FALSE;
1052 goto done;
1053 }
1054
1055 /* Set 'Sid' value */
1056 Error = RegSetValueExW(hKey,
1057 L"Sid",
1058 0,
1059 REG_BINARY,
1060 pSid,
1061 GetLengthSid(pSid));
1062 if (Error != ERROR_SUCCESS)
1063 {
1064 DPRINT1("Error: %lu\n", Error);
1065 RegCloseKey(hKey);
1066 bRet = FALSE;
1067 goto done;
1068 }
1069
1070 RegCloseKey(hKey);
1071
1072 /* Create user hive file */
1073
1074 /* Use the default hive file name */
1075 StringCbCopyW(szBuffer, sizeof(szBuffer), szUserProfilePath);
1076 StringCbCatW(szBuffer, sizeof(szBuffer), L"\\ntuser.dat");
1077
1078 /* Acquire restore privilege */
1079 if (!AcquireRemoveRestorePrivilege(TRUE))
1080 {
1081 Error = GetLastError();
1082 DPRINT1("Error: %lu\n", Error);
1083 bRet = FALSE;
1084 goto done;
1085 }
1086
1087 /* Load the user hive */
1088 Error = RegLoadKeyW(HKEY_USERS,
1089 SidString,
1090 szBuffer);
1091 AcquireRemoveRestorePrivilege(FALSE);
1092 if (Error != ERROR_SUCCESS)
1093 {
1094 DPRINT1("Error: %lu\n", Error);
1095 bRet = FALSE;
1096 goto done;
1097 }
1098
1099 /* Initialize user hive */
1100 if (!CreateUserHive(SidString, szUserProfilePath))
1101 {
1102 Error = GetLastError();
1103 DPRINT1("Error: %lu\n", Error);
1104 bRet = FALSE;
1105 }
1106
1107 /* Unload the hive */
1108 AcquireRemoveRestorePrivilege(TRUE);
1109 RegUnLoadKeyW(HKEY_USERS, SidString);
1110 AcquireRemoveRestorePrivilege(FALSE);
1111
1112 /*
1113 * If the caller wants to retrieve the user profile path,
1114 * give it now. 'dwDirSize' is the number of characters.
1115 */
1116 if (lpProfileDir && dwDirSize)
1117 StringCchCopyW(lpProfileDir, dwDirSize, szUserProfilePath);
1118
1119 done:
1120 LocalFree((HLOCAL)SidString);
1121 SetLastError((DWORD)Error);
1122
1123 DPRINT("CreateUserProfileExW() done\n");
1124
1125 return bRet;
1126 }
1127
1128
1129 BOOL
1130 WINAPI
1131 DeleteProfileA(
1132 _In_ LPCSTR lpSidString,
1133 _In_opt_ LPCSTR lpProfilePath,
1134 _In_opt_ LPCSTR lpComputerName)
1135 {
1136 BOOL bResult;
1137 UNICODE_STRING SidString = {0, 0, NULL}, ProfilePath = {0, 0, NULL}, ComputerName = {0, 0, NULL};
1138
1139 DPRINT("DeleteProfileA() called\n");
1140
1141 /* Conversion to UNICODE */
1142 if (lpSidString)
1143 RtlCreateUnicodeStringFromAsciiz(&SidString,
1144 (LPSTR)lpSidString);
1145
1146 if (lpProfilePath)
1147 RtlCreateUnicodeStringFromAsciiz(&ProfilePath,
1148 (LPSTR)lpProfilePath);
1149
1150 if (lpComputerName)
1151 RtlCreateUnicodeStringFromAsciiz(&ComputerName,
1152 (LPSTR)lpComputerName);
1153
1154 /* Call the UNICODE function */
1155 bResult = DeleteProfileW(SidString.Buffer,
1156 ProfilePath.Buffer,
1157 ComputerName.Buffer);
1158
1159 /* Memory cleanup */
1160 if (lpSidString)
1161 RtlFreeUnicodeString(&SidString);
1162
1163 if (lpProfilePath)
1164 RtlFreeUnicodeString(&ProfilePath);
1165
1166 if (lpComputerName)
1167 RtlFreeUnicodeString(&ComputerName);
1168
1169 return bResult;
1170 }
1171
1172
1173 BOOL
1174 WINAPI
1175 DeleteProfileW(
1176 _In_ LPCWSTR lpSidString,
1177 _In_opt_ LPCWSTR lpProfilePath,
1178 _In_opt_ LPCWSTR lpComputerName)
1179 {
1180 DPRINT1("DeleteProfileW(%S %S %S) not implemented!\n", lpSidString, lpProfilePath, lpComputerName);
1181 return TRUE; //FALSE;
1182 }
1183
1184
1185 BOOL
1186 WINAPI
1187 GetAllUsersProfileDirectoryA(
1188 _Out_opt_ LPSTR lpProfileDir,
1189 _Inout_ LPDWORD lpcchSize)
1190 {
1191 LPWSTR lpBuffer;
1192 BOOL bResult;
1193
1194 if (!lpcchSize)
1195 {
1196 SetLastError(ERROR_INVALID_PARAMETER);
1197 return FALSE;
1198 }
1199
1200 lpBuffer = GlobalAlloc(GMEM_FIXED,
1201 *lpcchSize * sizeof(WCHAR));
1202 if (lpBuffer == NULL)
1203 return FALSE;
1204
1205 bResult = GetAllUsersProfileDirectoryW(lpBuffer,
1206 lpcchSize);
1207 if (bResult && lpProfileDir)
1208 {
1209 bResult = WideCharToMultiByte(CP_ACP,
1210 0,
1211 lpBuffer,
1212 -1,
1213 lpProfileDir,
1214 *lpcchSize,
1215 NULL,
1216 NULL);
1217 }
1218
1219 GlobalFree(lpBuffer);
1220
1221 return bResult;
1222 }
1223
1224
1225 BOOL
1226 WINAPI
1227 GetAllUsersProfileDirectoryW(
1228 _Out_opt_ LPWSTR lpProfileDir,
1229 _Inout_ LPDWORD lpcchSize)
1230 {
1231 WCHAR szProfilePath[MAX_PATH];
1232 WCHAR szBuffer[MAX_PATH];
1233 DWORD dwType, dwLength;
1234 HKEY hKey;
1235 LONG Error;
1236
1237 if (!lpcchSize)
1238 {
1239 SetLastError(ERROR_INVALID_PARAMETER);
1240 return FALSE;
1241 }
1242
1243 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1244 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1245 0,
1246 KEY_QUERY_VALUE,
1247 &hKey);
1248 if (Error != ERROR_SUCCESS)
1249 {
1250 DPRINT1("Error: %lu\n", Error);
1251 SetLastError((DWORD)Error);
1252 return FALSE;
1253 }
1254
1255 /* Get profiles path */
1256 dwLength = sizeof(szBuffer);
1257 Error = RegQueryValueExW(hKey,
1258 L"ProfilesDirectory",
1259 NULL,
1260 &dwType,
1261 (LPBYTE)szBuffer,
1262 &dwLength);
1263 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1264 {
1265 DPRINT1("Error: %lu\n", Error);
1266 RegCloseKey(hKey);
1267 SetLastError((DWORD)Error);
1268 return FALSE;
1269 }
1270
1271 /* Expand it */
1272 if (!ExpandEnvironmentStringsW(szBuffer,
1273 szProfilePath,
1274 ARRAYSIZE(szProfilePath)))
1275 {
1276 DPRINT1("Error: %lu\n", GetLastError());
1277 RegCloseKey(hKey);
1278 return FALSE;
1279 }
1280
1281 /* Get 'AllUsersProfile' name */
1282 dwLength = sizeof(szBuffer);
1283 Error = RegQueryValueExW(hKey,
1284 L"AllUsersProfile",
1285 NULL,
1286 &dwType,
1287 (LPBYTE)szBuffer,
1288 &dwLength);
1289 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1290 {
1291 DPRINT1("Error: %lu\n", Error);
1292 RegCloseKey(hKey);
1293 SetLastError((DWORD)Error);
1294 return FALSE;
1295 }
1296
1297 RegCloseKey(hKey);
1298
1299 StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
1300 StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
1301
1302 dwLength = wcslen(szProfilePath) + 1;
1303 if (lpProfileDir && (*lpcchSize >= dwLength))
1304 {
1305 StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
1306 *lpcchSize = dwLength;
1307 return TRUE;
1308 }
1309 else // if (!lpProfileDir || (*lpcchSize < dwLength))
1310 {
1311 *lpcchSize = dwLength;
1312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1313 return FALSE;
1314 }
1315 }
1316
1317
1318 BOOL
1319 WINAPI
1320 GetDefaultUserProfileDirectoryA(
1321 _Out_opt_ LPSTR lpProfileDir,
1322 _Inout_ LPDWORD lpcchSize)
1323 {
1324 LPWSTR lpBuffer;
1325 BOOL bResult;
1326
1327 if (!lpcchSize)
1328 {
1329 SetLastError(ERROR_INVALID_PARAMETER);
1330 return FALSE;
1331 }
1332
1333 lpBuffer = GlobalAlloc(GMEM_FIXED,
1334 *lpcchSize * sizeof(WCHAR));
1335 if (lpBuffer == NULL)
1336 return FALSE;
1337
1338 bResult = GetDefaultUserProfileDirectoryW(lpBuffer,
1339 lpcchSize);
1340 if (bResult && lpProfileDir)
1341 {
1342 bResult = WideCharToMultiByte(CP_ACP,
1343 0,
1344 lpBuffer,
1345 -1,
1346 lpProfileDir,
1347 *lpcchSize,
1348 NULL,
1349 NULL);
1350 }
1351
1352 GlobalFree(lpBuffer);
1353
1354 return bResult;
1355 }
1356
1357
1358 BOOL
1359 WINAPI
1360 GetDefaultUserProfileDirectoryW(
1361 _Out_opt_ LPWSTR lpProfileDir,
1362 _Inout_ LPDWORD lpcchSize)
1363 {
1364 WCHAR szProfilePath[MAX_PATH];
1365 WCHAR szBuffer[MAX_PATH];
1366 DWORD dwType, dwLength;
1367 HKEY hKey;
1368 LONG Error;
1369
1370 if (!lpcchSize)
1371 {
1372 SetLastError(ERROR_INVALID_PARAMETER);
1373 return FALSE;
1374 }
1375
1376 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1377 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1378 0,
1379 KEY_QUERY_VALUE,
1380 &hKey);
1381 if (Error != ERROR_SUCCESS)
1382 {
1383 DPRINT1("Error: %lu\n", Error);
1384 SetLastError((DWORD)Error);
1385 return FALSE;
1386 }
1387
1388 /* Get profiles path */
1389 dwLength = sizeof(szBuffer);
1390 Error = RegQueryValueExW(hKey,
1391 L"ProfilesDirectory",
1392 NULL,
1393 &dwType,
1394 (LPBYTE)szBuffer,
1395 &dwLength);
1396 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1397 {
1398 DPRINT1("Error: %lu\n", Error);
1399 RegCloseKey(hKey);
1400 SetLastError((DWORD)Error);
1401 return FALSE;
1402 }
1403
1404 /* Expand it */
1405 if (!ExpandEnvironmentStringsW(szBuffer,
1406 szProfilePath,
1407 ARRAYSIZE(szProfilePath)))
1408 {
1409 DPRINT1("Error: %lu\n", GetLastError());
1410 RegCloseKey(hKey);
1411 return FALSE;
1412 }
1413
1414 /* Get 'DefaultUserProfile' name */
1415 dwLength = sizeof(szBuffer);
1416 Error = RegQueryValueExW(hKey,
1417 L"DefaultUserProfile",
1418 NULL,
1419 &dwType,
1420 (LPBYTE)szBuffer,
1421 &dwLength);
1422 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1423 {
1424 DPRINT1("Error: %lu\n", Error);
1425 RegCloseKey(hKey);
1426 SetLastError((DWORD)Error);
1427 return FALSE;
1428 }
1429
1430 RegCloseKey(hKey);
1431
1432 StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
1433 StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
1434
1435 dwLength = wcslen(szProfilePath) + 1;
1436 if (lpProfileDir && (*lpcchSize >= dwLength))
1437 {
1438 StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
1439 *lpcchSize = dwLength;
1440 return TRUE;
1441 }
1442 else // if (!lpProfileDir || (*lpcchSize < dwLength))
1443 {
1444 *lpcchSize = dwLength;
1445 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1446 return FALSE;
1447 }
1448 }
1449
1450
1451 BOOL
1452 WINAPI
1453 GetProfilesDirectoryA(
1454 _Out_ LPSTR lpProfileDir, // _Out_opt_
1455 _Inout_ LPDWORD lpcchSize)
1456 {
1457 LPWSTR lpBuffer;
1458 BOOL bResult;
1459
1460 if (!lpcchSize || !lpProfileDir)
1461 {
1462 SetLastError(ERROR_INVALID_PARAMETER);
1463 return FALSE;
1464 }
1465
1466 lpBuffer = GlobalAlloc(GMEM_FIXED,
1467 *lpcchSize * sizeof(WCHAR));
1468 if (lpBuffer == NULL)
1469 return FALSE;
1470
1471 bResult = GetProfilesDirectoryW(lpBuffer,
1472 lpcchSize);
1473 if (bResult && lpProfileDir)
1474 {
1475 bResult = WideCharToMultiByte(CP_ACP,
1476 0,
1477 lpBuffer,
1478 -1,
1479 lpProfileDir,
1480 *lpcchSize,
1481 NULL,
1482 NULL);
1483 }
1484
1485 GlobalFree(lpBuffer);
1486
1487 return bResult;
1488 }
1489
1490
1491 BOOL
1492 WINAPI
1493 GetProfilesDirectoryW(
1494 _Out_ LPWSTR lpProfilesDir, // _Out_opt_
1495 _Inout_ LPDWORD lpcchSize)
1496 {
1497 WCHAR szProfilesPath[MAX_PATH];
1498 WCHAR szBuffer[MAX_PATH];
1499 DWORD dwType, dwLength;
1500 HKEY hKey;
1501 LONG Error;
1502
1503 if (!lpcchSize)
1504 {
1505 SetLastError(ERROR_INVALID_PARAMETER);
1506 return FALSE;
1507 }
1508
1509 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1510 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1511 0,
1512 KEY_QUERY_VALUE,
1513 &hKey);
1514 if (Error != ERROR_SUCCESS)
1515 {
1516 DPRINT1("Error: %lu\n", Error);
1517 SetLastError((DWORD)Error);
1518 return FALSE;
1519 }
1520
1521 /* Get profiles path */
1522 dwLength = sizeof(szBuffer);
1523 Error = RegQueryValueExW(hKey,
1524 L"ProfilesDirectory",
1525 NULL,
1526 &dwType,
1527 (LPBYTE)szBuffer,
1528 &dwLength);
1529 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1530 {
1531 DPRINT1("Error: %lu\n", Error);
1532 RegCloseKey(hKey);
1533 SetLastError((DWORD)Error);
1534 return FALSE;
1535 }
1536
1537 RegCloseKey(hKey);
1538
1539 /* Expand it */
1540 if (!ExpandEnvironmentStringsW(szBuffer,
1541 szProfilesPath,
1542 ARRAYSIZE(szProfilesPath)))
1543 {
1544 DPRINT1("Error: %lu\n", GetLastError());
1545 return FALSE;
1546 }
1547
1548 dwLength = wcslen(szProfilesPath) + 1;
1549 if (lpProfilesDir && (*lpcchSize >= dwLength))
1550 {
1551 StringCchCopyW(lpProfilesDir, *lpcchSize, szProfilesPath);
1552 *lpcchSize = dwLength;
1553 return TRUE;
1554 }
1555 else // if (!lpProfilesDir || (*lpcchSize < dwLength))
1556 {
1557 *lpcchSize = dwLength;
1558 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1559 return FALSE;
1560 }
1561 }
1562
1563
1564 BOOL
1565 WINAPI
1566 GetProfileType(
1567 _Out_ PDWORD pdwFlags)
1568 {
1569 UNICODE_STRING SidString = {0, 0, NULL};
1570 HANDLE hToken;
1571 HKEY hProfilesKey = NULL, hProfileKey = NULL;
1572 DWORD dwType, dwLength, dwState = 0;
1573 DWORD dwError;
1574 BOOL bResult = FALSE;
1575
1576 DPRINT("GetProfileType(%p)\n", pdwFlags);
1577
1578 if (pdwFlags == NULL)
1579 {
1580 SetLastError(ERROR_INVALID_PARAMETER);
1581 return FALSE;
1582 }
1583
1584 if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
1585 {
1586 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
1587 {
1588 DPRINT1("Failed to open a token (Error %lu)\n", GetLastError());
1589 return FALSE;
1590 }
1591 }
1592
1593 /* Get the user SID string */
1594 if (!GetUserSidStringFromToken(hToken, &SidString))
1595 {
1596 DPRINT1("GetUserSidStringFromToken() failed\n");
1597 goto done;
1598 }
1599
1600 DPRINT("SID: %wZ\n", &SidString);
1601
1602 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1603 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1604 0,
1605 KEY_QUERY_VALUE,
1606 &hProfilesKey);
1607 if (dwError != ERROR_SUCCESS)
1608 {
1609 DPRINT1("Error: %lu\n", dwError);
1610 SetLastError(dwError);
1611 goto done;
1612 }
1613
1614 dwError = RegOpenKeyExW(hProfilesKey,
1615 SidString.Buffer,
1616 0,
1617 KEY_QUERY_VALUE | KEY_SET_VALUE,
1618 &hProfileKey);
1619 if (dwError != ERROR_SUCCESS)
1620 {
1621 DPRINT1("Error: %lu\n", dwError);
1622 SetLastError(dwError);
1623 goto done;
1624 }
1625
1626 /* Get the State value */
1627 dwLength = sizeof(dwState);
1628 dwError = RegQueryValueExW(hProfileKey,
1629 L"State",
1630 NULL,
1631 &dwType,
1632 (PBYTE)&dwState,
1633 &dwLength);
1634 if (dwError != ERROR_SUCCESS)
1635 {
1636 DPRINT1("Error: %lu\n", dwError);
1637 SetLastError(dwError);
1638 goto done;
1639 }
1640
1641 *pdwFlags = 0;
1642
1643 if (dwState & 0x80) /* PROFILE_GUEST_USER */
1644 *pdwFlags |= PT_TEMPORARY;
1645
1646 /* FIXME: Add checks for PT_MANDATORY and PT_ROAMING */
1647
1648 bResult = TRUE;
1649
1650 done:
1651 if (hProfileKey != NULL)
1652 RegCloseKey(hProfileKey);
1653
1654 if (hProfilesKey != NULL)
1655 RegCloseKey(hProfilesKey);
1656
1657 RtlFreeUnicodeString(&SidString);
1658
1659 CloseHandle(hToken);
1660
1661 return bResult;
1662 }
1663
1664
1665 BOOL
1666 WINAPI
1667 GetUserProfileDirectoryA(
1668 _In_ HANDLE hToken,
1669 _Out_opt_ LPSTR lpProfileDir,
1670 _Inout_ LPDWORD lpcchSize)
1671 {
1672 LPWSTR lpBuffer;
1673 BOOL bResult;
1674
1675 if (!lpcchSize || !lpProfileDir)
1676 {
1677 SetLastError(ERROR_INVALID_PARAMETER);
1678 return FALSE;
1679 }
1680
1681 lpBuffer = GlobalAlloc(GMEM_FIXED,
1682 *lpcchSize * sizeof(WCHAR));
1683 if (lpBuffer == NULL)
1684 return FALSE;
1685
1686 bResult = GetUserProfileDirectoryW(hToken,
1687 lpBuffer,
1688 lpcchSize);
1689 if (bResult && lpProfileDir)
1690 {
1691 bResult = WideCharToMultiByte(CP_ACP,
1692 0,
1693 lpBuffer,
1694 -1,
1695 lpProfileDir,
1696 *lpcchSize,
1697 NULL,
1698 NULL);
1699 }
1700
1701 GlobalFree(lpBuffer);
1702
1703 return bResult;
1704 }
1705
1706
1707 BOOL
1708 WINAPI
1709 GetUserProfileDirectoryW(
1710 _In_ HANDLE hToken,
1711 _Out_opt_ LPWSTR lpProfileDir,
1712 _Inout_ LPDWORD lpcchSize)
1713 {
1714 UNICODE_STRING SidString;
1715 WCHAR szKeyName[MAX_PATH];
1716 WCHAR szRawImagePath[MAX_PATH];
1717 WCHAR szImagePath[MAX_PATH];
1718 DWORD dwType, dwLength;
1719 HKEY hKey;
1720 LONG Error;
1721
1722 if (!hToken)
1723 {
1724 SetLastError(ERROR_INVALID_HANDLE);
1725 return FALSE;
1726 }
1727
1728 if (!lpcchSize)
1729 {
1730 SetLastError(ERROR_INVALID_PARAMETER);
1731 return FALSE;
1732 }
1733
1734 /* Get the user SID string */
1735 if (!GetUserSidStringFromToken(hToken, &SidString))
1736 {
1737 DPRINT1("GetUserSidStringFromToken() failed\n");
1738 return FALSE;
1739 }
1740
1741 DPRINT("SidString: '%wZ'\n", &SidString);
1742
1743 StringCbCopyW(szKeyName, sizeof(szKeyName),
1744 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
1745 StringCbCatW(szKeyName, sizeof(szKeyName), SidString.Buffer);
1746
1747 RtlFreeUnicodeString(&SidString);
1748
1749 DPRINT("KeyName: '%S'\n", szKeyName);
1750
1751 Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1752 szKeyName,
1753 0,
1754 KEY_QUERY_VALUE,
1755 &hKey);
1756 if (Error != ERROR_SUCCESS)
1757 {
1758 DPRINT1("Error: %lu\n", Error);
1759 SetLastError((DWORD)Error);
1760 return FALSE;
1761 }
1762
1763 dwLength = sizeof(szRawImagePath);
1764 Error = RegQueryValueExW(hKey,
1765 L"ProfileImagePath",
1766 NULL,
1767 &dwType,
1768 (LPBYTE)szRawImagePath,
1769 &dwLength);
1770 if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1771 {
1772 DPRINT1("Error: %lu\n", Error);
1773 RegCloseKey(hKey);
1774 SetLastError((DWORD)Error);
1775 return FALSE;
1776 }
1777
1778 RegCloseKey(hKey);
1779
1780 DPRINT("RawImagePath: '%S'\n", szRawImagePath);
1781
1782 /* Expand it */
1783 if (!ExpandEnvironmentStringsW(szRawImagePath,
1784 szImagePath,
1785 ARRAYSIZE(szImagePath)))
1786 {
1787 DPRINT1("Error: %lu\n", GetLastError());
1788 return FALSE;
1789 }
1790
1791 DPRINT("ImagePath: '%S'\n", szImagePath);
1792
1793 dwLength = wcslen(szImagePath) + 1;
1794 if (lpProfileDir && (*lpcchSize >= dwLength))
1795 {
1796 StringCchCopyW(lpProfileDir, *lpcchSize, szImagePath);
1797 *lpcchSize = dwLength;
1798 return TRUE;
1799 }
1800 else // if (!lpProfileDir || (*lpcchSize < dwLength))
1801 {
1802 *lpcchSize = dwLength;
1803 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1804 return FALSE;
1805 }
1806 }
1807
1808
1809 BOOL
1810 WINAPI
1811 LoadUserProfileA(
1812 _In_ HANDLE hToken,
1813 _Inout_ LPPROFILEINFOA lpProfileInfo)
1814 {
1815 BOOL bResult = FALSE;
1816 PROFILEINFOW ProfileInfoW = {0};
1817 int len;
1818
1819 DPRINT("LoadUserProfileA() called\n");
1820
1821 /* Check profile info */
1822 if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOA)) ||
1823 (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
1824 {
1825 SetLastError(ERROR_INVALID_PARAMETER);
1826 return FALSE;
1827 }
1828
1829 /* Convert the structure to UNICODE... */
1830 ProfileInfoW.dwSize = sizeof(ProfileInfoW);
1831 ProfileInfoW.dwFlags = lpProfileInfo->dwFlags;
1832
1833 if (lpProfileInfo->lpUserName)
1834 {
1835 len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, NULL, 0);
1836 ProfileInfoW.lpUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1837 if (!ProfileInfoW.lpUserName)
1838 {
1839 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1840 goto cleanup;
1841 }
1842 MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, ProfileInfoW.lpUserName, len);
1843 }
1844
1845 if (lpProfileInfo->lpProfilePath)
1846 {
1847 len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, NULL, 0);
1848 ProfileInfoW.lpProfilePath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1849 if (!ProfileInfoW.lpProfilePath)
1850 {
1851 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1852 goto cleanup;
1853 }
1854 MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, ProfileInfoW.lpProfilePath, len);
1855 }
1856
1857 if (lpProfileInfo->lpDefaultPath)
1858 {
1859 len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, NULL, 0);
1860 ProfileInfoW.lpDefaultPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1861 if (!ProfileInfoW.lpDefaultPath)
1862 {
1863 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1864 goto cleanup;
1865 }
1866 MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, ProfileInfoW.lpDefaultPath, len);
1867 }
1868
1869 if (lpProfileInfo->lpServerName)
1870 {
1871 len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, NULL, 0);
1872 ProfileInfoW.lpServerName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1873 if (!ProfileInfoW.lpServerName)
1874 {
1875 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1876 goto cleanup;
1877 }
1878 MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, ProfileInfoW.lpServerName, len);
1879 }
1880
1881 if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && lpProfileInfo->lpPolicyPath)
1882 {
1883 len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, NULL, 0);
1884 ProfileInfoW.lpPolicyPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1885 if (!ProfileInfoW.lpPolicyPath)
1886 {
1887 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1888 goto cleanup;
1889 }
1890 MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, ProfileInfoW.lpPolicyPath, len);
1891 }
1892
1893 /* ... and call the UNICODE function */
1894 bResult = LoadUserProfileW(hToken, &ProfileInfoW);
1895
1896 /* Save the returned value */
1897 lpProfileInfo->hProfile = ProfileInfoW.hProfile;
1898
1899 cleanup:
1900 /* Memory cleanup */
1901 if (ProfileInfoW.lpUserName)
1902 HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpUserName);
1903
1904 if (ProfileInfoW.lpProfilePath)
1905 HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpProfilePath);
1906
1907 if (ProfileInfoW.lpDefaultPath)
1908 HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpDefaultPath);
1909
1910 if (ProfileInfoW.lpServerName)
1911 HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpServerName);
1912
1913 if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && ProfileInfoW.lpPolicyPath)
1914 HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpPolicyPath);
1915
1916 return bResult;
1917 }
1918
1919
1920 BOOL
1921 WINAPI
1922 LoadUserProfileW(
1923 _In_ HANDLE hToken,
1924 _Inout_ LPPROFILEINFOW lpProfileInfo)
1925 {
1926 WCHAR szUserHivePath[MAX_PATH];
1927 PTOKEN_USER UserSid = NULL;
1928 UNICODE_STRING SidString = { 0, 0, NULL };
1929 HANDLE hProfileMutex = NULL;
1930 LONG Error;
1931 BOOL ret = FALSE;
1932 DWORD dwLength = sizeof(szUserHivePath) / sizeof(szUserHivePath[0]);
1933
1934 DPRINT("LoadUserProfileW(%p %p)\n", hToken, lpProfileInfo);
1935
1936 /* Check profile info */
1937 if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOW)) ||
1938 (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
1939 {
1940 SetLastError(ERROR_INVALID_PARAMETER);
1941 return FALSE;
1942 }
1943
1944 DPRINT("UserName: %S\n", lpProfileInfo->lpUserName);
1945
1946 /* Get the user SID string */
1947 ret = GetUserSidStringFromToken(hToken, &SidString);
1948 if (!ret)
1949 {
1950 DPRINT1("GetUserSidStringFromToken() failed\n");
1951 goto cleanup;
1952 }
1953 ret = FALSE;
1954
1955 /* Create the profile mutex */
1956 hProfileMutex = CreateProfileMutex(SidString.Buffer);
1957 if (hProfileMutex == NULL)
1958 {
1959 DPRINT1("Failed to create the profile mutex\n");
1960 goto cleanup;
1961 }
1962
1963 /* Wait for the profile mutex */
1964 WaitForSingleObject(hProfileMutex, INFINITE);
1965
1966 /* Don't load a profile twice */
1967 if (CheckForLoadedProfile(hToken))
1968 {
1969 DPRINT1("Profile %S already loaded\n", SidString.Buffer);
1970 }
1971 else
1972 {
1973 DPRINT1("Loading profile %S\n", SidString.Buffer);
1974
1975 if (lpProfileInfo->lpProfilePath)
1976 {
1977 /* Use the caller's specified roaming user profile path */
1978 StringCbCopyW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpProfilePath);
1979 }
1980 else
1981 {
1982 /* FIXME: check if MS Windows allows lpProfileInfo->lpProfilePath to be NULL */
1983 if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
1984 {
1985 DPRINT1("GetProfilesDirectoryW() failed (error %ld)\n", GetLastError());
1986 goto cleanup;
1987 }
1988 }
1989
1990 /* Create user hive name */
1991 StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\");
1992 StringCbCatW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpUserName);
1993 StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\ntuser.dat");
1994 DPRINT("szUserHivePath: %S\n", szUserHivePath);
1995
1996 /* Create user profile directory if needed */
1997 if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
1998 {
1999 /* Get user sid */
2000 if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) ||
2001 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2002 {
2003 DPRINT1 ("GetTokenInformation() failed\n");
2004 goto cleanup;
2005 }
2006
2007 UserSid = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, dwLength);
2008 if (!UserSid)
2009 {
2010 DPRINT1("HeapAlloc() failed\n");
2011 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2012 goto cleanup;
2013 }
2014
2015 if (!GetTokenInformation(hToken, TokenUser, UserSid, dwLength, &dwLength))
2016 {
2017 DPRINT1("GetTokenInformation() failed\n");
2018 goto cleanup;
2019 }
2020
2021 /* Create profile */
2022 ret = CreateUserProfileW(UserSid->User.Sid, lpProfileInfo->lpUserName);
2023 if (!ret)
2024 {
2025 DPRINT1("CreateUserProfileW() failed\n");
2026 goto cleanup;
2027 }
2028 }
2029
2030 /* Acquire restore privilege */
2031 if (!AcquireRemoveRestorePrivilege(TRUE))
2032 {
2033 DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
2034 goto cleanup;
2035 }
2036
2037 /* Load user registry hive */
2038 Error = RegLoadKeyW(HKEY_USERS,
2039 SidString.Buffer,
2040 szUserHivePath);
2041 AcquireRemoveRestorePrivilege(FALSE);
2042
2043 /* HACK: Do not fail if the profile has already been loaded! */
2044 if (Error == ERROR_SHARING_VIOLATION)
2045 Error = ERROR_SUCCESS;
2046
2047 if (Error != ERROR_SUCCESS)
2048 {
2049 DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
2050 SetLastError((DWORD)Error);
2051 goto cleanup;
2052 }
2053
2054 SetProfileData(SidString.Buffer,
2055 lpProfileInfo->dwFlags,
2056 hToken);
2057 }
2058
2059 /* Open future HKEY_CURRENT_USER */
2060 Error = RegOpenKeyExW(HKEY_USERS,
2061 SidString.Buffer,
2062 0,
2063 MAXIMUM_ALLOWED,
2064 (PHKEY)&lpProfileInfo->hProfile);
2065 if (Error != ERROR_SUCCESS)
2066 {
2067 DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
2068 SetLastError((DWORD)Error);
2069 goto cleanup;
2070 }
2071
2072 Error = IncrementRefCount(SidString.Buffer, NULL);
2073 if (Error != ERROR_SUCCESS)
2074 {
2075 DPRINT1("IncrementRefCount() failed (Error %ld)\n", Error);
2076 SetLastError((DWORD)Error);
2077 goto cleanup;
2078 }
2079
2080 ret = TRUE;
2081
2082 cleanup:
2083 if (UserSid != NULL)
2084 HeapFree(GetProcessHeap(), 0, UserSid);
2085
2086 if (hProfileMutex != NULL)
2087 {
2088 ReleaseMutex(hProfileMutex);
2089 CloseHandle(hProfileMutex);
2090 }
2091
2092 RtlFreeUnicodeString(&SidString);
2093
2094 DPRINT("LoadUserProfileW() done\n");
2095 return ret;
2096 }
2097
2098
2099 BOOL
2100 WINAPI
2101 UnloadUserProfile(
2102 _In_ HANDLE hToken,
2103 _In_ HANDLE hProfile)
2104 {
2105 UNICODE_STRING SidString = {0, 0, NULL};
2106 HANDLE hProfileMutex = NULL;
2107 HKEY hProfilesKey = NULL, hProfileKey = NULL;
2108 DWORD dwRefCount = 0, dwLength, dwType, dwState = 0;
2109 DWORD dwError;
2110 BOOL bRet = FALSE;
2111
2112 DPRINT("UnloadUserProfile() called\n");
2113
2114 if (hProfile == NULL)
2115 {
2116 DPRINT1("Invalid profile handle\n");
2117 SetLastError(ERROR_INVALID_PARAMETER);
2118 return FALSE;
2119 }
2120
2121 /* Get the user SID string */
2122 if (!GetUserSidStringFromToken(hToken, &SidString))
2123 {
2124 DPRINT1("GetUserSidStringFromToken() failed\n");
2125 return FALSE;
2126 }
2127
2128 DPRINT("SidString: '%wZ'\n", &SidString);
2129
2130 /* Create the profile mutex */
2131 hProfileMutex = CreateProfileMutex(SidString.Buffer);
2132 if (hProfileMutex == NULL)
2133 {
2134 DPRINT1("Failed to create the profile mutex\n");
2135 goto cleanup;
2136 }
2137
2138 /* Wait for the profile mutex */
2139 WaitForSingleObject(hProfileMutex, INFINITE);
2140
2141 /* Close the profile handle */
2142 RegFlushKey(hProfile);
2143 RegCloseKey(hProfile);
2144
2145 dwError = DecrementRefCount(SidString.Buffer, &dwRefCount);
2146 if (dwError != ERROR_SUCCESS)
2147 {
2148 DPRINT1("DecrementRefCount() failed (Error %lu)\n", dwError);
2149 SetLastError(dwError);
2150 goto cleanup;
2151 }
2152
2153 if (dwRefCount == 0)
2154 {
2155 DPRINT("RefCount is 0: Unload the Hive!\n");
2156
2157 /* Acquire restore privilege */
2158 if (!AcquireRemoveRestorePrivilege(TRUE))
2159 {
2160 DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %lu)\n", GetLastError());
2161 goto cleanup;
2162 }
2163
2164 /* HACK */
2165 {
2166 HKEY hUserKey;
2167
2168 dwError = RegOpenKeyExW(HKEY_USERS,
2169 SidString.Buffer,
2170 0,
2171 KEY_WRITE,
2172 &hUserKey);
2173 if (dwError == ERROR_SUCCESS)
2174 {
2175 RegDeleteKeyW(hUserKey,
2176 L"Volatile Environment");
2177
2178 RegCloseKey(hUserKey);
2179 }
2180 }
2181 /* End of HACK */
2182
2183 /* Unload the hive */
2184 dwError = RegUnLoadKeyW(HKEY_USERS,
2185 SidString.Buffer);
2186
2187 /* Remove restore privilege */
2188 AcquireRemoveRestorePrivilege(FALSE);
2189
2190 if (dwError != ERROR_SUCCESS)
2191 {
2192 DPRINT1("RegUnLoadKeyW() failed (Error %lu)\n", dwError);
2193 SetLastError(dwError);
2194 goto cleanup;
2195 }
2196
2197 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2198 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
2199 0,
2200 KEY_QUERY_VALUE,
2201 &hProfilesKey);
2202 if (dwError != ERROR_SUCCESS)
2203 {
2204 DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
2205 SetLastError(dwError);
2206 goto cleanup;
2207 }
2208
2209 dwError = RegOpenKeyExW(hProfilesKey,
2210 SidString.Buffer,
2211 0,
2212 KEY_QUERY_VALUE,
2213 &hProfileKey);
2214 if (dwError != ERROR_SUCCESS)
2215 {
2216 DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
2217 SetLastError(dwError);
2218 goto cleanup;
2219 }
2220
2221 /* Get the State value */
2222 dwLength = sizeof(dwState);
2223 dwError = RegQueryValueExW(hProfileKey,
2224 L"State",
2225 NULL,
2226 &dwType,
2227 (PBYTE)&dwState,
2228 &dwLength);
2229 if (dwError != ERROR_SUCCESS)
2230 {
2231 DPRINT1("RegQueryValueExW() failed (Error %lu)\n", dwError);
2232 SetLastError(dwError);
2233 goto cleanup;
2234 }
2235
2236 /* Delete a guest profile */
2237 if (dwState & 0x80) // PROFILE_GUEST_USER
2238 {
2239 if (!DeleteProfileW(SidString.Buffer, NULL, NULL))
2240 {
2241 DPRINT1("DeleteProfile(%S, NULL, NULL) failed (Error %lu)\n",
2242 SidString.Buffer, GetLastError());
2243 goto cleanup;
2244 }
2245 }
2246 }
2247
2248 bRet = TRUE;
2249
2250 cleanup:
2251 if (hProfileKey != NULL)
2252 RegCloseKey(hProfileKey);
2253
2254 if (hProfilesKey != NULL)
2255 RegCloseKey(hProfilesKey);
2256
2257 if (hProfileMutex != NULL)
2258 {
2259 ReleaseMutex(hProfileMutex);
2260 CloseHandle(hProfileMutex);
2261 }
2262
2263 RtlFreeUnicodeString(&SidString);
2264
2265 DPRINT("UnloadUserProfile() done\n");
2266
2267 return bRet;
2268 }
2269
2270 /* EOF */