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

Generated by: LCOV version 1.10