winbindd: queryuser - only get group name if needed
[Samba.git] / source3 / smbd / durable.c
blob602a96e1fe56bc874f738893685046a931b101ce
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 "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "libcli/security/security.h"
29 #include "messages.h"
30 #include "librpc/gen_ndr/ndr_open_files.h"
31 #include "serverid.h"
32 #include "fake_file.h"
34 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
35 TALLOC_CTX *mem_ctx,
36 DATA_BLOB *cookie_blob)
38 struct connection_struct *conn = fsp->conn;
39 enum ndr_err_code ndr_err;
40 struct vfs_default_durable_cookie cookie;
42 if (!lp_durable_handles(SNUM(conn))) {
43 return NT_STATUS_NOT_SUPPORTED;
46 if (lp_kernel_share_modes(SNUM(conn))) {
48 * We do not support durable handles
49 * if kernel share modes (flocks) are used
51 return NT_STATUS_NOT_SUPPORTED;
54 if (lp_kernel_oplocks(SNUM(conn))) {
56 * We do not support durable handles
57 * if kernel oplocks are used
59 return NT_STATUS_NOT_SUPPORTED;
62 if ((fsp->current_lock_count > 0) &&
63 lp_posix_locking(fsp->conn->params))
66 * We do not support durable handles
67 * if the handle has posix locks.
69 return NT_STATUS_NOT_SUPPORTED;
72 if (fsp->is_directory) {
73 return NT_STATUS_NOT_SUPPORTED;
76 if (fsp->fh->fd == -1) {
77 return NT_STATUS_NOT_SUPPORTED;
80 if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
82 * We do not support durable handles
83 * on streams for now.
85 return NT_STATUS_NOT_SUPPORTED;
88 if (is_fake_file(fsp->fsp_name)) {
90 * We do not support durable handles
91 * on fake files.
93 return NT_STATUS_NOT_SUPPORTED;
96 ZERO_STRUCT(cookie);
97 cookie.allow_reconnect = false;
98 cookie.id = fsp->file_id;
99 cookie.servicepath = conn->connectpath;
100 cookie.base_name = fsp->fsp_name->base_name;
101 cookie.initial_allocation_size = fsp->initial_allocation_size;
102 cookie.position_information = fsp->fh->position_information;
103 cookie.update_write_time_triggered = fsp->update_write_time_triggered;
104 cookie.update_write_time_on_close = fsp->update_write_time_on_close;
105 cookie.write_time_forced = fsp->write_time_forced;
106 cookie.close_write_time = fsp->close_write_time;
108 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
109 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
110 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
111 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
112 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
113 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
114 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
115 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
116 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
117 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
118 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
119 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
120 cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
121 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
122 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
123 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
124 cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
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->initial_delete_on_close) {
181 return NT_STATUS_NOT_SUPPORTED;
183 if (fsp->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 update_write_time_handler(fsp->conn->sconn->ev_ctx,
198 fsp->update_write_time_event,
199 timeval_current(),
200 (void *)fsp);
204 * The above checks are done in mark_share_mode_disconnected() too
205 * but we want to avoid getting the lock if possible
207 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
208 if (lck != NULL) {
209 struct smb_file_time ft;
211 ZERO_STRUCT(ft);
213 if (fsp->write_time_forced) {
214 ft.mtime = lck->data->changed_write_time;
215 } else if (fsp->update_write_time_on_close) {
216 if (null_timespec(fsp->close_write_time)) {
217 ft.mtime = timespec_current();
218 } else {
219 ft.mtime = fsp->close_write_time;
223 if (!null_timespec(ft.mtime)) {
224 round_timespec(conn->ts_res, &ft.mtime);
225 file_ntimes(conn, fsp->fsp_name, &ft);
228 ok = mark_share_mode_disconnected(lck, fsp);
229 if (!ok) {
230 TALLOC_FREE(lck);
233 if (lck != NULL) {
234 ok = brl_mark_disconnected(fsp);
235 if (!ok) {
236 TALLOC_FREE(lck);
239 if (lck == NULL) {
240 return NT_STATUS_NOT_SUPPORTED;
242 TALLOC_FREE(lck);
244 status = vfs_stat_fsp(fsp);
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
249 ZERO_STRUCT(cookie);
250 cookie.allow_reconnect = true;
251 cookie.id = fsp->file_id;
252 cookie.servicepath = conn->connectpath;
253 cookie.base_name = fsp->fsp_name->base_name;
254 cookie.initial_allocation_size = fsp->initial_allocation_size;
255 cookie.position_information = fsp->fh->position_information;
256 cookie.update_write_time_triggered = fsp->update_write_time_triggered;
257 cookie.update_write_time_on_close = fsp->update_write_time_on_close;
258 cookie.write_time_forced = fsp->write_time_forced;
259 cookie.close_write_time = fsp->close_write_time;
261 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
262 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
263 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
264 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
265 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
266 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
267 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
268 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
269 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
270 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
271 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
272 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
273 cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
274 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
275 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
276 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
277 cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
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_dev != fsp_st->st_ex_dev) {
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_dev",
315 (unsigned long long)cookie_st->st_ex_dev,
316 (unsigned long long)fsp_st->st_ex_dev));
317 return false;
320 if (cookie_st->st_ex_ino != fsp_st->st_ex_ino) {
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_ino",
327 (unsigned long long)cookie_st->st_ex_ino,
328 (unsigned long long)fsp_st->st_ex_ino));
329 return false;
332 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
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_mode",
339 (unsigned long long)cookie_st->st_ex_mode,
340 (unsigned long long)fsp_st->st_ex_mode));
341 return false;
344 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
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_nlink",
351 (unsigned long long)cookie_st->st_ex_nlink,
352 (unsigned long long)fsp_st->st_ex_nlink));
353 return false;
356 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
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_uid",
363 (unsigned long long)cookie_st->st_ex_uid,
364 (unsigned long long)fsp_st->st_ex_uid));
365 return false;
368 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
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_gid",
375 (unsigned long long)cookie_st->st_ex_gid,
376 (unsigned long long)fsp_st->st_ex_gid));
377 return false;
380 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
381 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
382 "stat_ex.%s differs: "
383 "cookie:%llu != stat:%llu, "
384 "denying durable reconnect\n",
385 name,
386 "st_ex_rdev",
387 (unsigned long long)cookie_st->st_ex_rdev,
388 (unsigned long long)fsp_st->st_ex_rdev));
389 return false;
392 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
393 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
394 "stat_ex.%s differs: "
395 "cookie:%llu != stat:%llu, "
396 "denying durable reconnect\n",
397 name,
398 "st_ex_size",
399 (unsigned long long)cookie_st->st_ex_size,
400 (unsigned long long)fsp_st->st_ex_size));
401 return false;
404 ret = timespec_compare(&cookie_st->st_ex_atime,
405 &fsp_st->st_ex_atime);
406 if (ret != 0) {
407 struct timeval tc, ts;
408 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
409 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
411 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
412 "stat_ex.%s differs: "
413 "cookie:'%s' != stat:'%s', "
414 "denying durable reconnect\n",
415 name,
416 "st_ex_atime",
417 timeval_string(talloc_tos(), &tc, true),
418 timeval_string(talloc_tos(), &ts, true)));
419 return false;
422 ret = timespec_compare(&cookie_st->st_ex_mtime,
423 &fsp_st->st_ex_mtime);
424 if (ret != 0) {
425 struct timeval tc, ts;
426 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
427 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
429 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
430 "stat_ex.%s differs: "
431 "cookie:'%s' != stat:'%s', "
432 "denying durable reconnect\n",
433 name,
434 "st_ex_mtime",
435 timeval_string(talloc_tos(), &tc, true),
436 timeval_string(talloc_tos(), &ts, true)));
437 return false;
440 ret = timespec_compare(&cookie_st->st_ex_ctime,
441 &fsp_st->st_ex_ctime);
442 if (ret != 0) {
443 struct timeval tc, ts;
444 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
445 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
447 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
448 "stat_ex.%s differs: "
449 "cookie:'%s' != stat:'%s', "
450 "denying durable reconnect\n",
451 name,
452 "st_ex_ctime",
453 timeval_string(talloc_tos(), &tc, true),
454 timeval_string(talloc_tos(), &ts, true)));
455 return false;
458 ret = timespec_compare(&cookie_st->st_ex_btime,
459 &fsp_st->st_ex_btime);
460 if (ret != 0) {
461 struct timeval tc, ts;
462 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
463 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
465 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
466 "stat_ex.%s differs: "
467 "cookie:'%s' != stat:'%s', "
468 "denying durable reconnect\n",
469 name,
470 "st_ex_btime",
471 timeval_string(talloc_tos(), &tc, true),
472 timeval_string(talloc_tos(), &ts, true)));
473 return false;
476 if (cookie_st->st_ex_calculated_birthtime !=
477 fsp_st->st_ex_calculated_birthtime)
479 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
480 "stat_ex.%s differs: "
481 "cookie:%llu != stat:%llu, "
482 "denying durable reconnect\n",
483 name,
484 "st_ex_calculated_birthtime",
485 (unsigned long long)cookie_st->st_ex_calculated_birthtime,
486 (unsigned long long)fsp_st->st_ex_calculated_birthtime));
487 return false;
490 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
491 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
492 "stat_ex.%s differs: "
493 "cookie:%llu != stat:%llu, "
494 "denying durable reconnect\n",
495 name,
496 "st_ex_blksize",
497 (unsigned long long)cookie_st->st_ex_blksize,
498 (unsigned long long)fsp_st->st_ex_blksize));
499 return false;
502 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
503 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
504 "stat_ex.%s differs: "
505 "cookie:%llu != stat:%llu, "
506 "denying durable reconnect\n",
507 name,
508 "st_ex_blocks",
509 (unsigned long long)cookie_st->st_ex_blocks,
510 (unsigned long long)fsp_st->st_ex_blocks));
511 return false;
514 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
515 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
516 "stat_ex.%s differs: "
517 "cookie:%llu != stat:%llu, "
518 "denying durable reconnect\n",
519 name,
520 "st_ex_flags",
521 (unsigned long long)cookie_st->st_ex_flags,
522 (unsigned long long)fsp_st->st_ex_flags));
523 return false;
526 if (cookie_st->st_ex_mask != fsp_st->st_ex_mask) {
527 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
528 "stat_ex.%s differs: "
529 "cookie:%llu != stat:%llu, "
530 "denying durable reconnect\n",
531 name,
532 "st_ex_mask",
533 (unsigned long long)cookie_st->st_ex_mask,
534 (unsigned long long)fsp_st->st_ex_mask));
535 return false;
538 return true;
541 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
542 struct smb_request *smb1req,
543 struct smbXsrv_open *op,
544 const DATA_BLOB old_cookie,
545 TALLOC_CTX *mem_ctx,
546 files_struct **result,
547 DATA_BLOB *new_cookie)
549 struct share_mode_lock *lck;
550 struct share_mode_entry *e;
551 struct files_struct *fsp = NULL;
552 NTSTATUS status;
553 bool ok;
554 int ret;
555 int flags = 0;
556 struct file_id file_id;
557 struct smb_filename *smb_fname = NULL;
558 enum ndr_err_code ndr_err;
559 struct vfs_default_durable_cookie cookie;
560 DATA_BLOB new_cookie_blob = data_blob_null;
562 *result = NULL;
563 *new_cookie = data_blob_null;
565 if (!lp_durable_handles(SNUM(conn))) {
566 return NT_STATUS_NOT_SUPPORTED;
570 * the checks for kernel oplocks
571 * and similar things are done
572 * in the vfs_default_durable_cookie()
573 * call below.
576 ZERO_STRUCT(cookie);
578 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
579 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
580 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
581 status = ndr_map_error2ntstatus(ndr_err);
582 return status;
585 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
586 return NT_STATUS_INVALID_PARAMETER;
589 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
590 return NT_STATUS_INVALID_PARAMETER;
593 if (!cookie.allow_reconnect) {
594 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
597 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
598 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
601 /* Create an smb_filename with stream_name == NULL. */
602 smb_fname = synthetic_smb_fname(talloc_tos(),
603 cookie.base_name,
604 NULL,
605 NULL,
607 if (smb_fname == NULL) {
608 return NT_STATUS_NO_MEMORY;
611 ret = SMB_VFS_LSTAT(conn, smb_fname);
612 if (ret == -1) {
613 status = map_nt_error_from_unix_common(errno);
614 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
615 smb_fname_str_dbg(smb_fname),
616 nt_errstr(status)));
617 return status;
620 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
621 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
624 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
625 if (!file_id_equal(&cookie.id, &file_id)) {
626 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
630 * 1. check entry in locking.tdb
633 lck = get_existing_share_mode_lock(mem_ctx, file_id);
634 if (lck == NULL) {
635 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
636 "not obtained from db\n"));
637 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
640 if (lck->data->num_share_modes == 0) {
641 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
642 "entry in existing share mode lock\n"));
643 TALLOC_FREE(lck);
644 return NT_STATUS_INTERNAL_DB_ERROR;
647 if (lck->data->num_share_modes > 1) {
649 * It can't be durable if there is more than one handle
650 * on the file.
652 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
653 "share-mode entry - can not be durable\n"));
654 TALLOC_FREE(lck);
655 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
658 e = &lck->data->share_modes[0];
660 if (!server_id_is_disconnected(&e->pid)) {
661 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
662 "reconnect for handle that was not marked "
663 "disconnected (e.g. smbd or cluster node died)\n"));
664 TALLOC_FREE(lck);
665 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
668 if (e->share_file_id != op->global->open_persistent_id) {
669 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
670 "share_file_id changed %llu != %llu"
671 "(e.g. another client had opened the file)\n",
672 (unsigned long long)e->share_file_id,
673 (unsigned long long)op->global->open_persistent_id));
674 TALLOC_FREE(lck);
675 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
678 if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
679 !CAN_WRITE(conn))
681 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
682 "share[%s] is not writeable anymore\n",
683 lp_servicename(talloc_tos(), SNUM(conn))));
684 TALLOC_FREE(lck);
685 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
689 * 2. proceed with opening file
692 status = fsp_new(conn, conn, &fsp);
693 if (!NT_STATUS_IS_OK(status)) {
694 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
695 "new fsp: %s\n", nt_errstr(status)));
696 TALLOC_FREE(lck);
697 return status;
700 fsp->fh->private_options = e->private_options;
701 fsp->fh->gen_id = smbXsrv_open_hash(op);
702 fsp->file_id = file_id;
703 fsp->file_pid = smb1req->smbpid;
704 fsp->vuid = smb1req->vuid;
705 fsp->open_time = e->time;
706 fsp->access_mask = e->access_mask;
707 fsp->share_access = e->share_access;
708 fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
709 fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
710 fsp->fnum = op->local_id;
713 * TODO:
714 * Do we need to store the modified flag in the DB?
716 fsp->modified = false;
718 * no durables for directories
720 fsp->is_directory = false;
722 * For normal files, can_lock == !is_directory
724 fsp->can_lock = true;
726 * We do not support aio write behind for smb2
728 fsp->aio_write_behind = false;
729 fsp->oplock_type = e->op_type;
731 if (fsp->oplock_type == LEASE_OPLOCK) {
732 struct share_mode_lease *l = &lck->data->leases[e->lease_idx];
733 struct smb2_lease_key key;
735 key.data[0] = l->lease_key.data[0];
736 key.data[1] = l->lease_key.data[1];
738 fsp->lease = find_fsp_lease(fsp, &key, l);
739 if (fsp->lease == NULL) {
740 TALLOC_FREE(lck);
741 fsp_free(fsp);
742 return NT_STATUS_NO_MEMORY;
746 * Ensure the existing client guid matches the
747 * stored one in the share_mode_lease.
749 if (!GUID_equal(fsp_client_guid(fsp),
750 &l->client_guid)) {
751 TALLOC_FREE(lck);
752 fsp_free(fsp);
753 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
757 fsp->initial_allocation_size = cookie.initial_allocation_size;
758 fsp->fh->position_information = cookie.position_information;
759 fsp->update_write_time_triggered = cookie.update_write_time_triggered;
760 fsp->update_write_time_on_close = cookie.update_write_time_on_close;
761 fsp->write_time_forced = cookie.write_time_forced;
762 fsp->close_write_time = cookie.close_write_time;
764 status = fsp_set_smb_fname(fsp, smb_fname);
765 if (!NT_STATUS_IS_OK(status)) {
766 TALLOC_FREE(lck);
767 fsp_free(fsp);
768 DEBUG(0, ("vfs_default_durable_reconnect: "
769 "fsp_set_smb_fname failed: %s\n",
770 nt_errstr(status)));
771 return status;
774 op->compat = fsp;
775 fsp->op = op;
777 e->pid = messaging_server_id(conn->sconn->msg_ctx);
778 e->op_mid = smb1req->mid;
779 e->share_file_id = fsp->fh->gen_id;
781 ok = brl_reconnect_disconnected(fsp);
782 if (!ok) {
783 status = NT_STATUS_INTERNAL_ERROR;
784 DEBUG(1, ("vfs_default_durable_reconnect: "
785 "failed to reopen brlocks: %s\n",
786 nt_errstr(status)));
787 TALLOC_FREE(lck);
788 op->compat = NULL;
789 fsp_free(fsp);
790 return status;
794 * TODO: properly calculate open flags
796 if (fsp->can_write && fsp->can_read) {
797 flags = O_RDWR;
798 } else if (fsp->can_write) {
799 flags = O_WRONLY;
800 } else if (fsp->can_read) {
801 flags = O_RDONLY;
804 status = fd_open(conn, fsp, flags, 0 /* mode */);
805 if (!NT_STATUS_IS_OK(status)) {
806 TALLOC_FREE(lck);
807 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
808 "file: %s\n", nt_errstr(status)));
809 op->compat = NULL;
810 fsp_free(fsp);
811 return status;
815 * We now check the stat info stored in the cookie against
816 * the current stat data from the file we just opened.
817 * If any detail differs, we deny the durable reconnect,
818 * because in that case it is very likely that someone
819 * opened the file while the handle was disconnected,
820 * which has to be interpreted as an oplock break.
823 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
824 if (ret == -1) {
825 status = map_nt_error_from_unix_common(errno);
826 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
827 smb_fname_str_dbg(smb_fname),
828 nt_errstr(status)));
829 ret = SMB_VFS_CLOSE(fsp);
830 if (ret == -1) {
831 DEBUG(0, ("vfs_default_durable_reconnect: "
832 "SMB_VFS_CLOSE failed (%s) - leaking file "
833 "descriptor\n", strerror(errno)));
835 TALLOC_FREE(lck);
836 op->compat = NULL;
837 fsp_free(fsp);
838 return status;
841 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
842 ret = SMB_VFS_CLOSE(fsp);
843 if (ret == -1) {
844 DEBUG(0, ("vfs_default_durable_reconnect: "
845 "SMB_VFS_CLOSE failed (%s) - leaking file "
846 "descriptor\n", strerror(errno)));
848 TALLOC_FREE(lck);
849 op->compat = NULL;
850 fsp_free(fsp);
851 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
854 file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
855 if (!file_id_equal(&cookie.id, &file_id)) {
856 ret = SMB_VFS_CLOSE(fsp);
857 if (ret == -1) {
858 DEBUG(0, ("vfs_default_durable_reconnect: "
859 "SMB_VFS_CLOSE failed (%s) - leaking file "
860 "descriptor\n", strerror(errno)));
862 TALLOC_FREE(lck);
863 op->compat = NULL;
864 fsp_free(fsp);
865 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
868 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
869 &fsp->fsp_name->st,
870 fsp_str_dbg(fsp));
871 if (!ok) {
872 ret = SMB_VFS_CLOSE(fsp);
873 if (ret == -1) {
874 DEBUG(0, ("vfs_default_durable_reconnect: "
875 "SMB_VFS_CLOSE failed (%s) - leaking file "
876 "descriptor\n", strerror(errno)));
878 TALLOC_FREE(lck);
879 op->compat = NULL;
880 fsp_free(fsp);
881 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
884 status = set_file_oplock(fsp);
885 if (!NT_STATUS_IS_OK(status)) {
886 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
887 "after opening file: %s\n", nt_errstr(status)));
888 ret = SMB_VFS_CLOSE(fsp);
889 if (ret == -1) {
890 DEBUG(0, ("vfs_default_durable_reconnect: "
891 "SMB_VFS_CLOSE failed (%s) - leaking file "
892 "descriptor\n", strerror(errno)));
894 TALLOC_FREE(lck);
895 op->compat = NULL;
896 fsp_free(fsp);
897 return status;
900 status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
901 if (!NT_STATUS_IS_OK(status)) {
902 TALLOC_FREE(lck);
903 DEBUG(1, ("vfs_default_durable_reconnect: "
904 "vfs_default_durable_cookie - %s\n",
905 nt_errstr(status)));
906 op->compat = NULL;
907 fsp_free(fsp);
908 return status;
911 smb1req->chain_fsp = fsp;
912 smb1req->smb2req->compat_chain_fsp = fsp;
914 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
915 fsp_str_dbg(fsp)));
918 * release the sharemode lock: this writes the changes
920 lck->data->modified = true;
921 TALLOC_FREE(lck);
923 *result = fsp;
924 *new_cookie = new_cookie_blob;
926 return NT_STATUS_OK;