/** * Does not closeHandle on the session handle, nor does it perform UnloadUserProfile * on the profile handle. The profile handle cannot be unloaded, that would unload * the registry keys that we just got the root to. These cleanup flaws are probably acceptable * for the Polarizer, which runs for a few minutes before shutting down. **/ RegKey getUserRegistryRoot(std::wstring accountName, std::wstring password) { HANDLE session; if (!LogonUser(accountName.c_str(), NULL, password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &session)) { DWORD error = GetLastError(); printf("LogonUser() failed: %d", error); logtools.log(L"LogonUser() failed", error); return RegKey::INVALID; } // Load the pet account's registry hive. wchar_t account[128] = {}; wcsncat(account, accountName.c_str(), 128); PROFILEINFO profile = { sizeof(PROFILEINFO), 0, account }; if (!LoadUserProfile(session, &profile)) { printf("LoadUserProfile() failed: %d", GetLastError()); logtools.log(L"LoadUserProfile() failed", GetLastError()); return RegKey::INVALID; } // now the pet hive is loaded, compute the SID so I // can get a name for the key that I can use to make a RegKey // Can't use the session handle I just got back because it // can't be converted to a regkey, either get the name or // give up on using our regkey abstraction. BYTE sid[10000]; DWORD sidSize = 10000; DWORD domainSize = 1000; wchar_t domain[1000]; SID_NAME_USE peUse; BOOL lookupWorked = LookupAccountName(NULL,accountName.c_str(), sid, &sidSize, domain, &domainSize, &peUse); if (lookupWorked) { LPTSTR sidNameChars; BOOL converted = ConvertSidToStringSidW(sid, &sidNameChars); if (converted) { std::wstring sidName = sidNameChars; RegKey key = RegKey::HKU.open(sidName); LocalFree(sidNameChars); return key; } else { logtools.log(L"convert sid to string failed", GetLastError()); return RegKey::INVALID; } } else { int err = GetLastError(); logtools.log(L"lookupAccountName failed", err); return RegKey::INVALID; } return RegKey::INVALID; }
ActivePet::ActivePet(wchar_t* user_password, std::wstring petname, FileEventLoop* files) : m_petname(petname), m_files(files), m_session(INVALID_HANDLE_VALUE), m_profile(INVALID_HANDLE_VALUE), m_job(CreateJobObject(NULL, NULL)), m_next_editable_name(1), m_ticks_while_invisible(0) { // Create a new logon session for the pet. std::wstring petRegistryPath = Constants::registryPets() + L"\\" + m_petname; RegKey petkey = RegKey::HKCU.open(petRegistryPath); std::wstring accountName = petkey.getValue(L"accountName"); std::wstring accountRegistryPath = Constants::registryAccounts() + L"\\" + accountName; RegKey accountKey = RegKey::HKCU.open(accountRegistryPath); std::wstring password = accountKey.getValue(L"password"); if (!LogonUser(accountName.c_str(), NULL, password.c_str(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &m_session)) { printf("LogonUser() failed: %d\n", GetLastError()); return; } // Tweak the Winsta0 and desktop ACLs to allow the pet to create windows. auto_buffer<PSID> logon_sid = GetLogonSID(m_session.get()); if (NULL == logon_sid.get()) { return; } auto_close<HWINSTA, &::CloseWindowStation> winsta0(OpenWindowStation(L"winsta0", FALSE, READ_CONTROL | WRITE_DAC)); if (NULL == winsta0.get()) { printf("OpenWindowStation() failed: %d\n", GetLastError()); return; } if (!AddAceToWindowStation(winsta0.get(), logon_sid.get())) { printf("AddAceToWindowStation() failed: %d", GetLastError()); return; } auto_close<HDESK, &::CloseDesktop> desktop(OpenDesktop(L"default", 0, FALSE, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)); if (NULL == desktop.get()) { printf("OpenDesktop() failed: %d\n", GetLastError()); return; } if (!AddAceToDesktop(desktop.get(), logon_sid.get())) { printf("AddAceToDesktop() failed: %d\n", GetLastError()); return; } // Load the pet account's registry hive. wchar_t account[128] = {}; wcsncpy(account, accountName.c_str(), 128); PROFILEINFO profile = { sizeof(PROFILEINFO), 0, account }; if (!LoadUserProfile(m_session.get(), &profile)) { printf("LoadUserProfile() failed: %d\n", GetLastError()); return; } m_profile = profile.hProfile; // Initialize the pet job. if (NULL == m_job.get()) { printf("CreateJobObject() failed: %d\n", GetLastError()); return; } JOBOBJECT_BASIC_UI_RESTRICTIONS buir = { JOB_OBJECT_UILIMIT_HANDLES }; if (!SetInformationJobObject(m_job.get(), JobObjectBasicUIRestrictions, &buir, sizeof buir)) { printf("SetInformationJobObject() failed: %d\n", GetLastError()); } // Some apps fail to launch without access to the desktop window. if (!UserHandleGrantAccess(GetDesktopWindow(), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Give apps access to all the standard cursors. if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_IBEAM), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_WAIT), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_CROSS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_UPARROW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_ICON), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENWSE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENESW), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEWE), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZENS), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_SIZEALL), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_NO), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HAND), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_APPSTARTING), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } if (!UserHandleGrantAccess(LoadCursor(NULL, IDC_HELP), m_job.get(), TRUE)) { printf("UserHandleGrantAccess() failed: %d\n", GetLastError()); } // Setup the use records for the printers. std::set<std::wstring> servers; RegKey printers = RegKey::HKCU.open(L"Printers\\Connections"); for (int i = 0; true; ++i) { RegKey printer = printers.getSubKey(i); if (!printer.isGood()) { break; } std::wstring server = printer.getValue(L"Server"); if (servers.count(server) == 0) { std::wstring resource = server + L"\\IPC$"; auto_array<wchar_t> remote(resource.length() + 1); lstrcpy(remote.get(), resource.c_str()); USE_INFO_2 use = {}; use.ui2_remote = remote.get(); use.ui2_domainname = _wgetenv(L"USERDOMAIN"); use.ui2_username = _wgetenv(L"USERNAME");; use.ui2_password = user_password; use.ui2_asg_type = USE_WILDCARD; auto_impersonation impersonate(m_session.get()); DWORD arg_error; NET_API_STATUS error = NetUseAdd(NULL, 2, (BYTE*)&use, &arg_error); if (error) { printf("NetUseAdd() failed: %d\n", error); } else { servers.insert(server); } } } // Add the message handlers. //m_requestFolderPath = accountKey.getValue(Constants::petDataPathName()) + Constants::requestPath(); m_requestFolderPath = Constants::requestsPath(Constants::polarisDataPath(Constants::userProfilePath(accountName))); m_dispatcher = new MessageDispatcher(m_requestFolderPath); m_files->watch(m_requestFolderPath, m_dispatcher); m_dispatcher->add("sendmail",makeSendMailHandler()); // TODO m_dispatcher->add("GetOpenFileNameA", makeGetOpenFileNameAHandler(this)); m_dispatcher->add("GetOpenFileNameW", makeGetOpenFileNameWHandler(this)); m_dispatcher->add("GetClipboardData", makeGetClipboardDataHandler()); }
Result<ExitCode> ProcessAsUser::Run(const Settings& settings, ProcessTracker& processTracker) const { Trace trace(settings.GetLogLevel()); trace < L"ProcessAsUser::Attempt to log a user on to the local computer"; StringBuffer userName(settings.GetUserName()); StringBuffer domain(settings.GetDomain()); StringBuffer password(settings.GetPassword()); StringBuffer workingDirectory(settings.GetWorkingDirectory()); StringBuffer commandLine(settings.GetCommandLine()); SecurityManager securityManager; auto setPrivilegesResult = securityManager.SetPrivileges(trace, { SE_TCB_NAME, SE_ASSIGNPRIMARYTOKEN_NAME }, true); if(setPrivilegesResult.HasError()) { return setPrivilegesResult.GetError(); } auto newUserSecurityTokenHandle = Handle(L"New user security token"); unsigned long logonTypeCount = sizeof(allLogonTypes) / sizeof(allLogonTypes[0]); for (unsigned long logonTypeIndex = 0; logonTypeIndex < logonTypeCount; logonTypeIndex++) { auto logonType = allLogonTypes[logonTypeIndex]; trace < L"::LogonUser using logon type "; switch (logonType) { case LOGON32_LOGON_INTERACTIVE: trace << L"LOGON32_LOGON_INTERACTIVE"; break; case LOGON32_LOGON_NETWORK: trace << L"LOGON32_LOGON_NETWORK"; break; case LOGON32_LOGON_BATCH: trace << L"LOGON32_LOGON_BATCH"; break; case LOGON32_LOGON_SERVICE: trace << L"LOGON32_LOGON_SERVICE"; break; } if (LogonUser( userName.GetPointer(), domain.GetPointer(), password.GetPointer(), logonType, LOGON32_PROVIDER_DEFAULT, &newUserSecurityTokenHandle)) { break; } auto error = Error(L"LogonUser"); trace << L" - "; trace << error.GetDescription(); if(logonTypeIndex == logonTypeCount -1) { return error; } } trace < L"ProcessAsUser::InitializeConsoleRedirection a new security descriptor"; trace < L"::InitializeSecurityDescriptor"; SECURITY_DESCRIPTOR securityDescriptor = {}; if (!InitializeSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION)) { return Error(L"InitializeSecurityDescriptor"); } trace < L"::SetSecurityDescriptorDacl"; if (!SetSecurityDescriptorDacl( &securityDescriptor, true, nullptr, false)) { return Error(L"SetSecurityDescriptorDacl"); } trace < L"ProcessAsUser::Creates a new access primary token that duplicates new process's token"; auto primaryNewUserSecurityTokenHandle = Handle(L"Primary new user security token"); SECURITY_ATTRIBUTES processSecAttributes = {}; processSecAttributes.lpSecurityDescriptor = &securityDescriptor; processSecAttributes.nLength = sizeof(SECURITY_DESCRIPTOR); processSecAttributes.bInheritHandle = true; trace < L"::DuplicateTokenEx"; if (!DuplicateTokenEx( newUserSecurityTokenHandle, 0, // MAXIMUM_ALLOWED &processSecAttributes, SecurityImpersonation, TokenPrimary, &primaryNewUserSecurityTokenHandle)) { return Error(L"DuplicateTokenEx"); } SECURITY_ATTRIBUTES threadSecAttributes = {}; threadSecAttributes.lpSecurityDescriptor = nullptr; threadSecAttributes.nLength = 0; threadSecAttributes.bInheritHandle = false; STARTUPINFO startupInfo = {}; trace < L"ProcessTracker::InitializeConsoleRedirection"; auto error = processTracker.InitializeConsoleRedirection(processSecAttributes, startupInfo); if(error.HasError()) { return Result<ExitCode>(error.GetError()); } trace < L"::LoadUserProfile"; PROFILEINFO profileInfo = {}; profileInfo.dwSize = sizeof(PROFILEINFO); profileInfo.lpUserName = userName.GetPointer(); if (!LoadUserProfile(primaryNewUserSecurityTokenHandle, &profileInfo)) { return Error(L"LoadUserProfile"); } auto newProcessEnvironmentResult = GetEnvironment(settings, primaryNewUserSecurityTokenHandle, settings.GetInheritanceMode(), trace); if (newProcessEnvironmentResult.HasError()) { UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return Result<ExitCode>(newProcessEnvironmentResult.GetError()); } auto setIntegrityLevelResult = securityManager.SetIntegrityLevel(settings.GetIntegrityLevel(), primaryNewUserSecurityTokenHandle, trace); if (setIntegrityLevelResult.HasError()) { return Result<ExitCode>(setIntegrityLevelResult.GetError()); } trace < L"ProcessAsUser::Create a new process and its primary thread. The new process runs in the security context of the user represented by the specified token."; PROCESS_INFORMATION processInformation = {}; startupInfo.dwFlags = STARTF_USESHOWWINDOW; startupInfo.wShowWindow = ShowModeConverter::ToShowWindowFlag(settings.GetShowMode()); auto cmdLine = settings.GetCommandLine(); trace < L"::CreateProcessAsUser"; if (!CreateProcessAsUser( primaryNewUserSecurityTokenHandle, nullptr, commandLine.GetPointer(), &processSecAttributes, &threadSecAttributes, true, CREATE_UNICODE_ENVIRONMENT, newProcessEnvironmentResult.GetResultValue().CreateEnvironment(), workingDirectory.GetPointer(), &startupInfo, &processInformation)) { auto result = Error(L"CreateProcessAsUser"); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return result; } // ReSharper disable CppInitializedValueIsAlwaysRewritten // ReSharper disable CppEntityAssignedButNoRead auto processHandle = Handle(L"Service Process"); processHandle = processInformation.hProcess; auto threadHandle = Handle(L"Thread"); threadHandle = processInformation.hThread; auto exitCode = processTracker.WaiteForExit(processInformation.hProcess, trace); UnloadUserProfile(primaryNewUserSecurityTokenHandle, profileInfo.hProfile); return exitCode; }
/* returns TRUE if the user profile is loaded; otherwise, FALSE. This is a simple helper that does all the initialization required to do the loading of a profile. */ BOOL OwnerProfile::loadProfile () { dprintf ( D_FULLDEBUG, "In OwnerProfile::loadProfile()\n" ); priv_state priv; BOOL profile_loaded = FALSE, ok = FALSE; __try { /* we must do the following as Condor, because, presumably, the account we are running as, does not have admin rights*/ priv = set_condor_priv (); /* initialize profile information */ ZeroMemory ( &user_profile_, sizeof ( PROFILEINFO ) ); user_profile_.dwSize = sizeof ( PROFILEINFO ); /* The PI_NOUI flag avoids the "I'm going to make a temporary profile for you... blah, blah, blah" dialog from being displayed in the case when a roaming profile is inaccessible because of a network outage, among other reasons. */ user_profile_.dwFlags = PI_NOUI; user_profile_.lpUserName = (char*)user_name_; /* load the user's profile for the first time-- this will effectively create it "for free", using the local "default" account as a template. */ profile_loaded = LoadUserProfile ( user_token_, &user_profile_ ); dprintf ( D_FULLDEBUG, "OwnerProfile::loadProfile: Loading the %s's " "profile %s. (last-error = %u)\n", user_profile_.lpUserName, profile_loaded ? "succeeded" : "failed", profile_loaded ? 0 : GetLastError () ); if ( !profile_loaded ) { __leave; } /* if we get here then we've managed to create the profile */ ok = TRUE; } __finally { /* return to previous privilege level */ set_priv ( priv ); } return ok; }
bool GetUserHandle(Settings& settings, BOOL& bLoadedProfile, PROFILEINFO& profile, HANDLE hCmdPipe) { DWORD gle = 0; if(settings.bUseSystemAccount) { if(BAD_HANDLE(settings.hUser)) //might already have hUser from a previous call { EnablePrivilege(SE_DEBUG_NAME); //helps with OpenProcess, required for GetLocalSystemProcessToken settings.hUser = GetLocalSystemProcessToken(); if(BAD_HANDLE(settings.hUser)) { Log(L"Not able to get Local System token", true); return false; } else Log(L"Got Local System handle", false); Duplicate(settings.hUser, __FILE__, __LINE__); } return true; } else { //not Local System, so either as specified user, or as current user if(FALSE == settings.user.IsEmpty()) { CString user, domain; GetUserDomain(settings.user, user, domain); BOOL bLoggedIn = LogonUser(user, domain.IsEmpty() ? NULL : domain, settings.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_WINNT50, &settings.hUser); gle = GetLastError(); #ifdef _DEBUG Log(L"DEBUG: LogonUser", gle); #endif if((FALSE == bLoggedIn) || BAD_HANDLE(settings.hUser)) { Log(StrFormat(L"Error logging in as %s", settings.user), gle); return false; } else Duplicate(settings.hUser, __FILE__, __LINE__); //gives max rights if(!BAD_HANDLE(settings.hUser) && (false == settings.bDontLoadProfile)) { EnablePrivilege(SE_RESTORE_NAME); EnablePrivilege(SE_BACKUP_NAME); bLoadedProfile = LoadUserProfile(settings.hUser, &profile); #ifdef _DEBUG gle = GetLastError(); Log(L"DEBUG: LoadUserProfile", gle); #endif } return true; } else { //run as current user if(NULL != hCmdPipe) { BOOL b = ImpersonateNamedPipeClient(hCmdPipe); DWORD gle = GetLastError(); if(FALSE == b) Log(L"Failed to impersonate client user", gle); else Log(L"Impersonated caller", false); } HANDLE hThread = GetCurrentThread(); BOOL bDupe = DuplicateHandle(GetCurrentProcess(), hThread, GetCurrentProcess(), &hThread, 0, TRUE, DUPLICATE_SAME_ACCESS); DWORD gle = GetLastError(); BOOL bOpen = OpenThreadToken(hThread, TOKEN_DUPLICATE | TOKEN_QUERY, TRUE, &settings.hUser); gle = GetLastError(); if(1008 == gle) //no thread token { bOpen = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &settings.hUser); gle = GetLastError(); } if(FALSE == bOpen) Log(L"Failed to open current user token", GetLastError()); Duplicate(settings.hUser, __FILE__, __LINE__); //gives max rights RevertToSelf(); return !BAD_HANDLE(settings.hUser); } } }
Result<ExitCode> ProcessWithLogon::RunInternal(Trace& trace, const Settings& settings, ProcessTracker& processTracker, Environment& environment, bool changeIntegrityLevel) const { SECURITY_ATTRIBUTES securityAttributes = {}; securityAttributes.nLength = sizeof(SECURITY_DESCRIPTOR); securityAttributes.bInheritHandle = true; STARTUPINFO startupInfo = {}; startupInfo.dwFlags = STARTF_USESHOWWINDOW; startupInfo.wShowWindow = ShowModeConverter::ToShowWindowFlag(settings.GetShowMode()); PROCESS_INFORMATION processInformation = {}; trace < L"ProcessTracker::InitializeConsoleRedirection"; processTracker.InitializeConsoleRedirection(securityAttributes, startupInfo); StringBuffer userName(settings.GetUserName()); StringBuffer domain(settings.GetDomain()); StringBuffer password(settings.GetPassword()); StringBuffer workingDirectory(settings.GetWorkingDirectory()); StringBuffer commandLine(settings.GetCommandLine()); if (changeIntegrityLevel) { trace < L"::LogonUser"; auto newUserSecurityTokenHandle = Handle(L"New user security token"); if (!LogonUser( userName.GetPointer(), domain.GetPointer(), password.GetPointer(), LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &newUserSecurityTokenHandle)) { return Error(L"LogonUser"); } trace < L"::LoadUserProfile"; PROFILEINFO profileInfo = {}; profileInfo.dwSize = sizeof(PROFILEINFO); profileInfo.lpUserName = userName.GetPointer(); if (!LoadUserProfile(newUserSecurityTokenHandle, &profileInfo)) { return Error(L"LoadUserProfile"); } SecurityManager securityManager; auto setIntegrityLevelResult = securityManager.SetIntegrityLevel(settings.GetIntegrityLevel(), newUserSecurityTokenHandle, trace); if (setIntegrityLevelResult.HasError()) { return Result<ExitCode>(setIntegrityLevelResult.GetError()); } trace < L"::CreateProcessWithTokenW"; if (!CreateProcessWithTokenW( newUserSecurityTokenHandle, LOGON_WITH_PROFILE, nullptr, commandLine.GetPointer(), CREATE_UNICODE_ENVIRONMENT, environment.CreateEnvironment(), workingDirectory.GetPointer(), &startupInfo, &processInformation)) { return Error(L"CreateProcessWithLogonW"); } } else { trace < L"::CreateProcessWithLogonW"; if (!CreateProcessWithLogonW( userName.GetPointer(), domain.GetPointer(), password.GetPointer(), LOGON_WITH_PROFILE, nullptr, commandLine.GetPointer(), CREATE_UNICODE_ENVIRONMENT, environment.CreateEnvironment(), workingDirectory.GetPointer(), &startupInfo, &processInformation)) { return Error(L"CreateProcessWithLogonW"); } } // ReSharper disable once CppInitializedValueIsAlwaysRewritten auto processHandle = Handle(L"Process"); processHandle = processInformation.hProcess; // ReSharper disable once CppInitializedValueIsAlwaysRewritten auto threadHandle = Handle(L"Thread"); threadHandle = processInformation.hThread; return processTracker.WaiteForExit(processInformation.hProcess, trace); }
wchar_t *gethomedir_w(char *pUserName, char *pDomainName) { HANDLE token; PROFILEINFOW profileInfo; wchar_t szPathW[MAX_PATH] = {0}; wchar_t pUserName_w[UNLEN + 1] = {0}; static wchar_t username_w[UNLEN + 1] = {0}; DWORD usernamelen = UNLEN + 1; wchar_t pDomainName_w[UNLEN + 1] = {0}; wchar_t *userprofile_w; /* * If there is home dir from lsa return it. */ if (HomeDirLsaW[0] != L'\0') { debug("Using LSA HomeDirW."); return _wcsdup(HomeDirLsaW); } szPathW[0] = '\0'; if (MultiByteToWideChar(CP_UTF8, 0, pUserName, -1, pUserName_w, UNLEN) == 0) { return NULL; } if (pDomainName && MultiByteToWideChar(CP_UTF8, 0, pDomainName, -1, pDomainName_w, UNLEN) == 0) { return NULL; } debug3("gethomedir: pUserName [%s]", pUserName); GetUserNameW(username_w, &usernamelen); debug3("gethomedir: username [%ls]", username_w); if (wcscmp(pUserName_w, username_w) == 0) { /* * User query his own home dir, we can take it from env. */ debug3("gethomedir: getenv"); userprofile_w = _wgetenv(L"USERPROFILE"); if (userprofile_w) { debug3("gethomedir: userprofile [%ls]", userprofile_w); /* * We have a %USERPROFILE% and we can return it */ return _wcsdup(userprofile_w); } /* * Env not set, let's try to take it from token */ } /* * If all above fail try to create user token manually * and get homedir using this token. */ #ifdef USE_NTCREATETOKEN token = CreateUserTokenW(pUserName_w, pDomainName_w, L"sshd"); if (token == NULL) { debug("gethomedir: create token failed"); return NULL; } debug2("setting up profile info..."); /* * Become the user */ memset(&profileInfo, 0, sizeof(profileInfo)); profileInfo.dwSize = sizeof(profileInfo); profileInfo.lpUserName = pUserName_w; profileInfo.lpServerName = pDomainName_w; debug2("LoadUserProfile()..."); if (!LoadUserProfile(token, &profileInfo)) { DWORD dwLast = GetLastError(); debug("gethomedir: load profile failed [%d]", dwLast); return NULL; } /* * Get user's home directory */ //if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, token, 0, szPath))) debug2("SGGetFolderPath()..."); if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, token, 0, szPathW))) { debug("gethomedir: get folder failed"); /* * Become self again. */ UnloadUserProfile(token, profileInfo.hProfile); RevertToSelf(); CloseHandle(token); return NULL; } debug3("gethomedir: szPathW [%ls]", szPathW); /* * Become self again. */ UnloadUserProfile(token, profileInfo.hProfile); RevertToSelf(); CloseHandle(token); debug2("<- gethomedir()..."); return _wcsdup(szPathW); #else return NULL; #endif }
char *GetHomeDirFromToken(char *userName, HANDLE token) { UCHAR domain[200]; wchar_t pw_buf[MAX_PATH] = { L'\0' }; debug("-> GetHomeDirFromToken()..."); PROFILEINFO profileInfo; // find the server name of the domain controller which created this token GetDomainFromToken ( &token, domain, sizeof(domain)); //if (MultiByteToWideChar(CP_UTF8, 0, domain, -1, domainW, sizeof(domainW)) == 0) //{ //debug("DomainServerName encoding conversion failure"); //return NULL; //} profileInfo.dwFlags = PI_NOUI; profileInfo.lpProfilePath = NULL; profileInfo.lpUserName = userName; profileInfo.lpDefaultPath = NULL; profileInfo.lpServerName = domain; profileInfo.lpPolicyPath = NULL; profileInfo.hProfile = NULL; profileInfo.dwSize = sizeof(profileInfo); if (LoadUserProfile(token, &profileInfo) == FALSE) { debug("<- GetHomeDirFromToken()..."); debug("LoadUserProfile failure: %d", GetLastError()); return NULL; } /* * And retrieve homedir from profile. */ if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, token, 0, pw_homedir))) { debug("<- GetHomeDirFromToken()..."); debug("SHGetFolderPath failed"); return NULL; } // update APPDATA user's env variable if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, token, 0, pw_buf))) { SetEnvironmentVariableW(L"APPDATA", pw_buf); } // update LOCALAPPDATA user's env variable if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, token, 0, pw_buf))) { SetEnvironmentVariableW(L"LOCALAPPDATA", pw_buf); } /* * Unload user profile. */ if (UnloadUserProfile(token, profileInfo.hProfile) == FALSE) { debug("WARNING. Cannot unload user profile (%u).", GetLastError()); } debug("<- GetHomeDirFromToken()..."); return pw_homedir; }