[comp.unix.questions] mkdir and access

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

In article <368@wsccs.UUCP> terry@wsccs.UUCP (terry) writes:
>... for instance, if mknod() had to be done by root, as the only user
>capable of modifying a file system, as is the case in a number of recent
>UNIX implimentations.  Your "mkdir" command would have to be SUID root,
>but still be able to tell who actually ran it.

This is precisely the problem.  When a setuid program is running
and needs to make a new directory, it must (on these systems) run
the `mkdir' program.  That setuid program's permissions are in
fact those of the EFFECTIVE user, not the real user; but mkdir
will check only the permissions of the real user.  Often this is
not what is desired.  Example:

	% ls -l foo
	-rwsr-xr-x  1 jane   misc   12345 Mar 26 14:27 foo
	% cat foo.c
		...
	int
	mkdir(dirname)		/* not quite right */
		char *dirname;
	{
		char buf[1000];

		(void) sprintf(buf, "/bin/mkdir %s", dirname);
		if (system(buf) == 0)
			return (0);
		errno = EPERM;	/* wrong! must scan output from /bin/mkdir */
		return (-1);
	}
		...
		realuser = uid_to_name(getuid());
		if (chdir("/tmp/jane/foousers") < 0) ...
		if (stat(realuser, &st) < 0 && errno == ENOENT)
			err = mkdir(realuser);
		...
	% ls -ldg /tmp/jane/foousers
	drwxr-xr-x  3 jane   misc     512 Mar 25 17:34 foousers
	% whoami
	joe
	% ./foo
	mkdir: joe: Not owner		(or is it Permission denied?)
	%

There is a way around it, but it is ugly:

		if (stat(realuser, &st) < 0 && errno == ENOENT) {
			/* BEGIN mkdir */
			int pid, w, status;
			switch (pid = fork()) {
			case -1:	/* error */
				...
			case 0:		/* child */
				(void) setgid(getgid());
				(void) setuid(getuid());
				_exit(mkdir(realuser) == 0 ? 0 : errno);
				/*NOTREACHED*/
			default:	/* parent */
				while ((w = wait(&status)) != pid)
					if (w == -1)
						uh oh.
				break;
			}
			err = status == 0 ? 0 : -1;
			if (err)
				errno = status >> 8;
			/* END mkdir */
		}

The above can be done.  It just is not done often enough.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

les@chinet.UUCP (Leslie Mikesell) (03/27/88)

In article <10811@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>UNIX implimentations.  Your "mkdir" command would have to be SUID root,
>>but still be able to tell who actually ran it.
>
>This is precisely the problem.  When a setuid program is running
>and needs to make a new directory, it must (on these systems) run
>the `mkdir' program.  That setuid program's permissions are in
>fact those of the EFFECTIVE user, not the real user; but mkdir
>will check only the permissions of the real user.  Often this is
>not what is desired.  Example:
>
Real-life example:
I have a subdirectory tree that I need to duplicate on another machine
via uucp.  To save transmission time, I like to use:
find . -print |cpio -oc |compress | uux - "remote!unpackit"
  where remote is the machine name and unpackit is a shell script
  that goes to the right place and runs zcat|cpio -imd on its input.

Now, one would think that these files and directories would be owned
by uucp since uuxqt is setuid to uucp.  However, if the particular
run of uucico that delivered the batch was started by a user on the
remote machine, guess who owns the newly created directories...
Cpio uses system(mkdir) which gives the directory to the real
user which happens to be the one who originally started the process
(even in SysVr3 where it doesn't have to!).  Even if the first
run operates as uucp (due to our system logging in to deliver the
file) later attempts may fail due to incorrect permissions when
creating a new dirctory.
  -Les
             ...ihnp4!chinet!les

james@bigtex.uucp (James Van Artsdalen) (03/28/88)

IN article <4190@chinet.UUCP>, les@chinet.UUCP (Leslie Mikesell) wrote:
> Cpio uses system(mkdir) which gives the directory to the real
> user which happens to be the one who originally started the process
> (even in SysVr3 where it doesn't have to!).

/bin/mkdir on my SysVr3 system isn't suid to anything.  Hence I assume it
works by creating directories via mkdir(2) and then giving them away to the
real uid and gid.  I don't think much would break if you replaced /bin/mkdir
with one that didn't give away the resulting directory.
-- 
James R. Van Artsdalen    ...!uunet!utastro!bigtex!james     "Live Free or Die"
Home: 512-346-2444 Work: 328-0282; 110 Wild Basin Rd. Ste #230, Austin TX 78746

samperi@marob.MASA.COM (Dominick Samperi) (03/28/88)

In article <4190@chinet.UUCP> les@chinet.UUCP (Leslie Mikesell) writes:
|>Real-life example:
|>I have a subdirectory tree that I need to duplicate on another machine
|>via uucp.  To save transmission time, I like to use:
|>find . -print |cpio -oc |compress | uux - "remote!unpackit"
|>  where remote is the machine name and unpackit is a shell script
|>  that goes to the right place and runs zcat|cpio -imd on its input.
|>
|>Now, one would think that these files and directories would be owned
|>by uucp since uuxqt is setuid to uucp.  However, if the particular
|>run of uucico that delivered the batch was started by a user on the
|>remote machine, guess who owns the newly created directories...
|>Cpio uses system(mkdir) which gives the directory to the real
|>user which happens to be the one who originally started the process
|>(even in SysVr3 where it doesn't have to!).  Even if the first
|>run operates as uucp (due to our system logging in to deliver the
|>file) later attempts may fail due to incorrect permissions when
|>creating a new dirctory.
|>  -Les
|>             ...ihnp4!chinet!les

This is precisely the problem that motivated me to write the (slightly)
enhanced version of mkdir that I recently posted to comp.unix.wizards. It
has a -g flag which causes mkdir to use the process EFFECTIVE group id
when it makes directories. You will have to modify cpio so that it
calls mkdir with the -g flag, and so that it always gives rwx access to
a particular group, like uucpio.
-- 
Dominick Samperi, Manhattan College, NYC
    manhat!samperi@NYU.EDU           ihnp4!rutgers!nyu.edu!manhat!samperi
    philabs!cmcl2!manhat!samperi     ihnp4!rutgers!hombre!samperi
              (^ that's an ell)      uunet!swlabs!mancol!samperi

zeeff@b-tech.UUCP (Jon Zeeff) (03/30/88)

Other than the correct fix of adding a system call, the way that News 
(2.11) uses is the only way I've seen of creating proper directories
from a suid program.

--Jon

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