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