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
;
43 bool def_perm_override
= false;
45 if (share_bool_option(scfg
, SHARE_MAP_HIDDEN
, SHARE_MAP_HIDDEN_DEFAULT
))
46 pvfs
->flags
|= PVFS_FLAG_MAP_HIDDEN
;
47 if (share_bool_option(scfg
, SHARE_MAP_ARCHIVE
, SHARE_MAP_ARCHIVE_DEFAULT
))
48 pvfs
->flags
|= PVFS_FLAG_MAP_ARCHIVE
;
49 if (share_bool_option(scfg
, SHARE_MAP_SYSTEM
, SHARE_MAP_SYSTEM_DEFAULT
))
50 pvfs
->flags
|= PVFS_FLAG_MAP_SYSTEM
;
51 if (share_bool_option(scfg
, SHARE_READONLY
, SHARE_READONLY_DEFAULT
))
52 pvfs
->flags
|= PVFS_FLAG_READONLY
;
53 if (share_bool_option(scfg
, SHARE_STRICT_SYNC
, SHARE_STRICT_SYNC_DEFAULT
))
54 pvfs
->flags
|= PVFS_FLAG_STRICT_SYNC
;
55 if (share_bool_option(scfg
, SHARE_STRICT_LOCKING
, SHARE_STRICT_LOCKING_DEFAULT
))
56 pvfs
->flags
|= PVFS_FLAG_STRICT_LOCKING
;
57 if (share_bool_option(scfg
, SHARE_CI_FILESYSTEM
, SHARE_CI_FILESYSTEM_DEFAULT
))
58 pvfs
->flags
|= PVFS_FLAG_CI_FILESYSTEM
;
59 if (share_bool_option(scfg
, PVFS_FAKE_OPLOCKS
, PVFS_FAKE_OPLOCKS_DEFAULT
))
60 pvfs
->flags
|= PVFS_FLAG_FAKE_OPLOCKS
;
61 if (share_bool_option(scfg
, PVFS_AIO
, false))
62 pvfs
->flags
|= PVFS_FLAG_LINUX_AIO
;
64 #if defined(O_DIRECTORY) && defined(O_NOFOLLOW)
65 /* set PVFS_PERM_OVERRIDE by default only if the system
66 * supports the necessary capabilities to make it secure
68 def_perm_override
= true;
70 if (share_bool_option(scfg
, PVFS_PERM_OVERRIDE
, def_perm_override
))
71 pvfs
->flags
|= PVFS_FLAG_PERM_OVERRIDE
;
73 /* file perm options */
74 pvfs
->options
.create_mask
= share_int_option(scfg
,
76 SHARE_CREATE_MASK_DEFAULT
);
77 pvfs
->options
.dir_mask
= share_int_option(scfg
,
79 SHARE_DIR_MASK_DEFAULT
);
80 pvfs
->options
.force_dir_mode
= share_int_option(scfg
,
82 SHARE_FORCE_DIR_MODE_DEFAULT
);
83 pvfs
->options
.force_create_mode
= share_int_option(scfg
,
84 SHARE_FORCE_CREATE_MODE
,
85 SHARE_FORCE_CREATE_MODE_DEFAULT
);
86 /* this must be a power of 2 */
87 pvfs
->alloc_size_rounding
= share_int_option(scfg
,
88 PVFS_ALLOCATION_ROUNDING
,
89 PVFS_ALLOCATION_ROUNDING_DEFAULT
);
91 pvfs
->search
.inactivity_time
= share_int_option(scfg
,
92 PVFS_SEARCH_INACTIVITY
,
93 PVFS_SEARCH_INACTIVITY_DEFAULT
);
95 #if HAVE_XATTR_SUPPORT
96 if (share_bool_option(scfg
, PVFS_XATTR
, PVFS_XATTR_DEFAULT
))
97 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
100 pvfs
->sharing_violation_delay
= share_int_option(scfg
,
102 PVFS_SHARE_DELAY_DEFAULT
);
104 pvfs
->oplock_break_timeout
= share_int_option(scfg
,
106 PVFS_OPLOCK_TIMEOUT_DEFAULT
);
108 pvfs
->writetime_delay
= share_int_option(scfg
,
109 PVFS_WRITETIME_DELAY
,
110 PVFS_WRITETIME_DELAY_DEFAULT
);
112 pvfs
->share_name
= talloc_strdup(pvfs
, scfg
->name
);
115 FS_ATTR_CASE_SENSITIVE_SEARCH
|
116 FS_ATTR_CASE_PRESERVED_NAMES
|
117 FS_ATTR_UNICODE_ON_DISK
|
118 FS_ATTR_SPARSE_FILES
;
120 /* allow xattrs to be stored in a external tdb */
121 eadb
= share_string_option(pvfs
, scfg
, PVFS_EADB
, NULL
);
123 pvfs
->ea_db
= tdb_wrap_open(
125 lpcfg_tdb_flags(pvfs
->ntvfs
->ctx
->lp_ctx
, TDB_DEFAULT
),
126 O_RDWR
|O_CREAT
, 0600);
128 if (pvfs
->ea_db
!= NULL
) {
129 pvfs
->flags
|= PVFS_FLAG_XATTR_ENABLE
;
131 DEBUG(0,("Failed to open eadb '%s' - %s\n",
132 eadb
, strerror(errno
)));
133 pvfs
->flags
&= ~PVFS_FLAG_XATTR_ENABLE
;
137 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
138 pvfs
->fs_attribs
|= FS_ATTR_NAMED_STREAMS
;
140 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
141 pvfs
->fs_attribs
|= FS_ATTR_PERSISTANT_ACLS
;
144 pvfs
->sid_cache
.creator_owner
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_OWNER
);
145 pvfs
->sid_cache
.creator_group
= dom_sid_parse_talloc(pvfs
, SID_CREATOR_GROUP
);
147 /* check if the system really supports xattrs */
148 if (pvfs
->flags
& PVFS_FLAG_XATTR_ENABLE
) {
149 pvfs_xattr_probe(pvfs
);
152 /* enable an ACL backend */
153 xattr_backend
= share_string_option(pvfs
, scfg
, PVFS_ACL
, "xattr");
154 pvfs
->acl_ops
= pvfs_acl_backend_byname(xattr_backend
);
155 TALLOC_FREE(xattr_backend
);
158 static int pvfs_state_destructor(struct pvfs_state
*pvfs
)
160 struct pvfs_file
*f
, *fn
;
161 struct pvfs_search_state
*s
, *sn
;
164 * make sure we cleanup files and searches before anything else
165 * because there destructors need to acess the pvfs_state struct
167 for (f
=pvfs
->files
.list
; f
; f
=fn
) {
172 for (s
=pvfs
->search
.list
; s
; s
=sn
) {
181 connect to a share - used when a tree_connect operation comes
182 in. For a disk based backend we needs to ensure that the base
183 directory exists (tho it doesn't need to be accessible by the user,
186 static NTSTATUS
pvfs_connect(struct ntvfs_module_context
*ntvfs
,
187 struct ntvfs_request
*req
,
188 union smb_tcon
* tcon
)
190 struct pvfs_state
*pvfs
;
192 char *base_directory
;
194 const char *sharename
;
196 switch (tcon
->generic
.level
) {
198 sharename
= tcon
->tcon
.in
.service
;
201 sharename
= tcon
->tconx
.in
.path
;
204 sharename
= tcon
->smb2
.in
.path
;
207 return NT_STATUS_INVALID_LEVEL
;
210 if (strncmp(sharename
, "\\\\", 2) == 0) {
211 char *p
= strchr(sharename
+2, '\\');
218 * TODO: call this from ntvfs_posix_init()
219 * but currently we don't have a lp_ctx there
221 status
= pvfs_acl_init();
222 NT_STATUS_NOT_OK_RETURN(status
);
224 pvfs
= talloc_zero(ntvfs
, struct pvfs_state
);
225 NT_STATUS_HAVE_NO_MEMORY(pvfs
);
227 /* for simplicity of path construction, remove any trailing slash now */
228 base_directory
= share_string_option(pvfs
, ntvfs
->ctx
->config
, SHARE_PATH
, "");
229 NT_STATUS_HAVE_NO_MEMORY(base_directory
);
230 if (strcmp(base_directory
, "/") != 0) {
231 trim_string(base_directory
, NULL
, "/");
235 pvfs
->base_directory
= base_directory
;
237 /* the directory must exist. Note that we deliberately don't
238 check that it is readable */
239 if (stat(pvfs
->base_directory
, &st
) != 0 || !S_ISDIR(st
.st_mode
)) {
240 DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
241 pvfs
->base_directory
, sharename
));
242 return NT_STATUS_BAD_NETWORK_NAME
;
245 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
246 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
248 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
249 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
251 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
252 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
253 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
256 ntvfs
->private_data
= pvfs
;
258 pvfs
->brl_context
= brlock_init(pvfs
,
259 pvfs
->ntvfs
->ctx
->server_id
,
260 pvfs
->ntvfs
->ctx
->lp_ctx
,
261 pvfs
->ntvfs
->ctx
->msg_ctx
);
262 if (pvfs
->brl_context
== NULL
) {
263 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
266 pvfs
->odb_context
= odb_init(pvfs
, pvfs
->ntvfs
->ctx
);
267 if (pvfs
->odb_context
== NULL
) {
268 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
271 /* allow this to be NULL - we just disable change notify */
272 pvfs
->notify_context
= notify_init(pvfs
,
273 pvfs
->ntvfs
->ctx
->server_id
,
274 pvfs
->ntvfs
->ctx
->msg_ctx
,
275 pvfs
->ntvfs
->ctx
->lp_ctx
,
276 pvfs
->ntvfs
->ctx
->event_ctx
,
277 pvfs
->ntvfs
->ctx
->config
);
279 /* allocate the search handle -> ptr tree */
280 pvfs
->search
.idtree
= idr_init(pvfs
);
281 NT_STATUS_HAVE_NO_MEMORY(pvfs
->search
.idtree
);
283 status
= pvfs_mangle_init(pvfs
);
284 NT_STATUS_NOT_OK_RETURN(status
);
286 pvfs_setup_options(pvfs
);
288 talloc_set_destructor(pvfs
, pvfs_state_destructor
);
291 /* who had the stupid idea to generate a signal on a large
292 file write instead of just failing it!? */
293 BlockSignals(true, SIGXFSZ
);
300 disconnect from a share
302 static NTSTATUS
pvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
308 check if a directory exists
310 static NTSTATUS
pvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
311 struct ntvfs_request
*req
,
312 union smb_chkpath
*cp
)
314 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
316 struct pvfs_filename
*name
;
319 /* resolve the cifs name to a posix name */
320 status
= pvfs_resolve_name(pvfs
, req
, cp
->chkpath
.in
.path
, 0, &name
);
321 NT_STATUS_NOT_OK_RETURN(status
);
324 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
327 if (!S_ISDIR(name
->st
.st_mode
)) {
328 return NT_STATUS_NOT_A_DIRECTORY
;
337 static NTSTATUS
pvfs_copy(struct ntvfs_module_context
*ntvfs
,
338 struct ntvfs_request
*req
, struct smb_copy
*cp
)
340 DEBUG(0,("pvfs_copy not implemented\n"));
341 return NT_STATUS_NOT_SUPPORTED
;
345 return print queue info
347 static NTSTATUS
pvfs_lpq(struct ntvfs_module_context
*ntvfs
,
348 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
350 return NT_STATUS_NOT_SUPPORTED
;
353 /* SMBtrans - not used on file shares */
354 static NTSTATUS
pvfs_trans(struct ntvfs_module_context
*ntvfs
,
355 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
357 return NT_STATUS_ACCESS_DENIED
;
361 initialialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
363 NTSTATUS
ntvfs_posix_init(void)
366 struct ntvfs_ops ops
;
367 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
371 ops
.type
= NTVFS_DISK
;
373 /* fill in all the operations */
374 ops
.connect_fn
= pvfs_connect
;
375 ops
.disconnect_fn
= pvfs_disconnect
;
376 ops
.unlink_fn
= pvfs_unlink
;
377 ops
.chkpath_fn
= pvfs_chkpath
;
378 ops
.qpathinfo_fn
= pvfs_qpathinfo
;
379 ops
.setpathinfo_fn
= pvfs_setpathinfo
;
380 ops
.open_fn
= pvfs_open
;
381 ops
.mkdir_fn
= pvfs_mkdir
;
382 ops
.rmdir_fn
= pvfs_rmdir
;
383 ops
.rename_fn
= pvfs_rename
;
384 ops
.copy_fn
= pvfs_copy
;
385 ops
.ioctl_fn
= pvfs_ioctl
;
386 ops
.read_fn
= pvfs_read
;
387 ops
.write_fn
= pvfs_write
;
388 ops
.seek_fn
= pvfs_seek
;
389 ops
.flush_fn
= pvfs_flush
;
390 ops
.close_fn
= pvfs_close
;
391 ops
.exit_fn
= pvfs_exit
;
392 ops
.lock_fn
= pvfs_lock
;
393 ops
.setfileinfo_fn
= pvfs_setfileinfo
;
394 ops
.qfileinfo_fn
= pvfs_qfileinfo
;
395 ops
.fsinfo_fn
= pvfs_fsinfo
;
396 ops
.lpq_fn
= pvfs_lpq
;
397 ops
.search_first_fn
= pvfs_search_first
;
398 ops
.search_next_fn
= pvfs_search_next
;
399 ops
.search_close_fn
= pvfs_search_close
;
400 ops
.trans_fn
= pvfs_trans
;
401 ops
.logoff_fn
= pvfs_logoff
;
402 ops
.async_setup_fn
= pvfs_async_setup
;
403 ops
.cancel_fn
= pvfs_cancel
;
404 ops
.notify_fn
= pvfs_notify
;
406 /* register ourselves with the NTVFS subsystem. We register
407 under the name 'default' as we wish to be the default
408 backend, and also register as 'posix' */
409 ops
.name
= "default";
410 ret
= ntvfs_register(&ops
, &vers
);
412 if (!NT_STATUS_IS_OK(ret
)) {
413 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
417 ret
= ntvfs_register(&ops
, &vers
);
419 if (!NT_STATUS_IS_OK(ret
)) {
420 DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops
.name
));
423 if (NT_STATUS_IS_OK(ret
)) {
424 ret
= ntvfs_common_init();