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 "../handy.h"
8 #include "../fsops.h"
9 #include "../iobuf.h"
10 #include "../lock.h"
11 #include "../log.h"
12 #include "../regexp.h"
13 #include "../run_script.h"
14 #include "main.h"
15 #include "backup.h"
16 #include "delete.h"
17 #include "diff.h"
18 #include "list.h"
19 #include "protocol2/restore.h"
20 #include "restore.h"
21 #include "rubble.h"
22 #include "sdirs.h"
23 #include "run_action.h"
24 #include "timestamp.h"
25
26 // FIX THIS: Somewhat haphazard.
27 /* Return 0 for everything OK. -1 for error, or 1 to mean that there was
28 another process that has the lock. */
get_lock_sdirs_for_write(struct asfd * asfd,struct sdirs * sdirs)29 static int get_lock_sdirs_for_write(struct asfd *asfd, struct sdirs *sdirs)
30 {
31 struct stat statp;
32
33 // Make sure the lock directory exists.
34 if(mkpath(&sdirs->lock_storage_for_write->path, sdirs->lockdir))
35 {
36 asfd->write_str(asfd, CMD_ERROR, "problem with lock directory");
37 goto error;
38 }
39
40 lock_get(sdirs->lock_storage_for_write);
41 switch(sdirs->lock_storage_for_write->status)
42 {
43 case GET_LOCK_GOT: break;
44 case GET_LOCK_NOT_GOT:
45 if(!lstat(sdirs->finishing, &statp))
46 {
47 char msg[256]="";
48 logp("finalising previous backup\n");
49 snprintf(msg, sizeof(msg),
50 "Finalising previous backup of client. "
51 "Please try again later.");
52 asfd->write_str(asfd, CMD_ERROR, msg);
53 }
54 else
55 {
56 logp("Another instance of client is already running.\n");
57 asfd->write_str(asfd, CMD_ERROR,
58 "another instance is already running");
59 }
60 goto lockedout;
61 case GET_LOCK_ERROR:
62 default:
63 logp("Problem with lock file on server: %s\n",
64 sdirs->lock_storage_for_write->path);
65 asfd->write_str(asfd, CMD_ERROR,
66 "problem with lock file on server");
67 goto error;
68 }
69
70 return 0;
71 lockedout:
72 return 1;
73 error:
74 return -1;
75 }
76
client_can_generic(struct conf ** cconfs,enum conf_opt o)77 static int client_can_generic(struct conf **cconfs, enum conf_opt o)
78 {
79 return get_int(cconfs[o]);
80 }
81
client_can_monitor(struct conf ** cconfs)82 int client_can_monitor(struct conf **cconfs)
83 {
84 return client_can_generic(cconfs, OPT_CLIENT_CAN_MONITOR);
85 }
86
client_can_restore(struct conf ** cconfs)87 static int client_can_restore(struct conf **cconfs)
88 {
89 const char *restore_path=get_string(cconfs[OPT_RESTORE_PATH]);
90
91 // If there is a restore file on the server, it is always OK.
92 if(restore_path && is_reg_lstat(restore_path)==1)
93 {
94 // Remove the file.
95 unlink(restore_path);
96 return 1;
97 }
98
99 return client_can_generic(cconfs, OPT_CLIENT_CAN_RESTORE);
100 }
101
maybe_do_notification(struct asfd * asfd,int status,const char * clientdir,const char * storagedir,const char * filename,const char * brv,struct conf ** cconfs)102 void maybe_do_notification(struct asfd *asfd,
103 int status, const char *clientdir,
104 const char *storagedir, const char *filename,
105 const char *brv, struct conf **cconfs)
106 {
107 int a=0;
108 const char *args[12];
109 struct cntr *cntr=get_cntr(cconfs);
110 args[a++]=NULL; // Fill in the script name later.
111 args[a++]=get_string(cconfs[OPT_CNAME]);
112 args[a++]=clientdir;
113 args[a++]=storagedir;
114 args[a++]=filename;
115 args[a++]=brv;
116 if(status)
117 {
118 args[0]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
119 args[a++]="0";
120 args[a++]=NULL;
121 run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
122 cconfs, 1, 1, 1);
123 }
124 else if((get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
125 && cntr->ent[CMD_WARNING]->count > 0)
126 || (get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])
127 && cntr->ent[CMD_TOTAL]->changed > 0)
128 || (!get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
129 && !get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])))
130 {
131 char warnings[32]="";
132 snprintf(warnings, sizeof(warnings), "%" PRIu64,
133 cntr->ent[CMD_WARNING]->count);
134 args[0]=get_string(cconfs[OPT_N_SUCCESS_SCRIPT]);
135 args[a++]=warnings;
136 args[a++]=NULL;
137 run_script(asfd, args, get_strlist(cconfs[OPT_N_SUCCESS_ARG]),
138 cconfs, 1, 1, 1);
139 }
140 }
141
parse_restore_str(const char * str,enum action * act,int * input,char ** backupnostr,char ** restoreregex)142 static int parse_restore_str(
143 const char *str,
144 enum action *act,
145 int *input,
146 char **backupnostr,
147 char **restoreregex
148 ) {
149 int ret=-1;
150 char *cp=NULL;
151 char *copy=NULL;
152
153 if(!str)
154 {
155 logp("NULL passed to %s\n", __func__);
156 goto end;
157 }
158
159 if(!(copy=strdup_w(str, __func__)))
160 goto end;
161
162 if(!strncmp_w(copy, "restore "))
163 *act=ACTION_RESTORE;
164 else if(!strncmp_w(copy, "verify "))
165 *act=ACTION_VERIFY;
166 else
167 {
168 logp("Could not parse %s in %s\n", copy, __func__);
169 goto end;
170 }
171
172 if(!(cp=strchr(copy, ' ')))
173 {
174 logp("Could not parse %s in %s\n", copy, __func__);
175 goto end;
176 }
177 cp++;
178 *input=0;
179 if(!strncmp_w(cp, "restore_list "))
180 {
181 cp+=strlen("restore_list ");
182 *input=1;
183 }
184 if(!(*backupnostr=strdup_w(cp, __func__)))
185 goto end;
186 if((cp=strchr(*backupnostr, ':')))
187 {
188 *cp='\0';
189 cp++;
190 if(!(*restoreregex=strdup_w(cp, __func__)))
191 goto end;
192 }
193
194 ret=0;
195 end:
196 free_w(©);
197 return ret;
198 }
199
200 #ifndef UTEST
201 static
202 #endif
parse_restore_str_and_set_confs(const char * str,enum action * act,struct conf ** cconfs)203 int parse_restore_str_and_set_confs(const char *str, enum action *act,
204 struct conf **cconfs)
205 {
206 int ret=-1;
207 int input=0;
208 char *backupnostr=NULL;
209 char *restoreregex=NULL;
210
211 if(parse_restore_str(str, act, &input, &backupnostr, &restoreregex))
212 goto end;
213
214 if(set_string(cconfs[OPT_RESTORE_LIST], input?"":NULL))
215 goto end;
216 if(set_string(cconfs[OPT_BACKUP], backupnostr))
217 goto end;
218 if(restoreregex && *restoreregex
219 && set_string(cconfs[OPT_REGEX], restoreregex))
220 goto end;
221 ret=0;
222 end:
223 free_w(&backupnostr);
224 free_w(&restoreregex);
225 return ret;
226 }
227
run_restore(struct asfd * asfd,struct sdirs * sdirs,struct conf ** cconfs,int srestore)228 static int run_restore(struct asfd *asfd,
229 struct sdirs *sdirs, struct conf **cconfs, int srestore)
230 {
231 int ret=-1;
232 char *dir_for_notify=NULL;
233 enum action act=ACTION_RESTORE;
234 struct iobuf *rbuf=asfd->rbuf;
235 const char *cname=get_string(cconfs[OPT_CNAME]);
236
237 if(parse_restore_str_and_set_confs(rbuf->buf, &act, cconfs))
238 goto end;
239
240 iobuf_free_content(rbuf);
241
242 if(act==ACTION_RESTORE)
243 {
244 int r;
245 if((r=client_can_restore(cconfs))<0)
246 goto end;
247 else if(!r)
248 {
249 logp("Not allowing restore of %s\n", cname);
250 if(!asfd->write_str(asfd, CMD_GEN,
251 "Client restore is not allowed")) ret=0;
252 goto end;
253 }
254 }
255 if(act==ACTION_VERIFY
256 && !(client_can_generic(cconfs, OPT_CLIENT_CAN_VERIFY)))
257 {
258 logp("Not allowing verify of %s\n", cname);
259 if(!asfd->write_str(asfd, CMD_GEN,
260 "Client verify is not allowed")) ret=0;
261 goto end;
262 }
263
264 if(get_string(cconfs[OPT_RESTORE_LIST]))
265 {
266 // Should start receiving the input file here.
267 if(asfd->write_str(asfd, CMD_GEN, "ok restore_list"))
268 goto end;
269 if(receive_a_file(asfd, sdirs->restore_list, get_cntr(cconfs)))
270 {
271 goto end;
272 }
273 }
274 else
275 {
276 if(asfd->write_str(asfd, CMD_GEN, "ok"))
277 goto end;
278 }
279
280 ret=do_restore_server(asfd, sdirs, act,
281 srestore, &dir_for_notify, cconfs);
282 if(dir_for_notify)
283 maybe_do_notification(asfd, ret,
284 sdirs->client, dir_for_notify,
285 act==ACTION_RESTORE?"restorelog":"verifylog",
286 act==ACTION_RESTORE?"restore":"verify",
287 cconfs);
288 end:
289 free_w(&dir_for_notify);
290 return ret;
291 }
292
run_delete(struct asfd * asfd,struct sdirs * sdirs,struct conf ** cconfs)293 static int run_delete(struct asfd *asfd,
294 struct sdirs *sdirs, struct conf **cconfs)
295 {
296 char *backupno=NULL;
297 struct iobuf *rbuf=asfd->rbuf;
298 const char *cname=get_string(cconfs[OPT_CNAME]);
299 if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DELETE))
300 {
301 logp("Not allowing delete of %s\n", cname);
302 asfd->write_str(asfd, CMD_GEN, "Client delete is not allowed");
303 return -1;
304 }
305 backupno=rbuf->buf+strlen("delete ");
306 return do_delete_server(asfd, sdirs,
307 cconfs, cname, backupno,
308 get_string(cconfs[OPT_MANUAL_DELETE]));
309 }
310
run_list(struct asfd * asfd,struct sdirs * sdirs,struct conf ** cconfs)311 static int run_list(struct asfd *asfd,
312 struct sdirs *sdirs, struct conf **cconfs)
313 {
314 int ret=-1;
315 char *cp=NULL;
316 char *backupno=NULL;
317 char *browsedir=NULL;
318 char *listregex=NULL;
319 struct iobuf *rbuf=asfd->rbuf;
320
321 if(!client_can_generic(cconfs, OPT_CLIENT_CAN_LIST))
322 {
323 logp("Not allowing list of %s\n",
324 get_string(cconfs[OPT_CNAME]));
325 asfd->write_str(asfd, CMD_GEN, "Client list is not allowed");
326 goto end;
327 }
328
329 if(!strncmp_w(rbuf->buf, "list "))
330 {
331 if((cp=strchr(rbuf->buf, ':')))
332 {
333 *cp='\0';
334 if(!(listregex=strdup_w(cp+1, __func__)))
335 goto end;
336 }
337 if(!(backupno=strdup_w(rbuf->buf+strlen("list "), __func__)))
338 goto end;
339
340 }
341 else if(!strncmp_w(rbuf->buf, "listb "))
342 {
343 if((cp=strchr(rbuf->buf, ':')))
344 {
345 *cp='\0';
346 if(!(browsedir=strdup_w(cp+1, __func__)))
347 goto end;
348 }
349 strip_trailing_slashes(&browsedir);
350 if(!(backupno=strdup_w(rbuf->buf+strlen("listb "), __func__)))
351 goto end;
352 }
353 if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
354
355 iobuf_free_content(asfd->rbuf);
356
357 if(list_server_init(asfd, sdirs, cconfs,
358 get_protocol(cconfs), backupno, listregex, browsedir))
359 goto end;
360 ret=do_list_server();
361 end:
362 free_w(&backupno);
363 free_w(&browsedir);
364 free_w(&listregex);
365 list_server_free();
366 return ret;
367 }
368
run_diff(struct asfd * asfd,struct sdirs * sdirs,struct conf ** cconfs)369 static int run_diff(struct asfd *asfd,
370 struct sdirs *sdirs, struct conf **cconfs)
371 {
372 int ret=-1;
373 char *backup1=NULL;
374 char *backup2=NULL;
375 struct iobuf *rbuf=asfd->rbuf;
376
377 if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DIFF))
378 {
379 logp("Not allowing diff of %s\n",
380 get_string(cconfs[OPT_CNAME]));
381 asfd->write_str(asfd, CMD_GEN, "Client diff is not allowed");
382 goto end;
383 }
384
385 if(!strncmp_w(rbuf->buf, "diff "))
386 {
387 char *cp;
388 if((cp=strchr(rbuf->buf, ':')))
389 {
390 *cp='\0';
391 if(!(backup2=strdup_w(cp+1, __func__)))
392 goto end;
393 }
394 if(!(backup1=strdup_w(rbuf->buf+strlen("diff "), __func__)))
395 goto end;
396 }
397 if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
398
399 iobuf_free_content(asfd->rbuf);
400
401 ret=do_diff_server(asfd, sdirs,
402 cconfs, get_protocol(cconfs), backup1, backup2);
403 end:
404 free_w(&backup1);
405 free_w(&backup2);
406 return ret;
407 }
408
unknown_command(struct asfd * asfd,const char * func)409 static int unknown_command(struct asfd *asfd, const char *func)
410 {
411 iobuf_log_unexpected(asfd->rbuf, func);
412 asfd->write_str(asfd, CMD_ERROR, "unknown command");
413 return -1;
414 }
415
buf_to_notify_str(struct iobuf * rbuf)416 static const char *buf_to_notify_str(struct iobuf *rbuf)
417 {
418 const char *buf=rbuf->buf;
419 if(!strncmp_w(buf, "backup")) return "backup";
420 else if(!strncmp_w(buf, "delete")) return "delete";
421 else if(!strncmp_w(buf, "diff")) return "diff";
422 else if(!strncmp_w(buf, "list")) return "list";
423 else if(!strncmp_w(buf, "restore")) return "restore";
424 else if(!strncmp_w(buf, "verify")) return "verify";
425 else return "unknown";
426 }
427
maybe_write_first_created_file(struct sdirs * sdirs,const char * tstmp)428 static int maybe_write_first_created_file(struct sdirs *sdirs,
429 const char *tstmp)
430 {
431 if(is_reg_lstat(sdirs->created)>0
432 || is_lnk_lstat(sdirs->current)>0
433 || is_lnk_lstat(sdirs->currenttmp)>0
434 || is_lnk_lstat(sdirs->working)>0
435 || is_lnk_lstat(sdirs->finishing)>0)
436 return 0;
437
438 return timestamp_write(sdirs->created, tstmp);
439 }
440
log_command(struct async * as,struct sdirs * sdirs,struct conf ** cconfs,const char * tstmp)441 static int log_command(struct async *as,
442 struct sdirs *sdirs, struct conf **cconfs, const char *tstmp)
443 {
444 struct fzp *fzp=NULL;
445 struct asfd *asfd=as->asfd;
446 struct iobuf *rbuf=asfd->rbuf;
447 char *cname=get_string(cconfs[OPT_CONNECT_CLIENT]);
448
449 if(rbuf->cmd!=CMD_GEN)
450 return 0;
451
452 if(!(fzp=fzp_open(sdirs->command, "a")))
453 return -1;
454 fzp_printf(fzp, "%s %s %s %s\n", tstmp, asfd->peer_addr, cname,
455 iobuf_to_printable(rbuf));
456 if(fzp_close(&fzp))
457 return -1;
458
459 return 0;
460 }
461
run_action_server_do(struct async * as,struct sdirs * sdirs,const char * incexc,int srestore,int * timer_ret,struct conf ** cconfs)462 static int run_action_server_do(struct async *as, struct sdirs *sdirs,
463 const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
464 {
465 int max_parallel_backups;
466 int working=0;
467 int ret;
468 int resume=0;
469 char msg[256]="";
470 char tstmp[48]="";
471 struct iobuf *rbuf=as->asfd->rbuf;
472
473 // Make sure some directories exist.
474 if(mkpath(&sdirs->current, sdirs->dedup))
475 {
476 snprintf(msg, sizeof(msg),
477 "could not mkpath %s", sdirs->current);
478 log_and_send(as->asfd, msg);
479 return -1;
480 }
481
482 if(timestamp_get_new(/*index*/0,
483 tstmp, sizeof(tstmp),
484 /*bufforfile*/NULL, /*bs*/0,
485 /*format*/NULL))
486 return -1;
487
488 // Carry on if these fail, otherwise you will not be able to restore
489 // from readonly backups.
490 maybe_write_first_created_file(sdirs, tstmp);
491 log_command(as, sdirs, cconfs, tstmp);
492
493 if(rbuf->cmd!=CMD_GEN)
494 return unknown_command(as->asfd, __func__);
495
496 // List and diff should work well enough without needing to lock
497 // anything.
498 if(!strncmp_w(rbuf->buf, "list ")
499 || !strncmp_w(rbuf->buf, "listb "))
500 return run_list(as->asfd, sdirs, cconfs);
501
502 if(!strncmp_w(rbuf->buf, "diff "))
503 return run_diff(as->asfd, sdirs, cconfs);
504
505 // Old clients will send 'delete', possibly accidentally due to the
506 // user trying to use the new diff/long diff options.
507 // Stop them from working, just to be safe.
508 if(!strncmp_w(rbuf->buf, "delete "))
509 {
510 logp("old style delete from %s denied\n",
511 get_string(cconfs[OPT_CNAME]));
512 as->asfd->write_str(as->asfd, CMD_ERROR,
513 "old style delete is not supported on this server");
514 return -1;
515 }
516
517 // Restore and verify should work well enough by locking only the
518 // backup directory they are interested in.
519 if(!strncmp_w(rbuf->buf, "restore ")
520 || !strncmp_w(rbuf->buf, "verify "))
521 {
522 ret=run_restore(as->asfd, sdirs, cconfs, srestore);
523 unlink(sdirs->restore_list);
524 return ret;
525 }
526
527 if(strncmp_w(rbuf->buf, "backup")
528 && strncmp_w(rbuf->buf, "Delete "))
529 return unknown_command(as->asfd, __func__);
530
531 // Beyond this point, only need to deal with backup and delete.
532 // These require locking out all other backups and deletes.
533
534 switch((ret=get_lock_sdirs_for_write(as->asfd, sdirs)))
535 {
536 case 0: break; // OK.
537 case 1: return 1; // Locked out.
538 default: // Error.
539 maybe_do_notification(as->asfd, ret,
540 "", "error in get_lock_sdirs()",
541 "", buf_to_notify_str(rbuf), cconfs);
542 return -1;
543 }
544
545 switch((ret=check_for_rubble_and_clean(as, sdirs,
546 incexc, &resume, cconfs)))
547 {
548 case 0: break; // OK.
549 case 1: return 1; // Now finalising.
550 default: // Error.
551 maybe_do_notification(as->asfd, ret,
552 "", "error in check_for_rubble()",
553 "", buf_to_notify_str(rbuf), cconfs);
554 return -1;
555 }
556
557 if(!strncmp_w(rbuf->buf, "Delete "))
558 return run_delete(as->asfd, sdirs, cconfs);
559
560 // Only backup action left to deal with.
561 working = server_get_working(NULL);
562 max_parallel_backups = get_int(cconfs[OPT_MAX_PARALLEL_BACKUPS]);
563
564 logp("%d/%d working (cur/max)\n", working, max_parallel_backups);
565
566 if(max_parallel_backups && working >= max_parallel_backups)
567 {
568 struct asfd *asfd=as->asfd;
569 logp("max parallel backups reached\n");
570 return asfd->write_str(asfd, CMD_GEN, "max parallel backups");
571 }
572
573 ret=run_backup(as, sdirs,
574 cconfs, incexc, timer_ret, resume);
575
576 // If this is a backup failure and the client has more servers
577 // to failover to, do not notify.
578 if(ret
579 && get_int(cconfs[OPT_N_FAILURE_BACKUP_FAILOVERS_LEFT])
580 && get_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT]))
581 return ret;
582
583 if(*timer_ret<0)
584 maybe_do_notification(as->asfd, ret,
585 "", "error running timer script",
586 "", "backup", cconfs);
587 else if(!*timer_ret)
588 maybe_do_notification(as->asfd, ret,
589 sdirs->client, sdirs->current,
590 "log", "backup", cconfs);
591 return ret;
592 }
593
run_action_server(struct async * as,const char * incexc,int srestore,int * timer_ret,struct conf ** cconfs)594 int run_action_server(struct async *as,
595 const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
596 {
597 int ret=-1;
598 struct sdirs *sdirs=NULL;
599 if((sdirs=sdirs_alloc())
600 && !sdirs_init_from_confs(sdirs, cconfs))
601 ret=run_action_server_do(as,
602 sdirs, incexc, srestore, timer_ret, cconfs);
603 if(sdirs) lock_release(sdirs->lock_storage_for_write);
604 sdirs_free(&sdirs);
605 return ret;
606 }
607