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