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