Annotation of embedaddon/rsync/uidlist.c, revision 1.1.1.1
1.1 misho 1: /*
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
6: * Copyright (C) 2004-2009 Wayne Davison
7: *
8: * This program is free software; you can redistribute it and/or modify
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.
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: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
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. */
25:
26: #include "rsync.h"
27: #include "io.h"
28:
29: extern int verbose;
30: extern int am_root;
31: extern int preserve_uid;
32: extern int preserve_gid;
33: extern int preserve_acls;
34: extern int numeric_ids;
35:
36: #ifdef HAVE_GETGROUPS
37: # ifndef GETGROUPS_T
38: # define GETGROUPS_T gid_t
39: # endif
40: #endif
41:
42: struct idlist {
43: struct idlist *next;
44: const char *name;
45: id_t id, id2;
46: uint16 flags;
47: };
48:
49: static struct idlist *uidlist;
50: static struct idlist *gidlist;
51:
52: static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
53: id_t id2, uint16 flags)
54: {
55: struct idlist *node = new(struct idlist);
56: if (!node)
57: out_of_memory("add_to_list");
58: node->next = *root;
59: node->name = name;
60: node->id = id;
61: node->id2 = id2;
62: node->flags = flags;
63: *root = node;
64: return node;
65: }
66:
67: /* turn a uid into a user name */
68: static const char *uid_to_name(uid_t uid)
69: {
70: struct passwd *pass = getpwuid(uid);
71: if (pass)
72: return strdup(pass->pw_name);
73: return NULL;
74: }
75:
76: /* turn a gid into a group name */
77: static const char *gid_to_name(gid_t gid)
78: {
79: struct group *grp = getgrgid(gid);
80: if (grp)
81: return strdup(grp->gr_name);
82: return NULL;
83: }
84:
85: static uid_t map_uid(uid_t id, const char *name)
86: {
87: uid_t uid;
88: if (id != 0 && name_to_uid(name, &uid))
89: return uid;
90: return id;
91: }
92:
93: static gid_t map_gid(gid_t id, const char *name)
94: {
95: gid_t gid;
96: if (id != 0 && name_to_gid(name, &gid))
97: return gid;
98: return id;
99: }
100:
101: static int is_in_group(gid_t gid)
102: {
103: #ifdef HAVE_GETGROUPS
104: static gid_t last_in;
105: static int ngroups = -2, last_out = -1;
106: static GETGROUPS_T *gidset;
107: int n;
108:
109: if (gid == last_in && last_out >= 0)
110: return last_out;
111: if (ngroups < -1) {
112: gid_t mygid = MY_GID();
113: if ((ngroups = getgroups(0, NULL)) < 0)
114: ngroups = 0;
115: gidset = new_array(GETGROUPS_T, ngroups+1);
116: if (!gidset)
117: out_of_memory("is_in_group");
118: if (ngroups > 0)
119: ngroups = getgroups(ngroups, gidset);
120: /* The default gid might not be in the list on some systems. */
121: for (n = 0; n < ngroups; n++) {
122: if (gidset[n] == mygid)
123: break;
124: }
125: if (n == ngroups)
126: gidset[ngroups++] = mygid;
127: if (verbose > 3) {
128: int pos;
129: char *gidbuf = new_array(char, ngroups*21+32);
130: if (!gidbuf)
131: out_of_memory("is_in_group");
132: pos = snprintf(gidbuf, 32, "process has %d gid%s: ",
133: ngroups, ngroups == 1? "" : "s");
134: for (n = 0; n < ngroups; n++) {
135: pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
136: }
137: rprintf(FINFO, "%s\n", gidbuf);
138: free(gidbuf);
139: }
140: }
141:
142: last_in = gid;
143: for (n = 0; n < ngroups; n++) {
144: if (gidset[n] == gid)
145: return last_out = 1;
146: }
147: return last_out = 0;
148:
149: #else
150: static gid_t mygid = GID_NONE;
151: if (mygid == GID_NONE) {
152: mygid = MY_GID();
153: if (verbose > 3)
154: rprintf(FINFO, "process has gid %u\n", (unsigned)mygid);
155: }
156: return gid == mygid;
157: #endif
158: }
159:
160: /* Add a uid to the list of uids. Only called on receiving side. */
161: static struct idlist *recv_add_uid(uid_t id, const char *name)
162: {
163: uid_t id2 = name ? map_uid(id, name) : id;
164: struct idlist *node;
165:
166: node = add_to_list(&uidlist, id, name, id2, 0);
167:
168: if (verbose > 3) {
169: rprintf(FINFO, "uid %u(%s) maps to %u\n",
170: (unsigned)id, name ? name : "", (unsigned)id2);
171: }
172:
173: return node;
174: }
175:
176: /* Add a gid to the list of gids. Only called on receiving side. */
177: static struct idlist *recv_add_gid(gid_t id, const char *name)
178: {
179: gid_t id2 = name ? map_gid(id, name) : id;
180: struct idlist *node;
181:
182: node = add_to_list(&gidlist, id, name, id2,
183: !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
184:
185: if (verbose > 3) {
186: rprintf(FINFO, "gid %u(%s) maps to %u\n",
187: (unsigned)id, name ? name : "", (unsigned)id2);
188: }
189:
190: return node;
191: }
192:
193: /* this function is a definate candidate for a faster algorithm */
194: uid_t match_uid(uid_t uid)
195: {
196: static uid_t last_in, last_out;
197: struct idlist *list;
198:
199: if (uid == 0)
200: return 0;
201:
202: if (uid == last_in)
203: return last_out;
204:
205: last_in = uid;
206:
207: for (list = uidlist; list; list = list->next) {
208: if (list->id == uid)
209: return last_out = list->id2;
210: }
211:
212: return last_out = uid;
213: }
214:
215: gid_t match_gid(gid_t gid, uint16 *flags_ptr)
216: {
217: static struct idlist *last = NULL;
218: struct idlist *list;
219:
220: if (last && gid == last->id)
221: list = last;
222: else {
223: for (list = gidlist; list; list = list->next) {
224: if (list->id == gid)
225: break;
226: }
227: if (!list)
228: list = recv_add_gid(gid, NULL);
229: last = list;
230: }
231:
232: if (flags_ptr && list->flags & FLAG_SKIP_GROUP)
233: *flags_ptr |= FLAG_SKIP_GROUP;
234: return list->id2;
235: }
236:
237: /* Add a uid to the list of uids. Only called on sending side. */
238: const char *add_uid(uid_t uid)
239: {
240: struct idlist *list;
241: struct idlist *node;
242:
243: if (uid == 0) /* don't map root */
244: return NULL;
245:
246: for (list = uidlist; list; list = list->next) {
247: if (list->id == uid)
248: return NULL;
249: }
250:
251: node = add_to_list(&uidlist, uid, uid_to_name(uid), 0, 0);
252: return node->name;
253: }
254:
255: /* Add a gid to the list of gids. Only called on sending side. */
256: const char *add_gid(gid_t gid)
257: {
258: struct idlist *list;
259: struct idlist *node;
260:
261: if (gid == 0) /* don't map root */
262: return NULL;
263:
264: for (list = gidlist; list; list = list->next) {
265: if (list->id == gid)
266: return NULL;
267: }
268:
269: node = add_to_list(&gidlist, gid, gid_to_name(gid), 0, 0);
270: return node->name;
271: }
272:
273: /* send a complete uid/gid mapping to the peer */
274: void send_id_list(int f)
275: {
276: struct idlist *list;
277:
278: if (preserve_uid || preserve_acls) {
279: int len;
280: /* we send sequences of uid/byte-length/name */
281: for (list = uidlist; list; list = list->next) {
282: if (!list->name)
283: continue;
284: len = strlen(list->name);
285: write_varint30(f, list->id);
286: write_byte(f, len);
287: write_buf(f, list->name, len);
288: }
289:
290: /* terminate the uid list with a 0 uid. We explicitly exclude
291: * 0 from the list */
292: write_varint30(f, 0);
293: }
294:
295: if (preserve_gid || preserve_acls) {
296: int len;
297: for (list = gidlist; list; list = list->next) {
298: if (!list->name)
299: continue;
300: len = strlen(list->name);
301: write_varint30(f, list->id);
302: write_byte(f, len);
303: write_buf(f, list->name, len);
304: }
305: write_varint30(f, 0);
306: }
307: }
308:
309: uid_t recv_user_name(int f, uid_t uid)
310: {
311: struct idlist *node;
312: int len = read_byte(f);
313: char *name = new_array(char, len+1);
314: if (!name)
315: out_of_memory("recv_user_name");
316: read_sbuf(f, name, len);
317: if (numeric_ids < 0) {
318: free(name);
319: name = NULL;
320: }
321: node = recv_add_uid(uid, name); /* node keeps name's memory */
322: return node->id2;
323: }
324:
325: gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
326: {
327: struct idlist *node;
328: int len = read_byte(f);
329: char *name = new_array(char, len+1);
330: if (!name)
331: out_of_memory("recv_group_name");
332: read_sbuf(f, name, len);
333: if (numeric_ids < 0) {
334: free(name);
335: name = NULL;
336: }
337: node = recv_add_gid(gid, name); /* node keeps name's memory */
338: if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
339: *flags_ptr |= FLAG_SKIP_GROUP;
340: return node->id2;
341: }
342:
343: /* recv a complete uid/gid mapping from the peer and map the uid/gid
344: * in the file list to local names */
345: void recv_id_list(int f, struct file_list *flist)
346: {
347: id_t id;
348: int i;
349:
350: if ((preserve_uid || preserve_acls) && numeric_ids <= 0) {
351: /* read the uid list */
352: while ((id = read_varint30(f)) != 0)
353: recv_user_name(f, id);
354: }
355:
356: if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
357: /* read the gid list */
358: while ((id = read_varint30(f)) != 0)
359: recv_group_name(f, id, NULL);
360: }
361:
362: /* Now convert all the uids/gids from sender values to our values. */
363: #ifdef SUPPORT_ACLS
364: if (preserve_acls && !numeric_ids)
365: match_acl_ids();
366: #endif
367: if (am_root && preserve_uid && !numeric_ids) {
368: for (i = 0; i < flist->used; i++)
369: F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
370: }
371: if (preserve_gid && (!am_root || !numeric_ids)) {
372: for (i = 0; i < flist->used; i++) {
373: F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
374: &flist->files[i]->flags);
375: }
376: }
377: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>