mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-03-02 21:38:02 -05:00
Adding the --usermap/--groupmap/--chown options.
This commit is contained in:
3
NEWS
3
NEWS
@@ -26,6 +26,9 @@ Changes since 3.0.4:
|
||||
protocol 31), and 3) to follow the file-count, created-count, and
|
||||
deleted-count with a break-out list of each count by type.
|
||||
|
||||
- Added the --usermap/--groupmap/--chown options for manipulating file
|
||||
ownership during the copy.
|
||||
|
||||
- Added the "%C" escape to the log-output handling, which will output the
|
||||
MD5 checksum of any transferred file, or all files if --checksum was
|
||||
specified (when protocol 30 or above is in effect).
|
||||
|
||||
9
flist.c
9
flist.c
@@ -72,6 +72,7 @@ extern int sender_keeps_checksum;
|
||||
extern int unsort_ndx;
|
||||
extern struct stats stats;
|
||||
extern char *filesfrom_host;
|
||||
extern char *usermap, *groupmap;
|
||||
|
||||
extern char curr_dir[MAXPATHLEN];
|
||||
|
||||
@@ -802,7 +803,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
uid = (uid_t)read_varint(f);
|
||||
if (xflags & XMIT_USER_NAME_FOLLOWS)
|
||||
uid = recv_user_name(f, uid);
|
||||
else if (inc_recurse && am_root && !numeric_ids)
|
||||
else if (inc_recurse && am_root && (!numeric_ids || usermap))
|
||||
uid = match_uid(uid);
|
||||
}
|
||||
}
|
||||
@@ -814,7 +815,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
|
||||
gid_flags = 0;
|
||||
if (xflags & XMIT_GROUP_NAME_FOLLOWS)
|
||||
gid = recv_group_name(f, gid, &gid_flags);
|
||||
else if (inc_recurse && (!am_root || !numeric_ids))
|
||||
else if (inc_recurse && (!am_root || !numeric_ids || groupmap))
|
||||
gid = match_gid(gid, &gid_flags);
|
||||
}
|
||||
}
|
||||
@@ -2303,6 +2304,10 @@ struct file_list *recv_file_list(int f)
|
||||
else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server)
|
||||
rprintf(FCLIENT, "receiving incremental file list\n");
|
||||
rprintf(FLOG, "receiving file list\n");
|
||||
if (usermap)
|
||||
parse_name_map(usermap, True);
|
||||
if (groupmap)
|
||||
parse_name_map(groupmap, False);
|
||||
}
|
||||
|
||||
start_read = stats.total_read;
|
||||
|
||||
92
options.c
92
options.c
@@ -167,6 +167,8 @@ char *rsync_path = RSYNC_PATH;
|
||||
char *backup_dir = NULL;
|
||||
char backup_dir_buf[MAXPATHLEN];
|
||||
char *sockopts = NULL;
|
||||
char *usermap = NULL;
|
||||
char *groupmap = NULL;
|
||||
int rsync_port = 0;
|
||||
int compare_dest = 0;
|
||||
int copy_dest = 0;
|
||||
@@ -296,6 +298,7 @@ static int refused_delete, refused_archive_part, refused_compress;
|
||||
static int refused_partial, refused_progress, refused_delete_before;
|
||||
static int refused_delete_during;
|
||||
static int refused_inplace, refused_no_iconv;
|
||||
static BOOL usermap_via_chown, groupmap_via_chown;
|
||||
static char *max_size_arg, *min_size_arg;
|
||||
static char tmp_partialdir[] = ".~tmp~";
|
||||
|
||||
@@ -725,6 +728,9 @@ void usage(enum logcode F)
|
||||
rprintf(F," --delay-updates put all updated files into place at transfer's end\n");
|
||||
rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n");
|
||||
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
|
||||
rprintf(F," --usermap=STRING custom username mapping\n");
|
||||
rprintf(F," --groupmap=STRING custom groupname mapping\n");
|
||||
rprintf(F," --chown=USER:GROUP simple username/groupname mapping\n");
|
||||
rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n");
|
||||
rprintf(F," --contimeout=SECONDS set daemon connection timeout in seconds\n");
|
||||
rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n");
|
||||
@@ -789,6 +795,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
|
||||
OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD,
|
||||
OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE,
|
||||
OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG,
|
||||
OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN,
|
||||
OPT_SERVER, OPT_REFUSED_BASE = 9000};
|
||||
|
||||
static struct poptOption long_options[] = {
|
||||
@@ -969,6 +976,9 @@ static struct poptOption long_options[] = {
|
||||
{"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
|
||||
{"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
|
||||
{"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
|
||||
{"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 },
|
||||
{"groupmap", 0, POPT_ARG_STRING, 0, OPT_GROUPMAP, 0, 0 },
|
||||
{"chown", 0, POPT_ARG_STRING, 0, OPT_CHOWN, 0, 0 },
|
||||
{"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
|
||||
{"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
|
||||
{"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 },
|
||||
@@ -1625,6 +1635,76 @@ int parse_arguments(int *argc_p, const char ***argv_p)
|
||||
parse_output_words(debug_words, debug_levels, arg, USER_PRIORITY);
|
||||
break;
|
||||
|
||||
case OPT_USERMAP:
|
||||
if (usermap) {
|
||||
if (usermap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--usermap conflicts with prior --chown.\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify --usermap once.\n");
|
||||
return 0;
|
||||
}
|
||||
usermap = (char *)poptGetOptArg(pc);
|
||||
usermap_via_chown = False;
|
||||
break;
|
||||
|
||||
case OPT_GROUPMAP:
|
||||
if (groupmap) {
|
||||
if (groupmap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--groupmap conflicts with prior --chown.\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify --groupmap once.\n");
|
||||
return 0;
|
||||
}
|
||||
groupmap = (char *)poptGetOptArg(pc);
|
||||
groupmap_via_chown = False;
|
||||
break;
|
||||
|
||||
case OPT_CHOWN: {
|
||||
const char *chown = poptGetOptArg(pc);
|
||||
int len;
|
||||
if ((arg = strchr(chown, ':')) != NULL)
|
||||
len = arg++ - chown;
|
||||
else
|
||||
len = strlen(chown);
|
||||
if (len) {
|
||||
if (usermap) {
|
||||
if (!usermap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--chown conflicts with prior --usermap.\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify a user-affecting --chown once.\n");
|
||||
return 0;
|
||||
}
|
||||
if (asprintf(&usermap, "*:%.*s", len, chown) < 0)
|
||||
out_of_memory("parse_arguments");
|
||||
usermap_via_chown = True;
|
||||
}
|
||||
if (arg && *arg) {
|
||||
if (groupmap) {
|
||||
if (!groupmap_via_chown) {
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"--chown conflicts with prior --groupmap.\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"You can only specify a group-affecting --chown once.\n");
|
||||
return 0;
|
||||
}
|
||||
if (asprintf(&groupmap, "*:%s", arg) < 0)
|
||||
out_of_memory("parse_arguments");
|
||||
groupmap_via_chown = True;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OPT_HELP:
|
||||
usage(FINFO);
|
||||
exit_cleanup(0);
|
||||
@@ -2435,6 +2515,18 @@ void server_options(char **args, int *argc_p)
|
||||
args[ac++] = "--use-qsort";
|
||||
|
||||
if (am_sender) {
|
||||
if (usermap) {
|
||||
if (asprintf(&arg, "--usermap=%s", usermap) < 0)
|
||||
goto oom;
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (groupmap) {
|
||||
if (asprintf(&arg, "--groupmap=%s", groupmap) < 0)
|
||||
goto oom;
|
||||
args[ac++] = arg;
|
||||
}
|
||||
|
||||
if (ignore_existing)
|
||||
args[ac++] = "--ignore-existing";
|
||||
|
||||
|
||||
54
rsync.yo
54
rsync.yo
@@ -385,6 +385,9 @@ to the detailed description below for a complete description. verb(
|
||||
--delay-updates put all updated files into place at end
|
||||
-m, --prune-empty-dirs prune empty directory chains from file-list
|
||||
--numeric-ids don't map uid/gid values by user/group name
|
||||
--usermap=STRING custom username mapping
|
||||
--groupmap=STRING custom groupname mapping
|
||||
--chown=USER:GROUP simple username/groupname mapping
|
||||
--timeout=SECONDS set I/O timeout in seconds
|
||||
--contimeout=SECONDS set daemon connection timeout in seconds
|
||||
-I, --ignore-times don't skip files that match size and time
|
||||
@@ -1716,6 +1719,57 @@ from the source system is used instead. See also the comments on the
|
||||
the chroot setting affects rsync's ability to look up the names of the
|
||||
users and groups and what you can do about it.
|
||||
|
||||
dit(bf(--usermap=STRING, --groupmap=STRING)) These options allow you to
|
||||
specify users and groups that should be mapped to other values by the
|
||||
receiving side. The bf(STRING) is one or more bf(FROM):bf(TO) pairs of
|
||||
values separated by commas. Any matching bf(FROM) value from the sender is
|
||||
replaced with a bf(TO) value from the receiver. You may specify usernames
|
||||
or user IDs for the bf(FROM) and bf(TO) values, and the bf(FROM) value may
|
||||
also be a wild-card string, which will be matched against the sender's
|
||||
names (wild-cards do NOT match against ID numbers, though see below for
|
||||
why a '*' matches everything). You may instead specify a range of ID
|
||||
numbers via an inclusive range: LOW-HIGH. For example:
|
||||
|
||||
verb( --usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr)
|
||||
|
||||
The first match in the list is the one that is used. You should specify
|
||||
all your user mappings using a single bf(--usermap) option, and/or all
|
||||
your group mappings using a single bf(--groupmap) option.
|
||||
|
||||
Note that the sender's name for the 0 user and group are not transmitted
|
||||
to the receiver, so you should either match these values using a 0, or use
|
||||
the names in effect on the receiving side (typically "root"). All other
|
||||
bf(FROM) names match those in use on the sending side. All bf(TO) names
|
||||
match those in use on the receiving side.
|
||||
|
||||
Any IDs that do not have a name on the sending side are treated as having an
|
||||
empty name for the purpose of matching. This allows them to be matched via
|
||||
a "*" or using an empty name. For instance:
|
||||
|
||||
verb( --usermap=:nobody --groupmap=*:nobody)
|
||||
|
||||
When the bf(--numeric-ids) option is used, the sender does not send any
|
||||
names, so all the IDs are treated as having an empty name. This means that
|
||||
you will need to specify numeric bf(FROM) values if you want to map these
|
||||
nameless IDs to different values.
|
||||
|
||||
For the bf(--usermap) option to have any effect, the bf(-o) (bf(--owner))
|
||||
option must be used (or implied), and the receiver will need to be running
|
||||
as a super-user (see also the bf(--fake-super) option). For the bf(--groupmap)
|
||||
option to have any effect, the bf(-g) (bf(--groups)) option must be used
|
||||
(or implied), and the receiver will need to have permissions to set that
|
||||
group.
|
||||
|
||||
dit(bf(--chown=USER:GROUP)) This option forces all files to be owned by USER
|
||||
with group GROUP. This is a simpler interface than using bf(--usermap) and
|
||||
bf(--groupmap) directly, but it is implemented using those options internally,
|
||||
so you cannot mix them. If either the USER or GROUP is empty, no mapping for
|
||||
the omitted user/group will occur. If GROUP is empty, the trailing colon may
|
||||
be omitted, but if USER is empty, a leading colon must be supplied.
|
||||
|
||||
If you specify "--chown=foo:bar, this is exactly the same as specifying
|
||||
"--usermap=*:foo --groupmap=*:bar", only easier.
|
||||
|
||||
dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum I/O
|
||||
timeout in seconds. If no data is transferred for the specified time
|
||||
then rsync will exit. The default is 0, which means no timeout.
|
||||
|
||||
5
support/mapfrom
Normal file
5
support/mapfrom
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/perl
|
||||
while (<>) {
|
||||
push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/;
|
||||
}
|
||||
print join(',', @_), "\n";
|
||||
5
support/mapto
Normal file
5
support/mapto
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/perl
|
||||
while (<>) {
|
||||
push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/;
|
||||
}
|
||||
print join(',', @_), "\n";
|
||||
196
uidlist.c
196
uidlist.c
@@ -24,6 +24,8 @@
|
||||
* are special. */
|
||||
|
||||
#include "rsync.h"
|
||||
#include "ifuncs.h"
|
||||
#include "itypes.h"
|
||||
#include "io.h"
|
||||
|
||||
extern int am_root;
|
||||
@@ -31,6 +33,8 @@ extern int preserve_uid;
|
||||
extern int preserve_gid;
|
||||
extern int preserve_acls;
|
||||
extern int numeric_ids;
|
||||
extern char *usermap;
|
||||
extern char *groupmap;
|
||||
|
||||
#ifdef HAVE_GETGROUPS
|
||||
# ifndef GETGROUPS_T
|
||||
@@ -40,6 +44,9 @@ extern int numeric_ids;
|
||||
|
||||
#define GID_NONE ((gid_t)-1)
|
||||
|
||||
#define NFLAGS_WILD_NAME_MATCH (1<<0)
|
||||
#define NFLAGS_NAME_MATCH (1<<1)
|
||||
|
||||
struct idlist {
|
||||
struct idlist *next;
|
||||
const char *name;
|
||||
@@ -47,8 +54,8 @@ struct idlist {
|
||||
uint16 flags;
|
||||
};
|
||||
|
||||
static struct idlist *uidlist;
|
||||
static struct idlist *gidlist;
|
||||
static struct idlist *uidlist, *uidmap;
|
||||
static struct idlist *gidlist, *gidmap;
|
||||
|
||||
static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
|
||||
id_t id2, uint16 flags)
|
||||
@@ -83,22 +90,6 @@ static const char *gid_to_name(gid_t gid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uid_t map_uid(uid_t id, const char *name)
|
||||
{
|
||||
uid_t uid;
|
||||
if (id != 0 && name_to_uid(name, &uid))
|
||||
return uid;
|
||||
return id;
|
||||
}
|
||||
|
||||
static gid_t map_gid(gid_t id, const char *name)
|
||||
{
|
||||
gid_t gid;
|
||||
if (id != 0 && name_to_gid(name, &gid))
|
||||
return gid;
|
||||
return id;
|
||||
}
|
||||
|
||||
static int is_in_group(gid_t gid)
|
||||
{
|
||||
#ifdef HAVE_GETGROUPS
|
||||
@@ -158,34 +149,53 @@ static int is_in_group(gid_t gid)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Add a uid to the list of uids. Only called on receiving side. */
|
||||
static struct idlist *recv_add_uid(uid_t id, const char *name)
|
||||
/* Add a uid/gid to its list of ids. Only called on receiving side. */
|
||||
static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap,
|
||||
id_t id, const char *name)
|
||||
{
|
||||
uid_t id2 = name ? map_uid(id, name) : id;
|
||||
struct idlist *node;
|
||||
int flag;
|
||||
id_t id2;
|
||||
|
||||
node = add_to_list(&uidlist, id, name, id2, 0);
|
||||
if (!name)
|
||||
name = "";
|
||||
|
||||
if (DEBUG_GTE(OWN, 2)) {
|
||||
rprintf(FINFO, "uid %u(%s) maps to %u\n",
|
||||
(unsigned)id, name ? name : "", (unsigned)id2);
|
||||
for (node = idmap; node; node = node->next) {
|
||||
if (node->flags & NFLAGS_WILD_NAME_MATCH) {
|
||||
if (!wildmatch(node->name, name))
|
||||
continue;
|
||||
} else if (node->flags & NFLAGS_NAME_MATCH) {
|
||||
if (strcmp(node->name, name) != 0)
|
||||
continue;
|
||||
} else if (node->name) {
|
||||
if (id < node->id || id > (unsigned long)node->name)
|
||||
continue;
|
||||
} else {
|
||||
if (node->id != id)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (node)
|
||||
id2 = node->id2;
|
||||
else if (*name && id) {
|
||||
if (idmap == uidmap) {
|
||||
uid_t uid;
|
||||
id2 = name_to_uid(name, &uid) ? uid : id;
|
||||
} else {
|
||||
gid_t gid;
|
||||
id2 = name_to_gid(name, &gid) ? gid : id;
|
||||
}
|
||||
} else
|
||||
id2 = id;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Add a gid to the list of gids. Only called on receiving side. */
|
||||
static struct idlist *recv_add_gid(gid_t id, const char *name)
|
||||
{
|
||||
gid_t id2 = name ? map_gid(id, name) : id;
|
||||
struct idlist *node;
|
||||
|
||||
node = add_to_list(&gidlist, id, name, id2,
|
||||
!am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
|
||||
flag = idmap == gidmap && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0;
|
||||
node = add_to_list(idlist_ptr, id, *name ? name : NULL, id2, flag);
|
||||
|
||||
if (DEBUG_GTE(OWN, 2)) {
|
||||
rprintf(FINFO, "gid %u(%s) maps to %u\n",
|
||||
(unsigned)id, name ? name : "", (unsigned)id2);
|
||||
rprintf(FINFO, "%sid %u(%s) maps to %u\n",
|
||||
idmap == uidmap ? "u" : "g",
|
||||
(unsigned)id, name, (unsigned)id2);
|
||||
}
|
||||
|
||||
return node;
|
||||
@@ -194,12 +204,9 @@ static struct idlist *recv_add_gid(gid_t id, const char *name)
|
||||
/* this function is a definate candidate for a faster algorithm */
|
||||
uid_t match_uid(uid_t uid)
|
||||
{
|
||||
static uid_t last_in, last_out;
|
||||
static uid_t last_in = -1, last_out = -1;
|
||||
struct idlist *list;
|
||||
|
||||
if (uid == 0)
|
||||
return 0;
|
||||
|
||||
if (uid == last_in)
|
||||
return last_out;
|
||||
|
||||
@@ -207,10 +214,13 @@ uid_t match_uid(uid_t uid)
|
||||
|
||||
for (list = uidlist; list; list = list->next) {
|
||||
if (list->id == uid)
|
||||
return last_out = list->id2;
|
||||
break;
|
||||
}
|
||||
|
||||
return last_out = uid;
|
||||
if (!list)
|
||||
list = recv_add_id(&uidlist, uidmap, uid, NULL);
|
||||
|
||||
return last_out = list->id2;
|
||||
}
|
||||
|
||||
gid_t match_gid(gid_t gid, uint16 *flags_ptr)
|
||||
@@ -226,7 +236,7 @@ gid_t match_gid(gid_t gid, uint16 *flags_ptr)
|
||||
break;
|
||||
}
|
||||
if (!list)
|
||||
list = recv_add_gid(gid, NULL);
|
||||
list = recv_add_id(&gidlist, gidmap, gid, NULL);
|
||||
last = list;
|
||||
}
|
||||
|
||||
@@ -319,7 +329,7 @@ uid_t recv_user_name(int f, uid_t uid)
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
node = recv_add_uid(uid, name); /* node keeps name's memory */
|
||||
node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */
|
||||
return node->id2;
|
||||
}
|
||||
|
||||
@@ -335,7 +345,7 @@ gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
node = recv_add_gid(gid, name); /* node keeps name's memory */
|
||||
node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */
|
||||
if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
|
||||
*flags_ptr |= FLAG_SKIP_GROUP;
|
||||
return node->id2;
|
||||
@@ -362,17 +372,103 @@ void recv_id_list(int f, struct file_list *flist)
|
||||
|
||||
/* Now convert all the uids/gids from sender values to our values. */
|
||||
#ifdef SUPPORT_ACLS
|
||||
if (preserve_acls && !numeric_ids)
|
||||
if (preserve_acls && (!numeric_ids || usermap || groupmap))
|
||||
match_acl_ids();
|
||||
#endif
|
||||
if (am_root && preserve_uid && !numeric_ids) {
|
||||
if (am_root && preserve_uid && (!numeric_ids || usermap)) {
|
||||
for (i = 0; i < flist->used; i++)
|
||||
F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
|
||||
}
|
||||
if (preserve_gid && (!am_root || !numeric_ids)) {
|
||||
if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
|
||||
for (i = 0; i < flist->used; i++) {
|
||||
F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
|
||||
&flist->files[i]->flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_name_map(char *map, BOOL usernames)
|
||||
{
|
||||
struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
|
||||
struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
|
||||
char *colon, *end, *name, *cp = map + strlen(map);
|
||||
id_t id1;
|
||||
uint16 flags;
|
||||
|
||||
/* Parse the list in reverse, so the order in the struct is right. */
|
||||
while (1) {
|
||||
end = cp;
|
||||
while (cp > map && cp[-1] != ',') cp--;
|
||||
if (!(colon = strchr(cp, ':'))) {
|
||||
rprintf(FERROR, "No colon found in --%smap: %s\n",
|
||||
usernames ? "user" : "group", cp);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (!colon[1]) {
|
||||
rprintf(FERROR, "No name found after colon --%smap: %s\n",
|
||||
usernames ? "user" : "group", cp);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
*colon = '\0';
|
||||
|
||||
if (isDigit(cp)) {
|
||||
char *dash = strchr(cp, '-');
|
||||
if (strspn(cp, "0123456789-") != (size_t)(colon - cp)
|
||||
|| (dash && (!dash[1] || strchr(dash+1, '-')))) {
|
||||
bad_number:
|
||||
rprintf(FERROR, "Invalid number in --%smap: %s\n",
|
||||
usernames ? "user" : "group", cp);
|
||||
exit_cleanup(RERR_SYNTAX);
|
||||
}
|
||||
if (dash)
|
||||
name = (char *)atol(dash+1);
|
||||
else
|
||||
name = (char *)0;
|
||||
flags = 0;
|
||||
id1 = atol(cp);
|
||||
} else if (strpbrk(cp, "*[?")) {
|
||||
flags = NFLAGS_WILD_NAME_MATCH;
|
||||
name = cp;
|
||||
id1 = 0;
|
||||
} else {
|
||||
flags = NFLAGS_NAME_MATCH;
|
||||
name = cp;
|
||||
id1 = 0;
|
||||
}
|
||||
|
||||
if (isDigit(colon+1)) {
|
||||
if (strspn(colon+1, "0123456789") != (size_t)(end - colon - 1)) {
|
||||
cp = colon+1;
|
||||
goto bad_number;
|
||||
}
|
||||
add_to_list(idmap_ptr, id1, name, atol(colon+1), flags);
|
||||
} else if (usernames) {
|
||||
uid_t uid;
|
||||
if (name_to_uid(colon+1, &uid))
|
||||
add_to_list(idmap_ptr, id1, name, uid, flags);
|
||||
else {
|
||||
rprintf(FERROR,
|
||||
"Unknown --usermap name on receiver: %s\n",
|
||||
colon+1);
|
||||
}
|
||||
} else {
|
||||
gid_t gid;
|
||||
if (name_to_gid(colon+1, &gid))
|
||||
add_to_list(idmap_ptr, id1, name, gid, flags);
|
||||
else {
|
||||
rprintf(FERROR,
|
||||
"Unknown --groupmap name on receiver: %s\n",
|
||||
colon+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cp == map)
|
||||
break;
|
||||
|
||||
*--cp = '\0'; /* replace comma */
|
||||
}
|
||||
|
||||
/* The 0 user/group doesn't get its name sent, so add it explicitly. */
|
||||
recv_add_id(idlist_ptr, *idmap_ptr, 0,
|
||||
numeric_ids ? NULL : usernames ? uid_to_name(0) : gid_to_name(0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user