Moved some misplaced code.
[rsync/rsync-patches.git] / acls.diff
CommitLineData
4db3c954
WD
1This patch adds backward-compatibility support for the --acls option.
2Since the main release has never had ACL support, the trunk doesn't
3need this code. If you want to make rsync 3.0.x communicate with an
4older (patched) release, use this.
5
03019e41 6To use this patch, run these commands for a successful build:
fa26e11c 7
03019e41 8 patch -p1 <patches/acls.diff
4db3c954 9 ./configure (optional if already run)
fa26e11c
WD
10 make
11
9a7eef96
WD
12--- old/acls.c
13+++ new/acls.c
e70a47f8 14@@ -98,6 +98,18 @@ static const char *str_acl_type(SMB_ACL_
4db3c954
WD
15 : "unknown SMB_ACL_TYPE_T";
16 }
17
8db8e7d2
WD
18+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
19+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
fa26e11c 20+
4db3c954 21+static int old_count_racl_entries(const rsync_acl *racl)
56294981 22+{
e70a47f8 23+ return racl->names.count
0870c22a
WD
24+ + (racl->user_obj != NO_ENTRY)
25+ + (racl->group_obj != NO_ENTRY)
4db3c954
WD
26+ + (racl->mask_obj != NO_ENTRY)
27+ + (racl->other_obj != NO_ENTRY);
0870c22a
WD
28+}
29+
4db3c954
WD
30 static int calc_sacl_entries(const rsync_acl *racl)
31 {
32 /* A System ACL always gets user/group/other permission entries. */
e70a47f8 33@@ -522,6 +534,96 @@ int get_acl(const char *fname, statx *sx
4db3c954
WD
34 return 0;
35 }
36
37+/* === OLD Send functions === */
0870c22a
WD
38+
39+/* Send the ida list over the file descriptor. */
4db3c954 40+static void old_send_ida_entries(int f, const ida_entries *idal, char tag_char)
0870c22a
WD
41+{
42+ id_access *ida;
43+ size_t count = idal->count;
44+ for (ida = idal->idas; count--; ida++) {
e70a47f8
WD
45+ if (tag_char == 'U') {
46+ if (!(ida->access & NAME_IS_USER))
47+ continue;
48+ add_uid(ida->id);
49+ } else {
50+ if (ida->access & NAME_IS_USER)
51+ continue;
52+ add_gid(ida->id);
53+ }
0870c22a
WD
54+ write_byte(f, tag_char);
55+ write_byte(f, ida->access);
56+ write_int(f, ida->id);
fa26e11c 57+ }
0870c22a
WD
58+}
59+
adabede5 60+/* Send an rsync ACL over the file descriptor. */
4db3c954 61+static void old_send_rsync_acl(int f, const rsync_acl *racl)
0870c22a 62+{
4db3c954 63+ size_t count = old_count_racl_entries(racl);
0870c22a
WD
64+ write_int(f, count);
65+ if (racl->user_obj != NO_ENTRY) {
66+ write_byte(f, 'u');
67+ write_byte(f, racl->user_obj);
68+ }
e70a47f8 69+ old_send_ida_entries(f, &racl->names, 'U');
0870c22a
WD
70+ if (racl->group_obj != NO_ENTRY) {
71+ write_byte(f, 'g');
72+ write_byte(f, racl->group_obj);
fa26e11c 73+ }
e70a47f8 74+ old_send_ida_entries(f, &racl->names, 'G');
4db3c954 75+ if (racl->mask_obj != NO_ENTRY) {
0870c22a 76+ write_byte(f, 'm');
4db3c954 77+ write_byte(f, racl->mask_obj);
0870c22a 78+ }
4db3c954 79+ if (racl->other_obj != NO_ENTRY) {
0870c22a 80+ write_byte(f, 'o');
4db3c954 81+ write_byte(f, racl->other_obj);
0870c22a
WD
82+ }
83+}
c6437996 84+
98ccc74a 85+/* Send the ACL from the statx structure down the indicated file descriptor.
0870c22a 86+ * This also frees the ACL data. */
4db3c954 87+void old_send_acl(statx *sxp, int f)
0870c22a
WD
88+{
89+ SMB_ACL_TYPE_T type;
90+ rsync_acl *racl, *new_racl;
91+ item_list *racl_list;
5d2612ca 92+ int ndx;
53c1073a 93+
0870c22a
WD
94+ type = SMB_ACL_TYPE_ACCESS;
95+ racl = sxp->acc_acl;
96+ racl_list = &access_acl_list;
97+ do {
5d2612ca
WD
98+ if (!racl) {
99+ racl = new(rsync_acl);
100+ if (!racl)
101+ out_of_memory("send_acl");
102+ *racl = empty_rsync_acl;
103+ if (type == SMB_ACL_TYPE_ACCESS) {
104+ rsync_acl_fake_perms(racl, sxp->st.st_mode);
105+ sxp->acc_acl = racl;
106+ } else
107+ sxp->def_acl = racl;
108+ }
0870c22a 109+
4db3c954 110+ if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) != -1) {
0870c22a
WD
111+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
112+ write_int(f, ndx);
0870c22a 113+ } else {
645e162c 114+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
0870c22a 115+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
4db3c954 116+ old_send_rsync_acl(f, racl);
0870c22a
WD
117+ *new_racl = *racl;
118+ *racl = empty_rsync_acl;
119+ }
120+ racl = sxp->def_acl;
121+ racl_list = &default_acl_list;
122+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
123+
98ccc74a 124+ free_acl(sxp);
fa26e11c
WD
125+}
126+
4db3c954
WD
127 /* === Send functions === */
128
129 /* The general strategy with the tag_type <-> character mapping is that
e70a47f8 130@@ -604,6 +706,11 @@ static void send_rsync_acl(rsync_acl *ra
4db3c954
WD
131 * This also frees the ACL data. */
132 void send_acl(statx *sxp, int f)
133 {
134+ if (protocol_version < 30) {
135+ old_send_acl(sxp, f);
136+ return;
137+ }
ffc18846 138+
4db3c954
WD
139 if (!sxp->acc_acl) {
140 sxp->acc_acl = create_racl();
ffc18846 141 rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
e70a47f8 142@@ -621,6 +728,160 @@ void send_acl(statx *sxp, int f)
4db3c954
WD
143 }
144 }
145
146+/* === OLD Receive functions */
0870c22a 147+
4db3c954 148+static void old_recv_rsync_acl(rsync_acl *racl, int f)
fa26e11c 149+{
6250eb3e 150+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
e70a47f8 151+ SMB_ACL_TAG_T tag_type = 0;
090d78e1 152+ uchar computed_mask_bits = 0;
c6437996 153+ id_access *ida;
ad625644
WD
154+ size_t count;
155+
156+ if (!(count = read_int(f)))
fa26e11c 157+ return;
ad625644 158+
fa26e11c 159+ while (count--) {
dfadc68a 160+ char tag = read_byte(f);
c6437996
WD
161+ uchar access = read_byte(f);
162+ if (access & ~ (4 | 2 | 1)) {
4db3c954 163+ rprintf(FERROR, "old_recv_rsync_acl: bogus permset %o\n",
c6437996
WD
164+ access);
165+ exit_cleanup(RERR_STREAMIO);
166+ }
fa26e11c
WD
167+ switch (tag) {
168+ case 'u':
0870c22a 169+ if (racl->user_obj != NO_ENTRY) {
4db3c954 170+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate USER_OBJ entry\n");
c6437996
WD
171+ exit_cleanup(RERR_STREAMIO);
172+ }
173+ racl->user_obj = access;
174+ continue;
fa26e11c 175+ case 'U':
0870c22a 176+ tag_type = SMB_ACL_USER;
fa26e11c
WD
177+ break;
178+ case 'g':
0870c22a 179+ if (racl->group_obj != NO_ENTRY) {
4db3c954 180+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate GROUP_OBJ entry\n");
c6437996
WD
181+ exit_cleanup(RERR_STREAMIO);
182+ }
183+ racl->group_obj = access;
184+ continue;
fa26e11c 185+ case 'G':
0870c22a 186+ tag_type = SMB_ACL_GROUP;
fa26e11c
WD
187+ break;
188+ case 'm':
4db3c954
WD
189+ if (racl->mask_obj != NO_ENTRY) {
190+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate MASK entry\n");
c6437996
WD
191+ exit_cleanup(RERR_STREAMIO);
192+ }
4db3c954 193+ racl->mask_obj = access;
c6437996
WD
194+ continue;
195+ case 'o':
4db3c954
WD
196+ if (racl->other_obj != NO_ENTRY) {
197+ rprintf(FERROR, "old_recv_rsync_acl: error: duplicate OTHER entry\n");
c6437996
WD
198+ exit_cleanup(RERR_STREAMIO);
199+ }
4db3c954 200+ racl->other_obj = access;
c6437996 201+ continue;
fa26e11c 202+ default:
4db3c954 203+ rprintf(FERROR, "old_recv_rsync_acl: unknown tag %c\n",
fa26e11c
WD
204+ tag);
205+ exit_cleanup(RERR_STREAMIO);
206+ }
645e162c 207+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
e70a47f8 208+ ida->access = access | (tag_type == SMB_ACL_USER ? NAME_IS_USER : 0);
c6437996 209+ ida->id = read_int(f);
090d78e1 210+ computed_mask_bits |= access;
c6437996 211+ }
8eb3e3ae 212+
e70a47f8
WD
213+ /* Transfer the count id_access items out of the temp_ida_list
214+ * into the names ida_entries list in racl. */
215+ if (temp_ida_list.count) {
216+#ifdef SMB_ACL_NEED_SORT
217+ if (temp_ida_list.count > 1) {
218+ qsort(temp_ida_list.items, temp_ida_list.count,
219+ sizeof (id_access), id_access_sorter);
220+ }
221+#endif
222+ if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
223+ out_of_memory("unpack_smb_acl");
224+ memcpy(racl->names.idas, temp_ida_list.items,
225+ temp_ida_list.count * sizeof (id_access));
226+ } else
227+ racl->names.idas = NULL;
228+
229+ racl->names.count = temp_ida_list.count;
230+
231+ /* Truncate the temporary list now that its idas have been saved. */
232+ temp_ida_list.count = 0;
233+
234+ if (!racl->names.count) {
8eb3e3ae 235+ /* If we received a superfluous mask, throw it away. */
4db3c954 236+ if (racl->mask_obj != NO_ENTRY) {
8eb3e3ae 237+ /* Mask off the group perms with it first. */
4db3c954
WD
238+ racl->group_obj &= racl->mask_obj | NO_ENTRY;
239+ racl->mask_obj = NO_ENTRY;
fa26e11c 240+ }
4db3c954 241+ } else if (racl->mask_obj == NO_ENTRY) /* Must be non-empty with lists. */
e70a47f8 242+ racl->mask_obj = (computed_mask_bits | racl->group_obj) & 7;
fa26e11c
WD
243+}
244+
0870c22a 245+/* Receive the ACL info the sender has included for this file-list entry. */
4db3c954 246+void old_recv_acl(struct file_struct *file, int f)
fa26e11c 247+{
8db8e7d2 248+ SMB_ACL_TYPE_T type;
0870c22a 249+ item_list *racl_list;
36aa3171 250+
162234a7 251+ if (S_ISLNK(file->mode))
fa26e11c 252+ return;
36aa3171 253+
8db8e7d2 254+ type = SMB_ACL_TYPE_ACCESS;
0870c22a 255+ racl_list = &access_acl_list;
8db8e7d2 256+ do {
0870c22a
WD
257+ char tag = read_byte(f);
258+ int ndx;
fa26e11c 259+
fa26e11c 260+ if (tag == 'A' || tag == 'a') {
8db8e7d2 261+ if (type != SMB_ACL_TYPE_ACCESS) {
fa26e11c 262+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
f4222aa5 263+ f_name(file, NULL));
fa26e11c
WD
264+ exit_cleanup(RERR_STREAMIO);
265+ }
266+ } else if (tag == 'D' || tag == 'd') {
8db8e7d2 267+ if (type == SMB_ACL_TYPE_ACCESS) {
fa26e11c 268+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
f4222aa5 269+ f_name(file, NULL));
fa26e11c
WD
270+ exit_cleanup(RERR_STREAMIO);
271+ }
272+ } else {
273+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
f4222aa5 274+ f_name(file, NULL), tag);
fa26e11c
WD
275+ exit_cleanup(RERR_STREAMIO);
276+ }
277+ if (tag == 'A' || tag == 'D') {
0870c22a
WD
278+ acl_duo *duo_item;
279+ ndx = racl_list->count;
645e162c 280+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
b6c2bb12 281+ duo_item->racl = empty_rsync_acl;
4db3c954 282+ old_recv_rsync_acl(&duo_item->racl, f);
0870c22a 283+ duo_item->sacl = NULL;
fa26e11c 284+ } else {
0870c22a 285+ ndx = read_int(f);
d4531ffb 286+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
fa26e11c 287+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
0870c22a 288+ f_name(file, NULL), str_acl_type(type), ndx);
fa26e11c
WD
289+ exit_cleanup(RERR_STREAMIO);
290+ }
fa26e11c 291+ }
70891d26
WD
292+ if (type == SMB_ACL_TYPE_ACCESS)
293+ F_ACL(file) = ndx;
294+ else
7bfcb297 295+ F_DIR_DEFACL(file) = ndx;
0870c22a 296+ racl_list = &default_acl_list;
8db8e7d2 297+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
fa26e11c
WD
298+}
299+
4db3c954
WD
300 /* === Receive functions === */
301
e70a47f8
WD
302 static uint32 recv_acl_access(uchar *name_follows_ptr, int f)
303@@ -738,6 +999,11 @@ static int recv_rsync_acl(item_list *rac
4db3c954
WD
304 /* Receive the ACL info the sender has included for this file-list entry. */
305 void receive_acl(struct file_struct *file, int f)
306 {
307+ if (protocol_version < 30) {
308+ old_recv_acl(file, f);
5d2612ca 309+ return;
fa26e11c 310+ }
fa26e11c 311+
4db3c954 312 F_ACL(file) = recv_rsync_acl(&access_acl_list, SMB_ACL_TYPE_ACCESS, f);
34a409bc 313
4db3c954
WD
314 if (S_ISDIR(file->mode))
315--- old/compat.c
316+++ new/compat.c
7bfcb297 317@@ -163,13 +163,6 @@ void setup_protocol(int f_out,int f_in)
99650e0d 318 if (protocol_version < 30) {
5ba66156
WD
319 if (append_mode == 1)
320 append_mode = 2;
8a38e00a 321- if (preserve_acls && !local_server) {
4db3c954
WD
322- rprintf(FERROR,
323- "--acls requires protocol 30 or higher"
324- " (negotiated %d).\n",
325- protocol_version);
326- exit_cleanup(RERR_PROTOCOL);
327- }
8a38e00a 328 if (preserve_xattrs && !local_server) {
5795bf59
WD
329 rprintf(FERROR,
330 "--xattrs requires protocol 30 or higher"