LCOV - code coverage report
Current view: top level - src/server/monitor - cstat.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 138 156 88.5 %
Date: 2018-03-30 Functions: 11 12 91.7 %

          Line data    Source code
       1             : #include "../../burp.h"
       2             : #include "../../alloc.h"
       3             : #include "../../bu.h"
       4             : #include "../../cstat.h"
       5             : #include "../../conffile.h"
       6             : #include "../../fsops.h"
       7             : #include "../../lock.h"
       8             : #include "../../log.h"
       9             : #include "../../strlist.h"
      10             : #include "../bu_get.h"
      11             : #include "../sdirs.h"
      12             : #include "cstat.h"
      13             : 
      14             : #ifndef UTEST
      15             : static 
      16             : #endif
      17          19 : int cstat_permitted(struct cstat *cstat,
      18             :         struct conf **monitor_cconfs, struct conf **cconfs)
      19             : {
      20             :         struct strlist *rclient;
      21             :         const char *monitorconf_cname;
      22             : 
      23          19 :         monitorconf_cname=get_string(monitor_cconfs[OPT_CNAME]);
      24          19 :         if(!monitorconf_cname)
      25             :                 return 0;
      26             : 
      27             :         // Allow clients to look at themselves.
      28           4 :         if(!strcmp(cstat->name, monitorconf_cname))
      29             :                 return 1;
      30             : 
      31             :         // Do not allow clients using the restore_client option to see more
      32             :         // than the client that it is pretending to be.
      33           3 :         if(get_string(monitor_cconfs[OPT_RESTORE_CLIENT]))
      34             :                 return 0;
      35             : 
      36             :         // If we are listed in this restore_client list.
      37           6 :         for(rclient=get_strlist(cconfs[OPT_RESTORE_CLIENTS]);
      38           2 :           rclient; rclient=rclient->next)
      39           3 :             if(!strcmp(get_string(monitor_cconfs[OPT_CNAME]), rclient->path))
      40             :                 return 1;
      41             :         return 0;
      42             : }
      43             : 
      44          15 : static int cstat_set_sdirs_protocol_unknown(struct cstat *cstat,
      45             :         struct conf **cconfs)
      46             : {
      47             :         struct stat buf1;
      48             :         struct stat buf2;
      49          15 :         struct sdirs *sdirs1=NULL;
      50          15 :         struct sdirs *sdirs2=NULL;
      51             : 
      52          15 :         if(!(sdirs1=sdirs_alloc())
      53          15 :           || !(sdirs2=sdirs_alloc()))
      54             :                 goto error;
      55             : 
      56          15 :         set_protocol(cconfs, PROTO_1);
      57          15 :         if(sdirs_init_from_confs(sdirs1, cconfs))
      58             :                 goto error;
      59          15 :         set_protocol(cconfs, PROTO_2);
      60          15 :         if(sdirs_init_from_confs(sdirs2, cconfs))
      61             :                 goto error;
      62             : 
      63          30 :         if(lstat(sdirs2->client, &buf2))
      64             :                 goto protocol1; // No protocol2 client directory.
      65             : 
      66           0 :         if(lstat(sdirs1->client, &buf1))
      67             :                 goto protocol2; // No protocol1 client directory.
      68             : 
      69             :         // Both directories exist.
      70             : 
      71           0 :         if(buf2.st_mtime>buf1.st_mtime)
      72             :                 goto protocol2; // 2 was modified most recently.
      73             : 
      74             :         // Fall through to protocol1.
      75             : 
      76             : protocol1:
      77          15 :         cstat->sdirs=sdirs1;
      78          15 :         cstat->protocol=PROTO_1;
      79          15 :         sdirs_free(&sdirs2);
      80          15 :         set_protocol(cconfs, PROTO_AUTO);
      81             :         return 0;
      82             : protocol2:
      83           0 :         cstat->sdirs=sdirs2;
      84           0 :         cstat->protocol=PROTO_2;
      85           0 :         sdirs_free(&sdirs1);
      86           0 :         set_protocol(cconfs, PROTO_AUTO);
      87             :         return 0;
      88             : error:
      89           0 :         sdirs_free(&sdirs1);
      90           0 :         sdirs_free(&sdirs2);
      91           0 :         set_protocol(cconfs, PROTO_AUTO);
      92             :         return -1;
      93             : }
      94             : 
      95           0 : static int cstat_set_sdirs_protocol_known(struct cstat *cstat,
      96             :         struct conf **cconfs)
      97             : {
      98           0 :         struct sdirs *sdirs=NULL;
      99             : 
     100           0 :         if(!(sdirs=sdirs_alloc()))
     101             :                 return -1;
     102           0 :         if(sdirs_init_from_confs(sdirs, cconfs))
     103             :         {
     104           0 :                 sdirs_free(&sdirs);
     105             :                 return -1;
     106             :         }
     107           0 :         cstat->sdirs=sdirs;
     108             :         return 0;
     109             : }
     110             : 
     111          15 : static int cstat_set_sdirs(struct cstat *cstat, struct conf **cconfs)
     112             : {
     113          15 :         enum protocol protocol=get_protocol(cconfs);
     114          15 :         sdirs_free((struct sdirs **)&cstat->sdirs);
     115             : 
     116          15 :         if(protocol==PROTO_AUTO)
     117          15 :                 return cstat_set_sdirs_protocol_unknown(cstat, cconfs);
     118             : 
     119           0 :         cstat->protocol=protocol;
     120           0 :         return cstat_set_sdirs_protocol_known(cstat, cconfs);
     121             : }
     122             : 
     123          15 : static int set_cstat_from_conf(struct cstat *cstat,
     124             :         struct conf **monitor_cconfs, struct conf **cconfs)
     125             : {
     126          15 :         struct strlist *s=NULL;
     127             :         // Make sure the permitted flag is set appropriately.
     128          15 :         cstat->permitted=cstat_permitted(cstat, monitor_cconfs, cconfs);
     129             : 
     130          15 :         if(cstat_set_sdirs(cstat, cconfs))
     131             :                 return -1;
     132          15 :         strlists_free(&cstat->labels);
     133          21 :         for(s=get_strlist(cconfs[OPT_LABEL]); s; s=s->next)
     134           6 :                 if(strlist_add_sorted(&cstat->labels, s->path, s->flag))
     135             :                         return -1;
     136             :         return 0;
     137             : }
     138             : 
     139             : #ifndef UTEST
     140             : static
     141             : #endif
     142          24 : int cstat_get_client_names(struct cstat **clist, const char *clientconfdir)
     143             : {
     144          24 :         int i=0;
     145          24 :         int n=0;
     146          24 :         int ret=-1;
     147             :         struct cstat *c;
     148             :         struct cstat *cnew;
     149          24 :         struct dirent **dir=NULL;
     150             : 
     151          24 :         if((n=scandir(clientconfdir, &dir, filter_dot, NULL))<0)
     152             :         {
     153           1 :                 logp("scandir failed for %s in %s: %s\n",
     154           1 :                         clientconfdir, __func__, strerror(errno));
     155           1 :                 goto end;
     156             :         }
     157          75 :         for(i=0; i<n; i++)
     158             :         {
     159             :                 // looks_like...() also avoids '.' and '..'.
     160          75 :                 if(looks_like_tmp_or_hidden_file(dir[i]->d_name))
     161           2 :                         continue;
     162         173 :                 for(c=*clist; c; c=c->next)
     163             :                 {
     164         117 :                         if(!c->name) continue;
     165         117 :                         if(!strcmp(dir[i]->d_name, c->name))
     166             :                                 break;
     167             :                 }
     168          73 :                 if(c) continue;
     169             : 
     170             :                 // We do not have this client yet. Add it.
     171          56 :                 if(!(cnew=cstat_alloc())
     172          56 :                   || cstat_init(cnew, dir[i]->d_name, clientconfdir))
     173             :                         goto end;
     174          56 :                 cstat_add_to_list(clist, cnew);
     175             :         }
     176             : 
     177             :         ret=0;
     178             : end:
     179          24 :         if(dir)
     180             :         {
     181          75 :                 for(i=0; i<n; i++)
     182          75 :                         free(dir[i]);
     183          23 :                 free(dir);
     184             :         }
     185          24 :         return ret;
     186             : }
     187             : 
     188             : static void cstat_free_w(struct cstat **cstat)
     189             : {
     190           8 :         sdirs_free((struct sdirs **)&(*cstat)->sdirs);
     191           8 :         cstat_free(cstat);
     192             : }
     193             : 
     194             : #ifndef UTEST
     195             : static
     196             : #endif
     197           8 : void cstat_remove(struct cstat **clist, struct cstat **cstat)
     198             : {
     199             :         struct cstat *c;
     200           8 :         if(!cstat || !*cstat) return;
     201           8 :         if(*clist==*cstat)
     202             :         {
     203           4 :                 *clist=(*clist)->next;
     204           4 :                 if(*clist) (*clist)->prev=NULL;
     205             :                 cstat_free_w(cstat);
     206           4 :                 *cstat=*clist;
     207           4 :                 return;
     208             :         }
     209          10 :         for(c=*clist; c; c=c->next)
     210             :         {
     211           7 :                 if(c->next!=*cstat)
     212           3 :                         continue;
     213           4 :                 c->next=(*cstat)->next;
     214           4 :                 if(c->next)
     215           3 :                         c->next->prev=(*cstat)->prev;
     216             :                 cstat_free_w(cstat);
     217           4 :                 *cstat=*clist;
     218           4 :                 return;
     219             :         }
     220             : }
     221             : 
     222             : // Returns -1 on error, otherwise the number of clients that were reloaded.
     223             : #ifndef UTEST
     224             : static
     225             : #endif
     226          12 : int cstat_reload_from_client_confs(struct cstat **clist,
     227             :         struct conf **monitor_cconfs,
     228             :         struct conf **globalcs, struct conf **cconfs)
     229             : {
     230             :         struct cstat *c;
     231             :         struct stat statp;
     232             :         static time_t global_mtime=0;
     233          12 :         time_t global_mtime_new=0;
     234             :         const char *globalconffile;
     235          12 :         int reloaded=0;
     236             : 
     237          12 :         globalconffile=get_string(globalcs[OPT_CONFFILE]);
     238             : 
     239          12 :         if(stat(globalconffile, &statp)
     240          11 :           || !S_ISREG(statp.st_mode))
     241             :         {
     242           1 :                 logp("Could not stat main conf file %s: %s\n",
     243           1 :                         globalconffile, strerror(errno));
     244           1 :                 return -1;
     245             :         }
     246          11 :         global_mtime_new=statp.st_mtime;
     247             : 
     248             :         // FIX THIS: If '. included' conf files have changed, this code will
     249             :         // not detect them. I guess that conf.c should make a list of them.
     250             :         while(1)
     251             :         {
     252          41 :                 for(c=*clist; c; c=c->next)
     253             :                 {
     254             :                         // Look at the client conf files to see if they have
     255             :                         // changed, and reload bits and pieces if they have.
     256             : 
     257          31 :                         if(!c->conffile) continue;
     258          62 :                         if(stat(c->conffile, &statp)
     259          28 :                           || !S_ISREG(statp.st_mode))
     260             :                         {
     261           3 :                                 cstat_remove(clist, &c);
     262           3 :                                 break; // Go to the beginning of the list.
     263             :                         }
     264          28 :                         if(statp.st_mtime==c->conf_mtime
     265          12 :                           && global_mtime_new==global_mtime)
     266             :                         {
     267             :                                 // The conf files have not changed - no need to
     268             :                                 // do anything.
     269          12 :                                 continue;
     270             :                         }
     271          16 :                         c->conf_mtime=statp.st_mtime;
     272             : 
     273          16 :                         confs_free_content(cconfs);
     274          16 :                         if(set_string(cconfs[OPT_CNAME], c->name))
     275             :                                 return -1;
     276          16 :                         if(conf_load_clientconfdir(globalcs, cconfs))
     277             :                         {
     278             :                                 // If the file has junk in it, we will keep
     279             :                                 // trying to reload it after removal.
     280             :                                 // So, just deny permission to view it.
     281           1 :                                 c->permitted=0;
     282           1 :                                 continue;
     283             :                         }
     284             : 
     285          15 :                         if(set_cstat_from_conf(c, monitor_cconfs, cconfs))
     286             :                                 return -1;
     287          15 :                         reloaded++;
     288             :                 }
     289             :                 // Only stop if the end of the list was not reached.
     290          13 :                 if(!c) break;
     291             :         }
     292          11 :         if(global_mtime!=global_mtime_new)
     293           3 :                 global_mtime=global_mtime_new;
     294          11 :         return reloaded;
     295             : }
     296             : 
     297          22 : void cstat_set_run_status(struct cstat *cstat, enum run_status run_status)
     298             : {
     299          22 :         if(!cstat->permitted)
     300          22 :                 return;
     301          20 :         cstat->run_status=run_status;
     302             : }
     303             : 
     304             : // Return -1 on error, or the number of reloaded clients.
     305             : #ifndef UTEST
     306             : static
     307             : #endif
     308           8 : int reload_from_clientdir(struct cstat **clist)
     309             : {
     310           8 :         int reloaded=0;
     311             :         struct cstat *c;
     312          27 :         for(c=*clist; c; c=c->next)
     313             :         {
     314             :                 struct stat statp;
     315             :                 struct sdirs *sdirs;
     316             : 
     317          36 :                 if(!c->permitted) continue;
     318             : 
     319           6 :                 sdirs=(struct sdirs *)c->sdirs;
     320           6 :                 if(!sdirs || !sdirs->client) continue;
     321          12 :                 if(stat(sdirs->client, &statp))
     322           2 :                         continue;
     323             : 
     324           4 :                 if(statp.st_mtime==c->clientdir_mtime)
     325             :                 {
     326             :                         // clientdir has not changed - no need to do anything.
     327           2 :                         continue;
     328             :                 }
     329           2 :                 c->clientdir_mtime=statp.st_mtime;
     330             : 
     331           2 :                 bu_list_free(&c->bu);
     332             : // FIX THIS: should probably not load everything each time.
     333             : //              if(bu_get_current(sdirs, &c->bu))
     334             : //                      goto error;
     335           2 :                 if(bu_get_list_with_working(sdirs, &c->bu, c))
     336             :                         goto error;
     337           2 :                 reloaded++;
     338             :         }
     339             :         return reloaded;
     340             : error:
     341           0 :         return -1;
     342             : }
     343             : 
     344           2 : int cstat_load_data_from_disk(struct cstat **clist,
     345             :         struct conf **monitor_cconfs,
     346             :         struct conf **globalcs, struct conf **cconfs)
     347             : {
     348           2 :         if(!globalcs) return -1;
     349           4 :         return cstat_get_client_names(clist,
     350           2 :                 get_string(globalcs[OPT_CLIENTCONFDIR]))
     351           2 :           || cstat_reload_from_client_confs(clist,
     352             :                 monitor_cconfs, globalcs, cconfs)<0
     353           4 :           || reload_from_clientdir(clist)<0;
     354             : }
     355             : 
     356          26 : int cstat_set_backup_list(struct cstat *cstat)
     357             : {
     358          26 :         struct bu *bu=NULL;
     359             : 
     360             :         // Free any previous list.
     361          26 :         bu_list_free(&cstat->bu);
     362             : 
     363          26 :         if(!cstat->permitted) return 0;
     364             : 
     365          24 :         if(bu_get_list_with_working((struct sdirs *)cstat->sdirs, &bu, cstat))
     366             :         {
     367             :                 //logp("error when looking up current backups\n");
     368             :                 return 0;
     369             :         }
     370             : 
     371             :         // Find the end of the list just loaded, so we can traverse
     372             :         // it backwards later.
     373          50 :         while(bu && bu->next) bu=bu->next;
     374             : 
     375          23 :         cstat->bu=bu;
     376          23 :         return 0;
     377             : }

Generated by: LCOV version 1.10