s3: smbd: Fix log spam. Change a normal error message from DBG_ERR (level 0) to DBG_I...
[Samba.git] / source3 / smbd / durable.c
blobb21c223b2e4466e9523f8fdbda4f60c3d3c3d5bc
1 /*
2 Unix SMB/CIFS implementation.
3 Durable Handle default VFS implementation
5 Copyright (C) Stefan Metzmacher 2012
6 Copyright (C) Michael Adam 2012
7 Copyright (C) Volker Lendecke 2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "lib/util/server_id.h"
26 #include "locking/share_mode_lock.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "libcli/security/security.h"
30 #include "messages.h"
31 #include "librpc/gen_ndr/ndr_open_files.h"
32 #include "serverid.h"
33 #include "fake_file.h"
34 #include "locking/leases_db.h"
36 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
37 TALLOC_CTX *mem_ctx,
38 DATA_BLOB *cookie_blob)
40 struct connection_struct *conn = fsp->conn;
41 enum ndr_err_code ndr_err;
42 struct vfs_default_durable_cookie cookie;
44 if (!lp_durable_handles(SNUM(conn))) {
45 return NT_STATUS_NOT_SUPPORTED;
48 if (lp_kernel_share_modes(SNUM(conn))) {
50 * We do not support durable handles
51 * if file system sharemodes are used
53 return NT_STATUS_NOT_SUPPORTED;
56 if (lp_kernel_oplocks(SNUM(conn))) {
58 * We do not support durable handles
59 * if kernel oplocks are used
61 return NT_STATUS_NOT_SUPPORTED;
64 if ((fsp->current_lock_count > 0) &&
65 lp_posix_locking(fsp->conn->params))
68 * We do not support durable handles
69 * if the handle has posix locks.
71 return NT_STATUS_NOT_SUPPORTED;
74 if (fsp->fsp_flags.is_directory) {
75 return NT_STATUS_NOT_SUPPORTED;
78 if (fsp_is_alternate_stream(fsp)) {
80 * We do not support durable handles
81 * on streams for now.
83 return NT_STATUS_NOT_SUPPORTED;
86 if (is_fake_file(fsp->fsp_name)) {
88 * We do not support durable handles
89 * on fake files.
91 return NT_STATUS_NOT_SUPPORTED;
94 ZERO_STRUCT(cookie);
95 cookie.allow_reconnect = false;
96 cookie.id = fsp->file_id;
97 cookie.servicepath = conn->connectpath;
98 cookie.base_name = fsp->fsp_name->base_name;
99 cookie.initial_allocation_size = fsp->initial_allocation_size;
100 cookie.position_information = fh_get_position_information(fsp->fh);
101 cookie.update_write_time_triggered =
102 fsp->fsp_flags.update_write_time_triggered;
103 cookie.update_write_time_on_close =
104 fsp->fsp_flags.update_write_time_on_close;
105 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
106 cookie.close_write_time = full_timespec_to_nt_time(
107 &fsp->close_write_time);
109 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
110 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
111 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
112 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
113 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
114 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
115 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
116 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
117 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
118 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
119 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
120 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
121 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
122 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
123 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
124 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
126 ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
127 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
129 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
130 return status;
133 return NT_STATUS_OK;
136 NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
137 const DATA_BLOB old_cookie,
138 TALLOC_CTX *mem_ctx,
139 DATA_BLOB *new_cookie)
141 struct connection_struct *conn = fsp->conn;
142 NTSTATUS status;
143 enum ndr_err_code ndr_err;
144 struct vfs_default_durable_cookie cookie;
145 DATA_BLOB new_cookie_blob = data_blob_null;
146 struct share_mode_lock *lck;
147 bool ok;
149 *new_cookie = data_blob_null;
151 ZERO_STRUCT(cookie);
153 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
154 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
156 status = ndr_map_error2ntstatus(ndr_err);
157 return status;
160 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
161 return NT_STATUS_INVALID_PARAMETER;
164 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
165 return NT_STATUS_INVALID_PARAMETER;
168 if (!file_id_equal(&fsp->file_id, &cookie.id)) {
169 return NT_STATUS_INVALID_PARAMETER;
172 if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
173 return NT_STATUS_NOT_SUPPORTED;
177 * For now let it be simple and do not keep
178 * delete on close files durable open
180 if (fsp->fsp_flags.initial_delete_on_close) {
181 return NT_STATUS_NOT_SUPPORTED;
183 if (fsp->fsp_flags.delete_on_close) {
184 return NT_STATUS_NOT_SUPPORTED;
187 if (!VALID_STAT(fsp->fsp_name->st)) {
188 return NT_STATUS_NOT_SUPPORTED;
191 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
192 return NT_STATUS_NOT_SUPPORTED;
195 /* Ensure any pending write time updates are done. */
196 if (fsp->update_write_time_event) {
197 fsp_flush_write_time_update(fsp);
201 * The above checks are done in mark_share_mode_disconnected() too
202 * but we want to avoid getting the lock if possible
204 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
205 if (lck != NULL) {
206 struct smb_file_time ft;
208 init_smb_file_time(&ft);
210 if (fsp->fsp_flags.write_time_forced) {
211 NTTIME mtime = share_mode_changed_write_time(lck);
212 ft.mtime = nt_time_to_full_timespec(mtime);
213 } else if (fsp->fsp_flags.update_write_time_on_close) {
214 if (is_omit_timespec(&fsp->close_write_time)) {
215 ft.mtime = timespec_current();
216 } else {
217 ft.mtime = fsp->close_write_time;
221 if (!is_omit_timespec(&ft.mtime)) {
222 round_timespec(conn->ts_res, &ft.mtime);
223 file_ntimes(conn, fsp, &ft);
226 ok = mark_share_mode_disconnected(lck, fsp);
227 if (!ok) {
228 TALLOC_FREE(lck);
231 if (lck != NULL) {
232 ok = brl_mark_disconnected(fsp);
233 if (!ok) {
234 TALLOC_FREE(lck);
237 if (lck == NULL) {
238 return NT_STATUS_NOT_SUPPORTED;
240 TALLOC_FREE(lck);
242 status = vfs_stat_fsp(fsp);
243 if (!NT_STATUS_IS_OK(status)) {
244 return status;
247 ZERO_STRUCT(cookie);
248 cookie.allow_reconnect = true;
249 cookie.id = fsp->file_id;
250 cookie.servicepath = conn->connectpath;
251 cookie.base_name = fsp_str_dbg(fsp);
252 cookie.initial_allocation_size = fsp->initial_allocation_size;
253 cookie.position_information = fh_get_position_information(fsp->fh);
254 cookie.update_write_time_triggered =
255 fsp->fsp_flags.update_write_time_triggered;
256 cookie.update_write_time_on_close =
257 fsp->fsp_flags.update_write_time_on_close;
258 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
259 cookie.close_write_time = full_timespec_to_nt_time(
260 &fsp->close_write_time);
262 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
263 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
264 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
265 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
266 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
267 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
268 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
269 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
270 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
271 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
272 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
273 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
274 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
275 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
276 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
277 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
279 ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
280 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282 status = ndr_map_error2ntstatus(ndr_err);
283 return status;
286 status = fd_close(fsp);
287 if (!NT_STATUS_IS_OK(status)) {
288 data_blob_free(&new_cookie_blob);
289 return status;
292 *new_cookie = new_cookie_blob;
293 return NT_STATUS_OK;
298 * Check whether a cookie-stored struct info is the same
299 * as a given SMB_STRUCT_STAT, as coming with the fsp.
301 static bool vfs_default_durable_reconnect_check_stat(
302 struct vfs_default_durable_stat *cookie_st,
303 SMB_STRUCT_STAT *fsp_st,
304 const char *name)
306 int ret;
308 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
309 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
310 "stat_ex.%s differs: "
311 "cookie:%llu != stat:%llu, "
312 "denying durable reconnect\n",
313 name,
314 "st_ex_mode",
315 (unsigned long long)cookie_st->st_ex_mode,
316 (unsigned long long)fsp_st->st_ex_mode));
317 return false;
320 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
321 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
322 "stat_ex.%s differs: "
323 "cookie:%llu != stat:%llu, "
324 "denying durable reconnect\n",
325 name,
326 "st_ex_nlink",
327 (unsigned long long)cookie_st->st_ex_nlink,
328 (unsigned long long)fsp_st->st_ex_nlink));
329 return false;
332 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
333 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
334 "stat_ex.%s differs: "
335 "cookie:%llu != stat:%llu, "
336 "denying durable reconnect\n",
337 name,
338 "st_ex_uid",
339 (unsigned long long)cookie_st->st_ex_uid,
340 (unsigned long long)fsp_st->st_ex_uid));
341 return false;
344 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
345 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
346 "stat_ex.%s differs: "
347 "cookie:%llu != stat:%llu, "
348 "denying durable reconnect\n",
349 name,
350 "st_ex_gid",
351 (unsigned long long)cookie_st->st_ex_gid,
352 (unsigned long long)fsp_st->st_ex_gid));
353 return false;
356 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
357 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
358 "stat_ex.%s differs: "
359 "cookie:%llu != stat:%llu, "
360 "denying durable reconnect\n",
361 name,
362 "st_ex_rdev",
363 (unsigned long long)cookie_st->st_ex_rdev,
364 (unsigned long long)fsp_st->st_ex_rdev));
365 return false;
368 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
369 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
370 "stat_ex.%s differs: "
371 "cookie:%llu != stat:%llu, "
372 "denying durable reconnect\n",
373 name,
374 "st_ex_size",
375 (unsigned long long)cookie_st->st_ex_size,
376 (unsigned long long)fsp_st->st_ex_size));
377 return false;
380 ret = timespec_compare(&cookie_st->st_ex_atime,
381 &fsp_st->st_ex_atime);
382 if (ret != 0) {
383 struct timeval tc, ts;
384 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
385 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
387 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
388 "stat_ex.%s differs: "
389 "cookie:'%s' != stat:'%s', "
390 "denying durable reconnect\n",
391 name,
392 "st_ex_atime",
393 timeval_string(talloc_tos(), &tc, true),
394 timeval_string(talloc_tos(), &ts, true)));
395 return false;
398 ret = timespec_compare(&cookie_st->st_ex_mtime,
399 &fsp_st->st_ex_mtime);
400 if (ret != 0) {
401 struct timeval tc, ts;
402 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
403 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
405 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
406 "stat_ex.%s differs: "
407 "cookie:'%s' != stat:'%s', "
408 "denying durable reconnect\n",
409 name,
410 "st_ex_mtime",
411 timeval_string(talloc_tos(), &tc, true),
412 timeval_string(talloc_tos(), &ts, true)));
413 return false;
416 ret = timespec_compare(&cookie_st->st_ex_ctime,
417 &fsp_st->st_ex_ctime);
418 if (ret != 0) {
419 struct timeval tc, ts;
420 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
421 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
423 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
424 "stat_ex.%s differs: "
425 "cookie:'%s' != stat:'%s', "
426 "denying durable reconnect\n",
427 name,
428 "st_ex_ctime",
429 timeval_string(talloc_tos(), &tc, true),
430 timeval_string(talloc_tos(), &ts, true)));
431 return false;
434 ret = timespec_compare(&cookie_st->st_ex_btime,
435 &fsp_st->st_ex_btime);
436 if (ret != 0) {
437 struct timeval tc, ts;
438 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
439 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
441 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
442 "stat_ex.%s differs: "
443 "cookie:'%s' != stat:'%s', "
444 "denying durable reconnect\n",
445 name,
446 "st_ex_btime",
447 timeval_string(talloc_tos(), &tc, true),
448 timeval_string(talloc_tos(), &ts, true)));
449 return false;
452 if (cookie_st->st_ex_iflags != fsp_st->st_ex_iflags) {
453 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
454 "stat_ex.%s differs: "
455 "cookie:%llu != stat:%llu, "
456 "denying durable reconnect\n",
457 name,
458 "st_ex_calculated_birthtime",
459 (unsigned long long)cookie_st->st_ex_iflags,
460 (unsigned long long)fsp_st->st_ex_iflags));
461 return false;
464 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
465 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
466 "stat_ex.%s differs: "
467 "cookie:%llu != stat:%llu, "
468 "denying durable reconnect\n",
469 name,
470 "st_ex_blksize",
471 (unsigned long long)cookie_st->st_ex_blksize,
472 (unsigned long long)fsp_st->st_ex_blksize));
473 return false;
476 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
477 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
478 "stat_ex.%s differs: "
479 "cookie:%llu != stat:%llu, "
480 "denying durable reconnect\n",
481 name,
482 "st_ex_blocks",
483 (unsigned long long)cookie_st->st_ex_blocks,
484 (unsigned long long)fsp_st->st_ex_blocks));
485 return false;
488 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
489 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
490 "stat_ex.%s differs: "
491 "cookie:%llu != stat:%llu, "
492 "denying durable reconnect\n",
493 name,
494 "st_ex_flags",
495 (unsigned long long)cookie_st->st_ex_flags,
496 (unsigned long long)fsp_st->st_ex_flags));
497 return false;
500 return true;
503 static bool durable_reconnect_fn(
504 struct share_mode_entry *e,
505 bool *modified,
506 void *private_data)
508 struct share_mode_entry *dst_e = private_data;
510 if (dst_e->pid.pid != 0) {
511 DBG_INFO("Found more than one entry, invalidating previous\n");
512 dst_e->pid.pid = 0;
513 return true; /* end the loop through share mode entries */
515 *dst_e = *e;
516 return false; /* Look at potential other entries */
519 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
520 struct smb_request *smb1req,
521 struct smbXsrv_open *op,
522 const DATA_BLOB old_cookie,
523 TALLOC_CTX *mem_ctx,
524 files_struct **result,
525 DATA_BLOB *new_cookie)
527 const struct loadparm_substitution *lp_sub =
528 loadparm_s3_global_substitution();
529 struct share_mode_lock *lck;
530 struct share_mode_entry e;
531 struct files_struct *fsp = NULL;
532 NTSTATUS status;
533 bool ok;
534 int ret;
535 struct vfs_open_how how = { .flags = 0, };
536 struct file_id file_id;
537 struct smb_filename *smb_fname = NULL;
538 enum ndr_err_code ndr_err;
539 struct vfs_default_durable_cookie cookie;
540 DATA_BLOB new_cookie_blob = data_blob_null;
542 *result = NULL;
543 *new_cookie = data_blob_null;
545 if (!lp_durable_handles(SNUM(conn))) {
546 return NT_STATUS_NOT_SUPPORTED;
550 * the checks for kernel oplocks
551 * and similar things are done
552 * in the vfs_default_durable_cookie()
553 * call below.
556 ndr_err = ndr_pull_struct_blob_all(
557 &old_cookie,
558 talloc_tos(),
559 &cookie,
560 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
562 status = ndr_map_error2ntstatus(ndr_err);
563 return status;
566 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
567 return NT_STATUS_INVALID_PARAMETER;
570 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
571 return NT_STATUS_INVALID_PARAMETER;
574 if (!cookie.allow_reconnect) {
575 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
578 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
579 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
582 /* Create an smb_filename with stream_name == NULL. */
583 smb_fname = synthetic_smb_fname(talloc_tos(),
584 cookie.base_name,
585 NULL,
586 NULL,
589 if (smb_fname == NULL) {
590 return NT_STATUS_NO_MEMORY;
593 ret = SMB_VFS_LSTAT(conn, smb_fname);
594 if (ret == -1) {
595 status = map_nt_error_from_unix_common(errno);
596 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
597 smb_fname_str_dbg(smb_fname),
598 nt_errstr(status)));
599 return status;
602 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
603 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
606 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
607 if (!file_id_equal(&cookie.id, &file_id)) {
608 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
612 * 1. check entry in locking.tdb
615 lck = get_existing_share_mode_lock(mem_ctx, file_id);
616 if (lck == NULL) {
617 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
618 "not obtained from db\n"));
619 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
622 e = (struct share_mode_entry) { .pid.pid = 0 };
624 ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
625 if (!ok) {
626 DBG_WARNING("share_mode_forall_entries failed\n");
627 TALLOC_FREE(lck);
628 return NT_STATUS_INTERNAL_DB_ERROR;
631 if (e.pid.pid == 0) {
632 DBG_WARNING("Did not find a unique valid share mode entry\n");
633 TALLOC_FREE(lck);
634 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
637 if (!server_id_is_disconnected(&e.pid)) {
638 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
639 "reconnect for handle that was not marked "
640 "disconnected (e.g. smbd or cluster node died)\n"));
641 TALLOC_FREE(lck);
642 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
645 if (e.share_file_id != op->global->open_persistent_id) {
646 DBG_INFO("denying durable "
647 "share_file_id changed %"PRIu64" != %"PRIu64" "
648 "(e.g. another client had opened the file)\n",
649 e.share_file_id,
650 op->global->open_persistent_id);
651 TALLOC_FREE(lck);
652 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
655 if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
656 !CAN_WRITE(conn))
658 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
659 "share[%s] is not writeable anymore\n",
660 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
661 TALLOC_FREE(lck);
662 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
666 * 2. proceed with opening file
669 status = fsp_new(conn, conn, &fsp);
670 if (!NT_STATUS_IS_OK(status)) {
671 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
672 "new fsp: %s\n", nt_errstr(status)));
673 TALLOC_FREE(lck);
674 return status;
677 fh_set_private_options(fsp->fh, e.private_options);
678 fsp->file_id = file_id;
679 fsp->file_pid = smb1req->smbpid;
680 fsp->vuid = smb1req->vuid;
681 fsp->open_time = e.time;
682 fsp->access_mask = e.access_mask;
683 fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0);
684 fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
685 fsp->fnum = op->local_id;
686 fsp_set_gen_id(fsp);
689 * TODO:
690 * Do we need to store the modified flag in the DB?
692 fsp->fsp_flags.modified = false;
694 * no durables for directories
696 fsp->fsp_flags.is_directory = false;
698 * For normal files, can_lock == !is_directory
700 fsp->fsp_flags.can_lock = true;
702 * We do not support aio write behind for smb2
704 fsp->fsp_flags.aio_write_behind = false;
705 fsp->oplock_type = e.op_type;
707 if (fsp->oplock_type == LEASE_OPLOCK) {
708 uint32_t current_state;
709 uint16_t lease_version, epoch;
712 * Ensure the existing client guid matches the
713 * stored one in the share_mode_entry.
715 if (!GUID_equal(fsp_client_guid(fsp),
716 &e.client_guid)) {
717 TALLOC_FREE(lck);
718 file_free(smb1req, fsp);
719 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
722 status = leases_db_get(
723 &e.client_guid,
724 &e.lease_key,
725 &file_id,
726 &current_state, /* current_state */
727 NULL, /* breaking */
728 NULL, /* breaking_to_requested */
729 NULL, /* breaking_to_required */
730 &lease_version, /* lease_version */
731 &epoch); /* epoch */
732 if (!NT_STATUS_IS_OK(status)) {
733 TALLOC_FREE(lck);
734 file_free(smb1req, fsp);
735 return status;
738 fsp->lease = find_fsp_lease(
739 fsp,
740 &e.lease_key,
741 current_state,
742 lease_version,
743 epoch);
744 if (fsp->lease == NULL) {
745 TALLOC_FREE(lck);
746 file_free(smb1req, fsp);
747 return NT_STATUS_NO_MEMORY;
751 fsp->initial_allocation_size = cookie.initial_allocation_size;
752 fh_set_position_information(fsp->fh, cookie.position_information);
753 fsp->fsp_flags.update_write_time_triggered =
754 cookie.update_write_time_triggered;
755 fsp->fsp_flags.update_write_time_on_close =
756 cookie.update_write_time_on_close;
757 fsp->fsp_flags.write_time_forced = cookie.write_time_forced;
758 fsp->close_write_time = nt_time_to_full_timespec(
759 cookie.close_write_time);
761 status = fsp_set_smb_fname(fsp, smb_fname);
762 if (!NT_STATUS_IS_OK(status)) {
763 TALLOC_FREE(lck);
764 file_free(smb1req, fsp);
765 DEBUG(0, ("vfs_default_durable_reconnect: "
766 "fsp_set_smb_fname failed: %s\n",
767 nt_errstr(status)));
768 return status;
771 op->compat = fsp;
772 fsp->op = op;
774 ok = reset_share_mode_entry(
775 lck,
776 e.pid,
777 e.share_file_id,
778 messaging_server_id(conn->sconn->msg_ctx),
779 smb1req->mid,
780 fh_get_gen_id(fsp->fh));
781 if (!ok) {
782 DBG_DEBUG("Could not set new share_mode_entry values\n");
783 TALLOC_FREE(lck);
784 op->compat = NULL;
785 fsp->op = NULL;
786 file_free(smb1req, fsp);
787 return NT_STATUS_INTERNAL_ERROR;
790 ok = brl_reconnect_disconnected(fsp);
791 if (!ok) {
792 status = NT_STATUS_INTERNAL_ERROR;
793 DEBUG(1, ("vfs_default_durable_reconnect: "
794 "failed to reopen brlocks: %s\n",
795 nt_errstr(status)));
796 TALLOC_FREE(lck);
797 op->compat = NULL;
798 fsp->op = NULL;
799 file_free(smb1req, fsp);
800 return status;
804 * TODO: properly calculate open flags
806 if (fsp->fsp_flags.can_write && fsp->fsp_flags.can_read) {
807 how.flags = O_RDWR;
808 } else if (fsp->fsp_flags.can_write) {
809 how.flags = O_WRONLY;
810 } else if (fsp->fsp_flags.can_read) {
811 how.flags = O_RDONLY;
814 status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
815 if (!NT_STATUS_IS_OK(status)) {
816 TALLOC_FREE(lck);
817 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
818 "file: %s\n", nt_errstr(status)));
819 op->compat = NULL;
820 fsp->op = NULL;
821 file_free(smb1req, fsp);
822 return status;
826 * We now check the stat info stored in the cookie against
827 * the current stat data from the file we just opened.
828 * If any detail differs, we deny the durable reconnect,
829 * because in that case it is very likely that someone
830 * opened the file while the handle was disconnected,
831 * which has to be interpreted as an oplock break.
834 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
835 if (ret == -1) {
836 NTSTATUS close_status;
837 status = map_nt_error_from_unix_common(errno);
838 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
839 smb_fname_str_dbg(smb_fname),
840 nt_errstr(status)));
841 close_status = fd_close(fsp);
842 if (!NT_STATUS_IS_OK(close_status)) {
843 DBG_ERR("fd_close failed (%s) - leaking file "
844 "descriptor\n", nt_errstr(close_status));
846 TALLOC_FREE(lck);
847 op->compat = NULL;
848 fsp->op = NULL;
849 file_free(smb1req, fsp);
850 return status;
853 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
854 NTSTATUS close_status = fd_close(fsp);
855 if (!NT_STATUS_IS_OK(close_status)) {
856 DBG_ERR("fd_close failed (%s) - leaking file "
857 "descriptor\n", nt_errstr(close_status));
859 TALLOC_FREE(lck);
860 op->compat = NULL;
861 fsp->op = NULL;
862 file_free(smb1req, fsp);
863 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
866 file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
867 if (!file_id_equal(&cookie.id, &file_id)) {
868 NTSTATUS close_status = fd_close(fsp);
869 if (!NT_STATUS_IS_OK(close_status)) {
870 DBG_ERR("fd_close failed (%s) - leaking file "
871 "descriptor\n", nt_errstr(close_status));
873 TALLOC_FREE(lck);
874 op->compat = NULL;
875 fsp->op = NULL;
876 file_free(smb1req, fsp);
877 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
880 (void)fdos_mode(fsp);
882 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
883 &fsp->fsp_name->st,
884 fsp_str_dbg(fsp));
885 if (!ok) {
886 NTSTATUS close_status = fd_close(fsp);
887 if (!NT_STATUS_IS_OK(close_status)) {
888 DBG_ERR("fd_close failed (%s) - leaking file "
889 "descriptor\n", nt_errstr(close_status));
891 TALLOC_FREE(lck);
892 op->compat = NULL;
893 fsp->op = NULL;
894 file_free(smb1req, fsp);
895 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
898 status = set_file_oplock(fsp);
899 if (!NT_STATUS_IS_OK(status)) {
900 NTSTATUS close_status = fd_close(fsp);
901 if (!NT_STATUS_IS_OK(close_status)) {
902 DBG_ERR("fd_close failed (%s) - leaking file "
903 "descriptor\n", nt_errstr(close_status));
905 TALLOC_FREE(lck);
906 op->compat = NULL;
907 fsp->op = NULL;
908 file_free(smb1req, fsp);
909 return status;
912 status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
913 if (!NT_STATUS_IS_OK(status)) {
914 TALLOC_FREE(lck);
915 DEBUG(1, ("vfs_default_durable_reconnect: "
916 "vfs_default_durable_cookie - %s\n",
917 nt_errstr(status)));
918 op->compat = NULL;
919 fsp->op = NULL;
920 file_free(smb1req, fsp);
921 return status;
924 smb1req->chain_fsp = fsp;
925 smb1req->smb2req->compat_chain_fsp = fsp;
927 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
928 fsp_str_dbg(fsp)));
930 TALLOC_FREE(lck);
932 fsp->fsp_flags.is_fsa = true;
934 *result = fsp;
935 *new_cookie = new_cookie_blob;
937 return NT_STATUS_OK;