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