s3: smbd: Change canonicalize_ea_name() to take a const smb_filename * parameter...
[sfrench/samba-autobuild/.git] / source3 / smbd / open.c
index ed0594b1756affdbaefc48bc98a0c6b9bde8b839..e5503f57f36103a42f066b3caa425cee73372051 100644 (file)
@@ -119,7 +119,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+       status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
                        (SECINFO_OWNER |
                        SECINFO_GROUP |
                         SECINFO_DACL), talloc_tos(), &sd);
@@ -243,6 +243,7 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        char *parent_dir = NULL;
        struct security_descriptor *parent_sd = NULL;
        uint32_t access_granted = 0;
+       struct smb_filename *parent_smb_fname = NULL;
 
        if (!parent_dirname(talloc_tos(),
                                smb_fname->base_name,
@@ -251,6 +252,14 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
                return NT_STATUS_NO_MEMORY;
        }
 
+       parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+                               parent_dir,
+                               NULL,
+                               NULL);
+       if (parent_smb_fname == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        if (get_current_uid(conn) == (uid_t)0) {
                /* I'm sorry sir, I didn't know you were root... */
                DEBUG(10,("check_parent_access: root override "
@@ -261,7 +270,7 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        }
 
        status = SMB_VFS_GET_NT_ACL(conn,
-                               parent_dir,
+                               parent_smb_fname,
                                SECINFO_DACL,
                                    talloc_tos(),
                                &parent_sd);
@@ -583,8 +592,10 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
        }
 
        become_root();
-       ret = SMB_VFS_LCHOWN(conn, ".", smb_fname_parent->st.st_ex_uid,
-                           (gid_t)-1);
+       ret = SMB_VFS_LCHOWN(conn,
+                       smb_fname_cwd,
+                       smb_fname_parent->st.st_ex_uid,
+                       (gid_t)-1);
        unbecome_root();
        if (ret == -1) {
                status = map_nt_error_from_unix(errno);
@@ -2171,7 +2182,7 @@ static NTSTATUS smbd_calculate_maximum_allowed_access(
                return NT_STATUS_OK;
        }
 
-       status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+       status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
                                    (SECINFO_OWNER |
                                     SECINFO_GROUP |
                                     SECINFO_DACL),
@@ -3049,7 +3060,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        /* Delete streams if create_disposition requires it */
        if (!new_file_created && clear_ads(create_disposition) &&
            !is_ntfs_stream_smb_fname(smb_fname)) {
-               status = delete_all_streams(conn, smb_fname->base_name);
+               status = delete_all_streams(conn, smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        TALLOC_FREE(lck);
                        fd_close(fsp);
@@ -3169,8 +3180,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (info != FILE_WAS_OPENED) {
-               /* Files should be initially set as archive */
-               if (lp_map_archive(SNUM(conn)) ||
+               /* Overwritten files should be initially set as archive */
+               if ((info == FILE_WAS_OVERWRITTEN && lp_map_archive(SNUM(conn))) ||
                    lp_store_dos_attributes(SNUM(conn))) {
                        if (!posix_open) {
                                if (file_set_dosmode(conn, smb_fname,
@@ -3293,7 +3304,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return status;
        }
 
-       if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) {
+       if (SMB_VFS_MKDIR(conn, smb_dname, mode) != 0) {
                return map_nt_error_from_unix(errno);
        }
 
@@ -3335,7 +3346,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                 */
                if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) &&
                    (mode & ~smb_dname->st.st_ex_mode)) {
-                       SMB_VFS_CHMOD(conn, smb_dname->base_name,
+                       SMB_VFS_CHMOD(conn, smb_dname,
                                      (smb_dname->st.st_ex_mode |
                                          (mode & ~smb_dname->st.st_ex_mode)));
                        need_re_stat = true;
@@ -3624,8 +3635,18 @@ static NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       /* Ensure there was no race condition. */
-       if (!check_same_stat(&smb_dname->st, &fsp->fsp_name->st)) {
+       if(!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+               DEBUG(5,("open_directory: %s is not a directory !\n",
+                        smb_fname_str_dbg(smb_dname)));
+                fd_close(fsp);
+                file_free(req, fsp);
+               return NT_STATUS_NOT_A_DIRECTORY;
+       }
+
+       /* Ensure there was no race condition.  We need to check
+        * dev/inode but not permissions, as these can change
+        * legitimately */
+       if (!check_same_dev_ino(&smb_dname->st, &fsp->fsp_name->st)) {
                DEBUG(5,("open_directory: stat struct differs for "
                        "directory %s.\n",
                        smb_fname_str_dbg(smb_dname)));
@@ -3838,8 +3859,8 @@ void msg_file_was_renamed(struct messaging_context *msg,
  * If that works, delete them all by setting the delete on close and close.
  */
 
-NTSTATUS open_streams_for_delete(connection_struct *conn,
-                                       const char *fname)
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+                                       const struct smb_filename *smb_fname)
 {
        struct stream_struct *stream_info = NULL;
        files_struct **streams = NULL;
@@ -3848,7 +3869,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
        TALLOC_CTX *frame = talloc_stackframe();
        NTSTATUS status;
 
-       status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+       status = vfs_streaminfo(conn, NULL, smb_fname, talloc_tos(),
                                &num_streams, &stream_info);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
@@ -3880,30 +3901,32 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
        }
 
        for (i=0; i<num_streams; i++) {
-               struct smb_filename *smb_fname;
+               struct smb_filename *smb_fname_cp;
 
                if (strequal(stream_info[i].name, "::$DATA")) {
                        streams[i] = NULL;
                        continue;
                }
 
-               smb_fname = synthetic_smb_fname(
-                       talloc_tos(), fname, stream_info[i].name, NULL);
-               if (smb_fname == NULL) {
+               smb_fname_cp = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       stream_info[i].name,
+                                       NULL);
+               if (smb_fname_cp == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto fail;
                }
 
-               if (SMB_VFS_STAT(conn, smb_fname) == -1) {
+               if (SMB_VFS_STAT(conn, smb_fname_cp) == -1) {
                        DEBUG(10, ("Unable to stat stream: %s\n",
-                                  smb_fname_str_dbg(smb_fname)));
+                                  smb_fname_str_dbg(smb_fname_cp)));
                }
 
                status = SMB_VFS_CREATE_FILE(
                         conn,                  /* conn */
                         NULL,                  /* req */
                         0,                     /* root_dir_fid */
-                        smb_fname,             /* fname */
+                        smb_fname_cp,          /* fname */
                         DELETE_ACCESS,         /* access_mask */
                         (FILE_SHARE_READ |     /* share_access */
                             FILE_SHARE_WRITE | FILE_SHARE_DELETE),
@@ -3922,13 +3945,13 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("Could not open stream %s: %s\n",
-                                  smb_fname_str_dbg(smb_fname),
+                                  smb_fname_str_dbg(smb_fname_cp),
                                   nt_errstr(status)));
 
-                       TALLOC_FREE(smb_fname);
+                       TALLOC_FREE(smb_fname_cp);
                        break;
                }
-               TALLOC_FREE(smb_fname);
+               TALLOC_FREE(smb_fname_cp);
        }
 
        /*
@@ -3977,14 +4000,24 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
        const struct dom_sid *SY_U_sid = NULL;
        const struct dom_sid *SY_G_sid = NULL;
        size_t size = 0;
+       struct smb_filename *parent_smb_fname = NULL;
 
        if (!parent_dirname(frame, fsp->fsp_name->base_name, &parent_name, NULL)) {
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
+       parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                               parent_name,
+                                               NULL,
+                                               NULL);
+
+       if (parent_smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        status = SMB_VFS_GET_NT_ACL(fsp->conn,
-                                   parent_name,
+                                   parent_smb_fname,
                                    (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
                                    frame,
                                    &parent_desc);
@@ -4492,7 +4525,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                 * We can't open a file with DELETE access if any of the
                 * streams is open without FILE_SHARE_DELETE
                 */
-               status = open_streams_for_delete(conn, smb_fname->base_name);
+               status = open_streams_for_delete(conn, smb_fname);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto fail;