Fix bug #7892 - open_file_fchmod() leaves a stale lock.
[samba.git] / source3 / smbd / open.c
index acd347520d1952d447a7fe2237b18d8486a59de6..1722895e37b7d94e3c33c5e582de318cc48d6ab4 100644 (file)
@@ -346,7 +346,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
        if (!CAN_WRITE(conn)) {
                /* It's a read-only share - fail if we wanted to write. */
-               if(accmode != O_RDONLY) {
+               if(accmode != O_RDONLY || (flags & O_TRUNC) || (flags & O_APPEND)) {
                        DEBUG(3,("Permission denied opening %s\n", path));
                        return NT_STATUS_ACCESS_DENIED;
                } else if(flags & O_CREAT) {
@@ -354,8 +354,8 @@ static NTSTATUS open_file(files_struct *fsp,
                           O_CREAT doesn't create the file if we have write
                           access into the directory.
                        */
-                       flags &= ~O_CREAT;
-                       local_flags &= ~O_CREAT;
+                       flags &= ~(O_CREAT|O_EXCL);
+                       local_flags &= ~(O_CREAT|O_EXCL);
                }
        }
 
@@ -454,8 +454,26 @@ static NTSTATUS open_file(files_struct *fsp,
                                        &access_granted);
                        if (!NT_STATUS_IS_OK(status)) {
                                if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+                                       /*
+                                        * On NT_STATUS_ACCESS_DENIED, access_granted
+                                        * contains the denied bits.
+                                        */
+
+                                       if ((access_mask & FILE_WRITE_ATTRIBUTES) &&
+                                                       (access_granted & FILE_WRITE_ATTRIBUTES) &&
+                                                       (lp_map_readonly(SNUM(conn)) ||
+                                                        lp_map_archive(SNUM(conn)) ||
+                                                        lp_map_hidden(SNUM(conn)) ||
+                                                        lp_map_system(SNUM(conn)))) {
+                                               access_granted &= ~FILE_WRITE_ATTRIBUTES;
+
+                                               DEBUG(10,("open_file: overrode FILE_WRITE_ATTRIBUTES "
+                                                       "on file %s\n",
+                                                       path ));
+                                       }
+
                                        if ((access_mask & DELETE_ACCESS) &&
-                                                       (access_granted == DELETE_ACCESS) &&
+                                                       (access_granted & DELETE_ACCESS) &&
                                                        can_delete_file_in_directory(conn, path)) {
                                                /* Were we trying to do a stat open
                                                 * for delete and didn't get DELETE
@@ -465,10 +483,14 @@ static NTSTATUS open_file(files_struct *fsp,
                                                 * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
                                                 * for details. */
 
-                                               DEBUG(10,("open_file: overrode ACCESS_DENIED "
+                                               access_granted &= ~DELETE_ACCESS;
+
+                                               DEBUG(10,("open_file: overrode DELETE_ACCESS "
                                                        "on file %s\n",
                                                        path ));
-                                       } else {
+                                       }
+
+                                       if (access_granted != 0) {
                                                DEBUG(10, ("open_file: Access denied on "
                                                        "file %s\n",
                                                        path));
@@ -2185,23 +2207,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
  Open a file for for write to ensure that we can fchmod it.
 ****************************************************************************/
 
-NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn,
+NTSTATUS open_file_fchmod(connection_struct *conn,
                          const char *fname,
                          SMB_STRUCT_STAT *psbuf, files_struct **result)
 {
-       files_struct *fsp = NULL;
-       NTSTATUS status;
-
        if (!VALID_STAT(*psbuf)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = file_new(req, conn, &fsp);
-       if(!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       status = SMB_VFS_CREATE_FILE(
+       return SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                NULL,                                   /* req */
                0,                                      /* root_dir_fid */
@@ -2213,37 +2227,13 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn,
                FILE_OPEN,                              /* create_disposition*/
                0,                                      /* create_options */
                0,                                      /* file_attributes */
-               0,                                      /* oplock_request */
+               INTERNAL_OPEN_ONLY,                     /* oplock_request */
                0,                                      /* allocation_size */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
-               &fsp,                                   /* result */
+               result,                                 /* result */
                NULL,                                   /* pinfo */
                psbuf);                                 /* psbuf */
-
-       /*
-        * This is not a user visible file open.
-        * Don't set a share mode.
-        */
-
-       if (!NT_STATUS_IS_OK(status)) {
-               file_free(req, fsp);
-               return status;
-       }
-
-       *result = fsp;
-       return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Close the fchmod file fd - ensure no locks are lost.
-****************************************************************************/
-
-NTSTATUS close_file_fchmod(struct smb_request *req, files_struct *fsp)
-{
-       NTSTATUS status = fd_close(fsp);
-       file_free(req, fsp);
-       return status;
 }
 
 static NTSTATUS mkdir_internal(connection_struct *conn,
@@ -2386,6 +2376,14 @@ static NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
+       /* We need to support SeSecurityPrivilege for this. */
+       if (access_mask & SEC_FLAG_SYSTEM_SECURITY) {
+               DEBUG(10, ("open_directory: open on %s "
+                       "failed - SEC_FLAG_SYSTEM_SECURITY denied.\n",
+                       fname));
+               return NT_STATUS_PRIVILEGE_NOT_HELD;
+       }
+
        switch( create_disposition ) {
                case FILE_OPEN:
 
@@ -2719,7 +2717,7 @@ struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx,
  * If that works, delete them all by setting the delete on close and close.
  */
 
-static NTSTATUS open_streams_for_delete(connection_struct *conn,
+NTSTATUS open_streams_for_delete(connection_struct *conn,
                                        const char *fname)
 {
        struct stream_struct *stream_info;
@@ -2777,13 +2775,15 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn,
                        goto fail;
                }
 
-               status = create_file_unixpath
-                       (conn,                  /* conn */
+               status = SMB_VFS_CREATE_FILE(
+                        conn,                  /* conn */
                         NULL,                  /* req */
+                        0,                     /* root_dir_fid */
                         streamname,            /* fname */
+                        0,                     /* create_file_flags */
                         DELETE_ACCESS,         /* access_mask */
-                        FILE_SHARE_READ | FILE_SHARE_WRITE
-                        | FILE_SHARE_DELETE,   /* share_access */
+                        (FILE_SHARE_READ |     /* share_access */
+                            FILE_SHARE_WRITE | FILE_SHARE_DELETE),
                         FILE_OPEN,             /* create_disposition*/
                         NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */
                         FILE_ATTRIBUTE_NORMAL, /* file_attributes */
@@ -2923,12 +2923,26 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
 
 #if 0
        /* We need to support SeSecurityPrivilege for this. */
-       if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) &&
+       if ((access_mask & SEC_FLAG_SYSTEM_SECURITY) &&
            !user_has_privileges(current_user.nt_user_token,
                                 &se_security)) {
                status = NT_STATUS_PRIVILEGE_NOT_HELD;
                goto fail;
        }
+#else
+       /* We need to support SeSecurityPrivilege for this. */
+       if (access_mask & SEC_FLAG_SYSTEM_SECURITY) {
+               status = NT_STATUS_PRIVILEGE_NOT_HELD;
+               goto fail;
+       }
+       /* Don't allow a SACL set from an NTtrans create until we
+        * support SeSecurityPrivilege. */
+       if (!VALID_STAT(sbuf) &&
+                       lp_nt_acl_support(SNUM(conn)) &&
+                       sd && (sd->sacl != NULL)) {
+               status = NT_STATUS_PRIVILEGE_NOT_HELD;
+               goto fail;
+       }
 #endif
 
        if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
@@ -3117,7 +3131,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                }
        }
 
-       if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) {
+       if ((ea_list != NULL) &&
+                       ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN))) {
                status = set_ea(conn, fsp, fname, ea_list);
                if (!NT_STATUS_IS_OK(status)) {
                        goto fail;
@@ -3297,7 +3312,6 @@ NTSTATUS create_file_default(connection_struct *conn,
                             int *pinfo,
                             SMB_STRUCT_STAT *psbuf)
 {
-       struct case_semantics_state *case_state = NULL;
        SMB_STRUCT_STAT sbuf;
        int info = FILE_WAS_OPENED;
        files_struct *fsp = NULL;
@@ -3318,6 +3332,29 @@ NTSTATUS create_file_default(connection_struct *conn,
                  (unsigned int)root_dir_fid,
                  ea_list, sd, create_file_flags, fname));
 
+       /* MSDFS pathname processing must be done FIRST.
+          MSDFS pathnames containing IPv6 addresses can
+          be confused with NTFS stream names (they contain
+          ":" characters. JRA. */
+
+       if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) {
+               char *resolved_fname;
+
+               status = resolve_dfspath(talloc_tos(), conn, true, fname,
+                                        &resolved_fname);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       /*
+                        * For PATH_NOT_COVERED we had
+                        * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
+                        *                 ERRSRV, ERRbadpath);
+                        * Need to fix in callers
+                        */
+                       goto fail;
+               }
+               fname = resolved_fname;
+       }
+
        /*
         * Calculate the filename from the root_dir_if if necessary.
         */
@@ -3373,32 +3410,6 @@ NTSTATUS create_file_default(connection_struct *conn,
                }
        }
 
-       if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) {
-               char *resolved_fname;
-
-               status = resolve_dfspath(talloc_tos(), conn, true, fname,
-                                        &resolved_fname);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       /*
-                        * For PATH_NOT_COVERED we had
-                        * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
-                        *                 ERRSRV, ERRbadpath);
-                        * Need to fix in callers
-                        */
-                       goto fail;
-               }
-               fname = resolved_fname;
-       }
-
-       /*
-        * Check if POSIX semantics are wanted.
-        */
-
-       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
-               case_state = set_posix_case_semantics(talloc_tos(), conn);
-       }
-
        if (create_file_flags & CFF_DOS_PATH) {
                char *converted_fname;
 
@@ -3421,8 +3432,6 @@ NTSTATUS create_file_default(connection_struct *conn,
 
        }
 
-       TALLOC_FREE(case_state);
-
        /* All file access must go through check_name() */
 
        status = check_name(conn, fname);