s3: Modify direct caller of open_file to call SMB_VFS_CREATE_FILE
[samba.git] / source3 / smbd / open.c
index aca64917b56c19951683d549f68daac89b97944e..2e34115071d6e9eabbe04dac8ef753ad5f505e04 100644 (file)
@@ -29,6 +29,23 @@ struct deferred_open_record {
        struct file_id id;
 };
 
+static NTSTATUS create_file_unixpath(connection_struct *conn,
+                                    struct smb_request *req,
+                                    const char *fname,
+                                    uint32_t access_mask,
+                                    uint32_t share_access,
+                                    uint32_t create_disposition,
+                                    uint32_t create_options,
+                                    uint32_t file_attributes,
+                                    uint32_t oplock_request,
+                                    uint64_t allocation_size,
+                                    struct security_descriptor *sd,
+                                    struct ea_list *ea_list,
+
+                                    files_struct **result,
+                                    int *pinfo,
+                                    SMB_STRUCT_STAT *psbuf);
+
 /****************************************************************************
  SMB1 file varient of se_access_check. Never test FILE_READ_ATTRIBUTES.
 ****************************************************************************/
@@ -332,6 +349,7 @@ static NTSTATUS open_file(files_struct *fsp,
        if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
            (!file_existed && (local_flags & O_CREAT)) ||
            ((local_flags & O_TRUNC) == O_TRUNC) ) {
+               const char *wild;
 
                /*
                 * We can't actually truncate here as the file may be locked.
@@ -353,8 +371,17 @@ static NTSTATUS open_file(files_struct *fsp,
 #endif
 
                /* Don't create files with Microsoft wildcard characters. */
+               if (fsp->base_fsp) {
+                       /*
+                        * wildcard characters are allowed in stream names
+                        * only test the basefilename
+                        */
+                       wild = fsp->base_fsp->fsp_name;
+               } else {
+                       wild = path;
+               }
                if ((local_flags & O_CREAT) && !file_existed &&
-                   ms_has_wild(path))  {
+                   ms_has_wild(wild))  {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
 
@@ -1651,7 +1678,7 @@ static NTSTATUS open_file_ntcreate_internal(connection_struct *conn,
                                                        share_access,
                                                        create_options);
 
-                               if (!NT_STATUS_IS_OK(status)) {
+                               if (NT_STATUS_IS_OK(status)) {
                                        TALLOC_FREE(lck);
                                        if (pinfo) {
                                                *pinfo = FILE_WAS_OPENED;
@@ -2116,10 +2143,25 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn,
                return status;
        }
 
-       /* note! we must use a non-zero desired access or we don't get
-           a real file descriptor. Oh what a twisted web we weave. */
-       status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY,
-                          0, FILE_WRITE_DATA, FILE_WRITE_DATA);
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               NULL,                                   /* req */
+               0,                                      /* root_dir_fid */
+               fname,                                  /* fname */
+               false,                                  /* is_dos_path */
+               FILE_WRITE_DATA,                        /* access_mask */
+               (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
+                   FILE_SHARE_DELETE),
+               FILE_OPEN,                              /* create_disposition*/
+               0,                                      /* create_options */
+               0,                                      /* file_attributes */
+               0,                                      /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               NULL,                                   /* pinfo */
+               psbuf);                                 /* psbuf */
 
        /*
         * This is not a user visible file open.
@@ -2466,14 +2508,24 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, cons
 
        SET_STAT_INVALID(sbuf);
        
-       status = open_directory(conn, req, directory, &sbuf,
-                               FILE_READ_ATTRIBUTES, /* Just a stat open */
-                               FILE_SHARE_NONE, /* Ignored for stat opens */
-                               FILE_CREATE,
-                               0,
-                               FILE_ATTRIBUTE_DIRECTORY,
-                               NULL,
-                               &fsp);
+       status = SMB_VFS_CREATE_FILE(
+               conn,                                   /* conn */
+               req,                                    /* req */
+               0,                                      /* root_dir_fid */
+               directory,                              /* fname */
+               false,                                  /* is_dos_path */
+               FILE_READ_ATTRIBUTES,                   /* access_mask */
+               FILE_SHARE_NONE,                        /* share_access */
+               FILE_CREATE,                            /* create_disposition*/
+               FILE_DIRECTORY_FILE,                    /* create_options */
+               FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
+               0,                                      /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &fsp,                                   /* result */
+               NULL,                                   /* pinfo */
+               &sbuf);                                 /* psbuf */
 
        if (NT_STATUS_IS_OK(status)) {
                close_file(req, fsp, NORMAL_CLOSE);
@@ -2698,22 +2750,22 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn,
  * Wrapper around open_file_ntcreate and open_directory
  */
 
-NTSTATUS create_file_unixpath(connection_struct *conn,
-                             struct smb_request *req,
-                             const char *fname,
-                             uint32_t access_mask,
-                             uint32_t share_access,
-                             uint32_t create_disposition,
-                             uint32_t create_options,
-                             uint32_t file_attributes,
-                             uint32_t oplock_request,
-                             uint64_t allocation_size,
-                             struct security_descriptor *sd,
-                             struct ea_list *ea_list,
-
-                             files_struct **result,
-                             int *pinfo,
-                             SMB_STRUCT_STAT *psbuf)
+static NTSTATUS create_file_unixpath(connection_struct *conn,
+                                    struct smb_request *req,
+                                    const char *fname,
+                                    uint32_t access_mask,
+                                    uint32_t share_access,
+                                    uint32_t create_disposition,
+                                    uint32_t create_options,
+                                    uint32_t file_attributes,
+                                    uint32_t oplock_request,
+                                    uint64_t allocation_size,
+                                    struct security_descriptor *sd,
+                                    struct ea_list *ea_list,
+
+                                    files_struct **result,
+                                    int *pinfo,
+                                    SMB_STRUCT_STAT *psbuf)
 {
        SMB_STRUCT_STAT sbuf;
        int info = FILE_WAS_OPENED;
@@ -2842,6 +2894,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                                   "%s\n", base, nt_errstr(status)));
                        goto fail;
                }
+               /* we don't need to low level fd */
+               fd_close(base_fsp);
        }
 
        /*
@@ -2878,13 +2932,52 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                 * Ordinary file case.
                 */
 
-               status = open_file_ntcreate(
-                       conn, req, fname, &sbuf, access_mask, share_access,
-                       create_disposition, create_options, file_attributes,
-                       oplock_request, &info, &fsp);
+               if (base_fsp) {
+                       /*
+                        * We're opening the stream element of a base_fsp
+                        * we already opened. We need to initialize
+                        * the fsp first, and set up the base_fsp pointer.
+                        */
+                       status = file_new(req, conn, &fsp);
+                       if(!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
+                       fsp->base_fsp = base_fsp;
+
+                       status = open_file_ntcreate_internal(conn,
+                                               req,
+                                               fname,
+                                               &sbuf,
+                                               access_mask,
+                                               share_access,
+                                               create_disposition,
+                                               create_options,
+                                               file_attributes,
+                                               oplock_request,
+                                               &info,
+                                               fsp);
+
+                       if(!NT_STATUS_IS_OK(status)) {
+                               file_free(req, fsp);
+                               fsp = NULL;
+                       }
+               } else {
+                       status = open_file_ntcreate(
+                               conn, req, fname, &sbuf, access_mask, share_access,
+                               create_disposition, create_options, file_attributes,
+                               oplock_request, &info, &fsp);
+               }
 
                if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
 
+                       /* A stream open never opens a directory */
+
+                       if (base_fsp) {
+                               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+                               goto fail;
+                       }
+
                        /*
                         * Fail the open if it was explicitly a non-directory
                         * file.
@@ -2908,6 +3001,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                goto fail;
        }
 
+       fsp->base_fsp = base_fsp;
+
        /*
         * According to the MS documentation, the only time the security
         * descriptor is applied to the opened file is iff we *created* the
@@ -2994,16 +3089,6 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
 
        DEBUG(10, ("create_file_unixpath: info=%d\n", info));
 
-       /*
-        * Set fsp->base_fsp late enough that we can't "goto fail" anymore. In
-        * the fail: branch we call close_file(fsp, ERROR_CLOSE) which would
-        * also close fsp->base_fsp which we have to also do explicitly in
-        * this routine here, as not in all "goto fail:" we have the fsp set
-        * up already to be initialized with the base_fsp.
-        */
-
-       fsp->base_fsp = base_fsp;
-
        *result = fsp;
        if (pinfo != NULL) {
                *pinfo = info;
@@ -3022,6 +3107,13 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
        DEBUG(10, ("create_file_unixpath: %s\n", nt_errstr(status)));
 
        if (fsp != NULL) {
+               if (base_fsp && fsp->base_fsp == base_fsp) {
+                       /*
+                        * The close_file below will close
+                        * fsp->base_fsp.
+                        */
+                       base_fsp = NULL;
+               }
                close_file(req, fsp, ERROR_CLOSE);
                fsp = NULL;
        }
@@ -3032,23 +3124,24 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
        return status;
 }
 
-NTSTATUS create_file(connection_struct *conn,
-                    struct smb_request *req,
-                    uint16_t root_dir_fid,
-                    const char *fname,
-                    uint32_t access_mask,
-                    uint32_t share_access,
-                    uint32_t create_disposition,
-                    uint32_t create_options,
-                    uint32_t file_attributes,
-                    uint32_t oplock_request,
-                    uint64_t allocation_size,
-                    struct security_descriptor *sd,
-                    struct ea_list *ea_list,
-
-                    files_struct **result,
-                    int *pinfo,
-                    SMB_STRUCT_STAT *psbuf)
+NTSTATUS create_file_default(connection_struct *conn,
+                            struct smb_request *req,
+                            uint16_t root_dir_fid,
+                            const char *fname,
+                            bool is_dos_path,
+                            uint32_t access_mask,
+                            uint32_t share_access,
+                            uint32_t create_disposition,
+                            uint32_t create_options,
+                            uint32_t file_attributes,
+                            uint32_t oplock_request,
+                            uint64_t allocation_size,
+                            struct security_descriptor *sd,
+                            struct ea_list *ea_list,
+
+                            files_struct **result,
+                            int *pinfo,
+                            SMB_STRUCT_STAT *psbuf)
 {
        struct case_semantics_state *case_state = NULL;
        SMB_STRUCT_STAT sbuf;
@@ -3061,7 +3154,7 @@ NTSTATUS create_file(connection_struct *conn,
                  "create_disposition = 0x%x create_options = 0x%x "
                  "oplock_request = 0x%x "
                  "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, "
-                 "fname = %s\n",
+                 "is_dos_path = %s, fname = %s\n",
                  (unsigned int)access_mask,
                  (unsigned int)file_attributes,
                  (unsigned int)share_access,
@@ -3069,7 +3162,7 @@ NTSTATUS create_file(connection_struct *conn,
                  (unsigned int)create_options,
                  (unsigned int)oplock_request,
                  (unsigned int)root_dir_fid,
-                 ea_list, sd, fname));
+                 ea_list, sd, fname, is_dos_path ? "true" : "false"));
 
        /*
         * Get the file name.
@@ -3225,7 +3318,7 @@ NTSTATUS create_file(connection_struct *conn,
                file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
        }
 
-       {
+       if (is_dos_path) {
                char *converted_fname;
 
                SET_STAT_INVALID(sbuf);
@@ -3236,6 +3329,15 @@ NTSTATUS create_file(connection_struct *conn,
                        goto fail;
                }
                fname = converted_fname;
+       } else {
+               if (psbuf != NULL) {
+                       sbuf = *psbuf;
+               } else {
+                       if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) {
+                               SET_STAT_INVALID(sbuf);
+                       }
+               }
+
        }
 
        TALLOC_FREE(case_state);