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