s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / modules / vfs_virusfilter_utils.c
blob90ae427023be53c2805439f08b3806c598b35e73
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
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.
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.
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/>.
20 #include "modules/vfs_virusfilter_common.h"
21 #include "modules/vfs_virusfilter_utils.h"
23 struct iovec;
25 #include "lib/util/iov_buf.h"
26 #include <tevent.h>
27 #include "lib/tsocket/tsocket.h"
29 int virusfilter_debug_class = DBGC_VFS;
31 /* ====================================================================== */
33 char *virusfilter_string_sub(
34 TALLOC_CTX *mem_ctx,
35 connection_struct *conn,
36 const char *str)
38 return talloc_sub_advanced(mem_ctx,
39 lp_servicename(mem_ctx, SNUM(conn)),
40 conn->session_info->unix_info->unix_name,
41 conn->connectpath,
42 conn->session_info->unix_token->gid,
43 conn->session_info->unix_info->sanitized_username,
44 conn->session_info->info->domain_name,
45 str);
48 int virusfilter_vfs_next_move(
49 struct vfs_handle_struct *vfs_h,
50 const struct smb_filename *smb_fname_src,
51 const struct smb_filename *smb_fname_dst)
53 int result;
55 result = SMB_VFS_NEXT_RENAME(vfs_h, smb_fname_src, smb_fname_dst);
56 if (result == 0 || errno != EXDEV) {
57 return result;
61 * For now, do not handle EXDEV as poking around violates
62 * stackability. Return -1, simply refuse access.
64 return -1;
67 /* Line-based socket I/O
68 * ======================================================================
71 struct virusfilter_io_handle *virusfilter_io_new(
72 TALLOC_CTX *mem_ctx,
73 int connect_timeout,
74 int io_timeout)
76 struct virusfilter_io_handle *io_h = talloc_zero(mem_ctx,
77 struct virusfilter_io_handle);
79 if (io_h == NULL) {
80 return NULL;
83 io_h->stream = NULL;
84 io_h->r_len = 0;
86 virusfilter_io_set_connect_timeout(io_h, connect_timeout);
87 virusfilter_io_set_io_timeout(io_h, io_timeout);
88 virusfilter_io_set_writel_eol(io_h, "\x0A", 1);
89 virusfilter_io_set_readl_eol(io_h, "\x0A", 1);
91 return io_h;
94 int virusfilter_io_set_connect_timeout(
95 struct virusfilter_io_handle *io_h,
96 int timeout)
98 int timeout_old = io_h->connect_timeout;
100 /* timeout <= 0 means infinite */
101 io_h->connect_timeout = (timeout > 0) ? timeout : -1;
103 return timeout_old;
106 int virusfilter_io_set_io_timeout(
107 struct virusfilter_io_handle *io_h,
108 int timeout)
110 int timeout_old = io_h->io_timeout;
112 /* timeout <= 0 means infinite */
113 io_h->io_timeout = (timeout > 0) ? timeout : -1;
115 return timeout_old;
118 void virusfilter_io_set_writel_eol(
119 struct virusfilter_io_handle *io_h,
120 const char *eol,
121 int eol_size)
123 if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
124 return;
127 memcpy(io_h->w_eol, eol, eol_size);
128 io_h->w_eol_size = eol_size;
131 void virusfilter_io_set_readl_eol(
132 struct virusfilter_io_handle *io_h,
133 const char *eol,
134 int eol_size)
136 if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
137 return;
140 memcpy(io_h->r_eol, eol, eol_size);
141 io_h->r_eol_size = eol_size;
144 bool virusfilter_io_connect_path(
145 struct virusfilter_io_handle *io_h,
146 const char *path)
148 struct sockaddr_un addr;
149 NTSTATUS status;
150 int socket, bes_result, flags, ret;
151 size_t len;
153 ZERO_STRUCT(addr);
154 addr.sun_family = AF_UNIX;
156 len = strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
157 if (len >= sizeof(addr.sun_path)) {
158 io_h->stream = NULL;
159 return false;
162 status = open_socket_out((struct sockaddr_storage *)&addr, 0,
163 io_h->connect_timeout,
164 &socket);
165 if (!NT_STATUS_IS_OK(status)) {
166 io_h->stream = NULL;
167 return false;
170 /* We must not block */
171 flags = fcntl(socket, F_GETFL);
172 if (flags <= 0) {
173 /* Handle error by ignoring */;
174 flags = 0;
175 DBG_WARNING("Could not get flags on socket (%s).\n",
176 strerror(errno));
178 flags |= SOCK_NONBLOCK;
179 ret = fcntl(socket, F_SETFL, flags);
180 if (ret == -1) {
181 /* Handle error by ignoring for now */
182 DBG_WARNING("Could not set flags on socket: %s.\n",
183 strerror(errno));
186 bes_result = tstream_bsd_existing_socket(io_h, socket, &io_h->stream);
187 if (bes_result < 0) {
188 DBG_ERR("Could not convert socket to tstream: %s.\n",
189 strerror(errno));
190 io_h->stream = NULL;
191 return false;
194 return true;
197 static void disconnect_done(struct tevent_req *req)
199 uint64_t *perr = tevent_req_callback_data(req, uint64_t);
200 int ret;
201 int err_ret;
203 ret = tstream_disconnect_recv(req, &err_ret);
204 TALLOC_FREE(req);
205 if (ret == -1) {
206 *perr = err_ret;
210 bool virusfilter_io_disconnect(
211 struct virusfilter_io_handle *io_h)
213 struct tevent_req *req;
214 struct tevent_context *ev;
215 uint64_t *perror = NULL;
216 bool ok = true;
217 TALLOC_CTX *frame = talloc_stackframe();
219 if (io_h->stream == NULL) {
220 io_h->r_len = 0;
221 TALLOC_FREE(frame);
222 return VIRUSFILTER_RESULT_OK;
225 ev = tevent_context_init(frame);
226 if (ev == NULL) {
227 DBG_ERR("Failed to setup event context.\n");
228 ok = false;
229 goto fail;
232 /* Error return - must be talloc'ed. */
233 perror = talloc_zero(frame, uint64_t);
234 if (perror == NULL) {
235 goto fail;
238 req = tstream_disconnect_send(io_h, ev, io_h->stream);
240 /* Callback when disconnect is done. */
241 tevent_req_set_callback(req, disconnect_done, perror);
243 /* Set timeout. */
244 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs_msec(
245 io_h->connect_timeout));
246 if (!ok) {
247 DBG_ERR("Can't set endtime\n");
248 goto fail;
251 /* Loop waiting for req to finish. */
252 ok = tevent_req_poll(req, ev);
253 if (!ok) {
254 DBG_ERR("tevent_req_poll failed\n");
255 goto fail;
258 /* Emit debug error if failed. */
259 if (*perror != 0) {
260 DBG_DEBUG("Error %s\n", strerror((int)*perror));
261 goto fail;
264 /* Here we know we disconnected. */
266 io_h->stream = NULL;
267 io_h->r_len = 0;
269 fail:
270 TALLOC_FREE(frame);
271 return ok;
274 static void writev_done(struct tevent_req *req)
276 uint64_t *perr = tevent_req_callback_data(req, uint64_t);
277 int ret;
278 int err_ret;
280 ret = tstream_writev_recv(req, &err_ret);
281 TALLOC_FREE(req);
282 if (ret == -1) {
283 *perr = err_ret;
287 /****************************************************************************
288 Write all data from an iov array, with msec timeout (per write)
289 NB. This can be called with a non-socket fd, don't add dependencies
290 on socket calls.
291 ****************************************************************************/
293 bool write_data_iov_timeout(
294 struct tstream_context *stream,
295 const struct iovec *iov,
296 size_t iovcnt,
297 int ms_timeout)
299 struct tevent_context *ev = NULL;
300 struct tevent_req *req = NULL;
301 uint64_t *perror = NULL;
302 bool ok = false;
303 TALLOC_CTX *frame = talloc_stackframe();
305 ev = tevent_context_init(frame);
306 if (ev == NULL) {
307 DBG_ERR("Failed to setup event context.\n");
308 goto fail;
311 /* Error return - must be talloc'ed. */
312 perror = talloc_zero(frame, uint64_t);
313 if (perror == NULL) {
314 goto fail;
317 /* Send the data. */
318 req = tstream_writev_send(frame, ev, stream, iov, iovcnt);
319 if (req == NULL) {
320 DBG_ERR("Out of memory.\n");
321 goto fail;
324 /* Callback when *all* data sent. */
325 tevent_req_set_callback(req, writev_done, perror);
327 /* Set timeout. */
328 ok = tevent_req_set_endtime(req, ev,
329 timeval_current_ofs_msec(ms_timeout));
330 if (!ok) {
331 DBG_ERR("Can't set endtime\n");
332 goto fail;
335 /* Loop waiting for req to finish. */
336 ok = tevent_req_poll(req, ev);
337 if (!ok) {
338 DBG_ERR("tevent_req_poll failed\n");
339 goto fail;
342 /* Done with req - freed by the callback. */
343 req = NULL;
345 /* Emit debug error if failed. */
346 if (*perror != 0) {
347 DBG_DEBUG("Error %s\n", strerror((int)*perror));
348 goto fail;
351 /* Here we know we correctly wrote all data. */
352 TALLOC_FREE(frame);
353 return true;
355 fail:
356 TALLOC_FREE(frame);
357 return false;
360 bool virusfilter_io_write(
361 struct virusfilter_io_handle *io_h,
362 const char *data,
363 size_t data_size)
365 struct iovec iov;
367 if (data_size == 0) {
368 return VIRUSFILTER_RESULT_OK;
371 iov.iov_base = discard_const_p(void, data);
372 iov.iov_len = data_size;
374 return write_data_iov_timeout(io_h->stream, &iov, 1, io_h->io_timeout);
377 bool virusfilter_io_writel(
378 struct virusfilter_io_handle *io_h,
379 const char *data,
380 size_t data_size)
382 bool ok;
384 ok = virusfilter_io_write(io_h, data, data_size);
385 if (!ok) {
386 return ok;
389 return virusfilter_io_write(io_h, io_h->w_eol, io_h->w_eol_size);
392 bool virusfilter_io_writefl(
393 struct virusfilter_io_handle *io_h,
394 const char *data_fmt, ...)
396 va_list ap;
397 char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
398 int data_size;
400 va_start(ap, data_fmt);
401 data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
402 va_end(ap);
404 if (unlikely (data_size < 0)) {
405 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
406 return false;
409 memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
410 data_size += io_h->w_eol_size;
412 return virusfilter_io_write(io_h, data, data_size);
415 bool virusfilter_io_vwritefl(
416 struct virusfilter_io_handle *io_h,
417 const char *data_fmt, va_list ap)
419 char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
420 int data_size;
422 data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
424 if (unlikely (data_size < 0)) {
425 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
426 return false;
429 memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
430 data_size += io_h->w_eol_size;
432 return virusfilter_io_write(io_h, data, data_size);
435 bool virusfilter_io_writev(
436 struct virusfilter_io_handle *io_h, ...)
438 va_list ap;
439 struct iovec iov[VIRUSFILTER_IO_IOV_MAX], *iov_p;
440 int iov_n;
442 va_start(ap, io_h);
443 for (iov_p = iov, iov_n = 0;
444 iov_n < VIRUSFILTER_IO_IOV_MAX;
445 iov_p++, iov_n++)
447 iov_p->iov_base = va_arg(ap, void *);
448 if (iov_p->iov_base == NULL) {
449 break;
451 iov_p->iov_len = va_arg(ap, int);
453 va_end(ap);
455 return write_data_iov_timeout(io_h->stream, iov, iov_n,
456 io_h->io_timeout);
459 bool virusfilter_io_writevl(
460 struct virusfilter_io_handle *io_h, ...)
462 va_list ap;
463 struct iovec iov[VIRUSFILTER_IO_IOV_MAX + 1], *iov_p;
464 int iov_n;
466 va_start(ap, io_h);
467 for (iov_p = iov, iov_n = 0; iov_n < VIRUSFILTER_IO_IOV_MAX;
468 iov_p++, iov_n++)
470 iov_p->iov_base = va_arg(ap, void *);
471 if (iov_p->iov_base == NULL) {
472 break;
474 iov_p->iov_len = va_arg(ap, int);
476 va_end(ap);
478 iov_p->iov_base = io_h->r_eol;
479 iov_p->iov_len = io_h->r_eol_size;
480 iov_n++;
482 return write_data_iov_timeout(io_h->stream, iov, iov_n,
483 io_h->io_timeout);
486 static bool return_existing_line(TALLOC_CTX *ctx,
487 struct virusfilter_io_handle *io_h,
488 char **read_line)
490 size_t read_line_len = 0;
491 char *end_p = NULL;
492 char *eol = NULL;
494 eol = memmem(io_h->r_buffer, io_h->r_len,
495 io_h->r_eol, io_h->r_eol_size);
496 if (eol == NULL) {
497 return false;
499 end_p = eol + io_h->r_eol_size;
501 *eol = '\0';
502 read_line_len = strlen(io_h->r_buffer) + 1;
503 *read_line = talloc_memdup(ctx,
504 io_h->r_buffer,
505 read_line_len);
506 if (*read_line == NULL) {
507 return false;
511 * Copy the remaining buffer over the line
512 * we returned.
514 memmove(io_h->r_buffer,
515 end_p,
516 io_h->r_len - (end_p - io_h->r_buffer));
518 /* And reduce the size left in the buffer. */
519 io_h->r_len -= (end_p - io_h->r_buffer);
520 return true;
523 static void readv_done(struct tevent_req *req)
525 uint64_t *perr = tevent_req_callback_data(req, uint64_t);
526 int ret;
527 int err_ret;
529 ret = tstream_readv_recv(req, &err_ret);
530 TALLOC_FREE(req);
531 if (ret == -1) {
532 *perr = err_ret;
536 bool virusfilter_io_readl(TALLOC_CTX *ctx,
537 struct virusfilter_io_handle *io_h,
538 char **read_line)
540 struct tevent_context *ev = NULL;
541 bool ok = false;
542 uint64_t *perror = NULL;
543 TALLOC_CTX *frame = talloc_stackframe();
545 /* Search for an existing complete line. */
546 ok = return_existing_line(ctx, io_h, read_line);
547 if (ok) {
548 goto finish;
552 * No complete line in the buffer. We must read more
553 * from the server.
555 ev = tevent_context_init(frame);
556 if (ev == NULL) {
557 DBG_ERR("Failed to setup event context.\n");
558 goto finish;
561 /* Error return - must be talloc'ed. */
562 perror = talloc_zero(frame, uint64_t);
563 if (perror == NULL) {
564 goto finish;
567 for (;;) {
568 ssize_t pending = 0;
569 size_t read_size = 0;
570 struct iovec iov;
571 struct tevent_req *req = NULL;
574 * How much can we read ?
576 pending = tstream_pending_bytes(io_h->stream);
577 if (pending < 0) {
578 DBG_ERR("tstream_pending_bytes failed (%s).\n",
579 strerror(errno));
580 goto finish;
583 read_size = pending;
584 /* Must read at least one byte. */
585 read_size = MIN(read_size, 1);
587 /* And max remaining buffer space. */
588 read_size = MAX(read_size,
589 (sizeof(io_h->r_buffer) - io_h->r_len));
591 if (read_size == 0) {
592 /* Buffer is full with no EOL. Error out. */
593 DBG_ERR("Line buffer full.\n");
594 goto finish;
597 iov.iov_base = io_h->r_buffer + io_h->r_len;
598 iov.iov_len = read_size;
600 /* Read the data. */
601 req = tstream_readv_send(frame,
603 io_h->stream,
604 &iov,
606 if (req == NULL) {
607 DBG_ERR("out of memory.\n");
608 goto finish;
611 /* Callback when *all* data read. */
612 tevent_req_set_callback(req, readv_done, perror);
614 /* Set timeout. */
615 ok = tevent_req_set_endtime(req, ev,
616 timeval_current_ofs_msec(io_h->io_timeout));
617 if (!ok) {
618 DBG_ERR("can't set endtime\n");
619 goto finish;
622 /* Loop waiting for req to finish. */
623 ok = tevent_req_poll(req, ev);
624 if (!ok) {
625 DBG_ERR("tevent_req_poll failed\n");
626 goto finish;
629 /* Done with req - freed by the callback. */
630 req = NULL;
633 * Emit debug error if failed.
634 * EPIPE may be success so, don't exit.
636 if (*perror != 0 && *perror != EPIPE) {
637 DBG_DEBUG("Error %s\n", strerror((int)*perror));
638 errno = (int)*perror;
639 goto finish;
643 * We read read_size bytes. Extend the useable
644 * buffer length.
646 io_h->r_len += read_size;
648 /* Paranoia... */
649 SMB_ASSERT(io_h->r_len <= sizeof(io_h->r_buffer));
651 /* Exit if we have a line to return. */
652 ok = return_existing_line(ctx, io_h, read_line);
653 if (ok) {
654 goto finish;
656 /* No eol - keep reading. */
659 finish:
661 TALLOC_FREE(frame);
662 return ok;
665 bool virusfilter_io_writefl_readl(
666 struct virusfilter_io_handle *io_h,
667 char **read_line,
668 const char *fmt, ...)
670 bool ok;
672 if (fmt) {
673 va_list ap;
675 va_start(ap, fmt);
676 ok = virusfilter_io_vwritefl(io_h, fmt, ap);
677 va_end(ap);
679 if (!ok) {
680 return ok;
684 ok = virusfilter_io_readl(talloc_tos(), io_h, read_line);
685 if (!ok) {
686 DBG_ERR("virusfilter_io_readl not OK: %d\n", ok);
687 return false;
689 if (io_h->r_len == 0) { /* EOF */
690 DBG_ERR("virusfilter_io_readl EOF\n");
691 return false;
694 return true;
697 struct virusfilter_cache *virusfilter_cache_new(
698 TALLOC_CTX *ctx,
699 int entry_limit,
700 time_t time_limit)
702 struct virusfilter_cache *cache;
704 if (time_limit == 0) {
705 return NULL;
708 cache = talloc_zero(ctx, struct virusfilter_cache);
709 if (cache == NULL) {
710 DBG_ERR("talloc_zero failed.\n");
711 return NULL;
714 cache->cache = memcache_init(cache->ctx, entry_limit *
715 (sizeof(struct virusfilter_cache_entry)
716 + VIRUSFILTER_CACHE_BUFFER_SIZE));
717 if (cache->cache == NULL) {
718 DBG_ERR("memcache_init failed.\n");
719 return NULL;
721 cache->ctx = ctx;
722 cache->time_limit = time_limit;
724 return cache;
727 bool virusfilter_cache_entry_add(
728 struct virusfilter_cache *cache,
729 const char *directory,
730 const char *fname,
731 virusfilter_result result,
732 char *report)
734 int blob_size = sizeof(struct virusfilter_cache_entry);
735 struct virusfilter_cache_entry *cache_e =
736 talloc_zero_size(NULL, blob_size);
737 int fname_len = 0;
739 if (fname == NULL || directory == NULL) {
740 TALLOC_FREE(report);
741 return false;
744 fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
746 if (fname == NULL) {
747 TALLOC_FREE(report);
748 return false;
751 fname_len = strlen(fname);
753 if (cache_e == NULL|| cache->time_limit == 0) {
754 TALLOC_FREE(report);
755 return false;
758 cache_e->result = result;
759 if (report != NULL) {
760 cache_e->report = talloc_steal(cache_e, report);
762 if (cache->time_limit > 0) {
763 cache_e->time = time(NULL);
766 memcache_add_talloc(cache->cache,
767 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
768 data_blob_const(fname, fname_len), &cache_e);
770 return true;
773 bool virusfilter_cache_entry_rename(
774 struct virusfilter_cache *cache,
775 const char *directory,
776 char *old_fname,
777 char *new_fname)
779 int old_fname_len = 0;
780 int new_fname_len = 0;
781 struct virusfilter_cache_entry *new_data = NULL;
782 struct virusfilter_cache_entry *old_data = NULL;
784 if (old_fname == NULL || new_fname == NULL || directory == NULL) {
785 return false;
788 old_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, old_fname);
789 new_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, new_fname);
791 if (old_fname == NULL || new_fname == NULL) {
792 TALLOC_FREE(old_fname);
793 TALLOC_FREE(new_fname);
794 return false;
797 old_fname_len = strlen(old_fname);
798 new_fname_len = strlen(new_fname);
800 old_data = memcache_lookup_talloc(
801 cache->cache,
802 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
803 data_blob_const(old_fname, old_fname_len));
805 if (old_data == NULL) {
806 return false;
809 new_data = talloc_memdup(cache->ctx, old_data,
810 sizeof(struct virusfilter_cache_entry));
811 if (new_data == NULL) {
812 return false;
814 new_data->report = talloc_strdup(new_data, old_data->report);
816 memcache_add_talloc(cache->cache,
817 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
818 data_blob_const(new_fname, new_fname_len), &new_data);
820 memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
821 data_blob_const(old_fname, old_fname_len));
823 return true;
826 void virusfilter_cache_purge(struct virusfilter_cache *cache)
828 memcache_flush(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC);
831 struct virusfilter_cache_entry *virusfilter_cache_get(
832 struct virusfilter_cache *cache,
833 const char *directory,
834 const char *fname)
836 int fname_len = 0;
837 struct virusfilter_cache_entry *cache_e = NULL;
838 struct virusfilter_cache_entry *data = NULL;
840 if (fname == NULL || directory == NULL) {
841 return 0;
844 fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
846 if (fname == NULL) {
847 return 0;
850 fname_len = strlen(fname);
852 data = memcache_lookup_talloc(cache->cache,
853 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
854 data_blob_const(fname, fname_len));
856 if (data == NULL) {
857 return cache_e;
860 if (cache->time_limit > 0) {
861 if (time(NULL) - data->time > cache->time_limit) {
862 DBG_DEBUG("Cache entry is too old: %s\n",
863 fname);
864 virusfilter_cache_remove(cache, directory, fname);
865 return cache_e;
868 cache_e = talloc_memdup(cache->ctx, data,
869 sizeof(struct virusfilter_cache_entry));
870 if (cache_e == NULL) {
871 return NULL;
873 if (data->report != NULL) {
874 cache_e->report = talloc_strdup(cache_e, data->report);
875 } else {
876 cache_e->report = NULL;
879 return cache_e;
882 void virusfilter_cache_remove(struct virusfilter_cache *cache,
883 const char *directory,
884 const char *fname)
886 DBG_DEBUG("Purging cache entry: %s/%s\n", directory, fname);
888 if (fname == NULL || directory == NULL) {
889 return;
892 fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
894 if (fname == NULL) {
895 return;
898 memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
899 data_blob_const(fname, strlen(fname)));
902 void virusfilter_cache_entry_free(struct virusfilter_cache_entry *cache_e)
904 if (cache_e != NULL) {
905 TALLOC_FREE(cache_e->report);
906 cache_e->report = NULL;
908 TALLOC_FREE(cache_e);
911 /* Shell scripting
912 * ======================================================================
915 int virusfilter_env_set(
916 TALLOC_CTX *mem_ctx,
917 char **env_list,
918 const char *name,
919 const char *value)
921 char *env_new;
922 int ret;
924 env_new = talloc_asprintf(mem_ctx, "%s=%s", name, value);
925 if (env_new == NULL) {
926 DBG_ERR("talloc_asprintf failed\n");
927 return -1;
930 ret = strv_add(mem_ctx, env_list, env_new);
932 TALLOC_FREE(env_new);
934 return ret;
937 /* virusfilter_env version Samba's *_sub_advanced() in substitute.c */
938 int virusfilter_shell_set_conn_env(
939 TALLOC_CTX *mem_ctx,
940 char **env_list,
941 connection_struct *conn)
943 int snum = SNUM(conn);
944 char *server_addr_p;
945 char *client_addr_p;
946 const char *local_machine_name = get_local_machine_name();
947 fstring pidstr;
948 int ret;
950 if (local_machine_name == NULL || *local_machine_name == '\0') {
951 local_machine_name = lp_netbios_name();
954 server_addr_p = tsocket_address_inet_addr_string(
955 conn->sconn->local_address, talloc_tos());
957 if (server_addr_p != NULL) {
958 ret = strncmp("::ffff:", server_addr_p, 7);
959 if (ret == 0) {
960 server_addr_p += 7;
962 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_IP",
963 server_addr_p);
965 TALLOC_FREE(server_addr_p);
967 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_NAME",
968 myhostname());
969 virusfilter_env_set(mem_ctx, env_list,
970 "VIRUSFILTER_SERVER_NETBIOS_NAME",
971 local_machine_name);
972 slprintf(pidstr,sizeof(pidstr)-1, "%ld", (long)getpid());
973 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_PID",
974 pidstr);
976 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVICE_NAME",
977 lp_const_servicename(snum));
978 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVICE_PATH",
979 conn->cwd_fname->base_name);
981 client_addr_p = tsocket_address_inet_addr_string(
982 conn->sconn->remote_address, talloc_tos());
984 if (client_addr_p != NULL) {
985 ret = strncmp("::ffff:", client_addr_p, 7);
986 if (ret == 0) {
987 client_addr_p += 7;
989 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_CLIENT_IP",
990 client_addr_p);
992 TALLOC_FREE(client_addr_p);
994 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_CLIENT_NAME",
995 conn->sconn->remote_hostname);
996 virusfilter_env_set(mem_ctx, env_list,
997 "VIRUSFILTER_CLIENT_NETBIOS_NAME",
998 get_remote_machine_name());
1000 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_USER_NAME",
1001 get_current_username());
1002 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_USER_DOMAIN",
1003 current_user_info.domain);
1005 return 0;
1008 /* Wrapper to Samba's smbrun() in smbrun.c */
1009 int virusfilter_shell_run(
1010 TALLOC_CTX *mem_ctx,
1011 const char *cmd,
1012 char **env_list,
1013 connection_struct *conn,
1014 bool sanitize)
1016 int ret;
1018 if (conn != NULL) {
1019 ret = virusfilter_shell_set_conn_env(mem_ctx, env_list, conn);
1020 if (ret == -1) {
1021 return -1;
1025 if (sanitize) {
1026 return smbrun(cmd, NULL, strv_to_env(talloc_tos(), *env_list));
1027 } else {
1028 return smbrun_no_sanitize(cmd, NULL, strv_to_env(talloc_tos(),
1029 *env_list));