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