smbd: Move fcb_or_dos_open() out of open_file_ntcreate()
authorVolker Lendecke <vl@samba.org>
Fri, 5 Jul 2019 07:52:43 +0000 (09:52 +0200)
committerRalph Boehme <slow@samba.org>
Mon, 8 Jul 2019 16:22:37 +0000 (16:22 +0000)
This is SMB1-only and pre-ntcreate with only 3 callers that look at
NTCREATEX_OPTIONS_PRIVATE_DENY_[DOS|FCB]. It is a bit less efficient
if it kicks in (we have to recreate the fsp), but SMB1 is less and
less popular, and this particular share mode combination from the
open&x family of calls might not be worth optimizing for.

This adds smb1_utils.[ch] as a kitchen sink for functions that can go
away once we drop SMB1.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/smbd/open.c
source3/smbd/reply.c
source3/smbd/smb1_utils.c [new file with mode: 0644]
source3/smbd/smb1_utils.h [new file with mode: 0644]
source3/smbd/trans2.c
source3/wscript_build

index ef73aa219eae1464536bcfb92893b08698417f44..2ee4a2c4fcae88260b3bea7f3215b7bdad5afd72 100644 (file)
@@ -21,6 +21,7 @@
 */
 
 #include "includes.h"
+#include "smb1_utils.h"
 #include "system/filesys.h"
 #include "lib/util/server_id.h"
 #include "printing.h"
@@ -2608,69 +2609,6 @@ static bool open_match_attributes(connection_struct *conn,
        return True;
 }
 
-/****************************************************************************
- Special FCB or DOS processing in the case of a sharing violation.
- Try and find a duplicated file handle.
-****************************************************************************/
-
-static NTSTATUS fcb_or_dos_open(struct smb_request *req,
-                               connection_struct *conn,
-                               files_struct *fsp_to_dup_into,
-                               const struct smb_filename *smb_fname,
-                               struct file_id id,
-                               uint16_t file_pid,
-                               uint64_t vuid,
-                               uint32_t access_mask,
-                               uint32_t share_access,
-                               uint32_t create_options)
-{
-       files_struct *fsp;
-
-       DEBUG(5,("fcb_or_dos_open: attempting old open semantics for "
-                "file %s.\n", smb_fname_str_dbg(smb_fname)));
-
-       for(fsp = file_find_di_first(conn->sconn, id); fsp;
-           fsp = file_find_di_next(fsp)) {
-
-               DEBUG(10,("fcb_or_dos_open: checking file %s, fd = %d, "
-                         "vuid = %llu, file_pid = %u, private_options = 0x%x "
-                         "access_mask = 0x%x\n", fsp_str_dbg(fsp),
-                         fsp->fh->fd, (unsigned long long)fsp->vuid,
-                         (unsigned int)fsp->file_pid,
-                         (unsigned int)fsp->fh->private_options,
-                         (unsigned int)fsp->access_mask ));
-
-               if (fsp != fsp_to_dup_into &&
-                   fsp->fh->fd != -1 &&
-                   fsp->vuid == vuid &&
-                   fsp->file_pid == file_pid &&
-                   (fsp->fh->private_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
-                                                NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
-                   (fsp->access_mask & FILE_WRITE_DATA) &&
-                   strequal(fsp->fsp_name->base_name, smb_fname->base_name) &&
-                   strequal(fsp->fsp_name->stream_name,
-                            smb_fname->stream_name)) {
-                       DEBUG(10,("fcb_or_dos_open: file match\n"));
-                       break;
-               }
-       }
-
-       if (!fsp) {
-               return NT_STATUS_NOT_FOUND;
-       }
-
-       /* quite an insane set of semantics ... */
-       if (is_executable(smb_fname->base_name) &&
-           (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
-               DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n"));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       /* We need to duplicate this fsp. */
-       return dup_file_fsp(req, fsp, access_mask, share_access,
-                           create_options, fsp_to_dup_into);
-}
-
 static void schedule_defer_open(struct share_mode_lock *lck,
                                struct file_id id,
                                struct timeval request_time,
@@ -3547,41 +3485,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
 
-               /* Check if this can be done with the deny_dos and fcb
-                * calls. */
-               if (private_flags &
-                   (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
-                    NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
-                       if (req == NULL) {
-                               DEBUG(0, ("DOS open without an SMB "
-                                         "request!\n"));
-                               TALLOC_FREE(lck);
-                               fd_close(fsp);
-                               return NT_STATUS_INTERNAL_ERROR;
-                       }
-
-                       /* Use the client requested access mask here,
-                        * not the one we open with. */
-                       status = fcb_or_dos_open(req,
-                                                conn,
-                                                fsp,
-                                                smb_fname,
-                                                id,
-                                                req->smbpid,
-                                                req->vuid,
-                                                access_mask,
-                                                share_access,
-                                                create_options);
-
-                       if (NT_STATUS_IS_OK(status)) {
-                               TALLOC_FREE(lck);
-                               if (pinfo) {
-                                       *pinfo = FILE_WAS_OPENED;
-                               }
-                               return NT_STATUS_OK;
-                       }
-               }
-
                /*
                 * This next line is a subtlety we need for
                 * MS-Access. If a file open will fail due to share
index 87729b23a83e5a6ebe378b72760afd5b025b0110..2622681a2da0dfb693e36367c80eed20160942d5 100644 (file)
@@ -45,6 +45,7 @@
 #include "libcli/smb/smb_signing.h"
 #include "lib/util/sys_rw_data.h"
 #include "librpc/gen_ndr/open_files.h"
+#include "smb1_utils.h"
 
 /****************************************************************************
  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
@@ -2219,8 +2220,23 @@ void reply_open(struct smb_request *req)
                        /* We have re-scheduled this call. */
                        goto out;
                }
-               reply_openerror(req, status);
-               goto out;
+
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
+
+               fsp = fcb_or_dos_open(
+                       req,
+                       smb_fname,
+                       access_mask,
+                       share_mode,
+                       create_options,
+                       private_flags);
+               if (fsp == NULL) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
        }
 
        /* Ensure we're pointing at the correct stat struct. */
@@ -2392,8 +2408,24 @@ void reply_open_and_X(struct smb_request *req)
                        /* We have re-scheduled this call. */
                        goto out;
                }
-               reply_openerror(req, status);
-               goto out;
+
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
+
+               fsp = fcb_or_dos_open(
+                       req,
+                       smb_fname,
+                       access_mask,
+                       share_mode,
+                       create_options,
+                       private_flags);
+               if (fsp == NULL) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
+               smb_action = FILE_WAS_OPENED;
        }
 
        /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
diff --git a/source3/smbd/smb1_utils.c b/source3/smbd/smb1_utils.c
new file mode 100644 (file)
index 0000000..8a7e66e
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Util functions valid in the SMB1 server
+ *
+ * Copyright (C) Volker Lendecke 2019
+ * Copyright by the authors of the functions moved here eventually
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "smb1_utils.h"
+#include "libcli/security/security.h"
+
+/****************************************************************************
+ Special FCB or DOS processing in the case of a sharing violation.
+ Try and find a duplicated file handle.
+****************************************************************************/
+
+struct files_struct *fcb_or_dos_open(
+       struct smb_request *req,
+       const struct smb_filename *smb_fname,
+       uint32_t access_mask,
+       uint32_t share_access,
+       uint32_t create_options,
+       uint32_t private_flags)
+{
+       struct connection_struct *conn = req->conn;
+       struct file_id id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
+       struct files_struct *fsp = NULL, *new_fsp = NULL;
+       NTSTATUS status;
+
+       if ((private_flags &
+            (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
+             NTCREATEX_OPTIONS_PRIVATE_DENY_FCB))
+           == 0) {
+               return NULL;
+       }
+
+       for(fsp = file_find_di_first(conn->sconn, id);
+           fsp != NULL;
+           fsp = file_find_di_next(fsp)) {
+
+               DBG_DEBUG("Checking file %s, fd = %d, vuid = %"PRIu64", "
+                         "file_pid = %"PRIu16", "
+                         "private_options = 0x%"PRIx32", "
+                         "access_mask = 0x%"PRIx32"\n",
+                         fsp_str_dbg(fsp),
+                         fsp->fh->fd,
+                         fsp->vuid,
+                         fsp->file_pid,
+                         fsp->fh->private_options,
+                         fsp->access_mask);
+
+               if (fsp->fh->fd != -1 &&
+                   fsp->vuid == req->vuid &&
+                   fsp->file_pid == req->smbpid &&
+                   (fsp->fh->private_options &
+                    (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
+                     NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
+                   (fsp->access_mask & FILE_WRITE_DATA) &&
+                   strequal(fsp->fsp_name->base_name, smb_fname->base_name) &&
+                   strequal(fsp->fsp_name->stream_name,
+                            smb_fname->stream_name)) {
+                       DBG_DEBUG("file match\n");
+                       break;
+               }
+       }
+
+       if (fsp == NULL) {
+               return NULL;
+       }
+
+       /* quite an insane set of semantics ... */
+       if (is_executable(smb_fname->base_name) &&
+           (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+               DBG_DEBUG("file fail due to is_executable.\n");
+               return NULL;
+       }
+
+       status = file_new(req, conn, &new_fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("file_new failed: %s\n", nt_errstr(status));
+               return NULL;
+       }
+
+       status = dup_file_fsp(
+               req,
+               fsp,
+               access_mask,
+               share_access,
+               create_options,
+               new_fsp);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("dup_file_fsp failed: %s\n", nt_errstr(status));
+               file_free(req, new_fsp);
+               return NULL;
+       }
+
+       return new_fsp;
+}
diff --git a/source3/smbd/smb1_utils.h b/source3/smbd/smb1_utils.h
new file mode 100644 (file)
index 0000000..719eb3e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Util functions valid in the SMB1 server
+ *
+ * Copyright (C) Volker Lendecke 2019
+ * Copyright by the authors of the functions moved here eventually
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SMBD_SMB1_UTILS_H__
+#define __SMBD_SMB1_UTILS_H__
+
+#include "includes.h"
+#include "vfs.h"
+#include "proto.h"
+
+struct files_struct *fcb_or_dos_open(
+       struct smb_request *req,
+       const struct smb_filename *smb_fname,
+       uint32_t access_mask,
+       uint32_t share_access,
+       uint32_t create_options,
+       uint32_t private_flags);
+
+#endif
index 4342b03a8c93525802fe78c7779295c874298b01..5b99240e9e88e890acaf4b4ade4aec28f6139bbf 100644 (file)
@@ -41,6 +41,7 @@
 #include "lib/util_ea.h"
 #include "lib/readdir_attr.h"
 #include "messages.h"
+#include "smb1_utils.h"
 
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
@@ -1440,8 +1441,24 @@ static void call_trans2open(connection_struct *conn,
                        /* We have re-scheduled this call. */
                        goto out;
                }
-               reply_openerror(req, status);
-               goto out;
+
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
+
+               fsp = fcb_or_dos_open(
+                       req,
+                       smb_fname,
+                       access_mask,
+                       share_mode,
+                       create_options,
+                       private_flags);
+               if (fsp == NULL) {
+                       reply_openerror(req, status);
+                       goto out;
+               }
+               smb_action = FILE_WAS_OPENED;
        }
 
        size = get_file_size_stat(&smb_fname->st);
index 7d44071225ea3ecd3c7d5a78bfa5cf67eb1f3e7d..aa3c71752026255d363b7dab25d362534c6300fb 100644 (file)
@@ -718,6 +718,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
                           smbd/notify.c
                           smbd/notify_msg.c
                           smbd/build_options.c
+                          smbd/smb1_utils.c
                           ''' + NOTIFY_SOURCES,
                    deps='''
                         talloc