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