LCOV - code coverage report
Current view: top level - source3/modules - vfs_virusfilter_utils.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 83 459 18.1 %
Date: 2024-02-28 12:06:22 Functions: 11 32 34.4 %

          Line data    Source code
       1             : /*
       2             :    Samba-VirusFilter VFS modules
       3             :    Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
       4             :    Copyright (C) 2016-2017 Trever L. Adams
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "modules/vfs_virusfilter_common.h"
      21             : #include "modules/vfs_virusfilter_utils.h"
      22             : 
      23             : struct iovec;
      24             : 
      25             : #include "lib/util/iov_buf.h"
      26             : #include <tevent.h>
      27             : #include "lib/tsocket/tsocket.h"
      28             : #include "source3/lib/substitute.h"
      29             : 
      30             : int virusfilter_debug_class = DBGC_VFS;
      31             : 
      32             : /* ====================================================================== */
      33             : 
      34           8 : char *virusfilter_string_sub(
      35             :         TALLOC_CTX *mem_ctx,
      36             :         connection_struct *conn,
      37             :         const char *str)
      38             : {
      39             :         const struct loadparm_substitution *lp_sub =
      40           8 :                 loadparm_s3_global_substitution();
      41             : 
      42           8 :         return talloc_sub_full(mem_ctx,
      43           8 :                 lp_servicename(mem_ctx, lp_sub, SNUM(conn)),
      44           8 :                 conn->session_info->unix_info->unix_name,
      45           8 :                 conn->connectpath,
      46           8 :                 conn->session_info->unix_token->gid,
      47           8 :                 conn->session_info->unix_info->sanitized_username,
      48           8 :                 conn->session_info->info->domain_name,
      49             :                 str);
      50             : }
      51             : 
      52           4 : int virusfilter_vfs_next_move(
      53             :         struct vfs_handle_struct *vfs_h,
      54             :         const struct smb_filename *smb_fname_src,
      55             :         const struct smb_filename *smb_fname_dst)
      56             : {
      57             :         int result;
      58             : 
      59           4 :         result = SMB_VFS_NEXT_RENAMEAT(vfs_h,
      60             :                         vfs_h->conn->cwd_fsp,
      61             :                         smb_fname_src,
      62             :                         vfs_h->conn->cwd_fsp,
      63             :                         smb_fname_dst);
      64           4 :         if (result == 0 || errno != EXDEV) {
      65           4 :                 return result;
      66             :         }
      67             : 
      68             :         /*
      69             :          * For now, do not handle EXDEV as poking around violates
      70             :          * stackability. Return -1, simply refuse access.
      71             :          */
      72           0 :         return -1;
      73             : }
      74             : 
      75             : /* Line-based socket I/O
      76             :  * ======================================================================
      77             :  */
      78             : 
      79           8 : struct virusfilter_io_handle *virusfilter_io_new(
      80             :         TALLOC_CTX *mem_ctx,
      81             :         int connect_timeout,
      82             :         int io_timeout)
      83             : {
      84           8 :         struct virusfilter_io_handle *io_h = talloc_zero(mem_ctx,
      85             :                                                 struct virusfilter_io_handle);
      86             : 
      87           8 :         if (io_h == NULL) {
      88           0 :                 return NULL;
      89             :         }
      90             : 
      91           8 :         io_h->stream = NULL;
      92           8 :         io_h->r_len = 0;
      93             : 
      94           8 :         virusfilter_io_set_connect_timeout(io_h, connect_timeout);
      95           8 :         virusfilter_io_set_io_timeout(io_h, io_timeout);
      96           8 :         virusfilter_io_set_writel_eol(io_h, "\x0A", 1);
      97           8 :         virusfilter_io_set_readl_eol(io_h, "\x0A", 1);
      98             : 
      99           8 :         return io_h;
     100             : }
     101             : 
     102           8 : int virusfilter_io_set_connect_timeout(
     103             :         struct virusfilter_io_handle *io_h,
     104             :         int timeout)
     105             : {
     106           8 :         int timeout_old = io_h->connect_timeout;
     107             : 
     108             :         /* timeout <= 0 means infinite */
     109           8 :         io_h->connect_timeout = (timeout > 0) ? timeout : -1;
     110             : 
     111           8 :         return timeout_old;
     112             : }
     113             : 
     114           8 : int virusfilter_io_set_io_timeout(
     115             :         struct virusfilter_io_handle *io_h,
     116             :         int timeout)
     117             : {
     118           8 :         int timeout_old = io_h->io_timeout;
     119             : 
     120             :         /* timeout <= 0 means infinite */
     121           8 :         io_h->io_timeout = (timeout > 0) ? timeout : -1;
     122             : 
     123           8 :         return timeout_old;
     124             : }
     125             : 
     126           8 : void virusfilter_io_set_writel_eol(
     127             :         struct virusfilter_io_handle *io_h,
     128             :         const char *eol,
     129             :         int eol_size)
     130             : {
     131           8 :         if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
     132           0 :                 return;
     133             :         }
     134             : 
     135           8 :         memcpy(io_h->w_eol, eol, eol_size);
     136           8 :         io_h->w_eol_size = eol_size;
     137             : }
     138             : 
     139           8 : void virusfilter_io_set_readl_eol(
     140             :         struct virusfilter_io_handle *io_h,
     141             :         const char *eol,
     142             :         int eol_size)
     143             : {
     144           8 :         if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
     145           0 :                 return;
     146             :         }
     147             : 
     148           8 :         memcpy(io_h->r_eol, eol, eol_size);
     149           8 :         io_h->r_eol_size = eol_size;
     150             : }
     151             : 
     152           0 : bool virusfilter_io_connect_path(
     153             :         struct virusfilter_io_handle *io_h,
     154             :         const char *path)
     155             : {
     156             :         struct sockaddr_un addr;
     157             :         NTSTATUS status;
     158             :         int socket, ret;
     159             :         size_t len;
     160             :         bool ok;
     161             : 
     162           0 :         ZERO_STRUCT(addr);
     163           0 :         addr.sun_family = AF_UNIX;
     164             : 
     165           0 :         len = strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
     166           0 :         if (len >= sizeof(addr.sun_path)) {
     167           0 :                 io_h->stream = NULL;
     168           0 :                 return false;
     169             :         }
     170             : 
     171           0 :         status = open_socket_out((struct sockaddr_storage *)&addr, 0,
     172             :                                  io_h->connect_timeout,
     173             :                                  &socket);
     174           0 :         if (!NT_STATUS_IS_OK(status)) {
     175           0 :                 io_h->stream = NULL;
     176           0 :                 return false;
     177             :         }
     178             : 
     179             :         /* We must not block */
     180           0 :         ret = set_blocking(socket, false);
     181           0 :         if (ret == -1) {
     182           0 :                 close(socket);
     183           0 :                 io_h->stream = NULL;
     184           0 :                 return false;
     185             :         }
     186             : 
     187           0 :         ok = smb_set_close_on_exec(socket);
     188           0 :         if (!ok) {
     189           0 :                 close(socket);
     190           0 :                 io_h->stream = NULL;
     191           0 :                 return false;
     192             :         }
     193             : 
     194           0 :         ret = tstream_bsd_existing_socket(io_h, socket, &io_h->stream);
     195           0 :         if (ret == -1) {
     196           0 :                 close(socket);
     197           0 :                 DBG_ERR("Could not convert socket to tstream: %s.\n",
     198             :                         strerror(errno));
     199           0 :                 io_h->stream = NULL;
     200           0 :                 return false;
     201             :         }
     202             : 
     203           0 :         return true;
     204             : }
     205             : 
     206           0 : static void disconnect_done(struct tevent_req *req)
     207             : {
     208           0 :         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
     209             :         int ret;
     210             :         int err_ret;
     211             : 
     212           0 :         ret = tstream_disconnect_recv(req, &err_ret);
     213           0 :         TALLOC_FREE(req);
     214           0 :         if (ret == -1) {
     215           0 :                 *perr = err_ret;
     216             :         }
     217           0 : }
     218             : 
     219           8 : bool virusfilter_io_disconnect(
     220             :         struct virusfilter_io_handle *io_h)
     221             : {
     222             :         struct tevent_req *req;
     223             :         struct tevent_context *ev;
     224           8 :         uint64_t *perror = NULL;
     225           8 :         bool ok = true;
     226           8 :         TALLOC_CTX *frame = talloc_stackframe();
     227             : 
     228           8 :         if (io_h->stream == NULL) {
     229           8 :                 io_h->r_len = 0;
     230           8 :                 TALLOC_FREE(frame);
     231           8 :                 return VIRUSFILTER_RESULT_OK;
     232             :         }
     233             : 
     234           0 :         ev = tevent_context_init(frame);
     235           0 :         if (ev == NULL) {
     236           0 :                 DBG_ERR("Failed to setup event context.\n");
     237           0 :                 ok = false;
     238           0 :                 goto fail;
     239             :         }
     240             : 
     241             :         /* Error return - must be talloc'ed. */
     242           0 :         perror = talloc_zero(frame, uint64_t);
     243           0 :         if (perror == NULL) {
     244           0 :                 goto fail;
     245             :         }
     246             : 
     247           0 :         req = tstream_disconnect_send(io_h, ev, io_h->stream);
     248             : 
     249             :         /* Callback when disconnect is done. */
     250           0 :         tevent_req_set_callback(req, disconnect_done, perror);
     251             : 
     252             :         /* Set timeout. */
     253           0 :         ok = tevent_req_set_endtime(req, ev, timeval_current_ofs_msec(
     254           0 :                                     io_h->connect_timeout));
     255           0 :         if (!ok) {
     256           0 :                 DBG_ERR("Can't set endtime\n");
     257           0 :                 goto fail;
     258             :         }
     259             : 
     260             :         /* Loop waiting for req to finish. */
     261           0 :         ok = tevent_req_poll(req, ev);
     262           0 :         if (!ok) {
     263           0 :                 DBG_ERR("tevent_req_poll failed\n");
     264           0 :                 goto fail;
     265             :         }
     266             : 
     267             :         /* Emit debug error if failed. */
     268           0 :         if (*perror != 0) {
     269           0 :                 DBG_DEBUG("Error %s\n", strerror((int)*perror));
     270           0 :                 goto fail;
     271             :         }
     272             : 
     273             :         /* Here we know we disconnected. */
     274             : 
     275           0 :         io_h->stream = NULL;
     276           0 :         io_h->r_len = 0;
     277             : 
     278           0 :         fail:
     279           0 :                 TALLOC_FREE(frame);
     280           0 :                 return ok;
     281             : }
     282             : 
     283           0 : static void writev_done(struct tevent_req *req)
     284             : {
     285           0 :         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
     286             :         int ret;
     287             :         int err_ret;
     288             : 
     289           0 :         ret = tstream_writev_recv(req, &err_ret);
     290           0 :         TALLOC_FREE(req);
     291           0 :         if (ret == -1) {
     292           0 :                 *perr = err_ret;
     293             :         }
     294           0 : }
     295             : 
     296             : /****************************************************************************
     297             :  Write all data from an iov array, with msec timeout (per write)
     298             :  NB. This can be called with a non-socket fd, don't add dependencies
     299             :  on socket calls.
     300             : ****************************************************************************/
     301             : 
     302           0 : bool write_data_iov_timeout(
     303             :         struct tstream_context *stream,
     304             :         const struct iovec *iov,
     305             :         size_t iovcnt,
     306             :         int ms_timeout)
     307             : {
     308           0 :         struct tevent_context *ev = NULL;
     309           0 :         struct tevent_req *req = NULL;
     310           0 :         uint64_t *perror = NULL;
     311           0 :         bool ok = false;
     312           0 :         TALLOC_CTX *frame = talloc_stackframe();
     313             : 
     314           0 :         ev = tevent_context_init(frame);
     315           0 :         if (ev == NULL) {
     316           0 :                 DBG_ERR("Failed to setup event context.\n");
     317           0 :                 goto fail;
     318             :         }
     319             : 
     320             :         /* Error return - must be talloc'ed. */
     321           0 :         perror = talloc_zero(frame, uint64_t);
     322           0 :         if (perror == NULL) {
     323           0 :                 goto fail;
     324             :         }
     325             : 
     326             :         /* Send the data. */
     327           0 :         req = tstream_writev_send(frame, ev, stream, iov, iovcnt);
     328           0 :         if (req == NULL) {
     329           0 :                 DBG_ERR("Out of memory.\n");
     330           0 :                 goto fail;
     331             :         }
     332             : 
     333             :         /* Callback when *all* data sent. */
     334           0 :         tevent_req_set_callback(req, writev_done, perror);
     335             : 
     336             :         /* Set timeout. */
     337           0 :         ok = tevent_req_set_endtime(req, ev,
     338             :                                     timeval_current_ofs_msec(ms_timeout));
     339           0 :         if (!ok) {
     340           0 :                 DBG_ERR("Can't set endtime\n");
     341           0 :                 goto fail;
     342             :         }
     343             : 
     344             :         /* Loop waiting for req to finish. */
     345           0 :         ok = tevent_req_poll(req, ev);
     346           0 :         if (!ok) {
     347           0 :                 DBG_ERR("tevent_req_poll failed\n");
     348           0 :                 goto fail;
     349             :         }
     350             : 
     351             :         /* Done with req - freed by the callback. */
     352           0 :         req = NULL;
     353             : 
     354             :         /* Emit debug error if failed. */
     355           0 :         if (*perror != 0) {
     356           0 :                 DBG_DEBUG("Error %s\n", strerror((int)*perror));
     357           0 :                 goto fail;
     358             :         }
     359             : 
     360             :         /* Here we know we correctly wrote all data. */
     361           0 :         TALLOC_FREE(frame);
     362           0 :         return true;
     363             : 
     364           0 :   fail:
     365           0 :         TALLOC_FREE(frame);
     366           0 :         return false;
     367             : }
     368             : 
     369           0 : bool virusfilter_io_write(
     370             :         struct virusfilter_io_handle *io_h,
     371             :         const char *data,
     372             :         size_t data_size)
     373             : {
     374             :         struct iovec iov;
     375             : 
     376           0 :         if (data_size == 0) {
     377           0 :                 return VIRUSFILTER_RESULT_OK;
     378             :         }
     379             : 
     380           0 :         iov.iov_base = discard_const_p(void, data);
     381           0 :         iov.iov_len = data_size;
     382             : 
     383           0 :         return write_data_iov_timeout(io_h->stream, &iov, 1, io_h->io_timeout);
     384             : }
     385             : 
     386           0 : bool virusfilter_io_writel(
     387             :         struct virusfilter_io_handle *io_h,
     388             :         const char *data,
     389             :         size_t data_size)
     390             : {
     391             :         bool ok;
     392             : 
     393           0 :         ok = virusfilter_io_write(io_h, data, data_size);
     394           0 :         if (!ok) {
     395           0 :                 return ok;
     396             :         }
     397             : 
     398           0 :         return virusfilter_io_write(io_h, io_h->w_eol, io_h->w_eol_size);
     399             : }
     400             : 
     401           0 : bool PRINTF_ATTRIBUTE(2, 3) virusfilter_io_writefl(
     402             :         struct virusfilter_io_handle *io_h,
     403             :         const char *data_fmt, ...)
     404             : {
     405             :         va_list ap;
     406             :         char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
     407             :         int data_size;
     408             : 
     409           0 :         va_start(ap, data_fmt);
     410           0 :         data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
     411           0 :         va_end(ap);
     412             : 
     413           0 :         if (unlikely (data_size < 0)) {
     414           0 :                 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
     415           0 :                 return false;
     416             :         }
     417             : 
     418           0 :         memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
     419           0 :         data_size += io_h->w_eol_size;
     420             : 
     421           0 :         return virusfilter_io_write(io_h, data, data_size);
     422             : }
     423             : 
     424           0 : bool PRINTF_ATTRIBUTE(2, 0) virusfilter_io_vwritefl(
     425             :         struct virusfilter_io_handle *io_h,
     426             :         const char *data_fmt, va_list ap)
     427             : {
     428             :         char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
     429             :         int data_size;
     430             : 
     431           0 :         data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
     432             : 
     433           0 :         if (unlikely (data_size < 0)) {
     434           0 :                 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
     435           0 :                 return false;
     436             :         }
     437             : 
     438           0 :         memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
     439           0 :         data_size += io_h->w_eol_size;
     440             : 
     441           0 :         return virusfilter_io_write(io_h, data, data_size);
     442             : }
     443             : 
     444           0 : bool virusfilter_io_writev(
     445             :         struct virusfilter_io_handle *io_h, ...)
     446             : {
     447             :         va_list ap;
     448             :         struct iovec iov[VIRUSFILTER_IO_IOV_MAX], *iov_p;
     449             :         int iov_n;
     450             : 
     451           0 :         va_start(ap, io_h);
     452           0 :         for (iov_p = iov, iov_n = 0;
     453           0 :              iov_n < VIRUSFILTER_IO_IOV_MAX;
     454           0 :              iov_p++, iov_n++)
     455             :         {
     456           0 :                 iov_p->iov_base = va_arg(ap, void *);
     457           0 :                 if (iov_p->iov_base == NULL) {
     458           0 :                         break;
     459             :                 }
     460           0 :                 iov_p->iov_len = va_arg(ap, int);
     461             :         }
     462           0 :         va_end(ap);
     463             : 
     464           0 :         return write_data_iov_timeout(io_h->stream, iov, iov_n,
     465             :                 io_h->io_timeout);
     466             : }
     467             : 
     468           0 : bool virusfilter_io_writevl(
     469             :         struct virusfilter_io_handle *io_h, ...)
     470             : {
     471             :         va_list ap;
     472             :         struct iovec iov[VIRUSFILTER_IO_IOV_MAX + 1], *iov_p;
     473             :         int iov_n;
     474             : 
     475           0 :         va_start(ap, io_h);
     476           0 :         for (iov_p = iov, iov_n = 0; iov_n < VIRUSFILTER_IO_IOV_MAX;
     477           0 :              iov_p++, iov_n++)
     478             :         {
     479           0 :                 iov_p->iov_base = va_arg(ap, void *);
     480           0 :                 if (iov_p->iov_base == NULL) {
     481           0 :                         break;
     482             :                 }
     483           0 :                 iov_p->iov_len = va_arg(ap, int);
     484             :         }
     485           0 :         va_end(ap);
     486             : 
     487           0 :         iov_p->iov_base = io_h->r_eol;
     488           0 :         iov_p->iov_len = io_h->r_eol_size;
     489           0 :         iov_n++;
     490             : 
     491           0 :         return write_data_iov_timeout(io_h->stream, iov, iov_n,
     492             :                 io_h->io_timeout);
     493             : }
     494             : 
     495           0 : static bool return_existing_line(TALLOC_CTX *ctx,
     496             :                                 struct virusfilter_io_handle *io_h,
     497             :                                 char **read_line)
     498             : {
     499           0 :         size_t read_line_len = 0;
     500           0 :         char *end_p = NULL;
     501           0 :         char *eol = NULL;
     502             : 
     503           0 :         eol = memmem(io_h->r_buffer, io_h->r_len,
     504           0 :                         io_h->r_eol, io_h->r_eol_size);
     505           0 :         if (eol == NULL) {
     506           0 :                 return false;
     507             :         }
     508           0 :         end_p = eol + io_h->r_eol_size;
     509             : 
     510           0 :         *eol = '\0';
     511           0 :         read_line_len = strlen(io_h->r_buffer) + 1;
     512           0 :         *read_line = talloc_memdup(ctx,
     513             :                                 io_h->r_buffer,
     514             :                                 read_line_len);
     515           0 :         if (*read_line == NULL) {
     516           0 :                 return false;
     517             :         }
     518             : 
     519             :         /*
     520             :          * Copy the remaining buffer over the line
     521             :          * we returned.
     522             :          */
     523           0 :         memmove(io_h->r_buffer,
     524             :                 end_p,
     525           0 :                 io_h->r_len - (end_p - io_h->r_buffer));
     526             : 
     527             :         /* And reduce the size left in the buffer. */
     528           0 :         io_h->r_len -= (end_p - io_h->r_buffer);
     529           0 :         return true;
     530             : }
     531             : 
     532           0 : static void readv_done(struct tevent_req *req)
     533             : {
     534           0 :         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
     535             :         int ret;
     536             :         int err_ret;
     537             : 
     538           0 :         ret = tstream_readv_recv(req, &err_ret);
     539           0 :         TALLOC_FREE(req);
     540           0 :         if (ret == -1) {
     541           0 :                 *perr = err_ret;
     542             :         }
     543           0 : }
     544             : 
     545           0 : bool virusfilter_io_readl(TALLOC_CTX *ctx,
     546             :                         struct virusfilter_io_handle *io_h,
     547             :                         char **read_line)
     548             : {
     549           0 :         struct tevent_context *ev = NULL;
     550           0 :         bool ok = false;
     551           0 :         uint64_t *perror = NULL;
     552           0 :         TALLOC_CTX *frame = talloc_stackframe();
     553             : 
     554             :         /* Search for an existing complete line. */
     555           0 :         ok = return_existing_line(ctx, io_h, read_line);
     556           0 :         if (ok) {
     557           0 :                 goto finish;
     558             :         }
     559             : 
     560             :         /*
     561             :          * No complete line in the buffer. We must read more
     562             :          * from the server.
     563             :          */
     564           0 :         ev = tevent_context_init(frame);
     565           0 :         if (ev == NULL) {
     566           0 :                 DBG_ERR("Failed to setup event context.\n");
     567           0 :                 goto finish;
     568             :         }
     569             : 
     570             :         /* Error return - must be talloc'ed. */
     571           0 :         perror = talloc_zero(frame, uint64_t);
     572           0 :         if (perror == NULL) {
     573           0 :                 goto finish;
     574             :         }
     575             : 
     576           0 :         for (;;) {
     577           0 :                 ssize_t pending = 0;
     578           0 :                 size_t read_size = 0;
     579             :                 struct iovec iov;
     580           0 :                 struct tevent_req *req = NULL;
     581             : 
     582             :                 /*
     583             :                  * How much can we read ?
     584             :                  */
     585           0 :                 pending = tstream_pending_bytes(io_h->stream);
     586           0 :                 if (pending < 0) {
     587           0 :                         DBG_ERR("tstream_pending_bytes failed (%s).\n",
     588             :                                 strerror(errno));
     589           0 :                         goto finish;
     590             :                 }
     591             : 
     592           0 :                 read_size = pending;
     593             :                 /* Must read at least one byte. */
     594           0 :                 read_size = MIN(read_size, 1);
     595             : 
     596             :                 /* And max remaining buffer space. */
     597           0 :                 read_size = MAX(read_size,
     598             :                                 (sizeof(io_h->r_buffer) - io_h->r_len));
     599             : 
     600           0 :                 if (read_size == 0) {
     601             :                         /* Buffer is full with no EOL. Error out. */
     602           0 :                         DBG_ERR("Line buffer full.\n");
     603           0 :                         goto finish;
     604             :                 }
     605             : 
     606           0 :                 iov.iov_base = io_h->r_buffer + io_h->r_len;
     607           0 :                 iov.iov_len = read_size;
     608             : 
     609             :                 /* Read the data. */
     610           0 :                 req = tstream_readv_send(frame,
     611             :                                         ev,
     612             :                                         io_h->stream,
     613             :                                         &iov,
     614             :                                         1);
     615           0 :                 if (req == NULL) {
     616           0 :                         DBG_ERR("out of memory.\n");
     617           0 :                         goto finish;
     618             :                 }
     619             : 
     620             :                 /* Callback when *all* data read. */
     621           0 :                 tevent_req_set_callback(req, readv_done, perror);
     622             : 
     623             :                 /* Set timeout. */
     624           0 :                 ok = tevent_req_set_endtime(req, ev,
     625           0 :                                 timeval_current_ofs_msec(io_h->io_timeout));
     626           0 :                 if (!ok) {
     627           0 :                         DBG_ERR("can't set endtime\n");
     628           0 :                         goto finish;
     629             :                 }
     630             : 
     631             :                 /* Loop waiting for req to finish. */
     632           0 :                 ok = tevent_req_poll(req, ev);
     633           0 :                 if (!ok) {
     634           0 :                         DBG_ERR("tevent_req_poll failed\n");
     635           0 :                         goto finish;
     636             :                 }
     637             : 
     638             :                 /* Done with req - freed by the callback. */
     639           0 :                 req = NULL;
     640             : 
     641             :                 /*
     642             :                  * Emit debug error if failed.
     643             :                  * EPIPE may be success so, don't exit.
     644             :                  */
     645           0 :                 if (*perror != 0 && *perror != EPIPE) {
     646           0 :                         DBG_DEBUG("Error %s\n", strerror((int)*perror));
     647           0 :                         errno = (int)*perror;
     648           0 :                         goto finish;
     649             :                 }
     650             : 
     651             :                 /*
     652             :                  * We read read_size bytes. Extend the usable
     653             :                  * buffer length.
     654             :                  */
     655           0 :                 io_h->r_len += read_size;
     656             : 
     657             :                 /* Paranoia... */
     658           0 :                 SMB_ASSERT(io_h->r_len <= sizeof(io_h->r_buffer));
     659             : 
     660             :                 /* Exit if we have a line to return. */
     661           0 :                 ok = return_existing_line(ctx, io_h, read_line);
     662           0 :                 if (ok) {
     663           0 :                         goto finish;
     664             :                 }
     665             :                 /* No eol - keep reading. */
     666             :         }
     667             : 
     668           0 :   finish:
     669             : 
     670           0 :         TALLOC_FREE(frame);
     671           0 :         return ok;
     672             : }
     673             : 
     674           0 : bool PRINTF_ATTRIBUTE(3, 4) virusfilter_io_writefl_readl(
     675             :         struct virusfilter_io_handle *io_h,
     676             :         char **read_line,
     677             :         const char *fmt, ...)
     678             : {
     679             :         bool ok;
     680             : 
     681           0 :         if (fmt) {
     682             :                 va_list ap;
     683             : 
     684           0 :                 va_start(ap, fmt);
     685           0 :                 ok = virusfilter_io_vwritefl(io_h, fmt, ap);
     686           0 :                 va_end(ap);
     687             : 
     688           0 :                 if (!ok) {
     689           0 :                         return ok;
     690             :                 }
     691             :         }
     692             : 
     693           0 :         ok = virusfilter_io_readl(talloc_tos(), io_h, read_line);
     694           0 :         if (!ok) {
     695           0 :                 DBG_ERR("virusfilter_io_readl not OK: %d\n", ok);
     696           0 :                 return false;
     697             :         }
     698           0 :         if (io_h->r_len == 0) { /* EOF */
     699           0 :                 DBG_ERR("virusfilter_io_readl EOF\n");
     700           0 :                 return false;
     701             :         }
     702             : 
     703           0 :         return true;
     704             : }
     705             : 
     706           8 : struct virusfilter_cache *virusfilter_cache_new(
     707             :         TALLOC_CTX *ctx,
     708             :         int entry_limit,
     709             :         time_t time_limit)
     710             : {
     711             :         struct virusfilter_cache *cache;
     712             : 
     713           8 :         if (time_limit == 0) {
     714           0 :                 return NULL;
     715             :         }
     716             : 
     717           8 :         cache = talloc_zero(ctx, struct virusfilter_cache);
     718           8 :         if (cache == NULL) {
     719           0 :                 DBG_ERR("talloc_zero failed.\n");
     720           0 :                 return NULL;
     721             :         }
     722             : 
     723           8 :         cache->cache = memcache_init(cache->ctx, entry_limit *
     724             :                                        (sizeof(struct virusfilter_cache_entry)
     725             :                                        + VIRUSFILTER_CACHE_BUFFER_SIZE));
     726           8 :         if (cache->cache == NULL) {
     727           0 :                 DBG_ERR("memcache_init failed.\n");
     728           0 :                 return NULL;
     729             :         }
     730           8 :         cache->ctx = ctx;
     731           8 :         cache->time_limit = time_limit;
     732             : 
     733           8 :         return cache;
     734             : }
     735             : 
     736           4 : bool virusfilter_cache_entry_add(
     737             :         struct virusfilter_cache *cache,
     738             :         const char *directory,
     739             :         const char *fname,
     740             :         virusfilter_result result,
     741             :         char *report)
     742             : {
     743           4 :         int blob_size = sizeof(struct virusfilter_cache_entry);
     744           4 :         struct virusfilter_cache_entry *cache_e =
     745           4 :                                         talloc_zero_size(NULL, blob_size);
     746           4 :         int fname_len = 0;
     747             : 
     748           4 :         if (fname == NULL || directory == NULL) {
     749           0 :                 TALLOC_FREE(report);
     750           0 :                 return false;
     751             :         }
     752             : 
     753           4 :         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
     754             : 
     755           4 :         if (fname == NULL) {
     756           0 :                 TALLOC_FREE(report);
     757           0 :                 return false;
     758             :         }
     759             : 
     760           4 :         fname_len = strlen(fname);
     761             : 
     762           4 :         if (cache_e == NULL|| cache->time_limit == 0) {
     763           0 :                 TALLOC_FREE(report);
     764           0 :                 return false;
     765             :         }
     766             : 
     767           4 :         cache_e->result = result;
     768           4 :         if (report != NULL) {
     769           0 :                 cache_e->report = talloc_steal(cache_e, report);
     770             :         }
     771           4 :         if (cache->time_limit > 0) {
     772           4 :                 cache_e->time = time(NULL);
     773             :         }
     774             : 
     775           4 :         memcache_add_talloc(cache->cache,
     776             :                             VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     777             :                             data_blob_const(fname, fname_len), &cache_e);
     778             : 
     779           4 :         return true;
     780             : }
     781             : 
     782           0 : bool virusfilter_cache_entry_rename(
     783             :         struct virusfilter_cache *cache,
     784             :         const char *directory,
     785             :         char *old_fname,
     786             :         char *new_fname)
     787             : {
     788           0 :         int old_fname_len = 0;
     789           0 :         int new_fname_len = 0;
     790           0 :         struct virusfilter_cache_entry *new_data = NULL;
     791           0 :         struct virusfilter_cache_entry *old_data = NULL;
     792             : 
     793           0 :         if (old_fname == NULL || new_fname == NULL || directory == NULL) {
     794           0 :                 return false;
     795             :         }
     796             : 
     797           0 :         old_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, old_fname);
     798           0 :         new_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, new_fname);
     799             : 
     800           0 :         if (old_fname == NULL || new_fname == NULL) {
     801           0 :                 TALLOC_FREE(old_fname);
     802           0 :                 TALLOC_FREE(new_fname);
     803           0 :                 return false;
     804             :         }
     805             : 
     806           0 :         old_fname_len = strlen(old_fname);
     807           0 :         new_fname_len = strlen(new_fname);
     808             : 
     809           0 :         old_data = memcache_lookup_talloc(
     810             :                                 cache->cache,
     811             :                                 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     812             :                                 data_blob_const(old_fname, old_fname_len));
     813             : 
     814           0 :         if (old_data == NULL) {
     815           0 :                 return false;
     816             :         }
     817             : 
     818           0 :         new_data = talloc_memdup(cache->ctx, old_data,
     819             :                                  sizeof(struct virusfilter_cache_entry));
     820           0 :         if (new_data == NULL) {
     821           0 :                 return false;
     822             :         }
     823           0 :         new_data->report = talloc_strdup(new_data, old_data->report);
     824             : 
     825           0 :         memcache_add_talloc(cache->cache,
     826             :                         VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     827             :                         data_blob_const(new_fname, new_fname_len), &new_data);
     828             : 
     829           0 :         memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     830             :                         data_blob_const(old_fname, old_fname_len));
     831             : 
     832           0 :         return true;
     833             : }
     834             : 
     835           0 : void virusfilter_cache_purge(struct virusfilter_cache *cache)
     836             : {
     837           0 :         memcache_flush(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC);
     838           0 : }
     839             : 
     840           8 : struct virusfilter_cache_entry *virusfilter_cache_get(
     841             :         struct virusfilter_cache *cache,
     842             :         const char *directory,
     843             :         const char *fname)
     844             : {
     845           8 :         int fname_len = 0;
     846           8 :         struct virusfilter_cache_entry *cache_e = NULL;
     847           8 :         struct virusfilter_cache_entry *data = NULL;
     848             : 
     849           8 :         if (fname == NULL || directory == NULL) {
     850           0 :                 return 0;
     851             :         }
     852             : 
     853           8 :         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
     854             : 
     855           8 :         if (fname == NULL) {
     856           0 :                 return 0;
     857             :         }
     858             : 
     859           8 :         fname_len = strlen(fname);
     860             : 
     861           8 :         data = memcache_lookup_talloc(cache->cache,
     862             :                                       VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     863             :                                       data_blob_const(fname, fname_len));
     864             : 
     865           8 :         if (data == NULL) {
     866           8 :                 return cache_e;
     867             :         }
     868             : 
     869           0 :         if (cache->time_limit > 0) {
     870           0 :                 if (time(NULL) - data->time  > cache->time_limit) {
     871           0 :                         DBG_DEBUG("Cache entry is too old: %s\n",
     872             :                                   fname);
     873           0 :                         virusfilter_cache_remove(cache, directory, fname);
     874           0 :                         return cache_e;
     875             :                 }
     876             :         }
     877           0 :         cache_e = talloc_memdup(cache->ctx, data,
     878             :                                sizeof(struct virusfilter_cache_entry));
     879           0 :         if (cache_e == NULL) {
     880           0 :                 return NULL;
     881             :         }
     882           0 :         if (data->report != NULL) {
     883           0 :                 cache_e->report = talloc_strdup(cache_e, data->report);
     884             :         } else {
     885           0 :                 cache_e->report = NULL;
     886             :         }
     887             : 
     888           0 :         return cache_e;
     889             : }
     890             : 
     891           0 : void virusfilter_cache_remove(struct virusfilter_cache *cache,
     892             :         const char *directory,
     893             :         const char *fname)
     894             : {
     895           0 :         DBG_DEBUG("Purging cache entry: %s/%s\n", directory, fname);
     896             : 
     897           0 :         if (fname == NULL || directory == NULL) {
     898           0 :                 return;
     899             :         }
     900             : 
     901           0 :         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
     902             : 
     903           0 :         if (fname == NULL) {
     904           0 :                 return;
     905             :         }
     906             : 
     907           0 :         memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
     908             :                         data_blob_const(fname, strlen(fname)));
     909             : }
     910             : 
     911           0 : void virusfilter_cache_entry_free(struct virusfilter_cache_entry *cache_e)
     912             : {
     913           0 :         if (cache_e != NULL) {
     914           0 :                 TALLOC_FREE(cache_e->report);
     915           0 :                 cache_e->report = NULL;
     916             :         }
     917           0 :         TALLOC_FREE(cache_e);
     918           0 : }
     919             : 
     920             : /* Shell scripting
     921             :  * ======================================================================
     922             :  */
     923             : 
     924           0 : int virusfilter_env_set(
     925             :         TALLOC_CTX *mem_ctx,
     926             :         char **env_list,
     927             :         const char *name,
     928             :         const char *value)
     929             : {
     930             :         char *env_new;
     931             :         int ret;
     932             : 
     933           0 :         env_new = talloc_asprintf(mem_ctx, "%s=%s", name, value);
     934           0 :         if (env_new == NULL) {
     935           0 :                 DBG_ERR("talloc_asprintf failed\n");
     936           0 :                 return -1;
     937             :         }
     938             : 
     939           0 :         ret = strv_add(mem_ctx, env_list, env_new);
     940             : 
     941           0 :         TALLOC_FREE(env_new);
     942             : 
     943           0 :         return ret;
     944             : }
     945             : 
     946             : /* virusfilter_env version Samba's *_sub_advanced() in substitute.c */
     947           0 : int virusfilter_shell_set_conn_env(
     948             :         TALLOC_CTX *mem_ctx,
     949             :         char **env_list,
     950             :         connection_struct *conn)
     951             : {
     952           0 :         int snum = SNUM(conn);
     953             :         char *server_addr_p;
     954             :         char *client_addr_p;
     955           0 :         const char *local_machine_name = get_local_machine_name();
     956             :         fstring pidstr;
     957             :         int ret;
     958             : 
     959           0 :         server_addr_p = tsocket_address_inet_addr_string(
     960           0 :                                 conn->sconn->local_address, talloc_tos());
     961             : 
     962           0 :         if (server_addr_p != NULL) {
     963           0 :                 ret = strncmp("::ffff:", server_addr_p, 7);
     964           0 :                 if (ret == 0) {
     965           0 :                         server_addr_p += 7;
     966             :                 }
     967           0 :                 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_IP",
     968             :                                     server_addr_p);
     969             :         }
     970           0 :         TALLOC_FREE(server_addr_p);
     971             : 
     972           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_NAME",
     973           0 :                             myhostname());
     974           0 :         virusfilter_env_set(mem_ctx, env_list,
     975             :                             "VIRUSFILTER_SERVER_NETBIOS_NAME",
     976             :                             local_machine_name);
     977           0 :         slprintf(pidstr,sizeof(pidstr)-1, "%ld", (long)getpid());
     978           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_PID",
     979             :                             pidstr);
     980             : 
     981           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVICE_NAME",
     982             :                             lp_const_servicename(snum));
     983           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVICE_PATH",
     984           0 :                             conn->cwd_fsp->fsp_name->base_name);
     985             : 
     986           0 :         client_addr_p = tsocket_address_inet_addr_string(
     987           0 :                                 conn->sconn->remote_address, talloc_tos());
     988             : 
     989           0 :         if (client_addr_p != NULL) {
     990           0 :                 ret = strncmp("::ffff:", client_addr_p, 7);
     991           0 :                 if (ret == 0) {
     992           0 :                         client_addr_p += 7;
     993             :                 }
     994           0 :                 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_CLIENT_IP",
     995             :                                     client_addr_p);
     996             :         }
     997           0 :         TALLOC_FREE(client_addr_p);
     998             : 
     999           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_CLIENT_NAME",
    1000           0 :                             conn->sconn->remote_hostname);
    1001           0 :         virusfilter_env_set(mem_ctx, env_list,
    1002             :                             "VIRUSFILTER_CLIENT_NETBIOS_NAME",
    1003             :                             get_remote_machine_name());
    1004             : 
    1005           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_USER_NAME",
    1006             :                             get_current_username());
    1007           0 :         virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_USER_DOMAIN",
    1008             :                             get_current_user_info_domain());
    1009             : 
    1010           0 :         return 0;
    1011             : }
    1012             : 
    1013             : /* Wrapper to Samba's smbrun() in smbrun.c */
    1014           0 : int virusfilter_shell_run(
    1015             :         TALLOC_CTX *mem_ctx,
    1016             :         const char *cmd,
    1017             :         char **env_list,
    1018             :         connection_struct *conn,
    1019             :         bool sanitize)
    1020             : {
    1021             :         int ret;
    1022             : 
    1023           0 :         if (conn != NULL) {
    1024           0 :                 ret = virusfilter_shell_set_conn_env(mem_ctx, env_list, conn);
    1025           0 :                 if (ret == -1) {
    1026           0 :                         return -1;
    1027             :                 }
    1028             :         }
    1029             : 
    1030           0 :         if (sanitize) {
    1031           0 :                 return smbrun(cmd, NULL, strv_to_env(talloc_tos(), *env_list));
    1032             :         } else {
    1033           0 :                 return smbrun_no_sanitize(cmd, NULL, strv_to_env(talloc_tos(),
    1034             :                                           *env_list));
    1035             :         }
    1036             : }

Generated by: LCOV version 1.14