xref: /reactos/dll/win32/userenv/profile.c (revision 279107d5)
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 /* PUBLIC FUNCTIONS ********************************************************/
147 
148 BOOL
149 WINAPI
150 CopySystemProfile(
151     _In_ ULONG Unused)
152 {
153     WCHAR szKeyName[MAX_PATH];
154     WCHAR szRawProfilePath[MAX_PATH];
155     WCHAR szProfilePath[MAX_PATH];
156     WCHAR szDefaultProfilePath[MAX_PATH];
157     UNICODE_STRING SidString = {0, 0, NULL};
158     HANDLE hToken = NULL;
159     PSID pUserSid = NULL;
160     HKEY hProfileKey = NULL;
161     DWORD dwDisposition;
162     BOOL bResult = FALSE;
163     DWORD cchSize;
164     DWORD dwError;
165 
166     DPRINT1("CopySystemProfile()\n");
167 
168     if (!OpenProcessToken(GetCurrentProcess(),
169                           TOKEN_QUERY | TOKEN_IMPERSONATE,
170                           &hToken))
171     {
172         DPRINT1("Failed to open the process token (Error %lu)\n", GetLastError());
173         return FALSE;
174     }
175 
176     pUserSid = GetUserSid(hToken);
177     if (pUserSid == NULL)
178     {
179         DPRINT1("Failed to get the users SID (Error %lu)\n", GetLastError());
180         goto done;
181     }
182 
183     /* Get the user SID string */
184     if (!GetUserSidStringFromToken(hToken, &SidString))
185     {
186         DPRINT1("GetUserSidStringFromToken() failed\n");
187         goto done;
188     }
189 
190     StringCbCopyW(szKeyName, sizeof(szKeyName),
191                   L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
192     StringCbCatW(szKeyName, sizeof(szKeyName), SidString.Buffer);
193 
194     RtlFreeUnicodeString(&SidString);
195 
196     dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
197                               szKeyName,
198                               0, NULL, 0,
199                               KEY_WRITE,
200                               NULL,
201                               &hProfileKey,
202                               &dwDisposition);
203     if (dwError != ERROR_SUCCESS)
204     {
205         DPRINT1("Failed to create the profile key for the %s profile (Error %lu)\n",
206                 SidString.Buffer, dwError);
207         goto done;
208     }
209 
210     dwError = RegSetValueExW(hProfileKey,
211                              L"Sid",
212                              0,
213                              REG_BINARY,
214                              (PBYTE)pUserSid,
215                              RtlLengthSid(pUserSid));
216     if (dwError != ERROR_SUCCESS)
217     {
218         DPRINT1("Failed to set the SID value (Error %lu)\n", dwError);
219         goto done;
220     }
221 
222     wcscpy(szRawProfilePath,
223            L"%systemroot%\\system32\\config\\systemprofile");
224 
225     dwError = RegSetValueExW(hProfileKey,
226                              L"ProfileImagePath",
227                              0,
228                              REG_EXPAND_SZ,
229                              (PBYTE)szRawProfilePath,
230                              (wcslen(szRawProfilePath) + 1) * sizeof(WCHAR));
231     if (dwError != ERROR_SUCCESS)
232     {
233         DPRINT1("Failed to set the ProfileImagePath value (Error %lu)\n", dwError);
234         goto done;
235     }
236 
237     /* Expand the raw profile path */
238     if (!ExpandEnvironmentStringsW(szRawProfilePath,
239                                    szProfilePath,
240                                    ARRAYSIZE(szProfilePath)))
241     {
242         DPRINT1("Failled to expand the raw profile path (Error %lu)\n", GetLastError());
243         goto done;
244     }
245 
246     /* Create the profile directory if it does not exist yet */
247     // FIXME: Security!
248     if (!CreateDirectoryW(szProfilePath, NULL))
249     {
250         if (GetLastError() != ERROR_ALREADY_EXISTS)
251         {
252             DPRINT1("Failed to create the profile directory (Error %lu)\n", GetLastError());
253             goto done;
254         }
255     }
256 
257     /* Get the path of the default profile */
258     cchSize = ARRAYSIZE(szDefaultProfilePath);
259     if (!GetDefaultUserProfileDirectoryW(szDefaultProfilePath, &cchSize))
260     {
261         DPRINT1("Failed to create the default profile path (Error %lu)\n", GetLastError());
262         goto done;
263     }
264 
265     /* Copy the default profile into the new profile directory */
266     // FIXME: Security!
267     if (!CopyDirectory(szProfilePath, szDefaultProfilePath))
268     {
269         DPRINT1("Failed to copy the default profile directory (Error %lu)\n", GetLastError());
270         goto done;
271     }
272 
273     bResult = TRUE;
274 
275 done:
276     if (hProfileKey != NULL)
277         RegCloseKey(hProfileKey);
278 
279     RtlFreeUnicodeString(&SidString);
280 
281     if (pUserSid != NULL)
282         LocalFree(pUserSid);
283 
284     if (hToken != NULL)
285         CloseHandle(hToken);
286 
287     return bResult;
288 }
289 
290 
291 BOOL
292 WINAPI
293 CreateUserProfileA(
294     _In_ PSID pSid,
295     _In_ LPCSTR lpUserName)
296 {
297     LPWSTR pUserNameW = NULL;
298     INT nLength;
299     BOOL bResult;
300 
301     DPRINT("CreateUserProfileA(%p %s)\n", pSid, lpUserName);
302 
303     /* Convert lpUserName to Unicode */
304     nLength = MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, NULL, 0);
305     pUserNameW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
306     if (pUserNameW == NULL)
307     {
308         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
309         return FALSE;
310     }
311     MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, pUserNameW, nLength);
312 
313     /* Call the Ex function */
314     bResult = CreateUserProfileExW(pSid,
315                                    pUserNameW,
316                                    NULL,
317                                    NULL,
318                                    0,
319                                    FALSE);
320 
321     HeapFree(GetProcessHeap(), 0, pUserNameW);
322 
323     return bResult;
324 }
325 
326 
327 BOOL
328 WINAPI
329 CreateUserProfileW(
330     _In_ PSID pSid,
331     _In_ LPCWSTR lpUserName)
332 {
333     DPRINT("CreateUserProfileW(%p %S)\n", pSid, lpUserName);
334 
335     /* Call the Ex function */
336     return CreateUserProfileExW(pSid,
337                                 lpUserName,
338                                 NULL,
339                                 NULL,
340                                 0,
341                                 FALSE);
342 }
343 
344 
345 BOOL
346 WINAPI
347 CreateUserProfileExA(
348     _In_ PSID pSid,
349     _In_ LPCSTR lpUserName,
350     _In_opt_ LPCSTR lpUserHive,
351     _Out_opt_ LPSTR lpProfileDir,
352     _In_ DWORD dwDirSize,
353     _In_ BOOL bWin9xUpg)
354 {
355     LPWSTR pUserNameW = NULL;
356     LPWSTR pUserHiveW = NULL;
357     LPWSTR pProfileDirW = NULL;
358     INT nLength;
359     BOOL bResult = FALSE;
360 
361     DPRINT("CreateUserProfileExA(%p %s %s %p %lu %d)\n",
362            pSid, lpUserName, lpUserHive, lpProfileDir, dwDirSize, bWin9xUpg);
363 
364     /* Check the parameters */
365     if (lpProfileDir != NULL && dwDirSize == 0)
366     {
367         SetLastError(ERROR_INVALID_PARAMETER);
368         return FALSE;
369     }
370 
371     /* Convert lpUserName to Unicode */
372     nLength = MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, NULL, 0);
373     pUserNameW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
374     if (pUserNameW == NULL)
375     {
376         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
377         goto done;
378     }
379     MultiByteToWideChar(CP_ACP, 0, lpUserName, -1, pUserNameW, nLength);
380 
381     /* Convert lpUserHive to Unicode */
382     if (lpUserHive != NULL)
383     {
384         nLength = MultiByteToWideChar(CP_ACP, 0, lpUserHive, -1, NULL, 0);
385         pUserHiveW = HeapAlloc(GetProcessHeap(), 0, nLength * sizeof(WCHAR));
386         if (pUserHiveW == NULL)
387         {
388             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
389             goto done;
390         }
391         MultiByteToWideChar(CP_ACP, 0, lpUserHive, -1, pUserHiveW, nLength);
392     }
393 
394     /* Allocate a Unicode buffer for lpProfileDir */
395     if (lpProfileDir != NULL)
396     {
397         pProfileDirW = HeapAlloc(GetProcessHeap(), 0, dwDirSize * sizeof(WCHAR));
398         if (pProfileDirW == NULL)
399         {
400             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
401             goto done;
402         }
403     }
404 
405     /* Call the Unicode function */
406     bResult = CreateUserProfileExW(pSid,
407                                    (LPCWSTR)pUserNameW,
408                                    (LPCWSTR)pUserHiveW,
409                                    pProfileDirW,
410                                    dwDirSize,
411                                    bWin9xUpg);
412 
413     /* Convert the profile path to ANSI */
414     if (bResult && lpProfileDir != NULL)
415     {
416         WideCharToMultiByte(CP_ACP, 0, pProfileDirW, -1, lpProfileDir, dwDirSize, NULL, NULL);
417     }
418 
419 done:
420     /* Free the buffers */
421     if (pProfileDirW != NULL)
422         HeapFree(GetProcessHeap(), 0, pProfileDirW);
423 
424     if (pUserHiveW != NULL)
425         HeapFree(GetProcessHeap(), 0, pUserHiveW);
426 
427     if (pUserNameW != NULL)
428         HeapFree(GetProcessHeap(), 0, pUserNameW);
429 
430     return bResult;
431 }
432 
433 
434 BOOL
435 WINAPI
436 CreateUserProfileExW(
437     _In_ PSID pSid,
438     _In_ LPCWSTR lpUserName,
439     _In_opt_ LPCWSTR lpUserHive,
440     _Out_opt_ LPWSTR lpProfileDir,
441     _In_ DWORD dwDirSize,
442     _In_ BOOL bWin9xUpg)
443 {
444     WCHAR szRawProfilesPath[MAX_PATH];
445     WCHAR szProfilesPath[MAX_PATH];
446     WCHAR szUserProfilePath[MAX_PATH];
447     WCHAR szDefaultUserPath[MAX_PATH];
448     WCHAR szUserProfileName[MAX_PATH];
449     WCHAR szBuffer[MAX_PATH];
450     LPWSTR SidString;
451     DWORD dwType, dwLength;
452     DWORD dwDisposition;
453     UINT i;
454     HKEY hKey;
455     BOOL bRet = TRUE;
456     LONG Error;
457 
458     DPRINT("CreateUserProfileExW(%p %S %S %p %lu %d)\n",
459            pSid, lpUserName, lpUserHive, lpProfileDir, dwDirSize, bWin9xUpg);
460 
461     /* Parameters validation */
462     if (!pSid || !lpUserName)
463     {
464         SetLastError(ERROR_INVALID_PARAMETER);
465         return FALSE;
466     }
467 
468     /*
469      * TODO:
470      *  - Add support for lpUserHive.
471      *  - bWin9xUpg is obsolete. Don't waste your time implementing this.
472      */
473 
474     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
475                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
476                           0,
477                           KEY_QUERY_VALUE,
478                           &hKey);
479     if (Error != ERROR_SUCCESS)
480     {
481         DPRINT1("Error: %lu\n", Error);
482         SetLastError((DWORD)Error);
483         return FALSE;
484     }
485 
486     /* Get profiles path */
487     dwLength = sizeof(szRawProfilesPath);
488     Error = RegQueryValueExW(hKey,
489                              L"ProfilesDirectory",
490                              NULL,
491                              &dwType,
492                              (LPBYTE)szRawProfilesPath,
493                              &dwLength);
494     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
495     {
496         DPRINT1("Error: %lu\n", Error);
497         RegCloseKey(hKey);
498         SetLastError((DWORD)Error);
499         return FALSE;
500     }
501 
502     /* Expand it */
503     if (!ExpandEnvironmentStringsW(szRawProfilesPath,
504                                    szProfilesPath,
505                                    ARRAYSIZE(szProfilesPath)))
506     {
507         DPRINT1("Error: %lu\n", GetLastError());
508         RegCloseKey(hKey);
509         return FALSE;
510     }
511 
512     /* Create the profiles directory if it does not exist yet */
513     // FIXME: Security!
514     if (!CreateDirectoryW(szProfilesPath, NULL))
515     {
516         if (GetLastError() != ERROR_ALREADY_EXISTS)
517         {
518             DPRINT1("Error: %lu\n", GetLastError());
519             return FALSE;
520         }
521     }
522 
523     /* Get default user path */
524     dwLength = sizeof(szBuffer);
525     Error = RegQueryValueExW(hKey,
526                              L"DefaultUserProfile",
527                              NULL,
528                              &dwType,
529                              (LPBYTE)szBuffer,
530                              &dwLength);
531     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
532     {
533         DPRINT1("Error: %lu\n", Error);
534         RegCloseKey(hKey);
535         SetLastError((DWORD)Error);
536         return FALSE;
537     }
538 
539     RegCloseKey(hKey);
540 
541     StringCbCopyW(szUserProfileName, sizeof(szUserProfileName), lpUserName);
542 
543     /* Create user profile directory */
544 
545     StringCbCopyW(szUserProfilePath, sizeof(szUserProfilePath), szProfilesPath);
546     StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), L"\\");
547     StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), szUserProfileName);
548 
549     // FIXME: Security!
550     if (!CreateDirectoryW(szUserProfilePath, NULL))
551     {
552         if (GetLastError() != ERROR_ALREADY_EXISTS)
553         {
554             DPRINT1("Error: %lu\n", GetLastError());
555             return FALSE;
556         }
557 
558         for (i = 0; i < 1000; i++)
559         {
560             swprintf(szUserProfileName, L"%s.%03u", lpUserName, i);
561 
562             StringCbCopyW(szUserProfilePath, sizeof(szUserProfilePath), szProfilesPath);
563             StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), L"\\");
564             StringCbCatW(szUserProfilePath, sizeof(szUserProfilePath), szUserProfileName);
565 
566             // FIXME: Security!
567             if (CreateDirectoryW(szUserProfilePath, NULL))
568                 break;
569 
570             if (GetLastError() != ERROR_ALREADY_EXISTS)
571             {
572                 DPRINT1("Error: %lu\n", GetLastError());
573                 return FALSE;
574             }
575         }
576     }
577 
578     /* Copy default user directory */
579 
580     StringCbCopyW(szDefaultUserPath, sizeof(szDefaultUserPath), szProfilesPath);
581     StringCbCatW(szDefaultUserPath, sizeof(szDefaultUserPath), L"\\");
582     StringCbCatW(szDefaultUserPath, sizeof(szDefaultUserPath), szBuffer);
583 
584     // FIXME: Security!
585     if (!CopyDirectory(szUserProfilePath, szDefaultUserPath))
586     {
587         DPRINT1("Error: %lu\n", GetLastError());
588         return FALSE;
589     }
590 
591     /* Add profile to profile list */
592     if (!ConvertSidToStringSidW(pSid,
593                                 &SidString))
594     {
595         DPRINT1("Error: %lu\n", GetLastError());
596         return FALSE;
597     }
598 
599     StringCbCopyW(szBuffer, sizeof(szBuffer),
600                   L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
601     StringCbCatW(szBuffer, sizeof(szBuffer), SidString);
602 
603     /* Create user profile key */
604     Error = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
605                             szBuffer,
606                             0,
607                             NULL,
608                             REG_OPTION_NON_VOLATILE,
609                             KEY_ALL_ACCESS,
610                             NULL,
611                             &hKey,
612                             &dwDisposition);
613     if (Error != ERROR_SUCCESS)
614     {
615         DPRINT1("Error: %lu\n", Error);
616         bRet = FALSE;
617         goto done;
618     }
619 
620     /* Create non-expanded user profile path */
621     StringCbCopyW(szBuffer, sizeof(szBuffer), szRawProfilesPath);
622     StringCbCatW(szBuffer, sizeof(szBuffer), L"\\");
623     StringCbCatW(szBuffer, sizeof(szBuffer), szUserProfileName);
624 
625     /* Set 'ProfileImagePath' value (non-expanded) */
626     Error = RegSetValueExW(hKey,
627                            L"ProfileImagePath",
628                            0,
629                            REG_EXPAND_SZ,
630                            (LPBYTE)szBuffer,
631                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
632     if (Error != ERROR_SUCCESS)
633     {
634         DPRINT1("Error: %lu\n", Error);
635         RegCloseKey(hKey);
636         bRet = FALSE;
637         goto done;
638     }
639 
640     /* Set 'Sid' value */
641     Error = RegSetValueExW(hKey,
642                            L"Sid",
643                            0,
644                            REG_BINARY,
645                            pSid,
646                            GetLengthSid(pSid));
647     if (Error != ERROR_SUCCESS)
648     {
649         DPRINT1("Error: %lu\n", Error);
650         RegCloseKey(hKey);
651         bRet = FALSE;
652         goto done;
653     }
654 
655     RegCloseKey(hKey);
656 
657     /* Create user hive file */
658 
659     /* Use the default hive file name */
660     StringCbCopyW(szBuffer, sizeof(szBuffer), szUserProfilePath);
661     StringCbCatW(szBuffer, sizeof(szBuffer), L"\\ntuser.dat");
662 
663     /* Acquire restore privilege */
664     if (!AcquireRemoveRestorePrivilege(TRUE))
665     {
666         Error = GetLastError();
667         DPRINT1("Error: %lu\n", Error);
668         bRet = FALSE;
669         goto done;
670     }
671 
672     /* Load the user hive */
673     Error = RegLoadKeyW(HKEY_USERS,
674                         SidString,
675                         szBuffer);
676     AcquireRemoveRestorePrivilege(FALSE);
677     if (Error != ERROR_SUCCESS)
678     {
679         DPRINT1("Error: %lu\n", Error);
680         bRet = FALSE;
681         goto done;
682     }
683 
684     /* Initialize user hive */
685     if (!CreateUserHive(SidString, szUserProfilePath))
686     {
687         Error = GetLastError();
688         DPRINT1("Error: %lu\n", Error);
689         bRet = FALSE;
690     }
691 
692     /* Unload the hive */
693     AcquireRemoveRestorePrivilege(TRUE);
694     RegUnLoadKeyW(HKEY_USERS, SidString);
695     AcquireRemoveRestorePrivilege(FALSE);
696 
697     /*
698      * If the caller wants to retrieve the user profile path,
699      * give it now. 'dwDirSize' is the number of characters.
700      */
701     if (lpProfileDir && dwDirSize)
702         StringCchCopyW(lpProfileDir, dwDirSize, szUserProfilePath);
703 
704 done:
705     LocalFree((HLOCAL)SidString);
706     SetLastError((DWORD)Error);
707 
708     DPRINT("CreateUserProfileExW() done\n");
709 
710     return bRet;
711 }
712 
713 
714 BOOL
715 WINAPI
716 DeleteProfileA(
717     _In_ LPCSTR lpSidString,
718     _In_opt_ LPCSTR lpProfilePath,
719     _In_opt_ LPCSTR lpComputerName)
720 {
721     BOOL bResult;
722     UNICODE_STRING SidString, ProfilePath, ComputerName;
723 
724     DPRINT("DeleteProfileA() called\n");
725 
726     /* Conversion to UNICODE */
727     if (lpSidString)
728         RtlCreateUnicodeStringFromAsciiz(&SidString,
729                                          (LPSTR)lpSidString);
730 
731     if (lpProfilePath)
732         RtlCreateUnicodeStringFromAsciiz(&ProfilePath,
733                                          (LPSTR)lpProfilePath);
734 
735     if (lpComputerName)
736         RtlCreateUnicodeStringFromAsciiz(&ComputerName,
737                                          (LPSTR)lpComputerName);
738 
739     /* Call the UNICODE function */
740     bResult = DeleteProfileW(SidString.Buffer,
741                              ProfilePath.Buffer,
742                              ComputerName.Buffer);
743 
744     /* Memory cleanup */
745     if (lpSidString)
746         RtlFreeUnicodeString(&SidString);
747 
748     if (lpProfilePath)
749         RtlFreeUnicodeString(&ProfilePath);
750 
751     if (lpComputerName)
752         RtlFreeUnicodeString(&ComputerName);
753 
754     return bResult;
755 }
756 
757 
758 BOOL
759 WINAPI
760 DeleteProfileW(
761     _In_ LPCWSTR lpSidString,
762     _In_opt_ LPCWSTR lpProfilePath,
763     _In_opt_ LPCWSTR lpComputerName)
764 {
765     DPRINT1("DeleteProfileW() not implemented!\n");
766     return FALSE;
767 }
768 
769 
770 BOOL
771 WINAPI
772 GetAllUsersProfileDirectoryA(
773     _Out_opt_ LPSTR lpProfileDir,
774     _Inout_ LPDWORD lpcchSize)
775 {
776     LPWSTR lpBuffer;
777     BOOL bResult;
778 
779     if (!lpcchSize)
780     {
781         SetLastError(ERROR_INVALID_PARAMETER);
782         return FALSE;
783     }
784 
785     lpBuffer = GlobalAlloc(GMEM_FIXED,
786                            *lpcchSize * sizeof(WCHAR));
787     if (lpBuffer == NULL)
788         return FALSE;
789 
790     bResult = GetAllUsersProfileDirectoryW(lpBuffer,
791                                            lpcchSize);
792     if (bResult && lpProfileDir)
793     {
794         bResult = WideCharToMultiByte(CP_ACP,
795                                       0,
796                                       lpBuffer,
797                                       -1,
798                                       lpProfileDir,
799                                       *lpcchSize,
800                                       NULL,
801                                       NULL);
802     }
803 
804     GlobalFree(lpBuffer);
805 
806     return bResult;
807 }
808 
809 
810 BOOL
811 WINAPI
812 GetAllUsersProfileDirectoryW(
813     _Out_opt_ LPWSTR lpProfileDir,
814     _Inout_ LPDWORD lpcchSize)
815 {
816     WCHAR szProfilePath[MAX_PATH];
817     WCHAR szBuffer[MAX_PATH];
818     DWORD dwType, dwLength;
819     HKEY hKey;
820     LONG Error;
821 
822     if (!lpcchSize)
823     {
824         SetLastError(ERROR_INVALID_PARAMETER);
825         return FALSE;
826     }
827 
828     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
829                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
830                           0,
831                           KEY_QUERY_VALUE,
832                           &hKey);
833     if (Error != ERROR_SUCCESS)
834     {
835         DPRINT1("Error: %lu\n", Error);
836         SetLastError((DWORD)Error);
837         return FALSE;
838     }
839 
840     /* Get profiles path */
841     dwLength = sizeof(szBuffer);
842     Error = RegQueryValueExW(hKey,
843                              L"ProfilesDirectory",
844                              NULL,
845                              &dwType,
846                              (LPBYTE)szBuffer,
847                              &dwLength);
848     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
849     {
850         DPRINT1("Error: %lu\n", Error);
851         RegCloseKey(hKey);
852         SetLastError((DWORD)Error);
853         return FALSE;
854     }
855 
856     /* Expand it */
857     if (!ExpandEnvironmentStringsW(szBuffer,
858                                    szProfilePath,
859                                    ARRAYSIZE(szProfilePath)))
860     {
861         DPRINT1("Error: %lu\n", GetLastError());
862         RegCloseKey(hKey);
863         return FALSE;
864     }
865 
866     /* Get 'AllUsersProfile' name */
867     dwLength = sizeof(szBuffer);
868     Error = RegQueryValueExW(hKey,
869                              L"AllUsersProfile",
870                              NULL,
871                              &dwType,
872                              (LPBYTE)szBuffer,
873                              &dwLength);
874     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
875     {
876         DPRINT1("Error: %lu\n", Error);
877         RegCloseKey(hKey);
878         SetLastError((DWORD)Error);
879         return FALSE;
880     }
881 
882     RegCloseKey(hKey);
883 
884     StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
885     StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
886 
887     dwLength = wcslen(szProfilePath) + 1;
888     if (lpProfileDir && (*lpcchSize >= dwLength))
889     {
890         StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
891         *lpcchSize = dwLength;
892         return TRUE;
893     }
894     else // if (!lpProfileDir || (*lpcchSize < dwLength))
895     {
896         *lpcchSize = dwLength;
897         SetLastError(ERROR_INSUFFICIENT_BUFFER);
898         return FALSE;
899     }
900 }
901 
902 
903 BOOL
904 WINAPI
905 GetDefaultUserProfileDirectoryA(
906     _Out_opt_ LPSTR lpProfileDir,
907     _Inout_ LPDWORD lpcchSize)
908 {
909     LPWSTR lpBuffer;
910     BOOL bResult;
911 
912     if (!lpcchSize)
913     {
914         SetLastError(ERROR_INVALID_PARAMETER);
915         return FALSE;
916     }
917 
918     lpBuffer = GlobalAlloc(GMEM_FIXED,
919                            *lpcchSize * sizeof(WCHAR));
920     if (lpBuffer == NULL)
921         return FALSE;
922 
923     bResult = GetDefaultUserProfileDirectoryW(lpBuffer,
924                                               lpcchSize);
925     if (bResult && lpProfileDir)
926     {
927         bResult = WideCharToMultiByte(CP_ACP,
928                                       0,
929                                       lpBuffer,
930                                       -1,
931                                       lpProfileDir,
932                                       *lpcchSize,
933                                       NULL,
934                                       NULL);
935     }
936 
937     GlobalFree(lpBuffer);
938 
939     return bResult;
940 }
941 
942 
943 BOOL
944 WINAPI
945 GetDefaultUserProfileDirectoryW(
946     _Out_opt_ LPWSTR lpProfileDir,
947     _Inout_ LPDWORD lpcchSize)
948 {
949     WCHAR szProfilePath[MAX_PATH];
950     WCHAR szBuffer[MAX_PATH];
951     DWORD dwType, dwLength;
952     HKEY hKey;
953     LONG Error;
954 
955     if (!lpcchSize)
956     {
957         SetLastError(ERROR_INVALID_PARAMETER);
958         return FALSE;
959     }
960 
961     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
962                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
963                           0,
964                           KEY_QUERY_VALUE,
965                           &hKey);
966     if (Error != ERROR_SUCCESS)
967     {
968         DPRINT1("Error: %lu\n", Error);
969         SetLastError((DWORD)Error);
970         return FALSE;
971     }
972 
973     /* Get profiles path */
974     dwLength = sizeof(szBuffer);
975     Error = RegQueryValueExW(hKey,
976                              L"ProfilesDirectory",
977                              NULL,
978                              &dwType,
979                              (LPBYTE)szBuffer,
980                              &dwLength);
981     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
982     {
983         DPRINT1("Error: %lu\n", Error);
984         RegCloseKey(hKey);
985         SetLastError((DWORD)Error);
986         return FALSE;
987     }
988 
989     /* Expand it */
990     if (!ExpandEnvironmentStringsW(szBuffer,
991                                    szProfilePath,
992                                    ARRAYSIZE(szProfilePath)))
993     {
994         DPRINT1("Error: %lu\n", GetLastError());
995         RegCloseKey(hKey);
996         return FALSE;
997     }
998 
999     /* Get 'DefaultUserProfile' name */
1000     dwLength = sizeof(szBuffer);
1001     Error = RegQueryValueExW(hKey,
1002                              L"DefaultUserProfile",
1003                              NULL,
1004                              &dwType,
1005                              (LPBYTE)szBuffer,
1006                              &dwLength);
1007     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1008     {
1009         DPRINT1("Error: %lu\n", Error);
1010         RegCloseKey(hKey);
1011         SetLastError((DWORD)Error);
1012         return FALSE;
1013     }
1014 
1015     RegCloseKey(hKey);
1016 
1017     StringCbCatW(szProfilePath, sizeof(szProfilePath), L"\\");
1018     StringCbCatW(szProfilePath, sizeof(szProfilePath), szBuffer);
1019 
1020     dwLength = wcslen(szProfilePath) + 1;
1021     if (lpProfileDir && (*lpcchSize >= dwLength))
1022     {
1023         StringCchCopyW(lpProfileDir, *lpcchSize, szProfilePath);
1024         *lpcchSize = dwLength;
1025         return TRUE;
1026     }
1027     else // if (!lpProfileDir || (*lpcchSize < dwLength))
1028     {
1029         *lpcchSize = dwLength;
1030         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1031         return FALSE;
1032     }
1033 }
1034 
1035 
1036 BOOL
1037 WINAPI
1038 GetProfilesDirectoryA(
1039     _Out_ LPSTR lpProfileDir, // _Out_opt_
1040     _Inout_ LPDWORD lpcchSize)
1041 {
1042     LPWSTR lpBuffer;
1043     BOOL bResult;
1044 
1045     if (!lpcchSize)
1046     {
1047         SetLastError(ERROR_INVALID_PARAMETER);
1048         return FALSE;
1049     }
1050 
1051     lpBuffer = GlobalAlloc(GMEM_FIXED,
1052                            *lpcchSize * sizeof(WCHAR));
1053     if (lpBuffer == NULL)
1054         return FALSE;
1055 
1056     bResult = GetProfilesDirectoryW(lpBuffer,
1057                                     lpcchSize);
1058     if (bResult && lpProfileDir)
1059     {
1060         bResult = WideCharToMultiByte(CP_ACP,
1061                                       0,
1062                                       lpBuffer,
1063                                       -1,
1064                                       lpProfileDir,
1065                                       *lpcchSize,
1066                                       NULL,
1067                                       NULL);
1068     }
1069 
1070     GlobalFree(lpBuffer);
1071 
1072     return bResult;
1073 }
1074 
1075 
1076 BOOL
1077 WINAPI
1078 GetProfilesDirectoryW(
1079     _Out_ LPWSTR lpProfilesDir, // _Out_opt_
1080     _Inout_ LPDWORD lpcchSize)
1081 {
1082     WCHAR szProfilesPath[MAX_PATH];
1083     WCHAR szBuffer[MAX_PATH];
1084     DWORD dwType, dwLength;
1085     HKEY hKey;
1086     LONG Error;
1087 
1088     if (!lpcchSize)
1089     {
1090         SetLastError(ERROR_INVALID_PARAMETER);
1091         return FALSE;
1092     }
1093 
1094     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1095                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
1096                           0,
1097                           KEY_QUERY_VALUE,
1098                           &hKey);
1099     if (Error != ERROR_SUCCESS)
1100     {
1101         DPRINT1("Error: %lu\n", Error);
1102         SetLastError((DWORD)Error);
1103         return FALSE;
1104     }
1105 
1106     /* Get profiles path */
1107     dwLength = sizeof(szBuffer);
1108     Error = RegQueryValueExW(hKey,
1109                              L"ProfilesDirectory",
1110                              NULL,
1111                              &dwType,
1112                              (LPBYTE)szBuffer,
1113                              &dwLength);
1114     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1115     {
1116         DPRINT1("Error: %lu\n", Error);
1117         RegCloseKey(hKey);
1118         SetLastError((DWORD)Error);
1119         return FALSE;
1120     }
1121 
1122     RegCloseKey(hKey);
1123 
1124     /* Expand it */
1125     if (!ExpandEnvironmentStringsW(szBuffer,
1126                                    szProfilesPath,
1127                                    ARRAYSIZE(szProfilesPath)))
1128     {
1129         DPRINT1("Error: %lu\n", GetLastError());
1130         return FALSE;
1131     }
1132 
1133     dwLength = wcslen(szProfilesPath) + 1;
1134     if (lpProfilesDir && (*lpcchSize >= dwLength))
1135     {
1136         StringCchCopyW(lpProfilesDir, *lpcchSize, szProfilesPath);
1137         *lpcchSize = dwLength;
1138         return TRUE;
1139     }
1140     else // if (!lpProfilesDir || (*lpcchSize < dwLength))
1141     {
1142         *lpcchSize = dwLength;
1143         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1144         return FALSE;
1145     }
1146 }
1147 
1148 
1149 BOOL
1150 WINAPI
1151 GetProfileType(
1152     _Out_ PDWORD pdwFlags)
1153 {
1154     DPRINT1("GetProfileType() not implemented!\n");
1155     return FALSE;
1156 }
1157 
1158 
1159 BOOL
1160 WINAPI
1161 GetUserProfileDirectoryA(
1162     _In_ HANDLE hToken,
1163     _Out_opt_ LPSTR lpProfileDir,
1164     _Inout_ LPDWORD lpcchSize)
1165 {
1166     LPWSTR lpBuffer;
1167     BOOL bResult;
1168 
1169     if (!lpcchSize)
1170     {
1171         SetLastError(ERROR_INVALID_PARAMETER);
1172         return FALSE;
1173     }
1174 
1175     lpBuffer = GlobalAlloc(GMEM_FIXED,
1176                            *lpcchSize * sizeof(WCHAR));
1177     if (lpBuffer == NULL)
1178         return FALSE;
1179 
1180     bResult = GetUserProfileDirectoryW(hToken,
1181                                        lpBuffer,
1182                                        lpcchSize);
1183     if (bResult && lpProfileDir)
1184     {
1185         bResult = WideCharToMultiByte(CP_ACP,
1186                                       0,
1187                                       lpBuffer,
1188                                       -1,
1189                                       lpProfileDir,
1190                                       *lpcchSize,
1191                                       NULL,
1192                                       NULL);
1193     }
1194 
1195     GlobalFree(lpBuffer);
1196 
1197     return bResult;
1198 }
1199 
1200 
1201 BOOL
1202 WINAPI
1203 GetUserProfileDirectoryW(
1204     _In_ HANDLE hToken,
1205     _Out_opt_ LPWSTR lpProfileDir,
1206     _Inout_ LPDWORD lpcchSize)
1207 {
1208     UNICODE_STRING SidString;
1209     WCHAR szKeyName[MAX_PATH];
1210     WCHAR szRawImagePath[MAX_PATH];
1211     WCHAR szImagePath[MAX_PATH];
1212     DWORD dwType, dwLength;
1213     HKEY hKey;
1214     LONG Error;
1215 
1216     if (!hToken)
1217     {
1218         SetLastError(ERROR_INVALID_HANDLE);
1219         return FALSE;
1220     }
1221 
1222     if (!lpcchSize)
1223     {
1224         SetLastError(ERROR_INVALID_PARAMETER);
1225         return FALSE;
1226     }
1227 
1228     /* Get the user SID string */
1229     if (!GetUserSidStringFromToken(hToken, &SidString))
1230     {
1231         DPRINT1("GetUserSidStringFromToken() failed\n");
1232         return FALSE;
1233     }
1234 
1235     DPRINT("SidString: '%wZ'\n", &SidString);
1236 
1237     StringCbCopyW(szKeyName, sizeof(szKeyName),
1238                   L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
1239     StringCbCatW(szKeyName, sizeof(szKeyName), SidString.Buffer);
1240 
1241     RtlFreeUnicodeString(&SidString);
1242 
1243     DPRINT("KeyName: '%S'\n", szKeyName);
1244 
1245     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1246                           szKeyName,
1247                           0,
1248                           KEY_QUERY_VALUE,
1249                           &hKey);
1250     if (Error != ERROR_SUCCESS)
1251     {
1252         DPRINT1("Error: %lu\n", Error);
1253         SetLastError((DWORD)Error);
1254         return FALSE;
1255     }
1256 
1257     dwLength = sizeof(szRawImagePath);
1258     Error = RegQueryValueExW(hKey,
1259                              L"ProfileImagePath",
1260                              NULL,
1261                              &dwType,
1262                              (LPBYTE)szRawImagePath,
1263                              &dwLength);
1264     if ((Error != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
1265     {
1266         DPRINT1("Error: %lu\n", Error);
1267         RegCloseKey(hKey);
1268         SetLastError((DWORD)Error);
1269         return FALSE;
1270     }
1271 
1272     RegCloseKey(hKey);
1273 
1274     DPRINT("RawImagePath: '%S'\n", szRawImagePath);
1275 
1276     /* Expand it */
1277     if (!ExpandEnvironmentStringsW(szRawImagePath,
1278                                    szImagePath,
1279                                    ARRAYSIZE(szImagePath)))
1280     {
1281         DPRINT1("Error: %lu\n", GetLastError());
1282         return FALSE;
1283     }
1284 
1285     DPRINT("ImagePath: '%S'\n", szImagePath);
1286 
1287     dwLength = wcslen(szImagePath) + 1;
1288     if (lpProfileDir && (*lpcchSize >= dwLength))
1289     {
1290         StringCchCopyW(lpProfileDir, *lpcchSize, szImagePath);
1291         *lpcchSize = dwLength;
1292         return TRUE;
1293     }
1294     else // if (!lpProfileDir || (*lpcchSize < dwLength))
1295     {
1296         *lpcchSize = dwLength;
1297         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1298         return FALSE;
1299     }
1300 }
1301 
1302 
1303 BOOL
1304 WINAPI
1305 LoadUserProfileA(
1306     _In_ HANDLE hToken,
1307     _Inout_ LPPROFILEINFOA lpProfileInfo)
1308 {
1309     BOOL bResult = FALSE;
1310     PROFILEINFOW ProfileInfoW = {0};
1311     int len;
1312 
1313     DPRINT("LoadUserProfileA() called\n");
1314 
1315     /* Check profile info */
1316     if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOA)) ||
1317         (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
1318     {
1319         SetLastError(ERROR_INVALID_PARAMETER);
1320         return FALSE;
1321     }
1322 
1323     /* Convert the structure to UNICODE... */
1324     ProfileInfoW.dwSize = sizeof(ProfileInfoW);
1325     ProfileInfoW.dwFlags = lpProfileInfo->dwFlags;
1326 
1327     if (lpProfileInfo->lpUserName)
1328     {
1329         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, NULL, 0);
1330         ProfileInfoW.lpUserName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1331         if (!ProfileInfoW.lpUserName)
1332         {
1333             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1334             goto cleanup;
1335         }
1336         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpUserName, -1, ProfileInfoW.lpUserName, len);
1337     }
1338 
1339     if (lpProfileInfo->lpProfilePath)
1340     {
1341         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, NULL, 0);
1342         ProfileInfoW.lpProfilePath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1343         if (!ProfileInfoW.lpProfilePath)
1344         {
1345             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1346             goto cleanup;
1347         }
1348         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpProfilePath, -1, ProfileInfoW.lpProfilePath, len);
1349     }
1350 
1351     if (lpProfileInfo->lpDefaultPath)
1352     {
1353         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, NULL, 0);
1354         ProfileInfoW.lpDefaultPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1355         if (!ProfileInfoW.lpDefaultPath)
1356         {
1357             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1358             goto cleanup;
1359         }
1360         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpDefaultPath, -1, ProfileInfoW.lpDefaultPath, len);
1361     }
1362 
1363     if (lpProfileInfo->lpServerName)
1364     {
1365         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, NULL, 0);
1366         ProfileInfoW.lpServerName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1367         if (!ProfileInfoW.lpServerName)
1368         {
1369             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1370             goto cleanup;
1371         }
1372         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpServerName, -1, ProfileInfoW.lpServerName, len);
1373     }
1374 
1375     if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && lpProfileInfo->lpPolicyPath)
1376     {
1377         len = MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, NULL, 0);
1378         ProfileInfoW.lpPolicyPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1379         if (!ProfileInfoW.lpPolicyPath)
1380         {
1381             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1382             goto cleanup;
1383         }
1384         MultiByteToWideChar(CP_ACP, 0, lpProfileInfo->lpPolicyPath, -1, ProfileInfoW.lpPolicyPath, len);
1385     }
1386 
1387     /* ... and call the UNICODE function */
1388     bResult = LoadUserProfileW(hToken, &ProfileInfoW);
1389 
1390     /* Save the returned value */
1391     lpProfileInfo->hProfile = ProfileInfoW.hProfile;
1392 
1393 cleanup:
1394     /* Memory cleanup */
1395     if (ProfileInfoW.lpUserName)
1396         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpUserName);
1397 
1398     if (ProfileInfoW.lpProfilePath)
1399         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpProfilePath);
1400 
1401     if (ProfileInfoW.lpDefaultPath)
1402         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpDefaultPath);
1403 
1404     if (ProfileInfoW.lpServerName)
1405         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpServerName);
1406 
1407     if ((ProfileInfoW.dwFlags & PI_APPLYPOLICY) != 0 && ProfileInfoW.lpPolicyPath)
1408         HeapFree(GetProcessHeap(), 0, ProfileInfoW.lpPolicyPath);
1409 
1410     return bResult;
1411 }
1412 
1413 
1414 BOOL
1415 WINAPI
1416 LoadUserProfileW(
1417     _In_ HANDLE hToken,
1418     _Inout_ LPPROFILEINFOW lpProfileInfo)
1419 {
1420     WCHAR szUserHivePath[MAX_PATH];
1421     PTOKEN_USER UserSid = NULL;
1422     UNICODE_STRING SidString = { 0, 0, NULL };
1423     LONG Error;
1424     BOOL ret = FALSE;
1425     DWORD dwLength = sizeof(szUserHivePath) / sizeof(szUserHivePath[0]);
1426 
1427     DPRINT("LoadUserProfileW(%p %p)\n", hToken, lpProfileInfo);
1428 
1429     /* Check profile info */
1430     if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOW)) ||
1431         (lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
1432     {
1433         SetLastError(ERROR_INVALID_PARAMETER);
1434         return FALSE;
1435     }
1436 
1437     DPRINT("UserName: %S\n", lpProfileInfo->lpUserName);
1438 
1439     /* Don't load a profile twice */
1440     if (CheckForLoadedProfile(hToken))
1441     {
1442         DPRINT ("Profile already loaded\n");
1443         lpProfileInfo->hProfile = NULL;
1444         return TRUE;
1445     }
1446 
1447     if (lpProfileInfo->lpProfilePath)
1448     {
1449         /* Use the caller's specified roaming user profile path */
1450         StringCbCopyW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpProfilePath);
1451     }
1452     else
1453     {
1454         /* FIXME: check if MS Windows allows lpProfileInfo->lpProfilePath to be NULL */
1455         if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
1456         {
1457             DPRINT1("GetProfilesDirectoryW() failed (error %ld)\n", GetLastError());
1458             return FALSE;
1459         }
1460     }
1461 
1462     /* Create user hive name */
1463     StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\");
1464     StringCbCatW(szUserHivePath, sizeof(szUserHivePath), lpProfileInfo->lpUserName);
1465     StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\ntuser.dat");
1466     DPRINT("szUserHivePath: %S\n", szUserHivePath);
1467 
1468     /* Create user profile directory if needed */
1469     if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
1470     {
1471         /* Get user sid */
1472         if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) ||
1473             GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1474         {
1475             DPRINT1 ("GetTokenInformation() failed\n");
1476             return FALSE;
1477         }
1478 
1479         UserSid = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, dwLength);
1480         if (!UserSid)
1481         {
1482             DPRINT1("HeapAlloc() failed\n");
1483             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1484             goto cleanup;
1485         }
1486 
1487         if (!GetTokenInformation(hToken, TokenUser, UserSid, dwLength, &dwLength))
1488         {
1489             DPRINT1("GetTokenInformation() failed\n");
1490             goto cleanup;
1491         }
1492 
1493         /* Create profile */
1494         ret = CreateUserProfileW(UserSid->User.Sid, lpProfileInfo->lpUserName);
1495         if (!ret)
1496         {
1497             DPRINT1("CreateUserProfileW() failed\n");
1498             goto cleanup;
1499         }
1500     }
1501 
1502     /* Get the user SID string */
1503     ret = GetUserSidStringFromToken(hToken, &SidString);
1504     if (!ret)
1505     {
1506         DPRINT1("GetUserSidStringFromToken() failed\n");
1507         goto cleanup;
1508     }
1509     ret = FALSE;
1510 
1511     /* Acquire restore privilege */
1512     if (!AcquireRemoveRestorePrivilege(TRUE))
1513     {
1514         DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
1515         goto cleanup;
1516     }
1517 
1518     /* Load user registry hive */
1519     Error = RegLoadKeyW(HKEY_USERS,
1520                         SidString.Buffer,
1521                         szUserHivePath);
1522     AcquireRemoveRestorePrivilege(FALSE);
1523 
1524     /* HACK: Do not fail if the profile has already been loaded! */
1525     if (Error == ERROR_SHARING_VIOLATION)
1526         Error = ERROR_SUCCESS;
1527 
1528     if (Error != ERROR_SUCCESS)
1529     {
1530         DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
1531         SetLastError((DWORD)Error);
1532         goto cleanup;
1533     }
1534 
1535     /* Open future HKEY_CURRENT_USER */
1536     Error = RegOpenKeyExW(HKEY_USERS,
1537                           SidString.Buffer,
1538                           0,
1539                           MAXIMUM_ALLOWED,
1540                           (PHKEY)&lpProfileInfo->hProfile);
1541     if (Error != ERROR_SUCCESS)
1542     {
1543         DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
1544         SetLastError((DWORD)Error);
1545         goto cleanup;
1546     }
1547 
1548     ret = TRUE;
1549 
1550 cleanup:
1551     HeapFree(GetProcessHeap(), 0, UserSid);
1552     RtlFreeUnicodeString(&SidString);
1553 
1554     DPRINT("LoadUserProfileW() done\n");
1555     return ret;
1556 }
1557 
1558 
1559 BOOL
1560 WINAPI
1561 UnloadUserProfile(
1562     _In_ HANDLE hToken,
1563     _In_ HANDLE hProfile)
1564 {
1565     UNICODE_STRING SidString;
1566     LONG Error;
1567 
1568     DPRINT("UnloadUserProfile() called\n");
1569 
1570     if (hProfile == NULL)
1571     {
1572         DPRINT1("Invalid profile handle\n");
1573         SetLastError(ERROR_INVALID_PARAMETER);
1574         return FALSE;
1575     }
1576 
1577     RegCloseKey(hProfile);
1578 
1579     /* Get the user SID string */
1580     if (!GetUserSidStringFromToken(hToken, &SidString))
1581     {
1582         DPRINT1("GetUserSidStringFromToken() failed\n");
1583         return FALSE;
1584     }
1585 
1586     DPRINT("SidString: '%wZ'\n", &SidString);
1587 
1588     /* Acquire restore privilege */
1589     if (!AcquireRemoveRestorePrivilege(TRUE))
1590     {
1591         DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
1592         RtlFreeUnicodeString(&SidString);
1593         return FALSE;
1594     }
1595 
1596     /* HACK */
1597     {
1598         HKEY hUserKey;
1599 
1600         Error = RegOpenKeyExW(HKEY_USERS,
1601                               SidString.Buffer,
1602                               0,
1603                               KEY_WRITE,
1604                               &hUserKey);
1605         if (Error == ERROR_SUCCESS)
1606         {
1607             RegDeleteKeyW(hUserKey,
1608                           L"Volatile Environment");
1609 
1610             RegCloseKey(hUserKey);
1611         }
1612     }
1613     /* End of HACK */
1614 
1615     /* Unload the hive */
1616     Error = RegUnLoadKeyW(HKEY_USERS,
1617                           SidString.Buffer);
1618 
1619     /* Remove restore privilege */
1620     AcquireRemoveRestorePrivilege(FALSE);
1621 
1622     if (Error != ERROR_SUCCESS)
1623     {
1624         DPRINT1("RegUnLoadKeyW() failed (Error %ld)\n", Error);
1625         RtlFreeUnicodeString(&SidString);
1626         SetLastError((DWORD)Error);
1627         return FALSE;
1628     }
1629 
1630     RtlFreeUnicodeString(&SidString);
1631 
1632     DPRINT("UnloadUserProfile() done\n");
1633 
1634     return TRUE;
1635 }
1636 
1637 /* EOF */
1638