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