AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod)
AC_CHECK_FUNCS(fchmod fstat strchr readlink link utime utimes strftime)
AC_CHECK_FUNCS(memmove getopt_long lchown vsnprintf snprintf setsid glob strpbrk)
-AC_CHECK_FUNCS(strlcat strlcpy)
+AC_CHECK_FUNCS(strlcat strlcpy getgroups)
echo $ac_n "checking for working fnmatch... $ac_c"
AC_TRY_RUN([#include <fnmatch.h>
return 0;
}
+static int is_in_group(gid_t gid)
+{
+#ifdef HAVE_GETGROUPS
+ static gid_t last_in = (gid_t) -2, last_out;
+ static int ngroups = -2;
+ static gid_t *gidset;
+ int n;
+
+ if (gid == last_in)
+ return last_out;
+ if (ngroups < -1) {
+ /* treat failure (-1) as if not member of any group */
+ ngroups = getgroups(0, 0);
+ if (ngroups > 0) {
+ gidset = (gid_t *) malloc(ngroups * sizeof(gid_t));
+ ngroups = getgroups(ngroups, gidset);
+ }
+ }
+
+ last_in = gid;
+ last_out = 0;
+ for (n = 0; n < ngroups; n++) {
+ if (gidset[n] == gid) {
+ last_out = 1;
+ break;
+ }
+ }
+ return last_out;
+
+#else
+ return 0;
+#endif
+}
int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
{
int updated = 0;
STRUCT_STAT st2;
+ int change_uid, change_gid;
extern int am_daemon;
if (dry_run) return 0;
}
}
- if ((am_root || !am_daemon) &&
- ((am_root && preserve_uid && st->st_uid != file->uid) ||
- (preserve_gid && st->st_gid != file->gid))) {
+ change_uid = am_root && preserve_uid && st->st_uid != file->uid;
+ change_gid = !am_daemon && preserve_gid && file->gid != -1 \
+ && st->st_gid != file->gid;
+ if (change_gid && !am_root) {
+ /* enforce bsd-style group semantics: non-root can only
+ change to groups that the user is a member of */
+ change_gid = is_in_group(file->gid);
+ }
+ if (change_uid || change_gid) {
if (do_lchown(fname,
- (am_root&&preserve_uid)?file->uid:st->st_uid,
- preserve_gid?file->gid:st->st_gid) != 0) {
- if (preserve_uid && st->st_uid != file->uid)
- updated = 1;
- if (verbose>1 || preserve_uid) {
- rprintf(FERROR,"chown %s : %s\n",
- fname,strerror(errno));
- return 0;
- }
- } else {
- updated = 1;
+ change_uid?file->uid:st->st_uid,
+ change_gid?file->gid:st->st_gid) != 0) {
+ /* shouldn't have attempted to change uid or gid
+ unless have the privilege */
+ rprintf(FERROR,"chown %s : %s\n", fname,strerror(errno));
+ return 0;
}
+ updated = 1;
}
#ifdef HAVE_CHMOD
mailto(rsync-bugs@samba.org)
-manpage(rsync)(1)(22 Feb 1999)()()
+manpage(rsync)(1)(1 Mar 1999)()()
manpagename(rsync)(faster, flexible replacement for rcp)
manpagesynopsis()
which already exist and have the same checksum and size on the
receiver are skipped. This option can be quite slow.
-dit(bf(-a, --archive)) This is equivalent to -rlptDg. It is a quick way
+dit(bf(-a, --archive)) This is equivalent to -rlptg. It is a quick way
of saying you want recursion and want to preserve everything.
-Note: if the user launching rsync is root then the -o option (preserve
-uid) is also implied.
+Note: if the user launching rsync is root then the -o (preserve
+uid) and -D (preserve devices) options are also implied.
dit(bf(-r, --recursive)) This tells rsync to copy directories recursively.
access to the usernames.
dit(bf(-g, --group)) This option causes rsync to update the remote group
-of the file to be the same as the local group. Note that if the source
-system is a daemon using chroot, the --numeric-ids option is implied because
-the source system cannot get access to the group names.
+of the file to be the same as the local group. If the receving system is
+not running as the super-user, only groups that the receiver is a member of
+will be preserved (by group name, not group id number).
dit(bf(-D, --devices)) This option causes rsync to transfer character and
block device information to the remote system to recreate these
extern int preserve_uid;
extern int preserve_gid;
extern int numeric_ids;
+extern int am_root;
struct idlist {
struct idlist *next;
list = list->next;
}
- last_out = gid;
+ if (am_root)
+ last_out = gid;
+ else
+ last_out = -1;
return last_out;
}
}
}
- if (!uidlist && !gidlist) return;
+ if (!(am_root && preserve_uid) && !preserve_gid) return;
/* now convert the uid/gid of all files in the list to the mapped
uid/gid */
for (i=0;i<flist->count;i++) {
- if (preserve_uid && flist->files[i]->uid != 0) {
+ if (am_root && preserve_uid && flist->files[i]->uid != 0) {
flist->files[i]->uid = match_uid(flist->files[i]->uid);
}
if (preserve_gid && flist->files[i]->gid != 0) {