Line data Source code
1 : #include "../burp.h"
2 : #include "../action.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../cmd.h"
6 : #include "../cntr.h"
7 : #include "../fsops.h"
8 : #include "../handy.h"
9 : #include "../iobuf.h"
10 : #include "../log.h"
11 : #include "../run_script.h"
12 : #include "auth.h"
13 : #include "backup.h"
14 : #include "ca.h"
15 : #include "delete.h"
16 : #include "extra_comms.h"
17 : #include "list.h"
18 : #include "monitor.h"
19 : #include "monitor/status_client_ncurses.h"
20 : #include "protocol2/restore.h"
21 : #include "restore.h"
22 :
23 : #ifndef HAVE_WIN32
24 : #include <sys/utsname.h>
25 : #endif
26 :
27 : // These will also be used as the exit codes of the program and are therefore
28 : // unsigned integers.
29 : // Remember to update the man page if you update these.
30 : enum cliret
31 : {
32 : CLIENT_OK=0,
33 : CLIENT_ERROR=1,
34 : CLIENT_RESTORE_WARNINGS=2,
35 : CLIENT_SERVER_TIMER_NOT_MET=3,
36 : CLIENT_COULD_NOT_CONNECT=4,
37 : // This one happens after a successful certificate signing request so
38 : // that it connects again straight away with the new key/certificate.
39 : CLIENT_RECONNECT=100
40 : };
41 :
42 : struct tchk
43 : {
44 : int resume;
45 : enum cliret ret;
46 : };
47 :
48 0 : static enum asl_ret maybe_check_timer_func(struct asfd *asfd,
49 : struct conf **confs, void *param)
50 : {
51 0 : int complen=0;
52 0 : struct tchk *tchk=(struct tchk *)param;
53 :
54 0 : if(!strcmp(asfd->rbuf->buf, "timer conditions not met"))
55 : {
56 0 : logp("Timer conditions on the server were not met\n");
57 0 : tchk->ret=CLIENT_SERVER_TIMER_NOT_MET;
58 0 : return ASL_END_OK;
59 : }
60 0 : else if(!strcmp(asfd->rbuf->buf, "timer conditions met"))
61 : {
62 : // Only happens on 'timer check only'.
63 0 : logp("Timer conditions on the server were met\n");
64 0 : tchk->ret=CLIENT_OK;
65 0 : return ASL_END_OK;
66 : }
67 :
68 0 : if(!strncmp_w(asfd->rbuf->buf, "ok"))
69 : complen=3;
70 0 : else if(!strncmp_w(asfd->rbuf->buf, "resume"))
71 : {
72 0 : complen=7;
73 0 : tchk->resume=1;
74 0 : logp("server wants to resume previous backup.\n");
75 : }
76 : else
77 : {
78 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
79 0 : return ASL_END_ERROR;
80 : }
81 :
82 : // The server now tells us the compression level in the OK response.
83 0 : if(strlen(asfd->rbuf->buf)>3)
84 0 : set_int(confs[OPT_COMPRESSION], atoi(asfd->rbuf->buf+complen));
85 : logp("Compression level: %d\n",
86 0 : get_int(confs[OPT_COMPRESSION]));
87 :
88 0 : return ASL_END_OK;
89 : }
90 :
91 0 : static enum cliret maybe_check_timer(struct asfd *asfd,
92 : enum action action, const char *phase1str,
93 : struct conf **confs, int *resume)
94 : {
95 : struct tchk tchk;
96 : memset(&tchk, 0, sizeof(tchk));
97 0 : if(asfd->write_str(asfd, CMD_GEN, phase1str))
98 : return CLIENT_ERROR;
99 :
100 0 : if(asfd->simple_loop(asfd, confs, &tchk,
101 0 : __func__, maybe_check_timer_func)) return CLIENT_ERROR;
102 0 : *resume=tchk.resume;
103 0 : return tchk.ret;
104 : }
105 :
106 0 : static enum cliret backup_wrapper(struct asfd *asfd,
107 : enum action action, const char *phase1str,
108 : const char *incexc, struct conf **confs)
109 : {
110 0 : int resume=0;
111 0 : enum cliret ret=CLIENT_OK;
112 0 : const char *b_script_pre=get_string(confs[OPT_B_SCRIPT_PRE]);
113 0 : const char *b_script_post=get_string(confs[OPT_B_SCRIPT_POST]);
114 :
115 : // Set bulk packets quality of service flags on backup.
116 0 : if(incexc)
117 : {
118 0 : logp("Server is overriding the configuration\n");
119 0 : logp("with the following settings:\n");
120 0 : if(log_incexcs_buf(incexc)) goto error;
121 : }
122 0 : if(!get_strlist(confs[OPT_STARTDIR]))
123 : {
124 0 : logp("Found no include paths!\n");
125 0 : goto error;
126 : }
127 :
128 0 : switch(maybe_check_timer(asfd, action, phase1str, confs, &resume))
129 : {
130 : case CLIENT_OK:
131 0 : if(action==ACTION_TIMER_CHECK) goto end;
132 : break;
133 : case CLIENT_SERVER_TIMER_NOT_MET:
134 : goto timer_not_met;
135 : default:
136 : goto error;
137 : }
138 :
139 0 : if(b_script_pre)
140 : {
141 0 : int a=0;
142 : const char *args[12];
143 0 : args[a++]=b_script_pre;
144 0 : if(get_int(confs[OPT_B_SCRIPT_RESERVED_ARGS]))
145 : {
146 0 : args[a++]="pre";
147 0 : args[a++]="reserved2";
148 0 : args[a++]="reserved3";
149 0 : args[a++]="reserved4";
150 0 : args[a++]="reserved5";
151 : }
152 0 : args[a++]=NULL;
153 0 : if(run_script(asfd,
154 : args, get_strlist(confs[OPT_B_SCRIPT_PRE_ARG]),
155 0 : confs, 1, 1, 1))
156 0 : ret=CLIENT_ERROR;
157 : }
158 :
159 0 : if(ret==CLIENT_OK && do_backup_client(asfd,
160 0 : confs, action, resume)) ret=CLIENT_ERROR;
161 :
162 0 : if((ret==CLIENT_OK || get_int(confs[OPT_B_SCRIPT_POST_RUN_ON_FAIL]))
163 0 : && b_script_post)
164 : {
165 0 : int a=0;
166 : const char *args[12];
167 0 : if(get_int(confs[OPT_B_SCRIPT_RESERVED_ARGS]))
168 : {
169 0 : args[a++]=b_script_post;
170 0 : args[a++]="post";
171 : // Tell post script whether the restore failed.
172 0 : args[a++]=ret?"1":"0";
173 0 : args[a++]="reserved3";
174 0 : args[a++]="reserved4";
175 0 : args[a++]="reserved5";
176 : }
177 0 : args[a++]=NULL;
178 0 : if(run_script(asfd,
179 : args, get_strlist(confs[OPT_B_SCRIPT_POST_ARG]),
180 0 : confs, 1, 1, 1))
181 0 : ret=CLIENT_ERROR;
182 : }
183 :
184 0 : if(ret==CLIENT_OK) logp("backup finished ok\n");
185 :
186 : end:
187 0 : return ret;
188 : error:
189 0 : logp("error in backup\n");
190 0 : return CLIENT_ERROR;
191 : timer_not_met:
192 : return CLIENT_SERVER_TIMER_NOT_MET;
193 : }
194 :
195 : static int s_server_session_id_context=1;
196 :
197 0 : static int ssl_setup(int *rfd, SSL **ssl, SSL_CTX **ctx,
198 : enum action action, struct conf **confs)
199 : {
200 0 : BIO *sbio=NULL;
201 0 : ssl_load_globals();
202 0 : if(!(*ctx=ssl_initialise_ctx(confs)))
203 : {
204 0 : logp("error initialising ssl ctx\n");
205 0 : return -1;
206 : }
207 :
208 : SSL_CTX_set_session_id_context(*ctx,
209 : (const uint8_t *)&s_server_session_id_context,
210 0 : sizeof(s_server_session_id_context));
211 :
212 0 : if((*rfd=init_client_socket(get_string(confs[OPT_SERVER]),
213 : action==ACTION_MONITOR?
214 0 : get_string(confs[OPT_STATUS_PORT]):get_string(confs[OPT_PORT])))<0)
215 : return -1;
216 :
217 0 : if(!(*ssl=SSL_new(*ctx))
218 0 : || !(sbio=BIO_new_socket(*rfd, BIO_NOCLOSE)))
219 : {
220 0 : logp_ssl_err("Problem joining SSL to the socket\n");
221 0 : return -1;
222 : }
223 0 : SSL_set_bio(*ssl, sbio, sbio);
224 0 : if(SSL_connect(*ssl)<=0)
225 : {
226 0 : logp_ssl_err("SSL connect error\n");
227 0 : return -1;
228 : }
229 : return 0;
230 : }
231 :
232 0 : static enum cliret initial_comms(struct async *as,
233 : enum action *action, char **incexc, struct conf **confs)
234 : {
235 : struct asfd *asfd;
236 0 : char *server_version=NULL;
237 0 : enum cliret ret=CLIENT_OK;
238 0 : asfd=as->asfd;
239 :
240 0 : if(authorise_client(asfd, &server_version,
241 0 : get_string(confs[OPT_CNAME]),
242 0 : get_string(confs[OPT_PASSWORD]),
243 0 : get_cntr(confs)))
244 : goto error;
245 :
246 0 : if(server_version)
247 : {
248 0 : logp("Server version: %s\n", server_version);
249 : // Servers before 1.3.2 did not tell us their versions.
250 : // 1.3.2 and above can do the automatic CA stuff that
251 : // follows.
252 0 : switch(ca_client_setup(asfd, confs))
253 : {
254 : case 0:
255 : break; // All OK.
256 : case 1:
257 : // Certificate signed successfully.
258 : // Everything is OK, but we will reconnect now,
259 : // in order to use the new keys/certificates.
260 : goto reconnect;
261 : default:
262 0 : logp("Error with cert signing request\n");
263 0 : goto error;
264 : }
265 : }
266 :
267 0 : set_non_blocking(asfd->fd);
268 :
269 0 : if(ssl_check_cert(asfd->ssl, NULL, confs))
270 : {
271 0 : logp("check cert failed\n");
272 0 : goto error;
273 : }
274 :
275 0 : if(extra_comms(as, confs, action, incexc))
276 : {
277 0 : logp("extra comms failed\n");
278 0 : goto error;
279 : }
280 :
281 : ret=CLIENT_OK; goto end;
282 : error:
283 : ret=CLIENT_ERROR; goto end;
284 : reconnect:
285 : ret=CLIENT_RECONNECT; goto end;
286 : end:
287 0 : free_w(&server_version);
288 0 : return ret;
289 : }
290 :
291 0 : static enum cliret restore_wrapper(struct asfd *asfd, enum action action,
292 : int vss_restore, struct conf **confs)
293 : {
294 0 : enum cliret ret=CLIENT_OK;
295 0 : const char *r_script_pre=get_string(confs[OPT_R_SCRIPT_PRE]);
296 0 : const char *r_script_post=get_string(confs[OPT_R_SCRIPT_POST]);
297 :
298 0 : if(r_script_pre)
299 : {
300 0 : int a=0;
301 : const char *args[12];
302 0 : args[a++]=r_script_pre;
303 0 : if(get_int(confs[OPT_R_SCRIPT_RESERVED_ARGS]))
304 : {
305 0 : args[a++]="pre";
306 0 : args[a++]="reserved2";
307 0 : args[a++]="reserved3";
308 0 : args[a++]="reserved4";
309 0 : args[a++]="reserved5";
310 : }
311 0 : args[a++]=NULL;
312 0 : if(run_script(asfd,
313 : args, get_strlist(confs[OPT_R_SCRIPT_PRE_ARG]),
314 0 : confs, 1, 1, 1))
315 0 : ret=CLIENT_ERROR;
316 : }
317 0 : if(ret==CLIENT_OK)
318 : {
319 0 : if(do_restore_client(asfd, confs,
320 0 : action, vss_restore)) ret=CLIENT_ERROR;
321 : }
322 0 : if((ret==CLIENT_OK || get_int(confs[OPT_R_SCRIPT_POST_RUN_ON_FAIL]))
323 0 : && r_script_post)
324 : {
325 0 : int a=0;
326 : const char *args[12];
327 0 : args[a++]=r_script_pre;
328 0 : if(get_int(confs[OPT_R_SCRIPT_RESERVED_ARGS]))
329 : {
330 0 : args[a++]="post";
331 : // Tell post script whether the restore failed.
332 0 : args[a++]=ret?"1":"0";
333 0 : args[a++]="reserved3";
334 0 : args[a++]="reserved4";
335 0 : args[a++]="reserved5";
336 : }
337 0 : args[a++]=NULL;
338 0 : if(run_script(asfd,
339 : args, get_strlist(confs[OPT_R_SCRIPT_POST_ARG]),
340 0 : confs, 1, 1, 1))
341 0 : ret=CLIENT_ERROR;
342 : }
343 :
344 : // Return non-zero if there were warnings,
345 : // so that the test script can easily check.
346 0 : if(ret==CLIENT_OK && get_cntr(confs)->ent[CMD_WARNING]->count)
347 0 : ret=CLIENT_RESTORE_WARNINGS;
348 :
349 0 : return ret;
350 : }
351 :
352 0 : static enum cliret do_client(struct conf **confs,
353 : enum action action, int vss_restore)
354 : {
355 0 : enum cliret ret=CLIENT_OK;
356 0 : int rfd=-1;
357 0 : SSL *ssl=NULL;
358 0 : SSL_CTX *ctx=NULL;
359 0 : struct cntr *cntr=NULL;
360 0 : char *incexc=NULL;
361 0 : enum action act=action;
362 0 : struct async *as=NULL;
363 0 : struct asfd *asfd=NULL;
364 :
365 : // as->settimers(0, 100);
366 :
367 : // logp("begin client\n");
368 : // logp("action %d\n", action);
369 :
370 : // Status monitor forks a child process instead of connecting to
371 : // the server directly.
372 0 : if(action==ACTION_STATUS
373 0 : || action==ACTION_STATUS_SNAPSHOT)
374 : {
375 : #ifdef HAVE_WIN32
376 : logp("Status mode not implemented on Windows.\n");
377 : goto error;
378 : #endif
379 0 : if(status_client_ncurses_init(act)
380 0 : || status_client_ncurses(confs)) ret=CLIENT_ERROR;
381 : goto end;
382 : }
383 :
384 0 : if(!(cntr=cntr_alloc())
385 0 : || cntr_init(cntr, get_string(confs[OPT_CNAME]))) goto error;
386 0 : set_cntr(confs[OPT_CNTR], cntr);
387 :
388 0 : if(act!=ACTION_ESTIMATE
389 0 : && ssl_setup(&rfd, &ssl, &ctx, action, confs))
390 : goto could_not_connect;
391 :
392 0 : if(!(as=async_alloc())
393 0 : || !(asfd=asfd_alloc())
394 0 : || as->init(as, act==ACTION_ESTIMATE)
395 0 : || asfd->init(asfd, "main socket", as, rfd, ssl,
396 0 : ASFD_STREAM_STANDARD, confs))
397 : goto end;
398 0 : as->asfd_add(as, asfd);
399 :
400 : // Set quality of service bits on backup packets.
401 0 : if(act==ACTION_BACKUP
402 0 : || act==ACTION_BACKUP_TIMED
403 0 : || act==ACTION_TIMER_CHECK)
404 0 : as->asfd->set_bulk_packets(as->asfd);
405 :
406 0 : if(act!=ACTION_ESTIMATE)
407 : {
408 0 : if((ret=initial_comms(as, &act, &incexc, confs)))
409 : goto end;
410 : }
411 :
412 0 : rfd=-1;
413 0 : switch(act)
414 : {
415 : case ACTION_BACKUP:
416 : ret=backup_wrapper(asfd, act, "backupphase1",
417 0 : incexc, confs);
418 0 : break;
419 : case ACTION_BACKUP_TIMED:
420 : ret=backup_wrapper(asfd, act, "backupphase1timed",
421 0 : incexc, confs);
422 0 : break;
423 : case ACTION_TIMER_CHECK:
424 : ret=backup_wrapper(asfd, act, "backupphase1timedcheck",
425 0 : incexc, confs);
426 0 : break;
427 : case ACTION_RESTORE:
428 : case ACTION_VERIFY:
429 0 : ret=restore_wrapper(asfd, act, vss_restore, confs);
430 0 : break;
431 : case ACTION_ESTIMATE:
432 0 : if(do_backup_client(asfd, confs, act, 0))
433 : goto error;
434 : break;
435 : case ACTION_DELETE:
436 0 : if(do_delete_client(asfd, confs)) goto error;
437 : break;
438 : case ACTION_MONITOR:
439 0 : if(do_monitor_client(asfd, confs)) goto error;
440 : break;
441 : case ACTION_DIFF:
442 : case ACTION_DIFF_LONG:
443 : /*
444 : if(!strcmp(get_string(confs[OPT_BACKUP2]), "n"))
445 : // Do a phase1 scan and diff that.
446 : ret=backup_wrapper(asfd, act,
447 : "backupphase1diff", incexc, confs);
448 : else
449 : */
450 : // Diff two backups that already exist.
451 : // Fall through, the list code is all we need
452 : // for simple diffs on the client side.
453 : case ACTION_LIST:
454 : case ACTION_LIST_LONG:
455 : default:
456 0 : if(do_list_client(asfd, act, confs)) goto error;
457 : break;
458 : }
459 :
460 0 : if(asfd_flush_asio(asfd))
461 0 : ret=CLIENT_ERROR;
462 :
463 : goto end;
464 : error:
465 : ret=CLIENT_ERROR; goto end;
466 : could_not_connect:
467 : ret=CLIENT_COULD_NOT_CONNECT;
468 : end:
469 0 : close_fd(&rfd);
470 0 : async_free(&as);
471 0 : asfd_free(&asfd);
472 0 : if(ctx) ssl_destroy_ctx(ctx);
473 0 : free_w(&incexc);
474 0 : set_cntr(confs[OPT_CNTR], NULL);
475 0 : cntr_free(&cntr);
476 :
477 : //logp("end client\n");
478 0 : return ret;
479 : }
480 :
481 0 : int client(struct conf **confs, enum action action, int vss_restore)
482 : {
483 0 : enum cliret ret=CLIENT_OK;
484 :
485 : #ifdef HAVE_WIN32
486 : // prevent sleep when idle
487 : SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
488 : #endif
489 :
490 0 : switch((ret=do_client(confs, action, vss_restore)))
491 : {
492 : case CLIENT_RECONNECT:
493 0 : logp("Re-opening connection to server\n");
494 0 : sleep(5);
495 0 : ret=do_client(confs, action, vss_restore);
496 : default:
497 : break;
498 : }
499 :
500 : #ifdef HAVE_WIN32
501 : // allow sleep when idle
502 : SetThreadExecutionState(ES_CONTINUOUS);
503 : #endif
504 :
505 : // See enum cliret for return codes.
506 0 : return (int)ret;
507 : }
|