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