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