Commit | Line | Data |
---|---|---|
409bd73e WD |
1 | This adds a --usermap and a --groupmap option. See the man page for |
2 | more details. | |
4122278d | 3 | |
409bd73e WD |
4 | To use this patch, run these commands for a successful build: |
5 | ||
6 | patch -p1 <patches/usermap.diff | |
7 | ./configure (optional if already run) | |
8 | make | |
4122278d | 9 | |
cc3e685d WD |
10 | diff --git a/flist.c b/flist.c |
11 | --- a/flist.c | |
12 | +++ b/flist.c | |
ae306a29 | 13 | @@ -71,6 +71,7 @@ extern int sender_symlink_iconv; |
d4dd2dd5 | 14 | extern int unsort_ndx; |
4122278d | 15 | extern struct stats stats; |
c8a8b4a7 | 16 | extern char *filesfrom_host; |
d4dd2dd5 | 17 | +extern char *usermap, *groupmap; |
4122278d | 18 | |
d4dd2dd5 WD |
19 | extern char curr_dir[MAXPATHLEN]; |
20 | ||
ae306a29 | 21 | @@ -767,7 +768,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, |
409bd73e | 22 | uid = (uid_t)read_varint(f); |
6a189d36 | 23 | if (xflags & XMIT_USER_NAME_FOLLOWS) |
409bd73e WD |
24 | uid = recv_user_name(f, uid); |
25 | - else if (inc_recurse && am_root && !numeric_ids) | |
f62e6e48 | 26 | + else if (inc_recurse && am_root && (!numeric_ids || usermap)) |
409bd73e WD |
27 | uid = match_uid(uid); |
28 | } | |
29 | } | |
ae306a29 | 30 | @@ -779,7 +780,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, |
761f1b71 | 31 | gid_flags = 0; |
6a189d36 | 32 | if (xflags & XMIT_GROUP_NAME_FOLLOWS) |
761f1b71 | 33 | gid = recv_group_name(f, gid, &gid_flags); |
409bd73e | 34 | - else if (inc_recurse && (!am_root || !numeric_ids)) |
f62e6e48 | 35 | + else if (inc_recurse && (!am_root || !numeric_ids || groupmap)) |
761f1b71 | 36 | gid = match_gid(gid, &gid_flags); |
409bd73e WD |
37 | } |
38 | } | |
bf1bd9d4 | 39 | @@ -2248,8 +2249,13 @@ struct file_list *recv_file_list(int f) |
4122278d | 40 | int64 start_read; |
bf1bd9d4 | 41 | int save_verbose = verbose; |
4122278d WD |
42 | |
43 | - if (!first_flist) | |
44 | + if (!first_flist) { | |
45 | rprintf(FLOG, "receiving file list\n"); | |
46 | + if (usermap) | |
47 | + parse_name_map(usermap, 1); | |
48 | + if (groupmap) | |
49 | + parse_name_map(groupmap, 0); | |
50 | + } | |
51 | if (show_filelist_p()) | |
52 | start_filelist_progress("receiving file list"); | |
53 | else if (inc_recurse && verbose && !am_server && !first_flist) | |
cc3e685d WD |
54 | diff --git a/options.c b/options.c |
55 | --- a/options.c | |
56 | +++ b/options.c | |
c0c7984e | 57 | @@ -167,6 +167,8 @@ char *rsync_path = RSYNC_PATH; |
4122278d WD |
58 | char *backup_dir = NULL; |
59 | char backup_dir_buf[MAXPATHLEN]; | |
60 | char *sockopts = NULL; | |
61 | +char *usermap = NULL; | |
62 | +char *groupmap = NULL; | |
63 | int rsync_port = 0; | |
64 | int compare_dest = 0; | |
65 | int copy_dest = 0; | |
abd3adb8 | 66 | @@ -385,6 +387,9 @@ void usage(enum logcode F) |
4122278d WD |
67 | rprintf(F," --delay-updates put all updated files into place at transfer's end\n"); |
68 | rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n"); | |
69 | rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); | |
70 | + rprintf(F," --usermap=STRING custom username mapping\n"); | |
71 | + rprintf(F," --groupmap=STRING custom groupname mapping\n"); | |
6ac9ce9a | 72 | + rprintf(F," --chown=USER:GROUP simple username/groupname mapping\n"); |
cc3e685d WD |
73 | rprintf(F," --timeout=SECONDS set I/O timeout in seconds\n"); |
74 | rprintf(F," --contimeout=SECONDS set daemon connection timeout in seconds\n"); | |
4122278d | 75 | rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n"); |
abd3adb8 | 76 | @@ -447,7 +452,7 @@ enum {OPT_VERSION = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM, |
ab5ffac0 WD |
77 | OPT_FILTER, OPT_COMPARE_DEST, OPT_COPY_DEST, OPT_LINK_DEST, OPT_HELP, |
78 | OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW, OPT_MIN_SIZE, OPT_CHMOD, | |
79 | OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_ONLY_WRITE_BATCH, OPT_MAX_SIZE, | |
80 | - OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, | |
6ac9ce9a | 81 | + OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, |
ab5ffac0 WD |
82 | OPT_SERVER, OPT_REFUSED_BASE = 9000}; |
83 | ||
84 | static struct poptOption long_options[] = { | |
abd3adb8 | 85 | @@ -623,6 +628,9 @@ static struct poptOption long_options[] = { |
c8a8b4a7 | 86 | {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, |
6cbbe66d WD |
87 | {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 }, |
88 | {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 }, | |
ab5ffac0 WD |
89 | + {"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 }, |
90 | + {"groupmap", 0, POPT_ARG_STRING, 0, OPT_GROUPMAP, 0, 0 }, | |
6ac9ce9a | 91 | + {"chown", 0, POPT_ARG_STRING, 0, OPT_CHOWN, 0, 0 }, |
4122278d | 92 | {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 }, |
6cbbe66d | 93 | {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 }, |
cc3e685d | 94 | {"contimeout", 0, POPT_ARG_INT, &connect_timeout, 0, 0, 0 }, |
abd3adb8 | 95 | @@ -1229,6 +1237,43 @@ int parse_arguments(int *argc_p, const char ***argv_p) |
ab5ffac0 WD |
96 | } |
97 | break; | |
98 | ||
99 | + case OPT_USERMAP: | |
100 | + if (usermap) { | |
101 | + snprintf(err_buf, sizeof err_buf, | |
102 | + "You can only specify --usermap once.\n"); | |
103 | + return 0; | |
104 | + } | |
105 | + usermap = (char *)poptGetOptArg(pc); | |
106 | + break; | |
107 | + | |
108 | + case OPT_GROUPMAP: | |
109 | + if (groupmap) { | |
110 | + snprintf(err_buf, sizeof err_buf, | |
111 | + "You can only specify --groupmap once.\n"); | |
112 | + return 0; | |
113 | + } | |
114 | + groupmap = (char *)poptGetOptArg(pc); | |
115 | + break; | |
6ac9ce9a WD |
116 | + |
117 | + case OPT_CHOWN: | |
118 | + if (usermap || groupmap) { | |
119 | + snprintf(err_buf, sizeof err_buf, | |
120 | + "You can only specify --chown once.\n"); | |
121 | + return 0; | |
122 | + } else { | |
123 | + const char *chown = poptGetOptArg(pc); | |
124 | + int len; | |
125 | + if ((arg = strchr(chown, ':')) != NULL) { | |
126 | + if (arg[1] && asprintf(&groupmap, "*:%s", arg+1) < 0) | |
127 | + out_of_memory("parse_arguments"); | |
128 | + len = arg - chown; | |
129 | + } else | |
130 | + len = strlen(chown); | |
131 | + if (len && asprintf(&usermap, "*:%.*s", len, chown) < 0) | |
132 | + out_of_memory("parse_arguments"); | |
133 | + } | |
134 | + break; | |
ab5ffac0 WD |
135 | + |
136 | case OPT_HELP: | |
137 | usage(FINFO); | |
138 | exit_cleanup(0); | |
abd3adb8 | 139 | @@ -2007,6 +2052,18 @@ void server_options(char **args, int *argc_p) |
d4dd2dd5 | 140 | args[ac++] = "--use-qsort"; |
4122278d WD |
141 | |
142 | if (am_sender) { | |
143 | + if (usermap) { | |
f62e6e48 | 144 | + if (asprintf(&arg, "--usermap=%s", usermap) < 0) |
4122278d WD |
145 | + goto oom; |
146 | + args[ac++] = arg; | |
147 | + } | |
148 | + | |
149 | + if (groupmap) { | |
f62e6e48 | 150 | + if (asprintf(&arg, "--groupmap=%s", groupmap) < 0) |
4122278d WD |
151 | + goto oom; |
152 | + args[ac++] = arg; | |
153 | + } | |
154 | + | |
155 | if (ignore_existing) | |
156 | args[ac++] = "--ignore-existing"; | |
157 | ||
cc3e685d WD |
158 | diff --git a/rsync.yo b/rsync.yo |
159 | --- a/rsync.yo | |
160 | +++ b/rsync.yo | |
abd3adb8 | 161 | @@ -382,6 +382,9 @@ to the detailed description below for a complete description. verb( |
4122278d WD |
162 | --delay-updates put all updated files into place at end |
163 | -m, --prune-empty-dirs prune empty directory chains from file-list | |
164 | --numeric-ids don't map uid/gid values by user/group name | |
165 | + --usermap=STRING custom username mapping | |
166 | + --groupmap=STRING custom groupname mapping | |
6ac9ce9a | 167 | + --chown=USER:GROUP simple username/groupname mapping |
cc3e685d WD |
168 | --timeout=SECONDS set I/O timeout in seconds |
169 | --contimeout=SECONDS set daemon connection timeout in seconds | |
4122278d | 170 | -I, --ignore-times don't skip files that match size and time |
abd3adb8 | 171 | @@ -1624,6 +1627,57 @@ from the source system is used instead. See also the comments on the |
4122278d WD |
172 | the chroot setting affects rsync's ability to look up the names of the |
173 | users and groups and what you can do about it. | |
174 | ||
175 | +dit(bf(--usermap=STRING, --groupmap=STRING)) These options allow you to | |
409bd73e WD |
176 | +specify users and groups that should be mapped to other values by the |
177 | +receiving side. The bf(STRING) is one or more bf(FROM):bf(TO) pairs of | |
178 | +values separated by commas. Any matching bf(FROM) value from the sender is | |
179 | +replaced with a bf(TO) value from the receiver. You may specify usernames | |
180 | +or user IDs for the bf(FROM) and bf(TO) values, and the bf(FROM) value may | |
181 | +also be a wild-card string, which will be matched against the sender's | |
ab5ffac0 WD |
182 | +names (wild-cards do NOT match against ID numbers, though see below for |
183 | +why a '*' matches everything). You may instead specify a range of ID | |
184 | +numbers via an inclusive range: LOW-HIGH. For example: | |
409bd73e | 185 | + |
ab5ffac0 | 186 | +verb( --usermap=0-99:nobody,wayne:admin,*:normal --groupmap=usr:1,1:usr) |
409bd73e | 187 | + |
ab5ffac0 WD |
188 | +The first match in the list is the one that is used. You should specify |
189 | +all your user mappings using a single bf(--usermap) option, and/or all | |
190 | +your group mappings using a single bf(--groupmap) option. | |
4122278d | 191 | + |
9405aad3 | 192 | +Note that the sender's name for the 0 user and group are not transmitted |
409bd73e | 193 | +to the receiver, so you should either match these values using a 0, or use |
ab5ffac0 WD |
194 | +the names in effect on the receiving side (typically "root"). All other |
195 | +bf(FROM) names match those in use on the sending side. All bf(TO) names | |
196 | +match those in use on the receiving side. | |
4122278d | 197 | + |
ab5ffac0 | 198 | +Any IDs that do not have a name on the sending side are treated as having an |
9405aad3 | 199 | +empty name for the purpose of matching. This allows them to be matched via |
ab5ffac0 | 200 | +a "*" or using an empty name. For instance: |
9405aad3 WD |
201 | + |
202 | +verb( --usermap=:nobody --groupmap=*:nobody) | |
203 | + | |
204 | +When the bf(--numeric-ids) option is used,the sender does not send any | |
ab5ffac0 | 205 | +names, so all the IDs are treated as having an empty name. This means that |
9405aad3 WD |
206 | +you will need to specify numeric bf(FROM) values if you want to map these |
207 | +nameless IDs to different values. | |
4122278d | 208 | + |
409bd73e WD |
209 | +For the bf(--usermap) option to have any effect, the bf(-o) (bf(--owner)) |
210 | +option must be used (or implied), and the receiver will need to be running | |
9405aad3 | 211 | +as a super-user (see also the bf(--fake-super) option). For the bf(--groupmap) |
409bd73e WD |
212 | +option to have any effect, the bf(-g) (bf(--groups)) option must be used |
213 | +(or implied), and the receiver will need to have permissions to set that | |
214 | +group. | |
6ac9ce9a WD |
215 | + |
216 | +dit(bf(--chown=USER:GROUP)) This option forces all files to be owned by USER | |
217 | +with group GROUP. This is a simpler interface than using bf(--usermap) and | |
218 | +bf(--groupmap) directly, but it is implemented using those options internally, | |
219 | +so you cannot mix them. If either the USER or GROUP is empty, no mapping for | |
220 | +the omitted user/group will occur. If GROUP is empty, the trailing colon may | |
221 | +be omitted, but if USER is empty, a leading colon must be supplied. | |
222 | + | |
223 | +If you specify "--chown=foo:bar, this is exactly the same as specifying | |
224 | +"--usermap=*:foo --groupmap=*:bar", only easier. | |
4122278d WD |
225 | + |
226 | dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum I/O | |
227 | timeout in seconds. If no data is transferred for the specified time | |
228 | then rsync will exit. The default is 0, which means no timeout. | |
ae306a29 WD |
229 | diff --git a/support/mapfrom b/support/mapfrom |
230 | new file mode 100755 | |
231 | --- /dev/null | |
232 | +++ b/support/mapfrom | |
233 | @@ -0,0 +1,5 @@ | |
234 | +#!/usr/bin/perl | |
235 | +while (<>) { | |
236 | + push @_, "$2:$1" if /^(\w+):[^:]+:(\d+)/; | |
237 | +} | |
238 | +print join(',', @_), "\n"; | |
239 | diff --git a/support/mapto b/support/mapto | |
240 | new file mode 100755 | |
241 | --- /dev/null | |
242 | +++ b/support/mapto | |
243 | @@ -0,0 +1,5 @@ | |
244 | +#!/usr/bin/perl | |
245 | +while (<>) { | |
246 | + push @_, "$1:$2" if /^(\w+):[^:]+:(\d+)/; | |
247 | +} | |
248 | +print join(',', @_), "\n"; | |
cc3e685d WD |
249 | diff --git a/uidlist.c b/uidlist.c |
250 | --- a/uidlist.c | |
251 | +++ b/uidlist.c | |
c82285d5 WD |
252 | @@ -24,6 +24,7 @@ |
253 | * are special. */ | |
254 | ||
255 | #include "rsync.h" | |
256 | +#include "ifuncs.h" | |
257 | #include "io.h" | |
258 | ||
259 | extern int verbose; | |
260 | @@ -32,6 +33,8 @@ extern int preserve_uid; | |
4122278d WD |
261 | extern int preserve_gid; |
262 | extern int preserve_acls; | |
263 | extern int numeric_ids; | |
409bd73e WD |
264 | +extern char *usermap; |
265 | +extern char *groupmap; | |
4122278d | 266 | |
6a189d36 WD |
267 | #ifdef HAVE_GETGROUPS |
268 | # ifndef GETGROUPS_T | |
c82285d5 | 269 | @@ -41,6 +44,9 @@ extern int numeric_ids; |
6a189d36 WD |
270 | |
271 | #define GID_NONE ((gid_t)-1) | |
272 | ||
273 | +#define NFLAGS_WILD_NAME_MATCH (1<<0) | |
274 | +#define NFLAGS_NAME_MATCH (1<<1) | |
275 | + | |
4122278d WD |
276 | struct idlist { |
277 | struct idlist *next; | |
4c15e800 | 278 | const char *name; |
c82285d5 | 279 | @@ -48,8 +54,8 @@ struct idlist { |
6a189d36 | 280 | uint16 flags; |
4122278d WD |
281 | }; |
282 | ||
283 | -static struct idlist *uidlist; | |
284 | -static struct idlist *gidlist; | |
285 | +static struct idlist *uidlist, *uidmap; | |
286 | +static struct idlist *gidlist, *gidmap; | |
287 | ||
4c15e800 | 288 | static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name, |
6a189d36 | 289 | id_t id2, uint16 flags) |
4c15e800 | 290 | @@ -84,22 +90,6 @@ static const char *gid_to_name(gid_t gid) |
9405aad3 WD |
291 | return NULL; |
292 | } | |
293 | ||
85096e5e | 294 | -static uid_t map_uid(uid_t id, const char *name) |
9405aad3 WD |
295 | -{ |
296 | - uid_t uid; | |
297 | - if (id != 0 && name_to_uid(name, &uid)) | |
298 | - return uid; | |
299 | - return id; | |
300 | -} | |
301 | - | |
85096e5e | 302 | -static gid_t map_gid(gid_t id, const char *name) |
9405aad3 WD |
303 | -{ |
304 | - gid_t gid; | |
305 | - if (id != 0 && name_to_gid(name, &gid)) | |
306 | - return gid; | |
307 | - return id; | |
308 | -} | |
309 | - | |
310 | static int is_in_group(gid_t gid) | |
311 | { | |
312 | #ifdef HAVE_GETGROUPS | |
ab5ffac0 | 313 | @@ -159,34 +149,53 @@ static int is_in_group(gid_t gid) |
9405aad3 WD |
314 | #endif |
315 | } | |
316 | ||
317 | -/* Add a uid to the list of uids. Only called on receiving side. */ | |
85096e5e | 318 | -static struct idlist *recv_add_uid(uid_t id, const char *name) |
9405aad3 | 319 | +/* Add a uid/gid to its list of ids. Only called on receiving side. */ |
ab5ffac0 WD |
320 | +static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap, |
321 | + id_t id, const char *name) | |
4122278d WD |
322 | { |
323 | - uid_t id2 = name ? map_uid(id, name) : id; | |
324 | struct idlist *node; | |
ab5ffac0 | 325 | + int flag; |
6a189d36 | 326 | + id_t id2; |
409bd73e | 327 | |
6a189d36 | 328 | - node = add_to_list(&uidlist, id, name, id2, 0); |
409bd73e WD |
329 | + if (!name) |
330 | + name = ""; | |
4122278d | 331 | |
9405aad3 | 332 | - if (verbose > 3) { |
6a189d36 WD |
333 | - rprintf(FINFO, "uid %u(%s) maps to %u\n", |
334 | - (unsigned)id, name ? name : "", (unsigned)id2); | |
ab5ffac0 | 335 | + for (node = idmap; node; node = node->next) { |
6a189d36 | 336 | + if (node->flags & NFLAGS_WILD_NAME_MATCH) { |
409bd73e WD |
337 | + if (!wildmatch(node->name, name)) |
338 | + continue; | |
6a189d36 | 339 | + } else if (node->flags & NFLAGS_NAME_MATCH) { |
409bd73e WD |
340 | + if (strcmp(node->name, name) != 0) |
341 | + continue; | |
ab5ffac0 WD |
342 | + } else if (node->name) { |
343 | + if (id < node->id || id > (unsigned long)node->name) | |
344 | + continue; | |
6a189d36 | 345 | + } else { |
9405aad3 | 346 | + if (node->id != id) |
409bd73e | 347 | + continue; |
4122278d | 348 | + } |
409bd73e | 349 | + break; |
9405aad3 | 350 | } |
409bd73e WD |
351 | + if (node) |
352 | + id2 = node->id2; | |
9405aad3 | 353 | + else if (*name && id) { |
41b674b3 | 354 | + if (idlist_ptr == &uidlist) { |
9405aad3 | 355 | + uid_t uid; |
6a189d36 | 356 | + id2 = name_to_uid(name, &uid) ? uid : id; |
9405aad3 WD |
357 | + } else { |
358 | + gid_t gid; | |
6a189d36 | 359 | + id2 = name_to_gid(name, &gid) ? gid : id; |
9405aad3 WD |
360 | + } |
361 | + } else | |
409bd73e | 362 | + id2 = id; |
4122278d | 363 | |
6a189d36 | 364 | - return node; |
9405aad3 WD |
365 | -} |
366 | - | |
367 | -/* Add a gid to the list of gids. Only called on receiving side. */ | |
85096e5e | 368 | -static struct idlist *recv_add_gid(gid_t id, const char *name) |
9405aad3 WD |
369 | -{ |
370 | - gid_t id2 = name ? map_gid(id, name) : id; | |
371 | - struct idlist *node; | |
372 | - | |
6a189d36 WD |
373 | - node = add_to_list(&gidlist, id, name, id2, |
374 | - !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0); | |
41b674b3 | 375 | + flag = idlist_ptr == &gidlist && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0; |
ab5ffac0 | 376 | + node = add_to_list(idlist_ptr, id, *name ? name : NULL, id2, flag); |
409bd73e WD |
377 | |
378 | if (verbose > 3) { | |
6a189d36 WD |
379 | - rprintf(FINFO, "gid %u(%s) maps to %u\n", |
380 | - (unsigned)id, name ? name : "", (unsigned)id2); | |
381 | + rprintf(FINFO, "%sid %u(%s) maps to %u\n", | |
41b674b3 | 382 | + idlist_ptr == &uidlist ? "u" : "g", |
6a189d36 | 383 | + (unsigned)id, name, (unsigned)id2); |
409bd73e WD |
384 | } |
385 | ||
6a189d36 | 386 | return node; |
ab5ffac0 | 387 | @@ -195,12 +204,9 @@ static struct idlist *recv_add_gid(gid_t id, const char *name) |
409bd73e WD |
388 | /* this function is a definate candidate for a faster algorithm */ |
389 | uid_t match_uid(uid_t uid) | |
390 | { | |
391 | - static uid_t last_in, last_out; | |
392 | + static uid_t last_in = -1, last_out = -1; | |
4122278d WD |
393 | struct idlist *list; |
394 | ||
395 | - if (uid == 0) | |
396 | - return 0; | |
397 | - | |
398 | if (uid == last_in) | |
399 | return last_out; | |
400 | ||
ab5ffac0 | 401 | @@ -208,10 +214,13 @@ uid_t match_uid(uid_t uid) |
6a189d36 WD |
402 | |
403 | for (list = uidlist; list; list = list->next) { | |
404 | if (list->id == uid) | |
405 | - return last_out = list->id2; | |
406 | + break; | |
409bd73e | 407 | } |
4122278d | 408 | |
409bd73e | 409 | - return last_out = uid; |
6a189d36 | 410 | + if (!list) |
ab5ffac0 | 411 | + list = recv_add_id(&uidlist, uidmap, uid, NULL); |
6a189d36 WD |
412 | + |
413 | + return last_out = list->id2; | |
409bd73e | 414 | } |
4122278d | 415 | |
6a189d36 | 416 | gid_t match_gid(gid_t gid, uint16 *flags_ptr) |
ab5ffac0 | 417 | @@ -227,7 +236,7 @@ gid_t match_gid(gid_t gid, uint16 *flags_ptr) |
761f1b71 WD |
418 | break; |
419 | } | |
420 | if (!list) | |
8f1c03c8 | 421 | - list = recv_add_gid(gid, NULL); |
ab5ffac0 | 422 | + list = recv_add_id(&gidlist, gidmap, gid, NULL); |
761f1b71 | 423 | last = list; |
9405aad3 WD |
424 | } |
425 | ||
ab5ffac0 | 426 | @@ -320,7 +329,7 @@ uid_t recv_user_name(int f, uid_t uid) |
85096e5e WD |
427 | free(name); |
428 | name = NULL; | |
429 | } | |
6a189d36 | 430 | - node = recv_add_uid(uid, name); /* node keeps name's memory */ |
ab5ffac0 | 431 | + node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */ |
6a189d36 | 432 | return node->id2; |
9405aad3 WD |
433 | } |
434 | ||
ab5ffac0 | 435 | @@ -336,7 +345,7 @@ gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr) |
85096e5e WD |
436 | free(name); |
437 | name = NULL; | |
438 | } | |
6a189d36 | 439 | - node = recv_add_gid(gid, name); /* node keeps name's memory */ |
ab5ffac0 | 440 | + node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */ |
6a189d36 WD |
441 | if (flags_ptr && node->flags & FLAG_SKIP_GROUP) |
442 | *flags_ptr |= FLAG_SKIP_GROUP; | |
443 | return node->id2; | |
ab5ffac0 | 444 | @@ -363,17 +372,103 @@ void recv_id_list(int f, struct file_list *flist) |
4122278d | 445 | |
409bd73e WD |
446 | /* Now convert all the uids/gids from sender values to our values. */ |
447 | #ifdef SUPPORT_ACLS | |
448 | - if (preserve_acls && !numeric_ids) | |
6a189d36 | 449 | + if (preserve_acls && (!numeric_ids || usermap || groupmap)) |
409bd73e WD |
450 | match_acl_ids(); |
451 | #endif | |
452 | - if (am_root && preserve_uid && !numeric_ids) { | |
453 | + if (am_root && preserve_uid && (!numeric_ids || usermap)) { | |
9c85142a | 454 | for (i = 0; i < flist->used; i++) |
6a189d36 | 455 | F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i])); |
409bd73e WD |
456 | } |
457 | - if (preserve_gid && (!am_root || !numeric_ids)) { | |
458 | + if (preserve_gid && (!am_root || !numeric_ids || groupmap)) { | |
9c85142a | 459 | for (i = 0; i < flist->used; i++) { |
6a189d36 WD |
460 | F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), |
461 | &flist->files[i]->flags); | |
462 | } | |
4122278d WD |
463 | } |
464 | } | |
465 | + | |
466 | +void parse_name_map(char *map, int usernames) | |
467 | +{ | |
9405aad3 WD |
468 | + struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap; |
469 | + struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist; | |
ab5ffac0 WD |
470 | + char *colon, *end, *name, *cp = map + strlen(map); |
471 | + id_t id1; | |
6a189d36 | 472 | + uint16 flags; |
4122278d | 473 | + |
ab5ffac0 | 474 | + /* Parse the list in reverse, so the order in the struct is right. */ |
4122278d WD |
475 | + while (1) { |
476 | + end = cp; | |
477 | + while (cp > map && cp[-1] != ',') cp--; | |
478 | + if (!(colon = strchr(cp, ':'))) { | |
479 | + rprintf(FERROR, "No colon found in --%smap: %s\n", | |
480 | + usernames ? "user" : "group", cp); | |
481 | + exit_cleanup(RERR_SYNTAX); | |
482 | + } | |
ab5ffac0 WD |
483 | + if (!colon[1]) { |
484 | + rprintf(FERROR, "No name found after colon --%smap: %s\n", | |
485 | + usernames ? "user" : "group", cp); | |
486 | + exit_cleanup(RERR_SYNTAX); | |
487 | + } | |
4122278d WD |
488 | + *colon = '\0'; |
489 | + | |
490 | + if (isDigit(cp)) { | |
ab5ffac0 WD |
491 | + char *dash = strchr(cp, '-'); |
492 | + if (strspn(cp, "0123456789-") != (size_t)(colon - cp) | |
493 | + || (dash && (!dash[1] || strchr(dash+1, '-')))) { | |
4122278d WD |
494 | + bad_number: |
495 | + rprintf(FERROR, "Invalid number in --%smap: %s\n", | |
496 | + usernames ? "user" : "group", cp); | |
497 | + exit_cleanup(RERR_SYNTAX); | |
498 | + } | |
ab5ffac0 WD |
499 | + if (dash) |
500 | + name = (char *)atol(dash+1); | |
501 | + else | |
502 | + name = (char *)0; | |
6a189d36 | 503 | + flags = 0; |
ab5ffac0 | 504 | + id1 = atol(cp); |
6a189d36 WD |
505 | + } else if (strpbrk(cp, "*[?")) { |
506 | + flags = NFLAGS_WILD_NAME_MATCH; | |
ab5ffac0 | 507 | + name = cp; |
6a189d36 WD |
508 | + id1 = 0; |
509 | + } else { | |
510 | + flags = NFLAGS_NAME_MATCH; | |
ab5ffac0 | 511 | + name = cp; |
6a189d36 WD |
512 | + id1 = 0; |
513 | + } | |
4122278d WD |
514 | + |
515 | + if (isDigit(colon+1)) { | |
516 | + if (strspn(colon+1, "0123456789") != (size_t)(end - colon - 1)) { | |
517 | + cp = colon+1; | |
518 | + goto bad_number; | |
519 | + } | |
ab5ffac0 WD |
520 | + add_to_list(idmap_ptr, id1, name, atol(colon+1), flags); |
521 | + } else if (usernames) { | |
522 | + uid_t uid; | |
523 | + if (name_to_uid(colon+1, &uid)) | |
524 | + add_to_list(idmap_ptr, id1, name, uid, flags); | |
525 | + else { | |
526 | + rprintf(FERROR, | |
527 | + "Unknown --usermap name on receiver: %s\n", | |
528 | + colon+1); | |
529 | + } | |
4122278d | 530 | + } else { |
ab5ffac0 WD |
531 | + gid_t gid; |
532 | + if (name_to_gid(colon+1, &gid)) | |
533 | + add_to_list(idmap_ptr, id1, name, gid, flags); | |
534 | + else { | |
535 | + rprintf(FERROR, | |
536 | + "Unknown --groupmap name on receiver: %s\n", | |
537 | + colon+1); | |
4122278d WD |
538 | + } |
539 | + } | |
540 | + | |
4122278d WD |
541 | + if (cp == map) |
542 | + break; | |
543 | + | |
544 | + *--cp = '\0'; /* replace comma */ | |
545 | + } | |
409bd73e | 546 | + |
85096e5e | 547 | + /* The 0 user/group doesn't get its name sent, so add it explicitly. */ |
ab5ffac0 | 548 | + recv_add_id(idlist_ptr, *idmap_ptr, 0, |
85096e5e | 549 | + numeric_ids ? NULL : usernames ? uid_to_name(0) : gid_to_name(0)); |
4122278d | 550 | +} |