diff --git a/checkin_notes b/checkin_notes index 8c8764e29e..5a6250c9a3 100644 --- a/checkin_notes +++ b/checkin_notes @@ -7412,3 +7412,28 @@ Rom 1 Sept 2009 client/ http_curl.cpp,h + +Charlie 1 Sept 2009 + - Mac Sandbox: Security fixes for Mac OS 10.6 Snow Leopard. + Mac OS 10.6 requires administrator authorization to run setgid + applications if they use the AppKit (Cocoa) framework. The Mac + installer adds all users with admin privileges (members of group + admin) to group boinc_master. Since the Manager doesn't need to + run setgid boinc_master if the user is a member of that group, + we eliminate the setgid. + This means that non-admin users will be able to run the Manager + only if the sysadmin adds them to group boinc_master, so we now + create a login item or set the screensaver only for those users + who are members of group boinc_master. + If a user who is not a member of that group runs the Manager, it + displays an alert saying that in order to administer BOINC, he + needs to ask the sysadmin to add him to group boinc_master. + + client/ + check_security.cpp + clientgui/ + BOINCGUIApp.cpp + mac/ + SetupSecurity.cpp + mac_installer/ + PostInstall.cpp diff --git a/client/check_security.cpp b/client/check_security.cpp index 02c921be9f..099b027daf 100644 --- a/client/check_security.cpp +++ b/client/check_security.cpp @@ -32,10 +32,13 @@ #endif #include "util.h" -#include "str_replace.h" #include "error_numbers.h" #include "file_names.h" +#ifdef __WXMAC__ // If Mac BOINC Manager +bool IsUserInGroupBM(); +#endif + static int CheckNestedDirectories(char * basepath, int depth, int use_sandbox); #if (! defined(__WXMAC__) && ! defined(_MAC_INSTALLER)) @@ -81,10 +84,6 @@ int use_sandbox, int isManager ProcessSerialNumber ourPSN; ProcessInfoRec pInfo; FSRef ourFSRef; - char *p; -#endif -#ifdef _MAC_INSTALLER - char *p; #endif #define NUMBRANDS 3 @@ -159,10 +158,14 @@ saverName[2] = "Progress Thru Processors"; boinc_master_uid = sbuf.st_uid; boinc_master_gid = sbuf.st_gid; + +#ifdef __WXMAC__ + if (!IsUserInGroupBM()) + return -1099; +#endif } else { boinc_master_uid = geteuid(); boinc_master_gid = getegid(); - } #ifdef _MAC_INSTALLER @@ -213,6 +216,7 @@ saverName[2] = "Progress Thru Processors"; boinc_project_gid = grp->gr_gid; } +#if 0 // Manager is no longer setgid #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 strlcpy(full_path, dir_path, sizeof(full_path)); @@ -238,6 +242,8 @@ saverName[2] = "Progress Thru Processors"; return -1015; } #endif +#endif // Manager is no longer setgid + #ifdef _MAC_INSTALLER // Require absolute owner and group boinc_master:boinc_master @@ -304,12 +310,13 @@ saverName[2] = "Progress Thru Processors"; #else // _MAC_INSTALLER getcwd(dir_path, sizeof(dir_path)); // Client or Manager + if (! isManager) { // If BOINC Client if (egid != boinc_master_gid) - return -1019; // Client or Manager should be running setgid boinc_master + return -1019; // Client should be running setgid boinc_master - if (! isManager) // If BOINC Client if (euid != boinc_master_uid) return -1020; // BOINC Client should be running setuid boinc_master + } #endif retval = stat(dir_path, &sbuf); @@ -650,3 +657,36 @@ static void GetPathToThisProcess(char* outbuf, size_t maxLen) { *q = '\0'; } #endif + + +#ifdef __WXMAC__ // If Mac BOINC Manager +bool IsUserInGroupBM() { + group *grp; + gid_t rgid; + char *userName, *groupMember; + int i; + + grp = getgrgid(boinc_master_gid); + if (grp) { + + rgid = getgid(); + if (rgid == boinc_master_gid) { + return true; // User's primary group is boinc_master + } + + userName = getlogin(); + if (userName) { + for (i=0; ; i++) { // Step through all users in group boinc_master + groupMember = grp->gr_mem[i]; + if (groupMember == NULL) + return false; // User is not a member of group boinc_master + if (strcmp(userName, groupMember) == 0) { + return true; // User is a member of group boinc_master + } + } // for (i) + } // if (userName) + } // if grp + + return false; +} +#endif // __WXMAC__ diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index 37559e50dd..d20486f4a9 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -304,11 +304,16 @@ bool CBOINCGUIApp::OnInit() { ShowApplication(true); + if (iErrorCode == -1099) { + strDialogMessage = + _("You currently are not authorized to manage the client.\nPlease contact your administrator to add you to the 'boinc_master' user group."); + } else { strDialogMessage.Printf( - wxT("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)\n"), + _("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)\n"), iErrorCode ); + } wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT("BOINC Manager"), wxOK); pDlg->ShowModal(); diff --git a/clientgui/mac/SetupSecurity.cpp b/clientgui/mac/SetupSecurity.cpp index 8471efcd1f..90b7d90723 100644 --- a/clientgui/mac/SetupSecurity.cpp +++ b/clientgui/mac/SetupSecurity.cpp @@ -179,14 +179,14 @@ saverName[2] = "Progress Thru Processors"; #ifdef _DEBUG // chmod u=rwx,g=rwsx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager - // 02775 = S_ISGID | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH - // setgid-on-execution plus read, write and execute permission for user & group, read & execute for others - err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwsx,o=rx", fullpath, NULL, NULL, NULL); + // 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 & execute for others + err = DoPrivilegedExec(chmodPath, "u=rwx,g=rwx,o=rx", fullpath, NULL, NULL, NULL); #else // chmod u=rx,g=rsx,o=rx path/BOINCManager.app/Contents/MacOS/BOINCManager - // 02555 = S_ISGID | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH - // setgid-on-execution plus read and execute permission for user, group & others - err = DoPrivilegedExec(chmodPath, "u=rx,g=rsx,o=rx", fullpath, NULL, NULL, NULL); + // 0555 = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH + // read and execute permission for user, group & others + err = DoPrivilegedExec(chmodPath, "u=rx,g=rx,o=rx", fullpath, NULL, NULL, NULL); #endif if (err) return err; diff --git a/mac_installer/PostInstall.cpp b/mac_installer/PostInstall.cpp index 06ab255987..82bf473394 100755 --- a/mac_installer/PostInstall.cpp +++ b/mac_installer/PostInstall.cpp @@ -657,12 +657,16 @@ OSErr UpdateAllVisibleUsers(long brandID) Boolean deleteLoginItem; char skinName[256]; char s[256]; - group *grp; + group grpAdmin, *grpAdminPtr; + char adminBuf[32768]; + group grpBOINC_master, *grpBOINC_masterPtr; + char bmBuf[32768]; Boolean saverAlreadySet = true; Boolean found = false; FILE *f; OSStatus err; long response; + Boolean isGroupMember; #ifdef SANDBOX char *p; short i; @@ -671,11 +675,17 @@ OSErr UpdateAllVisibleUsers(long brandID) if (err != noErr) return err; - grp = getgrnam("admin"); - if (grp == NULL) { // Should never happen + err = getgrnam_r("admin", &grpAdmin, adminBuf, sizeof(adminBuf), &grpAdminPtr); + if (err) { // Should never happen unless buffer too small puts("getgrnam(\"admin\") failed\n"); return -1; } + + err = getgrnam_r("boinc_master", &grpBOINC_master, bmBuf, sizeof(bmBuf), &grpBOINC_masterPtr); + if (err) { // Should never happen unless buffer too small + puts("getgrnam(\"boinc_master\") failed\n"); + return -1; + } #endif FindSkinName(skinName, sizeof(skinName)); @@ -699,25 +709,45 @@ OSErr UpdateAllVisibleUsers(long brandID) continue; #ifdef SANDBOX + isGroupMember = false; i = 0; - while ((p = grp->gr_mem[i]) != NULL) { // Step through all users in group admin + while ((p = grpAdmin.gr_mem[i]) != NULL) { // Step through all users in group admin if (strcmp(p, dp->d_name) == 0) { // User is a member of group admin, so add user to groups boinc_master and boinc_project err = AddAdminUserToGroups(p); if (err != noErr) return err; + isGroupMember = true; break; } ++i; } + + if (!isGroupMember) { + i = 0; + while ((p = grpBOINC_master.gr_mem[i]) != NULL) { // Step through all users in group boinc_master + if (strcmp(p, dp->d_name) == 0) { + // User is a member of group boinc_master + isGroupMember = true; + break; + } + ++i; + } + } +#else + isGroupMember = true; #endif deleteLoginItem = CheckDeleteFile(dp->d_name); + if (!isGroupMember) { + deleteLoginItem = true; + } saved_uid = geteuid(); seteuid(pw->pw_uid); // Temporarily set effective uid to this user SetLoginItem(brandID, deleteLoginItem); // Set login item for this user + if (isGroupMember) { SetSkinInUserPrefs(dp->d_name, skinName); if (response < 0x1060) { @@ -739,6 +769,7 @@ OSErr UpdateAllVisibleUsers(long brandID) pclose(f); if (!found) { saverAlreadySet = false; + } } } @@ -751,8 +782,8 @@ OSErr UpdateAllVisibleUsers(long brandID) return noErr; } - if (!ShowMessage(true, "Do you want to set %s as the screensaver for all users on this Mac?", - brandName[brandID])) { + if (!ShowMessage(true, "Do you want to set %s as the screensaver for all %s users on this Mac?", + brandName[brandID], brandName[brandID])) { return noErr; } @@ -775,6 +806,24 @@ OSErr UpdateAllVisibleUsers(long brandID) if (pw == NULL) // "Deleted Users", "Shared", etc. continue; +#ifdef SANDBOX + isGroupMember = false; + + i = 0; + while ((p = grpBOINC_master.gr_mem[i]) != NULL) { // Step through all users in group boinc_master + if (strcmp(p, dp->d_name) == 0) { + // User is a member of group boinc_master + isGroupMember = true; + break; + } + ++i; + } + + if (!isGroupMember) { + continue; + } +#endif + saved_uid = geteuid(); seteuid(pw->pw_uid); // Temporarily set effective uid to this user