[comp.unix.wizards] How does 'mv' rename directories?

mike@isi.UUCP (Mike Maloney) (09/13/89)

Dear wizards,

I was recently trying to figure out why the 'mv' command on a Microport 
System V box would refused to rename directories.  The commands
		cd
		mkdir junk
		mv junk junk2
would elicit the response: mv: cannot link 'junk' and 'junk2'.
(No, 'junk2' did not already exist.)  The same commands would work
fine on another system RUNNING THE SAME OPERATING SYSTEM!

I suspect that it is something subtle to do with permissions.  But anyway,
this led me to wonder how the 'mv' command can rename directories at all.
The Rochkind book shows an implementation of 'mv' using link() and unlink().
If the target path is a directory it first checks to see if it already exists, 
and if it does, fails.  If I understand him correctly, his version of 'mv' 
must have the Set-UID bit set and be owned be root because only processes 
with an effective UID of root can link directories.

But on Microport, Xenix, and Sun Unix 4.0, /bin/mv is -rwxr-xr-x and is
owned by 'bin'.   How is 'mv' able to rename directories on a properly 
working system?

-- 
Mike Maloney             Integral Systems, Inc 
(301) 731-4233		 5000 Philadelpha Way, Suite A,
			 Lanham, MD  20706

cpcahil@virtech.UUCP (Conor P. Cahill) (09/14/89)

In article <544@isi.UUCP>, mike@isi.UUCP (Mike Maloney) writes:
> But on Microport, Xenix, and Sun Unix 4.0, /bin/mv is -rwxr-xr-x and is
> owned by 'bin'.   How is 'mv' able to rename directories on a properly 
> working system?

On system V 3.2 mv determines that a directory is to be moved and calls
the program /usr/lib/mv_dir which is setuid to root.


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

guy@auspex.auspex.com (Guy Harris) (09/15/89)

>But on Microport, Xenix, and Sun Unix 4.0, /bin/mv is -rwxr-xr-x and is
>owned by 'bin'.   How is 'mv' able to rename directories on a properly 
>working system?

In SunOS 4.0 - and in other systems that have the "rename()" system call
from 4.[23]BSD, including all other SunOS releases, 4.[23]BSD
themselves, Ultrix, etc. - it uses the "rename" call, which lets you
move directories when it's safe, and doesn't require super-user
privileges.

I expect S5R4 to have this as well, and thus to render obsolete the
program that S5R3, at least (and possibly Microport and Xenix, and maybe
some older S5 releases, as well) uses to move directories. 

bill@twwells.com (T. William Wells) (09/15/89)

In article <544@isi.UUCP> mike@isi.UUCP (Mike Maloney) writes:
: But on Microport, Xenix, and Sun Unix 4.0, /bin/mv is -rwxr-xr-x and is
: owned by 'bin'.   How is 'mv' able to rename directories on a properly
: working system?

On my Microport, it calls /usr/lib/mv_dir to do the dirty work.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

bph@buengc.BU.EDU (Blair P. Houghton) (09/15/89)

In article <544@isi.UUCP> mike@isi.UUCP (Mike Maloney) writes:
>Dear wizards,
>
>I was recently trying to figure out why the 'mv' command on a Microport 
>System V box would refused to rename directories.  The commands
>		cd
>		mkdir junk
>		mv junk junk2
>would elicit the response: mv: cannot link 'junk' and 'junk2'.
>(No, 'junk2' did not already exist.)  The same commands would work
>fine on another system RUNNING THE SAME OPERATING SYSTEM!

Was it really 'junk1' and 'junk2' and not two files with long pathnames
on different filesystems?

>I suspect that it is something subtle to do with permissions.  But anyway,
>this led me to wonder how the 'mv' command can rename directories at all.

Setuid root, and you can move the cpu.  (That's not the case, here, it's
just a funny thing to say.  I do that, sometimes...)  Oh, but it isn't
a "setuid program"...

>The Rochkind book shows an implementation of 'mv' using link() and unlink().
>If the target path is a directory it first checks to see if it already exists, 
>and if it does, fails.  If I understand him correctly, his version of 'mv' 
>must have the Set-UID bit set and be owned be root because only processes 
>with an effective UID of root can link directories.

Yep.  One other case:  if the source and destination are on different
filesystems, it should effectively do mkdir() and then copy the
directory recursively and then remove the source, again recursively.

I've seen this done, and I'm wondering how much more effective it is,
in software-installation routines by using tar(1) instead of a
recursive copy.  Any comments?

>But on Microport, Xenix, and Sun Unix 4.0, /bin/mv is -rwxr-xr-x and is
>owned by 'bin'.   How is 'mv' able to rename directories on a properly 
>working system?

Does mv not do setuid()?  The setuid bit tells the OS to make the
effective uid (that which is used to derive ownership) the owner of the
program, but doesn't alter the possibility that there's a uid change in
the program itself.  (Sounds of digging Bach out of a back pack -- a
Bachpach? :-S -- and rummaging around the indexed ref to setuid for
verification, then the smell of paraphrasing fills the air) Since the
owner of the files has placed his uid in the kernel's process table,
the setuid() system call is free to change the effective uid to that
one.  The process is now permitted to change your files.

Faux Plagiarism:

p. 197, Bach, The Design of the UNIX O. S.
"The real user ID identifies the user who is responsible for the
running process.  the effective user ID is used to assign ownership
of newly created files, to check file access permissions, and to check
permission to send signals to processes via the kill(2) system call."

				--Blair
				  "Now comes the pain wherein
				   kill(1) fails to setuid(2) to you
				   because you are su-personating
				   yourself from elsewhom..."

cpcahil@virtech.UUCP (Conor P. Cahill) (09/15/89)

In article <4158@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:
> Does mv not do setuid()?  The setuid bit tells the OS to make the
> effective uid (that which is used to derive ownership) the owner of the
> program, but doesn't alter the possibility that there's a uid change in
> the program itself.

The only ids a program can setuid() to are as follows:

	1. the effective user id of the process 
	2. the real user id of the process
	3. (for system V) the "saved" user id of the process.

	The exception is if either the real user id or effective user id
	of the process is root, these limitations are rescinded

  (Sounds of digging Bach out of a back pack -- a
> Bachpach? :-S -- and rummaging around the indexed ref to setuid for
> verification, then the smell of paraphrasing fills the air) Since the
> owner of the files has placed his uid in the kernel's process table,
> the setuid() system call is free to change the effective uid to that
> one.  The process is now permitted to change your files.

I'm not sure what you are talking about, but it sounds like you are talking
about the method the kernel uses to interpret/execute the setuid-bits on
the file.  This automatically sets the effective user id and allows the program
to change it's "real" user id to match the effective user id (or to change
the effective user id back to the real user id) by using the setuid() syscall.


If you aint root, the only way to get root uid privileges is to run a
setuid-root program.
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

blm@6sigma.UUCP (Brian Matthews) (09/16/89)

In article <544@isi.UUCP> mike@isi.UUCP (Mike Maloney) writes:
|I was recently trying to figure out why the 'mv' command on a Microport 
|System V box would refused to rename directories.

I don't have Microport, but I do have a System V box, and directory moving
is implemented by /usr/lib/mv_dir, which has permissions -r-sr-xr-x and
is owned by root.  mv uses mv_dir when renaming directories.
-- 
Brian L. Matthews			blm@6sigma.UUCP
Six Sigma CASE, Inc.			+1 206 854 6578
PO Box 40316, Bellevue, WA  98004

bph@buengc.BU.EDU (Blair P. Houghton) (09/16/89)

In article <1160@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>In article <4158@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:
>> Does mv not do setuid()?  The setuid bit tells the OS to make the
>> effective uid (that which is used to derive ownership) the owner of the
>> program, but doesn't alter the possibility that there's a uid change in
>> the program itself.
>
>The only ids a program can setuid() to are as follows:
>
>	1. the effective user id of the process 
>	2. the real user id of the process
>	3. (for system V) the "saved" user id of the process.

Okay.  Nothing odd there.

>	The exception is if either the real user id or effective user id
>	of the process is root, these limitations are rescinded
>
>  (Sounds of digging Bach out of a back pack -- a
>> Bachpach? :-S -- and rummaging around the indexed ref to setuid for
>> verification, then the smell of paraphrasing fills the air) Since the
>> owner of the files has placed his uid in the kernel's process table,
>> the setuid() system call is free to change the effective uid to that
>> one.  The process is now permitted to change your files.

The real uid is the caller's uid.

>I'm not sure what you are talking about, but it sounds like you are talking
>about the method the kernel uses to interpret/execute the setuid-bits on
>the file.

No, That's what I was talking about up there where it says "setuid bit tells
the OS..."  Now, I'm talking about seteuid(getuid()), which makes the
process-owner the owner of any files created by the process, and allows
the process to access any files owned by the process owner.

>This automatically sets the effective user id and allows the program
>to change it's "real" user id to match the effective user id (or to change
>the effective user id back to the real user id) by using the setuid() syscall.

Like I said I said.  (Hey.  Now _I_ am starting to get lost... :-)

>If you aint root, the only way to get root uid privileges is to run a
>setuid-root program.

True, but not in the paragdigm for mv(1).

You only want mv(1) to be able to seteuid(2) to you, so you can move
your own files.  If mv(1) was setuid-root, you could move files all
over the place, without a care.  Hence, mv(1) is most definitely
not setuid-root.

I've been told that mv(1) may call mv_dir(?) (which doesn't exist
on this machine... Encore's Umax is a vanilla BSD...) which is
setuid-root (it is claimed).  If this is how it's done, then the
reason for the setuid-root could be to allow the moving of a
directory across partition boundaries when the directory may
contain files with an owner different from the directory-owner.

Moving from one partition to the next requires a copy-then-unlink,
whereas moving within a partition only requires a link-then-unlink.

Linking to a file is a thing done on the directory containing that
file, and so requires only the permission of the directory.  Copying
the file, however, requires permission to read from that file.

The destination-writing can be accomplished by chown'ing once the file
is written, but the source-reading absolutely requires the permission.

But, basically, there's no need to become uid 0 when you're just moving
files around in a partition.

				--Blair
				  "Maybe.  It's too much
				   blither and not enough
				   snarl.  Is it clear?"

cpcahil@virtech.UUCP (Conor P. Cahill) (09/16/89)

In article <4195@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:
> In article <1160@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> >In article <4158@buengc.BU.EDU>, bph@buengc.BU.EDU (Blair P. Houghton) writes:
	[ much deleted junk... ]
> 
> You only want mv(1) to be able to seteuid(2) to you, so you can move
> your own files.  If mv(1) was setuid-root, you could move files all
> over the place, without a care.  Hence, mv(1) is most definitely
> not setuid-root.

mv doesn't need to seteuid() since it is not a setuid program.  The reason
for the discussion about setuid was due to the fact that the original poster
wanted to know how a directory could be moved.  For BSD, this is simple
because the rename(2) syscall allows this, but for SYSV, there is no
rename syscall and the old link/unlink pair won't work for directories
unless the effective user is root.  The solution under sysV is to have
a second program mv_dir (in /usr/lib) that is setuid root and is called
by mv whenever a directory is to be moved.  However the mv_dir program
will only allow mv's within the same direcory.

> I've been told that mv(1) may call mv_dir(?) (which doesn't exist
> on this machine... Encore's Umax is a vanilla BSD...) which is
> setuid-root (it is claimed).  If this is how it's done, then the
> reason for the setuid-root could be to allow the moving of a
> directory across partition boundaries when the directory may
> contain files with an owner different from the directory-owner.

Nope.  See above.

> Linking to a file is a thing done on the directory containing that
> file, and so requires only the permission of the directory.  Copying

It requires search permission to the source file directory and 
write permission to the target file direcory.

> the file, however, requires permission to read from that file.
> 
> But, basically, there's no need to become uid 0 when you're just moving
> files around in a partition.

The discussion was not about moving files, it was about moving directories
and on a SYSV system you need to be euid root to accomplish it.


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

rmtodd@servalan.uucp (Richard Todd) (09/17/89)

In article <4195@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>You only want mv(1) to be able to seteuid(2) to you, so you can move
>your own files.  If mv(1) was setuid-root, you could move files all
>over the place, without a care.  Hence, mv(1) is most definitely
>not setuid-root.
  mv(1) can only move files about without a care if mv(1) wasn't
written to check the destination mode and ownership to see if you're
allowed to move it.  On some systems, mv(1) is setuid-root, and it
does check permissions itself.  On some systems, mv isn't setuid. 

>I've been told that mv(1) may call mv_dir(?) (which doesn't exist
>on this machine... Encore's Umax is a vanilla BSD...) which is
>setuid-root (it is claimed).  If this is how it's done, then the
>reason for the setuid-root could be to allow the moving of a
>directory across partition boundaries when the directory may
>contain files with an owner different from the directory-owner.

  Uh, not quite.  First of all, I don't know of *any* version of the
mv command that allows moving directories across partition boundaries.

  Secondly, there are at least three different ways mv(1) can be
implemented on Unix systems, and different systems use different ones.  

  1. The mv command may be setuid root, and check to see if the real
user has appropriate permissions on the target directory.  The reason
root privileges are needed is not, as you say, to do directory moves
from one partition to another, since mv doesn't do that sort of move.
The real reason is this: Suppose we want to move directory foo from
/usr/bin to /usr/lib.  Not only must a link be made to foo in /usr/lib
and the existing link to foo in /usr/bin be removed, but the entry for
".." in the foo directory must be unlinked and a new link for ".."
must be made pointing to the new parent.  Ordinary (non-root) users
aren't allowed to unlink "..", for the simple reason that one could
accidentally make a tremendous mess of the filesystem.  Thus the power
to unlink ".." (or, for that matter, any directory) is restricted to
root.  On such systems, mkdir and rmdir have to be setuid-root, too,
for the same reasons.
  I believe V7 used the above scheme; perhaps System III did as well.
Minix, the V7 clone for PCs, definitely uses this scheme.

  2. Same as above, except that mv is non-setuid, and whenever mv
needs to move a directory, it calls mv_dir, a setuid program which
does the actual directory move.  mv itself doesn't call mv_dir when
ordinary files are moved.  System V systems without NFS apparently use
this scheme.  

  3. The operation of moving a file/directory from one place to
another (making the new link and unlinking the old one) can be done
inside a system call, rename(2), which does all the grotty work of
checking permissions, linking and unlinking, and making sure that ".."
in the moved directory is set correctly.  BSD systems and systems that
have client-mode NFS have this system call, and mv on such systems
uses this call; basically, mv just calls rename(2) directly for
intra-partition moves, and does the copy of files for moves between
partitions.  mv is not setuid, and needs no setuid program to assist
it.  The reason you didn't find mv_dir on your Encore system is that
it isn't needed there.  Putting the functionality of "move" in the
kernel has two advantages: 1, it removes the need for programs that
move directories to mess with the ".." business and be setuid-root,
and 2. the whole operation of moving the file/directory can be made
atomic inside the kernel, thus avoiding certain race conditions.
Also, it's useful on NFS systems, where the server you're mounting
your filesystem from may not be a Unix system and may require some
other (server-specific) technique to move files/directories; with
rename(2), moves on remote-mounted filesystems are simply translated
to appropriate calls to the NFS server.  Mkdir and rmdir are also
system calls on BSD or NFS systems, for much the same reasons.

>But, basically, there's no need to become uid 0 when you're just moving
>files around in a partition.
  Agreed.  It's the business of moving directories around that
sometimes causes problems.
--
Richard Todd	rmtodd@uokmax.ecn.uoknor.edu  rmtodd@chinet.chi.il.us
	rmtodd@servalan.uucp
Motorola Skates On Intel's Head!

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

In article <4195@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
-I've been told that mv(1) may call mv_dir(?) (which doesn't exist
-on this machine... Encore's Umax is a vanilla BSD...) which is
-setuid-root (it is claimed).  If this is how it's done, then the
-reason for the setuid-root could be to allow the moving of a
-directory across partition boundaries when the directory may
-contain files with an owner different from the directory-owner.

No, the setUID-0 is because linking to directories requires privilege.

guy@auspex.auspex.com (Guy Harris) (09/19/89)

>Also, [the rename system call is] useful on NFS systems, where the server
>you're mounting your filesystem from may not be a Unix system and may
>require some other (server-specific) technique to move files/directories; with
>rename(2), moves on remote-mounted filesystems are simply translated
>to appropriate calls to the NFS server.  Mkdir and rmdir are also
>system calls on BSD or NFS systems, for much the same reasons.

And also because:

	1) the remote server may not give clients the ability to get
	   root privileges (true both of NFS and RFS), so that even
	   set-UID "root" programs on the client may not have the root
	   privileges necessary to create, remove, or rename directories
	   in the "traditional" fashion;

and

	2) the file system in question may, even if it's not a remote
	   file system, not look enough like a "traditional" UNIX file
	   system (either V7/S5 *or* BSD) for the "traditional" ways of
	   creating, removing, or renaming directories to work, since
	   systems with VFS or the File System Switch can have all sorts
	   of different file system types plugged into them.

S5R3, having both RFS and the File System Switch, also has "mkdir" and
"rmdir" system calls; unfortunately, they forgot "rename", but that'll
be fixed in S5R4.