summaryrefslogtreecommitdiff
path: root/rsync.c
diff options
context:
space:
mode:
authorDavid Dykstra <dwd@samba.org>1999-03-01 19:24:39 +0000
committerDavid Dykstra <dwd@samba.org>1999-03-01 19:24:39 +0000
commit460f6b990a89a13060b57e1e52f72346bf020679 (patch)
treec4b3d91d37566edbca65262c4c0ee1e13eb19143 /rsync.c
parent896bd482c0c87d11e19f9bcffbcb35c6aba00e43 (diff)
downloadrsync-460f6b990a89a13060b57e1e52f72346bf020679.tar.gz
Prevent the -g option from preserving groups that a non-root receiver
does not belong to, in these two ways: 1. If a group mapping doesn't exist for a group name, do not preserve it for a non-root receiver. This is especially evident with the sender is a daemon using chroot because then no mappings are available. 2. Before setting the group on a file make sure that it is in the list of groups returned by getgroups(). The same thing is done by chgrp on systems that support bsd-style chown/chgrp, and this enforces that it happens the same way on all systems. Overhead is very little, especially since most systems don't allow more then 16 groups per user.
Diffstat (limited to 'rsync.c')
-rw-r--r--rsync.c64
1 files changed, 50 insertions, 14 deletions
diff --git a/rsync.c b/rsync.c
index 3f79f504..ceabfdac 100644
--- a/rsync.c
+++ b/rsync.c
@@ -113,12 +113,46 @@ int delete_file(char *fname)
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;
@@ -145,22 +179,24 @@ int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
}
}
- 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