LCOV - code coverage report
Current view: top level - src/server - child.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 15 122 12.3 %
Date: 2020-08-31 23:02:24 Functions: 3 7 42.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 "../cntr.h"
       7             : #include "../conf.h"
       8             : #include "../cstat.h"
       9             : #include "../handy.h"
      10             : #include "../iobuf.h"
      11             : #include "../log.h"
      12             : #include "../prepend.h"
      13             : #include "../run_script.h"
      14             : #include "extra_comms.h"
      15             : #include "monitor/status_server.h"
      16             : #include "run_action.h"
      17             : #include "child.h"
      18             : #include "timer.h"
      19             : 
      20             : static struct asfd *wasfd=NULL;
      21             : 
      22             : static enum action act=ACTION_UNSET;
      23             : 
      24      218059 : static int write_status(
      25             :         enum cntr_status cntr_status,
      26             :         const char *path,
      27             :         struct cntr *cntr,
      28             :         time_t now
      29             : ) {
      30             :         static size_t l=0;
      31             :         static struct iobuf *wbuf=NULL;
      32             :         static time_t lasttime=0;
      33      218059 :         time_t diff=0;
      34             : 
      35             :         // Only update every 2 seconds.
      36      218059 :         diff=now-lasttime;
      37      218059 :         if(diff<2)
      38             :         {
      39             :                 // Might as well do this in case they fiddled their
      40             :                 // clock back in time.
      41      218027 :                 if(diff<0) lasttime=now;
      42             :                 return 0;
      43             :         }
      44          32 :         lasttime=now;
      45             : 
      46          32 :         if(!wasfd) return 0;
      47           0 :         if(!cntr || !cntr->bno)
      48             :                 return 0;
      49             : 
      50             :         // Only get a new string if we did not manage to write the previous
      51             :         // one.
      52           0 :         if(!l)
      53             :         {
      54           0 :                 cntr->cntr_status=cntr_status;
      55           0 :                 if(!(l=cntr_to_str(cntr, path))) goto error;
      56           0 :                 if(!wbuf && !(wbuf=iobuf_alloc())) goto error;
      57           0 :                 iobuf_set(wbuf, CMD_APPEND, cntr->str, l);
      58             :         }
      59             : 
      60           0 :         switch(wasfd->append_all_to_write_buffer(wasfd, wbuf))
      61             :         {
      62             :                 case APPEND_OK:
      63           0 :                         l=0; // Fall through.
      64             :                 case APPEND_BLOCKED:
      65             :                         return 0;
      66             :                 default:
      67             :                         break;
      68             :         }
      69             : error:
      70           0 :         iobuf_free(&wbuf);
      71           0 :         return -1;
      72             : }
      73             : 
      74           0 : static int check_timer_script(
      75             :         enum cntr_status cntr_status,
      76             :         struct asfd *asfd,
      77             :         struct sdirs *sdirs,
      78             :         struct conf **confs,
      79             :         time_t now
      80             : ) {
      81             :         int interval;
      82           0 :         time_t diff=0;
      83             :         static time_t lasttime=0;
      84             : 
      85           0 :         if(cntr_status!=CNTR_STATUS_SCANNING
      86           0 :         && cntr_status!=CNTR_STATUS_BACKUP)
      87             :                 return 0;
      88             : 
      89             :         // The conf is in minutes, so multiply by 60 to get seconds.
      90           0 :         interval=get_int(confs[OPT_TIMER_REPEAT_INTERVAL]) * 60;
      91           0 :         if (!interval)
      92             :                 return 0;
      93             : 
      94           0 :         diff=now-lasttime;
      95           0 :         if(diff<interval)
      96             :         {
      97             :                 // Might as well do this in case they fiddled their
      98             :                 // clock back in time.
      99           0 :                 if(diff<0) lasttime=now;
     100             :                 return 0;
     101             :         }
     102           0 :         lasttime=now;
     103             : 
     104           0 :         return run_timer(
     105             :                 asfd,
     106             :                 sdirs,
     107             :                 confs
     108             :         );
     109             : }
     110             : 
     111      218120 : int timed_operation(
     112             :         enum cntr_status cntr_status,
     113             :         const char *path,
     114             :         struct asfd *asfd,
     115             :         struct sdirs *sdirs,
     116             :         struct conf **confs
     117             : ) {
     118      218120 :         time_t now=0;
     119             : 
     120      218120 :         if(!confs) return 0;
     121             : 
     122      218059 :         now=time(NULL);
     123             : 
     124      218059 :         if(write_status(cntr_status, path, get_cntr(confs), now))
     125             :                 return -1;
     126             : 
     127      218059 :         if(act!=ACTION_BACKUP_TIMED)
     128             :                 return 0;
     129           0 :         return check_timer_script(cntr_status,
     130             :                 asfd, sdirs, confs, now);
     131             : }
     132             : 
     133         217 : int timed_operation_status_only(
     134             :         enum cntr_status cntr_status,
     135             :         const char *path,
     136             :         struct conf **confs
     137             : ) {
     138         217 :         return timed_operation(
     139             :                 cntr_status,
     140             :                 path,
     141             :                 NULL, /*asfd*/
     142             :                 NULL, /*sdirs*/
     143             :                 confs
     144             :         );
     145             : }
     146             : 
     147           0 : static int run_server_script(struct asfd *asfd,
     148             :         const char *pre_or_post,
     149             :         const char *action_from_client,
     150             :         const char *script, struct strlist *script_arg,
     151             :         uint8_t notify, struct conf **cconfs, int backup_ret, int timer_ret)
     152             : {
     153           0 :         int a=0;
     154           0 :         int ret=0;
     155           0 :         char *logbuf=NULL;
     156             :         const char *args[12];
     157           0 :         const char *cname=get_string(cconfs[OPT_CNAME]);
     158             : 
     159           0 :         args[a++]=script;
     160           0 :         args[a++]=pre_or_post;
     161           0 :         args[a++]=action_from_client;
     162           0 :         args[a++]=cname;
     163           0 :         args[a++]=backup_ret?"1":"0", // Indicate success or failure.
     164             :         // Indicate whether the timer script said OK or not.
     165           0 :         args[a++]=timer_ret?"1":"0",
     166           0 :         args[a++]=NULL;
     167             : 
     168             :         // Do not have a client storage directory, so capture the
     169             :         // output in a buffer to pass to the notification script.
     170           0 :         if(run_script_to_buf(asfd, args, script_arg, cconfs, 1, 1, 0, &logbuf))
     171             :         {
     172             :                 char msg[256];
     173           0 :                 snprintf(msg, sizeof(msg),
     174             :                         "server %s script %s returned an error",
     175             :                         pre_or_post, script);
     176           0 :                 log_and_send(asfd, msg);
     177           0 :                 ret=-1;
     178           0 :                 if(!notify) goto end;
     179             : 
     180             :                 // If this is a backup failure and the client has more servers
     181             :                 // to failover to, do not notify.
     182           0 :                 if(!strncmp_w(action_from_client, "backup")
     183           0 :                   && get_int(cconfs[OPT_N_FAILURE_BACKUP_FAILOVERS_LEFT])
     184           0 :                   && get_int(cconfs[OPT_BACKUP_FAILOVERS_LEFT]))
     185             :                         goto end;
     186             : 
     187           0 :                 a=0;
     188           0 :                 args[a++]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
     189           0 :                 args[a++]=cname;
     190             :                 // magic - set basedir blank and the
     191             :                 // notify script will know to get the content
     192             :                 // from the next argument (usually storagedir)
     193           0 :                 args[a++]=""; // usually basedir
     194           0 :                 args[a++]=logbuf?logbuf:""; //usually storagedir
     195           0 :                 args[a++]=""; // usually file
     196           0 :                 args[a++]=""; // usually brv
     197           0 :                 args[a++]=""; // usually warnings
     198           0 :                 args[a++]=NULL;
     199           0 :                 run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
     200             :                         cconfs, 1, 1, 0);
     201             :         }
     202             : end:
     203           0 :         free_w(&logbuf);
     204           0 :         return ret;
     205             : }
     206             : 
     207           0 : static char *get_action_from_client(const char *buf)
     208             : {
     209           0 :         char *cp=NULL;
     210           0 :         char *ret=NULL;
     211             : 
     212           0 :         if(buf)
     213             :         {
     214           0 :                 if(!strcmp(buf, "backupphase1"))
     215             :                 {
     216           0 :                         act=ACTION_BACKUP;
     217           0 :                         return strdup_w("backup", __func__);
     218             :                 }
     219           0 :                 if(!strcmp(buf, "backupphase1timed"))
     220             :                 {
     221           0 :                         act=ACTION_BACKUP_TIMED;
     222           0 :                         return strdup_w("backup_timed", __func__);
     223             :                 }
     224             :         }
     225             : 
     226           0 :         if(!(ret=strdup_w(buf?buf:"", __func__)))
     227             :                 return NULL;
     228           0 :         if((cp=strchr(ret, ' ')))
     229           0 :                 *cp='\0';
     230             :         return ret;
     231             : }
     232             : 
     233           0 : int child(struct async *as, int is_status_server,
     234             :         int status_wfd, struct conf **confs, struct conf **cconfs)
     235             : {
     236           0 :         int ret=-1;
     237           0 :         int srestore=0;
     238           0 :         int timer_ret=0;
     239           0 :         char *incexc=NULL;
     240           0 :         char *action_from_client=NULL;
     241             :         const char *confs_user;
     242             :         const char *cconfs_user;
     243             :         const char *confs_group;
     244             :         const char *cconfs_group;
     245             :         const char *s_script_pre;
     246             :         const char *s_script_post;
     247             : 
     248             :         // If we are not a status server, we are a normal child - set up the
     249             :         // parent socket to write status to.
     250           0 :         if(status_wfd>0)
     251             :         {
     252           0 :                 if(!(wasfd=setup_asfd(as, "child status pipe", &status_wfd,
     253             :                         /*listen*/"")))
     254             :                                 goto end;
     255           0 :                 wasfd->attempt_reads=0;
     256             :         }
     257             :         /* Has to be before the chuser/chgrp stuff to allow clients to switch
     258             :            to different clients when both clients have different user/group
     259             :            settings. */
     260           0 :         if(extra_comms(as, &incexc, &srestore, confs, cconfs))
     261             :         {
     262           0 :                 log_and_send(as->asfd, "running extra comms failed on server");
     263           0 :                 goto end;
     264             :         }
     265             : 
     266             :         // Needs to happen after extra_comms, in case extra_comms resets them.
     267           0 :         confs_user=get_string(confs[OPT_USER]);
     268           0 :         cconfs_user=get_string(cconfs[OPT_USER]);
     269           0 :         confs_group=get_string(confs[OPT_GROUP]);
     270           0 :         cconfs_group=get_string(cconfs[OPT_GROUP]);
     271             : 
     272             :         /* Now that the client conf is loaded, we might want to chuser or
     273             :            chgrp.
     274             :            The main process could have already done this, so we don't want
     275             :            to try doing it again if cconfs has the same values, because it
     276             :            will fail. */
     277           0 :         if( (!confs_user  || (cconfs_user && strcmp(confs_user, cconfs_user)))
     278           0 :           ||(!confs_group ||(cconfs_group && strcmp(confs_group,cconfs_group))))
     279             :         {
     280           0 :                 if(chuser_and_or_chgrp(cconfs_user, cconfs_group, 0))
     281             :                 {
     282           0 :                         log_and_send(as->asfd,
     283             :                                 "chuser_and_or_chgrp failed on server");
     284           0 :                         goto end;
     285             :                 }
     286             :         }
     287             : 
     288           0 :         if(as->asfd->read(as->asfd))
     289             :                 goto end;
     290             : 
     291             :         // If this is a status server, run the status server.
     292           0 :         if(is_status_server)
     293             :         {
     294           0 :                 ret=status_server(as, cconfs);
     295           0 :                 goto end;
     296             :         }
     297             : 
     298           0 :         if(!(action_from_client=get_action_from_client(as->asfd->rbuf->buf)))
     299             :                 goto end;
     300           0 :         ret=0;
     301             : 
     302           0 :         s_script_pre=get_string(cconfs[OPT_S_SCRIPT_PRE]);
     303           0 :         s_script_post=get_string(cconfs[OPT_S_SCRIPT_POST]);
     304             : 
     305             :         // FIX THIS: Make the script components part of a struct, and just
     306             :         // pass in the correct struct. Same below.
     307             :         
     308           0 :         if(s_script_pre)
     309           0 :                 ret=run_server_script(as->asfd, "pre", action_from_client,
     310             :                         s_script_pre,
     311             :                         get_strlist(cconfs[OPT_S_SCRIPT_PRE_ARG]),
     312           0 :                         get_int(cconfs[OPT_S_SCRIPT_PRE_NOTIFY]),
     313             :                         cconfs, ret, timer_ret);
     314             : 
     315           0 :         if(!ret)
     316           0 :                 ret=run_action_server(as, incexc, srestore, &timer_ret, cconfs);
     317             : 
     318           0 :         if(!s_script_post)
     319             :                 goto end;
     320           0 :         if(ret && !get_int(cconfs[OPT_S_SCRIPT_POST_RUN_ON_FAIL]))
     321             :                         goto end;
     322           0 :         ret=run_server_script(as->asfd, "post", action_from_client,
     323             :                 s_script_post,
     324             :                 get_strlist(cconfs[OPT_S_SCRIPT_POST_ARG]),
     325           0 :                 get_int(cconfs[OPT_S_SCRIPT_POST_NOTIFY]),
     326             :                 cconfs, ret, timer_ret);
     327             : 
     328             : end:
     329           0 :         free_w(&action_from_client);
     330           0 :         return ret;
     331             : }

Generated by: LCOV version 1.13