xref: /reactos/dll/win32/userenv/profile.c (revision a1fc312a)
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     HKEY hProfilesKey = NULL, hProfileKey = NULL;
1181     WCHAR szRawProfilePath[MAX_PATH], szProfilePath[MAX_PATH];
1182     DWORD dwLength, dwType;
1183     DWORD dwError = ERROR_SUCCESS;
1184     BOOL bRet = FALSE;
1185 
1186     DPRINT("DeleteProfileW(%S %S %S)\n", lpSidString, lpProfilePath, lpComputerName);
1187 
1188     if (lpSidString == NULL)
1189     {
1190         SetLastError(ERROR_INVALID_PARAMETER);
1191         return FALSE;
1192     }
1193 
1194     if (lpProfilePath != NULL)
1195     {
1196         dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1197                                 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1198                                 0,
1199                                 KEY_QUERY_VALUE,
1200                                 &hProfilesKey);
1201         if (dwError != ERROR_SUCCESS)
1202         {
1203             DPRINT1("Error: %lu\n", dwError);
1204             goto done;
1205         }
1206 
1207         dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1208                                 lpSidString,
1209                                 0,
1210                                 KEY_QUERY_VALUE,
1211                                 &hProfileKey);
1212         if (dwError != ERROR_SUCCESS)
1213         {
1214             DPRINT1("Error: %lu\n", dwError);
1215             goto done;
1216         }
1217 
1218         /* Get the profile image path */
1219         dwLength = sizeof(szRawProfilePath);
1220         dwError = RegQueryValueExW(hProfileKey,
1221                                    L"ProfileImagePath",
1222                                    NULL,
1223                                    &dwType,
1224                                    (PBYTE)szRawProfilePath,
1225                                    &dwLength);
1226         if (dwError != ERROR_SUCCESS)
1227         {
1228              DPRINT1("Error: %lu\n", dwError);
1229              goto done;
1230         }
1231 
1232         if (!ExpandEnvironmentStringsW(szRawProfilePath,
1233                                        szProfilePath,
1234                                        ARRAYSIZE(szProfilePath)))
1235         {
1236             dwError = GetLastError();
1237             DPRINT1("Failled to expand the raw profile path (Error %lu)\n", dwError);
1238             goto done;
1239         }
1240     }
1241     else
1242     {
1243         StringCchCopyW(szProfilePath, ARRAYSIZE(szProfilePath), lpProfilePath);
1244     }
1245 
1246     DPRINT("ProfilePath: %S\n", szProfilePath);
1247 
1248     if (!RemoveDirectoryPath(szProfilePath))
1249     {
1250         dwError = GetLastError();
1251         DPRINT1("Error: %lu\n", dwError);
1252         goto done;
1253     }
1254 
1255     bRet = TRUE;
1256 
1257 done:
1258     if (hProfileKey != NULL)
1259         RegCloseKey(hProfileKey);
1260 
1261     if (hProfilesKey != NULL)
1262         RegCloseKey(hProfilesKey);
1263 
1264     return bRet;
1265 }
1266 
1267 
1268 BOOL
1269 WINAPI
1270 GetAllUsersProfileDirectoryA(
1271     _Out_opt_ LPSTR lpProfileDir,
1272     _Inout_ LPDWORD lpcchSize)
1273 {
1274     LPWSTR lpBuffer;
1275     BOOL bResult;
1276 
1277     if (!lpcchSize)
1278     {
1279         SetLastError(ERROR_INVALID_PARAMETER);
1280         return FALSE;
1281     }
1282 
1283     lpBuffer = GlobalAlloc(GMEM_FIXED,
1284                            *lpcchSize * sizeof(WCHAR));
1285     if (lpBuffer == NULL)
1286         return FALSE;
1287 
1288     bResult = GetAllUsersProfileDirectoryW(lpBuffer,
1289                                            lpcchSize);
1290     if (bResult && lpProfileDir)
1291     {
1292         bResult = WideCharToMultiByte(CP_ACP,
1293                                       0,
1294                                       lpBuffer,
1295                                       -1,
1296                                       lpProfileDir,
1297                                       *lpcchSize,
1298                                       NULL,
1299                                       NULL);
1300     }
1301 
1302     GlobalFree(lpBuffer);
1303 
1304     return bResult;
1305 }
1306 
1307 
1308 BOOL
1309 WINAPI
1310 GetAllUsersProfileDirectoryW(
1311     _Out_opt_ LPWSTR lpProfileDir,
1312     _Inout_ LPDWORD lpcchSize)
1313 {
1314     WCHAR szProfilePath[MAX_PATH];
1315     WCHAR szBuffer[MAX_PATH];
1316     DWORD dwType, dwLength;
1317     HKEY hKey;
1318     LONG Error;
1319 
1320     if (!lpcchSize)
1321     {
1322         SetLastError(ERROR_INVALID_PARAMETER);
1323         return FALSE;
1324     }
1325 
1326     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1327                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1328                           0,
1329                           KEY_QUERY_VALUE,
1330                           &hKey);
1331     if (Error != ERROR_SUCCESS)
1332     {
1333         DPRINT1("Error: %lu\n", Error);
1334         SetLastError((DWORD)Error);
1335         return FALSE;
1336     }
1337 
1338     /* Get profiles path */
1339     dwLength = sizeof(szBuffer);
1340     Error = RegQueryValueExW(hKey,
1341                              L"ProfilesDirectory",
1342                              NULL,
1343                              &dwType,
1344                              (LPBYTE)szBuffer,
1345                              &dwLength);
1346     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1347     {
1348         DPRINT1("Error: %lu\n", Error);
1349         RegCloseKey(hKey);
1350         SetLastError((DWORD)Error);
1351         return FALSE;
1352     }
1353 
1354     /* Expand it */
1355     if (!ExpandEnvironmentStringsW(szBuffer,
1356                                    szProfilePath,
1357                                    ARRAYSIZE(szProfilePath)))
1358     {
1359         DPRINT1("Error: %lu\n", GetLastError());
1360         RegCloseKey(hKey);
1361         return FALSE;
1362     }
1363 
1364     /* Get 'AllUsersProfile' name */
1365     dwLength = sizeof(szBuffer);
1366     Error = RegQueryValueExW(hKey,
1367                              L"AllUsersProfile",
1368                              NULL,
1369                              &dwType,
1370                              (LPBYTE)szBuffer,
1371                              &dwLength);
1372     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1373     {
1374         DPRINT1("Error: %lu\n", Error);
1375         RegCloseKey(hKey);
1376         SetLastError((DWORD)Error);
1377         return FALSE;
1378     }
1379 
1380     RegCloseKey(hKey);
1381 
1382     StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
1383     StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
1384 
1385     dwLength = wcslen(szProfilePath) + 1;
1386     if (lpProfileDir && (*lpcchSize >= dwLength))
1387     {
1388         StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
1389         *lpcchSize = dwLength;
1390         return TRUE;
1391     }
1392     else // if (!lpProfileDir || (*lpcchSize < dwLength))
1393     {
1394         *lpcchSize = dwLength;
1395         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1396         return FALSE;
1397     }
1398 }
1399 
1400 
1401 BOOL
1402 WINAPI
1403 GetDefaultUserProfileDirectoryA(
1404     _Out_opt_ LPSTR lpProfileDir,
1405     _Inout_ LPDWORD lpcchSize)
1406 {
1407     LPWSTR lpBuffer;
1408     BOOL bResult;
1409 
1410     if (!lpcchSize)
1411     {
1412         SetLastError(ERROR_INVALID_PARAMETER);
1413         return FALSE;
1414     }
1415 
1416     lpBuffer = GlobalAlloc(GMEM_FIXED,
1417                            *lpcchSize * sizeof(WCHAR));
1418     if (lpBuffer == NULL)
1419         return FALSE;
1420 
1421     bResult = GetDefaultUserProfileDirectoryW(lpBuffer,
1422                                               lpcchSize);
1423     if (bResult && lpProfileDir)
1424     {
1425         bResult = WideCharToMultiByte(CP_ACP,
1426                                       0,
1427                                       lpBuffer,
1428                                       -1,
1429                                       lpProfileDir,
1430                                       *lpcchSize,
1431                                       NULL,
1432                                       NULL);
1433     }
1434 
1435     GlobalFree(lpBuffer);
1436 
1437     return bResult;
1438 }
1439 
1440 
1441 BOOL
1442 WINAPI
1443 GetDefaultUserProfileDirectoryW(
1444     _Out_opt_ LPWSTR lpProfileDir,
1445     _Inout_ LPDWORD lpcchSize)
1446 {
1447     WCHAR szProfilePath[MAX_PATH];
1448     WCHAR szBuffer[MAX_PATH];
1449     DWORD dwType, dwLength;
1450     HKEY hKey;
1451     LONG Error;
1452 
1453     if (!lpcchSize)
1454     {
1455         SetLastError(ERROR_INVALID_PARAMETER);
1456         return FALSE;
1457     }
1458 
1459     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1460                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1461                           0,
1462                           KEY_QUERY_VALUE,
1463                           &hKey);
1464     if (Error != ERROR_SUCCESS)
1465     {
1466         DPRINT1("Error: %lu\n", Error);
1467         SetLastError((DWORD)Error);
1468         return FALSE;
1469     }
1470 
1471     /* Get profiles path */
1472     dwLength = sizeof(szBuffer);
1473     Error = RegQueryValueExW(hKey,
1474                              L"ProfilesDirectory",
1475                              NULL,
1476                              &dwType,
1477                              (LPBYTE)szBuffer,
1478                              &dwLength);
1479     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1480     {
1481         DPRINT1("Error: %lu\n", Error);
1482         RegCloseKey(hKey);
1483         SetLastError((DWORD)Error);
1484         return FALSE;
1485     }
1486 
1487     /* Expand it */
1488     if (!ExpandEnvironmentStringsW(szBuffer,
1489                                    szProfilePath,
1490                                    ARRAYSIZE(szProfilePath)))
1491     {
1492         DPRINT1("Error: %lu\n", GetLastError());
1493         RegCloseKey(hKey);
1494         return FALSE;
1495     }
1496 
1497     /* Get 'DefaultUserProfile' name */
1498     dwLength = sizeof(szBuffer);
1499     Error = RegQueryValueExW(hKey,
1500                              L"DefaultUserProfile",
1501                              NULL,
1502                              &dwType,
1503                              (LPBYTE)szBuffer,
1504                              &dwLength);
1505     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1506     {
1507         DPRINT1("Error: %lu\n", Error);
1508         RegCloseKey(hKey);
1509         SetLastError((DWORD)Error);
1510         return FALSE;
1511     }
1512 
1513     RegCloseKey(hKey);
1514 
1515     StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
1516     StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
1517 
1518     dwLength = wcslen(szProfilePath) + 1;
1519     if (lpProfileDir && (*lpcchSize >= dwLength))
1520     {
1521         StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
1522         *lpcchSize = dwLength;
1523         return TRUE;
1524     }
1525     else // if (!lpProfileDir || (*lpcchSize < dwLength))
1526     {
1527         *lpcchSize = dwLength;
1528         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1529         return FALSE;
1530     }
1531 }
1532 
1533 
1534 BOOL
1535 WINAPI
1536 GetProfilesDirectoryA(
1537     _Out_ LPSTR lpProfileDir, // _Out_opt_
1538     _Inout_ LPDWORD lpcchSize)
1539 {
1540     LPWSTR lpBuffer;
1541     BOOL bResult;
1542 
1543     if (!lpcchSize || !lpProfileDir)
1544     {
1545         SetLastError(ERROR_INVALID_PARAMETER);
1546         return FALSE;
1547     }
1548 
1549     lpBuffer = GlobalAlloc(GMEM_FIXED,
1550                            *lpcchSize * sizeof(WCHAR));
1551     if (lpBuffer == NULL)
1552         return FALSE;
1553 
1554     bResult = GetProfilesDirectoryW(lpBuffer,
1555                                     lpcchSize);
1556     if (bResult && lpProfileDir)
1557     {
1558         bResult = WideCharToMultiByte(CP_ACP,
1559                                       0,
1560                                       lpBuffer,
1561                                       -1,
1562                                       lpProfileDir,
1563                                       *lpcchSize,
1564                                       NULL,
1565                                       NULL);
1566     }
1567 
1568     GlobalFree(lpBuffer);
1569 
1570     return bResult;
1571 }
1572 
1573 
1574 BOOL
1575 WINAPI
1576 GetProfilesDirectoryW(
1577     _Out_ LPWSTR lpProfilesDir, // _Out_opt_
1578     _Inout_ LPDWORD lpcchSize)
1579 {
1580     WCHAR szProfilesPath[MAX_PATH];
1581     WCHAR szBuffer[MAX_PATH];
1582     DWORD dwType, dwLength;
1583     HKEY hKey;
1584     LONG Error;
1585 
1586     if (!lpcchSize)
1587     {
1588         SetLastError(ERROR_INVALID_PARAMETER);
1589         return FALSE;
1590     }
1591 
1592     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1593                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1594                           0,
1595                           KEY_QUERY_VALUE,
1596                           &hKey);
1597     if (Error != ERROR_SUCCESS)
1598     {
1599         DPRINT1("Error: %lu\n", Error);
1600         SetLastError((DWORD)Error);
1601         return FALSE;
1602     }
1603 
1604     /* Get profiles path */
1605     dwLength = sizeof(szBuffer);
1606     Error = RegQueryValueExW(hKey,
1607                              L"ProfilesDirectory",
1608                              NULL,
1609                              &dwType,
1610                              (LPBYTE)szBuffer,
1611                              &dwLength);
1612     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1613     {
1614         DPRINT1("Error: %lu\n", Error);
1615         RegCloseKey(hKey);
1616         SetLastError((DWORD)Error);
1617         return FALSE;
1618     }
1619 
1620     RegCloseKey(hKey);
1621 
1622     /* Expand it */
1623     if (!ExpandEnvironmentStringsW(szBuffer,
1624                                    szProfilesPath,
1625                                    ARRAYSIZE(szProfilesPath)))
1626     {
1627         DPRINT1("Error: %lu\n", GetLastError());
1628         return FALSE;
1629     }
1630 
1631     dwLength = wcslen(szProfilesPath) + 1;
1632     if (lpProfilesDir && (*lpcchSize >= dwLength))
1633     {
1634         StringCchCopyW(lpProfilesDir, *lpcchSize, szProfilesPath);
1635         *lpcchSize = dwLength;
1636         return TRUE;
1637     }
1638     else // if (!lpProfilesDir || (*lpcchSize < dwLength))
1639     {
1640         *lpcchSize = dwLength;
1641         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1642         return FALSE;
1643     }
1644 }
1645 
1646 
1647 BOOL
1648 WINAPI
1649 GetProfileType(
1650     _Out_ PDWORD pdwFlags)
1651 {
1652     UNICODE_STRING SidString = {0, 0, NULL};
1653     HANDLE hToken;
1654     HKEY hProfilesKey = NULL, hProfileKey = NULL;
1655     DWORD dwType, dwLength, dwState = 0;
1656     DWORD dwError;
1657     BOOL bResult = FALSE;
1658 
1659     DPRINT("GetProfileType(%p)\n", pdwFlags);
1660 
1661     if (pdwFlags == NULL)
1662     {
1663         SetLastError(ERROR_INVALID_PARAMETER);
1664         return FALSE;
1665     }
1666 
1667     if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
1668     {
1669         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
1670         {
1671             DPRINT1("Failed to open a token (Error %lu)\n", GetLastError());
1672             return FALSE;
1673         }
1674     }
1675 
1676     /* Get the user SID string */
1677     if (!GetUserSidStringFromToken(hToken, &SidString))
1678     {
1679         DPRINT1("GetUserSidStringFromToken() failed\n");
1680         goto done;
1681     }
1682 
1683     DPRINT("SID: %wZ\n", &SidString);
1684 
1685     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1686                             L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1687                             0,
1688                             KEY_QUERY_VALUE,
1689                             &hProfilesKey);
1690     if (dwError != ERROR_SUCCESS)
1691     {
1692         DPRINT1("Error: %lu\n", dwError);
1693         SetLastError(dwError);
1694         goto done;
1695     }
1696 
1697     dwError = RegOpenKeyExW(hProfilesKey,
1698                             SidString.Buffer,
1699                             0,
1700                             KEY_QUERY_VALUE | KEY_SET_VALUE,
1701                             &hProfileKey);
1702     if (dwError != ERROR_SUCCESS)
1703     {
1704         DPRINT1("Error: %lu\n", dwError);
1705         SetLastError(dwError);
1706         goto done;
1707     }
1708 
1709     /* Get the State value */
1710     dwLength = sizeof(dwState);
1711     dwError = RegQueryValueExW(hProfileKey,
1712                                L"State",
1713                                NULL,
1714                                &dwType,
1715                                (PBYTE)&dwState,
1716                                &dwLength);
1717     if (dwError != ERROR_SUCCESS)
1718     {
1719         DPRINT1("Error: %lu\n", dwError);
1720         SetLastError(dwError);
1721         goto done;
1722     }
1723 
1724     *pdwFlags = 0;
1725 
1726     if (dwState & 0x80) /* PROFILE_GUEST_USER */
1727         *pdwFlags |= PT_TEMPORARY;
1728 
1729     /* FIXME: Add checks for PT_MANDATORY and PT_ROAMING */
1730 
1731     bResult = TRUE;
1732 
1733 done:
1734     if (hProfileKey != NULL)
1735         RegCloseKey(hProfileKey);
1736 
1737     if (hProfilesKey != NULL)
1738         RegCloseKey(hProfilesKey);
1739 
1740     RtlFreeUnicodeString(&SidString);
1741 
1742     CloseHandle(hToken);
1743 
1744     return bResult;
1745 }
1746 
1747 
1748 BOOL
1749 WINAPI
1750 GetUserProfileDirectoryA(
1751     _In_ HANDLE hToken,
1752     _Out_opt_ LPSTR lpProfileDir,
1753     _Inout_ LPDWORD lpcchSize)
1754 {
1755     LPWSTR lpBuffer;
1756     BOOL bResult;
1757 
1758     if (!lpcchSize || !lpProfileDir)
1759     {
1760         SetLastError(ERROR_INVALID_PARAMETER);
1761         return FALSE;
1762     }
1763 
1764     lpBuffer = GlobalAlloc(GMEM_FIXED,
1765                            *lpcchSize * sizeof(WCHAR));
1766     if (lpBuffer == NULL)
1767         return FALSE;
1768 
1769     bResult = GetUserProfileDirectoryW(hToken,
1770                                        lpBuffer,
1771                                        lpcchSize);
1772     if (bResult && lpProfileDir)
1773     {
1774         bResult = WideCharToMultiByte(CP_ACP,
1775                                       0,
1776                                       lpBuffer,
1777                                       -1,
1778                                       lpProfileDir,
1779                                       *lpcchSize,
1780                                       NULL,
1781                                       NULL);
1782     }
1783 
1784     GlobalFree(lpBuffer);
1785 
1786     return bResult;
1787 }
1788 
1789 
1790 BOOL
1791 WINAPI
1792 GetUserProfileDirectoryW(
1793     _In_ HANDLE hToken,
1794     _Out_opt_ LPWSTR lpProfileDir,
1795     _Inout_ LPDWORD lpcchSize)
1796 {
1797     UNICODE_STRING SidString;
1798     WCHAR szKeyName[MAX_PATH];
1799     WCHAR szRawImagePath[MAX_PATH];
1800     WCHAR szImagePath[MAX_PATH];
1801     DWORD dwType, dwLength;
1802     HKEY hKey;
1803     LONG Error;
1804 
1805     if (!hToken)
1806     {
1807         SetLastError(ERROR_INVALID_HANDLE);
1808         return FALSE;
1809     }
1810 
1811     if (!lpcchSize)
1812     {
1813         SetLastError(ERROR_INVALID_PARAMETER);
1814         return FALSE;
1815     }
1816 
1817     /* Get the user SID string */
1818     if (!GetUserSidStringFromToken(hToken, &SidString))
1819     {
1820         DPRINT1("GetUserSidStringFromToken() failed\n");
1821         return FALSE;
1822     }
1823 
1824     DPRINT("SidString: '%wZ'\n", &SidString);
1825 
1826     StringCbCopyW(szKeyName, sizeof(szKeyName),
1827                   L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
1828     StringCbCatW(szKeyName, sizeof(szKeyName), SidString.Buffer);
1829 
1830     RtlFreeUnicodeString(&SidString);
1831 
1832     DPRINT("KeyName: '%S'\n", szKeyName);
1833 
1834     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1835                           szKeyName,
1836                           0,
1837                           KEY_QUERY_VALUE,
1838                           &hKey);
1839     if (Error != ERROR_SUCCESS)
1840     {
1841         DPRINT1("Error: %lu\n", Error);
1842         SetLastError((DWORD)Error);
1843         return FALSE;
1844     }
1845 
1846     dwLength = sizeof(szRawImagePath);
1847     Error = RegQueryValueExW(hKey,
1848                              L"ProfileImagePath",
1849                              NULL,
1850                              &dwType,
1851                              (LPBYTE)szRawImagePath,
1852                              &dwLength);
1853     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1854     {
1855         DPRINT1("Error: %lu\n", Error);
1856         RegCloseKey(hKey);
1857         SetLastError((DWORD)Error);
1858         return FALSE;
1859     }
1860 
1861     RegCloseKey(hKey);
1862 
1863     DPRINT("RawImagePath: '%S'\n", szRawImagePath);
1864 
1865     /* Expand it */
1866     if (!ExpandEnvironmentStringsW(szRawImagePath,
1867                                    szImagePath,
1868                                    ARRAYSIZE(szImagePath)))
1869     {
1870         DPRINT1("Error: %lu\n", GetLastError());
1871         return FALSE;
1872     }
1873 
1874     DPRINT("ImagePath: '%S'\n", szImagePath);
1875 
1876     dwLength = wcslen(szImagePath) + 1;
1877     if (lpProfileDir && (*lpcchSize >= dwLength))
1878     {
1879         StringCchCopyW(lpProfileDir, *lpcchSize, szImagePath);
1880         *lpcchSize = dwLength;
1881         return TRUE;
1882     }
1883     else // if (!lpProfileDir || (*lpcchSize < dwLength))
1884     {
1885         *lpcchSize = dwLength;
1886         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1887         return FALSE;
1888     }
1889 }
1890 
1891 
1892 BOOL
1893 WINAPI
1894 LoadUserProfileA(
1895     _In_ HANDLE hToken,
1896     _Inout_ LPPROFILEINFOA lpProfileInfo)
1897 {
1898     BOOL bResult = FALSE;
1899     PROFILEINFOW ProfileInfoW = {0};
1900     int len;
1901 
1902     DPRINT("LoadUserProfileA() called\n");
1903 
1904     /* Check profile info */
1905     if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOA)) ||
1906         (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
1907     {
1908         SetLastError(ERROR_INVALID_PARAMETER);
1909         return FALSE;
1910     }
1911 
1912     /* Convert the structure to UNICODE... */
1913     ProfileInfoW.dwSize = sizeof(ProfileInfoW);
1914     ProfileInfoW.dwFlags = lpProfileInfo->dwFlags;
1915 
1916     if (lpProfileInfo->lpUserName)
1917     {
1918         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, NULL, 0);
1919         ProfileInfoW.lpUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1920         if (!ProfileInfoW.lpUserName)
1921         {
1922             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1923             goto cleanup;
1924         }
1925         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, ProfileInfoW.lpUserName, len);
1926     }
1927 
1928     if (lpProfileInfo->lpProfilePath)
1929     {
1930         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, NULL, 0);
1931         ProfileInfoW.lpProfilePath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1932         if (!ProfileInfoW.lpProfilePath)
1933         {
1934             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1935             goto cleanup;
1936         }
1937         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, ProfileInfoW.lpProfilePath, len);
1938     }
1939 
1940     if (lpProfileInfo->lpDefaultPath)
1941     {
1942         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, NULL, 0);
1943         ProfileInfoW.lpDefaultPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1944         if (!ProfileInfoW.lpDefaultPath)
1945         {
1946             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1947             goto cleanup;
1948         }
1949         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, ProfileInfoW.lpDefaultPath, len);
1950     }
1951 
1952     if (lpProfileInfo->lpServerName)
1953     {
1954         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, NULL, 0);
1955         ProfileInfoW.lpServerName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1956         if (!ProfileInfoW.lpServerName)
1957         {
1958             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1959             goto cleanup;
1960         }
1961         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, ProfileInfoW.lpServerName, len);
1962     }
1963 
1964     if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && lpProfileInfo->lpPolicyPath)
1965     {
1966         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, NULL, 0);
1967         ProfileInfoW.lpPolicyPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1968         if (!ProfileInfoW.lpPolicyPath)
1969         {
1970             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1971             goto cleanup;
1972         }
1973         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, ProfileInfoW.lpPolicyPath, len);
1974     }
1975 
1976     /* ... and call the UNICODE function */
1977     bResult = LoadUserProfileW(hToken, &ProfileInfoW);
1978 
1979     /* Save the returned value */
1980     lpProfileInfo->hProfile = ProfileInfoW.hProfile;
1981 
1982 cleanup:
1983     /* Memory cleanup */
1984     if (ProfileInfoW.lpUserName)
1985         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpUserName);
1986 
1987     if (ProfileInfoW.lpProfilePath)
1988         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpProfilePath);
1989 
1990     if (ProfileInfoW.lpDefaultPath)
1991         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpDefaultPath);
1992 
1993     if (ProfileInfoW.lpServerName)
1994         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpServerName);
1995 
1996     if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && ProfileInfoW.lpPolicyPath)
1997         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpPolicyPath);
1998 
1999     return bResult;
2000 }
2001 
2002 
2003 BOOL
2004 WINAPI
2005 LoadUserProfileW(
2006     _In_ HANDLE hToken,
2007     _Inout_ LPPROFILEINFOW lpProfileInfo)
2008 {
2009     WCHAR szUserHivePath[MAX_PATH];
2010     PTOKEN_USER UserSid = NULL;
2011     UNICODE_STRING SidString = { 0, 0, NULL };
2012     HANDLE hProfileMutex = NULL;
2013     LONG Error;
2014     BOOL ret = FALSE;
2015     DWORD dwLength = sizeof(szUserHivePath) / sizeof(szUserHivePath[0]);
2016 
2017     DPRINT("LoadUserProfileW(%p %p)\n", hToken, lpProfileInfo);
2018 
2019     /* Check profile info */
2020     if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOW)) ||
2021         (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
2022     {
2023         SetLastError(ERROR_INVALID_PARAMETER);
2024         return FALSE;
2025     }
2026 
2027     DPRINT("UserName: %S\n", lpProfileInfo->lpUserName);
2028 
2029     /* Get the user SID string */
2030     ret = GetUserSidStringFromToken(hToken, &SidString);
2031     if (!ret)
2032     {
2033         DPRINT1("GetUserSidStringFromToken() failed\n");
2034         goto cleanup;
2035     }
2036     ret = FALSE;
2037 
2038     /* Create the profile mutex */
2039     hProfileMutex = CreateProfileMutex(SidString.Buffer);
2040     if (hProfileMutex == NULL)
2041     {
2042         DPRINT1("Failed to create the profile mutex\n");
2043         goto cleanup;
2044     }
2045 
2046     /* Wait for the profile mutex */
2047     WaitForSingleObject(hProfileMutex, INFINITE);
2048 
2049     /* Don't load a profile twice */
2050     if (CheckForLoadedProfile(hToken))
2051     {
2052         DPRINT1("Profile %S already loaded\n", SidString.Buffer);
2053     }
2054     else
2055     {
2056         DPRINT1("Loading profile %S\n", SidString.Buffer);
2057 
2058         if (lpProfileInfo->lpProfilePath)
2059         {
2060             /* Use the caller's specified roaming user profile path */
2061             StringCbCopyW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpProfilePath);
2062         }
2063         else
2064         {
2065             /* FIXME: check if MS Windows allows lpProfileInfo->lpProfilePath to be NULL */
2066             if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
2067             {
2068                 DPRINT1("GetProfilesDirectoryW() failed (error %ld)\n", GetLastError());
2069                 goto cleanup;
2070             }
2071         }
2072 
2073         /* Create user hive name */
2074         StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\");
2075         StringCbCatW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpUserName);
2076         StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\ntuser.dat");
2077         DPRINT("szUserHivePath: %S\n", szUserHivePath);
2078 
2079         /* Create user profile directory if needed */
2080         if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
2081         {
2082             /* Get user sid */
2083             if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) ||
2084                 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2085             {
2086                 DPRINT1 ("GetTokenInformation() failed\n");
2087                 goto cleanup;
2088             }
2089 
2090             UserSid = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, dwLength);
2091             if (!UserSid)
2092             {
2093                 DPRINT1("HeapAlloc() failed\n");
2094                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2095                 goto cleanup;
2096             }
2097 
2098             if (!GetTokenInformation(hToken, TokenUser, UserSid, dwLength, &dwLength))
2099             {
2100                 DPRINT1("GetTokenInformation() failed\n");
2101                 goto cleanup;
2102             }
2103 
2104             /* Create profile */
2105             ret = CreateUserProfileW(UserSid->User.Sid, lpProfileInfo->lpUserName);
2106             if (!ret)
2107             {
2108                 DPRINT1("CreateUserProfileW() failed\n");
2109                 goto cleanup;
2110             }
2111         }
2112 
2113         /* Acquire restore privilege */
2114         if (!AcquireRemoveRestorePrivilege(TRUE))
2115         {
2116             DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
2117             goto cleanup;
2118         }
2119 
2120         /* Load user registry hive */
2121         Error = RegLoadKeyW(HKEY_USERS,
2122                             SidString.Buffer,
2123                             szUserHivePath);
2124         AcquireRemoveRestorePrivilege(FALSE);
2125 
2126         /* HACK: Do not fail if the profile has already been loaded! */
2127         if (Error == ERROR_SHARING_VIOLATION)
2128             Error = ERROR_SUCCESS;
2129 
2130         if (Error != ERROR_SUCCESS)
2131         {
2132             DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
2133             SetLastError((DWORD)Error);
2134             goto cleanup;
2135         }
2136 
2137         SetProfileData(SidString.Buffer,
2138                        lpProfileInfo->dwFlags,
2139                        hToken);
2140     }
2141 
2142     /* Open future HKEY_CURRENT_USER */
2143     Error = RegOpenKeyExW(HKEY_USERS,
2144                           SidString.Buffer,
2145                           0,
2146                           MAXIMUM_ALLOWED,
2147                           (PHKEY)&lpProfileInfo->hProfile);
2148     if (Error != ERROR_SUCCESS)
2149     {
2150         DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
2151         SetLastError((DWORD)Error);
2152         goto cleanup;
2153     }
2154 
2155     Error = IncrementRefCount(SidString.Buffer, NULL);
2156     if (Error != ERROR_SUCCESS)
2157     {
2158         DPRINT1("IncrementRefCount() failed (Error %ld)\n", Error);
2159         SetLastError((DWORD)Error);
2160         goto cleanup;
2161     }
2162 
2163     ret = TRUE;
2164 
2165 cleanup:
2166     if (UserSid != NULL)
2167         HeapFree(GetProcessHeap(), 0, UserSid);
2168 
2169     if (hProfileMutex != NULL)
2170     {
2171         ReleaseMutex(hProfileMutex);
2172         CloseHandle(hProfileMutex);
2173     }
2174 
2175     RtlFreeUnicodeString(&SidString);
2176 
2177     DPRINT("LoadUserProfileW() done\n");
2178     return ret;
2179 }
2180 
2181 
2182 BOOL
2183 WINAPI
2184 UnloadUserProfile(
2185     _In_ HANDLE hToken,
2186     _In_ HANDLE hProfile)
2187 {
2188     UNICODE_STRING SidString = {0, 0, NULL};
2189     HANDLE hProfileMutex = NULL;
2190     HKEY hProfilesKey = NULL, hProfileKey = NULL;
2191     DWORD dwRefCount = 0, dwLength, dwType, dwState = 0;
2192     DWORD dwError;
2193     BOOL bRet = FALSE;
2194 
2195     DPRINT("UnloadUserProfile() called\n");
2196 
2197     if (hProfile == NULL)
2198     {
2199         DPRINT1("Invalid profile handle\n");
2200         SetLastError(ERROR_INVALID_PARAMETER);
2201         return FALSE;
2202     }
2203 
2204     /* Get the user SID string */
2205     if (!GetUserSidStringFromToken(hToken, &SidString))
2206     {
2207         DPRINT1("GetUserSidStringFromToken() failed\n");
2208         return FALSE;
2209     }
2210 
2211     DPRINT("SidString: '%wZ'\n", &SidString);
2212 
2213     /* Create the profile mutex */
2214     hProfileMutex = CreateProfileMutex(SidString.Buffer);
2215     if (hProfileMutex == NULL)
2216     {
2217         DPRINT1("Failed to create the profile mutex\n");
2218         goto cleanup;
2219     }
2220 
2221     /* Wait for the profile mutex */
2222     WaitForSingleObject(hProfileMutex, INFINITE);
2223 
2224     /* Close the profile handle */
2225     RegFlushKey(hProfile);
2226     RegCloseKey(hProfile);
2227 
2228     dwError = DecrementRefCount(SidString.Buffer, &dwRefCount);
2229     if (dwError != ERROR_SUCCESS)
2230     {
2231         DPRINT1("DecrementRefCount() failed (Error %lu)\n", dwError);
2232         SetLastError(dwError);
2233         goto cleanup;
2234     }
2235 
2236     if (dwRefCount == 0)
2237     {
2238         DPRINT("RefCount is 0: Unload the Hive!\n");
2239 
2240         /* Acquire restore privilege */
2241         if (!AcquireRemoveRestorePrivilege(TRUE))
2242         {
2243             DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %lu)\n", GetLastError());
2244             goto cleanup;
2245         }
2246 
2247         /* HACK */
2248         {
2249             HKEY hUserKey;
2250 
2251             dwError = RegOpenKeyExW(HKEY_USERS,
2252                                     SidString.Buffer,
2253                                     0,
2254                                     KEY_WRITE,
2255                                     &hUserKey);
2256             if (dwError == ERROR_SUCCESS)
2257             {
2258                 RegDeleteKeyW(hUserKey,
2259                               L"Volatile Environment");
2260 
2261                 RegCloseKey(hUserKey);
2262             }
2263         }
2264         /* End of HACK */
2265 
2266         /* Unload the hive */
2267         dwError = RegUnLoadKeyW(HKEY_USERS,
2268                                 SidString.Buffer);
2269 
2270         /* Remove restore privilege */
2271         AcquireRemoveRestorePrivilege(FALSE);
2272 
2273         if (dwError != ERROR_SUCCESS)
2274         {
2275             DPRINT1("RegUnLoadKeyW() failed (Error %lu)\n", dwError);
2276             SetLastError(dwError);
2277             goto cleanup;
2278         }
2279 
2280         dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2281                                 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
2282                                 0,
2283                                 KEY_QUERY_VALUE,
2284                                 &hProfilesKey);
2285         if (dwError != ERROR_SUCCESS)
2286         {
2287             DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
2288             SetLastError(dwError);
2289             goto cleanup;
2290         }
2291 
2292         dwError = RegOpenKeyExW(hProfilesKey,
2293                                 SidString.Buffer,
2294                                 0,
2295                                 KEY_QUERY_VALUE,
2296                                 &hProfileKey);
2297         if (dwError != ERROR_SUCCESS)
2298         {
2299             DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
2300             SetLastError(dwError);
2301             goto cleanup;
2302         }
2303 
2304         /* Get the State value */
2305         dwLength = sizeof(dwState);
2306         dwError = RegQueryValueExW(hProfileKey,
2307                                    L"State",
2308                                    NULL,
2309                                    &dwType,
2310                                    (PBYTE)&dwState,
2311                                    &dwLength);
2312         if (dwError != ERROR_SUCCESS)
2313         {
2314             DPRINT1("RegQueryValueExW() failed (Error %lu)\n", dwError);
2315             SetLastError(dwError);
2316             goto cleanup;
2317         }
2318 
2319         /* Delete a guest profile */
2320         if (dwState & 0x80) // PROFILE_GUEST_USER
2321         {
2322             if (!DeleteProfileW(SidString.Buffer, NULL, NULL))
2323             {
2324                 DPRINT1("DeleteProfile(%S, NULL, NULL) failed (Error %lu)\n",
2325                         SidString.Buffer, GetLastError());
2326                 goto cleanup;
2327             }
2328         }
2329     }
2330 
2331     bRet = TRUE;
2332 
2333 cleanup:
2334     if (hProfileKey != NULL)
2335         RegCloseKey(hProfileKey);
2336 
2337     if (hProfilesKey != NULL)
2338         RegCloseKey(hProfilesKey);
2339 
2340     if (hProfileMutex != NULL)
2341     {
2342         ReleaseMutex(hProfileMutex);
2343         CloseHandle(hProfileMutex);
2344     }
2345 
2346     RtlFreeUnicodeString(&SidString);
2347 
2348     DPRINT("UnloadUserProfile() done\n");
2349 
2350     return bRet;
2351 }
2352 
2353 /* EOF */
2354