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