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 if (getsockopt(so
->socket
, SOL_SOCKET
, SO_RCVBUF
,
232 (char *)&sndsize
, &size
) == 0) {
233 DEBUG(SCANNEDONLY_DEBUG
,
234 ("current socket buffer size=%d\n",
238 if (setsockopt(so
->socket
, SOL_SOCKET
, SO_RCVBUF
,
240 (int)sizeof(sndsize
)) != 0) {
241 DEBUG(SCANNEDONLY_DEBUG
,
242 ("error setting socket buffer %s (%d)\n",
243 strerror(errno
), errno
));
246 set_blocking(so
->socket
, false);
250 static void flush_sendbuffer(vfs_handle_struct
* handle
)
252 struct Tscannedonly
*so
= (struct Tscannedonly
*)handle
->data
;
253 int ret
, len
, loop
= 10;
254 if (so
->gsendbuffer
[0] == '\0') {
260 len
= strlen(so
->gsendbuffer
);
261 ret
= send(so
->socket
, so
->gsendbuffer
, len
, 0);
263 so
->gsendbuffer
[0] = '\0';
267 DEBUG(3,("scannedonly flush_sendbuffer: "
268 "error sending on socket %d to scanner:"
270 so
->socket
, strerror(errno
), errno
));
271 if (errno
== ECONNREFUSED
|| errno
== ENOTCONN
272 || errno
== ECONNRESET
) {
273 if (connect_to_scanner(handle
) == -1)
274 break; /* connecting fails, abort */
276 } else if (errno
!= EINTR
) {
277 /* on EINTR we just try again, all remaining
278 other errors we log the error
279 and try again ONCE */
281 DEBUG(3,("scannedonly flush_sendbuffer: "
282 "error sending data to scanner: %s "
283 "(%d)\n", strerror(errno
), errno
));
286 /* --> partial write: Resend all filenames that were
287 not or not completely written. a partial filename
288 written means the filename will not arrive correctly,
289 so resend it completely */
292 char *tmp
= strchr(so
->gsendbuffer
+pos
, '\n');
293 if (tmp
&& tmp
- so
->gsendbuffer
< ret
)
294 pos
= tmp
- so
->gsendbuffer
+ 1;
298 memmove(so
->gsendbuffer
, so
->gsendbuffer
+ pos
,
299 SENDBUFFERSIZE
- ret
);
304 if (so
->gsendbuffer
[0] != '\0') {
306 ("scannedonly flush_sendbuffer: "
307 "failed to send files to AV scanner, "
308 "discarding files."));
309 so
->gsendbuffer
[0] = '\0';
313 static void notify_scanner(vfs_handle_struct
* handle
, const char *scanfile
)
316 int tmplen
, gsendlen
;
317 struct Tscannedonly
*so
= (struct Tscannedonly
*)handle
->data
;
318 TALLOC_CTX
*ctx
=talloc_tos();
319 if (scanfile
[0] != '/') {
320 tmp
= construct_full_path(ctx
,handle
, scanfile
, false);
322 tmp
= (const char *)scanfile
;
324 tmplen
= strlen(tmp
);
325 gsendlen
= strlen(so
->gsendbuffer
);
326 DEBUG(SCANNEDONLY_DEBUG
,
327 ("scannedonly notify_scanner: tmp=%s, tmplen=%d, gsendlen=%d\n",
328 tmp
, tmplen
, gsendlen
));
329 if (gsendlen
+ tmplen
>= SENDBUFFERSIZE
) {
330 flush_sendbuffer(handle
);
332 /* FIXME ! Truncate checks... JRA. */
333 (void)strlcat(so
->gsendbuffer
, tmp
, SENDBUFFERSIZE
+ 1);
334 (void)strlcat(so
->gsendbuffer
, "\n", SENDBUFFERSIZE
+ 1);
337 static bool is_scannedonly_file(struct Tscannedonly
*so
, const char *shortname
)
339 if (shortname
[0]!='.') {
342 if (strncmp(shortname
, so
->p_scanned
, strlen(so
->p_scanned
)) == 0) {
345 if (strncmp(shortname
, so
->p_virus
, strlen(so
->p_virus
)) == 0) {
348 if (strncmp(shortname
, so
->p_failed
, strlen(so
->p_failed
)) == 0) {
354 static bool timespec_is_newer(struct timespec
*base
, struct timespec
*test
)
356 return timespec_compare(base
,test
) < 0;
360 vfs_handle_struct *handle the scannedonly handle
361 scannedonly_DIR * sDIR the scannedonly struct if called from _readdir()
363 fullpath is a full path starting from / or a relative path to the
364 current working directory
365 shortname is the filename without directory components
366 basename, is the directory without file name component
367 allow_nonexistent return TRUE if stat() on the requested file fails
368 recheck_time, the time in milliseconds to wait for the daemon to
369 create a .scanned file
370 recheck_tries, the number of tries to wait
371 recheck_size, size in Kb of files that should not be waited for
372 loop : boolean if we should try to loop over all files in the directory
373 and send a notify to the scanner for all files that need scanning
375 static bool scannedonly_allow_access(vfs_handle_struct
* handle
,
376 struct scannedonly_DIR
*sDIR
,
377 struct smb_filename
*smb_fname
,
378 const char *shortname
,
379 const char *base_name
,
380 int allow_nonexistent
,
381 int recheck_time
, int recheck_tries
,
382 int recheck_size
, int loop
)
384 struct smb_filename
*cache_smb_fname
;
385 TALLOC_CTX
*ctx
=talloc_tos();
388 DEBUG(SCANNEDONLY_DEBUG
,
389 ("smb_fname->base_name=%s, shortname=%s, base_name=%s\n"
390 ,smb_fname
->base_name
,shortname
,base_name
));
392 if (ISDOT(shortname
) || ISDOTDOT(shortname
)) {
395 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), shortname
)) {
396 DEBUG(SCANNEDONLY_DEBUG
,
397 ("scannedonly_allow_access, %s is a scannedonly file, "
398 "return 0\n", shortname
));
402 if (!VALID_STAT(smb_fname
->st
)) {
403 DEBUG(SCANNEDONLY_DEBUG
,("stat %s\n",smb_fname
->base_name
));
404 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
406 /* failed to stat this file?!? --> hide it */
407 DEBUG(SCANNEDONLY_DEBUG
,("no valid stat, return"
408 " allow_nonexistent=%d\n",
410 return allow_nonexistent
;
413 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
414 DEBUG(SCANNEDONLY_DEBUG
,
415 ("%s is not a regular file, ISDIR=%d\n",
416 smb_fname
->base_name
,
417 S_ISDIR(smb_fname
->st
.st_ex_mode
)));
418 return (STRUCTSCANO(handle
->data
)->
419 show_special_files
||
420 S_ISDIR(smb_fname
->st
.st_ex_mode
));
422 if (smb_fname
->st
.st_ex_size
== 0) {
423 DEBUG(SCANNEDONLY_DEBUG
,("empty file, return 1\n"));
424 return true; /* empty files cannot contain viruses ! */
426 cachefile
= cachefile_name(ctx
,
429 STRUCTSCANO(handle
->data
)->p_scanned
);
430 cache_smb_fname
= synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
);
431 if (!VALID_STAT(cache_smb_fname
->st
)) {
432 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
434 if (retval
== 0 && VALID_STAT(cache_smb_fname
->st
)) {
435 if (timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
436 &cache_smb_fname
->st
.st_ex_ctime
)) {
437 talloc_free(cache_smb_fname
);
440 /* no cachefile or too old */
441 SMB_VFS_NEXT_UNLINK(handle
, cache_smb_fname
);
445 notify_scanner(handle
, smb_fname
->base_name
);
447 if (loop
&& sDIR
&& sDIR
->recheck_tries_done
== 0) {
448 /* check the rest of the directory and notify the
449 scanner if some file needs scanning */
453 offset
= SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
454 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, NULL
);
457 struct smb_filename
*smb_fname2
;
458 fpath2
= talloc_asprintf(ctx
, "%s%s", base_name
,dire
->d_name
);
459 DEBUG(SCANNEDONLY_DEBUG
,
460 ("scannedonly_allow_access in loop, "
461 "found %s\n", fpath2
));
462 smb_fname2
= synthetic_smb_fname(
463 ctx
, fpath2
,NULL
,NULL
);
464 scannedonly_allow_access(handle
, NULL
,
467 base_name
, 0, 0, 0, 0, 0);
469 talloc_free(smb_fname2
);
470 dire
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR,NULL
);
472 sDIR
->recheck_tries_done
= 1;
473 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
476 && ((recheck_size
> 0
477 && smb_fname
->st
.st_ex_size
< (1024 * recheck_size
))
478 || (sDIR
&& sDIR
->recheck_tries_done
< recheck_tries
)
480 int numloops
= sDIR
? sDIR
->recheck_tries_done
: 0;
481 flush_sendbuffer(handle
);
482 while (retval
!= 0 /*&& errno == ENOENT */
483 && numloops
< recheck_tries
) {
484 DEBUG(SCANNEDONLY_DEBUG
,
485 ("scannedonly_allow_access, wait (try=%d "
486 "(max %d), %d ms) for %s\n",
487 numloops
, recheck_tries
,
488 recheck_time
, cache_smb_fname
->base_name
));
489 smb_msleep(recheck_time
);
490 retval
= SMB_VFS_NEXT_STAT(handle
, cache_smb_fname
);
494 sDIR
->recheck_tries_done
= numloops
;
496 /* still no cachefile, or still too old, return 0 */
498 || !timespec_is_newer(&smb_fname
->st
.st_ex_ctime
,
499 &cache_smb_fname
->st
.st_ex_ctime
)) {
500 DEBUG(SCANNEDONLY_DEBUG
,
501 ("retval=%d, return 0\n",retval
));
507 /*********************/
509 /*********************/
511 static DIR *scannedonly_opendir(vfs_handle_struct
* handle
,
513 const char *mask
, uint32_t attr
)
516 struct scannedonly_DIR
*sDIR
;
518 DIRp
= SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
523 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
524 if (fname
[0] != '/') {
525 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
527 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
529 DEBUG(SCANNEDONLY_DEBUG
,
530 ("scannedonly_opendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
532 sDIR
->recheck_tries_done
= 0;
536 static DIR *scannedonly_fdopendir(vfs_handle_struct
* handle
,
538 const char *mask
, uint32_t attr
)
541 struct scannedonly_DIR
*sDIR
;
544 DIRp
= SMB_VFS_NEXT_FDOPENDIR(handle
, fsp
, mask
, attr
);
549 fname
= (const char *)fsp
->fsp_name
->base_name
;
551 sDIR
= talloc(NULL
, struct scannedonly_DIR
);
552 if (fname
[0] != '/') {
553 sDIR
->base
= construct_full_path(sDIR
,handle
, fname
, true);
555 sDIR
->base
= name_w_ending_slash(sDIR
, fname
);
557 DEBUG(SCANNEDONLY_DEBUG
,
558 ("scannedonly_fdopendir, fname=%s, base=%s\n",fname
,sDIR
->base
));
560 sDIR
->recheck_tries_done
= 0;
565 static struct dirent
*scannedonly_readdir(vfs_handle_struct
*handle
,
567 SMB_STRUCT_STAT
*sbuf
)
569 struct dirent
*result
;
572 struct smb_filename
*smb_fname
;
575 struct dirent
*newdirent
;
576 TALLOC_CTX
*ctx
=talloc_tos();
578 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
583 result
= SMB_VFS_NEXT_READDIR(handle
, sDIR
->DIR, sbuf
);
588 if (is_scannedonly_file(STRUCTSCANO(handle
->data
), result
->d_name
)) {
589 DEBUG(SCANNEDONLY_DEBUG
,
590 ("scannedonly_readdir, %s is a scannedonly file, "
591 "skip to next entry\n", result
->d_name
));
592 return scannedonly_readdir(handle
, dirp
, NULL
);
594 tmp
= talloc_asprintf(ctx
, "%s%s", sDIR
->base
, result
->d_name
);
595 DEBUG(SCANNEDONLY_DEBUG
,
596 ("scannedonly_readdir, check access to %s (sbuf=%p)\n",
599 /* even if we don't hide nonscanned files or we allow non scanned
600 files we call allow_access because it will notify the daemon to
602 smb_fname
= synthetic_smb_fname(ctx
, tmp
,NULL
,
603 sbuf
?VALID_STAT(*sbuf
)?sbuf
:NULL
:NULL
);
604 allowed
= scannedonly_allow_access(
605 handle
, sDIR
, smb_fname
,
608 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
609 ? STRUCTSCANO(handle
->data
)->recheck_time_readdir
611 STRUCTSCANO(handle
->data
)->recheck_tries_readdir
,
614 DEBUG(SCANNEDONLY_DEBUG
,
615 ("scannedonly_readdir access to %s (%s) = %d\n", tmp
,
616 result
->d_name
, allowed
));
620 DEBUG(SCANNEDONLY_DEBUG
,
621 ("hide_nonscanned_files=%d, allow_nonscanned_files=%d\n",
622 STRUCTSCANO(handle
->data
)->hide_nonscanned_files
,
623 STRUCTSCANO(handle
->data
)->allow_nonscanned_files
626 if (!STRUCTSCANO(handle
->data
)->hide_nonscanned_files
627 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
631 DEBUG(SCANNEDONLY_DEBUG
,
632 ("scannedonly_readdir, readdir listing for %s not "
633 "allowed, notify user\n", result
->d_name
));
634 notify_name
= talloc_asprintf(
635 ctx
,"%s %s",result
->d_name
,
636 STRUCTSCANO(handle
->data
)->scanning_message
);
637 namelen
= strlen(notify_name
);
638 newdirent
= (struct dirent
*)talloc_array(
639 ctx
, char, sizeof(struct dirent
) + namelen
+ 1);
643 memcpy(newdirent
, result
, sizeof(struct dirent
));
644 memcpy(&newdirent
->d_name
, notify_name
, namelen
+ 1);
645 DEBUG(SCANNEDONLY_DEBUG
,
646 ("scannedonly_readdir, return newdirent at %p with "
647 "notification %s\n", newdirent
, newdirent
->d_name
));
651 static void scannedonly_seekdir(struct vfs_handle_struct
*handle
,
652 DIR * dirp
, long offset
)
654 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
655 SMB_VFS_NEXT_SEEKDIR(handle
, sDIR
->DIR, offset
);
658 static long scannedonly_telldir(struct vfs_handle_struct
*handle
,
661 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
662 return SMB_VFS_NEXT_TELLDIR(handle
, sDIR
->DIR);
665 static void scannedonly_rewinddir(struct vfs_handle_struct
*handle
,
668 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
669 SMB_VFS_NEXT_REWINDDIR(handle
, sDIR
->DIR);
672 static int scannedonly_closedir(vfs_handle_struct
* handle
,
676 struct scannedonly_DIR
*sDIR
= (struct scannedonly_DIR
*)dirp
;
677 flush_sendbuffer(handle
);
678 retval
= SMB_VFS_NEXT_CLOSEDIR(handle
, sDIR
->DIR);
683 static int scannedonly_stat(vfs_handle_struct
* handle
,
684 struct smb_filename
*smb_fname
)
687 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
688 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_stat: %s returned %d\n",
689 smb_fname
->base_name
, ret
));
690 if (ret
!= 0 && errno
== ENOENT
) {
691 TALLOC_CTX
*ctx
=talloc_tos();
692 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
693 /* possibly this was a fake name (file is being scanned for
694 viruses.txt): check for that and create the real name and
695 stat the real name */
696 test_base_name
= real_path_from_notify_path(
698 STRUCTSCANO(handle
->data
),
699 smb_fname
->base_name
);
700 if (test_base_name
) {
701 smb_fname
->base_name
= test_base_name
;
702 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
703 DEBUG(5, ("_stat: %s returned %d\n",
704 test_base_name
, ret
));
705 smb_fname
->base_name
= tmp_base_name
;
711 static int scannedonly_lstat(vfs_handle_struct
* handle
,
712 struct smb_filename
*smb_fname
)
715 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
716 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_lstat: %s returned %d\n",
717 smb_fname
->base_name
, ret
));
718 if (ret
!= 0 && errno
== ENOENT
) {
719 TALLOC_CTX
*ctx
=talloc_tos();
720 char *test_base_name
, *tmp_base_name
= smb_fname
->base_name
;
721 /* possibly this was a fake name (file is being scanned for
722 viruses.txt): check for that and create the real name and
723 stat the real name */
724 test_base_name
= real_path_from_notify_path(
725 ctx
, STRUCTSCANO(handle
->data
), smb_fname
->base_name
);
726 if (test_base_name
) {
727 smb_fname
->base_name
= test_base_name
;
728 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
729 DEBUG(5, ("_lstat: %s returned %d\n",
730 test_base_name
, ret
));
731 smb_fname
->base_name
= tmp_base_name
;
737 static int scannedonly_open(vfs_handle_struct
* handle
,
738 struct smb_filename
*smb_fname
,
739 files_struct
* fsp
, int flags
, mode_t mode
)
742 char *tmp
, *shortname
;
743 int allowed
, write_access
= 0;
744 TALLOC_CTX
*ctx
=talloc_tos();
745 /* if open for writing ignore it */
746 if ((flags
& O_ACCMODE
) == O_WRONLY
) {
747 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
749 if ((flags
& O_ACCMODE
) == O_RDWR
) {
752 /* check if this file is scanned already */
753 tmp
= strrchr(smb_fname
->base_name
, '/');
755 base
= talloc_strndup(ctx
,smb_fname
->base_name
,
756 (tmp
- smb_fname
->base_name
) + 1);
760 shortname
= (char *)smb_fname
->base_name
;
762 allowed
= scannedonly_allow_access(
763 handle
, NULL
, smb_fname
, shortname
,
766 STRUCTSCANO(handle
->data
)->recheck_time_open
,
767 STRUCTSCANO(handle
->data
)->recheck_tries_open
,
768 STRUCTSCANO(handle
->data
)->recheck_size_open
,
770 flush_sendbuffer(handle
);
771 DEBUG(SCANNEDONLY_DEBUG
, ("scannedonly_open: allow=%d for %s\n",
772 allowed
, smb_fname
->base_name
));
774 || STRUCTSCANO(handle
->data
)->allow_nonscanned_files
) {
775 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
781 static int scannedonly_close(vfs_handle_struct
* handle
, files_struct
* fsp
)
783 /* we only have to notify the scanner
784 for files that were open readwrite or writable. */
785 if (fsp
->can_write
) {
786 TALLOC_CTX
*ctx
= talloc_tos();
787 notify_scanner(handle
, construct_full_path(
789 fsp
->fsp_name
->base_name
,false));
790 flush_sendbuffer(handle
);
792 return SMB_VFS_NEXT_CLOSE(handle
, fsp
);
795 static int scannedonly_rename(vfs_handle_struct
* handle
,
796 const struct smb_filename
*smb_fname_src
,
797 const struct smb_filename
*smb_fname_dst
)
799 /* rename the cache file before we pass the actual rename on */
800 struct smb_filename
*smb_fname_src_tmp
= NULL
;
801 struct smb_filename
*smb_fname_dst_tmp
= NULL
;
802 char *cachefile_src
, *cachefile_dst
;
803 bool needscandst
=false;
805 TALLOC_CTX
*ctx
= talloc_tos();
807 /* Setup temporary smb_filename structs. */
808 cachefile_src
= cachefile_name_f_fullpath(
810 smb_fname_src
->base_name
,
811 STRUCTSCANO(handle
->data
)->p_scanned
);
812 cachefile_dst
= cachefile_name_f_fullpath(
814 smb_fname_dst
->base_name
,
815 STRUCTSCANO(handle
->data
)->p_scanned
);
816 smb_fname_src_tmp
= synthetic_smb_fname(ctx
, cachefile_src
,NULL
,NULL
);
817 smb_fname_dst_tmp
= 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 smb_fname_cache
= synthetic_smb_fname(ctx
, cachefile
,NULL
,NULL
);
849 if (SMB_VFS_NEXT_UNLINK(handle
, smb_fname_cache
) != 0) {
850 DEBUG(SCANNEDONLY_DEBUG
, ("_unlink: failed to unlink %s\n",
851 smb_fname_cache
->base_name
));
853 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
856 static int scannedonly_rmdir(vfs_handle_struct
* handle
, const char *path
)
858 /* if there are only .scanned: .virus: or .failed: files, we delete
859 those, because the client cannot see them */
862 TALLOC_CTX
*ctx
= talloc_tos();
863 bool only_deletable_files
= true, have_files
= false;
866 if (!STRUCTSCANO(handle
->data
)->rm_hidden_files_on_rmdir
)
867 return SMB_VFS_NEXT_RMDIR(handle
, path
);
869 path_w_slash
= name_w_ending_slash(ctx
,path
);
870 dirp
= SMB_VFS_NEXT_OPENDIR(handle
, path
, NULL
, 0);
874 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
)) != NULL
) {
875 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
879 if (!is_scannedonly_file(STRUCTSCANO(handle
->data
),
881 struct smb_filename
*smb_fname
= NULL
;
885 if (STRUCTSCANO(handle
->data
)->show_special_files
) {
886 only_deletable_files
= false;
889 /* stat the file and see if it is a
891 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
893 smb_fname
= synthetic_smb_fname(ctx
, fullpath
,
895 retval
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
897 && S_ISREG(smb_fname
->st
.st_ex_mode
)) {
898 only_deletable_files
= false;
900 TALLOC_FREE(fullpath
);
901 TALLOC_FREE(smb_fname
);
905 DEBUG(SCANNEDONLY_DEBUG
,
906 ("path=%s, have_files=%d, only_deletable_files=%d\n",
907 path
, have_files
, only_deletable_files
));
908 if (have_files
&& only_deletable_files
) {
909 DEBUG(SCANNEDONLY_DEBUG
,
910 ("scannedonly_rmdir, remove leftover scannedonly "
911 "files from %s\n", path_w_slash
));
912 SMB_VFS_NEXT_REWINDDIR(handle
, dirp
);
913 while ((dire
= SMB_VFS_NEXT_READDIR(handle
, dirp
, NULL
))
916 struct smb_filename
*smb_fname
= NULL
;
917 if (ISDOT(dire
->d_name
) || ISDOTDOT(dire
->d_name
)) {
920 fullpath
= talloc_asprintf(ctx
, "%s%s", path_w_slash
,
922 smb_fname
= synthetic_smb_fname(ctx
, fullpath
,
924 DEBUG(SCANNEDONLY_DEBUG
, ("unlink %s\n", fullpath
));
925 SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
926 TALLOC_FREE(fullpath
);
927 TALLOC_FREE(smb_fname
);
930 SMB_VFS_NEXT_CLOSEDIR(handle
, dirp
);
931 return SMB_VFS_NEXT_RMDIR(handle
, path
);
934 static void free_scannedonly_data(void **data
)
939 static int scannedonly_connect(struct vfs_handle_struct
*handle
,
940 const char *service
, const char *user
)
943 struct Tscannedonly
*so
;
945 so
= SMB_MALLOC_P(struct Tscannedonly
);
950 handle
->data
= (void *)so
;
951 handle
->free_data
= free_scannedonly_data
;
952 so
->gsendbuffer
[0]='\0';
954 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
955 "domain_socket", True
);
956 so
->socketname
= lp_parm_const_string(SNUM(handle
->conn
),
957 "scannedonly", "socketname",
958 "/var/lib/scannedonly/scan");
961 lp_parm_int(SNUM(handle
->conn
), "scannedonly", "portnum",
963 so
->scanhost
= lp_parm_const_string(SNUM(handle
->conn
),
964 "scannedonly", "scanhost",
967 so
->show_special_files
=
968 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
969 "show_special_files", True
);
970 so
->rm_hidden_files_on_rmdir
=
971 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
972 "rm_hidden_files_on_rmdir", True
);
973 so
->hide_nonscanned_files
=
974 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
975 "hide_nonscanned_files", False
);
976 so
->allow_nonscanned_files
=
977 lp_parm_bool(SNUM(handle
->conn
), "scannedonly",
978 "allow_nonscanned_files", False
);
979 so
->scanning_message
= lp_parm_const_string(SNUM(handle
->conn
),
982 "is being scanned for viruses");
983 so
->scanning_message_len
= strlen(so
->scanning_message
);
984 so
->recheck_time_open
=
985 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
986 "recheck_time_open", 50);
987 so
->recheck_tries_open
=
988 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
989 "recheck_tries_open", 100);
990 so
->recheck_size_open
=
991 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
992 "recheck_size_open", 100);
993 so
->recheck_time_readdir
=
994 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
995 "recheck_time_readdir", 50);
996 so
->recheck_tries_readdir
=
997 lp_parm_int(SNUM(handle
->conn
), "scannedonly",
998 "recheck_tries_readdir", 20);
1001 lp_parm_const_string(SNUM(handle
->conn
),
1006 lp_parm_const_string(SNUM(handle
->conn
),
1011 lp_parm_const_string(SNUM(handle
->conn
),
1015 connect_to_scanner(handle
);
1017 return SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
1020 /* VFS operations structure */
1021 static struct vfs_fn_pointers vfs_scannedonly_fns
= {
1022 .opendir_fn
= scannedonly_opendir
,
1023 .fdopendir_fn
= scannedonly_fdopendir
,
1024 .readdir_fn
= scannedonly_readdir
,
1025 .seekdir_fn
= scannedonly_seekdir
,
1026 .telldir_fn
= scannedonly_telldir
,
1027 .rewind_dir_fn
= scannedonly_rewinddir
,
1028 .closedir_fn
= scannedonly_closedir
,
1029 .rmdir_fn
= scannedonly_rmdir
,
1030 .stat_fn
= scannedonly_stat
,
1031 .lstat_fn
= scannedonly_lstat
,
1032 .open_fn
= scannedonly_open
,
1033 .close_fn
= scannedonly_close
,
1034 .rename_fn
= scannedonly_rename
,
1035 .unlink_fn
= scannedonly_unlink
,
1036 .connect_fn
= scannedonly_connect
1039 NTSTATUS
vfs_scannedonly_init(void)
1041 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "scannedonly",
1042 &vfs_scannedonly_fns
);