LCOV - code coverage report
Current view: top level - src/server - extra_comms.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 183 225 81.3 %
Date: 2022-05-01 01:22:11 Functions: 10 11 90.9 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../cmd.h"
       6             : #include "../conf.h"
       7             : #include "../conffile.h"
       8             : #include "../fsops.h"
       9             : #include "../handy.h"
      10             : #include "../incexc_recv.h"
      11             : #include "../incexc_send.h"
      12             : #include "../iobuf.h"
      13             : #include "../log.h"
      14             : #include "../pathcmp.h"
      15             : #include "../prepend.h"
      16             : #include "autoupgrade.h"
      17             : #include "extra_comms.h"
      18             : 
      19             : #include <librsync.h>
      20             : 
      21         202 : static int append_to_feat(char **feat, const char *str)
      22             : {
      23         202 :         char *tmp=NULL;
      24         202 :         if(!*feat)
      25             :         {
      26          18 :                 if(!(*feat=strdup_w(str, __func__)))
      27             :                         return -1;
      28          18 :                 return 0;
      29             :         }
      30         184 :         if(!(tmp=prepend(*feat, str)))
      31             :                 return -1;
      32         184 :         free_w(feat);
      33         184 :         *feat=tmp;
      34         184 :         return 0;
      35             : }
      36             : 
      37             : // It is unfortunate that we are having to figure out the server-initiated
      38             : // restore paths here instead of setting it in a struct sdirs.
      39             : // But doing the extra_comms needs to come before setting the sdirs, because
      40             : // extra_comms sets up a bunch of settings that sdirs need to know.
      41          18 : static char *get_restorepath_proto1(struct conf **cconfs)
      42             : {
      43          18 :         char *tmp=NULL;
      44          18 :         char *restorepath=NULL;
      45          18 :         if((tmp=prepend_s(get_string(cconfs[OPT_DIRECTORY]),
      46          18 :                 get_string(cconfs[OPT_CNAME]))))
      47          18 :                         restorepath=prepend_s(tmp, "restore");
      48          18 :         free_w(&tmp);
      49          18 :         return restorepath;
      50             : }
      51             : 
      52          18 : static char *get_restorepath_proto2(struct conf **cconfs)
      53             : {
      54          18 :         char *tmp1=NULL;
      55          18 :         char *tmp2=NULL;
      56          18 :         char *restorepath=NULL;
      57          18 :         if(!(tmp1=prepend_s(get_string(cconfs[OPT_DIRECTORY]),
      58          18 :                 get_string(cconfs[OPT_DEDUP_GROUP]))))
      59             :                         goto error;
      60          18 :         if(!(tmp2=prepend_s(tmp1, "clients")))
      61             :                 goto error;
      62          18 :         free_w(&tmp1);
      63          18 :         if(!(tmp1=prepend_s(tmp2, get_string(cconfs[OPT_CNAME]))))
      64             :                 goto error;
      65          18 :         if(!(restorepath=prepend_s(tmp1, "restore")))
      66             :                 goto error;
      67             :         goto end;
      68             : error:
      69           0 :         free_w(&restorepath);
      70             : end:
      71          18 :         free_w(&tmp1);
      72          18 :         free_w(&tmp2);
      73          18 :         return restorepath;
      74             : }
      75             : 
      76          18 : static int set_restore_path(struct conf **cconfs, char **feat)
      77             : {
      78          18 :         int ret=-1;
      79          18 :         char *restorepath1=NULL;
      80          18 :         char *restorepath2=NULL;
      81          18 :         if(!(restorepath1=get_restorepath_proto1(cconfs))
      82          18 :           || !(restorepath2=get_restorepath_proto2(cconfs)))
      83             :                 goto end;
      84          18 :         if(is_reg_lstat(restorepath1)==1
      85           4 :           && set_string(cconfs[OPT_RESTORE_PATH], restorepath1))
      86             :                 goto end;
      87          18 :         else if(is_reg_lstat(restorepath2)==1
      88           0 :           && set_string(cconfs[OPT_RESTORE_PATH], restorepath2))
      89             :                 goto end;
      90          18 :         if(get_string(cconfs[OPT_RESTORE_PATH])
      91           4 :           && append_to_feat(feat, "srestore:"))
      92             :                 goto end;
      93             :         ret=0;
      94             : end:
      95          18 :         free_w(&restorepath1);
      96          18 :         free_w(&restorepath2);
      97          18 :         return ret;
      98             : }
      99             : 
     100             : struct vers
     101             : {
     102             :         long min;
     103             :         long cli;
     104             :         long ser;
     105             :         long feat_list;
     106             :         long directory_tree;
     107             :         long burp2;
     108             :         long counters_json;
     109             : };
     110             : 
     111          18 : static int send_features(struct asfd *asfd, struct conf **cconfs,
     112             :         struct vers *vers)
     113             : {
     114          18 :         int ret=-1;
     115          18 :         char *feat=NULL;
     116          18 :         struct strlist *startdir=get_strlist(cconfs[OPT_STARTDIR]);
     117          18 :         struct strlist *incglob=get_strlist(cconfs[OPT_INCGLOB]);
     118             : 
     119          18 :         if(append_to_feat(&feat, "extra_comms_begin ok:")
     120             :                 /* clients can autoupgrade */
     121          18 :           || append_to_feat(&feat, "autoupgrade:")
     122             :                 /* clients can give server incexc conf so that the
     123             :                    server knows better what to do on resume */
     124          18 :           || append_to_feat(&feat, "incexc:")
     125             :                 /* clients can give the server an alternative client
     126             :                    to restore from */
     127          18 :           || append_to_feat(&feat, "orig_client:")
     128             :                 /* clients can tell the server what kind of system they are. */
     129          18 :           || append_to_feat(&feat, "uname:")
     130          18 :           || append_to_feat(&feat, "failover:")
     131          18 :           || append_to_feat(&feat, "vss_restore:")
     132          18 :           || append_to_feat(&feat, "regex_icase:"))
     133             :                 goto end;
     134             : 
     135             :         /* Clients can receive restore initiated from the server. */
     136          18 :         if(set_restore_path(cconfs, &feat))
     137             :                 goto end;
     138             : 
     139             :         /* Clients can receive incexc conf from the server.
     140             :            Only give it as an option if the server has some starting
     141             :            directory configured in the clientconfdir. */
     142          18 :         if((startdir || incglob)
     143           0 :           && append_to_feat(&feat, "sincexc:"))
     144             :                 goto end;
     145             : 
     146          18 :         if(vers->cli>=vers->counters_json)
     147             :         {
     148             :                 /* Clients can be sent cntrs on resume/verify/restore. */
     149          18 :                 if(append_to_feat(&feat, "counters_json:"))
     150             :                         goto end;
     151             :         }
     152             : 
     153             :         // We support CMD_MESSAGE.
     154          18 :         if(append_to_feat(&feat, "msg:"))
     155             :                 goto end;
     156             : 
     157             : #ifdef HAVE_BLAKE2
     158             :         if(append_to_feat(&feat, "rshash=blake2:"))
     159             :                 goto end;
     160             : #endif
     161             : 
     162          18 :         if(append_to_feat(&feat, "seed:"))
     163             :                 goto end;
     164             : 
     165             :         //printf("feat: %s\n", feat);
     166             : 
     167          18 :         if(asfd->write_str(asfd, CMD_GEN, feat))
     168             :         {
     169           1 :                 logp("problem in extra_comms\n");
     170             :                 goto end;
     171             :         }
     172             : 
     173             :         ret=0;
     174             : end:
     175          18 :         free_w(&feat);
     176          18 :         return ret;
     177             : }
     178             : 
     179           2 : static int do_autoupgrade(struct asfd *asfd, struct vers *vers,
     180             :         struct conf **globalcs)
     181             : {
     182           2 :         int ret=-1;
     183           2 :         char *os=NULL;
     184           2 :         struct iobuf *rbuf=asfd->rbuf;
     185           2 :         const char *autoupgrade_dir=get_string(globalcs[OPT_AUTOUPGRADE_DIR]);
     186             : 
     187           2 :         if(!(os=strdup_w(rbuf->buf+strlen("autoupgrade:"), __func__)))
     188             :                 goto end;
     189           2 :         iobuf_free_content(rbuf);
     190           2 :         ret=0;
     191           2 :         if(os && *os)
     192             :         {
     193             :                 // Sanitise path separators
     194           7 :                 for(char *i=os; *i; ++i)
     195           7 :                         if(*i == '/' || *i == '\\' || *i == ':')
     196           0 :                                 *i='-';
     197             : 
     198           1 :                 ret=autoupgrade_server(asfd, vers->ser,
     199             :                         vers->cli, os, get_cntr(globalcs),
     200             :                         autoupgrade_dir);
     201             :         }
     202             : end:
     203           2 :         free_w(&os);
     204           2 :         return ret;
     205             : }
     206             : 
     207           0 : static int setup_seed(
     208             :         struct asfd *asfd,
     209             :         struct conf **cconfs,
     210             :         struct iobuf *rbuf,
     211             :         const char *what,
     212             :         enum conf_opt opt
     213             : ) {
     214           0 :         int ret=-1;
     215           0 :         char *tmp=NULL;
     216           0 :         char *str=NULL;
     217             : 
     218           0 :         str=rbuf->buf+strlen(what)+1;
     219           0 :         strip_trailing_slashes(&str);
     220             : 
     221           0 :         if(!is_absolute(str))
     222             :         {
     223             :                 char msg[128];
     224           0 :                 snprintf(msg, sizeof(msg), "A %s needs to be absolute!", what);
     225           0 :                 log_and_send(asfd, msg);
     226             :                 goto end;
     227             :         }
     228           0 :         if(opt==OPT_SEED_SRC && *str!='/')
     229             :         {
     230           0 : printf("here: %s\n", str);
     231             :                 // More windows hacks - add a slash to the beginning of things
     232             :                 // like 'C:'.
     233           0 :                 if(astrcat(&tmp, "/", __func__)
     234           0 :                   || astrcat(&tmp, str, __func__))
     235             :                         goto end;
     236           0 :                 str=tmp;
     237             :         }
     238           0 :         if(set_string(cconfs[opt], str))
     239             :                 goto end;
     240           0 :         ret=0;
     241             : end:
     242           0 :         free_w(&tmp);
     243           0 :         return ret;
     244             : }
     245             : 
     246          17 : static int extra_comms_read(struct async *as,
     247             :         struct vers *vers, int *srestore,
     248             :         char **incexc, struct conf **globalcs, struct conf **cconfs)
     249             : {
     250          17 :         int ret=-1;
     251             :         struct asfd *asfd;
     252             :         struct iobuf *rbuf;
     253          17 :         asfd=as->asfd;
     254          17 :         rbuf=asfd->rbuf;
     255             : 
     256             :         while(1)
     257             :         {
     258          31 :                 iobuf_free_content(rbuf);
     259          31 :                 if(asfd->read(asfd)) goto end;
     260             : 
     261          31 :                 if(rbuf->cmd!=CMD_GEN)
     262             :                 {
     263           1 :                         iobuf_log_unexpected(rbuf, __func__);
     264             :                         goto end;
     265             :                 }
     266             : 
     267          30 :                 if(!strcmp(rbuf->buf, "extra_comms_end"))
     268             :                 {
     269          12 :                         if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok"))
     270             :                                 goto end;
     271             :                         break;
     272             :                 }
     273          18 :                 else if(!strncmp_w(rbuf->buf, "autoupgrade:"))
     274             :                 {
     275           2 :                         if(do_autoupgrade(asfd, vers, globalcs))
     276             :                                 goto end;
     277             :                 }
     278          16 :                 else if(!strcmp(rbuf->buf, "srestore ok"))
     279             :                 {
     280           4 :                         char *restore_path=get_string(cconfs[OPT_RESTORE_PATH]);
     281           4 :                         if(!restore_path)
     282             :                         {
     283           0 :                                 logp("got srestore ok without a restore_path");
     284             :                                 goto end;
     285             :                         }
     286             :                         
     287           4 :                         iobuf_free_content(rbuf);
     288             :                         // Client can accept the restore.
     289             :                         // Load the restore config, then send it.
     290           4 :                         *srestore=1;
     291             :                         // Need to wipe out OPT_INCEXDIR, as it is needed for
     292             :                         // srestore includes. If it is not wiped out, it can
     293             :                         // interfere if cconfs[OPT_RESTORE_PATH] contained no
     294             :                         // includes.
     295           4 :                         set_strlist(cconfs[OPT_INCEXCDIR], NULL);
     296           4 :                         if(conf_parse_incexcs_path(cconfs, restore_path)
     297           4 :                           || incexc_send_server_restore(asfd, cconfs))
     298             :                                 goto end;
     299             :                         // Do not unlink it here - wait until
     300             :                         // the client says that it wants to do the
     301             :                         // restore.
     302             :                         // Also need to leave it around if the
     303             :                         // restore is to an alternative client, so
     304             :                         // that the code below that reloads the config
     305             :                         // can read it again.
     306             :                         // NOTE: that appears to be in
     307             :                         // src/server/run_action.c::client_can_restore()
     308             :                         //unlink(get_string(cconfs[OPT_RESTORE_PATH]));
     309             :                 }
     310          12 :                 else if(!strcmp(rbuf->buf, "srestore not ok"))
     311             :                 {
     312           1 :                         const char *restore_path=get_string(
     313             :                                 cconfs[OPT_RESTORE_PATH]);
     314             :                         // Client will not accept the restore.
     315           1 :                         if (restore_path)
     316           1 :                                 unlink(restore_path);
     317           1 :                         if(set_string(cconfs[OPT_RESTORE_PATH], NULL))
     318             :                                 goto end;
     319           1 :                         logp("Client not accepting server initiated restore.\n");
     320             :                 }
     321          11 :                 else if(!strcmp(rbuf->buf, "sincexc ok"))
     322             :                 {
     323             :                         // Client can accept incexc conf from the
     324             :                         // server.
     325           1 :                         iobuf_free_content(rbuf);
     326           1 :                         if(incexc_send_server(asfd, cconfs))
     327             :                                 goto end;
     328             :                 }
     329          10 :                 else if(!strcmp(rbuf->buf, "incexc"))
     330             :                 {
     331             :                         // Client is telling server its incexc
     332             :                         // configuration so that it can better decide
     333             :                         // what to do on resume.
     334           1 :                         iobuf_free_content(rbuf);
     335           1 :                         if(incexc_recv_server(asfd, incexc, globalcs))
     336             :                                 goto end;
     337           1 :                         if(*incexc)
     338             :                         {
     339           1 :                                 char *tmp=NULL;
     340           1 :                                 char comp[32]="";
     341           1 :                                 snprintf(comp, sizeof(comp),
     342             :                                         "compression = %d\n",
     343             :                                         get_int(cconfs[OPT_COMPRESSION]));
     344           1 :                                 if(!(tmp=prepend(*incexc, comp)))
     345             :                                         goto end;
     346           1 :                                 free_w(incexc);
     347           1 :                                 *incexc=tmp;
     348             :                         }
     349             :                 }
     350           9 :                 else if(!strcmp(rbuf->buf, "counters_json ok"))
     351             :                 {
     352             :                         // Client can accept counters on
     353             :                         // resume/verify/restore.
     354           1 :                         logp("Client supports being sent json counters.\n");
     355           1 :                         set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1);
     356             :                 }
     357           8 :                 else if(!strncmp_w(rbuf->buf, "uname=")
     358           2 :                   && strlen(rbuf->buf)>strlen("uname="))
     359             :                 {
     360           2 :                         char *uname=rbuf->buf+strlen("uname=");
     361           2 :                         if(!strncasecmp("Windows", uname, strlen("Windows")))
     362           1 :                                 set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1);
     363             :                 }
     364           6 :                 else if(!strncmp_w(rbuf->buf, "orig_client=")
     365           3 :                   && strlen(rbuf->buf)>strlen("orig_client="))
     366             :                 {
     367           3 :                         if(conf_switch_to_orig_client(globalcs, cconfs,
     368           3 :                                 rbuf->buf+strlen("orig_client=")))
     369             :                                         goto end;
     370             :                         // If this started out as a server-initiated
     371             :                         // restore, need to load the restore file
     372             :                         // again.
     373           2 :                         if(*srestore)
     374             :                         {
     375           1 :                                 if(conf_parse_incexcs_path(cconfs,
     376           1 :                                         get_string(cconfs[OPT_RESTORE_PATH])))
     377             :                                                 goto end;
     378             :                         }
     379           2 :                         if(asfd->write_str(asfd, CMD_GEN, "orig_client ok"))
     380             :                                 goto end;
     381             :                 }
     382           3 :                 else if(!strncmp_w(rbuf->buf, "restore_spool="))
     383             :                 {
     384             :                         // Removed.
     385             :                 }
     386           3 :                 else if(!strncmp_w(rbuf->buf, "rshash=blake2"))
     387             :                 {
     388             : #ifdef HAVE_BLAKE2
     389             :                         set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2);
     390             :                         set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2);
     391             : #else
     392           1 :                         logp("Client is trying to use librsync hash blake2, but server does not support it.\n");
     393             :                         goto end;
     394             : #endif
     395             :                 }
     396           2 :                 else if(!strncmp_w(rbuf->buf, "msg"))
     397             :                 {
     398           1 :                         set_int(cconfs[OPT_MESSAGE], 1);
     399           1 :                         set_int(globalcs[OPT_MESSAGE], 1);
     400             :                 }
     401           1 :                 else if(!strncmp_w(rbuf->buf, "backup_failovers_left="))
     402             :                 {
     403             :                         int l;
     404           0 :                         l=atoi(rbuf->buf+strlen("backup_failovers_left="));
     405           0 :                         set_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT], l);
     406           0 :                         set_int(globalcs[OPT_BACKUP_FAILOVERS_LEFT], l);
     407             :                 }
     408           1 :                 else if(!strncmp_w(rbuf->buf, "seed_src="))
     409             :                 {
     410           0 :                         if(setup_seed(asfd, cconfs,
     411             :                                 rbuf, "seed_src", OPT_SEED_SRC))
     412             :                                         goto end;
     413             :                 }
     414           1 :                 else if(!strncmp_w(rbuf->buf, "seed_dst="))
     415             :                 {
     416           0 :                         if(setup_seed(asfd, cconfs,
     417             :                                 rbuf, "seed_dst", OPT_SEED_DST))
     418             :                                         goto end;
     419             :                 }
     420           1 :                 else if(!strncmp_w(rbuf->buf, "vss_restore=off"))
     421             :                 {
     422           0 :                         set_int(cconfs[OPT_VSS_RESTORE], VSS_RESTORE_OFF);
     423           0 :                         set_int(globalcs[OPT_VSS_RESTORE], VSS_RESTORE_OFF);
     424             :                 }
     425           1 :                 else if(!strncmp_w(rbuf->buf, "vss_restore=strip"))
     426             :                 {
     427           0 :                         set_int(cconfs[OPT_VSS_RESTORE], VSS_RESTORE_OFF_STRIP);
     428           0 :                         set_int(globalcs[OPT_VSS_RESTORE], VSS_RESTORE_OFF_STRIP);
     429             :                 }
     430           1 :                 else if(!strncmp_w(rbuf->buf, "regex_icase=1"))
     431             :                 {
     432           0 :                         set_int(cconfs[OPT_REGEX_CASE_INSENSITIVE], 1);
     433           0 :                         set_int(globalcs[OPT_REGEX_CASE_INSENSITIVE], 1);
     434             :                 }
     435             :                 else
     436             :                 {
     437           1 :                         iobuf_log_unexpected(rbuf, __func__);
     438             :                         goto end;
     439             :                 }
     440             :         }
     441             : 
     442          12 :         ret=0;
     443             : end:
     444          17 :         iobuf_free_content(rbuf);
     445          17 :         return ret;
     446             : }
     447             : 
     448          22 : static int vers_init(struct vers *vers, struct conf **cconfs)
     449             : {
     450          22 :         memset(vers, 0, sizeof(struct vers));
     451          22 :         return ((vers->min=version_to_long("1.2.7"))<0
     452          22 :           || (vers->cli=version_to_long(get_string(cconfs[OPT_PEER_VERSION])))<0
     453          22 :           || (vers->ser=version_to_long(PACKAGE_VERSION))<0
     454          22 :           || (vers->feat_list=version_to_long("1.3.0"))<0
     455          22 :           || (vers->directory_tree=version_to_long("1.3.6"))<0
     456          22 :           || (vers->burp2=version_to_long("2.0.0"))<0
     457          44 :           || (vers->counters_json=version_to_long("2.0.46"))<0);
     458             : }
     459             : 
     460          12 : static int check_seed(struct asfd *asfd, struct conf **cconfs)
     461             : {
     462          12 :         char msg[128]="";
     463          12 :         const char *src=get_string(cconfs[OPT_SEED_SRC]);
     464          12 :         const char *dst=get_string(cconfs[OPT_SEED_DST]);
     465          12 :         if(!src && !dst)
     466             :                 return 0;
     467           0 :         if(src && dst)
     468             :         {
     469           0 :                 logp("Seeding '%s' -> '%s'\n", src, dst);
     470           0 :                 return 0;
     471             :         }
     472           0 :         snprintf(msg, sizeof(msg),
     473             :                 "You must specify %s and %s options together, or not at all.",
     474           0 :                         cconfs[OPT_SEED_SRC]->field,
     475           0 :                         cconfs[OPT_SEED_DST]->field);
     476           0 :         log_and_send(asfd, msg);
     477           0 :         return -1;
     478             : }
     479             : 
     480          22 : int extra_comms(struct async *as,
     481             :         char **incexc, int *srestore, struct conf **confs, struct conf **cconfs)
     482             : {
     483             :         struct vers vers;
     484             :         struct asfd *asfd;
     485          22 :         asfd=as->asfd;
     486             :         //char *restorepath=NULL;
     487             : 
     488          22 :         if(vers_init(&vers, cconfs))
     489             :                 goto error;
     490             : 
     491          22 :         if(vers.cli<vers.directory_tree)
     492             :         {
     493           3 :                 set_int(confs[OPT_DIRECTORY_TREE], 0);
     494           3 :                 set_int(cconfs[OPT_DIRECTORY_TREE], 0);
     495             :         }
     496             : 
     497             :         // Clients before 1.2.7 did not know how to do extra comms, so skip
     498             :         // this section for them.
     499          22 :         if(vers.cli<vers.min)
     500             :                 return 0;
     501             : 
     502          20 :         if(asfd_read_expect(asfd, CMD_GEN, "extra_comms_begin"))
     503             :         {
     504           1 :                 logp("problem reading in extra_comms\n");
     505           1 :                 goto error;
     506             :         }
     507             :         // Want to tell the clients the extra comms features that are
     508             :         // supported, so that new clients are more likely to work with old
     509             :         // servers.
     510          19 :         if(vers.cli==vers.feat_list)
     511             :         {
     512             :                 // 1.3.0 did not support the feature list.
     513           1 :                 if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin ok"))
     514             :                 {
     515           1 :                         logp("problem writing in extra_comms\n");
     516           1 :                         goto error;
     517             :                 }
     518             :         }
     519             :         else
     520             :         {
     521          18 :                 if(send_features(asfd, cconfs, &vers))
     522             :                         goto error;
     523             :         }
     524             : 
     525          17 :         if(extra_comms_read(as, &vers, srestore, incexc, confs, cconfs))
     526             :                 goto error;
     527             : 
     528          12 :         if(check_seed(asfd, cconfs))
     529             :                 goto error;
     530             : 
     531             :         return 0;
     532             : error:
     533             :         return -1;
     534             : }

Generated by: LCOV version 1.13