Removed am_client variable. It was being set in one place, when a client
[rsync/rsync.git] / uidlist.c
CommitLineData
f6c34742
AT
1/*
2 Copyright (C) Andrew Tridgell 1996
3 Copyright (C) Paul Mackerras 1996
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/* handle the mapping of uid/gid and user/group names between systems.
21 If the source username/group does not exist on the target then use
22 the numeric ids. Never do any mapping for uid=0 or gid=0 as these
23 are special.
24*/
25
26#include "rsync.h"
27
28extern int preserve_uid;
29extern int preserve_gid;
30extern int numeric_ids;
31
32struct idlist {
33 struct idlist *next;
34 int id, id2;
35 char *name;
36};
37
38static struct idlist *uidlist;
39static struct idlist *gidlist;
40
41static struct idlist *add_list(int id, char *name)
42{
43 struct idlist *list = (struct idlist *)malloc(sizeof(list[0]));
44 if (!list) out_of_memory("add_list");
45 list->next = NULL;
46 list->name = strdup(name);
47 if (!list->name) out_of_memory("add_list");
48 list->id = (int)id;
49 return list;
50}
51
52
53
54/* turn a uid into a user name */
55static char *uid_to_name(uid_t uid)
56{
57 struct passwd *pass = getpwuid(uid);
58 if (pass) return(pass->pw_name);
59 return NULL;
60}
61
62/* turn a gid into a group name */
63static char *gid_to_name(gid_t gid)
64{
65 struct group *grp = getgrgid(gid);
66 if (grp) return(grp->gr_name);
67 return NULL;
68}
69
f6c34742
AT
70static int map_uid(int id, char *name)
71{
8ef4ffd6
AT
72 uid_t uid;
73 if (name_to_uid(name, &uid) && uid != 0)
74 return uid;
f6c34742
AT
75 return id;
76}
77
78static int map_gid(int id, char *name)
79{
8ef4ffd6
AT
80 gid_t gid;
81 if (name_to_gid(name, &gid) && gid != 0)
82 return gid;
f6c34742
AT
83 return id;
84}
85
86/* this function is a definate candidate for a faster algorithm */
87static uid_t match_uid(uid_t uid)
88{
89 static uid_t last_in, last_out;
90 struct idlist *list = uidlist;
91
92 if (uid == last_in) return last_out;
93
94 last_in = uid;
95
96 while (list) {
97 if (list->id == (int)uid) {
98 last_out = (uid_t)list->id2;
99 return last_out;
100 }
101 list = list->next;
102 }
103
104 last_out = uid;
105 return last_out;
106}
107
108static gid_t match_gid(gid_t gid)
109{
110 static gid_t last_in, last_out;
111 struct idlist *list = gidlist;
112
113 if (gid == last_in) return last_out;
114
115 last_in = gid;
116
117 while (list) {
118 if (list->id == (int)gid) {
119 last_out = (gid_t)list->id2;
120 return last_out;
121 }
122 list = list->next;
123 }
124
125 last_out = gid;
126 return last_out;
127}
128
129/* add a uid to the list of uids */
130void add_uid(uid_t uid)
131{
132 struct idlist *list = uidlist;
133 char *name;
134
135 if (numeric_ids) return;
136
137 /* don't map root */
138 if (uid==0) return;
139
140 if (!list) {
141 if (!(name = uid_to_name(uid))) return;
142 uidlist = add_list((int)uid, name);
143 return;
144 }
145
146 while (list->next) {
147 if (list->id == (int)uid) return;
148 list = list->next;
149 }
150
151 if (list->id == (int)uid) return;
152
153 if (!(name = uid_to_name(uid))) return;
154
155 list->next = add_list((int)uid, name);
156}
157
158/* add a gid to the list of gids */
159void add_gid(gid_t gid)
160{
161 struct idlist *list = gidlist;
162 char *name;
163
164 if (numeric_ids) return;
165
166 /* don't map root */
167 if (gid==0) return;
168
169 if (!list) {
170 if (!(name = gid_to_name(gid))) return;
171 gidlist = add_list((int)gid, name);
172 return;
173 }
174
175 while (list->next) {
176 if (list->id == (int)gid) return;
177 list = list->next;
178 }
179
180 if (list->id == (int)gid) return;
181
182 if (!(name = gid_to_name(gid))) return;
183
184 list->next = add_list((int)gid, name);
185}
186
187
188/* send a complete uid/gid mapping to the peer */
189void send_uid_list(int f)
190{
191 struct idlist *list;
192
193 if (numeric_ids) return;
194
195 if (preserve_uid) {
196 /* we send sequences of uid/byte-length/name */
197 list = uidlist;
198 while (list) {
199 int len = strlen(list->name);
200 write_int(f, list->id);
201 write_byte(f, len);
202 write_buf(f, list->name, len);
203 list = list->next;
204 }
205
206 /* terminate the uid list with a 0 uid. We explicitly exclude
207 0 from the list */
208 write_int(f, 0);
209 }
210
211 if (preserve_gid) {
212 list = gidlist;
213 while (list) {
214 int len = strlen(list->name);
215 write_int(f, list->id);
216 write_byte(f, len);
217 write_buf(f, list->name, len);
218 list = list->next;
219 }
220 write_int(f, 0);
221 }
222}
223
224/* recv a complete uid/gid mapping from the peer and map the uid/gid
225 in the file list to local names */
226void recv_uid_list(int f, struct file_list *flist)
227{
228 int id, i;
229 char *name;
230 struct idlist *list;
231
232 if (numeric_ids) return;
233
234 if (preserve_uid) {
235 /* read the uid list */
236 list = uidlist;
237 id = read_int(f);
238 while (id != 0) {
239 int len = read_byte(f);
575f2fca 240 name = (char *)malloc(len+1);
f6c34742 241 if (!name) out_of_memory("recv_uid_list");
575f2fca 242 read_sbuf(f, name, len);
f6c34742
AT
243 if (!list) {
244 uidlist = add_list(id, name);
245 list = uidlist;
246 } else {
247 list->next = add_list(id, name);
248 list = list->next;
249 }
250 list->id2 = map_uid(id, name);
251 free(name);
252 id = read_int(f);
253 }
254 }
255
256
257 if (preserve_gid) {
258 /* and the gid list */
259 list = gidlist;
260 id = read_int(f);
261 while (id != 0) {
262 int len = read_byte(f);
575f2fca 263 name = (char *)malloc(len+1);
f6c34742 264 if (!name) out_of_memory("recv_uid_list");
575f2fca 265 read_sbuf(f, name, len);
f6c34742
AT
266 if (!list) {
267 gidlist = add_list(id, name);
268 list = gidlist;
269 } else {
270 list->next = add_list(id, name);
271 list = list->next;
272 }
273 list->id2 = map_gid(id, name);
274 free(name);
275 id = read_int(f);
276 }
277 }
278
279 if (!uidlist && !gidlist) return;
280
281 /* now convert the uid/gid of all files in the list to the mapped
282 uid/gid */
283 for (i=0;i<flist->count;i++) {
3ec4dd97
AT
284 if (preserve_uid && flist->files[i]->uid != 0) {
285 flist->files[i]->uid = match_uid(flist->files[i]->uid);
f6c34742 286 }
3ec4dd97
AT
287 if (preserve_gid && flist->files[i]->gid != 0) {
288 flist->files[i]->gid = match_gid(flist->files[i]->gid);
f6c34742
AT
289 }
290 }
291}