From e05a8ed1871000a22d588c56453bc07b363fa7a3 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Wed, 14 Jun 2006 10:45:42 +0000 Subject: [PATCH] *** empty log message *** svn path=/trunk/boinc/; revision=10340 --- checkin_notes | 32 ++++-- client/check_security.C | 131 ++++++++++++++++++++++ clientgui/BOINCGUIApp.cpp | 10 ++ clientgui/mac/SetupSecurity.cpp | 69 ++++++++---- clientgui/mac/SetupSecurity.h | 1 + lib/util.h | 1 + mac_build/boinc.xcodeproj/project.pbxproj | 6 + 7 files changed, 215 insertions(+), 35 deletions(-) create mode 100644 client/check_security.C diff --git a/checkin_notes b/checkin_notes index 8d5a7c5464..3e35b89aed 100755 --- a/checkin_notes +++ b/checkin_notes @@ -5934,18 +5934,6 @@ Rom 14 June 2006 lib/ diagnostics.C, .h -Charlie 14 June 2006 - - more sandbox stuff, with #ifdef SANDBOX: - Change projects, slots directories to boinc_master:boinc_master 0775. - Mac: I Manager creates BOINC Data directory set its permissions to 0575. - - client/ - file_names.C - clientgui/ - BOINCGUIApp.cpp - mac/ - SetupSecurity.cpp,h - Rom 14 June 2006 - Reduce duplicate code in diagnostics.C. - Display the detected CPU capabilities for those who want to @@ -5956,3 +5944,23 @@ Rom 14 June 2006 lib/ diagnostics.C, .h +Charlie 14 June 2006 + - more sandbox stuff, with #ifdef SANDBOX: + Change projects, slots directories to boinc_master:boinc_master 0775. + Mac: I Manager creates BOINC Data directory set its permissions to 0575. + Manager checks ownership and permissions; if incorrect it alerts user + and quits. + + client/ + check_security.C (new) + file_names.C + clientgui/ + BOINCGUIApp.cpp + mac/ + SetupSecurity.cpp,h + lib/ + util.h + mac_build/ + boinc.xcodeproj/ + project.pbxproj + diff --git a/client/check_security.C b/client/check_security.C new file mode 100644 index 0000000000..6603c61fbd --- /dev/null +++ b/client/check_security.C @@ -0,0 +1,131 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2006 University of California +// +// This 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 2.1 of the License, or (at your option) any later version. +// +// This software 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. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// check_security.C + + +#include +#include +#include +#include // getpwnam +#include +#include // for MAXPATHLEN +#include "util.h" +#include "error_numbers.h" + +#define boinc_master_name "boinc_master" +#define boinc_project_name "boinc_project" + + +// Returns FALSE (0) if owners and permissions are OK, else TRUE (1) +int check_security(int isManager) { + passwd *pw; + gid_t egid, rgid, boinc_master_gid, boinc_project_gid; + uid_t euid, ruid, boinc_master_uid, boinc_project_uid; + char *p; + group *grp; + int i; + char dir_path[MAXPATHLEN]; + struct stat sbuf; + int retval; + + pw = getpwnam(boinc_master_name); + if (pw == NULL) + return ERR_USER_REJECTED; // User boinc_master does not exist + boinc_master_uid = pw->pw_uid; + + pw = getpwnam(boinc_project_name); + if (pw == NULL) + return ERR_USER_REJECTED; // User boinc_project does not exist + boinc_project_uid = pw->pw_uid; + + grp = getgrnam(boinc_master_name); + if (grp == NULL) + return ERR_GETGRNAM; // Group boinc_master does not exist + boinc_master_gid = grp->gr_gid; + + grp = getgrnam(boinc_project_name); + if (grp == NULL) + return ERR_GETGRNAM; // Group boinc_project does not exist + boinc_project_gid = grp->gr_gid; + + for (i=0; ; i++) { // Step through all users in group boinc_project + p = grp->gr_mem[i]; + if (p == NULL) + return ERR_GETGRNAM; // User boinc_master is not a member of group boinc_project + if (strcmp(p, boinc_master_name) == 0) + break; + } + + rgid = getgid(); + egid = getegid(); + if (egid != boinc_master_gid) + return ERR_USER_PERMISSION; // We should be running setgid boinc_master + + ruid = getuid(); + euid = geteuid(); + if (! isManager) { + if (euid != boinc_master_uid) + return ERR_USER_PERMISSION; // BOINC Client should be running setuid boinc_master + } + + getcwd(dir_path, sizeof(dir_path)); + retval = stat(dir_path, &sbuf); + if (retval) + return retval; + + // 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 ERR_USER_PERMISSION; + + // The top-level BOINC Data directory should have permission 775 or 575 + if ((sbuf.st_mode & 0575) != 0575) + return ERR_USER_PERMISSION; + + getcwd(dir_path, sizeof(dir_path)); + strlcat(dir_path, "/projects", MAXPATHLEN); + retval = stat(dir_path, &sbuf); + if (! retval) { // Client can create projects directory if it does not yet exist. + if (sbuf.st_gid != boinc_master_gid) + return ERR_USER_PERMISSION; + + if (sbuf.st_uid != boinc_master_uid) + return ERR_USER_PERMISSION; + + if ((sbuf.st_mode & 0775) != 0775) + return ERR_USER_PERMISSION; + } + + getcwd(dir_path, sizeof(dir_path)); + strlcat(dir_path, "/slots", MAXPATHLEN); + retval = stat(dir_path, &sbuf); + if (! retval) { // Client can create slots directory if it does not yet exist. + if (sbuf.st_gid != boinc_master_gid) + return ERR_USER_PERMISSION; + + if (sbuf.st_uid != boinc_master_uid) + return ERR_USER_PERMISSION; + + if ((sbuf.st_mode & 0775) != 0775) + return ERR_USER_PERMISSION; + } + + return 0; +} diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index bb95a3decf..1d0066bfd3 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -335,6 +335,16 @@ bool CBOINCGUIApp::OnInit() { #endif // __WXMAC__ +#ifdef SANDBOX + if (check_security(true)) { + wxMessageDialog* pDlg = + new wxMessageDialog(m_pFrame, wxT("BOINC ownership or permissions are not set properly; please reinstall BOINC"),wxT(""), wxOK); + pDlg->ShowModal(); + if (pDlg) + pDlg->Destroy(); + return false; + } +#endif // Initialize the BOINC Diagnostics Framework int dwDiagnosticsFlags = diff --git a/clientgui/mac/SetupSecurity.cpp b/clientgui/mac/SetupSecurity.cpp index be3d64cb4f..6ae27274c2 100644 --- a/clientgui/mac/SetupSecurity.cpp +++ b/clientgui/mac/SetupSecurity.cpp @@ -95,7 +95,7 @@ OSStatus SetBOINCAppOwnersGroupsAndPermissions(char *path, char *managerName, Bo // chmod -R u=rwsx,g=rwsx,o=rx path/BOINCManager.app // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH - // read, write and execute permission for user, group & others + // read, write and execute permission for user & group; read and execute permission for others err = DoPrivilegedExec(chmodPath, "-R", "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL); if (err) return err; @@ -192,18 +192,20 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions() { if (err) return err; +#if 0 // Redundant if we already set BOINC Data directory to boinc_master:boinc_master // Set owner and group of BOINC Data directory itself - sprintf(buf1, "%s:%s", boinc_master_name, boinc_project_name); - // chown boinc_master:boinc_project "/Library/Applications/BOINC Data" + sprintf(buf1, "%s:%s", boinc_master_name, boinc_master_name); + // chown boinc_master:boinc_master "/Library/Applications/BOINC Data" err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL); if (err) return err; +#endif // Set permissions of BOINC Data directory itself - // chmod -R u+rwx,g=rx,o-rwx "/Library/Applications/BOINC Data" - // 0750 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP| S_IXGRP - // set read, write, execute permission for user and group, no access for others - err = DoPrivilegedExec(chmodPath, "u+rwx,g=rx,o-rwx", fullpath, NULL, NULL, NULL); + // chmod -R u=rwsx,g=rwsx,o=rx "/Library/Applications/BOINC Data" + // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH + // read, write and execute permission for user & group; read and execute permission for others + err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL); if (err) return err; @@ -238,18 +240,25 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions() { result = FSPathMakeRef((StringPtr)fullpath, &ref, &isDirectory); if ((result == noErr) && (isDirectory)) { - // Set owner and group of projects directory and all its contents + // Set owner and group of projects directory's contents sprintf(buf1, "%s:%s", boinc_master_name, boinc_project_name); // chown boinc_master:boinc_project "/Library/Applications/BOINC Data/projects" err = DoPrivilegedExec(chownPath, "-R", buf1, fullpath, NULL, NULL); if (err) return err; + // Set owner and group of projects directory itself + sprintf(buf1, "%s:%s", boinc_master_name, boinc_master_name); + // chown boinc_master:boinc_master "/Library/Applications/BOINC Data/projects" + err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL); + if (err) + return err; + // Set permissions for projects directory itself (not its contents) - // chmod u=rwx,g=rx,o= "/Library/Applications/BOINC Data/projects" - // 0750 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP| S_IXGRP - // set read, write, execute permission for user, read and execute for group, no access for others - err = DoPrivilegedExec(chmodPath, "u=rwx,g=rx,o=", fullpath, NULL, NULL, NULL); + // chmod -R u=rwsx,g=rwsx,o=rx "/Library/Applications/BOINC Data/projects" + // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH + // read, write and execute permission for user & group; read and execute permission for others + err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL); if (err) return err; } // projects directory @@ -260,18 +269,25 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions() { result = FSPathMakeRef((StringPtr)fullpath, &ref, &isDirectory); if ((result == noErr) && (isDirectory)) { - // Set owner and group of slots directory and all its contents + // Set owner and group of slots directory's contents sprintf(buf1, "%s:%s", boinc_master_name, boinc_project_name); // chown boinc_master:boinc_project "/Library/Applications/BOINC Data/slots" err = DoPrivilegedExec(chownPath, "-R", buf1, fullpath, NULL, NULL); if (err) return err; + // Set owner and group of slots directory itself + sprintf(buf1, "%s:%s", boinc_master_name, boinc_master_name); + // chown boinc_master:boinc_master "/Library/Applications/BOINC Data/slots" + err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL); + if (err) + return err; + // Set permissions for slots directory itself (not its contents) - // chmod u=rwx,g=rx,o= "/Library/Applications/BOINC Data/slots" - // 0750 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP| S_IXGRP - // set read, write, execute permission for user, read and execute for group, no access for others - err = DoPrivilegedExec(chmodPath, "u=rwx,g=rx,o=", fullpath, NULL, NULL, NULL); + // chmod -R u=rwsx,g=rwsx,o=rx "/Library/Applications/BOINC Data/slots" + // 0775 = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH + // read, write and execute permission for user & group; read and execute permission for others + err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL); if (err) return err; } // slots directory @@ -306,17 +322,17 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions() { #if 0 // Redundant if we already set contents of BOINC Data directory to boinc_master:boinc_master 0660 result = FSPathMakeRef((StringPtr)fullpath, &ref, &isDirectory); if ((result == noErr) && (isDirectory)) { - // Set owner and group of switcher directory and its contents + // Set owner and group of switcher directory sprintf(buf1, "%s:%s", boinc_master_name, boinc_master_name); // chown boinc_master:boinc_master "/Library/Applications/BOINC Data/switcher" - err = DoPrivilegedExec(chownPath, "-R", buf1, fullpath, NULL, NULL); + err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL); if (err) return err; - // chmod -R u+rw,g+rw,o= "/Library/Applications/BOINC Data/switcher" + // chmod u+rw,g+rw,o= "/Library/Applications/BOINC Data/switcher" // 0660 = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP // set read and write permission for user and group, no access for others (leaves execute bits unchanged) - err = DoPrivilegedExec(chmodPath, "-R", "u+rw,g+rw,o=", fullpath, NULL, NULL); + err = DoPrivilegedExec(chmodPath, "u+rw,g+rw,o=", fullpath, NULL, NULL, NULL); if (err) return err; } // switcher directory @@ -325,11 +341,18 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions() { strlcat(fullpath, "/switcher", MAXPATHLEN); result = FSPathMakeRef((StringPtr)fullpath, &ref, &isDirectory); if ((result == noErr) && (! isDirectory)) { + // Set owner and group of switcher application + sprintf(buf1, "%s:%s", boinc_project_name, boinc_project_name); + // chown boinc_project:boinc_project "/Library/Applications/BOINC Data/switcher/switcher" + err = DoPrivilegedExec(chownPath, buf1, fullpath, NULL, NULL, NULL); + if (err) + return err; + // Set permissions of switcher application - // chmod -R u=rsx,g=rsx,o= "/Library/Applications/BOINC Data/switcher" + // chmod u=rsx,g=rsx,o= "/Library/Applications/BOINC Data/switcher/switcher" // 06550 = S_ISUID | S_ISGID | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP // setuid-on-execution, setgid-on-execution plus read and execute permission for user and group, no access for others - err = DoPrivilegedExec(chmodPath, "-R", "u=rsx,g=rsx,o=", fullpath, NULL, NULL); + err = DoPrivilegedExec(chmodPath, "u=rsx,g=rsx,o=", fullpath, NULL, NULL, NULL); if (err) return err; } // switcher application diff --git a/clientgui/mac/SetupSecurity.h b/clientgui/mac/SetupSecurity.h index b05324112f..6849702eaf 100644 --- a/clientgui/mac/SetupSecurity.h +++ b/clientgui/mac/SetupSecurity.h @@ -26,3 +26,4 @@ OSStatus SetBOINCDataOwnersGroupsAndPermissions(void); OSStatus AddAdminUserToGroups(char *user_name); void ShowSecurityError(const char *format, ...); +int CheckSecurity(int isManager); diff --git a/lib/util.h b/lib/util.h index 5d307b4668..c691ba8819 100755 --- a/lib/util.h +++ b/lib/util.h @@ -132,6 +132,7 @@ extern const char* boincerror(int which_error); #ifndef _WIN32 extern int lookup_group(char*, gid_t& gid); +extern int check_security(int isManager); #endif #endif diff --git a/mac_build/boinc.xcodeproj/project.pbxproj b/mac_build/boinc.xcodeproj/project.pbxproj index 5788724ef4..67b8f32bb8 100755 --- a/mac_build/boinc.xcodeproj/project.pbxproj +++ b/mac_build/boinc.xcodeproj/project.pbxproj @@ -159,6 +159,8 @@ DD64DF0509DCC5E000668B3A /* gutil_text.C in Sources */ = {isa = PBXBuildFile; fileRef = DD64DF0409DCC5E000668B3A /* gutil_text.C */; }; DD65020A09F599B9008E8A3A /* texfont.c in Sources */ = {isa = PBXBuildFile; fileRef = DD65020609F599B9008E8A3A /* texfont.c */; }; DD65020B09F599B9008E8A3A /* txf_util.C in Sources */ = {isa = PBXBuildFile; fileRef = DD65020809F599B9008E8A3A /* txf_util.C */; }; + DD6617880A3FFD8C00FFEBEB /* check_security.C in Sources */ = {isa = PBXBuildFile; fileRef = DD6617870A3FFD8C00FFEBEB /* check_security.C */; }; + DD6617890A3FFD8C00FFEBEB /* check_security.C in Sources */ = {isa = PBXBuildFile; fileRef = DD6617870A3FFD8C00FFEBEB /* check_security.C */; }; DD69FEF508416C6B00C01361 /* gui_rpc_client.C in Sources */ = {isa = PBXBuildFile; fileRef = DD81C5CC07C5D7D90098A04D /* gui_rpc_client.C */; }; DD69FEF708416C9A00C01361 /* boinc_cmd.C in Sources */ = {isa = PBXBuildFile; fileRef = DD69FEF608416C9A00C01361 /* boinc_cmd.C */; }; DD69FF0C084171CF00C01361 /* network.C in Sources */ = {isa = PBXBuildFile; fileRef = DD6D0A8507E9A61B007F882B /* network.C */; }; @@ -884,6 +886,7 @@ DD65020709F599B9008E8A3A /* texfont.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = texfont.h; path = ../api/texfont.h; sourceTree = SOURCE_ROOT; }; DD65020809F599B9008E8A3A /* txf_util.C */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = txf_util.C; path = ../api/txf_util.C; sourceTree = SOURCE_ROOT; }; DD65020909F599B9008E8A3A /* txf_util.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = txf_util.h; path = ../api/txf_util.h; sourceTree = SOURCE_ROOT; }; + DD6617870A3FFD8C00FFEBEB /* check_security.C */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = check_security.C; sourceTree = ""; }; DD69FEE808416C1300C01361 /* boinc_cmd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = boinc_cmd; sourceTree = BUILT_PRODUCTS_DIR; }; DD69FEF608416C9A00C01361 /* boinc_cmd.C */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = boinc_cmd.C; path = ../lib/boinc_cmd.C; sourceTree = SOURCE_ROOT; }; DD6D0A8507E9A61B007F882B /* network.C */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = network.C; path = ../lib/network.C; sourceTree = SOURCE_ROOT; }; @@ -1456,6 +1459,7 @@ F519F98E02C44A7501BDB3CA /* scheduler_op.h */, AA8B6B23046C366200A80164 /* ss_logic.C */, AA8B6B24046C366200A80164 /* ss_logic.h */, + DD6617870A3FFD8C00FFEBEB /* check_security.C */, F54B8FE402AC0A0C01FB7237 /* time_stats.C */, F54B8FE502AC0A0C01FB7237 /* time_stats.h */, DD5EF08807C5B7C7007CCE8D /* version.h */, @@ -2474,6 +2478,7 @@ DD58C47408F334EA00C1DF66 /* WizardAttachProject.cpp in Sources */, DD58C47608F334EA00C1DF66 /* wizardex.cpp in Sources */, DD8DD4A709D9432F0043019E /* BOINCDialupManager.cpp in Sources */, + DD6617890A3FFD8C00FFEBEB /* check_security.C in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2684,6 +2689,7 @@ DDD74DD207CF493C0065AC9D /* proxy_info.C in Sources */, DDD74DD307CF493D0065AC9D /* shmem.C in Sources */, DDD74DD407CF493E0065AC9D /* util.C in Sources */, + DD6617880A3FFD8C00FFEBEB /* check_security.C in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };