2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this implements most of the POSIX NTVFS backend
23 This is the default backend
27 #include "vfs_posix.h"
28 #include "librpc/gen_ndr/security.h"
29 #include "tdb_compat.h"
30 #include "lib/tdb_wrap/tdb_wrap.h"
31 #include "libcli/security/security.h"
32 #include "lib/events/events.h"
33 #include "param/param.h"
36 setup config options for a posix share
38 static void pvfs_setup_options(struct pvfs_state
*pvfs
)
40 struct share_config
*scfg
= pvfs
->ntvfs
->ctx
->config
;
42 bool def_perm_override
= false;
44 if (share_bool_option(scfg
, SHARE_MAP_HIDDEN
, SHARE_MAP_HIDDEN_DEFAULT
))
45 pvfs
->flags
|= PVFS_FLAG_MAP_HIDDEN
;
46 if (share_bool_option(scfg
, SHARE_MAP_ARCHIVE
, SHARE_MAP_ARCHIVE_DEFAULT
))
47 pvfs
->flags
|= PVFS_FLAG_MAP_ARCHIVE
;
48 if (share_bool_option(scfg
, SHARE_MAP_SYSTEM
, SHARE_MAP_SYSTEM_DEFAULT
))
49 pvfs
->flags
|= PVFS_FLAG_MAP_SYSTEM
;
50 if (share_bool_option(scfg
, SHARE_READONLY
, SHARE_READONLY_DEFAULT
))
51 pvfs
->flags
|= PVFS_FLAG_READONLY
;
52 if (share_bool_option(scfg
, SHARE_STRICT_SYNC
, SHARE_STRICT_SYNC_DEFAULT
))
53 pvfs
->flags
|= PVFS_FLAG_STRICT_SYNC
;
54 if (share_bool_option(scfg
, SHARE_STRICT_LOCKING
, SHARE_STRICT_LOCKING_DEFAULT
))
55 pvfs
->flags
|= PVFS_FLAG_STRICT_LOCKING
;
56 if (share_bool_option(scfg
, SHARE_CI_FILESYSTEM
, SHARE_CI_FILESYSTEM_DEFAULT
))
57 pvfs
->flags
|= PVFS_FLAG_CI_FILESYSTEM
;
58 if (share_bool_option(scfg
, PVFS_FAKE_OPLOCKS
, PVFS_FAKE_OPLOCKS_DEFAULT
))
59 pvfs
->flags
|= PVFS_FLAG_FAKE_OPLOCKS
;
60 if (share_bool_option(scfg
, PVFS_AIO
, false))
61 pvfs
->flags
|= PVFS_FLAG_LINUX_AIO
;
63 #if defined(O_DIRECTORY) && defined(O_NOFOLLOW)
64 /* set PVFS_PERM_OVERRIDE by default only if the system
65 * supports the necessary capabilities to make it secure
67 def_perm_override
= true;
69 if (share_bool_option(scfg
, PVFS_PERM_OVERRIDE
, def_perm_override
))
70 pvfs
->flags
|= PVFS_FLAG_PERM_OVERRIDE
;
72 /* file perm options */
73 pvfs
->options
.create_mask
= share_int_option(scfg
,
75 SHARE_CREATE_MASK_DEFAULT
);
76 pvfs
->options
.dir_mask
= share_int_option(scfg
,
78 SHARE_DIR_MASK_DEFAULT
);
79 pvfs
->options
.force_dir_mode
= share_int_option(scfg
,
81 SHARE_FORCE_DIR_MODE_DEFAULT
);
82 pvfs
->options
.force_create_mode
= share_int_option(scfg
,
83 SHARE_FORCE_CREATE_MODE
,
84 SHARE_FORCE_CREATE_MODE_DEFAULT
);
85 /* this must be a power of 2 */
86 pvfs
->alloc_size_rounding
= share_int_option(scfg
,
87 PVFS_ALLOCATION_ROUNDING
,
88 PVFS_ALLOCATION_ROUNDING_DEFAULT
);
90 pvfs
->search
.inactivity_time
= share_int_option(scfg
,
91 PVFS_SEARCH_INACTIVITY
,
92 PVFS_SEARCH_INACTIVITY_DEFAULT
);
94 #if HAVE_XATTR_SUPPORT
95 if (share_bool_option(scfg
, PVFS_XATTR
, PVFS_XATTR_DEFAULT
))
96 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
99 pvfs
->sharing_violation_delay
= share_int_option(scfg
,
101 PVFS_SHARE_DELAY_DEFAULT
);
103 pvfs
->oplock_break_timeout
= share_int_option(scfg
,
105 PVFS_OPLOCK_TIMEOUT_DEFAULT
);
107 pvfs
->writetime_delay
= share_int_option(scfg
,
108 PVFS_WRITETIME_DELAY
,
109 PVFS_WRITETIME_DELAY_DEFAULT
);
111 pvfs
->share_name
= talloc_strdup(pvfs
, scfg
->name
);
114 FS_ATTR_CASE_SENSITIVE_SEARCH
|
115 FS_ATTR_CASE_PRESERVED_NAMES
|
116 FS_ATTR_UNICODE_ON_DISK
|
117 FS_ATTR_SPARSE_FILES
;
119 /* allow xattrs to be stored in a external tdb */
120 eadb
= share_string_option(scfg
, PVFS_EADB
, NULL
);
122 pvfs
->ea_db
= tdb_wrap_open(pvfs
, eadb
, 50000,
123 TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600,
124 pvfs
->ntvfs
->ctx
->lp_ctx
);
125 if (pvfs
->ea_db
!= NULL
) {
126 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
128 DEBUG(0,("Failed to open eadb '%s' - %s\n",
129 eadb
, strerror(errno
)));
130 pvfs
->flags
&= ~PVFS_FLAG_XATTR_ENABLE
;
134 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
135 pvfs
->fs_attribs
|= FS_ATTR_NAMED_STREAMS
;
137 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
138 pvfs
->fs_attribs
|= FS_ATTR_PERSISTANT_ACLS
;
141 pvfs
->sid_cache
.creator_owner
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_OWNER
);
142 pvfs
->sid_cache
.creator_group
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_GROUP
);
144 /* check if the system really supports xattrs */
145 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
146 pvfs_xattr_probe(pvfs
);
149 /* enable an ACL backend */
150 pvfs
->acl_ops
= pvfs_acl_backend_byname(share_string_option(scfg
, PVFS_ACL
, "xattr"));
153 static int pvfs_state_destructor(struct pvfs_state
*pvfs
)
155 struct pvfs_file
*f
, *fn
;
156 struct pvfs_search_state
*s
, *sn
;
159 * make sure we cleanup files and searches before anything else
160 * because there destructors need to acess the pvfs_state struct
162 for (f
=pvfs
->files
.list
; f
; f
=fn
) {
167 for (s
=pvfs
->search
.list
; s
; s
=sn
) {
176 connect to a share - used when a tree_connect operation comes
177 in. For a disk based backend we needs to ensure that the base
178 directory exists (tho it doesn't need to be accessible by the user,
181 static NTSTATUS
pvfs_connect(struct ntvfs_module_context
*ntvfs
,
182 struct ntvfs_request
*req
,
183 union smb_tcon
* tcon
)
185 struct pvfs_state
*pvfs
;
187 char *base_directory
;
189 const char *sharename
;
191 switch (tcon
->generic
.level
) {
193 sharename
= tcon
->tcon
.in
.service
;
196 sharename
= tcon
->tconx
.in
.path
;
199 sharename
= tcon
->smb2
.in
.path
;
202 return NT_STATUS_INVALID_LEVEL
;
205 if (strncmp(sharename
, "\\\\", 2) == 0) {
206 char *p
= strchr(sharename
+2, '\\');
213 * TODO: call this from ntvfs_posix_init()
214 * but currently we don't have a lp_ctx there
216 status
= pvfs_acl_init();
217 NT_STATUS_NOT_OK_RETURN(status
);
219 pvfs
= talloc_zero(ntvfs
, struct pvfs_state
);
220 NT_STATUS_HAVE_NO_MEMORY(pvfs
);
222 /* for simplicity of path construction, remove any trailing slash now */
223 base_directory
= talloc_strdup(pvfs
, share_string_option(ntvfs
->ctx
->config
, SHARE_PATH
, ""));
224 NT_STATUS_HAVE_NO_MEMORY(base_directory
);
225 if (strcmp(base_directory
, "/") != 0) {
226 trim_string(base_directory
, NULL
, "/");
230 pvfs
->base_directory
= base_directory
;
232 /* the directory must exist. Note that we deliberately don't
233 check that it is readable */
234 if (stat(pvfs
->base_directory
, &st
) != 0 || !S_ISDIR(st
.st_mode
)) {
235 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
236 pvfs
->base_directory
, sharename
));
237 return NT_STATUS_BAD_NETWORK_NAME
;
240 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
241 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
243 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
244 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
246 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
247 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
248 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
251 ntvfs
->private_data
= pvfs
;
253 pvfs
->brl_context
= brlock_init(pvfs
,
254 pvfs
->ntvfs
->ctx
->server_id
,
255 pvfs
->ntvfs
->ctx
->lp_ctx
,
256 pvfs
->ntvfs
->ctx
->msg_ctx
);
257 if (pvfs
->brl_context
== NULL
) {
258 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
261 pvfs
->odb_context
= odb_init(pvfs
, pvfs
->ntvfs
->ctx
);
262 if (pvfs
->odb_context
== NULL
) {
263 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
266 /* allow this to be NULL - we just disable change notify */
267 pvfs
->notify_context
= notify_init(pvfs
,
268 pvfs
->ntvfs
->ctx
->server_id
,
269 pvfs
->ntvfs
->ctx
->msg_ctx
,
270 pvfs
->ntvfs
->ctx
->lp_ctx
,
271 pvfs
->ntvfs
->ctx
->event_ctx
,
272 pvfs
->ntvfs
->ctx
->config
);
274 pvfs
->wbc_ctx
= wbc_init(pvfs
,
275 pvfs
->ntvfs
->ctx
->msg_ctx
,
276 pvfs
->ntvfs
->ctx
->event_ctx
);
277 if (pvfs
->wbc_ctx
== NULL
) {
278 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
281 /* allocate the search handle -> ptr tree */
282 pvfs
->search
.idtree
= idr_init(pvfs
);
283 NT_STATUS_HAVE_NO_MEMORY(pvfs
->search
.idtree
);
285 status
= pvfs_mangle_init(pvfs
);
286 NT_STATUS_NOT_OK_RETURN(status
);
288 pvfs_setup_options(pvfs
);
290 talloc_set_destructor(pvfs
, pvfs_state_destructor
);
293 /* who had the stupid idea to generate a signal on a large
294 file write instead of just failing it!? */
295 BlockSignals(true, SIGXFSZ
);
302 disconnect from a share
304 static NTSTATUS
pvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
310 check if a directory exists
312 static NTSTATUS
pvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
313 struct ntvfs_request
*req
,
314 union smb_chkpath
*cp
)
316 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
318 struct pvfs_filename
*name
;
321 /* resolve the cifs name to a posix name */
322 status
= pvfs_resolve_name(pvfs
, req
, cp
->chkpath
.in
.path
, 0, &name
);
323 NT_STATUS_NOT_OK_RETURN(status
);
326 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
329 if (!S_ISDIR(name
->st
.st_mode
)) {
330 return NT_STATUS_NOT_A_DIRECTORY
;
339 static NTSTATUS
pvfs_copy(struct ntvfs_module_context
*ntvfs
,
340 struct ntvfs_request
*req
, struct smb_copy
*cp
)
342 DEBUG(0,("pvfs_copy not implemented\n"));
343 return NT_STATUS_NOT_SUPPORTED
;
347 return print queue info
349 static NTSTATUS
pvfs_lpq(struct ntvfs_module_context
*ntvfs
,
350 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
352 return NT_STATUS_NOT_SUPPORTED
;
355 /* SMBtrans - not used on file shares */
356 static NTSTATUS
pvfs_trans(struct ntvfs_module_context
*ntvfs
,
357 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
359 return NT_STATUS_ACCESS_DENIED
;
363 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
365 NTSTATUS
ntvfs_posix_init(void)
368 struct ntvfs_ops ops
;
369 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
373 ops
.type
= NTVFS_DISK
;
375 /* fill in all the operations */
376 ops
.connect_fn
= pvfs_connect
;
377 ops
.disconnect_fn
= pvfs_disconnect
;
378 ops
.unlink_fn
= pvfs_unlink
;
379 ops
.chkpath_fn
= pvfs_chkpath
;
380 ops
.qpathinfo_fn
= pvfs_qpathinfo
;
381 ops
.setpathinfo_fn
= pvfs_setpathinfo
;
382 ops
.open_fn
= pvfs_open
;
383 ops
.mkdir_fn
= pvfs_mkdir
;
384 ops
.rmdir_fn
= pvfs_rmdir
;
385 ops
.rename_fn
= pvfs_rename
;
386 ops
.copy_fn
= pvfs_copy
;
387 ops
.ioctl_fn
= pvfs_ioctl
;
388 ops
.read_fn
= pvfs_read
;
389 ops
.write_fn
= pvfs_write
;
390 ops
.seek_fn
= pvfs_seek
;
391 ops
.flush_fn
= pvfs_flush
;
392 ops
.close_fn
= pvfs_close
;
393 ops
.exit_fn
= pvfs_exit
;
394 ops
.lock_fn
= pvfs_lock
;
395 ops
.setfileinfo_fn
= pvfs_setfileinfo
;
396 ops
.qfileinfo_fn
= pvfs_qfileinfo
;
397 ops
.fsinfo_fn
= pvfs_fsinfo
;
398 ops
.lpq_fn
= pvfs_lpq
;
399 ops
.search_first_fn
= pvfs_search_first
;
400 ops
.search_next_fn
= pvfs_search_next
;
401 ops
.search_close_fn
= pvfs_search_close
;
402 ops
.trans_fn
= pvfs_trans
;
403 ops
.logoff_fn
= pvfs_logoff
;
404 ops
.async_setup_fn
= pvfs_async_setup
;
405 ops
.cancel_fn
= pvfs_cancel
;
406 ops
.notify_fn
= pvfs_notify
;
408 /* register ourselves with the NTVFS subsystem. We register
409 under the name 'default' as we wish to be the default
410 backend, and also register as 'posix' */
411 ops
.name
= "default";
412 ret
= ntvfs_register(&ops
, &vers
);
414 if (!NT_STATUS_IS_OK(ret
)) {
415 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
419 ret
= ntvfs_register(&ops
, &vers
);
421 if (!NT_STATUS_IS_OK(ret
)) {
422 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
425 if (NT_STATUS_IS_OK(ret
)) {
426 ret
= ntvfs_common_init();