diff --git a/clientgui/mac/SetupSecurity.cpp b/clientgui/mac/SetupSecurity.cpp index 91a65bd277..40b4b46e47 100644 --- a/clientgui/mac/SetupSecurity.cpp +++ b/clientgui/mac/SetupSecurity.cpp @@ -28,18 +28,24 @@ #include -static OSStatus CreateUserAndGroup(char * name); +static OSStatus CreateUserAndGroup(char * name, Boolean * createdNew); static OSStatus GetAuthorization(void); static void ShowSecurityError(const char *format, ...); - +static pascal Boolean ErrorDlgFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *theItemHit); static AuthorizationRef gOurAuthRef = NULL; +#define AUTHORIZE_LOOKUPD_MEMBERD false + static char dsclPath[] = "/usr/bin/dscl"; static char chmodPath[] = "/bin/chmod"; static char chownPath[] = "/usr/sbin/chown"; +#if AUTHORIZE_LOOKUPD_MEMBERD static char lookupdPath[] = "/usr/sbin/lookupd"; static char memberdPath[] = "/usr/sbin/memberd"; - +#define RIGHTS_COUNT 5 +#else +#define RIGHTS_COUNT 3 +#endif #define boinc_master_name "boinc_master" #define boinc_project_name "boinc_project" @@ -47,18 +53,27 @@ static char memberdPath[] = "/usr/sbin/memberd"; #define MIN_ID 25 /* Minimum user ID / Group ID to create */ int main(int argc, char *argv[]) { + unsigned long endSleep; + Boolean createdNew; OSStatus err = noErr; - err = CreateUserAndGroup(boinc_master_name); + err = CreateUserAndGroup(boinc_master_name, &createdNew); if (err != noErr) return err; - - err = CreateUserAndGroup(boinc_project_name); + + if (createdNew) { + endSleep = TickCount() + (2*60); + while (TickCount() < endSleep) { + sleep (1); + } + } + + err = CreateUserAndGroup(boinc_project_name, &createdNew); return err; } -static OSStatus CreateUserAndGroup(char * name) { +static OSStatus CreateUserAndGroup(char * name, Boolean * createdNew) { OSStatus err = noErr; passwd *pw = NULL; group *grp = NULL; @@ -73,6 +88,7 @@ static OSStatus CreateUserAndGroup(char * name) { char buf2[80]; char buf3[80]; + *createdNew = false; pw = getpwnam(name); if (pw) { @@ -88,6 +104,8 @@ static OSStatus CreateUserAndGroup(char * name) { if ( userExists && groupExists ) return noErr; // User and group already exist + + *createdNew = true; // If only user or only group exists, try to use the same ID for the one we create if (userExists) { // User exists but group does not @@ -148,25 +166,33 @@ static OSStatus CreateUserAndGroup(char * name) { sprintf(buf2, "%d", groupid); if (! groupExists) { // If we need to create group - // Something like "dscl . -create /groups/boinc_master" - args[0] = "."; - args[1] = "-create"; - args[2] = buf1; - args[3] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + // Something like "dscl . -create /groups/boinc_master" + args[0] = "."; + args[1] = "-create"; + args[2] = buf1; + args[3] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"dscl . -create %s\" returned error %d", buf1, err); return err; } // Something like "dscl . -create /groups/boinc_master gid 33" - args[0] = "."; - args[1] = "-create"; // "-append"; - args[2] = buf1; - args[3] = "gid"; - args[4] = buf2; - args[5] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + args[0] = "."; + args[1] = "-create"; // "-append"; + args[2] = buf1; + args[3] = "gid"; + args[4] = buf2; + args[5] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"dscl . -create %s gid %s\" returned error %d", buf1, buf2, err); return err; @@ -178,75 +204,115 @@ static OSStatus CreateUserAndGroup(char * name) { sprintf(buf3, "%d", userid); if (! userExists) { // If we need to create user - // Something like "dscl . -create /users/boinc_master" - args[0] = "."; - args[1] = "-create"; - args[2] = buf1; - args[3] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + // Something like "dscl . -create /users/boinc_master" + args[0] = "."; + args[1] = "-create"; + args[2] = buf1; + args[3] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"dscl . -create %s\" returned error %d", buf1, err); return err; } - // Something like "dscl . -create /users/boinc_master uid 33" - args[0] = "."; - args[1] = "-create"; // "-append"; - args[2] = buf1; - args[3] = "uid"; - args[4] = buf3; - args[5] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + // Something like "dscl . -create /users/boinc_master uid 33" + args[0] = "."; + args[1] = "-create"; // "-append"; + args[2] = buf1; + args[3] = "uid"; + args[4] = buf3; + args[5] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"dscl . -create %s uid %s\" returned error %d", buf1, buf3, err); return err; } + + for (i=0; i<5; i++) { // Retry 5 times if error + // Prevent a security hole by not allowing a login from this user + // Something like "dscl . -create /users/boinc_master shell /sbin/nologin" + args[0] = "."; + args[1] = "-create"; + args[2] = buf1; + args[3] = "shell"; + args[4] = "/sbin/nologin"; + args[5] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } + if (err != noErr) { + ShowSecurityError("\"dscl . -create %s shell /sbin/nologin\" returned error %d", buf1, err); + return err; + } } - // Always set the user gid if we created either the user or the group or both - // Something like "dscl . -create /users/boinc_master gid 33" - args[0] = "."; - args[1] = "-create"; // "-append"; - args[2] = buf1; - args[3] = "gid"; - args[4] = buf2; - args[5] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + // Always set the user gid if we created either the user or the group or both + // Something like "dscl . -create /users/boinc_master gid 33" + args[0] = "."; + args[1] = "-create"; // "-append"; + args[2] = buf1; + args[3] = "gid"; + args[4] = buf2; + args[5] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, dsclPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"dscl . -create %s gid %s\" returned error %d", buf1, buf2, err); return err; } -#if 0 - // "lookupd -flushcache" - args[0] = "-flushcache"; - args[1] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, lookupdPath, 0, args, NULL); +#if AUTHORIZE_LOOKUPD_MEMBERD + for (i=0; i<5; i++) { // Retry 5 times if error + // "lookupd -flushcache" + args[0] = "-flushcache"; + args[1] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, lookupdPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"lookupdPath -flushcache\" returned error %d", err); return err; } -#endif - // "memberd -r" - args[0] = "-r"; - args[1] = NULL; - err = AuthorizationExecuteWithPrivileges (gOurAuthRef, memberdPath, 0, args, NULL); + for (i=0; i<5; i++) { // Retry 5 times if error + // "memberd -r" + args[0] = "-r"; + args[1] = NULL; + err = AuthorizationExecuteWithPrivileges (gOurAuthRef, memberdPath, 0, args, NULL); + if (err == noErr) + break; + } if (err != noErr) { ShowSecurityError("\"memberd -r\" returned error %d", err); return err; } +#else + system("lookupd -flushcache"); + system("memberd -r"); +#endif return noErr; } -static OSStatus GetAuthorization (void) -{ +static OSStatus GetAuthorization (void) { static Boolean sIsAuthorized = false; AuthorizationRights ourAuthRights; AuthorizationFlags ourAuthFlags; - AuthorizationItem ourAuthItem[5]; + AuthorizationItem ourAuthItem[RIGHTS_COUNT]; OSErr err = noErr; if (sIsAuthorized) @@ -276,6 +342,7 @@ static OSStatus GetAuthorization (void) ourAuthItem[2].valueLength = strlen (chownPath); ourAuthItem[2].flags = 0; +#if AUTHORIZE_LOOKUPD_MEMBERD ourAuthItem[3].name = kAuthorizationRightExecute; ourAuthItem[3].value = lookupdPath; ourAuthItem[3].valueLength = strlen (lookupdPath); @@ -285,8 +352,9 @@ static OSStatus GetAuthorization (void) ourAuthItem[4].value = memberdPath; ourAuthItem[4].valueLength = strlen (memberdPath); ourAuthItem[4].flags = 0; +#endif - ourAuthRights.count = 5; + ourAuthRights.count = RIGHTS_COUNT; ourAuthRights.items = ourAuthItem; ourAuthFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; @@ -300,19 +368,47 @@ static OSStatus GetAuthorization (void) } -static void ShowSecurityError(const char *format, ...) -{ - va_list args; - char s[1024]; - short itemHit; +static void ShowSecurityError(const char *format, ...) { + va_list args; + char s[1024]; + short itemHit; + AlertStdAlertParamRec alertParams; + ModalFilterUPP ErrorDlgFilterProcUPP; + ProcessSerialNumber ourProcess; va_start(args, format); s[0] = vsprintf(s+1, format, args); va_end(args); + ErrorDlgFilterProcUPP = NewModalFilterUPP(ErrorDlgFilterProc); + + alertParams.movable = true; + alertParams.helpButton = false; + alertParams.filterProc = ErrorDlgFilterProcUPP; + alertParams.defaultText = "\pOK"; + alertParams.cancelText = NULL; + alertParams.otherText = NULL; + alertParams.defaultButton = kAlertStdAlertOKButton; + alertParams.cancelButton = 0; + alertParams.position = kWindowDefaultPosition; + ::GetCurrentProcess (&ourProcess); ::SetFrontProcess(&ourProcess); - StandardAlert (kAlertStopAlert, (StringPtr)s, NULL, NULL, &itemHit); -} \ No newline at end of file + StandardAlert (kAlertStopAlert, (StringPtr)s, NULL, &alertParams, &itemHit); + + DisposeModalFilterUPP(ErrorDlgFilterProcUPP); +} + + +static pascal Boolean ErrorDlgFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *theItemHit) { + // We need this because this is a command-line application so it does not get normal events + if (Button()) { + *theItemHit = kStdOkItemIndex; + return true; + } + + return StdFilterProc(theDialog, theEvent, theItemHit); +} +