5

How do I programmatically check if the user that ran my executable is an administrator?

This is C++ on Mac OS X 10.6 (Snow Leopard) or higher. My many searches have not turned up anything.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
meg18019
  • 159
  • 1
  • 14
  • Yeah everything I see is only on how to elevate privileges. Are you using some kind of a bridge to Coacoa? That would be good to know before I start looking around :) I'd recommend directing your search towards Unix rather than OS X since C code to find out privileges would likely be the same as on any Unix system. – evanmcdonnal Jun 14 '12 at 01:34

4 Answers4

2

Check the groups that the user is in, and confirm that the user is in the required group. I think you want to check that the user belongs to 'admin', but you may instead want to check for other, more specific access. Why do you want to check for admin anyway? It's usually a better idea to directly attempt the task, than to check for a broad level of access and failing if the user doesn't have that access, but does infact have the specific access you want.

Arafangion
  • 11,517
  • 1
  • 40
  • 72
1

How about checking a user id by calling getuid()? OS X is based on BSD. Thus, I think you might be able to check what ID runs the process by this function.

Kyokook Hwang
  • 2,682
  • 21
  • 36
  • 3
    This probably returns the _real user id_ of the process -- i.e., the user account of the person that executed the program. `geteuid()` will return the _effective user id_ of the process, the user id that is used for access control checks. `geteuid()` is better answer but perhaps not complete. – sarnold Jun 14 '12 at 01:38
1
#include <grp.h>
#include <pwd.h>
#include <string.h>

bool currentUserIsAdmin ( ) {
    // A user cannot be member in more than NGROUPS groups,
    // not counting the default group (hence the + 1)
    gid_t groupIDs[NGROUPS + 1];
    // ID of user who started the process
    uid_t userID = getuid();
    // Get user password info for that user
    struct passwd * pw = getpwuid(userID);

    int groupCount;
    if (pw) {
        // Look up groups that user belongs to
        groupCount = NGROUPS + 1;
        // getgrouplist returns ints and not gid_t and
        // both may not necessarily have the same size
        int intGroupIDs[NGROUPS + 1];
        getgrouplist(pw->pw_name, pw->pw_gid, intGroupIDs, &groupCount);
        // Copy them to real array
        for (int i = 0; i < groupCount; i++) groupIDs[i] = intGroupIDs[i];

    } else {
        // We cannot lookup the user but we can look what groups this process
        // currently belongs to (which is usually the same group list).
        groupCount = getgroups(NGROUPS + 1, groupIDs);
    }

    for (int i = 0; i < groupCount; i++) {
        // Get the group info for each group
        struct group * group = getgrgid(groupIDs[i]);
        if (!group) continue;
        // An admin user is member of the group named "admin"
        if (strcmp(group->gr_name, "admin") == 0) return true;
    }
    return false;
}
Mecki
  • 125,244
  • 33
  • 244
  • 253
0

It looks like Open Directory is the proper way to do this. You might be able to cheap it out by using getegid() and/or setegid()

I haven't tested it but this might work:

// 80 should be the admin group number, but it Apple might change it in a later release.
if (getegid() == 80 || setegid(80) == 0) {
    // Yea! I'm an admin.
}

Just a couple of quick ideas to follow up on. I hope they lead you in the right direction.

Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • downvoted by mistake, cant upvote it now :(. Open Directory does sound right way to go. – JamesWebbTelescopeAlien Apr 07 '13 at 03:24
  • How could you use Open Directory and do it the proper way? – Kaydell Sep 24 '15 at 03:18
  • @Kaydell Are you claiming that non-admin users could set the effective group id of the process to admin? Unless you have the group id [sticky bit](https://en.wikipedia.org/wiki/Sticky_bit) set on the binary, it violates the documentation [setegid(2)](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/setegid.2.html) and basic security. – Jeffery Thomas Sep 24 '15 at 12:10
  • @Jeffery Thomas, what I'm claiming is that getegid() returned 20 for me, even though I'm an admin and setegid(80) returned -1 for my admin account, and I think for my standard account too. At least, the whole expression: (getegid() == 80 || setegid(80) == 0) is always true, both for my admin account, and for my standard account. Here is a link to a solution that works properly: http://stackoverflow.com/questions/6614901/objective-c-and-os-user-type The accepted answer in this link works, your "cheap" solution doesn't work. – Kaydell Sep 24 '15 at 17:31
  • @Kaydell That's fine. I'm not sure how `getegid() == 80` is false and `setegid(80) == 0` is false, but `getegid() == 80 || setegid(80) == 0` is true. Perhaps you are using a different kind of boolean logic. Either way `setegid(80)` should not return `-1`, if the user is an admin. I'm sorry it didn't work for you. – Jeffery Thomas Sep 24 '15 at 17:42