mirror of https://github.com/BOINC/boinc.git
612 lines
18 KiB
C++
612 lines
18 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2008 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC 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 Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Code to run a BOINC application (main or graphics) under Windows
|
|
// Don't include this in applications
|
|
|
|
#include "boinc_win.h"
|
|
|
|
#include "win_util.h"
|
|
#include "filesys.h"
|
|
#include "error_numbers.h"
|
|
#include "str_replace.h"
|
|
#include "common_defs.h"
|
|
#include "util.h"
|
|
#include "parse.h"
|
|
#include "base64.h"
|
|
|
|
HANDLE sandbox_account_interactive_token = NULL;
|
|
HANDLE sandbox_account_service_token = NULL;
|
|
|
|
/*++
|
|
This function attempts to obtain a SID representing the supplied
|
|
account on the supplied system.
|
|
|
|
If the function succeeds, the return value is TRUE. A buffer is
|
|
allocated which contains the SID representing the supplied account.
|
|
This buffer should be freed when it is no longer needed by calling
|
|
HeapFree(GetProcessHeap(), 0, buffer)
|
|
|
|
If the function fails, the return value is FALSE. Call GetLastError()
|
|
to obtain extended error information.
|
|
|
|
Scott Field (sfield) 12-Jul-95
|
|
--*/
|
|
|
|
BOOL
|
|
GetAccountSid(
|
|
LPCSTR SystemName,
|
|
LPCSTR AccountName,
|
|
PSID *Sid
|
|
)
|
|
{
|
|
LPSTR ReferencedDomain=NULL;
|
|
DWORD cbSid=128; // initial allocation attempt
|
|
DWORD cchReferencedDomain=16; // initial allocation size
|
|
SID_NAME_USE peUse;
|
|
BOOL bSuccess=FALSE; // assume this function will fail
|
|
|
|
try
|
|
{
|
|
//
|
|
// initial memory allocations
|
|
//
|
|
*Sid = (PSID)HeapAlloc(GetProcessHeap(), 0, cbSid);
|
|
|
|
if(*Sid == NULL) throw 0;
|
|
|
|
ReferencedDomain = (LPSTR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
0,
|
|
cchReferencedDomain * sizeof(CHAR)
|
|
);
|
|
|
|
if(ReferencedDomain == NULL) throw 0;
|
|
|
|
//
|
|
// Obtain the SID of the specified account on the specified system.
|
|
//
|
|
while(!LookupAccountNameA(
|
|
SystemName, // machine to lookup account on
|
|
AccountName, // account to lookup
|
|
*Sid, // SID of interest
|
|
&cbSid, // size of SID
|
|
ReferencedDomain, // domain account was found on
|
|
&cchReferencedDomain,
|
|
&peUse
|
|
)) {
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
//
|
|
// reallocate memory
|
|
//
|
|
*Sid = (PSID)HeapReAlloc(
|
|
GetProcessHeap(),
|
|
0,
|
|
*Sid,
|
|
cbSid
|
|
);
|
|
if(*Sid == NULL) throw 0;
|
|
|
|
ReferencedDomain = (LPSTR)HeapReAlloc(
|
|
GetProcessHeap(),
|
|
0,
|
|
ReferencedDomain,
|
|
cchReferencedDomain * sizeof(CHAR)
|
|
);
|
|
if(ReferencedDomain == NULL) throw 0;
|
|
}
|
|
else throw 0;
|
|
}
|
|
|
|
//
|
|
// Indicate success.
|
|
//
|
|
bSuccess = TRUE;
|
|
|
|
} // try
|
|
catch(...)
|
|
{
|
|
//
|
|
// Cleanup and indicate failure, if appropriate.
|
|
//
|
|
|
|
HeapFree(GetProcessHeap(), 0, ReferencedDomain);
|
|
|
|
if(!bSuccess) {
|
|
if(*Sid != NULL) {
|
|
HeapFree(GetProcessHeap(), 0, *Sid);
|
|
*Sid = NULL;
|
|
}
|
|
}
|
|
} // finally
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
void get_sandbox_account_interactive_token() {
|
|
FILE* f;
|
|
char buf[256];
|
|
std::string encoded_username_str;
|
|
std::string encoded_password_str;
|
|
std::string username_str;
|
|
std::string domainname_str;
|
|
std::string password_str;
|
|
int retval = 0;
|
|
static bool first = true;
|
|
|
|
if (!first) return;
|
|
first = false;
|
|
|
|
f = fopen(CLIENT_AUTH_FILENAME, "r");
|
|
if (!f) return;
|
|
while (fgets(buf, 256, f)) {
|
|
if (parse_str(buf, "<username>", encoded_username_str)) continue;
|
|
if (parse_str(buf, "<password>", encoded_password_str)) continue;
|
|
}
|
|
fclose(f);
|
|
|
|
password_str = r_base64_decode(encoded_password_str);
|
|
|
|
if (std::string::npos != encoded_username_str.find('\\')) {
|
|
domainname_str = encoded_username_str.substr(
|
|
0, encoded_username_str.find('\\')
|
|
);
|
|
username_str = encoded_username_str.substr(
|
|
encoded_username_str.rfind(_T('\\')) + 1,
|
|
encoded_username_str.length() - encoded_username_str.rfind(_T('\\')) - 1
|
|
);
|
|
retval = LogonUserA(
|
|
username_str.c_str(),
|
|
domainname_str.c_str(),
|
|
password_str.c_str(),
|
|
LOGON32_LOGON_INTERACTIVE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&sandbox_account_interactive_token
|
|
);
|
|
} else {
|
|
username_str = encoded_username_str;
|
|
retval = LogonUserA(
|
|
username_str.c_str(),
|
|
NULL,
|
|
password_str.c_str(),
|
|
LOGON32_LOGON_INTERACTIVE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&sandbox_account_interactive_token
|
|
);
|
|
}
|
|
|
|
if (!retval) {
|
|
sandbox_account_interactive_token = NULL;
|
|
} else {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
void get_sandbox_account_service_token() {
|
|
ACCESS_ALLOWED_ACE *pace1 = NULL;
|
|
ACCESS_ALLOWED_ACE *pace2 = NULL;
|
|
ACL_SIZE_INFORMATION aclSizeInfo;
|
|
DWORD dwNewAclSize;
|
|
PACL pOldAcl = NULL;
|
|
PACL pNewAcl = NULL;
|
|
PSID pBOINCProjectSID = NULL;
|
|
PSID pBOINCMasterSID = NULL;
|
|
PTOKEN_DEFAULT_DACL pTokenDefaultDACL = NULL;
|
|
PVOID pTempAce;
|
|
DWORD dwSize = 0;
|
|
DWORD dwSizeNeeded = 0;
|
|
LPTSTR pszUserName = NULL;
|
|
FILE* f;
|
|
char buf[256];
|
|
std::string encoded_username_str;
|
|
std::string encoded_password_str;
|
|
std::string username_str;
|
|
std::string domainname_str;
|
|
std::string password_str;
|
|
int retval = 0;
|
|
static bool first=true;
|
|
|
|
if (!first) return;
|
|
first = false;
|
|
|
|
f = fopen(CLIENT_AUTH_FILENAME, "r");
|
|
if (!f) return;
|
|
while (fgets(buf, 256, f)) {
|
|
if (parse_str(buf, "<username>", encoded_username_str)) continue;
|
|
if (parse_str(buf, "<password>", encoded_password_str)) continue;
|
|
}
|
|
fclose(f);
|
|
|
|
password_str = r_base64_decode(encoded_password_str);
|
|
|
|
if (std::string::npos != encoded_username_str.find('\\')) {
|
|
domainname_str = encoded_username_str.substr(
|
|
0, encoded_username_str.find('\\')
|
|
);
|
|
username_str = encoded_username_str.substr(
|
|
encoded_username_str.rfind(_T('\\')) + 1,
|
|
encoded_username_str.length() - encoded_username_str.rfind(_T('\\')) - 1
|
|
);
|
|
retval = LogonUserA(
|
|
username_str.c_str(),
|
|
domainname_str.c_str(),
|
|
password_str.c_str(),
|
|
LOGON32_LOGON_SERVICE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&sandbox_account_service_token
|
|
);
|
|
if (retval) {
|
|
GetAccountSid(domainname_str.c_str(), username_str.c_str(), &pBOINCProjectSID);
|
|
}
|
|
} else {
|
|
username_str = encoded_username_str;
|
|
retval = LogonUserA(
|
|
username_str.c_str(),
|
|
NULL,
|
|
password_str.c_str(),
|
|
LOGON32_LOGON_SERVICE,
|
|
LOGON32_PROVIDER_DEFAULT,
|
|
&sandbox_account_service_token
|
|
);
|
|
if (retval) {
|
|
GetAccountSid(NULL, username_str.c_str(), &pBOINCProjectSID);
|
|
}
|
|
}
|
|
|
|
if (!retval) {
|
|
sandbox_account_service_token = NULL;
|
|
} else {
|
|
|
|
try
|
|
{
|
|
// Obtain the current user name.
|
|
|
|
dwSize = 0;
|
|
dwSizeNeeded = 0;
|
|
if (!GetUserNameEx(
|
|
NameSamCompatible,
|
|
pszUserName,
|
|
&dwSize)
|
|
)
|
|
if (GetLastError() == ERROR_MORE_DATA)
|
|
{
|
|
pszUserName = (LPTSTR)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSize + 1);
|
|
|
|
if (pszUserName == NULL)
|
|
throw 0;
|
|
|
|
if (!GetUserNameEx(
|
|
NameSamCompatible,
|
|
pszUserName,
|
|
&dwSize)
|
|
)
|
|
throw 0;
|
|
}
|
|
else
|
|
throw 0;
|
|
|
|
// Obtain the SID for the current user name.
|
|
|
|
if (!GetAccountSid(
|
|
NULL,
|
|
pszUserName,
|
|
&pBOINCMasterSID)
|
|
)
|
|
throw 0;
|
|
|
|
// Obtain the DACL for the service token.
|
|
|
|
dwSize = 0;
|
|
dwSizeNeeded = 0;
|
|
if (!GetTokenInformation(
|
|
sandbox_account_service_token,
|
|
TokenDefaultDacl,
|
|
NULL,
|
|
dwSize,
|
|
&dwSizeNeeded)
|
|
)
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pTokenDefaultDACL = (PTOKEN_DEFAULT_DACL)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwSizeNeeded);
|
|
|
|
if (pTokenDefaultDACL == NULL)
|
|
throw 0;
|
|
|
|
dwSize = dwSizeNeeded;
|
|
|
|
if (!GetTokenInformation(
|
|
sandbox_account_service_token,
|
|
TokenDefaultDacl,
|
|
pTokenDefaultDACL,
|
|
dwSize,
|
|
&dwSizeNeeded)
|
|
)
|
|
throw 0;
|
|
}
|
|
else
|
|
throw 0;
|
|
|
|
//
|
|
pOldAcl = pTokenDefaultDACL->DefaultDacl;
|
|
|
|
// Initialize the ACL.
|
|
|
|
ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
|
|
aclSizeInfo.AclBytesInUse = sizeof(ACL);
|
|
|
|
// Call only if the DACL is not NULL.
|
|
|
|
if (pOldAcl != NULL)
|
|
{
|
|
// get the file ACL size info
|
|
if (!GetAclInformation(
|
|
pOldAcl,
|
|
(LPVOID)&aclSizeInfo,
|
|
sizeof(ACL_SIZE_INFORMATION),
|
|
AclSizeInformation)
|
|
)
|
|
throw 0;
|
|
}
|
|
|
|
// Compute the size of the new ACL.
|
|
|
|
dwNewAclSize = aclSizeInfo.AclBytesInUse +
|
|
(2*sizeof(ACCESS_ALLOWED_ACE)) +
|
|
(2*GetLengthSid(pBOINCProjectSID)) +
|
|
(2*GetLengthSid(pBOINCMasterSID));
|
|
|
|
// Allocate memory for the new ACL.
|
|
|
|
pNewAcl = (PACL)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwNewAclSize);
|
|
|
|
if (pNewAcl == NULL)
|
|
throw 0;
|
|
|
|
// Initialize the new DACL.
|
|
|
|
if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
|
|
throw 0;
|
|
|
|
// If DACL is present, copy it to a new DACL.
|
|
|
|
if (pOldAcl)
|
|
{
|
|
// Copy the ACEs to the new ACL.
|
|
if (aclSizeInfo.AceCount)
|
|
{
|
|
for (unsigned int i=0; i < aclSizeInfo.AceCount; i++)
|
|
{
|
|
// Get an ACE.
|
|
if (!GetAce(pOldAcl, i, &pTempAce))
|
|
throw 0;
|
|
|
|
// Add the ACE to the new ACL.
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
pTempAce,
|
|
((PACE_HEADER)pTempAce)->AceSize)
|
|
)
|
|
throw 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add the first ACE to the process.
|
|
|
|
pace1 = (ACCESS_ALLOWED_ACE *)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pBOINCProjectSID) - sizeof(DWORD)
|
|
);
|
|
|
|
if (pace1 == NULL)
|
|
throw 0;
|
|
|
|
pace1->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
pace1->Header.AceFlags = CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE |
|
|
OBJECT_INHERIT_ACE;
|
|
pace1->Header.AceSize = (WORD)sizeof(ACCESS_ALLOWED_ACE) +
|
|
(WORD)GetLengthSid(pBOINCProjectSID) -
|
|
(WORD)sizeof(DWORD);
|
|
pace1->Mask = PROCESS_ALL_ACCESS;
|
|
|
|
if (!CopySid(GetLengthSid(pBOINCProjectSID), &pace1->SidStart, pBOINCProjectSID))
|
|
throw 0;
|
|
|
|
// Add an ACE to the process.
|
|
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(LPVOID)pace1,
|
|
pace1->Header.AceSize)
|
|
)
|
|
throw 0;
|
|
|
|
// Add the second ACE to the process.
|
|
|
|
pace2 = (ACCESS_ALLOWED_ACE *)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pBOINCMasterSID) - sizeof(DWORD)
|
|
);
|
|
|
|
if (pace2 == NULL)
|
|
throw 0;
|
|
|
|
pace2->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
|
|
pace2->Header.AceFlags = CONTAINER_INHERIT_ACE |
|
|
INHERIT_ONLY_ACE |
|
|
OBJECT_INHERIT_ACE;
|
|
pace2->Header.AceSize = (WORD)sizeof(ACCESS_ALLOWED_ACE) +
|
|
(WORD)GetLengthSid(pBOINCMasterSID) -
|
|
(WORD)sizeof(DWORD);
|
|
pace2->Mask = PROCESS_ALL_ACCESS;
|
|
|
|
if (!CopySid(GetLengthSid(pBOINCMasterSID), &pace2->SidStart, pBOINCMasterSID))
|
|
throw 0;
|
|
|
|
// Add an ACE to the process.
|
|
|
|
if (!AddAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
MAXDWORD,
|
|
(LPVOID)pace2,
|
|
pace2->Header.AceSize)
|
|
)
|
|
throw 0;
|
|
|
|
// Set a new Default DACL for the token.
|
|
pTokenDefaultDACL->DefaultDacl = pNewAcl;
|
|
|
|
if (!SetTokenInformation(
|
|
sandbox_account_service_token,
|
|
TokenDefaultDacl,
|
|
pTokenDefaultDACL,
|
|
dwNewAclSize)
|
|
)
|
|
throw 0;
|
|
|
|
// Indicate success.
|
|
fprintf(stderr, "New Token ACL Success!!!\n");
|
|
}
|
|
catch(...)
|
|
{
|
|
// Free the allocated buffers.
|
|
|
|
if (pace1 != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pace1);
|
|
|
|
if (pace2 != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pace2);
|
|
|
|
if (pOldAcl != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pOldAcl);
|
|
|
|
if (pNewAcl != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);
|
|
|
|
if (pBOINCProjectSID != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pBOINCProjectSID);
|
|
|
|
if (pBOINCMasterSID != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pBOINCMasterSID);
|
|
|
|
}
|
|
|
|
if (pszUserName != NULL)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pszUserName);
|
|
|
|
}
|
|
}
|
|
|
|
// Run application, Windows.
|
|
// chdir into the given directory, and run a program there.
|
|
// argv is set up Unix-style, i.e. argv[0] is the program name
|
|
//
|
|
|
|
int run_app_windows(
|
|
const char* dir, const char* file, int argc, char *const argv[], HANDLE& id
|
|
) {
|
|
int retval;
|
|
PROCESS_INFORMATION process_info;
|
|
STARTUPINFOA startup_info;
|
|
LPVOID environment_block = NULL;
|
|
char cmdline[1024];
|
|
char error_msg[1024];
|
|
|
|
memset(&process_info, 0, sizeof(process_info));
|
|
memset(&startup_info, 0, sizeof(startup_info));
|
|
startup_info.cb = sizeof(startup_info);
|
|
|
|
safe_strcpy(cmdline, "");
|
|
for (int i=0; i<argc; i++) {
|
|
safe_strcat(cmdline, argv[i]);
|
|
if (i<argc-1) {
|
|
safe_strcat(cmdline, " ");
|
|
}
|
|
}
|
|
|
|
get_sandbox_account_interactive_token();
|
|
if (sandbox_account_interactive_token != NULL) {
|
|
|
|
// Construct an environment block that contains environment variables that don't
|
|
// describe the current user.
|
|
if (!CreateEnvironmentBlock(&environment_block, sandbox_account_interactive_token, FALSE)) {
|
|
windows_format_error_string(GetLastError(), error_msg, sizeof(error_msg));
|
|
fprintf(stderr, "CreateEnvironmentBlock failed: %s\n", error_msg);
|
|
}
|
|
|
|
retval = CreateProcessAsUserA(
|
|
sandbox_account_interactive_token,
|
|
file,
|
|
cmdline,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_PROCESS_GROUP|CREATE_UNICODE_ENVIRONMENT,
|
|
environment_block,
|
|
dir,
|
|
&startup_info,
|
|
&process_info
|
|
);
|
|
|
|
if (!DestroyEnvironmentBlock(environment_block)) {
|
|
windows_format_error_string(GetLastError(), error_msg, sizeof(error_msg));
|
|
fprintf(stderr, "DestroyEnvironmentBlock failed: %s\n", error_msg);
|
|
}
|
|
|
|
} else {
|
|
retval = CreateProcessA(
|
|
file,
|
|
cmdline,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
dir,
|
|
&startup_info,
|
|
&process_info
|
|
);
|
|
}
|
|
if (!retval) {
|
|
windows_format_error_string(GetLastError(), error_msg, sizeof(error_msg));
|
|
fprintf(stderr, "CreateProcess failed: '%s'\n", error_msg);
|
|
return -1; // CreateProcess returns 1 if successful, false if it failed.
|
|
}
|
|
|
|
id = process_info.hProcess;
|
|
return 0;
|
|
}
|