*** empty log message ***

svn path=/trunk/boinc/; revision=10803
This commit is contained in:
Charlie Fenton 2006-08-01 12:36:19 +00:00
parent 3be29b3ae9
commit 6ecd5de4d9
20 changed files with 535 additions and 349 deletions

View File

@ -8203,3 +8203,40 @@ Bruce 31 July 2006
doc/
project_options.php
Charlie 1 Aug 2006
- Sandbox: extend security to all UNIX and Linux platforms. To
enable this feature, add the compiler flag -DSANDBOX and add
check_security.C to the source file list for both Manager and
Client.
- Manager and Client both accept command-line argument -insecure
which runs without special boinc users and groups. Both
Manager and Client check owners and permissions and refuse
to run unless they are set correctly for the selected secure
or insecure mode. If Manager is called with -insecure, it
runs the Client with -insecure.
- Added code to Mac_SA_Secure.sh and Mac_SA_Insecure.sh scripts.
client/
app_start.C
check_security.C
client_state.C
client_types.C
cs_cmdline.C
file_names.C
gui_rpc_server.C
main.C
clientGUI/
BOINCGUIApp.cpp,h
MainDocument.cpp
mac/
Mac_GUI.cpp
mac_saver_module.cpp
lib/
boinc_cmd.C
filesys.C
util.h
mac_build/
Mac_SA_Insecure.sh
Mac_SA_Secure.sh
mac_installer/
PostInstall.cpp

View File

@ -90,11 +90,10 @@ static int make_link(const char *existing, const char *new_link) {
if (!fp) return ERR_FOPEN;
fprintf(fp, "<soft_link>%s</soft_link>\n", existing);
fclose(fp);
#ifdef SANDBOX
return set_to_project_group(new_link);
#else
return 0;
#endif
if (g_use_sandbox)
return set_to_project_group(new_link);
else
return 0;
}
int ACTIVE_TASK::link_user_files() {
@ -603,22 +602,22 @@ int ACTIVE_TASK::start(bool first_time) {
char cmdline[8192];
strcpy(cmdline, wup->command_line.c_str());
sprintf(buf, "../../%s", exec_path );
#ifdef SANDBOX
char switcher_path[100];
sprintf(switcher_path, "../../%s/%s", SWITCHER_DIR, SWITCHER_FILE_NAME);
argv[0] = SWITCHER_FILE_NAME;
argv[1] = buf;
argv[2] = exec_name;
parse_command_line(cmdline, argv+3);
if (log_flags.task_debug) {
debug_print_argv(argv);
if (g_use_sandbox) {
char switcher_path[100];
sprintf(switcher_path, "../../%s/%s", SWITCHER_DIR, SWITCHER_FILE_NAME);
argv[0] = SWITCHER_FILE_NAME;
argv[1] = buf;
argv[2] = exec_name;
parse_command_line(cmdline, argv+3);
if (log_flags.task_debug) {
debug_print_argv(argv);
}
retval = execv(switcher_path, argv);
} else {
argv[0] = exec_name;
parse_command_line(cmdline, argv+1);
retval = execv(buf, argv);
}
retval = execv(switcher_path, argv);
#else
argv[0] = exec_name;
parse_command_line(cmdline, argv+1);
retval = execv(buf, argv);
#endif
msg_printf(wup->project, MSG_ERROR,
"Process creation (%s) failed: %s, errno=%d\n", buf, boincerror(retval), errno
);

View File

@ -31,7 +31,11 @@
#include "error_numbers.h"
#include "file_names.h"
static int CheckNestedDirectories(char * basepath, int depth);
static int CheckNestedDirectories(char * basepath, int depth, int use_sandbox);
#if (! defined(__WXMAC__) && ! defined(_MAC_INSTALLER))
static void GetPathToThisProcess(char* outbuf, size_t maxLen);
#endif
#define REAL_BOINC_MASTER_NAME "boinc_master"
#define REAL_BOINC_PROJECT_NAME "boinc_project"
@ -50,8 +54,9 @@ static uid_t boinc_master_uid, boinc_project_uid;
// Returns FALSE (0) if owners and permissions are OK, else TRUE (1)
int check_security(
#ifdef _MAC_INSTALLER
char *bundlePath, char *dataPath
char *bundlePath, char *dataPath,
#endif
int use_sandbox, int isManager
) {
passwd *pw;
group *grp;
@ -60,6 +65,7 @@ char *bundlePath, char *dataPath
char dir_path[MAXPATHLEN], full_path[MAXPATHLEN];
struct stat sbuf;
int retval;
int useFakeProjectUserAndGroup = 0;
#ifdef __WXMAC__ // If Mac BOINC Manager
ProcessSerialNumber ourPSN;
ProcessInfoRec pInfo;
@ -68,7 +74,12 @@ char *bundlePath, char *dataPath
#endif
#ifdef _MAC_INSTALLER
char *p;
#else
#endif
#if (defined(_DEBUG) && defined(DEBUG_WITH_FAKE_PROJECT_USER_AND_GROUP))
useFakeProjectUserAndGroup = 1;
#else
useFakeProjectUserAndGroup = ! use_sandbox;
#endif
// GDB can't attach to applications which are running as a diferent user or group so
@ -97,32 +108,38 @@ char *bundlePath, char *dataPath
retval = FSRefMakePath (&ourFSRef, (UInt8*)dir_path, sizeof(dir_path));
if (retval)
return -1003; // Should never happen
#endif
#ifdef _MAC_INSTALLER
#elif defined (_MAC_INSTALLER)
strlcpy(dir_path, bundlePath, sizeof(dir_path));
#endif
#if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If Mac BOINC Manager or installer
// Get the full path to BOINC Clients inside this application's bundle
strlcpy(full_path, dir_path, sizeof(full_path));
strlcat(full_path, "/Contents/Resources/boinc", sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1004; // Should never happen
if ((sbuf.st_mode & (S_ISUID | S_ISGID)) != (S_ISUID | S_ISGID))
return -1005;
boinc_master_uid = sbuf.st_gid;
boinc_master_gid = sbuf.st_uid;
if (use_sandbox) {
#if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If called from Mac BOINC Manager or installer
// Get the full path to BOINC Client inside this application's bundle
strlcpy(full_path, dir_path, sizeof(full_path));
strlcat(full_path, "/Contents/Resources/boinc", sizeof(full_path));
#else
boinc_master_uid = geteuid();
boinc_master_gid = getegid();
if (isManager) { // If called from BOINC Manager but not on Mac
getcwd(full_path, sizeof(full_path)); // Assume Client is in current directory
strlcat(full_path, "/boinc", sizeof(full_path));
} else // If called from BOINC Client
GetPathToThisProcess(full_path, sizeof(full_path));
#endif
retval = stat(full_path, &sbuf);
if (retval)
return -1004; // Should never happen
if ((sbuf.st_mode & (S_ISUID | S_ISGID)) != (S_ISUID | S_ISGID))
return -1005;
boinc_master_uid = sbuf.st_gid;
boinc_master_gid = sbuf.st_uid;
} else {
boinc_master_uid = geteuid();
boinc_master_gid = getegid();
}
#ifdef _MAC_INSTALLER
// Require absolute owner and group boinc_master:boinc_master
strlcpy(boinc_master_user_name, REAL_BOINC_MASTER_NAME, sizeof(boinc_master_user_name));
@ -151,25 +168,25 @@ char *bundlePath, char *dataPath
#endif
#if (defined(_DEBUG) && defined(DEBUG_WITH_FAKE_PROJECT_USER_AND_GROUP))
// For easier debugging of project applications
strlcpy(boinc_project_user_name, boinc_master_user_name, sizeof(boinc_project_user_name));
strlcpy(boinc_project_group_name, boinc_master_group_name, sizeof(boinc_project_group_name));
boinc_project_uid = boinc_master_uid;
boinc_project_gid = boinc_master_gid;
#else
strlcpy(boinc_project_user_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_user_name));
pw = getpwnam(boinc_project_user_name);
if (pw == NULL)
return -1010; // User boinc_project does not exist
boinc_project_uid = pw->pw_uid;
if (useFakeProjectUserAndGroup) {
// For easier debugging of project applications
strlcpy(boinc_project_user_name, boinc_master_user_name, sizeof(boinc_project_user_name));
strlcpy(boinc_project_group_name, boinc_master_group_name, sizeof(boinc_project_group_name));
boinc_project_uid = boinc_master_uid;
boinc_project_gid = boinc_master_gid;
} else {
strlcpy(boinc_project_user_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_user_name));
pw = getpwnam(boinc_project_user_name);
if (pw == NULL)
return -1010; // User boinc_project does not exist
boinc_project_uid = pw->pw_uid;
strlcpy(boinc_project_group_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_group_name));
grp = getgrnam(boinc_project_group_name);
if (grp == NULL)
return -1011; // Group boinc_project does not exist
boinc_project_gid = grp->gr_gid;
#endif
strlcpy(boinc_project_group_name, REAL_BOINC_PROJECT_NAME, sizeof(boinc_project_group_name));
grp = getgrnam(boinc_project_group_name);
if (grp == NULL)
return -1011; // Group boinc_project does not exist
boinc_project_gid = grp->gr_gid;
}
#if (defined(__WXMAC__) || defined(_MAC_INSTALLER)) // If Mac BOINC Manager or installer
// Get the full path to BOINC Manager executable inside this application's bundle
@ -191,13 +208,15 @@ char *bundlePath, char *dataPath
if (sbuf.st_gid != boinc_master_gid)
return -1014;
if ((sbuf.st_mode & S_ISGID) != S_ISGID)
return -1015;
if (use_sandbox) {
if ((sbuf.st_mode & S_ISGID) != S_ISGID)
return -1015;
}
#endif
#ifdef _MAC_INSTALLER
// Require absolute owner and group boinc_master:boinc_master
// Get the full path to BOINC Clients inside this application's bundle
// Get the full path to BOINC Client inside this application's bundle
strlcpy(full_path, dir_path, sizeof(full_path));
strlcat(full_path, "/Contents/Resources/boinc", sizeof(full_path));
@ -217,49 +236,59 @@ char *bundlePath, char *dataPath
egid = getegid();
euid = geteuid();
#ifndef _MAC_INSTALLER
#ifdef _MAC_INSTALLER
strlcpy(dir_path, dataPath, sizeof(dir_path)); // Installer
#else // _MAC_INSTALLER
getcwd(dir_path, sizeof(dir_path)); // Client or Manager
if (egid != boinc_master_gid)
return -1019; // Client or Manager should be running setgid boinc_master
#ifndef __WXMAC__ // If BOINC Client
if (euid != boinc_master_uid)
return -1020; // BOINC Client should be running setuid boinc_master
if (! isManager) // If BOINC Client
if (euid != boinc_master_uid)
return -1020; // BOINC Client should be running setuid boinc_master
#endif
getcwd(dir_path, sizeof(dir_path)); // Client or Manager
#else // _MAC_INSTALLER
strlcpy(dir_path, dataPath, sizeof(dir_path)); // Installer
#endif // _MAC_INSTALLER
retval = stat(dir_path, &sbuf);
if (retval)
return -1021; // Should never happen
if (use_sandbox) {
// The top-level BOINC Data directory can have a different user if created by the Manager,
// but it should always have group boinc_master.
if (sbuf.st_gid != boinc_master_gid)
return -1022;
// The top-level BOINC Data directory can have a different user if created by the Manager,
// but it should always have group boinc_master.
if (sbuf.st_gid != boinc_master_gid)
return -1022;
// The top-level BOINC Data directory should have permission 775 or 575
if ((sbuf.st_mode & 0577) != 0575)
return -1023;
// The top-level BOINC Data directory should have permission 775 or 575
if ((sbuf.st_mode & 0577) != 0575)
return -1023;
} else {
if (sbuf.st_uid != boinc_master_uid)
return -1022;
}
strlcpy(full_path, dir_path, sizeof(full_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, PROJECTS_DIR, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (! retval) { // Client can create projects directory if it does not yet exist.
if (sbuf.st_gid != boinc_master_gid)
return -1024;
if (sbuf.st_uid != boinc_master_uid)
return -1025;
if (use_sandbox) {
if (sbuf.st_gid != boinc_master_gid)
return -1024;
if ((sbuf.st_mode & 0777) != 0775)
return -1025;
}
if (sbuf.st_uid != boinc_master_uid)
return -1026;
// Step through project directories
retval = CheckNestedDirectories(full_path, 1);
retval = CheckNestedDirectories(full_path, 1, use_sandbox);
if (retval)
return retval;
}
@ -269,17 +298,19 @@ char *bundlePath, char *dataPath
strlcat(full_path, SLOTS_DIR, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (! retval) { // Client can create slots directory if it does not yet exist.
if (sbuf.st_gid != boinc_master_gid)
return -1027;
if (use_sandbox) {
if (sbuf.st_gid != boinc_master_gid)
return -1027;
if ((sbuf.st_mode & 0777) != 0775)
return -1028;
}
if (sbuf.st_uid != boinc_master_uid)
return -1028;
if ((sbuf.st_mode & 0777) != 0775)
return -1029;
// Step through slot directories
retval = CheckNestedDirectories(full_path, 1);
retval = CheckNestedDirectories(full_path, 1, use_sandbox);
if (retval)
return retval;
}
@ -289,71 +320,78 @@ char *bundlePath, char *dataPath
strlcat(full_path, GUI_RPC_PASSWD_FILE, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (! retval) { // Client can create RPC password file if it does not yet exist.
if (sbuf.st_gid != boinc_master_gid)
return -1030;
if (use_sandbox) {
if (sbuf.st_gid != boinc_master_gid)
return -1030;
if ((sbuf.st_mode & 0777) != 0660)
return -1032;
} else {
if ((sbuf.st_mode & 0717) != 0600)
return -1032;
}
if (sbuf.st_uid != boinc_master_uid)
return -1031;
if ((sbuf.st_mode & 0777) != 0660)
return -1032;
}
strlcpy(full_path, dir_path, sizeof(dir_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_DIR, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1033;
if (sbuf.st_gid != boinc_master_gid)
return -1034;
if (use_sandbox) {
strlcpy(full_path, dir_path, sizeof(dir_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_DIR, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1033;
if (sbuf.st_gid != boinc_master_gid)
return -1034;
if (sbuf.st_uid != boinc_master_uid)
return -1035;
if (sbuf.st_uid != boinc_master_uid)
return -1035;
if ((sbuf.st_mode & 0777) != 0550)
return -1036;
if ((sbuf.st_mode & 0777) != 0550)
return -1036;
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_FILE_NAME, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1037;
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_FILE_NAME, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1037;
if (sbuf.st_gid != boinc_project_gid)
return -1038;
if (sbuf.st_uid != boinc_project_uid)
return -1039;
if ((sbuf.st_mode & 07777) != 06551)
return -1040;
strlcpy(full_path, dir_path, sizeof(dir_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_DIR, sizeof(full_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SETPROJECTGRP_FILE_NAME, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1041;
if (sbuf.st_gid != boinc_project_gid)
return -1042;
if (sbuf.st_uid != boinc_master_uid)
return -1043;
if ((sbuf.st_mode & 07777) != 02500)
return -1044;
} // if (use_sandbox)
if (sbuf.st_gid != boinc_project_gid)
return -1038;
if (sbuf.st_uid != boinc_project_uid)
return -1039;
if ((sbuf.st_mode & 07777) != 06551)
return -1040;
strlcpy(full_path, dir_path, sizeof(dir_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SWITCHER_DIR, sizeof(full_path));
strlcat(full_path, "/", sizeof(full_path));
strlcat(full_path, SETPROJECTGRP_FILE_NAME, sizeof(full_path));
retval = stat(full_path, &sbuf);
if (retval)
return -1041;
if (sbuf.st_gid != boinc_project_gid)
return -1042;
if (sbuf.st_uid != boinc_master_uid)
return -1043;
if ((sbuf.st_mode & 07777) != 02500)
return -1044;
return 0;
}
static int CheckNestedDirectories(char * basepath, int depth) {
static int CheckNestedDirectories(char * basepath, int depth, int use_sandbox) {
int isDirectory;
char full_path[MAXPATHLEN];
struct stat sbuf;
@ -383,11 +421,6 @@ static int CheckNestedDirectories(char * basepath, int depth) {
isDirectory = S_ISDIR(sbuf.st_mode);
if (sbuf.st_gid != boinc_project_gid) {
retval = -1201;
break;
}
if (depth > 1) {
// files and subdirectories created by projects may have owner boinc_master or boinc_project
if ( (sbuf.st_uid != boinc_master_uid) && (sbuf.st_uid != boinc_project_uid) ) {
@ -395,7 +428,7 @@ static int CheckNestedDirectories(char * basepath, int depth) {
break;
}
} else {
// project & slot directories (projets/setiathome.berkeley.edu, slots/0 etc.)
// project & slot directories (projects/setiathome.berkeley.edu, slots/0 etc.)
// must have owner boinc_master
if (sbuf.st_uid != boinc_master_uid) {
retval = -1202;
@ -403,38 +436,45 @@ static int CheckNestedDirectories(char * basepath, int depth) {
}
}
if (isDirectory) {
if (depth == 1) {
// project & slot directories (projets/setiathome.berkeley.edu, slots/0 etc.)
// must be readable & executable by other
if ((sbuf.st_mode & 0777) != 0775) {
retval = -1203;
if (use_sandbox) {
if (sbuf.st_gid != boinc_project_gid) {
retval = -1201;
break;
}
#if 0 // We may enforce permissions later for subdirectories written by project applications
} else {
// subdirectories created by projects may be executable by other or not
if ((sbuf.st_mode & 0770) != 0770) {
retval = -1203;
if (isDirectory) {
if (depth == 1) {
// project & slot directories (projects/setiathome.berkeley.edu, slots/0 etc.)
// must be readable & executable by other
if ((sbuf.st_mode & 0777) != 0775) {
retval = -1203;
break;
}
#if 0 // We may enforce permissions later for subdirectories written by project applications
} else {
// subdirectories created by projects may be executable by other or not
if ((sbuf.st_mode & 0770) != 0770) {
retval = -1203;
break;
}
#endif
}
#if 0 // We may enforce permissions later for files written by project applications
} else { // ! isDirectory
if ((sbuf.st_mode & 0666) != 0660) {
retval = -1204;
break;
}
#endif
}
#if 0 // We may enforce permissions later for files written by project applications
} else { // ! isDirectory
if ((sbuf.st_mode & 0666) != 0660) {
retval = -1204;
break;
}
#endif
}
} // if (use_sandbox)
if (isDirectory) {
if (depth > 1)
if (use_sandbox && (depth > 1))
if ((sbuf.st_uid != boinc_master_uid) && (sbuf.st_gid != boinc_master_gid))
continue; // We can't check subdirectories owned by boinc_project
retval = CheckNestedDirectories(full_path, depth + 1);
retval = CheckNestedDirectories(full_path, depth + 1, use_sandbox);
if (retval)
break;
}
@ -445,3 +485,37 @@ static int CheckNestedDirectories(char * basepath, int depth) {
return retval;
}
#if (! defined(__WXMAC__) && ! defined(_MAC_INSTALLER))
static void GetPathToThisProcess(char* outbuf, size_t maxLen) {
FILE *f;
char buf[256], *p, *q;
pid_t aPID = getpid();
*outbuf = '\0';
sprintf(buf, "ps -xwo command -p %d", (int)aPID);
f = popen(buf, "r");
if (f == NULL)
return;
fgets (outbuf, maxLen, f); // Discard header line
fgets (outbuf, maxLen, f);
pclose(f);
// Strip off any arguments
p = strstr(outbuf, " -");
q = p;
if (p) {
while (*p == ' ') {
q = p;
if (--p < outbuf)
break;
}
}
if (q)
*q = '\0';
}
#endif

View File

@ -106,6 +106,11 @@ CLIENT_STATE::CLIENT_STATE() {
have_tentative_project = false;
new_version_check_time = 0;
detach_console = false;
#ifdef SANDBOX
g_use_sandbox = true; // User can override with -insecure command-line arg
#else
g_use_sandbox = false;
#endif
}
void CLIENT_STATE::show_host_info() {
@ -309,16 +314,16 @@ int CLIENT_STATE::init() {
}
#ifndef _WIN32
#ifdef SANDBOX
if (g_use_sandbox) {
#ifdef _DEBUG
boinc_project_gid = getegid();
boinc_project_gid = getegid();
#else
retval = lookup_group(BOINC_PROJECT_GROUP_NAME, boinc_project_gid);
if (retval) return retval;
retval = lookup_group(BOINC_PROJECT_GROUP_NAME, boinc_project_gid);
if (retval) return retval;
#endif // _DEBUG
#else
boinc_project_gid = 0;
#endif
} else {
boinc_project_gid = 0;
}
#endif
check_file_existence();

View File

@ -613,37 +613,37 @@ int FILE_INFO::set_permissions() {
// give read/exec permissions for user, group and others
// in case someone runs BOINC from different user
#ifdef SANDBOX
retval = set_to_project_group(pathname);
if (retval) return retval;
if (executable) {
retval = chmod(pathname,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
if (g_use_sandbox) {
retval = set_to_project_group(pathname);
if (retval) return retval;
if (executable) {
retval = chmod(pathname,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
} else {
retval = chmod(pathname,
S_IRUSR|S_IWUSR
|S_IRGRP|S_IWGRP
|S_IROTH
);
}
} else {
retval = chmod(pathname,
S_IRUSR|S_IWUSR
|S_IRGRP|S_IWGRP
|S_IROTH
);
if (executable) {
retval = chmod(pathname,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
} else {
retval = chmod(pathname,
S_IRUSR|S_IWUSR
|S_IRGRP
|S_IROTH
);
}
}
#else
if (executable) {
retval = chmod(pathname,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
} else {
retval = chmod(pathname,
S_IRUSR|S_IWUSR
|S_IRGRP
|S_IROTH
);
}
#endif
return retval;
#endif
}

View File

@ -53,6 +53,7 @@ static void print_options(char* prog) {
" -dir <path> use given dir as BOINC home\n"
" -no_gui_rpc don't allow GUI RPC, don't make socket\n"
" -daemon run as daemon (Unix)\n"
" -insecure disable BOINC security users and permissions (Unix, Linux)\n"
,
prog
);
@ -174,6 +175,8 @@ void CLIENT_STATE::parse_cmdline(int argc, char** argv) {
}
} else if (ARG(no_gui_rpc)) {
no_gui_rpc = true;
} else if (ARG(insecure)) {
g_use_sandbox = false;
} else {
printf("Unknown option: %s\n", argv[i]);
show_options = true;

View File

@ -95,23 +95,23 @@ int make_project_dir(PROJECT& p) {
int retval;
boinc_mkdir(PROJECTS_DIR);
#ifdef SANDBOX
chmod(PROJECTS_DIR,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
#endif
if (g_use_sandbox) {
chmod(PROJECTS_DIR,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
}
get_project_dir(&p, buf);
retval = boinc_mkdir(buf);
#ifdef SANDBOX
chmod(buf,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
set_to_project_group(buf);
#endif
if (g_use_sandbox) {
chmod(buf,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
set_to_project_group(buf);
}
return retval;
}
@ -137,23 +137,23 @@ int make_slot_dir(int slot) {
return ERR_NEG;
}
boinc_mkdir(SLOTS_DIR);
#ifdef SANDBOX
chmod(SLOTS_DIR,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
#endif
if (g_use_sandbox) {
chmod(SLOTS_DIR,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
}
get_slot_dir(slot, buf);
int retval = boinc_mkdir(buf);
#ifdef SANDBOX
chmod(buf,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
set_to_project_group(buf);
#endif
if (g_use_sandbox) {
chmod(buf,
S_IRUSR|S_IWUSR|S_IXUSR
|S_IRGRP|S_IWGRP|S_IXGRP
|S_IROTH|S_IXOTH
);
set_to_project_group(buf);
}
return retval;
}
@ -261,17 +261,14 @@ bool is_image_file(const char* filename) {
}
int set_to_project_group(const char* path) {
#ifdef SANDBOX
char buf[1024];
sprintf(buf, "%s/%s %s", SWITCHER_DIR, SETPROJECTGRP_FILE_NAME, path);
if (system(buf))
return ERR_CHOWN;
return 0;
#else
return ERR_CHOWN;
#endif
if (g_use_sandbox) {
sprintf(buf, "%s/%s %s", SWITCHER_DIR, SETPROJECTGRP_FILE_NAME, path);
if (system(buf))
return ERR_CHOWN;
}
return 0;
}
const char *BOINC_RCSID_7d362a6a52 = "$Id$";

View File

@ -104,12 +104,12 @@ int GUI_RPC_CONN_SET::get_password() {
// they can cause code to execute as this user.
// So better protect it.
//
#ifdef SANDBOX
// Allow group access so authorized administrator can modify it
chmod(GUI_RPC_PASSWD_FILE, S_IRUSR|S_IWUSR | S_IRGRP | S_IWGRP);
#else
chmod(GUI_RPC_PASSWD_FILE, S_IRUSR|S_IWUSR);
#endif
if (g_use_sandbox) {
// Allow group access so authorized administrator can modify it
chmod(GUI_RPC_PASSWD_FILE, S_IRUSR|S_IWUSR | S_IRGRP | S_IWGRP);
} else {
chmod(GUI_RPC_PASSWD_FILE, S_IRUSR|S_IWUSR);
}
#endif
}
}

View File

@ -78,6 +78,12 @@ typedef void (CALLBACK* ClientLibraryShutdown)();
int finalize();
// Ideally, we would access this using wxGetApp().m_use_sandbox in the Manager
// and gstate.m_use_sandbox in the Client, but it is used by some source files
// (filesys.C, check_security.C) that are linked with both Manager and Client
// so the most practical solution is to use a global.
int g_use_sandbox;
static bool boinc_cleanup_completed = false;
// Used on Windows 95/98/ME to determine when it is safe to leave
// the WM_ENDSESSION message handler and allow Windows to finish
@ -335,15 +341,17 @@ static void init_core_client(int argc, char** argv) {
}
#else
#ifdef SANDBOX
umask (2); // Set file creation mask to be writable by both user and group
// Our umask will be inherited by all our child processes
#endif
#endif
read_config_file();
gstate.parse_cmdline(argc, argv);
#ifndef _WIN32
if (g_use_sandbox)
umask (2); // Set file creation mask to be writable by both user and group
// Our umask will be inherited by all our child processes
#endif
// Initialize the BOINC Diagnostics Framework
int dwDiagnosticsFlags =
BOINC_DIAG_DUMPCALLSTACKENABLED |
@ -752,13 +760,14 @@ int main(int argc, char** argv) {
#else
#ifdef SANDBOX
// Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox
#if defined(_DEBUG) && defined(__APPLE__)
// GDB can't attach to applications which are running as a diferent user
// or group, so fix up data with current user and group during debugging
if (check_security())
// GDB can't attach to applications which are running as a diferent user
// or group, so fix up data with current user and group during debugging
if (check_security(g_use_sandbox, false))
SetBOINCDataOwnersGroupsAndPermissions();
#endif // _DEBUG && __APPLE__
int i = check_security();
int i = check_security(g_use_sandbox, false);
if (i) {
printf( "\nBOINC ownership or permissions are not set properly; please reinstall BOINC. (Error code %d)\n", i);
return ERR_USER_PERMISSION;

View File

@ -87,6 +87,13 @@ EXTERN_C DWORD BOINCGetIdleTickCount();
IMPLEMENT_APP(CBOINCGUIApp)
IMPLEMENT_DYNAMIC_CLASS(CBOINCGUIApp, wxApp)
// Ideally, we would access this using wxGetApp().m_use_sandbox in the Manager
// and gstate.m_use_sandbox in the Client, but it is used by some source files
// (filesys.C, check_security.C) that are linked with both Manager and Client
// so the most practical solution is to use a global.
int g_use_sandbox;
bool CBrandingScheme::OnInit( wxConfigBase *pConfig ) {
wxString strBaseConfigLocation = wxEmptyString;
@ -260,9 +267,19 @@ bool CBOINCGUIApp::OnInit() {
int errCode = 0;
#endif
#if (defined(SANDBOX) && !defined(_WIN32))
umask (2); // Set file creation mask to be writable by both user and group
// Our umask will be inherited by all our child processes
#ifdef SANDBOX
g_use_sandbox = true;
// Commandline parsing is done in wxApp::OnInit()
if (!wxApp::OnInit()) { // Command line arg -insecure sets g_use_sandbox to false
return false;
}
#ifndef _WIN32
if (g_use_sandbox)
umask (2); // Set file creation mask to be writable by both user and group
// Our umask will be inherited by all our child processes
#endif
#else
g_use_sandbox = false;
#endif
// Setup variables with default values
@ -341,10 +358,10 @@ bool CBOINCGUIApp::OnInit() {
if (success) {
// If SetWD failed, don't create a directory in wrong place
strDirectory += wxT("BOINC Data"); // We don't customize BOINC Data directory name for branding
#ifndef SANDBOX
if (! wxDirExists(strDirectory))
success = wxMkdir(strDirectory, 0777); // Does nothing if dir exists
#endif // ! SANDBOX
if (! g_use_sandbox) {
if (! wxDirExists(strDirectory))
success = wxMkdir(strDirectory, 0777); // Does nothing if dir exists
}
success = ::wxSetWorkingDirectory(strDirectory);
// wxChar *wd = wxGetWorkingDirectory(buf, 1000); // For debugging
}
@ -354,17 +371,18 @@ bool CBOINCGUIApp::OnInit() {
#endif // __WXMAC__
#ifdef SANDBOX
// Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox
if (!errCode) {
#if (defined(__WXMAC__) && defined(_DEBUG)) // TODO: implement this for other platforms
// GDB can't attach to applications which are running as a different user
// or group, so fix up data with current user and group during debugging
if (check_security()) {
if (check_security(g_use_sandbox, true)) {
CreateBOINCUsersAndGroups();
SetBOINCDataOwnersGroupsAndPermissions();
SetBOINCAppOwnersGroupsAndPermissions(NULL);
}
#endif // __WXMAC__ && _DEBUG
errCode = check_security();
errCode = check_security(g_use_sandbox, true);
}
if (errCode) {
@ -424,10 +442,12 @@ bool CBOINCGUIApp::OnInit() {
// help if you use this help provider:
wxHelpProvider::Set(new wxHelpControllerHelpProvider());
#ifndef SANDBOX
// Commandline parsing is done in wxApp::OnInit()
if (!wxApp::OnInit()) {
return false;
}
#endif
// Initialize the main document
m_pDocument = new CMainDocument();
@ -543,6 +563,9 @@ void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) {
wxApp::OnInitCmdLine(parser);
static const wxCmdLineEntryDesc cmdLineDesc[] = {
{ wxCMD_LINE_SWITCH, wxT("s"), wxT("systray"), _("Startup BOINC so only the system tray icon is visible")},
#if (defined(SANDBOX) && ! defined(_WIN32))
{ wxCMD_LINE_SWITCH, wxT("insecure"), wxT("insecure"), _("disable BOINC security users and permissions")},
#endif
{ wxCMD_LINE_NONE} //DON'T forget this line!!
};
parser.SetDesc(cmdLineDesc);
@ -555,6 +578,9 @@ bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) {
if (parser.Found(wxT("systray"))) {
m_bGUIVisible = false;
}
if (parser.Found(wxT("insecure"))) {
g_use_sandbox = false;
}
return true;
}
@ -686,7 +712,7 @@ void CBOINCGUIApp::StartupBOINCCore() {
{
wxChar buf[1024];
wxChar *argv[3];
wxChar *argv[4];
ProcessSerialNumber ourPSN;
FSRef ourFSRef;
OSErr err;
@ -710,6 +736,12 @@ void CBOINCGUIApp::StartupBOINCCore() {
argv[0] = buf;
argv[1] = "-redirectio";
argv[2] = NULL;
#ifdef SANDBOX
if (! g_use_sandbox) {
argv[2] = "-insecure";
argv[3] = NULL;
}
#endif
m_lBOINCCoreProcessId = ::wxExecute(argv);
#endif
} else {
@ -772,6 +804,8 @@ void CBOINCGUIApp::StartupBOINCCore() {
// Append boinc.exe to the end of the strExecute string and get ready to rock
strExecute = wxT("./boinc -redirectio");
if (! g_use_sandbox)
strExecute += wxT(" -insecure");
m_lBOINCCoreProcessId = ::wxExecute(strExecute);
#endif // ! __WXMAC__

View File

@ -37,7 +37,6 @@
#define BOINC_ADVANCEDGUI 1
#define BOINC_SIMPLEGUI 2
class CBrandingScheme : public wxObject {
private:
bool m_bIsBranded;

View File

@ -21,16 +21,17 @@
#pragma implementation "MainDocument.h"
#endif
#ifdef SANDBOX
#include <grp.h>
#endif
#include "stdwx.h"
#include "BOINCGUIApp.h"
#include "BOINCBaseFrame.h"
#include "MainDocument.h"
#include "error_numbers.h"
#ifdef SANDBOX
#include <grp.h>
#include "util.h" // For g_use_sandbox
#endif
using std::string;
CNetworkConnection::CNetworkConnection(CMainDocument* pDocument) :
@ -594,43 +595,47 @@ int CMainDocument::CoreClientQuit() {
bool CMainDocument::IsUserAuthorized() {
#ifdef SANDBOX
#ifdef _WIN32
return true;
#else // ! _WIN32
group *grp;
gid_t rgid, boinc_master_gid;
char *userName, *groupMember;
int i;
static bool sIsAuthorized = false;
if (sIsAuthorized)
return true; // We already checked and OK'd current user
grp = getgrnam(BOINC_MASTER_GROUP_NAME);
if (grp) {
boinc_master_gid = grp->gr_gid;
#ifdef SANDBOX
group *grp;
gid_t rgid, boinc_master_gid;
char *userName, *groupMember;
int i;
rgid = getgid();
if (rgid == boinc_master_gid) {
sIsAuthorized = true; // User's primary group is boinc_master
return true;
}
if (g_use_sandbox) {
grp = getgrnam(BOINC_MASTER_GROUP_NAME);
if (grp) {
boinc_master_gid = grp->gr_gid;
userName = getlogin();
if (userName) {
for (i=0; ; i++) { // Step through all users in group boinc_master
groupMember = grp->gr_mem[i];
if (groupMember == NULL)
break; // User is not a member of group boinc_master
if (strcmp(userName, groupMember) == 0) {
sIsAuthorized = true; // User is a member of group boinc_master
return true;
}
} // for (i)
} // if (userName)
} // if grp
rgid = getgid();
if (rgid == boinc_master_gid) {
sIsAuthorized = true; // User's primary group is boinc_master
return true;
}
userName = getlogin();
if (userName) {
for (i=0; ; i++) { // Step through all users in group boinc_master
groupMember = grp->gr_mem[i];
if (groupMember == NULL)
break; // User is not a member of group boinc_master
if (strcmp(userName, groupMember) == 0) {
sIsAuthorized = true; // User is a member of group boinc_master
return true;
}
} // for (i)
} // if (userName)
} // if grp
}
#endif // SANDBOX
#endif // ! _WIN32
#ifdef __WXMAC__
@ -640,17 +645,11 @@ bool CMainDocument::IsUserAuthorized() {
}
#endif // __WXMAC__
#ifdef SANDBOX
return false;
#else // ! SANDBOX
#ifdef __WXMAC__
return Mac_Authorize(); // Run Mac Authentication dialog
#else // ! __WXMAC__
#else
return true;
#endif // ! __WXMAC__
#endif // ! SANDBOX
#endif
}

View File

@ -23,6 +23,7 @@
#include <Security/AuthorizationTags.h>
#include <unistd.h>
#include "util.h" // For g_use_sandbox
// Determine if the currently logged-in user is auhorized to
@ -45,18 +46,18 @@ Boolean Mac_Authorize()
if (sIsAuthorized)
return true;
#ifndef SANDBOX
uid_t effectiveUserID, realUserID;
effectiveUserID = geteuid();
realUserID = getuid();
if (effectiveUserID == realUserID)
{
// Logged in user is also the owner
sIsAuthorized = true;
return true;
if (g_use_sandbox) {
effectiveUserID = geteuid();
realUserID = getuid();
if (effectiveUserID == realUserID)
{
// Logged in user is also the owner
sIsAuthorized = true;
return true;
}
}
#endif
// User is not the owner, so require admin authorization
ourAuthItem[0].name = kAuthorizationRightExecute;

View File

@ -147,6 +147,8 @@ const char * BOINCUnrecoverableErrorMsg = "Sorry, an unrecoverable error occurr
const char * BOINCTestmodeMg = "This BOINC screensaver does not support Test mode";
//const char * BOINCExitedSaverMode = "BOINC is no longer in screensaver mode.";
int g_use_sandbox = 0;
// Returns desired Animation Frequency (per second) or 0 for no change
int initBOINCSaver(Boolean ispreview) {

View File

@ -43,6 +43,9 @@ using std::string;
#include "util.h"
#include "version.h"
int g_use_sandbox = 0;
void usage() {
fprintf(stderr, "\
Usage: boinc_cmd [--host hostname] [--passwd passwd] command\n\

View File

@ -258,13 +258,10 @@ int boinc_delete_file(const char* path) {
}
#else
retval = unlink(path);
#ifdef SANDBOX
if (retval)
// We may not have permission to read subdirectories created by projects
if (errno == EACCES) {
return remove_project_owned_file_or_dir(path);
}
#endif
if (retval && g_use_sandbox && (errno == EACCES)) {
// We may not have permission to read subdirectories created by projects
return remove_project_owned_file_or_dir(path);
}
return retval;
#endif
if (retval) {
@ -313,14 +310,14 @@ int clean_out_dir(const char* dirpath) {
DIRREF dirp;
dirp = dir_open(dirpath);
if (!dirp)
#ifdef SANDBOX
// We may not have permission to read subdirectories created by projects
if (errno == EACCES) {
return remove_project_owned_file_or_dir(dirpath);
} else
#endif
if (!dirp) {
if (g_use_sandbox && (errno == EACCES)) {
// We may not have permission to read subdirectories created by projects
return remove_project_owned_file_or_dir(dirpath);
}
return 0; // if dir doesn't exist, it's empty
}
while (1) {
strcpy(filename, "");
retval = dir_scan(filename, dirp, sizeof(filename));
@ -488,13 +485,9 @@ int boinc_rmdir(const char* name) {
#else
int retval;
retval = rmdir(name);
#ifdef SANDBOX
if (retval)
// We may not have permission to read subdirectories created by projects
if (errno == EACCES) {
return remove_project_owned_file_or_dir(name);
}
#endif
if (retval && g_use_sandbox && (errno == EACCES))
retval = remove_project_owned_file_or_dir(name);
return retval;
#endif
}
@ -502,12 +495,13 @@ int boinc_rmdir(const char* name) {
int remove_project_owned_file_or_dir(const char* path) {
#ifdef SANDBOX
char cmd[1024];
sprintf(cmd, "%s/%s /bin/rm rm -fR \"%s\"", SWITCHER_DIR, SWITCHER_FILE_NAME, path);
return system(cmd);
#else
return ERR_UNLINK;
if (g_use_sandbox) {
sprintf(cmd, "%s/%s /bin/rm rm -fR \"%s\"", SWITCHER_DIR, SWITCHER_FILE_NAME, path);
return system(cmd);
}
#endif
return ERR_UNLINK;
}
#ifndef _WIN32

View File

@ -34,6 +34,14 @@
#endif
// Ideally, we would access this using wxGetApp().m_use_sandbox in the Manager
// and gstate.m_use_sandbox in the Client, but it is used by some source files
// (filesys.C, check_security.C) that are linked with both Manager and Client
// so the most practical solution is to use a global.
extern int g_use_sandbox;
#if !defined(HAVE_STRLCPY)
extern size_t strlcpy(char*, const char*, size_t);
#endif
@ -143,7 +151,7 @@ extern pthread_mutex_t getrusage_mutex;
#ifndef _WIN32
extern int lookup_group(char*, gid_t& gid);
extern int check_security(void);
extern int check_security(int use_sandbox, int isManager);
#endif
#endif

View File

@ -65,7 +65,7 @@ then
exit
fi
if [ ! -f "boinc" ]
if [ ! -x "boinc" ]
then
echo "Can't find boinc Client in directory $(pwd); exiting"
exit
@ -74,4 +74,15 @@ fi
chown -R ${user}:${group} .
chmod -R u+rw-s,g+r-w-s,o+r-w .
chmod 600 gui_rpc_auth.cfg
if [ -x /Applications/BOINCManager.app/Contents/MacOS/BOINCManager ] ; then
chown ${user}:${group} /Applications/BOINCManager.app/Contents/MacOS/BOINCManager
chmod -R u+r-w+s,g+r-ws,o+r-ws /Applications/BOINCManager.app/Contents/MacOS/BOINCManager
fi
if [ -x /Applications/BOINCManager.app/Contents/Resources/boinc ] ; then
chown ${user}:${group} /Applications/BOINCManager.app/Contents/Resources/boinc
chmod -R u+r-ws,g+r-ws,o+r-ws /Applications/BOINCManager.app/Contents/Resources/boinc
fi
remove_boinc_users

View File

@ -189,3 +189,14 @@ set_perm switcher boinc_master boinc_master 0550
set_perm_recursive locale boinc_master boinc_master u+r-w,g+r-w,o-rwx
set_perm boinc boinc_master boinc_master 6555 # boinc client
if [ -x /Applications/BOINCManager.app/Contents/MacOS/BOINCManager ] ; then
set_perm /Applications/BOINCManager.app/Contents/MacOS/BOINCManager boinc_master boinc_master 2555
fi
if [ -x /Applications/BOINCManager.app/Contents/Resources/boinc ] ; then
set_perm /Applications/BOINCManager.app/Contents/Resources/boinc boinc_master boinc_master 6555
fi

View File

@ -56,7 +56,7 @@ static OSErr QuitAppleEventHandler(const AppleEvent *appleEvt, AppleEvent* reply
void print_to_log_file(const char *format, ...);
void strip_cr(char *buf);
extern int check_security(char *bundlePath, char *dataPath);
extern int check_security(char *bundlePath, char *dataPath, int use_sandbox, int isManager);
static Boolean gQuitFlag = false; /* global */
@ -173,7 +173,7 @@ int main(int argc, char *argv[])
continue;
}
err = check_security(p, "/Library/Application Support/BOINC Data");
err = check_security(p, "/Library/Application Support/BOINC Data", true, false);
if (err == noErr)
break;
// print_to_log_file("check_security returned %d (repetition=%d)", err, i);