90ae427023be53c2805439f08b3806c598b35e73
[metze/samba/wip.git] / source3 / modules / vfs_virusfilter_utils.c
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 char *virusfilter_string_sub(
34         TALLOC_CTX *mem_ctx,
35         connection_struct *conn,
36         const char *str)
37 {
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);
46 }
47
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)
52 {
53         int result;
54
55         result = SMB_VFS_NEXT_RENAME(vfs_h, smb_fname_src, smb_fname_dst);
56         if (result == 0 || errno != EXDEV) {
57                 return result;
58         }
59
60         /*
61          * For now, do not handle EXDEV as poking around violates
62          * stackability. Return -1, simply refuse access.
63          */
64         return -1;
65 }
66
67 /* Line-based socket I/O
68  * ======================================================================
69  */
70
71 struct virusfilter_io_handle *virusfilter_io_new(
72         TALLOC_CTX *mem_ctx,
73         int connect_timeout,
74         int io_timeout)
75 {
76         struct virusfilter_io_handle *io_h = talloc_zero(mem_ctx,
77                                                 struct virusfilter_io_handle);
78
79         if (io_h == NULL) {
80                 return NULL;
81         }
82
83         io_h->stream = NULL;
84         io_h->r_len = 0;
85
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);
90
91         return io_h;
92 }
93
94 int virusfilter_io_set_connect_timeout(
95         struct virusfilter_io_handle *io_h,
96         int timeout)
97 {
98         int timeout_old = io_h->connect_timeout;
99
100         /* timeout <= 0 means infinite */
101         io_h->connect_timeout = (timeout > 0) ? timeout : -1;
102
103         return timeout_old;
104 }
105
106 int virusfilter_io_set_io_timeout(
107         struct virusfilter_io_handle *io_h,
108         int timeout)
109 {
110         int timeout_old = io_h->io_timeout;
111
112         /* timeout <= 0 means infinite */
113         io_h->io_timeout = (timeout > 0) ? timeout : -1;
114
115         return timeout_old;
116 }
117
118 void virusfilter_io_set_writel_eol(
119         struct virusfilter_io_handle *io_h,
120         const char *eol,
121         int eol_size)
122 {
123         if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
124                 return;
125         }
126
127         memcpy(io_h->w_eol, eol, eol_size);
128         io_h->w_eol_size = eol_size;
129 }
130
131 void virusfilter_io_set_readl_eol(
132         struct virusfilter_io_handle *io_h,
133         const char *eol,
134         int eol_size)
135 {
136         if (eol_size < 1 || eol_size > VIRUSFILTER_IO_EOL_SIZE) {
137                 return;
138         }
139
140         memcpy(io_h->r_eol, eol, eol_size);
141         io_h->r_eol_size = eol_size;
142 }
143
144 bool virusfilter_io_connect_path(
145         struct virusfilter_io_handle *io_h,
146         const char *path)
147 {
148         struct sockaddr_un addr;
149         NTSTATUS status;
150         int socket, bes_result, flags, ret;
151         size_t len;
152
153         ZERO_STRUCT(addr);
154         addr.sun_family = AF_UNIX;
155
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;
160         }
161
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;
168         }
169
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));
177         }
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));
184         }
185
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;
192         }
193
194         return true;
195 }
196
197 static void disconnect_done(struct tevent_req *req)
198 {
199         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
200         int ret;
201         int err_ret;
202
203         ret = tstream_disconnect_recv(req, &err_ret);
204         TALLOC_FREE(req);
205         if (ret == -1) {
206                 *perr = err_ret;
207         }
208 }
209
210 bool virusfilter_io_disconnect(
211         struct virusfilter_io_handle *io_h)
212 {
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();
218
219         if (io_h->stream == NULL) {
220                 io_h->r_len = 0;
221                 TALLOC_FREE(frame);
222                 return VIRUSFILTER_RESULT_OK;
223         }
224
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;
230         }
231
232         /* Error return - must be talloc'ed. */
233         perror = talloc_zero(frame, uint64_t);
234         if (perror == NULL) {
235                 goto fail;
236         }
237
238         req = tstream_disconnect_send(io_h, ev, io_h->stream);
239
240         /* Callback when disconnect is done. */
241         tevent_req_set_callback(req, disconnect_done, perror);
242
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;
249         }
250
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;
256         }
257
258         /* Emit debug error if failed. */
259         if (*perror != 0) {
260                 DBG_DEBUG("Error %s\n", strerror((int)*perror));
261                 goto fail;
262         }
263
264         /* Here we know we disconnected. */
265
266         io_h->stream = NULL;
267         io_h->r_len = 0;
268
269         fail:
270                 TALLOC_FREE(frame);
271                 return ok;
272 }
273
274 static void writev_done(struct tevent_req *req)
275 {
276         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
277         int ret;
278         int err_ret;
279
280         ret = tstream_writev_recv(req, &err_ret);
281         TALLOC_FREE(req);
282         if (ret == -1) {
283                 *perr = err_ret;
284         }
285 }
286
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 ****************************************************************************/
292
293 bool write_data_iov_timeout(
294         struct tstream_context *stream,
295         const struct iovec *iov,
296         size_t iovcnt,
297         int ms_timeout)
298 {
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();
304
305         ev = tevent_context_init(frame);
306         if (ev == NULL) {
307                 DBG_ERR("Failed to setup event context.\n");
308                 goto fail;
309         }
310
311         /* Error return - must be talloc'ed. */
312         perror = talloc_zero(frame, uint64_t);
313         if (perror == NULL) {
314                 goto fail;
315         }
316
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;
322         }
323
324         /* Callback when *all* data sent. */
325         tevent_req_set_callback(req, writev_done, perror);
326
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;
333         }
334
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;
340         }
341
342         /* Done with req - freed by the callback. */
343         req = NULL;
344
345         /* Emit debug error if failed. */
346         if (*perror != 0) {
347                 DBG_DEBUG("Error %s\n", strerror((int)*perror));
348                 goto fail;
349         }
350
351         /* Here we know we correctly wrote all data. */
352         TALLOC_FREE(frame);
353         return true;
354
355   fail:
356         TALLOC_FREE(frame);
357         return false;
358 }
359
360 bool virusfilter_io_write(
361         struct virusfilter_io_handle *io_h,
362         const char *data,
363         size_t data_size)
364 {
365         struct iovec iov;
366
367         if (data_size == 0) {
368                 return VIRUSFILTER_RESULT_OK;
369         }
370
371         iov.iov_base = discard_const_p(void, data);
372         iov.iov_len = data_size;
373
374         return write_data_iov_timeout(io_h->stream, &iov, 1, io_h->io_timeout);
375 }
376
377 bool virusfilter_io_writel(
378         struct virusfilter_io_handle *io_h,
379         const char *data,
380         size_t data_size)
381 {
382         bool ok;
383
384         ok = virusfilter_io_write(io_h, data, data_size);
385         if (!ok) {
386                 return ok;
387         }
388
389         return virusfilter_io_write(io_h, io_h->w_eol, io_h->w_eol_size);
390 }
391
392 bool virusfilter_io_writefl(
393         struct virusfilter_io_handle *io_h,
394         const char *data_fmt, ...)
395 {
396         va_list ap;
397         char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
398         int data_size;
399
400         va_start(ap, data_fmt);
401         data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
402         va_end(ap);
403
404         if (unlikely (data_size < 0)) {
405                 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
406                 return false;
407         }
408
409         memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
410         data_size += io_h->w_eol_size;
411
412         return virusfilter_io_write(io_h, data, data_size);
413 }
414
415 bool virusfilter_io_vwritefl(
416         struct virusfilter_io_handle *io_h,
417         const char *data_fmt, va_list ap)
418 {
419         char data[VIRUSFILTER_IO_BUFFER_SIZE + VIRUSFILTER_IO_EOL_SIZE];
420         int data_size;
421
422         data_size = vsnprintf(data, VIRUSFILTER_IO_BUFFER_SIZE, data_fmt, ap);
423
424         if (unlikely (data_size < 0)) {
425                 DBG_ERR("vsnprintf failed: %s\n", strerror(errno));
426                 return false;
427         }
428
429         memcpy(data + data_size, io_h->w_eol, io_h->w_eol_size);
430         data_size += io_h->w_eol_size;
431
432         return virusfilter_io_write(io_h, data, data_size);
433 }
434
435 bool virusfilter_io_writev(
436         struct virusfilter_io_handle *io_h, ...)
437 {
438         va_list ap;
439         struct iovec iov[VIRUSFILTER_IO_IOV_MAX], *iov_p;
440         int iov_n;
441
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++)
446         {
447                 iov_p->iov_base = va_arg(ap, void *);
448                 if (iov_p->iov_base == NULL) {
449                         break;
450                 }
451                 iov_p->iov_len = va_arg(ap, int);
452         }
453         va_end(ap);
454
455         return write_data_iov_timeout(io_h->stream, iov, iov_n,
456                 io_h->io_timeout);
457 }
458
459 bool virusfilter_io_writevl(
460         struct virusfilter_io_handle *io_h, ...)
461 {
462         va_list ap;
463         struct iovec iov[VIRUSFILTER_IO_IOV_MAX + 1], *iov_p;
464         int iov_n;
465
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++)
469         {
470                 iov_p->iov_base = va_arg(ap, void *);
471                 if (iov_p->iov_base == NULL) {
472                         break;
473                 }
474                 iov_p->iov_len = va_arg(ap, int);
475         }
476         va_end(ap);
477
478         iov_p->iov_base = io_h->r_eol;
479         iov_p->iov_len = io_h->r_eol_size;
480         iov_n++;
481
482         return write_data_iov_timeout(io_h->stream, iov, iov_n,
483                 io_h->io_timeout);
484 }
485
486 static bool return_existing_line(TALLOC_CTX *ctx,
487                                 struct virusfilter_io_handle *io_h,
488                                 char **read_line)
489 {
490         size_t read_line_len = 0;
491         char *end_p = NULL;
492         char *eol = NULL;
493
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;
498         }
499         end_p = eol + io_h->r_eol_size;
500
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;
508         }
509
510         /*
511          * Copy the remaining buffer over the line
512          * we returned.
513          */
514         memmove(io_h->r_buffer,
515                 end_p,
516                 io_h->r_len - (end_p - io_h->r_buffer));
517
518         /* And reduce the size left in the buffer. */
519         io_h->r_len -= (end_p - io_h->r_buffer);
520         return true;
521 }
522
523 static void readv_done(struct tevent_req *req)
524 {
525         uint64_t *perr = tevent_req_callback_data(req, uint64_t);
526         int ret;
527         int err_ret;
528
529         ret = tstream_readv_recv(req, &err_ret);
530         TALLOC_FREE(req);
531         if (ret == -1) {
532                 *perr = err_ret;
533         }
534 }
535
536 bool virusfilter_io_readl(TALLOC_CTX *ctx,
537                         struct virusfilter_io_handle *io_h,
538                         char **read_line)
539 {
540         struct tevent_context *ev = NULL;
541         bool ok = false;
542         uint64_t *perror = NULL;
543         TALLOC_CTX *frame = talloc_stackframe();
544
545         /* Search for an existing complete line. */
546         ok = return_existing_line(ctx, io_h, read_line);
547         if (ok) {
548                 goto finish;
549         }
550
551         /*
552          * No complete line in the buffer. We must read more
553          * from the server.
554          */
555         ev = tevent_context_init(frame);
556         if (ev == NULL) {
557                 DBG_ERR("Failed to setup event context.\n");
558                 goto finish;
559         }
560
561         /* Error return - must be talloc'ed. */
562         perror = talloc_zero(frame, uint64_t);
563         if (perror == NULL) {
564                 goto finish;
565         }
566
567         for (;;) {
568                 ssize_t pending = 0;
569                 size_t read_size = 0;
570                 struct iovec iov;
571                 struct tevent_req *req = NULL;
572
573                 /*
574                  * How much can we read ?
575                  */
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;
581                 }
582
583                 read_size = pending;
584                 /* Must read at least one byte. */
585                 read_size = MIN(read_size, 1);
586
587                 /* And max remaining buffer space. */
588                 read_size = MAX(read_size,
589                                 (sizeof(io_h->r_buffer) - io_h->r_len));
590
591                 if (read_size == 0) {
592                         /* Buffer is full with no EOL. Error out. */
593                         DBG_ERR("Line buffer full.\n");
594                         goto finish;
595                 }
596
597                 iov.iov_base = io_h->r_buffer + io_h->r_len;
598                 iov.iov_len = read_size;
599
600                 /* Read the data. */
601                 req = tstream_readv_send(frame,
602                                         ev,
603                                         io_h->stream,
604                                         &iov,
605                                         1);
606                 if (req == NULL) {
607                         DBG_ERR("out of memory.\n");
608                         goto finish;
609                 }
610
611                 /* Callback when *all* data read. */
612                 tevent_req_set_callback(req, readv_done, perror);
613
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;
620                 }
621
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;
627                 }
628
629                 /* Done with req - freed by the callback. */
630                 req = NULL;
631
632                 /*
633                  * Emit debug error if failed.
634                  * EPIPE may be success so, don't exit.
635                  */
636                 if (*perror != 0 && *perror != EPIPE) {
637                         DBG_DEBUG("Error %s\n", strerror((int)*perror));
638                         errno = (int)*perror;
639                         goto finish;
640                 }
641
642                 /*
643                  * We read read_size bytes. Extend the useable
644                  * buffer length.
645                  */
646                 io_h->r_len += read_size;
647
648                 /* Paranoia... */
649                 SMB_ASSERT(io_h->r_len <= sizeof(io_h->r_buffer));
650
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;
655                 }
656                 /* No eol - keep reading. */
657         }
658
659   finish:
660
661         TALLOC_FREE(frame);
662         return ok;
663 }
664
665 bool virusfilter_io_writefl_readl(
666         struct virusfilter_io_handle *io_h,
667         char **read_line,
668         const char *fmt, ...)
669 {
670         bool ok;
671
672         if (fmt) {
673                 va_list ap;
674
675                 va_start(ap, fmt);
676                 ok = virusfilter_io_vwritefl(io_h, fmt, ap);
677                 va_end(ap);
678
679                 if (!ok) {
680                         return ok;
681                 }
682         }
683
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;
688         }
689         if (io_h->r_len == 0) { /* EOF */
690                 DBG_ERR("virusfilter_io_readl EOF\n");
691                 return false;
692         }
693
694         return true;
695 }
696
697 struct virusfilter_cache *virusfilter_cache_new(
698         TALLOC_CTX *ctx,
699         int entry_limit,
700         time_t time_limit)
701 {
702         struct virusfilter_cache *cache;
703
704         if (time_limit == 0) {
705                 return NULL;
706         }
707
708         cache = talloc_zero(ctx, struct virusfilter_cache);
709         if (cache == NULL) {
710                 DBG_ERR("talloc_zero failed.\n");
711                 return NULL;
712         }
713
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;
720         }
721         cache->ctx = ctx;
722         cache->time_limit = time_limit;
723
724         return cache;
725 }
726
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)
733 {
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;
738
739         if (fname == NULL || directory == NULL) {
740                 TALLOC_FREE(report);
741                 return false;
742         }
743
744         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
745
746         if (fname == NULL) {
747                 TALLOC_FREE(report);
748                 return false;
749         }
750
751         fname_len = strlen(fname);
752
753         if (cache_e == NULL|| cache->time_limit == 0) {
754                 TALLOC_FREE(report);
755                 return false;
756         }
757
758         cache_e->result = result;
759         if (report != NULL) {
760                 cache_e->report = talloc_steal(cache_e, report);
761         }
762         if (cache->time_limit > 0) {
763                 cache_e->time = time(NULL);
764         }
765
766         memcache_add_talloc(cache->cache,
767                             VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
768                             data_blob_const(fname, fname_len), &cache_e);
769
770         return true;
771 }
772
773 bool virusfilter_cache_entry_rename(
774         struct virusfilter_cache *cache,
775         const char *directory,
776         char *old_fname,
777         char *new_fname)
778 {
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;
783
784         if (old_fname == NULL || new_fname == NULL || directory == NULL) {
785                 return false;
786         }
787
788         old_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, old_fname);
789         new_fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, new_fname);
790
791         if (old_fname == NULL || new_fname == NULL) {
792                 TALLOC_FREE(old_fname);
793                 TALLOC_FREE(new_fname);
794                 return false;
795         }
796
797         old_fname_len = strlen(old_fname);
798         new_fname_len = strlen(new_fname);
799
800         old_data = memcache_lookup_talloc(
801                                 cache->cache,
802                                 VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
803                                 data_blob_const(old_fname, old_fname_len));
804
805         if (old_data == NULL) {
806                 return false;
807         }
808
809         new_data = talloc_memdup(cache->ctx, old_data,
810                                  sizeof(struct virusfilter_cache_entry));
811         if (new_data == NULL) {
812                 return false;
813         }
814         new_data->report = talloc_strdup(new_data, old_data->report);
815
816         memcache_add_talloc(cache->cache,
817                         VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
818                         data_blob_const(new_fname, new_fname_len), &new_data);
819
820         memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
821                         data_blob_const(old_fname, old_fname_len));
822
823         return true;
824 }
825
826 void virusfilter_cache_purge(struct virusfilter_cache *cache)
827 {
828         memcache_flush(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC);
829 }
830
831 struct virusfilter_cache_entry *virusfilter_cache_get(
832         struct virusfilter_cache *cache,
833         const char *directory,
834         const char *fname)
835 {
836         int fname_len = 0;
837         struct virusfilter_cache_entry *cache_e = NULL;
838         struct virusfilter_cache_entry *data = NULL;
839
840         if (fname == NULL || directory == NULL) {
841                 return 0;
842         }
843
844         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
845
846         if (fname == NULL) {
847                 return 0;
848         }
849
850         fname_len = strlen(fname);
851
852         data = memcache_lookup_talloc(cache->cache,
853                                       VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
854                                       data_blob_const(fname, fname_len));
855
856         if (data == NULL) {
857                 return cache_e;
858         }
859
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;
866                 }
867         }
868         cache_e = talloc_memdup(cache->ctx, data,
869                                sizeof(struct virusfilter_cache_entry));
870         if (cache_e == NULL) {
871                 return NULL;
872         }
873         if (data->report != NULL) {
874                 cache_e->report = talloc_strdup(cache_e, data->report);
875         } else {
876                 cache_e->report = NULL;
877         }
878
879         return cache_e;
880 }
881
882 void virusfilter_cache_remove(struct virusfilter_cache *cache,
883         const char *directory,
884         const char *fname)
885 {
886         DBG_DEBUG("Purging cache entry: %s/%s\n", directory, fname);
887
888         if (fname == NULL || directory == NULL) {
889                 return;
890         }
891
892         fname = talloc_asprintf(talloc_tos(), "%s/%s", directory, fname);
893
894         if (fname == NULL) {
895                 return;
896         }
897
898         memcache_delete(cache->cache, VIRUSFILTER_SCAN_RESULTS_CACHE_TALLOC,
899                         data_blob_const(fname, strlen(fname)));
900 }
901
902 void virusfilter_cache_entry_free(struct virusfilter_cache_entry *cache_e)
903 {
904         if (cache_e != NULL) {
905                 TALLOC_FREE(cache_e->report);
906                 cache_e->report = NULL;
907         }
908         TALLOC_FREE(cache_e);
909 }
910
911 /* Shell scripting
912  * ======================================================================
913  */
914
915 int virusfilter_env_set(
916         TALLOC_CTX *mem_ctx,
917         char **env_list,
918         const char *name,
919         const char *value)
920 {
921         char *env_new;
922         int ret;
923
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;
928         }
929
930         ret = strv_add(mem_ctx, env_list, env_new);
931
932         TALLOC_FREE(env_new);
933
934         return ret;
935 }
936
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)
942 {
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;
949
950         if (local_machine_name == NULL || *local_machine_name == '\0') {
951                 local_machine_name = lp_netbios_name();
952         }
953
954         server_addr_p = tsocket_address_inet_addr_string(
955                                 conn->sconn->local_address, talloc_tos());
956
957         if (server_addr_p != NULL) {
958                 ret = strncmp("::ffff:", server_addr_p, 7);
959                 if (ret == 0) {
960                         server_addr_p += 7;
961                 }
962                 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_SERVER_IP",
963                                     server_addr_p);
964         }
965         TALLOC_FREE(server_addr_p);
966
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);
975
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);
980
981         client_addr_p = tsocket_address_inet_addr_string(
982                                 conn->sconn->remote_address, talloc_tos());
983
984         if (client_addr_p != NULL) {
985                 ret = strncmp("::ffff:", client_addr_p, 7);
986                 if (ret == 0) {
987                         client_addr_p += 7;
988                 }
989                 virusfilter_env_set(mem_ctx, env_list, "VIRUSFILTER_CLIENT_IP",
990                                     client_addr_p);
991         }
992         TALLOC_FREE(client_addr_p);
993
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());
999
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);
1004
1005         return 0;
1006 }
1007
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)
1015 {
1016         int ret;
1017
1018         if (conn != NULL) {
1019                 ret = virusfilter_shell_set_conn_env(mem_ctx, env_list, conn);
1020                 if (ret == -1) {
1021                         return -1;
1022                 }
1023         }
1024
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));
1030         }
1031 }