From: Paul Eggert Date: Tue, 31 May 2005 06:14:24 +0000 (+0000) Subject: Port to Solaris 10's rules for whether programs can chown files. X-Git-Tag: CPPI-1_12~692 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e6a9bbce565defebd361d54979737f0e1ab00f7b;p=thirdparty%2Fcoreutils.git Port to Solaris 10's rules for whether programs can chown files. [HAVE_PRIV_H]: Include . (DO_CHOWN): Remove. Replaced by chown_failure_ok. All callers changed. (copy_internal): If chown failed, don't worry about what happened to the mode bits; they can't have changed. (chown_privileges, chown_failure_ok): New functions. --- diff --git a/src/copy.c b/src/copy.c index 2db057f427..c91557e3b8 100644 --- a/src/copy.c +++ b/src/copy.c @@ -25,6 +25,9 @@ #if HAVE_HURD_H # include #endif +#if HAVE_PRIV_H +# include +#endif #include "system.h" #include "backupfile.h" @@ -47,13 +50,6 @@ #include "xreadlink.h" #include "yesno.h" -#define DO_CHOWN(Chown, File, New_uid, New_gid) \ - (Chown (File, New_uid, New_gid) \ - /* If non-root uses -p, it's ok if we can't preserve ownership. \ - But root probably wants to know, e.g. if NFS disallows it, \ - or if the target system doesn't support file ownership. */ \ - && ((errno != EPERM && errno != EINVAL) || x->myeuid == 0)) - #define SAME_OWNER(A, B) ((A).st_uid == (B).st_uid) #define SAME_GROUP(A, B) ((A).st_gid == (B).st_gid) #define SAME_OWNER_AND_GROUP(A, B) (SAME_OWNER (A, B) && SAME_GROUP (A, B)) @@ -848,7 +844,7 @@ copy_internal (const char *src_path, const char *dst_path, bool backup_succeeded = false; bool delayed_ok; bool copied_as_regular = false; - bool ran_chown = false; + bool chown_succeeded = false; bool preserve_metadata; if (x->move_mode && rename_succeeded) @@ -1530,7 +1526,8 @@ copy_internal (const char *src_path, const char *dst_path, /* Preserve the owner and group of the just-`copied' symbolic link, if possible. */ # if HAVE_LCHOWN - if (DO_CHOWN (lchown, dst_path, src_sb.st_uid, src_sb.st_gid)) + if (lchown (dst_path, src_sb.st_uid, src_sb.st_gid) != 0 + && ! chown_failure_ok (x)) { error (0, errno, _("failed to preserve ownership for %s"), dst_path); @@ -1590,8 +1587,9 @@ copy_internal (const char *src_path, const char *dst_path, if (x->preserve_ownership && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) { - ran_chown = true; - if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) + if (chown (dst_path, src_sb.st_uid, src_sb.st_gid) == 0) + chown_succeeded = true; + else if (! chown_failure_ok (x)) { error (0, errno, _("failed to preserve ownership for %s"), quote (dst_path)); @@ -1619,9 +1617,9 @@ copy_internal (const char *src_path, const char *dst_path, /* Permissions of newly-created regular files were set upon `open' in copy_reg. But don't return early if there were any special bits and - we had to run chown, because the chown must have reset those bits. */ + chown succeeded, because the chown must have reset those bits. */ if ((new_dst && copied_as_regular) - && !(ran_chown && (src_mode & ~S_IRWXUGO))) + && !(chown_succeeded && (src_mode & ~S_IRWXUGO))) return delayed_ok; if ((x->preserve_mode || new_dst) @@ -1701,3 +1699,37 @@ copy (const char *src_path, const char *dst_path, return copy_internal (src_path, dst_path, nonexistent_dst, 0, NULL, options, true, copy_into_self, rename_succeeded); } + +/* Return true if this process has appropriate privileges to chown a + file whose owner is not the effective user ID. */ + +bool +chown_privileges (void) +{ +#ifdef PRIV_FILE_CHOWN + bool result; + priv_set_t *pset = priv_allocset (); + if (!pset) + xalloc_die (); + result = (getppriv (PRIV_EFFECTIVE, pset) == 0 + && priv_ismember (pset, PRIV_FILE_CHOWN)); + priv_freeset (pset); + return result; +#else + return (geteuid () == 0); +#endif +} + +/* Return true if it's OK for chown to fail, where errno is + the error number that chown failed with and X is the copying + option set. */ + +bool +chown_failure_ok (struct cp_options const *x) +{ + /* If non-root uses -p, it's ok if we can't preserve ownership. + But root probably wants to know, e.g. if NFS disallows it, + or if the target system doesn't support file ownership. */ + + return ((errno == EPERM || errno == EINVAL) && !x->chown_privileges); +}