LCOV - code coverage report
Current view: top level - src/client - restore.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 130 351 37.0 %
Date: 2022-12-03 01:09:05 Functions: 6 14 42.9 %

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

Generated by: LCOV version 1.13