mirror of
https://github.com/reactos/reactos.git
synced 2024-08-18 17:37:02 +00:00
1186 lines
30 KiB
C
1186 lines
30 KiB
C
/*
|
|
* ReactOS kernel
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: lib/userenv/profile.c
|
|
* PURPOSE: User profile code
|
|
* PROGRAMMERS: Eric Kohl
|
|
* Hervé Poussineau
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
BOOL
|
|
AppendSystemPostfix(LPWSTR lpName,
|
|
DWORD dwMaxLength)
|
|
{
|
|
WCHAR szSystemRoot[MAX_PATH];
|
|
LPWSTR lpszPostfix;
|
|
LPWSTR lpszPtr;
|
|
|
|
/* Build profile name postfix */
|
|
if (!ExpandEnvironmentStringsW(L"%SystemRoot%",
|
|
szSystemRoot,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
_wcsupr(szSystemRoot);
|
|
|
|
/* Get name postfix */
|
|
szSystemRoot[2] = L'.';
|
|
lpszPostfix = &szSystemRoot[2];
|
|
lpszPtr = lpszPostfix;
|
|
while (*lpszPtr != (WCHAR)0)
|
|
{
|
|
if (*lpszPtr == L'\\')
|
|
*lpszPtr = '_';
|
|
lpszPtr++;
|
|
}
|
|
|
|
if (wcslen(lpName) + wcslen(lpszPostfix) + 1 >= dwMaxLength)
|
|
{
|
|
DPRINT1("Error: buffer overflow\n");
|
|
SetLastError(ERROR_BUFFER_OVERFLOW);
|
|
return FALSE;
|
|
}
|
|
|
|
wcscat(lpName, lpszPostfix);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CreateUserProfileA(PSID Sid,
|
|
LPCSTR lpUserName)
|
|
{
|
|
UNICODE_STRING UserName;
|
|
BOOL bResult;
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlCreateUnicodeStringFromAsciiz(&UserName,
|
|
(LPSTR)lpUserName);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return FALSE;
|
|
}
|
|
|
|
bResult = CreateUserProfileW(Sid, UserName.Buffer);
|
|
|
|
RtlFreeUnicodeString(&UserName);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
AcquireRemoveRestorePrivilege(IN BOOL bAcquire)
|
|
{
|
|
HANDLE Process;
|
|
HANDLE Token;
|
|
PTOKEN_PRIVILEGES TokenPriv;
|
|
BOOL bRet;
|
|
|
|
DPRINT("AcquireRemoveRestorePrivilege(%d)\n", bAcquire);
|
|
|
|
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
|
|
if (!Process)
|
|
{
|
|
DPRINT1("OpenProcess() failed with error %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
bRet = OpenProcessToken(Process, TOKEN_ADJUST_PRIVILEGES, &Token);
|
|
CloseHandle(Process);
|
|
if (!bRet)
|
|
{
|
|
DPRINT1("OpenProcessToken() failed with error %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
TokenPriv = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES));
|
|
if (!TokenPriv)
|
|
{
|
|
DPRINT1("Failed to allocate mem for token privileges\n");
|
|
CloseHandle(Token);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
TokenPriv->PrivilegeCount = 1;
|
|
TokenPriv->Privileges[0].Attributes = bAcquire ? SE_PRIVILEGE_ENABLED : 0;
|
|
if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &TokenPriv->Privileges[0].Luid))
|
|
{
|
|
DPRINT1("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
|
|
HeapFree(GetProcessHeap(), 0, TokenPriv);
|
|
CloseHandle(Token);
|
|
return FALSE;
|
|
}
|
|
bRet = AdjustTokenPrivileges(
|
|
Token,
|
|
FALSE,
|
|
TokenPriv,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
HeapFree(GetProcessHeap(), 0, TokenPriv);
|
|
CloseHandle(Token);
|
|
|
|
if (!bRet)
|
|
{
|
|
DPRINT1("AdjustTokenPrivileges() failed with error %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CreateUserProfileW(PSID Sid,
|
|
LPCWSTR lpUserName)
|
|
{
|
|
WCHAR szRawProfilesPath[MAX_PATH];
|
|
WCHAR szProfilesPath[MAX_PATH];
|
|
WCHAR szUserProfilePath[MAX_PATH];
|
|
WCHAR szDefaultUserPath[MAX_PATH];
|
|
WCHAR szUserProfileName[MAX_PATH];
|
|
WCHAR szBuffer[MAX_PATH];
|
|
LPWSTR SidString;
|
|
DWORD dwLength;
|
|
DWORD dwDisposition;
|
|
UINT i;
|
|
HKEY hKey;
|
|
LONG Error;
|
|
|
|
DPRINT("CreateUserProfileW() called\n");
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get profiles path */
|
|
dwLength = MAX_PATH * sizeof(WCHAR);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"ProfilesDirectory",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szRawProfilesPath,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Expand it */
|
|
if (!ExpandEnvironmentStringsW(szRawProfilesPath,
|
|
szProfilesPath,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
/* create the profiles directory if it does not yet exist */
|
|
if (!CreateDirectoryW(szProfilesPath, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Get default user path */
|
|
dwLength = MAX_PATH * sizeof(WCHAR);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"DefaultUserProfile",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
wcscpy(szUserProfileName, lpUserName);
|
|
|
|
wcscpy(szUserProfilePath, szProfilesPath);
|
|
wcscat(szUserProfilePath, L"\\");
|
|
wcscat(szUserProfilePath, szUserProfileName);
|
|
|
|
wcscpy(szDefaultUserPath, szProfilesPath);
|
|
wcscat(szDefaultUserPath, L"\\");
|
|
wcscat(szDefaultUserPath, szBuffer);
|
|
|
|
/* Create user profile directory */
|
|
if (!CreateDirectoryW(szUserProfilePath, NULL))
|
|
{
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < 1000; i++)
|
|
{
|
|
swprintf(szUserProfileName, L"%s.%03u", lpUserName, i);
|
|
|
|
wcscpy(szUserProfilePath, szProfilesPath);
|
|
wcscat(szUserProfilePath, L"\\");
|
|
wcscat(szUserProfilePath, szUserProfileName);
|
|
|
|
if (CreateDirectoryW(szUserProfilePath, NULL))
|
|
break;
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Copy default user directory */
|
|
if (!CopyDirectory(szUserProfilePath, szDefaultUserPath))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
/* Add profile to profile list */
|
|
if (!ConvertSidToStringSidW(Sid,
|
|
&SidString))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy(szBuffer,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
|
|
wcscat(szBuffer, SidString);
|
|
|
|
/* Create user profile key */
|
|
Error = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
szBuffer,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
LocalFree((HLOCAL)SidString);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create non-expanded user profile path */
|
|
wcscpy(szBuffer, szRawProfilesPath);
|
|
wcscat(szBuffer, L"\\");
|
|
wcscat(szBuffer, szUserProfileName);
|
|
|
|
/* Set 'ProfileImagePath' value (non-expanded) */
|
|
Error = RegSetValueExW(hKey,
|
|
L"ProfileImagePath",
|
|
0,
|
|
REG_EXPAND_SZ,
|
|
(LPBYTE)szBuffer,
|
|
(wcslen (szBuffer) + 1) * sizeof(WCHAR));
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
LocalFree((HLOCAL)SidString);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Set 'Sid' value */
|
|
Error = RegSetValueExW(hKey,
|
|
L"Sid",
|
|
0,
|
|
REG_BINARY,
|
|
Sid,
|
|
GetLengthSid(Sid));
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
LocalFree((HLOCAL)SidString);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
/* Create user hive name */
|
|
wcscpy(szBuffer, szUserProfilePath);
|
|
wcscat(szBuffer, L"\\ntuser.dat");
|
|
|
|
/* Acquire restore privilege */
|
|
if (!AcquireRemoveRestorePrivilege(TRUE))
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
LocalFree((HLOCAL)SidString);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create new user hive */
|
|
Error = RegLoadKeyW(HKEY_USERS,
|
|
SidString,
|
|
szBuffer);
|
|
AcquireRemoveRestorePrivilege(FALSE);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
LocalFree((HLOCAL)SidString);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initialize user hive */
|
|
if (!CreateUserHive(SidString, szUserProfilePath))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
LocalFree((HLOCAL)SidString);
|
|
return FALSE;
|
|
}
|
|
|
|
RegUnLoadKeyW(HKEY_USERS, SidString);
|
|
|
|
LocalFree((HLOCAL)SidString);
|
|
|
|
DPRINT("CreateUserProfileW() done\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetAllUsersProfileDirectoryA(LPSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
LPWSTR lpBuffer;
|
|
BOOL bResult;
|
|
|
|
lpBuffer = GlobalAlloc(GMEM_FIXED,
|
|
*lpcchSize * sizeof(WCHAR));
|
|
if (lpBuffer == NULL)
|
|
return FALSE;
|
|
|
|
bResult = GetAllUsersProfileDirectoryW(lpBuffer,
|
|
lpcchSize);
|
|
if (bResult)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
-1,
|
|
lpProfileDir,
|
|
*lpcchSize,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
GlobalFree(lpBuffer);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetAllUsersProfileDirectoryW(LPWSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
WCHAR szProfilePath[MAX_PATH];
|
|
WCHAR szBuffer[MAX_PATH];
|
|
DWORD dwLength;
|
|
HKEY hKey;
|
|
LONG Error;
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get profiles path */
|
|
dwLength = sizeof(szBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"ProfilesDirectory",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Expand it */
|
|
if (!ExpandEnvironmentStringsW(szBuffer,
|
|
szProfilePath,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
RegCloseKey (hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get 'AllUsersProfile' name */
|
|
dwLength = sizeof(szBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"AllUsersProfile",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
|
|
wcscat(szProfilePath, L"\\");
|
|
wcscat(szProfilePath, szBuffer);
|
|
|
|
dwLength = wcslen(szProfilePath) + 1;
|
|
if (lpProfileDir != NULL)
|
|
{
|
|
if (*lpcchSize < dwLength)
|
|
{
|
|
*lpcchSize = dwLength;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy(lpProfileDir, szProfilePath);
|
|
}
|
|
|
|
*lpcchSize = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetDefaultUserProfileDirectoryA(LPSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
LPWSTR lpBuffer;
|
|
BOOL bResult;
|
|
|
|
lpBuffer = GlobalAlloc(GMEM_FIXED,
|
|
*lpcchSize * sizeof(WCHAR));
|
|
if (lpBuffer == NULL)
|
|
return FALSE;
|
|
|
|
bResult = GetDefaultUserProfileDirectoryW(lpBuffer,
|
|
lpcchSize);
|
|
if (bResult)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
-1,
|
|
lpProfileDir,
|
|
*lpcchSize,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
GlobalFree(lpBuffer);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetDefaultUserProfileDirectoryW(LPWSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
WCHAR szProfilePath[MAX_PATH];
|
|
WCHAR szBuffer[MAX_PATH];
|
|
DWORD dwLength;
|
|
HKEY hKey;
|
|
LONG Error;
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get profiles path */
|
|
dwLength = sizeof(szBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"ProfilesDirectory",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Expand it */
|
|
if (!ExpandEnvironmentStringsW(szBuffer,
|
|
szProfilePath,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
RegCloseKey(hKey);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get 'DefaultUserProfile' name */
|
|
dwLength = sizeof(szBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"DefaultUserProfile",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
wcscat(szProfilePath, L"\\");
|
|
wcscat(szProfilePath, szBuffer);
|
|
|
|
dwLength = wcslen(szProfilePath) + 1;
|
|
if (lpProfileDir != NULL)
|
|
{
|
|
if (*lpcchSize < dwLength)
|
|
{
|
|
*lpcchSize = dwLength;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy(lpProfileDir, szProfilePath);
|
|
}
|
|
|
|
*lpcchSize = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetProfilesDirectoryA(LPSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
LPWSTR lpBuffer;
|
|
BOOL bResult;
|
|
|
|
lpBuffer = GlobalAlloc(GMEM_FIXED,
|
|
*lpcchSize * sizeof(WCHAR));
|
|
if (lpBuffer == NULL)
|
|
return FALSE;
|
|
|
|
bResult = GetProfilesDirectoryW(lpBuffer,
|
|
lpcchSize);
|
|
if (bResult)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
-1,
|
|
lpProfileDir,
|
|
*lpcchSize,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
GlobalFree(lpBuffer);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetProfilesDirectoryW(LPWSTR lpProfilesDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
WCHAR szProfilesPath[MAX_PATH];
|
|
WCHAR szBuffer[MAX_PATH];
|
|
DWORD dwLength;
|
|
HKEY hKey;
|
|
LONG Error;
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Get profiles path */
|
|
dwLength = sizeof(szBuffer);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"ProfilesDirectory",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szBuffer,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
/* Expand it */
|
|
if (!ExpandEnvironmentStringsW(szBuffer,
|
|
szProfilesPath,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
dwLength = wcslen (szProfilesPath) + 1;
|
|
if (lpProfilesDir != NULL)
|
|
{
|
|
if (*lpcchSize < dwLength)
|
|
{
|
|
*lpcchSize = dwLength;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
wcscpy(lpProfilesDir, szProfilesPath);
|
|
}
|
|
|
|
*lpcchSize = dwLength;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetUserProfileDirectoryA(HANDLE hToken,
|
|
LPSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
LPWSTR lpBuffer;
|
|
BOOL bResult;
|
|
|
|
lpBuffer = GlobalAlloc(GMEM_FIXED,
|
|
*lpcchSize * sizeof(WCHAR));
|
|
if (lpBuffer == NULL)
|
|
return FALSE;
|
|
|
|
bResult = GetUserProfileDirectoryW(hToken,
|
|
lpBuffer,
|
|
lpcchSize);
|
|
if (bResult)
|
|
{
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lpBuffer,
|
|
-1,
|
|
lpProfileDir,
|
|
*lpcchSize,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
GlobalFree(lpBuffer);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetUserProfileDirectoryW(HANDLE hToken,
|
|
LPWSTR lpProfileDir,
|
|
LPDWORD lpcchSize)
|
|
{
|
|
UNICODE_STRING SidString;
|
|
WCHAR szKeyName[MAX_PATH];
|
|
WCHAR szRawImagePath[MAX_PATH];
|
|
WCHAR szImagePath[MAX_PATH];
|
|
DWORD dwLength;
|
|
HKEY hKey;
|
|
LONG Error;
|
|
|
|
if (!GetUserSidFromToken(hToken,
|
|
&SidString))
|
|
{
|
|
DPRINT1("GetUserSidFromToken() failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("SidString: '%wZ'\n", &SidString);
|
|
|
|
wcscpy(szKeyName,
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\");
|
|
wcscat(szKeyName,
|
|
SidString.Buffer);
|
|
|
|
RtlFreeUnicodeString(&SidString);
|
|
|
|
DPRINT("KeyName: '%S'\n", szKeyName);
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szKeyName,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
dwLength = sizeof(szRawImagePath);
|
|
Error = RegQueryValueExW(hKey,
|
|
L"ProfileImagePath",
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)szRawImagePath,
|
|
&dwLength);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", Error);
|
|
RegCloseKey(hKey);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
DPRINT("RawImagePath: '%S'\n", szRawImagePath);
|
|
|
|
/* Expand it */
|
|
if (!ExpandEnvironmentStringsW(szRawImagePath,
|
|
szImagePath,
|
|
MAX_PATH))
|
|
{
|
|
DPRINT1 ("Error: %lu\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("ImagePath: '%S'\n", szImagePath);
|
|
|
|
dwLength = wcslen (szImagePath) + 1;
|
|
if (*lpcchSize < dwLength)
|
|
{
|
|
*lpcchSize = dwLength;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
*lpcchSize = dwLength;
|
|
wcscpy(lpProfileDir, szImagePath);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static
|
|
BOOL
|
|
CheckForLoadedProfile(HANDLE hToken)
|
|
{
|
|
UNICODE_STRING SidString;
|
|
HKEY hKey;
|
|
|
|
DPRINT("CheckForLoadedProfile() called\n");
|
|
|
|
if (!GetUserSidFromToken(hToken,
|
|
&SidString))
|
|
{
|
|
DPRINT1("GetUserSidFromToken() failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (RegOpenKeyExW(HKEY_USERS,
|
|
SidString.Buffer,
|
|
0,
|
|
MAXIMUM_ALLOWED,
|
|
&hKey))
|
|
{
|
|
DPRINT("Profile not loaded\n");
|
|
RtlFreeUnicodeString(&SidString);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
RtlFreeUnicodeString(&SidString);
|
|
|
|
DPRINT("Profile already loaded\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
LoadUserProfileA(HANDLE hToken,
|
|
LPPROFILEINFOA lpProfileInfo)
|
|
{
|
|
DPRINT ("LoadUserProfileA() not implemented\n");
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
LoadUserProfileW(IN HANDLE hToken,
|
|
IN OUT LPPROFILEINFOW lpProfileInfo)
|
|
{
|
|
WCHAR szUserHivePath[MAX_PATH];
|
|
LPWSTR UserName = NULL, Domain = NULL;
|
|
DWORD UserNameLength = 0, DomainLength = 0;
|
|
PTOKEN_USER UserSid = NULL;
|
|
SID_NAME_USE AccountType;
|
|
UNICODE_STRING SidString = { 0, 0, NULL };
|
|
LONG Error;
|
|
BOOL ret = FALSE;
|
|
DWORD dwLength = sizeof(szUserHivePath) / sizeof(szUserHivePath[0]);
|
|
|
|
DPRINT("LoadUserProfileW() called\n");
|
|
|
|
/* Check profile info */
|
|
if (!lpProfileInfo || (lpProfileInfo->dwSize != sizeof(PROFILEINFOW)) ||
|
|
(lpProfileInfo->lpUserName == NULL) || (lpProfileInfo->lpUserName[0] == 0))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Don't load a profile twice */
|
|
if (CheckForLoadedProfile(hToken))
|
|
{
|
|
DPRINT ("Profile already loaded\n");
|
|
lpProfileInfo->hProfile = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
if (lpProfileInfo->lpProfilePath)
|
|
{
|
|
wcscpy(szUserHivePath, lpProfileInfo->lpProfilePath);
|
|
}
|
|
else
|
|
{
|
|
/* FIXME: check if MS Windows allows lpProfileInfo->lpProfilePath to be NULL */
|
|
if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
|
|
{
|
|
DPRINT1("GetProfilesDirectoryW() failed (error %ld)\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Create user hive name */
|
|
wcscat(szUserHivePath, L"\\");
|
|
wcscat(szUserHivePath, lpProfileInfo->lpUserName);
|
|
wcscat(szUserHivePath, L"\\ntuser.dat");
|
|
DPRINT("szUserHivePath: %S\n", szUserHivePath);
|
|
|
|
/* Create user profile directory if needed */
|
|
if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
/* Get user sid */
|
|
if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength) ||
|
|
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
DPRINT1 ("GetTokenInformation() failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
UserSid = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, dwLength);
|
|
if (!UserSid)
|
|
{
|
|
DPRINT1("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!GetTokenInformation(hToken, TokenUser, UserSid, dwLength, &dwLength))
|
|
{
|
|
DPRINT1("GetTokenInformation() failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Get user name */
|
|
do
|
|
{
|
|
if (UserNameLength > 0)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, UserName);
|
|
UserName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, UserNameLength * sizeof(WCHAR));
|
|
if (!UserName)
|
|
{
|
|
DPRINT1("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (DomainLength > 0)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, Domain);
|
|
Domain = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, DomainLength * sizeof(WCHAR));
|
|
if (!Domain)
|
|
{
|
|
DPRINT1("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
ret = LookupAccountSidW(NULL,
|
|
UserSid->User.Sid,
|
|
UserName,
|
|
&UserNameLength,
|
|
Domain,
|
|
&DomainLength,
|
|
&AccountType);
|
|
} while (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if (!ret)
|
|
{
|
|
DPRINT1("LookupAccountSidW() failed\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Create profile */
|
|
/* FIXME: ignore Domain? */
|
|
DPRINT("UserName %S, Domain %S\n", UserName, Domain);
|
|
ret = CreateUserProfileW(UserSid->User.Sid, UserName);
|
|
if (!ret)
|
|
{
|
|
DPRINT1("CreateUserProfileW() failed\n");
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* Get user SID string */
|
|
ret = GetUserSidFromToken(hToken, &SidString);
|
|
if (!ret)
|
|
{
|
|
DPRINT1("GetUserSidFromToken() failed\n");
|
|
goto cleanup;
|
|
}
|
|
ret = FALSE;
|
|
|
|
/* Acquire restore privilege */
|
|
if (!AcquireRemoveRestorePrivilege(TRUE))
|
|
{
|
|
DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Load user registry hive */
|
|
Error = RegLoadKeyW(HKEY_USERS,
|
|
SidString.Buffer,
|
|
szUserHivePath);
|
|
AcquireRemoveRestorePrivilege(FALSE);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Open future HKEY_CURRENT_USER */
|
|
Error = RegOpenKeyExW(HKEY_USERS,
|
|
SidString.Buffer,
|
|
0,
|
|
MAXIMUM_ALLOWED,
|
|
(PHKEY)&lpProfileInfo->hProfile);
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
|
|
SetLastError((DWORD)Error);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
cleanup:
|
|
HeapFree(GetProcessHeap(), 0, UserSid);
|
|
HeapFree(GetProcessHeap(), 0, UserName);
|
|
HeapFree(GetProcessHeap(), 0, Domain);
|
|
RtlFreeUnicodeString(&SidString);
|
|
|
|
DPRINT("LoadUserProfileW() done\n");
|
|
return ret;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
UnloadUserProfile(HANDLE hToken,
|
|
HANDLE hProfile)
|
|
{
|
|
UNICODE_STRING SidString;
|
|
LONG Error;
|
|
|
|
DPRINT("UnloadUserProfile() called\n");
|
|
|
|
if (hProfile == NULL)
|
|
{
|
|
DPRINT1("Invalide profile handle\n");
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
RegCloseKey(hProfile);
|
|
|
|
if (!GetUserSidFromToken(hToken,
|
|
&SidString))
|
|
{
|
|
DPRINT1("GetUserSidFromToken() failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("SidString: '%wZ'\n", &SidString);
|
|
|
|
/* Acquire restore privilege */
|
|
if (!AcquireRemoveRestorePrivilege(TRUE))
|
|
{
|
|
DPRINT1("AcquireRemoveRestorePrivilege() failed (Error %ld)\n", GetLastError());
|
|
RtlFreeUnicodeString(&SidString);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Unload the hive */
|
|
Error = RegUnLoadKeyW(HKEY_USERS,
|
|
SidString.Buffer);
|
|
|
|
/* Remove restore privilege */
|
|
AcquireRemoveRestorePrivilege(FALSE);
|
|
|
|
if (Error != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("RegUnLoadKeyW() failed (Error %ld)\n", Error);
|
|
RtlFreeUnicodeString(&SidString);
|
|
SetLastError((DWORD)Error);
|
|
return FALSE;
|
|
}
|
|
|
|
RtlFreeUnicodeString(&SidString);
|
|
|
|
DPRINT("UnloadUserProfile() done\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DeleteProfileW(LPCWSTR lpSidString,
|
|
LPCWSTR lpProfilePath,
|
|
LPCWSTR lpComputerName)
|
|
{
|
|
DPRINT1("DeleteProfileW() not implemented!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DeleteProfileA(LPCSTR lpSidString,
|
|
LPCSTR lpProfilePath,
|
|
LPCSTR lpComputerName)
|
|
{
|
|
DPRINT1("DeleteProfileA() not implemented!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* EOF */
|