4c6ff67153c910403831f10940eecdc8d7d46e5e
[samba.git] / source3 / smbd / durable.c
1 /*
2    Unix SMB/CIFS implementation.
3    Durable Handle default VFS implementation
4
5    Copyright (C) Stefan Metzmacher 2012
6    Copyright (C) Michael Adam 2012
7    Copyright (C) Volker Lendecke 2012
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "libcli/security/security.h"
28 #include "messages.h"
29 #include "librpc/gen_ndr/ndr_open_files.h"
30 #include "serverid.h"
31 #include "fake_file.h"
32
33 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
34                                     TALLOC_CTX *mem_ctx,
35                                     DATA_BLOB *cookie_blob)
36 {
37         struct connection_struct *conn = fsp->conn;
38         enum ndr_err_code ndr_err;
39         struct vfs_default_durable_cookie cookie;
40
41         if (!lp_durable_handles(SNUM(conn))) {
42                 return NT_STATUS_NOT_SUPPORTED;
43         }
44
45         if (lp_kernel_share_modes(SNUM(conn))) {
46                 /*
47                  * We do not support durable handles
48                  * if kernel share modes (flocks) are used
49                  */
50                 return NT_STATUS_NOT_SUPPORTED;
51         }
52
53         if (lp_kernel_oplocks(SNUM(conn))) {
54                 /*
55                  * We do not support durable handles
56                  * if kernel oplocks are used
57                  */
58                 return NT_STATUS_NOT_SUPPORTED;
59         }
60
61         if ((fsp->current_lock_count > 0) &&
62             lp_posix_locking(fsp->conn->params))
63         {
64                 /*
65                  * We do not support durable handles
66                  * if the handle has posix locks.
67                  */
68                 return NT_STATUS_NOT_SUPPORTED;
69         }
70
71         if (fsp->is_directory) {
72                 return NT_STATUS_NOT_SUPPORTED;
73         }
74
75         if (fsp->fh->fd == -1) {
76                 return NT_STATUS_NOT_SUPPORTED;
77         }
78
79         if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
80                 /*
81                  * We do not support durable handles
82                  * on streams for now.
83                  */
84                 return NT_STATUS_NOT_SUPPORTED;
85         }
86
87         if (is_fake_file(fsp->fsp_name)) {
88                 /*
89                  * We do not support durable handles
90                  * on fake files.
91                  */
92                 return NT_STATUS_NOT_SUPPORTED;
93         }
94
95         ZERO_STRUCT(cookie);
96         cookie.allow_reconnect = false;
97         cookie.id = fsp->file_id;
98         cookie.servicepath = conn->connectpath;
99         cookie.base_name = fsp->fsp_name->base_name;
100         cookie.initial_allocation_size = fsp->initial_allocation_size;
101         cookie.position_information = fsp->fh->position_information;
102         cookie.update_write_time_triggered = fsp->update_write_time_triggered;
103         cookie.update_write_time_on_close = fsp->update_write_time_on_close;
104         cookie.write_time_forced = fsp->write_time_forced;
105         cookie.close_write_time = fsp->close_write_time;
106
107         cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
108         cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
109         cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
110         cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
111         cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
112         cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
113         cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
114         cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
115         cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
116         cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
117         cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
118         cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
119         cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
120         cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
121         cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
122         cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
123         cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
124         cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
125
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;
131         }
132
133         return NT_STATUS_OK;
134 }
135
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)
140 {
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;
148
149         *new_cookie = data_blob_null;
150
151         ZERO_STRUCT(cookie);
152
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;
158         }
159
160         if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
161                 return NT_STATUS_INVALID_PARAMETER;
162         }
163
164         if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
165                 return NT_STATUS_INVALID_PARAMETER;
166         }
167
168         if (!file_id_equal(&fsp->file_id, &cookie.id)) {
169                 return NT_STATUS_INVALID_PARAMETER;
170         }
171
172         if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
173                 return NT_STATUS_NOT_SUPPORTED;
174         }
175
176         if (fsp->num_pending_break_messages > 0) {
177                 return NT_STATUS_NOT_SUPPORTED;
178         }
179
180         /*
181          * For now let it be simple and do not keep
182          * delete on close files durable open
183          */
184         if (fsp->initial_delete_on_close) {
185                 return NT_STATUS_NOT_SUPPORTED;
186         }
187         if (fsp->delete_on_close) {
188                 return NT_STATUS_NOT_SUPPORTED;
189         }
190
191         if (!VALID_STAT(fsp->fsp_name->st)) {
192                 return NT_STATUS_NOT_SUPPORTED;
193         }
194
195         if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
196                 return NT_STATUS_NOT_SUPPORTED;
197         }
198
199         /* Ensure any pending write time updates are done. */
200         if (fsp->update_write_time_event) {
201                 update_write_time_handler(fsp->conn->sconn->ev_ctx,
202                                         fsp->update_write_time_event,
203                                         timeval_current(),
204                                         (void *)fsp);
205         }
206
207         /*
208          * The above checks are done in mark_share_mode_disconnected() too
209          * but we want to avoid getting the lock if possible
210          */
211         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
212         if (lck != NULL) {
213                 struct smb_file_time ft;
214
215                 ZERO_STRUCT(ft);
216
217                 if (fsp->write_time_forced) {
218                         ft.mtime = lck->data->changed_write_time;
219                 } else if (fsp->update_write_time_on_close) {
220                         if (null_timespec(fsp->close_write_time)) {
221                                 ft.mtime = timespec_current();
222                         } else {
223                                 ft.mtime = fsp->close_write_time;
224                         }
225                 }
226
227                 if (!null_timespec(ft.mtime)) {
228                         round_timespec(conn->ts_res, &ft.mtime);
229                         file_ntimes(conn, fsp->fsp_name, &ft);
230                 }
231
232                 ok = mark_share_mode_disconnected(lck, fsp);
233                 if (!ok) {
234                         TALLOC_FREE(lck);
235                 }
236         }
237         if (lck != NULL) {
238                 ok = brl_mark_disconnected(fsp);
239                 if (!ok) {
240                         TALLOC_FREE(lck);
241                 }
242         }
243         if (lck == NULL) {
244                 return NT_STATUS_NOT_SUPPORTED;
245         }
246         TALLOC_FREE(lck);
247
248         status = vfs_stat_fsp(fsp);
249         if (!NT_STATUS_IS_OK(status)) {
250                 return status;
251         }
252
253         ZERO_STRUCT(cookie);
254         cookie.allow_reconnect = true;
255         cookie.id = fsp->file_id;
256         cookie.servicepath = conn->connectpath;
257         cookie.base_name = fsp->fsp_name->base_name;
258         cookie.initial_allocation_size = fsp->initial_allocation_size;
259         cookie.position_information = fsp->fh->position_information;
260         cookie.update_write_time_triggered = fsp->update_write_time_triggered;
261         cookie.update_write_time_on_close = fsp->update_write_time_on_close;
262         cookie.write_time_forced = fsp->write_time_forced;
263         cookie.close_write_time = fsp->close_write_time;
264
265         cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
266         cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
267         cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
268         cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
269         cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
270         cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
271         cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
272         cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
273         cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
274         cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
275         cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
276         cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
277         cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
278         cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
279         cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
280         cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
281         cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
282         cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
283
284         ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
285                         (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
286         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
287                 status = ndr_map_error2ntstatus(ndr_err);
288                 return status;
289         }
290
291         status = fd_close(fsp);
292         if (!NT_STATUS_IS_OK(status)) {
293                 data_blob_free(&new_cookie_blob);
294                 return status;
295         }
296
297         *new_cookie = new_cookie_blob;
298         return NT_STATUS_OK;
299 }
300
301 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
302                                        struct smb_request *smb1req,
303                                        struct smbXsrv_open *op,
304                                        const DATA_BLOB old_cookie,
305                                        TALLOC_CTX *mem_ctx,
306                                        files_struct **result,
307                                        DATA_BLOB *new_cookie)
308 {
309         struct share_mode_lock *lck;
310         struct share_mode_entry *e;
311         struct files_struct *fsp = NULL;
312         NTSTATUS status;
313         bool ok;
314         int ret;
315         int flags = 0;
316         struct file_id file_id;
317         struct smb_filename *smb_fname = NULL;
318         enum ndr_err_code ndr_err;
319         struct vfs_default_durable_cookie cookie;
320         DATA_BLOB new_cookie_blob = data_blob_null;
321
322         *result = NULL;
323         *new_cookie = data_blob_null;
324
325         if (!lp_durable_handles(SNUM(conn))) {
326                 return NT_STATUS_NOT_SUPPORTED;
327         }
328
329         /*
330          * the checks for kernel oplocks
331          * and similar things are done
332          * in the vfs_default_durable_cookie()
333          * call below.
334          */
335
336         ZERO_STRUCT(cookie);
337
338         ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
339                         (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
340         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
341                 status = ndr_map_error2ntstatus(ndr_err);
342                 return status;
343         }
344
345         if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
346                 return NT_STATUS_INVALID_PARAMETER;
347         }
348
349         if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
350                 return NT_STATUS_INVALID_PARAMETER;
351         }
352
353         if (!cookie.allow_reconnect) {
354                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
355         }
356
357         if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
358                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
359         }
360
361         /* Create an smb_filename with stream_name == NULL. */
362         status = create_synthetic_smb_fname(talloc_tos(),
363                                             cookie.base_name,
364                                             NULL, NULL,
365                                             &smb_fname);
366         if (!NT_STATUS_IS_OK(status)) {
367                 return status;
368         }
369
370         ret = SMB_VFS_LSTAT(conn, smb_fname);
371         if (ret == -1) {
372                 status = map_nt_error_from_unix_common(errno);
373                 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
374                           smb_fname_str_dbg(smb_fname),
375                           nt_errstr(status)));
376                 return status;
377         }
378
379         if (!S_ISREG(smb_fname->st.st_ex_mode)) {
380                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
381         }
382
383         file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
384         if (!file_id_equal(&cookie.id, &file_id)) {
385                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
386         }
387
388         /*
389          * 1. check entry in locking.tdb
390          */
391
392         lck = get_existing_share_mode_lock(mem_ctx, file_id);
393         if (lck == NULL) {
394                 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
395                            "not obtained from db\n"));
396                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
397         }
398
399         if (lck->data->num_share_modes == 0) {
400                 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
401                           "entry in existing share mode lock\n"));
402                 TALLOC_FREE(lck);
403                 return NT_STATUS_INTERNAL_DB_ERROR;
404         }
405
406         if (lck->data->num_share_modes > 1) {
407                 /*
408                  * It can't be durable if there is more than one handle
409                  * on the file.
410                  */
411                 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
412                           "share-mode entry - can not be durable\n"));
413                 TALLOC_FREE(lck);
414                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
415         }
416
417         e = &lck->data->share_modes[0];
418
419         if (!server_id_is_disconnected(&e->pid)) {
420                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
421                           "reconnect for handle that was not marked "
422                           "disconnected (e.g. smbd or cluster node died)\n"));
423                 TALLOC_FREE(lck);
424                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
425         }
426
427         if (e->share_file_id != op->global->open_persistent_id) {
428                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
429                           "share_file_id changed %llu != %llu"
430                           "(e.g. another client had opened the file)\n",
431                           (unsigned long long)e->share_file_id,
432                           (unsigned long long)op->global->open_persistent_id));
433                 TALLOC_FREE(lck);
434                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
435         }
436
437         if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
438             !CAN_WRITE(conn))
439         {
440                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
441                           "share[%s] is not writeable anymore\n",
442                           lp_servicename(talloc_tos(), SNUM(conn))));
443                 TALLOC_FREE(lck);
444                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
445         }
446
447         /*
448          * TODO:
449          * add scavenger timer functionality
450          *
451          * For now we always allow the reconnect
452          */
453 #if 0
454         expire_time = op->global->disconnect_time;
455         expire_time += NTTIME_MAGIC(op->global->durable_timeout_msec);
456         if (expire < now) {
457                 //TODO reopen and close before telling the client...
458         }
459 #endif
460
461         /*
462          * 2. proceed with opening file
463          */
464
465         status = fsp_new(conn, conn, &fsp);
466         if (!NT_STATUS_IS_OK(status)) {
467                 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
468                           "new fsp: %s\n", nt_errstr(status)));
469                 TALLOC_FREE(lck);
470                 return status;
471         }
472
473         fsp->fh->private_options = e->private_options;
474         fsp->fh->gen_id = smbXsrv_open_hash(op);
475         fsp->file_id = file_id;
476         fsp->file_pid = smb1req->smbpid;
477         fsp->vuid = smb1req->vuid;
478         fsp->open_time = e->time;
479         fsp->access_mask = e->access_mask;
480         fsp->share_access = e->share_access;
481         fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
482         fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
483
484         /*
485          * TODO:
486          * Do we need to store the modified flag in the DB?
487          * How to handle update_write_time and friends
488          * during a disconnected client on a durable handle?
489          */
490         fsp->modified = false;
491         /*
492          * no durables for directories
493          */
494         fsp->is_directory = false;
495         /*
496          * For normal files, can_lock == !is_directory
497          */
498         fsp->can_lock = true;
499         /*
500          * We do not support aio write behind for smb2
501          */
502         fsp->aio_write_behind = false;
503         fsp->oplock_type = e->op_type;
504
505         fsp->initial_allocation_size = cookie.initial_allocation_size;
506         fsp->fh->position_information = cookie.position_information;
507         fsp->update_write_time_triggered = cookie.update_write_time_triggered;
508         fsp->update_write_time_on_close = cookie.update_write_time_on_close;
509         fsp->write_time_forced = cookie.write_time_forced;
510         fsp->close_write_time = cookie.close_write_time;
511
512         status = fsp_set_smb_fname(fsp, smb_fname);
513         if (!NT_STATUS_IS_OK(status)) {
514                 TALLOC_FREE(lck);
515                 fsp_free(fsp);
516                 DEBUG(0, ("vfs_default_durable_reconnect: "
517                           "fsp_set_smb_fname failed: %s\n",
518                           nt_errstr(status)));
519                 return status;
520         }
521
522         op->compat = fsp;
523         fsp->op = op;
524
525         e->pid = messaging_server_id(conn->sconn->msg_ctx);
526         e->op_mid = smb1req->mid;
527         e->share_file_id = fsp->fh->gen_id;
528
529         ok = brl_reconnect_disconnected(fsp);
530         if (!ok) {
531                 status = NT_STATUS_INTERNAL_ERROR;
532                 DEBUG(1, ("vfs_default_durable_reconnect: "
533                           "failed to reopen brlocks: %s\n",
534                           nt_errstr(status)));
535                 TALLOC_FREE(lck);
536                 op->compat = NULL;
537                 fsp_free(fsp);
538                 return status;
539         }
540
541         /*
542          * TODO: properly calculate open flags
543          */
544         if (fsp->can_write && fsp->can_read) {
545                 flags = O_RDWR;
546         } else if (fsp->can_write) {
547                 flags = O_WRONLY;
548         } else if (fsp->can_read) {
549                 flags = O_RDONLY;
550         }
551
552         status = fd_open(conn, fsp, flags, 0 /* mode */);
553         if (!NT_STATUS_IS_OK(status)) {
554                 TALLOC_FREE(lck);
555                 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
556                           "file: %s\n", nt_errstr(status)));
557                 op->compat = NULL;
558                 fsp_free(fsp);
559                 return status;
560         }
561
562         /*
563          * We now check the stat info stored in the cookie against
564          * the current stat data from the file we just opened.
565          * If any detail differs, we deny the durable reconnect,
566          * because in that case it is very likely that someone
567          * opened the file while the handle was disconnected,
568          * which has to be interpreted as an oplock break.
569          */
570
571         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
572         if (ret == -1) {
573                 status = map_nt_error_from_unix_common(errno);
574                 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
575                           smb_fname_str_dbg(smb_fname),
576                           nt_errstr(status)));
577                 ret = SMB_VFS_CLOSE(fsp);
578                 if (ret == -1) {
579                         DEBUG(0, ("vfs_default_durable_reconnect: "
580                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
581                                   "descriptor\n", strerror(errno)));
582                 }
583                 TALLOC_FREE(lck);
584                 op->compat = NULL;
585                 fsp_free(fsp);
586                 return status;
587         }
588
589         if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
590                 ret = SMB_VFS_CLOSE(fsp);
591                 if (ret == -1) {
592                         DEBUG(0, ("vfs_default_durable_reconnect: "
593                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
594                                   "descriptor\n", strerror(errno)));
595                 }
596                 TALLOC_FREE(lck);
597                 op->compat = NULL;
598                 fsp_free(fsp);
599                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
600         }
601
602         file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
603         if (!file_id_equal(&cookie.id, &file_id)) {
604                 ret = SMB_VFS_CLOSE(fsp);
605                 if (ret == -1) {
606                         DEBUG(0, ("vfs_default_durable_reconnect: "
607                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
608                                   "descriptor\n", strerror(errno)));
609                 }
610                 TALLOC_FREE(lck);
611                 op->compat = NULL;
612                 fsp_free(fsp);
613                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
614         }
615
616         if (cookie.stat_info.st_ex_dev != fsp->fsp_name->st.st_ex_dev) {
617                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
618                           "stat_ex.%s differs: "
619                           "cookie:%llu != stat:%llu, "
620                           "denying durable reconnect\n",
621                           fsp_str_dbg(fsp),
622                           "st_ex_dev",
623                           (unsigned long long)cookie.stat_info.st_ex_dev,
624                           (unsigned long long)fsp->fsp_name->st.st_ex_dev));
625                 ret = SMB_VFS_CLOSE(fsp);
626                 if (ret == -1) {
627                         DEBUG(0, ("vfs_default_durable_reconnect: "
628                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
629                                   "descriptor\n", strerror(errno)));
630                 }
631                 TALLOC_FREE(lck);
632                 op->compat = NULL;
633                 fsp_free(fsp);
634                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
635         }
636
637         if (cookie.stat_info.st_ex_ino != fsp->fsp_name->st.st_ex_ino) {
638                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
639                           "stat_ex.%s differs: "
640                           "cookie:%llu != stat:%llu, "
641                           "denying durable reconnect\n",
642                           fsp_str_dbg(fsp),
643                           "st_ex_ino",
644                           (unsigned long long)cookie.stat_info.st_ex_ino,
645                           (unsigned long long)fsp->fsp_name->st.st_ex_ino));
646                 ret = SMB_VFS_CLOSE(fsp);
647                 if (ret == -1) {
648                         DEBUG(0, ("vfs_default_durable_reconnect: "
649                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
650                                   "descriptor\n", strerror(errno)));
651                 }
652                 TALLOC_FREE(lck);
653                 op->compat = NULL;
654                 fsp_free(fsp);
655                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
656         }
657
658         if (cookie.stat_info.st_ex_mode != fsp->fsp_name->st.st_ex_mode) {
659                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
660                           "stat_ex.%s differs: "
661                           "cookie:%llu != stat:%llu, "
662                           "denying durable reconnect\n",
663                           fsp_str_dbg(fsp),
664                           "st_ex_mode",
665                           (unsigned long long)cookie.stat_info.st_ex_mode,
666                           (unsigned long long)fsp->fsp_name->st.st_ex_mode));
667                 ret = SMB_VFS_CLOSE(fsp);
668                 if (ret == -1) {
669                         DEBUG(0, ("vfs_default_durable_reconnect: "
670                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
671                                   "descriptor\n", strerror(errno)));
672                 }
673                 TALLOC_FREE(lck);
674                 op->compat = NULL;
675                 fsp_free(fsp);
676                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
677         }
678
679         if (cookie.stat_info.st_ex_nlink != fsp->fsp_name->st.st_ex_nlink) {
680                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
681                           "stat_ex.%s differs: "
682                           "cookie:%llu != stat:%llu, "
683                           "denying durable reconnect\n",
684                           fsp_str_dbg(fsp),
685                           "st_ex_nlink",
686                           (unsigned long long)cookie.stat_info.st_ex_nlink,
687                           (unsigned long long)fsp->fsp_name->st.st_ex_nlink));
688                 ret = SMB_VFS_CLOSE(fsp);
689                 if (ret == -1) {
690                         DEBUG(0, ("vfs_default_durable_reconnect: "
691                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
692                                   "descriptor\n", strerror(errno)));
693                 }
694                 TALLOC_FREE(lck);
695                 op->compat = NULL;
696                 fsp_free(fsp);
697                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
698         }
699
700         if (cookie.stat_info.st_ex_uid != fsp->fsp_name->st.st_ex_uid) {
701                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
702                           "stat_ex.%s differs: "
703                           "cookie:%llu != stat:%llu, "
704                           "denying durable reconnect\n",
705                           fsp_str_dbg(fsp),
706                           "st_ex_uid",
707                           (unsigned long long)cookie.stat_info.st_ex_uid,
708                           (unsigned long long)fsp->fsp_name->st.st_ex_uid));
709                 ret = SMB_VFS_CLOSE(fsp);
710                 if (ret == -1) {
711                         DEBUG(0, ("vfs_default_durable_reconnect: "
712                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
713                                   "descriptor\n", strerror(errno)));
714                 }
715                 TALLOC_FREE(lck);
716                 op->compat = NULL;
717                 fsp_free(fsp);
718                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
719         }
720
721         if (cookie.stat_info.st_ex_gid != fsp->fsp_name->st.st_ex_gid) {
722                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
723                           "stat_ex.%s differs: "
724                           "cookie:%llu != stat:%llu, "
725                           "denying durable reconnect\n",
726                           fsp_str_dbg(fsp),
727                           "st_ex_gid",
728                           (unsigned long long)cookie.stat_info.st_ex_gid,
729                           (unsigned long long)fsp->fsp_name->st.st_ex_gid));
730                 ret = SMB_VFS_CLOSE(fsp);
731                 if (ret == -1) {
732                         DEBUG(0, ("vfs_default_durable_reconnect: "
733                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
734                                   "descriptor\n", strerror(errno)));
735                 }
736                 TALLOC_FREE(lck);
737                 op->compat = NULL;
738                 fsp_free(fsp);
739                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
740         }
741
742         if (cookie.stat_info.st_ex_rdev != fsp->fsp_name->st.st_ex_rdev) {
743                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
744                           "stat_ex.%s differs: "
745                           "cookie:%llu != stat:%llu, "
746                           "denying durable reconnect\n",
747                           fsp_str_dbg(fsp),
748                           "st_ex_rdev",
749                           (unsigned long long)cookie.stat_info.st_ex_rdev,
750                           (unsigned long long)fsp->fsp_name->st.st_ex_rdev));
751                 ret = SMB_VFS_CLOSE(fsp);
752                 if (ret == -1) {
753                         DEBUG(0, ("vfs_default_durable_reconnect: "
754                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
755                                   "descriptor\n", strerror(errno)));
756                 }
757                 TALLOC_FREE(lck);
758                 op->compat = NULL;
759                 fsp_free(fsp);
760                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
761         }
762
763         if (cookie.stat_info.st_ex_size != fsp->fsp_name->st.st_ex_size) {
764                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
765                           "stat_ex.%s differs: "
766                           "cookie:%llu != stat:%llu, "
767                           "denying durable reconnect\n",
768                           fsp_str_dbg(fsp),
769                           "st_ex_size",
770                           (unsigned long long)cookie.stat_info.st_ex_size,
771                           (unsigned long long)fsp->fsp_name->st.st_ex_size));
772                 ret = SMB_VFS_CLOSE(fsp);
773                 if (ret == -1) {
774                         DEBUG(0, ("vfs_default_durable_reconnect: "
775                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
776                                   "descriptor\n", strerror(errno)));
777                 }
778                 TALLOC_FREE(lck);
779                 op->compat = NULL;
780                 fsp_free(fsp);
781                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
782         }
783
784         ret = timespec_compare(&cookie.stat_info.st_ex_atime,
785                                &fsp->fsp_name->st.st_ex_atime);
786         if (ret != 0) {
787                 struct timeval tc, ts;
788                 tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_atime);
789                 ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_atime);
790
791                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
792                           "stat_ex.%s differs: "
793                           "cookie:'%s' != stat:'%s', "
794                           "denying durable reconnect\n",
795                           fsp_str_dbg(fsp),
796                           "st_ex_atime",
797                           timeval_string(talloc_tos(), &tc, true),
798                           timeval_string(talloc_tos(), &ts, true)));
799                 ret = SMB_VFS_CLOSE(fsp);
800                 if (ret == -1) {
801                         DEBUG(0, ("vfs_default_durable_reconnect: "
802                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
803                                   "descriptor\n", strerror(errno)));
804                 }
805                 TALLOC_FREE(lck);
806                 op->compat = NULL;
807                 fsp_free(fsp);
808                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
809         }
810
811         ret = timespec_compare(&cookie.stat_info.st_ex_mtime,
812                                &fsp->fsp_name->st.st_ex_mtime);
813         if (ret != 0) {
814                 struct timeval tc, ts;
815                 tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_mtime);
816                 ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_mtime);
817
818                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
819                           "stat_ex.%s differs: "
820                           "cookie:'%s' != stat:'%s', "
821                           "denying durable reconnect\n",
822                           fsp_str_dbg(fsp),
823                           "st_ex_mtime",
824                           timeval_string(talloc_tos(), &tc, true),
825                           timeval_string(talloc_tos(), &ts, true)));
826                 ret = SMB_VFS_CLOSE(fsp);
827                 if (ret == -1) {
828                         DEBUG(0, ("vfs_default_durable_reconnect: "
829                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
830                                   "descriptor\n", strerror(errno)));
831                 }
832                 TALLOC_FREE(lck);
833                 op->compat = NULL;
834                 fsp_free(fsp);
835                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
836         }
837
838         ret = timespec_compare(&cookie.stat_info.st_ex_ctime,
839                                &fsp->fsp_name->st.st_ex_ctime);
840         if (ret != 0) {
841                 struct timeval tc, ts;
842                 tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_ctime);
843                 ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_ctime);
844
845                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
846                           "stat_ex.%s differs: "
847                           "cookie:'%s' != stat:'%s', "
848                           "denying durable reconnect\n",
849                           fsp_str_dbg(fsp),
850                           "st_ex_ctime",
851                           timeval_string(talloc_tos(), &tc, true),
852                           timeval_string(talloc_tos(), &ts, true)));
853                 ret = SMB_VFS_CLOSE(fsp);
854                 if (ret == -1) {
855                         DEBUG(0, ("vfs_default_durable_reconnect: "
856                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
857                                   "descriptor\n", strerror(errno)));
858                 }
859                 TALLOC_FREE(lck);
860                 op->compat = NULL;
861                 fsp_free(fsp);
862                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
863         }
864
865         ret = timespec_compare(&cookie.stat_info.st_ex_btime,
866                                &fsp->fsp_name->st.st_ex_btime);
867         if (ret != 0) {
868                 struct timeval tc, ts;
869                 tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_btime);
870                 ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_btime);
871
872                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
873                           "stat_ex.%s differs: "
874                           "cookie:'%s' != stat:'%s', "
875                           "denying durable reconnect\n",
876                           fsp_str_dbg(fsp),
877                           "st_ex_btime",
878                           timeval_string(talloc_tos(), &tc, true),
879                           timeval_string(talloc_tos(), &ts, true)));
880                 ret = SMB_VFS_CLOSE(fsp);
881                 if (ret == -1) {
882                         DEBUG(0, ("vfs_default_durable_reconnect: "
883                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
884                                   "descriptor\n", strerror(errno)));
885                 }
886                 TALLOC_FREE(lck);
887                 op->compat = NULL;
888                 fsp_free(fsp);
889                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
890         }
891
892         if (cookie.stat_info.st_ex_calculated_birthtime !=
893             fsp->fsp_name->st.st_ex_calculated_birthtime)
894         {
895                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
896                           "stat_ex.%s differs: "
897                           "cookie:%llu != stat:%llu, "
898                           "denying durable reconnect\n",
899                           fsp_str_dbg(fsp),
900                           "st_ex_calculated_birthtime",
901                           (unsigned long long)cookie.stat_info.st_ex_calculated_birthtime,
902                           (unsigned long long)fsp->fsp_name->st.st_ex_calculated_birthtime));
903                 ret = SMB_VFS_CLOSE(fsp);
904                 if (ret == -1) {
905                         DEBUG(0, ("vfs_default_durable_reconnect: "
906                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
907                                   "descriptor\n", strerror(errno)));
908                 }
909                 TALLOC_FREE(lck);
910                 op->compat = NULL;
911                 fsp_free(fsp);
912                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
913         }
914
915         if (cookie.stat_info.st_ex_blksize != fsp->fsp_name->st.st_ex_blksize) {
916                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
917                           "stat_ex.%s differs: "
918                           "cookie:%llu != stat:%llu, "
919                           "denying durable reconnect\n",
920                           fsp_str_dbg(fsp),
921                           "st_ex_blksize",
922                           (unsigned long long)cookie.stat_info.st_ex_blksize,
923                           (unsigned long long)fsp->fsp_name->st.st_ex_blksize));
924                 ret = SMB_VFS_CLOSE(fsp);
925                 if (ret == -1) {
926                         DEBUG(0, ("vfs_default_durable_reconnect: "
927                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
928                                   "descriptor\n", strerror(errno)));
929                 }
930                 TALLOC_FREE(lck);
931                 op->compat = NULL;
932                 fsp_free(fsp);
933                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
934         }
935
936         if (cookie.stat_info.st_ex_blocks != fsp->fsp_name->st.st_ex_blocks) {
937                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
938                           "stat_ex.%s differs: "
939                           "cookie:%llu != stat:%llu, "
940                           "denying durable reconnect\n",
941                           fsp_str_dbg(fsp),
942                           "st_ex_blocks",
943                           (unsigned long long)cookie.stat_info.st_ex_blocks,
944                           (unsigned long long)fsp->fsp_name->st.st_ex_blocks));
945                 ret = SMB_VFS_CLOSE(fsp);
946                 if (ret == -1) {
947                         DEBUG(0, ("vfs_default_durable_reconnect: "
948                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
949                                   "descriptor\n", strerror(errno)));
950                 }
951                 TALLOC_FREE(lck);
952                 op->compat = NULL;
953                 fsp_free(fsp);
954                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
955         }
956
957         if (cookie.stat_info.st_ex_flags != fsp->fsp_name->st.st_ex_flags) {
958                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
959                           "stat_ex.%s differs: "
960                           "cookie:%llu != stat:%llu, "
961                           "denying durable reconnect\n",
962                           fsp_str_dbg(fsp),
963                           "st_ex_flags",
964                           (unsigned long long)cookie.stat_info.st_ex_flags,
965                           (unsigned long long)fsp->fsp_name->st.st_ex_flags));
966                 ret = SMB_VFS_CLOSE(fsp);
967                 if (ret == -1) {
968                         DEBUG(0, ("vfs_default_durable_reconnect: "
969                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
970                                   "descriptor\n", strerror(errno)));
971                 }
972                 TALLOC_FREE(lck);
973                 op->compat = NULL;
974                 fsp_free(fsp);
975                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
976         }
977
978         if (cookie.stat_info.st_ex_mask != fsp->fsp_name->st.st_ex_mask) {
979                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
980                           "stat_ex.%s differs: "
981                           "cookie:%llu != stat:%llu, "
982                           "denying durable reconnect\n",
983                           fsp_str_dbg(fsp),
984                           "st_ex_mask",
985                           (unsigned long long)cookie.stat_info.st_ex_mask,
986                           (unsigned long long)fsp->fsp_name->st.st_ex_mask));
987                 ret = SMB_VFS_CLOSE(fsp);
988                 if (ret == -1) {
989                         DEBUG(0, ("vfs_default_durable_reconnect: "
990                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
991                                   "descriptor\n", strerror(errno)));
992                 }
993                 TALLOC_FREE(lck);
994                 op->compat = NULL;
995                 fsp_free(fsp);
996                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
997         }
998
999         if (cookie.stat_info.vfs_private != fsp->fsp_name->st.vfs_private) {
1000                 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
1001                           "stat_ex.%s differs: "
1002                           "cookie:%llu != stat:%llu, "
1003                           "denying durable reconnect\n",
1004                           fsp_str_dbg(fsp),
1005                           "vfs_private",
1006                           (unsigned long long)cookie.stat_info.vfs_private,
1007                           (unsigned long long)fsp->fsp_name->st.vfs_private));
1008                 ret = SMB_VFS_CLOSE(fsp);
1009                 if (ret == -1) {
1010                         DEBUG(0, ("vfs_default_durable_reconnect: "
1011                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
1012                                   "descriptor\n", strerror(errno)));
1013                 }
1014                 TALLOC_FREE(lck);
1015                 op->compat = NULL;
1016                 fsp_free(fsp);
1017                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1018         }
1019
1020         status = set_file_oplock(fsp, e->op_type);
1021         if (!NT_STATUS_IS_OK(status)) {
1022                 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
1023                           "after opening file: %s\n", nt_errstr(status)));
1024                 ret = SMB_VFS_CLOSE(fsp);
1025                 if (ret == -1) {
1026                         DEBUG(0, ("vfs_default_durable_reconnect: "
1027                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
1028                                   "descriptor\n", strerror(errno)));
1029                 }
1030                 TALLOC_FREE(lck);
1031                 op->compat = NULL;
1032                 fsp_free(fsp);
1033                 return status;
1034         }
1035
1036         status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
1037         if (!NT_STATUS_IS_OK(status)) {
1038                 TALLOC_FREE(lck);
1039                 DEBUG(1, ("vfs_default_durable_reconnect: "
1040                           "vfs_default_durable_cookie - %s\n",
1041                           nt_errstr(status)));
1042                 op->compat = NULL;
1043                 fsp_free(fsp);
1044                 return status;
1045         }
1046
1047         smb1req->chain_fsp = fsp;
1048         smb1req->smb2req->compat_chain_fsp = fsp;
1049
1050         DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
1051                    fsp_str_dbg(fsp)));
1052
1053         /*
1054          * release the sharemode lock: this writes the changes
1055          */
1056         lck->data->modified = true;
1057         TALLOC_FREE(lck);
1058
1059         *result = fsp;
1060         *new_cookie = new_cookie_blob;
1061
1062         return NT_STATUS_OK;
1063 }