Newsgroups: comp.unix.wizards
Path: utzoo!utgpu!jarvis.csri.toronto.edu!ai.toronto.edu!rayan
From: rayan@ai.toronto.edu (Rayan Zachariassen)
Subject: setreuid() functionality in sysV
Message-ID: <1988Jan19.192854.3411@jarvis.csri.toronto.edu>
Organization: University of Toronto, AI group
Date: Tue, 19-Jan-88 19:28:54 EST

I'm trying to simulate the effect (within a root process) of the BSD construct:

	setreuid(0, uid);
	...
	setreuid(0, 0);

The important thing being that the '...' is run with effective uid 'uid',
and that both real and effective uid are restored to 0 afterwards.

Now, the SysV manual for setuid() says that

	setuid(uid);
	...
	setuid(0);

is possible iff 0 is the "saved set_user id" and refers to exec(2).
Of course, exec(2) doesn't mention this concept.  What does "saved set_user id"
mean? That the suid bit is set on the executable and this is the owner of
the binary, or that it is the uid that actually did the exec'ing (uid of
parent)?

So, we tried it under SysVr2v4 (no, this is not crypt output...) on a
Honeywell box, the token System V machine here.

Apparently, the documented behaviour refers to neither of the two possibilities
hypothesized.  If anyone knows how to achieve the desired result under
some System V (without using fork()), pray tell.

Incidentally, the '...' is essentially an fopen call.  Can't use access();
for one thing it is junk, for another it tests on the real uid anyway, which
brings us back to the problem at hand.

You can also tell me it can't be done, in which case this program will
allow astute persons to deduce the contents of files they can't read, and
aren't allowed to access. :-( How does one write secure code under System V
without using zillions of forks? (that's rhetorical).

Incidentally, I was reminded that the SVID mumbles something about setuid()
making use of the original uid/gid's of the process.  Might this mean that
(some versions of) System V and the SVID are different in these details?
If so, what's the scoop?  I dimly recall a discussion here on the subject.

rayan

ps: to make this educational, here's a method using one too many fork()'s:

	if ((pid = fork()) == 0) {	/* child */
		(void) setuid(uid);
		if (open(file, 0) < 0)
			_exit(errno)
		_exit(0);
	} else if (pid < 0) {
		sorry, we can't check permissions right now...
		return; /* assume bad guy */
	}
	(void) wait(&status);
	if (status > 0)
		return;	/* permission denied */
	...open file, etc...

but this is really really really silly.
