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 /* FIXME ! Truncate checks... JRA. */
331 (void)strlcat(so
->gsendbuffer
, tmp
, SENDBUFFERSIZE
+ 1);
332 (void)strlcat(so
->gsendbuffer
, "\n", SENDBUFFERSIZE
+ 1);
335 static bool is_scannedonly_file(struct Tscannedonly
*so
, const char *shortname
)
337 if (shortname
[0]!='.') {
340 if (strncmp(shortname
, so
->p_scanned
, strlen(so
->p_scanned
)) == 0) {
343 if (strncmp(shortname
, so
->p_virus
, strlen(so
->p_virus
)) == 0) {
346 if (strncmp(shortname
, so
->p_failed
, strlen(so
->p_failed
)) == 0) {
352 static bool timespec_is_newer(struct timespec
*base
, struct timespec
*test
)
354 return timespec_compare(base
,test
) < 0;
358 vfs_handle_struct *handle the scannedonly handle
359 scannedonly_DIR * sDIR the scannedonly struct if called from _readdir()
361 fullpath is a full path starting from / or a relative path to the
362 current working directory
363 shortname is the filename without directory components
364 basename, is the directory without file name component
365 allow_nonexistant return TRUE if stat() on the requested file fails
366 recheck_time, the time in milliseconds to wait for the daemon to
367 create a .scanned file
368 recheck_tries, the number of tries to wait
369 recheck_size, size in Kb of files that should not be waited for
370 loop : boolean if we should try to loop over all files in the directory
371 and send a notify to the scanner for all files that need scanning
373 static bool scannedonly_allow_access(vfs_handle_struct
* handle
,
374 struct scannedonly_DIR
*sDIR
,
375 struct smb_filename
*smb_fname
,
376 const char *shortname
,
377 const char *base_name
,
378 int allow_nonexistant
,
379 int recheck_time
, int recheck_tries
,
380 int recheck_size
, int loop
)
382 struct smb_filename
*cache_smb_fname
;
383 TALLOC_CTX
*ctx
=talloc_tos();
386 DEBUG(SCANNEDONLY_DEBUG
,
387 ("smb_fname->base_name=%s, shortname=%s, base_name=%s\n"
388 ,smb_fname
->base_name
,shortname
,base_name
));
390 if (ISDOT(shortname
) || ISDOTDOT(shortname
)) {
393 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), shortname
)) {
394 DEBUG(SCANNEDONLY_DEBUG
,
395 ("scannedonly_allow_access, %s is a scannedonly file, "
396 "return 0\n", shortname
));
400 if (!VALID_STAT(smb_fname
->st
)) {
401 DEBUG(SCANNEDONLY_DEBUG
,("stat %s\n",smb_fname
->base_name
));
402 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
404 /* failed to stat this file?!? --> hide it */
405 DEBUG(SCANNEDONLY_DEBUG
,("no valid stat, return"
406 " allow_nonexistant=%d\n",
408 return allow_nonexistant
;
411 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
412 DEBUG(SCANNEDONLY_DEBUG
,
413 ("%s is not a regular file, ISDIR=%d\n",
414 smb_fname
->base_name
,
415 S_ISDIR(smb_fname
->st
.st_ex_mode
)));
416 return (STRUCTSCANO(handle
->data
)->
417 show_special_files
||
418 S_ISDIR(smb_fname
->st
.st_ex_mode
));
420 if (smb_fname
->st
.st_ex_size
== 0) {
421 DEBUG(SCANNEDONLY_DEBUG
,("empty file, return 1\n"));
422 return true; /* empty files cannot contain viruses ! */
424 cachefile
= cachefile_name(ctx
,
427 STRUCTSCANO(handle
->data
)->p_scanned
);
428 create_synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
,&cache_smb_fname
);
429 if (!VALID_STAT(cache_smb_fname
->st
)) {
430 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
432 if (retval
== 0 && VALID_STAT(cache_smb_fname
->st
)) {
433 if (timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
434 &cache_smb_fname
->st
.st_ex_ctime
)) {
435 talloc_free(cache_smb_fname
);
438 /* no cachefile or too old */
439 SMB_VFS_NEXT_UNLINK(handle
, cache_smb_fname
);
443 notify_scanner(handle
, smb_fname
->base_name
);
445 if (loop
&& sDIR
&& sDIR
->recheck_tries_done
== 0) {
446 /* check the rest of the directory and notify the
447 scanner if some file needs scanning */
451 offset
= SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
452 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, NULL
);
455 struct smb_filename
*smb_fname2
;
456 fpath2
= talloc_asprintf(ctx
, "%s%s", base_name
,dire
->d_name
);
457 DEBUG(SCANNEDONLY_DEBUG
,
458 ("scannedonly_allow_access in loop, "
459 "found %s\n", fpath2
));
460 create_synthetic_smb_fname(ctx
, fpath2
,NULL
,NULL
,
462 scannedonly_allow_access(handle
, NULL
,
465 base_name
, 0, 0, 0, 0, 0);
467 talloc_free(smb_fname2
);
468 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR,NULL
);
470 sDIR
->recheck_tries_done
= 1;
471 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
474 && ((recheck_size
> 0
475 && smb_fname
->st
.st_ex_size
< (1024 * recheck_size
))
476 || (sDIR
&& sDIR
->recheck_tries_done
< recheck_tries
)
478 int numloops
= sDIR
? sDIR
->recheck_tries_done
: 0;
479 flush_sendbuffer(handle
);
480 while (retval
!= 0 /*&& errno == ENOENT */
481 && numloops
< recheck_tries
) {
482 DEBUG(SCANNEDONLY_DEBUG
,
483 ("scannedonly_allow_access, wait (try=%d "
484 "(max %d), %d ms) for %s\n",
485 numloops
, recheck_tries
,
486 recheck_time
, cache_smb_fname
->base_name
));
487 smb_msleep(recheck_time
);
488 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
492 sDIR
->recheck_tries_done
= numloops
;
494 /* still no cachefile, or still too old, return 0 */
496 || !timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
497 &cache_smb_fname
->st
.st_ex_ctime
)) {
498 DEBUG(SCANNEDONLY_DEBUG
,
499 ("retval=%d, return 0\n",retval
));
505 /*********************/
507 /*********************/
509 static DIR *scannedonly_opendir(vfs_handle_struct
* handle
,
511 const char *mask
, uint32 attr
)
514 struct scannedonly_DIR
*sDIR
;
516 DIRp
= SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
521 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
522 if (fname
[0] != '/') {
523 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
525 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
527 DEBUG(SCANNEDONLY_DEBUG
,
528 ("scannedonly_opendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
530 sDIR
->recheck_tries_done
= 0;
534 static DIR *scannedonly_fdopendir(vfs_handle_struct
* handle
,
536 const char *mask
, uint32 attr
)
539 struct scannedonly_DIR
*sDIR
;
542 DIRp
= SMB_VFS_NEXT_FDOPENDIR(handle
, fsp
, mask
, attr
);
547 fname
= (const char *)fsp
->fsp_name
->base_name
;
549 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
550 if (fname
[0] != '/') {
551 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
553 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
555 DEBUG(SCANNEDONLY_DEBUG
,
556 ("scannedonly_fdopendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
558 sDIR
->recheck_tries_done
= 0;
563 static struct dirent
*scannedonly_readdir(vfs_handle_struct
*handle
,
565 SMB_STRUCT_STAT
*sbuf
)
567 struct dirent
*result
;
570 struct smb_filename
*smb_fname
;
573 struct dirent
*newdirent
;
574 TALLOC_CTX
*ctx
=talloc_tos();
576 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
581 result
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, sbuf
);
586 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), result
->d_name
)) {
587 DEBUG(SCANNEDONLY_DEBUG
,
588 ("scannedonly_readdir, %s is a scannedonly file, "
589 "skip to next entry\n", result
->d_name
));
590 return scannedonly_readdir(handle
, dirp
, NULL
);
592 tmp
= talloc_asprintf(ctx
, "%s%s", sDIR
->base
, result
->d_name
);
593 DEBUG(SCANNEDONLY_DEBUG
,
594 ("scannedonly_readdir, check access to %s (sbuf=%p)\n",
597 /* even if we don't hide nonscanned files or we allow non scanned
598 files we call allow_access because it will notify the daemon to
600 create_synthetic_smb_fname(ctx
, tmp
,NULL
,
601 sbuf
?VALID_STAT(*sbuf
)?sbuf
:NULL
:NULL
,
603 allowed
= scannedonly_allow_access(
604 handle
, sDIR
, smb_fname
,
607 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
608 ? STRUCTSCANO(handle
->data
)->recheck_time_readdir
610 STRUCTSCANO(handle
->data
)->recheck_tries_readdir
,
613 DEBUG(SCANNEDONLY_DEBUG
,
614 ("scannedonly_readdir access to %s (%s) = %d\n", tmp
,
615 result
->d_name
, allowed
));
619 DEBUG(SCANNEDONLY_DEBUG
,
620 ("hide_nonscanned_files=%d, allow_nonscanned_files=%d\n",
621 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
,
622 STRUCTSCANO(handle
->data
)->allow_nonscanned_files
625 if (!STRUCTSCANO(handle
->data
)->hide_nonscanned_files
626 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
630 DEBUG(SCANNEDONLY_DEBUG
,
631 ("scannedonly_readdir, readdir listing for %s not "
632 "allowed, notify user\n", result
->d_name
));
633 notify_name
= talloc_asprintf(
634 ctx
,"%s %s",result
->d_name
,
635 STRUCTSCANO(handle
->data
)->scanning_message
);
636 namelen
= strlen(notify_name
);
637 newdirent
= (struct dirent
*)talloc_array(
638 ctx
, char, sizeof(struct dirent
) + namelen
+ 1);
642 memcpy(newdirent
, result
, sizeof(struct dirent
));
643 memcpy(&newdirent
->d_name
, notify_name
, namelen
+ 1);
644 DEBUG(SCANNEDONLY_DEBUG
,
645 ("scannedonly_readdir, return newdirent at %p with "
646 "notification %s\n", newdirent
, newdirent
->d_name
));
650 static void scannedonly_seekdir(struct vfs_handle_struct
*handle
,
651 DIR * dirp
, long offset
)
653 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
654 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
657 static long scannedonly_telldir(struct vfs_handle_struct
*handle
,
660 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
661 return SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
664 static void scannedonly_rewinddir(struct vfs_handle_struct
*handle
,
667 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
668 SMB_VFS_NEXT_REWINDDIR(handle
, sDIR
->DIR);
671 static int scannedonly_closedir(vfs_handle_struct
* handle
,
675 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
676 flush_sendbuffer(handle
);
677 retval
= SMB_VFS_NEXT_CLOSEDIR(handle
, sDIR
->DIR);
682 static int scannedonly_stat(vfs_handle_struct
* handle
,
683 struct smb_filename
*smb_fname
)
686 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
687 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_stat: %s returned %d\n",
688 smb_fname
->base_name
, ret
));
689 if (ret
!= 0 && errno
== ENOENT
) {
690 TALLOC_CTX
*ctx
=talloc_tos();
691 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
692 /* possibly this was a fake name (file is being scanned for
693 viruses.txt): check for that and create the real name and
694 stat the real name */
695 test_base_name
= real_path_from_notify_path(
697 STRUCTSCANO(handle
->data
),
698 smb_fname
->base_name
);
699 if (test_base_name
) {
700 smb_fname
->base_name
= test_base_name
;
701 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
702 DEBUG(5, ("_stat: %s returned %d\n",
703 test_base_name
, ret
));
704 smb_fname
->base_name
= tmp_base_name
;
710 static int scannedonly_lstat(vfs_handle_struct
* handle
,
711 struct smb_filename
*smb_fname
)
714 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
715 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_lstat: %s returned %d\n",
716 smb_fname
->base_name
, ret
));
717 if (ret
!= 0 && errno
== ENOENT
) {
718 TALLOC_CTX
*ctx
=talloc_tos();
719 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
720 /* possibly this was a fake name (file is being scanned for
721 viruses.txt): check for that and create the real name and
722 stat the real name */
723 test_base_name
= real_path_from_notify_path(
724 ctx
, STRUCTSCANO(handle
->data
), smb_fname
->base_name
);
725 if (test_base_name
) {
726 smb_fname
->base_name
= test_base_name
;
727 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
728 DEBUG(5, ("_lstat: %s returned %d\n",
729 test_base_name
, ret
));
730 smb_fname
->base_name
= tmp_base_name
;
736 static int scannedonly_open(vfs_handle_struct
* handle
,
737 struct smb_filename
*smb_fname
,
738 files_struct
* fsp
, int flags
, mode_t mode
)
741 char *tmp
, *shortname
;
742 int allowed
, write_access
= 0;
743 TALLOC_CTX
*ctx
=talloc_tos();
744 /* if open for writing ignore it */
745 if ((flags
& O_ACCMODE
) == O_WRONLY
) {
746 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
748 if ((flags
& O_ACCMODE
) == O_RDWR
) {
751 /* check if this file is scanned already */
752 tmp
= strrchr(smb_fname
->base_name
, '/');
754 base
= talloc_strndup(ctx
,smb_fname
->base_name
,
755 (tmp
- smb_fname
->base_name
) + 1);
759 shortname
= (char *)smb_fname
->base_name
;
761 allowed
= scannedonly_allow_access(
762 handle
, NULL
, smb_fname
, shortname
,
765 STRUCTSCANO(handle
->data
)->recheck_time_open
,
766 STRUCTSCANO(handle
->data
)->recheck_tries_open
,
767 STRUCTSCANO(handle
->data
)->recheck_size_open
,
769 flush_sendbuffer(handle
);
770 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_open: allow=%d for %s\n",
771 allowed
, smb_fname
->base_name
));
773 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
774 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
780 static int scannedonly_close(vfs_handle_struct
* handle
, files_struct
* fsp
)
782 /* we only have to notify the scanner
783 for files that were open readwrite or writable. */
784 if (fsp
->can_write
) {
785 TALLOC_CTX
*ctx
= talloc_tos();
786 notify_scanner(handle
, construct_full_path(
788 fsp
->fsp_name
->base_name
,false));
789 flush_sendbuffer(handle
);
791 return SMB_VFS_NEXT_CLOSE(handle
, fsp
);
794 static int scannedonly_rename(vfs_handle_struct
* handle
,
795 const struct smb_filename
*smb_fname_src
,
796 const struct smb_filename
*smb_fname_dst
)
798 /* rename the cache file before we pass the actual rename on */
799 struct smb_filename
*smb_fname_src_tmp
= NULL
;
800 struct smb_filename
*smb_fname_dst_tmp
= NULL
;
801 char *cachefile_src
, *cachefile_dst
;
802 bool needscandst
=false;
804 TALLOC_CTX
*ctx
= talloc_tos();
806 /* Setup temporary smb_filename structs. */
807 cachefile_src
= cachefile_name_f_fullpath(
809 smb_fname_src
->base_name
,
810 STRUCTSCANO(handle
->data
)->p_scanned
);
811 cachefile_dst
= cachefile_name_f_fullpath(
813 smb_fname_dst
->base_name
,
814 STRUCTSCANO(handle
->data
)->p_scanned
);
815 create_synthetic_smb_fname(ctx
, cachefile_src
,NULL
,NULL
,
817 create_synthetic_smb_fname(ctx
, cachefile_dst
,NULL
,NULL
,
820 ret
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src_tmp
, smb_fname_dst_tmp
);
823 } else if (ret
!= 0) {
824 DEBUG(SCANNEDONLY_DEBUG
,
825 ("failed to rename %s into %s error %d: %s\n", cachefile_src
,
826 cachefile_dst
, ret
, strerror(ret
)));
829 ret
= SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
830 if (ret
== 0 && needscandst
) {
831 notify_scanner(handle
, smb_fname_dst
->base_name
);
832 flush_sendbuffer(handle
);
837 static int scannedonly_unlink(vfs_handle_struct
* handle
,
838 const struct smb_filename
*smb_fname
)
840 /* unlink the 'scanned' file too */
841 struct smb_filename
*smb_fname_cache
= NULL
;
843 TALLOC_CTX
*ctx
= talloc_tos();
845 cachefile
= cachefile_name_f_fullpath(
847 smb_fname
->base_name
,
848 STRUCTSCANO(handle
->data
)->p_scanned
);
849 create_synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
,
851 if (SMB_VFS_NEXT_UNLINK(handle
, smb_fname_cache
) != 0) {
852 DEBUG(SCANNEDONLY_DEBUG
, ("_unlink: failed to unlink %s\n",
853 smb_fname_cache
->base_name
));
855 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
858 static int scannedonly_rmdir(vfs_handle_struct
* handle
, const char *path
)
860 /* if there are only .scanned: .virus: or .failed: files, we delete
861 those, because the client cannot see them */
864 TALLOC_CTX
*ctx
= talloc_tos();
865 bool only_deletable_files
= true, have_files
= false;
868 if (!STRUCTSCANO(handle
->data
)->rm_hidden_files_on_rmdir
)
869 return SMB_VFS_NEXT_RMDIR(handle
, path
);
871 path_w_slash
= name_w_ending_slash(ctx
,path
);
872 dirp
= SMB_VFS_NEXT_OPENDIR(handle
, path
, NULL
, 0);
876 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
)) != NULL
) {
877 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
881 if (!is_scannedonly_file(STRUCTSCANO(handle
->data
),
883 struct smb_filename
*smb_fname
= NULL
;
887 if (STRUCTSCANO(handle
->data
)->show_special_files
) {
888 only_deletable_files
= false;
891 /* stat the file and see if it is a
893 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
895 create_synthetic_smb_fname(ctx
, fullpath
,NULL
,NULL
,
897 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
899 && S_ISREG(smb_fname
->st
.st_ex_mode
)) {
900 only_deletable_files
= false;
902 TALLOC_FREE(fullpath
);
903 TALLOC_FREE(smb_fname
);
907 DEBUG(SCANNEDONLY_DEBUG
,
908 ("path=%s, have_files=%d, only_deletable_files=%d\n",
909 path
, have_files
, only_deletable_files
));
910 if (have_files
&& only_deletable_files
) {
911 DEBUG(SCANNEDONLY_DEBUG
,
912 ("scannedonly_rmdir, remove leftover scannedonly "
913 "files from %s\n", path_w_slash
));
914 SMB_VFS_NEXT_REWINDDIR(handle
, dirp
);
915 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
))
918 struct smb_filename
*smb_fname
= NULL
;
919 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
922 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
924 create_synthetic_smb_fname(ctx
, fullpath
,NULL
,NULL
,
926 DEBUG(SCANNEDONLY_DEBUG
, ("unlink %s\n", fullpath
));
927 SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
928 TALLOC_FREE(fullpath
);
929 TALLOC_FREE(smb_fname
);
932 SMB_VFS_NEXT_CLOSEDIR(handle
, dirp
);
933 return SMB_VFS_NEXT_RMDIR(handle
, path
);
936 static void free_scannedonly_data(void **data
)
941 static int scannedonly_connect(struct vfs_handle_struct
*handle
,
942 const char *service
, const char *user
)
945 struct Tscannedonly
*so
;
947 so
= SMB_MALLOC_P(struct Tscannedonly
);
952 handle
->data
= (void *)so
;
953 handle
->free_data
= free_scannedonly_data
;
954 so
->gsendbuffer
[0]='\0';
956 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
957 "domain_socket", True
);
958 so
->socketname
= lp_parm_const_string(SNUM(handle
->conn
),
959 "scannedonly", "socketname",
960 "/var/lib/scannedonly/scan");
963 lp_parm_int(SNUM(handle
->conn
), "scannedonly", "portnum",
965 so
->scanhost
= lp_parm_const_string(SNUM(handle
->conn
),
966 "scannedonly", "scanhost",
969 so
->show_special_files
=
970 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
971 "show_special_files", True
);
972 so
->rm_hidden_files_on_rmdir
=
973 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
974 "rm_hidden_files_on_rmdir", True
);
975 so
->hide_nonscanned_files
=
976 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
977 "hide_nonscanned_files", False
);
978 so
->allow_nonscanned_files
=
979 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
980 "allow_nonscanned_files", False
);
981 so
->scanning_message
= lp_parm_const_string(SNUM(handle
->conn
),
984 "is being scanned for viruses");
985 so
->scanning_message_len
= strlen(so
->scanning_message
);
986 so
->recheck_time_open
=
987 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
988 "recheck_time_open", 50);
989 so
->recheck_tries_open
=
990 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
991 "recheck_tries_open", 100);
992 so
->recheck_size_open
=
993 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
994 "recheck_size_open", 100);
995 so
->recheck_time_readdir
=
996 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
997 "recheck_time_readdir", 50);
998 so
->recheck_tries_readdir
=
999 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
1000 "recheck_tries_readdir", 20);
1003 lp_parm_const_string(SNUM(handle
->conn
),
1008 lp_parm_const_string(SNUM(handle
->conn
),
1013 lp_parm_const_string(SNUM(handle
->conn
),
1017 connect_to_scanner(handle
);
1019 return SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
1022 /* VFS operations structure */
1023 static struct vfs_fn_pointers vfs_scannedonly_fns
= {
1024 .opendir_fn
= scannedonly_opendir
,
1025 .fdopendir_fn
= scannedonly_fdopendir
,
1026 .readdir_fn
= scannedonly_readdir
,
1027 .seekdir_fn
= scannedonly_seekdir
,
1028 .telldir_fn
= scannedonly_telldir
,
1029 .rewind_dir_fn
= scannedonly_rewinddir
,
1030 .closedir_fn
= scannedonly_closedir
,
1031 .rmdir_fn
= scannedonly_rmdir
,
1032 .stat_fn
= scannedonly_stat
,
1033 .lstat_fn
= scannedonly_lstat
,
1034 .open_fn
= scannedonly_open
,
1035 .close_fn
= scannedonly_close
,
1036 .rename_fn
= scannedonly_rename
,
1037 .unlink_fn
= scannedonly_unlink
,
1038 .connect_fn
= scannedonly_connect
1041 NTSTATUS
vfs_scannedonly_init(void)
1043 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "scannedonly",
1044 &vfs_scannedonly_fns
);