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 200 : 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, char **incexc)
36 : {
37 28 : int ret=-1;
38 28 : char *feat=NULL;
39 : struct asfd *asfd;
40 : struct iobuf *rbuf;
41 28 : const char *orig_client=NULL;
42 28 : asfd=as->asfd;
43 28 : rbuf=asfd->rbuf;
44 :
45 28 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin"))
46 : {
47 1 : logp("Problem requesting extra_comms_begin\n");
48 1 : goto end;
49 : }
50 : // Servers greater than 1.3.0 will list the extra_comms
51 : // features they support.
52 27 : if(asfd->read(asfd))
53 : {
54 1 : logp("Problem reading response to extra_comms_begin\n");
55 1 : goto end;
56 : }
57 26 : if(rbuf->cmd!=CMD_GEN
58 26 : || strncmp_w(rbuf->buf, "extra_comms_begin ok"))
59 : {
60 1 : iobuf_log_unexpected(rbuf, __func__);
61 1 : goto end;
62 : }
63 25 : feat=rbuf->buf;
64 25 : rbuf->buf=NULL;
65 25 : logp("%s\n", feat);
66 25 : iobuf_init(rbuf);
67 :
68 : // Can add extra bits here. The first extra bit is the
69 : // autoupgrade stuff.
70 25 : if(server_supports_autoupgrade(feat)
71 1 : && get_string(confs[OPT_AUTOUPGRADE_DIR])
72 1 : && get_string(confs[OPT_AUTOUPGRADE_OS])
73 1 : && autoupgrade_client(as, confs))
74 : goto end;
75 :
76 :
77 : // :srestore: means that the server wants to do a restore.
78 48 : if(server_supports(feat, ":srestore:"))
79 : {
80 6 : logp("Server wants to initiate a restore\n");
81 6 : if(*action==ACTION_MONITOR)
82 : {
83 1 : logp("Client is in monitor mode, so ignoring\n");
84 : }
85 5 : else if(get_int(confs[OPT_SERVER_CAN_RESTORE]))
86 : {
87 4 : logp("Client accepts.\n");
88 4 : if(incexc_recv_client_restore(asfd, incexc, confs))
89 : goto end;
90 4 : if(*incexc)
91 : {
92 4 : if(conf_parse_incexcs_srestore(confs, *incexc))
93 : goto end;
94 2 : *action=ACTION_RESTORE;
95 2 : log_restore_settings(confs, 1);
96 : }
97 : }
98 : else
99 : {
100 1 : logp("Client configuration says no\n");
101 1 : if(asfd->write_str(asfd, CMD_GEN, "srestore not ok"))
102 : goto end;
103 : }
104 : }
105 :
106 : // Needs to be after the srestore stuff, as the server may set
107 : // orig_client in the server-initiated restore file.
108 22 : if((orig_client=get_string(confs[OPT_ORIG_CLIENT])))
109 : {
110 4 : char str[512]="";
111 4 : snprintf(str, sizeof(str), "orig_client=%s", orig_client);
112 8 : if(!server_supports(feat, ":orig_client:"))
113 : {
114 1 : logp("Server does not support switching client.\n");
115 1 : goto end;
116 : }
117 3 : if(asfd->write_str(asfd, CMD_GEN, str)
118 3 : || asfd_read_expect(asfd, CMD_GEN, "orig_client ok"))
119 : {
120 1 : logp("Problem requesting %s\n", str);
121 1 : goto end;
122 : }
123 2 : logp("Switched to client %s\n", orig_client);
124 : }
125 :
126 : // :sincexc: is for the server giving the client the
127 : // incexc config.
128 40 : if(*action==ACTION_BACKUP
129 20 : || *action==ACTION_BACKUP_TIMED
130 3 : || *action==ACTION_TIMER_CHECK)
131 : {
132 34 : if(!*incexc && server_supports(feat, ":sincexc:"))
133 : {
134 2 : logp("Server is setting includes/excludes.\n");
135 2 : if(get_int(confs[OPT_SERVER_CAN_OVERRIDE_INCLUDES]))
136 : {
137 1 : logp("Client accepts.\n");
138 1 : if(incexc_recv_client(asfd, incexc, confs))
139 : goto end;
140 1 : if(*incexc && conf_parse_incexcs_buf(confs,
141 : *incexc)) goto end;
142 : }
143 : else
144 : {
145 1 : logp("Client configuration says no\n");
146 : }
147 : }
148 : }
149 :
150 40 : if(server_supports(feat, ":counters_json:"))
151 : {
152 1 : if(asfd->write_str(asfd, CMD_GEN, "counters_json ok"))
153 : goto end;
154 1 : set_int(confs[OPT_SEND_CLIENT_CNTR], 1);
155 : }
156 :
157 : // :incexc: is for the client sending the server the
158 : // incexc conf so that it better knows what to do on
159 : // resume.
160 40 : if(server_supports(feat, ":incexc:")
161 0 : && incexc_send_client(asfd, confs))
162 : goto end;
163 :
164 40 : if(server_supports(feat, ":uname:"))
165 : {
166 1 : const char *clientos=NULL;
167 : #ifdef HAVE_WIN32
168 : #ifdef _WIN64
169 : clientos="Windows 64bit";
170 : #else
171 : clientos="Windows 32bit";
172 : #endif
173 : #else
174 : struct utsname utsname;
175 1 : if(!uname(&utsname))
176 1 : clientos=(const char *)utsname.sysname;
177 : #endif
178 1 : if(clientos)
179 : {
180 1 : char *msg=NULL;
181 1 : if(astrcat(&msg, "uname=", __func__)
182 1 : || astrcat(&msg, clientos, __func__))
183 : goto end;
184 1 : if(asfd->write_str(asfd, CMD_GEN, msg))
185 : {
186 0 : free_w(&msg);
187 0 : goto end;
188 : }
189 1 : free_w(&msg);
190 : }
191 : }
192 :
193 40 : if(server_supports(feat, ":csetproto:"))
194 : {
195 3 : char msg[128]="";
196 : // Use protocol1 if no choice has been made on client side.
197 3 : if(get_protocol(confs)==PROTO_AUTO)
198 : {
199 1 : logp("Server has protocol=0 (auto)\n");
200 1 : set_protocol(confs, PROTO_1);
201 : }
202 : // Send choice to server.
203 3 : snprintf(msg, sizeof(msg), "protocol=%d",
204 3 : get_protocol(confs));
205 3 : if(asfd->write_str(asfd, CMD_GEN, msg))
206 : goto end;
207 3 : logp("Using protocol=%d\n",
208 3 : get_protocol(confs));
209 : }
210 34 : else if(server_supports(feat, ":forceproto=1:"))
211 : {
212 2 : logp("Server is forcing protocol 1\n");
213 2 : if(get_protocol(confs)!=PROTO_AUTO
214 2 : && get_protocol(confs)!=PROTO_1)
215 : {
216 1 : logp("But client has set protocol=%d!\n",
217 1 : get_protocol(confs));
218 1 : goto end;
219 : }
220 1 : set_protocol(confs, PROTO_1);
221 : }
222 30 : else if(server_supports(feat, ":forceproto=2:"))
223 : {
224 2 : logp("Server is forcing protocol 2\n");
225 2 : if(get_protocol(confs)!=PROTO_AUTO
226 2 : && get_protocol(confs)!=PROTO_2)
227 : {
228 1 : logp("But client has set protocol=%d!\n",
229 1 : get_protocol(confs));
230 1 : goto end;
231 : }
232 1 : set_protocol(confs, PROTO_2);
233 : }
234 :
235 36 : if(server_supports(feat, ":msg:"))
236 : {
237 1 : set_int(confs[OPT_MESSAGE], 1);
238 1 : if(asfd->write_str(asfd, CMD_GEN, "msg"))
239 : goto end;
240 : }
241 :
242 : #ifdef HAVE_BLAKE2
243 : if(server_supports(feat, ":rshash=blake2:"))
244 : {
245 : set_e_rshash(confs[OPT_RSHASH], RSHASH_BLAKE2);
246 : // Send choice to server.
247 : if(asfd->write_str(asfd, CMD_GEN, "rshash=blake2"))
248 : goto end;
249 : }
250 : else
251 : #endif
252 18 : set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4);
253 :
254 18 : if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end")
255 18 : || asfd_read_expect(asfd, CMD_GEN, "extra_comms_end ok"))
256 : {
257 1 : logp("Problem requesting extra_comms_end\n");
258 1 : goto end;
259 : }
260 :
261 : ret=0;
262 : end:
263 28 : free_w(&feat);
264 28 : return ret;
265 : }
|