Fixed failing hunks.
[rsync/rsync-patches.git] / usermap.diff
CommitLineData
409bd73e
WD
1This adds a --usermap and a --groupmap option. See the man page for
2more details.
4122278d 3
409bd73e
WD
4To 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
WD
9
10--- old/flist.c
11+++ new/flist.c
d4dd2dd5
WD
12@@ -67,6 +67,7 @@ extern int need_unsorted_flist;
13 extern int unsort_ndx;
4122278d 14 extern struct stats stats;
c8a8b4a7 15 extern char *filesfrom_host;
d4dd2dd5 16+extern char *usermap, *groupmap;
4122278d 17
d4dd2dd5
WD
18 extern char curr_dir[MAXPATHLEN];
19
20@@ -747,7 +748,7 @@ static struct file_struct *recv_file_ent
409bd73e 21 uid = (uid_t)read_varint(f);
6a189d36 22 if (xflags & XMIT_USER_NAME_FOLLOWS)
409bd73e
WD
23 uid = recv_user_name(f, uid);
24- else if (inc_recurse && am_root && !numeric_ids)
f62e6e48 25+ else if (inc_recurse && am_root && (!numeric_ids || usermap))
409bd73e
WD
26 uid = match_uid(uid);
27 }
28 }
d4dd2dd5 29@@ -759,7 +760,7 @@ static struct file_struct *recv_file_ent
761f1b71 30 gid_flags = 0;
6a189d36 31 if (xflags & XMIT_GROUP_NAME_FOLLOWS)
761f1b71 32 gid = recv_group_name(f, gid, &gid_flags);
409bd73e 33- else if (inc_recurse && (!am_root || !numeric_ids))
f62e6e48 34+ else if (inc_recurse && (!am_root || !numeric_ids || groupmap))
761f1b71 35 gid = match_gid(gid, &gid_flags);
409bd73e
WD
36 }
37 }
d4dd2dd5 38@@ -2076,8 +2077,13 @@ struct file_list *recv_file_list(int f)
4122278d
WD
39 int dstart, flags;
40 int64 start_read;
41
42- if (!first_flist)
43+ if (!first_flist) {
44 rprintf(FLOG, "receiving file list\n");
45+ if (usermap)
46+ parse_name_map(usermap, 1);
47+ if (groupmap)
48+ parse_name_map(groupmap, 0);
49+ }
50 if (show_filelist_p())
51 start_filelist_progress("receiving file list");
52 else if (inc_recurse && verbose && !am_server && !first_flist)
53--- old/options.c
54+++ new/options.c
c8a8b4a7 55@@ -164,6 +164,8 @@ char *rsync_path = RSYNC_PATH;
4122278d
WD
56 char *backup_dir = NULL;
57 char backup_dir_buf[MAXPATHLEN];
58 char *sockopts = NULL;
59+char *usermap = NULL;
60+char *groupmap = NULL;
61 int rsync_port = 0;
62 int compare_dest = 0;
63 int copy_dest = 0;
c8a8b4a7 64@@ -377,6 +379,8 @@ void usage(enum logcode F)
4122278d
WD
65 rprintf(F," --delay-updates put all updated files into place at transfer's end\n");
66 rprintf(F," -m, --prune-empty-dirs prune empty directory chains from the file-list\n");
67 rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
68+ rprintf(F," --usermap=STRING custom username mapping\n");
69+ rprintf(F," --groupmap=STRING custom groupname mapping\n");
70 rprintf(F," --timeout=TIME set I/O timeout in seconds\n");
71 rprintf(F," -I, --ignore-times don't skip files that match in size and mod-time\n");
72 rprintf(F," --size-only skip files that match in size\n");
c8a8b4a7
WD
73@@ -601,6 +605,8 @@ static struct poptOption long_options[]
74 {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0},
6cbbe66d
WD
75 {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 },
76 {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 },
4122278d
WD
77+ {"usermap", 0, POPT_ARG_STRING, &usermap, 0, 0, 0 },
78+ {"groupmap", 0, POPT_ARG_STRING, &groupmap, 0, 0, 0 },
79 {"timeout", 0, POPT_ARG_INT, &io_timeout, 0, 0, 0 },
6cbbe66d 80 {"no-timeout", 0, POPT_ARG_VAL, &io_timeout, 0, 0, 0 },
4122278d 81 {"rsh", 'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
d4dd2dd5
WD
82@@ -1931,6 +1937,18 @@ void server_options(char **args, int *ar
83 args[ac++] = "--use-qsort";
4122278d
WD
84
85 if (am_sender) {
86+ if (usermap) {
f62e6e48 87+ if (asprintf(&arg, "--usermap=%s", usermap) < 0)
4122278d
WD
88+ goto oom;
89+ args[ac++] = arg;
90+ }
91+
92+ if (groupmap) {
f62e6e48 93+ if (asprintf(&arg, "--groupmap=%s", groupmap) < 0)
4122278d
WD
94+ goto oom;
95+ args[ac++] = arg;
96+ }
97+
98 if (ignore_existing)
99 args[ac++] = "--ignore-existing";
100
101--- old/rsync.yo
102+++ new/rsync.yo
d4dd2dd5 103@@ -378,6 +378,8 @@ to the detailed description below for a
4122278d
WD
104 --delay-updates put all updated files into place at end
105 -m, --prune-empty-dirs prune empty directory chains from file-list
106 --numeric-ids don't map uid/gid values by user/group name
107+ --usermap=STRING custom username mapping
108+ --groupmap=STRING custom groupname mapping
109 --timeout=TIME set I/O timeout in seconds
110 -I, --ignore-times don't skip files that match size and time
111 --size-only skip files that match in size
d4dd2dd5 112@@ -1566,6 +1568,46 @@ from the source system is used instead.
4122278d
WD
113 the chroot setting affects rsync's ability to look up the names of the
114 users and groups and what you can do about it.
115
116+dit(bf(--usermap=STRING, --groupmap=STRING)) These options allow you to
409bd73e
WD
117+specify users and groups that should be mapped to other values by the
118+receiving side. The bf(STRING) is one or more bf(FROM):bf(TO) pairs of
119+values separated by commas. Any matching bf(FROM) value from the sender is
120+replaced with a bf(TO) value from the receiver. You may specify usernames
121+or user IDs for the bf(FROM) and bf(TO) values, and the bf(FROM) value may
122+also be a wild-card string, which will be matched against the sender's
f62e6e48 123+names (wild-cards do NOT match against ID numbers). For example:
409bd73e 124+
f62e6e48 125+verb( --usermap=0:bin,wayne:admin,*:nobody --groupmap=usr:1,1:usr)
409bd73e
WD
126+
127+The first match in the list is the one that is used. You should not use
128+multiple options of the same type, but instead include all the user
129+mappings you need separated by commas to a single bf(--usermap) option,
130+and likewise for groups with the bf(--groupmap) option.
4122278d 131+
9405aad3 132+Note that the sender's name for the 0 user and group are not transmitted
409bd73e
WD
133+to the receiver, so you should either match these values using a 0, or use
134+the names in effect on the receiving side. All other bf(FROM) names match
9405aad3
WD
135+those in use on the sending side. All bf(TO) names match those in use on
136+the receiving side.
4122278d 137+
9405aad3
WD
138+Any IDs that do not have name on the sending side are treaded as having an
139+empty name for the purpose of matching. This allows them to be matched via
140+a "*" as well as an empty name mapping. For instance:
141+
142+verb( --usermap=:nobody --groupmap=*:nobody)
143+
144+When the bf(--numeric-ids) option is used,the sender does not send any
145+names, so all the IDs are treaded as having an empty name. This means that
146+you will need to specify numeric bf(FROM) values if you want to map these
147+nameless IDs to different values.
4122278d 148+
409bd73e
WD
149+For the bf(--usermap) option to have any effect, the bf(-o) (bf(--owner))
150+option must be used (or implied), and the receiver will need to be running
9405aad3 151+as a super-user (see also the bf(--fake-super) option). For the bf(--groupmap)
409bd73e
WD
152+option to have any effect, the bf(-g) (bf(--groups)) option must be used
153+(or implied), and the receiver will need to have permissions to set that
154+group.
4122278d
WD
155+
156 dit(bf(--timeout=TIMEOUT)) This option allows you to set a maximum I/O
157 timeout in seconds. If no data is transferred for the specified time
158 then rsync will exit. The default is 0, which means no timeout.
159--- old/uidlist.c
160+++ new/uidlist.c
c82285d5
WD
161@@ -24,6 +24,7 @@
162 * are special. */
163
164 #include "rsync.h"
165+#include "ifuncs.h"
166 #include "io.h"
167
168 extern int verbose;
169@@ -32,6 +33,8 @@ extern int preserve_uid;
4122278d
WD
170 extern int preserve_gid;
171 extern int preserve_acls;
172 extern int numeric_ids;
409bd73e
WD
173+extern char *usermap;
174+extern char *groupmap;
4122278d 175
6a189d36
WD
176 #ifdef HAVE_GETGROUPS
177 # ifndef GETGROUPS_T
c82285d5 178@@ -41,6 +44,9 @@ extern int numeric_ids;
6a189d36
WD
179
180 #define GID_NONE ((gid_t)-1)
181
182+#define NFLAGS_WILD_NAME_MATCH (1<<0)
183+#define NFLAGS_NAME_MATCH (1<<1)
184+
4122278d
WD
185 struct idlist {
186 struct idlist *next;
4122278d 187 char *name;
c82285d5 188@@ -48,8 +54,8 @@ struct idlist {
6a189d36 189 uint16 flags;
4122278d
WD
190 };
191
192-static struct idlist *uidlist;
193-static struct idlist *gidlist;
194+static struct idlist *uidlist, *uidmap;
195+static struct idlist *gidlist, *gidmap;
196
6a189d36
WD
197 static struct idlist *add_to_list(struct idlist **root, id_t id, char *name,
198 id_t id2, uint16 flags)
c82285d5 199@@ -84,22 +90,6 @@ static char *gid_to_name(gid_t gid)
9405aad3
WD
200 return NULL;
201 }
202
203-static uid_t map_uid(uid_t id, char *name)
204-{
205- uid_t uid;
206- if (id != 0 && name_to_uid(name, &uid))
207- return uid;
208- return id;
209-}
210-
211-static gid_t map_gid(gid_t id, char *name)
212-{
213- gid_t gid;
214- if (id != 0 && name_to_gid(name, &gid))
215- return gid;
216- return id;
217-}
218-
219 static int is_in_group(gid_t gid)
220 {
221 #ifdef HAVE_GETGROUPS
c82285d5 222@@ -159,34 +149,49 @@ static int is_in_group(gid_t gid)
9405aad3
WD
223 #endif
224 }
225
226-/* Add a uid to the list of uids. Only called on receiving side. */
6a189d36 227-static struct idlist *recv_add_uid(uid_t id, char *name)
9405aad3 228+/* Add a uid/gid to its list of ids. Only called on receiving side. */
6a189d36 229+static struct idlist *recv_add_id(struct idlist **idmap_ptr, id_t id, char *name)
4122278d
WD
230 {
231- uid_t id2 = name ? map_uid(id, name) : id;
232 struct idlist *node;
6a189d36 233+ id_t id2;
409bd73e 234
6a189d36 235- node = add_to_list(&uidlist, id, name, id2, 0);
409bd73e
WD
236+ if (!name)
237+ name = "";
4122278d 238
9405aad3 239- if (verbose > 3) {
6a189d36
WD
240- rprintf(FINFO, "uid %u(%s) maps to %u\n",
241- (unsigned)id, name ? name : "", (unsigned)id2);
9405aad3 242+ for (node = *idmap_ptr; node; node = node->next) {
6a189d36 243+ if (node->flags & NFLAGS_WILD_NAME_MATCH) {
409bd73e
WD
244+ if (!wildmatch(node->name, name))
245+ continue;
6a189d36 246+ } else if (node->flags & NFLAGS_NAME_MATCH) {
409bd73e
WD
247+ if (strcmp(node->name, name) != 0)
248+ continue;
6a189d36 249+ } else {
9405aad3 250+ if (node->id != id)
409bd73e 251+ continue;
4122278d 252+ }
409bd73e 253+ break;
9405aad3 254 }
409bd73e
WD
255+ if (node)
256+ id2 = node->id2;
9405aad3
WD
257+ else if (*name && id) {
258+ if (idmap_ptr == &uidmap) {
259+ uid_t uid;
6a189d36 260+ id2 = name_to_uid(name, &uid) ? uid : id;
9405aad3
WD
261+ } else {
262+ gid_t gid;
6a189d36 263+ id2 = name_to_gid(name, &gid) ? gid : id;
9405aad3
WD
264+ }
265+ } else
409bd73e 266+ id2 = id;
4122278d 267
6a189d36 268- return node;
9405aad3
WD
269-}
270-
271-/* Add a gid to the list of gids. Only called on receiving side. */
6a189d36 272-static struct idlist *recv_add_gid(gid_t id, char *name)
9405aad3
WD
273-{
274- gid_t id2 = name ? map_gid(id, name) : id;
275- struct idlist *node;
276-
6a189d36
WD
277- node = add_to_list(&gidlist, id, name, id2,
278- !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
279+ node = add_to_list(idmap_ptr, id, *name ? name : NULL, id2,
280+ !am_root && idmap_ptr == &gidmap
281+ && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
409bd73e
WD
282
283 if (verbose > 3) {
6a189d36
WD
284- rprintf(FINFO, "gid %u(%s) maps to %u\n",
285- (unsigned)id, name ? name : "", (unsigned)id2);
286+ rprintf(FINFO, "%sid %u(%s) maps to %u\n",
287+ idmap_ptr == &uidmap ? "u" : "g",
288+ (unsigned)id, name, (unsigned)id2);
409bd73e
WD
289 }
290
6a189d36 291 return node;
c82285d5 292@@ -195,12 +200,9 @@ static struct idlist *recv_add_gid(gid_t
409bd73e
WD
293 /* this function is a definate candidate for a faster algorithm */
294 uid_t match_uid(uid_t uid)
295 {
296- static uid_t last_in, last_out;
297+ static uid_t last_in = -1, last_out = -1;
4122278d
WD
298 struct idlist *list;
299
300- if (uid == 0)
301- return 0;
302-
303 if (uid == last_in)
304 return last_out;
305
c82285d5 306@@ -208,10 +210,13 @@ uid_t match_uid(uid_t uid)
6a189d36
WD
307
308 for (list = uidlist; list; list = list->next) {
309 if (list->id == uid)
310- return last_out = list->id2;
311+ break;
409bd73e 312 }
4122278d 313
409bd73e 314- return last_out = uid;
6a189d36
WD
315+ if (!list)
316+ list = recv_add_id(&uidmap, uid, NULL);
317+
318+ return last_out = list->id2;
409bd73e 319 }
4122278d 320
6a189d36 321 gid_t match_gid(gid_t gid, uint16 *flags_ptr)
c82285d5 322@@ -227,7 +232,7 @@ gid_t match_gid(gid_t gid, uint16 *flags
761f1b71
WD
323 break;
324 }
325 if (!list)
8f1c03c8
WD
326- list = recv_add_gid(gid, NULL);
327+ list = recv_add_id(&gidmap, gid, NULL);
761f1b71 328 last = list;
9405aad3
WD
329 }
330
c82285d5 331@@ -316,7 +321,7 @@ uid_t recv_user_name(int f, uid_t uid)
9405aad3
WD
332 if (!name)
333 out_of_memory("recv_user_name");
334 read_sbuf(f, name, len);
6a189d36
WD
335- node = recv_add_uid(uid, name); /* node keeps name's memory */
336+ node = recv_add_id(&uidmap, uid, name); /* node keeps name's memory */
337 return node->id2;
9405aad3
WD
338 }
339
c82285d5 340@@ -328,7 +333,7 @@ gid_t recv_group_name(int f, gid_t gid,
9405aad3
WD
341 if (!name)
342 out_of_memory("recv_group_name");
343 read_sbuf(f, name, len);
6a189d36
WD
344- node = recv_add_gid(gid, name); /* node keeps name's memory */
345+ node = recv_add_id(&gidmap, gid, name); /* node keeps name's memory */
346 if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
347 *flags_ptr |= FLAG_SKIP_GROUP;
348 return node->id2;
c82285d5 349@@ -355,17 +360,96 @@ void recv_id_list(int f, struct file_lis
4122278d 350
409bd73e
WD
351 /* Now convert all the uids/gids from sender values to our values. */
352 #ifdef SUPPORT_ACLS
353- if (preserve_acls && !numeric_ids)
6a189d36 354+ if (preserve_acls && (!numeric_ids || usermap || groupmap))
409bd73e
WD
355 match_acl_ids();
356 #endif
357- if (am_root && preserve_uid && !numeric_ids) {
358+ if (am_root && preserve_uid && (!numeric_ids || usermap)) {
9c85142a 359 for (i = 0; i < flist->used; i++)
6a189d36 360 F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
409bd73e
WD
361 }
362- if (preserve_gid && (!am_root || !numeric_ids)) {
363+ if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
9c85142a 364 for (i = 0; i < flist->used; i++) {
6a189d36
WD
365 F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
366 &flist->files[i]->flags);
367 }
4122278d
WD
368 }
369 }
370+
371+void parse_name_map(char *map, int usernames)
372+{
9405aad3
WD
373+ struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
374+ struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
4122278d 375+ char *colon, *end, *cp = map + strlen(map);
6a189d36
WD
376+ id_t id1, id2;
377+ uint16 flags;
4122278d
WD
378+
379+ while (1) {
380+ end = cp;
381+ while (cp > map && cp[-1] != ',') cp--;
382+ if (!(colon = strchr(cp, ':'))) {
383+ rprintf(FERROR, "No colon found in --%smap: %s\n",
384+ usernames ? "user" : "group", cp);
385+ exit_cleanup(RERR_SYNTAX);
386+ }
387+ *colon = '\0';
388+
389+ if (isDigit(cp)) {
390+ if (strspn(cp, "0123456789") != (size_t)(colon - cp)) {
391+ bad_number:
392+ rprintf(FERROR, "Invalid number in --%smap: %s\n",
393+ usernames ? "user" : "group", cp);
394+ exit_cleanup(RERR_SYNTAX);
395+ }
6a189d36 396+ flags = 0;
4122278d 397+ id1 = atoi(cp);
6a189d36
WD
398+ } else if (strpbrk(cp, "*[?")) {
399+ flags = NFLAGS_WILD_NAME_MATCH;
400+ id1 = 0;
401+ } else {
402+ flags = NFLAGS_NAME_MATCH;
403+ id1 = 0;
404+ }
4122278d
WD
405+
406+ if (isDigit(colon+1)) {
407+ if (strspn(colon+1, "0123456789") != (size_t)(end - colon - 1)) {
408+ cp = colon+1;
409+ goto bad_number;
410+ }
411+ id2 = atoi(colon+1);
412+ } else {
413+ if (usernames) {
414+ uid_t uid;
9405aad3
WD
415+ if (!name_to_uid(colon+1, &uid)) {
416+ bad_name:
417+ rprintf(FERROR,
418+ "Invalid name in --%smap: %s\n",
419+ usernames ? "user" : "group",
420+ colon+1);
421+ exit_cleanup(RERR_SYNTAX);
422+ }
6a189d36 423+ id2 = uid;
4122278d
WD
424+ } else {
425+ gid_t gid;
9405aad3
WD
426+ if (!name_to_gid(colon+1, &gid))
427+ goto bad_name;
6a189d36 428+ id2 = gid;
4122278d
WD
429+ }
430+ }
431+
6a189d36
WD
432+ add_to_list(idmap_ptr, id1, flags ? cp : NULL, id2, flags);
433+ if (numeric_ids && !flags)
434+ add_to_list(idlist_ptr, id1, NULL, id2, flags);
4122278d
WD
435+
436+ if (cp == map)
437+ break;
438+
439+ *--cp = '\0'; /* replace comma */
440+ }
409bd73e 441+
6a189d36 442+ /* The 0 user/group doesn't get its name sent, or add it explicitly. */
9405aad3
WD
443+ if (numeric_ids)
444+ cp = NULL;
445+ else
446+ cp = usernames ? uid_to_name(0) : gid_to_name(0);
447+ recv_add_id(idmap_ptr, 0, cp);
4122278d 448+}