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(&copy);
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