LCOV - code coverage report
Current view: top level - src/server - extra_comms.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 174 174 100.0 %
Date: 2016-07-02 Functions: 6 6 100.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 "../handy.h"
       9             : #include "../incexc_recv.h"
      10             : #include "../incexc_send.h"
      11             : #include "../iobuf.h"
      12             : #include "../log.h"
      13             : #include "../prepend.h"
      14             : #include "autoupgrade.h"
      15             : 
      16             : #include <librsync.h>
      17             : 
      18         256 : static int append_to_feat(char **feat, const char *str)
      19             : {
      20         256 :         char *tmp=NULL;
      21         256 :         if(!*feat)
      22             :         {
      23          36 :                 if(!(*feat=strdup_w(str, __func__)))
      24             :                         return -1;
      25          36 :                 return 0;
      26             :         }
      27         220 :         if(!(tmp=prepend(*feat, str)))
      28             :                 return -1;
      29         220 :         free_w(feat);
      30         220 :         *feat=tmp;
      31         220 :         return 0;
      32             : }
      33             : 
      34          36 : static char *get_restorepath(struct conf **cconfs)
      35             : {
      36          36 :         char *tmp=NULL;
      37          36 :         char *restorepath=NULL;
      38          72 :         if((tmp=prepend_s(get_string(cconfs[OPT_DIRECTORY]),
      39          72 :                 get_string(cconfs[OPT_CNAME]))))
      40          36 :                         restorepath=prepend_s(tmp, "restore");
      41          36 :         free_w(&tmp);
      42          36 :         return restorepath;
      43             : }
      44             : 
      45          36 : static int send_features(struct asfd *asfd, struct conf **cconfs)
      46             : {
      47          36 :         int ret=-1;
      48          36 :         char *feat=NULL;
      49             :         struct stat statp;
      50          36 :         char *restorepath=NULL;
      51          36 :         enum protocol protocol=get_protocol(cconfs);
      52          36 :         struct strlist *startdir=get_strlist(cconfs[OPT_STARTDIR]);
      53          36 :         struct strlist *incglob=get_strlist(cconfs[OPT_INCGLOB]);
      54             : 
      55          72 :         if(append_to_feat(&feat, "extra_comms_begin ok:")
      56             :                 /* clients can autoupgrade */
      57          36 :           || append_to_feat(&feat, "autoupgrade:")
      58             :                 /* clients can give server incexc conf so that the
      59             :                    server knows better what to do on resume */
      60          36 :           || append_to_feat(&feat, "incexc:")
      61             :                 /* clients can give the server an alternative client
      62             :                    to restore from */
      63          36 :           || append_to_feat(&feat, "orig_client:")
      64             :                 /* clients can tell the server what kind of system they are. */
      65          72 :           || append_to_feat(&feat, "uname:"))
      66             :                 goto end;
      67             : 
      68             :         /* Clients can receive restore initiated from the server. */
      69          72 :         if(!(restorepath=get_restorepath(cconfs))
      70          36 :           || set_string(cconfs[OPT_RESTORE_PATH], restorepath))
      71             :                 goto end;
      72          76 :         if(!lstat(restorepath, &statp) && S_ISREG(statp.st_mode)
      73          40 :           && append_to_feat(&feat, "srestore:"))
      74             :                 goto end;
      75             : 
      76             :         /* Clients can receive incexc conf from the server.
      77             :            Only give it as an option if the server has some starting
      78             :            directory configured in the clientconfdir. */
      79          72 :         if((startdir || incglob)
      80          36 :           && append_to_feat(&feat, "sincexc:"))
      81             :                 goto end;
      82             : 
      83             :         /* Clients can be sent cntrs on resume/verify/restore. */
      84             : /*
      85             :         if(append_to_feat(&feat, "counters_json:"))
      86             :                 goto end;
      87             : */
      88             : 
      89             :         // We support CMD_MESSAGE.
      90          36 :         if(append_to_feat(&feat, "msg:"))
      91             :                 goto end;
      92             : 
      93          36 :         if(protocol==PROTO_AUTO)
      94             :         {
      95             :                 /* If the server is configured to use either protocol, let the
      96             :                    client know that it can choose. */
      97          26 :                 logp("Server is using protocol=0 (auto)\n");
      98          26 :                 if(append_to_feat(&feat, "csetproto:"))
      99             :                         goto end;
     100             :         }
     101             :         else
     102             :         {
     103          10 :                 char p[32]="";
     104             :                 /* Tell the client what we are going to use. */
     105          10 :                 logp("Server is using protocol=%d\n", (int)protocol);
     106          10 :                 snprintf(p, sizeof(p), "forceproto=%d:", (int)protocol);
     107          10 :                 if(append_to_feat(&feat, p))
     108             :                         goto end;
     109             :         }
     110             : 
     111             : #ifndef RS_DEFAULT_STRONG_LEN
     112             :         if(append_to_feat(&feat, "rshash=blake2:"))
     113             :                 goto end;
     114             : #endif
     115             : 
     116             :         //printf("feat: %s\n", feat);
     117             : 
     118          36 :         if(asfd->write_str(asfd, CMD_GEN, feat))
     119             :         {
     120           1 :                 logp("problem in extra_comms\n");
     121           1 :                 goto end;
     122             :         }
     123             : 
     124             :         ret=0;
     125             : end:
     126          36 :         free_w(&feat);
     127          36 :         free_w(&restorepath);
     128          36 :         return ret;
     129             : }
     130             : 
     131             : struct vers
     132             : {
     133             :         long min;
     134             :         long cli;
     135             :         long ser;
     136             :         long feat_list;
     137             :         long directory_tree;
     138             :         long burp2;
     139             : };
     140             : 
     141          35 : static int extra_comms_read(struct async *as,
     142             :         struct vers *vers, int *srestore,
     143             :         char **incexc, struct conf **globalcs, struct conf **cconfs)
     144             : {
     145          35 :         int ret=-1;
     146             :         struct asfd *asfd;
     147             :         struct iobuf *rbuf;
     148          35 :         asfd=as->asfd;
     149          35 :         rbuf=asfd->rbuf;
     150             : 
     151             :         while(1)
     152             :         {
     153          54 :                 iobuf_free_content(rbuf);
     154          54 :                 if(asfd->read(asfd)) goto end;
     155             : 
     156          54 :                 if(rbuf->cmd!=CMD_GEN)
     157             :                 {
     158           1 :                         iobuf_log_unexpected(rbuf, __func__);
     159             :                         goto end;
     160             :                 }
     161             : 
     162          53 :                 if(!strcmp(rbuf->buf, "extra_comms_end"))
     163             :                 {
     164          23 :                         if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok"))
     165             :                                 goto end;
     166             :                         break;
     167             :                 }
     168          30 :                 else if(!strncmp_w(rbuf->buf, "autoupgrade:"))
     169             :                 {
     170           2 :                         char *os=NULL;
     171             :                         const char *autoupgrade_dir=
     172           2 :                                 get_string(globalcs[OPT_AUTOUPGRADE_DIR]);
     173           2 :                         os=rbuf->buf+strlen("autoupgrade:");
     174           2 :                         iobuf_free_content(rbuf);
     175           3 :                         if(os && *os && autoupgrade_server(as, vers->ser,
     176             :                                 vers->cli, os, get_cntr(globalcs),
     177           1 :                                 autoupgrade_dir))
     178             :                                         goto end;
     179             :                 }
     180          28 :                 else if(!strcmp(rbuf->buf, "srestore ok"))
     181             :                 {
     182           4 :                         iobuf_free_content(rbuf);
     183             :                         // Client can accept the restore.
     184             :                         // Load the restore config, then send it.
     185           4 :                         *srestore=1;
     186           4 :                         if(conf_parse_incexcs_path(cconfs,
     187           4 :                                 get_string(cconfs[OPT_RESTORE_PATH]))
     188           4 :                           || incexc_send_server_restore(asfd, cconfs))
     189             :                                 goto end;
     190             :                         // Do not unlink it here - wait until
     191             :                         // the client says that it wants to do the
     192             :                         // restore.
     193             :                         // Also need to leave it around if the
     194             :                         // restore is to an alternative client, so
     195             :                         // that the code below that reloads the config
     196             :                         // can read it again.
     197             :                         //unlink(get_string(cconfs[OPT_RESTORE_PATH]));
     198             :                 }
     199          24 :                 else if(!strcmp(rbuf->buf, "srestore not ok"))
     200             :                 {
     201             :                         const char *restore_path=get_string(
     202           1 :                                 cconfs[OPT_RESTORE_PATH]);
     203             :                         // Client will not accept the restore.
     204           1 :                         unlink(restore_path);
     205           1 :                         if(set_string(cconfs[OPT_RESTORE_PATH], NULL))
     206             :                                 goto end;
     207           1 :                         logp("Client not accepting server initiated restore.\n");
     208             :                 }
     209          23 :                 else if(!strcmp(rbuf->buf, "sincexc ok"))
     210             :                 {
     211             :                         // Client can accept incexc conf from the
     212             :                         // server.
     213           1 :                         iobuf_free_content(rbuf);
     214           1 :                         if(incexc_send_server(asfd, cconfs))
     215             :                                 goto end;
     216             :                 }
     217          22 :                 else if(!strcmp(rbuf->buf, "incexc"))
     218             :                 {
     219             :                         // Client is telling server its incexc
     220             :                         // configuration so that it can better decide
     221             :                         // what to do on resume.
     222           1 :                         iobuf_free_content(rbuf);
     223           1 :                         if(incexc_recv_server(asfd, incexc, globalcs))
     224             :                                 goto end;
     225           1 :                         if(*incexc)
     226             :                         {
     227           1 :                                 char *tmp=NULL;
     228           1 :                                 char comp[32]="";
     229             :                                 snprintf(comp, sizeof(comp),
     230             :                                         "compression = %d\n",
     231           1 :                                         get_int(cconfs[OPT_COMPRESSION]));
     232           1 :                                 if(!(tmp=prepend(*incexc, comp)))
     233             :                                         goto end;
     234           1 :                                 free_w(incexc);
     235           1 :                                 *incexc=tmp;
     236             :                         }
     237             :                 }
     238          21 :                 else if(!strcmp(rbuf->buf, "counters_json ok"))
     239             :                 {
     240             :                         // Client can accept counters on
     241             :                         // resume/verify/restore.
     242           1 :                         logp("Client supports being sent json counters.\n");
     243           1 :                         set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1);
     244             :                 }
     245          40 :                 else if(!strncmp_w(rbuf->buf, "uname=")
     246          20 :                   && strlen(rbuf->buf)>strlen("uname="))
     247             :                 {
     248           2 :                         char *uname=rbuf->buf+strlen("uname=");
     249           2 :                         if(!strncasecmp("Windows", uname, strlen("Windows")))
     250           1 :                                 set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1);
     251             :                 }
     252          36 :                 else if(!strncmp_w(rbuf->buf, "orig_client=")
     253          18 :                   && strlen(rbuf->buf)>strlen("orig_client="))
     254             :                 {
     255           3 :                         if(conf_switch_to_orig_client(globalcs, cconfs,
     256           3 :                                 rbuf->buf+strlen("orig_client=")))
     257             :                                         goto end;
     258             :                         // If this started out as a server-initiated
     259             :                         // restore, need to load the restore file
     260             :                         // again.
     261           2 :                         if(*srestore)
     262             :                         {
     263           1 :                                 if(conf_parse_incexcs_path(cconfs,
     264           1 :                                         get_string(cconfs[OPT_RESTORE_PATH])))
     265             :                                                 goto end;
     266             :                         }
     267           2 :                         if(asfd->write_str(asfd, CMD_GEN, "orig_client ok"))
     268             :                                 goto end;
     269             :                 }
     270          15 :                 else if(!strncmp_w(rbuf->buf, "restore_spool="))
     271             :                 {
     272             :                         // Client supports temporary spool directory
     273             :                         // for restores.
     274           1 :                         if(set_string(cconfs[OPT_RESTORE_SPOOL],
     275           1 :                                 rbuf->buf+strlen("restore_spool=")))
     276             :                                         goto end;
     277             :                 }
     278          14 :                 else if(!strncmp_w(rbuf->buf, "protocol="))
     279             :                 {
     280          11 :                         char msg[128]="";
     281             :                         // Client wants to set protocol.
     282          11 :                         enum protocol protocol=get_protocol(cconfs);
     283          11 :                         const char *cliproto=rbuf->buf+strlen("protocol=");
     284          11 :                         if(protocol!=PROTO_AUTO)
     285             :                         {
     286           6 :                                 snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s but server is set to protocol=%d\n", cliproto, protocol);
     287           6 :                                 log_and_send(asfd, msg);
     288           7 :                                 goto end;
     289             :                         }
     290           5 :                         else if(!strcmp(cliproto, "1"))
     291             :                         {
     292           2 :                                 set_protocol(cconfs, PROTO_1);
     293           2 :                                 set_protocol(globalcs, PROTO_1);
     294             :                         }
     295           3 :                         else if(!strcmp(cliproto, "2"))
     296             :                         {
     297           2 :                                 set_protocol(cconfs, PROTO_2);
     298           2 :                                 set_protocol(globalcs, PROTO_2);
     299             :                         }
     300             :                         else
     301             :                         {
     302             :                                 snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s, which is unknown\n", cliproto);
     303           1 :                                 log_and_send(asfd, msg);
     304             :                                 goto end;
     305             :                         }
     306             :                         logp("Client has set protocol=%d\n",
     307           4 :                                 (int)get_protocol(cconfs));
     308             :                 }
     309           3 :                 else if(!strncmp_w(rbuf->buf, "rshash=blake2"))
     310             :                 {
     311             : #ifdef RS_DEFAULT_STRONG_LEN
     312           1 :                         logp("Client is trying to use librsync hash blake2, but server does not support it.\n");
     313             :                         goto end;
     314             : #else
     315             :                         set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2);
     316             :                         set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2);
     317             : #endif
     318             :                 }
     319           2 :                 else if(!strncmp_w(rbuf->buf, "msg"))
     320             :                 {
     321           1 :                         set_int(cconfs[OPT_MESSAGE], 1);
     322           1 :                         set_int(globalcs[OPT_MESSAGE], 1);
     323             :                 }
     324             :                 else
     325             :                 {
     326           1 :                         iobuf_log_unexpected(rbuf, __func__);
     327             :                         goto end;
     328             :                 }
     329             :         }
     330             : 
     331          23 :         ret=0;
     332             : end:
     333          35 :         iobuf_free_content(rbuf);
     334          35 :         return ret;
     335             : }
     336             : 
     337          40 : static int vers_init(struct vers *vers, struct conf **cconfs)
     338             : {
     339             :         memset(vers, 0, sizeof(struct vers));
     340          40 :         return ((vers->min=version_to_long("1.2.7"))<0
     341          40 :           || (vers->cli=version_to_long(get_string(cconfs[OPT_PEER_VERSION])))<0
     342          40 :           || (vers->ser=version_to_long(VERSION))<0
     343          40 :           || (vers->feat_list=version_to_long("1.3.0"))<0
     344          40 :           || (vers->directory_tree=version_to_long("1.3.6"))<0
     345          80 :           || (vers->burp2=version_to_long("2.0.0"))<0);
     346             : }
     347             : 
     348          40 : int extra_comms(struct async *as,
     349             :         char **incexc, int *srestore, struct conf **confs, struct conf **cconfs)
     350             : {
     351             :         struct vers vers;
     352             :         struct asfd *asfd;
     353          40 :         asfd=as->asfd;
     354             :         //char *restorepath=NULL;
     355          40 :         const char *peer_version=NULL;
     356             : 
     357          40 :         if(vers_init(&vers, cconfs))
     358             :                 goto error;
     359             : 
     360          40 :         if(vers.cli<vers.directory_tree)
     361             :         {
     362           3 :                 set_int(confs[OPT_DIRECTORY_TREE], 0);
     363           3 :                 set_int(cconfs[OPT_DIRECTORY_TREE], 0);
     364             :         }
     365             : 
     366             :         // Clients before 1.2.7 did not know how to do extra comms, so skip
     367             :         // this section for them.
     368          40 :         if(vers.cli<vers.min)
     369             :                 return 0;
     370             : 
     371          38 :         if(asfd_read_expect(asfd, CMD_GEN, "extra_comms_begin"))
     372             :         {
     373           1 :                 logp("problem reading in extra_comms\n");
     374           1 :                 goto error;
     375             :         }
     376             :         // Want to tell the clients the extra comms features that are
     377             :         // supported, so that new clients are more likely to work with old
     378             :         // servers.
     379          37 :         if(vers.cli==vers.feat_list)
     380             :         {
     381             :                 // 1.3.0 did not support the feature list.
     382           1 :                 if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin ok"))
     383             :                 {
     384           1 :                         logp("problem writing in extra_comms\n");
     385           1 :                         goto error;
     386             :                 }
     387             :         }
     388             :         else
     389             :         {
     390          36 :                 if(send_features(asfd, cconfs))
     391             :                         goto error;
     392             :         }
     393             : 
     394          35 :         if(extra_comms_read(as, &vers, srestore, incexc, confs, cconfs))
     395             :                 goto error;
     396             : 
     397          23 :         peer_version=get_string(cconfs[OPT_PEER_VERSION]);
     398             : 
     399             :         // This needs to come after extra_comms_read, as the client might
     400             :         // have set PROTO_1 or PROTO_2.
     401          23 :         switch(get_protocol(cconfs))
     402             :         {
     403             :                 case PROTO_AUTO:
     404             :                         // The protocol has not been specified. Make a choice.
     405          15 :                         if(vers.cli<vers.burp2)
     406             :                         {
     407             :                                 // Client is burp-1.x.x, use protocol1.
     408           1 :                                 set_protocol(confs, PROTO_1);
     409           1 :                                 set_protocol(cconfs, PROTO_1);
     410             :                                 logp("Client is burp-%s - using protocol=%d\n",
     411           1 :                                         peer_version, PROTO_1);
     412             :                         }
     413             :                         else
     414             :                         {
     415             :                                 // Client is burp-2.x.x, use protocol2.
     416             :                                 // This will probably never be reached because
     417             :                                 // the negotiation will take care of it.
     418          14 :                                 set_protocol(confs, PROTO_2);
     419          14 :                                 set_protocol(cconfs, PROTO_2);
     420             :                                 logp("Client is burp-%s - using protocol=%d\n",
     421          14 :                                         peer_version, PROTO_2);
     422             :                         }
     423             :                         break;
     424             :                 case PROTO_1:
     425             :                         // It is OK for the client to be burp1 and for the
     426             :                         // server to be forced to protocol1.
     427             :                         break;
     428             :                 case PROTO_2:
     429           4 :                         if(vers.cli>=vers.burp2)
     430             :                                 break;
     431             :                         logp("protocol=%d is set server side, "
     432             :                           "but client is burp version %s\n",
     433           2 :                           PROTO_2, peer_version);
     434           2 :                         goto error;
     435             :         }
     436             : 
     437          21 :         if(get_protocol(cconfs)==PROTO_1)
     438             :         {
     439           5 :                 if(get_e_rshash(cconfs[OPT_RSHASH])==RSHASH_UNSET)
     440             :                 {
     441           5 :                         set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4);
     442           5 :                         set_e_rshash(cconfs[OPT_RSHASH], RSHASH_MD4);
     443             :                 }
     444             :         }
     445             : 
     446             :         return 0;
     447             : error:
     448             :         return -1;
     449             : }

Generated by: LCOV version 1.10