s4-pvfs: log more error conditions in NTVFS backend
[ira/wip.git] / source4 / ntvfs / posix / pvfs_open.c
index 8dbc6742419602c00044629dd74c10461679da33..d9d0d2178ab134949398e5acdb439fd02927c777 100644 (file)
@@ -23,7 +23,7 @@
 #include "vfs_posix.h"
 #include "system/dir.h"
 #include "system/time.h"
-#include "lib/util/dlinklist.h"
+#include "../lib/util/dlinklist.h"
 #include "messaging/messaging.h"
 #include "librpc/gen_ndr/xattr.h"
 
@@ -103,9 +103,10 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
                                        struct ntvfs_request *req,
                                        struct pvfs_filename *name,
                                        int fd, struct pvfs_file *f,
-                                       union smb_open *io)
+                                       union smb_open *io,
+                                       struct security_descriptor *sd)
 {
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_OK;
 
        /* setup any EAs that were asked for */
        if (io->ntcreatex.in.ea_list) {
@@ -118,7 +119,7 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
        }
 
        /* setup an initial sec_desc if requested */
-       if (io->ntcreatex.in.sec_desc) {
+       if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
                union smb_setfileinfo set;
 /* 
  * TODO: set the full ACL! 
@@ -129,12 +130,9 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
  */
                set.set_secdesc.in.file.ntvfs = f->ntvfs;
                set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
-               set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
+               set.set_secdesc.in.sd = sd;
 
                status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
-       } else {
-               /* otherwise setup an inherited acl from the parent */
-               status = pvfs_acl_inherit(pvfs, req, name, fd);
        }
 
        return status;
@@ -183,6 +181,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        uint32_t create_options;
        uint32_t share_access;
        bool forced;
+       struct security_descriptor *sd = NULL;
 
        create_options = io->generic.in.create_options;
        share_access   = io->generic.in.share_access;
@@ -207,6 +206,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
            (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
            (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
+               DEBUG(3,(__location__ ": Invalid access_mask/create_options 0x%08x 0x%08x for %s\n",
+                        io->ntcreatex.in.access_mask, io->ntcreatex.in.create_options, name->original_name));
                return NT_STATUS_INVALID_PARAMETER;
        }
        
@@ -230,6 +231,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        case NTCREATEX_DISP_OVERWRITE:
        case NTCREATEX_DISP_SUPERSEDE:
        default:
+               DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
+                        io->generic.in.open_disposition, name->original_name));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -249,8 +252,9 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        if (name->exists) {
                /* check the security descriptor */
                status = pvfs_access_check(pvfs, req, name, &access_mask);
-       } else {
-               status = pvfs_access_check_create(pvfs, req, name, &access_mask);
+       } else {                
+               sd = io->ntcreatex.in.sec_desc;
+               status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
        }
        NT_STATUS_NOT_OK_RETURN(status);
 
@@ -276,6 +280,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->handle->fd                = -1;
        f->handle->odb_locking_key   = data_blob(NULL, 0);
        f->handle->create_options    = io->generic.in.create_options;
+       f->handle->private_flags     = io->generic.in.private_flags;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
@@ -350,7 +355,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                        goto cleanup_delete;
                }
 
-               status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
+               status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
                if (!NT_STATUS_IS_OK(status)) {
                        goto cleanup_delete;
                }
@@ -532,7 +537,7 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
 
                if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
                        if (utimes(h->name->full_name, tv) == -1) {
-                               DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
+                               DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
                                         h->name->full_name, strerror(errno)));
                        }
                }
@@ -614,21 +619,29 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        struct pvfs_filename *parent;
        uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
        bool allow_level_II_oplock = false;
+       struct security_descriptor *sd = NULL;
 
        if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
+               DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
+                        io->ntcreatex.in.file_attr, name->original_name));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
+               DEBUG(3,(__location__ ": Invalid encryption request for %s\n",
+                        name->original_name));
                return NT_STATUS_ACCESS_DENIED;
        }
            
        if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
            (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
+               DEBUG(4,(__location__ ": Invalid delete on close for readonly file %s\n",
+                        name->original_name));
                return NT_STATUS_CANNOT_DELETE;
        }
 
-       status = pvfs_access_check_create(pvfs, req, name, &access_mask);
+       sd = io->ntcreatex.in.sec_desc;
+       status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
        NT_STATUS_NOT_OK_RETURN(status);
 
        /* check that the parent isn't opened with delete on close set */
@@ -696,7 +709,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        }
 
 
-       status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
+       status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
        if (!NT_STATUS_IS_OK(status)) {
                goto cleanup_delete;
        }
@@ -774,6 +787,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->name              = talloc_steal(f->handle, name);
        f->handle->fd                = fd;
        f->handle->create_options    = io->generic.in.create_options;
+       f->handle->private_flags     = io->generic.in.private_flags;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
@@ -866,7 +880,8 @@ struct pvfs_odb_retry {
 /* destroy a pending request */
 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
 {
-       struct pvfs_state *pvfs = r->ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
+                                 struct pvfs_state);
        if (r->odb_locking_key.data) {
                struct odb_lock *lck;
                lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
@@ -911,7 +926,8 @@ NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
                                               void *private_data,
                                               enum pvfs_wait_notice reason))
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct pvfs_odb_retry *r;
        struct pvfs_wait *wait_handle;
        NTSTATUS status;
@@ -1037,7 +1053,8 @@ static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
                                   struct ntvfs_request *req, union smb_open *io,
                                   struct pvfs_file *f, struct odb_lock *lck)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct pvfs_file *f2;
        struct pvfs_filename *name;
        NTSTATUS status;
@@ -1056,7 +1073,7 @@ static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
                if (f2 != f &&
                    f2->ntvfs->session_info == req->session_info &&
                    f2->ntvfs->smbpid == req->smbpid &&
-                   (f2->handle->create_options & 
+                   (f2->handle->private_flags &
                     (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
                      NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
                    (f2->access_mask & SEC_FILE_WRITE_DATA) &&
@@ -1072,7 +1089,7 @@ static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
 
        /* quite an insane set of semantics ... */
        if (is_exe_filename(io->generic.in.fname) &&
-           (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+           (f2->handle->private_flags & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
                return NT_STATUS_SHARING_VIOLATION;
        }
 
@@ -1118,12 +1135,13 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
                                      struct odb_lock *lck,
                                      NTSTATUS parent_status)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        NTSTATUS status;
        struct timeval end_time;
        struct timeval *final_timeout = NULL;
 
-       if (io->generic.in.create_options & 
+       if (io->generic.in.private_flags &
            (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
                /* see if we can satisfy the request using the special DENY_DOS
                   code */
@@ -1172,7 +1190,8 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                   struct ntvfs_request *req, union smb_open *io)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        int flags = 0;
        struct pvfs_filename *name;
        struct pvfs_file *f;
@@ -1204,6 +1223,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        access_mask    = io->generic.in.access_mask;
 
        if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
+               DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
+                        share_access, io->ntcreatex.in.fname));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1212,7 +1233,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
         * but we reuse some of them as private values for the generic mapping
         */
        create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
-       create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
        create_options &= ~create_options_must_ignore_mask;
 
        if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
@@ -1222,6 +1242,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
+               DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
+                        create_options, io->ntcreatex.in.fname));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1252,6 +1274,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        /* other create options are not allowed */
        if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            !(access_mask & SEC_STD_DELETE)) {
+               DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
+                        create_options, access_mask, io->ntcreatex.in.fname));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1265,9 +1289,26 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       /* cope with non-zero root_fid */
+       if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
+               f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
+               if (f == NULL) {
+                       return NT_STATUS_INVALID_HANDLE;
+               }
+               if (f->handle->fd != -1) {
+                       return NT_STATUS_INVALID_DEVICE_REQUEST;
+               }
+               io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s", 
+                                                        f->handle->name->original_name,
+                                                        io->ntcreatex.in.fname);
+               NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);                       
+       }
+
        if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
                                          FILE_ATTRIBUTE_VOLUME| 
                                          (~FILE_ATTRIBUTE_ALL_MASK))) {
+               DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
+                        io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1351,6 +1392,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                break;
 
        default:
+               DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
+                        io->generic.in.open_disposition, name->original_name));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1416,6 +1459,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->handle->fd                = -1;
        f->handle->name              = talloc_steal(f->handle, name);
        f->handle->create_options    = io->generic.in.create_options;
+       f->handle->private_flags     = io->generic.in.private_flags;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
@@ -1509,6 +1553,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        if (fd == -1) {
                status = pvfs_map_errno(f->pvfs, errno);
 
+               DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n", 
+                        nt_errstr(status), f->handle->name->full_name, errno));
                /*
                 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
                 */
@@ -1574,10 +1620,12 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        if (f->handle->name->stream_id == 0 &&
            (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
             io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
-               /* for overwrite we need to replace file permissions */
+               /* for overwrite we may need to replace file permissions */
                uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
                mode_t mode = pvfs_fileperms(pvfs, attrib);
-               if (fchmod(fd, mode) == -1) {
+               if (f->handle->name->st.st_mode != mode &&
+                   f->handle->name->dos.attrib != attrib &&
+                   fchmod(fd, mode) == -1) {
                        talloc_free(lck);
                        return pvfs_map_errno(pvfs, errno);
                }
@@ -1625,7 +1673,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
                    struct ntvfs_request *req, union smb_close *io)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct pvfs_file *f;
 
        if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
@@ -1682,9 +1731,15 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
                     struct ntvfs_request *req)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct pvfs_file *f, *next;
 
+       /* If pvfs is NULL, we never logged on, and no files are open. */
+       if(pvfs == NULL) {
+               return NT_STATUS_OK;
+       }
+
        for (f=pvfs->files.list;f;f=next) {
                next = f->next;
                if (f->ntvfs->session_info == req->session_info) {
@@ -1702,7 +1757,8 @@ NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
                   struct ntvfs_request *req)
 {
-       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
+                                 struct pvfs_state);
        struct pvfs_file *f, *next;
 
        for (f=pvfs->files.list;f;f=next) {
@@ -1912,15 +1968,12 @@ NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
                          NTCREATEX_SHARE_ACCESS_WRITE |
                          NTCREATEX_SHARE_ACCESS_DELETE;
        /*
-        * I would have thought that we would need to pass
-        * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
-        *
-        * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
-        * to set the filesize.
-        *
-        * --metze
+        * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
+        * a comment that this seemed to be wrong, but matched windows
+        * behaviour. It now appears that this windows behaviour is
+        * just a bug.
         */
-       access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
+       access_mask     = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
        delete_on_close = false;
        break_to_none   = true;