Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 : /*
22 : this implements most of the POSIX NTVFS backend
23 : This is the default backend
24 : */
25 :
26 : #include "includes.h"
27 : #include "vfs_posix.h"
28 : #include "librpc/gen_ndr/security.h"
29 : #include <tdb.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"
34 : #include "lib/util/idtree.h"
35 :
36 : /*
37 : setup config options for a posix share
38 : */
39 1328 : static void pvfs_setup_options(struct pvfs_state *pvfs)
40 : {
41 1328 : struct share_config *scfg = pvfs->ntvfs->ctx->config;
42 0 : char *eadb;
43 0 : char *xattr_backend;
44 1328 : bool def_perm_override = false;
45 :
46 1328 : if (share_bool_option(scfg, SHARE_MAP_HIDDEN, SHARE_MAP_HIDDEN_DEFAULT))
47 0 : pvfs->flags |= PVFS_FLAG_MAP_HIDDEN;
48 1328 : if (share_bool_option(scfg, SHARE_MAP_ARCHIVE, SHARE_MAP_ARCHIVE_DEFAULT))
49 1328 : pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE;
50 1328 : if (share_bool_option(scfg, SHARE_MAP_SYSTEM, SHARE_MAP_SYSTEM_DEFAULT))
51 0 : pvfs->flags |= PVFS_FLAG_MAP_SYSTEM;
52 1328 : if (share_bool_option(scfg, SHARE_READONLY, SHARE_READONLY_DEFAULT))
53 0 : pvfs->flags |= PVFS_FLAG_READONLY;
54 1328 : if (share_bool_option(scfg, SHARE_STRICT_SYNC, SHARE_STRICT_SYNC_DEFAULT))
55 1328 : pvfs->flags |= PVFS_FLAG_STRICT_SYNC;
56 1328 : if (share_bool_option(scfg, SHARE_STRICT_LOCKING, SHARE_STRICT_LOCKING_DEFAULT))
57 1328 : pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
58 1328 : if (share_bool_option(scfg, SHARE_CI_FILESYSTEM, SHARE_CI_FILESYSTEM_DEFAULT))
59 0 : pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
60 1328 : if (share_bool_option(scfg, PVFS_FAKE_OPLOCKS, PVFS_FAKE_OPLOCKS_DEFAULT))
61 0 : pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS;
62 :
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
66 : */
67 1328 : def_perm_override = true;
68 : #endif
69 1328 : if (share_bool_option(scfg, PVFS_PERM_OVERRIDE, def_perm_override))
70 1328 : pvfs->flags |= PVFS_FLAG_PERM_OVERRIDE;
71 :
72 : /* file perm options */
73 1328 : pvfs->options.create_mask = share_int_option(scfg,
74 : SHARE_CREATE_MASK,
75 : SHARE_CREATE_MASK_DEFAULT);
76 1328 : pvfs->options.dir_mask = share_int_option(scfg,
77 : SHARE_DIR_MASK,
78 : SHARE_DIR_MASK_DEFAULT);
79 1328 : pvfs->options.force_dir_mode = share_int_option(scfg,
80 : SHARE_FORCE_DIR_MODE,
81 : SHARE_FORCE_DIR_MODE_DEFAULT);
82 1328 : 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 1328 : pvfs->alloc_size_rounding = share_int_option(scfg,
87 : PVFS_ALLOCATION_ROUNDING,
88 : PVFS_ALLOCATION_ROUNDING_DEFAULT);
89 :
90 1328 : pvfs->search.inactivity_time = share_int_option(scfg,
91 : PVFS_SEARCH_INACTIVITY,
92 : PVFS_SEARCH_INACTIVITY_DEFAULT);
93 :
94 : #ifdef HAVE_XATTR_SUPPORT
95 1328 : if (share_bool_option(scfg, PVFS_XATTR, PVFS_XATTR_DEFAULT))
96 1328 : pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
97 : #endif
98 :
99 1328 : pvfs->sharing_violation_delay = share_int_option(scfg,
100 : PVFS_SHARE_DELAY,
101 : PVFS_SHARE_DELAY_DEFAULT);
102 :
103 1328 : pvfs->oplock_break_timeout = share_int_option(scfg,
104 : PVFS_OPLOCK_TIMEOUT,
105 : PVFS_OPLOCK_TIMEOUT_DEFAULT);
106 :
107 1328 : pvfs->writetime_delay = share_int_option(scfg,
108 : PVFS_WRITETIME_DELAY,
109 : PVFS_WRITETIME_DELAY_DEFAULT);
110 :
111 1328 : pvfs->share_name = talloc_strdup(pvfs, scfg->name);
112 :
113 1328 : pvfs->fs_attribs =
114 : FS_ATTR_CASE_SENSITIVE_SEARCH |
115 : FS_ATTR_CASE_PRESERVED_NAMES |
116 : FS_ATTR_UNICODE_ON_DISK;
117 :
118 : /* allow xattrs to be stored in a external tdb */
119 1328 : eadb = share_string_option(pvfs, scfg, PVFS_EADB, NULL);
120 1328 : if (eadb != NULL) {
121 1328 : pvfs->ea_db = tdb_wrap_open(
122 : pvfs, eadb, 50000,
123 1328 : lpcfg_tdb_flags(pvfs->ntvfs->ctx->lp_ctx, TDB_DEFAULT),
124 : O_RDWR|O_CREAT, 0600);
125 1328 : if (pvfs->ea_db != NULL) {
126 1328 : pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
127 : } else {
128 0 : DEBUG(0,("Failed to open eadb '%s' - %s\n",
129 : eadb, strerror(errno)));
130 0 : pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE;
131 : }
132 1328 : TALLOC_FREE(eadb);
133 : }
134 :
135 1328 : if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
136 1328 : pvfs->fs_attribs |= FS_ATTR_NAMED_STREAMS;
137 : }
138 1328 : if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
139 1328 : pvfs->fs_attribs |= FS_ATTR_PERSISTANT_ACLS;
140 : }
141 :
142 1328 : pvfs->sid_cache.creator_owner = dom_sid_parse_talloc(pvfs, SID_CREATOR_OWNER);
143 1328 : pvfs->sid_cache.creator_group = dom_sid_parse_talloc(pvfs, SID_CREATOR_GROUP);
144 :
145 : /* check if the system really supports xattrs */
146 1328 : if (pvfs->flags & PVFS_FLAG_XATTR_ENABLE) {
147 1328 : pvfs_xattr_probe(pvfs);
148 : }
149 :
150 : /* enable an ACL backend */
151 1328 : xattr_backend = share_string_option(pvfs, scfg, PVFS_ACL, "xattr");
152 1328 : pvfs->acl_ops = pvfs_acl_backend_byname(xattr_backend);
153 1328 : TALLOC_FREE(xattr_backend);
154 1328 : }
155 :
156 1328 : static int pvfs_state_destructor(struct pvfs_state *pvfs)
157 : {
158 0 : struct pvfs_file *f, *fn;
159 0 : struct pvfs_search_state *s, *sn;
160 :
161 : /*
162 : * make sure we cleanup files and searches before anything else
163 : * because there destructors need to access the pvfs_state struct
164 : */
165 1328 : for (f=pvfs->files.list; f; f=fn) {
166 0 : fn = f->next;
167 0 : talloc_free(f);
168 : }
169 :
170 1354 : for (s=pvfs->search.list; s; s=sn) {
171 26 : sn = s->next;
172 26 : talloc_free(s);
173 : }
174 :
175 1328 : return 0;
176 : }
177 :
178 : /*
179 : connect to a share - used when a tree_connect operation comes
180 : in. For a disk based backend we needs to ensure that the base
181 : directory exists (tho it doesn't need to be accessible by the user,
182 : that comes later)
183 : */
184 1328 : static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
185 : struct ntvfs_request *req,
186 : union smb_tcon* tcon)
187 : {
188 0 : struct pvfs_state *pvfs;
189 0 : struct stat st;
190 0 : char *base_directory;
191 0 : NTSTATUS status;
192 0 : const char *sharename;
193 :
194 1328 : switch (tcon->generic.level) {
195 0 : case RAW_TCON_TCON:
196 0 : sharename = tcon->tcon.in.service;
197 0 : break;
198 760 : case RAW_TCON_TCONX:
199 760 : sharename = tcon->tconx.in.path;
200 760 : break;
201 568 : case RAW_TCON_SMB2:
202 568 : sharename = tcon->smb2.in.path;
203 568 : break;
204 0 : default:
205 0 : return NT_STATUS_INVALID_LEVEL;
206 : }
207 :
208 1328 : if (strncmp(sharename, "\\\\", 2) == 0) {
209 1325 : char *p = strchr(sharename+2, '\\');
210 1325 : if (p) {
211 1325 : sharename = p + 1;
212 : }
213 : }
214 :
215 : /*
216 : * TODO: call this from ntvfs_posix_init()
217 : * but currently we don't have a lp_ctx there
218 : */
219 1328 : status = pvfs_acl_init();
220 1328 : NT_STATUS_NOT_OK_RETURN(status);
221 :
222 1328 : pvfs = talloc_zero(ntvfs, struct pvfs_state);
223 1328 : NT_STATUS_HAVE_NO_MEMORY(pvfs);
224 :
225 : /* for simplicity of path construction, remove any trailing slash now */
226 1328 : base_directory = share_string_option(pvfs, ntvfs->ctx->config, SHARE_PATH, "");
227 1328 : NT_STATUS_HAVE_NO_MEMORY(base_directory);
228 1328 : if (strcmp(base_directory, "/") != 0) {
229 1328 : trim_string(base_directory, NULL, "/");
230 : }
231 :
232 1328 : pvfs->ntvfs = ntvfs;
233 1328 : pvfs->base_directory = base_directory;
234 :
235 : /* the directory must exist. Note that we deliberately don't
236 : check that it is readable */
237 1328 : if (stat(pvfs->base_directory, &st) != 0 || !S_ISDIR(st.st_mode)) {
238 0 : DEBUG(0,("pvfs_connect: '%s' is not a directory, when connecting to [%s]\n",
239 : pvfs->base_directory, sharename));
240 0 : return NT_STATUS_BAD_NETWORK_NAME;
241 : }
242 :
243 1328 : ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
244 1328 : NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
245 :
246 1328 : ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
247 1328 : NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
248 :
249 1328 : if (tcon->generic.level == RAW_TCON_TCONX) {
250 760 : tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
251 760 : tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
252 : }
253 :
254 1328 : ntvfs->private_data = pvfs;
255 :
256 2656 : pvfs->brl_context = brlock_init(pvfs,
257 1328 : pvfs->ntvfs->ctx->server_id,
258 1328 : pvfs->ntvfs->ctx->lp_ctx,
259 1328 : pvfs->ntvfs->ctx->msg_ctx);
260 1328 : if (pvfs->brl_context == NULL) {
261 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
262 : }
263 :
264 1328 : pvfs->odb_context = odb_init(pvfs, pvfs->ntvfs->ctx);
265 1328 : if (pvfs->odb_context == NULL) {
266 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
267 : }
268 :
269 : /* allow this to be NULL - we just disable change notify */
270 2656 : pvfs->notify_context = notify_init(pvfs,
271 1328 : pvfs->ntvfs->ctx->server_id,
272 1328 : pvfs->ntvfs->ctx->msg_ctx,
273 1328 : pvfs->ntvfs->ctx->lp_ctx,
274 1328 : pvfs->ntvfs->ctx->event_ctx,
275 1328 : pvfs->ntvfs->ctx->config);
276 :
277 : /* allocate the search handle -> ptr tree */
278 1328 : pvfs->search.idtree = idr_init(pvfs);
279 1328 : NT_STATUS_HAVE_NO_MEMORY(pvfs->search.idtree);
280 :
281 1328 : status = pvfs_mangle_init(pvfs);
282 1328 : NT_STATUS_NOT_OK_RETURN(status);
283 :
284 1328 : pvfs_setup_options(pvfs);
285 :
286 1328 : talloc_set_destructor(pvfs, pvfs_state_destructor);
287 :
288 : #ifdef SIGXFSZ
289 : /* who had the stupid idea to generate a signal on a large
290 : file write instead of just failing it!? */
291 1328 : BlockSignals(true, SIGXFSZ);
292 : #endif
293 :
294 1328 : return NT_STATUS_OK;
295 : }
296 :
297 : /*
298 : disconnect from a share
299 : */
300 1328 : static NTSTATUS pvfs_disconnect(struct ntvfs_module_context *ntvfs)
301 : {
302 1328 : return NT_STATUS_OK;
303 : }
304 :
305 : /*
306 : check if a directory exists
307 : */
308 732 : static NTSTATUS pvfs_chkpath(struct ntvfs_module_context *ntvfs,
309 : struct ntvfs_request *req,
310 : union smb_chkpath *cp)
311 : {
312 732 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
313 : struct pvfs_state);
314 0 : struct pvfs_filename *name;
315 0 : NTSTATUS status;
316 :
317 : /* resolve the cifs name to a posix name */
318 732 : status = pvfs_resolve_name(pvfs, req, cp->chkpath.in.path, 0, &name);
319 732 : NT_STATUS_NOT_OK_RETURN(status);
320 :
321 645 : if (!name->exists) {
322 95 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
323 : }
324 :
325 550 : if (!S_ISDIR(name->st.st_mode)) {
326 5 : return NT_STATUS_NOT_A_DIRECTORY;
327 : }
328 :
329 545 : return NT_STATUS_OK;
330 : }
331 :
332 : /*
333 : copy a set of files
334 : */
335 0 : static NTSTATUS pvfs_copy(struct ntvfs_module_context *ntvfs,
336 : struct ntvfs_request *req, struct smb_copy *cp)
337 : {
338 0 : DEBUG(0,("pvfs_copy not implemented\n"));
339 0 : return NT_STATUS_NOT_SUPPORTED;
340 : }
341 :
342 : /*
343 : return print queue info
344 : */
345 0 : static NTSTATUS pvfs_lpq(struct ntvfs_module_context *ntvfs,
346 : struct ntvfs_request *req, union smb_lpq *lpq)
347 : {
348 0 : return NT_STATUS_NOT_SUPPORTED;
349 : }
350 :
351 : /* SMBtrans - not used on file shares */
352 2 : static NTSTATUS pvfs_trans(struct ntvfs_module_context *ntvfs,
353 : struct ntvfs_request *req, struct smb_trans2 *trans2)
354 : {
355 2 : return NT_STATUS_ACCESS_DENIED;
356 : }
357 :
358 : /*
359 : initialise the POSIX disk backend, registering ourselves with the ntvfs subsystem
360 : */
361 68 : NTSTATUS ntvfs_posix_init(TALLOC_CTX *ctx)
362 : {
363 3 : NTSTATUS ret;
364 3 : struct ntvfs_ops ops;
365 68 : NTVFS_CURRENT_CRITICAL_SIZES(vers);
366 :
367 68 : ZERO_STRUCT(ops);
368 :
369 68 : ops.type = NTVFS_DISK;
370 :
371 : /* fill in all the operations */
372 68 : ops.connect_fn = pvfs_connect;
373 68 : ops.disconnect_fn = pvfs_disconnect;
374 68 : ops.unlink_fn = pvfs_unlink;
375 68 : ops.chkpath_fn = pvfs_chkpath;
376 68 : ops.qpathinfo_fn = pvfs_qpathinfo;
377 68 : ops.setpathinfo_fn = pvfs_setpathinfo;
378 68 : ops.open_fn = pvfs_open;
379 68 : ops.mkdir_fn = pvfs_mkdir;
380 68 : ops.rmdir_fn = pvfs_rmdir;
381 68 : ops.rename_fn = pvfs_rename;
382 68 : ops.copy_fn = pvfs_copy;
383 68 : ops.ioctl_fn = pvfs_ioctl;
384 68 : ops.read_fn = pvfs_read;
385 68 : ops.write_fn = pvfs_write;
386 68 : ops.seek_fn = pvfs_seek;
387 68 : ops.flush_fn = pvfs_flush;
388 68 : ops.close_fn = pvfs_close;
389 68 : ops.exit_fn = pvfs_exit;
390 68 : ops.lock_fn = pvfs_lock;
391 68 : ops.setfileinfo_fn = pvfs_setfileinfo;
392 68 : ops.qfileinfo_fn = pvfs_qfileinfo;
393 68 : ops.fsinfo_fn = pvfs_fsinfo;
394 68 : ops.lpq_fn = pvfs_lpq;
395 68 : ops.search_first_fn = pvfs_search_first;
396 68 : ops.search_next_fn = pvfs_search_next;
397 68 : ops.search_close_fn = pvfs_search_close;
398 68 : ops.trans_fn = pvfs_trans;
399 68 : ops.logoff_fn = pvfs_logoff;
400 68 : ops.async_setup_fn = pvfs_async_setup;
401 68 : ops.cancel_fn = pvfs_cancel;
402 68 : ops.notify_fn = pvfs_notify;
403 :
404 : /* register ourselves with the NTVFS subsystem. We register
405 : under the name 'default' as we wish to be the default
406 : backend, and also register as 'posix' */
407 68 : ops.name = "default";
408 68 : ret = ntvfs_register(&ops, &vers);
409 :
410 68 : if (!NT_STATUS_IS_OK(ret)) {
411 0 : DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
412 : }
413 :
414 68 : ops.name = "posix";
415 68 : ret = ntvfs_register(&ops, &vers);
416 :
417 68 : if (!NT_STATUS_IS_OK(ret)) {
418 0 : DEBUG(0,("Failed to register POSIX backend as '%s'!\n", ops.name));
419 : }
420 :
421 68 : if (NT_STATUS_IS_OK(ret)) {
422 68 : ret = ntvfs_common_init();
423 : }
424 :
425 68 : return ret;
426 : }
|