Beispiel #1
0
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;
    
    PersistentFGets (outbuf, maxLen, f);      // Discard header line
    PersistentFGets (outbuf, maxLen, f);
    pclose(f);

    // Remove trailing newline if present
    p = strchr(outbuf, '\n');
    if (p)
        *p = '\0';
    
    // Strip off any arguments
    p = strstr(outbuf, " -");
    q = p;
    if (p) {
        while (*p == ' ') {
            q = p;
            if (--p < outbuf)
                break;
        }
    }
    
    if (q)
        *q = '\0';
}
Beispiel #2
0
pid_t FindProcessPID(char* name, pid_t thePID)
{
    FILE *f;
    char buf[1024];
    size_t n = 0;
    pid_t aPID;
    
    if (name != NULL)     // Search ny name
        n = strlen(name);
    
    f = popen("ps -a -x -c -o command,pid", "r");
    if (f == NULL)
        return 0;
    
    while (PersistentFGets(buf, sizeof(buf), f))
    {
        if (name != NULL) {     // Search by name
            if (strncmp(buf, name, n) == 0)
            {
                aPID = atol(buf+16);
                pclose(f);
                return aPID;
            }
        } else {      // Search by PID
            aPID = atol(buf+16);
            if (aPID == thePID) {
                pclose(f);
                return aPID;
            }
        }
    }
    pclose(f);
    return 0;
}
Beispiel #3
0
int FindSkinName(char *name, size_t len)
{
    FILE *f;
    char buf[MAXPATHLEN];
    char *pattern = "/BOINC Data/skins/";
    char *p, *q;

    name[0] = '\0';
    
    f = popen("lsbom -d -s ./Contents/Archive.bom", "r");
    if (f == NULL)
        return 0;
    
    while (PersistentFGets(buf, sizeof(buf), f)) {
        p = strstr(buf, pattern);
        if (p) {
            p += strlen(pattern);
            q = strchr(p, '/');
            if (q) *q = 0;
            q = strchr(p, '\n');
            if (q) *q = 0;

            if (strlen(p) > (len-1))
                return 0;
            strlcpy(name, p, len);
            pclose(f);
            return 1;
        }
    }
    pclose(f);
    return 0;
}
Beispiel #4
0
static Boolean IsUserLoggedIn(const char *userName){
    char s[1024];
    
    sprintf(s, "w -h \"%s\"", userName);
    FILE *f = popen(s, "r");
    if (f) {
        if (PersistentFGets(s, sizeof(s), f) != NULL) {
            pclose (f);
            printf("User %s is currently logged in\n", userName);
            return true; // this user is logged in (perhaps via fast user switching)
        }
        pclose (f);         
    }
    return false;
}
bool CBOINCClientManager::ProcessExists(pid_t thePID)
{
    FILE *f;
    char buf[256];
    pid_t aPID;

    f = popen("ps -a -x -c -o pid,state", "r");
    if (f == NULL)
        return false;
    
    while (PersistentFGets(buf, sizeof(buf), f)) {
        aPID = atol(buf);
        if (aPID == thePID) {
            if (strchr(buf, 'Z'))   // A 'zombie', stopped but waiting
                break;              // for us (its parent) to quit
            pclose(f);
            return true;
        }
    }
    pclose(f);
    return false;
}
Beispiel #6
0
OSErr GetCurrentScreenSaverSelection(passwd *pw, char *moduleName, size_t maxLen) {
    char                buf[1024];
    FILE                *f;
    char                *p, *q;
    int                 i;

    *moduleName = '\0';
    sprintf(buf, "su -l \"%s\" -c 'defaults -currentHost read com.apple.screensaver moduleDict'", pw->pw_name);
    f = popen(buf, "r");
    if (f == NULL) {
        fprintf(stderr, "Could not get current screensaver selection for user %s\n", pw->pw_name);
        fflush(stderr);
        return fnfErr;
    }
    
    while (PersistentFGets(buf, sizeof(buf), f))
    {
        p = strstr(buf, "moduleName = ");
        if (p) {
            p += 13;    // Point past "moduleName = "
            q = moduleName;
            for (i=0; i<maxLen-1; ++i) {
                if (*p == '"') {
                    ++p;
                    continue;
                }
                if (*p == ';') break;
                *q++ = *p++;
            }
            *q = '\0';
            pclose(f);
            return 0;
        }
    }
    
    pclose(f);
    return fnfErr;
}
Beispiel #7
0
// Find all visible users.
// If user is a member of group admin, add user to groups boinc_master and boinc_project.
// Optionally add non-admin users to group boinc_master but not to group boinc_project.
// Set login item for all members of group boinc_master to launch BOINC Manager.
// If our install package included a skin, set those user's preferences to use that skin.
// Optionally set BOINC as screensaver for all users running BOINC.
OSErr UpdateAllVisibleUsers(long brandID)
{
    DIR                 *dirp;
    dirent              *dp;
    passwd              *pw;
    uid_t               saved_uid;
    Boolean             deleteLoginItem;
    char                skinName[256];
    char                s[256];
    group               grpAdmin, *grpAdminPtr;
    char                adminBuf[32768];
    group               grpBOINC_master, *grpBOINC_masterPtr;
    char                bmBuf[32768];
    Boolean             saverAlreadySetForAll = true;
    Boolean             setSaverForAllUsers = false;
    Boolean             allNonAdminUsersAreSet = true;
    Boolean             allowNonAdminUsersToRunBOINC = false;
    Boolean             found = false;
    FILE                *f;
    OSStatus            err;
    Boolean             isGroupMember;
#ifdef SANDBOX
    char                *p;
    short               i;

    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  // SANDBOX

    FindSkinName(skinName, sizeof(skinName));

    // Step through all users
    puts("Beginning first pass through all users\n");

    dirp = opendir("/Users");
    if (dirp == NULL) {      // Should never happen
        puts("[1] opendir(\"/Users\") failed\n");
        return -1;
    }
    
    while (true) {
        dp = readdir(dirp);
        if (dp == NULL)
            break;                  // End of list

        printf("[1] Checking user %s\n", dp->d_name);
            
        if (dp->d_name[0] == '.')
            continue;               // Ignore names beginning with '.'
    
        // getpwnam works with either the full / login name (pw->pw_gecos) 
        // or the short / Posix name (pw->pw_name)
        pw = getpwnam(dp->d_name);
        if (pw == NULL) {           // "Deleted Users", "Shared", etc.
            printf("[1] %s not in getpwnam data base\n", dp->d_name);
            continue;
        }

        printf("[1] User %s: Posix name=%s, Full name=%s\n", dp->d_name, pw->pw_name, pw->pw_gecos);
        
#ifdef SANDBOX
        isGroupMember = false;
        i = 0;
        while ((p = grpAdmin.gr_mem[i]) != NULL) {  // Step through all users in group admin
            if (strcmp(p, pw->pw_name) == 0) {
                // User is a member of group admin, so add user to groups boinc_master and boinc_project
                printf("[1] User %s is a member of group admin\n", pw->pw_name);
                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, pw->pw_name) == 0) {
                    // User is a member of group boinc_master
                    printf("[1] User %s is a member of group boinc_master\n", pw->pw_name);
                    isGroupMember = true;
                    break;
                }
                ++i;
            }
        }
        if (!isGroupMember) {
            allNonAdminUsersAreSet = false;
        }
#else   // SANDBOX
        isGroupMember = true;
#endif  // SANDBOX

        if (isGroupMember) {
            if ((strcmp(loginName, dp->d_name) == 0) || (strcmp(loginName, pw->pw_name) == 0)) {
                currentUserCanRunBOINC = true;
            }
            
            saved_uid = geteuid();
            seteuid(pw->pw_uid);                        // Temporarily set effective uid to this user
            
            if (OSVersion < 0x1060) {
                f = popen("defaults -currentHost read com.apple.screensaver moduleName", "r");
            } else {
                sprintf(s, "sudo -u %s defaults -currentHost read com.apple.screensaver moduleDict -dict", 
                        pw->pw_name); 
                f = popen(s, "r");
            }
            
            if (f) {
                found = false;
                while (PersistentFGets(s, sizeof(s), f)) {
                    if (strstr(s, saverName[brandID])) {
                        found = true;
                        break;
                    }
                }
                pclose(f);
                if (!found) {
                    saverAlreadySetForAll = false;
                }
            }
            
            seteuid(saved_uid);                         // Set effective uid back to privileged user
        }       // End if (isGroupMember)
    }           // End while (true)
    
    closedir(dirp);

    ResynchSystem();

    if (! allNonAdminUsersAreSet) {
        if (ShowMessage(true, 
            "Users who are permitted to administer this computer will automatically be allowed to "
            "run and control %s.\n\n"
            "Do you also want non-administrative users to be able to run and control %s on this Mac?",
            brandName[brandID], brandName[brandID])
        ) {
            allowNonAdminUsersToRunBOINC = true;
            currentUserCanRunBOINC = true;
            saverAlreadySetForAll = false;
            printf("[2] User answered Yes to allowing non-admin users to run %s\n", brandName[brandID]);
        } else {
            printf("[2] User answered No to allowing non-admin users to run %s\n", brandName[brandID]);
        }
    } else {
        puts("[2] All non-admin users are already members of group boinc_master\n");
    }
    
    if (! saverAlreadySetForAll) {
        setSaverForAllUsers = ShowMessage(true, 
                    "Do you want to set %s as the screensaver for all %s users on this Mac?", 
                    brandName[brandID], brandName[brandID]);    
    }

    // Step through all users a second time, setting non-admin users and / or our screensaver
    puts("Beginning second pass through all users\n");

    dirp = opendir("/Users");
    if (dirp == NULL) {      // Should never happen
        puts("[2] opendir(\"/Users\") failed\n");
        return -1;
    }
    
    while (true) {
        dp = readdir(dirp);
        if (dp == NULL)
            break;                  // End of list

        printf("[2] Checking user %s\n", dp->d_name);
            
        if (dp->d_name[0] == '.')
            continue;               // Ignore names beginning with '.'
    
        pw = getpwnam(dp->d_name);
        if (pw == NULL) {           // "Deleted Users", "Shared", etc.
            printf("[2] %s not in getpwnam data base\n", dp->d_name);
            continue;
        }

        printf("[2] User %s: Posix name=%s, Full name=%s\n", dp->d_name, pw->pw_name, pw->pw_gecos);
        
#ifdef SANDBOX
        isGroupMember = false;

        i = 0;
        while ((p = grpAdmin.gr_mem[i]) != NULL) {  // Step through all users in group admin
            if (strcmp(p, pw->pw_name) == 0) {
                // User is a member of group admin
                printf("[2] User %s is a member of group admin\n", pw->pw_name);
                isGroupMember = true;
                break;
            }
            ++i;
        }

        // If allNonAdminUsersAreSet, some older versions added non-admin users only to group 
        // boinc_master; ensure all permitted BOINC users are also members of group boinc_project
        if (isGroupMember || allowNonAdminUsersToRunBOINC || allNonAdminUsersAreSet) {
            // Add to group boinc_master but not group boinc_project
            err = AddAdminUserToGroups(pw->pw_name);
            printf("[2] Calling AddAdminUserToGroups(%s)\n", pw->pw_name);
            isGroupMember = true;
        }
        
#else   // SANDBOX
        isGroupMember = true;
#endif  // SANDBOX

        saved_uid = geteuid();
        seteuid(pw->pw_uid);                        // Temporarily set effective uid to this user
        deleteLoginItem = CheckDeleteFile(dp->d_name);
        if (CheckDeleteFile(pw->pw_name)) {
            deleteLoginItem = true;
        }
        if (!isGroupMember) {
            deleteLoginItem = true;
        }

        SetLoginItem(brandID, deleteLoginItem);     // Set login item for this user

        if (isGroupMember) {
            SetSkinInUserPrefs(dp->d_name, skinName);
        
            if (setSaverForAllUsers) {
                if (OSVersion < 0x1060) {
                    sprintf(s, "defaults -currentHost write com.apple.screensaver moduleName %s", saverNameEscaped[brandID]);
                    system (s);
                    sprintf(s, "defaults -currentHost write com.apple.screensaver modulePath /Library/Screen\\ Savers/%s.saver", 
                                saverNameEscaped[brandID]);
                } else {
                    sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName %s path /Library/Screen\\ Savers/%s.saver", 
                            pw->pw_name, saverNameEscaped[brandID], saverNameEscaped[brandID]);
                }
                system (s);
            }
        }
        
        seteuid(saved_uid);                         // Set effective uid back to privileged user
    }
    
    closedir(dirp);

    ResynchSystem();

    return noErr;
}
Beispiel #8
0
// NOTE: getgrnam and getgrgid use one static memory area to return their results, 
//  so each call to getgrnam or getgrgid overwrites the data from any previous calls.
void CheckUserAndGroupConflicts()
{
#ifdef SANDBOX
    passwd          *pw = NULL;
    group           *grp = NULL;
    gid_t           boinc_master_gid = 0, boinc_project_gid = 0;
    uid_t           boinc_master_uid = 0, boinc_project_uid = 0;
    
    FILE            *f;
    char            cmd[256], buf[256];
    int             entryCount;

    entryCount = 0;
    grp = getgrnam(boinc_master_group_name);
    if (grp) {
        boinc_master_gid = grp->gr_gid;
        sprintf(cmd, "dscl . -search /Groups PrimaryGroupID %d", boinc_master_gid);
        f = popen(cmd, "r");
        if (f) {
            while (PersistentFGets(buf, sizeof(buf), f)) {
                if (strstr(buf, "PrimaryGroupID")) {
                    ++entryCount;
                }
            }
            pclose(f);
        }    
    }
        
    if (entryCount > 1) {
        system ("dscl . -delete /groups/boinc_master");
        // User boinc_master must have group boinc_master as its primary group.
        // Since this group no longer exists, delete the user as well.
        system ("dscl . -delete /users/boinc_master");
        ResynchSystem();
    }

    entryCount = 0;
    grp = getgrnam(boinc_project_group_name);
    if (grp) {
        boinc_project_gid = grp->gr_gid;
        sprintf(cmd, "dscl . -search /Groups PrimaryGroupID %d", boinc_project_gid);
        f = popen(cmd, "r");
        if (f) {
            while (PersistentFGets(buf, sizeof(buf), f)) {
                if (strstr(buf, "PrimaryGroupID")) {
                    ++entryCount;
                }
            }
            pclose(f);
        }    
    }

    if (entryCount > 1) {
       system ("dscl . -delete /groups/boinc_project");
        // User boinc_project must have group boinc_project as its primary group.
        // Since this group no longer exists, delete the user as well.
        system ("dscl . -delete /users/boinc_project");
        ResynchSystem();
    }

    entryCount = 0;
    pw = getpwnam(boinc_master_user_name);
    if (pw) {
        boinc_master_uid = pw->pw_uid;
        sprintf(cmd, "dscl . -search /Users UniqueID %d", boinc_master_uid);
        f = popen(cmd, "r");
        if (f) {
            while (PersistentFGets(buf, sizeof(buf), f)) {
                if (strstr(buf, "UniqueID")) {
                    ++entryCount;
                }
            }
            pclose(f);
        }    
    }

    if (entryCount > 1) {
        system ("dscl . -delete /users/boinc_master");
        ResynchSystem();
    }
        
    entryCount = 0;
    pw = getpwnam(boinc_project_user_name);
    if (pw) {
        boinc_project_uid = pw->pw_uid;
        sprintf(cmd, "dscl . -search /Users UniqueID %d", boinc_project_uid);
        f = popen(cmd, "r");
        if (f) {
            while (PersistentFGets(buf, sizeof(buf), f)) {
                if (strstr(buf, "UniqueID")) {
                    ++entryCount;
                }
            }
            pclose(f);
        }    
    }

    if (entryCount > 1) {
        system ("dscl . -delete /users/boinc_project");
        ResynchSystem();
    }
#endif  // SANDBOX
}
int main(int argc, char *argv[])
{
    Boolean             AddUsers = false;
    Boolean             SetSavers = false;
    Boolean             isBMGroupMember, isBPGroupMember;
    Boolean             saverIsSet = false;
    passwd              *pw;
    uid_t               saved_uid;
    long                OSVersion;
    group               grpBOINC_master, *grpBOINC_masterPtr;
    group               grpBOINC_project, *grpBOINC_projectPtr;
    char                bmBuf[32768];
    char                bpBuf[32768];
    short               index, i;
    char                *p;
    char                s[256];
    FILE                *f;
    OSStatus            err;
    
#ifndef _DEBUG
    if (getuid() != 0) {
        printf("This program must be run as root\n");
        printUsage();
        return 0;
    }
#endif

    if (argc < 3) {
        printUsage();
        return 0;
    }
    
    if (strcmp(argv[1], "-a") == 0) {
        AddUsers = true;
    } else if (strcmp(argv[1], "-s") == 0) {
        AddUsers = true;
        SetSavers = true;
    } else if (strcmp(argv[1], "-r") != 0) {
        printUsage();
        return 0;
    }
    
    err = Gestalt(gestaltSystemVersion, &OSVersion);
    if (err != noErr)
        return err;

    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;
    }

    err = getgrnam_r("boinc_project", &grpBOINC_project, bpBuf, sizeof(bpBuf), &grpBOINC_projectPtr);
    if (err) {          // Should never happen unless buffer too small
        puts("getgrnam(\"boinc_project\") failed\n");
        return -1;
    }

    for (index=2; index<argc; index++) {
        // getpwnam works with either the full / login name (pw->pw_gecos) 
        // or the short / Posix name (pw->pw_name)
        pw = getpwnam(argv[index]);
        if (pw == NULL) {
            printf("User %s not found.\n", argv[index]);
            continue;
        }

        isBMGroupMember = false;
        i = 0;
        while ((p = grpBOINC_master.gr_mem[i]) != NULL) {  // Step through all users in group boinc_master
            if (strcmp(p, pw->pw_name) == 0) {      // Only the short / Posix names are in the list
                // User is a member of group boinc_master
                isBMGroupMember = true;
                break;
            }
            ++i;
        }

        isBPGroupMember = false;
        i = 0;
        while ((p = grpBOINC_project.gr_mem[i]) != NULL) {  // Step through all users in group boinc_project
            if (strcmp(p, pw->pw_name) == 0) {      // Only the short / Posix names are in the list
                // User is a member of group boinc_master
                isBPGroupMember = true;
                break;
            }
            ++i;
        }

        if ((!isBMGroupMember) && AddUsers) {
            sprintf(s, "dscl . -merge /groups/boinc_master users %s", pw->pw_name);
            system(s);
        }
        
        if ((!isBPGroupMember) && AddUsers) {
            sprintf(s, "dscl . -merge /groups/boinc_project users %s", pw->pw_name);
            system(s);
        }
        
        if (isBMGroupMember && (!AddUsers)) {
            sprintf(s, "dscl . -delete /Groups/boinc_master GroupMembership %s", pw->pw_name);
            system(s);
        }

        if (isBPGroupMember && (!AddUsers)) {
            sprintf(s, "dscl . -delete /Groups/boinc_project GroupMembership %s", pw->pw_name);
            system(s);
        }

        saved_uid = geteuid();
        seteuid(pw->pw_uid);                        // Temporarily set effective uid to this user

        SetLoginItem(AddUsers);                     // Set or remove login item for this user

        if (OSVersion < 0x1060) {
            sprintf(s, "sudo -u %s defaults -currentHost read com.apple.screensaver moduleName", 
                    pw->pw_name); 
        } else {
            sprintf(s, "sudo -u %s defaults -currentHost read com.apple.screensaver moduleDict -dict", 
                    pw->pw_name); 
        }
        f = popen(s, "r");
        
        if (f) {
            saverIsSet = false;
            while (PersistentFGets(s, sizeof(s), f)) {
                if (strstr(s, "BOINCSaver")) {
                    saverIsSet = true;
                    break;
                }
            }
            pclose(f);
        }

        if ((!saverIsSet) && SetSavers) {
            if (OSVersion < 0x1060) {
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver moduleName BOINCSaver", 
                    pw->pw_name); 
                system(s);
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver modulePath \"/Library/Screen Savers/BOINCSaver.saver\"", 
                    pw->pw_name); 
                system(s);
            } else {
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName BOINCSaver path \"/Library/Screen Savers/BOINCSaver.saver\"", 
                        pw->pw_name);
                system(s);
            }
        }
        
        if (saverIsSet && (!AddUsers)) {
            if (OSVersion < 0x1060) {
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver moduleName Flurry", 
                    pw->pw_name); 
                system(s);
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver modulePath \"/System/Library/Screen Savers/Flurry.saver\"", 
                    pw->pw_name); 
                system(s);
            } else {
                sprintf(s, "sudo -u %s defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName Flurry path \"/System/Library/Screen Savers/Flurry.saver\"", 
                        pw->pw_name);
                system(s);
            }
        }

        seteuid(saved_uid);                         // Set effective uid back to privileged user
    }
    
    return 0;
}
Beispiel #10
0
int main(int argc, char *argv[])
{
    long                brandID = 0;
    Boolean             AddUsers = false;
    Boolean             SetSavers = false;
    Boolean             isBMGroupMember, isBPGroupMember;
    Boolean             saverIsSet = false;
    passwd              *pw;
    uid_t               saved_uid;
    group               grpBOINC_master, *grpBOINC_masterPtr;
    group               grpBOINC_project, *grpBOINC_projectPtr;
    char                bmBuf[32768];
    char                bpBuf[32768];
    char                loginName[256];
    short               index, i;
    FILE                *f;
    int                 flag;
    char                *p;
    char                s[1024], buf[1024];
    OSStatus            err;
    
    brandID = GetBrandID();

#ifndef _DEBUG
    if (getuid() != 0) {
        printf("This program must be run as root\n");
        printUsage(brandID);
        return 0;
    }
#endif
    saved_uid = geteuid();

    if (argc < 3) {
        printUsage(brandID);
        return 0;
    }
    
    if (strcmp(argv[1], "-a") == 0) {
        AddUsers = true;
    } else if (strcmp(argv[1], "-s") == 0) {
        AddUsers = true;
        SetSavers = true;
    } else if (strcmp(argv[1], "-r") != 0) {
        printUsage(brandID);
        return 0;
    }

    printf("\n");

    if (!check_branding_arrays(s, sizeof(s))) {
        printf("Branding array has too few entries: %s\n", s);
        return -1;
    }

    loginName[0] = '\0';
    strncpy(loginName, getenv("USER"), sizeof(loginName)-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;
    }

    err = getgrnam_r("boinc_project", &grpBOINC_project, bpBuf, sizeof(bpBuf), &grpBOINC_projectPtr);
    if (err) {          // Should never happen unless buffer too small
        puts("getgrnam(\"boinc_project\") failed\n");
        return -1;
    }

    for (index=2; index<argc; index++) {
        // getpwnam works with either the full / login name (pw->pw_gecos) 
        // or the short / Posix name (pw->pw_name)
        pw = getpwnam(argv[index]);
        if ((pw == NULL) || (pw->pw_uid < 501)) {
            printf("User %s not found.\n\n", argv[index]);
            continue;
        }

        flag = 0;
        sprintf(s, "dscl . -read \"/Users/%s\" NFSHomeDirectory", pw->pw_name);    
        f = popen(s, "r");
        if (!f) {
            flag = 1;
            } else {
            while (PersistentFGets(buf, sizeof(buf), f)) {
                p = strrchr(buf, ' ');
                if (p) {
                    if (strstr(p, "/var/empty") != NULL) {
                        flag = 1;
                        break;
                    }
                }
            }
            pclose(f);
        }

        if (flag) {
            sprintf(s, "dscl . -read \"/Users/%s\" UserShell", pw->pw_name);    
            f = popen(s, "r");
            if (!f) {
                flag |= 2;
            } else {
                while (PersistentFGets(buf, sizeof(buf), f)) {
                    p = strrchr(buf, ' ');
                    if (p) {
                        if (strstr(p, "/usr/bin/false") != NULL) {
                            flag |= 2;
                            break;
                        }
                    }
                }
                pclose(f);
            }
        }
    
        if (flag == 3) { // if (Home Directory == "/var/empty") && (UserShell == "/usr/bin/false")
            printf("%s is not a valid user name.\n\n", argv[index]);
            continue;
        }

        printf("%s user %s (/Users/%s)\n", AddUsers? "Adding" : "Removing", pw->pw_gecos, pw->pw_name);

        isBMGroupMember = false;
        i = 0;
        while ((p = grpBOINC_master.gr_mem[i]) != NULL) {  // Step through all users in group boinc_master
            if (strcmp(p, pw->pw_name) == 0) {      // Only the short / Posix names are in the list
                // User is a member of group boinc_master
                isBMGroupMember = true;
                break;
            }
            ++i;
        }

        isBPGroupMember = false;
        i = 0;
        while ((p = grpBOINC_project.gr_mem[i]) != NULL) {  // Step through all users in group boinc_project
            if (strcmp(p, pw->pw_name) == 0) {      // Only the short / Posix names are in the list
                // User is a member of group boinc_master
                isBPGroupMember = true;
                break;
            }
            ++i;
        }

        if ((!isBMGroupMember) && AddUsers) {
            sprintf(s, "dscl . -merge /groups/boinc_master GroupMembership %s", pw->pw_name);
            callPosixSpawn(s);
        }
        
        if ((!isBPGroupMember) && AddUsers) {
            sprintf(s, "dscl . -merge /groups/boinc_project GroupMembership %s", pw->pw_name);
            callPosixSpawn(s);
        }
        
        if (isBMGroupMember && (!AddUsers)) {
            sprintf(s, "dscl . -delete /Groups/boinc_master GroupMembership %s", pw->pw_name);
            callPosixSpawn(s);
        }

        if (isBPGroupMember && (!AddUsers)) {
            sprintf(s, "dscl . -delete /Groups/boinc_project GroupMembership %s", pw->pw_name);
            callPosixSpawn(s);
        }

        if (!AddUsers) {
            // Delete per-user BOINC Manager and screensaver files
            sprintf(s, "rm -fR \"/Users/%s/Library/Application Support/BOINC\"", pw->pw_name);
            callPosixSpawn (s);
        }
    
        // Set or remove login item for this user
        bool useOSASript = false;
        
        if ((compareOSVersionTo(10, 13) < 0)
            || (strcmp(loginName, pw->pw_name) == 0) 
                || (strcmp(loginName, pw->pw_gecos) == 0)) {
            useOSASript = true;
        }
#if USE_OSASCRIPT_FOR_ALL_LOGGED_IN_USERS
        if (! useOSASript) {
            useOSASript = IsUserLoggedIn(pw->pw_name);
        }
#endif
       if (useOSASript) {
            snprintf(s, sizeof(s), "/Users/%s/Library/LaunchAgents/edu.berkeley.boinc.plist", pw->pw_name);
            boinc_delete_file(s);
            SetLoginItemOSAScript(brandID, !AddUsers, pw->pw_name);
        } else {
            SetLoginItemLaunchAgent(brandID, !AddUsers, pw);
        }

        saverIsSet = false;
        err = GetCurrentScreenSaverSelection(pw, s, sizeof(s) -1);
#if VERBOSE
        fprintf(stderr, "Current Screensaver Selection for user %s is: \"%s\"\n", pw->pw_name, s);
#endif
        if (err == noErr) {
            if (!strcmp(s, saverName[brandID])) {
                saverIsSet = true;
            }
        }
        
        if (SetSavers) {
            if (saverIsSet) {
                printf("Screensaver already set to %s for user %s (/Users/%s)\n", saverName[brandID], pw->pw_gecos, pw->pw_name);
            } else {
                printf("Setting screensaver to %s for user %s (/Users/%s)\n", saverName[brandID], pw->pw_gecos, pw->pw_name);
            }
        }
        
        if ((!saverIsSet) && SetSavers) {
            seteuid(pw->pw_uid);    // Temporarily set effective uid to this user
            sprintf(s, "/Library/Screen Savers/%s.saver", saverName[brandID]);
            err = SetScreenSaverSelection(pw, saverName[brandID], s, 0);
#if VERBOSE
            fprintf(stderr, "SetScreenSaverSelection for user %s (uid %d) to \"%s\" returned error %d\n", pw->pw_name, geteuid(), saverName[brandID], err);
#endif
            seteuid(saved_uid);     // Set effective uid back to privileged user
            // This seems to work also:
            // sprintf(buf, "su -l \"%s\" -c 'defaults -currentHost write com.apple.screensaver moduleDict -dict moduleName \"%s\" path \"%s\ type 0'", pw->pw_name, saverName[brandID], s);
            // callPosixSpawn(s);
        }
        
        if (saverIsSet && (!AddUsers)) {
            printf("Setting screensaver to Flurry for user %s (/Users/%s)\n", pw->pw_gecos, pw->pw_name);
            seteuid(pw->pw_uid);    // Temporarily set effective uid to this user
            err = SetScreenSaverSelection(pw, "Flurry", "/System/Library/Screen Savers/Flurry.saver", 0);
#if VERBOSE
            fprintf(stderr, "SetScreenSaverSelection for user %s (%d) to Flurry returned error %d\n", pw->pw_name, geteuid(), err);
#endif
            seteuid(saved_uid);     // Set effective uid back to privileged user
        }

        seteuid(saved_uid);                         // Set effective uid back to privileged user
        
        printf("\n");
    }

    printf("WARNING: Changes may require a system restart to take effect.\n");
    
    return 0;
}