Commit | Line | Data |
---|---|---|
ade7292a | 1 | /* |
0f78b815 WD |
2 | * Handle the mapping of uid/gid and user/group names between systems. |
3 | * | |
4 | * Copyright (C) 1996 Andrew Tridgell | |
5 | * Copyright (C) 1996 Paul Mackerras | |
b3bf9b9d | 6 | * Copyright (C) 2004-2009 Wayne Davison |
0f78b815 WD |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
8e41b68e WD |
9 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 3 of the License, or | |
11 | * (at your option) any later version. | |
0f78b815 WD |
12 | * |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
e7c67065 | 18 | * You should have received a copy of the GNU General Public License along |
4fd842f9 | 19 | * with this program; if not, visit the http://fsf.org website. |
0f78b815 WD |
20 | */ |
21 | ||
22 | /* If the source username/group does not exist on the target then use | |
23 | * the numeric IDs. Never do any mapping for uid=0 or gid=0 as these | |
24 | * are special. */ | |
f6c34742 AT |
25 | |
26 | #include "rsync.h" | |
2df20057 WD |
27 | #include "ifuncs.h" |
28 | #include "itypes.h" | |
ab14d01a | 29 | #include "io.h" |
f6c34742 | 30 | |
283887d7 | 31 | extern int am_root; |
f6c34742 AT |
32 | extern int preserve_uid; |
33 | extern int preserve_gid; | |
1c3344a1 | 34 | extern int preserve_acls; |
f6c34742 | 35 | extern int numeric_ids; |
3b83a220 | 36 | extern gid_t our_gid; |
2df20057 WD |
37 | extern char *usermap; |
38 | extern char *groupmap; | |
f6c34742 | 39 | |
142a5e7b WD |
40 | #ifdef HAVE_GETGROUPS |
41 | # ifndef GETGROUPS_T | |
42 | # define GETGROUPS_T gid_t | |
43 | # endif | |
44 | #endif | |
45 | ||
2df20057 WD |
46 | #define NFLAGS_WILD_NAME_MATCH (1<<0) |
47 | #define NFLAGS_NAME_MATCH (1<<1) | |
48 | ||
d518e022 WD |
49 | union name_or_id { |
50 | const char *name; | |
51 | id_t max_id; | |
52 | }; | |
53 | ||
f6c34742 AT |
54 | struct idlist { |
55 | struct idlist *next; | |
d518e022 | 56 | union name_or_id u; |
d6b422a6 WD |
57 | id_t id, id2; |
58 | uint16 flags; | |
f6c34742 AT |
59 | }; |
60 | ||
2df20057 WD |
61 | static struct idlist *uidlist, *uidmap; |
62 | static struct idlist *gidlist, *gidmap; | |
f6c34742 | 63 | |
eee2c77a WD |
64 | static id_t id_parse(const char *num_str) |
65 | { | |
66 | id_t tmp, num = 0; | |
67 | const char *cp = num_str; | |
68 | ||
69 | while (*cp) { | |
70 | if (!isDigit(cp)) { | |
71 | invalid_num: | |
72 | rprintf(FERROR, "Invalid ID number: %s\n", num_str); | |
73 | exit_cleanup(RERR_SYNTAX); | |
74 | } | |
75 | tmp = num * 10 + *cp++ - '0'; | |
76 | if (tmp < num) | |
77 | goto invalid_num; | |
78 | num = tmp; | |
79 | } | |
80 | ||
81 | return num; | |
82 | } | |
83 | ||
d518e022 | 84 | static struct idlist *add_to_list(struct idlist **root, id_t id, union name_or_id noiu, |
d6b422a6 | 85 | id_t id2, uint16 flags) |
f6c34742 | 86 | { |
d49def48 WD |
87 | struct idlist *node = new(struct idlist); |
88 | if (!node) | |
89 | out_of_memory("add_to_list"); | |
90 | node->next = *root; | |
d518e022 | 91 | node->u = noiu; |
d49def48 WD |
92 | node->id = id; |
93 | node->id2 = id2; | |
d6b422a6 | 94 | node->flags = flags; |
d49def48 WD |
95 | *root = node; |
96 | return node; | |
f6c34742 AT |
97 | } |
98 | ||
f6c34742 | 99 | /* turn a uid into a user name */ |
d7205694 | 100 | char *uid_to_user(uid_t uid) |
f6c34742 AT |
101 | { |
102 | struct passwd *pass = getpwuid(uid); | |
d49def48 WD |
103 | if (pass) |
104 | return strdup(pass->pw_name); | |
f6c34742 AT |
105 | return NULL; |
106 | } | |
107 | ||
108 | /* turn a gid into a group name */ | |
d7205694 | 109 | char *gid_to_group(gid_t gid) |
f6c34742 AT |
110 | { |
111 | struct group *grp = getgrgid(gid); | |
d49def48 WD |
112 | if (grp) |
113 | return strdup(grp->gr_name); | |
f6c34742 AT |
114 | return NULL; |
115 | } | |
116 | ||
d7205694 WD |
117 | /* Parse a user name or (optionally) a number into a uid */ |
118 | int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok) | |
119 | { | |
120 | struct passwd *pass; | |
121 | if (!name || !*name) | |
122 | return 0; | |
123 | if (num_ok && name[strspn(name, "0123456789")] == '\0') { | |
eee2c77a | 124 | *uid_p = id_parse(name); |
d7205694 WD |
125 | return 1; |
126 | } | |
127 | if (!(pass = getpwnam(name))) | |
128 | return 0; | |
129 | *uid_p = pass->pw_uid; | |
130 | return 1; | |
131 | } | |
132 | ||
133 | /* Parse a group name or (optionally) a number into a gid */ | |
134 | int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok) | |
135 | { | |
136 | struct group *grp; | |
137 | if (!name || !*name) | |
138 | return 0; | |
139 | if (num_ok && name[strspn(name, "0123456789")] == '\0') { | |
eee2c77a | 140 | *gid_p = id_parse(name); |
d7205694 WD |
141 | return 1; |
142 | } | |
143 | if (!(grp = getgrnam(name))) | |
144 | return 0; | |
145 | *gid_p = grp->gr_gid; | |
146 | return 1; | |
147 | } | |
148 | ||
5b540e86 WD |
149 | static int is_in_group(gid_t gid) |
150 | { | |
4f5b0756 | 151 | #ifdef HAVE_GETGROUPS |
eee2c77a WD |
152 | static gid_t last_in; |
153 | static int ngroups = -2, last_out = -1; | |
5b540e86 WD |
154 | static GETGROUPS_T *gidset; |
155 | int n; | |
156 | ||
eee2c77a | 157 | if (gid == last_in && last_out >= 0) |
5b540e86 WD |
158 | return last_out; |
159 | if (ngroups < -1) { | |
f567e9b3 | 160 | if ((ngroups = getgroups(0, NULL)) < 0) |
dbd8811b | 161 | ngroups = 0; |
72fc7ec5 | 162 | gidset = new_array(GETGROUPS_T, ngroups+1); |
f567e9b3 WD |
163 | if (!gidset) |
164 | out_of_memory("is_in_group"); | |
72fc7ec5 | 165 | if (ngroups > 0) |
5b540e86 | 166 | ngroups = getgroups(ngroups, gidset); |
72fc7ec5 WD |
167 | /* The default gid might not be in the list on some systems. */ |
168 | for (n = 0; n < ngroups; n++) { | |
3b83a220 | 169 | if (gidset[n] == our_gid) |
72fc7ec5 | 170 | break; |
5b540e86 | 171 | } |
72fc7ec5 | 172 | if (n == ngroups) |
3b83a220 | 173 | gidset[ngroups++] = our_gid; |
951e826b | 174 | if (DEBUG_GTE(OWN, 2)) { |
187e9c24 | 175 | int pos; |
f567e9b3 WD |
176 | char *gidbuf = new_array(char, ngroups*21+32); |
177 | if (!gidbuf) | |
178 | out_of_memory("is_in_group"); | |
10944395 WD |
179 | pos = snprintf(gidbuf, 32, "process has %d gid%s: ", |
180 | ngroups, ngroups == 1? "" : "s"); | |
84fa865c | 181 | for (n = 0; n < ngroups; n++) { |
10944395 | 182 | pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]); |
84fa865c | 183 | } |
187e9c24 | 184 | rprintf(FINFO, "%s\n", gidbuf); |
f567e9b3 | 185 | free(gidbuf); |
84fa865c | 186 | } |
5b540e86 WD |
187 | } |
188 | ||
189 | last_in = gid; | |
5b540e86 | 190 | for (n = 0; n < ngroups; n++) { |
a2687b64 WD |
191 | if (gidset[n] == gid) |
192 | return last_out = 1; | |
5b540e86 | 193 | } |
a2687b64 | 194 | return last_out = 0; |
5b540e86 WD |
195 | |
196 | #else | |
3b83a220 | 197 | return gid == our_gid; |
5b540e86 WD |
198 | #endif |
199 | } | |
200 | ||
2df20057 WD |
201 | /* Add a uid/gid to its list of ids. Only called on receiving side. */ |
202 | static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap, | |
203 | id_t id, const char *name) | |
d49def48 | 204 | { |
d49def48 | 205 | struct idlist *node; |
d518e022 | 206 | union name_or_id noiu; |
2df20057 WD |
207 | int flag; |
208 | id_t id2; | |
d49def48 | 209 | |
d518e022 | 210 | noiu.name = name; /* ensure that add_to_list() gets the raw value. */ |
2df20057 WD |
211 | if (!name) |
212 | name = ""; | |
d49def48 | 213 | |
2df20057 WD |
214 | for (node = idmap; node; node = node->next) { |
215 | if (node->flags & NFLAGS_WILD_NAME_MATCH) { | |
d518e022 | 216 | if (!wildmatch(node->u.name, name)) |
2df20057 WD |
217 | continue; |
218 | } else if (node->flags & NFLAGS_NAME_MATCH) { | |
d518e022 | 219 | if (strcmp(node->u.name, name) != 0) |
2df20057 | 220 | continue; |
d518e022 WD |
221 | } else if (node->u.max_id) { |
222 | if (id < node->id || id > node->u.max_id) | |
2df20057 WD |
223 | continue; |
224 | } else { | |
225 | if (node->id != id) | |
226 | continue; | |
227 | } | |
228 | break; | |
d49def48 | 229 | } |
2df20057 WD |
230 | if (node) |
231 | id2 = node->id2; | |
232 | else if (*name && id) { | |
46d68be3 | 233 | if (idlist_ptr == &uidlist) { |
2df20057 | 234 | uid_t uid; |
56017d31 | 235 | id2 = user_to_uid(name, &uid, False) ? uid : id; |
2df20057 WD |
236 | } else { |
237 | gid_t gid; | |
56017d31 | 238 | id2 = group_to_gid(name, &gid, False) ? gid : id; |
2df20057 WD |
239 | } |
240 | } else | |
241 | id2 = id; | |
d49def48 | 242 | |
46d68be3 | 243 | flag = idlist_ptr == &gidlist && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0; |
d518e022 | 244 | node = add_to_list(idlist_ptr, id, noiu, id2, flag); |
d49def48 | 245 | |
951e826b | 246 | if (DEBUG_GTE(OWN, 2)) { |
2df20057 | 247 | rprintf(FINFO, "%sid %u(%s) maps to %u\n", |
46d68be3 | 248 | idlist_ptr == &uidlist ? "u" : "g", |
2df20057 | 249 | (unsigned)id, name, (unsigned)id2); |
d49def48 WD |
250 | } |
251 | ||
d6b422a6 | 252 | return node; |
d49def48 WD |
253 | } |
254 | ||
ade7292a | 255 | /* this function is a definate candidate for a faster algorithm */ |
496c809f | 256 | uid_t match_uid(uid_t uid) |
ade7292a | 257 | { |
eee2c77a | 258 | static struct idlist *last = NULL; |
d49def48 WD |
259 | struct idlist *list; |
260 | ||
eee2c77a WD |
261 | if (last && uid == last->id) |
262 | return last->id2; | |
ade7292a | 263 | |
d49def48 | 264 | for (list = uidlist; list; list = list->next) { |
d6b422a6 | 265 | if (list->id == uid) |
2df20057 | 266 | break; |
ade7292a WD |
267 | } |
268 | ||
2df20057 WD |
269 | if (!list) |
270 | list = recv_add_id(&uidlist, uidmap, uid, NULL); | |
eee2c77a | 271 | last = list; |
2df20057 | 272 | |
eee2c77a | 273 | return list->id2; |
ade7292a WD |
274 | } |
275 | ||
d6b422a6 | 276 | gid_t match_gid(gid_t gid, uint16 *flags_ptr) |
f6c34742 | 277 | { |
4504b225 | 278 | static struct idlist *last = NULL; |
d49def48 WD |
279 | struct idlist *list; |
280 | ||
4504b225 WD |
281 | if (last && gid == last->id) |
282 | list = last; | |
283 | else { | |
284 | for (list = gidlist; list; list = list->next) { | |
285 | if (list->id == gid) | |
286 | break; | |
287 | } | |
288 | if (!list) | |
2df20057 | 289 | list = recv_add_id(&gidlist, gidmap, gid, NULL); |
4504b225 | 290 | last = list; |
f6c34742 | 291 | } |
d49def48 | 292 | |
d6b422a6 WD |
293 | if (flags_ptr && list->flags & FLAG_SKIP_GROUP) |
294 | *flags_ptr |= FLAG_SKIP_GROUP; | |
4504b225 | 295 | return list->id2; |
f6c34742 AT |
296 | } |
297 | ||
d49def48 | 298 | /* Add a uid to the list of uids. Only called on sending side. */ |
c78cb8f3 | 299 | const char *add_uid(uid_t uid) |
f6c34742 | 300 | { |
d49def48 | 301 | struct idlist *list; |
496c809f | 302 | struct idlist *node; |
d518e022 | 303 | union name_or_id noiu; |
f6c34742 | 304 | |
d49def48 | 305 | if (uid == 0) /* don't map root */ |
496c809f | 306 | return NULL; |
f6c34742 | 307 | |
d49def48 | 308 | for (list = uidlist; list; list = list->next) { |
d6b422a6 | 309 | if (list->id == uid) |
496c809f | 310 | return NULL; |
f6c34742 AT |
311 | } |
312 | ||
d518e022 WD |
313 | noiu.name = uid_to_user(uid); |
314 | node = add_to_list(&uidlist, uid, noiu, 0, 0); | |
315 | return node->u.name; | |
f6c34742 AT |
316 | } |
317 | ||
d49def48 | 318 | /* Add a gid to the list of gids. Only called on sending side. */ |
c78cb8f3 | 319 | const char *add_gid(gid_t gid) |
f6c34742 | 320 | { |
d49def48 | 321 | struct idlist *list; |
496c809f | 322 | struct idlist *node; |
d518e022 | 323 | union name_or_id noiu; |
f6c34742 | 324 | |
d49def48 | 325 | if (gid == 0) /* don't map root */ |
496c809f | 326 | return NULL; |
f6c34742 | 327 | |
d49def48 | 328 | for (list = gidlist; list; list = list->next) { |
d6b422a6 | 329 | if (list->id == gid) |
496c809f | 330 | return NULL; |
f6c34742 AT |
331 | } |
332 | ||
d518e022 WD |
333 | noiu.name = gid_to_group(gid); |
334 | node = add_to_list(&gidlist, gid, noiu, 0, 0); | |
335 | return node->u.name; | |
f6c34742 AT |
336 | } |
337 | ||
f6c34742 | 338 | /* send a complete uid/gid mapping to the peer */ |
d6b422a6 | 339 | void send_id_list(int f) |
f6c34742 AT |
340 | { |
341 | struct idlist *list; | |
342 | ||
1c3344a1 | 343 | if (preserve_uid || preserve_acls) { |
d49def48 | 344 | int len; |
f6c34742 | 345 | /* we send sequences of uid/byte-length/name */ |
d49def48 | 346 | for (list = uidlist; list; list = list->next) { |
d518e022 | 347 | if (!list->u.name) |
d49def48 | 348 | continue; |
d518e022 | 349 | len = strlen(list->u.name); |
f31514ad | 350 | write_varint30(f, list->id); |
f6c34742 | 351 | write_byte(f, len); |
d518e022 | 352 | write_buf(f, list->u.name, len); |
f6c34742 AT |
353 | } |
354 | ||
355 | /* terminate the uid list with a 0 uid. We explicitly exclude | |
84fa865c | 356 | * 0 from the list */ |
f31514ad | 357 | write_varint30(f, 0); |
f6c34742 AT |
358 | } |
359 | ||
1c3344a1 | 360 | if (preserve_gid || preserve_acls) { |
d49def48 WD |
361 | int len; |
362 | for (list = gidlist; list; list = list->next) { | |
d518e022 | 363 | if (!list->u.name) |
d49def48 | 364 | continue; |
d518e022 | 365 | len = strlen(list->u.name); |
f31514ad | 366 | write_varint30(f, list->id); |
f6c34742 | 367 | write_byte(f, len); |
d518e022 | 368 | write_buf(f, list->u.name, len); |
f6c34742 | 369 | } |
f31514ad | 370 | write_varint30(f, 0); |
f6c34742 AT |
371 | } |
372 | } | |
373 | ||
496c809f | 374 | uid_t recv_user_name(int f, uid_t uid) |
283887d7 | 375 | { |
d6b422a6 | 376 | struct idlist *node; |
283887d7 WD |
377 | int len = read_byte(f); |
378 | char *name = new_array(char, len+1); | |
379 | if (!name) | |
380 | out_of_memory("recv_user_name"); | |
381 | read_sbuf(f, name, len); | |
0b52f94d WD |
382 | if (numeric_ids < 0) { |
383 | free(name); | |
384 | name = NULL; | |
385 | } | |
2df20057 | 386 | node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */ |
d6b422a6 | 387 | return node->id2; |
283887d7 WD |
388 | } |
389 | ||
d6b422a6 | 390 | gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr) |
283887d7 | 391 | { |
d6b422a6 | 392 | struct idlist *node; |
283887d7 WD |
393 | int len = read_byte(f); |
394 | char *name = new_array(char, len+1); | |
395 | if (!name) | |
396 | out_of_memory("recv_group_name"); | |
397 | read_sbuf(f, name, len); | |
0b52f94d WD |
398 | if (numeric_ids < 0) { |
399 | free(name); | |
400 | name = NULL; | |
401 | } | |
2df20057 | 402 | node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */ |
d6b422a6 WD |
403 | if (flags_ptr && node->flags & FLAG_SKIP_GROUP) |
404 | *flags_ptr |= FLAG_SKIP_GROUP; | |
405 | return node->id2; | |
283887d7 WD |
406 | } |
407 | ||
f6c34742 | 408 | /* recv a complete uid/gid mapping from the peer and map the uid/gid |
84fa865c | 409 | * in the file list to local names */ |
d6b422a6 | 410 | void recv_id_list(int f, struct file_list *flist) |
f6c34742 | 411 | { |
d6b422a6 WD |
412 | id_t id; |
413 | int i; | |
f6c34742 | 414 | |
0b52f94d | 415 | if ((preserve_uid || preserve_acls) && numeric_ids <= 0) { |
f6c34742 | 416 | /* read the uid list */ |
f31514ad | 417 | while ((id = read_varint30(f)) != 0) |
d6b422a6 | 418 | recv_user_name(f, id); |
f6c34742 AT |
419 | } |
420 | ||
0b52f94d | 421 | if ((preserve_gid || preserve_acls) && numeric_ids <= 0) { |
d49def48 | 422 | /* read the gid list */ |
f31514ad | 423 | while ((id = read_varint30(f)) != 0) |
d6b422a6 | 424 | recv_group_name(f, id, NULL); |
f6c34742 AT |
425 | } |
426 | ||
a217c453 | 427 | /* Now convert all the uids/gids from sender values to our values. */ |
1c3344a1 | 428 | #ifdef SUPPORT_ACLS |
2df20057 | 429 | if (preserve_acls && (!numeric_ids || usermap || groupmap)) |
a217c453 | 430 | match_acl_ids(); |
1c3344a1 | 431 | #endif |
2df20057 | 432 | if (am_root && preserve_uid && (!numeric_ids || usermap)) { |
9decb4d2 | 433 | for (i = 0; i < flist->used; i++) |
d6b422a6 | 434 | F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i])); |
d49def48 | 435 | } |
2df20057 | 436 | if (preserve_gid && (!am_root || !numeric_ids || groupmap)) { |
9decb4d2 | 437 | for (i = 0; i < flist->used; i++) { |
d6b422a6 WD |
438 | F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), |
439 | &flist->files[i]->flags); | |
440 | } | |
5e58e3f9 | 441 | } |
f6c34742 | 442 | } |
2df20057 WD |
443 | |
444 | void parse_name_map(char *map, BOOL usernames) | |
445 | { | |
446 | struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap; | |
447 | struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist; | |
d518e022 WD |
448 | char *colon, *end, *cp = map + strlen(map); |
449 | union name_or_id noiu; | |
2df20057 WD |
450 | id_t id1; |
451 | uint16 flags; | |
452 | ||
453 | /* Parse the list in reverse, so the order in the struct is right. */ | |
454 | while (1) { | |
455 | end = cp; | |
456 | while (cp > map && cp[-1] != ',') cp--; | |
457 | if (!(colon = strchr(cp, ':'))) { | |
458 | rprintf(FERROR, "No colon found in --%smap: %s\n", | |
459 | usernames ? "user" : "group", cp); | |
460 | exit_cleanup(RERR_SYNTAX); | |
461 | } | |
462 | if (!colon[1]) { | |
463 | rprintf(FERROR, "No name found after colon --%smap: %s\n", | |
464 | usernames ? "user" : "group", cp); | |
465 | exit_cleanup(RERR_SYNTAX); | |
466 | } | |
467 | *colon = '\0'; | |
468 | ||
469 | if (isDigit(cp)) { | |
470 | char *dash = strchr(cp, '-'); | |
471 | if (strspn(cp, "0123456789-") != (size_t)(colon - cp) | |
472 | || (dash && (!dash[1] || strchr(dash+1, '-')))) { | |
2df20057 WD |
473 | rprintf(FERROR, "Invalid number in --%smap: %s\n", |
474 | usernames ? "user" : "group", cp); | |
475 | exit_cleanup(RERR_SYNTAX); | |
476 | } | |
477 | if (dash) | |
d518e022 | 478 | noiu.max_id = id_parse(dash+1); |
2df20057 | 479 | else |
d518e022 | 480 | noiu.max_id = 0; |
2df20057 | 481 | flags = 0; |
eee2c77a | 482 | id1 = id_parse(cp); |
2df20057 WD |
483 | } else if (strpbrk(cp, "*[?")) { |
484 | flags = NFLAGS_WILD_NAME_MATCH; | |
d518e022 | 485 | noiu.name = cp; |
2df20057 WD |
486 | id1 = 0; |
487 | } else { | |
488 | flags = NFLAGS_NAME_MATCH; | |
d518e022 | 489 | noiu.name = cp; |
2df20057 WD |
490 | id1 = 0; |
491 | } | |
492 | ||
56017d31 | 493 | if (usernames) { |
2df20057 | 494 | uid_t uid; |
56017d31 | 495 | if (user_to_uid(colon+1, &uid, True)) |
d518e022 | 496 | add_to_list(idmap_ptr, id1, noiu, uid, flags); |
2df20057 WD |
497 | else { |
498 | rprintf(FERROR, | |
499 | "Unknown --usermap name on receiver: %s\n", | |
500 | colon+1); | |
501 | } | |
502 | } else { | |
503 | gid_t gid; | |
56017d31 | 504 | if (group_to_gid(colon+1, &gid, True)) |
d518e022 | 505 | add_to_list(idmap_ptr, id1, noiu, gid, flags); |
2df20057 WD |
506 | else { |
507 | rprintf(FERROR, | |
508 | "Unknown --groupmap name on receiver: %s\n", | |
509 | colon+1); | |
510 | } | |
511 | } | |
512 | ||
513 | if (cp == map) | |
514 | break; | |
515 | ||
516 | *--cp = '\0'; /* replace comma */ | |
517 | } | |
518 | ||
519 | /* The 0 user/group doesn't get its name sent, so add it explicitly. */ | |
520 | recv_add_id(idlist_ptr, *idmap_ptr, 0, | |
d7205694 | 521 | numeric_ids ? NULL : usernames ? uid_to_user(0) : gid_to_group(0)); |
2df20057 | 522 | } |
d7205694 WD |
523 | |
524 | #ifdef HAVE_GETGROUPLIST | |
525 | const char *getallgroups(uid_t uid, gid_t *gid_list, int *size_ptr) | |
526 | { | |
527 | struct passwd *pw; | |
528 | if ((pw = getpwuid(uid)) == NULL) | |
529 | return "getpwuid failed"; | |
530 | /* Get all the process's groups, with the pw_gid group first. */ | |
531 | if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list, size_ptr) < 0) | |
532 | return "getgrouplist failed"; | |
533 | /* Paranoia: is the default group not first in the list? */ | |
534 | if (gid_list[0] != pw->pw_gid) { | |
535 | int j; | |
536 | for (j = 0; j < *size_ptr; j++) { | |
537 | if (gid_list[j] == pw->pw_gid) { | |
538 | gid_list[j] = gid_list[0]; | |
539 | gid_list[0] = pw->pw_gid; | |
540 | break; | |
541 | } | |
542 | } | |
543 | } | |
544 | return NULL; | |
545 | } | |
546 | #endif |