LCOV - code coverage report
Current view: top level - src/server - run_action.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 168 237 70.9 %
Date: 2017-04-01 Functions: 13 14 92.9 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../action.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../cmd.h"
       6             : #include "../cntr.h"
       7             : #include "../handy.h"
       8             : #include "../fsops.h"
       9             : #include "../iobuf.h"
      10             : #include "../lock.h"
      11             : #include "../log.h"
      12             : #include "../regexp.h"
      13             : #include "../run_script.h"
      14             : #include "backup.h"
      15             : #include "delete.h"
      16             : #include "diff.h"
      17             : #include "list.h"
      18             : #include "protocol2/restore.h"
      19             : #include "restore.h"
      20             : #include "rubble.h"
      21             : #include "sdirs.h"
      22             : #include "run_action.h"
      23             : 
      24             : // FIX THIS: Somewhat haphazard.
      25             : /* Return 0 for everything OK. -1 for error, or 1 to mean that there was
      26             :    another process that has the lock. */
      27           6 : static int get_lock_sdirs(struct asfd *asfd, struct sdirs *sdirs)
      28             : {
      29             :         struct stat statp;
      30             : 
      31             :         // Make sure the lock directory exists.
      32           6 :         if(mkpath(&sdirs->lock->path, sdirs->lockdir))
      33             :         {
      34           0 :                 asfd->write_str(asfd, CMD_ERROR, "problem with lock directory");
      35           0 :                 goto error;
      36             :         }
      37             : 
      38           6 :         lock_get(sdirs->lock);
      39           6 :         switch(sdirs->lock->status)
      40             :         {
      41             :                 case GET_LOCK_GOT: break;
      42             :                 case GET_LOCK_NOT_GOT:
      43           0 :                         if(!lstat(sdirs->finishing, &statp))
      44             :                         {
      45           0 :                                 char msg[256]="";
      46           0 :                                 logp("finalising previous backup\n");
      47             :                                 snprintf(msg, sizeof(msg),
      48             :                                         "Finalising previous backup of client. "
      49             :                                         "Please try again later.");
      50           0 :                                 asfd->write_str(asfd, CMD_ERROR, msg);
      51             :                         }
      52             :                         else
      53             :                         {
      54           0 :                                 logp("Another instance of client is already running.\n");
      55           0 :                                 asfd->write_str(asfd, CMD_ERROR,
      56             :                                         "another instance is already running");
      57             :                         }
      58             :                         goto lockedout;
      59             :                 case GET_LOCK_ERROR:
      60             :                 default:
      61           0 :                         logp("Problem with lock file on server: %s\n",
      62             :                                 sdirs->lock->path);
      63           0 :                         asfd->write_str(asfd, CMD_ERROR,
      64             :                                 "problem with lock file on server");
      65           0 :                         goto error;
      66             :         }
      67             : 
      68             :         return 0;
      69             : lockedout:
      70             :         return 1;
      71             : error:
      72             :         return -1;
      73             : }
      74             : 
      75           5 : static int client_can_generic(struct conf **cconfs, enum conf_opt o)
      76             : {
      77             :         // Always allow restore_clients, unless we are talking about forcing
      78             :         // a backup.
      79           5 :         if(get_string(cconfs[OPT_RESTORE_CLIENT])
      80           0 :           && o!=OPT_CLIENT_CAN_FORCE_BACKUP)
      81             :                 return 1;
      82             : 
      83           5 :         return get_int(cconfs[o]);
      84             : }
      85             : 
      86           1 : static int client_can_restore(struct conf **cconfs)
      87             : {
      88           1 :         const char *restore_path=get_string(cconfs[OPT_RESTORE_PATH]);
      89             : 
      90             :         // If there is a restore file on the server, it is always OK.
      91           1 :         if(is_reg_lstat(restore_path)==1)
      92             :         {
      93             :                 // Remove the file.
      94           0 :                 unlink(restore_path);
      95           0 :                 return 1;
      96             :         }
      97             : 
      98           1 :         return client_can_generic(cconfs, OPT_CLIENT_CAN_RESTORE);
      99             : }
     100             : 
     101           1 : static void maybe_do_notification(struct asfd *asfd,
     102             :         int status, const char *clientdir,
     103             :         const char *storagedir, const char *filename,
     104             :         const char *brv, struct conf **cconfs)
     105             : {
     106           1 :         int a=0;
     107             :         const char *args[12];
     108           1 :         struct cntr *cntr=get_cntr(cconfs);
     109           1 :         args[a++]=NULL; // Fill in the script name later.
     110           1 :         args[a++]=get_string(cconfs[OPT_CNAME]);
     111           1 :         args[a++]=clientdir;
     112           1 :         args[a++]=storagedir;
     113           1 :         args[a++]=filename;
     114           1 :         args[a++]=brv;
     115           1 :         if(status)
     116             :         {
     117           1 :                 args[0]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
     118           1 :                 args[a++]="0";
     119           1 :                 args[a++]=NULL;
     120           1 :                 run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
     121             :                         cconfs, 1, 1, 1);
     122             :         }
     123           0 :         else if((get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
     124           0 :                 && cntr->ent[CMD_WARNING]->count > 0)
     125           0 :           || (get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])
     126           0 :                 && cntr->ent[CMD_TOTAL]->changed > 0)
     127           0 :           || (!get_int(cconfs[OPT_N_SUCCESS_WARNINGS_ONLY])
     128           0 :                 && !get_int(cconfs[OPT_N_SUCCESS_CHANGES_ONLY])))
     129             :         {
     130           0 :                 char warnings[32]="";
     131           0 :                 snprintf(warnings, sizeof(warnings), "%" PRIu64,
     132           0 :                         cntr->ent[CMD_WARNING]->count);
     133           0 :                 args[0]=get_string(cconfs[OPT_N_SUCCESS_SCRIPT]);
     134           0 :                 args[a++]=warnings;
     135           0 :                 args[a++]=NULL;
     136           0 :                 run_script(asfd, args, get_strlist(cconfs[OPT_N_SUCCESS_ARG]),
     137             :                         cconfs, 1, 1, 1);
     138             :         }
     139           1 : }
     140             : 
     141          12 : static int parse_restore_str(const char *str, enum action *act,
     142             :         char **backupnostr, char **restoreregex)
     143             : {
     144          12 :         int ret=-1;
     145          12 :         char *cp=NULL;
     146          12 :         char *copy=NULL;
     147             : 
     148          12 :         if(!str)
     149             :         {
     150           1 :                 logp("NULL passed to %s\n", __func__);
     151           1 :                 goto end;
     152             :         }
     153             : 
     154          11 :         if(!(copy=strdup_w(str, __func__)))
     155             :                 goto end;
     156             : 
     157          11 :         if(!strncmp_w(copy, "restore "))
     158           4 :                 *act=ACTION_RESTORE;
     159           7 :         else if(!strncmp_w(copy, "verify "))
     160           4 :                 *act=ACTION_VERIFY;
     161             :         else
     162             :         {
     163           3 :                 logp("Could not parse %s in %s\n", copy, __func__);
     164           3 :                 goto end;
     165             :         }
     166             : 
     167           8 :         if(!(cp=strchr(copy, ' ')))
     168             :         {
     169           0 :                 logp("Could not parse %s in %s\n", copy, __func__);
     170           0 :                 goto end;
     171             :         }
     172           8 :         cp++;
     173           8 :         if(!(*backupnostr=strdup_w(cp, __func__)))
     174             :                 goto end;
     175           8 :         if((cp=strchr(*backupnostr, ':')))
     176             :         {
     177           4 :                 *cp='\0';
     178           4 :                 cp++;
     179           4 :                 if(!(*restoreregex=strdup_w(cp, __func__)))
     180             :                         goto end;
     181             :         }
     182             : 
     183             :         ret=0;
     184             : end:
     185          12 :         free_w(&copy);
     186          12 :         return ret;
     187             : }
     188             : 
     189             : #ifndef UTEST
     190             : static
     191             : #endif
     192          12 : int parse_restore_str_and_set_confs(const char *str, enum action *act,
     193             :         struct conf **cconfs)
     194             : {
     195          12 :         int ret=-1;
     196          12 :         char *backupnostr=NULL;
     197          12 :         char *restoreregex=NULL;
     198             : 
     199          12 :         if(parse_restore_str(str, act, &backupnostr, &restoreregex))
     200             :                 goto end;
     201             : 
     202           8 :         if(set_string(cconfs[OPT_BACKUP], backupnostr))
     203             :                 goto end;
     204           8 :         if(restoreregex && *restoreregex
     205           2 :           && set_string(cconfs[OPT_REGEX], restoreregex))
     206             :                 goto end;
     207             :         ret=0;
     208             : end:
     209          12 :         free_w(&backupnostr);
     210          12 :         free_w(&restoreregex);
     211          12 :         return ret;
     212             : }
     213             : 
     214           2 : static int run_restore(struct asfd *asfd,
     215             :         struct sdirs *sdirs, struct conf **cconfs, int srestore)
     216             : {
     217           2 :         int ret=-1;
     218           2 :         char *dir_for_notify=NULL;
     219           2 :         enum action act=ACTION_RESTORE;
     220           2 :         struct iobuf *rbuf=asfd->rbuf;
     221           2 :         const char *cname=get_string(cconfs[OPT_CNAME]);
     222             : 
     223           2 :         if(parse_restore_str_and_set_confs(rbuf->buf, &act, cconfs))
     224             :                 goto end;
     225             : 
     226           2 :         iobuf_free_content(rbuf);
     227             : 
     228           2 :         if(act==ACTION_RESTORE)
     229             :         {
     230             :                 int r;
     231           1 :                 if((r=client_can_restore(cconfs))<0)
     232             :                         goto end;
     233           1 :                 else if(!r)
     234             :                 {
     235           0 :                         logp("Not allowing restore of %s\n", cname);
     236           0 :                         if(!asfd->write_str(asfd, CMD_GEN,
     237           0 :                                 "Client restore is not allowed")) ret=0;
     238             :                         goto end;
     239             :                 }
     240             :         }
     241           2 :         if(act==ACTION_VERIFY
     242           1 :           && !(client_can_generic(cconfs, OPT_CLIENT_CAN_VERIFY)))
     243             :         {
     244           0 :                 logp("Not allowing verify of %s\n", cname);
     245           0 :                 if(!asfd->write_str(asfd, CMD_GEN,
     246           0 :                         "Client verify is not allowed")) ret=0;
     247             :                 goto end;
     248             :         }
     249             : 
     250           2 :         if(asfd->write_str(asfd, CMD_GEN, "ok"))
     251             :                 goto end;
     252           2 :         ret=do_restore_server(asfd, sdirs, act,
     253             :                 srestore, &dir_for_notify, cconfs);
     254           2 :         if(dir_for_notify)
     255           0 :                 maybe_do_notification(asfd, ret,
     256           0 :                         sdirs->client, dir_for_notify,
     257             :                         act==ACTION_RESTORE?"restorelog":"verifylog",
     258           0 :                         act==ACTION_RESTORE?"restore":"verify",
     259             :                         cconfs);
     260             : end:
     261           2 :         free_w(&dir_for_notify);
     262           2 :         return ret;
     263             : }
     264             : 
     265           1 : static int run_delete(struct asfd *asfd,
     266             :         struct sdirs *sdirs, struct conf **cconfs)
     267             : {
     268           1 :         char *backupno=NULL;
     269           1 :         struct iobuf *rbuf=asfd->rbuf;
     270           1 :         const char *cname=get_string(cconfs[OPT_CNAME]);
     271           1 :         if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DELETE))
     272             :         {
     273           0 :                 logp("Not allowing delete of %s\n", cname);
     274           0 :                 asfd->write_str(asfd, CMD_GEN, "Client delete is not allowed");
     275           0 :                 return -1;
     276             :         }
     277           1 :         backupno=rbuf->buf+strlen("delete ");
     278           1 :         return do_delete_server(asfd, sdirs,
     279             :                 get_cntr(cconfs), cname, backupno,
     280           1 :                 get_string(cconfs[OPT_MANUAL_DELETE]));
     281             : }
     282             : 
     283           1 : static int run_list(struct asfd *asfd,
     284             :         struct sdirs *sdirs, struct conf **cconfs)
     285             : {
     286           1 :         int ret=-1;
     287           1 :         char *cp=NULL;
     288           1 :         char *backupno=NULL;
     289           1 :         char *browsedir=NULL;
     290           1 :         char *listregex=NULL;
     291           1 :         struct iobuf *rbuf=asfd->rbuf;
     292             : 
     293           1 :         if(!client_can_generic(cconfs, OPT_CLIENT_CAN_LIST))
     294             :         {
     295           0 :                 logp("Not allowing list of %s\n",
     296             :                         get_string(cconfs[OPT_CNAME]));
     297           0 :                 asfd->write_str(asfd, CMD_GEN, "Client list is not allowed");
     298           0 :                 goto end;
     299             :         }
     300             : 
     301           1 :         if(!strncmp_w(rbuf->buf, "list "))
     302             :         {
     303           1 :                 if((cp=strchr(rbuf->buf, ':')))
     304             :                 {
     305           0 :                         *cp='\0';
     306           0 :                         if(!(listregex=strdup_w(cp+1, __func__)))
     307             :                                 goto end;
     308             :                 }
     309           1 :                 if(!(backupno=strdup_w(rbuf->buf+strlen("list "), __func__)))
     310             :                         goto end;
     311             :                 
     312             :         }
     313           0 :         else if(!strncmp_w(rbuf->buf, "listb "))
     314             :         {
     315           0 :                 if((cp=strchr(rbuf->buf, ':')))
     316             :                 {
     317           0 :                         *cp='\0';
     318           0 :                         if(!(browsedir=strdup_w(cp+1, __func__)))
     319             :                                 goto end;
     320             :                 }
     321           0 :                 strip_trailing_slashes(&browsedir);
     322           0 :                 if(!(backupno=strdup_w(rbuf->buf+strlen("listb "), __func__)))
     323             :                         goto end;
     324             :         }
     325           1 :         if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
     326             : 
     327           1 :         iobuf_free_content(asfd->rbuf);
     328             : 
     329           1 :         if(list_server_init(asfd, sdirs, get_cntr(cconfs),
     330             :                 get_protocol(cconfs), backupno, listregex, browsedir))
     331             :                         goto end;
     332           1 :         ret=do_list_server();
     333             : end:
     334           1 :         free_w(&backupno);
     335           1 :         free_w(&browsedir);
     336           1 :         free_w(&listregex);
     337           1 :         list_server_free();
     338           1 :         return ret;
     339             : }
     340             : 
     341           1 : static int run_diff(struct asfd *asfd,
     342             :         struct sdirs *sdirs, struct conf **cconfs)
     343             : {
     344           1 :         int ret=-1;
     345           1 :         char *backup1=NULL;
     346           1 :         char *backup2=NULL;
     347           1 :         struct iobuf *rbuf=asfd->rbuf;
     348             : 
     349           1 :         if(!client_can_generic(cconfs, OPT_CLIENT_CAN_DIFF))
     350             :         {
     351           0 :                 logp("Not allowing diff of %s\n",
     352             :                         get_string(cconfs[OPT_CNAME]));
     353           0 :                 asfd->write_str(asfd, CMD_GEN, "Client diff is not allowed");
     354           0 :                 goto end;
     355             :         }
     356             : 
     357           1 :         if(!strncmp_w(rbuf->buf, "diff "))
     358             :         {
     359             :                 char *cp;
     360           1 :                 if((cp=strchr(rbuf->buf, ':')))
     361             :                 {
     362           0 :                         *cp='\0';
     363           0 :                         if(!(backup2=strdup_w(cp+1, __func__)))
     364             :                                 goto end;
     365             :                 }
     366           1 :                 if(!(backup1=strdup_w(rbuf->buf+strlen("diff "), __func__)))
     367             :                         goto end;
     368             :         }
     369           1 :         if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end;
     370             : 
     371           1 :         iobuf_free_content(asfd->rbuf);
     372             : 
     373           1 :         ret=do_diff_server(asfd, sdirs,
     374             :                 get_cntr(cconfs), get_protocol(cconfs), backup1, backup2);
     375             : end:
     376           1 :         free_w(&backup1);
     377           1 :         free_w(&backup2);
     378           1 :         return ret;
     379             : }
     380             : 
     381           2 : static int unknown_command(struct asfd *asfd)
     382             : {
     383           2 :         iobuf_log_unexpected(asfd->rbuf, __func__);
     384           2 :         asfd->write_str(asfd, CMD_ERROR, "unknown command");
     385           2 :         return -1;
     386             : }
     387             : 
     388           0 : static const char *buf_to_notify_str(struct iobuf *rbuf)
     389             : {
     390           0 :         const char *buf=rbuf->buf;
     391           0 :         if(!strncmp_w(buf, "backup")) return "backup";
     392           0 :         else if(!strncmp_w(buf, "restore")) return "restore";
     393           0 :         else if(!strncmp_w(buf, "verify")) return "verify";
     394           0 :         else if(!strncmp_w(buf, "delete")) return "delete";
     395           0 :         else if(!strncmp_w(buf, "list")) return "list";
     396             :         else return "unknown";
     397             : }
     398             : 
     399          10 : static int run_action_server_do(struct async *as, struct sdirs *sdirs,
     400             :         const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
     401             : {
     402             :         int ret;
     403          10 :         int resume=0;
     404          10 :         char msg[256]="";
     405          10 :         struct iobuf *rbuf=as->asfd->rbuf;
     406             : 
     407             :         // Make sure some directories exist.
     408          10 :         if(mkpath(&sdirs->current, sdirs->dedup))
     409             :         {
     410           1 :                 snprintf(msg, sizeof(msg),
     411             :                         "could not mkpath %s", sdirs->current);
     412           1 :                 log_and_send(as->asfd, msg);
     413           1 :                 return -1;
     414             :         }
     415             : 
     416           9 :         if(rbuf->cmd!=CMD_GEN)
     417           1 :                 return unknown_command(as->asfd);
     418             : 
     419             :         // List and diff should work even while backups are running.
     420           8 :         if(!strncmp_w(rbuf->buf, "list ")
     421           7 :           || !strncmp_w(rbuf->buf, "listb "))
     422           1 :                 return run_list(as->asfd, sdirs, cconfs);
     423             : 
     424           7 :         if(!strncmp_w(rbuf->buf, "diff "))
     425           1 :                 return run_diff(as->asfd, sdirs, cconfs);
     426             : 
     427           6 :         switch((ret=get_lock_sdirs(as->asfd, sdirs)))
     428             :         {
     429             :                 case 0: break; // OK.
     430             :                 case 1: return 1; // Locked out.
     431             :                 default: // Error.
     432           0 :                         maybe_do_notification(as->asfd, ret,
     433             :                                 "", "error in get_lock_sdirs()",
     434             :                                 "", buf_to_notify_str(rbuf), cconfs);
     435           0 :                         return -1;
     436             :         }
     437             : 
     438           6 :         switch((ret=check_for_rubble(as, sdirs, incexc, &resume, cconfs)))
     439             :         {
     440             :                 case 0: break; // OK.
     441             :                 case 1: return 1; // Now finalising.
     442             :                 default: // Error.
     443           0 :                         maybe_do_notification(as->asfd, ret,
     444             :                                 "", "error in check_for_rubble()",
     445             :                                 "", buf_to_notify_str(rbuf), cconfs);
     446           0 :                         return -1;
     447             :         }
     448             : 
     449           6 :         if(!strncmp_w(rbuf->buf, "backup"))
     450             :         {
     451           1 :                 ret=run_backup(as, sdirs, cconfs, incexc, timer_ret, resume);
     452           1 :                 if(*timer_ret<0)
     453           0 :                         maybe_do_notification(as->asfd, ret, "",
     454             :                                 "error running timer script",
     455             :                                 "", "backup", cconfs);
     456           1 :                 else if(!*timer_ret)
     457           1 :                         maybe_do_notification(as->asfd, ret, sdirs->client,
     458           1 :                                 sdirs->current, "log", "backup", cconfs);
     459           1 :                 return ret;
     460             :         }
     461             : 
     462           5 :         if(!strncmp_w(rbuf->buf, "restore ")
     463           4 :           || !strncmp_w(rbuf->buf, "verify "))
     464           2 :                 return run_restore(as->asfd, sdirs, cconfs, srestore);
     465             : 
     466           3 :         if(!strncmp_w(rbuf->buf, "Delete "))
     467           1 :                 return run_delete(as->asfd, sdirs, cconfs);
     468             : 
     469             :         // Old clients will send 'delete', possibly accidentally due to the
     470             :         // user trying to use the new diff/long diff options.
     471             :         // Stop them from working, just to be safe.
     472           2 :         if(!strncmp_w(rbuf->buf, "delete "))
     473             :         {
     474           1 :                 logp("old style delete from %s denied\n",
     475             :                         get_string(cconfs[OPT_CNAME]));
     476           1 :                 as->asfd->write_str(as->asfd, CMD_ERROR,
     477             :                         "old style delete is not supported on this server");
     478           1 :                 return -1;
     479             :         }
     480             : 
     481           1 :         return unknown_command(as->asfd);
     482             : }
     483             : 
     484          10 : int run_action_server(struct async *as,
     485             :         const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
     486             : {
     487          10 :         int ret=-1;
     488          10 :         struct sdirs *sdirs=NULL;
     489          10 :         if((sdirs=sdirs_alloc())
     490          10 :           && !sdirs_init_from_confs(sdirs, cconfs))
     491          10 :                 ret=run_action_server_do(as,
     492             :                         sdirs, incexc, srestore, timer_ret, cconfs);
     493          10 :         if(sdirs) lock_release(sdirs->lock);
     494          10 :         sdirs_free(&sdirs);
     495          10 :         return ret;
     496             : }

Generated by: LCOV version 1.10