Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend - open and close
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 : #include "includes.h"
23 : #include "vfs_posix.h"
24 : #include "system/dir.h"
25 : #include "system/time.h"
26 : #include "../lib/util/dlinklist.h"
27 : #include "messaging/messaging.h"
28 : #include "librpc/gen_ndr/xattr.h"
29 :
30 : /*
31 : find open file handle given fnum
32 : */
33 305464 : struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 : struct ntvfs_request *req, struct ntvfs_handle *h)
35 : {
36 0 : void *p;
37 0 : struct pvfs_file *f;
38 :
39 305464 : p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
40 305464 : if (!p) return NULL;
41 :
42 305464 : f = talloc_get_type(p, struct pvfs_file);
43 305464 : if (!f) return NULL;
44 :
45 305464 : return f;
46 : }
47 :
48 : /*
49 : cleanup a open directory handle
50 : */
51 17040 : static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
52 : {
53 17040 : if (h->have_opendb_entry) {
54 0 : struct odb_lock *lck;
55 0 : NTSTATUS status;
56 17040 : const char *delete_path = NULL;
57 :
58 17040 : lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
59 17040 : if (lck == NULL) {
60 0 : DEBUG(0,("Unable to lock opendb for close\n"));
61 0 : return 0;
62 : }
63 :
64 17040 : status = odb_close_file(lck, h, &delete_path);
65 17040 : if (!NT_STATUS_IS_OK(status)) {
66 0 : DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 : h->name->full_name, nt_errstr(status)));
68 : }
69 :
70 17040 : if (h->name->stream_name == NULL && delete_path) {
71 413 : status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 413 : if (!NT_STATUS_IS_OK(status)) {
73 0 : DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 : delete_path, nt_errstr(status)));
75 : }
76 413 : if (pvfs_sys_rmdir(h->pvfs, delete_path, h->name->allow_override) != 0) {
77 0 : DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 : delete_path, strerror(errno)));
79 : }
80 : }
81 :
82 17040 : talloc_free(lck);
83 : }
84 :
85 17040 : return 0;
86 : }
87 :
88 : /*
89 : cleanup a open directory fnum
90 : */
91 17040 : static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
92 : {
93 17040 : DLIST_REMOVE(f->pvfs->files.list, f);
94 17040 : ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
95 :
96 17040 : return 0;
97 : }
98 :
99 : /*
100 : setup any EAs and the ACL on newly created files/directories
101 : */
102 101687 : static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 : struct ntvfs_request *req,
104 : struct pvfs_filename *name,
105 : int fd, struct pvfs_file *f,
106 : union smb_open *io,
107 : struct security_descriptor *sd)
108 : {
109 101687 : NTSTATUS status = NT_STATUS_OK;
110 :
111 : /* setup any EAs that were asked for */
112 101687 : if (io->ntcreatex.in.ea_list) {
113 66310 : status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
114 66310 : io->ntcreatex.in.ea_list->num_eas,
115 66310 : io->ntcreatex.in.ea_list->eas);
116 66310 : if (!NT_STATUS_IS_OK(status)) {
117 0 : return status;
118 : }
119 : }
120 :
121 : /* setup an initial sec_desc if requested */
122 101687 : if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
123 0 : union smb_setfileinfo set;
124 : /*
125 : * TODO: set the full ACL!
126 : * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
127 : * when a SACL is present on the sd,
128 : * but the user doesn't have SeSecurityPrivilege
129 : * - w2k3 allows it
130 : */
131 393 : set.set_secdesc.in.file.ntvfs = f->ntvfs;
132 393 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
133 393 : set.set_secdesc.in.sd = sd;
134 :
135 393 : status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
136 : }
137 :
138 101687 : return status;
139 : }
140 :
141 : /*
142 : form the lock context used for opendb locking. Note that we must
143 : zero here to take account of possible padding on some architectures
144 : */
145 890474 : NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
146 : TALLOC_CTX *mem_ctx, DATA_BLOB *key)
147 : {
148 0 : struct {
149 : dev_t device;
150 : ino_t inode;
151 : } lock_context;
152 890474 : ZERO_STRUCT(lock_context);
153 :
154 890474 : lock_context.device = name->st.st_dev;
155 890474 : lock_context.inode = name->st.st_ino;
156 :
157 890474 : *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
158 890474 : if (key->data == NULL) {
159 0 : return NT_STATUS_NO_MEMORY;
160 : }
161 :
162 890474 : return NT_STATUS_OK;
163 : }
164 :
165 :
166 : /*
167 : open a directory
168 : */
169 17197 : static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
170 : struct ntvfs_request *req,
171 : struct pvfs_filename *name,
172 : union smb_open *io)
173 : {
174 0 : struct pvfs_file *f;
175 0 : struct ntvfs_handle *h;
176 0 : NTSTATUS status;
177 0 : uint32_t create_action;
178 17197 : uint32_t access_mask = io->generic.in.access_mask;
179 0 : struct odb_lock *lck;
180 0 : bool del_on_close;
181 0 : uint32_t create_options;
182 0 : uint32_t share_access;
183 0 : bool forced;
184 17197 : struct security_descriptor *sd = NULL;
185 :
186 17197 : create_options = io->generic.in.create_options;
187 17197 : share_access = io->generic.in.share_access;
188 :
189 17197 : forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
190 :
191 17197 : if (name->stream_name) {
192 7 : if (forced) {
193 4 : return NT_STATUS_NOT_A_DIRECTORY;
194 : } else {
195 3 : return NT_STATUS_FILE_IS_A_DIRECTORY;
196 : }
197 : }
198 :
199 : /* if the client says it must be a directory, and it isn't,
200 : then fail */
201 17190 : if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
202 0 : return NT_STATUS_NOT_A_DIRECTORY;
203 : }
204 :
205 : /* found with gentest */
206 17190 : if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
207 54 : (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
208 51 : (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
209 0 : DEBUG(3,(__location__ ": Invalid access_mask/create_options 0x%08x 0x%08x for %s\n",
210 : io->ntcreatex.in.access_mask, io->ntcreatex.in.create_options, name->original_name));
211 0 : return NT_STATUS_INVALID_PARAMETER;
212 : }
213 :
214 17190 : switch (io->generic.in.open_disposition) {
215 8611 : case NTCREATEX_DISP_OPEN_IF:
216 8611 : break;
217 :
218 8215 : case NTCREATEX_DISP_OPEN:
219 8215 : if (!name->exists) {
220 106 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
221 : }
222 8109 : break;
223 :
224 353 : case NTCREATEX_DISP_CREATE:
225 353 : if (name->exists) {
226 15 : return NT_STATUS_OBJECT_NAME_COLLISION;
227 : }
228 338 : break;
229 :
230 11 : case NTCREATEX_DISP_OVERWRITE_IF:
231 : case NTCREATEX_DISP_OVERWRITE:
232 : case NTCREATEX_DISP_SUPERSEDE:
233 : default:
234 11 : DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
235 : io->generic.in.open_disposition, name->original_name));
236 11 : return NT_STATUS_INVALID_PARAMETER;
237 : }
238 :
239 17058 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
240 17058 : NT_STATUS_NOT_OK_RETURN(status);
241 :
242 17058 : f = talloc(h, struct pvfs_file);
243 17058 : if (f == NULL) {
244 0 : return NT_STATUS_NO_MEMORY;
245 : }
246 :
247 17058 : f->handle = talloc(f, struct pvfs_file_handle);
248 17058 : if (f->handle == NULL) {
249 0 : return NT_STATUS_NO_MEMORY;
250 : }
251 :
252 17058 : if (name->exists) {
253 : /* check the security descriptor */
254 12389 : status = pvfs_access_check(pvfs, req, name, &access_mask);
255 : } else {
256 4669 : sd = io->ntcreatex.in.sec_desc;
257 4669 : status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
258 : }
259 17058 : NT_STATUS_NOT_OK_RETURN(status);
260 :
261 17058 : if (io->generic.in.query_maximal_access) {
262 0 : status = pvfs_access_maximal_allowed(pvfs, req, name,
263 : &io->generic.out.maximal_access);
264 0 : NT_STATUS_NOT_OK_RETURN(status);
265 : }
266 :
267 17058 : f->ntvfs = h;
268 17058 : f->pvfs = pvfs;
269 17058 : f->pending_list = NULL;
270 17058 : f->lock_count = 0;
271 17058 : f->share_access = io->generic.in.share_access;
272 17058 : f->impersonation = io->generic.in.impersonation;
273 17058 : f->access_mask = access_mask;
274 17058 : f->brl_handle = NULL;
275 17058 : f->notify_buffer = NULL;
276 17058 : f->search = NULL;
277 :
278 17058 : f->handle->pvfs = pvfs;
279 17058 : f->handle->name = talloc_steal(f->handle, name);
280 17058 : f->handle->fd = -1;
281 17058 : f->handle->odb_locking_key = data_blob(NULL, 0);
282 17058 : f->handle->create_options = io->generic.in.create_options;
283 17058 : f->handle->private_flags = io->generic.in.private_flags;
284 17058 : f->handle->seek_offset = 0;
285 17058 : f->handle->position = 0;
286 17058 : f->handle->mode = 0;
287 17058 : f->handle->oplock = NULL;
288 17058 : ZERO_STRUCT(f->handle->write_time);
289 17058 : f->handle->open_completed = false;
290 :
291 17218 : if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
292 160 : pvfs_directory_empty(pvfs, f->handle->name)) {
293 155 : del_on_close = true;
294 : } else {
295 16903 : del_on_close = false;
296 : }
297 :
298 17058 : if (name->exists) {
299 : /* form the lock context used for opendb locking */
300 12389 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
301 12389 : if (!NT_STATUS_IS_OK(status)) {
302 0 : return status;
303 : }
304 :
305 : /* get a lock on this file before the actual open */
306 12389 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
307 12389 : if (lck == NULL) {
308 0 : DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
309 : name->full_name));
310 : /* we were supposed to do a blocking lock, so something
311 : is badly wrong! */
312 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
313 : }
314 :
315 : /* see if we are allowed to open at the same time as existing opens */
316 12389 : status = odb_can_open(lck, name->stream_id,
317 : share_access, access_mask, del_on_close,
318 : io->generic.in.open_disposition, false);
319 12389 : if (!NT_STATUS_IS_OK(status)) {
320 18 : talloc_free(lck);
321 18 : return status;
322 : }
323 :
324 : /* now really mark the file as open */
325 12371 : status = odb_open_file(lck, f->handle, name->full_name,
326 12371 : NULL, name->dos.write_time,
327 : false, OPLOCK_NONE, NULL);
328 :
329 12371 : if (!NT_STATUS_IS_OK(status)) {
330 0 : talloc_free(lck);
331 0 : return status;
332 : }
333 :
334 12371 : f->handle->have_opendb_entry = true;
335 : }
336 :
337 17040 : DLIST_ADD(pvfs->files.list, f);
338 :
339 : /* setup destructors to avoid leaks on abnormal termination */
340 17040 : talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
341 17040 : talloc_set_destructor(f, pvfs_dir_fnum_destructor);
342 :
343 17040 : if (!name->exists) {
344 4669 : uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
345 4669 : mode_t mode = pvfs_fileperms(pvfs, attrib);
346 :
347 4669 : if (pvfs_sys_mkdir(pvfs, name->full_name, mode, name->allow_override) == -1) {
348 0 : return pvfs_map_errno(pvfs,errno);
349 : }
350 :
351 4669 : pvfs_xattr_unlink_hook(pvfs, name->full_name);
352 :
353 4669 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
354 4669 : if (!NT_STATUS_IS_OK(status)) {
355 0 : goto cleanup_delete;
356 : }
357 :
358 4669 : status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
359 4669 : if (!NT_STATUS_IS_OK(status)) {
360 0 : goto cleanup_delete;
361 : }
362 :
363 : /* form the lock context used for opendb locking */
364 4669 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
365 4669 : if (!NT_STATUS_IS_OK(status)) {
366 0 : return status;
367 : }
368 :
369 4669 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
370 4669 : if (lck == NULL) {
371 0 : DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
372 : name->full_name));
373 : /* we were supposed to do a blocking lock, so something
374 : is badly wrong! */
375 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
376 : }
377 :
378 4669 : status = odb_can_open(lck, name->stream_id,
379 : share_access, access_mask, del_on_close,
380 : io->generic.in.open_disposition, false);
381 :
382 4669 : if (!NT_STATUS_IS_OK(status)) {
383 0 : goto cleanup_delete;
384 : }
385 :
386 4669 : status = odb_open_file(lck, f->handle, name->full_name,
387 4669 : NULL, name->dos.write_time,
388 : false, OPLOCK_NONE, NULL);
389 :
390 4669 : if (!NT_STATUS_IS_OK(status)) {
391 0 : goto cleanup_delete;
392 : }
393 :
394 4669 : f->handle->have_opendb_entry = true;
395 :
396 4669 : create_action = NTCREATEX_ACTION_CREATED;
397 :
398 4669 : notify_trigger(pvfs->notify_context,
399 : NOTIFY_ACTION_ADDED,
400 : FILE_NOTIFY_CHANGE_DIR_NAME,
401 4669 : name->full_name);
402 : } else {
403 12371 : create_action = NTCREATEX_ACTION_EXISTED;
404 : }
405 :
406 17040 : if (!name->exists) {
407 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
408 : }
409 :
410 17040 : if (io->generic.in.query_on_disk_id) {
411 0 : ZERO_ARRAY(io->generic.out.on_disk_id);
412 0 : SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
413 0 : SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
414 : }
415 :
416 : /* the open succeeded, keep this handle permanently */
417 17040 : status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
418 17040 : if (!NT_STATUS_IS_OK(status)) {
419 0 : goto cleanup_delete;
420 : }
421 :
422 17040 : f->handle->open_completed = true;
423 :
424 17040 : io->generic.out.oplock_level = OPLOCK_NONE;
425 17040 : io->generic.out.file.ntvfs = h;
426 17040 : io->generic.out.create_action = create_action;
427 17040 : io->generic.out.create_time = name->dos.create_time;
428 17040 : io->generic.out.access_time = name->dos.access_time;
429 17040 : io->generic.out.write_time = name->dos.write_time;
430 17040 : io->generic.out.change_time = name->dos.change_time;
431 17040 : io->generic.out.attrib = name->dos.attrib;
432 17040 : io->generic.out.alloc_size = name->dos.alloc_size;
433 17040 : io->generic.out.size = name->st.st_size;
434 17040 : io->generic.out.file_type = FILE_TYPE_DISK;
435 17040 : io->generic.out.ipc_state = 0;
436 17040 : io->generic.out.is_directory = 1;
437 :
438 17040 : return NT_STATUS_OK;
439 :
440 0 : cleanup_delete:
441 0 : pvfs_sys_rmdir(pvfs, name->full_name, name->allow_override);
442 0 : return status;
443 : }
444 :
445 : /*
446 : destroy a struct pvfs_file_handle
447 : */
448 189155 : static int pvfs_handle_destructor(struct pvfs_file_handle *h)
449 : {
450 189155 : talloc_free(h->write_time.update_event);
451 189155 : h->write_time.update_event = NULL;
452 :
453 189155 : if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
454 65993 : h->name->stream_name) {
455 0 : NTSTATUS status;
456 5 : status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
457 5 : if (!NT_STATUS_IS_OK(status)) {
458 0 : DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
459 : h->name->stream_name, h->name->full_name));
460 : }
461 : }
462 :
463 189155 : if (h->fd != -1) {
464 186188 : if (close(h->fd) != 0) {
465 0 : DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
466 : h->fd, h->name->full_name, strerror(errno)));
467 : }
468 186188 : h->fd = -1;
469 : }
470 :
471 189155 : if (!h->write_time.update_forced &&
472 188864 : h->write_time.update_on_close &&
473 9251 : h->write_time.close_time == 0) {
474 0 : struct timeval tv;
475 9250 : tv = timeval_current();
476 9250 : h->write_time.close_time = timeval_to_nttime(&tv);
477 : }
478 :
479 189155 : if (h->have_opendb_entry) {
480 0 : struct odb_lock *lck;
481 0 : NTSTATUS status;
482 186188 : const char *delete_path = NULL;
483 :
484 186188 : lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
485 186188 : if (lck == NULL) {
486 0 : DEBUG(0,("Unable to lock opendb for close\n"));
487 0 : return 0;
488 : }
489 :
490 186188 : if (h->write_time.update_forced) {
491 291 : status = odb_get_file_infos(h->pvfs->odb_context,
492 : &h->odb_locking_key,
493 : NULL,
494 : &h->write_time.close_time);
495 291 : if (!NT_STATUS_IS_OK(status)) {
496 0 : DEBUG(0,("Unable get write time for '%s' - %s\n",
497 : h->name->full_name, nt_errstr(status)));
498 : }
499 :
500 291 : h->write_time.update_forced = false;
501 291 : h->write_time.update_on_close = true;
502 185897 : } else if (h->write_time.update_on_close) {
503 9251 : status = odb_set_write_time(lck, h->write_time.close_time, true);
504 9251 : if (!NT_STATUS_IS_OK(status)) {
505 0 : DEBUG(0,("Unable set write time for '%s' - %s\n",
506 : h->name->full_name, nt_errstr(status)));
507 : }
508 : }
509 :
510 186188 : status = odb_close_file(lck, h, &delete_path);
511 186188 : if (!NT_STATUS_IS_OK(status)) {
512 0 : DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
513 : h->name->full_name, nt_errstr(status)));
514 : }
515 :
516 186188 : if (h->name->stream_name == NULL &&
517 186082 : h->open_completed && delete_path) {
518 65953 : status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
519 65953 : if (!NT_STATUS_IS_OK(status)) {
520 0 : DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
521 : delete_path, nt_errstr(status)));
522 : }
523 65953 : if (pvfs_sys_unlink(h->pvfs, delete_path, h->name->allow_override) != 0) {
524 0 : DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
525 : delete_path, strerror(errno)));
526 : } else {
527 65953 : notify_trigger(h->pvfs->notify_context,
528 : NOTIFY_ACTION_REMOVED,
529 : FILE_NOTIFY_CHANGE_FILE_NAME,
530 : delete_path);
531 : }
532 65953 : h->write_time.update_on_close = false;
533 : }
534 :
535 186188 : talloc_free(lck);
536 : }
537 :
538 189155 : if (h->write_time.update_on_close) {
539 0 : struct timeval tv[2];
540 :
541 9535 : nttime_to_timeval(&tv[0], h->name->dos.access_time);
542 9535 : nttime_to_timeval(&tv[1], h->write_time.close_time);
543 :
544 9535 : if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
545 9535 : if (utimes(h->name->full_name, tv) == -1) {
546 1 : DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
547 : h->name->full_name, strerror(errno)));
548 : }
549 : }
550 : }
551 :
552 189155 : return 0;
553 : }
554 :
555 :
556 : /*
557 : destroy a struct pvfs_file
558 : */
559 189155 : static int pvfs_fnum_destructor(struct pvfs_file *f)
560 : {
561 189155 : DLIST_REMOVE(f->pvfs->files.list, f);
562 189155 : pvfs_lock_close(f->pvfs, f);
563 189155 : ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
564 :
565 189155 : return 0;
566 : }
567 :
568 :
569 : /*
570 : form the lock context used for byte range locking. This is separate
571 : from the locking key used for opendb locking as it needs to take
572 : account of file streams (each stream is a separate byte range
573 : locking space)
574 : */
575 189155 : static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
576 : struct pvfs_filename *name,
577 : struct ntvfs_handle *ntvfs,
578 : struct brl_handle **_h)
579 : {
580 0 : DATA_BLOB odb_key, key;
581 0 : NTSTATUS status;
582 0 : struct brl_handle *h;
583 :
584 189155 : status = pvfs_locking_key(name, mem_ctx, &odb_key);
585 189155 : NT_STATUS_NOT_OK_RETURN(status);
586 :
587 189155 : if (name->stream_name == NULL) {
588 189032 : key = odb_key;
589 : } else {
590 123 : key = data_blob_talloc(mem_ctx, NULL,
591 : odb_key.length + strlen(name->stream_name) + 1);
592 123 : NT_STATUS_HAVE_NO_MEMORY(key.data);
593 123 : memcpy(key.data, odb_key.data, odb_key.length);
594 123 : memcpy(key.data + odb_key.length,
595 123 : name->stream_name, strlen(name->stream_name) + 1);
596 123 : data_blob_free(&odb_key);
597 : }
598 :
599 189155 : h = brlock_create_handle(mem_ctx, ntvfs, &key);
600 189155 : NT_STATUS_HAVE_NO_MEMORY(h);
601 :
602 189155 : *_h = h;
603 189155 : return NT_STATUS_OK;
604 : }
605 :
606 : /*
607 : create a new file
608 : */
609 97024 : static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
610 : struct ntvfs_request *req,
611 : struct pvfs_filename *name,
612 : union smb_open *io)
613 : {
614 0 : struct pvfs_file *f;
615 0 : NTSTATUS status;
616 0 : struct ntvfs_handle *h;
617 0 : int flags, fd;
618 0 : struct odb_lock *lck;
619 97024 : uint32_t create_options = io->generic.in.create_options;
620 97024 : uint32_t share_access = io->generic.in.share_access;
621 97024 : uint32_t access_mask = io->generic.in.access_mask;
622 0 : mode_t mode;
623 0 : uint32_t attrib;
624 0 : bool del_on_close;
625 0 : struct pvfs_filename *parent;
626 97024 : uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
627 97024 : bool allow_level_II_oplock = false;
628 97024 : struct security_descriptor *sd = NULL;
629 :
630 97024 : if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
631 0 : DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
632 : io->ntcreatex.in.file_attr, name->original_name));
633 0 : return NT_STATUS_INVALID_PARAMETER;
634 : }
635 :
636 97024 : if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
637 1 : DEBUG(3,(__location__ ": Invalid encryption request for %s\n",
638 : name->original_name));
639 1 : return NT_STATUS_ACCESS_DENIED;
640 : }
641 :
642 97023 : if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
643 32 : (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
644 3 : DEBUG(4,(__location__ ": Invalid delete on close for readonly file %s\n",
645 : name->original_name));
646 3 : return NT_STATUS_CANNOT_DELETE;
647 : }
648 :
649 97020 : sd = io->ntcreatex.in.sec_desc;
650 97020 : status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
651 97020 : NT_STATUS_NOT_OK_RETURN(status);
652 :
653 : /* check that the parent isn't opened with delete on close set */
654 97020 : status = pvfs_resolve_parent(pvfs, req, name, &parent);
655 97020 : if (NT_STATUS_IS_OK(status)) {
656 0 : DATA_BLOB locking_key;
657 97020 : status = pvfs_locking_key(parent, req, &locking_key);
658 97022 : NT_STATUS_NOT_OK_RETURN(status);
659 97020 : status = odb_get_file_infos(pvfs->odb_context, &locking_key,
660 : &del_on_close, NULL);
661 97020 : NT_STATUS_NOT_OK_RETURN(status);
662 97020 : if (del_on_close) {
663 2 : return NT_STATUS_DELETE_PENDING;
664 : }
665 : }
666 :
667 97018 : if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
668 92665 : flags = O_RDWR;
669 : } else {
670 4353 : flags = O_RDONLY;
671 : }
672 :
673 97018 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
674 97018 : NT_STATUS_NOT_OK_RETURN(status);
675 :
676 97018 : f = talloc(h, struct pvfs_file);
677 97018 : NT_STATUS_HAVE_NO_MEMORY(f);
678 :
679 97018 : f->handle = talloc(f, struct pvfs_file_handle);
680 97018 : NT_STATUS_HAVE_NO_MEMORY(f->handle);
681 :
682 97018 : attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
683 97018 : mode = pvfs_fileperms(pvfs, attrib);
684 :
685 : /* create the file */
686 97018 : fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode, name->allow_override);
687 97018 : if (fd == -1) {
688 0 : return pvfs_map_errno(pvfs, errno);
689 : }
690 :
691 97018 : pvfs_xattr_unlink_hook(pvfs, name->full_name);
692 :
693 : /* if this was a stream create then create the stream as well */
694 97018 : if (name->stream_name) {
695 22 : status = pvfs_stream_create(pvfs, name, fd);
696 22 : if (!NT_STATUS_IS_OK(status)) {
697 0 : close(fd);
698 0 : return status;
699 : }
700 : }
701 :
702 : /* re-resolve the open fd */
703 97018 : status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
704 97018 : if (!NT_STATUS_IS_OK(status)) {
705 0 : close(fd);
706 0 : return status;
707 : }
708 :
709 : /* support initial alloc sizes */
710 97018 : name->dos.alloc_size = io->ntcreatex.in.alloc_size;
711 97018 : name->dos.attrib = attrib;
712 97018 : status = pvfs_dosattrib_save(pvfs, name, fd);
713 97018 : if (!NT_STATUS_IS_OK(status)) {
714 0 : goto cleanup_delete;
715 : }
716 :
717 :
718 97018 : status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
719 97018 : if (!NT_STATUS_IS_OK(status)) {
720 0 : goto cleanup_delete;
721 : }
722 :
723 97018 : if (io->generic.in.query_maximal_access) {
724 0 : status = pvfs_access_maximal_allowed(pvfs, req, name,
725 : &io->generic.out.maximal_access);
726 0 : if (!NT_STATUS_IS_OK(status)) {
727 0 : goto cleanup_delete;
728 : }
729 : }
730 :
731 97018 : if (io->generic.in.query_on_disk_id) {
732 0 : ZERO_ARRAY(io->generic.out.on_disk_id);
733 0 : SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
734 0 : SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
735 : }
736 :
737 : /* form the lock context used for byte range locking and
738 : opendb locking */
739 97018 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
740 97018 : if (!NT_STATUS_IS_OK(status)) {
741 0 : goto cleanup_delete;
742 : }
743 :
744 97018 : status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
745 97018 : if (!NT_STATUS_IS_OK(status)) {
746 0 : goto cleanup_delete;
747 : }
748 :
749 : /* grab a lock on the open file record */
750 97018 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
751 97018 : if (lck == NULL) {
752 0 : DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
753 : name->full_name));
754 : /* we were supposed to do a blocking lock, so something
755 : is badly wrong! */
756 0 : status = NT_STATUS_INTERNAL_DB_CORRUPTION;
757 0 : goto cleanup_delete;
758 : }
759 :
760 97018 : if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
761 20 : del_on_close = true;
762 : } else {
763 96998 : del_on_close = false;
764 : }
765 :
766 97018 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
767 0 : oplock_level = OPLOCK_NONE;
768 97018 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
769 65 : oplock_level = OPLOCK_BATCH;
770 96953 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
771 22 : oplock_level = OPLOCK_EXCLUSIVE;
772 : }
773 :
774 97018 : if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
775 96745 : allow_level_II_oplock = true;
776 : }
777 :
778 97018 : status = odb_can_open(lck, name->stream_id,
779 : share_access, access_mask, del_on_close,
780 : io->generic.in.open_disposition, false);
781 97018 : if (!NT_STATUS_IS_OK(status)) {
782 0 : talloc_free(lck);
783 : /* bad news, we must have hit a race - we don't delete the file
784 : here as the most likely scenario is that someone else created
785 : the file at the same time */
786 0 : close(fd);
787 0 : return status;
788 : }
789 :
790 97018 : f->ntvfs = h;
791 97018 : f->pvfs = pvfs;
792 97018 : f->pending_list = NULL;
793 97018 : f->lock_count = 0;
794 97018 : f->share_access = io->generic.in.share_access;
795 97018 : f->access_mask = access_mask;
796 97018 : f->impersonation = io->generic.in.impersonation;
797 97018 : f->notify_buffer = NULL;
798 97018 : f->search = NULL;
799 :
800 97018 : f->handle->pvfs = pvfs;
801 97018 : f->handle->name = talloc_steal(f->handle, name);
802 97018 : f->handle->fd = fd;
803 97018 : f->handle->create_options = io->generic.in.create_options;
804 97018 : f->handle->private_flags = io->generic.in.private_flags;
805 97018 : f->handle->seek_offset = 0;
806 97018 : f->handle->position = 0;
807 97018 : f->handle->mode = 0;
808 97018 : f->handle->oplock = NULL;
809 97018 : f->handle->have_opendb_entry = true;
810 97018 : ZERO_STRUCT(f->handle->write_time);
811 97018 : f->handle->open_completed = false;
812 :
813 97018 : status = odb_open_file(lck, f->handle, name->full_name,
814 97018 : &f->handle->fd, name->dos.write_time,
815 : allow_level_II_oplock,
816 : oplock_level, &oplock_granted);
817 97018 : talloc_free(lck);
818 97018 : if (!NT_STATUS_IS_OK(status)) {
819 : /* bad news, we must have hit a race - we don't delete the file
820 : here as the most likely scenario is that someone else created
821 : the file at the same time */
822 0 : close(fd);
823 0 : return status;
824 : }
825 :
826 97018 : DLIST_ADD(pvfs->files.list, f);
827 :
828 : /* setup a destructor to avoid file descriptor leaks on
829 : abnormal termination */
830 97018 : talloc_set_destructor(f, pvfs_fnum_destructor);
831 97018 : talloc_set_destructor(f->handle, pvfs_handle_destructor);
832 :
833 97018 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
834 0 : oplock_granted = OPLOCK_BATCH;
835 97018 : } else if (oplock_granted != OPLOCK_NONE) {
836 87 : status = pvfs_setup_oplock(f, oplock_granted);
837 87 : if (!NT_STATUS_IS_OK(status)) {
838 0 : return status;
839 : }
840 : }
841 :
842 97018 : io->generic.out.oplock_level = oplock_granted;
843 97018 : io->generic.out.file.ntvfs = f->ntvfs;
844 97018 : io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
845 97018 : io->generic.out.create_time = name->dos.create_time;
846 97018 : io->generic.out.access_time = name->dos.access_time;
847 97018 : io->generic.out.write_time = name->dos.write_time;
848 97018 : io->generic.out.change_time = name->dos.change_time;
849 97018 : io->generic.out.attrib = name->dos.attrib;
850 97018 : io->generic.out.alloc_size = name->dos.alloc_size;
851 97018 : io->generic.out.size = name->st.st_size;
852 97018 : io->generic.out.file_type = FILE_TYPE_DISK;
853 97018 : io->generic.out.ipc_state = 0;
854 97018 : io->generic.out.is_directory = 0;
855 :
856 : /* success - keep the file handle */
857 97018 : status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
858 97018 : if (!NT_STATUS_IS_OK(status)) {
859 0 : goto cleanup_delete;
860 : }
861 :
862 97018 : f->handle->open_completed = true;
863 :
864 97018 : notify_trigger(pvfs->notify_context,
865 : NOTIFY_ACTION_ADDED,
866 : FILE_NOTIFY_CHANGE_FILE_NAME,
867 97018 : name->full_name);
868 :
869 97018 : return NT_STATUS_OK;
870 :
871 0 : cleanup_delete:
872 0 : close(fd);
873 0 : pvfs_sys_unlink(pvfs, name->full_name, name->allow_override);
874 0 : return status;
875 : }
876 :
877 : /*
878 : state of a pending retry
879 : */
880 : struct pvfs_odb_retry {
881 : struct ntvfs_module_context *ntvfs;
882 : struct ntvfs_request *req;
883 : DATA_BLOB odb_locking_key;
884 : void *io;
885 : void *private_data;
886 : void (*callback)(struct pvfs_odb_retry *r,
887 : struct ntvfs_module_context *ntvfs,
888 : struct ntvfs_request *req,
889 : void *io,
890 : void *private_data,
891 : enum pvfs_wait_notice reason);
892 : };
893 :
894 : /* destroy a pending request */
895 2915 : static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
896 : {
897 2915 : struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
898 : struct pvfs_state);
899 2915 : if (r->odb_locking_key.data) {
900 0 : struct odb_lock *lck;
901 2831 : lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
902 2831 : if (lck != NULL) {
903 2831 : odb_remove_pending(lck, r);
904 : }
905 2831 : talloc_free(lck);
906 : }
907 2915 : return 0;
908 : }
909 :
910 2875 : static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
911 : {
912 2875 : struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
913 :
914 2875 : if (reason == PVFS_WAIT_EVENT) {
915 : /*
916 : * The pending odb entry is already removed.
917 : * We use a null locking key to indicate this
918 : * to the destructor.
919 : */
920 84 : data_blob_free(&r->odb_locking_key);
921 : }
922 :
923 2875 : r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
924 2875 : }
925 :
926 : /*
927 : setup for a retry of a request that was rejected
928 : by odb_can_open()
929 : */
930 2915 : NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
931 : struct ntvfs_request *req,
932 : struct odb_lock *lck,
933 : struct timeval end_time,
934 : void *io,
935 : void *private_data,
936 : void (*callback)(struct pvfs_odb_retry *r,
937 : struct ntvfs_module_context *ntvfs,
938 : struct ntvfs_request *req,
939 : void *io,
940 : void *private_data,
941 : enum pvfs_wait_notice reason))
942 : {
943 2915 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
944 : struct pvfs_state);
945 0 : struct pvfs_odb_retry *r;
946 0 : struct pvfs_wait *wait_handle;
947 0 : NTSTATUS status;
948 :
949 2915 : r = talloc(req, struct pvfs_odb_retry);
950 2915 : NT_STATUS_HAVE_NO_MEMORY(r);
951 :
952 2915 : r->ntvfs = ntvfs;
953 2915 : r->req = req;
954 2915 : r->io = io;
955 2915 : r->private_data = private_data;
956 2915 : r->callback = callback;
957 2915 : r->odb_locking_key = odb_get_key(r, lck);
958 2915 : if (r->odb_locking_key.data == NULL) {
959 0 : return NT_STATUS_NO_MEMORY;
960 : }
961 :
962 : /* setup a pending lock */
963 2915 : status = odb_open_file_pending(lck, r);
964 2915 : if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
965 : /*
966 : * maybe only a unix application
967 : * has the file open
968 : */
969 0 : data_blob_free(&r->odb_locking_key);
970 2915 : } else if (!NT_STATUS_IS_OK(status)) {
971 0 : return status;
972 : }
973 :
974 2915 : talloc_free(lck);
975 :
976 2915 : talloc_set_destructor(r, pvfs_odb_retry_destructor);
977 :
978 2915 : wait_handle = pvfs_wait_message(pvfs, req,
979 : MSG_PVFS_RETRY_OPEN, end_time,
980 : pvfs_odb_retry_callback, r);
981 2915 : if (wait_handle == NULL) {
982 0 : return NT_STATUS_NO_MEMORY;
983 : }
984 :
985 2915 : talloc_steal(r, wait_handle);
986 :
987 2915 : return NT_STATUS_OK;
988 : }
989 :
990 : /*
991 : retry an open after a sharing violation
992 : */
993 2818 : static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
994 : struct ntvfs_module_context *ntvfs,
995 : struct ntvfs_request *req,
996 : void *_io,
997 : void *private_data,
998 : enum pvfs_wait_notice reason)
999 : {
1000 2818 : union smb_open *io = talloc_get_type(_io, union smb_open);
1001 2818 : struct timeval *final_timeout = NULL;
1002 0 : NTSTATUS status;
1003 :
1004 2818 : if (private_data) {
1005 0 : final_timeout = talloc_get_type(private_data,
1006 : struct timeval);
1007 : }
1008 :
1009 : /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
1010 : just a bug in their server, but we better do the same */
1011 2818 : if (reason == PVFS_WAIT_CANCEL) {
1012 2754 : return;
1013 : }
1014 :
1015 2817 : if (reason == PVFS_WAIT_TIMEOUT) {
1016 2746 : if (final_timeout &&
1017 0 : !timeval_expired(final_timeout)) {
1018 : /*
1019 : * we need to retry periodictly
1020 : * after an EAGAIN as there's
1021 : * no way the kernel tell us
1022 : * an oplock is released.
1023 : */
1024 0 : goto retry;
1025 : }
1026 : /* if it timed out, then give the failure
1027 : immediately */
1028 2746 : talloc_free(r);
1029 2746 : req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1030 2746 : req->async_states->send_fn(req);
1031 2746 : return;
1032 : }
1033 :
1034 71 : retry:
1035 71 : talloc_free(r);
1036 :
1037 : /* try the open again, which could trigger another retry setup
1038 : if it wants to, so we have to unmark the async flag so we
1039 : will know if it does a second async reply */
1040 71 : req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1041 :
1042 71 : status = pvfs_open(ntvfs, req, io);
1043 71 : if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1044 : /* the 2nd try also replied async, so we don't send
1045 : the reply yet */
1046 7 : return;
1047 : }
1048 :
1049 : /* re-mark it async, just in case someone up the chain does
1050 : paranoid checking */
1051 64 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1052 :
1053 : /* send the reply up the chain */
1054 64 : req->async_states->status = status;
1055 64 : req->async_states->send_fn(req);
1056 : }
1057 :
1058 :
1059 : /*
1060 : special handling for openx DENY_DOS semantics
1061 :
1062 : This function attempts a reference open using an existing handle. If its allowed,
1063 : then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1064 : open processing continues.
1065 : */
1066 768 : static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1067 : struct ntvfs_request *req, union smb_open *io,
1068 : struct pvfs_file *f, struct odb_lock *lck)
1069 : {
1070 768 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1071 : struct pvfs_state);
1072 0 : struct pvfs_file *f2;
1073 0 : struct pvfs_filename *name;
1074 0 : NTSTATUS status;
1075 :
1076 : /* search for an existing open with the right parameters. Note
1077 : the magic ntcreatex options flag, which is set in the
1078 : generic mapping code. This might look ugly, but its
1079 : actually pretty much now w2k does it internally as well.
1080 :
1081 : If you look at the BASE-DENYDOS test you will see that a
1082 : DENY_DOS is a very special case, and in the right
1083 : circumstances you actually get the _same_ handle back
1084 : twice, rather than a new handle.
1085 : */
1086 1809 : for (f2=pvfs->files.list;f2;f2=f2->next) {
1087 1156 : if (f2 != f &&
1088 388 : f2->ntvfs->session_info == req->session_info &&
1089 388 : f2->ntvfs->smbpid == req->smbpid &&
1090 388 : (f2->handle->private_flags &
1091 : (NTCREATEX_FLAG_DENY_DOS |
1092 131 : NTCREATEX_FLAG_DENY_FCB)) &&
1093 246 : (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1094 115 : strcasecmp_m(f2->handle->name->original_name,
1095 : io->generic.in.fname)==0) {
1096 115 : break;
1097 : }
1098 : }
1099 :
1100 768 : if (!f2) {
1101 653 : return NT_STATUS_SHARING_VIOLATION;
1102 : }
1103 :
1104 : /* quite an insane set of semantics ... */
1105 115 : if (is_exe_filename(io->generic.in.fname) &&
1106 48 : (f2->handle->private_flags & NTCREATEX_FLAG_DENY_DOS)) {
1107 12 : return NT_STATUS_SHARING_VIOLATION;
1108 : }
1109 :
1110 : /*
1111 : setup a reference to the existing handle
1112 : */
1113 103 : talloc_free(f->handle);
1114 103 : f->handle = talloc_reference(f, f2->handle);
1115 :
1116 103 : talloc_free(lck);
1117 :
1118 103 : name = f->handle->name;
1119 :
1120 103 : io->generic.out.oplock_level = OPLOCK_NONE;
1121 103 : io->generic.out.file.ntvfs = f->ntvfs;
1122 103 : io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1123 103 : io->generic.out.create_time = name->dos.create_time;
1124 103 : io->generic.out.access_time = name->dos.access_time;
1125 103 : io->generic.out.write_time = name->dos.write_time;
1126 103 : io->generic.out.change_time = name->dos.change_time;
1127 103 : io->generic.out.attrib = name->dos.attrib;
1128 103 : io->generic.out.alloc_size = name->dos.alloc_size;
1129 103 : io->generic.out.size = name->st.st_size;
1130 103 : io->generic.out.file_type = FILE_TYPE_DISK;
1131 103 : io->generic.out.ipc_state = 0;
1132 103 : io->generic.out.is_directory = 0;
1133 :
1134 103 : status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1135 103 : NT_STATUS_NOT_OK_RETURN(status);
1136 :
1137 103 : return NT_STATUS_OK;
1138 : }
1139 :
1140 :
1141 :
1142 : /*
1143 : setup for a open retry after a sharing violation
1144 : */
1145 2961 : static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1146 : struct ntvfs_request *req,
1147 : union smb_open *io,
1148 : struct pvfs_file *f,
1149 : struct odb_lock *lck,
1150 : NTSTATUS parent_status)
1151 : {
1152 2961 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1153 : struct pvfs_state);
1154 0 : NTSTATUS status;
1155 0 : struct timeval end_time;
1156 2961 : struct timeval *final_timeout = NULL;
1157 :
1158 2961 : if (io->generic.in.private_flags &
1159 : (NTCREATEX_FLAG_DENY_DOS | NTCREATEX_FLAG_DENY_FCB)) {
1160 : /* see if we can satisfy the request using the special DENY_DOS
1161 : code */
1162 768 : status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1163 768 : if (NT_STATUS_IS_OK(status)) {
1164 103 : return status;
1165 : }
1166 : }
1167 :
1168 : /* the retry should allocate a new file handle */
1169 2858 : talloc_free(f);
1170 :
1171 2858 : if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1172 2788 : end_time = timeval_add(&req->statistics.request_time,
1173 : 0, pvfs->sharing_violation_delay);
1174 70 : } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1175 70 : end_time = timeval_add(&req->statistics.request_time,
1176 : pvfs->oplock_break_timeout, 0);
1177 0 : } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1178 : /*
1179 : * we got EAGAIN which means a unix application
1180 : * has an oplock or share mode
1181 : *
1182 : * we retry every 4/5 of the sharing violation delay
1183 : * to see if the unix application
1184 : * has released the oplock or share mode.
1185 : */
1186 0 : final_timeout = talloc(req, struct timeval);
1187 0 : NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1188 0 : *final_timeout = timeval_add(&req->statistics.request_time,
1189 : pvfs->oplock_break_timeout,
1190 : 0);
1191 0 : end_time = timeval_current_ofs_usec((pvfs->sharing_violation_delay*4)/5);
1192 0 : end_time = timeval_min(final_timeout, &end_time);
1193 : } else {
1194 0 : return NT_STATUS_INTERNAL_ERROR;
1195 : }
1196 :
1197 2858 : return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1198 : final_timeout, pvfs_retry_open_sharing);
1199 : }
1200 :
1201 : /*
1202 : open a file
1203 : */
1204 490812 : NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1205 : struct ntvfs_request *req, union smb_open *io)
1206 : {
1207 490812 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1208 : struct pvfs_state);
1209 490812 : int flags = 0;
1210 0 : struct pvfs_filename *name;
1211 0 : struct pvfs_file *f;
1212 0 : struct ntvfs_handle *h;
1213 0 : NTSTATUS status;
1214 0 : int fd, count;
1215 0 : struct odb_lock *lck;
1216 0 : uint32_t create_options;
1217 0 : uint32_t create_options_must_ignore_mask;
1218 0 : uint32_t share_access;
1219 0 : uint32_t access_mask;
1220 490812 : uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1221 0 : bool del_on_close;
1222 490812 : bool stream_existed, stream_truncate=false;
1223 490812 : uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1224 490812 : bool allow_level_II_oplock = false;
1225 :
1226 : /* use the generic mapping code to avoid implementing all the
1227 : different open calls. */
1228 490812 : if (io->generic.level != RAW_OPEN_GENERIC &&
1229 217304 : io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1230 217207 : return ntvfs_map_open(ntvfs, req, io);
1231 : }
1232 :
1233 273605 : ZERO_STRUCT(io->generic.out);
1234 :
1235 273605 : create_options = io->generic.in.create_options;
1236 273605 : share_access = io->generic.in.share_access;
1237 273605 : access_mask = io->generic.in.access_mask;
1238 :
1239 273605 : if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1240 0 : DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
1241 : share_access, io->ntcreatex.in.fname));
1242 0 : return NT_STATUS_INVALID_PARAMETER;
1243 : }
1244 :
1245 : /*
1246 : * These options are ignored,
1247 : * but we reuse some of them as private values for the generic mapping
1248 : */
1249 273605 : create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1250 273605 : create_options &= ~create_options_must_ignore_mask;
1251 :
1252 273605 : if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1253 4 : DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1254 : create_options));
1255 4 : return NT_STATUS_NOT_SUPPORTED;
1256 : }
1257 :
1258 273601 : if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1259 22 : DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
1260 : create_options, io->ntcreatex.in.fname));
1261 22 : return NT_STATUS_INVALID_PARAMETER;
1262 : }
1263 :
1264 : /* TODO: When we implement HSM, add a hook here not to pull
1265 : * the actual file off tape, when this option is passed from
1266 : * the client */
1267 273579 : if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1268 : /* no-op */
1269 0 : }
1270 :
1271 : /* TODO: If (unlikely) Linux does a good compressed
1272 : * filesystem, we might need an ioctl call for this */
1273 273579 : if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1274 : /* no-op */
1275 0 : }
1276 :
1277 273579 : if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1278 2 : create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1279 : }
1280 :
1281 : /* Open the file with sync, if they asked for it, but
1282 : 'strict sync = no' turns this client request into a no-op */
1283 273579 : if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && pvfs->flags & PVFS_FLAG_STRICT_SYNC) {
1284 6 : flags |= O_SYNC;
1285 : }
1286 :
1287 :
1288 : /* other create options are not allowed */
1289 273579 : if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1290 132162 : !(access_mask & SEC_STD_DELETE)) {
1291 35 : DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
1292 : create_options, access_mask, io->ntcreatex.in.fname));
1293 35 : return NT_STATUS_INVALID_PARAMETER;
1294 : }
1295 :
1296 273544 : if (access_mask & SEC_MASK_INVALID) {
1297 309 : return NT_STATUS_ACCESS_DENIED;
1298 : }
1299 :
1300 : /* what does this bit really mean?? */
1301 273235 : if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
1302 208589 : access_mask == SEC_STD_SYNCHRONIZE) {
1303 5 : return NT_STATUS_ACCESS_DENIED;
1304 : }
1305 :
1306 : /* cope with non-zero root_fid */
1307 273230 : if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
1308 16656 : f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
1309 16656 : if (f == NULL) {
1310 0 : return NT_STATUS_INVALID_HANDLE;
1311 : }
1312 16656 : if (f->handle->fd != -1) {
1313 0 : return NT_STATUS_INVALID_DEVICE_REQUEST;
1314 : }
1315 33312 : io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s",
1316 16656 : f->handle->name->original_name,
1317 : io->ntcreatex.in.fname);
1318 16656 : NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);
1319 : }
1320 :
1321 273230 : if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1322 : FILE_ATTRIBUTE_VOLUME|
1323 : (~FILE_ATTRIBUTE_ALL_MASK))) {
1324 27 : DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
1325 : io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
1326 27 : return NT_STATUS_INVALID_PARAMETER;
1327 : }
1328 :
1329 : /* we ignore some file_attr bits */
1330 273203 : io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1331 : FILE_ATTRIBUTE_COMPRESSED |
1332 : FILE_ATTRIBUTE_REPARSE_POINT |
1333 : FILE_ATTRIBUTE_SPARSE |
1334 : FILE_ATTRIBUTE_NORMAL);
1335 :
1336 : /* resolve the cifs name to a posix name */
1337 273203 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1338 : PVFS_RESOLVE_STREAMS, &name);
1339 273203 : if (!NT_STATUS_IS_OK(status)) {
1340 113 : return status;
1341 : }
1342 :
1343 : /* if the client specified that it must not be a directory then
1344 : check that it isn't */
1345 273090 : if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1346 12648 : (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1347 235 : return NT_STATUS_FILE_IS_A_DIRECTORY;
1348 : }
1349 :
1350 : /* if the client specified that it must be a directory then
1351 : check that it is */
1352 272855 : if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1353 92699 : (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1354 118 : return NT_STATUS_NOT_A_DIRECTORY;
1355 : }
1356 :
1357 : /* directory opens are handled separately */
1358 272737 : if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1359 260324 : (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1360 17197 : return pvfs_open_directory(pvfs, req, name, io);
1361 : }
1362 :
1363 : /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1364 : open doesn't match */
1365 255540 : io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1366 :
1367 255540 : switch (io->generic.in.open_disposition) {
1368 3549 : case NTCREATEX_DISP_SUPERSEDE:
1369 : case NTCREATEX_DISP_OVERWRITE_IF:
1370 3549 : if (name->stream_name == NULL) {
1371 3537 : flags |= O_TRUNC;
1372 : } else {
1373 12 : stream_truncate = true;
1374 : }
1375 3549 : create_action = NTCREATEX_ACTION_TRUNCATED;
1376 3549 : break;
1377 :
1378 148081 : case NTCREATEX_DISP_OPEN:
1379 148081 : if (!name->stream_exists) {
1380 66177 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1381 : }
1382 81904 : break;
1383 :
1384 799 : case NTCREATEX_DISP_OVERWRITE:
1385 799 : if (!name->stream_exists) {
1386 5 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1387 : }
1388 794 : if (name->stream_name == NULL) {
1389 794 : flags |= O_TRUNC;
1390 : } else {
1391 0 : stream_truncate = true;
1392 : }
1393 794 : create_action = NTCREATEX_ACTION_TRUNCATED;
1394 794 : break;
1395 :
1396 82999 : case NTCREATEX_DISP_CREATE:
1397 82999 : if (name->stream_exists) {
1398 151 : return NT_STATUS_OBJECT_NAME_COLLISION;
1399 : }
1400 82848 : break;
1401 :
1402 20106 : case NTCREATEX_DISP_OPEN_IF:
1403 20106 : break;
1404 :
1405 6 : default:
1406 6 : DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
1407 : io->generic.in.open_disposition, name->original_name));
1408 6 : return NT_STATUS_INVALID_PARAMETER;
1409 : }
1410 :
1411 : /* handle creating a new file separately */
1412 189201 : if (!name->exists) {
1413 97024 : status = pvfs_create_file(pvfs, req, name, io);
1414 97024 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1415 97024 : return status;
1416 : }
1417 :
1418 : /* we've hit a race - the file was created during this call */
1419 0 : if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1420 0 : return status;
1421 : }
1422 :
1423 : /* try re-resolving the name */
1424 0 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1425 0 : if (!NT_STATUS_IS_OK(status)) {
1426 0 : return status;
1427 : }
1428 : /* fall through to a normal open */
1429 : }
1430 :
1431 92177 : if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1432 512 : (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1433 5 : return NT_STATUS_CANNOT_DELETE;
1434 : }
1435 :
1436 : /* check the security descriptor */
1437 92172 : status = pvfs_access_check(pvfs, req, name, &access_mask);
1438 92172 : NT_STATUS_NOT_OK_RETURN(status);
1439 :
1440 92137 : if (io->generic.in.query_maximal_access) {
1441 12 : status = pvfs_access_maximal_allowed(pvfs, req, name,
1442 : &io->generic.out.maximal_access);
1443 12 : NT_STATUS_NOT_OK_RETURN(status);
1444 : }
1445 :
1446 92137 : if (io->generic.in.query_on_disk_id) {
1447 10 : ZERO_ARRAY(io->generic.out.on_disk_id);
1448 10 : SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
1449 10 : SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
1450 : }
1451 :
1452 92137 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1453 92137 : NT_STATUS_NOT_OK_RETURN(status);
1454 :
1455 92137 : f = talloc(h, struct pvfs_file);
1456 92137 : if (f == NULL) {
1457 0 : return NT_STATUS_NO_MEMORY;
1458 : }
1459 :
1460 92137 : f->handle = talloc(f, struct pvfs_file_handle);
1461 92137 : if (f->handle == NULL) {
1462 0 : return NT_STATUS_NO_MEMORY;
1463 : }
1464 :
1465 92137 : f->ntvfs = h;
1466 92137 : f->pvfs = pvfs;
1467 92137 : f->pending_list = NULL;
1468 92137 : f->lock_count = 0;
1469 92137 : f->share_access = io->generic.in.share_access;
1470 92137 : f->access_mask = access_mask;
1471 92137 : f->impersonation = io->generic.in.impersonation;
1472 92137 : f->notify_buffer = NULL;
1473 92137 : f->search = NULL;
1474 :
1475 92137 : f->handle->pvfs = pvfs;
1476 92137 : f->handle->fd = -1;
1477 92137 : f->handle->name = talloc_steal(f->handle, name);
1478 92137 : f->handle->create_options = io->generic.in.create_options;
1479 92137 : f->handle->private_flags = io->generic.in.private_flags;
1480 92137 : f->handle->seek_offset = 0;
1481 92137 : f->handle->position = 0;
1482 92137 : f->handle->mode = 0;
1483 92137 : f->handle->oplock = NULL;
1484 92137 : f->handle->have_opendb_entry = false;
1485 92137 : ZERO_STRUCT(f->handle->write_time);
1486 92137 : f->handle->open_completed = false;
1487 :
1488 : /* form the lock context used for byte range locking and
1489 : opendb locking */
1490 92137 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1491 92137 : if (!NT_STATUS_IS_OK(status)) {
1492 0 : return status;
1493 : }
1494 :
1495 92137 : status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1496 92137 : if (!NT_STATUS_IS_OK(status)) {
1497 0 : return status;
1498 : }
1499 :
1500 : /* get a lock on this file before the actual open */
1501 92137 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1502 92137 : if (lck == NULL) {
1503 0 : DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1504 : name->full_name));
1505 : /* we were supposed to do a blocking lock, so something
1506 : is badly wrong! */
1507 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1508 : }
1509 :
1510 92137 : DLIST_ADD(pvfs->files.list, f);
1511 :
1512 : /* setup a destructor to avoid file descriptor leaks on
1513 : abnormal termination */
1514 92137 : talloc_set_destructor(f, pvfs_fnum_destructor);
1515 92137 : talloc_set_destructor(f->handle, pvfs_handle_destructor);
1516 :
1517 : /*
1518 : * Only SMB2 takes care of the delete_on_close,
1519 : * on existing files
1520 : */
1521 92137 : if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1522 65949 : req->ctx->protocol >= PROTOCOL_SMB2_02) {
1523 65925 : del_on_close = true;
1524 : } else {
1525 26212 : del_on_close = false;
1526 : }
1527 :
1528 92137 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1529 0 : oplock_level = OPLOCK_NONE;
1530 92137 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1531 88 : oplock_level = OPLOCK_BATCH;
1532 92049 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1533 50 : oplock_level = OPLOCK_EXCLUSIVE;
1534 : }
1535 :
1536 92137 : if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1537 92077 : allow_level_II_oplock = true;
1538 : }
1539 :
1540 : /* see if we are allowed to open at the same time as existing opens */
1541 92137 : status = odb_can_open(lck, name->stream_id,
1542 : share_access, access_mask, del_on_close,
1543 : io->generic.in.open_disposition, false);
1544 :
1545 : /*
1546 : * on a sharing violation we need to retry when the file is closed by
1547 : * the other user, or after 1 second
1548 : * on a non granted oplock we need to retry when the file is closed by
1549 : * the other user, or after 30 seconds
1550 : */
1551 92137 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1552 89246 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1553 2961 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1554 2961 : return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1555 : }
1556 :
1557 89176 : if (!NT_STATUS_IS_OK(status)) {
1558 6 : talloc_free(lck);
1559 6 : return status;
1560 : }
1561 :
1562 89170 : if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1563 17003 : flags |= O_RDWR;
1564 : } else {
1565 72167 : flags |= O_RDONLY;
1566 : }
1567 :
1568 : /* do the actual open */
1569 89170 : fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
1570 89170 : if (fd == -1) {
1571 0 : status = pvfs_map_errno(f->pvfs, errno);
1572 :
1573 0 : DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1574 : nt_errstr(status), f->handle->name->full_name, errno));
1575 : /*
1576 : * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1577 : */
1578 0 : if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1579 0 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1580 0 : return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1581 : }
1582 :
1583 0 : talloc_free(lck);
1584 0 : return status;
1585 : }
1586 :
1587 89170 : f->handle->fd = fd;
1588 :
1589 89170 : status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
1590 89170 : if (!NT_STATUS_IS_OK(status)) {
1591 0 : talloc_free(lck);
1592 0 : return status;
1593 : }
1594 :
1595 89170 : if (count != 0) {
1596 89 : oplock_level = OPLOCK_NONE;
1597 : }
1598 :
1599 : /* now really mark the file as open */
1600 89170 : status = odb_open_file(lck, f->handle, name->full_name,
1601 89170 : &f->handle->fd, name->dos.write_time,
1602 : allow_level_II_oplock,
1603 : oplock_level, &oplock_granted);
1604 :
1605 89170 : if (!NT_STATUS_IS_OK(status)) {
1606 0 : talloc_free(lck);
1607 0 : return status;
1608 : }
1609 :
1610 89170 : f->handle->have_opendb_entry = true;
1611 :
1612 89170 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1613 0 : oplock_granted = OPLOCK_BATCH;
1614 89170 : } else if (oplock_granted != OPLOCK_NONE) {
1615 77 : status = pvfs_setup_oplock(f, oplock_granted);
1616 77 : if (!NT_STATUS_IS_OK(status)) {
1617 0 : talloc_free(lck);
1618 0 : return status;
1619 : }
1620 : }
1621 :
1622 89170 : stream_existed = name->stream_exists;
1623 :
1624 : /* if this was a stream create then create the stream as well */
1625 89170 : if (!name->stream_exists) {
1626 27 : status = pvfs_stream_create(pvfs, f->handle->name, fd);
1627 27 : if (!NT_STATUS_IS_OK(status)) {
1628 0 : talloc_free(lck);
1629 0 : return status;
1630 : }
1631 27 : if (stream_truncate) {
1632 3 : status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1633 3 : if (!NT_STATUS_IS_OK(status)) {
1634 0 : talloc_free(lck);
1635 0 : return status;
1636 : }
1637 : }
1638 : }
1639 :
1640 : /* re-resolve the open fd */
1641 89170 : status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1642 89170 : if (!NT_STATUS_IS_OK(status)) {
1643 0 : talloc_free(lck);
1644 0 : return status;
1645 : }
1646 :
1647 89170 : if (f->handle->name->stream_id == 0 &&
1648 89086 : (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1649 88297 : io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1650 : /* for overwrite we may need to replace file permissions */
1651 1406 : uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1652 1406 : mode_t mode = pvfs_fileperms(pvfs, attrib);
1653 1406 : if (f->handle->name->st.st_mode != mode &&
1654 2122 : f->handle->name->dos.attrib != attrib &&
1655 716 : pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
1656 0 : talloc_free(lck);
1657 0 : return pvfs_map_errno(pvfs, errno);
1658 : }
1659 1406 : name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1660 1406 : name->dos.attrib = attrib;
1661 1406 : status = pvfs_dosattrib_save(pvfs, name, fd);
1662 1406 : if (!NT_STATUS_IS_OK(status)) {
1663 0 : talloc_free(lck);
1664 0 : return status;
1665 : }
1666 : }
1667 :
1668 89170 : talloc_free(lck);
1669 :
1670 89170 : status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1671 89170 : NT_STATUS_NOT_OK_RETURN(status);
1672 :
1673 : /* mark the open as having completed fully, so delete on close
1674 : can now be used */
1675 89170 : f->handle->open_completed = true;
1676 :
1677 89170 : io->generic.out.oplock_level = oplock_granted;
1678 89170 : io->generic.out.file.ntvfs = h;
1679 89170 : io->generic.out.create_action = stream_existed?
1680 89170 : create_action:NTCREATEX_ACTION_CREATED;
1681 :
1682 89170 : io->generic.out.create_time = name->dos.create_time;
1683 89170 : io->generic.out.access_time = name->dos.access_time;
1684 89170 : io->generic.out.write_time = name->dos.write_time;
1685 89170 : io->generic.out.change_time = name->dos.change_time;
1686 89170 : io->generic.out.attrib = name->dos.attrib;
1687 89170 : io->generic.out.alloc_size = name->dos.alloc_size;
1688 89170 : io->generic.out.size = name->st.st_size;
1689 89170 : io->generic.out.file_type = FILE_TYPE_DISK;
1690 89170 : io->generic.out.ipc_state = 0;
1691 89170 : io->generic.out.is_directory = 0;
1692 :
1693 89170 : return NT_STATUS_OK;
1694 : }
1695 :
1696 :
1697 : /*
1698 : close a file
1699 : */
1700 405989 : NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1701 : struct ntvfs_request *req, union smb_close *io)
1702 : {
1703 405989 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1704 : struct pvfs_state);
1705 0 : struct pvfs_file *f;
1706 :
1707 405989 : if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1708 1 : return NT_STATUS_DOS(ERRSRV, ERRerror);
1709 : }
1710 :
1711 405988 : if (io->generic.level != RAW_CLOSE_GENERIC) {
1712 202994 : return ntvfs_map_close(ntvfs, req, io);
1713 : }
1714 :
1715 202994 : f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1716 202994 : if (!f) {
1717 0 : return NT_STATUS_INVALID_HANDLE;
1718 : }
1719 :
1720 202994 : if (!null_time(io->generic.in.write_time)) {
1721 1 : f->handle->write_time.update_forced = false;
1722 1 : f->handle->write_time.update_on_close = true;
1723 1 : unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1724 : }
1725 :
1726 202994 : if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1727 0 : struct pvfs_filename *name;
1728 0 : NTSTATUS status;
1729 2 : struct pvfs_file_handle *h = f->handle;
1730 :
1731 2 : status = pvfs_resolve_name_handle(pvfs, h);
1732 2 : if (!NT_STATUS_IS_OK(status)) {
1733 0 : return status;
1734 : }
1735 2 : name = h->name;
1736 :
1737 2 : io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1738 2 : io->generic.out.create_time = name->dos.create_time;
1739 2 : io->generic.out.access_time = name->dos.access_time;
1740 2 : io->generic.out.write_time = name->dos.write_time;
1741 2 : io->generic.out.change_time = name->dos.change_time;
1742 2 : io->generic.out.alloc_size = name->dos.alloc_size;
1743 2 : io->generic.out.size = name->st.st_size;
1744 2 : io->generic.out.file_attr = name->dos.attrib;
1745 : } else {
1746 202992 : ZERO_STRUCT(io->generic.out);
1747 : }
1748 :
1749 202994 : talloc_free(f);
1750 :
1751 202994 : return NT_STATUS_OK;
1752 : }
1753 :
1754 :
1755 : /*
1756 : logoff - close all file descriptors open by a vuid
1757 : */
1758 21 : NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1759 : struct ntvfs_request *req)
1760 : {
1761 21 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1762 : struct pvfs_state);
1763 0 : struct pvfs_file *f, *next;
1764 :
1765 : /* If pvfs is NULL, we never logged on, and no files are open. */
1766 21 : if(pvfs == NULL) {
1767 0 : return NT_STATUS_OK;
1768 : }
1769 :
1770 21 : for (f=pvfs->files.list;f;f=next) {
1771 0 : next = f->next;
1772 0 : if (f->ntvfs->session_info == req->session_info) {
1773 0 : talloc_free(f);
1774 : }
1775 : }
1776 :
1777 21 : return NT_STATUS_OK;
1778 : }
1779 :
1780 :
1781 : /*
1782 : exit - close files for the current pid
1783 : */
1784 523 : NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1785 : struct ntvfs_request *req)
1786 : {
1787 523 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1788 : struct pvfs_state);
1789 0 : struct pvfs_file *f, *next;
1790 :
1791 566 : for (f=pvfs->files.list;f;f=next) {
1792 43 : next = f->next;
1793 43 : if (f->ntvfs->session_info == req->session_info &&
1794 42 : f->ntvfs->smbpid == req->smbpid) {
1795 40 : talloc_free(f);
1796 : }
1797 : }
1798 :
1799 523 : return NT_STATUS_OK;
1800 : }
1801 :
1802 :
1803 : /*
1804 : change the delete on close flag on an already open file
1805 : */
1806 324 : NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1807 : struct ntvfs_request *req,
1808 : struct pvfs_file *f, bool del_on_close)
1809 : {
1810 0 : struct odb_lock *lck;
1811 0 : NTSTATUS status;
1812 :
1813 324 : if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1814 3 : return NT_STATUS_CANNOT_DELETE;
1815 : }
1816 :
1817 321 : if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1818 267 : !pvfs_directory_empty(pvfs, f->handle->name)) {
1819 4 : return NT_STATUS_DIRECTORY_NOT_EMPTY;
1820 : }
1821 :
1822 317 : if (del_on_close) {
1823 296 : f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1824 : } else {
1825 21 : f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1826 : }
1827 :
1828 317 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1829 317 : if (lck == NULL) {
1830 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1831 : }
1832 :
1833 317 : status = odb_set_delete_on_close(lck, del_on_close);
1834 :
1835 317 : talloc_free(lck);
1836 :
1837 317 : return status;
1838 : }
1839 :
1840 :
1841 : /*
1842 : determine if a file can be deleted, or if it is prevented by an
1843 : already open file
1844 : */
1845 31060 : NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1846 : struct ntvfs_request *req,
1847 : struct pvfs_filename *name,
1848 : struct odb_lock **lckp)
1849 : {
1850 0 : NTSTATUS status;
1851 0 : DATA_BLOB key;
1852 0 : struct odb_lock *lck;
1853 0 : uint32_t share_access;
1854 0 : uint32_t access_mask;
1855 0 : bool delete_on_close;
1856 :
1857 31060 : status = pvfs_locking_key(name, name, &key);
1858 31060 : if (!NT_STATUS_IS_OK(status)) {
1859 0 : return NT_STATUS_NO_MEMORY;
1860 : }
1861 :
1862 31060 : lck = odb_lock(req, pvfs->odb_context, &key);
1863 31060 : if (lck == NULL) {
1864 0 : DEBUG(0,("Unable to lock opendb for can_delete\n"));
1865 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1866 : }
1867 :
1868 31060 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1869 : NTCREATEX_SHARE_ACCESS_WRITE |
1870 : NTCREATEX_SHARE_ACCESS_DELETE;
1871 31060 : access_mask = SEC_STD_DELETE;
1872 31060 : delete_on_close = true;
1873 :
1874 31060 : status = odb_can_open(lck, name->stream_id,
1875 : share_access, access_mask, delete_on_close,
1876 : NTCREATEX_DISP_OPEN, false);
1877 :
1878 31060 : if (NT_STATUS_IS_OK(status)) {
1879 31021 : status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1880 : }
1881 :
1882 : /*
1883 : * if it's a sharing violation or we got no oplock
1884 : * only keep the lock if the caller requested access
1885 : * to the lock
1886 : */
1887 31060 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1888 31028 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1889 38 : if (lckp) {
1890 37 : *lckp = lck;
1891 : } else {
1892 1 : talloc_free(lck);
1893 : }
1894 31022 : } else if (!NT_STATUS_IS_OK(status)) {
1895 1 : talloc_free(lck);
1896 1 : if (lckp) {
1897 0 : *lckp = NULL;
1898 : }
1899 31021 : } else if (lckp) {
1900 31019 : *lckp = lck;
1901 : }
1902 :
1903 31060 : return status;
1904 : }
1905 :
1906 : /*
1907 : determine if a file can be renamed, or if it is prevented by an
1908 : already open file
1909 : */
1910 115 : NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1911 : struct ntvfs_request *req,
1912 : struct pvfs_filename *name,
1913 : struct odb_lock **lckp)
1914 : {
1915 0 : NTSTATUS status;
1916 0 : DATA_BLOB key;
1917 0 : struct odb_lock *lck;
1918 0 : uint32_t share_access;
1919 0 : uint32_t access_mask;
1920 0 : bool delete_on_close;
1921 :
1922 115 : status = pvfs_locking_key(name, name, &key);
1923 115 : if (!NT_STATUS_IS_OK(status)) {
1924 0 : return NT_STATUS_NO_MEMORY;
1925 : }
1926 :
1927 115 : lck = odb_lock(req, pvfs->odb_context, &key);
1928 115 : if (lck == NULL) {
1929 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
1930 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1931 : }
1932 :
1933 115 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1934 : NTCREATEX_SHARE_ACCESS_WRITE;
1935 115 : access_mask = SEC_STD_DELETE;
1936 115 : delete_on_close = false;
1937 :
1938 115 : status = odb_can_open(lck, name->stream_id,
1939 : share_access, access_mask, delete_on_close,
1940 : NTCREATEX_DISP_OPEN, false);
1941 :
1942 : /*
1943 : * if it's a sharing violation or we got no oplock
1944 : * only keep the lock if the caller requested access
1945 : * to the lock
1946 : */
1947 115 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1948 104 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1949 15 : if (lckp) {
1950 15 : *lckp = lck;
1951 : } else {
1952 0 : talloc_free(lck);
1953 : }
1954 100 : } else if (!NT_STATUS_IS_OK(status)) {
1955 0 : talloc_free(lck);
1956 0 : if (lckp) {
1957 0 : *lckp = NULL;
1958 : }
1959 100 : } else if (lckp) {
1960 100 : *lckp = lck;
1961 : }
1962 :
1963 115 : return status;
1964 : }
1965 :
1966 : /*
1967 : determine if the file size of a file can be changed,
1968 : or if it is prevented by an already open file
1969 : */
1970 13 : NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1971 : struct ntvfs_request *req,
1972 : struct pvfs_filename *name,
1973 : struct odb_lock **lckp)
1974 : {
1975 0 : NTSTATUS status;
1976 0 : DATA_BLOB key;
1977 0 : struct odb_lock *lck;
1978 0 : uint32_t share_access;
1979 0 : uint32_t access_mask;
1980 0 : bool break_to_none;
1981 0 : bool delete_on_close;
1982 :
1983 13 : status = pvfs_locking_key(name, name, &key);
1984 13 : if (!NT_STATUS_IS_OK(status)) {
1985 0 : return NT_STATUS_NO_MEMORY;
1986 : }
1987 :
1988 13 : lck = odb_lock(req, pvfs->odb_context, &key);
1989 13 : if (lck == NULL) {
1990 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
1991 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1992 : }
1993 :
1994 13 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1995 : NTCREATEX_SHARE_ACCESS_WRITE |
1996 : NTCREATEX_SHARE_ACCESS_DELETE;
1997 : /*
1998 : * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1999 : * a comment that this seemed to be wrong, but matched windows
2000 : * behaviour. It now appears that this windows behaviour is
2001 : * just a bug.
2002 : */
2003 13 : access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
2004 13 : delete_on_close = false;
2005 13 : break_to_none = true;
2006 :
2007 13 : status = odb_can_open(lck, name->stream_id,
2008 : share_access, access_mask, delete_on_close,
2009 : NTCREATEX_DISP_OPEN, break_to_none);
2010 :
2011 : /*
2012 : * if it's a sharing violation or we got no oplock
2013 : * only keep the lock if the caller requested access
2014 : * to the lock
2015 : */
2016 13 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
2017 11 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
2018 5 : if (lckp) {
2019 5 : *lckp = lck;
2020 : } else {
2021 0 : talloc_free(lck);
2022 : }
2023 8 : } else if (!NT_STATUS_IS_OK(status)) {
2024 0 : talloc_free(lck);
2025 0 : if (lckp) {
2026 0 : *lckp = NULL;
2027 : }
2028 8 : } else if (lckp) {
2029 8 : *lckp = lck;
2030 : }
2031 :
2032 13 : return status;
2033 : }
2034 :
2035 : /*
2036 : determine if file meta data can be accessed, or if it is prevented by an
2037 : already open file
2038 : */
2039 5078 : NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2040 : struct ntvfs_request *req,
2041 : struct pvfs_filename *name)
2042 : {
2043 0 : NTSTATUS status;
2044 0 : DATA_BLOB key;
2045 0 : struct odb_lock *lck;
2046 0 : uint32_t share_access;
2047 0 : uint32_t access_mask;
2048 0 : bool delete_on_close;
2049 :
2050 5078 : status = pvfs_locking_key(name, name, &key);
2051 5078 : if (!NT_STATUS_IS_OK(status)) {
2052 0 : return NT_STATUS_NO_MEMORY;
2053 : }
2054 :
2055 5078 : lck = odb_lock(req, pvfs->odb_context, &key);
2056 5078 : if (lck == NULL) {
2057 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
2058 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2059 : }
2060 :
2061 5078 : share_access = NTCREATEX_SHARE_ACCESS_READ |
2062 : NTCREATEX_SHARE_ACCESS_WRITE;
2063 5078 : access_mask = SEC_FILE_READ_ATTRIBUTE;
2064 5078 : delete_on_close = false;
2065 :
2066 5078 : status = odb_can_open(lck, name->stream_id,
2067 : share_access, access_mask, delete_on_close,
2068 : NTCREATEX_DISP_OPEN, false);
2069 :
2070 5078 : if (!NT_STATUS_IS_OK(status)) {
2071 32 : talloc_free(lck);
2072 : }
2073 :
2074 5078 : return status;
2075 : }
2076 :
2077 :
2078 : /*
2079 : determine if delete on close is set on
2080 : */
2081 1073 : bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2082 : {
2083 0 : NTSTATUS status;
2084 0 : bool del_on_close;
2085 :
2086 1073 : status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2087 : &del_on_close, NULL);
2088 1073 : if (!NT_STATUS_IS_OK(status)) {
2089 0 : DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2090 0 : return false;
2091 : }
2092 :
2093 1073 : return del_on_close;
2094 : }
|