]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Add bconsole 'list files type=malware' command
authorEric Bollengier <eric@baculasystems.com>
Wed, 4 May 2022 17:27:44 +0000 (19:27 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 14 Sep 2023 11:56:59 +0000 (13:56 +0200)
bacula/src/cats/bdb.h
bacula/src/cats/protos.h
bacula/src/cats/sql_list.c
bacula/src/dird/malware.c
bacula/src/dird/ua_output.c

index 27589685ff6b02c3120486b30b95dfed684a631a..e640d60fb7efeec78e62c45f6f42a73388139420 100644 (file)
@@ -274,6 +274,7 @@ public:
    void bdb_list_jobs_for_file(JCR *jcr, const char *client, const char *fname, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx);
    void bdb_list_files_for_job(JCR *jcr, uint32_t jobid, int deleted, DB_LIST_HANDLER sendit, void *ctx);
+   void bdb_list_fileevents_for_job(JCR *jcr, uint32_t jobid, char etype, DB_LIST_HANDLER sendit, void *ctx, e_list_type type);
    void bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_jobmedia_records(JCR *jcr, JobId_t JobId, char *volume, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_filemedia_records(JCR *jcr, JobId_t JobId, uint32_t FileIndex, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
index f57c18bd5a9c7832fd7ee10062e083ca911c0647..2243eabfbd7425fa1b3f82e5763a0c9aad30bbbf 100644 (file)
@@ -288,6 +288,8 @@ void bdb_free_restoreobject_record(JCR *jcr, ROBJECT_DBR *rr);
            mdb->bdb_list_job_totals(jcr, jr, sendit, ctx)
 #define db_list_files_for_job(jcr, mdb, jobid, deleted, sendit, ctx)     \
            mdb->bdb_list_files_for_job(jcr, jobid, deleted, sendit, ctx)
+#define db_list_fileevents_for_job(jcr, mdb, jobid, etype, sendit, ctx, type) \
+           mdb->bdb_list_fileevents_for_job(jcr, jobid, etype, sendit, ctx, type)
 #define db_list_media_records(jcr, mdb, mdbr, sendit, ctx, type) \
            mdb->bdb_list_media_records(jcr, mdbr, sendit, ctx, type)
 #define db_list_jobmedia_records(jcr, mdb, JobId, volume, sendit, ctx, type) \
index e7d6bad70fc5af7360fc6204da18fdcce52eb984..e457c6431cfe6d00d1d7354ad0043fd1d3e3821b 100644 (file)
@@ -1115,6 +1115,77 @@ void BDB::bdb_list_files_for_job(JCR *jcr, JobId_t jobid, int deleted, DB_LIST_H
    bdb_unlock();
 }
 
+/* List all file records from a job
+ * "deleted" values are described just below
+ */
+void BDB::bdb_list_fileevents_for_job(JCR *jcr, JobId_t jobid, char etype, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
+{
+   char ed1[50];
+   POOL_MEM f, fields;
+   const char *concat="Path.Path||F.Filename";
+
+   bdb_lock();
+   /* Get optional filters for the SQL query */
+   const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                DB_ACL_BIT(DB_ACL_CLIENT) |
+                                DB_ACL_BIT(DB_ACL_FILESET), true);
+
+   const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) |
+                                                   DB_ACL_BIT(DB_ACL_CLIENT) |
+                                                   DB_ACL_BIT(DB_ACL_FILESET)) : "";
+
+   if (etype) {
+      Mmsg(f, " AND FileEvents.Type = '%c' ", etype);
+   }
+
+   /*
+    * MySQL is different with no || operator
+    */
+   if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
+      concat = " CONCAT(Path.Path,F.Filename) ";
+   }
+
+   switch (type) {
+   case JSON_LIST:
+      Mmsg(fields, "JobId, %s AS Filename, Type, Severity, Description, Source", concat);
+      break;
+   case VERT_LIST:
+      Mmsg(fields, "JobId, SourceJobId, %s AS Filename, Type, Severity, Description, Source", concat);
+      break;
+   case HORZ_LIST:
+      Mmsg(fields, "JobId, %s AS Filename, Description, Source", concat);
+      break;
+   default:
+      goto bail_out;
+   }
+
+   Mmsg(cmd, "SELECT DISTINCT %s  "
+           "FROM (SELECT PathId, Filename, File.JobId, FileEvents.SourceJobId, FileEvents.Type, FileEvents.Description, FileEvents.Source, FileEvents.Severity FROM File "
+                   "JOIN FileEvents ON (File.JobId = FileEvents.JobId AND File.FileIndex = FileEvents.FileIndex) "
+                   "WHERE File.JobId=%s %s "
+                  "UNION ALL "
+                 "SELECT PathId, Filename, BaseFiles.JobId, FileEvents.SourceJobId, FileEvents.Type, FileEvents.Description, FileEvents.Source, FileEvents.Severity "
+                   "FROM BaseFiles JOIN File  ON (BaseFiles.FileId = File.FileId) "
+                    "JOIN FileEvents ON (File.JobId = FileEvents.JobId AND File.FileIndex = FileEvents.FileIndex) "
+                  "WHERE BaseFiles.JobId = %s %s "
+           ") AS F JOIN Path ON (Path.PathId=F.PathId) %s %s",
+        fields.c_str(),
+        edit_int64(jobid, ed1), f.c_str(), ed1, f.c_str(), join, where);
+
+   Dmsg1(DT_SQL|50, "q=%s\n", cmd);
+
+   if (!QueryDB(jcr, cmd)) {
+      goto bail_out;
+   }
+
+   // TODO: Display
+   list_result(jcr, this, "fileevents", sendit, ctx, type);
+
+bail_out:
+   sql_free_result();
+   bdb_unlock();
+}
+
 void BDB::bdb_list_base_files_for_job(JCR *jcr, JobId_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
 {
    char ed1[50];
index 0a132bd825d64b11205f66f9b7d562255782792b..8e027c53989c285f60cc281ac0371bf7ea571db7 100644 (file)
@@ -263,7 +263,7 @@ int check_malware(JCR *jcr, const char *jobids, POOLMEM **errmsg)
 
    type = hash_get_type(strlen((char *)lst[0]));
    if (!type) {
-      Mmsg(errmsg, "[DE0006] Unable to detect the checksum type for JobIds %s\n", jobids);
+      Mmsg(errmsg, "[DE0006] Unable to find a valid checksum database for JobIds %s\n", jobids);
       return -1;
    }
 
@@ -348,8 +348,8 @@ int check_malware(JCR *jcr, const char *jobids, POOLMEM **errmsg)
    
    /* We keep track of the infected files in the FileEvents table */
    Mmsg(q, "INSERT INTO FileEvents (SourceJobId, JobId, FileId, Type, Description, Severity, Source) "
-        "SELECT JobId, JobId, FileId, 'M', 'Malware found', 100, '%s' FROM File JOIN Malware%s USING (MD5) "
-        "WHERE JobId IN (%s)", source_esc.c_str(), type, jobids);
+        "SELECT %ld, JobId, FileId, 'M', 'Malware found', 100, '%s' FROM File JOIN Malware%s USING (MD5) "
+        "WHERE JobId IN (%s)", jcr->JobId, source_esc.c_str(), type, jobids);
 
    if (!db_sql_query(jcr->db, q.c_str(), NULL, NULL)) {
       Mmsg(errmsg, "[DE0008] SQL Error %s\n", jcr->db->errmsg);
index 3a9bbc1d9db292f418424aa02a5bc7c627d430c3..10eff1f5ff54abbc62a42c944b7b2a68ad4c196c 100644 (file)
@@ -324,8 +324,8 @@ bail_out:
  *  list joblog pattern=xxx jobid=<nn> 
  *  list joblog pattern=xxx jobid=<nn> 
  *  list joblog job=name
- *  list files [type=<deleted|all>] jobid=<nn> - list files saved for job nn
- *  list files [type=<deleted|all>] job=name
+ *  list files [type=<deleted|all|malware>] jobid=<nn> - list files saved for job nn
+ *  list files [type=<deleted|all|malware>] job=name
  *  list pools          - list pool records
  *  list jobtotals      - list totals for all jobs
  *  list media          - list media for given pool (deprecated)
@@ -346,7 +346,6 @@ bail_out:
  *             starttime=<time> endtime=<time>
  *             limit=<int> offset=<int>  order=<Asc|desc> alljobs
  *             emailid=<str>
- *
  *  Note: keyword "long" is before the first command on the command 
  *    line results in doing a llist (long listing).
  */
@@ -546,6 +545,7 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
       /* List FILES */
       } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
          int deleted = 0;       /* see only backed up files */
+         char malware = 0;       /* List malware detected */
          for (j=i+1; j<ua->argc; j++) {
             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
@@ -561,13 +561,20 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
                   deleted = 1;
                } else if (strcasecmp(ua->argv[j], NT_("all")) == 0) {
                   deleted = -1;
+               } else if (strcasecmp(ua->argv[j], NT_("malware")) == 0) {
+                  malware = 'M';
                }
                continue;        /* Type should be before the jobid... */
             } else {
                continue;
             }
             if (jobid > 0) {
-               db_list_files_for_job(ua->jcr, ua->db, jobid, deleted, prtit, ua);
+               if (malware) {
+                  db_list_fileevents_for_job(ua->jcr, ua->db, jobid, malware, prtit, ua, llist);
+
+               } else {
+                  db_list_files_for_job(ua->jcr, ua->db, jobid, deleted, prtit, ua);
+               }
             }
          }