Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../attribs.h"
6 : #include "../berrno.h"
7 : #include "../cmd.h"
8 : #include "../cntr.h"
9 : #include "../fsops.h"
10 : #include "../handy.h"
11 : #include "../pathcmp.h"
12 : #include "../log.h"
13 : #include "../prepend.h"
14 : #include "cvss.h"
15 : #include "restore_switch.h"
16 : #include "restore.h"
17 :
18 0 : int restore_interrupt(struct asfd *asfd,
19 : struct sbuf *sb, const char *msg, struct cntr *cntr)
20 : {
21 0 : int ret=-1;
22 0 : char *path=NULL;
23 0 : struct iobuf *rbuf=asfd->rbuf;
24 :
25 0 : if(cntr)
26 : {
27 0 : cntr_add(cntr, CMD_WARNING, 1);
28 0 : logp("WARNING: %s\n", msg);
29 0 : if(asfd->write_str(asfd, CMD_WARNING, msg))
30 : goto end;
31 : }
32 :
33 0 : if(!iobuf_is_filedata(&sb->path)
34 0 : && !iobuf_is_vssdata(&sb->path))
35 : {
36 : // Do not need to do anything.
37 : ret=0;
38 : goto end;
39 : }
40 :
41 : // If it is file data, get the server
42 : // to interrupt the flow and move on.
43 :
44 0 : path=sb->datapth.buf;
45 :
46 0 : if(!path)
47 : {
48 : ret=0;
49 : goto end;
50 : }
51 :
52 0 : if(asfd->write_str(asfd, CMD_INTERRUPT, path))
53 : goto end;
54 :
55 : // Read to the end file marker.
56 : while(1)
57 : {
58 0 : iobuf_free_content(rbuf);
59 0 : if(asfd->read(asfd))
60 : goto end; // Error.
61 0 : if(!rbuf->len)
62 0 : continue;
63 :
64 0 : switch(rbuf->cmd)
65 : {
66 : case CMD_APPEND:
67 0 : continue;
68 : case CMD_END_FILE:
69 : ret=0;
70 : goto end;
71 : default:
72 0 : iobuf_log_unexpected(rbuf, __func__);
73 0 : goto end;
74 : }
75 : }
76 : end:
77 0 : iobuf_free_content(rbuf);
78 0 : return ret;
79 : }
80 :
81 4 : static int make_link(
82 : #ifdef HAVE_WIN32
83 : struct asfd *asfd,
84 : struct cntr *cntr,
85 : #endif
86 : const char *fname, const char *lnk,
87 : enum cmd cmd, const char *restore_desired_dir)
88 : {
89 4 : int ret=-1;
90 :
91 : #ifdef HAVE_WIN32
92 : logw(asfd, cntr, "windows seems not to support hardlinks or symlinks\n");
93 : #else
94 4 : unlink(fname);
95 4 : if(cmd==CMD_HARD_LINK)
96 : {
97 1 : char *flnk=NULL;
98 1 : if(!(flnk=prepend_s(restore_desired_dir, lnk)))
99 : {
100 0 : log_out_of_memory(__func__);
101 0 : return -1;
102 : }
103 : //printf("%s -> %s\n", fname, flnk);
104 1 : ret=link(flnk, fname);
105 1 : free_w(&flnk);
106 : }
107 3 : else if(cmd==CMD_SOFT_LINK)
108 : {
109 : //printf("%s -> %s\n", fname, lnk);
110 3 : ret=symlink(lnk, fname);
111 : }
112 : else
113 : {
114 0 : logp("unexpected link command: %c\n", cmd);
115 0 : ret=-1;
116 : }
117 : #endif
118 :
119 4 : if(ret) logp("could not %slink %s -> %s: %s\n",
120 : cmd==CMD_HARD_LINK?"hard":"sym",
121 0 : fname, lnk, strerror(errno));
122 :
123 : return ret;
124 : }
125 :
126 : // FIX THIS: Maybe should be in bfile.c.
127 4 : enum ofr_e open_for_restore(struct asfd *asfd,
128 : struct BFILE *bfd, const char *path,
129 : struct sbuf *sb, enum vss_restore vss_restore, struct cntr *cntr)
130 : {
131 : static int flags;
132 4 : if(bfd->mode!=BF_CLOSED)
133 : {
134 : #ifdef HAVE_WIN32
135 : if(bfd->path && !strcmp(bfd->path, path))
136 : {
137 : // Already open after restoring the VSS data.
138 : // Time now for the actual file data.
139 : return OFR_OK;
140 : }
141 : else
142 : {
143 : #endif
144 0 : if(bfd->close(bfd, asfd))
145 : {
146 0 : logp("error closing %s in %s()\n",
147 : path, __func__);
148 0 : return OFR_ERROR;
149 : }
150 : #ifdef HAVE_WIN32
151 : }
152 : #endif
153 : }
154 :
155 : #ifdef HAVE_WIN32
156 : // Some massive hacks to work around times that winattr was not
157 : // getting set correctly inside server side backups.
158 : // The EFS one will stop burp segfaulting when restoring affected
159 : // EFS files.
160 : if(sb->path.cmd==CMD_EFS_FILE)
161 : sb->winattr |= FILE_ATTRIBUTE_ENCRYPTED;
162 : if(S_ISDIR(sb->statp.st_mode))
163 : sb->winattr |= FILE_ATTRIBUTE_DIRECTORY;
164 : #endif
165 :
166 4 : bfile_init(bfd, sb->winattr, cntr);
167 4 : bfd->set_attribs_on_close=1;
168 4 : switch(vss_restore)
169 : {
170 : case VSS_RESTORE_OFF:
171 : #ifdef HAVE_WIN32
172 : bfd->set_win32_api(bfd, 0);
173 : #endif
174 0 : bfd->set_vss_strip(bfd, 0);
175 0 : break;
176 : case VSS_RESTORE_OFF_STRIP:
177 : #ifdef HAVE_WIN32
178 : bfd->set_win32_api(bfd, 0);
179 : #endif
180 0 : bfd->set_vss_strip(bfd, 1);
181 0 : break;
182 : case VSS_RESTORE_ON:
183 : #ifdef HAVE_WIN32
184 : bfd->set_win32_api(bfd, 1);
185 : #endif
186 4 : bfd->set_vss_strip(bfd, 0);
187 4 : break;
188 : }
189 4 : flags=O_WRONLY|O_BINARY
190 : #ifdef O_NOFOLLOW
191 : |O_NOFOLLOW
192 : #endif
193 : ;
194 4 : if(S_ISDIR(sb->statp.st_mode))
195 : {
196 : // Windows directories are treated as having file data.
197 0 : mkdir(path, 0777);
198 : }
199 : else
200 : {
201 4 : flags|=O_CREAT|O_TRUNC;
202 :
203 : // Unlink first, so that a new file is created instead of
204 : // overwriting an existing file in place. Should be safer in
205 : // cases where the old file was hardlinked everywhere.
206 4 : if(unlink(path) && errno!=ENOENT)
207 : {
208 0 : char msg[256]="";
209 0 : snprintf(msg, sizeof(msg),
210 : "Cannot unlink before restore: '%s': %s",
211 : path, strerror(errno));
212 0 : if(restore_interrupt(asfd, sb, msg, cntr))
213 : return OFR_ERROR;
214 0 : return OFR_CONTINUE;
215 : }
216 : }
217 :
218 4 : if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR))
219 : {
220 : struct berrno be;
221 0 : berrno_init(&be);
222 0 : char msg[256]="";
223 0 : snprintf(msg, sizeof(msg), "Could not open for writing %s: %s",
224 0 : path, berrno_bstrerror(&be, errno));
225 0 : if(restore_interrupt(asfd, sb, msg, cntr))
226 : return OFR_ERROR;
227 0 : return OFR_CONTINUE;
228 : }
229 : // Add attributes to bfd so that they can be set when it is closed.
230 4 : bfd->winattr=sb->winattr;
231 4 : memcpy(&bfd->statp, &sb->statp, sizeof(struct stat));
232 4 : return OFR_OK;
233 : }
234 :
235 : static char *build_msg(const char *text, const char *param)
236 : {
237 : static char msg[256]="";
238 0 : snprintf(msg, sizeof(msg), text, param);
239 : return msg;
240 : }
241 :
242 : #ifndef HAVE_WIN32
243 0 : static void do_logw(struct asfd *asfd, struct cntr *cntr,
244 : const char *text, const char *param)
245 : {
246 0 : logw(asfd, cntr, "%s", build_msg(text, param));
247 0 : }
248 : #endif
249 :
250 : static int warn_and_interrupt(struct asfd *asfd, struct sbuf *sb,
251 : struct cntr *cntr, const char *text, const char *param)
252 : {
253 0 : return restore_interrupt(asfd, sb, build_msg(text, param), cntr);
254 : }
255 :
256 0 : static int restore_special(struct asfd *asfd, struct sbuf *sb,
257 : const char *fname, enum action act, struct cntr *cntr)
258 : {
259 0 : int ret=0;
260 0 : char *rpath=NULL;
261 : #ifdef HAVE_WIN32
262 : logw(asfd, cntr, "Cannot restore special files to Windows: %s\n", fname);
263 : goto end;
264 : #else
265 0 : struct stat statp=sb->statp;
266 :
267 0 : if(act==ACTION_VERIFY)
268 : {
269 0 : cntr_add(cntr, CMD_SPECIAL, 1);
270 0 : return 0;
271 : }
272 :
273 0 : if(build_path(fname, "", &rpath, NULL))
274 : {
275 : // failed - do a warning
276 0 : if(restore_interrupt(asfd, sb,
277 0 : build_msg("build path failed: %s", fname),
278 : cntr))
279 0 : ret=-1;
280 : goto end;
281 : }
282 0 : if(S_ISFIFO(statp.st_mode))
283 : {
284 0 : if(mkfifo(rpath, statp.st_mode) && errno!=EEXIST)
285 0 : do_logw(asfd, cntr,
286 0 : "Cannot make fifo: %s\n", strerror(errno));
287 : else
288 : {
289 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
290 0 : cntr_add(cntr, CMD_SPECIAL, 1);
291 : }
292 : }
293 0 : else if(S_ISSOCK(statp.st_mode))
294 : {
295 0 : if(mksock(rpath))
296 0 : do_logw(asfd, cntr,
297 0 : "Cannot make socket: %s\n", strerror(errno));
298 : else
299 : {
300 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
301 0 : cntr_add(cntr, CMD_SPECIAL, 1);
302 : }
303 : }
304 : #ifdef S_IFDOOR // Solaris high speed RPC mechanism
305 : else if (S_ISDOOR(statp.st_mode))
306 : do_logw(asfd, cntr,
307 : "Skipping restore of door file: %s\n", fname);
308 : #endif
309 : #ifdef S_IFPORT // Solaris event port for handling AIO
310 : else if (S_ISPORT(statp.st_mode))
311 : do_logw(asfd, cntr,
312 : "Skipping restore of event port file: %s\n", fname);
313 : #endif
314 0 : else if(mknod(fname, statp.st_mode, statp.st_rdev) && errno!=EEXIST)
315 0 : do_logw(asfd, cntr, "Cannot make node: %s\n", strerror(errno));
316 : else
317 : {
318 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
319 0 : cntr_add(cntr, CMD_SPECIAL, 1);
320 : }
321 : #endif
322 : end:
323 0 : free_w(&rpath);
324 0 : return ret;
325 : }
326 :
327 0 : int restore_dir(struct asfd *asfd, struct sbuf *sb,
328 : const char *dname, enum action act, struct cntr *cntr)
329 : {
330 0 : int ret=0;
331 0 : char *rpath=NULL;
332 0 : if(act==ACTION_RESTORE)
333 : {
334 0 : if(build_path(dname, "", &rpath, NULL))
335 : {
336 0 : ret=warn_and_interrupt(asfd, sb, cntr,
337 : "build path failed: %s", dname);
338 0 : goto end;
339 : }
340 0 : else if(is_dir_lstat(rpath)<=0)
341 : {
342 0 : if(mkdir(rpath, 0777))
343 : {
344 0 : ret=warn_and_interrupt(asfd, sb, cntr,
345 0 : "mkdir error: %s", strerror(errno));
346 0 : goto end;
347 : }
348 : }
349 0 : attribs_set(asfd, rpath, &(sb->statp), sb->winattr, cntr);
350 0 : if(!ret) cntr_add(cntr, sb->path.cmd, 1);
351 : }
352 0 : else cntr_add(cntr, sb->path.cmd, 1);
353 : end:
354 0 : free_w(&rpath);
355 0 : return ret;
356 : }
357 :
358 4 : static int restore_link(struct asfd *asfd, struct sbuf *sb,
359 : const char *fname, enum action act, struct cntr *cntr,
360 : const char *restore_desired_dir)
361 : {
362 4 : int ret=0;
363 :
364 4 : if(act==ACTION_RESTORE)
365 : {
366 4 : char *rpath=NULL;
367 4 : if(build_path(fname, "", &rpath, NULL))
368 : {
369 0 : ret=warn_and_interrupt(asfd, sb, cntr,
370 : "build path failed: %s", fname);
371 0 : goto end;
372 : }
373 8 : else if(make_link(
374 : #ifdef HAVE_WIN32
375 : asfd,
376 : cntr,
377 : #endif
378 4 : fname, sb->link.buf,
379 : sb->link.cmd, restore_desired_dir))
380 : {
381 0 : ret=warn_and_interrupt(asfd, sb, cntr,
382 : "could not create link", "");
383 0 : goto end;
384 : }
385 : else if(!ret)
386 : {
387 4 : attribs_set(asfd, fname,
388 : &(sb->statp), sb->winattr, cntr);
389 4 : cntr_add(cntr, sb->path.cmd, 1);
390 : }
391 4 : free_w(&rpath);
392 : }
393 0 : else cntr_add(cntr, sb->path.cmd, 1);
394 : end:
395 4 : return ret;
396 : }
397 :
398 : static void strip_invalid_characters(char **path)
399 : {
400 : #ifdef HAVE_WIN32
401 : char *ch = *path;
402 : if (ch[0] != 0 && ch[1] != 0) {
403 : ch += 2;
404 : while (*ch) {
405 : switch (*ch) {
406 : case ':':
407 : case '<':
408 : case '>':
409 : case '*':
410 : case '?':
411 : case '|':
412 : *ch = '_';
413 : break;
414 : }
415 : ch++;
416 : }
417 : }
418 : #endif
419 : }
420 :
421 : static const char *act_str(enum action act)
422 : {
423 : static const char *ret=NULL;
424 12 : if(act==ACTION_RESTORE) ret="restore";
425 0 : else ret="verify";
426 12 : return ret;
427 : }
428 :
429 : #ifndef UTEST
430 : static
431 : #endif
432 7 : void strip_from_path(char *path, const char *strip)
433 : {
434 : char *p;
435 : char *src;
436 : size_t len;
437 14 : if(!path
438 7 : || !strip
439 6 : || strlen(path)<=strlen(strip)
440 5 : || !(p=strstr(path, strip)))
441 : return;
442 :
443 5 : len=strlen(p)-strlen(strip)+1;
444 5 : src=p+strlen(strip);
445 5 : memmove(p, src, len);
446 : }
447 :
448 :
449 : // Return 1 for ok, -1 for error, 0 for too many components stripped.
450 0 : static int strip_path_components(struct asfd *asfd,
451 : struct sbuf *sb, int strip, struct cntr *cntr)
452 : {
453 0 : int s=0;
454 0 : char *tmp=NULL;
455 0 : char *cp=sb->path.buf;
456 0 : char *dp=NULL;
457 0 : for(s=0; cp && *cp && s<strip; s++)
458 : {
459 0 : if(!(dp=strchr(cp, '/')))
460 : {
461 0 : char msg[256]="";
462 0 : snprintf(msg, sizeof(msg),
463 : "Stripped too many components: %s",
464 : iobuf_to_printable(&sb->path));
465 0 : if(restore_interrupt(asfd, sb, msg, cntr))
466 : return -1;
467 0 : return 0;
468 : }
469 0 : cp=dp+1;
470 : }
471 0 : if(!cp)
472 : {
473 0 : char msg[256]="";
474 0 : snprintf(msg, sizeof(msg),
475 : "Stripped too many components: %s",
476 : iobuf_to_printable(&sb->path));
477 0 : if(restore_interrupt(asfd, sb, msg, cntr))
478 : return -1;
479 0 : return 0;
480 : }
481 0 : if(!(tmp=strdup_w(cp, __func__)))
482 : return -1;
483 0 : free_w(&sb->path.buf);
484 0 : sb->path.buf=tmp;
485 0 : return 1;
486 : }
487 :
488 9 : static int overwrite_ok(struct sbuf *sb,
489 : int overwrite,
490 : #ifdef HAVE_WIN32
491 : struct BFILE *bfd,
492 : #endif
493 : const char *fullpath)
494 : {
495 : struct stat checkstat;
496 :
497 : // User specified overwrite is OK.
498 : #ifdef HAVE_WIN32
499 : if(overwrite) return 1;
500 : #else
501 : // User specified overwrite is OK,
502 : // UNLESS we are trying to overwrite the file with trailing VSS data.
503 9 : if(overwrite)
504 0 : return (sb->path.cmd!=CMD_VSS_T
505 0 : && sb->path.cmd!=CMD_ENC_VSS_T);
506 : #endif
507 :
508 9 : if(!S_ISDIR(sb->statp.st_mode)
509 9 : && sb->path.cmd!=CMD_METADATA
510 9 : && sb->path.cmd!=CMD_ENC_METADATA
511 9 : && sb->path.cmd!=CMD_VSS
512 9 : && sb->path.cmd!=CMD_ENC_VSS)
513 : {
514 : #ifdef HAVE_WIN32
515 : // If Windows previously got some VSS data, it needs to append
516 : // the file data to the already open bfd.
517 : // And trailing VSS data.
518 : if(bfd->mode!=BF_CLOSED
519 : && (sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE
520 : || sb->path.cmd==CMD_VSS_T || sb->path.cmd==CMD_ENC_VSS_T)
521 : && bfd->path && !strcmp(bfd->path, fullpath))
522 : return 1;
523 : #endif
524 : // If we have file data and the destination is
525 : // a fifo, it is OK to write to the fifo.
526 9 : if((sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE)
527 5 : && S_ISFIFO(sb->statp.st_mode))
528 : return 1;
529 :
530 : // File path exists. Do not overwrite.
531 9 : if(!lstat(fullpath, &checkstat)) return 0;
532 : }
533 :
534 : return 1;
535 : }
536 :
537 : #define RESTORE_STREAM "restore_stream"
538 : // Used to have "restore_spool". Removed for simplicity.
539 :
540 : static char *restore_style=NULL;
541 :
542 : static enum asl_ret restore_style_func(struct asfd *asfd,
543 : __attribute__ ((unused)) struct conf **confs,
544 : __attribute__ ((unused)) void *param)
545 : {
546 : char msg[32]="";
547 : restore_style=NULL;
548 : if(strcmp(asfd->rbuf->buf, RESTORE_STREAM))
549 : {
550 : iobuf_log_unexpected(asfd->rbuf, __func__);
551 : return ASL_END_ERROR;
552 : }
553 : snprintf(msg, sizeof(msg), "%s_ok", asfd->rbuf->buf);
554 : if(asfd->write_str(asfd, CMD_GEN, msg))
555 : return ASL_END_ERROR;
556 : restore_style=asfd->rbuf->buf;
557 : iobuf_init(asfd->rbuf);
558 : return ASL_END_OK;
559 : }
560 :
561 : static char *get_restore_style(struct asfd *asfd, struct conf **confs)
562 : {
563 5 : return strdup_w(RESTORE_STREAM, __func__);
564 : if(asfd->simple_loop(asfd, confs, NULL, __func__,
565 : restore_style_func)) return NULL;
566 : return restore_style;
567 : }
568 :
569 : #ifdef HAVE_WIN32
570 : #ifndef PATH_MAX
571 : #define PATH_MAX _MAX_PATH
572 : #endif
573 : #endif
574 :
575 0 : static char *get_restore_desired_dir(
576 : const char *restoreprefix,
577 : struct asfd *asfd,
578 : struct cntr *cntr
579 : ) {
580 0 : char *ret=NULL;
581 0 : char *path=NULL;
582 :
583 0 : if(
584 : #ifdef HAVE_WIN32
585 : isalpha(*restoreprefix) && *(restoreprefix+1)==':'
586 : #else
587 0 : *restoreprefix=='/'
588 : #endif
589 : ) {
590 0 : if(!(path=strdup_w(restoreprefix, __func__)))
591 : return NULL;
592 : }
593 : else
594 : {
595 : static char d[PATH_MAX];
596 0 : if(!getcwd(d, sizeof(d)))
597 : {
598 0 : logw(asfd, cntr,
599 : "Could not get current working directory: %s\n",
600 0 : strerror(errno));
601 0 : return NULL;
602 : }
603 0 : if(!(path=prepend_s(d, restoreprefix)))
604 : return NULL;
605 : }
606 :
607 : // Canonicalise the path so that we can protect against symlinks that
608 : // point outsired of the desired restore directory.
609 0 : if((ret=realpath(path, NULL)))
610 : goto end;
611 0 : if(errno!=ENOENT)
612 : goto realpath_error;
613 : // Try to create the directory if it did not exist, then try again.
614 0 : mkdir(path, 0777);
615 0 : if(!(ret=realpath(path, NULL)))
616 : goto realpath_error;
617 :
618 : end:
619 0 : free_w(&path);
620 0 : return ret;
621 :
622 : realpath_error:
623 0 : logp("%s: Could not get realpath in %s: %s\n",
624 : path, __func__, strerror(errno));
625 0 : free_w(&path);
626 0 : return NULL;
627 : }
628 :
629 : // Seems that windows has no dirname(), so do something similar instead.
630 0 : static int strip_trailing_component(char **path)
631 : {
632 0 : char *cp=NULL;
633 :
634 0 : if(**path=='/' && !*((*path)+1))
635 : return -1;
636 0 : if(!(cp=strrchr(*path, '/')))
637 : return -1;
638 0 : if(*path==cp)
639 0 : *(cp+1)='\0'; // Deal with '/somepath' in root, gives '/'.
640 : else
641 0 : *cp='\0'; // Deal with '/some/path', gives '/some'.
642 : return 0;
643 : }
644 :
645 0 : static int canonicalise(
646 : struct asfd *asfd,
647 : struct sbuf *sb,
648 : struct cntr *cntr,
649 : const char *restore_desired_dir,
650 : char **fullpath
651 : ) {
652 0 : int ret=-1;
653 0 : char *tmp=NULL;
654 0 : char *copy=NULL;
655 0 : char *canonical=NULL;
656 :
657 0 : if(!(copy=strdup_w(*fullpath, __func__)))
658 : goto end;
659 :
660 : // The realpath function does not work on entries that do not exist,
661 : // so we have to do complicated things.
662 : while(1)
663 : {
664 0 : if(strip_trailing_component(©))
665 : {
666 0 : char msg[512]="";
667 0 : snprintf(msg, sizeof(msg),
668 : "%s: Could not get dirname of '%s'",
669 : *fullpath, copy);
670 0 : if(restore_interrupt(asfd, sb, msg, cntr))
671 : goto end;
672 0 : ret=1;
673 0 : goto end;
674 : }
675 0 : if((canonical=realpath(copy, NULL)))
676 : break;
677 0 : if(errno!=ENOENT)
678 : {
679 0 : char msg[512]="";
680 0 : snprintf(msg, sizeof(msg),
681 : "%s: Could not get realpath of %s in %s: %s",
682 : *fullpath, copy, __func__, strerror(errno));
683 0 : if(restore_interrupt(asfd, sb, msg, cntr))
684 : goto end;
685 0 : ret=1;
686 0 : goto end;
687 : }
688 : }
689 :
690 : // Protect against malicious servers trying to install a symlink and
691 : // then files over the top of it to directories outside of the
692 : // desired directory.
693 0 : if(!is_subdir(restore_desired_dir, canonical))
694 : {
695 0 : char msg[512]="";
696 0 : snprintf(msg, sizeof(msg),
697 : "%s: Is not in a subdir of '%s'",
698 : *fullpath,
699 : restore_desired_dir);
700 0 : if(restore_interrupt(asfd, sb, msg, cntr))
701 : goto end;
702 0 : ret=1;
703 0 : goto end;
704 : }
705 :
706 : // Add the trailing content back onto the canonical path.
707 0 : if(!(tmp=prepend_s(canonical, (*fullpath)+strlen(copy))))
708 : goto end;
709 0 : free_w(fullpath);
710 0 : *fullpath=tmp;
711 :
712 0 : ret=0;
713 : end:
714 : // Cannot use free_w() because it was not allocated by alloc.c, and
715 : // I cannot implement realpath() it in alloc.c because I cannot get
716 : // Windows code to use alloc.c.
717 0 : if(canonical) free(canonical);
718 0 : free_w(©);
719 0 : return ret;
720 : }
721 :
722 5 : int do_restore_client(struct asfd *asfd,
723 : struct conf **confs, enum action act)
724 : {
725 5 : int ret=-1;
726 5 : char msg[512]="";
727 5 : struct sbuf *sb=NULL;
728 5 : struct BFILE *bfd=NULL;
729 5 : char *fullpath=NULL;
730 5 : char *style=NULL;
731 5 : char *restore_desired_dir=NULL;
732 5 : struct cntr *cntr=get_cntr(confs);
733 5 : int strip=get_int(confs[OPT_STRIP]);
734 5 : int overwrite=get_int(confs[OPT_OVERWRITE]);
735 5 : const char *strip_path=get_string(confs[OPT_STRIP_FROM_PATH]);
736 5 : const char *backup=get_string(confs[OPT_BACKUP]);
737 5 : const char *regex=get_string(confs[OPT_REGEX]);
738 5 : const char *encryption_password=
739 5 : get_string(confs[OPT_ENCRYPTION_PASSWORD]);
740 5 : enum vss_restore vss_restore=
741 5 : (enum vss_restore)get_int(confs[OPT_VSS_RESTORE]);
742 5 : const char *restore_list=get_string(confs[OPT_RESTORE_LIST]);
743 :
744 5 : if(act==ACTION_RESTORE)
745 : {
746 5 : const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
747 5 : if(!restore_prefix)
748 : {
749 0 : logw(NULL, cntr,
750 : "You must specify a restore directory (-d)!\n");
751 0 : goto error;
752 : }
753 5 : if(!strcmp(restore_prefix, "/")) {
754 : // Special case to try to help Windows users that are
755 : // trying to do "bare metal" restores. Let them give
756 : // '/' as the restore prefix, and have it mean that
757 : // everything gets restored back to the original
758 : // locations (this would work on Linux *without* this
759 : // special case anyway, but hey-ho).
760 : }
761 0 : else if(!(restore_desired_dir=get_restore_desired_dir(
762 : restore_prefix, asfd, cntr)))
763 : goto error;
764 : }
765 :
766 5 : if(!(bfd=bfile_alloc()))
767 : goto error;
768 :
769 5 : bfile_init(bfd, 0, cntr);
770 5 : bfd->set_attribs_on_close=1;
771 :
772 10 : snprintf(msg, sizeof(msg), "%s%s %s:%s",
773 : act_str(act),
774 : restore_list?" restore_list":"",
775 : backup?backup:"",
776 : regex?regex:"");
777 :
778 5 : logp("Doing %s\n", msg);
779 5 : if(asfd->write_str(asfd, CMD_GEN, msg))
780 : goto error;
781 5 : if(restore_list)
782 : {
783 0 : if(!strcmp(restore_list, "-"))
784 0 : restore_list="/dev/stdin";
785 0 : logp("Reading from: '%s'\n", restore_list);
786 0 : if(asfd_read_expect(asfd, CMD_GEN, "ok restore_list"))
787 : goto error;
788 0 : if(send_a_file(asfd, restore_list, cntr))
789 : goto error;
790 : }
791 : else
792 : {
793 5 : if(asfd_read_expect(asfd, CMD_GEN, "ok"))
794 : goto error;
795 : }
796 5 : logp("Doing %s confirmed\n", act_str(act));
797 5 : if(act==ACTION_RESTORE)
798 5 : logp("Directory: '%s'\n",
799 : restore_desired_dir ? restore_desired_dir : "/");
800 :
801 : #if defined(HAVE_WIN32)
802 : if(act==ACTION_RESTORE) win32_enable_backup_privileges();
803 : #endif
804 :
805 5 : logfmt("\n");
806 :
807 5 : if(cntr_recv(asfd, confs))
808 : goto error;
809 :
810 10 : if(!(style=get_restore_style(asfd, confs)))
811 : goto error;
812 :
813 5 : if(!(sb=sbuf_alloc()))
814 : {
815 0 : log_and_send_oom(asfd);
816 0 : goto error;
817 : }
818 :
819 : while(1)
820 : {
821 13 : sbuf_free_content(sb);
822 13 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
823 :
824 13 : switch(sbuf_fill_from_net(sb, asfd, cntr))
825 : {
826 : case 0: break;
827 2 : case 1: if(asfd->write_str(asfd, CMD_GEN,
828 : "restoreend ok")) goto error;
829 : goto end; // It was OK.
830 : default:
831 : case -1: goto error;
832 : }
833 :
834 9 : switch(sb->path.cmd)
835 : {
836 : case CMD_DIRECTORY:
837 : case CMD_FILE:
838 : case CMD_ENC_FILE:
839 : case CMD_SOFT_LINK:
840 : case CMD_HARD_LINK:
841 : case CMD_SPECIAL:
842 : case CMD_METADATA:
843 : case CMD_ENC_METADATA:
844 : case CMD_VSS:
845 : case CMD_ENC_VSS:
846 : case CMD_VSS_T:
847 : case CMD_ENC_VSS_T:
848 : case CMD_EFS_FILE:
849 9 : if(strip)
850 : {
851 : int s;
852 0 : s=strip_path_components(asfd,
853 : sb, strip, cntr);
854 0 : if(s<0) goto error;
855 0 : if(s==0)
856 : {
857 : // Too many components stripped
858 : // - carry on.
859 0 : continue;
860 : }
861 : // It is OK, sb.path is now stripped.
862 : }
863 9 : if(strip_path)
864 : {
865 0 : strip_from_path(sb->path.buf,
866 : strip_path);
867 : // Strip links if their path is absolute
868 0 : if(sb->link.buf && !is_absolute(sb->link.buf))
869 0 : strip_from_path(sb->link.buf,
870 : strip_path);
871 : }
872 9 : free_w(&fullpath);
873 9 : if(!(fullpath=prepend_s(restore_desired_dir,
874 9 : sb->path.buf)))
875 : {
876 0 : log_and_send_oom(asfd);
877 0 : goto error;
878 : }
879 :
880 9 : if(act==ACTION_RESTORE)
881 : {
882 9 : strip_invalid_characters(&fullpath);
883 : // canonicalise will fail on Windows split_vss
884 : // restores if we do not make sure bfd is
885 : // closed first.
886 9 : if(bfd
887 9 : && bfd->mode!=BF_CLOSED
888 0 : && bfd->path
889 0 : && strcmp(bfd->path, fullpath))
890 0 : bfd->close(bfd, asfd);
891 9 : if(restore_desired_dir) {
892 0 : switch(canonicalise(
893 : asfd,
894 : sb,
895 : cntr,
896 : restore_desired_dir,
897 : &fullpath
898 : )) {
899 : case 0: break;
900 0 : case 1: continue;
901 : default: goto error;
902 : }
903 : }
904 :
905 9 : if(!overwrite_ok(sb, overwrite,
906 : #ifdef HAVE_WIN32
907 : bfd,
908 : #endif
909 : fullpath))
910 : {
911 0 : char msg[512]="";
912 : // Something exists at that path.
913 0 : snprintf(msg, sizeof(msg),
914 : "Path exists: %s\n", fullpath);
915 0 : if(restore_interrupt(asfd,
916 : sb, msg, cntr))
917 : goto error;
918 0 : continue;
919 : }
920 : }
921 : break;
922 : case CMD_MESSAGE:
923 : case CMD_WARNING:
924 0 : log_recvd(&sb->path, cntr, 1);
925 0 : logfmt("\n");
926 0 : continue;
927 : default:
928 : break;
929 : }
930 :
931 9 : switch(sb->path.cmd)
932 : {
933 : case CMD_DIRECTORY:
934 0 : if(restore_dir(asfd, sb, fullpath, act, cntr))
935 : goto error;
936 0 : continue;
937 : case CMD_SOFT_LINK:
938 : case CMD_HARD_LINK:
939 4 : if(restore_link(asfd, sb, fullpath, act, cntr,
940 : restore_desired_dir))
941 : goto error;
942 4 : continue;
943 : case CMD_SPECIAL:
944 0 : if(restore_special(asfd, sb,
945 : fullpath, act, cntr))
946 : goto error;
947 0 : continue;
948 : default:
949 : break;
950 : }
951 :
952 5 : if(restore_switch(asfd, sb, fullpath, act,
953 : bfd, vss_restore, cntr, encryption_password))
954 : goto error;
955 : }
956 :
957 : end:
958 2 : ret=0;
959 : error:
960 : // It is possible for a fd to still be open.
961 5 : if(bfd)
962 : {
963 5 : bfd->close(bfd, asfd);
964 5 : bfile_free(&bfd);
965 : }
966 :
967 5 : cntr_print_end(cntr);
968 5 : cntr_set_bytes(cntr, asfd);
969 5 : cntr_print(cntr, act);
970 :
971 7 : if(!ret) logp("%s finished\n", act_str(act));
972 3 : else logp("ret: %d\n", ret);
973 :
974 5 : sbuf_free(&sb);
975 5 : free_w(&style);
976 5 : free_w(&fullpath);
977 :
978 : // Cannot use free_w() because it was not allocated by alloc.c, and
979 : // I cannot implement realpath() it in alloc.c because I cannot get
980 : // Windows code to use alloc.c.
981 5 : if(restore_desired_dir)
982 0 : free(restore_desired_dir);
983 :
984 5 : return ret;
985 : }
|