X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/f6c347425ac550dd1b7d1ff739bedd1489099d91..4836c3eece276abc14a4574b350f68d8f1e429c0:/uidlist.c diff --git a/uidlist.c b/uidlist.c index b7d84ce9..27e7046e 100644 --- a/uidlist.c +++ b/uidlist.c @@ -1,17 +1,17 @@ -/* +/* Copyright (C) Andrew Tridgell 1996 Copyright (C) Paul Mackerras 1996 - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -25,9 +25,21 @@ #include "rsync.h" +#ifdef HAVE_GETGROUPS +# if !defined(GETGROUPS_T) +# define GETGROUPS_T gid_t +# endif +# ifndef NGROUPS_MAX +/* It ought to be defined, but just in case. */ +# define NGROUPS_MAX 32 +# endif +#endif + +extern int verbose; extern int preserve_uid; extern int preserve_gid; extern int numeric_ids; +extern int am_root; struct idlist { struct idlist *next; @@ -40,7 +52,7 @@ static struct idlist *gidlist; static struct idlist *add_list(int id, char *name) { - struct idlist *list = (struct idlist *)malloc(sizeof(list[0])); + struct idlist *list = new(struct idlist); if (!list) out_of_memory("add_list"); list->next = NULL; list->name = strdup(name); @@ -67,48 +79,86 @@ static char *gid_to_name(gid_t gid) return NULL; } - -/* turn a user name into a uid */ -static uid_t name_to_uid(char *name) -{ - struct passwd *pass; - if (!name || !*name) return 0; - pass = getpwnam(name); - if (pass) return(pass->pw_uid); - return 0; -} - -/* turn a group name into a gid */ -static gid_t name_to_gid(char *name) -{ - struct group *grp; - if (!name || !*name) return 0; - grp = getgrnam(name); - if (grp) return(grp->gr_gid); - return 0; -} - static int map_uid(int id, char *name) { - uid_t uid = name_to_uid(name); - if (uid != 0) return uid; + uid_t uid; + if (uid != 0 && name_to_uid(name, &uid)) + return uid; return id; } static int map_gid(int id, char *name) { - gid_t gid = name_to_gid(name); - if (gid != 0) return gid; + gid_t gid; + if (gid != 0 && name_to_gid(name, &gid)) + return gid; return id; } +static int is_in_group(gid_t gid) +{ +#ifdef HAVE_GETGROUPS + static gid_t last_in = GID_NONE, last_out; + static int ngroups = -2; + static GETGROUPS_T *gidset; + int n; + + if (gid == last_in) + return last_out; + if (ngroups < -1) { + gid_t mygid = MY_GID(); + if ((ngroups = getgroups(0, 0)) < 0) + ngroups = 0; + gidset = new_array(GETGROUPS_T, ngroups+1); + if (ngroups > 0) + ngroups = getgroups(ngroups, gidset); + /* The default gid might not be in the list on some systems. */ + for (n = 0; n < ngroups; n++) { + if (gidset[n] == mygid) + break; + } + if (n == ngroups) + gidset[ngroups++] = mygid; + if (verbose > 3) { + char gidbuf[NGROUPS_MAX*16+32]; + int pos; + sprintf(gidbuf, "process has %d gid%s: ", + ngroups, ngroups == 1? "" : "s"); + pos = strlen(gidbuf); + for (n = 0; n < ngroups; n++) { + sprintf(gidbuf+pos, " %ld", (long)gidset[n]); + pos += strlen(gidbuf+pos); + } + rprintf(FINFO, "%s\n", gidbuf); + } + } + + last_in = gid; + for (n = 0; n < ngroups; n++) { + if (gidset[n] == gid) + return last_out = 1; + } + return last_out = 0; + +#else + static gid_t mygid = GID_NONE; + if (mygid == GID_NONE) { + mygid = MY_GID(); + if (verbose > 3) + rprintf(FINFO, "process has gid %ld\n", (long)mygid); + } + return gid == mygid; +#endif +} + /* this function is a definate candidate for a faster algorithm */ static uid_t match_uid(uid_t uid) { static uid_t last_in, last_out; struct idlist *list = uidlist; - if (uid == last_in) return last_out; + if (uid == last_in) + return last_out; last_in = uid; @@ -119,17 +169,18 @@ static uid_t match_uid(uid_t uid) } list = list->next; } - + last_out = uid; return last_out; } static gid_t match_gid(gid_t gid) { - static gid_t last_in, last_out; + static gid_t last_in = GID_NONE, last_out = GID_NONE; struct idlist *list = gidlist; - if (gid == last_in) return last_out; + if (gid == last_in) + return last_out; last_in = gid; @@ -141,7 +192,10 @@ static gid_t match_gid(gid_t gid) list = list->next; } - last_out = gid; + if (am_root || is_in_group(gid)) + last_out = gid; + else + last_out = GID_NONE; return last_out; } @@ -223,7 +277,7 @@ void send_uid_list(int f) } /* terminate the uid list with a 0 uid. We explicitly exclude - 0 from the list */ + * 0 from the list */ write_int(f, 0); } @@ -241,7 +295,7 @@ void send_uid_list(int f) } /* recv a complete uid/gid mapping from the peer and map the uid/gid - in the file list to local names */ + * in the file list to local names */ void recv_uid_list(int f, struct file_list *flist) { int id, i; @@ -253,12 +307,11 @@ void recv_uid_list(int f, struct file_list *flist) if (preserve_uid) { /* read the uid list */ list = uidlist; - id = read_int(f); - while (id != 0) { + while ((id = read_int(f)) != 0) { int len = read_byte(f); - name = (char *)malloc(len); + name = new_array(char, len+1); if (!name) out_of_memory("recv_uid_list"); - read_buf(f, name, len); + read_sbuf(f, name, len); if (!list) { uidlist = add_list(id, name); list = uidlist; @@ -268,7 +321,13 @@ void recv_uid_list(int f, struct file_list *flist) } list->id2 = map_uid(id, name); free(name); - id = read_int(f); + } + if (verbose > 3) { + for (list = uidlist; list; list = list->next) { + rprintf(FINFO, "uid %ld (%s) maps to %ld\n", + (long)list->id, list->name, + (long)list->id2); + } } } @@ -276,12 +335,11 @@ void recv_uid_list(int f, struct file_list *flist) if (preserve_gid) { /* and the gid list */ list = gidlist; - id = read_int(f); - while (id != 0) { + while ((id = read_int(f)) != 0) { int len = read_byte(f); - name = (char *)malloc(len); + name = new_array(char, len+1); if (!name) out_of_memory("recv_uid_list"); - read_buf(f, name, len); + read_sbuf(f, name, len); if (!list) { gidlist = add_list(id, name); list = gidlist; @@ -290,21 +348,27 @@ void recv_uid_list(int f, struct file_list *flist) list = list->next; } list->id2 = map_gid(id, name); + if (!am_root && !is_in_group(list->id2)) + list->id2 = GID_NONE; free(name); - id = read_int(f); + } + if (verbose > 3) { + for (list = gidlist; list; list = list->next) { + rprintf(FINFO, "gid %ld (%s) maps to %ld\n", + (long)list->id, list->name, + (long)list->id2); + } } } - 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;icount;i++) { - if (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) { - flist->files[i].gid = match_gid(flist->files[i].gid); - } + * uid/gid */ + for (i = 0; i < flist->count; i++) { + if (am_root && preserve_uid && flist->files[i]->uid != 0) + flist->files[i]->uid = match_uid(flist->files[i]->uid); + if (preserve_gid && (!am_root || flist->files[i]->gid != 0)) + flist->files[i]->gid = match_gid(flist->files[i]->gid); } }