Начиная с версии 2.2 Samba поддерживает модульную abstraction layer for virtual file system - VFS и все операции с файловой системой внутри Samba используют эту прослойку. Такое нововведение позволяет не только упросить использование Samba поверх различных файловых систем, но и дает возможность в любой момент вмешиваться в процесс работы Samba с файловой системой. В заголовочном файле vfs.h описаны все типы операций, которые реализованы в рамках VFS:
typedef enum _vfs_op_type {
SMB_VFS_OP_NOOP = -1,
/* Disk operations */
SMB_VFS_OP_CONNECT = 0,
SMB_VFS_OP_DISCONNECT,
SMB_VFS_OP_DISK_FREE,
SMB_VFS_OP_GET_QUOTA,
SMB_VFS_OP_SET_QUOTA,
SMB_VFS_OP_GET_SHADOW_COPY_DATA,
SMB_VFS_OP_STATVFS,
SMB_VFS_OP_FS_CAPABILITIES,
/* Directory operations */
SMB_VFS_OP_OPENDIR,
SMB_VFS_OP_READDIR,
SMB_VFS_OP_SEEKDIR,
SMB_VFS_OP_TELLDIR,
SMB_VFS_OP_REWINDDIR,
SMB_VFS_OP_MKDIR,
SMB_VFS_OP_RMDIR,
SMB_VFS_OP_CLOSEDIR,
SMB_VFS_OP_INIT_SEARCH_OP,
/* File operations */
SMB_VFS_OP_OPEN,
SMB_VFS_OP_CREATE_FILE,
SMB_VFS_OP_CLOSE,
SMB_VFS_OP_READ,
SMB_VFS_OP_PREAD,
SMB_VFS_OP_WRITE,
SMB_VFS_OP_PWRITE,
SMB_VFS_OP_LSEEK,
SMB_VFS_OP_SENDFILE,
SMB_VFS_OP_RECVFILE,
SMB_VFS_OP_RENAME,
SMB_VFS_OP_FSYNC,
SMB_VFS_OP_STAT,
SMB_VFS_OP_FSTAT,
SMB_VFS_OP_LSTAT,
SMB_VFS_OP_GET_ALLOC_SIZE,
SMB_VFS_OP_UNLINK,
SMB_VFS_OP_CHMOD,
SMB_VFS_OP_FCHMOD,
SMB_VFS_OP_CHOWN,
SMB_VFS_OP_FCHOWN,
SMB_VFS_OP_LCHOWN,
SMB_VFS_OP_CHDIR,
SMB_VFS_OP_GETWD,
SMB_VFS_OP_NTIMES,
SMB_VFS_OP_FTRUNCATE,
SMB_VFS_OP_LOCK,
SMB_VFS_OP_KERNEL_FLOCK,
SMB_VFS_OP_LINUX_SETLEASE,
SMB_VFS_OP_GETLOCK,
SMB_VFS_OP_SYMLINK,
SMB_VFS_OP_READLINK,
SMB_VFS_OP_LINK,
SMB_VFS_OP_MKNOD,
SMB_VFS_OP_REALPATH,
SMB_VFS_OP_NOTIFY_WATCH,
SMB_VFS_OP_CHFLAGS,
SMB_VFS_OP_FILE_ID_CREATE,
SMB_VFS_OP_STREAMINFO,
SMB_VFS_OP_GET_REAL_FILENAME,
SMB_VFS_OP_BRL_LOCK_WINDOWS,
SMB_VFS_OP_BRL_UNLOCK_WINDOWS,
SMB_VFS_OP_BRL_CANCEL_WINDOWS,
SMB_VFS_OP_STRICT_LOCK,
SMB_VFS_OP_STRICT_UNLOCK,
/* NT ACL operations. */
SMB_VFS_OP_FGET_NT_ACL,
SMB_VFS_OP_GET_NT_ACL,
SMB_VFS_OP_FSET_NT_ACL,
/* POSIX ACL operations. */
SMB_VFS_OP_CHMOD_ACL,
SMB_VFS_OP_FCHMOD_ACL,
SMB_VFS_OP_SYS_ACL_GET_ENTRY,
SMB_VFS_OP_SYS_ACL_GET_TAG_TYPE,
SMB_VFS_OP_SYS_ACL_GET_PERMSET,
SMB_VFS_OP_SYS_ACL_GET_QUALIFIER,
SMB_VFS_OP_SYS_ACL_GET_FILE,
SMB_VFS_OP_SYS_ACL_GET_FD,
SMB_VFS_OP_SYS_ACL_CLEAR_PERMS,
SMB_VFS_OP_SYS_ACL_ADD_PERM,
SMB_VFS_OP_SYS_ACL_TO_TEXT,
SMB_VFS_OP_SYS_ACL_INIT,
SMB_VFS_OP_SYS_ACL_CREATE_ENTRY,
SMB_VFS_OP_SYS_ACL_SET_TAG_TYPE,
SMB_VFS_OP_SYS_ACL_SET_QUALIFIER,
SMB_VFS_OP_SYS_ACL_SET_PERMSET,
SMB_VFS_OP_SYS_ACL_VALID,
SMB_VFS_OP_SYS_ACL_SET_FILE,
SMB_VFS_OP_SYS_ACL_SET_FD,
SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
SMB_VFS_OP_SYS_ACL_GET_PERM,
SMB_VFS_OP_SYS_ACL_FREE_TEXT,
SMB_VFS_OP_SYS_ACL_FREE_ACL,
SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER,
/* EA operations. */
SMB_VFS_OP_GETXATTR,
SMB_VFS_OP_LGETXATTR,
SMB_VFS_OP_FGETXATTR,
SMB_VFS_OP_LISTXATTR,
SMB_VFS_OP_LLISTXATTR,
SMB_VFS_OP_FLISTXATTR,
SMB_VFS_OP_REMOVEXATTR,
SMB_VFS_OP_LREMOVEXATTR,
SMB_VFS_OP_FREMOVEXATTR,
SMB_VFS_OP_SETXATTR,
SMB_VFS_OP_LSETXATTR,
SMB_VFS_OP_FSETXATTR,
/* aio operations */
SMB_VFS_OP_AIO_READ,
SMB_VFS_OP_AIO_WRITE,
SMB_VFS_OP_AIO_RETURN,
SMB_VFS_OP_AIO_CANCEL,
SMB_VFS_OP_AIO_ERROR,
SMB_VFS_OP_AIO_FSYNC,
SMB_VFS_OP_AIO_SUSPEND,
SMB_VFS_OP_AIO_FORCE,
/* offline operations */
SMB_VFS_OP_IS_OFFLINE,
SMB_VFS_OP_SET_OFFLINE,
/* This should always be last enum value */
SMB_VFS_OP_LAST
} vfs_op_type;
Соответственно, можно написать свой VFS модуль и сделать его обработчиком любых из вышеперечисленных операций. В качестве примера хочу рассмотреть создание VFS модуля, который анализирует тип файла в момент его закрытия и удаляет файл, если тот не соответствует какому-то определенному типу. Тип файла определяется не по расширению, а по фактическому содержимому. На практике, такой модуль можно использовать для разрешения хранения на файловом ресурсе Samba файлов определенных типов. В качестве точки вызова модуля я выбрал операцию закрытия файла исходя из следующих соображений:
1. определить тип файла в момент его открытия не всегда возможно, например, при создании соедержимого еще нет, а при перезаписи тип может поменятся
2. попытка удалить файл в процессе работы может не понравиться приложению, которое с ним работает
3. подобным образом работают другие VFS модули Samba
Определить тип файла нам поможет библиотека libmagic, которая вместе с программой file входит в состав любой Unix-like операционной системы:
$ file samba-3.4.5.tar.gz camera.avi
samba-3.4.5.tar.gz: gzip compressed data, was "samba-3.4.5.tar", from Unix, last modified: Mon Jan 18 16:31:18 2010, max compression
camera.avi: RIFF (little-endian) data, AVI, 720 x 400, 23.98 fps, video: XviD, audio: Dolby AC3 (stereo, 48000 Hz
Рассмотрим исходный текст модуля, комментарии в тексте описывают ход его выполнения:
/*
* VFS module to delete files at closing if their mime type does
* not match with rules.
*
* Copyright (C) Alexander Deiter 2004-2010
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Short instructions:
*
* Build it with:
* LDFLAGS = -lmagic
*
* Sample smb.conf:
*
* [test]
* path = /path/to/test
* vfs objects = magic_perms
* magic_perms: filetypes = image/jpeg, application/pdf
* writeable = yes
*/
#include "includes.h"
#include <magic.h>
#define MODULE_NAME "magic_perms"
#define FILETYPES "filetypes"
static int magic_perms_close(vfs_handle_struct *handle, files_struct *fsp)
{
int i;
magic_t mc;
const char *ftype;
const char **ftypes;
char *fpath;
int retval = SMB_VFS_NEXT_CLOSE(handle, fsp);
/* возвращаем управление если после открытия файл не был модифицирован */
if ( !fsp->modified ) {
DEBUG(10,("%s file %s was not modified.\n",
MODULE_NAME, fsp->fsp_name));
return retval;
}
/* возвращаем управление если это каталог */
if ( fsp->is_directory ) {
DEBUG(10,("%s %s like directory.\n",
MODULE_NAME, fsp->fsp_name));
return retval;
}
/* читаем параметры модуля из smb.conf */
ftypes = lp_parm_string_list(SNUM(handle->conn),
(handle->param ? handle->param : MODULE_NAME),
FILETYPES, NULL);
/* возвращаем управление если параметры не определены */
if (!ftypes) {
DEBUG(2,("%s empty file type list.\n",
MODULE_NAME));
return retval;
}
/* находим путь к файлу на файловой системе */
fpath = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath, fsp->fsp_name);
DEBUG(2,("%s get full path for %s: %s.\n",
MODULE_NAME, fsp->fsp_name, fpath));
/* открываем базу данных, в которой описаны все известные типы файлов */
mc = magic_open(MAGIC_PRESERVE_ATIME|MAGIC_MIME_TYPE);
if (mc == NULL) {
DEBUG(2,("%s cannot open magic file: %s.\n",
MODULE_NAME, strerror(errno)));
return retval;
}
/* загружаем базу данных*/
if (magic_load(mc, NULL) == -1) {
DEBUG(2,("%s cannot load magic file: %s.\n",
MODULE_NAME, magic_error(mc)));
magic_close(mc);
return retval;
}
/* определяем тип файла */
ftype = magic_file(mc, fpath);
/* возвращаем управление если тип неизвестен */
if (ftype == NULL) {
DEBUG(2,("%s cannot get type for file %s.\n",
MODULE_NAME, fpath));
magic_close(mc);
return retval;
}
magic_close(mc);
DEBUG(2,("%s get magic for %s: %s.\n",
MODULE_NAME, fpath, ftype));
/* возвращаем управление если тип файла в списке разрешенных */
for (i=0; ftypes[i]; i++) {
if (strcmp(ftype, ftypes[i]) == 0) {
DEBUG(2,("%s match %s for %s.\n",
MODULE_NAME, ftype, fpath));
return retval;
}
}
/* удаляем файл если он не входит в список разрешенных */
DEBUG(1,("%s unlink file %s with type %s.\n",
MODULE_NAME, fpath, ftype));
unlink(fpath);
TALLOC_FREE(fpath);
return retval;
}
/* регистрируем модуль для операции закрытия файла */
static vfs_op_tuple magic_perms_op_tuples[] = {
{SMB_VFS_OP(magic_perms_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
};
/* инициализируем модуль */
NTSTATUS init_samba_module(void)
{
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE_NAME, magic_perms_op_tuples);
}
Для использования модуля его исходный код необходимо скомпилировать в загружаемую библиотеку. При сборке нам понадобится исходный код Samba. Воспользовавшись системой портов FreeBSD загрузим исходный код продукта и настроим параметры его сборки:
# cd /usr/ports/net/samba34
# make fetch
# make configure
Теперь нам останется скопировать файл с исходным кодом модуля в дерево исходных тектстов Samba и изменить сценарий сборки для включения нашего модуля в готовый пакет:
# diff -u work/samba-3.4.5/source3/Makefile.orig work/samba-3.4.5/source3/Makefile
--- work/samba-3.4.5/source3/Makefile.orig 2010-03-21 23:33:54.524574380 +0300
+++ work/samba-3.4.5/source3/Makefile 2010-03-22 01:47:23.172429344 +0300
@@ -231,7 +231,7 @@
SCRIPTS = $(srcdir)/script/smbtar $(builddir)/script/findsmb
-VFS_MODULES = bin/recycle.so bin/audit.so bin/extd_audit.so bin/full_audit.so \
+VFS_MODULES = bin/recycle.so bin/audit.so bin/magic_perms.so bin/extd_audit.so \
PERFCOUNT_MODULES =
PDB_MODULES =
RPC_MODULES =
@@ -645,6 +645,7 @@
VFS_DEFAULT_OBJ = modules/vfs_default.o
VFS_AUDIT_OBJ = modules/vfs_audit.o
+VFS_MAGIC_PERMS_OBJ = modules/vfs_magic_perms.o
VFS_EXTD_AUDIT_OBJ = modules/vfs_extd_audit.o
VFS_FULL_AUDIT_OBJ = modules/vfs_full_audit.o
VFS_FAKE_PERMS_OBJ = modules/vfs_fake_perms.o
@@ -2502,6 +2503,10 @@
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_AUDIT_OBJ)
+bin/magic_perms.so: $(BINARY_PREREQS) $(VFS_MAGIC_PERMS_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) -lmagic $(VFS_MAGIC_PERMS_OBJ)
+
bin/extd_audit.so: $(BINARY_PREREQS) $(VFS_EXTD_AUDIT_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_EXTD_AUDIT_OBJ)
Запускаем процесс сборки и установки пакета:
# make package
После непродолжительного ожидания получаем установленный в системе пакет Samba:
# pkg_info -c samba34-3.4.5_1
Information for samba34-3.4.5_1:
Comment:
A free SMB and CIFS client and server for UNIX
Для проверки работоспособности модуля настроим минимальную конфигурацию Samba, разрешив на единственном общедоступном ресурсе только два типа файлов изображения в формате jpeg и документы в формате pdf:
# testparm -s
Load smb config files from /usr/local/etc/smb.conf
Processing section "[test]"
Loaded services file OK.
Server role: ROLE_STANDALONE
[global]
dos charset = cp866
display charset = UTF-8
workgroup = MYGROUP
security = SHARE
log level = 2
log file = /var/log/samba34/log.%m
max log size = 4096
[test]
path = /var/tmp/test
read only = No
guest ok = Yes
vfs objects = magic_perms
magic_perms: filetypes = image/jpeg, application/pdf
Запустим Samba:
# /usr/local/etc/rc.d/samba start
Removing stale Samba tdb files: done
Starting nmbd.
Starting smbd.
И попробуем скопировать на ресурс [test] файлы различных типов:
$ smbclient -N //localhost/test
Domain=[MYGROUP] OS=[Unix] Server=[Samba 3.4.5]
Server not using user level security and no password supplied.
smb: \> put space_wind_mp3
putting file space_wind_mp3 as \space_wind.mp3 (17483.8 kb/s) (average 8716.3 kb/s)
smb: \> put 820-1011.pdf
putting file 820-1011.pdf as \820-1011.pdf (620.0 kb/s) (average 3982.8 kb/s)
smb: \> put ssa.jnlp
putting file ssa.jnlp as \ssa.jnlp (2.7 kb/s) (average 2795.6 kb/s)
smb: \> put moz-screenshot.jpg
putting file moz-screenshot.jpg as \moz-screenshot.jpg (206.1 kb/s) (average 2110.4 kb/s)
smb: \>
В журналах Samba мы увидим, что файлы space_wind_mp3 и ssa.jnlp были удалены по причине несоответствия разрешенным типам:
[2010/04/02 00:45:48, 2] modules/vfs_magic_perms.c:77(magic_perms_close)
magic_perms get full path for space_wind_mp3: /var/tmp/test/space_wind.mp3.
[2010/04/02 00:45:48, 2] modules/vfs_magic_perms.c:104(magic_perms_close)
magic_perms get magic for /var/tmp/test/space_wind_mp3: audio/mpeg.
[2010/04/02 00:45:48, 1] modules/vfs_magic_perms.c:115(magic_perms_close)
magic_perms unlink file /var/tmp/test/space_wind_mp3 with type audio/mpeg.
...
[2010/04/02 00:46:26, 2] modules/vfs_magic_perms.c:77(magic_perms_close)
magic_perms get full path for 820-1011.pdf: /var/tmp/test/820-1011.pdf.
[2010/04/02 00:46:26, 2] modules/vfs_magic_perms.c:104(magic_perms_close)
magic_perms get magic for /var/tmp/test/820-1011.pdf: application/pdf.
[2010/04/02 00:46:26, 2] modules/vfs_magic_perms.c:109(magic_perms_close)
magic_perms match application/pdf for /var/tmp/test/820-1011.pdf.
...
[2010/04/02 00:46:42, 2] modules/vfs_magic_perms.c:77(magic_perms_close)
magic_perms get full path for ssa.jnlp: /var/tmp/test/ssa.jnlp.
[2010/04/02 00:46:42, 2] modules/vfs_magic_perms.c:104(magic_perms_close)
magic_perms get magic for /var/tmp/test/ssa.jnlp: application/xml.
[2010/04/02 00:46:42, 1] modules/vfs_magic_perms.c:115(magic_perms_close)
magic_perms unlink file /var/tmp/test/ssa.jnlp with type application/xml.
...
[2010/04/02 00:47:05, 2] modules/vfs_magic_perms.c:77(magic_perms_close)
magic_perms get full path for moz-screenshot.jpg: /var/tmp/test/moz-screenshot.jpg.
[2010/04/02 00:47:05, 2] modules/vfs_magic_perms.c:104(magic_perms_close)
magic_perms get magic for /var/tmp/test/moz-screenshot.jpg: image/jpeg.
[2010/04/02 00:47:05, 2] modules/vfs_magic_perms.c:109(magic_perms_close)
magic_perms match image/jpeg for /var/tmp/test/moz-screenshot.jpg.
Как и множество других открытых програмных продуктов, Samba позволяет легко наращивать свой фунционал, создавая по мере необходимости сколь угодно сложные решения, которые могут решать самые разные задачи.