LCOV - code coverage report
Current view: top level - src/client - restore.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 185 388 47.7 %
Date: 2021-06-01 21:59:08 Functions: 9 16 56.2 %

          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(&copy))
     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(&copy);
     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             : }

Generated by: LCOV version 1.13