s3:smbd/durable: remove an extra blank line from vfs_default_durable_reconnect()
[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         ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
108                         (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
109         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
110                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
111                 return status;
112         }
113
114         return NT_STATUS_OK;
115 }
116
117 NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
118                                         const DATA_BLOB old_cookie,
119                                         TALLOC_CTX *mem_ctx,
120                                         DATA_BLOB *new_cookie)
121 {
122         struct connection_struct *conn = fsp->conn;
123         NTSTATUS status;
124         enum ndr_err_code ndr_err;
125         struct vfs_default_durable_cookie cookie;
126         DATA_BLOB new_cookie_blob = data_blob_null;
127         struct share_mode_lock *lck;
128         bool ok;
129
130         *new_cookie = data_blob_null;
131
132         ZERO_STRUCT(cookie);
133
134         ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
135                         (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
136         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137                 status = ndr_map_error2ntstatus(ndr_err);
138                 return status;
139         }
140
141         if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
142                 return NT_STATUS_INVALID_PARAMETER;
143         }
144
145         if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
146                 return NT_STATUS_INVALID_PARAMETER;
147         }
148
149         if (!file_id_equal(&fsp->file_id, &cookie.id)) {
150                 return NT_STATUS_INVALID_PARAMETER;
151         }
152
153         if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
154                 return NT_STATUS_NOT_SUPPORTED;
155         }
156
157         if (fsp->num_pending_break_messages > 0) {
158                 return NT_STATUS_NOT_SUPPORTED;
159         }
160
161         /*
162          * For now let it be simple and do not keep
163          * delete on close files durable open
164          */
165         if (fsp->initial_delete_on_close) {
166                 return NT_STATUS_NOT_SUPPORTED;
167         }
168         if (fsp->delete_on_close) {
169                 return NT_STATUS_NOT_SUPPORTED;
170         }
171
172         if (!VALID_STAT(fsp->fsp_name->st)) {
173                 return NT_STATUS_NOT_SUPPORTED;
174         }
175
176         if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
177                 return NT_STATUS_NOT_SUPPORTED;
178         }
179
180         /* Ensure any pending write time updates are done. */
181         if (fsp->update_write_time_event) {
182                 update_write_time_handler(fsp->conn->sconn->ev_ctx,
183                                         fsp->update_write_time_event,
184                                         timeval_current(),
185                                         (void *)fsp);
186         }
187
188         /*
189          * The above checks are done in mark_share_mode_disconnected() too
190          * but we want to avoid getting the lock if possible
191          */
192         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
193         if (lck != NULL) {
194                 struct smb_file_time ft;
195
196                 ZERO_STRUCT(ft);
197
198                 if (fsp->write_time_forced) {
199                         ft.mtime = lck->data->changed_write_time;
200                 } else if (fsp->update_write_time_on_close) {
201                         if (null_timespec(fsp->close_write_time)) {
202                                 ft.mtime = timespec_current();
203                         } else {
204                                 ft.mtime = fsp->close_write_time;
205                         }
206                 }
207
208                 if (!null_timespec(ft.mtime)) {
209                         round_timespec(conn->ts_res, &ft.mtime);
210                         file_ntimes(conn, fsp->fsp_name, &ft);
211                 }
212
213                 ok = mark_share_mode_disconnected(lck, fsp);
214                 if (!ok) {
215                         TALLOC_FREE(lck);
216                 }
217         }
218         if (lck != NULL) {
219                 ok = brl_mark_disconnected(fsp);
220                 if (!ok) {
221                         TALLOC_FREE(lck);
222                 }
223         }
224         if (lck == NULL) {
225                 return NT_STATUS_NOT_SUPPORTED;
226         }
227         TALLOC_FREE(lck);
228
229         ZERO_STRUCT(cookie);
230         cookie.allow_reconnect = true;
231         cookie.id = fsp->file_id;
232         cookie.servicepath = conn->connectpath;
233         cookie.base_name = fsp->fsp_name->base_name;
234         cookie.initial_allocation_size = fsp->initial_allocation_size;
235         cookie.position_information = fsp->fh->position_information;
236         cookie.update_write_time_triggered = fsp->update_write_time_triggered;
237         cookie.update_write_time_on_close = fsp->update_write_time_on_close;
238         cookie.write_time_forced = fsp->write_time_forced;
239         cookie.close_write_time = fsp->close_write_time;
240
241         ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
242                         (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
243         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
244                 status = ndr_map_error2ntstatus(ndr_err);
245                 return status;
246         }
247
248         status = fd_close(fsp);
249         if (!NT_STATUS_IS_OK(status)) {
250                 data_blob_free(&new_cookie_blob);
251                 return status;
252         }
253
254         *new_cookie = new_cookie_blob;
255         return NT_STATUS_OK;
256 }
257
258 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
259                                        struct smb_request *smb1req,
260                                        struct smbXsrv_open *op,
261                                        const DATA_BLOB old_cookie,
262                                        TALLOC_CTX *mem_ctx,
263                                        files_struct **result,
264                                        DATA_BLOB *new_cookie)
265 {
266         struct share_mode_lock *lck;
267         struct share_mode_entry *e;
268         struct files_struct *fsp = NULL;
269         NTSTATUS status;
270         bool ok;
271         int ret;
272         int flags = 0;
273         struct file_id file_id;
274         struct smb_filename *smb_fname = NULL;
275         enum ndr_err_code ndr_err;
276         struct vfs_default_durable_cookie cookie;
277         DATA_BLOB new_cookie_blob = data_blob_null;
278
279         *result = NULL;
280         *new_cookie = data_blob_null;
281
282         if (!lp_durable_handles(SNUM(conn))) {
283                 return NT_STATUS_NOT_SUPPORTED;
284         }
285
286         /*
287          * the checks for kernel oplocks
288          * and similar things are done
289          * in the vfs_default_durable_cookie()
290          * call below.
291          */
292
293         ZERO_STRUCT(cookie);
294
295         ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
296                         (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
297         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
298                 status = ndr_map_error2ntstatus(ndr_err);
299                 return status;
300         }
301
302         if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
303                 return NT_STATUS_INVALID_PARAMETER;
304         }
305
306         if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
307                 return NT_STATUS_INVALID_PARAMETER;
308         }
309
310         if (!cookie.allow_reconnect) {
311                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
312         }
313
314         if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
315                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
316         }
317
318         /* Create an smb_filename with stream_name == NULL. */
319         status = create_synthetic_smb_fname(talloc_tos(),
320                                             cookie.base_name,
321                                             NULL, NULL,
322                                             &smb_fname);
323         if (!NT_STATUS_IS_OK(status)) {
324                 return status;
325         }
326
327         ret = SMB_VFS_LSTAT(conn, smb_fname);
328         if (ret == -1) {
329                 status = map_nt_error_from_unix_common(errno);
330                 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
331                           smb_fname_str_dbg(smb_fname),
332                           nt_errstr(status)));
333                 return status;
334         }
335
336         if (!S_ISREG(smb_fname->st.st_ex_mode)) {
337                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
338         }
339
340         file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
341         if (!file_id_equal(&cookie.id, &file_id)) {
342                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
343         }
344
345         /*
346          * 1. check entry in locking.tdb
347          */
348
349         lck = get_existing_share_mode_lock(mem_ctx, file_id);
350         if (lck == NULL) {
351                 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
352                            "not obtained from db\n"));
353                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
354         }
355
356         if (lck->data->num_share_modes == 0) {
357                 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
358                           "entry in existing share mode lock\n"));
359                 TALLOC_FREE(lck);
360                 return NT_STATUS_INTERNAL_DB_ERROR;
361         }
362
363         if (lck->data->num_share_modes > 1) {
364                 /*
365                  * It can't be durable if there is more than one handle
366                  * on the file.
367                  */
368                 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
369                           "share-mode entry - can not be durable\n"));
370                 TALLOC_FREE(lck);
371                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
372         }
373
374         e = &lck->data->share_modes[0];
375
376         if (!server_id_is_disconnected(&e->pid)) {
377                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
378                           "reconnect for handle that was not marked "
379                           "disconnected (e.g. smbd or cluster node died)\n"));
380                 TALLOC_FREE(lck);
381                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
382         }
383
384         if (e->share_file_id != op->global->open_persistent_id) {
385                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
386                           "share_file_id changed %llu != %llu"
387                           "(e.g. another client had opened the file)\n",
388                           (unsigned long long)e->share_file_id,
389                           (unsigned long long)op->global->open_persistent_id));
390                 TALLOC_FREE(lck);
391                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
392         }
393
394         if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
395             !CAN_WRITE(conn))
396         {
397                 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
398                           "share[%s] is not writeable anymore\n",
399                           lp_servicename(talloc_tos(), SNUM(conn))));
400                 TALLOC_FREE(lck);
401                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
402         }
403
404         /*
405          * TODO:
406          * add scavenger timer functionality
407          *
408          * For now we always allow the reconnect
409          */
410 #if 0
411         expire_time = op->global->disconnect_time;
412         expire_time += NTTIME_MAGIC(op->global->durable_timeout_msec);
413         if (expire < now) {
414                 //TODO reopen and close before telling the client...
415         }
416 #endif
417
418         /*
419          * 2. proceed with opening file
420          */
421
422         status = fsp_new(conn, conn, &fsp);
423         if (!NT_STATUS_IS_OK(status)) {
424                 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
425                           "new fsp: %s\n", nt_errstr(status)));
426                 TALLOC_FREE(lck);
427                 return status;
428         }
429
430         fsp->fh->private_options = e->private_options;
431         fsp->fh->gen_id = smbXsrv_open_hash(op);
432         fsp->file_id = file_id;
433         fsp->file_pid = smb1req->smbpid;
434         fsp->vuid = smb1req->vuid;
435         fsp->open_time = e->time;
436         fsp->access_mask = e->access_mask;
437         fsp->share_access = e->share_access;
438         fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
439         fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
440
441         /*
442          * TODO:
443          * Do we need to store the modified flag in the DB?
444          * How to handle update_write_time and friends
445          * during a disconnected client on a durable handle?
446          */
447         fsp->modified = false;
448         /*
449          * no durables for directories
450          */
451         fsp->is_directory = false;
452         /*
453          * For normal files, can_lock == !is_directory
454          */
455         fsp->can_lock = true;
456         /*
457          * We do not support aio write behind for smb2
458          */
459         fsp->aio_write_behind = false;
460         fsp->oplock_type = e->op_type;
461
462         fsp->initial_allocation_size = cookie.initial_allocation_size;
463         fsp->fh->position_information = cookie.position_information;
464         fsp->update_write_time_triggered = cookie.update_write_time_triggered;
465         fsp->update_write_time_on_close = cookie.update_write_time_on_close;
466         fsp->write_time_forced = cookie.write_time_forced;
467         fsp->close_write_time = cookie.close_write_time;
468
469         status = fsp_set_smb_fname(fsp, smb_fname);
470         if (!NT_STATUS_IS_OK(status)) {
471                 TALLOC_FREE(lck);
472                 fsp_free(fsp);
473                 DEBUG(0, ("vfs_default_durable_reconnect: "
474                           "fsp_set_smb_fname failed: %s\n",
475                           nt_errstr(status)));
476                 return status;
477         }
478
479         op->compat = fsp;
480         fsp->op = op;
481
482         e->pid = messaging_server_id(conn->sconn->msg_ctx);
483         e->op_mid = smb1req->mid;
484         e->share_file_id = fsp->fh->gen_id;
485
486         ok = brl_reconnect_disconnected(fsp);
487         if (!ok) {
488                 status = NT_STATUS_INTERNAL_ERROR;
489                 DEBUG(1, ("vfs_default_durable_reconnect: "
490                           "failed to reopen brlocks: %s\n",
491                           nt_errstr(status)));
492                 TALLOC_FREE(lck);
493                 op->compat = NULL;
494                 fsp_free(fsp);
495                 return status;
496         }
497
498         /*
499          * TODO: properly calculate open flags
500          */
501         if (fsp->can_write && fsp->can_read) {
502                 flags = O_RDWR;
503         } else if (fsp->can_write) {
504                 flags = O_WRONLY;
505         } else if (fsp->can_read) {
506                 flags = O_RDONLY;
507         }
508
509         status = fd_open(conn, fsp, flags, 0 /* mode */);
510         if (!NT_STATUS_IS_OK(status)) {
511                 TALLOC_FREE(lck);
512                 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
513                           "file: %s\n", nt_errstr(status)));
514                 op->compat = NULL;
515                 fsp_free(fsp);
516                 return status;
517         }
518
519         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
520         if (ret == -1) {
521                 status = map_nt_error_from_unix_common(errno);
522                 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
523                           smb_fname_str_dbg(smb_fname),
524                           nt_errstr(status)));
525                 ret = SMB_VFS_CLOSE(fsp);
526                 if (ret == -1) {
527                         DEBUG(0, ("vfs_default_durable_reconnect: "
528                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
529                                   "descriptor\n", strerror(errno)));
530                 }
531                 TALLOC_FREE(lck);
532                 op->compat = NULL;
533                 fsp_free(fsp);
534                 return status;
535         }
536
537         if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
538                 ret = SMB_VFS_CLOSE(fsp);
539                 if (ret == -1) {
540                         DEBUG(0, ("vfs_default_durable_reconnect: "
541                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
542                                   "descriptor\n", strerror(errno)));
543                 }
544                 TALLOC_FREE(lck);
545                 op->compat = NULL;
546                 fsp_free(fsp);
547                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
548         }
549
550         file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
551         if (!file_id_equal(&cookie.id, &file_id)) {
552                 ret = SMB_VFS_CLOSE(fsp);
553                 if (ret == -1) {
554                         DEBUG(0, ("vfs_default_durable_reconnect: "
555                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
556                                   "descriptor\n", strerror(errno)));
557                 }
558                 TALLOC_FREE(lck);
559                 op->compat = NULL;
560                 fsp_free(fsp);
561                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
562         }
563
564         status = set_file_oplock(fsp, e->op_type);
565         if (!NT_STATUS_IS_OK(status)) {
566                 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
567                           "after opening file: %s\n", nt_errstr(status)));
568                 ret = SMB_VFS_CLOSE(fsp);
569                 if (ret == -1) {
570                         DEBUG(0, ("vfs_default_durable_reconnect: "
571                                   "SMB_VFS_CLOSE failed (%s) - leaking file "
572                                   "descriptor\n", strerror(errno)));
573                 }
574                 TALLOC_FREE(lck);
575                 op->compat = NULL;
576                 fsp_free(fsp);
577                 return status;
578         }
579
580         status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
581         if (!NT_STATUS_IS_OK(status)) {
582                 TALLOC_FREE(lck);
583                 DEBUG(1, ("vfs_default_durable_reconnect: "
584                           "vfs_default_durable_cookie - %s\n",
585                           nt_errstr(status)));
586                 op->compat = NULL;
587                 fsp_free(fsp);
588                 return status;
589         }
590
591         smb1req->chain_fsp = fsp;
592         smb1req->smb2req->compat_chain_fsp = fsp;
593
594         DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
595                    fsp_str_dbg(fsp)));
596
597         /*
598          * release the sharemode lock: this writes the changes
599          */
600         lck->data->modified = true;
601         TALLOC_FREE(lck);
602
603         *result = fsp;
604         *new_cookie = new_cookie_blob;
605
606         return NT_STATUS_OK;
607 }