r20340: Join vfs_MkDir to its only caller
[samba.git] / source3 / smbd / open.c
index 5c10c59054915678db560e02aef2cec5fb3b37dc..1ca793fb80a498b333efe645b9a84345ead914d4 100644 (file)
@@ -84,10 +84,10 @@ int fd_close(struct connection_struct *conn,
  Do this by fd if possible.
 ****************************************************************************/
 
-void change_owner_to_parent(connection_struct *conn,
-                           files_struct *fsp,
-                           const char *fname,
-                           SMB_STRUCT_STAT *psbuf)
+static void change_owner_to_parent(connection_struct *conn,
+                                  files_struct *fsp,
+                                  const char *fname,
+                                  SMB_STRUCT_STAT *psbuf)
 {
        const char *parent_path = parent_dirname(fname);
        SMB_STRUCT_STAT parent_st;
@@ -283,7 +283,9 @@ static NTSTATUS open_file(files_struct *fsp,
                }
 
                /* Inherit the ACL if the file was created. */
-               if ((local_flags & O_CREAT) && !file_existed) {
+               if ((local_flags & O_CREAT)
+                   && !file_existed
+                   && lp_inherit_perms(SNUM(conn))) {
                        inherit_access_acl(conn, fname, unx_mode);
                }
 
@@ -475,8 +477,8 @@ static void validate_my_share_entries(int num,
        if (is_deferred_open_entry(share_entry) &&
            !open_was_deferred(share_entry->op_mid)) {
                pstring str;
-               DEBUG(0, ("Got a deferred entry without a request: "
-                         "PANIC: %s\n", share_mode_str(num, share_entry)));
+               pstr_sprintf(str, "Got a deferred entry without a request: "
+                            "PANIC: %s\n", share_mode_str(num, share_entry));
                smb_panic(str);
        }
 
@@ -783,28 +785,6 @@ static void defer_open(struct share_mode_lock *lck,
        srv_defer_sign_response(mid);
 }
 
-/****************************************************************************
- Set a kernel flock on a file for NFS interoperability.
- This requires a patch to Linux.
-****************************************************************************/
-
-static void kernel_flock(files_struct *fsp, uint32 share_mode)
-{
-#if HAVE_KERNEL_SHARE_MODES
-       int kernel_mode = 0;
-       if (share_mode == FILE_SHARE_WRITE) {
-               kernel_mode = LOCK_MAND|LOCK_WRITE;
-       } else if (share_mode == FILE_SHARE_READ) {
-               kernel_mode = LOCK_MAND|LOCK_READ;
-       } else if (share_mode == FILE_SHARE_NONE) {
-               kernel_mode = LOCK_MAND;
-       }
-       if (kernel_mode) {
-               flock(fsp->fh->fd, kernel_mode);
-       }
-#endif
-       ;
-}
 
 /****************************************************************************
  On overwrite open ensure that the attributes match.
@@ -1126,6 +1106,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        struct share_mode_lock *lck = NULL;
        uint32 open_access_mask = access_mask;
        NTSTATUS status;
+       int ret_flock;
 
        if (conn->printer) {
                /* 
@@ -1139,7 +1120,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname));
 
-               return print_fsp_open(conn, fname, &fsp);
+               return print_fsp_open(conn, fname, result);
        }
 
        /* We add aARCH to this as this mode is only used if the file is
@@ -1320,7 +1301,15 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         */
 
        if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
-               flags = O_RDWR;
+               /* DENY_DOS opens are always underlying read-write on the
+                  file handle, no matter what the requested access mask
+                   says. */
+               if ((create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) ||
+                       access_mask & (FILE_READ_ATTRIBUTES|FILE_READ_DATA|FILE_READ_EA|FILE_EXECUTE)) {
+                       flags = O_RDWR;
+               } else {
+                       flags = O_WRONLY;
+               }
        } else {
                flags = O_RDONLY;
        }
@@ -1468,11 +1457,13 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        if (flags & O_RDWR) {
                                can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
+                       } else if (flags & O_WRONLY) {
+                               can_access_mask = FILE_WRITE_DATA;
                        } else {
                                can_access_mask = FILE_READ_DATA;
                        }
 
-                       if (((flags & O_RDWR) && !CAN_WRITE(conn)) ||
+                       if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) ||
                            !can_access_file(conn,fname,psbuf,can_access_mask)) {
                                can_access = False;
                        }
@@ -1644,9 +1635,18 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
            these only read them. Nobody but Samba can ever set a deny
            mode and we have already checked our more authoritative
            locking database for permission to set this deny mode. If
-           the kernel refuses the operations then the kernel is wrong */
+           the kernel refuses the operations then the kernel is wrong.
+          note that GPFS supports it as well - jmcd */
 
-       kernel_flock(fsp, share_access);
+       ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, fsp->fh->fd, share_access);
+       if(ret_flock == -1 ){
+
+               talloc_free(lck);
+               fd_close(conn, fsp);
+               file_free(fsp);
+               
+               return NT_STATUS_SHARING_VIOLATION;
+       }
 
        /*
         * At this point onwards, we can guarentee that the share entry
@@ -1851,6 +1851,48 @@ int close_file_fchmod(files_struct *fsp)
        return ret;
 }
 
+static NTSTATUS mkdir_internal(connection_struct *conn, const char *name)
+{
+       SMB_STRUCT_STAT sbuf;
+       int ret= -1;
+       mode_t mode;
+
+       if(!CAN_WRITE(conn)) {
+               DEBUG(5,("mkdir_internal: failing create on read-only share "
+                        "%s\n", lp_servicename(SNUM(conn))));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (!check_name(name, conn)) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       mode = unix_mode(conn, aDIR, name, True);
+
+       if ((ret=SMB_VFS_MKDIR(conn, name, mode)) != 0) {
+               return map_nt_error_from_unix(errno);
+       }
+
+       if (lp_inherit_perms(SNUM(conn))) {
+               inherit_access_acl(conn, name, mode);
+       }
+
+       /*
+        * Check if high bits should have been set,
+        * then (if bits are missing): add them.
+        * Consider bits automagically set by UNIX, i.e. SGID bit from parent
+        * dir.
+        */
+       if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)
+           && (SMB_VFS_STAT(conn, name, &sbuf) == 0)
+           && (mode & ~sbuf.st_mode)) {
+               SMB_VFS_CHMOD(conn, name,
+                             sbuf.st_mode | (mode & ~sbuf.st_mode));
+       }
+
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Open a directory from an NT SMB call.
 ****************************************************************************/
@@ -1867,7 +1909,6 @@ NTSTATUS open_directory(connection_struct *conn,
 {
        files_struct *fsp = NULL;
        BOOL dir_existed = VALID_STAT(*psbuf) ? True : False;
-       BOOL create_dir = False;
        struct share_mode_lock *lck = NULL;
        NTSTATUS status;
        int info = 0;
@@ -1888,44 +1929,47 @@ NTSTATUS open_directory(connection_struct *conn,
 
        switch( create_disposition ) {
                case FILE_OPEN:
-                       /* If directory exists open. If directory doesn't
-                        * exist error. */
-                       if (!dir_existed) {
-                               DEBUG(5,("open_directory: FILE_OPEN requested "
-                                        "for directory %s and it doesn't "
-                                        "exist.\n", fname ));
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-                       }
+                       /*
+                        * Don't do anything. The check for existence is done
+                        * futher down.
+                        */
                        info = FILE_WAS_OPENED;
                        break;
 
                case FILE_CREATE:
+
                        /* If directory exists error. If directory doesn't
                         * exist create. */
-                       if (dir_existed) {
-                               DEBUG(5,("open_directory: FILE_CREATE "
-                                        "requested for directory %s and it "
-                                        "already exists.\n", fname ));
-                               if (use_nt_status()) {
-                                       return NT_STATUS_OBJECT_NAME_COLLISION;
-                               } else {
-                                       return NT_STATUS_DOS(ERRDOS,
-                                                            ERRfilexists);
-                               }
+
+                       status = mkdir_internal(conn, fname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(2, ("open_directory: unable to create "
+                                         "%s. Error was %s\n", fname,
+                                         nt_errstr(status)));
+                               return status;
                        }
-                       create_dir = True;
+
                        info = FILE_WAS_CREATED;
                        break;
 
                case FILE_OPEN_IF:
-                       /* If directory exists open. If directory doesn't
-                        * exist create. */
-                       if (!dir_existed) {
-                               create_dir = True;
+                       /*
+                        * If directory exists open. If directory doesn't
+                        * exist create.
+                        */
+
+                       status = mkdir_internal(conn, fname);
+
+                       if (NT_STATUS_IS_OK(status)) {
                                info = FILE_WAS_CREATED;
-                       } else {
+                       }
+
+                       if (NT_STATUS_EQUAL(status,
+                                           NT_STATUS_OBJECT_NAME_COLLISION)) {
                                info = FILE_WAS_OPENED;
+                               status = NT_STATUS_OK;
                        }
+                               
                        break;
 
                case FILE_SUPERSEDE:
@@ -1938,35 +1982,17 @@ NTSTATUS open_directory(connection_struct *conn,
                        return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (create_dir) {
-               /*
-                * Try and create the directory.
-                */
-
-               /* We know bad_path is false as it's caught earlier. */
-
-               status = mkdir_internal(conn, fname, False);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(2,("open_directory: unable to create %s. "
-                                "Error was %s\n", fname, strerror(errno) ));
-                       /* Ensure we return the correct NT status to the
-                        * client. */
-                       return status;
-               }
+       /* Ensure we're checking for a symlink here.... */
+       /* We don't want to get caught by a symlink racer. */
 
-               /* Ensure we're checking for a symlink here.... */
-               /* We don't want to get caught by a symlink racer. */
-
-               if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) {
-                       return map_nt_error_from_unix(errno);
-               }
+       if(SMB_VFS_LSTAT(conn,fname, psbuf) != 0) {
+               return map_nt_error_from_unix(errno);
+       }
 
-               if(!S_ISDIR(psbuf->st_mode)) {
-                       DEBUG(0,("open_directory: %s is not a directory !\n",
-                                fname ));
-                       return NT_STATUS_NOT_A_DIRECTORY;
-               }
+       if(!S_ISDIR(psbuf->st_mode)) {
+               DEBUG(5,("open_directory: %s is not a directory !\n",
+                        fname ));
+               return NT_STATUS_NOT_A_DIRECTORY;
        }
 
        status = file_new(conn, &fsp);
@@ -2053,11 +2079,31 @@ NTSTATUS open_directory(connection_struct *conn,
        return NT_STATUS_OK;
 }
 
+NTSTATUS create_directory(connection_struct *conn, const char *directory)
+{
+       NTSTATUS status;
+       SMB_STRUCT_STAT sbuf;
+       files_struct *fsp;
+
+       SET_STAT_INVALID(sbuf);
+       
+       status = open_directory(conn, directory, &sbuf,
+                               FILE_READ_ATTRIBUTES, /* Just a stat open */
+                               FILE_SHARE_NONE, /* Ignored for stat opens */
+                               FILE_CREATE, 0, NULL, &fsp);
+
+       if (NT_STATUS_IS_OK(status)) {
+               close_file(fsp, NORMAL_CLOSE);
+       }
+
+       return status;
+}
+
 /****************************************************************************
  Open a pseudo-file (no locking checks - a 'stat' open).
 ****************************************************************************/
 
-NTSTATUS open_file_stat(connection_struct *conn, char *fname,
+NTSTATUS open_file_stat(connection_struct *conn, const char *fname,
                        SMB_STRUCT_STAT *psbuf, files_struct **result)
 {
        files_struct *fsp = NULL;