2 * scannedonly VFS module for Samba 3.5 and beyond
4 * Copyright 2007,2008,2009,2010,2011 (C) Olivier Sessink
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * scannedonly implements a 'filter' like vfs module that talks over a
23 * unix domain socket or over UDP to a anti-virus engine.
25 * files that are clean have a corresponding .scanned:{filename} file
26 * in the same directory. So why the .scanned: files? They take up
27 * only an inode, because they are 0 bytes. To test if the file is
28 * scanned only a stat() call on the filesystem is needed which is
29 * very quick compared to a database lookup. All modern filesystems
30 * use database technology such as balanced trees for lookups anyway.
31 * The number of inodes in modern filesystems is also not limiting
32 * anymore. The .scanned: files are also easy scriptable. You can
33 * remove them with a simple find command or create them with a
34 * simple touch command. Extended filesystem attributes have similar
35 * properties, but are not supported on all filesystems, so that
36 * would limit the usage of the module (and attributes are not as
39 * files that are not clean are sent to the AV-engine. Only the
40 * filename is sent over the socket. The protocol is very simple:
41 * a newline separated list of filenames inside each datagram.
43 * a file AV-scan may be requested multiple times, the AV-engine
44 * should also check if the file has been scanned already. Requests
45 * can also be dropped by the AV-engine (and we thus don't need the
46 * reliability of TCP).
51 #include "smbd/smbd.h"
52 #include "system/filesys.h"
56 #define SENDBUFFERSIZE 1450
59 #define SUN_LEN(sunp) ((size_t)((struct sockaddr_un *)0)->sun_path \
60 + strlen((sunp)->sun_path))
68 int scanning_message_len
;
69 int recheck_time_open
;
70 int recheck_tries_open
;
71 int recheck_size_open
;
72 int recheck_time_readdir
;
73 int recheck_tries_readdir
;
74 bool show_special_files
;
75 bool rm_hidden_files_on_rmdir
;
76 bool hide_nonscanned_files
;
77 bool allow_nonscanned_files
;
78 const char *socketname
;
80 const char *scanning_message
;
81 const char *p_scanned
; /* prefix for scanned files */
82 const char *p_virus
; /* prefix for virus containing files */
83 const char *p_failed
; /* prefix for failed to scan files */
84 char gsendbuffer
[SENDBUFFERSIZE
+ 1];
87 #define STRUCTSCANO(var) ((struct Tscannedonly *)var)
89 struct scannedonly_DIR
{
91 int recheck_tries_done
; /* if 0 the directory listing has not yet
92 been checked for files that need to be scanned. */
95 #define SCANNEDONLY_DEBUG 9
96 /*********************/
97 /* utility functions */
98 /*********************/
100 static char *real_path_from_notify_path(TALLOC_CTX
*ctx
,
101 struct Tscannedonly
*so
,
107 name
= strrchr(path
, '/');
111 pathlen
= name
- path
;
114 if (len
<= so
->scanning_message_len
) {
118 if (strcmp(name
+ (len
- so
->scanning_message_len
),
119 so
->scanning_message
) != 0) {
123 return talloc_strndup(ctx
,path
,
124 pathlen
+ len
- so
->scanning_message_len
);
127 static char *cachefile_name(TALLOC_CTX
*ctx
,
128 const char *shortname
,
130 const char *p_scanned
)
132 return talloc_asprintf(ctx
, "%s%s%s", base
, p_scanned
, shortname
);
135 static char *name_w_ending_slash(TALLOC_CTX
*ctx
, const char *name
)
137 int len
= strlen(name
);
138 if (name
[len
- 1] == '/') {
139 return talloc_strdup(ctx
,name
);
141 return talloc_asprintf(ctx
, "%s/", name
);
145 static char *cachefile_name_f_fullpath(TALLOC_CTX
*ctx
,
146 const char *fullpath
,
147 const char *p_scanned
)
150 char *tmp
, *cachefile
;
151 const char *shortname
;
152 tmp
= strrchr(fullpath
, '/');
154 base
= talloc_strndup(ctx
, fullpath
, (tmp
- fullpath
) + 1);
158 shortname
= (const char *)fullpath
;
160 cachefile
= cachefile_name(ctx
, shortname
, base
, p_scanned
);
161 DEBUG(SCANNEDONLY_DEBUG
,
162 ("cachefile_name_f_fullpath cachefile=%s\n", cachefile
));
166 static char *construct_full_path(TALLOC_CTX
*ctx
, vfs_handle_struct
* handle
,
167 const char *somepath
, bool ending_slash
)
174 if (somepath
[0] == '/') {
176 return name_w_ending_slash(ctx
,somepath
);
178 return talloc_strdup(ctx
,somepath
);
181 if (tmp
[0]=='.'&&tmp
[1]=='/') {
184 /* vfs_GetWd() seems to return a path with a slash */
186 return talloc_asprintf(ctx
, "%s/%s/",
187 vfs_GetWd(ctx
, handle
->conn
),tmp
);
189 return talloc_asprintf(ctx
, "%s/%s",
190 vfs_GetWd(ctx
, handle
->conn
),tmp
);
193 static int connect_to_scanner(vfs_handle_struct
* handle
)
195 struct Tscannedonly
*so
= (struct Tscannedonly
*)handle
->data
;
197 if (so
->domain_socket
) {
198 struct sockaddr_un saun
;
199 DEBUG(SCANNEDONLY_DEBUG
, ("socket=%s\n", so
->socketname
));
200 if ((so
->socket
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0) {
201 DEBUG(2, ("failed to create socket %s\n",
205 saun
.sun_family
= AF_UNIX
;
206 strncpy(saun
.sun_path
, so
->socketname
,
207 sizeof(saun
.sun_path
) - 1);
208 if (connect(so
->socket
, (struct sockaddr
*)(void *)&saun
,
209 SUN_LEN(&saun
)) < 0) {
210 DEBUG(2, ("failed to connect to socket %s\n",
214 DEBUG(SCANNEDONLY_DEBUG
,("bound %s to socket %d\n",
215 saun
.sun_path
, so
->socket
));
218 so
->socket
= open_udp_socket(so
->scanhost
, so
->portnum
);
219 if (so
->socket
< 0) {
220 DEBUG(2,("failed to open UDP socket to %s:%d\n",
221 so
->scanhost
,so
->portnum
));
226 {/* increasing the socket buffer is done because we have large bursts
227 of UDP packets or DGRAM's on a domain socket whenever we hit a
228 large directory with lots of unscanned files. */
230 socklen_t size
= sizeof(int);
231 getsockopt(so
->socket
, SOL_SOCKET
, SO_RCVBUF
,
232 (char *)&sndsize
, &size
);
233 DEBUG(SCANNEDONLY_DEBUG
, ("current socket buffer size=%d\n",
236 if (setsockopt(so
->socket
, SOL_SOCKET
, SO_RCVBUF
,
238 (int)sizeof(sndsize
)) != 0) {
239 DEBUG(SCANNEDONLY_DEBUG
,
240 ("error setting socket buffer %s (%d)\n",
241 strerror(errno
), errno
));
244 set_blocking(so
->socket
, false);
248 static void flush_sendbuffer(vfs_handle_struct
* handle
)
250 struct Tscannedonly
*so
= (struct Tscannedonly
*)handle
->data
;
251 int ret
, len
, loop
= 10;
252 if (so
->gsendbuffer
[0] == '\0') {
258 len
= strlen(so
->gsendbuffer
);
259 ret
= send(so
->socket
, so
->gsendbuffer
, len
, 0);
261 so
->gsendbuffer
[0] = '\0';
265 DEBUG(3,("scannedonly flush_sendbuffer: "
266 "error sending on socket %d to scanner:"
268 so
->socket
, strerror(errno
), errno
));
269 if (errno
== ECONNREFUSED
|| errno
== ENOTCONN
270 || errno
== ECONNRESET
) {
271 if (connect_to_scanner(handle
) == -1)
272 break; /* connecting fails, abort */
274 } else if (errno
!= EINTR
) {
275 /* on EINTR we just try again, all remaining
276 other errors we log the error
277 and try again ONCE */
279 DEBUG(3,("scannedonly flush_sendbuffer: "
280 "error sending data to scanner: %s "
281 "(%d)\n", strerror(errno
), errno
));
284 /* --> partial write: Resend all filenames that were
285 not or not completely written. a partial filename
286 written means the filename will not arrive correctly,
287 so resend it completely */
290 char *tmp
= strchr(so
->gsendbuffer
+pos
, '\n');
291 if (tmp
&& tmp
- so
->gsendbuffer
< ret
)
292 pos
= tmp
- so
->gsendbuffer
+ 1;
296 memmove(so
->gsendbuffer
, so
->gsendbuffer
+ pos
,
297 SENDBUFFERSIZE
- ret
);
302 if (so
->gsendbuffer
[0] != '\0') {
304 ("scannedonly flush_sendbuffer: "
305 "failed to send files to AV scanner, "
306 "discarding files."));
307 so
->gsendbuffer
[0] = '\0';
311 static void notify_scanner(vfs_handle_struct
* handle
, const char *scanfile
)
314 int tmplen
, gsendlen
;
315 struct Tscannedonly
*so
= (struct Tscannedonly
*)handle
->data
;
316 TALLOC_CTX
*ctx
=talloc_tos();
317 if (scanfile
[0] != '/') {
318 tmp
= construct_full_path(ctx
,handle
, scanfile
, false);
320 tmp
= (const char *)scanfile
;
322 tmplen
= strlen(tmp
);
323 gsendlen
= strlen(so
->gsendbuffer
);
324 DEBUG(SCANNEDONLY_DEBUG
,
325 ("scannedonly notify_scanner: tmp=%s, tmplen=%d, gsendlen=%d\n",
326 tmp
, tmplen
, gsendlen
));
327 if (gsendlen
+ tmplen
>= SENDBUFFERSIZE
) {
328 flush_sendbuffer(handle
);
330 strlcat(so
->gsendbuffer
, tmp
, SENDBUFFERSIZE
+ 1);
331 strlcat(so
->gsendbuffer
, "\n", SENDBUFFERSIZE
+ 1);
334 static bool is_scannedonly_file(struct Tscannedonly
*so
, const char *shortname
)
336 if (shortname
[0]!='.') {
339 if (strncmp(shortname
, so
->p_scanned
, strlen(so
->p_scanned
)) == 0) {
342 if (strncmp(shortname
, so
->p_virus
, strlen(so
->p_virus
)) == 0) {
345 if (strncmp(shortname
, so
->p_failed
, strlen(so
->p_failed
)) == 0) {
351 static bool timespec_is_newer(struct timespec
*base
, struct timespec
*test
)
353 return timespec_compare(base
,test
) < 0;
357 vfs_handle_struct *handle the scannedonly handle
358 scannedonly_DIR * sDIR the scannedonly struct if called from _readdir()
360 fullpath is a full path starting from / or a relative path to the
361 current working directory
362 shortname is the filename without directory components
363 basename, is the directory without file name component
364 allow_nonexistant return TRUE if stat() on the requested file fails
365 recheck_time, the time in milliseconds to wait for the daemon to
366 create a .scanned file
367 recheck_tries, the number of tries to wait
368 recheck_size, size in Kb of files that should not be waited for
369 loop : boolean if we should try to loop over all files in the directory
370 and send a notify to the scanner for all files that need scanning
372 static bool scannedonly_allow_access(vfs_handle_struct
* handle
,
373 struct scannedonly_DIR
*sDIR
,
374 struct smb_filename
*smb_fname
,
375 const char *shortname
,
376 const char *base_name
,
377 int allow_nonexistant
,
378 int recheck_time
, int recheck_tries
,
379 int recheck_size
, int loop
)
381 struct smb_filename
*cache_smb_fname
;
382 TALLOC_CTX
*ctx
=talloc_tos();
385 DEBUG(SCANNEDONLY_DEBUG
,
386 ("smb_fname->base_name=%s, shortname=%s, base_name=%s\n"
387 ,smb_fname
->base_name
,shortname
,base_name
));
389 if (ISDOT(shortname
) || ISDOTDOT(shortname
)) {
392 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), shortname
)) {
393 DEBUG(SCANNEDONLY_DEBUG
,
394 ("scannedonly_allow_access, %s is a scannedonly file, "
395 "return 0\n", shortname
));
399 if (!VALID_STAT(smb_fname
->st
)) {
400 DEBUG(SCANNEDONLY_DEBUG
,("stat %s\n",smb_fname
->base_name
));
401 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
403 /* failed to stat this file?!? --> hide it */
404 DEBUG(SCANNEDONLY_DEBUG
,("no valid stat, return"
405 " allow_nonexistant=%d\n",
407 return allow_nonexistant
;
410 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
411 DEBUG(SCANNEDONLY_DEBUG
,
412 ("%s is not a regular file, ISDIR=%d\n",
413 smb_fname
->base_name
,
414 S_ISDIR(smb_fname
->st
.st_ex_mode
)));
415 return (STRUCTSCANO(handle
->data
)->
416 show_special_files
||
417 S_ISDIR(smb_fname
->st
.st_ex_mode
));
419 if (smb_fname
->st
.st_ex_size
== 0) {
420 DEBUG(SCANNEDONLY_DEBUG
,("empty file, return 1\n"));
421 return true; /* empty files cannot contain viruses ! */
423 cachefile
= cachefile_name(ctx
,
426 STRUCTSCANO(handle
->data
)->p_scanned
);
427 create_synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
,&cache_smb_fname
);
428 if (!VALID_STAT(cache_smb_fname
->st
)) {
429 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
431 if (retval
== 0 && VALID_STAT(cache_smb_fname
->st
)) {
432 if (timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
433 &cache_smb_fname
->st
.st_ex_ctime
)) {
434 talloc_free(cache_smb_fname
);
437 /* no cachefile or too old */
438 SMB_VFS_NEXT_UNLINK(handle
, cache_smb_fname
);
442 notify_scanner(handle
, smb_fname
->base_name
);
444 if (loop
&& sDIR
&& sDIR
->recheck_tries_done
== 0) {
445 /* check the rest of the directory and notify the
446 scanner if some file needs scanning */
448 SMB_STRUCT_DIRENT
*dire
;
450 offset
= SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
451 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, NULL
);
454 struct smb_filename
*smb_fname2
;
455 fpath2
= talloc_asprintf(ctx
, "%s%s", base_name
,dire
->d_name
);
456 DEBUG(SCANNEDONLY_DEBUG
,
457 ("scannedonly_allow_access in loop, "
458 "found %s\n", fpath2
));
459 create_synthetic_smb_fname(ctx
, fpath2
,NULL
,NULL
,
461 scannedonly_allow_access(handle
, NULL
,
464 base_name
, 0, 0, 0, 0, 0);
466 talloc_free(smb_fname2
);
467 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR,NULL
);
469 sDIR
->recheck_tries_done
= 1;
470 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
473 && ((recheck_size
> 0
474 && smb_fname
->st
.st_ex_size
< (1024 * recheck_size
))
475 || (sDIR
&& sDIR
->recheck_tries_done
< recheck_tries
)
477 int numloops
= sDIR
? sDIR
->recheck_tries_done
: 0;
478 flush_sendbuffer(handle
);
479 while (retval
!= 0 /*&& errno == ENOENT */
480 && numloops
< recheck_tries
) {
481 DEBUG(SCANNEDONLY_DEBUG
,
482 ("scannedonly_allow_access, wait (try=%d "
483 "(max %d), %d ms) for %s\n",
484 numloops
, recheck_tries
,
485 recheck_time
, cache_smb_fname
->base_name
));
486 smb_msleep(recheck_time
);
487 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
491 sDIR
->recheck_tries_done
= numloops
;
493 /* still no cachefile, or still too old, return 0 */
495 || !timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
496 &cache_smb_fname
->st
.st_ex_ctime
)) {
497 DEBUG(SCANNEDONLY_DEBUG
,
498 ("retval=%d, return 0\n",retval
));
504 /*********************/
506 /*********************/
508 static SMB_STRUCT_DIR
*scannedonly_opendir(vfs_handle_struct
* handle
,
510 const char *mask
, uint32 attr
)
512 SMB_STRUCT_DIR
*DIRp
;
513 struct scannedonly_DIR
*sDIR
;
515 DIRp
= SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
520 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
521 if (fname
[0] != '/') {
522 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
524 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
526 DEBUG(SCANNEDONLY_DEBUG
,
527 ("scannedonly_opendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
529 sDIR
->recheck_tries_done
= 0;
530 return (SMB_STRUCT_DIR
*) sDIR
;
533 static SMB_STRUCT_DIR
*scannedonly_fdopendir(vfs_handle_struct
* handle
,
535 const char *mask
, uint32 attr
)
537 SMB_STRUCT_DIR
*DIRp
;
538 struct scannedonly_DIR
*sDIR
;
541 DIRp
= SMB_VFS_NEXT_FDOPENDIR(handle
, fsp
, mask
, attr
);
546 fname
= (const char *)fsp
->fsp_name
->base_name
;
548 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
549 if (fname
[0] != '/') {
550 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
552 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
554 DEBUG(SCANNEDONLY_DEBUG
,
555 ("scannedonly_fdopendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
557 sDIR
->recheck_tries_done
= 0;
558 return (SMB_STRUCT_DIR
*) sDIR
;
562 static SMB_STRUCT_DIRENT
*scannedonly_readdir(vfs_handle_struct
*handle
,
563 SMB_STRUCT_DIR
* dirp
,
564 SMB_STRUCT_STAT
*sbuf
)
566 SMB_STRUCT_DIRENT
*result
;
569 struct smb_filename
*smb_fname
;
572 SMB_STRUCT_DIRENT
*newdirent
;
573 TALLOC_CTX
*ctx
=talloc_tos();
575 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
580 result
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, sbuf
);
585 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), result
->d_name
)) {
586 DEBUG(SCANNEDONLY_DEBUG
,
587 ("scannedonly_readdir, %s is a scannedonly file, "
588 "skip to next entry\n", result
->d_name
));
589 return scannedonly_readdir(handle
, dirp
, NULL
);
591 tmp
= talloc_asprintf(ctx
, "%s%s", sDIR
->base
, result
->d_name
);
592 DEBUG(SCANNEDONLY_DEBUG
,
593 ("scannedonly_readdir, check access to %s (sbuf=%p)\n",
596 /* even if we don't hide nonscanned files or we allow non scanned
597 files we call allow_access because it will notify the daemon to
599 create_synthetic_smb_fname(ctx
, tmp
,NULL
,
600 sbuf
?VALID_STAT(*sbuf
)?sbuf
:NULL
:NULL
,
602 allowed
= scannedonly_allow_access(
603 handle
, sDIR
, smb_fname
,
606 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
607 ? STRUCTSCANO(handle
->data
)->recheck_time_readdir
609 STRUCTSCANO(handle
->data
)->recheck_tries_readdir
,
612 DEBUG(SCANNEDONLY_DEBUG
,
613 ("scannedonly_readdir access to %s (%s) = %d\n", tmp
,
614 result
->d_name
, allowed
));
618 DEBUG(SCANNEDONLY_DEBUG
,
619 ("hide_nonscanned_files=%d, allow_nonscanned_files=%d\n",
620 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
,
621 STRUCTSCANO(handle
->data
)->allow_nonscanned_files
624 if (!STRUCTSCANO(handle
->data
)->hide_nonscanned_files
625 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
629 DEBUG(SCANNEDONLY_DEBUG
,
630 ("scannedonly_readdir, readdir listing for %s not "
631 "allowed, notify user\n", result
->d_name
));
632 notify_name
= talloc_asprintf(
633 ctx
,"%s %s",result
->d_name
,
634 STRUCTSCANO(handle
->data
)->scanning_message
);
635 namelen
= strlen(notify_name
);
636 newdirent
= (SMB_STRUCT_DIRENT
*)talloc_array(
637 ctx
, char, sizeof(SMB_STRUCT_DIRENT
) + namelen
+ 1);
641 memcpy(newdirent
, result
, sizeof(SMB_STRUCT_DIRENT
));
642 memcpy(&newdirent
->d_name
, notify_name
, namelen
+ 1);
643 DEBUG(SCANNEDONLY_DEBUG
,
644 ("scannedonly_readdir, return newdirent at %p with "
645 "notification %s\n", newdirent
, newdirent
->d_name
));
649 static void scannedonly_seekdir(struct vfs_handle_struct
*handle
,
650 SMB_STRUCT_DIR
* dirp
, long offset
)
652 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
653 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
656 static long scannedonly_telldir(struct vfs_handle_struct
*handle
,
657 SMB_STRUCT_DIR
* dirp
)
659 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
660 return SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
663 static void scannedonly_rewinddir(struct vfs_handle_struct
*handle
,
664 SMB_STRUCT_DIR
* dirp
)
666 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
667 SMB_VFS_NEXT_REWINDDIR(handle
, sDIR
->DIR);
670 static int scannedonly_closedir(vfs_handle_struct
* handle
,
671 SMB_STRUCT_DIR
* dirp
)
674 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
675 flush_sendbuffer(handle
);
676 retval
= SMB_VFS_NEXT_CLOSEDIR(handle
, sDIR
->DIR);
681 static int scannedonly_stat(vfs_handle_struct
* handle
,
682 struct smb_filename
*smb_fname
)
685 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
686 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_stat: %s returned %d\n",
687 smb_fname
->base_name
, ret
));
688 if (ret
!= 0 && errno
== ENOENT
) {
689 TALLOC_CTX
*ctx
=talloc_tos();
690 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
691 /* possibly this was a fake name (file is being scanned for
692 viruses.txt): check for that and create the real name and
693 stat the real name */
694 test_base_name
= real_path_from_notify_path(
696 STRUCTSCANO(handle
->data
),
697 smb_fname
->base_name
);
698 if (test_base_name
) {
699 smb_fname
->base_name
= test_base_name
;
700 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
701 DEBUG(5, ("_stat: %s returned %d\n",
702 test_base_name
, ret
));
703 smb_fname
->base_name
= tmp_base_name
;
709 static int scannedonly_lstat(vfs_handle_struct
* handle
,
710 struct smb_filename
*smb_fname
)
713 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
714 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_lstat: %s returned %d\n",
715 smb_fname
->base_name
, ret
));
716 if (ret
!= 0 && errno
== ENOENT
) {
717 TALLOC_CTX
*ctx
=talloc_tos();
718 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
719 /* possibly this was a fake name (file is being scanned for
720 viruses.txt): check for that and create the real name and
721 stat the real name */
722 test_base_name
= real_path_from_notify_path(
723 ctx
, STRUCTSCANO(handle
->data
), smb_fname
->base_name
);
724 if (test_base_name
) {
725 smb_fname
->base_name
= test_base_name
;
726 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
727 DEBUG(5, ("_lstat: %s returned %d\n",
728 test_base_name
, ret
));
729 smb_fname
->base_name
= tmp_base_name
;
735 static int scannedonly_open(vfs_handle_struct
* handle
,
736 struct smb_filename
*smb_fname
,
737 files_struct
* fsp
, int flags
, mode_t mode
)
740 char *tmp
, *shortname
;
741 int allowed
, write_access
= 0;
742 TALLOC_CTX
*ctx
=talloc_tos();
743 /* if open for writing ignore it */
744 if ((flags
& O_ACCMODE
) == O_WRONLY
) {
745 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
747 if ((flags
& O_ACCMODE
) == O_RDWR
) {
750 /* check if this file is scanned already */
751 tmp
= strrchr(smb_fname
->base_name
, '/');
753 base
= talloc_strndup(ctx
,smb_fname
->base_name
,
754 (tmp
- smb_fname
->base_name
) + 1);
758 shortname
= (char *)smb_fname
->base_name
;
760 allowed
= scannedonly_allow_access(
761 handle
, NULL
, smb_fname
, shortname
,
764 STRUCTSCANO(handle
->data
)->recheck_time_open
,
765 STRUCTSCANO(handle
->data
)->recheck_tries_open
,
766 STRUCTSCANO(handle
->data
)->recheck_size_open
,
768 flush_sendbuffer(handle
);
769 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_open: allow=%d for %s\n",
770 allowed
, smb_fname
->base_name
));
772 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
773 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
779 static int scannedonly_close(vfs_handle_struct
* handle
, files_struct
* fsp
)
781 /* we only have to notify the scanner
782 for files that were open readwrite or writable. */
783 if (fsp
->can_write
) {
784 TALLOC_CTX
*ctx
= talloc_tos();
785 notify_scanner(handle
, construct_full_path(
787 fsp
->fsp_name
->base_name
,false));
788 flush_sendbuffer(handle
);
790 return SMB_VFS_NEXT_CLOSE(handle
, fsp
);
793 static int scannedonly_rename(vfs_handle_struct
* handle
,
794 const struct smb_filename
*smb_fname_src
,
795 const struct smb_filename
*smb_fname_dst
)
797 /* rename the cache file before we pass the actual rename on */
798 struct smb_filename
*smb_fname_src_tmp
= NULL
;
799 struct smb_filename
*smb_fname_dst_tmp
= NULL
;
800 char *cachefile_src
, *cachefile_dst
;
801 bool needscandst
=false;
803 TALLOC_CTX
*ctx
= talloc_tos();
805 /* Setup temporary smb_filename structs. */
806 cachefile_src
= cachefile_name_f_fullpath(
808 smb_fname_src
->base_name
,
809 STRUCTSCANO(handle
->data
)->p_scanned
);
810 cachefile_dst
= cachefile_name_f_fullpath(
812 smb_fname_dst
->base_name
,
813 STRUCTSCANO(handle
->data
)->p_scanned
);
814 create_synthetic_smb_fname(ctx
, cachefile_src
,NULL
,NULL
,
816 create_synthetic_smb_fname(ctx
, cachefile_dst
,NULL
,NULL
,
819 ret
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src_tmp
, smb_fname_dst_tmp
);
822 } else if (ret
!= 0) {
823 DEBUG(SCANNEDONLY_DEBUG
,
824 ("failed to rename %s into %s error %d: %s\n", cachefile_src
,
825 cachefile_dst
, ret
, strerror(ret
)));
828 ret
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
829 if (ret
== 0 && needscandst
) {
830 notify_scanner(handle
, smb_fname_dst
->base_name
);
831 flush_sendbuffer(handle
);
836 static int scannedonly_unlink(vfs_handle_struct
* handle
,
837 const struct smb_filename
*smb_fname
)
839 /* unlink the 'scanned' file too */
840 struct smb_filename
*smb_fname_cache
= NULL
;
842 TALLOC_CTX
*ctx
= talloc_tos();
844 cachefile
= cachefile_name_f_fullpath(
846 smb_fname
->base_name
,
847 STRUCTSCANO(handle
->data
)->p_scanned
);
848 create_synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
,
850 if (SMB_VFS_NEXT_UNLINK(handle
, smb_fname_cache
) != 0) {
851 DEBUG(SCANNEDONLY_DEBUG
, ("_unlink: failed to unlink %s\n",
852 smb_fname_cache
->base_name
));
854 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
857 static int scannedonly_rmdir(vfs_handle_struct
* handle
, const char *path
)
859 /* if there are only .scanned: .virus: or .failed: files, we delete
860 those, because the client cannot see them */
862 SMB_STRUCT_DIRENT
*dire
;
863 TALLOC_CTX
*ctx
= talloc_tos();
864 bool only_deletable_files
= true, have_files
= false;
867 if (!STRUCTSCANO(handle
->data
)->rm_hidden_files_on_rmdir
)
868 return SMB_VFS_NEXT_RMDIR(handle
, path
);
870 path_w_slash
= name_w_ending_slash(ctx
,path
);
871 dirp
= SMB_VFS_NEXT_OPENDIR(handle
, path
, NULL
, 0);
875 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
)) != NULL
) {
876 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
880 if (!is_scannedonly_file(STRUCTSCANO(handle
->data
),
882 struct smb_filename
*smb_fname
= NULL
;
886 if (STRUCTSCANO(handle
->data
)->show_special_files
) {
887 only_deletable_files
= false;
890 /* stat the file and see if it is a
892 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
894 create_synthetic_smb_fname(ctx
, fullpath
,NULL
,NULL
,
896 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
898 && S_ISREG(smb_fname
->st
.st_ex_mode
)) {
899 only_deletable_files
= false;
901 TALLOC_FREE(fullpath
);
902 TALLOC_FREE(smb_fname
);
906 DEBUG(SCANNEDONLY_DEBUG
,
907 ("path=%s, have_files=%d, only_deletable_files=%d\n",
908 path
, have_files
, only_deletable_files
));
909 if (have_files
&& only_deletable_files
) {
910 DEBUG(SCANNEDONLY_DEBUG
,
911 ("scannedonly_rmdir, remove leftover scannedonly "
912 "files from %s\n", path_w_slash
));
913 SMB_VFS_NEXT_REWINDDIR(handle
, dirp
);
914 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
))
917 struct smb_filename
*smb_fname
= NULL
;
918 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
921 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
923 create_synthetic_smb_fname(ctx
, fullpath
,NULL
,NULL
,
925 DEBUG(SCANNEDONLY_DEBUG
, ("unlink %s\n", fullpath
));
926 SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
927 TALLOC_FREE(fullpath
);
928 TALLOC_FREE(smb_fname
);
931 SMB_VFS_NEXT_CLOSEDIR(handle
, dirp
);
932 return SMB_VFS_NEXT_RMDIR(handle
, path
);
935 static void free_scannedonly_data(void **data
)
940 static int scannedonly_connect(struct vfs_handle_struct
*handle
,
941 const char *service
, const char *user
)
944 struct Tscannedonly
*so
;
946 so
= SMB_MALLOC_P(struct Tscannedonly
);
947 handle
->data
= (void *)so
;
948 handle
->free_data
= free_scannedonly_data
;
949 so
->gsendbuffer
[0]='\0';
951 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
952 "domain_socket", True
);
953 so
->socketname
= lp_parm_const_string(SNUM(handle
->conn
),
954 "scannedonly", "socketname",
955 "/var/lib/scannedonly/scan");
958 lp_parm_int(SNUM(handle
->conn
), "scannedonly", "portnum",
960 so
->scanhost
= lp_parm_const_string(SNUM(handle
->conn
),
961 "scannedonly", "scanhost",
964 so
->show_special_files
=
965 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
966 "show_special_files", True
);
967 so
->rm_hidden_files_on_rmdir
=
968 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
969 "rm_hidden_files_on_rmdir", True
);
970 so
->hide_nonscanned_files
=
971 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
972 "hide_nonscanned_files", False
);
973 so
->allow_nonscanned_files
=
974 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
975 "allow_nonscanned_files", False
);
976 so
->scanning_message
= lp_parm_const_string(SNUM(handle
->conn
),
979 "is being scanned for viruses");
980 so
->scanning_message_len
= strlen(so
->scanning_message
);
981 so
->recheck_time_open
=
982 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
983 "recheck_time_open", 50);
984 so
->recheck_tries_open
=
985 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
986 "recheck_tries_open", 100);
987 so
->recheck_size_open
=
988 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
989 "recheck_size_open", 100);
990 so
->recheck_time_readdir
=
991 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
992 "recheck_time_readdir", 50);
993 so
->recheck_tries_readdir
=
994 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
995 "recheck_tries_readdir", 20);
998 lp_parm_const_string(SNUM(handle
->conn
),
1003 lp_parm_const_string(SNUM(handle
->conn
),
1008 lp_parm_const_string(SNUM(handle
->conn
),
1012 connect_to_scanner(handle
);
1014 return SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
1017 /* VFS operations structure */
1018 static struct vfs_fn_pointers vfs_scannedonly_fns
= {
1019 .opendir
= scannedonly_opendir
,
1020 .fdopendir
= scannedonly_fdopendir
,
1021 .readdir
= scannedonly_readdir
,
1022 .seekdir
= scannedonly_seekdir
,
1023 .telldir
= scannedonly_telldir
,
1024 .rewind_dir
= scannedonly_rewinddir
,
1025 .closedir
= scannedonly_closedir
,
1026 .rmdir
= scannedonly_rmdir
,
1027 .stat
= scannedonly_stat
,
1028 .lstat
= scannedonly_lstat
,
1029 .open_fn
= scannedonly_open
,
1030 .close_fn
= scannedonly_close
,
1031 .rename
= scannedonly_rename
,
1032 .unlink
= scannedonly_unlink
,
1033 .connect_fn
= scannedonly_connect
1036 NTSTATUS
vfs_scannedonly_init(void)
1038 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "scannedonly",
1039 &vfs_scannedonly_fns
);