views:

41

answers:

2

I am looking for a way to determine file permissions for the current user (i.e. the process's UID) on POSIX-compliant systems. I don't want to try opening the file - that could get messy with directories and all kinds of special files.

I am compiling a directory listing of a specified directory, and for each file, reporting a bunch of things: filename, size, type (file/directory/other), permissions (you can read, you can write). For size and type, i already have results of stat call available.

Here's what i came up with:

if ((dirent->st_uid == getuid() && dirent->st_mode & S_IRUSR)
 || (dirent->st_gid == getgid() && dirent->st_mode & S_IRGRP)
 || (dirent->st_mode && S_IROTH)) entry->perm |= PERM_READ;
if ((dirent->st_uid == getuid() && dirent->st_mode & S_IWUSR)
 || (dirent->st_gid == getgid() && dirent->st_mode & S_IWGRP)
 || (dirent->st_mode && S_IWOTH)) entry->perm |= PERM_WRITE;

Do i have to do this way, or is there a simple call/macro that would accomplish the same thing? Bonus points for ACL support, although that is not strictly necessary at this point.

+2  A: 

Use access() to check for permissions.

unwind
+6  A: 

access(2) will perform the full suite of permissions tests for you, in the kernel:

#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
    int i;

    for (i=0;i<argc;i++) {
            if(access(argv[i], R_OK)) {
                    printf("%s\n", argv[i]);
                    perror("R_OK");
            }
            if(access(argv[i], W_OK)) {
                    printf("%s\n", argv[i]);
                    perror("W_OK");
            }
    }

    return 0;
}

Some sample output:

$ ./foo ./foo /etc/passwd /etc/shadow
/etc/passwd
W_OK: Permission denied
/etc/shadow
R_OK: Permission denied
/etc/shadow
W_OK: Permission denied

EDIT

Note that access(2) is vulnerable to a TOCTTOU Time-of-check-to-time-of-use race condition. You shouldn't use access(2) to grant or deny access to files to a user from a privileged process, your program would be vulnerable to a race condition that could be exploited. If this is what you want the test for, use setfsuid(2) before doing any open(2) or exec*() calls.

sarnold