LCOV - code coverage report
Current view: top level - src/server - extra_comms.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 170 210 81.0 %
Date: 2022-12-03 01:09:05 Functions: 9 10 90.0 %

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

Generated by: LCOV version 1.13