LCOV - code coverage report
Current view: top level - source3/modules - vfs_virusfilter.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 8 828 1.0 %
Date: 2021-09-23 10:06:22 Functions: 1 19 5.3 %

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

Generated by: LCOV version 1.13