[comp.unix.wizards] access

ok@quintus.UUCP (Richard A. O'Keefe) (04/20/88)

In article <14020030@hpisod2.HP.COM>, decot@hpisod2.HP.COM (Dave Decot) writes:
> access(2) should not be used to determine the other access permissions
> except in setuid programs, and even then, not for testing execute
> access by setuid-root programs.

If a program which is never intended to run setuid ensures that it is
not being run setuid or setgid by doing
	my_uid = getuid();
	my_gid = getgid();
	if (geteuid() != my_uid || getegid() != my_gid) {
	    fprintf(stderr, "%s: must not run setuid or setgid", programname);
	    exit(1);
	}

where is the harm in subsequently using access(2) to test for permission to
read or write a file?

Is there any legitimate reason why someone might take a program which was
not originally designed to run setuid or setguid and do chmod u+s
or chmod g+s to it?

friedl@vsi.UUCP (Stephen J. Friedl) (04/21/88)

In article <887@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes:
> In article <14020030@hpisod2.HP.COM>, decot@hpisod2.HP.COM (Dave Decot) writes:
> > access(2) should not be used to determine the other access permissions
> > except in setuid programs, and even then, not for testing execute
> > access by setuid-root programs.
> 
> where is the harm in subsequently using access(2) to test for permission to
> read or write a file?
> 
> Is there any legitimate reason why someone might take a program which was
> not originally designed to run setuid or setguid and do chmod u+s
> or chmod g+s to it?

[let's call this never-to-run-setuid program "foo"]

     Probably not in the manner you suggest, but making "foo" part
of a larger, setuid/setgid system should be entirely legitimate.
The front-end program to a financial system at a customer is
called "acctmenu", and it runs set-group-id to the accounting
group.  No human is a member of that group, and the /usr/acct
directory is generally unavailable to all by the accounting
system.  Acctmenu calls up menus, reports, forms, and *scripts*,
all as the accounting group.

     If "foo" is called by this script and it uses access(2) just
to see if a file is around, it will break almost every time.  We see
this all the time with the Sys V shell, the Informix database,
mkdir(1), and other programs that either use access(2) in a lazy
manner or don't do it entirely correctly.

     Please, if you don't fully understand the difficulties
we claim then you probably don't understand access(2) enough
to be using it correctly.  Send mail with questions if you want
to learn the right way, but please don't use it.  Trust us.

-- 
Steve Friedl       V-Systems, Inc.      Resident access(2) basher
friedl@vsi.com   {backbones}!vsi.com!friedl    attmail!vsi!friedl

chris@mimsy.UUCP (Chris Torek) (04/21/88)

In article <887@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard
A. O'Keefe) writes:
>If a program which is never intended to run setuid ensures that it is
>not being run setuid or setgid by doing
[edited]
>	if (geteuid() != getuid() || getegid() != getgid()) {
>	    fprintf(stderr, "%s: must not run setuid or setgid", programname);
>	    exit(1);
>	}
>where is the harm in subsequently using access(2) to test for permission to
>read or write a file?

None.  But the code above may prove harmful:

>Is there any legitimate reason why someone might take a program which was
>not originally designed to run setuid or setguid and do chmod u+s
>or chmod g+s to it?

Possibly not.  Certainly I cannot think of any offhand.  But if this
program might be run from another program that *is* setuid, the code
above will print an error and stop: in 4BSD, at least, exec() does
not touch the IDs if the program being exec'ed is not set-ID.  So
some *other* set-ID program may cause this one to fail.

(Of course, each set-ID program can always do

	setgid(getegid()); setuid(geteuid());

before attempting to run other programs, but few do.  Then again,
there are few set-ID programs that run other programs....)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

mike@turing.UNM.EDU (Michael I. Bushnell) (04/21/88)

In article <887@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>In article <14020030@hpisod2.HP.COM>, decot@hpisod2.HP.COM (Dave Decot) writes:
>> access(2) should not be used to determine the other access permissions
>> except in setuid programs, and even then, not for testing execute
>> access by setuid-root programs.
>
>If a program which is never intended to run setuid ensures that it is
>not being run setuid or setgid by doing

[Code fragment to test for suid conditions]

>where is the harm in subsequently using access(2) to test for permission to
>read or write a file?
>
>Is there any legitimate reason why someone might take a program which was
>not originally designed to run setuid or setguid and do chmod u+s
>or chmod g+s to it?


Not really.  But there is another way it can run under suid
conditions:

% whoami
foo
% su
Password:
# nifty_program


Note that nifty program will now have REAL uid foo and EFFECTIVE uid
root.


                N u m q u a m   G l o r i a   D e o 

			Michael I. Bushnell
			HASA - "A" division
14308 Skyline Rd NE				Computer Science Dept.
Albuquerque, NM  87123		OR		Farris Engineering Ctr.
	OR					University of New Mexico
mike@turing.unm.edu				Albuquerque, NM  87131
{ucbvax,gatech}!unmvax!turing.unm.edu!mike

limes@sun.uucp (Greg Limes) (04/21/88)

In article <887@cresswell.quintus.UUCP>, ok@quintus.UUCP (Richard A. O'Keefe) writes:
> In article <14020030@hpisod2.HP.COM>, decot@hpisod2.HP.COM (Dave Decot) writes:
> > access(2) should not be used to determine the other access permissions
> > except in setuid programs, and even then, not for testing execute
> > access by setuid-root programs.

> If a program which is never intended to run setuid ensures that it is
> not being run setuid or setgid by [aborting if getuid() != geteuid()]
> where is the harm in subsequently using access(2) to test for permission to
> read or write a file?

> Is there any legitimate reason why someone might take a program which was
> not originally designed to run setuid or setguid and do chmod u+s
> or chmod g+s to it?

Occasionally I need to do a single command, as a different uid -- bin,
daemon, games, whatever; usually an install, or changing a
configuration file, or whathaveyou. So, I have a little utility that
checks for permission, sets the effective user id, and execs the
requested command. A program as described above would detect that it is
running "setuid", and fail. So, it is not necessary to actually set the
setuid and setgid bits on a program for the real and effective uids to
be different.

I would like to pose a modified version of your question back at you:
Is there any legitimate reason why someone might need to disable
switchuser-ed access to a program? (not a flame, an invitation for
discussion ... I use this little utility quite a lot, and in fact rarely
log in a "root" or start a root shell, even when configuring kernels).

-- Greg Limes [limes@sun.com]			frames to /dev/fb

les@chinet.UUCP (Leslie Mikesell) (04/21/88)

In article <11144@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>(Of course, each set-ID program can always do
>	setgid(getegid()); setuid(geteuid());
>before attempting to run other programs, but few do.  Then again,
>there are few set-ID programs that run other programs....)

Uuxqt is perhaps a notable execption?  Switching to the real uid
(which is likely to be some random person that sent mail recently)
would probably not be a good idea...


  Les Mikesell

ok@quintus.UUCP (Richard A. O'Keefe) (04/21/88)

In article <50280@sun.uucp>, limes@sun.uucp (Greg Limes) writes:
>                             So, it is not necessary to actually set the
> setuid and setgid bits on a program for the real and effective uids to
> be different.
  
This is the key point I had forgotten.

> I would like to pose a modified version of your question back at you:
> Is there any legitimate reason why someone might need to disable
> switchuser-ed access to a program?

Yes, there is.  Someone providing a programming system such as a Lisp or
SmallTalk interpreter might want to do this to reduce the chance of their
being held liable for loss or damage due to a security bug.  (Ok, this is
a wee bit paranoid, but I am a devout comp.risks reader.)

decot@hpisod2.HP.COM (Dave Decot) (04/21/88)

> >> AAAAAAAAAARGH!  Please do not use access(2) as a handy-dandy
> >> "does the file exist?" function.  It is designed to be used
> >> by set-{user,group}-id programs to see if the underlying user
> >> has permission to access the file in the requested manner.
> 
> >Uh...I think a file's existence is independent of your user-id.
> 
> Nope.  A file can be said to "exist" for a process if you can SEARCH
> ALL THE DIRECTORIES in the path leading to the file.  So, if you are
> under suid conditions, use access for F_OK, then you will get
> misleading results if a directory along the path wasn't searcheable
> for your real uid.

Sounds to me like a weird definition of "exist", but apparently
most implementations of access(2) agree with you.  I just tried
it out, and you're right.

> >It's perfectly acceptable to use access(2) the F_OK (0) value of amode
> >it to determine whether files exist.  Such calls succeed exactly when
> >calls to stat(2) succeed.
> 
> So, DON'T use access(2) EVER unless you are a suid program (or have
> done setuid(geteuid()) (which is really perverse in non-suid programs).

If the process has chdir()'ed to the directory where it is thinking of
accessing the file, there can be no harm in seeing whether the file
is here or not.

However, given what you've said about the other cases, I'll use stat()
in this case as well.

> >access(2) should not be used to determine the other access permissions
> >except in setuid programs, and even then, not for testing execute
> >access by setuid-root programs.
> 
> Why not?  What if I have a suid program which executes a given user
> program in a funky way, with appropriate permission settings, but it
> needs to determine if it will be able to run the program before is
> does its funky stuff (to wit):

It does not correctly detect whether the superuser can execute
files with mode 0.  access() always returns 0 if the ruid is superuser
and the file exists, even if no execute bits are turned on for the file.
Such files cannot actually be executed, even by the superuser.

Dave Decot
hpda!decot

mwp@munnari.oz (Michael Paddon) (04/22/88)

in article <975@unmvax.unm.edu>, mike@turing.UNM.EDU (Michael I. Bushnell) says:
>
>>Is there any legitimate reason why someone might take a program which was
>>not originally designed to run setuid or setguid and do chmod u+s
>>or chmod g+s to it?
> 
> Not really.  But there is another way it can run under suid
> conditions:
> 
> % whoami
> foo
> % su
> Password:
> # nifty_program
> 
> Note that nifty program will now have REAL uid foo and EFFECTIVE uid
> root.

"Su" on all the BSD and SunOs systems I have come across changes
both the real and effective uid/gid and the group access list.
If this were not so, many programs would not run from a "su" shell
because their authors used "access". :-) Your "su" behaviour is,
perhaps, System V madness.

In answer to the query above:
=============================
Server processes and the like are often setuid "nobody" even if
they were never originally designed to be run so (and never
take advantage of the fact). This basic security precaution
can forestall many problems.

While this was sufficient in earlier Unix versions, the ability
to swap uid/euid or to set either one to the other that BSD
now provides means that the setuid program must explicitly
revoke any priveleges that may exist.

Consider a server program (setuid "nobody") which runs arbitrary object
sent to it and which is started up by root in "rc.local". This is a
real life example -- we have one like this running at Melbourne Uni
right now.

The moral is that it is never safe to make an arbitrary program setuid.
Given the latitude allowed by current UNIX kernels in manipulating uids
a program needs to know it is setuid to take advantage of the fact, or
to cover possible security problems.

                                         Michael Paddon
                                         ==============

===========================
UUCP:	{seismo,mcvax,ukc,ubc-vision}!munnari!mwp
ARPA:	mwp%munnari.oz@seismo.css.gov
CSNET:	mwp%munnari.oz@australia

jal@occrsh.ATT.COM (J_Allen_Schones) (04/23/88)

In article <975@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
[ Much stuff deleted. ]
>Not really.  But there is another way it can run under suid
>conditions:
>
>% whoami
>foo
>% su
>Password:
># nifty_program
>
>
>Note that nifty program will now have REAL uid foo and EFFECTIVE uid
>root.
>
[ .signature deleted ]

Is nifty_program(1) :-) setuid or just a regular (non-setuid) program?
I can't speak for BSD systems, but on a 3B15 running System V Rel.
3.1.1 UNIX (trademark of AT&T), nifty_program (running non-setuid)
will have both REAL and EFFECTIVE uid set to root.  nifty_program
(running setuid) will have REAL uid root and EFFECTIVE uid foo.  su(1)
does a "setuid(geteuid())" when you run it.

Two programs:
	nifty.c:

#include <stdio.h>

main()
{
	printf("uid == %d\n", getuid());
	printf("euid == %d\n", geteuid());
}

	setuid.c:

#include <stdio.h>

main()
{
	execlp("./nifty", "nifty", 0);
}

Session follows:

$ ls -l 
total 42
-rwxr-xr-x	1 jal	user1	13536 Apr 22 12:14 nifty
-rw-r--r--	1 jal	user1	  113 Apr 22 12:02 nifty.c
-rwsr-xr-x	1 jal	user1	 5180 Apr 22 12:14 setuid
-rw-r--r--	1 jal	user1	   63 Apr 22 12:14 setuid.c
$ id
uid=326(jal) gid=300(user1)
$ ./nifty
uid == 326
euid == 326
$ ./setuid
uid == 326
euid == 326
$ su
Password: <generic root password>
# id
uid=0(root) gid=3(sys)
# ./nifty
uid == 0
euid == 0
# ./setuid
uid == 0
euid == 326

End of session.
-- 
J. Allen Schones -- AT&T -- Oklahoma City Works
 MAIL: 7725 W. Reno -- Oklahoma City, OK -- 73125 -- Dept: 11OC0307720
PHONE: (405) 491-4950		| UUCP: {AT&T}!okcedu!jal
  FAX: (405) 491-4530 Attn: Schones 0772 x4950

jas@llama.rtech.UUCP (Jim Shankland) (04/23/88)

In article <975@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
>There is another way [a program] can run under suid
>conditions:
>
>% whoami
>foo
>% su
>Password:
># nifty_program
>
>Note that nifty program will now have REAL uid foo and EFFECTIVE uid
>root.

Nope.  This seems to be a common misconception.  su alters your
real uid as well as your effective uid.

Jim Shankland
  ..!ihnp4!cpsc6a!\
               sun!rtech!jas
 ..!ucbvax!mtxinu!/

	And I will show you something different from either
	Your shadow at morning striding behind you
	Or your shadow at evening rising to meet you;
	I will show you fear in a handful of dust.

			-- T. S. Eliot

sullivan@vsi.UUCP (Michael T Sullivan) (04/23/88)

On the one side you have people giving reasons not to use access() and
on the other you have people saying "but what's the harm".  Remember,
you can use system("ls filename > /tmp/snork") to determine whether a
file exists, it's just not the best/right way.  If you can't give an
reason any better than "what's the harm" (and the stat people give good
reasons not to) then just use access().

-- 
Michael Sullivan		{uunet|attmail}!vsi!sullivan
				sullivan@vsi.com
HE V MTL

sullivan@vsi.UUCP (Michael T Sullivan) (04/23/88)

In article <594@vsi.UUCP>, sullivan@vsi.UUCP (Michael T Sullivan) writes:
> 
> file exists, it's just not the best/right way.  If you can't give an
> reason any better than "what's the harm" (and the stat people give good
> reasons not to) then just use access().
                                ^^^^^^


That should be stat().  I'm such a weenie sometimes.



-- 
Michael Sullivan		{uunet|attmail}!vsi!sullivan
				sullivan@vsi.com
HE V MTL

ok@quintus.UUCP (Richard A. O'Keefe) (04/23/88)

Recently we've heard again the negative reason not to use access(2):
it doesn't do what you'd expect if a program runs set[ug]id, and any
useful program might be run as a tool by a set[ug]id suite.

There is also a positive reason why it is better to use stat(2).
While you _can_ read a directory in UNIX, it usually doesn't make
sense.  (Some versions of UNIX now support only the BSD directory(3)
routines.)  And of course write access to a directory doesn't mean
that you can _write_ on it.  So if you want to know whether a given
path name identifies a _file_ that you can read/write/whatever, you
have to call stat(2) _anyway_ in order to find out what sort of thing
the path name identifies.  When I first ran into the access(2) problem,
I wrote two functions
	eaccess(char *path, int mode)		 /* "effective" access */
	saccess(struct stat *stat_buf, int mode) /* "stat"      access */
and was chagrined to discover that saccess() was the one I almost always
wanted, so using access(2) had been costing me an extra system call to
no good purpose.

I have wondered about posting this code to comp.sources.unix, but it
strikes me that it might be better still to extend the specification
slightly:  if the S_IFDIR bit were set in the mode, the path would
have to identify a directory, or if the S_IFREG bit were set in the
mode, the path would have to identify something other than a directory.
The test would be

	if ((stat_buf->st_mode & S_IFMT) == S_IFDIR) {
	    if (mode & S_IFREG) { errno = EISDIR;  return -1; }
	} else {
	    if (mode & S_IFDIR) { errno = ENOTDIR; return -1; }
	}

What do you think?

zeeff@b-tech.UUCP (Jon Zeeff) (04/23/88)

In article <975@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
>
>% whoami
>foo
>% su
>Password:
># nifty_program
>
>
>Note that nifty program will now have REAL uid foo and EFFECTIVE uid
>root.

That's not what I see on a Sys V.3 system.

$who am i
zeeff      cons3        Apr 22 18:58
$su
#id
uid=0(root) gid=3(sys)

Note that id claims my uid and euid are the same.



-- 
Jon Zeeff           		Branch Technology,
uunet!umix!b-tech!zeeff  	zeeff%b-tech.uucp@umix.cc.umich.edu

cudcv@daisy.warwick.ac.uk (Rob McMahon) (04/24/88)

In article <975@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
>% whoami
>foo
>% su
>Password:
># nifty_program
>
>Note that nifty program will now have REAL uid foo and EFFECTIVE uid
>root.

Well I can't speak for SYS5, but BSD certainly doesn't work that way,
and I imagine su is one of those programs that has come down unchanged
from the mists of time.  su calls setuid which sets both the real and
effective uid's.

I suppose 1001 other people are going to say this, and I ought to keep
stumm for a while, but I hate to see misinformation going round.

Rob
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick.cu          ARPA:   cudcv@cu.warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

ok@quintus.UUCP (Richard A. O'Keefe) (04/25/88)

In article <2001@rtech.UUCP>, jas@llama.rtech.UUCP (Jim Shankland) writes:
> In article <975@unmvax.unm.edu> mike@turing.UNM.EDU.UUCP (Michael I. Bushnell) writes:
> >There is another way [a program] can run under suid conditions: ...
> >% su
> >Note that nifty program will now have REAL uid foo and EFFECTIVE uid root.
 
> Nope.  This seems to be a common misconception.  su alters your
> real uid as well as your effective uid.

Nope, it's not a misconception.  Them's the facts.  Tried it just now:
% su
Password:
# wmi
root daemon     ok quintus

The SVID says "su will execute a new environment with the real and
effective user ID set to that of the specified user", though it remains
completely quiet about the group id.  However, not all UNIX systems are
System V.  Anyone know which variants do what?

ok@quintus.UUCP (Richard A. O'Keefe) (04/25/88)

I just said that "Them's the facts" about su(1) not changing the real
uid and gid, and exhibited a wee transcript to prove it.  I should read
the manual more closely, I really should.  The 'wmi' command reports
the effective and _LOGIN_ uid&gid, not the effective and _real_ uid&gid.

There are three things:
    -	the effective uid and gid (geteuid(), getegid())
    -	the real uid and gid (getuid(), getgid())
    -	who you logged in as (getlogin(), followed by getpwnam())
and all of them are discoverable.  su changes the first two but not the
third.

If I learn from my mistakes, pretty soon I'll know everything.

limes@sun.uucp (Greg Limes) (04/26/88)

In article <898@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>The SVID says "su will execute a new environment with the real and
>effective user ID set to that of the specified user", though it remains
>completely quiet about the group id.  However, not all UNIX systems are
>System V.  Anyone know which variants do what?

SunOS version 4.0 "su" sets both the real and effective userid, and
both real and effective group id; I have not investigated what it does
to the group list. I keep on hand a nifty little utility called "be"
that sets only the effective userid; it comes in handy quite often.
-- 
   Greg Limes [limes@sun.com]				frames to /dev/fb

chris@mimsy.UUCP (Chris Torek) (04/27/88)

In article <13113@brl-adm.ARPA> mouse@larry.mcrcim.mcgill.edu (der Mouse)
writes:
>What we need, it seems, is a way to say "I wish to restrict myself to
>the real user's access privileges" for a time, with the potential to
>revert back to the previous state.  4.3's setreuid() appears to be
>exactly this

It does.

>though I seem to recall that if the real uid is 0, the process has
>superuser access even if the effective uid is not 0 ...

Not so.

The proper way to test the validity of operation X `before' doing
operation X is to write:

	uid_t ruid, euid; gid_t rgid, egid;
	ruid = getuid(), euid = geteuid(); /* there should be getreuid */
	rgid = getgid(), egid = getegid(); /* and getregid interfaces. */
	...

	int
	do_restricted_operation(op, arg)
		int (*op)();
		caddr_t arg;
	{
		int result, saverr;

		/* this should never fail */
		if (setregid(egid, rgid) || setreuid(euid, ruid))
			panic("setre?id 1");
		result = (*op)(arg);
		/* note that successful syscalls are allowed to alter errno */
		saverr = errno;
		if (setregid(rgid, egid) || setreuid(ruid, euid))
			panic("setre?id 2");
		errno = saverr;
		return (result);
	}

In practise, one would just do the desired operation directly.
To use this particular encapsulation correctly, one must write,
for instance,

	struct open_context {
		char	*path;
		int	flags;
		int	mode;
	};

	int
	do_open(arg)
		caddr_t arg;
	{
		struct open_context *c = (struct open_context *)arg;

		return (open(c->path, c->flags, c->mode));
	}
	...
		struct open_context c;
		int fd;

		c.path = "/some/file/name";
		c.flags = O_CREAT|O_RDWR|O_EXCL;
		c.mode = 0600;
		fd = do_restricted_operation(do_open, (caddr_t)&c);

This is quite a bother; it would be nice if C had a `package
up some arguments into a generic argument blob' operation and
an `expand generic argument blob into real arguments' operation,
so that one could write instead

		fd = do_restricted_operation(open,
			[["/some/file/name", O_CREAT|O_RDWR|O_EXCL, 0600]]);

and inside do_restricted_operation itself,

		result = (*op)(<< arg);

(presuming that [[...]] is the argument-builder and unary << is the
argument exploder).  An equivalent if less compact representation
would be unnamed functions (a C version of lambda :-) ) and aggregates:

		fd = do_restricted_operation(
			int (void *arg) {
				struct open_context *c = arg;
				return (open(c->path, c->flags, c->mode));
			},
			(void *) &(struct open_context) {
				"/some/file/name", O_CREAT|O_RDWR|O_EXCL, 0600
			});

which requires no exploder operation.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

mike@turing.UNM.EDU (Michael I. Bushnell) (05/01/88)

In article <2089@munnari.oz> mwp@munnari.oz (Michael Paddon) writes:
>in article <975@unmvax.unm.edu>, mike@turing.UNM.EDU (Michael I. Bushnell) says:
>> [Here I made a stupid mistake about the behavior of su(1).]

>"Su" on all the BSD and SunOs systems I have come across changes
>both the real and effective uid/gid and the group access list.
>If this were not so, many programs would not run from a "su" shell
>because their authors used "access". :-) Your "su" behaviour is,
>perhaps, System V madness.

I KNOW, now.  I foolishly posted first and checked later.  We run REAL
4.3 BSD...I just goofed.  From the myriad of mail and other related posts,
I gather that the SysV behavior is the same as the BSD.
                N u m q u a m   G l o r i a   D e o 

			Michael I. Bushnell
			HASA - "A" division
14308 Skyline Rd NE				Computer Science Dept.
Albuquerque, NM  87123		OR		Farris Engineering Ctr.
	OR					University of New Mexico
mike@turing.unm.edu				Albuquerque, NM  87131
{ucbvax,gatech}!unmvax!turing.unm.edu!mike

gore@eecs.nwu.edu (Jacob Gore) (09/15/88)

Suppose you have this situation:
----------------------------------------------------
	drwxrwxr-x usera groupa /tmp/jjj
	-rwxr-sr-x usera groupa a.out (provided below)

I am now userb/groupb.  userb in NOT listed in /etc/group entry for groupa.
	
a.out is:

main(){
    if (access("/tmp/jjj", 2) < 0) perror("directory");
}
----------------------------------------------------

Now, what I want to happen is for 'access' to fail -- in my application,
since the directory is not writable by userb/groupb, userb/groupb user
should not be able to use such a setgid program to create files in it.

But when I run this on 4.3BSD, 'access' succeeds.  The manual entry for
access(2) says:

     The real user ID and the group access list (including the
     real group ID) are used in verifying permission, so this
     call is useful to set-UID programs.

But what about set-Gid programs?  Is the effective gid automatically in the
group access list?

If so, what can I do to let such a setgid program check whether
userb/groupb is actually allowed to create files in a directory?

Jacob Gore				Gore@EECS.NWU.Edu
Northwestern Univ., EECS Dept.		{oddjob,gargoyle,att}!nucsrl!gore

guy@auspex.UUCP (Guy Harris) (02/11/89)

>Hmmm...as I understand it, this disallows pathnames of the form
>"//filename" and is ambiguous about pathnames of the form
>"filename//filename".

Well, what it says after that is:

	Multiple successive *slashes* are considered the same as one
	*slash*.  A pathname that begins with two successive *slashes*
	may be interpreted in an implementation-defined manner, although
	more than two leading *slashes* shall be treated as a single
	*slash*.

So it doesn't disallow "//filename", although it indicates that it may
not do what you think it does, and explicitly indicates that
"filename//filename" is the same as "filename/filename".

>This is not very UNIX-like.

No, but it *is* somewhat Aegis-like; it permits
"//nodename/filename/filename..." to mean "file '/filename/filename...'
on node "nodename" (or whatever it means on Aegis/DOMAIN/OS).  I'm quite
able to live with that trivial restriction in my applications. 

peter@ficc.uu.net (Peter da Silva) (02/16/89)

In article <999@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:
> 	Multiple successive *slashes* are considered the same as one
> 	*slash*.  A pathname that begins with two successive *slashes*
> 	may be interpreted in an implementation-defined manner, although
> 	more than two leading *slashes* shall be treated as a single
> 	*slash*.

So someone should tell the people doing HDB uucp to stop converting:

	//node/path/file

into:

	/node/path/file

so we could access remote nodes on our net from our new System V box.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
Opinions may not represent the policies of FICC or the Xenix Support group.

guy@auspex.UUCP (Guy Harris) (02/18/89)

 >So someone should tell the people doing HDB uucp to stop converting:
 >	//node/path/file
 >into:
 >	/node/path/file
 >so we could access remote nodes on our net from our new System V box.

I'm not sure what you're trying to say here, but I'm sure you realize
that, unless you're running Domain/OS or something like it on "your new
System V box", merely changing HDB not to do that won't have that
effect.  I shall therefore assume that you're trying to make some sort
of point here.

If you're trying to say "interpreting '//' specially is a stupid idea",
I'll let the Apollo people respond to that one.

If you're trying to say "programs shouldn't have to worry about whether
'//' means something special or not", sorry, but POSIX seems to indicate
that perhaps programs *should* worry about it.  POSIX-conformant
programs can't *depend* on '//' meaning something special, but they must
be prepared for it to mean something special. 

The fact that HDB performs that transformation really says nothing other
than that the people who wrote the code to do that thought it was OK to
do so; since they were, I think, all running on systems with
more-or-less AT&T-derived file system handling code (or code written to
behave pretty much like said code), they probably either didn't think
about systems where '//' means something special or didn't care about
them. 

peter@ficc.uu.net (Peter da Silva) (03/03/89)

In article <1040@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:
>  >So someone should tell the people doing HDB uucp to stop converting:
>  >	//node/path/file
>  >into:
>  >	/node/path/file
>  >so we could access remote nodes on our net from our new System V box.

OK. Our new system V box is just... System V. The name on the front is
Unisys, but it's really an Arix box. The CPU is a 68020.

Our old boxes are Xenix 286 3.5, based on System III. They are running a
network called "OpenNET" that uses the syntax:

	//node/path/file

to access files on another node. OK. We're a freindly bunch. We let the
System V box access the whole net. Or we try to.

	sysv% uucp xenix1!//xenix2/usr/fred/project/code.plm code.plm

Sounds good. Except BNU decides that "//" is a typo, and changes it to "/".
Then xenix1 sees "/xenix2/..." and can't find the file.

I can't think of a good reason for it to perform this translation. Can
you?

> The fact that HDB performs that transformation really says nothing other
> than that the people who wrote the code to do that thought it was OK to
> do so; since they were, I think, all running on systems with
> more-or-less AT&T-derived file system handling code (or code written to
> behave pretty much like said code), they probably either didn't think
> about systems where '//' means something special or didn't care about
> them. 

Ah, but AT&T systems have no problem with "//" or "///" or "/////", so there
should be no advantage to doing this.

You want to know what my point is... it's simply this: if it's not broken,
why did they decide to fix it? It causes problems in the feild. They should
take the code out again.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Work: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.   `-_-'
Home: bigtex!texbell!sugar!peter, peter@sugar.uu.net.                 'U`
People have opinions. Companies have policy. And typos are my own business.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/03/89)

In article <3281@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>Ah, but AT&T systems have no problem with "//" or "///" or "/////", ...

IEEE 1003.1 requires that consecutive slashes be allowed and in effect
be interpreted as a single slash.  (Thus OpenNet's convention would not
be POSIX-compliant.)

The only reason I can think of for an application to merge adjacent
slashes is to compensate for sloppy programming.

rml@hpfcdc.HP.COM (Bob Lenk) (03/08/89)

> IEEE 1003.1 requires that consecutive slashes be allowed and in effect
> be interpreted as a single slash.  (Thus OpenNet's convention would not
> be POSIX-compliant.)

1003.1 makes an explicit exception for // at the start of a pathname,
precisely because of networked file systems like this.  Three or more
slashes at the beginning of a pathname or two or more anywhere else
are equivalent to a single slash.  This was the topic of considerable
debate, and varied among drafts.

		Bob Lenk
		hplabs!hpfcla!rml
		rml%hpfcla@hplabs.hp.com

karish@forel.stanford.edu (Chuck Karish) (03/11/89)

In article <5980045@hpfcdc.HP.COM> rml@hpfcdc.HP.COM (Bob Lenk) wrote:
>> IEEE 1003.1 requires that consecutive slashes be allowed and in effect
>> be interpreted as a single slash.  (Thus OpenNet's convention would not
>> be POSIX-compliant.)

>1003.1 makes an explicit exception for // at the start of a pathname,
>precisely because of networked file systems like this.  Three or more
>slashes at the beginning of a pathname or two or more anywhere else
>are equivalent to a single slash.  This was the topic of considerable
>debate, and varied among drafts.

	Where does this show up in the standard?  I've looked in the
	entry for 'pathname resolution' (IEEE Std 1003.1-1988, Chapter
	2.4, p. 36) and can find no such exception described.

	The only relevant requirement I found says "If the pathname
	begins with a slash, the predecessor of the first filename in
	the pathname is taken to be the root directory of the process[.]"

	Since a filename may not contain a slash, this means that
	two leading slashes are equivalent to a single slash.

	Chuck Karish	karish@denali.stanford.edu
			hplabs!hpda!mindcrf!karish
			(415) 493-7277

guy@auspex.UUCP (Guy Harris) (03/14/89)

>	Where does this show up in the standard?

P. 32:

	*pathname*.  A string that is used to identify a "file".  ...
	A *pathname* that beings with two successive *slashes* may be
	interpreted in an implementation-defined manner, although more
	than two leading *slashes* should be treated as a single *slash*.

rml@hpfcdc.HP.COM (Bob Lenk) (03/14/89)

>	Where does this show up in the standard?  I've looked in the
>	entry for 'pathname resolution' (IEEE Std 1003.1-1988, Chapter
>	2.4, p. 36) and can find no such exception described.

See the definition of "pathname" in section 2.3 (p 32).  The rationale
discusses it under "pathname resolution" in B.2.4.

		Bob Lenk
		hplabs!hpfcla!rml
		rml%hpfcla@hplabs.hp.com

m5@lynx.uucp (Mike McNally) (06/06/89)

Is it appropriate that access("somefile", X_OK) always succeeds
(returns 0), whether "somefile" has an "x" bit or not, when called
while the eff. user id is root?

For the curious, I tested this under 4.3BSD on my Integrated
"Solutions" 68020 box with the following program:

main(ac, av)
int ac;
char **av;
{
    printf("%d\n", access(av[1], atoi(av[2])));
}

The program is invoked as "t something 1".  When run on a particular
file while not setuid to root, it prints -1 for a plain text file
without any "x" bits.  After I setuid to root, the exact same
invocation prints 0.  Of course, even while setuid, an attempt to
execute the file fails with EACCES.

Note that I don't want to start another war about the usefulness of
access().

-- 
Mike McNally                                    Lynx Real-Time Systems
uucp: {voder,athsys}!lynx!m5                    phone: 408 370 2233

            Where equal mind and contest equal, go.