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

Generated by: LCOV version 1.13