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