Re: utimes() no good for symbolic links?
site_archiver@lists.apple.com Delivered-To: darwin-kernel@lists.apple.com 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:... I don't know, given only the information you've given me. (2) The user ownership will be the creating user - (7) set your umask back to what it was (8) regain root privilege for your helper (setuid(0)) (11) remove the "group helper" directory - -- Terry _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.a... On Dec 17, 2006, at 7:02 PM, Jerry Krinock wrote: on 06/12/16 21:51, Terry Lambert at tlambert@apple.com wrote: 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? 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 (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) (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 ...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. This email sent to site_archiver@lists.apple.com
participants (1)
-
Terry Lambert