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