Re: utimes() no good for symbolic links?
Re: utimes() no good for symbolic links?
- Subject: Re: utimes() no good for symbolic links?
- From: Terry Lambert <email@hidden>
- Date: Tue, 19 Dec 2006 00:08:20 -0800
On Dec 17, 2006, at 7:02 PM, Jerry Krinock wrote:
on 06/12/16 21:51, Terry Lambert at email@hidden wrote:
Here is the short answer:...
Here is a long answer you are not going to like:...
Here is a longer answer that you're really not going to like:...
Thanks very much, Terry. I had come across some of this history,
but can
now appreciate how dumb we are indeed when we look at an icon in a
Finder
window and say "That's a file", as if we know what that means!
My assignment was to write code which would copy "symlinks with all
their
metadata". But I've not yet found a way to copy the datetimes
metadata of a
symlink. One unexplored possibility might be to copy the symlink,
somehow
setting it to to be a "regular file", so that I can fool utimes() or
setattrlist() into setting its datetimes metadata to that of the
"original
symlink", and then after that, sneakily change the file type to be a
symlink. But this seems too wacky to use in real life, and I might
well run
into another showstopper anyhow, because I noticed accidentally that
setattrlist() fails with errno=22 "invalid argument" if I ever try
and set
the file type, ATTR_CMN_OBJTYPE. (By the way, this failure is
undocumented
also.)
So, unless someone has another idea, I am going to resolve this
issue by
telling my user: "When you copy a symlink, the datetimes metadata of
the
copy will be the time of the copy, instead of the times on the
original
symlink, because a symlink cannot be copied, it can only be
'recreated'.
This is OK because a symlink is not really a file. And who the hell
cares
^when^ you created, modified or accessed a symlink anyhow, because
it's only
a stupid symlink, for God's sake!"
Does that make sense?
I don't know, given only the information you've given me.
The answer would depend on the specific version of MacOS X you were
doing this for, and what the underlying FS was that you were copying
from and to.
I suspect that you are running on 10.4.x on HFS+, and if so, the
answer is that:
(1) The permissions are going to be 0777, as modified by your umask at
the time the symlink is created
(2) The user ownership will be the creating user
(3) The group ownership will be the group of the directory in which
you created the symlink
(4) Nothing you do will change the symlink permissions after the fact
(and the OS is free to ignore them in deciding whether or not someone
is allowed to follow the link)
(5) You could also explicitly set the user and group on the symlink
later, using the lchown() system call, if you could live with the
security implications.
So if you wanted to tie yourself in particular HFS+ and version 10.4.x
of the OS, you could manipulate the symlink permissions at create time
(and *only* at create time!) by modifying your umask to be the inverse
of the permissions you want, creating the link, and setting your umask
back. Note that this will only work for the normal permissions bits,
which is to say 0777, not including the suid/sgid/sticky bit, and not
including any of the chflags flags in the upper bits of the st_mode
field from lstat.
So, for example, without an SUID "helper" program, it would be
impossible to create a symlink with no permissions, change the
ownership, and then open up the permissions (e.g. do the same thing
you would do with a file to ensure that no one can access it until it
has the proper ownership set on it before any access permissions are
granted, e.g. to create something that's inaccessible to an exclusion
group). This is particularly problematic for the group membership.
-
To work around all _that_, you would need to have your SUID "helper"
do an even more complicated dance:
So here's how you would do it in such a way that, if the underlying FS
supported it at all, you could portably and securely do what you want:
(1) create a "group helper" directory with the proper group ownership
on the same FS as place the link was eventually going to live
(2) change the group ownership of the directory to the target group
(requires that you be root, if you are not a member of the group)
(3) set your effective GID (setegid(XXX)) to the group you want the
link to have (requires that you be root, if you are not a member of
that group)
(4) set your effective UID (seteuid(YYY)) to the owner you want the
link to have (requires that you be root, if you are not already that
user)
(5) set your umask to the inverse of the permissions you wish the link
to have
(6) create the link in the helper directory (rather than where you
actually wanted it to live)
(7) set your umask back to what it was
(8) regain root privilege for your helper (setuid(0))
(9) change your effective group back to what it was (have to do #8
first, since if you weren't a member of the group, then this would
otherwise be denied)
(10) rename the link to the destination directory you actually wanted
it created in
(11) remove the "group helper" directory
...in other words, there no way to close the permissions/owner race
window with the lchown() (and lchmod(), if your OS supports it) unless
you start with the link being the right group/owner/permissions
atomically.
Steps #1-2 and #10-11 are required if the FS or OS is "BSD-like", and
groups on created FS objects are inherited from the containing
directory (this can either be an OS-level thing, or it can be a per-FS
thing, depending on what level the PSOX security model is implemented
at). #3 and #9 are required if the FS or OS is "System V-like", and
groups on created FS objects are inherited from the creating processes
GID.
And _still_ you would have no guarantee that the OS or underlying FS
would treat the link as a first or second class object, or if it did,
whether the visible ownership/permissions came from the symlink
itself, or from the directory container.
-
Personally, I would not recommend this approach, since whether the
symlink permissions are from the link FS object or from the directory
containing the link or purely synthetic is going to vary from version
to version of the OS... for example, this would not work on MacOS X
10.3.x, since most the information for symlinks was taken from the
directory. There's also the slight problem of ensuring your SUID
helper program doesn't have any exploitable bugs.
IMO, symlink information should be treated as cosmetic and visible to
the whole world, since you don't know what the underlying OS or FS is
going to do with the information. If you write code that depends on
it, then you are going to end up breaking somewhere, at some point,
when the underlying FS happens to have slightly different
implementation details/semantics.
If you need to control whether or not a symlink is deletable, put it
in a directory with 01xxx set on it (i.e. like /tmp), where it's not
possible for non-owners (except "root", of course) to delete a file
(or symlink) that was created there.
Anything else opens you up to making bad decisions that could break
your security model when you run into an OS/FS that doesn't support
the attributes you're trying to control.
-- Terry
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden