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