diff options
author | David Dykstra <dwd@samba.org> | 1999-03-01 19:24:39 +0000 |
---|---|---|
committer | David Dykstra <dwd@samba.org> | 1999-03-01 19:24:39 +0000 |
commit | 460f6b990a89a13060b57e1e52f72346bf020679 (patch) | |
tree | c4b3d91d37566edbca65262c4c0ee1e13eb19143 /rsync.c | |
parent | 896bd482c0c87d11e19f9bcffbcb35c6aba00e43 (diff) | |
download | rsync-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.c | 64 |
1 files changed, 50 insertions, 14 deletions
@@ -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 |