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 "../protocol2/blk.h"
15 : #include "cvss.h"
16 : #include "protocol1/restore.h"
17 : #include "protocol2/restore.h"
18 : #include "restore.h"
19 :
20 7 : int restore_interrupt(struct asfd *asfd,
21 : struct sbuf *sb, const char *msg, struct cntr *cntr,
22 : enum protocol protocol)
23 : {
24 7 : int ret=-1;
25 7 : char *path=NULL;
26 7 : struct iobuf *rbuf=asfd->rbuf;
27 :
28 7 : if(cntr)
29 : {
30 0 : cntr_add(cntr, CMD_WARNING, 1);
31 0 : logp("WARNING: %s\n", msg);
32 0 : if(asfd->write_str(asfd, CMD_WARNING, msg))
33 : goto end;
34 : }
35 :
36 7 : if(!iobuf_is_filedata(&sb->path)
37 0 : && !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 7 : if(protocol==PROTO_1)
48 0 : path=sb->protocol1->datapth.buf;
49 7 : else if(protocol==PROTO_2)
50 7 : path=sb->path.buf;
51 :
52 7 : if(!path)
53 : {
54 : ret=0;
55 : goto end;
56 : }
57 :
58 7 : if(asfd->write_str(asfd, CMD_INTERRUPT, path))
59 : goto end;
60 :
61 : // Read to the end file marker.
62 : while(1)
63 : {
64 714 : iobuf_free_content(rbuf);
65 714 : if(asfd->read(asfd))
66 : goto end; // Error.
67 714 : if(!rbuf->len)
68 0 : continue;
69 :
70 714 : switch(rbuf->cmd)
71 : {
72 : case CMD_APPEND:
73 : case CMD_DATA:
74 707 : continue;
75 : case CMD_END_FILE:
76 : ret=0;
77 : goto end;
78 : default:
79 0 : iobuf_log_unexpected(rbuf, __func__);
80 0 : goto end;
81 : }
82 : }
83 : end:
84 7 : iobuf_free_content(rbuf);
85 7 : return ret;
86 : }
87 :
88 6 : 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 6 : int ret=-1;
97 :
98 : #ifdef HAVE_WIN32
99 : logw(asfd, cntr, "windows seems not to support hardlinks or symlinks\n");
100 : #else
101 6 : unlink(fname);
102 6 : if(cmd==CMD_HARD_LINK)
103 : {
104 1 : char *flnk=NULL;
105 1 : if(!(flnk=prepend_s(restore_desired_dir, lnk)))
106 : {
107 0 : log_out_of_memory(__func__);
108 0 : return -1;
109 : }
110 : //printf("%s -> %s\n", fname, flnk);
111 1 : ret=link(flnk, fname);
112 1 : free_w(&flnk);
113 : }
114 5 : else if(cmd==CMD_SOFT_LINK)
115 : {
116 : //printf("%s -> %s\n", fname, lnk);
117 5 : ret=symlink(lnk, fname);
118 : }
119 : else
120 : {
121 0 : logp("unexpected link command: %c\n", cmd);
122 0 : ret=-1;
123 : }
124 : #endif
125 :
126 6 : if(ret) logp("could not %slink %s -> %s: %s\n",
127 : cmd==CMD_HARD_LINK?"hard":"sym",
128 0 : fname, lnk, strerror(errno));
129 :
130 : return ret;
131 : }
132 :
133 : // FIX THIS: Maybe should be in bfile.c.
134 18 : 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 18 : 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 0 : if(bfd->close(bfd, asfd))
153 : {
154 0 : logp("error closing %s in %s()\n",
155 : path, __func__);
156 0 : 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 18 : bfile_init(bfd, sb->winattr, cntr);
175 18 : bfd->set_attribs_on_close=1;
176 18 : switch(vss_restore)
177 : {
178 : case VSS_RESTORE_OFF:
179 : #ifdef HAVE_WIN32
180 : bfd->set_win32_api(bfd, 0);
181 : #endif
182 0 : bfd->set_vss_strip(bfd, 0);
183 0 : break;
184 : case VSS_RESTORE_OFF_STRIP:
185 : #ifdef HAVE_WIN32
186 : bfd->set_win32_api(bfd, 0);
187 : #endif
188 0 : bfd->set_vss_strip(bfd, 1);
189 0 : break;
190 : case VSS_RESTORE_ON:
191 : #ifdef HAVE_WIN32
192 : bfd->set_win32_api(bfd, 1);
193 : #endif
194 18 : bfd->set_vss_strip(bfd, 0);
195 18 : break;
196 : }
197 18 : flags=O_WRONLY|O_BINARY
198 : #ifdef O_NOFOLLOW
199 : |O_NOFOLLOW
200 : #endif
201 : ;
202 18 : if(S_ISDIR(sb->statp.st_mode))
203 : {
204 : // Windows directories are treated as having file data.
205 0 : mkdir(path, 0777);
206 : }
207 : else
208 : {
209 18 : 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 18 : if(unlink(path) && errno!=ENOENT)
215 : {
216 0 : char msg[256]="";
217 0 : snprintf(msg, sizeof(msg),
218 : "Cannot unlink before restore: '%s': %s",
219 : path, strerror(errno));
220 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
221 : return OFR_ERROR;
222 0 : return OFR_CONTINUE;
223 : }
224 : }
225 :
226 18 : if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR))
227 : {
228 : struct berrno be;
229 0 : berrno_init(&be);
230 0 : char msg[256]="";
231 0 : snprintf(msg, sizeof(msg), "Could not open for writing %s: %s",
232 0 : path, berrno_bstrerror(&be, errno));
233 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
234 : return OFR_ERROR;
235 0 : return OFR_CONTINUE;
236 : }
237 : // Add attributes to bfd so that they can be set when it is closed.
238 18 : bfd->winattr=sb->winattr;
239 18 : memcpy(&bfd->statp, &sb->statp, sizeof(struct stat));
240 18 : return OFR_OK;
241 : }
242 :
243 : static char *build_msg(const char *text, const char *param)
244 : {
245 : static char msg[256]="";
246 0 : snprintf(msg, sizeof(msg), text, param);
247 : return msg;
248 : }
249 :
250 : #ifndef HAVE_WIN32
251 0 : static void do_logw(struct asfd *asfd, struct cntr *cntr,
252 : const char *text, const char *param)
253 : {
254 0 : logw(asfd, cntr, "%s", build_msg(text, param));
255 0 : }
256 : #endif
257 :
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 0 : return restore_interrupt(asfd, sb, build_msg(text, param), cntr,
263 : protocol);
264 : }
265 :
266 0 : 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 0 : int ret=0;
271 0 : 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 0 : struct stat statp=sb->statp;
277 :
278 0 : if(act==ACTION_VERIFY)
279 : {
280 0 : cntr_add(cntr, CMD_SPECIAL, 1);
281 0 : return 0;
282 : }
283 :
284 0 : if(build_path(fname, "", &rpath, NULL))
285 : {
286 : // failed - do a warning
287 0 : if(restore_interrupt(asfd, sb,
288 0 : build_msg("build path failed: %s", fname),
289 : cntr, protocol))
290 0 : ret=-1;
291 : goto end;
292 : }
293 0 : if(S_ISFIFO(statp.st_mode))
294 : {
295 0 : if(mkfifo(rpath, statp.st_mode) && errno!=EEXIST)
296 0 : do_logw(asfd, cntr,
297 0 : "Cannot make fifo: %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 0 : else if(S_ISSOCK(statp.st_mode))
305 : {
306 0 : if(mksock(rpath))
307 0 : do_logw(asfd, cntr,
308 0 : "Cannot make socket: %s\n", strerror(errno));
309 : else
310 : {
311 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
312 0 : 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 0 : else if(mknod(fname, statp.st_mode, statp.st_rdev) && errno!=EEXIST)
326 0 : do_logw(asfd, cntr, "Cannot make node: %s\n", strerror(errno));
327 : else
328 : {
329 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
330 0 : cntr_add(cntr, CMD_SPECIAL, 1);
331 : }
332 : #endif
333 : end:
334 0 : free_w(&rpath);
335 0 : return ret;
336 : }
337 :
338 0 : 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 0 : int ret=0;
343 0 : char *rpath=NULL;
344 0 : if(act==ACTION_RESTORE)
345 : {
346 0 : if(build_path(dname, "", &rpath, NULL))
347 : {
348 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
349 : "build path failed: %s", dname);
350 0 : goto end;
351 : }
352 0 : else if(is_dir_lstat(rpath)<=0)
353 : {
354 0 : if(mkdir(rpath, 0777))
355 : {
356 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
357 0 : "mkdir error: %s", strerror(errno));
358 0 : goto end;
359 : }
360 : }
361 0 : attribs_set(asfd, rpath, &(sb->statp), sb->winattr, cntr);
362 0 : if(!ret) cntr_add(cntr, sb->path.cmd, 1);
363 : }
364 0 : else cntr_add(cntr, sb->path.cmd, 1);
365 : end:
366 0 : free_w(&rpath);
367 0 : return ret;
368 : }
369 :
370 6 : 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 6 : int ret=0;
375 :
376 6 : if(act==ACTION_RESTORE)
377 : {
378 6 : char *rpath=NULL;
379 6 : if(build_path(fname, "", &rpath, NULL))
380 : {
381 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
382 : "build path failed: %s", fname);
383 0 : goto end;
384 : }
385 12 : else if(make_link(
386 : #ifdef HAVE_WIN32
387 : asfd,
388 : cntr,
389 : #endif
390 6 : fname, sb->link.buf,
391 : sb->link.cmd, restore_desired_dir))
392 : {
393 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
394 : "could not create link", "");
395 0 : goto end;
396 : }
397 : else if(!ret)
398 : {
399 6 : attribs_set(asfd, fname,
400 : &(sb->statp), sb->winattr, cntr);
401 6 : cntr_add(cntr, sb->path.cmd, 1);
402 : }
403 6 : free_w(&rpath);
404 : }
405 0 : else cntr_add(cntr, sb->path.cmd, 1);
406 : end:
407 6 : return ret;
408 : }
409 :
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 :
433 : static const char *act_str(enum action act)
434 : {
435 : static const char *ret=NULL;
436 20 : if(act==ACTION_RESTORE) ret="restore";
437 0 : else ret="verify";
438 20 : return ret;
439 : }
440 :
441 : #ifndef UTEST
442 : static
443 : #endif
444 7 : void strip_from_path(char *path, const char *strip)
445 : {
446 : char *p;
447 : char *src;
448 : size_t len;
449 14 : if(!path
450 7 : || !strip
451 6 : || strlen(path)<=strlen(strip)
452 5 : || !(p=strstr(path, strip)))
453 : return;
454 :
455 5 : len=strlen(p)-strlen(strip)+1;
456 5 : src=p+strlen(strip);
457 5 : memmove(p, src, len);
458 : }
459 :
460 :
461 : // Return 1 for ok, -1 for error, 0 for too many components stripped.
462 0 : static int strip_path_components(struct asfd *asfd,
463 : struct sbuf *sb, int strip, struct cntr *cntr, enum protocol protocol)
464 : {
465 0 : int s=0;
466 0 : char *tmp=NULL;
467 0 : char *cp=sb->path.buf;
468 0 : char *dp=NULL;
469 0 : for(s=0; cp && *cp && s<strip; s++)
470 : {
471 0 : if(!(dp=strchr(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, protocol))
478 : return -1;
479 0 : return 0;
480 : }
481 0 : cp=dp+1;
482 : }
483 0 : if(!cp)
484 : {
485 0 : char msg[256]="";
486 0 : snprintf(msg, sizeof(msg),
487 : "Stripped too many components: %s",
488 : iobuf_to_printable(&sb->path));
489 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
490 : return -1;
491 0 : return 0;
492 : }
493 0 : if(!(tmp=strdup_w(cp, __func__)))
494 : return -1;
495 0 : free_w(&sb->path.buf);
496 0 : sb->path.buf=tmp;
497 0 : return 1;
498 : }
499 :
500 32 : 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 32 : if(overwrite)
516 0 : return (sb->path.cmd!=CMD_VSS_T
517 0 : && sb->path.cmd!=CMD_ENC_VSS_T);
518 : #endif
519 :
520 32 : if(!S_ISDIR(sb->statp.st_mode)
521 32 : && sb->path.cmd!=CMD_METADATA
522 32 : && sb->path.cmd!=CMD_ENC_METADATA
523 32 : && sb->path.cmd!=CMD_VSS
524 32 : && 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 32 : if((sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE)
539 26 : && S_ISFIFO(sb->statp.st_mode))
540 : return 1;
541 :
542 : // File path exists. Do not overwrite.
543 32 : 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 :
554 2 : static enum asl_ret restore_style_func(struct asfd *asfd,
555 : __attribute__ ((unused)) struct conf **confs,
556 : __attribute__ ((unused)) void *param)
557 : {
558 2 : char msg[32]="";
559 2 : restore_style=NULL;
560 2 : if(strcmp(asfd->rbuf->buf, RESTORE_STREAM))
561 : {
562 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
563 0 : return ASL_END_ERROR;
564 : }
565 2 : snprintf(msg, sizeof(msg), "%s_ok", asfd->rbuf->buf);
566 2 : if(asfd->write_str(asfd, CMD_GEN, msg))
567 : return ASL_END_ERROR;
568 2 : restore_style=asfd->rbuf->buf;
569 2 : iobuf_init(asfd->rbuf);
570 2 : return ASL_END_OK;
571 : }
572 :
573 8 : static char *get_restore_style(struct asfd *asfd, struct conf **confs)
574 : {
575 8 : if(get_protocol(confs)==PROTO_1)
576 5 : return strdup_w(RESTORE_STREAM, __func__);
577 3 : if(asfd->simple_loop(asfd, confs, NULL, __func__,
578 : restore_style_func)) return NULL;
579 2 : return restore_style;
580 : }
581 :
582 : #ifdef HAVE_WIN32
583 : #ifndef PATH_MAX
584 : #define PATH_MAX _MAX_PATH
585 : #endif
586 : #endif
587 :
588 0 : static char *get_restore_desired_dir(
589 : const char *restoreprefix,
590 : struct asfd *asfd,
591 : struct cntr *cntr
592 : ) {
593 0 : char *ret=NULL;
594 0 : char *path=NULL;
595 :
596 0 : if(
597 : #ifdef HAVE_WIN32
598 : isalpha(*restoreprefix) && *(restoreprefix+1)==':'
599 : #else
600 0 : *restoreprefix=='/'
601 : #endif
602 : ) {
603 0 : if(!(path=strdup_w(restoreprefix, __func__)))
604 : return NULL;
605 : }
606 : else
607 : {
608 : static char d[PATH_MAX];
609 0 : if(!getcwd(d, sizeof(d)))
610 : {
611 0 : logw(asfd, cntr,
612 : "Could not get current working directory: %s\n",
613 0 : strerror(errno));
614 0 : return NULL;
615 : }
616 0 : 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 0 : if((ret=realpath(path, NULL)))
623 : goto end;
624 0 : if(errno!=ENOENT)
625 : goto realpath_error;
626 : // Try to create the directory if it did not exist, then try again.
627 0 : mkdir(path, 0777);
628 0 : if(!(ret=realpath(path, NULL)))
629 : goto realpath_error;
630 :
631 : end:
632 0 : free_w(&path);
633 0 : return ret;
634 :
635 : realpath_error:
636 0 : logp("%s: Could not get realpath in %s: %s\n",
637 : path, __func__, strerror(errno));
638 0 : free_w(&path);
639 0 : return NULL;
640 : }
641 :
642 : // Seems that windows has no dirname(), so do something similar instead.
643 0 : static int strip_trailing_component(char **path)
644 : {
645 0 : char *cp=NULL;
646 :
647 0 : if(**path=='/' && !*((*path)+1))
648 : return -1;
649 0 : if(!(cp=strrchr(*path, '/')))
650 : return -1;
651 0 : if(*path==cp)
652 0 : *(cp+1)='\0'; // Deal with '/somepath' in root, gives '/'.
653 : else
654 0 : *cp='\0'; // Deal with '/some/path', gives '/some'.
655 : return 0;
656 : }
657 :
658 0 : 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 0 : int ret=-1;
667 0 : char *tmp=NULL;
668 0 : char *copy=NULL;
669 0 : char *canonical=NULL;
670 :
671 0 : 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 0 : if(strip_trailing_component(©))
679 : {
680 0 : char msg[512]="";
681 0 : snprintf(msg, sizeof(msg),
682 : "%s: Could not get dirname of '%s'",
683 : *fullpath, copy);
684 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
685 : goto end;
686 0 : ret=1;
687 0 : goto end;
688 : }
689 0 : if((canonical=realpath(copy, NULL)))
690 : break;
691 0 : if(errno!=ENOENT)
692 : {
693 0 : char msg[512]="";
694 0 : snprintf(msg, sizeof(msg),
695 : "%s: Could not get realpath of %s in %s: %s",
696 : *fullpath, copy, __func__, strerror(errno));
697 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
698 : goto end;
699 0 : ret=1;
700 0 : 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 0 : if(!is_subdir(restore_desired_dir, canonical))
708 : {
709 0 : char msg[512]="";
710 0 : snprintf(msg, sizeof(msg),
711 : "%s: Is not in a subdir of '%s'",
712 : *fullpath,
713 : restore_desired_dir);
714 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
715 : goto end;
716 0 : ret=1;
717 0 : goto end;
718 : }
719 :
720 : // Add the trailing content back onto the canonical path.
721 0 : if(!(tmp=prepend_s(canonical, (*fullpath)+strlen(copy))))
722 : goto end;
723 0 : free_w(fullpath);
724 0 : *fullpath=tmp;
725 :
726 0 : 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 0 : if(canonical) free(canonical);
732 0 : free_w(©);
733 0 : return ret;
734 : }
735 :
736 8 : int do_restore_client(struct asfd *asfd,
737 : struct conf **confs, enum action act)
738 : {
739 8 : int ret=-1;
740 8 : char msg[512]="";
741 8 : struct sbuf *sb=NULL;
742 8 : struct blk *blk=NULL;
743 8 : struct BFILE *bfd=NULL;
744 8 : char *fullpath=NULL;
745 8 : char *style=NULL;
746 8 : char *restore_desired_dir=NULL;
747 8 : struct cntr *cntr=get_cntr(confs);
748 8 : enum protocol protocol=get_protocol(confs);
749 8 : int strip=get_int(confs[OPT_STRIP]);
750 8 : int overwrite=get_int(confs[OPT_OVERWRITE]);
751 8 : const char *strip_path=get_string(confs[OPT_STRIP_FROM_PATH]);
752 8 : const char *backup=get_string(confs[OPT_BACKUP]);
753 8 : const char *regex=get_string(confs[OPT_REGEX]);
754 8 : const char *encryption_password=
755 8 : get_string(confs[OPT_ENCRYPTION_PASSWORD]);
756 8 : enum vss_restore vss_restore=
757 8 : (enum vss_restore)get_int(confs[OPT_VSS_RESTORE]);
758 8 : const char *restore_list=get_string(confs[OPT_RESTORE_LIST]);
759 :
760 8 : if(act==ACTION_RESTORE)
761 : {
762 8 : const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
763 8 : if(!restore_prefix)
764 : {
765 0 : logw(NULL, cntr,
766 : "You must specify a restore directory (-d)!\n");
767 0 : goto error;
768 : }
769 8 : 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 0 : else if(!(restore_desired_dir=get_restore_desired_dir(
778 : restore_prefix, asfd, cntr)))
779 : goto error;
780 : }
781 :
782 8 : if(!(bfd=bfile_alloc()))
783 : goto error;
784 :
785 8 : bfile_init(bfd, 0, cntr);
786 8 : bfd->set_attribs_on_close=1;
787 :
788 16 : 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 8 : logp("Doing %s\n", msg);
795 8 : if(asfd->write_str(asfd, CMD_GEN, msg))
796 : goto error;
797 8 : if(restore_list)
798 : {
799 0 : if(!strcmp(restore_list, "-"))
800 0 : restore_list="/dev/stdin";
801 0 : logp("Reading from: '%s'\n", restore_list);
802 0 : if(asfd_read_expect(asfd, CMD_GEN, "ok restore_list"))
803 : goto error;
804 0 : if(send_a_file(asfd, restore_list, cntr))
805 : goto error;
806 : }
807 : else
808 : {
809 8 : if(asfd_read_expect(asfd, CMD_GEN, "ok"))
810 : goto error;
811 : }
812 8 : logp("Doing %s confirmed\n", act_str(act));
813 8 : if(act==ACTION_RESTORE)
814 8 : 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 8 : logfmt("\n");
822 :
823 8 : if(cntr_recv(asfd, confs))
824 : goto error;
825 :
826 8 : if(!(style=get_restore_style(asfd, confs)))
827 : goto error;
828 :
829 7 : if(!(sb=sbuf_alloc(protocol))
830 7 : || (protocol==PROTO_2 && !(blk=blk_alloc())))
831 : {
832 0 : log_and_send_oom(asfd);
833 0 : goto error;
834 : }
835 :
836 : while(1)
837 : {
838 52 : sbuf_free_content(sb);
839 52 : if(protocol==PROTO_1)
840 13 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
841 :
842 52 : switch(sbuf_fill_from_net(sb, asfd, blk, cntr))
843 : {
844 : case 0: break;
845 4 : 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 46 : if(protocol==PROTO_2)
853 : {
854 37 : if(blk->data)
855 : {
856 14 : int wret=0;
857 14 : if(act==ACTION_VERIFY)
858 0 : cntr_add(cntr, CMD_DATA, 1);
859 : else
860 14 : wret=write_protocol2_data(asfd,
861 : bfd, blk, vss_restore);
862 14 : blk_free_content(blk);
863 14 : blk->data=NULL;
864 14 : if(wret) goto error;
865 14 : continue;
866 : }
867 23 : else if(sb->endfile.buf)
868 : {
869 0 : continue;
870 : }
871 : }
872 :
873 32 : 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 32 : if(strip)
889 : {
890 : int s;
891 0 : s=strip_path_components(asfd,
892 : sb, strip, cntr, protocol);
893 0 : if(s<0) goto error;
894 0 : if(s==0)
895 : {
896 : // Too many components stripped
897 : // - carry on.
898 0 : continue;
899 : }
900 : // It is OK, sb.path is now stripped.
901 : }
902 32 : if(strip_path)
903 : {
904 0 : strip_from_path(sb->path.buf,
905 : strip_path);
906 : // Strip links if their path is absolute
907 0 : if(sb->link.buf && !is_absolute(sb->link.buf))
908 0 : strip_from_path(sb->link.buf,
909 : strip_path);
910 : }
911 32 : free_w(&fullpath);
912 32 : if(!(fullpath=prepend_s(restore_desired_dir,
913 32 : sb->path.buf)))
914 : {
915 0 : log_and_send_oom(asfd);
916 0 : goto error;
917 : }
918 :
919 32 : if(act==ACTION_RESTORE)
920 : {
921 32 : 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 32 : if(bfd
926 32 : && bfd->mode!=BF_CLOSED
927 19 : && bfd->path
928 19 : && strcmp(bfd->path, fullpath))
929 12 : bfd->close(bfd, asfd);
930 32 : if(restore_desired_dir) {
931 0 : switch(canonicalise(
932 : asfd,
933 : sb,
934 : cntr,
935 : protocol,
936 : restore_desired_dir,
937 : &fullpath
938 : )) {
939 : case 0: break;
940 0 : case 1: continue;
941 : default: goto error;
942 : }
943 : }
944 :
945 32 : if(!overwrite_ok(sb, overwrite,
946 : #ifdef HAVE_WIN32
947 : bfd,
948 : #endif
949 : fullpath))
950 : {
951 7 : char msg[512]="";
952 : // Something exists at that path.
953 7 : snprintf(msg, sizeof(msg),
954 : "Path exists: %s\n", fullpath);
955 7 : if(restore_interrupt(asfd,
956 : sb, msg, cntr, protocol))
957 : goto error;
958 7 : continue;
959 : }
960 : }
961 : break;
962 : case CMD_MESSAGE:
963 : case CMD_WARNING:
964 0 : log_recvd(&sb->path, cntr, 1);
965 0 : logfmt("\n");
966 0 : continue;
967 : default:
968 : break;
969 : }
970 :
971 25 : switch(sb->path.cmd)
972 : {
973 : // These are the same in both protocol1 and protocol2.
974 : case CMD_DIRECTORY:
975 0 : if(restore_dir(asfd, sb, fullpath, act, cntr,
976 : protocol))
977 : goto error;
978 0 : continue;
979 : case CMD_SOFT_LINK:
980 : case CMD_HARD_LINK:
981 6 : if(restore_link(asfd, sb, fullpath, act, cntr,
982 : protocol, restore_desired_dir))
983 : goto error;
984 6 : continue;
985 : case CMD_SPECIAL:
986 0 : if(restore_special(asfd, sb,
987 : fullpath, act, cntr, protocol))
988 : goto error;
989 0 : continue;
990 : default:
991 : break;
992 : }
993 :
994 19 : if(protocol==PROTO_2)
995 : {
996 14 : if(restore_switch_protocol2(asfd, sb, fullpath, act,
997 : bfd, vss_restore, cntr))
998 : goto error;
999 : }
1000 : else
1001 : {
1002 5 : if(restore_switch_protocol1(asfd, sb, fullpath, act,
1003 : bfd, vss_restore, cntr, encryption_password))
1004 : goto error;
1005 : }
1006 : }
1007 :
1008 : end:
1009 4 : ret=0;
1010 : error:
1011 : // It is possible for a fd to still be open.
1012 8 : if(bfd)
1013 : {
1014 8 : bfd->close(bfd, asfd);
1015 8 : bfile_free(&bfd);
1016 : }
1017 :
1018 8 : cntr_print_end(cntr);
1019 8 : cntr_set_bytes(cntr, asfd);
1020 8 : cntr_print(cntr, act);
1021 :
1022 12 : if(!ret) logp("%s finished\n", act_str(act));
1023 4 : else logp("ret: %d\n", ret);
1024 :
1025 8 : sbuf_free(&sb);
1026 8 : free_w(&style);
1027 8 : free_w(&fullpath);
1028 8 : 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 8 : if(restore_desired_dir)
1034 0 : free(restore_desired_dir);
1035 :
1036 8 : return ret;
1037 : }
|