[net.unix-wizards] Usefulness of access

mark@laidbak.UUCP (09/23/83)

NOTE: This is in response to an article in net.bugs, asking for an
      eaccess() system call to check permissions based on effective
      user- and group-ids. I've added net.unix-wizards to the news
      group list, since it belongs there, but shouldn't be stranded
      from the original article.

Rather than another application-specific system call, how about a
more general solution:

	int permiss(path, uid, gid)
	char	*path;
	int	uid;
	int	gid;

Permiss() determines filesystem permissions to 'path' by user 'uid' in
group 'gid'. Returns a value built up from 04 for read-, 02 for write-
and 01 for execute-access.

Permiss() could even replace access(), with a compatibility function
in libc:

extern int
access(path, mode)
char	*path;
int	mode;
{
	return ((permiss(path, getuid(), getgid()) & mode) == 0 ? -1 : 0);
}

This is still a partially-baked idea, but I believe it to be "cleaner"
than access(), and preferable to adding yet another system call.

			Mark Brukhartz
			..!{allegra,ihnp4,ittvax,trsvax}!laidbak!mark

lee@rochester.UUCP (Lee Moore) (09/25/83)

Actually this is a great idea.  I wanted such a function a long-time
ago for an "ftp" server that I wrote.  The server had to run as root
but create files as if it were a specific user.  I believe somebody from
Stanford posted a query to Unix-Wizards about this same subject some time
ago.
-- 
	 = lee@rochester
	       rochester!lee =

dave@utcsrgv.UUCP (Dave Sherman) (09/25/83)

Pardon me, but surely open(2) will do fine when you want to find out
whether the *effective* UID has permission to get to a file?!!!

I recently ran into a case where I wanted a setUID-root program,
which flips my phone line from originate to answer mode, to check
whether anyone (e.g., cu or uucico) has the line open with TIOCEXCL.
The driver allows root to stomp in on top of a TIOCEXCL. The suggested
access(2) using the real UID would have worked. But who needs a new
system call? I just did:

	if((pid=fork())==0)
	{
		setuid(1);
		if(open(line,1) < 0)
			exit(1);
		exit(0);
	}
	wait(&status);
	if(status)
	{
		/* do whatever you'd do if you couldn't open the line */
	}

Sure it's a little ugly, and requires a fork, but it's a heckuva lot
better than a new system call! (This is on v7 on an 11/23, by the way.)
[Of course, I have to fork since after the setuid(1) you can't setuid
back to 0 to do the work of changing the line status.]

Dave Sherman
-- 
 {cornell,decvax,ihnp4,linus,utzoo,uw-beaver}!utcsrgv!lsuc!dave

kendall@wjh12.UUCP (Sam Kendall) (09/26/83)

I have a function which simulates access(2) for effective UID.
If a lot of people are interested in it, I'll post it to the
net.  But it's not hard to write; if someone else wants to submit
their version, that's fine, since mine is not on a machine
with net access, and will otherwise take time to submit.

	Sam Kendall			{allegra,ihnp4}!wjh12!kendall
	Delft Consulting Corporation	  decvax!genrad!wjh12!kendall

mark@laidbak.UUCP (Mark Brukhartz) (09/26/83)

In response to spanky!ka, regarding a proposed replacement for access(2):

	I see little need for a function to check for access permission on a
	file by the effective user/group id.  Simply doing a stat(2) on the
	file will achieve the same result.

An eaccess(2) has been proposed to check access by effective user- and group-
ids. Rather than adding another single-purpose system call, I'd rather replace
access(2) with a more general case. There would, of course, be a compatibility
function in libc. Note that stat(2) doesn't check parent directory permissions.

	The problems with the proposed pathaccess system call are twofold.
	First, it would require a lot more work to implement than access.
	Access simply resets the effective id's temporarily and calls nami
	to check the permissions; the proposed new call would have to do its
	own path search.

I didn't say that it would be easy [:-)].

	The second problem has to do with security. Access will perform a
	directory search even if the effective user id doesn't have execute
	permission on a directory. In the case of the more general call, care
	would have to be taken to ensure that such searches didn't create a
	security hole.

Now things become messier. Directory access would have to be restricted by
the effective user- and group-ids of the invoker. This would break access()
when a component directory can by "executed" by the real user- and group-ids,
but not the effective ones. Perhaps this would all be easier with stacked
user- and group-ids, but that "improvement" has been argued already. Oh, well...

				Mark Brukhartz
				..!{allegra,ihnp4,ittral,trsvax}!laidbak!mark

mjb@brunix.UUCP (Mike Braca) (09/27/83)

Here is eaccess for 4.1c BSD:

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/errno.h>

/*
 * Like access(2) except uses effective uid/gid.
 * 4.1c BSD version.
 */

eaccess(filename, mode)
char *filename;
register int mode;
{
	extern int errno;
	struct stat statbuf;
	int euid = geteuid();
	mode &= 7;	/* Clear cruft */

	/*
	 * If we're trying to write, check for
	 * read-only file system or text file busy.
	 */
	if ((mode & 2) &&
	    (access(filename, 2) < 0) &&
	    (errno == EROFS || errno == ETXTBSY))
		return -1;

	/*
	 * Otherwise, superuser always passes.
	 */
	if (euid == 0)
		return 0;

	/*
	 * Stat will fail with correct error number
	 * if we don't have access.
	 */
	if (stat(filename, &statbuf) < 0)
		return -1;

	/*
	 * If we own the file, check owner bits.
	 */
	if (statbuf.st_uid == euid)
		mode <<= 6;

	/*
	 * If we're the same group as the file,
	 * check group bits.
	 */
	else if (statbuf.st_gid == getegid())
		mode <<= 3;

	/*
	 * This is the 4.1c BSD way to check group
	 * membership. 4.2 should be the same.
	 */
	else {
		int ngroups = NGROUPS;	/* from <sys/param.h> */
		int groups[NGROUPS];
		getgroups(&ngroups, groups);
		while (--ngroups >= 0)
			if (groups[ngroups] == statbuf.st_gid) {
				mode <<= 3;
				break;
			}
	}

	/*
	 * Otherwise we are checking "world" bits.
	 * See if the requested access matches the
	 * file permissions.
	 */
	if ((mode & statbuf.st_mode) != mode) {
		errno = EACCES;	/* sic */
		return -1;
	}
	return 0;
}

Mike Braca, Brown U. Institute for Research in Information and Scholarship
{ihnp4,allegra,decvax}!brunix!mjb, mjb.Brown@UDel-Relay, MJB@BROWNCS.BITNET

dan%bbncd@sri-unix.UUCP (09/28/83)

From:  Dan Franklin <dan@bbncd>

While I don't really see the need for pathaccess, if it
were needed it would not be hard.  Just as access()
replaces the effective u/gid with the real ones temporarily,
pathaccess() would replace the effective u/gid with the
arguments, and call nami just as access does.

	Dan

SHAWN%mit-ml@sri-unix.UUCP (09/29/83)

From:  Shawn F. McKay <SHAWN@mit-ml>


For one thing, if the program is SETUID root, just 'try to access the file'
does not work. (i.e. you will allways win, less the files not there).
Then again, I am not so sure that access would be much more useful if
you were root, but I think its clear how it would be useful to have
some system call that takes uid, and gid as args, when running
from a setuid program.

		Yours In Hacking(c),
		   -Shawn

CopyRight 1983, All Rights Reserved,

gwyn%brl-vld@sri-unix.UUCP (09/29/83)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

That is correct behavior, since you were asking for a way to check
access for the effective UID.  Set-UID root makes your effective UID 0,
trying to access the file wins, and that is correct.

gwyn@brl-vld@sri-unix.UUCP (10/02/83)

From:      Doug Gwyn (VLD/VMB) <gwyn@brl-vld>

The easiest way to check file access permissions for the effective
UID/GID is to try to access the file.  Why would one care otherwise?

ka@spanky.UUCP (Kenneth Almquist) (10/02/83)

I see little need for a function to check for access permission on a file
by the effective user/group id.  Simply doing a stat(2) on the file will
achieve the same result.

The problems with the proposed pathaccess system call are twofold.  First,
it would require a lot more work to implement than access.  Access simply
resets the effective id's temporarily and calls nami to check the permissions;
the proposed new call would have to do its own path search.

The second problem has to do with security.  Access will perform a directory
search even if the effective user id doesn't have execute permission on a
directory.  In the case of the more general call, care would have to be taken
to ensure that such searches didn't create a security hole.
					Kenneth Almquist