LCOV - code coverage report
Current view: top level - source3/modules - vfs_virusfilter.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 325 838 38.8 %
Date: 2024-02-28 12:06:22 Functions: 11 20 55.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
       3             :  * Copyright (C) 2016-2017 Trever L. Adams
       4             :  * Copyright (C) 2017 Ralph Boehme <slow@samba.org>
       5             :  * Copyright (C) 2017 Jeremy Allison <jra@samba.org>
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include "vfs_virusfilter_common.h"
      22             : #include "vfs_virusfilter_utils.h"
      23             : 
      24             : /*
      25             :  * Default configuration values
      26             :  * ======================================================================
      27             :  */
      28             : 
      29             : #define VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX           "virusfilter."
      30             : #define VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX           ".infected"
      31             : #define VIRUSFILTER_DEFAULT_RENAME_PREFIX               "virusfilter."
      32             : #define VIRUSFILTER_DEFAULT_RENAME_SUFFIX               ".infected"
      33             : 
      34             : /* ====================================================================== */
      35             : 
      36             : enum virusfilter_scanner_enum {
      37             :         VIRUSFILTER_SCANNER_CLAMAV,
      38             :         VIRUSFILTER_SCANNER_DUMMY,
      39             :         VIRUSFILTER_SCANNER_FSAV,
      40             :         VIRUSFILTER_SCANNER_SOPHOS
      41             : };
      42             : 
      43             : static const struct enum_list scanner_list[] = {
      44             :         { VIRUSFILTER_SCANNER_CLAMAV,   "clamav" },
      45             :         { VIRUSFILTER_SCANNER_DUMMY,    "dummy" },
      46             :         { VIRUSFILTER_SCANNER_FSAV,     "fsav" },
      47             :         { VIRUSFILTER_SCANNER_SOPHOS,   "sophos" },
      48             :         { -1,                           NULL }
      49             : };
      50             : 
      51             : static const struct enum_list virusfilter_actions[] = {
      52             :         { VIRUSFILTER_ACTION_QUARANTINE,        "quarantine" },
      53             :         { VIRUSFILTER_ACTION_RENAME,            "rename" },
      54             :         { VIRUSFILTER_ACTION_DELETE,            "delete" },
      55             : 
      56             :         /* alias for "delete" */
      57             :         { VIRUSFILTER_ACTION_DELETE,            "remove" },
      58             : 
      59             :         /* alias for "delete" */
      60             :         { VIRUSFILTER_ACTION_DELETE,            "unlink" },
      61             :         { VIRUSFILTER_ACTION_DO_NOTHING,        "nothing" },
      62             :         { -1,                                   NULL}
      63             : };
      64             : 
      65           8 : static int virusfilter_config_destructor(struct virusfilter_config *config)
      66             : {
      67           8 :         TALLOC_FREE(config->backend);
      68           8 :         return 0;
      69             : }
      70             : 
      71             : /*
      72             :  * This is adapted from vfs_recycle module.
      73             :  * Caller must have become_root();
      74             :  */
      75           0 : static bool quarantine_directory_exist(
      76             :         struct vfs_handle_struct *handle,
      77             :         const char *dname)
      78             : {
      79           0 :         int ret = -1;
      80           0 :         struct smb_filename smb_fname = {
      81             :                 .base_name = discard_const_p(char, dname)
      82             :         };
      83             : 
      84           0 :         ret = SMB_VFS_STAT(handle->conn, &smb_fname);
      85           0 :         if (ret == 0) {
      86           0 :                 return S_ISDIR(smb_fname.st.st_ex_mode);
      87             :         }
      88             : 
      89           0 :         return false;
      90             : }
      91             : 
      92             : /**
      93             :  * Create directory tree
      94             :  * @param conn connection
      95             :  * @param dname Directory tree to be created
      96             :  * @return Returns true for success
      97             :  * This is adapted from vfs_recycle module.
      98             :  * Caller must have become_root();
      99             :  */
     100           0 : static bool quarantine_create_dir(
     101             :         struct vfs_handle_struct *handle,
     102             :         struct virusfilter_config *config,
     103             :         const char *dname)
     104             : {
     105           0 :         size_t len = 0;
     106           0 :         size_t cat_len = 0;
     107           0 :         char *new_dir = NULL;
     108           0 :         char *tmp_str = NULL;
     109           0 :         char *token = NULL;
     110           0 :         char *tok_str = NULL;
     111           0 :         bool status = false;
     112           0 :         bool ok = false;
     113           0 :         int ret = -1;
     114           0 :         char *saveptr = NULL;
     115             : 
     116           0 :         tmp_str = talloc_strdup(talloc_tos(), dname);
     117           0 :         if (tmp_str == NULL) {
     118           0 :                 DBG_ERR("virusfilter-vfs: out of memory!\n");
     119           0 :                 errno = ENOMEM;
     120           0 :                 goto done;
     121             :         }
     122           0 :         tok_str = tmp_str;
     123             : 
     124           0 :         len = strlen(dname)+1;
     125           0 :         new_dir = (char *)talloc_size(talloc_tos(), len + 1);
     126           0 :         if (new_dir == NULL) {
     127           0 :                 DBG_ERR("virusfilter-vfs: out of memory!\n");
     128           0 :                 errno = ENOMEM;
     129           0 :                 goto done;
     130             :         }
     131           0 :         *new_dir = '\0';
     132           0 :         if (dname[0] == '/') {
     133             :                 /* Absolute path. */
     134           0 :                 cat_len = strlcat(new_dir, "/", len + 1);
     135           0 :                 if (cat_len >= len+1) {
     136           0 :                         goto done;
     137             :                 }
     138             :         }
     139             : 
     140             :         /* Create directory tree if necessary */
     141           0 :         for (token = strtok_r(tok_str, "/", &saveptr);
     142           0 :              token != NULL;
     143           0 :              token = strtok_r(NULL, "/", &saveptr))
     144             :         {
     145           0 :                 cat_len = strlcat(new_dir, token, len + 1);
     146           0 :                 if (cat_len >= len+1) {
     147           0 :                         goto done;
     148             :                 }
     149           0 :                 ok = quarantine_directory_exist(handle, new_dir);
     150           0 :                 if (ok == true) {
     151           0 :                         DBG_DEBUG("quarantine: dir %s already exists\n",
     152             :                                   new_dir);
     153             :                 } else {
     154           0 :                         struct smb_filename *smb_fname = NULL;
     155             : 
     156           0 :                         DBG_INFO("quarantine: creating new dir %s\n", new_dir);
     157             : 
     158           0 :                         smb_fname = synthetic_smb_fname(talloc_tos(),
     159             :                                                         new_dir,
     160             :                                                         NULL,
     161             :                                                         NULL,
     162             :                                                         0,
     163             :                                                         0);
     164           0 :                         if (smb_fname == NULL) {
     165           0 :                                 goto done;
     166             :                         }
     167             : 
     168           0 :                         ret = SMB_VFS_NEXT_MKDIRAT(handle,
     169             :                                         handle->conn->cwd_fsp,
     170             :                                         smb_fname,
     171             :                                         config->quarantine_dir_mode);
     172           0 :                         if (ret != 0) {
     173           0 :                                 TALLOC_FREE(smb_fname);
     174             : 
     175           0 :                                 DBG_WARNING("quarantine: mkdirat failed for %s "
     176             :                                             "with error: %s\n", new_dir,
     177             :                                             strerror(errno));
     178           0 :                                 status = false;
     179           0 :                                 goto done;
     180             :                         }
     181           0 :                         TALLOC_FREE(smb_fname);
     182             :                 }
     183           0 :                 cat_len = strlcat(new_dir, "/", len + 1);
     184           0 :                 if (cat_len >= len + 1) {
     185           0 :                         goto done;
     186             :                 }
     187             :         }
     188             : 
     189           0 :         status = true;
     190           0 : done:
     191           0 :         TALLOC_FREE(tmp_str);
     192           0 :         TALLOC_FREE(new_dir);
     193           0 :         return status;
     194             : }
     195             : 
     196           8 : static int virusfilter_vfs_connect(
     197             :         struct vfs_handle_struct *handle,
     198             :         const char *svc,
     199             :         const char *user)
     200             : {
     201           8 :         int snum = SNUM(handle->conn);
     202           8 :         struct virusfilter_config *config = NULL;
     203           8 :         const char *exclude_files = NULL;
     204           8 :         const char *infected_files = NULL;
     205           8 :         const char *temp_quarantine_dir_mode = NULL;
     206           8 :         const char *infected_file_command = NULL;
     207           8 :         const char *scan_error_command = NULL;
     208           8 :         const char *quarantine_dir = NULL;
     209           8 :         const char *quarantine_prefix = NULL;
     210           8 :         const char *quarantine_suffix = NULL;
     211           8 :         const char *rename_prefix = NULL;
     212           8 :         const char *rename_suffix = NULL;
     213           8 :         const char *socket_path = NULL;
     214           8 :         char *sret = NULL;
     215           8 :         char *tmp = NULL;
     216             :         enum virusfilter_scanner_enum backend;
     217           8 :         int connect_timeout = 0;
     218           8 :         int io_timeout = 0;
     219           8 :         int ret = -1;
     220             : 
     221           8 :         config = talloc_zero(handle, struct virusfilter_config);
     222           8 :         if (config == NULL) {
     223           0 :                 DBG_ERR("talloc_zero failed\n");
     224           0 :                 return -1;
     225             :         }
     226           8 :         talloc_set_destructor(config, virusfilter_config_destructor);
     227             : 
     228           8 :         SMB_VFS_HANDLE_SET_DATA(handle, config, NULL,
     229             :                                 struct virusfilter_config, return -1);
     230             : 
     231           8 :         config->scan_request_limit = lp_parm_int(
     232             :                 snum, "virusfilter", "scan request limit", 0);
     233             : 
     234           8 :         config->scan_on_open = lp_parm_bool(
     235             :                 snum, "virusfilter", "scan on open", true);
     236             : 
     237           8 :         config->scan_on_close = lp_parm_bool(
     238             :                 snum, "virusfilter", "scan on close", false);
     239             : 
     240           8 :         config->max_nested_scan_archive = lp_parm_int(
     241             :                 snum, "virusfilter", "max nested scan archive", 1);
     242             : 
     243           8 :         config->scan_archive = lp_parm_bool(
     244             :                 snum, "virusfilter", "scan archive", false);
     245             : 
     246           8 :         config->scan_mime = lp_parm_bool(
     247             :                 snum, "virusfilter", "scan mime", false);
     248             : 
     249           8 :         config->max_file_size = (ssize_t)lp_parm_ulong(
     250             :                 snum, "virusfilter", "max file size", 100000000L);
     251             : 
     252           8 :         config->min_file_size = (ssize_t)lp_parm_ulong(
     253             :                 snum, "virusfilter", "min file size", 10);
     254             : 
     255           8 :         exclude_files = lp_parm_const_string(
     256             :                 snum, "virusfilter", "exclude files", NULL);
     257           8 :         if (exclude_files != NULL) {
     258           0 :                 set_namearray(&config->exclude_files, exclude_files);
     259             :         }
     260             : 
     261           8 :         infected_files = lp_parm_const_string(
     262             :                 snum, "virusfilter", "infected files", NULL);
     263           8 :         if (infected_files != NULL) {
     264           8 :                 set_namearray(&config->infected_files, infected_files);
     265             :         }
     266             : 
     267           8 :         config->cache_entry_limit = lp_parm_int(
     268             :                 snum, "virusfilter", "cache entry limit", 100);
     269             : 
     270           8 :         config->cache_time_limit = lp_parm_int(
     271             :                 snum, "virusfilter", "cache time limit", 10);
     272             : 
     273           8 :         config->infected_file_action = lp_parm_enum(
     274             :                 snum, "virusfilter", "infected file action",
     275             :                 virusfilter_actions, VIRUSFILTER_ACTION_DO_NOTHING);
     276             : 
     277           8 :         infected_file_command = lp_parm_const_string(
     278             :                 snum, "virusfilter", "infected file command", NULL);
     279           8 :         if (infected_file_command != NULL) {
     280           0 :                 config->infected_file_command = talloc_strdup(
     281             :                                                         config,
     282             :                                                         infected_file_command);
     283           0 :                 if (config->infected_file_command == NULL) {
     284           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     285           0 :                         return -1;
     286             :                 }
     287             :         }
     288           8 :         scan_error_command = lp_parm_const_string(
     289             :                 snum, "virusfilter", "scan error command", NULL);
     290           8 :         if (scan_error_command != NULL) {
     291           0 :                 config->scan_error_command = talloc_strdup(config,
     292             :                                                            scan_error_command);
     293           0 :                 if (config->scan_error_command == NULL) {
     294           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     295           0 :                         return -1;
     296             :                 }
     297             :         }
     298             : 
     299           8 :         config->block_access_on_error = lp_parm_bool(
     300             :                 snum, "virusfilter", "block access on error", false);
     301             : 
     302           8 :         tmp = talloc_asprintf(config, "%s/.quarantine",
     303           8 :                 handle->conn->connectpath);
     304             : 
     305           8 :         quarantine_dir = lp_parm_const_string(
     306             :                 snum, "virusfilter", "quarantine directory",
     307             :                 tmp ? tmp : "/tmp/.quarantine");
     308           8 :         if (quarantine_dir != NULL) {
     309           8 :                 config->quarantine_dir = talloc_strdup(config, quarantine_dir);
     310           8 :                 if (config->quarantine_dir == NULL) {
     311           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     312           0 :                         return -1;
     313             :                 }
     314             :         }
     315             : 
     316           8 :         if (tmp != config->quarantine_dir) {
     317           8 :                 TALLOC_FREE(tmp);
     318             :         }
     319             : 
     320           8 :         temp_quarantine_dir_mode = lp_parm_const_string(
     321             :                 snum, "virusfilter", "quarantine directory mode", "0755");
     322           8 :         if (temp_quarantine_dir_mode != NULL) {
     323           8 :                 unsigned int mode = 0;
     324           8 :                 sscanf(temp_quarantine_dir_mode, "%o", &mode);
     325           8 :                 config->quarantine_dir_mode = mode;
     326             :         }
     327             : 
     328           8 :         quarantine_prefix = lp_parm_const_string(
     329             :                 snum, "virusfilter", "quarantine prefix",
     330             :                 VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX);
     331           8 :         if (quarantine_prefix != NULL) {
     332           8 :                 config->quarantine_prefix = talloc_strdup(config,
     333             :                                                           quarantine_prefix);
     334           8 :                 if (config->quarantine_prefix == NULL) {
     335           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     336           0 :                         return -1;
     337             :                 }
     338             :         }
     339             : 
     340           8 :         quarantine_suffix = lp_parm_const_string(
     341             :                 snum, "virusfilter", "quarantine suffix",
     342             :                 VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX);
     343           8 :         if (quarantine_suffix != NULL) {
     344           8 :                 config->quarantine_suffix = talloc_strdup(config,
     345             :                                                           quarantine_suffix);
     346           8 :                 if (config->quarantine_suffix == NULL) {
     347           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     348           0 :                         return -1;
     349             :                 }
     350             :         }
     351             : 
     352             :         /*
     353             :          * Make sure prefixes and suffixes do not contain directory
     354             :          * delimiters
     355             :          */
     356           8 :         if (config->quarantine_prefix != NULL) {
     357           8 :                 sret = strstr(config->quarantine_prefix, "/");
     358           8 :                 if (sret != NULL) {
     359           0 :                         DBG_ERR("quarantine prefix must not contain directory "
     360             :                                 "delimiter(s) such as '/' (%s replaced with %s)\n",
     361             :                                 config->quarantine_prefix,
     362             :                                 VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX);
     363           0 :                         config->quarantine_prefix =
     364             :                                 VIRUSFILTER_DEFAULT_QUARANTINE_PREFIX;
     365             :                 }
     366             :         }
     367           8 :         if (config->quarantine_suffix != NULL) {
     368           8 :                 sret = strstr(config->quarantine_suffix, "/");
     369           8 :                 if (sret != NULL) {
     370           0 :                         DBG_ERR("quarantine suffix must not contain directory "
     371             :                                 "delimiter(s) such as '/' (%s replaced with %s)\n",
     372             :                                 config->quarantine_suffix,
     373             :                                 VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX);
     374           0 :                         config->quarantine_suffix =
     375             :                                 VIRUSFILTER_DEFAULT_QUARANTINE_SUFFIX;
     376             :                 }
     377             :         }
     378             : 
     379           8 :         config->quarantine_keep_tree = lp_parm_bool(
     380             :                 snum, "virusfilter", "quarantine keep tree", true);
     381             : 
     382           8 :         config->quarantine_keep_name = lp_parm_bool(
     383             :                 snum, "virusfilter", "quarantine keep name", true);
     384             : 
     385           8 :         rename_prefix = lp_parm_const_string(
     386             :                 snum, "virusfilter", "rename prefix",
     387             :                 VIRUSFILTER_DEFAULT_RENAME_PREFIX);
     388           8 :         if (rename_prefix != NULL) {
     389           8 :                 config->rename_prefix = talloc_strdup(config, rename_prefix);
     390           8 :                 if (config->rename_prefix == NULL) {
     391           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     392           0 :                         return -1;
     393             :                 }
     394             :         }
     395             : 
     396           8 :         rename_suffix = lp_parm_const_string(
     397             :                 snum, "virusfilter", "rename suffix",
     398             :                 VIRUSFILTER_DEFAULT_RENAME_SUFFIX);
     399           8 :         if (rename_suffix != NULL) {
     400           8 :                 config->rename_suffix = talloc_strdup(config, rename_suffix);
     401           8 :                 if (config->rename_suffix == NULL) {
     402           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     403           0 :                         return -1;
     404             :                 }
     405             :         }
     406             : 
     407             :         /*
     408             :          * Make sure prefixes and suffixes do not contain directory
     409             :          * delimiters
     410             :          */
     411           8 :         if (config->rename_prefix != NULL) {
     412           8 :                 sret = strstr(config->rename_prefix, "/");
     413           8 :                 if (sret != NULL) {
     414           0 :                         DBG_ERR("rename prefix must not contain directory "
     415             :                                 "delimiter(s) such as '/' (%s replaced with %s)\n",
     416             :                                 config->rename_prefix,
     417             :                                 VIRUSFILTER_DEFAULT_RENAME_PREFIX);
     418           0 :                         config->rename_prefix =
     419             :                                 VIRUSFILTER_DEFAULT_RENAME_PREFIX;
     420             :                 }
     421             :         }
     422           8 :         if (config->rename_suffix != NULL) {
     423           8 :                 sret = strstr(config->rename_suffix, "/");
     424           8 :                 if (sret != NULL) {
     425           0 :                         DBG_ERR("rename suffix must not contain directory "
     426             :                                 "delimiter(s) such as '/' (%s replaced with %s)\n",
     427             :                                 config->rename_suffix,
     428             :                                 VIRUSFILTER_DEFAULT_RENAME_SUFFIX);
     429           0 :                         config->rename_suffix =
     430             :                                 VIRUSFILTER_DEFAULT_RENAME_SUFFIX;
     431             :                 }
     432             :         }
     433             : 
     434           8 :         config->infected_open_errno = lp_parm_int(
     435             :                 snum, "virusfilter", "infected file errno on open", EACCES);
     436             : 
     437           8 :         config->infected_close_errno = lp_parm_int(
     438             :                 snum, "virusfilter", "infected file errno on close", 0);
     439             : 
     440           8 :         config->scan_error_open_errno = lp_parm_int(
     441             :                 snum, "virusfilter", "scan error errno on open", EACCES);
     442             : 
     443           8 :         config->scan_error_close_errno = lp_parm_int(
     444             :                 snum, "virusfilter", "scan error errno on close", 0);
     445             : 
     446           8 :         socket_path = lp_parm_const_string(
     447             :                 snum, "virusfilter", "socket path", NULL);
     448           8 :         if (socket_path != NULL) {
     449           0 :                 config->socket_path = talloc_strdup(config, socket_path);
     450           0 :                 if (config->socket_path == NULL) {
     451           0 :                         DBG_ERR("virusfilter-vfs: out of memory!\n");
     452           0 :                         return -1;
     453             :                 }
     454             :         }
     455             : 
     456             :         /* canonicalize socket_path */
     457           8 :         if (config->socket_path != NULL && config->socket_path[0] != '/') {
     458           0 :                 DBG_ERR("socket path must be an absolute path. "
     459             :                         "Using backend default\n");
     460           0 :                 config->socket_path = NULL;
     461             :         }
     462           8 :         if (config->socket_path != NULL) {
     463           0 :                 config->socket_path = canonicalize_absolute_path(
     464             :                         handle, config->socket_path);
     465           0 :                 if (config->socket_path == NULL) {
     466           0 :                         errno = ENOMEM;
     467           0 :                         return -1;
     468             :                 }
     469             :         }
     470             : 
     471           8 :         connect_timeout = lp_parm_int(snum, "virusfilter",
     472             :                                       "connect timeout", 30000);
     473             : 
     474           8 :         io_timeout = lp_parm_int(snum, "virusfilter", "io timeout", 60000);
     475             : 
     476           8 :         config->io_h = virusfilter_io_new(config, connect_timeout, io_timeout);
     477           8 :         if (config->io_h == NULL) {
     478           0 :                 DBG_ERR("virusfilter_io_new failed\n");
     479           0 :                 return -1;
     480             :         }
     481             : 
     482           8 :         if (config->cache_entry_limit > 0) {
     483          16 :                 config->cache = virusfilter_cache_new(handle,
     484             :                                         config->cache_entry_limit,
     485           8 :                                         config->cache_time_limit);
     486           8 :                 if (config->cache == NULL) {
     487           0 :                         DBG_ERR("Initializing cache failed: Cache disabled\n");
     488           0 :                         return -1;
     489             :                 }
     490             :         }
     491             : 
     492             :         /*
     493             :          * Check quarantine directory now to save processing
     494             :          * and becoming root over and over.
     495             :          */
     496           8 :         if (config->infected_file_action == VIRUSFILTER_ACTION_QUARANTINE) {
     497           0 :                 bool ok = true;
     498             :                 bool dir_exists;
     499             : 
     500             :                 /*
     501             :                  * Do SMB_VFS_NEXT_MKDIR(config->quarantine_dir)
     502             :                  * hierarchy
     503             :                  */
     504           0 :                 become_root();
     505           0 :                 dir_exists = quarantine_directory_exist(handle,
     506             :                                                 config->quarantine_dir);
     507           0 :                 if (!dir_exists) {
     508           0 :                         DBG_DEBUG("Creating quarantine directory: %s\n",
     509             :                                   config->quarantine_dir);
     510           0 :                         ok = quarantine_create_dir(handle, config,
     511             :                                               config->quarantine_dir);
     512             :                 }
     513           0 :                 unbecome_root();
     514           0 :                 if (!ok) {
     515           0 :                         DBG_ERR("Creating quarantine directory %s "
     516             :                                 "failed with %s\n",
     517             :                                 config->quarantine_dir,
     518             :                                 strerror(errno));
     519           0 :                         return -1;
     520             :                 }
     521             :         }
     522             : 
     523             :         /*
     524             :          * Now that the frontend options are initialized, load the configured
     525             :          * backend.
     526             :          */
     527             : 
     528           8 :         backend = (enum virusfilter_scanner_enum)lp_parm_enum(snum,
     529             :                                 "virusfilter",
     530             :                                 "scanner",
     531             :                                 scanner_list,
     532             :                                -1);
     533           8 :         if (backend == (enum virusfilter_scanner_enum)-1) {
     534           0 :                 DBG_ERR("No AV-Scanner configured, "
     535             :                         "please set \"virusfilter:scanner\"\n");
     536           0 :                 return -1;
     537             :         }
     538             : 
     539           8 :         switch (backend) {
     540           0 :         case VIRUSFILTER_SCANNER_SOPHOS:
     541           0 :                 ret = virusfilter_sophos_init(config);
     542           0 :                 break;
     543           0 :         case VIRUSFILTER_SCANNER_FSAV:
     544           0 :                 ret = virusfilter_fsav_init(config);
     545           0 :                 break;
     546           0 :         case VIRUSFILTER_SCANNER_CLAMAV:
     547           0 :                 ret = virusfilter_clamav_init(config);
     548           0 :                 break;
     549           8 :         case VIRUSFILTER_SCANNER_DUMMY:
     550           8 :                 ret = virusfilter_dummy_init(config);
     551           8 :                 break;
     552           0 :         default:
     553           0 :                 DBG_ERR("Unhandled scanner %d\n", backend);
     554           0 :                 return -1;
     555             :         }
     556           8 :         if (ret != 0) {
     557           0 :                 DBG_ERR("Scanner backend init failed\n");
     558           0 :                 return -1;
     559             :         }
     560             : 
     561           8 :         if (config->backend->fns->connect != NULL) {
     562           0 :                 ret = config->backend->fns->connect(handle, config, svc, user);
     563           0 :                 if (ret == -1) {
     564           0 :                         return -1;
     565             :                 }
     566             :         }
     567             : 
     568           8 :         return SMB_VFS_NEXT_CONNECT(handle, svc, user);
     569             : }
     570             : 
     571           8 : static void virusfilter_vfs_disconnect(struct vfs_handle_struct *handle)
     572             : {
     573           8 :         struct virusfilter_config *config = NULL;
     574             : 
     575           8 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
     576             :                                 struct virusfilter_config, return);
     577             : 
     578           8 :         if (config->backend->fns->disconnect != NULL) {
     579           0 :                 config->backend->fns->disconnect(handle);
     580             :         }
     581             : 
     582           8 :         free_namearray(config->exclude_files);
     583           8 :         virusfilter_io_disconnect(config->io_h);
     584             : 
     585           8 :         SMB_VFS_NEXT_DISCONNECT(handle);
     586             : }
     587             : 
     588           0 : static int virusfilter_set_module_env(TALLOC_CTX *mem_ctx,
     589             :                                       struct virusfilter_config *config,
     590             :                                       char **env_list)
     591             : {
     592             :         int ret;
     593             : 
     594           0 :         ret = virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_VERSION",
     595             :                                   VIRUSFILTER_VERSION);
     596           0 :         if (ret == -1) {
     597           0 :                 return -1;
     598             :         }
     599           0 :         ret = virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_MODULE_NAME",
     600           0 :                                   config->backend->name);
     601           0 :         if (ret == -1) {
     602           0 :                 return -1;
     603             :         }
     604             : 
     605           0 :         if (config->backend->version != 0) {
     606           0 :                 char *version = NULL;
     607             : 
     608           0 :                 version = talloc_asprintf(talloc_tos(), "%u",
     609           0 :                                           config->backend->version);
     610           0 :                 if (version == NULL) {
     611           0 :                         return -1;
     612             :                 }
     613           0 :                 ret = virusfilter_env_set(mem_ctx, env_list,
     614             :                                           "VIRUSFILTER_MODULE_VERSION",
     615             :                                           version);
     616           0 :                 TALLOC_FREE(version);
     617           0 :                 if (ret == -1) {
     618           0 :                         return -1;
     619             :                 }
     620             :         }
     621             : 
     622           0 :         return 0;
     623             : }
     624             : 
     625           0 : static char *quarantine_check_tree(TALLOC_CTX *mem_ctx,
     626             :                                    struct vfs_handle_struct *handle,
     627             :                                    struct virusfilter_config *config,
     628             :                                    const struct smb_filename *smb_fname,
     629             :                                    char *q_dir_in,
     630             :                                    char *cwd_fname)
     631             : {
     632           0 :         char *temp_path = NULL;
     633           0 :         char *q_dir_out = NULL;
     634             :         bool ok;
     635             : 
     636           0 :         temp_path = talloc_asprintf(talloc_tos(), "%s/%s", q_dir_in, cwd_fname);
     637           0 :         if (temp_path == NULL) {
     638           0 :                 DBG_ERR("talloc_asprintf failed\n");
     639           0 :                 goto out;
     640             :         }
     641             : 
     642           0 :         become_root();
     643           0 :         ok = quarantine_directory_exist(handle, temp_path);
     644           0 :         unbecome_root();
     645           0 :         if (ok) {
     646           0 :                 DBG_DEBUG("quarantine: directory [%s] exists\n", temp_path);
     647           0 :                 q_dir_out = talloc_move(mem_ctx, &temp_path);
     648           0 :                 goto out;
     649             :         }
     650             : 
     651           0 :         DBG_DEBUG("quarantine: Creating directory %s\n", temp_path);
     652             : 
     653           0 :         become_root();
     654           0 :         ok = quarantine_create_dir(handle, config, temp_path);
     655           0 :         unbecome_root();
     656           0 :         if (!ok) {
     657           0 :                 DBG_NOTICE("Could not create quarantine directory [%s], "
     658             :                            "ignoring for [%s]\n",
     659             :                            temp_path, smb_fname_str_dbg(smb_fname));
     660           0 :                 goto out;
     661             :         }
     662             : 
     663           0 :         q_dir_out = talloc_move(mem_ctx, &temp_path);
     664             : 
     665           0 : out:
     666           0 :         TALLOC_FREE(temp_path);
     667           0 :         return q_dir_out;
     668             : }
     669             : 
     670           0 : static virusfilter_action infected_file_action_quarantine(
     671             :         struct vfs_handle_struct *handle,
     672             :         struct virusfilter_config *config,
     673             :         TALLOC_CTX *mem_ctx,
     674             :         const struct files_struct *fsp,
     675             :         const char **filepath_newp)
     676             : {
     677           0 :         TALLOC_CTX *frame = talloc_stackframe();
     678           0 :         connection_struct *conn = handle->conn;
     679           0 :         char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
     680           0 :         char *fname = fsp->fsp_name->base_name;
     681           0 :         const struct smb_filename *smb_fname = fsp->fsp_name;
     682           0 :         struct smb_filename *q_smb_fname = NULL;
     683           0 :         char *q_dir = NULL;
     684           0 :         char *q_prefix = NULL;
     685           0 :         char *q_suffix = NULL;
     686           0 :         char *q_filepath = NULL;
     687           0 :         char *dir_name = NULL;
     688           0 :         const char *base_name = NULL;
     689           0 :         char *rand_filename_component = NULL;
     690           0 :         virusfilter_action action = VIRUSFILTER_ACTION_QUARANTINE;
     691           0 :         bool ok = false;
     692           0 :         int ret = -1;
     693           0 :         int saved_errno = 0;
     694             : 
     695           0 :         q_dir = virusfilter_string_sub(frame, conn,
     696             :                                        config->quarantine_dir);
     697           0 :         q_prefix = virusfilter_string_sub(frame, conn,
     698             :                                           config->quarantine_prefix);
     699           0 :         q_suffix = virusfilter_string_sub(frame, conn,
     700             :                                           config->quarantine_suffix);
     701           0 :         if (q_dir == NULL || q_prefix == NULL || q_suffix == NULL) {
     702           0 :                 DBG_ERR("Quarantine failed: %s/%s: Cannot allocate "
     703             :                         "memory\n", cwd_fname, fname);
     704           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     705           0 :                 goto out;
     706             :         }
     707             : 
     708           0 :         if (config->quarantine_keep_name || config->quarantine_keep_tree) {
     709           0 :                 ok = parent_dirname(frame, smb_fname->base_name,
     710             :                                     &dir_name, &base_name);
     711           0 :                 if (!ok) {
     712           0 :                         DBG_ERR("parent_dirname failed\n");
     713           0 :                         action = VIRUSFILTER_ACTION_DO_NOTHING;
     714           0 :                         goto out;
     715             :                 }
     716             : 
     717           0 :                 if (config->quarantine_keep_tree) {
     718           0 :                         char *tree = NULL;
     719             : 
     720           0 :                         tree = quarantine_check_tree(frame, handle, config,
     721             :                                                      smb_fname, q_dir,
     722             :                                                      cwd_fname);
     723           0 :                         if (tree == NULL) {
     724             :                                 /*
     725             :                                  * If we can't create the tree, just move it
     726             :                                  * into the toplevel quarantine dir.
     727             :                                  */
     728           0 :                                 tree = q_dir;
     729             :                         }
     730           0 :                         q_dir = tree;
     731             :                 }
     732             :         }
     733             : 
     734             :         /* Get a 16 byte + \0 random filename component. */
     735           0 :         rand_filename_component = generate_random_str(frame, 16);
     736           0 :         if (rand_filename_component == NULL) {
     737           0 :                 DBG_ERR("generate_random_str failed\n");
     738           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     739           0 :                 goto out;
     740             :         }
     741             : 
     742           0 :         if (config->quarantine_keep_name) {
     743           0 :                 q_filepath = talloc_asprintf(frame, "%s/%s%s%s-%s",
     744             :                                              q_dir, q_prefix,
     745             :                                              base_name, q_suffix,
     746             :                                              rand_filename_component);
     747             :         } else {
     748           0 :                 q_filepath = talloc_asprintf(frame, "%s/%s%s",
     749             :                                              q_dir, q_prefix,
     750             :                                              rand_filename_component);
     751             :         }
     752           0 :         if (q_filepath == NULL) {
     753           0 :                 DBG_ERR("talloc_asprintf failed\n");
     754           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     755           0 :                 goto out;
     756             :         }
     757             : 
     758           0 :         q_smb_fname = synthetic_smb_fname(frame,
     759             :                                           q_filepath,
     760           0 :                                           smb_fname->stream_name,
     761             :                                           NULL,
     762             :                                           0,
     763           0 :                                           smb_fname->flags);
     764           0 :         if (q_smb_fname == NULL) {
     765           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     766           0 :                 goto out;
     767             :         }
     768             : 
     769           0 :         become_root();
     770           0 :         ret = virusfilter_vfs_next_move(handle, smb_fname, q_smb_fname);
     771           0 :         if (ret == -1) {
     772           0 :                 saved_errno = errno;
     773             :         }
     774           0 :         unbecome_root();
     775           0 :         if (ret == -1) {
     776           0 :                 DBG_ERR("Quarantine [%s/%s] rename to %s failed: %s\n",
     777             :                         cwd_fname, fname, q_filepath, strerror(saved_errno));
     778           0 :                 errno = saved_errno;
     779           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     780           0 :                 goto out;
     781             :         }
     782             : 
     783           0 :         *filepath_newp = talloc_move(mem_ctx, &q_filepath);
     784             : 
     785           0 : out:
     786           0 :         TALLOC_FREE(frame);
     787           0 :         return action;
     788             : }
     789             : 
     790           4 : static virusfilter_action infected_file_action_rename(
     791             :         struct vfs_handle_struct *handle,
     792             :         struct virusfilter_config *config,
     793             :         TALLOC_CTX *mem_ctx,
     794             :         const struct files_struct *fsp,
     795             :         const char **filepath_newp)
     796             : {
     797           4 :         TALLOC_CTX *frame = talloc_stackframe();
     798           4 :         connection_struct *conn = handle->conn;
     799           4 :         char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
     800           4 :         char *fname = fsp->fsp_name->base_name;
     801           4 :         const struct smb_filename *smb_fname = fsp->fsp_name;
     802           4 :         struct smb_filename *q_smb_fname = NULL;
     803           4 :         char *q_dir = NULL;
     804           4 :         char *q_prefix = NULL;
     805           4 :         char *q_suffix = NULL;
     806           4 :         char *q_filepath = NULL;
     807           4 :         const char *base_name = NULL;
     808           4 :         virusfilter_action action = VIRUSFILTER_ACTION_RENAME;
     809           4 :         bool ok = false;
     810           4 :         int ret = -1;
     811           4 :         int saved_errno = 0;
     812             : 
     813           4 :         q_prefix = virusfilter_string_sub(frame, conn,
     814             :                                           config->rename_prefix);
     815           4 :         q_suffix = virusfilter_string_sub(frame, conn,
     816             :                                           config->rename_suffix);
     817           4 :         if (q_prefix == NULL || q_suffix == NULL) {
     818           0 :                 DBG_ERR("Rename failed: %s/%s: Cannot allocate "
     819             :                         "memory\n", cwd_fname, fname);
     820           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     821           0 :                 goto out;
     822             :         }
     823             : 
     824           4 :         ok = parent_dirname(frame, fname, &q_dir, &base_name);
     825           4 :         if (!ok) {
     826           0 :                 DBG_ERR("Rename failed: %s/%s: Cannot allocate "
     827             :                         "memory\n", cwd_fname, fname);
     828           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     829           0 :                 goto out;
     830             :         }
     831             : 
     832           4 :         if (q_dir == NULL) {
     833           0 :                 DBG_ERR("Rename failed: %s/%s: Cannot allocate "
     834             :                         "memory\n", cwd_fname, fname);
     835           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     836           0 :                 goto out;
     837             :         }
     838             : 
     839           4 :         q_filepath = talloc_asprintf(frame, "%s/%s%s%s", q_dir,
     840             :                                      q_prefix, base_name, q_suffix);
     841             : 
     842           4 :         q_smb_fname = synthetic_smb_fname(frame, q_filepath,
     843           4 :                                           smb_fname->stream_name, NULL,
     844             :                                           0,
     845           4 :                                           smb_fname->flags);
     846           4 :         if (q_smb_fname == NULL) {
     847           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     848           0 :                 goto out;
     849             :         }
     850             : 
     851           4 :         become_root();
     852           4 :         ret = virusfilter_vfs_next_move(handle, smb_fname, q_smb_fname);
     853           4 :         if (ret == -1) {
     854           0 :                 saved_errno = errno;
     855             :         }
     856           4 :         unbecome_root();
     857             : 
     858           4 :         if (ret == -1) {
     859           0 :                 DBG_ERR("Rename failed: %s/%s: Rename failed: %s\n",
     860             :                         cwd_fname, fname, strerror(saved_errno));
     861           0 :                 errno = saved_errno;
     862           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     863           0 :                 goto out;
     864             :         }
     865             : 
     866           4 :         *filepath_newp = talloc_move(mem_ctx, &q_filepath);
     867             : 
     868           4 : out:
     869           4 :         TALLOC_FREE(frame);
     870           4 :         return action;
     871             : }
     872             : 
     873           0 : static virusfilter_action infected_file_action_delete(
     874             :         struct vfs_handle_struct *handle,
     875             :         const struct files_struct *fsp)
     876             : {
     877             :         int ret;
     878           0 :         int saved_errno = 0;
     879             : 
     880           0 :         become_root();
     881           0 :         ret = SMB_VFS_NEXT_UNLINKAT(handle,
     882             :                                 handle->conn->cwd_fsp,
     883             :                                 fsp->fsp_name,
     884             :                                 0);
     885           0 :         if (ret == -1) {
     886           0 :                 saved_errno = errno;
     887             :         }
     888           0 :         unbecome_root();
     889           0 :         if (ret == -1) {
     890           0 :                 DBG_ERR("Delete [%s/%s] failed: %s\n",
     891             :                         fsp->conn->cwd_fsp->fsp_name->base_name,
     892             :                         fsp->fsp_name->base_name,
     893             :                         strerror(saved_errno));
     894           0 :                 errno = saved_errno;
     895           0 :                 return VIRUSFILTER_ACTION_DO_NOTHING;
     896             :         }
     897             : 
     898           0 :         return VIRUSFILTER_ACTION_DELETE;
     899             : }
     900             : 
     901           4 : static virusfilter_action virusfilter_do_infected_file_action(
     902             :         struct vfs_handle_struct *handle,
     903             :         struct virusfilter_config *config,
     904             :         TALLOC_CTX *mem_ctx,
     905             :         const struct files_struct *fsp,
     906             :         const char **filepath_newp)
     907             : {
     908             :         virusfilter_action action;
     909             : 
     910           4 :         *filepath_newp = NULL;
     911             : 
     912           4 :         switch (config->infected_file_action) {
     913           4 :         case VIRUSFILTER_ACTION_RENAME:
     914           4 :                 action = infected_file_action_rename(handle, config, mem_ctx,
     915             :                                                      fsp, filepath_newp);
     916           4 :                 break;
     917             : 
     918           0 :         case VIRUSFILTER_ACTION_QUARANTINE:
     919           0 :                 action = infected_file_action_quarantine(handle, config, mem_ctx,
     920             :                                                          fsp, filepath_newp);
     921           0 :                 break;
     922             : 
     923           0 :         case VIRUSFILTER_ACTION_DELETE:
     924           0 :                 action = infected_file_action_delete(handle, fsp);
     925           0 :                 break;
     926             : 
     927           0 :         case VIRUSFILTER_ACTION_DO_NOTHING:
     928             :         default:
     929           0 :                 action = VIRUSFILTER_ACTION_DO_NOTHING;
     930           0 :                 break;
     931             :         }
     932             : 
     933           4 :         return action;
     934             : }
     935             : 
     936           4 : static virusfilter_action virusfilter_treat_infected_file(
     937             :         struct vfs_handle_struct *handle,
     938             :         struct virusfilter_config *config,
     939             :         const struct files_struct *fsp,
     940             :         const char *report,
     941             :         bool is_cache)
     942             : {
     943           4 :         connection_struct *conn = handle->conn;
     944           4 :         char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
     945           4 :         char *fname = fsp->fsp_name->base_name;
     946           4 :         TALLOC_CTX *mem_ctx = talloc_tos();
     947             :         int i;
     948             :         virusfilter_action action;
     949           4 :         const char *action_name = "UNKNOWN";
     950           4 :         const char *filepath_q = NULL;
     951           4 :         char *env_list = NULL;
     952           4 :         char *command = NULL;
     953             :         int command_result;
     954             :         int ret;
     955             : 
     956           4 :         action = virusfilter_do_infected_file_action(handle, config, mem_ctx,
     957             :                                                      fsp, &filepath_q);
     958           8 :         for (i=0; virusfilter_actions[i].name; i++) {
     959           8 :                 if (virusfilter_actions[i].value == action) {
     960           4 :                         action_name = virusfilter_actions[i].name;
     961           4 :                         break;
     962             :                 }
     963             :         }
     964           4 :         DBG_WARNING("Infected file action: %s/%s: %s\n", cwd_fname,
     965             :                     fname, action_name);
     966             : 
     967           4 :         if (!config->infected_file_command) {
     968           4 :                 return action;
     969             :         }
     970             : 
     971           0 :         ret = virusfilter_set_module_env(mem_ctx, config, &env_list);
     972           0 :         if (ret == -1) {
     973           0 :                 goto done;
     974             :         }
     975           0 :         ret = virusfilter_env_set(mem_ctx, &env_list,
     976             :                                   "VIRUSFILTER_INFECTED_SERVICE_FILE_PATH",
     977             :                                   fname);
     978           0 :         if (ret == -1) {
     979           0 :                 goto done;
     980             :         }
     981           0 :         if (report != NULL) {
     982           0 :                 ret = virusfilter_env_set(mem_ctx, &env_list,
     983             :                                           "VIRUSFILTER_INFECTED_FILE_REPORT",
     984             :                                           report);
     985           0 :                 if (ret == -1) {
     986           0 :                         goto done;
     987             :                 }
     988             :         }
     989           0 :         ret = virusfilter_env_set(mem_ctx, &env_list,
     990             :                                   "VIRUSFILTER_INFECTED_FILE_ACTION",
     991             :                                   action_name);
     992           0 :         if (ret == -1) {
     993           0 :                 goto done;
     994             :         }
     995           0 :         if (filepath_q != NULL) {
     996           0 :                 ret = virusfilter_env_set(mem_ctx, &env_list,
     997             :                                           "VIRUSFILTER_QUARANTINED_FILE_PATH",
     998             :                                           filepath_q);
     999           0 :                 if (ret == -1) {
    1000           0 :                         goto done;
    1001             :                 }
    1002             :         }
    1003           0 :         if (is_cache) {
    1004           0 :                 ret = virusfilter_env_set(mem_ctx, &env_list,
    1005             :                                           "VIRUSFILTER_RESULT_IS_CACHE", "yes");
    1006           0 :                 if (ret == -1) {
    1007           0 :                         goto done;
    1008             :                 }
    1009             :         }
    1010             : 
    1011           0 :         command = virusfilter_string_sub(mem_ctx, conn,
    1012             :                                          config->infected_file_command);
    1013           0 :         if (command == NULL) {
    1014           0 :                 DBG_ERR("virusfilter_string_sub failed\n");
    1015           0 :                 goto done;
    1016             :         }
    1017             : 
    1018           0 :         DBG_NOTICE("Infected file command line: %s/%s: %s\n", cwd_fname,
    1019             :                    fname, command);
    1020             : 
    1021           0 :         command_result = virusfilter_shell_run(mem_ctx, command, &env_list,
    1022             :                                                conn, true);
    1023           0 :         if (command_result != 0) {
    1024           0 :                 DBG_ERR("Infected file command failed: %d\n", command_result);
    1025             :         }
    1026             : 
    1027           0 :         DBG_DEBUG("Infected file command finished: %d\n", command_result);
    1028             : 
    1029           0 : done:
    1030           0 :         TALLOC_FREE(env_list);
    1031           0 :         TALLOC_FREE(command);
    1032             : 
    1033           0 :         return action;
    1034             : }
    1035             : 
    1036           0 : static void virusfilter_treat_scan_error(
    1037             :         struct vfs_handle_struct *handle,
    1038             :         struct virusfilter_config *config,
    1039             :         const struct files_struct *fsp,
    1040             :         const char *report,
    1041             :         bool is_cache)
    1042             : {
    1043           0 :         connection_struct *conn = handle->conn;
    1044           0 :         const char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
    1045           0 :         const char *fname = fsp->fsp_name->base_name;
    1046           0 :         TALLOC_CTX *mem_ctx = talloc_tos();
    1047           0 :         char *env_list = NULL;
    1048           0 :         char *command = NULL;
    1049             :         int command_result;
    1050             :         int ret;
    1051             : 
    1052           0 :         if (!config->scan_error_command) {
    1053           0 :                 return;
    1054             :         }
    1055           0 :         ret = virusfilter_set_module_env(mem_ctx, config, &env_list);
    1056           0 :         if (ret == -1) {
    1057           0 :                 goto done;
    1058             :         }
    1059           0 :         ret = virusfilter_env_set(mem_ctx, &env_list,
    1060             :                                   "VIRUSFILTER_SCAN_ERROR_SERVICE_FILE_PATH",
    1061             :                                   fname);
    1062           0 :         if (ret == -1) {
    1063           0 :                 goto done;
    1064             :         }
    1065           0 :         if (report != NULL) {
    1066           0 :                 ret = virusfilter_env_set(mem_ctx, &env_list,
    1067             :                                           "VIRUSFILTER_SCAN_ERROR_REPORT",
    1068             :                                           report);
    1069           0 :                 if (ret == -1) {
    1070           0 :                         goto done;
    1071             :                 }
    1072             :         }
    1073           0 :         if (is_cache) {
    1074           0 :                 ret = virusfilter_env_set(mem_ctx, &env_list,
    1075             :                                           "VIRUSFILTER_RESULT_IS_CACHE", "1");
    1076           0 :                 if (ret == -1) {
    1077           0 :                         goto done;
    1078             :                 }
    1079             :         }
    1080             : 
    1081           0 :         command = virusfilter_string_sub(mem_ctx, conn,
    1082             :                                          config->scan_error_command);
    1083           0 :         if (command == NULL) {
    1084           0 :                 DBG_ERR("virusfilter_string_sub failed\n");
    1085           0 :                 goto done;
    1086             :         }
    1087             : 
    1088           0 :         DBG_NOTICE("Scan error command line: %s/%s: %s\n", cwd_fname,
    1089             :                    fname, command);
    1090             : 
    1091           0 :         command_result = virusfilter_shell_run(mem_ctx, command, &env_list,
    1092             :                                                conn, true);
    1093           0 :         if (command_result != 0) {
    1094           0 :                 DBG_ERR("Scan error command failed: %d\n", command_result);
    1095             :         }
    1096             : 
    1097           0 : done:
    1098           0 :         TALLOC_FREE(env_list);
    1099           0 :         TALLOC_FREE(command);
    1100             : }
    1101             : 
    1102           8 : static virusfilter_result virusfilter_scan(
    1103             :         struct vfs_handle_struct *handle,
    1104             :         struct virusfilter_config *config,
    1105             :         const struct files_struct *fsp)
    1106             : {
    1107             :         virusfilter_result scan_result;
    1108           8 :         char *scan_report = NULL;
    1109           8 :         const char *fname = fsp->fsp_name->base_name;
    1110           8 :         const char *cwd_fname = fsp->conn->cwd_fsp->fsp_name->base_name;
    1111           8 :         struct virusfilter_cache_entry *scan_cache_e = NULL;
    1112           8 :         bool is_cache = false;
    1113           8 :         virusfilter_action file_action = VIRUSFILTER_ACTION_DO_NOTHING;
    1114           8 :         bool add_scan_cache = true;
    1115           8 :         bool ok = false;
    1116             : 
    1117           8 :         if (config->cache) {
    1118           8 :                 DBG_DEBUG("Searching cache entry: fname: %s\n", fname);
    1119           8 :                 scan_cache_e = virusfilter_cache_get(config->cache,
    1120             :                                                      cwd_fname, fname);
    1121           8 :                 if (scan_cache_e != NULL) {
    1122           0 :                         DBG_DEBUG("Cache entry found: cached result: %d\n",
    1123             :                               scan_cache_e->result);
    1124           0 :                         is_cache = true;
    1125           0 :                         scan_result = scan_cache_e->result;
    1126           0 :                         scan_report = scan_cache_e->report;
    1127           0 :                         goto virusfilter_scan_result_eval;
    1128             :                 }
    1129           8 :                 DBG_DEBUG("Cache entry not found\n");
    1130             :         }
    1131             : 
    1132           8 :         if (config->backend->fns->scan_init != NULL) {
    1133           0 :                 scan_result = config->backend->fns->scan_init(config);
    1134           0 :                 if (scan_result != VIRUSFILTER_RESULT_OK) {
    1135           0 :                         scan_result = VIRUSFILTER_RESULT_ERROR;
    1136           0 :                         scan_report = talloc_asprintf(
    1137           0 :                                 talloc_tos(),
    1138             :                                 "Initializing scanner failed");
    1139           0 :                         goto virusfilter_scan_result_eval;
    1140             :                 }
    1141             :         }
    1142             : 
    1143           8 :         scan_result = config->backend->fns->scan(handle, config, fsp,
    1144             :                                                  &scan_report);
    1145             : 
    1146           8 :         if (config->backend->fns->scan_end != NULL) {
    1147           0 :                 bool scan_end = true;
    1148             : 
    1149           0 :                 if (config->scan_request_limit > 0) {
    1150           0 :                         scan_end = false;
    1151           0 :                         config->scan_request_count++;
    1152           0 :                         if (config->scan_request_count >=
    1153           0 :                             config->scan_request_limit)
    1154             :                         {
    1155           0 :                                 scan_end = true;
    1156           0 :                                 config->scan_request_count = 0;
    1157             :                         }
    1158             :                 }
    1159           0 :                 if (scan_end) {
    1160           0 :                         config->backend->fns->scan_end(config);
    1161             :                 }
    1162             :         }
    1163             : 
    1164           8 : virusfilter_scan_result_eval:
    1165             : 
    1166           8 :         switch (scan_result) {
    1167           4 :         case VIRUSFILTER_RESULT_CLEAN:
    1168           4 :                 DBG_INFO("Scan result: Clean: %s/%s\n", cwd_fname, fname);
    1169           4 :                 break;
    1170             : 
    1171           4 :         case VIRUSFILTER_RESULT_INFECTED:
    1172           4 :                 DBG_ERR("Scan result: Infected: %s/%s: %s\n",
    1173             :                         cwd_fname, fname, scan_report ? scan_report :
    1174             :                         "infected (memory error on report)");
    1175           4 :                 file_action = virusfilter_treat_infected_file(handle,
    1176             :                                         config, fsp, scan_report, is_cache);
    1177           4 :                 if (file_action != VIRUSFILTER_ACTION_DO_NOTHING) {
    1178           4 :                         add_scan_cache = false;
    1179             :                 }
    1180           4 :                 break;
    1181             : 
    1182           0 :         case VIRUSFILTER_RESULT_SUSPECTED:
    1183           0 :                 if (!config->block_suspected_file) {
    1184           0 :                         break;
    1185             :                 }
    1186           0 :                 DBG_ERR("Scan result: Suspected: %s/%s: %s\n",
    1187             :                         cwd_fname, fname, scan_report ? scan_report :
    1188             :                         "suspected infection (memory error on report)");
    1189           0 :                 file_action = virusfilter_treat_infected_file(handle,
    1190             :                                         config, fsp, scan_report, is_cache);
    1191           0 :                 if (file_action != VIRUSFILTER_ACTION_DO_NOTHING) {
    1192           0 :                         add_scan_cache = false;
    1193             :                 }
    1194           0 :                 break;
    1195             : 
    1196           0 :         case VIRUSFILTER_RESULT_ERROR:
    1197           0 :                 DBG_ERR("Scan result: Error: %s/%s: %s\n",
    1198             :                         cwd_fname, fname, scan_report ? scan_report :
    1199             :                         "error (memory error on report)");
    1200           0 :                 virusfilter_treat_scan_error(handle, config, fsp,
    1201             :                                              scan_report, is_cache);
    1202           0 :                 add_scan_cache = false;
    1203           0 :                 break;
    1204             : 
    1205           0 :         default:
    1206           0 :                 DBG_ERR("Scan result: Unknown result code %d: %s/%s: %s\n",
    1207             :                         scan_result, cwd_fname, fname, scan_report ?
    1208             :                         scan_report : "Unknown (memory error on report)");
    1209           0 :                 virusfilter_treat_scan_error(handle, config, fsp,
    1210             :                                              scan_report, is_cache);
    1211           0 :                 add_scan_cache = false;
    1212           0 :                 break;
    1213             :         }
    1214             : 
    1215           8 :         if (config->cache) {
    1216           8 :                 if (!is_cache && add_scan_cache) {
    1217           4 :                         DBG_DEBUG("Adding new cache entry: %s, %d\n", fname,
    1218             :                                   scan_result);
    1219           4 :                         ok = virusfilter_cache_entry_add(
    1220             :                                         config->cache, cwd_fname, fname,
    1221             :                                         scan_result, scan_report);
    1222           4 :                         if (!ok) {
    1223           0 :                                 DBG_ERR("Cannot create cache entry: "
    1224             :                                         "virusfilter_cache_entry_new failed\n");
    1225           0 :                                 goto virusfilter_scan_return;
    1226             :                         }
    1227           4 :                 } else if (is_cache) {
    1228           0 :                         virusfilter_cache_entry_free(scan_cache_e);
    1229             :                 }
    1230             :         }
    1231             : 
    1232           4 : virusfilter_scan_return:
    1233           8 :         return scan_result;
    1234             : }
    1235             : 
    1236          30 : static int virusfilter_vfs_openat(struct vfs_handle_struct *handle,
    1237             :                                   const struct files_struct *dirfsp,
    1238             :                                   const struct smb_filename *smb_fname_in,
    1239             :                                   struct files_struct *fsp,
    1240             :                                   const struct vfs_open_how *how)
    1241             : {
    1242          30 :         TALLOC_CTX *mem_ctx = talloc_tos();
    1243          30 :         struct virusfilter_config *config = NULL;
    1244          30 :         const char *cwd_fname = dirfsp->fsp_name->base_name;
    1245             :         virusfilter_result scan_result;
    1246          30 :         const char *fname = fsp->fsp_name->base_name;
    1247          30 :         char *dir_name = NULL;
    1248          30 :         const char *base_name = NULL;
    1249          30 :         int scan_errno = 0;
    1250             :         size_t test_prefix;
    1251             :         size_t test_suffix;
    1252          30 :         int rename_trap_count = 0;
    1253             :         int ret;
    1254             :         bool ok1;
    1255          30 :         char *sret = NULL;
    1256          30 :         struct smb_filename *smb_fname = NULL;
    1257          30 :         SMB_STRUCT_STAT sbuf = smb_fname_in->st;
    1258             : 
    1259          30 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
    1260             :                                 struct virusfilter_config, return -1);
    1261             : 
    1262          30 :         if (fsp->fsp_flags.is_directory) {
    1263           4 :                 DBG_INFO("Not scanned: Directory: %s/\n", cwd_fname);
    1264           4 :                 goto virusfilter_vfs_open_next;
    1265             :         }
    1266             : 
    1267          26 :         test_prefix = strlen(config->rename_prefix);
    1268          26 :         test_suffix = strlen(config->rename_suffix);
    1269          26 :         if (test_prefix > 0) {
    1270          26 :                 rename_trap_count++;
    1271             :         }
    1272          26 :         if (test_suffix > 0) {
    1273          26 :                 rename_trap_count++;
    1274             :         }
    1275             : 
    1276          26 :         smb_fname = cp_smb_filename(mem_ctx, smb_fname_in);
    1277          26 :         if (smb_fname == NULL) {
    1278           0 :                 goto virusfilter_vfs_open_fail;
    1279             :         }
    1280             : 
    1281          26 :         if (is_named_stream(smb_fname)) {
    1282           0 :                 DBG_INFO("Not scanned: only file backed streams can be scanned:"
    1283             :                          " %s/%s\n", cwd_fname, fname);
    1284           0 :                 goto virusfilter_vfs_open_next;
    1285             :         }
    1286             : 
    1287          26 :         if (!config->scan_on_open) {
    1288           0 :                 DBG_INFO("Not scanned: scan on open is disabled: %s/%s\n",
    1289             :                          cwd_fname, fname);
    1290           0 :                 goto virusfilter_vfs_open_next;
    1291             :         }
    1292             : 
    1293          26 :         if (how->flags & O_TRUNC) {
    1294           0 :                 DBG_INFO("Not scanned: Open flags have O_TRUNC: %s/%s\n",
    1295             :                          cwd_fname, fname);
    1296           0 :                 goto virusfilter_vfs_open_next;
    1297             :         }
    1298             : 
    1299          26 :         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf);
    1300          26 :         if (ret != 0) {
    1301             : 
    1302             :                 /*
    1303             :                  * Do not return immediately if !(flags & O_CREAT) &&
    1304             :                  * errno != ENOENT.
    1305             :                  * Do not do this here or anywhere else. The module is
    1306             :                  * stackable and there may be modules below, such as audit
    1307             :                  * modules, which should be handled.
    1308             :                  */
    1309          22 :                 goto virusfilter_vfs_open_next;
    1310             :         }
    1311           4 :         ret = S_ISREG(sbuf.st_ex_mode);
    1312           4 :         if (ret == 0) {
    1313           0 :                 DBG_INFO("Not scanned: Directory or special file: %s/%s\n",
    1314             :                          cwd_fname, fname);
    1315           0 :                 goto virusfilter_vfs_open_next;
    1316             :         }
    1317           4 :         if (config->max_file_size > 0 &&
    1318           4 :             sbuf.st_ex_size > config->max_file_size)
    1319             :         {
    1320           0 :                 DBG_INFO("Not scanned: file size > max file size: %s/%s\n",
    1321             :                          cwd_fname, fname);
    1322           0 :                 goto virusfilter_vfs_open_next;
    1323             :         }
    1324           4 :         if (config->min_file_size > 0 &&
    1325           0 :             sbuf.st_ex_size < config->min_file_size)
    1326             :         {
    1327           0 :                 DBG_INFO("Not scanned: file size < min file size: %s/%s\n",
    1328             :                       cwd_fname, fname);
    1329           0 :                 goto virusfilter_vfs_open_next;
    1330             :         }
    1331             : 
    1332           4 :         ok1 = is_in_path(fname, config->exclude_files, false);
    1333           4 :         if (config->exclude_files && ok1)
    1334             :         {
    1335           0 :                 DBG_INFO("Not scanned: exclude files: %s/%s\n",
    1336             :                          cwd_fname, fname);
    1337           0 :                 goto virusfilter_vfs_open_next;
    1338             :         }
    1339             : 
    1340           4 :         if (config->infected_file_action == VIRUSFILTER_ACTION_QUARANTINE) {
    1341           0 :                 sret = strstr_m(fname, config->quarantine_dir);
    1342           0 :                 if (sret != NULL) {
    1343           0 :                         scan_errno = config->infected_open_errno;
    1344           0 :                         goto virusfilter_vfs_open_fail;
    1345             :                 }
    1346             :         }
    1347             : 
    1348           4 :         if (test_prefix > 0 || test_suffix > 0) {
    1349           4 :                 ok1 = parent_dirname(mem_ctx, fname, &dir_name, &base_name);
    1350           4 :                 if (ok1)
    1351             :                 {
    1352           4 :                         if (test_prefix > 0) {
    1353           4 :                                 ret = strncmp(base_name,
    1354             :                                     config->rename_prefix, test_prefix);
    1355           4 :                                 if (ret != 0) {
    1356           4 :                                         test_prefix = 0;
    1357             :                                 }
    1358             :                         }
    1359           4 :                         if (test_suffix > 0) {
    1360           4 :                                 ret = strcmp(base_name + (strlen(base_name)
    1361           4 :                                                  - test_suffix),
    1362             :                                                  config->rename_suffix);
    1363           4 :                                 if (ret != 0) {
    1364           4 :                                         test_suffix = 0;
    1365             :                                 }
    1366             :                         }
    1367             : 
    1368           4 :                         TALLOC_FREE(dir_name);
    1369             : 
    1370           4 :                         if ((rename_trap_count == 2 && test_prefix &&
    1371           4 :                             test_suffix) || (rename_trap_count == 1 &&
    1372           0 :                             (test_prefix || test_suffix)))
    1373             :                         {
    1374           0 :                                 scan_errno =
    1375             :                                         config->infected_open_errno;
    1376           0 :                                 goto virusfilter_vfs_open_fail;
    1377             :                         }
    1378             :                 }
    1379             :         }
    1380             : 
    1381           4 :         scan_result = virusfilter_scan(handle, config, fsp);
    1382             : 
    1383           4 :         switch (scan_result) {
    1384           2 :         case VIRUSFILTER_RESULT_CLEAN:
    1385           2 :                 break;
    1386           2 :         case VIRUSFILTER_RESULT_INFECTED:
    1387           2 :                 scan_errno = config->infected_open_errno;
    1388           2 :                 goto virusfilter_vfs_open_fail;
    1389           0 :         case VIRUSFILTER_RESULT_ERROR:
    1390           0 :                 if (config->block_access_on_error) {
    1391           0 :                         DBG_INFO("Block access\n");
    1392           0 :                         scan_errno = config->scan_error_open_errno;
    1393           0 :                         goto virusfilter_vfs_open_fail;
    1394             :                 }
    1395           0 :                 break;
    1396           0 :         default:
    1397           0 :                 scan_errno = config->scan_error_open_errno;
    1398           0 :                 goto virusfilter_vfs_open_fail;
    1399             :         }
    1400             : 
    1401           2 :         TALLOC_FREE(smb_fname);
    1402             : 
    1403           0 : virusfilter_vfs_open_next:
    1404          28 :         return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname_in, fsp, how);
    1405             : 
    1406           2 : virusfilter_vfs_open_fail:
    1407           2 :         TALLOC_FREE(smb_fname);
    1408           2 :         errno = (scan_errno != 0) ? scan_errno : EACCES;
    1409           2 :         return -1;
    1410             : }
    1411             : 
    1412          20 : static int virusfilter_vfs_close(
    1413             :         struct vfs_handle_struct *handle,
    1414             :         files_struct *fsp)
    1415             : {
    1416             :         /*
    1417             :          * The name of this variable is for consistency. If API changes to
    1418             :          * match _open change to cwd_fname as in virusfilter_vfs_open.
    1419             :          */
    1420          20 :         const char *cwd_fname = handle->conn->connectpath;
    1421             : 
    1422          20 :         struct virusfilter_config *config = NULL;
    1423          20 :         char *fname = fsp->fsp_name->base_name;
    1424          20 :         int close_result = -1;
    1425          20 :         int close_errno = 0;
    1426             :         virusfilter_result scan_result;
    1427          20 :         int scan_errno = 0;
    1428             : 
    1429          20 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
    1430             :                                 struct virusfilter_config, return -1);
    1431             : 
    1432             :         /*
    1433             :          * Must close after scan? It appears not as the scanners are not
    1434             :          * internal and other modules such as greyhole seem to do
    1435             :          * SMB_VFS_NEXT_* functions before processing.
    1436             :          */
    1437          20 :         close_result = SMB_VFS_NEXT_CLOSE(handle, fsp);
    1438          20 :         if (close_result == -1) {
    1439           0 :                 close_errno = errno;
    1440             :         }
    1441             : 
    1442             :         /*
    1443             :          * Return immediately if close_result == -1, and close_errno == EBADF.
    1444             :          * If close failed, file likely doesn't exist, do not try to scan.
    1445             :          */
    1446          20 :         if (close_result == -1 && close_errno == EBADF) {
    1447           0 :                 if (fsp->fsp_flags.modified) {
    1448           0 :                         DBG_DEBUG("Removing cache entry (if existent): "
    1449             :                                   "fname: %s\n", fname);
    1450           0 :                         virusfilter_cache_remove(config->cache,
    1451             :                                                  cwd_fname, fname);
    1452             :                 }
    1453           0 :                 goto virusfilter_vfs_close_fail;
    1454             :         }
    1455             : 
    1456          20 :         if (fsp->fsp_flags.is_directory) {
    1457           8 :                 DBG_INFO("Not scanned: Directory: %s/\n", cwd_fname);
    1458           8 :                 return close_result;
    1459             :         }
    1460             : 
    1461          12 :         if (fsp_is_alternate_stream(fsp)) {
    1462           0 :                 if (config->scan_on_open && fsp->fsp_flags.modified) {
    1463           0 :                         if (config->cache) {
    1464           0 :                                 DBG_DEBUG("Removing cache entry (if existent)"
    1465             :                                           ": fname: %s\n", fname);
    1466           0 :                                 virusfilter_cache_remove(
    1467             :                                                 config->cache,
    1468             :                                                 cwd_fname, fname);
    1469             :                         }
    1470             :                 }
    1471           0 :                 DBG_INFO("Not scanned: only file backed streams can be scanned:"
    1472             :                          " %s/%s\n", cwd_fname, fname);
    1473           0 :                 return close_result;
    1474             :         }
    1475             : 
    1476          12 :         if (!config->scan_on_close) {
    1477           0 :                 if (config->scan_on_open && fsp->fsp_flags.modified) {
    1478           0 :                         if (config->cache) {
    1479           0 :                                 DBG_DEBUG("Removing cache entry (if existent)"
    1480             :                                           ": fname: %s\n", fname);
    1481           0 :                                 virusfilter_cache_remove(
    1482             :                                                 config->cache,
    1483             :                                                 cwd_fname, fname);
    1484             :                         }
    1485             :                 }
    1486           0 :                 DBG_INFO("Not scanned: scan on close is disabled: %s/%s\n",
    1487             :                          cwd_fname, fname);
    1488           0 :                 return close_result;
    1489             :         }
    1490             : 
    1491          12 :         if (!fsp->fsp_flags.modified) {
    1492           8 :                 DBG_NOTICE("Not scanned: File not modified: %s/%s\n",
    1493             :                            cwd_fname, fname);
    1494             : 
    1495           8 :                 return close_result;
    1496             :         }
    1497             : 
    1498           4 :         if (is_in_path(fname, config->exclude_files, false)) {
    1499           0 :                 DBG_INFO("Not scanned: exclude files: %s/%s\n",
    1500             :                          cwd_fname, fname);
    1501           0 :                 return close_result;
    1502             :         }
    1503             : 
    1504           4 :         scan_result = virusfilter_scan(handle, config, fsp);
    1505             : 
    1506           4 :         switch (scan_result) {
    1507           2 :         case VIRUSFILTER_RESULT_CLEAN:
    1508           2 :                 break;
    1509           2 :         case VIRUSFILTER_RESULT_INFECTED:
    1510           2 :                 scan_errno = config->infected_close_errno;
    1511           2 :                 goto virusfilter_vfs_close_fail;
    1512           0 :         case VIRUSFILTER_RESULT_ERROR:
    1513           0 :                 if (config->block_access_on_error) {
    1514           0 :                         DBG_INFO("Block access\n");
    1515           0 :                         scan_errno = config->scan_error_close_errno;
    1516           0 :                         goto virusfilter_vfs_close_fail;
    1517             :                 }
    1518           0 :                 break;
    1519           0 :         default:
    1520           0 :                 scan_errno = config->scan_error_close_errno;
    1521           0 :                 goto virusfilter_vfs_close_fail;
    1522             :         }
    1523             : 
    1524           2 :         if (close_errno != 0) {
    1525           0 :                 errno = close_errno;
    1526             :         }
    1527             : 
    1528           2 :         return close_result;
    1529             : 
    1530           2 : virusfilter_vfs_close_fail:
    1531             : 
    1532           2 :         errno = (scan_errno != 0) ? scan_errno : close_errno;
    1533             : 
    1534           2 :         return close_result;
    1535             : }
    1536             : 
    1537           0 : static int virusfilter_vfs_unlinkat(struct vfs_handle_struct *handle,
    1538             :                 struct files_struct *dirfsp,
    1539             :                 const struct smb_filename *smb_fname,
    1540             :                 int flags)
    1541             : {
    1542           0 :         int ret = SMB_VFS_NEXT_UNLINKAT(handle,
    1543             :                         dirfsp,
    1544             :                         smb_fname,
    1545             :                         flags);
    1546           0 :         struct virusfilter_config *config = NULL;
    1547           0 :         struct smb_filename *full_fname = NULL;
    1548           0 :         char *fname = NULL;
    1549           0 :         char *cwd_fname = dirfsp->fsp_name->base_name;
    1550             : 
    1551           0 :         if (ret != 0 && errno != ENOENT) {
    1552           0 :                 return ret;
    1553             :         }
    1554             : 
    1555           0 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
    1556             :                                 struct virusfilter_config, return -1);
    1557             : 
    1558           0 :         if (config->cache == NULL) {
    1559           0 :                 return 0;
    1560             :         }
    1561             : 
    1562           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    1563             :                                                   dirfsp,
    1564             :                                                   smb_fname);
    1565           0 :         if (full_fname == NULL) {
    1566           0 :                 return -1;
    1567             :         }
    1568             : 
    1569           0 :         fname = full_fname->base_name;
    1570             : 
    1571           0 :         DBG_DEBUG("Removing cache entry (if existent): fname: %s\n", fname);
    1572           0 :         virusfilter_cache_remove(config->cache, cwd_fname, fname);
    1573             : 
    1574           0 :         TALLOC_FREE(full_fname);
    1575           0 :         return 0;
    1576             : }
    1577             : 
    1578           0 : static int virusfilter_vfs_renameat(
    1579             :         struct vfs_handle_struct *handle,
    1580             :         files_struct *srcfsp,
    1581             :         const struct smb_filename *smb_fname_src,
    1582             :         files_struct *dstfsp,
    1583             :         const struct smb_filename *smb_fname_dst)
    1584             : {
    1585           0 :         int ret = SMB_VFS_NEXT_RENAMEAT(handle,
    1586             :                         srcfsp,
    1587             :                         smb_fname_src,
    1588             :                         dstfsp,
    1589             :                         smb_fname_dst);
    1590           0 :         struct virusfilter_config *config = NULL;
    1591           0 :         char *fname = NULL;
    1592           0 :         char *dst_fname = NULL;
    1593           0 :         char *cwd_fname = handle->conn->cwd_fsp->fsp_name->base_name;
    1594           0 :         struct smb_filename *full_src = NULL;
    1595           0 :         struct smb_filename *full_dst = NULL;
    1596             : 
    1597           0 :         if (ret != 0) {
    1598           0 :                 return ret;
    1599             :         }
    1600             : 
    1601           0 :         SMB_VFS_HANDLE_GET_DATA(handle, config,
    1602             :                                 struct virusfilter_config, return -1);
    1603             : 
    1604           0 :         if (config->cache == NULL) {
    1605           0 :                 return 0;
    1606             :         }
    1607             : 
    1608           0 :         full_src = full_path_from_dirfsp_atname(talloc_tos(),
    1609             :                                                 srcfsp,
    1610             :                                                 smb_fname_src);
    1611           0 :         if (full_src == NULL) {
    1612           0 :                 errno = ENOMEM;
    1613           0 :                 ret = -1;
    1614           0 :                 goto out;
    1615             :         }
    1616             : 
    1617           0 :         full_dst = full_path_from_dirfsp_atname(talloc_tos(),
    1618             :                                                 dstfsp,
    1619             :                                                 smb_fname_dst);
    1620           0 :         if (full_dst == NULL) {
    1621           0 :                 errno = ENOMEM;
    1622           0 :                 ret = -1;
    1623           0 :                 goto out;
    1624             :         }
    1625             : 
    1626           0 :         fname = full_src->base_name;
    1627           0 :         dst_fname = full_dst->base_name;
    1628             : 
    1629           0 :         DBG_DEBUG("Renaming cache entry: fname: %s to: %s\n",
    1630             :                   fname, dst_fname);
    1631           0 :         virusfilter_cache_entry_rename(config->cache,
    1632             :                                        cwd_fname,
    1633             :                                        fname,
    1634             :                                        dst_fname);
    1635             : 
    1636           0 :         ret = 0;
    1637           0 :   out:
    1638           0 :         TALLOC_FREE(full_src);
    1639           0 :         TALLOC_FREE(full_dst);
    1640           0 :         return ret;
    1641             : }
    1642             : 
    1643             : 
    1644             : /* VFS operations */
    1645             : static struct vfs_fn_pointers vfs_virusfilter_fns = {
    1646             :         .connect_fn     = virusfilter_vfs_connect,
    1647             :         .disconnect_fn  = virusfilter_vfs_disconnect,
    1648             :         .openat_fn      = virusfilter_vfs_openat,
    1649             :         .close_fn       = virusfilter_vfs_close,
    1650             :         .unlinkat_fn    = virusfilter_vfs_unlinkat,
    1651             :         .renameat_fn    = virusfilter_vfs_renameat,
    1652             : };
    1653             : 
    1654             : NTSTATUS vfs_virusfilter_init(TALLOC_CTX *);
    1655          35 : NTSTATUS vfs_virusfilter_init(TALLOC_CTX *ctx)
    1656             : {
    1657             :         NTSTATUS status;
    1658             : 
    1659          35 :         status = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
    1660             :                                   "virusfilter",
    1661             :                                   &vfs_virusfilter_fns);
    1662          35 :         if (!NT_STATUS_IS_OK(status)) {
    1663           0 :                 return status;
    1664             :         }
    1665             : 
    1666          35 :         virusfilter_debug_class = debug_add_class("virusfilter");
    1667          35 :         if (virusfilter_debug_class == -1) {
    1668           0 :                 virusfilter_debug_class = DBGC_VFS;
    1669           0 :                 DBG_ERR("Couldn't register custom debugging class!\n");
    1670             :         } else {
    1671          35 :                 DBG_DEBUG("Debug class number: %d\n", virusfilter_debug_class);
    1672             :         }
    1673             : 
    1674          35 :         DBG_INFO("registered\n");
    1675             : 
    1676          35 :         return status;
    1677             : }

Generated by: LCOV version 1.14