diff options
author | Andrew Tridgell <tridge@samba.org> | 1998-01-13 15:57:26 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1998-01-13 15:57:26 +0000 |
commit | f6c347425ac550dd1b7d1ff739bedd1489099d91 (patch) | |
tree | e809fc3af665129184bf114c0f300d3d5d2cb3c6 /uidlist.c | |
parent | 3b3a2fbcf058b90d9116f48ba26ad9528d450134 (diff) | |
download | rsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.tar.gz rsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.tar.bz2 rsync-f6c347425ac550dd1b7d1ff739bedd1489099d91.zip |
*** empty log message ***
Diffstat (limited to 'uidlist.c')
-rw-r--r-- | uidlist.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/uidlist.c b/uidlist.c new file mode 100644 index 00000000..b7d84ce9 --- /dev/null +++ b/uidlist.c @@ -0,0 +1,310 @@ +/* + 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. +*/ + +/* handle the mapping of uid/gid and user/group names between systems. + If the source username/group does not exist on the target then use + the numeric ids. Never do any mapping for uid=0 or gid=0 as these + are special. +*/ + +#include "rsync.h" + +extern int preserve_uid; +extern int preserve_gid; +extern int numeric_ids; + +struct idlist { + struct idlist *next; + int id, id2; + char *name; +}; + +static struct idlist *uidlist; +static struct idlist *gidlist; + +static struct idlist *add_list(int id, char *name) +{ + struct idlist *list = (struct idlist *)malloc(sizeof(list[0])); + if (!list) out_of_memory("add_list"); + list->next = NULL; + list->name = strdup(name); + if (!list->name) out_of_memory("add_list"); + list->id = (int)id; + return list; +} + + + +/* turn a uid into a user name */ +static char *uid_to_name(uid_t uid) +{ + struct passwd *pass = getpwuid(uid); + if (pass) return(pass->pw_name); + return NULL; +} + +/* turn a gid into a group name */ +static char *gid_to_name(gid_t gid) +{ + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + 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; + return id; +} + +static int map_gid(int id, char *name) +{ + gid_t gid = name_to_gid(name); + if (gid != 0) return gid; + return id; +} + +/* 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; + + last_in = uid; + + while (list) { + if (list->id == (int)uid) { + last_out = (uid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = uid; + return last_out; +} + +static gid_t match_gid(gid_t gid) +{ + static gid_t last_in, last_out; + struct idlist *list = gidlist; + + if (gid == last_in) return last_out; + + last_in = gid; + + while (list) { + if (list->id == (int)gid) { + last_out = (gid_t)list->id2; + return last_out; + } + list = list->next; + } + + last_out = gid; + return last_out; +} + +/* add a uid to the list of uids */ +void add_uid(uid_t uid) +{ + struct idlist *list = uidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (uid==0) return; + + if (!list) { + if (!(name = uid_to_name(uid))) return; + uidlist = add_list((int)uid, name); + return; + } + + while (list->next) { + if (list->id == (int)uid) return; + list = list->next; + } + + if (list->id == (int)uid) return; + + if (!(name = uid_to_name(uid))) return; + + list->next = add_list((int)uid, name); +} + +/* add a gid to the list of gids */ +void add_gid(gid_t gid) +{ + struct idlist *list = gidlist; + char *name; + + if (numeric_ids) return; + + /* don't map root */ + if (gid==0) return; + + if (!list) { + if (!(name = gid_to_name(gid))) return; + gidlist = add_list((int)gid, name); + return; + } + + while (list->next) { + if (list->id == (int)gid) return; + list = list->next; + } + + if (list->id == (int)gid) return; + + if (!(name = gid_to_name(gid))) return; + + list->next = add_list((int)gid, name); +} + + +/* send a complete uid/gid mapping to the peer */ +void send_uid_list(int f) +{ + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* we send sequences of uid/byte-length/name */ + list = uidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + + /* terminate the uid list with a 0 uid. We explicitly exclude + 0 from the list */ + write_int(f, 0); + } + + if (preserve_gid) { + list = gidlist; + while (list) { + int len = strlen(list->name); + write_int(f, list->id); + write_byte(f, len); + write_buf(f, list->name, len); + list = list->next; + } + write_int(f, 0); + } +} + +/* recv a complete uid/gid mapping from the peer and map the uid/gid + in the file list to local names */ +void recv_uid_list(int f, struct file_list *flist) +{ + int id, i; + char *name; + struct idlist *list; + + if (numeric_ids) return; + + if (preserve_uid) { + /* read the uid list */ + list = uidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + uidlist = add_list(id, name); + list = uidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_uid(id, name); + free(name); + id = read_int(f); + } + } + + + if (preserve_gid) { + /* and the gid list */ + list = gidlist; + id = read_int(f); + while (id != 0) { + int len = read_byte(f); + name = (char *)malloc(len); + if (!name) out_of_memory("recv_uid_list"); + read_buf(f, name, len); + if (!list) { + gidlist = add_list(id, name); + list = gidlist; + } else { + list->next = add_list(id, name); + list = list->next; + } + list->id2 = map_gid(id, name); + free(name); + id = read_int(f); + } + } + + if (!uidlist && !gidlist) 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) { + 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); + } + } +} |