Question regarding UNIX access() call - Unix
This is a discussion on Question regarding UNIX access() call - Unix ; Hi,
I was wondering if there is a function similar to access(2), but one
that uses *effective* userid and groupid rather than *real*?
For instance, in order to test whether the process has execute
permissions on the file I can ...
-
Question regarding UNIX access() call
Hi,
I was wondering if there is a function similar to access(2), but one
that uses *effective* userid and groupid rather than *real*?
For instance, in order to test whether the process has execute
permissions on the file I can call access(file, X_OK). However, I want
to check if my effective UID/GID and supplementary groups allow me to
execute this file. How can I do this kind of check?
I can certainly read the access control list using libacl, but I
guess there must be simpler way to do it.
Checking for read and write permissions is easy - I can just open the
file in read or write mode and check the return value of open(). In
case of execute I dont want to just execute the file since the process
that is performing this check is a networked file server which is
processing the requests from remote users. That is, the remote client
checks with the file server to see if the user can execute this file
(by forwarding the access request to the server). The file server
which is running as root switches its effective uid and gid to that of
the requester and then performs the requested operation.
What would be a good way to handle this?
Thanks in advance.
-Fantoosh
-
Re: Question regarding UNIX access() call
On Jul 31, 9:05 pm, Fantoosh B wrote:
> I was wondering if there is a function similar to access(2), but one
> that uses *effective* userid and groupid rather than *real*?
Not that I know of.
> What would be a good way to handle this?
Swap the process's effective and real uids and gids using setreuid()
or setresuid() and one of their gid equivalents, call access(), then
swap them back. Issues:
1) if one of the set* calls fails, the process is screwed
(this is probably a "can't happen", but to be safe in the face of
OS
changes you better test and die if one fails. Linux capabilities
made
it possible for setuid() to fail for root, creating security holes
in several
programs...)
2) this is probably too painful if the process is multithreaded
3) setreuid() and setresuid() aren't as portable as one might wish.
Philip Guenther
-
Re: Question regarding UNIX access() call
Fantoosh B writes:
>I was wondering if there is a function similar to access(2), but one
>that uses *effective* userid and groupid rather than *real*?
Not a standard one. (Solaris, e.g., has eaccess() in a separate library
and a secret "E_OK" flag which you can or in to the access flags)
>For instance, in order to test whether the process has execute
>permissions on the file I can call access(file, X_OK). However, I want
>to check if my effective UID/GID and supplementary groups allow me to
>execute this file. How can I do this kind of check?
>I can certainly read the access control list using libacl, but I
>guess there must be simpler way to do it.
You are approaching this incorrectly because you can never be sure
you can execute a program before you actually executed it.
Is there any reason why you can't "just do it"?
Casper
-
Re: Question regarding UNIX access() call
I am running Linux and setresuid did the trick for me. Heres the
simple function to switch ids. Thanks.
/* Changes uid and gids to that of the requesting user */
int set_access_ids(uid_t fsuid, uid_t fsgid, size_t num_sgrps, const
gid_t *sgrps){
/* Root uid and gid is disallowed */
if(fsuid == ROOT_UID || fsgid == ROOT_GID)
return -1;
int i = 0;
for( i = 0; i < num_sgrps; i++){
if(sgrps[i] == 0) return -1;
}
/* Lets change the ids */
if(setresuid(ROOT_UID, ROOT_UID, ROOT_UID) < 0) return -1; //
Escalate to root
if(setresgid(ROOT_UID, ROOT_GID, ROOT_GID) < 0) return -1;
if(setgroups(1, &fsgid) < -1) return -1; /* Wipe out previous
* supplementary groups */
if(setresgid(fsgid, fsgid, fsgid) < 0) return -1; /* Drop
* privileges to
* that of the
* user */
if(num_sgrps > 0) {
if(setgroups(num_sgrps,sgrps) < 0) return -1;;
}
if(setresuid(fsuid, fsuid, ROOT_UID) < 0) return -1; /* Always set
* the euid at
* the last */
return 0;
}
On Jul 31, 10:49 pm, "guent...@gmail.com" wrote:
> On Jul 31, 9:05 pm, Fantoosh B wrote:
>
> > I was wondering if there is a function similar to access(2), but one
> > that uses *effective* userid and groupid rather than *real*?
>
> Not that I know of.
>
> > What would be a good way to handle this?
>
> Swap the process's effective and real uids and gids using setreuid()
> or setresuid() and one of their gid equivalents, call access(), then
> swap them back. Issues:
> 1) if one of the set* calls fails, the process is screwed
> (this is probably a "can't happen", but to be safe in the face of
> OS
> changes you better test and die if one fails. Linux capabilities
> made
> it possible for setuid() to fail for root, creating security holes
> in several
> programs...)
> 2) this is probably too painful if the process is multithreaded
> 3) setreuid() and setresuid() aren't as portable as one might wish.
>
> Philip Guenther
-
Re: Question regarding UNIX access() call
On Aug 1, 12:18 pm, Casper H.S. Dik wrote:
> Fantoosh B writes:
> >I was wondering if there is a function similar to access(2), but one
> >that uses *effective* userid and groupid rather than *real*?
>
> Not a standard one. (Solaris, e.g., has eaccess() in a separate library
> and a secret "E_OK" flag which you can or in to the access flags)
>
> >For instance, in order to test whether the process has execute
> >permissions on the file I can call access(file, X_OK). However, I want
> >to check if my effective UID/GID and supplementary groups allow me to
> >execute this file. How can I do this kind of check?
> >I can certainly read the access control list using libacl, but I
> >guess there must be simpler way to do it.
>
> You are approaching this incorrectly because you can never be sure
> you can execute a program before you actually executed it.
I am writing a networked file system. The file server is a user-space
process that receives requests from the clients and processes them.
The client file system is built using FUSE(http://
fuse.sourceforge.net/), which is also in the user-space. Now, If a
process wants to check if it can perform a particular operation on a
file R,W,X etc, then at the client side, I can let the OS take care of
these checks based on the results retured by the stat (and getxattr
for posix acls) calls from the client. However, for this to work uids
and gids on the server and the client machine have to be synchronized,
which is not happening in my case yet. Instead, FUSE lets my file
system to trap the access() system call. This is nice because then the
client filesystem can simply transfer the access call across to the
server and the server can perform the check. For example, strace of vi
shows that before opening a file vi calls: access(foo.txt, R_OK),
access(foo.txt,W_OK). If the second access() call is successful VI
does all kinds of strange things: creates foo.tmp, deletes the
foo.txt, and then creates foo.txt again and copies foo.tmp to foo.txt.
So if my uid and gids are not synchorized, the client side access()
function has no way to accurately check the rights. A wrong response
to the second access() call screws up the foo.txt. Instead, I forward
the access() call to the server and the server switches ids and
performs a local access().
Since the server is doing the check, I dont want the server to
unecessarily execute the users file ( which is dangerous as well since
the server is running as root).
Certainly, in case of X_OK a successful access() does not necessarily
indicate that a user can execute the file (execv can still fail), but
in this case the client is just trying to get a hint whether it can
attempt to execute the file. Also, right now I am not to worried about
portability. Please let me know if I am on a totally wrong path. Thank
you.
>
> Is there any reason why you can't "just do it"?
>
> Casper