eResult CSecRunAsUser::RestartAsUser(){ USES_CONVERSION; if (m_bRunningRestricted || m_bRunningAsEmule) return RES_OK; if (!LoadAPI()) return RES_FAILED; ASSERT ( !m_strPassword.IsEmpty() ); BOOL bResult; try{ PROCESS_INFORMATION ProcessInfo = {0}; TCHAR szAppPath[MAX_PATH]; GetModuleFileName(NULL, szAppPath, MAX_PATH); CString strAppName; strAppName.Format(_T("\"%s\""),szAppPath); STARTUPINFOW StartInf = {0}; StartInf.cb = sizeof(StartInf); StartInf.dwFlags = STARTF_USESHOWWINDOW; StartInf.wShowWindow = SW_NORMAL; // remove the current mutex, so that the restart emule can create its own without problems // in the rare case CreateProcessWithLogonW fails, this will allow mult. instances, but if that function fails we have other problems anyway //MODIFIED by fengwen on 2007/03/05 <begin> : //::CloseHandle(theApp.m_hMutexOneInstance); if (NULL != theApp.m_pSingleInst) theApp.m_pSingleInst->AppEnd(); //MODIFIED by fengwen on 2007/03/05 <end> : if (NULL != theApp.m_pSingleInst2Loader) theApp.m_pSingleInst2Loader->AppEnd(); bResult = CreateProcessWithLogonW(EMULEACCOUNTW, m_strDomain, m_strPassword, LOGON_WITH_PROFILE, NULL, (LPWSTR)T2CW(strAppName), 0, NULL, NULL, &StartInf, &ProcessInfo); CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); } catch(...){ CGlobalVariable::QueueDebugLogLine(false, _T("Run as unpriveleged user: Error: Unexpected exception while loading advapi32.dll")); FreeAPI(); return RES_FAILED; } FreeAPI(); if (!bResult) CGlobalVariable::QueueDebugLogLine(false, _T("Run as unpriveleged user: Error: Failed to restart eMule as different user! Error Code: %i"),GetLastError()); if (bResult) return RES_OK_NEED_RESTART; else return RES_FAILED; }
// Initializes the PCANLight for a specific hardware // "HWType" = Hardware to be used // bool PCANLight::InitializeAPI(HardwareType HWType) { // Unloads the current DLL // UnloadAPI(); // Sets the new Hardware // hwType = HWType; // Loads the API for the new Hardware // LoadAPI(); return bWasLoaded; }
eResult CSecRunAsUser::RestartAsUser(){ if (m_bRunningRestricted || m_bRunningAsEmule) return RES_OK; if (!LoadAPI()) return RES_FAILED; TCHAR szAppPath[MAX_PATH]; DWORD dwModPathLen = GetModuleFileName(NULL, szAppPath, _countof(szAppPath)); if (dwModPathLen == 0 || dwModPathLen == _countof(szAppPath)) return RES_FAILED; ASSERT ( !m_strPassword.IsEmpty() ); BOOL bResult; try{ PROCESS_INFORMATION ProcessInfo = {0}; CString strAppName; strAppName.Format(_T("\"%s\""),szAppPath); STARTUPINFOW StartInf = {0}; StartInf.cb = sizeof(StartInf); StartInf.dwFlags = STARTF_USESHOWWINDOW; StartInf.wShowWindow = SW_NORMAL; // remove the current mutex, so that the restart emule can create its own without problems // in the rare case CreateProcessWithLogonW fails, this will allow mult. instances, but if that function fails we have other problems anyway ::CloseHandle(theApp.m_hMutexOneInstance); bResult = CreateProcessWithLogonW(EMULEACCOUNTW, m_strDomain, m_strPassword, LOGON_WITH_PROFILE, NULL, const_cast<LPWSTR>((LPCWSTR)strAppName), 0, NULL, NULL, &StartInf, &ProcessInfo); CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); } catch(...){ theApp.QueueDebugLogLine(false, _T("Run as unpriveleged user: Error: Unexpected exception while loading advapi32.dll")); FreeAPI(); return RES_FAILED; } FreeAPI(); if (!bResult) theApp.QueueDebugLogLine(false, _T("Run as unpriveleged user: Error: Failed to restart eMule as different user! Error Code: %i"),GetLastError()); if (bResult) return RES_OK_NEED_RESTART; else return RES_FAILED; }
eResult CSecRunAsUser::RestartAsRestricted(){ if (m_bRunningRestricted || m_bRunningAsEmule) return RES_OK; if (!LoadAPI()) return RES_FAILED; HANDLE hProcessToken = NULL; HANDLE hRestrictedToken = NULL; PTOKEN_USER pstructUserToken = NULL; try{ // get our access token from the process if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_READ, &hProcessToken)){ throw(CString(_T("Failed to retrieve access token from process"))); } // there is no easy way to check if we have already restircted token when not using the restricted sid list // so just check if we set the SANDBOX_INERT flag and hope noone else did // (which isunlikely tho because afaik you would only set it when using CreateRestirctedToken) :) DWORD dwLen = 0; DWORD dwInertFlag; if (!GetTokenInformation(hProcessToken, TokenSandBoxInert, &dwInertFlag, sizeof(dwInertFlag), &dwLen)){ throw(CString(_T("Failed to Flag-Status from AccessToken"))); } if (dwInertFlag != 0){ m_bRunningRestricted = true; throw(CString(_T("Already using a restricted Token it seems (everything is fine!)"))); } // get the user account SID to disable it in our new token dwLen = 0; while (!GetTokenInformation(hProcessToken, TokenUser, pstructUserToken, dwLen, &dwLen)){ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && pstructUserToken == NULL){ pstructUserToken = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen); continue; } throw(CString(_T("Failed to retrieve UserSID from AccessToken"))); } if (pstructUserToken == NULL) throw(CString(_T("Failed to retrieve UserSID from AccessToken"))); // disabling our primary token would make sense from an Security POV, but this would cause file acces conflicts // in the default settings (since we cannot access files we created ourself if they don't have the write flag for the group "users") // so it stays enabled for now and we only reduce privileges // create the new token if(!CreateRestrictedToken(hProcessToken, DISABLE_MAX_PRIVILEGE | SANDBOX_INERT, 0 /*disabled*/, &pstructUserToken->User, 0, NULL, 0, NULL, &hRestrictedToken ) ){ throw(CString(_T("Failed to create Restricted Token"))); } // do the starting job PROCESS_INFORMATION ProcessInfo = {0}; TCHAR szAppPath[MAX_PATH]; DWORD dwModPathLen = GetModuleFileName(NULL, szAppPath, _countof(szAppPath)); if (dwModPathLen == 0 || dwModPathLen == _countof(szAppPath)) throw CString(_T("Failed to get module file path")); CString strAppName; strAppName.Format(_T("\"%s\""),szAppPath); STARTUPINFO StartInf = {0}; StartInf.cb = sizeof(StartInf); StartInf.dwFlags = STARTF_USESHOWWINDOW; StartInf.wShowWindow = SW_NORMAL; // remove the current mutex, so that the restart emule can create its own without problems // in the rare case CreateProcessWithLogonW fails, this will allow mult. instances, but if that function fails we have other problems anyway ::CloseHandle(theApp.m_hMutexOneInstance); if(!CreateProcessAsUser(hRestrictedToken, NULL, strAppName.GetBuffer(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &StartInf, &ProcessInfo) ){ CString e; GetErrorMessage(GetLastError(), e, 0); throw(CString(_T("CreateProcessAsUser failed"))); } strAppName.ReleaseBuffer(); CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); // cleanup HeapFree(GetProcessHeap(), 0, (LPVOID)pstructUserToken); pstructUserToken = NULL; CloseHandle(hRestrictedToken); CloseHandle(hProcessToken); } catch(CString strError){ if (hProcessToken != NULL) CloseHandle(hProcessToken); if (hRestrictedToken != NULL) CloseHandle(hRestrictedToken); if (pstructUserToken != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pstructUserToken); theApp.QueueDebugLogLine(false, _T("SecureShellExecute exception: %s!"), strError); if (m_bRunningRestricted) return RES_OK; else return RES_FAILED; } return RES_OK_NEED_RESTART; }
eResult CSecRunAsUser::PrepareUser(){ CoInitialize(NULL); bool bResult = false; if (!LoadAPI()) return RES_FAILED; try{ IADsContainerPtr pUsers; try{ IADsWinNTSystemInfoPtr pNTsys; if (CoCreateInstance(CLSID_WinNTSystemInfo,NULL,CLSCTX_INPROC_SERVER,IID_IADsWinNTSystemInfo,(void**)&pNTsys) != S_OK) throw CString(_T("Failed to create IADsWinNTSystemInfo")); // check if we are already running on our eMule Account // todo: check if the current account is an administrator CComBSTR bstrUserName; pNTsys->get_UserName(&bstrUserName); m_strCurrentUser = bstrUserName; if (m_strCurrentUser == EMULEACCOUNTW){ m_bRunningAsEmule = true; throw CString(_T("Already running as eMule_Secure Account (everything is fine)")); } CComBSTR bstrCompName; pNTsys->get_ComputerName(&bstrCompName); CStringW cscompName = bstrCompName; CComBSTR bstrDomainName; pNTsys->get_DomainName(&bstrDomainName); m_strDomain = bstrDomainName; ADSPath.Format(L"WinNT://%s,computer",cscompName); if ( !SUCCEEDED(ADsGetObject(ADSPath.AllocSysString(),IID_IADsContainer,(void **)&pUsers)) ) throw CString(_T("Failed ADsGetObject()")); IEnumVARIANTPtr pEnum; ADsBuildEnumerator (pUsers,&pEnum); IADsUserPtr pChild; _variant_t vChild; while( ADsEnumerateNext (pEnum,1,&vChild,NULL) == S_OK ) { if (vChild.pdispVal->QueryInterface(IID_IADsUser,(void **)&pChild) != S_OK) continue; //If the object in the container is user then get properties CComBSTR bstrName; pChild->get_Name(&bstrName); CStringW csName= bstrName; // find the emule user account if possible if ( csName == EMULEACCOUNTW ){ // account found, set new random password and save it m_strPassword = CreateRandomPW(); if ( !SUCCEEDED(pChild->SetPassword(m_strPassword.AllocSysString())) ) throw CString(_T("Failed to set password")); bResult = true; break; } } } catch(CString error){ // clean up and abort theApp.QueueDebugLogLine(false, _T("Run as unpriveleged user: Exception while preparing user account: %s!"), error); CoUninitialize(); if (m_bRunningAsEmule) return RES_OK; else return RES_FAILED; } if (bResult || CreateEmuleUser(pUsers) ){ bResult = SetDirectoryPermissions(); } } catch(...){ // clean up and abort theApp.QueueDebugLogLine(false, _T("Run as unpriveleged user: Unexpected fatal error while preparing user account!")); CoUninitialize(); return RES_FAILED; } CoUninitialize(); FreeAPI(); if (bResult) return RES_OK_NEED_RESTART; else return RES_FAILED; }