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