Line data Source code
1 : #include "../burp.h"
2 : #include "../asfd.h"
3 : #include "../async.h"
4 : #include "../cmd.h"
5 : #include "../conf.h"
6 : #include "../conffile.h"
7 : #include "../handy.h"
8 : #include "../incexc_recv.h"
9 : #include "../incexc_send.h"
10 : #include "../iobuf.h"
11 : #include "../log.h"
12 : #include "autoupgrade.h"
13 : #include "extra_comms.h"
14 :
15 : #ifndef HAVE_WIN32
16 : #include <sys/utsname.h>
17 : #endif
18 :
19 : static const char *server_supports(const char *feat, const char *wanted)
20 : {
21 236 : return strstr(feat, wanted);
22 : }
23 :
24 25 : static const char *server_supports_autoupgrade(const char *feat)
25 : {
26 : // 1.3.0 servers did not list the features, but the only feature
27 : // that was supported was autoupgrade.
28 25 : if(!strcmp(feat, "extra_comms_begin ok")) return "ok";
29 25 : return server_supports(feat, ":autoupgrade:");
30 : }
31 :
32 : #include <librsync.h>
33 :
34 28 : int extra_comms_client(struct async *as, struct conf **confs,
35 : enum action *action, struct strlist *failover, char **incexc)
36 : {
37 28 : int ret=-1;
38 28 : char *feat=NULL;
39 28 : char *seed_src=NULL;
40 28 : char *seed_dst=NULL;
41 : struct asfd *asfd;
42 : struct iobuf *rbuf;
43 28 : const char *orig_client=NULL;
44 28 : asfd=as->asfd;
45 28 : rbuf=asfd->rbuf;
46 :
47 28 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin"))
48 : {
49 1 : logp("Problem requesting extra_comms_begin\n");
50 1 : goto end;
51 : }
52 : // Servers greater than 1.3.0 will list the extra_comms
53 : // features they support.
54 27 : if(asfd->read(asfd))
55 : {
56 1 : logp("Problem reading response to extra_comms_begin\n");
57 1 : goto end;
58 : }
59 26 : if(rbuf->cmd!=CMD_GEN
60 26 : || strncmp_w(rbuf->buf, "extra_comms_begin ok"))
61 : {
62 1 : iobuf_log_unexpected(rbuf, __func__);
63 1 : goto end;
64 : }
65 25 : feat=rbuf->buf;
66 25 : rbuf->buf=NULL;
67 25 : logp("%s\n", feat);
68 25 : iobuf_init(rbuf);
69 :
70 : // Can add extra bits here. The first extra bit is the
71 : // autoupgrade stuff.
72 25 : if(server_supports_autoupgrade(feat)
73 1 : && get_string(confs[OPT_AUTOUPGRADE_DIR])
74 1 : && get_string(confs[OPT_AUTOUPGRADE_OS])
75 1 : && autoupgrade_client(as, confs))
76 : goto end;
77 :
78 :
79 : // :srestore: means that the server wants to do a restore.
80 48 : if(server_supports(feat, ":srestore:"))
81 : {
82 6 : logp("Server wants to initiate a restore\n");
83 6 : if(*action==ACTION_MONITOR)
84 : {
85 1 : logp("Client is in monitor mode, so ignoring\n");
86 : }
87 5 : else if(get_int(confs[OPT_SERVER_CAN_RESTORE]))
88 : {
89 4 : logp("Client accepts.\n");
90 4 : if(incexc_recv_client_restore(asfd, incexc, confs))
91 : goto end;
92 4 : if(*incexc)
93 : {
94 4 : if(conf_parse_incexcs_srestore(confs, *incexc))
95 : goto end;
96 2 : *action=ACTION_RESTORE;
97 2 : log_restore_settings(confs, 1);
98 : }
99 : }
100 : else
101 : {
102 1 : logp("Client configuration says no\n");
103 1 : if(asfd->write_str(asfd, CMD_GEN, "srestore not ok"))
104 : goto end;
105 : }
106 : }
107 :
108 : // Needs to be after the srestore stuff, as the server may set
109 : // orig_client in the server-initiated restore file.
110 22 : if((orig_client=get_string(confs[OPT_ORIG_CLIENT])))
111 : {
112 4 : char str[512]="";
113 4 : snprintf(str, sizeof(str), "orig_client=%s", orig_client);
114 8 : if(!server_supports(feat, ":orig_client:"))
115 : {
116 1 : logp("Server does not support switching client.\n");
117 1 : goto end;
118 : }
119 3 : if(asfd->write_str(asfd, CMD_GEN, str)
120 3 : || asfd_read_expect(asfd, CMD_GEN, "orig_client ok"))
121 : {
122 1 : logp("Problem requesting %s\n", str);
123 1 : goto end;
124 : }
125 2 : logp("Switched to client %s\n", orig_client);
126 : }
127 :
128 : // :sincexc: is for the server giving the client the
129 : // incexc config.
130 40 : if(*action==ACTION_BACKUP
131 20 : || *action==ACTION_BACKUP_TIMED
132 3 : || *action==ACTION_TIMER_CHECK)
133 : {
134 34 : if(!*incexc && server_supports(feat, ":sincexc:"))
135 : {
136 2 : logp("Server is setting includes/excludes.\n");
137 2 : if(get_int(confs[OPT_SERVER_CAN_OVERRIDE_INCLUDES]))
138 : {
139 1 : logp("Client accepts.\n");
140 1 : if(incexc_recv_client(asfd, incexc, confs))
141 : goto end;
142 1 : if(*incexc && conf_parse_incexcs_buf(confs,
143 : *incexc)) goto end;
144 : }
145 : else
146 : {
147 1 : logp("Client configuration says no\n");
148 : }
149 : }
150 : }
151 :
152 40 : if(server_supports(feat, ":counters_json:"))
153 : {
154 1 : if(asfd->write_str(asfd, CMD_GEN, "counters_json ok"))
155 : goto end;
156 1 : set_int(confs[OPT_SEND_CLIENT_CNTR], 1);
157 : }
158 :
159 : // :incexc: is for the client sending the server the
160 : // incexc conf so that it better knows what to do on
161 : // resume.
162 40 : if(server_supports(feat, ":incexc:")
163 0 : && incexc_send_client(asfd, confs))
164 : goto end;
165 :
166 40 : if(server_supports(feat, ":uname:"))
167 : {
168 1 : const char *clientos=NULL;
169 : #ifdef HAVE_WIN32
170 : #ifdef _WIN64
171 : clientos="Windows 64bit";
172 : #else
173 : clientos="Windows 32bit";
174 : #endif
175 : #else
176 : struct utsname utsname;
177 1 : if(!uname(&utsname))
178 1 : clientos=(const char *)utsname.sysname;
179 : #endif
180 1 : if(clientos)
181 : {
182 1 : char *msg=NULL;
183 1 : if(astrcat(&msg, "uname=", __func__)
184 1 : || astrcat(&msg, clientos, __func__))
185 : goto end;
186 1 : if(asfd->write_str(asfd, CMD_GEN, msg))
187 : {
188 0 : free_w(&msg);
189 0 : goto end;
190 : }
191 1 : free_w(&msg);
192 : }
193 : }
194 :
195 40 : if(server_supports(feat, ":csetproto:"))
196 : {
197 3 : char msg[128]="";
198 : // Use protocol1 if no choice has been made on client side.
199 3 : if(get_protocol(confs)==PROTO_AUTO)
200 : {
201 1 : logp("Server has protocol=0 (auto)\n");
202 1 : set_protocol(confs, PROTO_1);
203 : }
204 : // Send choice to server.
205 3 : snprintf(msg, sizeof(msg), "protocol=%d",
206 3 : get_protocol(confs));
207 3 : if(asfd->write_str(asfd, CMD_GEN, msg))
208 : goto end;
209 3 : logp("Using protocol=%d\n",
210 3 : get_protocol(confs));
211 : }
212 34 : else if(server_supports(feat, ":forceproto=1:"))
213 : {
214 2 : logp("Server is forcing protocol 1\n");
215 2 : if(get_protocol(confs)!=PROTO_AUTO
216 2 : && get_protocol(confs)!=PROTO_1)
217 : {
218 1 : logp("But client has set protocol=%d!\n",
219 1 : get_protocol(confs));
220 1 : goto end;
221 : }
222 1 : set_protocol(confs, PROTO_1);
223 : }
224 30 : else if(server_supports(feat, ":forceproto=2:"))
225 : {
226 2 : logp("Server is forcing protocol 2\n");
227 2 : if(get_protocol(confs)!=PROTO_AUTO
228 2 : && get_protocol(confs)!=PROTO_2)
229 : {
230 1 : logp("But client has set protocol=%d!\n",
231 1 : get_protocol(confs));
232 1 : goto end;
233 : }
234 1 : set_protocol(confs, PROTO_2);
235 : }
236 :
237 18 : if(get_protocol(confs)==PROTO_2
238 2 : && get_string(confs[OPT_ENCRYPTION_PASSWORD]))
239 : {
240 0 : char msg[64]="";
241 0 : snprintf(msg, sizeof(msg),
242 : "%s is not supported in protocol 2",
243 0 : confs[OPT_ENCRYPTION_PASSWORD]->field);
244 0 : log_and_send(asfd, msg);
245 : goto end;
246 : }
247 :
248 36 : if(server_supports(feat, ":msg:"))
249 : {
250 1 : set_int(confs[OPT_MESSAGE], 1);
251 1 : if(asfd->write_str(asfd, CMD_GEN, "msg"))
252 : goto end;
253 : }
254 :
255 : #ifdef HAVE_BLAKE2
256 : if(server_supports(feat, ":rshash=blake2:"))
257 : {
258 : set_e_rshash(confs[OPT_RSHASH], RSHASH_BLAKE2);
259 : // Send choice to server.
260 : if(asfd->write_str(asfd, CMD_GEN, "rshash=blake2"))
261 : goto end;
262 : }
263 : else
264 : #endif
265 18 : set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4);
266 :
267 36 : if(server_supports(feat, ":failover:"))
268 : {
269 0 : if(*action==ACTION_BACKUP
270 0 : || *action==ACTION_BACKUP_TIMED)
271 : {
272 0 : char msg[64]="";
273 0 : int left=0;
274 0 : struct strlist *f=NULL;
275 0 : for(f=failover; f; f=f->next)
276 0 : left++;
277 0 : snprintf(msg, sizeof(msg),
278 : "backup_failovers_left=%d", left);
279 0 : if(asfd->write_str(asfd, CMD_GEN, msg))
280 : goto end;
281 : }
282 : }
283 :
284 18 : seed_src=get_string(confs[OPT_SEED_SRC]);
285 18 : seed_dst=get_string(confs[OPT_SEED_DST]);
286 18 : if(seed_src && *seed_src
287 0 : && seed_dst && *seed_dst
288 0 : && server_supports(feat, ":seed:"))
289 : {
290 0 : char *msg=NULL;
291 0 : logp("Seeding from %s\n", seed_src);
292 0 : if(astrcat(&msg, "seed_src=", __func__)
293 0 : || astrcat(&msg, seed_src, __func__)
294 0 : || asfd->write_str(asfd, CMD_GEN, msg))
295 : {
296 0 : free_w(&msg);
297 0 : goto end;
298 : }
299 0 : free_w(&msg);
300 0 : logp("Seeding to %s\n", seed_dst);
301 0 : if(astrcat(&msg, "seed_dst=", __func__)
302 0 : || astrcat(&msg, seed_dst, __func__)
303 0 : || asfd->write_str(asfd, CMD_GEN, msg))
304 : {
305 0 : free_w(&msg);
306 0 : goto end;
307 : }
308 0 : free_w(&msg);
309 : }
310 :
311 36 : if(server_supports(feat, ":vss_restore:"))
312 : {
313 0 : enum vss_restore vss_restore=(enum vss_restore)
314 0 : get_int(confs[OPT_VSS_RESTORE]);
315 0 : if(vss_restore==VSS_RESTORE_OFF
316 0 : && asfd->write_str(asfd, CMD_GEN, "vss_restore=off"))
317 : goto end;
318 0 : if(vss_restore==VSS_RESTORE_OFF_STRIP
319 0 : && asfd->write_str(asfd, CMD_GEN, "vss_restore=strip"))
320 : goto end;
321 : }
322 :
323 18 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end")
324 18 : || asfd_read_expect(asfd, CMD_GEN, "extra_comms_end ok"))
325 : {
326 1 : logp("Problem requesting extra_comms_end\n");
327 1 : goto end;
328 : }
329 :
330 : ret=0;
331 : end:
332 28 : free_w(&feat);
333 28 : return ret;
334 : }
|