1 /*-
2 * Copyright (c) 2000-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33
34 #include <limits.h>
35 #include <pthread.h>
36 #include <string.h>
37
38 #include "compat_stdbool.h"
39 #include "compat_stdint.h"
40 #include "compat_inttypes.h"
41 #include "compat_limits.h"
42 #include "basedef.h"
43
44 #include "attribute.h"
45 #include "collection.h"
46 #include "cvsync.h"
47 #include "hash.h"
48 #include "logmsg.h"
49 #include "mux.h"
50 #include "network.h"
51 #include "version.h"
52
53 #include "defs.h"
54
55 bool collection_exchange_list(int, struct collection *);
56 bool collection_exchange_rcs(int, struct collection *);
57
58 bool
protocol_exchange(int sock,struct config * cf)59 protocol_exchange(int sock, struct config *cf)
60 {
61 uint8_t cmd[CVSYNC_MAXCMDLEN], mn;
62 size_t len;
63
64 SetWord(cmd, 2);
65 cmd[2] = CVSYNC_PROTO_MAJOR;
66 cmd[3] = CVSYNC_PROTO_MINOR;
67 if (!sock_send(sock, cmd, 4)) {
68 logmsg_err("Send: protocol version");
69 return (false);
70 }
71
72 if (!sock_recv(sock, cmd, 2)) {
73 logmsg_err("Recv: protocol version length");
74 return (false);
75 }
76 if ((len = GetWord(cmd)) != 2) {
77 logmsg_err("Recv: protocol version: invalid length: %u", len);
78 return (false);
79 }
80 if (!sock_recv(sock, cmd, len)) {
81 logmsg_err("Recv: protocol version");
82 return (false);
83 }
84
85 if (cmd[0] == CVSYNC_PROTO_ERROR) {
86 switch (cmd[1]) {
87 case CVSYNC_ERROR_DENIED:
88 logmsg_err("Access denied");
89 break;
90 case CVSYNC_ERROR_LIMITED:
91 logmsg_err("Access limited");
92 break;
93 case CVSYNC_ERROR_UNAVAIL:
94 logmsg_err("Service unavailable");
95 break;
96 case CVSYNC_ERROR_UNSPEC:
97 default:
98 logmsg_err("Your software seems to be old.\n"
99 "Please upgrade to the newer version.\n"
100 "URL: %s", CVSYNC_URL);
101 break;
102 }
103 SetWord(cmd, 2);
104 cmd[2] = CVSYNC_PROTO_ERROR;
105 cmd[3] = CVSYNC_ERROR_UNSPEC;
106 sock_send(sock, cmd, 4);
107 return (false);
108 }
109
110 if (cmd[0] != CVSYNC_PROTO_MAJOR) {
111 logmsg_err("The server(%u.%u) seems to be too old.", cmd[0],
112 cmd[1]);
113 SetWord(cmd, 2);
114 cmd[2] = CVSYNC_PROTO_ERROR;
115 cmd[3] = CVSYNC_ERROR_UNSPEC;
116 sock_send(sock, cmd, 4);
117 return (false);
118 }
119
120 if ((cmd[0] == 0) && (cmd[1] < 20)) {
121 logmsg_err("The server (%u.%u) seems to be old.", cmd[0],
122 cmd[1]);
123 SetWord(cmd, 2);
124 cmd[2] = CVSYNC_PROTO_ERROR;
125 cmd[3] = CVSYNC_ERROR_UNSPEC;
126 sock_send(sock, cmd, 4);
127 return (false);
128 }
129
130 if ((cmd[0] == 0) && (cmd[1] < CVSYNC_PROTO_MINOR))
131 mn = cmd[1];
132 else
133 mn = CVSYNC_PROTO_MINOR;
134
135 SetWord(cmd, 2);
136 cmd[2] = CVSYNC_PROTO_MAJOR;
137 cmd[3] = mn;
138 if (!sock_send(sock, cmd, 4)) {
139 logmsg_err("Send: protocol version: %u.%u", CVSYNC_PROTO_MAJOR,
140 mn);
141 return (false);
142 }
143
144 cf->cf_proto = CVSYNC_PROTO(CVSYNC_PROTO_MAJOR, mn);
145
146 logmsg_verbose("Protocol: %u.%u", cmd[2], cmd[3]);
147
148 return (true);
149 }
150
151 bool
hash_exchange(int sock,struct config * cf)152 hash_exchange(int sock, struct config *cf)
153 {
154 uint8_t cmd[CVSYNC_MAXCMDLEN];
155 char name[CVSYNC_NAME_MAX + 1];
156 size_t len;
157
158 if ((len = hash_ntop(cf->cf_hash, name, sizeof(name))) == 0)
159 return (false);
160
161 SetWord(cmd, len);
162 if (!sock_send(sock, cmd, 2)) {
163 logmsg_err("Send: hash type");
164 return (false);
165 }
166 if (!sock_send(sock, name, len)) {
167 logmsg_err("Send: hash type");
168 return (false);
169 }
170
171 if (!sock_recv(sock, cmd, 2)) {
172 logmsg_err("Recv: hash type length");
173 return (false);
174 }
175 len = GetWord(cmd);
176 if ((len == 0) || (len >= sizeof(name))) {
177 logmsg_err("Recv: hash type: invaild length: %u", len);
178 return (false);
179 }
180 if (!sock_recv(sock, name, len)) {
181 logmsg_err("Recv: hash type");
182 return (false);
183 }
184
185 if ((cf->cf_hash = hash_pton(name, len)) == HASH_UNSPEC) {
186 logmsg_err("Unknwon hash type: %.*s", len, name);
187 return (false);
188 }
189
190 logmsg_verbose("Hash: %.*s", len, name);
191
192 return (true);
193 }
194
195 bool
collectionlist_exchange(int sock,struct config * cf)196 collectionlist_exchange(int sock, struct config *cf)
197 {
198 struct collection *cl;
199 uint8_t cmd[CVSYNC_MAXCMDLEN];
200 size_t len;
201 int enabled;
202
203 logmsg_verbose("Exchanging collection list...");
204
205 enabled = 0;
206 for (cl = cf->cf_collections ; cl != NULL ; cl = cl->cl_next) {
207 switch (cvsync_release_pton(cl->cl_release)) {
208 case CVSYNC_RELEASE_LIST:
209 if (!collection_exchange_list(sock, cl))
210 return (false);
211 break;
212 case CVSYNC_RELEASE_RCS:
213 if (!collection_exchange_rcs(sock, cl))
214 return (false);
215 break;
216 default:
217 return (false);
218 }
219
220 if (!(cl->cl_flags & CLFLAGS_DISABLE))
221 enabled++;
222 }
223
224 SetWord(cmd, 4);
225 cmd[2] = 1;
226 cmd[3] = 1;
227 cmd[4] = '.';
228 cmd[5] = '.';
229 if (!sock_send(sock, cmd, 6))
230 return (false);
231
232 if (!sock_recv(sock, cmd, 2))
233 return (false);
234 if ((len = GetWord(cmd)) != 4)
235 return (false);
236 if (!sock_recv(sock, cmd, len))
237 return (false);
238 if ((cmd[0] != 1) || (cmd[1] != 1) ||
239 (cmd[2] != '.') || (cmd[3] != '.')) {
240 return (false);
241 }
242
243 if (!collection_resolv_prefix(cf->cf_collections))
244 return (false);
245
246 if (enabled == 0) {
247 logmsg_err("No collections is available");
248 return (false);
249 }
250
251 return (true);
252 }
253
254 bool
collection_exchange_list(int sock,struct collection * cl)255 collection_exchange_list(int sock, struct collection *cl)
256 {
257 uint8_t cmd[CVSYNC_MAXCMDLEN];
258 size_t namelen, relnamelen, len;
259
260 if ((namelen = strlen(cl->cl_name)) >= sizeof(cl->cl_name))
261 return (false);
262 if ((relnamelen = strlen(cl->cl_release)) >= sizeof(cl->cl_release))
263 return (false);
264 if ((len = namelen + relnamelen + 4) >= sizeof(cmd))
265 return (false);
266
267 SetWord(cmd, len - 2);
268 cmd[2] = namelen;
269 cmd[3] = relnamelen;
270 if (!sock_send(sock, cmd, 4))
271 return (false);
272 if (!sock_send(sock, cl->cl_name, namelen))
273 return (false);
274 if (!sock_send(sock, cl->cl_release, relnamelen))
275 return (false);
276
277 if (!sock_recv(sock, cmd, 2))
278 return (false);
279 if ((len = GetWord(cmd)) > sizeof(cmd) - 2)
280 return (false);
281 if (len == 0) {
282 logmsg("Not found such a collection %s/%s", cl->cl_name,
283 cl->cl_release);
284 cl->cl_flags |= CLFLAGS_DISABLE;
285 return (true);
286 }
287 if (len != namelen + relnamelen + 2)
288 return (false);
289
290 if (!sock_recv(sock, cmd, len))
291 return (false);
292
293 if ((cmd[0] != namelen) || (cmd[1] != relnamelen)) {
294 logmsg_err("Not match name/release length");
295 return (false);
296 }
297 if ((memcmp(&cmd[2], cl->cl_name, namelen) != 0) ||
298 (memcmp(&cmd[namelen + 2], cl->cl_release, relnamelen) != 0)) {
299 logmsg_err("Not match collection name/release");
300 return (false);
301 }
302
303 logmsg_verbose(" collection name \"%s\" release \"%s\"",
304 cl->cl_name, cl->cl_release);
305
306 return (true);
307 }
308
309 bool
collection_exchange_rcs(int sock,struct collection * cl)310 collection_exchange_rcs(int sock, struct collection *cl)
311 {
312 uint8_t cmd[CVSYNC_MAXCMDLEN];
313 size_t namelen, relnamelen, len;
314
315 if ((namelen = strlen(cl->cl_name)) >= sizeof(cl->cl_name))
316 return (false);
317 if ((relnamelen = strlen(cl->cl_release)) >= sizeof(cl->cl_release))
318 return (false);
319 if ((len = namelen + relnamelen + 6) >= sizeof(cmd))
320 return (false);
321
322 SetWord(cmd, len - 2);
323 cmd[2] = namelen;
324 cmd[3] = relnamelen;
325 if (!sock_send(sock, cmd, 4))
326 return (false);
327 if (!sock_send(sock, cl->cl_name, namelen))
328 return (false);
329 if (!sock_send(sock, cl->cl_release, relnamelen))
330 return (false);
331
332 SetWord(cmd, cl->cl_umask);
333 if (!sock_send(sock, cmd, 2))
334 return (false);
335
336 if (!sock_recv(sock, cmd, 2))
337 return (false);
338 if ((len = GetWord(cmd)) > sizeof(cmd) - 2)
339 return (false);
340 if (len == 0) {
341 logmsg("Not found such a collection %s/%s", cl->cl_name,
342 cl->cl_release);
343 cl->cl_flags |= CLFLAGS_DISABLE;
344 return (true);
345 }
346
347 if (len < namelen + relnamelen + 4)
348 return (false);
349
350 if (!sock_recv(sock, cmd, len))
351 return (false);
352
353 if ((cmd[0] != namelen) || (cmd[1] != relnamelen)) {
354 logmsg_err("Not match name/release length");
355 return (false);
356 }
357 if ((memcmp(&cmd[2], cl->cl_name, namelen) != 0) ||
358 (memcmp(&cmd[namelen + 2], cl->cl_release, relnamelen) != 0)) {
359 logmsg_err("Not match collection name/release");
360 return (false);
361 }
362
363 cl->cl_umask = GetWord(&cmd[namelen + relnamelen + 2]);
364 if (cl->cl_umask & ~CVSYNC_ALLPERMS)
365 return (false);
366
367 cl->cl_rprefixlen = len - namelen - relnamelen - 4;
368 if (cl->cl_rprefixlen > sizeof(cl->cl_rprefix))
369 return (false);
370 (void)memcpy(cl->cl_rprefix, &cmd[namelen + relnamelen + 4],
371 cl->cl_rprefixlen);
372 cl->cl_rprefix[cl->cl_rprefixlen] = '/';
373
374 logmsg_verbose(" collection name \"%s\" release \"%s\" umask %03o",
375 cl->cl_name, cl->cl_release, cl->cl_umask);
376
377 return (true);
378 }
379
380 bool
compress_exchange(int sock,struct config * cf)381 compress_exchange(int sock, struct config *cf)
382 {
383 const char *name;
384 uint8_t cmd[CVSYNC_MAXCMDLEN];
385 size_t len;
386
387 if (cf->cf_proto < CVSYNC_PROTO(0, 22)) {
388 cf->cf_compress = CVSYNC_COMPRESS_NO;
389 cf->cf_mss = MUX_MAX_MSS;
390 return (true);
391 }
392
393 if (cf->cf_proto == CVSYNC_PROTO(0, 22))
394 cf->cf_compress = CVSYNC_COMPRESS_NO;
395
396 name = cvsync_compress_ntop(cf->cf_compress);
397
398 len = strlen(name);
399 SetWord(cmd, len);
400 if (!sock_send(sock, cmd, 2))
401 return (false);
402 if (!sock_send(sock, name, len))
403 return (false);
404
405 if (!sock_recv(sock, cmd, 2))
406 return (false);
407 len = GetWord(cmd);
408 if ((len == 0) || (len >= sizeof(cmd)))
409 return (false);
410 if (!sock_recv(sock, cmd, len))
411 return (false);
412 cmd[len] = '\0';
413
414 cf->cf_compress = cvsync_compress_pton((const char *)cmd);
415 if (cf->cf_compress == CVSYNC_COMPRESS_UNSPEC) {
416 logmsg_err("Unsupported compression type: %s", name);
417 return (false);
418 }
419
420 name = cvsync_compress_ntop(cf->cf_compress);
421 len = strlen(name);
422 SetWord(cmd, len);
423 if (!sock_send(sock, cmd, 2))
424 return (false);
425 if (!sock_send(sock, name, len))
426 return (false);
427
428 if ((cf->cf_proto > CVSYNC_PROTO(0, 22)) &&
429 (cf->cf_compress != CVSYNC_COMPRESS_NO)) {
430 cf->cf_mss = MUX_MAX_MSS_ZLIB;
431 } else {
432 cf->cf_mss = MUX_DEFAULT_MSS;
433 }
434
435 logmsg_verbose("Compression: %s", name);
436
437 return (true);
438 }
439
440 struct mux *
channel_establish(int sock,struct config * cf)441 channel_establish(int sock, struct config *cf)
442 {
443 struct mux *mx;
444 struct muxbuf *mxb;
445 uint8_t cmd[CVSYNC_MAXCMDLEN];
446 size_t len;
447 int i;
448
449 logmsg_verbose("Trying to establish the multiplexed channel...");
450
451 if ((mx = mux_init(sock, cf->cf_mss, cf->cf_compress,
452 CVSYNC_COMPRESS_LEVEL_BEST)) == NULL) {
453 return (NULL);
454 }
455
456 for (i = 0 ; i < MUX_MAXCHANNELS ; i++) {
457 mxb = &mx->mx_buffer[MUX_IN][i];
458
459 SetWord(cmd, 7);
460 cmd[2] = i;
461 SetWord(&cmd[3], mxb->mxb_mss);
462 SetDWord(&cmd[5], mxb->mxb_bufsize);
463 if (!sock_send(sock, cmd, 9)) {
464 mux_destroy(mx);
465 return (NULL);
466 }
467
468 if (!sock_recv(sock, cmd, 2)) {
469 mux_destroy(mx);
470 return (NULL);
471 }
472 if ((len = GetWord(cmd)) != 7) {
473 mux_destroy(mx);
474 return (NULL);
475 }
476 if (!sock_recv(sock, cmd, len)) {
477 mux_destroy(mx);
478 return (NULL);
479 }
480 if (cmd[0] != i) {
481 mux_destroy(mx);
482 return (NULL);
483 }
484
485 mxb = &mx->mx_buffer[MUX_OUT][i];
486
487 if (!muxbuf_init(mxb, GetWord(&cmd[1]), GetDWord(&cmd[3]),
488 cf->cf_compress)) {
489 mux_destroy(mx);
490 return (NULL);
491 }
492 }
493
494 return (mx);
495 }
496