Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cmd.h"
6 : #include "../conf.h"
7 : #include "../conffile.h"
8 : #include "../fsops.h"
9 : #include "../handy.h"
10 : #include "../incexc_recv.h"
11 : #include "../incexc_send.h"
12 : #include "../iobuf.h"
13 : #include "../log.h"
14 : #include "../prepend.h"
15 : #include "autoupgrade.h"
16 : #include "extra_comms.h"
17 :
18 : #include <librsync.h>
19 :
20 279 : static int append_to_feat(char **feat, const char *str)
21 : {
22 279 : char *tmp=NULL;
23 279 : if(!*feat)
24 : {
25 35 : if(!(*feat=strdup_w(str, __func__)))
26 : return -1;
27 35 : return 0;
28 : }
29 244 : if(!(tmp=prepend(*feat, str)))
30 : return -1;
31 244 : free_w(feat);
32 244 : *feat=tmp;
33 244 : return 0;
34 : }
35 :
36 : // It is unfortunate that we are having to figure out the server-initiated
37 : // restore paths here instead of setting it in a struct sdirs.
38 : // But doing the extra_comms needs to come before setting the sdirs, because
39 : // extra_comms sets up a bunch of settings that sdirs need to know.
40 35 : static char *get_restorepath_proto1(struct conf **cconfs)
41 : {
42 35 : char *tmp=NULL;
43 35 : char *restorepath=NULL;
44 35 : if((tmp=prepend_s(get_string(cconfs[OPT_DIRECTORY]),
45 35 : get_string(cconfs[OPT_CNAME]))))
46 35 : restorepath=prepend_s(tmp, "restore");
47 35 : free_w(&tmp);
48 35 : return restorepath;
49 : }
50 :
51 35 : static char *get_restorepath_proto2(struct conf **cconfs)
52 : {
53 35 : char *tmp1=NULL;
54 35 : char *tmp2=NULL;
55 35 : char *restorepath=NULL;
56 35 : if(!(tmp1=prepend_s(get_string(cconfs[OPT_DIRECTORY]),
57 35 : get_string(cconfs[OPT_DEDUP_GROUP]))))
58 : goto error;
59 35 : if(!(tmp2=prepend_s(tmp1, "clients")))
60 : goto error;
61 35 : free_w(&tmp1);
62 35 : if(!(tmp1=prepend_s(tmp2, get_string(cconfs[OPT_CNAME]))))
63 : goto error;
64 35 : if(!(restorepath=prepend_s(tmp1, "restore")))
65 : goto error;
66 : goto end;
67 : error:
68 0 : free_w(&restorepath);
69 : end:
70 35 : free_w(&tmp1);
71 35 : free_w(&tmp2);
72 35 : return restorepath;
73 : }
74 :
75 35 : static int set_restore_path(struct conf **cconfs, char **feat)
76 : {
77 35 : int ret=-1;
78 35 : char *restorepath1=NULL;
79 35 : char *restorepath2=NULL;
80 35 : if(!(restorepath1=get_restorepath_proto1(cconfs))
81 35 : || !(restorepath2=get_restorepath_proto2(cconfs)))
82 : goto end;
83 35 : if(is_reg_lstat(restorepath1)==1
84 4 : && set_string(cconfs[OPT_RESTORE_PATH], restorepath1))
85 : goto end;
86 35 : else if(is_reg_lstat(restorepath2)==1
87 0 : && set_string(cconfs[OPT_RESTORE_PATH], restorepath2))
88 : goto end;
89 35 : if(get_string(cconfs[OPT_RESTORE_PATH])
90 4 : && append_to_feat(feat, "srestore:"))
91 : goto end;
92 : ret=0;
93 : end:
94 35 : free_w(&restorepath1);
95 35 : free_w(&restorepath2);
96 35 : return ret;
97 : }
98 :
99 : struct vers
100 : {
101 : long min;
102 : long cli;
103 : long ser;
104 : long feat_list;
105 : long directory_tree;
106 : long burp2;
107 : long counters_json;
108 : };
109 :
110 35 : static int send_features(struct asfd *asfd, struct conf **cconfs,
111 : struct vers *vers)
112 : {
113 35 : int ret=-1;
114 35 : char *feat=NULL;
115 35 : enum protocol protocol=get_protocol(cconfs);
116 35 : struct strlist *startdir=get_strlist(cconfs[OPT_STARTDIR]);
117 35 : struct strlist *incglob=get_strlist(cconfs[OPT_INCGLOB]);
118 :
119 35 : if(append_to_feat(&feat, "extra_comms_begin ok:")
120 : /* clients can autoupgrade */
121 35 : || append_to_feat(&feat, "autoupgrade:")
122 : /* clients can give server incexc conf so that the
123 : server knows better what to do on resume */
124 35 : || append_to_feat(&feat, "incexc:")
125 : /* clients can give the server an alternative client
126 : to restore from */
127 35 : || append_to_feat(&feat, "orig_client:")
128 : /* clients can tell the server what kind of system they are. */
129 35 : || append_to_feat(&feat, "uname:"))
130 : goto end;
131 :
132 : /* Clients can receive restore initiated from the server. */
133 35 : if(set_restore_path(cconfs, &feat))
134 : goto end;
135 :
136 : /* Clients can receive incexc conf from the server.
137 : Only give it as an option if the server has some starting
138 : directory configured in the clientconfdir. */
139 35 : if((startdir || incglob)
140 0 : && append_to_feat(&feat, "sincexc:"))
141 : goto end;
142 :
143 35 : if(vers->cli>=vers->counters_json)
144 : {
145 : /* Clients can be sent cntrs on resume/verify/restore. */
146 30 : if(append_to_feat(&feat, "counters_json:"))
147 : goto end;
148 : }
149 :
150 : // We support CMD_MESSAGE.
151 35 : if(append_to_feat(&feat, "msg:"))
152 : goto end;
153 :
154 35 : if(protocol==PROTO_AUTO)
155 : {
156 : /* If the server is configured to use either protocol, let the
157 : client know that it can choose. */
158 25 : logp("Server is using protocol=0 (auto)\n");
159 25 : if(append_to_feat(&feat, "csetproto:"))
160 : goto end;
161 : }
162 : else
163 : {
164 10 : char p[32]="";
165 : /* Tell the client what we are going to use. */
166 10 : logp("Server is using protocol=%d\n", (int)protocol);
167 10 : snprintf(p, sizeof(p), "forceproto=%d:", (int)protocol);
168 10 : if(append_to_feat(&feat, p))
169 : goto end;
170 : }
171 :
172 : #ifndef RS_DEFAULT_STRONG_LEN
173 : if(append_to_feat(&feat, "rshash=blake2:"))
174 : goto end;
175 : #endif
176 :
177 : //printf("feat: %s\n", feat);
178 :
179 35 : if(asfd->write_str(asfd, CMD_GEN, feat))
180 : {
181 1 : logp("problem in extra_comms\n");
182 : goto end;
183 : }
184 :
185 : ret=0;
186 : end:
187 35 : free_w(&feat);
188 35 : return ret;
189 : }
190 :
191 34 : static int extra_comms_read(struct async *as,
192 : struct vers *vers, int *srestore,
193 : char **incexc, struct conf **globalcs, struct conf **cconfs)
194 : {
195 34 : int ret=-1;
196 : struct asfd *asfd;
197 : struct iobuf *rbuf;
198 34 : asfd=as->asfd;
199 34 : rbuf=asfd->rbuf;
200 :
201 : while(1)
202 : {
203 52 : iobuf_free_content(rbuf);
204 52 : if(asfd->read(asfd)) goto end;
205 :
206 52 : if(rbuf->cmd!=CMD_GEN)
207 : {
208 1 : iobuf_log_unexpected(rbuf, __func__);
209 : goto end;
210 : }
211 :
212 51 : if(!strcmp(rbuf->buf, "extra_comms_end"))
213 : {
214 22 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok"))
215 : goto end;
216 : break;
217 : }
218 29 : else if(!strncmp_w(rbuf->buf, "autoupgrade:"))
219 : {
220 2 : char *os=NULL;
221 2 : const char *autoupgrade_dir=
222 2 : get_string(globalcs[OPT_AUTOUPGRADE_DIR]);
223 2 : os=rbuf->buf+strlen("autoupgrade:");
224 2 : iobuf_free_content(rbuf);
225 2 : if(os && *os && autoupgrade_server(as, vers->ser,
226 : vers->cli, os, get_cntr(globalcs),
227 : autoupgrade_dir))
228 : goto end;
229 : }
230 27 : else if(!strcmp(rbuf->buf, "srestore ok"))
231 : {
232 4 : char *restore_path=get_string(cconfs[OPT_RESTORE_PATH]);
233 4 : if(!restore_path)
234 : {
235 0 : logp("got srestore ok without a restore_path");
236 : goto end;
237 : }
238 :
239 4 : iobuf_free_content(rbuf);
240 : // Client can accept the restore.
241 : // Load the restore config, then send it.
242 4 : *srestore=1;
243 4 : if(conf_parse_incexcs_path(cconfs, restore_path)
244 4 : || incexc_send_server_restore(asfd, cconfs))
245 : goto end;
246 : // Do not unlink it here - wait until
247 : // the client says that it wants to do the
248 : // restore.
249 : // Also need to leave it around if the
250 : // restore is to an alternative client, so
251 : // that the code below that reloads the config
252 : // can read it again.
253 : //unlink(get_string(cconfs[OPT_RESTORE_PATH]));
254 : }
255 23 : else if(!strcmp(rbuf->buf, "srestore not ok"))
256 : {
257 1 : const char *restore_path=get_string(
258 : cconfs[OPT_RESTORE_PATH]);
259 : // Client will not accept the restore.
260 1 : unlink(restore_path);
261 1 : if(set_string(cconfs[OPT_RESTORE_PATH], NULL))
262 : goto end;
263 1 : logp("Client not accepting server initiated restore.\n");
264 : }
265 22 : else if(!strcmp(rbuf->buf, "sincexc ok"))
266 : {
267 : // Client can accept incexc conf from the
268 : // server.
269 1 : iobuf_free_content(rbuf);
270 1 : if(incexc_send_server(asfd, cconfs))
271 : goto end;
272 : }
273 21 : else if(!strcmp(rbuf->buf, "incexc"))
274 : {
275 : // Client is telling server its incexc
276 : // configuration so that it can better decide
277 : // what to do on resume.
278 1 : iobuf_free_content(rbuf);
279 1 : if(incexc_recv_server(asfd, incexc, globalcs))
280 : goto end;
281 1 : if(*incexc)
282 : {
283 1 : char *tmp=NULL;
284 1 : char comp[32]="";
285 1 : snprintf(comp, sizeof(comp),
286 : "compression = %d\n",
287 : get_int(cconfs[OPT_COMPRESSION]));
288 1 : if(!(tmp=prepend(*incexc, comp)))
289 : goto end;
290 1 : free_w(incexc);
291 1 : *incexc=tmp;
292 : }
293 : }
294 20 : else if(!strcmp(rbuf->buf, "counters_json ok"))
295 : {
296 : // Client can accept counters on
297 : // resume/verify/restore.
298 1 : logp("Client supports being sent json counters.\n");
299 1 : set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1);
300 : }
301 19 : else if(!strncmp_w(rbuf->buf, "uname=")
302 2 : && strlen(rbuf->buf)>strlen("uname="))
303 : {
304 2 : char *uname=rbuf->buf+strlen("uname=");
305 2 : if(!strncasecmp("Windows", uname, strlen("Windows")))
306 1 : set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1);
307 : }
308 17 : else if(!strncmp_w(rbuf->buf, "orig_client=")
309 3 : && strlen(rbuf->buf)>strlen("orig_client="))
310 : {
311 3 : if(conf_switch_to_orig_client(globalcs, cconfs,
312 : rbuf->buf+strlen("orig_client=")))
313 : goto end;
314 : // If this started out as a server-initiated
315 : // restore, need to load the restore file
316 : // again.
317 2 : if(*srestore)
318 : {
319 1 : if(conf_parse_incexcs_path(cconfs,
320 1 : get_string(cconfs[OPT_RESTORE_PATH])))
321 : goto end;
322 : }
323 2 : if(asfd->write_str(asfd, CMD_GEN, "orig_client ok"))
324 : goto end;
325 : }
326 14 : else if(!strncmp_w(rbuf->buf, "restore_spool="))
327 : {
328 : // Removed.
329 : }
330 14 : else if(!strncmp_w(rbuf->buf, "protocol="))
331 : {
332 11 : char msg[128]="";
333 : // Client wants to set protocol.
334 11 : enum protocol protocol=get_protocol(cconfs);
335 11 : const char *cliproto=rbuf->buf+strlen("protocol=");
336 11 : if(protocol!=PROTO_AUTO)
337 : {
338 : snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s but server is set to protocol=%d\n", cliproto, protocol);
339 6 : log_and_send(asfd, msg);
340 7 : goto end;
341 : }
342 5 : else if(!strcmp(cliproto, "1"))
343 : {
344 2 : set_protocol(cconfs, PROTO_1);
345 2 : set_protocol(globalcs, PROTO_1);
346 : }
347 3 : else if(!strcmp(cliproto, "2"))
348 : {
349 2 : set_protocol(cconfs, PROTO_2);
350 2 : set_protocol(globalcs, PROTO_2);
351 : }
352 : else
353 : {
354 : snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s, which is unknown\n", cliproto);
355 1 : log_and_send(asfd, msg);
356 : goto end;
357 : }
358 4 : logp("Client has set protocol=%d\n",
359 4 : (int)get_protocol(cconfs));
360 : }
361 3 : else if(!strncmp_w(rbuf->buf, "rshash=blake2"))
362 : {
363 : #ifdef RS_DEFAULT_STRONG_LEN
364 1 : logp("Client is trying to use librsync hash blake2, but server does not support it.\n");
365 : goto end;
366 : #else
367 : set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2);
368 : set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2);
369 : #endif
370 : }
371 2 : else if(!strncmp_w(rbuf->buf, "msg"))
372 : {
373 1 : set_int(cconfs[OPT_MESSAGE], 1);
374 1 : set_int(globalcs[OPT_MESSAGE], 1);
375 : }
376 : else
377 : {
378 1 : iobuf_log_unexpected(rbuf, __func__);
379 : goto end;
380 : }
381 : }
382 :
383 22 : ret=0;
384 : end:
385 34 : iobuf_free_content(rbuf);
386 34 : return ret;
387 : }
388 :
389 39 : static int vers_init(struct vers *vers, struct conf **cconfs)
390 : {
391 : memset(vers, 0, sizeof(struct vers));
392 78 : return ((vers->min=version_to_long("1.2.7"))<0
393 39 : || (vers->cli=version_to_long(get_string(cconfs[OPT_PEER_VERSION])))<0
394 39 : || (vers->ser=version_to_long(VERSION))<0
395 39 : || (vers->feat_list=version_to_long("1.3.0"))<0
396 39 : || (vers->directory_tree=version_to_long("1.3.6"))<0
397 39 : || (vers->burp2=version_to_long("2.0.0"))<0
398 78 : || (vers->counters_json=version_to_long("2.0.46"))<0);
399 : }
400 :
401 39 : int extra_comms(struct async *as,
402 : char **incexc, int *srestore, struct conf **confs, struct conf **cconfs)
403 : {
404 : struct vers vers;
405 : struct asfd *asfd;
406 39 : asfd=as->asfd;
407 : //char *restorepath=NULL;
408 39 : const char *peer_version=NULL;
409 :
410 39 : if(vers_init(&vers, cconfs))
411 : goto error;
412 :
413 39 : if(vers.cli<vers.directory_tree)
414 : {
415 3 : set_int(confs[OPT_DIRECTORY_TREE], 0);
416 3 : set_int(cconfs[OPT_DIRECTORY_TREE], 0);
417 : }
418 :
419 : // Clients before 1.2.7 did not know how to do extra comms, so skip
420 : // this section for them.
421 39 : if(vers.cli<vers.min)
422 : return 0;
423 :
424 37 : if(asfd_read_expect(asfd, CMD_GEN, "extra_comms_begin"))
425 : {
426 1 : logp("problem reading in extra_comms\n");
427 1 : goto error;
428 : }
429 : // Want to tell the clients the extra comms features that are
430 : // supported, so that new clients are more likely to work with old
431 : // servers.
432 36 : if(vers.cli==vers.feat_list)
433 : {
434 : // 1.3.0 did not support the feature list.
435 1 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin ok"))
436 : {
437 1 : logp("problem writing in extra_comms\n");
438 1 : goto error;
439 : }
440 : }
441 : else
442 : {
443 35 : if(send_features(asfd, cconfs, &vers))
444 : goto error;
445 : }
446 :
447 34 : if(extra_comms_read(as, &vers, srestore, incexc, confs, cconfs))
448 : goto error;
449 :
450 22 : peer_version=get_string(cconfs[OPT_PEER_VERSION]);
451 :
452 : // This needs to come after extra_comms_read, as the client might
453 : // have set PROTO_1 or PROTO_2.
454 22 : switch(get_protocol(cconfs))
455 : {
456 : case PROTO_AUTO:
457 : // The protocol has not been specified. Make a choice.
458 14 : if(vers.cli<vers.burp2)
459 : {
460 : // Client is burp-1.x.x, use protocol1.
461 1 : set_protocol(confs, PROTO_1);
462 1 : set_protocol(cconfs, PROTO_1);
463 1 : logp("Client is burp-%s - using protocol=%d\n",
464 : peer_version, PROTO_1);
465 : }
466 : else
467 : {
468 : // Client is burp-2.x.x, use protocol2.
469 : // This will probably never be reached because
470 : // the negotiation will take care of it.
471 : /*
472 : set_protocol(confs, PROTO_2);
473 : set_protocol(cconfs, PROTO_2);
474 : logp("Client is burp-%s - using protocol=%d\n",
475 : peer_version, PROTO_2);
476 : */
477 : // PROTO_1 is safer for now.
478 13 : set_protocol(confs, PROTO_1);
479 13 : set_protocol(cconfs, PROTO_1);
480 13 : logp("Client is burp-%s - using protocol=%d\n",
481 : peer_version, PROTO_1);
482 : }
483 : break;
484 : case PROTO_1:
485 : // It is OK for the client to be burp1 and for the
486 : // server to be forced to protocol1.
487 : break;
488 : case PROTO_2:
489 4 : if(vers.cli>=vers.burp2)
490 : break;
491 2 : logp("protocol=%d is set server side, "
492 : "but client is burp version %s\n",
493 : PROTO_2, peer_version);
494 2 : goto error;
495 : }
496 :
497 20 : if(get_protocol(cconfs)==PROTO_1)
498 : {
499 18 : if(get_e_rshash(cconfs[OPT_RSHASH])==RSHASH_UNSET)
500 : {
501 18 : set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4);
502 18 : set_e_rshash(cconfs[OPT_RSHASH], RSHASH_MD4);
503 : }
504 : }
505 :
506 : return 0;
507 : error:
508 : return -1;
509 : }
|