1 #include "burp.h"
2 #include "base64.h"
3 #include "cmd.h"
4 #include "conf.h"
5 #include "conffile.h"
6 #include "client/main.h"
7 #include "handy.h"
8 #include "hexmap.h"
9 #include "lock.h"
10 #include "log.h"
11 #include "strlist.h"
12 #include "server/main.h"
13 #include "server/protocol1/bedup.h"
14 #include "server/protocol2/bsigs.h"
15 #include "server/protocol2/bsparse.h"
16 #include "server/protocol2/champ_chooser/champ_server.h"
17 
usage_server(void)18 static void usage_server(void)
19 {
20 #ifndef HAVE_WIN32
21 	printf("\nThe configuration file specifies whether %s runs in server or client mode.\n", PACKAGE_TARNAME);
22 	printf("\nServer usage: %s [options]\n", progname());
23 	printf("\n");
24 	printf(" Options:\n");
25 	printf("  -a c          Run as a stand-alone champion chooser.\n");
26 	printf("  -c <path>     Path to conf file (default: %s).\n", config_default_path());
27 	printf("  -d <path>     a single client in the status monitor.\n");
28 	printf("  -o <option>   Override a given configuration option\n");
29 	printf("                (you can use this flag several times).\n");
30 	printf("  -F            Stay in the foreground.\n");
31 	printf("  -g            Generate initial CA certificates and exit.\n");
32 	printf("  -h|-?         Print this text and exit.\n");
33 	printf("  -i            Print index of symbols and exit.\n");
34 	printf("  -n            Do not fork any children (implies '-F').\n");
35 	printf("  -Q            Do not log to stdout\n");
36 	printf("  -t            Dry-run to test config file syntax.\n");
37 	printf("  -v            Log to stdout.\n");
38 	printf("  -V            Print version and exit.\n");
39 	printf("Options to use with '-a c':\n");
40 	printf("  -C <client>   Run as if forked via a connection from this client.\n");
41 	printf("\n");
42 #endif
43 }
44 
usage_client(void)45 static void usage_client(void)
46 {
47 	printf("\nClient usage: %s [options]\n", progname());
48 	printf("\n");
49 	printf(" Options:\n");
50 	printf("  -a <action>    The action can be one of the following.\n");
51 	printf("                  b: backup\n");
52 	printf("                  delete: delete\n");
53 	printf("                  d: diff\n");
54 	printf("                  e: estimate\n");
55 	printf("                  l: list (this is the default when an action is not given)\n");
56 	printf("                  L: long list\n");
57 	printf("                  m: monitor interface\n");
58 	printf("                  p: parseable list\n");
59 	printf("                  r: restore\n");
60 	printf("                  R: Restore (matching ordered paths on stdin)\n");
61 #ifndef HAVE_WIN32
62 	printf("                  s: status monitor (ncurses)\n");
63 	printf("                  S: status monitor snapshot\n");
64 #endif
65 	printf("                  t: timed backup\n");
66 	printf("                  T: check backup timer, but do not actually backup\n");
67 	printf("                  v: verify\n");
68 	printf("                  V: Verify (matching ordered paths on stdin)\n");
69 	printf("  -b <number>    Backup number (default: the most recent backup).\n");
70 	printf("  -c <path>      Path to conf file (default: %s).\n", config_default_path());
71 	printf("  -d <directory> Directory to restore to, or directory to list.\n");
72 	printf("  -o <option>    Override a given configuration option (you can use this flag several times).\n");
73 	printf("  -f             Allow overwrite during restore.\n");
74 	printf("  -h|-?          Print this text and exit.\n");
75 	printf("  -i             Print index of symbols and exit.\n");
76 	printf("  -q <max secs>  Randomised delay of starting a timed backup.\n");
77 	printf("  -Q             Do not log to stdout\n");
78 	printf("  -r|-R <regex> Specify a regular expression (case sensitive or insensitive.\n");
79 	printf("  -s <number>    Number of leading path components to strip during restore.\n");
80 	printf("  -t             Dry-run to test config file syntax.\n");
81 	printf("  -V             Print version and exit.\n");
82 	printf("  -v             Log to stdout.\n");
83 #ifdef HAVE_WIN32
84 	printf("  -X             Do not use the Windows VSS API when restoring.\n");
85 	printf("  -x             Do not use the Windows VSS API when restoring,\n");
86 	printf("                 and strip out VSS data.\n");
87 #else
88 	printf("  -x             Strip Windows VSS data when restoring.\n");
89 	printf("Options to use with '-a S':\n");
90 	printf("  -C <client>   Show a particular client.\n");
91 	printf("  -b <number>   Show listable files in a particular backup (requires -C).\n");
92 	printf("  -d <path>     Show a particular path in a backup (requires -C and -b).\n");
93 	printf("  -l <path>     Log file for the status monitor.\n");
94 	printf("  -z <file>     Dump a particular log file in a backup (requires -C and -b).\n");
95 #endif
96 	printf("\n");
97 #ifndef HAVE_WIN32
98 	printf(" See ");
99 	// Older versions of autoconf do not pick up PACKAGE_URL.
100 	#ifdef PACKAGE_URL
101 		printf("%s or ", PACKAGE_URL);
102 	#endif
103 	printf( "the man page ('man %s') for usage examples\n",
104 			PACKAGE_TARNAME);
105 	printf(" and additional configuration options.\n\n");
106 #else
107 	printf(" See %s for usage examples and additional configuration\n",
108 		PACKAGE_TARNAME);
109 	printf(" options.\n\n");
110 #endif
111 }
112 
reload(struct conf ** confs,const char * conffile,bool firsttime)113 int reload(struct conf **confs, const char *conffile, bool firsttime)
114 {
115 	if(!firsttime) logp("Reloading config\n");
116 
117 	if(confs_init(confs)) return -1;
118 
119 	if(conf_load_global_only(conffile, confs)) return -1;
120 
121 	umask(get_mode_t(confs[OPT_UMASK]));
122 
123 	// This will turn on syslogging which could not be turned on before
124 	// conf_load.
125 	log_fzp_set(NULL, confs);
126 
127 #ifndef HAVE_WIN32
128 	if(get_e_burp_mode(confs[OPT_BURP_MODE])==BURP_MODE_SERVER)
129 		setup_signals();
130 #endif
131 
132 	return 0;
133 }
134 
replace_conf_str(struct conf * conf,const char * newval)135 static int replace_conf_str(struct conf *conf, const char *newval)
136 {
137 	if(!newval) return 0;
138 	return set_string(conf, newval);
139 }
140 
usage(void)141 static void usage(void)
142 {
143 	usage_server();
144 	usage_client();
145 }
146 
parse_action(enum action * act,const char * optarg,struct strlist ** cli_overrides)147 static int parse_action(enum action *act, const char *optarg,
148 	struct strlist **cli_overrides)
149 {
150 	if(!strncmp(optarg, "backup", 1))
151 		*act=ACTION_BACKUP;
152 	else if(!strncmp(optarg, "timedbackup", 1))
153 		*act=ACTION_BACKUP_TIMED;
154 	else if(!strncmp(optarg, "Timercheck", 1))
155 		*act=ACTION_TIMER_CHECK;
156 	else if(!strncmp(optarg, "restore", 1))
157 		*act=ACTION_RESTORE;
158 	else if(!strncmp(optarg, "Restore", 1))
159 	{
160 		*act=ACTION_RESTORE;
161 		strlist_add(cli_overrides, "restore_list=/dev/stdin", 0);
162 	}
163 	else if(!strncmp(optarg, "verify", 1))
164 		*act=ACTION_VERIFY;
165 	else if(!strncmp(optarg, "Verify", 1))
166 	{
167 		*act=ACTION_VERIFY;
168 		strlist_add(cli_overrides, "restore_list=/dev/stdin", 0);
169 	}
170 	else if(!strncmp(optarg, "list", 1))
171 		*act=ACTION_LIST;
172 	else if(!strncmp(optarg, "List", 1))
173 		*act=ACTION_LIST_LONG;
174 	else if(!strncmp(optarg, "parseablelist", 1))
175 		*act=ACTION_LIST_PARSEABLE;
176 	else if(!strncmp(optarg, "status", 1))
177 		*act=ACTION_STATUS;
178 	else if(!strncmp(optarg, "Status", 1))
179 		*act=ACTION_STATUS_SNAPSHOT;
180 	else if(!strncmp(optarg, "estimate", 1))
181 		*act=ACTION_ESTIMATE;
182 	// Make them spell 'delete' out fully so that it is less likely to be
183 	// used accidently.
184 	else if(!strncmp_w(optarg, "delete"))
185 		*act=ACTION_DELETE;
186 	else if(!strncmp(optarg, "champchooser", 1))
187 		*act=ACTION_CHAMP_CHOOSER;
188 	else if(!strncmp(optarg, "diff", 1))
189 		*act=ACTION_DIFF;
190 	else if(!strncmp(optarg, "Diff", 1))
191 		*act=ACTION_DIFF_LONG;
192 	else if(!strncmp(optarg, "monitor", 1))
193 		*act=ACTION_MONITOR;
194 	else
195 	{
196 		usage();
197 		return -1;
198 	}
199 	return 0;
200 }
201 
202 #ifndef HAVE_WIN32
run_champ_chooser(struct conf ** confs)203 static int run_champ_chooser(struct conf **confs)
204 {
205 	const char *orig_client=get_string(confs[OPT_ORIG_CLIENT]);
206 	if(orig_client && *orig_client)
207 		return champ_chooser_server_standalone(confs);
208 	logp("No client name given for standalone champion chooser process.\n");
209 	logp("Try using the '-C' option.\n");
210 	return 1;
211 }
212 
server_modes(enum action act,const char * conffile,struct lock * lock,int generate_ca_only,struct conf ** confs)213 static int server_modes(enum action act,
214 	const char *conffile, struct lock *lock, int generate_ca_only,
215 	struct conf **confs)
216 {
217 	switch(act)
218 	{
219 		case ACTION_CHAMP_CHOOSER:
220 			// We are running on the server machine, wanting to
221 			// be a standalone champion chooser process.
222 			return run_champ_chooser(confs);
223 		default:
224 			return server(confs, conffile, lock, generate_ca_only);
225 	}
226 }
227 #endif
228 
random_delay(struct conf ** confs)229 static void random_delay(struct conf **confs)
230 {
231 	int delay;
232 	int randomise=get_int(confs[OPT_RANDOMISE]);
233 	if(!randomise) return;
234 	srand(getpid());
235 	delay=rand()%randomise;
236 	logp("Sleeping %d seconds\n", delay);
237 	sleep(delay);
238 }
239 
run_test_confs(struct conf ** confs,const char * client)240 static int run_test_confs(struct conf **confs, const char *client)
241 {
242 	int ret=-1;
243 	struct conf **cconfs=NULL;
244 	if(!client)
245 	{
246 		confs_dump(confs, 0);
247 		ret=0;
248 		goto end;
249 	}
250 	if(!(cconfs=confs_alloc()))
251 		goto end;
252 	confs_init(cconfs);
253 	if(set_string(cconfs[OPT_CNAME], client)
254 	  || set_string(cconfs[OPT_PEER_VERSION], PACKAGE_VERSION)
255 	  || conf_load_clientconfdir(confs, cconfs))
256 		goto end;
257 	confs_dump(cconfs, CONF_FLAG_CC_OVERRIDE|CONF_FLAG_INCEXC);
258 
259 end:
260 	confs_free(&cconfs);
261 	return ret;
262 }
263 
get_prog_lock(struct conf ** confs)264 static struct lock *get_prog_lock(struct conf **confs)
265 {
266 	struct lock *lock=NULL;
267 	const char *lockfile=confs_get_lockfile(confs);
268 	if(!(lock=lock_alloc_and_init(lockfile)))
269 		goto error;
270 	lock_get(lock);
271 	switch(lock->status)
272 	{
273 		case GET_LOCK_GOT:
274 			return lock;
275 		case GET_LOCK_NOT_GOT:
276 			logp("Could not get lockfile.\n");
277 			logp("Another process is probably running.\n");
278 			goto error;
279 		case GET_LOCK_ERROR:
280 		default:
281 			logp("Could not get lockfile.\n");
282 			logp("Maybe you do not have permissions to write to %s.\n", lockfile);
283 			goto error;
284 	}
285 error:
286 	lock_free(&lock);
287 	return NULL;
288 }
289 
290 #ifdef HAVE_WIN32
291 #define main RealMain
292 #endif
293 #ifndef UTEST
294 static
295 #endif
real_main(int argc,char * argv[])296 int real_main(int argc, char *argv[])
297 {
298 	int ret=1;
299 	int option=0;
300 	int daemon=1;
301 	int forking=1;
302 	int strip=0;
303 	int randomise=0;
304 	struct lock *lock=NULL;
305 	struct conf **confs=NULL;
306 	int forceoverwrite=0;
307 	enum action act=ACTION_LIST;
308 	const char *backup=NULL;
309 	const char *backup2=NULL;
310 	char *restoreprefix=NULL;
311 	char *stripfrompath=NULL;
312 	const char *regex=NULL;
313 	const char *browsefile=NULL;
314 	char *browsedir=NULL;
315 	const char *conffile=config_default_path();
316 	const char *orig_client=NULL;
317 	const char *logfile=NULL;
318 	// The orig_client is the original client that the normal client
319 	// would like to restore from.
320 #ifndef HAVE_WIN32
321 	int generate_ca_only=0;
322 #endif
323 	enum vss_restore vss_restore=VSS_RESTORE_ON;
324 	int test_confs=0;
325 	enum burp_mode mode;
326 	struct strlist *cli_overrides=NULL;
327 	int keep_readall_caps=0;
328 	int regex_case_insensitive=0;
329 
330 	log_init(argv[0]);
331 #ifndef HAVE_WIN32
332 	if(!strcmp(prog, "bedup"))
333 		return run_bedup(argc, argv);
334 	if(!strcmp(prog, "bsigs"))
335 		return run_bsigs(argc, argv);
336 	if(!strcmp(prog, "bsparse"))
337 		return run_bsparse(argc, argv);
338 #endif
339 
340 	while((option=getopt(argc, argv, "a:b:C:c:d:o:Ffghijl:nQq:R:r:s:tVvXxz:?"))!=-1)
341 	{
342 		switch(option)
343 		{
344 			case 'a':
345 				if(parse_action(&act, optarg,
346 					&cli_overrides)) goto end;
347 				break;
348 			case 'b':
349 				// The diff command may have two backups
350 				// specified.
351 				if(!backup2 && backup) backup2=optarg;
352 				if(!backup) backup=optarg;
353 				break;
354 			case 'C':
355 				orig_client=optarg;
356 				break;
357 			case 'c':
358 				conffile=optarg;
359 				break;
360 			case 'd':
361 				restoreprefix=optarg; // for restores
362 				browsedir=optarg; // for lists
363 				break;
364 			case 'F':
365 				daemon=0;
366 				break;
367 			case 'f':
368 				forceoverwrite=1;
369 				break;
370 			case 'g':
371 #ifndef HAVE_WIN32
372 				generate_ca_only=1;
373 #endif
374 				break;
375 			case 'i':
376 				cmd_print_all();
377 				ret=0;
378 				goto end;
379 			case 'l':
380 				logfile=optarg;
381 				break;
382 			case 'n':
383 				forking=0;
384 				break;
385 			case 'o':
386 				strlist_add(&cli_overrides, optarg, 0);
387 				break;
388 			case 'Q':
389 				strlist_add(&cli_overrides, "progress_counter=0", 0);
390 				strlist_add(&cli_overrides, "stdout=0", 0);
391 				break;
392 			case 'q':
393 				randomise=atoi(optarg);
394 				break;
395 			case 'R':
396 				regex_case_insensitive=1;
397 				regex=optarg;
398 				break;
399 			case 'r':
400 				regex_case_insensitive=0;
401 				regex=optarg;
402 				break;
403 			case 's':
404 				strip=atoi(optarg);
405 				break;
406 			case 'V':
407 				printf("%s-%s\n", progname(), PACKAGE_VERSION);
408 				ret=0;
409 				goto end;
410 			case 'v':
411 				strlist_add(&cli_overrides, "stdout=1", 0);
412 				break;
413 			case 'X':
414 				vss_restore=VSS_RESTORE_OFF;
415 				break;
416 			case 'x':
417 				vss_restore=VSS_RESTORE_OFF_STRIP;
418 				break;
419 			case 't':
420 				test_confs=1;
421 				break;
422 			case 'z':
423 				browsefile=optarg;
424 				break;
425 			case 'h':
426 			case '?':
427 			default:
428 				usage();
429 				goto end;
430 		}
431 	}
432 	if(optind<argc)
433 	{
434 		usage();
435 		goto end;
436 	}
437 
438 	if(act==ACTION_MONITOR)
439 	{
440 		// Try to output everything in JSON.
441 		log_set_json(1);
442 		// Need to do this so that processes reading stdout get the
443 		// result of the printfs of logp straight away.
444 		setvbuf(stdout, NULL, _IONBF, 0);
445 	}
446 
447 	if(act==ACTION_LIST_PARSEABLE)
448 		strlist_add(&cli_overrides, "stdout=0", 0);
449 
450 	conf_set_cli_overrides(cli_overrides);
451 	if(!(confs=confs_alloc()))
452 		goto end;
453 
454 	if(reload(confs, conffile, 1))
455 		goto end;
456 
457 	// Dry run to test config file syntax.
458 	if(test_confs)
459 	{
460 		ret=run_test_confs(confs, orig_client);
461 		goto end;
462 	}
463 
464 	if(!backup) switch(act)
465 	{
466 		case ACTION_DELETE:
467 			logp("No backup specified for deletion.\n");
468 			goto end;
469 		case ACTION_RESTORE:
470 		case ACTION_VERIFY:
471 		case ACTION_DIFF:
472 		case ACTION_DIFF_LONG:
473 			logp("No backup specified. Using the most recent.\n");
474 			backup="0";
475 		default:
476 			break;
477 	}
478 	if(!backup2) switch(act)
479 	{
480 		case ACTION_DIFF:
481 		case ACTION_DIFF_LONG:
482 			logp("No second backup specified. Using file system scan.\n");
483 			backup2="n"; // For 'next'.
484 		default:
485 			break;
486 	}
487 
488 	// The logfile option is only used for the status client stuff.
489 	if(logfile
490 	  && (act!=ACTION_STATUS
491 		&& act!=ACTION_STATUS_SNAPSHOT))
492 			logp("-l <logfile> option obsoleted\n");
493 
494 	if(orig_client
495 	  && *orig_client
496 	  && set_string(confs[OPT_ORIG_CLIENT], orig_client))
497 		goto end;
498 
499 	// The random delay needs to happen before the lock is got, otherwise
500 	// you would never be able to use burp by hand.
501 	if(randomise) set_int(confs[OPT_RANDOMISE], randomise);
502 	mode=get_e_burp_mode(confs[OPT_BURP_MODE]);
503 	if(mode==BURP_MODE_CLIENT
504 	  && (act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK))
505 		random_delay(confs);
506 
507 	if(mode==BURP_MODE_SERVER)
508 	{
509 		switch(act)
510 		{
511 			case ACTION_CHAMP_CHOOSER:
512 				// Need to run without getting the lock.
513 				break;
514 			default:
515 				if(!(lock=get_prog_lock(confs)))
516 					goto end;
517 				break;
518 		}
519 	}
520 	else if(mode==BURP_MODE_CLIENT)
521 	{
522 		set_int(confs[OPT_VSS_RESTORE], vss_restore);
523 		switch(act)
524 		{
525 			case ACTION_BACKUP:
526 			case ACTION_BACKUP_TIMED:
527 			case ACTION_TIMER_CHECK:
528 #ifdef ENABLE_KEEP_READALL_CAPS_SUPPORT
529 				keep_readall_caps=get_int(confs[OPT_READALL]);
530 				// readall=1 cannot work with atime=0 (O_NOATIME)
531 				if (keep_readall_caps)
532 					set_int(confs[OPT_ATIME], 1);
533 #endif
534 				// Need to get the lock.
535 				if(!(lock=get_prog_lock(confs)))
536 					goto end;
537 				break;
538 			default:
539 				break;
540 		}
541 	}
542 
543 	// Change privileges after having got the lock, for convenience.
544 	if(chuser_and_or_chgrp(
545 		get_string(confs[OPT_USER]), get_string(confs[OPT_GROUP]),
546 		keep_readall_caps))
547 			return -1;
548 
549 	set_int(confs[OPT_OVERWRITE], forceoverwrite);
550 	set_int(confs[OPT_STRIP], strip);
551 	set_int(confs[OPT_FORK], forking);
552 	set_int(confs[OPT_DAEMON], daemon);
553 	set_int(confs[OPT_REGEX_CASE_INSENSITIVE], regex_case_insensitive);
554 
555 	strip_trailing_slashes(&restoreprefix);
556 	strip_trailing_slashes(&browsedir);
557 	if(replace_conf_str(confs[OPT_BACKUP], backup)
558 	  || replace_conf_str(confs[OPT_BACKUP2], backup2)
559 	  || replace_conf_str(confs[OPT_RESTOREPREFIX], restoreprefix)
560 	  || replace_conf_str(confs[OPT_STRIP_FROM_PATH], stripfrompath)
561 	  || replace_conf_str(confs[OPT_REGEX], regex)
562 	  || replace_conf_str(confs[OPT_BROWSEFILE], browsefile)
563 	  || replace_conf_str(confs[OPT_BROWSEDIR], browsedir)
564 	  || replace_conf_str(confs[OPT_MONITOR_LOGFILE], logfile))
565 		goto end;
566 
567 	base64_init();
568 	hexmap_init();
569 
570 	if(mode==BURP_MODE_SERVER)
571 	{
572 #ifdef HAVE_WIN32
573 		logp("Sorry, server mode is not implemented for Windows.\n");
574 #else
575 		ret=server_modes(act,
576 			conffile, lock, generate_ca_only, confs);
577 #endif
578 	}
579 	else
580 	{
581 		ret=client(confs, act);
582 	}
583 
584 end:
585 	lock_release(lock);
586 	lock_free(&lock);
587 	confs_free(&confs);
588 	strlists_free(&cli_overrides);
589 	return ret;
590 }
591 
592 #ifndef UTEST
main(int argc,char * argv[])593 int main(int argc, char *argv[])
594 {
595 	return real_main(argc, argv);
596 }
597 #endif
598