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 303832 : struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 : struct ntvfs_request *req, struct ntvfs_handle *h)
35 : {
36 : void *p;
37 : struct pvfs_file *f;
38 :
39 303832 : p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
40 303832 : if (!p) return NULL;
41 :
42 303832 : f = talloc_get_type(p, struct pvfs_file);
43 303832 : if (!f) return NULL;
44 :
45 303832 : return f;
46 : }
47 :
48 : /*
49 : cleanup a open directory handle
50 : */
51 15765 : static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
52 : {
53 15765 : if (h->have_opendb_entry) {
54 : struct odb_lock *lck;
55 : NTSTATUS status;
56 15765 : const char *delete_path = NULL;
57 :
58 15765 : lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
59 15765 : if (lck == NULL) {
60 0 : DEBUG(0,("Unable to lock opendb for close\n"));
61 0 : return 0;
62 : }
63 :
64 15765 : status = odb_close_file(lck, h, &delete_path);
65 15765 : 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 15765 : if (h->name->stream_name == NULL && delete_path) {
71 405 : status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 405 : 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 405 : 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 15765 : talloc_free(lck);
83 : }
84 :
85 15765 : return 0;
86 : }
87 :
88 : /*
89 : cleanup a open directory fnum
90 : */
91 15765 : static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
92 : {
93 15765 : DLIST_REMOVE(f->pvfs->files.list, f);
94 15765 : ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
95 :
96 15765 : return 0;
97 : }
98 :
99 : /*
100 : setup any EAs and the ACL on newly created files/directories
101 : */
102 101650 : 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 101650 : NTSTATUS status = NT_STATUS_OK;
110 :
111 : /* setup any EAs that were asked for */
112 101650 : if (io->ntcreatex.in.ea_list) {
113 132550 : status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
114 66275 : io->ntcreatex.in.ea_list->num_eas,
115 66275 : io->ntcreatex.in.ea_list->eas);
116 66275 : if (!NT_STATUS_IS_OK(status)) {
117 0 : return status;
118 : }
119 : }
120 :
121 : /* setup an initial sec_desc if requested */
122 101650 : if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
123 : 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 383 : set.set_secdesc.in.file.ntvfs = f->ntvfs;
132 383 : set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
133 383 : set.set_secdesc.in.sd = sd;
134 :
135 383 : status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
136 : }
137 :
138 101650 : 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 888430 : NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
146 : TALLOC_CTX *mem_ctx, DATA_BLOB *key)
147 : {
148 : struct {
149 : dev_t device;
150 : ino_t inode;
151 : } lock_context;
152 888430 : ZERO_STRUCT(lock_context);
153 :
154 888430 : lock_context.device = name->st.st_dev;
155 888430 : lock_context.inode = name->st.st_ino;
156 :
157 888430 : *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
158 888430 : if (key->data == NULL) {
159 0 : return NT_STATUS_NO_MEMORY;
160 : }
161 :
162 888430 : return NT_STATUS_OK;
163 : }
164 :
165 :
166 : /*
167 : open a directory
168 : */
169 15920 : 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 : struct pvfs_file *f;
175 : struct ntvfs_handle *h;
176 : NTSTATUS status;
177 : uint32_t create_action;
178 15920 : uint32_t access_mask = io->generic.in.access_mask;
179 : struct odb_lock *lck;
180 : bool del_on_close;
181 : uint32_t create_options;
182 : uint32_t share_access;
183 : bool forced;
184 15920 : struct security_descriptor *sd = NULL;
185 :
186 15920 : create_options = io->generic.in.create_options;
187 15920 : share_access = io->generic.in.share_access;
188 :
189 15920 : forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
190 :
191 15920 : 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 15913 : if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
202 0 : return NT_STATUS_NOT_A_DIRECTORY;
203 : }
204 :
205 : /* found with gentest */
206 15966 : if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
207 103 : (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
208 50 : (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 15913 : switch (io->generic.in.open_disposition) {
215 8609 : case NTCREATEX_DISP_OPEN_IF:
216 8609 : break;
217 :
218 6947 : case NTCREATEX_DISP_OPEN:
219 6947 : if (!name->exists) {
220 104 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
221 : }
222 6843 : break;
223 :
224 346 : case NTCREATEX_DISP_CREATE:
225 346 : if (name->exists) {
226 15 : return NT_STATUS_OBJECT_NAME_COLLISION;
227 : }
228 331 : 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 15783 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
240 15783 : NT_STATUS_NOT_OK_RETURN(status);
241 :
242 15783 : f = talloc(h, struct pvfs_file);
243 15783 : if (f == NULL) {
244 0 : return NT_STATUS_NO_MEMORY;
245 : }
246 :
247 15783 : f->handle = talloc(f, struct pvfs_file_handle);
248 15783 : if (f->handle == NULL) {
249 0 : return NT_STATUS_NO_MEMORY;
250 : }
251 :
252 15783 : if (name->exists) {
253 : /* check the security descriptor */
254 11122 : status = pvfs_access_check(pvfs, req, name, &access_mask);
255 : } else {
256 4661 : sd = io->ntcreatex.in.sec_desc;
257 4661 : status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
258 : }
259 15783 : NT_STATUS_NOT_OK_RETURN(status);
260 :
261 15783 : 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 15783 : f->ntvfs = h;
268 15783 : f->pvfs = pvfs;
269 15783 : f->pending_list = NULL;
270 15783 : f->lock_count = 0;
271 15783 : f->share_access = io->generic.in.share_access;
272 15783 : f->impersonation = io->generic.in.impersonation;
273 15783 : f->access_mask = access_mask;
274 15783 : f->brl_handle = NULL;
275 15783 : f->notify_buffer = NULL;
276 15783 : f->search = NULL;
277 :
278 15783 : f->handle->pvfs = pvfs;
279 15783 : f->handle->name = talloc_steal(f->handle, name);
280 15783 : f->handle->fd = -1;
281 15783 : f->handle->odb_locking_key = data_blob(NULL, 0);
282 15783 : f->handle->create_options = io->generic.in.create_options;
283 15783 : f->handle->private_flags = io->generic.in.private_flags;
284 15783 : f->handle->seek_offset = 0;
285 15783 : f->handle->position = 0;
286 15783 : f->handle->mode = 0;
287 15783 : f->handle->oplock = NULL;
288 15783 : ZERO_STRUCT(f->handle->write_time);
289 15783 : f->handle->open_completed = false;
290 :
291 15941 : if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
292 158 : pvfs_directory_empty(pvfs, f->handle->name)) {
293 153 : del_on_close = true;
294 : } else {
295 15630 : del_on_close = false;
296 : }
297 :
298 15783 : if (name->exists) {
299 : /* form the lock context used for opendb locking */
300 11122 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
301 11122 : if (!NT_STATUS_IS_OK(status)) {
302 0 : return status;
303 : }
304 :
305 : /* get a lock on this file before the actual open */
306 11122 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
307 11122 : 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 11122 : status = odb_can_open(lck, name->stream_id,
317 : share_access, access_mask, del_on_close,
318 : io->generic.in.open_disposition, false);
319 11122 : 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 11104 : status = odb_open_file(lck, f->handle, name->full_name,
326 11104 : NULL, name->dos.write_time,
327 : false, OPLOCK_NONE, NULL);
328 :
329 11104 : if (!NT_STATUS_IS_OK(status)) {
330 0 : talloc_free(lck);
331 0 : return status;
332 : }
333 :
334 11104 : f->handle->have_opendb_entry = true;
335 : }
336 :
337 15765 : DLIST_ADD(pvfs->files.list, f);
338 :
339 : /* setup destructors to avoid leaks on abnormal termination */
340 15765 : talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
341 15765 : talloc_set_destructor(f, pvfs_dir_fnum_destructor);
342 :
343 15765 : if (!name->exists) {
344 4661 : uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
345 4661 : mode_t mode = pvfs_fileperms(pvfs, attrib);
346 :
347 4661 : if (pvfs_sys_mkdir(pvfs, name->full_name, mode, name->allow_override) == -1) {
348 0 : return pvfs_map_errno(pvfs,errno);
349 : }
350 :
351 4661 : pvfs_xattr_unlink_hook(pvfs, name->full_name);
352 :
353 4661 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
354 4661 : if (!NT_STATUS_IS_OK(status)) {
355 0 : goto cleanup_delete;
356 : }
357 :
358 4661 : status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
359 4661 : if (!NT_STATUS_IS_OK(status)) {
360 0 : goto cleanup_delete;
361 : }
362 :
363 : /* form the lock context used for opendb locking */
364 4661 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
365 4661 : if (!NT_STATUS_IS_OK(status)) {
366 0 : return status;
367 : }
368 :
369 4661 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
370 4661 : 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 4661 : 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 4661 : if (!NT_STATUS_IS_OK(status)) {
383 0 : goto cleanup_delete;
384 : }
385 :
386 4661 : status = odb_open_file(lck, f->handle, name->full_name,
387 4661 : NULL, name->dos.write_time,
388 : false, OPLOCK_NONE, NULL);
389 :
390 4661 : if (!NT_STATUS_IS_OK(status)) {
391 0 : goto cleanup_delete;
392 : }
393 :
394 4661 : f->handle->have_opendb_entry = true;
395 :
396 4661 : create_action = NTCREATEX_ACTION_CREATED;
397 :
398 4661 : notify_trigger(pvfs->notify_context,
399 : NOTIFY_ACTION_ADDED,
400 : FILE_NOTIFY_CHANGE_DIR_NAME,
401 4661 : name->full_name);
402 : } else {
403 11104 : create_action = NTCREATEX_ACTION_EXISTED;
404 : }
405 :
406 15765 : if (!name->exists) {
407 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
408 : }
409 :
410 15765 : 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 15765 : status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
418 15765 : if (!NT_STATUS_IS_OK(status)) {
419 0 : goto cleanup_delete;
420 : }
421 :
422 15765 : f->handle->open_completed = true;
423 :
424 15765 : io->generic.out.oplock_level = OPLOCK_NONE;
425 15765 : io->generic.out.file.ntvfs = h;
426 15765 : io->generic.out.create_action = create_action;
427 15765 : io->generic.out.create_time = name->dos.create_time;
428 15765 : io->generic.out.access_time = name->dos.access_time;
429 15765 : io->generic.out.write_time = name->dos.write_time;
430 15765 : io->generic.out.change_time = name->dos.change_time;
431 15765 : io->generic.out.attrib = name->dos.attrib;
432 15765 : io->generic.out.alloc_size = name->dos.alloc_size;
433 15765 : io->generic.out.size = name->st.st_size;
434 15765 : io->generic.out.file_type = FILE_TYPE_DISK;
435 15765 : io->generic.out.ipc_state = 0;
436 15765 : io->generic.out.is_directory = 1;
437 :
438 15765 : 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 188958 : static int pvfs_handle_destructor(struct pvfs_file_handle *h)
449 : {
450 188958 : talloc_free(h->write_time.update_event);
451 188958 : h->write_time.update_event = NULL;
452 :
453 254924 : if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
454 65966 : h->name->stream_name) {
455 : 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 188958 : if (h->fd != -1) {
464 185993 : 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 185993 : h->fd = -1;
469 : }
470 :
471 377610 : if (!h->write_time.update_forced &&
472 197879 : h->write_time.update_on_close &&
473 9215 : h->write_time.close_time == 0) {
474 : struct timeval tv;
475 9214 : tv = timeval_current();
476 9214 : h->write_time.close_time = timeval_to_nttime(&tv);
477 : }
478 :
479 188958 : if (h->have_opendb_entry) {
480 : struct odb_lock *lck;
481 : NTSTATUS status;
482 185993 : const char *delete_path = NULL;
483 :
484 185993 : lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
485 185993 : if (lck == NULL) {
486 0 : DEBUG(0,("Unable to lock opendb for close\n"));
487 0 : return 0;
488 : }
489 :
490 185993 : 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 185702 : } else if (h->write_time.update_on_close) {
503 9215 : status = odb_set_write_time(lck, h->write_time.close_time, true);
504 9215 : 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 185993 : status = odb_close_file(lck, h, &delete_path);
511 185993 : 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 371867 : if (h->name->stream_name == NULL &&
517 371763 : h->open_completed && delete_path) {
518 65926 : status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
519 65926 : 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 65926 : 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 65926 : notify_trigger(h->pvfs->notify_context,
528 : NOTIFY_ACTION_REMOVED,
529 : FILE_NOTIFY_CHANGE_FILE_NAME,
530 : delete_path);
531 : }
532 65926 : h->write_time.update_on_close = false;
533 : }
534 :
535 185993 : talloc_free(lck);
536 : }
537 :
538 188958 : if (h->write_time.update_on_close) {
539 : struct timeval tv[2];
540 :
541 9499 : nttime_to_timeval(&tv[0], h->name->dos.access_time);
542 9499 : nttime_to_timeval(&tv[1], h->write_time.close_time);
543 :
544 9499 : if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
545 9499 : 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 188958 : return 0;
553 : }
554 :
555 :
556 : /*
557 : destroy a struct pvfs_file
558 : */
559 188958 : static int pvfs_fnum_destructor(struct pvfs_file *f)
560 : {
561 188958 : DLIST_REMOVE(f->pvfs->files.list, f);
562 188958 : pvfs_lock_close(f->pvfs, f);
563 188958 : ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
564 :
565 188958 : 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 188958 : 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 : DATA_BLOB odb_key, key;
581 : NTSTATUS status;
582 : struct brl_handle *h;
583 :
584 188958 : status = pvfs_locking_key(name, mem_ctx, &odb_key);
585 188958 : NT_STATUS_NOT_OK_RETURN(status);
586 :
587 188958 : if (name->stream_name == NULL) {
588 188841 : key = odb_key;
589 : } else {
590 117 : key = data_blob_talloc(mem_ctx, NULL,
591 : odb_key.length + strlen(name->stream_name) + 1);
592 117 : NT_STATUS_HAVE_NO_MEMORY(key.data);
593 117 : memcpy(key.data, odb_key.data, odb_key.length);
594 234 : memcpy(key.data + odb_key.length,
595 234 : name->stream_name, strlen(name->stream_name) + 1);
596 117 : data_blob_free(&odb_key);
597 : }
598 :
599 188958 : h = brlock_create_handle(mem_ctx, ntvfs, &key);
600 188958 : NT_STATUS_HAVE_NO_MEMORY(h);
601 :
602 188958 : *_h = h;
603 188958 : return NT_STATUS_OK;
604 : }
605 :
606 : /*
607 : create a new file
608 : */
609 96995 : 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 : struct pvfs_file *f;
615 : NTSTATUS status;
616 : struct ntvfs_handle *h;
617 : int flags, fd;
618 : struct odb_lock *lck;
619 96995 : uint32_t create_options = io->generic.in.create_options;
620 96995 : uint32_t share_access = io->generic.in.share_access;
621 96995 : uint32_t access_mask = io->generic.in.access_mask;
622 : mode_t mode;
623 : uint32_t attrib;
624 : bool del_on_close;
625 : struct pvfs_filename *parent;
626 96995 : uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
627 96995 : bool allow_level_II_oplock = false;
628 96995 : struct security_descriptor *sd = NULL;
629 :
630 96995 : 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 96995 : 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 97025 : if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
643 31 : (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 96991 : sd = io->ntcreatex.in.sec_desc;
650 96991 : status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
651 96991 : NT_STATUS_NOT_OK_RETURN(status);
652 :
653 : /* check that the parent isn't opened with delete on close set */
654 96991 : status = pvfs_resolve_parent(pvfs, req, name, &parent);
655 96991 : if (NT_STATUS_IS_OK(status)) {
656 : DATA_BLOB locking_key;
657 96991 : status = pvfs_locking_key(parent, req, &locking_key);
658 96993 : NT_STATUS_NOT_OK_RETURN(status);
659 96991 : status = odb_get_file_infos(pvfs->odb_context, &locking_key,
660 : &del_on_close, NULL);
661 96991 : NT_STATUS_NOT_OK_RETURN(status);
662 96991 : if (del_on_close) {
663 2 : return NT_STATUS_DELETE_PENDING;
664 : }
665 : }
666 :
667 96989 : if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
668 92637 : flags = O_RDWR;
669 : } else {
670 4352 : flags = O_RDONLY;
671 : }
672 :
673 96989 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
674 96989 : NT_STATUS_NOT_OK_RETURN(status);
675 :
676 96989 : f = talloc(h, struct pvfs_file);
677 96989 : NT_STATUS_HAVE_NO_MEMORY(f);
678 :
679 96989 : f->handle = talloc(f, struct pvfs_file_handle);
680 96989 : NT_STATUS_HAVE_NO_MEMORY(f->handle);
681 :
682 96989 : attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
683 96989 : mode = pvfs_fileperms(pvfs, attrib);
684 :
685 : /* create the file */
686 96989 : fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode, name->allow_override);
687 96989 : if (fd == -1) {
688 0 : return pvfs_map_errno(pvfs, errno);
689 : }
690 :
691 96989 : pvfs_xattr_unlink_hook(pvfs, name->full_name);
692 :
693 : /* if this was a stream create then create the stream as well */
694 96989 : if (name->stream_name) {
695 20 : status = pvfs_stream_create(pvfs, name, fd);
696 20 : if (!NT_STATUS_IS_OK(status)) {
697 0 : close(fd);
698 0 : return status;
699 : }
700 : }
701 :
702 : /* re-resolve the open fd */
703 96989 : status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
704 96989 : if (!NT_STATUS_IS_OK(status)) {
705 0 : close(fd);
706 0 : return status;
707 : }
708 :
709 : /* support initial alloc sizes */
710 96989 : name->dos.alloc_size = io->ntcreatex.in.alloc_size;
711 96989 : name->dos.attrib = attrib;
712 96989 : status = pvfs_dosattrib_save(pvfs, name, fd);
713 96989 : if (!NT_STATUS_IS_OK(status)) {
714 0 : goto cleanup_delete;
715 : }
716 :
717 :
718 96989 : status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
719 96989 : if (!NT_STATUS_IS_OK(status)) {
720 0 : goto cleanup_delete;
721 : }
722 :
723 96989 : 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 96989 : 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 96989 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
740 96989 : if (!NT_STATUS_IS_OK(status)) {
741 0 : goto cleanup_delete;
742 : }
743 :
744 96989 : status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
745 96989 : if (!NT_STATUS_IS_OK(status)) {
746 0 : goto cleanup_delete;
747 : }
748 :
749 : /* grab a lock on the open file record */
750 96989 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
751 96989 : 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 96989 : if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
761 20 : del_on_close = true;
762 : } else {
763 96969 : del_on_close = false;
764 : }
765 :
766 96989 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
767 0 : oplock_level = OPLOCK_NONE;
768 96989 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
769 65 : oplock_level = OPLOCK_BATCH;
770 96924 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
771 22 : oplock_level = OPLOCK_EXCLUSIVE;
772 : }
773 :
774 96989 : if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
775 96716 : allow_level_II_oplock = true;
776 : }
777 :
778 96989 : status = odb_can_open(lck, name->stream_id,
779 : share_access, access_mask, del_on_close,
780 : io->generic.in.open_disposition, false);
781 96989 : 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 96989 : f->ntvfs = h;
791 96989 : f->pvfs = pvfs;
792 96989 : f->pending_list = NULL;
793 96989 : f->lock_count = 0;
794 96989 : f->share_access = io->generic.in.share_access;
795 96989 : f->access_mask = access_mask;
796 96989 : f->impersonation = io->generic.in.impersonation;
797 96989 : f->notify_buffer = NULL;
798 96989 : f->search = NULL;
799 :
800 96989 : f->handle->pvfs = pvfs;
801 96989 : f->handle->name = talloc_steal(f->handle, name);
802 96989 : f->handle->fd = fd;
803 96989 : f->handle->create_options = io->generic.in.create_options;
804 96989 : f->handle->private_flags = io->generic.in.private_flags;
805 96989 : f->handle->seek_offset = 0;
806 96989 : f->handle->position = 0;
807 96989 : f->handle->mode = 0;
808 96989 : f->handle->oplock = NULL;
809 96989 : f->handle->have_opendb_entry = true;
810 96989 : ZERO_STRUCT(f->handle->write_time);
811 96989 : f->handle->open_completed = false;
812 :
813 193974 : status = odb_open_file(lck, f->handle, name->full_name,
814 96989 : &f->handle->fd, name->dos.write_time,
815 : allow_level_II_oplock,
816 : oplock_level, &oplock_granted);
817 96989 : talloc_free(lck);
818 96989 : 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 96989 : DLIST_ADD(pvfs->files.list, f);
827 :
828 : /* setup a destructor to avoid file descriptor leaks on
829 : abnormal termination */
830 96989 : talloc_set_destructor(f, pvfs_fnum_destructor);
831 96989 : talloc_set_destructor(f->handle, pvfs_handle_destructor);
832 :
833 96989 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
834 0 : oplock_granted = OPLOCK_BATCH;
835 96989 : } 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 96989 : io->generic.out.oplock_level = oplock_granted;
843 96989 : io->generic.out.file.ntvfs = f->ntvfs;
844 96989 : io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
845 96989 : io->generic.out.create_time = name->dos.create_time;
846 96989 : io->generic.out.access_time = name->dos.access_time;
847 96989 : io->generic.out.write_time = name->dos.write_time;
848 96989 : io->generic.out.change_time = name->dos.change_time;
849 96989 : io->generic.out.attrib = name->dos.attrib;
850 96989 : io->generic.out.alloc_size = name->dos.alloc_size;
851 96989 : io->generic.out.size = name->st.st_size;
852 96989 : io->generic.out.file_type = FILE_TYPE_DISK;
853 96989 : io->generic.out.ipc_state = 0;
854 96989 : io->generic.out.is_directory = 0;
855 :
856 : /* success - keep the file handle */
857 96989 : status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
858 96989 : if (!NT_STATUS_IS_OK(status)) {
859 0 : goto cleanup_delete;
860 : }
861 :
862 96989 : f->handle->open_completed = true;
863 :
864 96989 : notify_trigger(pvfs->notify_context,
865 : NOTIFY_ACTION_ADDED,
866 : FILE_NOTIFY_CHANGE_FILE_NAME,
867 96989 : name->full_name);
868 :
869 96989 : 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 2913 : static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
896 : {
897 2913 : struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
898 : struct pvfs_state);
899 2913 : if (r->odb_locking_key.data) {
900 : struct odb_lock *lck;
901 2829 : lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
902 2829 : if (lck != NULL) {
903 2829 : odb_remove_pending(lck, r);
904 : }
905 2829 : talloc_free(lck);
906 : }
907 2913 : return 0;
908 : }
909 :
910 2873 : static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
911 : {
912 2873 : struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
913 :
914 2873 : 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 2873 : r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
924 2873 : }
925 :
926 : /*
927 : setup for a retry of a request that was rejected
928 : by odb_can_open()
929 : */
930 2913 : 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 2913 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
944 : struct pvfs_state);
945 : struct pvfs_odb_retry *r;
946 : struct pvfs_wait *wait_handle;
947 : NTSTATUS status;
948 :
949 2913 : r = talloc(req, struct pvfs_odb_retry);
950 2913 : NT_STATUS_HAVE_NO_MEMORY(r);
951 :
952 2913 : r->ntvfs = ntvfs;
953 2913 : r->req = req;
954 2913 : r->io = io;
955 2913 : r->private_data = private_data;
956 2913 : r->callback = callback;
957 2913 : r->odb_locking_key = odb_get_key(r, lck);
958 2913 : if (r->odb_locking_key.data == NULL) {
959 0 : return NT_STATUS_NO_MEMORY;
960 : }
961 :
962 : /* setup a pending lock */
963 2913 : status = odb_open_file_pending(lck, r);
964 2913 : 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 2913 : } else if (!NT_STATUS_IS_OK(status)) {
971 0 : return status;
972 : }
973 :
974 2913 : talloc_free(lck);
975 :
976 2913 : talloc_set_destructor(r, pvfs_odb_retry_destructor);
977 :
978 2913 : wait_handle = pvfs_wait_message(pvfs, req,
979 : MSG_PVFS_RETRY_OPEN, end_time,
980 : pvfs_odb_retry_callback, r);
981 2913 : if (wait_handle == NULL) {
982 0 : return NT_STATUS_NO_MEMORY;
983 : }
984 :
985 2913 : talloc_steal(r, wait_handle);
986 :
987 2913 : return NT_STATUS_OK;
988 : }
989 :
990 : /*
991 : retry an open after a sharing violation
992 : */
993 2816 : 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 2816 : union smb_open *io = talloc_get_type(_io, union smb_open);
1001 2816 : struct timeval *final_timeout = NULL;
1002 : NTSTATUS status;
1003 :
1004 2816 : 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 2816 : if (reason == PVFS_WAIT_CANCEL) {
1012 2753 : return;
1013 : }
1014 :
1015 2815 : if (reason == PVFS_WAIT_TIMEOUT) {
1016 2744 : 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 2744 : talloc_free(r);
1029 2744 : req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1030 2744 : req->async_states->send_fn(req);
1031 2744 : 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 : struct pvfs_file *f2;
1073 : struct pvfs_filename *name;
1074 : 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 1544 : if (f2 != f &&
1088 776 : f2->ntvfs->session_info == req->session_info &&
1089 776 : 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 163 : 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 2959 : 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 2959 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1153 : struct pvfs_state);
1154 : NTSTATUS status;
1155 : struct timeval end_time;
1156 2959 : struct timeval *final_timeout = NULL;
1157 :
1158 2959 : 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 2856 : talloc_free(f);
1170 :
1171 2856 : if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1172 2786 : 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 2856 : 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 487844 : NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1205 : struct ntvfs_request *req, union smb_open *io)
1206 : {
1207 487844 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1208 : struct pvfs_state);
1209 487844 : int flags = 0;
1210 : struct pvfs_filename *name;
1211 : struct pvfs_file *f;
1212 : struct ntvfs_handle *h;
1213 : NTSTATUS status;
1214 : int fd, count;
1215 : struct odb_lock *lck;
1216 : uint32_t create_options;
1217 : uint32_t create_options_must_ignore_mask;
1218 : uint32_t share_access;
1219 : uint32_t access_mask;
1220 487844 : uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1221 : bool del_on_close;
1222 487844 : bool stream_existed, stream_truncate=false;
1223 487844 : uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1224 487844 : bool allow_level_II_oplock = false;
1225 :
1226 : /* use the generic mapping code to avoid implementing all the
1227 : different open calls. */
1228 703660 : if (io->generic.level != RAW_OPEN_GENERIC &&
1229 215823 : io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1230 215726 : return ntvfs_map_open(ntvfs, req, io);
1231 : }
1232 :
1233 272118 : ZERO_STRUCT(io->generic.out);
1234 :
1235 272118 : create_options = io->generic.in.create_options;
1236 272118 : share_access = io->generic.in.share_access;
1237 272118 : access_mask = io->generic.in.access_mask;
1238 :
1239 272118 : if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1240 2 : DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
1241 : share_access, io->ntcreatex.in.fname));
1242 2 : 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 272116 : create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1250 272116 : create_options &= ~create_options_must_ignore_mask;
1251 :
1252 272116 : 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 272112 : if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1259 20 : DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
1260 : create_options, io->ntcreatex.in.fname));
1261 20 : 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 272092 : if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1268 : /* no-op */
1269 : }
1270 :
1271 : /* TODO: If (unlikely) Linux does a good compressed
1272 : * filesystem, we might need an ioctl call for this */
1273 272092 : if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1274 : /* no-op */
1275 : }
1276 :
1277 272092 : 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 : if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1284 : flags |= O_SYNC;
1285 : }
1286 :
1287 :
1288 : /* other create options are not allowed */
1289 404218 : if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1290 132126 : !(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 272057 : if (access_mask & SEC_MASK_INVALID) {
1297 309 : return NT_STATUS_ACCESS_DENIED;
1298 : }
1299 :
1300 : /* what does this bit really mean?? */
1301 478858 : if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
1302 207110 : access_mask == SEC_STD_SYNCHRONIZE) {
1303 5 : return NT_STATUS_ACCESS_DENIED;
1304 : }
1305 :
1306 : /* cope with non-zero root_fid */
1307 271743 : 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 271743 : if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1322 : FILE_ATTRIBUTE_VOLUME|
1323 : (~FILE_ATTRIBUTE_ALL_MASK))) {
1324 29 : DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
1325 : io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
1326 29 : return NT_STATUS_INVALID_PARAMETER;
1327 : }
1328 :
1329 : /* we ignore some file_attr bits */
1330 271714 : 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 271714 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1338 : PVFS_RESOLVE_STREAMS, &name);
1339 271714 : 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 282981 : if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1346 11380 : (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1347 234 : 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 363882 : if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1353 92526 : (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1354 114 : return NT_STATUS_NOT_A_DIRECTORY;
1355 : }
1356 :
1357 : /* directory opens are handled separately */
1358 531345 : if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1359 260107 : (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1360 15920 : 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 255333 : io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1366 :
1367 255333 : switch (io->generic.in.open_disposition) {
1368 3509 : case NTCREATEX_DISP_SUPERSEDE:
1369 : case NTCREATEX_DISP_OVERWRITE_IF:
1370 3509 : if (name->stream_name == NULL) {
1371 3497 : flags = O_TRUNC;
1372 : } else {
1373 12 : stream_truncate = true;
1374 : }
1375 3509 : create_action = NTCREATEX_ACTION_TRUNCATED;
1376 3509 : break;
1377 :
1378 147946 : case NTCREATEX_DISP_OPEN:
1379 147946 : if (!name->stream_exists) {
1380 66168 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1381 : }
1382 81778 : flags = 0;
1383 81778 : break;
1384 :
1385 799 : case NTCREATEX_DISP_OVERWRITE:
1386 799 : if (!name->stream_exists) {
1387 5 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1388 : }
1389 794 : if (name->stream_name == NULL) {
1390 794 : flags = O_TRUNC;
1391 : } else {
1392 0 : stream_truncate = true;
1393 : }
1394 794 : create_action = NTCREATEX_ACTION_TRUNCATED;
1395 794 : break;
1396 :
1397 82978 : case NTCREATEX_DISP_CREATE:
1398 82978 : if (name->stream_exists) {
1399 151 : return NT_STATUS_OBJECT_NAME_COLLISION;
1400 : }
1401 82827 : flags = 0;
1402 82827 : break;
1403 :
1404 20095 : case NTCREATEX_DISP_OPEN_IF:
1405 20095 : flags = 0;
1406 20095 : break;
1407 :
1408 6 : default:
1409 6 : DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
1410 : io->generic.in.open_disposition, name->original_name));
1411 6 : return NT_STATUS_INVALID_PARAMETER;
1412 : }
1413 :
1414 : /* handle creating a new file separately */
1415 189003 : if (!name->exists) {
1416 96995 : status = pvfs_create_file(pvfs, req, name, io);
1417 96995 : if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1418 96995 : return status;
1419 : }
1420 :
1421 : /* we've hit a race - the file was created during this call */
1422 0 : if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1423 0 : return status;
1424 : }
1425 :
1426 : /* try re-resolving the name */
1427 0 : status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1428 0 : if (!NT_STATUS_IS_OK(status)) {
1429 0 : return status;
1430 : }
1431 : /* fall through to a normal open */
1432 : }
1433 :
1434 92517 : if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1435 509 : (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1436 4 : return NT_STATUS_CANNOT_DELETE;
1437 : }
1438 :
1439 : /* check the security descriptor */
1440 92004 : status = pvfs_access_check(pvfs, req, name, &access_mask);
1441 92004 : NT_STATUS_NOT_OK_RETURN(status);
1442 :
1443 91969 : if (io->generic.in.query_maximal_access) {
1444 12 : status = pvfs_access_maximal_allowed(pvfs, req, name,
1445 : &io->generic.out.maximal_access);
1446 12 : NT_STATUS_NOT_OK_RETURN(status);
1447 : }
1448 :
1449 91969 : if (io->generic.in.query_on_disk_id) {
1450 10 : ZERO_ARRAY(io->generic.out.on_disk_id);
1451 10 : SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
1452 10 : SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
1453 : }
1454 :
1455 91969 : status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1456 91969 : NT_STATUS_NOT_OK_RETURN(status);
1457 :
1458 91969 : f = talloc(h, struct pvfs_file);
1459 91969 : if (f == NULL) {
1460 0 : return NT_STATUS_NO_MEMORY;
1461 : }
1462 :
1463 91969 : f->handle = talloc(f, struct pvfs_file_handle);
1464 91969 : if (f->handle == NULL) {
1465 0 : return NT_STATUS_NO_MEMORY;
1466 : }
1467 :
1468 91969 : f->ntvfs = h;
1469 91969 : f->pvfs = pvfs;
1470 91969 : f->pending_list = NULL;
1471 91969 : f->lock_count = 0;
1472 91969 : f->share_access = io->generic.in.share_access;
1473 91969 : f->access_mask = access_mask;
1474 91969 : f->impersonation = io->generic.in.impersonation;
1475 91969 : f->notify_buffer = NULL;
1476 91969 : f->search = NULL;
1477 :
1478 91969 : f->handle->pvfs = pvfs;
1479 91969 : f->handle->fd = -1;
1480 91969 : f->handle->name = talloc_steal(f->handle, name);
1481 91969 : f->handle->create_options = io->generic.in.create_options;
1482 91969 : f->handle->private_flags = io->generic.in.private_flags;
1483 91969 : f->handle->seek_offset = 0;
1484 91969 : f->handle->position = 0;
1485 91969 : f->handle->mode = 0;
1486 91969 : f->handle->oplock = NULL;
1487 91969 : f->handle->have_opendb_entry = false;
1488 91969 : ZERO_STRUCT(f->handle->write_time);
1489 91969 : f->handle->open_completed = false;
1490 :
1491 : /* form the lock context used for byte range locking and
1492 : opendb locking */
1493 91969 : status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1494 91969 : if (!NT_STATUS_IS_OK(status)) {
1495 0 : return status;
1496 : }
1497 :
1498 91969 : status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1499 91969 : if (!NT_STATUS_IS_OK(status)) {
1500 0 : return status;
1501 : }
1502 :
1503 : /* get a lock on this file before the actual open */
1504 91969 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1505 91969 : if (lck == NULL) {
1506 0 : DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1507 : name->full_name));
1508 : /* we were supposed to do a blocking lock, so something
1509 : is badly wrong! */
1510 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511 : }
1512 :
1513 91969 : DLIST_ADD(pvfs->files.list, f);
1514 :
1515 : /* setup a destructor to avoid file descriptor leaks on
1516 : abnormal termination */
1517 91969 : talloc_set_destructor(f, pvfs_fnum_destructor);
1518 91969 : talloc_set_destructor(f->handle, pvfs_handle_destructor);
1519 :
1520 : /*
1521 : * Only SMB2 takes care of the delete_on_close,
1522 : * on existing files
1523 : */
1524 157891 : if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1525 65922 : req->ctx->protocol >= PROTOCOL_SMB2_02) {
1526 65898 : del_on_close = true;
1527 : } else {
1528 26071 : del_on_close = false;
1529 : }
1530 :
1531 91969 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1532 0 : oplock_level = OPLOCK_NONE;
1533 91969 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1534 88 : oplock_level = OPLOCK_BATCH;
1535 91881 : } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1536 50 : oplock_level = OPLOCK_EXCLUSIVE;
1537 : }
1538 :
1539 91969 : if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1540 91909 : allow_level_II_oplock = true;
1541 : }
1542 :
1543 : /* see if we are allowed to open at the same time as existing opens */
1544 91969 : status = odb_can_open(lck, name->stream_id,
1545 : share_access, access_mask, del_on_close,
1546 : io->generic.in.open_disposition, false);
1547 :
1548 : /*
1549 : * on a sharing violation we need to retry when the file is closed by
1550 : * the other user, or after 1 second
1551 : * on a non granted oplock we need to retry when the file is closed by
1552 : * the other user, or after 30 seconds
1553 : */
1554 181038 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1555 92039 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1556 2959 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1557 2959 : return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1558 : }
1559 :
1560 89010 : if (!NT_STATUS_IS_OK(status)) {
1561 6 : talloc_free(lck);
1562 6 : return status;
1563 : }
1564 :
1565 89004 : if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1566 16954 : flags |= O_RDWR;
1567 : } else {
1568 72050 : flags |= O_RDONLY;
1569 : }
1570 :
1571 : /* do the actual open */
1572 89004 : fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
1573 89004 : if (fd == -1) {
1574 0 : status = pvfs_map_errno(f->pvfs, errno);
1575 :
1576 0 : DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1577 : nt_errstr(status), f->handle->name->full_name, errno));
1578 : /*
1579 : * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1580 : */
1581 0 : if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1582 0 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1583 0 : return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1584 : }
1585 :
1586 0 : talloc_free(lck);
1587 0 : return status;
1588 : }
1589 :
1590 89004 : f->handle->fd = fd;
1591 :
1592 89004 : status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
1593 89004 : if (!NT_STATUS_IS_OK(status)) {
1594 0 : talloc_free(lck);
1595 0 : return status;
1596 : }
1597 :
1598 89004 : if (count != 0) {
1599 83 : oplock_level = OPLOCK_NONE;
1600 : }
1601 :
1602 : /* now really mark the file as open */
1603 266990 : status = odb_open_file(lck, f->handle, name->full_name,
1604 177997 : &f->handle->fd, name->dos.write_time,
1605 : allow_level_II_oplock,
1606 : oplock_level, &oplock_granted);
1607 :
1608 89004 : if (!NT_STATUS_IS_OK(status)) {
1609 0 : talloc_free(lck);
1610 0 : return status;
1611 : }
1612 :
1613 89004 : f->handle->have_opendb_entry = true;
1614 :
1615 89004 : if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1616 0 : oplock_granted = OPLOCK_BATCH;
1617 89004 : } else if (oplock_granted != OPLOCK_NONE) {
1618 77 : status = pvfs_setup_oplock(f, oplock_granted);
1619 77 : if (!NT_STATUS_IS_OK(status)) {
1620 0 : talloc_free(lck);
1621 0 : return status;
1622 : }
1623 : }
1624 :
1625 89004 : stream_existed = name->stream_exists;
1626 :
1627 : /* if this was a stream create then create the stream as well */
1628 89004 : if (!name->stream_exists) {
1629 27 : status = pvfs_stream_create(pvfs, f->handle->name, fd);
1630 27 : if (!NT_STATUS_IS_OK(status)) {
1631 0 : talloc_free(lck);
1632 0 : return status;
1633 : }
1634 27 : if (stream_truncate) {
1635 3 : status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1636 3 : if (!NT_STATUS_IS_OK(status)) {
1637 0 : talloc_free(lck);
1638 0 : return status;
1639 : }
1640 : }
1641 : }
1642 :
1643 : /* re-resolve the open fd */
1644 89004 : status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1645 89004 : if (!NT_STATUS_IS_OK(status)) {
1646 0 : talloc_free(lck);
1647 0 : return status;
1648 : }
1649 :
1650 177913 : if (f->handle->name->stream_id == 0 &&
1651 177040 : (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1652 88131 : io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1653 : /* for overwrite we may need to replace file permissions */
1654 1372 : uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1655 1372 : mode_t mode = pvfs_fileperms(pvfs, attrib);
1656 2741 : if (f->handle->name->st.st_mode != mode &&
1657 2087 : f->handle->name->dos.attrib != attrib &&
1658 715 : pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
1659 0 : talloc_free(lck);
1660 0 : return pvfs_map_errno(pvfs, errno);
1661 : }
1662 1372 : name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1663 1372 : name->dos.attrib = attrib;
1664 1372 : status = pvfs_dosattrib_save(pvfs, name, fd);
1665 1372 : if (!NT_STATUS_IS_OK(status)) {
1666 0 : talloc_free(lck);
1667 0 : return status;
1668 : }
1669 : }
1670 :
1671 89004 : talloc_free(lck);
1672 :
1673 89004 : status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1674 89004 : NT_STATUS_NOT_OK_RETURN(status);
1675 :
1676 : /* mark the open as having completed fully, so delete on close
1677 : can now be used */
1678 89004 : f->handle->open_completed = true;
1679 :
1680 89004 : io->generic.out.oplock_level = oplock_granted;
1681 89004 : io->generic.out.file.ntvfs = h;
1682 89004 : io->generic.out.create_action = stream_existed?
1683 89004 : create_action:NTCREATEX_ACTION_CREATED;
1684 :
1685 89004 : io->generic.out.create_time = name->dos.create_time;
1686 89004 : io->generic.out.access_time = name->dos.access_time;
1687 89004 : io->generic.out.write_time = name->dos.write_time;
1688 89004 : io->generic.out.change_time = name->dos.change_time;
1689 89004 : io->generic.out.attrib = name->dos.attrib;
1690 89004 : io->generic.out.alloc_size = name->dos.alloc_size;
1691 89004 : io->generic.out.size = name->st.st_size;
1692 89004 : io->generic.out.file_type = FILE_TYPE_DISK;
1693 89004 : io->generic.out.ipc_state = 0;
1694 89004 : io->generic.out.is_directory = 0;
1695 :
1696 89004 : return NT_STATUS_OK;
1697 : }
1698 :
1699 :
1700 : /*
1701 : close a file
1702 : */
1703 403057 : NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1704 : struct ntvfs_request *req, union smb_close *io)
1705 : {
1706 403057 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1707 : struct pvfs_state);
1708 : struct pvfs_file *f;
1709 :
1710 403057 : if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1711 1 : return NT_STATUS_DOS(ERRSRV, ERRerror);
1712 : }
1713 :
1714 403056 : if (io->generic.level != RAW_CLOSE_GENERIC) {
1715 201528 : return ntvfs_map_close(ntvfs, req, io);
1716 : }
1717 :
1718 201528 : f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1719 201528 : if (!f) {
1720 0 : return NT_STATUS_INVALID_HANDLE;
1721 : }
1722 :
1723 201528 : if (!null_time(io->generic.in.write_time)) {
1724 1 : f->handle->write_time.update_forced = false;
1725 1 : f->handle->write_time.update_on_close = true;
1726 1 : unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1727 : }
1728 :
1729 201528 : if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1730 : struct pvfs_filename *name;
1731 : NTSTATUS status;
1732 2 : struct pvfs_file_handle *h = f->handle;
1733 :
1734 2 : status = pvfs_resolve_name_handle(pvfs, h);
1735 2 : if (!NT_STATUS_IS_OK(status)) {
1736 0 : return status;
1737 : }
1738 2 : name = h->name;
1739 :
1740 2 : io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1741 2 : io->generic.out.create_time = name->dos.create_time;
1742 2 : io->generic.out.access_time = name->dos.access_time;
1743 2 : io->generic.out.write_time = name->dos.write_time;
1744 2 : io->generic.out.change_time = name->dos.change_time;
1745 2 : io->generic.out.alloc_size = name->dos.alloc_size;
1746 2 : io->generic.out.size = name->st.st_size;
1747 2 : io->generic.out.file_attr = name->dos.attrib;
1748 : } else {
1749 201526 : ZERO_STRUCT(io->generic.out);
1750 : }
1751 :
1752 201528 : talloc_free(f);
1753 :
1754 201528 : return NT_STATUS_OK;
1755 : }
1756 :
1757 :
1758 : /*
1759 : logoff - close all file descriptors open by a vuid
1760 : */
1761 21 : NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1762 : struct ntvfs_request *req)
1763 : {
1764 21 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1765 : struct pvfs_state);
1766 : struct pvfs_file *f, *next;
1767 :
1768 : /* If pvfs is NULL, we never logged on, and no files are open. */
1769 21 : if(pvfs == NULL) {
1770 0 : return NT_STATUS_OK;
1771 : }
1772 :
1773 21 : for (f=pvfs->files.list;f;f=next) {
1774 0 : next = f->next;
1775 0 : if (f->ntvfs->session_info == req->session_info) {
1776 0 : talloc_free(f);
1777 : }
1778 : }
1779 :
1780 21 : return NT_STATUS_OK;
1781 : }
1782 :
1783 :
1784 : /*
1785 : exit - close files for the current pid
1786 : */
1787 523 : NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1788 : struct ntvfs_request *req)
1789 : {
1790 523 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1791 : struct pvfs_state);
1792 : struct pvfs_file *f, *next;
1793 :
1794 566 : for (f=pvfs->files.list;f;f=next) {
1795 43 : next = f->next;
1796 85 : if (f->ntvfs->session_info == req->session_info &&
1797 42 : f->ntvfs->smbpid == req->smbpid) {
1798 40 : talloc_free(f);
1799 : }
1800 : }
1801 :
1802 523 : return NT_STATUS_OK;
1803 : }
1804 :
1805 :
1806 : /*
1807 : change the delete on close flag on an already open file
1808 : */
1809 318 : NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1810 : struct ntvfs_request *req,
1811 : struct pvfs_file *f, bool del_on_close)
1812 : {
1813 : struct odb_lock *lck;
1814 : NTSTATUS status;
1815 :
1816 318 : if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1817 3 : return NT_STATUS_CANNOT_DELETE;
1818 : }
1819 :
1820 576 : if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1821 261 : !pvfs_directory_empty(pvfs, f->handle->name)) {
1822 4 : return NT_STATUS_DIRECTORY_NOT_EMPTY;
1823 : }
1824 :
1825 311 : if (del_on_close) {
1826 290 : f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1827 : } else {
1828 21 : f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1829 : }
1830 :
1831 311 : lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1832 311 : if (lck == NULL) {
1833 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1834 : }
1835 :
1836 311 : status = odb_set_delete_on_close(lck, del_on_close);
1837 :
1838 311 : talloc_free(lck);
1839 :
1840 311 : return status;
1841 : }
1842 :
1843 :
1844 : /*
1845 : determine if a file can be deleted, or if it is prevented by an
1846 : already open file
1847 : */
1848 31060 : NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1849 : struct ntvfs_request *req,
1850 : struct pvfs_filename *name,
1851 : struct odb_lock **lckp)
1852 : {
1853 : NTSTATUS status;
1854 : DATA_BLOB key;
1855 : struct odb_lock *lck;
1856 : uint32_t share_access;
1857 : uint32_t access_mask;
1858 : bool delete_on_close;
1859 :
1860 31060 : status = pvfs_locking_key(name, name, &key);
1861 31060 : if (!NT_STATUS_IS_OK(status)) {
1862 0 : return NT_STATUS_NO_MEMORY;
1863 : }
1864 :
1865 31060 : lck = odb_lock(req, pvfs->odb_context, &key);
1866 31060 : if (lck == NULL) {
1867 0 : DEBUG(0,("Unable to lock opendb for can_delete\n"));
1868 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1869 : }
1870 :
1871 31060 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1872 : NTCREATEX_SHARE_ACCESS_WRITE |
1873 : NTCREATEX_SHARE_ACCESS_DELETE;
1874 31060 : access_mask = SEC_STD_DELETE;
1875 31060 : delete_on_close = true;
1876 :
1877 31060 : status = odb_can_open(lck, name->stream_id,
1878 : share_access, access_mask, delete_on_close,
1879 : NTCREATEX_DISP_OPEN, false);
1880 :
1881 31060 : if (NT_STATUS_IS_OK(status)) {
1882 31021 : status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1883 : }
1884 :
1885 : /*
1886 : * if it's a sharing violation or we got no oplock
1887 : * only keep the lock if the caller requested access
1888 : * to the lock
1889 : */
1890 62085 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1891 31028 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1892 76 : if (lckp) {
1893 37 : *lckp = lck;
1894 : } else {
1895 1 : talloc_free(lck);
1896 : }
1897 31022 : } else if (!NT_STATUS_IS_OK(status)) {
1898 1 : talloc_free(lck);
1899 1 : if (lckp) {
1900 0 : *lckp = NULL;
1901 : }
1902 31021 : } else if (lckp) {
1903 31019 : *lckp = lck;
1904 : }
1905 :
1906 31060 : return status;
1907 : }
1908 :
1909 : /*
1910 : determine if a file can be renamed, or if it is prevented by an
1911 : already open file
1912 : */
1913 109 : NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1914 : struct ntvfs_request *req,
1915 : struct pvfs_filename *name,
1916 : struct odb_lock **lckp)
1917 : {
1918 : NTSTATUS status;
1919 : DATA_BLOB key;
1920 : struct odb_lock *lck;
1921 : uint32_t share_access;
1922 : uint32_t access_mask;
1923 : bool delete_on_close;
1924 :
1925 109 : status = pvfs_locking_key(name, name, &key);
1926 109 : if (!NT_STATUS_IS_OK(status)) {
1927 0 : return NT_STATUS_NO_MEMORY;
1928 : }
1929 :
1930 109 : lck = odb_lock(req, pvfs->odb_context, &key);
1931 109 : if (lck == NULL) {
1932 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
1933 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1934 : }
1935 :
1936 109 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1937 : NTCREATEX_SHARE_ACCESS_WRITE;
1938 109 : access_mask = SEC_STD_DELETE;
1939 109 : delete_on_close = false;
1940 :
1941 109 : status = odb_can_open(lck, name->stream_id,
1942 : share_access, access_mask, delete_on_close,
1943 : NTCREATEX_DISP_OPEN, false);
1944 :
1945 : /*
1946 : * if it's a sharing violation or we got no oplock
1947 : * only keep the lock if the caller requested access
1948 : * to the lock
1949 : */
1950 206 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1951 98 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1952 30 : if (lckp) {
1953 15 : *lckp = lck;
1954 : } else {
1955 0 : talloc_free(lck);
1956 : }
1957 94 : } else if (!NT_STATUS_IS_OK(status)) {
1958 0 : talloc_free(lck);
1959 0 : if (lckp) {
1960 0 : *lckp = NULL;
1961 : }
1962 94 : } else if (lckp) {
1963 94 : *lckp = lck;
1964 : }
1965 :
1966 109 : return status;
1967 : }
1968 :
1969 : /*
1970 : determine if the file size of a file can be changed,
1971 : or if it is prevented by an already open file
1972 : */
1973 13 : NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1974 : struct ntvfs_request *req,
1975 : struct pvfs_filename *name,
1976 : struct odb_lock **lckp)
1977 : {
1978 : NTSTATUS status;
1979 : DATA_BLOB key;
1980 : struct odb_lock *lck;
1981 : uint32_t share_access;
1982 : uint32_t access_mask;
1983 : bool break_to_none;
1984 : bool delete_on_close;
1985 :
1986 13 : status = pvfs_locking_key(name, name, &key);
1987 13 : if (!NT_STATUS_IS_OK(status)) {
1988 0 : return NT_STATUS_NO_MEMORY;
1989 : }
1990 :
1991 13 : lck = odb_lock(req, pvfs->odb_context, &key);
1992 13 : if (lck == NULL) {
1993 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
1994 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1995 : }
1996 :
1997 13 : share_access = NTCREATEX_SHARE_ACCESS_READ |
1998 : NTCREATEX_SHARE_ACCESS_WRITE |
1999 : NTCREATEX_SHARE_ACCESS_DELETE;
2000 : /*
2001 : * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
2002 : * a comment that this seemed to be wrong, but matched windows
2003 : * behaviour. It now appears that this windows behaviour is
2004 : * just a bug.
2005 : */
2006 13 : access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
2007 13 : delete_on_close = false;
2008 13 : break_to_none = true;
2009 :
2010 13 : status = odb_can_open(lck, name->stream_id,
2011 : share_access, access_mask, delete_on_close,
2012 : NTCREATEX_DISP_OPEN, break_to_none);
2013 :
2014 : /*
2015 : * if it's a sharing violation or we got no oplock
2016 : * only keep the lock if the caller requested access
2017 : * to the lock
2018 : */
2019 24 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
2020 11 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
2021 10 : if (lckp) {
2022 5 : *lckp = lck;
2023 : } else {
2024 0 : talloc_free(lck);
2025 : }
2026 8 : } else if (!NT_STATUS_IS_OK(status)) {
2027 0 : talloc_free(lck);
2028 0 : if (lckp) {
2029 0 : *lckp = NULL;
2030 : }
2031 8 : } else if (lckp) {
2032 8 : *lckp = lck;
2033 : }
2034 :
2035 13 : return status;
2036 : }
2037 :
2038 : /*
2039 : determine if file meta data can be accessed, or if it is prevented by an
2040 : already open file
2041 : */
2042 5074 : NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2043 : struct ntvfs_request *req,
2044 : struct pvfs_filename *name)
2045 : {
2046 : NTSTATUS status;
2047 : DATA_BLOB key;
2048 : struct odb_lock *lck;
2049 : uint32_t share_access;
2050 : uint32_t access_mask;
2051 : bool delete_on_close;
2052 :
2053 5074 : status = pvfs_locking_key(name, name, &key);
2054 5074 : if (!NT_STATUS_IS_OK(status)) {
2055 0 : return NT_STATUS_NO_MEMORY;
2056 : }
2057 :
2058 5074 : lck = odb_lock(req, pvfs->odb_context, &key);
2059 5074 : if (lck == NULL) {
2060 0 : DEBUG(0,("Unable to lock opendb for can_stat\n"));
2061 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2062 : }
2063 :
2064 5074 : share_access = NTCREATEX_SHARE_ACCESS_READ |
2065 : NTCREATEX_SHARE_ACCESS_WRITE;
2066 5074 : access_mask = SEC_FILE_READ_ATTRIBUTE;
2067 5074 : delete_on_close = false;
2068 :
2069 5074 : status = odb_can_open(lck, name->stream_id,
2070 : share_access, access_mask, delete_on_close,
2071 : NTCREATEX_DISP_OPEN, false);
2072 :
2073 5074 : if (!NT_STATUS_IS_OK(status)) {
2074 32 : talloc_free(lck);
2075 : }
2076 :
2077 5074 : return status;
2078 : }
2079 :
2080 :
2081 : /*
2082 : determine if delete on close is set on
2083 : */
2084 1025 : bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2085 : {
2086 : NTSTATUS status;
2087 : bool del_on_close;
2088 :
2089 1025 : status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2090 : &del_on_close, NULL);
2091 1025 : if (!NT_STATUS_IS_OK(status)) {
2092 0 : DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2093 0 : return false;
2094 : }
2095 :
2096 1025 : return del_on_close;
2097 : }
|