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