LCOV - code coverage report
Current view: top level - source3/modules - vfs_virusfilter_utils.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 0 460 0.0 %
Date: 2021-09-23 10:06:22 Functions: 0 32 0.0 %

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

Generated by: LCOV version 1.13