xref: /reactos/dll/win32/userenv/profile.c (revision 1ac9e484)
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 = 0;
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 */
2271