2010-04-04 Nicolas François <nicolas.francois@centraliens.net>
* src/useradd.c: spool is a constant string. * src/useradd.c: Set the new copy_tree's paramater 'copy_root' to false 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * src/usermod.c: move_home() is only called if mflg is set. * src/usermod.c: Fail is -m is provided but the old home directory is not a directory. * src/usermod.c: Use the previous improvement of copy_tree to provide better error diagnosis. * src/usermod.c: When rename() is used, also change the ownership. * src/usermod.c: Do not change the ownership of the root directory twice. * src/usermod.c: When -u is provided, only change the ownership of the home directory if it is a directory. * src/usermod.c: Also change ownerships when -g is used. 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * lib/prototypes.h, libmisc/copydir.c: Add the old UID and GID to copy_tree to detect when ownership shall be changed. * libmisc/copydir.c: Document the behavior when the IDs are set to -1. * lib/prototypes.h, libmisc/copydir.c (copy_tree): Add parameter copy_root. * libmisc/copydir.c: error() and ctx can be static. * libmisc/copydir.c (copy_hardlink): Remove parameter src. 2010-04-04 Nicolas François <nicolas.francois@centraliens.net> * libmisc/chowndir.c: Dynamically allocate memory to support path longer than 1024 characters. * libmisc/chowndir.c: Fix typos in documentation. * libmisc/chowndir.c: Support and document the behavior when a old or new ID is set to -1. * libmisc/chowndir.c: Improved error detection when chown fails. * libmisc/chowndir.c: Harmonize error handling strategy when an error occurs: stop changing ownership as soon as an error was detected.
This commit is contained in:
		@@ -45,23 +45,36 @@
 | 
			
		||||
 *
 | 
			
		||||
 *	chown_dir() walks a directory tree and changes the ownership
 | 
			
		||||
 *	of all files owned by the provided user ID.
 | 
			
		||||
 *
 | 
			
		||||
 *	Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
 | 
			
		||||
 *	will have their ownership (resp. group-ownership) modified, unless
 | 
			
		||||
 *	old_uid (resp. old_gid) is set to -1.
 | 
			
		||||
 *
 | 
			
		||||
 *	new_uid and new_gid can be set to -1 to indicate that no owner or
 | 
			
		||||
 *	group-owner shall be changed.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
chown_tree (const char *root,
 | 
			
		||||
            uid_t old_uid,
 | 
			
		||||
            uid_t new_uid,
 | 
			
		||||
            gid_t old_gid,
 | 
			
		||||
            gid_t new_gid)
 | 
			
		||||
int chown_tree (const char *root,
 | 
			
		||||
                uid_t old_uid,
 | 
			
		||||
                uid_t new_uid,
 | 
			
		||||
                gid_t old_gid,
 | 
			
		||||
                gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	char new_name[1024];
 | 
			
		||||
	char *new_name;
 | 
			
		||||
	size_t new_name_len;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	struct DIRECT *ent;
 | 
			
		||||
	struct stat sb;
 | 
			
		||||
	DIR *dir;
 | 
			
		||||
 | 
			
		||||
	new_name = malloc (1024);
 | 
			
		||||
	if (NULL == new_name) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	new_name_len = 1024;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Make certain the directory exists.  This routine is called
 | 
			
		||||
	 * directory by the invoker, or recursively.
 | 
			
		||||
	 * directly by the invoker, or recursively.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (access (root, F_OK) != 0) {
 | 
			
		||||
@@ -71,8 +84,8 @@ chown_tree (const char *root,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Open the directory and read each entry.  Every entry is tested
 | 
			
		||||
	 * to see if it is a directory, and if so this routine is called
 | 
			
		||||
	 * recursively.  If not, it is checked to see if it is owned by
 | 
			
		||||
	 * old user ID.
 | 
			
		||||
	 * recursively.  If not, it is checked to see if an ownership
 | 
			
		||||
	 * shall be changed.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	dir = opendir (root);
 | 
			
		||||
@@ -81,6 +94,8 @@ chown_tree (const char *root,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while ((ent = readdir (dir))) {
 | 
			
		||||
		uid_t tmpuid = (uid_t) -1;
 | 
			
		||||
		gid_t tmpgid = (gid_t) -1;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Skip the "." and ".." entries
 | 
			
		||||
@@ -96,12 +111,16 @@ chown_tree (const char *root,
 | 
			
		||||
		 * destination files.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
 | 
			
		||||
			break;
 | 
			
		||||
		if (strlen (root) + strlen (ent->d_name) + 2 > new_name_len) {
 | 
			
		||||
			new_name = realloc (new_name, new_name_len + 1024);
 | 
			
		||||
			if (NULL == new_name) {
 | 
			
		||||
				rc = -1;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			new_name_len += 1024;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		snprintf (new_name, sizeof new_name, "%s/%s", root,
 | 
			
		||||
		          ent->d_name);
 | 
			
		||||
		snprintf (new_name, new_name_len, "%s/%s", root, ent->d_name);
 | 
			
		||||
 | 
			
		||||
		/* Don't follow symbolic links! */
 | 
			
		||||
		if (LSTAT (new_name, &sb) == -1) {
 | 
			
		||||
@@ -126,23 +145,52 @@ chown_tree (const char *root,
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		if (sb.st_uid == old_uid) {
 | 
			
		||||
			LCHOWN (new_name, new_uid,
 | 
			
		||||
			        (sb.st_gid == old_gid) ? new_gid : sb.st_gid);
 | 
			
		||||
		/*
 | 
			
		||||
		 * By default, the IDs are not changed (-1).
 | 
			
		||||
		 *
 | 
			
		||||
		 * If the file is not owned by the user, the owner is not
 | 
			
		||||
		 * changed.
 | 
			
		||||
		 *
 | 
			
		||||
		 * If the file is not group-owned by the group, the
 | 
			
		||||
		 * group-owner is not changed.
 | 
			
		||||
		 */
 | 
			
		||||
		if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
 | 
			
		||||
			tmpuid = new_uid;
 | 
			
		||||
		}
 | 
			
		||||
		if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
 | 
			
		||||
			tmpgid = new_gid;
 | 
			
		||||
		}
 | 
			
		||||
		if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
 | 
			
		||||
			rc = LCHOWN (new_name, tmpuid, tmpgid);
 | 
			
		||||
			if (0 != rc) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free (new_name);
 | 
			
		||||
	(void) closedir (dir);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Now do the root of the tree
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (stat (root, &sb) == 0) {
 | 
			
		||||
		if (sb.st_uid == old_uid) {
 | 
			
		||||
			LCHOWN (root, new_uid,
 | 
			
		||||
			        sb.st_gid == old_gid ? new_gid : sb.st_gid);
 | 
			
		||||
	if ((0 == rc) && (stat (root, &sb) == 0)) {
 | 
			
		||||
		uid_t tmpuid = (uid_t) -1;
 | 
			
		||||
		gid_t tmpgid = (gid_t) -1;
 | 
			
		||||
		if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
 | 
			
		||||
			tmpuid = new_uid;
 | 
			
		||||
		}
 | 
			
		||||
		if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
 | 
			
		||||
			tmpgid = new_gid;
 | 
			
		||||
		}
 | 
			
		||||
		if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
 | 
			
		||||
			rc = LCHOWN (root, tmpuid, tmpgid);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		rc = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -68,24 +68,38 @@ struct link_name {
 | 
			
		||||
static /*@exposed@*/struct link_name *links;
 | 
			
		||||
 | 
			
		||||
static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
                       long int uid, long int gid);
 | 
			
		||||
                       uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                       gid_t old_gid, gid_t new_gid);
 | 
			
		||||
static int copy_dir (const char *src, const char *dst,
 | 
			
		||||
                     const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                     long int uid, long int gid);
 | 
			
		||||
                     uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                     gid_t old_gid, gid_t new_gid);
 | 
			
		||||
#ifdef	S_IFLNK
 | 
			
		||||
static char *readlink_malloc (const char *filename);
 | 
			
		||||
static int copy_symlink (const char *src, const char *dst,
 | 
			
		||||
                         const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                         long int uid, long int gid);
 | 
			
		||||
                         uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                         gid_t old_gid, gid_t new_gid);
 | 
			
		||||
#endif				/* S_IFLNK */
 | 
			
		||||
static int copy_hardlink (const char *src, const char *dst,
 | 
			
		||||
static int copy_hardlink (const char *dst,
 | 
			
		||||
                          struct link_name *lp);
 | 
			
		||||
static int copy_special (const char *src, const char *dst,
 | 
			
		||||
                         const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                         long int uid, long int gid);
 | 
			
		||||
                         uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                         gid_t old_gid, gid_t new_gid);
 | 
			
		||||
static int copy_file (const char *src, const char *dst,
 | 
			
		||||
                      const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                      long int uid, long int gid);
 | 
			
		||||
                      uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                      gid_t old_gid, gid_t new_gid);
 | 
			
		||||
static int chown_if_needed (const char *dst, const struct stat *statp,
 | 
			
		||||
                            uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                            gid_t old_gid, gid_t new_gid);
 | 
			
		||||
static int lchown_if_needed (const char *dst, const struct stat *statp,
 | 
			
		||||
                             uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                             gid_t old_gid, gid_t new_gid);
 | 
			
		||||
static int fchown_if_needed (int fdst, const struct stat *statp,
 | 
			
		||||
                             uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                             gid_t old_gid, gid_t new_gid);
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_SELINUX
 | 
			
		||||
/*
 | 
			
		||||
@@ -130,7 +144,10 @@ int selinux_file_context (const char *dst_name)
 | 
			
		||||
#endif				/* WITH_SELINUX */
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_ACL) || defined(WITH_ATTR)
 | 
			
		||||
void error (struct error_context *ctx, const char *fmt, ...)
 | 
			
		||||
/*
 | 
			
		||||
 * error - format the error messages for the ACL and EQ libraries.
 | 
			
		||||
 */
 | 
			
		||||
static void error (struct error_context *ctx, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list ap;
 | 
			
		||||
 | 
			
		||||
@@ -143,7 +160,7 @@ void error (struct error_context *ctx, const char *fmt, ...)
 | 
			
		||||
	va_end (ap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct error_context ctx = {
 | 
			
		||||
static struct error_context ctx = {
 | 
			
		||||
	error
 | 
			
		||||
};
 | 
			
		||||
#endif				/* WITH_ACL || WITH_ATTR */
 | 
			
		||||
@@ -225,15 +242,46 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
 | 
			
		||||
 *
 | 
			
		||||
 *	copy_tree() walks a directory tree and copies ordinary files
 | 
			
		||||
 *	as it goes.
 | 
			
		||||
 *
 | 
			
		||||
 *	old_uid and new_uid are used to set the ownership of the copied
 | 
			
		||||
 *	files. Unless old_uid is set to -1, only the files owned by
 | 
			
		||||
 *	old_uid have their ownership changed to new_uid. In addition, if
 | 
			
		||||
 *	new_uid is set to -1, no ownership will be changed.
 | 
			
		||||
 *
 | 
			
		||||
 *	The same logic applies for the group-ownership and
 | 
			
		||||
 *	old_gid/new_gid.
 | 
			
		||||
 */
 | 
			
		||||
int copy_tree (const char *src_root, const char *dst_root,
 | 
			
		||||
               long int uid, long int gid)
 | 
			
		||||
               bool copy_root,
 | 
			
		||||
               uid_t old_uid, uid_t new_uid,
 | 
			
		||||
               gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	bool set_orig = false;
 | 
			
		||||
	struct DIRECT *ent;
 | 
			
		||||
	DIR *dir;
 | 
			
		||||
 | 
			
		||||
	if (copy_root) {
 | 
			
		||||
		struct stat sb;
 | 
			
		||||
		if (access (dst_root, F_OK) == 0) {
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (LSTAT (src_root, &sb) == -1) {
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!S_ISDIR (sb.st_mode)) {
 | 
			
		||||
			fprintf (stderr,
 | 
			
		||||
			         "%s: %s is not a directory",
 | 
			
		||||
			         Prog, src_root);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return copy_entry (src_root, dst_root,
 | 
			
		||||
		                   old_uid, new_uid, old_gid, new_gid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Make certain both directories exist.  This routine is called
 | 
			
		||||
	 * after the home directory is created, or recursively after the
 | 
			
		||||
@@ -290,7 +338,9 @@ int copy_tree (const char *src_root, const char *dst_root,
 | 
			
		||||
				snprintf (dst_name, dst_len, "%s/%s",
 | 
			
		||||
				          dst_root, ent->d_name);
 | 
			
		||||
 | 
			
		||||
				err = copy_entry (src_name, dst_name, uid, gid);
 | 
			
		||||
				err = copy_entry (src_name, dst_name,
 | 
			
		||||
				                  old_uid, new_uid,
 | 
			
		||||
				                  old_gid, new_gid);
 | 
			
		||||
			}
 | 
			
		||||
			if (NULL != src_name) {
 | 
			
		||||
				free (src_name);
 | 
			
		||||
@@ -330,13 +380,18 @@ int copy_tree (const char *src_root, const char *dst_root,
 | 
			
		||||
 *
 | 
			
		||||
 *	The access and modification time will not be modified.
 | 
			
		||||
 *
 | 
			
		||||
 *	The permissions will be set to uid/gid.
 | 
			
		||||
 *	The permissions will be set to new_uid/new_gid.
 | 
			
		||||
 *
 | 
			
		||||
 *	If uid (resp. gid) is equal to -1, the user (resp. group) will
 | 
			
		||||
 *	If new_uid (resp. new_gid) is equal to -1, the user (resp. group) will
 | 
			
		||||
 *	not be modified.
 | 
			
		||||
 *
 | 
			
		||||
 *	Only the files owned (resp. group-owned) by old_uid (resp.
 | 
			
		||||
 *	old_gid) will be modified, unless old_uid (resp. old_gid) is set
 | 
			
		||||
 *	to -1.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
                       long int uid, long int gid)
 | 
			
		||||
                       uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                       gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	struct stat sb;
 | 
			
		||||
@@ -371,7 +426,8 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
#endif				/* !HAVE_STRUCT_STAT_ST_MTIM */
 | 
			
		||||
 | 
			
		||||
		if (S_ISDIR (sb.st_mode)) {
 | 
			
		||||
			err = copy_dir (src, dst, &sb, mt, uid, gid);
 | 
			
		||||
			err = copy_dir (src, dst, &sb, mt,
 | 
			
		||||
			                old_uid, new_uid, old_gid, new_gid);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#ifdef	S_IFLNK
 | 
			
		||||
@@ -380,7 +436,8 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		else if (S_ISLNK (sb.st_mode)) {
 | 
			
		||||
			err = copy_symlink (src, dst, &sb, mt, uid, gid);
 | 
			
		||||
			err = copy_symlink (src, dst, &sb, mt,
 | 
			
		||||
			                    old_uid, new_uid, old_gid, new_gid);
 | 
			
		||||
		}
 | 
			
		||||
#endif				/* S_IFLNK */
 | 
			
		||||
 | 
			
		||||
@@ -389,7 +446,7 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		else if ((lp = check_link (src, &sb)) != NULL) {
 | 
			
		||||
			err = copy_hardlink (src, dst, lp);
 | 
			
		||||
			err = copy_hardlink (dst, lp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
@@ -399,7 +456,8 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		else if (!S_ISREG (sb.st_mode)) {
 | 
			
		||||
			err = copy_special (src, dst, &sb, mt, uid, gid);
 | 
			
		||||
			err = copy_special (src, dst, &sb, mt,
 | 
			
		||||
			                    old_uid, new_uid, old_gid, new_gid);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
@@ -408,7 +466,8 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		else {
 | 
			
		||||
			err = copy_file (src, dst, &sb, mt, uid, gid);
 | 
			
		||||
			err = copy_file (src, dst, &sb, mt,
 | 
			
		||||
			                 old_uid, new_uid, old_gid, new_gid);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -420,14 +479,15 @@ static int copy_entry (const char *src, const char *dst,
 | 
			
		||||
 *
 | 
			
		||||
 *	Copy a directory (recursively) from src to dst.
 | 
			
		||||
 *
 | 
			
		||||
 *	statp, mt, uid, gid are used to set the access and modification and the
 | 
			
		||||
 *	access rights.
 | 
			
		||||
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 | 
			
		||||
 *	the access and modification and the access rights.
 | 
			
		||||
 *
 | 
			
		||||
 *	Return 0 on success, -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_dir (const char *src, const char *dst,
 | 
			
		||||
                     const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                     long int uid, long int gid)
 | 
			
		||||
                     uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                     gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
@@ -440,9 +500,8 @@ static int copy_dir (const char *src, const char *dst,
 | 
			
		||||
	selinux_file_context (dst);
 | 
			
		||||
#endif				/* WITH_SELINUX */
 | 
			
		||||
	if (   (mkdir (dst, statp->st_mode) != 0)
 | 
			
		||||
	    || (chown (dst,
 | 
			
		||||
	               (uid == - 1) ? statp->st_uid : (uid_t) uid,
 | 
			
		||||
	               (gid == - 1) ? statp->st_gid : (gid_t) gid) != 0)
 | 
			
		||||
	    || (chown_if_needed (dst, statp,
 | 
			
		||||
	                         old_uid, new_uid, old_gid, new_gid) != 0)
 | 
			
		||||
#ifdef WITH_ACL
 | 
			
		||||
	    || (perm_copy_file (src, dst, &ctx) != 0)
 | 
			
		||||
#else				/* !WITH_ACL */
 | 
			
		||||
@@ -458,7 +517,8 @@ static int copy_dir (const char *src, const char *dst,
 | 
			
		||||
	 */
 | 
			
		||||
	    || (attr_copy_file (src, dst, NULL, &ctx) != 0)
 | 
			
		||||
#endif				/* WITH_ATTR */
 | 
			
		||||
	    || (copy_tree (src, dst, uid, gid) != 0)
 | 
			
		||||
	    || (copy_tree (src, dst, false,
 | 
			
		||||
	                   old_uid, new_uid, old_gid, new_gid) != 0)
 | 
			
		||||
	    || (utimes (dst, mt) != 0)) {
 | 
			
		||||
		err = -1;
 | 
			
		||||
	}
 | 
			
		||||
@@ -508,14 +568,15 @@ static char *readlink_malloc (const char *filename)
 | 
			
		||||
 *
 | 
			
		||||
 *	Copy a symlink from src to dst.
 | 
			
		||||
 *
 | 
			
		||||
 *	statp, mt, uid, gid are used to set the access and modification and the
 | 
			
		||||
 *	access rights.
 | 
			
		||||
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 | 
			
		||||
 *	the access and modification and the access rights.
 | 
			
		||||
 *
 | 
			
		||||
 *	Return 0 on success, -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_symlink (const char *src, const char *dst,
 | 
			
		||||
                         const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                         long int uid, long int gid)
 | 
			
		||||
                         uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                         gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	char *oldlink;
 | 
			
		||||
 | 
			
		||||
@@ -554,9 +615,8 @@ static int copy_symlink (const char *src, const char *dst,
 | 
			
		||||
	selinux_file_context (dst);
 | 
			
		||||
#endif				/* WITH_SELINUX */
 | 
			
		||||
	if (   (symlink (oldlink, dst) != 0)
 | 
			
		||||
	    || (lchown (dst,
 | 
			
		||||
	                (uid == -1) ? statp->st_uid : (uid_t) uid,
 | 
			
		||||
	                (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
 | 
			
		||||
	    || (lchown_if_needed (dst, statp,
 | 
			
		||||
	                          old_uid, new_uid, old_gid, new_gid) != 0)) {
 | 
			
		||||
		/* FIXME: there are no modes on symlinks, right?
 | 
			
		||||
		 *        ACL could be copied, but this would be much more
 | 
			
		||||
		 *        complex than calling perm_copy_file.
 | 
			
		||||
@@ -589,7 +649,7 @@ static int copy_symlink (const char *src, const char *dst,
 | 
			
		||||
 *
 | 
			
		||||
 *	Return 0 on success, -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_hardlink (const char *src, const char *dst,
 | 
			
		||||
static int copy_hardlink (const char *dst,
 | 
			
		||||
                          struct link_name *lp)
 | 
			
		||||
{
 | 
			
		||||
	/* FIXME: selinux, ACL, Extended Attributes needed? */
 | 
			
		||||
@@ -613,14 +673,15 @@ static int copy_hardlink (const char *src, const char *dst,
 | 
			
		||||
 *
 | 
			
		||||
 *	Copy a special file from src to dst.
 | 
			
		||||
 *
 | 
			
		||||
 *	statp, mt, uid, gid are used to set the access and modification and the
 | 
			
		||||
 *	access rights.
 | 
			
		||||
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 | 
			
		||||
 *	the access and modification and the access rights.
 | 
			
		||||
 *
 | 
			
		||||
 *	Return 0 on success, -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_special (const char *src, const char *dst,
 | 
			
		||||
                         const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                         long int uid, long int gid)
 | 
			
		||||
                         uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                         gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
 | 
			
		||||
@@ -629,9 +690,8 @@ static int copy_special (const char *src, const char *dst,
 | 
			
		||||
#endif				/* WITH_SELINUX */
 | 
			
		||||
 | 
			
		||||
	if (   (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
 | 
			
		||||
	    || (chown (dst,
 | 
			
		||||
	               (uid == -1) ? statp->st_uid : (uid_t) uid,
 | 
			
		||||
	               (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
 | 
			
		||||
	    || (chown_if_needed (dst, statp,
 | 
			
		||||
	                         old_uid, new_uid, old_gid, new_gid) != 0)
 | 
			
		||||
#ifdef WITH_ACL
 | 
			
		||||
	    || (perm_copy_file (src, dst, &ctx) != 0)
 | 
			
		||||
#else				/* !WITH_ACL */
 | 
			
		||||
@@ -659,14 +719,15 @@ static int copy_special (const char *src, const char *dst,
 | 
			
		||||
 *
 | 
			
		||||
 *	Copy a file from src to dst.
 | 
			
		||||
 *
 | 
			
		||||
 *	statp, mt, uid, gid are used to set the access and modification and the
 | 
			
		||||
 *	access rights.
 | 
			
		||||
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 | 
			
		||||
 *	the access and modification and the access rights.
 | 
			
		||||
 *
 | 
			
		||||
 *	Return 0 on success, -1 on error.
 | 
			
		||||
 */
 | 
			
		||||
static int copy_file (const char *src, const char *dst,
 | 
			
		||||
                      const struct stat *statp, const struct timeval mt[],
 | 
			
		||||
                      long int uid, long int gid)
 | 
			
		||||
                      uid_t old_uid, uid_t new_uid,
 | 
			
		||||
                      gid_t old_gid, gid_t new_gid)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	int ifd;
 | 
			
		||||
@@ -683,9 +744,8 @@ static int copy_file (const char *src, const char *dst,
 | 
			
		||||
#endif				/* WITH_SELINUX */
 | 
			
		||||
	ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
 | 
			
		||||
	if (   (ofd < 0)
 | 
			
		||||
	    || (fchown (ofd,
 | 
			
		||||
	                (uid == -1) ? statp->st_uid : (uid_t) uid,
 | 
			
		||||
	                (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)
 | 
			
		||||
	    || (fchown_if_needed (ofd, statp,
 | 
			
		||||
	                          old_uid, new_uid, old_gid, new_gid) != 0)
 | 
			
		||||
#ifdef WITH_ACL
 | 
			
		||||
	    || (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
 | 
			
		||||
#else				/* !WITH_ACL */
 | 
			
		||||
@@ -734,3 +794,37 @@ static int copy_file (const char *src, const char *dst,
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define def_chown_if_needed(chown_function, type_dst)                  \
 | 
			
		||||
static int chown_function ## _if_needed (type_dst dst,                 \
 | 
			
		||||
                                         const struct stat *statp,     \
 | 
			
		||||
                                         uid_t old_uid, uid_t new_uid, \
 | 
			
		||||
                                         gid_t old_gid, gid_t new_gid) \
 | 
			
		||||
{                                                                      \
 | 
			
		||||
	uid_t tmpuid = (uid_t) -1;                                     \
 | 
			
		||||
	gid_t tmpgid = (gid_t) -1;                                     \
 | 
			
		||||
                                                                       \
 | 
			
		||||
	/* Use new_uid if old_uid is set to -1 or if the file was      \
 | 
			
		||||
	 * owned by the user. */                                       \
 | 
			
		||||
	if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) {   \
 | 
			
		||||
		tmpuid = new_uid;                                      \
 | 
			
		||||
	}                                                              \
 | 
			
		||||
	/* Otherwise, or if new_uid was set to -1, we keep the same    \
 | 
			
		||||
	 * owner. */                                                   \
 | 
			
		||||
	if ((uid_t) -1 == tmpuid) {                                    \
 | 
			
		||||
		tmpuid = statp->st_uid;                                \
 | 
			
		||||
	}                                                              \
 | 
			
		||||
                                                                       \
 | 
			
		||||
	if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) {   \
 | 
			
		||||
		tmpgid = new_gid;                                      \
 | 
			
		||||
	}                                                              \
 | 
			
		||||
	if ((gid_t) -1 == tmpgid) {                                    \
 | 
			
		||||
		tmpgid = statp->st_gid;                                \
 | 
			
		||||
	}                                                              \
 | 
			
		||||
                                                                       \
 | 
			
		||||
	return chown_function (dst, tmpuid, tmpgid);                   \
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def_chown_if_needed (chown, const char *)
 | 
			
		||||
def_chown_if_needed (lchown, const char *)
 | 
			
		||||
def_chown_if_needed (fchown, int)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user