I wish to know how to check if the "user" (other than who is running this program)
has execute permissions on a file ? [C api]
I have looked at "access" it gives information with respect to the caller.
I am looking for something like :-
"<cmd> <user_name> <file_name>"
here I am trying to get if <user_name> has execute permissions for <file_name> ?
I am looking C api ?
Possible solution :- I am using the following algo to get this information
boolean_t
is_user_has_execute_permissions(char *run_as_user)
{
/* Check world execute permission */
if ((cmd_stat.st_mode & S_IXOTH) == S_IXOTH) {
return (TRUE);
}
/* group id for run_as_user */
getpwnam_r(run_as_user, &pw, buf, passwd_len);
/* Check group execute permission */
if ((cmd_stat.st_mode & S_IXGRP) == S_IXGRP) {
if (pw->pw_gid == cmd_stat.st_gid)
return (TRUE);
}
return (FALSE);
}
Did anyone see any error in this one ?
You need the call stat(2), which returns the permission bits, for the owner of the file, the owner group, and the others. Than you have to find out the id of the user you're interested in and ids its groups: see getpwent(3) and getgrouplist(3). The first which match, will give the resulting permissions.
From the command line, you can use an Awk program easily enough. Something like
ls -l filename | awk -F '{ if (substring($1,3,1) == "x" exit(0); exit(1)}'
will set the return code to 0 if it's found, 1 if it's not.
From a C program, you want to use fstat. Basically you open the file
int fd = fopen("filename", "r");
then get the file stat block with fstat
fstat(fd, &bufr)
and look at bufr.st_mode.
Here's a description of fstat.
Update
I'll note crankily that when the OP originally posted, it wasn't clear the C API was what was desired.
Related
I need to run from a privileged (root) application another application with current logged on user.
getenv("USER") and getenv("LOGNAME") return "root" in the privileged application. Effective and current user ids are 0.
cat /proc/self/status | grep [GU]id:
Uid: 0 0 0 0
Gid: 0 0 0 0
I found something close to my needs, user-1000.slice, but I would like to avoid using fscanf on the file /proc/self/cgroup.
cat /proc/self/cgroup | fgrep user
9:devices:/user.slice
8:pids:/user.slice/user-1000.slice
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope
The code bellow outputs 1000 as desired. Is there any more convenient way or API to get a user name of current UI session from a privileged application?
#include <stdio.h>
int main() {
int luid = 0;
char line[100];
FILE* file = fopen("/proc/self/cgroup", "r");
while (fgets(line, sizeof(line), file)) {
if (sscanf(line, "%*d:pids:/user.slice/user-%d.slice", &luid) == 1)
break;
}
fclose(file);
printf("Logged on User Id: ");
luid ? printf("%d\n", luid) : printf("Not found\n");
return 0;
}
The is no machine wide notion of "current UI session" under Unix. It does not make sense as Unix has its origin as a multi-user system, that mean that several people may be logged on at the same time, each with several UI session. It's the case for me on the machine I'm working one, there are 4 people logged on, 6 UI sessions and about 20 non UI sessions.
There is a database of current logged on people, /var/run/utmp. Maintaining this database is somewhat to the programs discretion (for instance, the version of gnome-terminal I'm using allow to add or not entries in the database). The database format is described in utmp(5), and there are functions to access it (see getutent(3)). There are programs to display its content (who(1) and w(1)) and modify it (sessreg(1)).
I'm not sure what your purpose is, so it is difficult to recommend an approach. Ensuring that your display manager add an entry in utmp and parsing the result of who is probably the easiest but you have to pay attention to assumptions you are making.
Assuming that root session was launched with 'pkexec' from a terminal.
When running pkexec from a termnal, the following process hierarchies is displayed:
pstree -p | grep $$
...
|-gnome-terminal-(3295)-+-bash(3302)---bash(93463)-+-grep(93500)
...
In this situation possible to extract the user based on the following logic:
Find the grand parent of the current process: cur_user_pid
Depending on the specific setup, might have to go up additional layers, potentially, until detecting a non-root ID.
Lookup the user id cur_user_pid
Much easier to do in shell, so if possible, escape to the shell, following the partial example:
char buff[50], cur_user[50] ;
int cur_user_pid = 0 ;
sprintf(buff, "x=$(ps -oppid= %d) ; ps -ouid,user= $x", getppid()) ;
FILE *fp = popen(buff, "r") ;
fscanf(fp, "%d %s", &cur_user_pid, curr_user) ;
pclose(fp) ;
If not possible to escape to the shell, I believe possible to travel process tree using /proc file system. Per How to get a grandparents/ancestors process ID?, it available in the fourth field of '/proc/[pid]/stat'.
I noticed it lately that the upstart process is running under a log on user, I thought it is running under root. So, my solution below looks better than one with extracting user id from /proc/self/cgroup.
#include <stdio.h>
int main() {
int uid = -1;
char line[100];
pid_t sid = getsid(0);
sprintf(line, "/proc/%d/status", sid);
FILE *file = fopen(line, "r");
while (fgets(line, sizeof(line), file)) {
if (sscanf(line, "Uid: %d", &uid) == 1)
break;
}
fclose(file);
printf("Logged on User Id: ");
uid != -1 ? printf("%d\n", uid) : printf("Not found\n");
}
Im trying to get the file permissions for a file or directory using the function stat(). I can get the correct information, such as; st_nlinks is for number of hard links and st_mode gives the mode of the file, which is what I am looking for. But the value stores in st_mode is an octal number. How do I now extract just the owner permissions.
For example the st_mode might store 42755 which means the owner has read write and execution permissions, but I don't know how to get extract the 7 from the number. If this is confusing maybe my code below will clarify things.
CODE:
DIR *dirp;
struct dirent *dp;
struct stat buf;
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL){
stat(dp->d_name, &buf);
//now here I have the octal number for the file permissions
//If I put a print statement here like so:
printf(">> %o %s\n", buf.st_mode, dp->d_name);
}
So some of you may see that I am trying to do what ls -l does on a Unix system. So instead of printing out the octal number for the mode I want to convert it to something like:
drwxr-xr-x for the value stored in st_mode: 42755
My professor recommended using a mask and perform a bitwise operation on it. I understand what he means but I tried something like:
mode_t owner = 0000100 & st_mode;
But when I print out owner I get the value of 100.
printf(">> owner permission: %o\n", owner);
OUTPUT:
owner permission: 100
So I am confused on how to do this. Does anyone know how to solve this problem?
By the way in case anyone is wondering I use mode_t as the type for owner because according to the man page for stat (man 2 stat) the member variable st_mode of the stat structure is of type mode_t. I figure this is just like a long int or something.
Use the macros defined in sys/stat.h to resolve the mode bits.
Refer to:
http://www.johnloomis.org/ece537/notes/Files/Examples/ls2.html
function mode_to_letters() for implementation details.
You should consider using defined macros rather than trying to "parse" permissions manually. Let's say you wish you get the write permission for the file owner user, that's could be checked like this:
int wpo = buff.st_mode & S_IWUSR;
if (wpo) {
printf("Ower has write permission");
} else {
printf("Ower doesn't have write permission");
}
You will find more useful macros in documentation: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/stat.h.html
The mask must be 0700:
111 000 000
To get owner rights rwx
For example, I have directory a and b under my current working directory. I'm trying to locate file X, how can I modify the stat() command so that it checks both directory a and b instead of just current working directory? would stat(a/file, &buf) work? also, to check if it's executable, I know the code is buf.S_IXUSR, does if (buf.S_IXUSR) work?
thanks!
I suggest you consult the stat(2) man page.
Here's an example of how to use stat:
struct stat buf;
if (stat("a/file", &buf) != 0) {
// handle failure
}
// Check the `st_mode` field to see if the `S_IXUSR` bit is set
if (buf.st_mode & S_IXUSR) {
// Executable by user
}
However, for your use case, you might consider access(2) instead:
if (access("/path/to/file", X_OK) == 0) {
// File exists and is executable by the calling process's
// _real_ UID / GID.
}
For the following snippet of code, I get an error:
Unable to open file: No such file or directory
redirect_ptr is char**
And I have tried printing redirect_ptr[0], it prints it correctly. Any idea where the problem might lie?
if ((in_fd = open(redirect_ptr[0], O_RDWR | O_CREAT)) == -1) {
perror("Unable to open file");
return -1;
}
When you create a file, open() needs an additional argument, the permission bits on the file to create.
You need to do e.g.
if ((in_fd = open(redirect_ptr[0], O_RDWR | O_CREAT, 0644) == -1)
That might not be the cause of the error you get, however if the error is "No such file or directory", then that's precisely what is wrong, you program cannot find the file.
Perhaps you have some non-printable characters in the file name, or the name ends with a space or newline or similar, or you spelled the name wrong, or have the wrong case, or the path is a relative path that doesn't match the file based on the current working directory of your process.
It's often helpful to print the filename inside a pair of '' , so you can see if there's some whitespace that should not be there. add a
printf("Filename: '%s'\n",redirect_ptr[0]);
to your code. And if it looks good, do a ls -l on the filename it prints out, standing in the working directory of the process.
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.
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.
Use access() to check for permissions.