s4: ntvfs/posix: to set a DACL at open time SEC_DESC_DACL_PRESENT must be set
[kai/samba.git] / source4 / ntvfs / posix / pvfs_open.c
index 49710806c7e4a058f44223e68228405b1dcf2d22..fe3c915576f9ef3051441f2b9a0db83571b8bfc7 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"
 
@@ -106,6 +106,7 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
                                        union smb_open *io)
 {
        NTSTATUS status;
+       struct security_descriptor *sd;
 
        /* setup any EAs that were asked for */
        if (io->ntcreatex.in.ea_list) {
@@ -117,8 +118,9 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
                }
        }
 
+       sd = io->ntcreatex.in.sec_desc;
        /* 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,7 +131,7 @@ 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 {
@@ -252,8 +254,12 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        } else {
                status = pvfs_access_check_create(pvfs, req, name, &access_mask);
        }
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       if (io->generic.in.query_maximal_access) {
+               status = pvfs_access_maximal_allowed(pvfs, req, name, 
+                                                    &io->generic.out.maximal_access);
+               NT_STATUS_NOT_OK_RETURN(status);
        }
 
        f->ntvfs         = h;
@@ -276,6 +282,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->handle->position          = 0;
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
@@ -313,7 +320,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
 
                /* now really mark the file as open */
                status = odb_open_file(lck, f->handle, name->full_name,
-                                      NULL, false, OPLOCK_NONE, NULL);
+                                      NULL, name->dos.write_time,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(lck);
@@ -373,7 +381,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                }
 
                status = odb_open_file(lck, f->handle, name->full_name,
-                                      NULL, false, OPLOCK_NONE, NULL);
+                                      NULL, name->dos.write_time,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto cleanup_delete;
@@ -429,6 +438,9 @@ cleanup_delete:
 */
 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
 {
+       talloc_free(h->write_time.update_event);
+       h->write_time.update_event = NULL;
+
        if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            h->name->stream_name) {
                NTSTATUS status;
@@ -447,6 +459,14 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                h->fd = -1;
        }
 
+       if (!h->write_time.update_forced &&
+           h->write_time.update_on_close &&
+           h->write_time.close_time == 0) {
+               struct timeval tv;
+               tv = timeval_current();
+               h->write_time.close_time = timeval_to_nttime(&tv);
+       }
+
        if (h->have_opendb_entry) {
                struct odb_lock *lck;
                NTSTATUS status;
@@ -458,6 +478,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                        return 0;
                }
 
+               if (h->write_time.update_forced) {
+                       status = odb_get_file_infos(h->pvfs->odb_context,
+                                                   &h->odb_locking_key,
+                                                   NULL,
+                                                   &h->write_time.close_time);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Unable get write time for '%s' - %s\n",
+                                        h->name->full_name, nt_errstr(status)));
+                       }
+
+                       h->write_time.update_forced = false;
+                       h->write_time.update_on_close = true;
+               } else if (h->write_time.update_on_close) {
+                       status = odb_set_write_time(lck, h->write_time.close_time, true);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Unable set write time for '%s' - %s\n",
+                                        h->name->full_name, nt_errstr(status)));
+                       }
+               }
+
                status = odb_close_file(lck, h, &delete_path);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
@@ -480,11 +520,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                                               FILE_NOTIFY_CHANGE_FILE_NAME,
                                               delete_path);
                        }
+                       h->write_time.update_on_close = false;
                }
 
                talloc_free(lck);
        }
 
+       if (h->write_time.update_on_close) {
+               struct timeval tv[2];
+
+               nttime_to_timeval(&tv[0], h->name->dos.access_time);
+               nttime_to_timeval(&tv[1], h->write_time.close_time);
+
+               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",
+                                        h->name->full_name, strerror(errno)));
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -584,8 +639,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                DATA_BLOB locking_key;
                status = pvfs_locking_key(parent, req, &locking_key);
                NT_STATUS_NOT_OK_RETURN(status);
-               status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
-                                                &del_on_close);
+               status = odb_get_file_infos(pvfs->odb_context, &locking_key,
+                                           &del_on_close, NULL);
                NT_STATUS_NOT_OK_RETURN(status);
                if (del_on_close) {
                        return NT_STATUS_DELETE_PENDING;
@@ -628,12 +683,14 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        }
 
        /* re-resolve the open fd */
-       status = pvfs_resolve_name_fd(pvfs, fd, name);
+       status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
        if (!NT_STATUS_IS_OK(status)) {
                close(fd);
                return status;
        }
 
+       /* support initial alloc sizes */
+       name->dos.alloc_size = io->ntcreatex.in.alloc_size;
        name->dos.attrib = attrib;
        status = pvfs_dosattrib_save(pvfs, name, fd);
        if (!NT_STATUS_IS_OK(status)) {
@@ -646,6 +703,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                goto cleanup_delete;
        }
 
+       if (io->generic.in.query_maximal_access) {
+               status = pvfs_access_maximal_allowed(pvfs, req, name, 
+                                                    &io->generic.out.maximal_access);
+               NT_STATUS_NOT_OK_RETURN(status);
+       }
+
        /* form the lock context used for byte range locking and
           opendb locking */
        status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
@@ -718,10 +781,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = true;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        status = odb_open_file(lck, f->handle, name->full_name,
-                              &f->handle->fd, allow_level_II_oplock,
+                              &f->handle->fd, name->dos.write_time,
+                              allow_level_II_oplock,
                               oplock_level, &oplock_granted);
        talloc_free(lck);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1110,7 +1175,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                   struct ntvfs_request *req, union smb_open *io)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
-       int flags;
+       int flags = 0;
        struct pvfs_filename *name;
        struct pvfs_file *f;
        struct ntvfs_handle *h;
@@ -1118,8 +1183,10 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        int fd;
        struct odb_lock *lck;
        uint32_t create_options;
+       uint32_t create_options_must_ignore_mask;
        uint32_t share_access;
        uint32_t access_mask;
+       uint32_t create_action = NTCREATEX_ACTION_EXISTED;
        bool del_on_close;
        bool stream_existed, stream_truncate=false;
        uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
@@ -1132,6 +1199,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return ntvfs_map_open(ntvfs, req, io);
        }
 
+       ZERO_STRUCT(io->generic.out);
+
        create_options = io->generic.in.create_options;
        share_access   = io->generic.in.share_access;
        access_mask    = io->generic.in.access_mask;
@@ -1140,11 +1209,48 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       /* some create options are not supported */
+       /*
+        * These options are ignored,
+        * 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) {
+               DEBUG(2,(__location__ " create_options 0x%x not supported\n", 
+                        create_options));
                return NT_STATUS_NOT_SUPPORTED;
        }
 
+       if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* TODO: When we implement HSM, add a hook here not to pull
+        * the actual file off tape, when this option is passed from
+        * the client */
+       if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
+               /* no-op */
+       }
+
+       /* TODO: If (unlikely) Linux does a good compressed
+        * filesystem, we might need an ioctl call for this */
+       if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
+               /* no-op */
+       }
+
+       if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
+               create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
+       }
+
+       /* Open the file with sync, if they asked for it, but
+          'strict sync = no' turns this client request into a no-op */
+       if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
+               flags |= O_SYNC;
+       }
+
+
        /* other create options are not allowed */
        if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            !(access_mask & SEC_STD_DELETE)) {
@@ -1167,6 +1273,13 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       /* we ignore some file_attr bits */
+       io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED | 
+                                       FILE_ATTRIBUTE_COMPRESSED |
+                                       FILE_ATTRIBUTE_REPARSE_POINT |
+                                       FILE_ATTRIBUTE_SPARSE |
+                                       FILE_ATTRIBUTE_NORMAL);
+
        /* resolve the cifs name to a posix name */
        status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 
                                   PVFS_RESOLVE_STREAMS, &name);
@@ -1198,8 +1311,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
           open doesn't match */
        io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
 
-       flags = 0;
-
        switch (io->generic.in.open_disposition) {
        case NTCREATEX_DISP_SUPERSEDE:
        case NTCREATEX_DISP_OVERWRITE_IF:
@@ -1208,6 +1319,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                } else {
                        stream_truncate = true;
                }
+               create_action = NTCREATEX_ACTION_TRUNCATED;
                break;
 
        case NTCREATEX_DISP_OPEN:
@@ -1226,6 +1338,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                } else {
                        stream_truncate = true;
                }
+               create_action = NTCREATEX_ACTION_TRUNCATED;
                break;
 
        case NTCREATEX_DISP_CREATE:
@@ -1270,8 +1383,12 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        /* check the security descriptor */
        status = pvfs_access_check(pvfs, req, name, &access_mask);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       if (io->generic.in.query_maximal_access) {
+               status = pvfs_access_maximal_allowed(pvfs, req, name, 
+                                                    &io->generic.out.maximal_access);
+               NT_STATUS_NOT_OK_RETURN(status);
        }
 
        status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
@@ -1306,6 +1423,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = false;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        /* form the lock context used for byte range locking and
@@ -1409,7 +1527,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        /* now really mark the file as open */
        status = odb_open_file(lck, f->handle, name->full_name,
-                              &f->handle->fd, allow_level_II_oplock,
+                              &f->handle->fd, name->dos.write_time,
+                              allow_level_II_oplock,
                               oplock_level, &oplock_granted);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1448,7 +1567,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        /* re-resolve the open fd */
-       status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
+       status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(lck);
                return status;
@@ -1464,6 +1583,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                        talloc_free(lck);
                        return pvfs_map_errno(pvfs, errno);
                }
+               name->dos.alloc_size = io->ntcreatex.in.alloc_size;
                name->dos.attrib = attrib;
                status = pvfs_dosattrib_save(pvfs, name, fd);
                if (!NT_STATUS_IS_OK(status)) {
@@ -1484,7 +1604,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        io->generic.out.oplock_level  = oplock_granted;
        io->generic.out.file.ntvfs    = h;
        io->generic.out.create_action = stream_existed?
-               NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
+               create_action:NTCREATEX_ACTION_CREATED;
+       
        io->generic.out.create_time   = name->dos.create_time;
        io->generic.out.access_time   = name->dos.access_time;
        io->generic.out.write_time    = name->dos.write_time;
@@ -1508,7 +1629,6 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_file *f;
-       struct utimbuf unix_times;
 
        if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
                return NT_STATUS_DOS(ERRSRV, ERRerror);
@@ -1524,9 +1644,9 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
        }
 
        if (!null_time(io->generic.in.write_time)) {
-               unix_times.actime = 0;
-               unix_times.modtime = io->close.in.write_time;
-               utime(f->handle->name->full_name, &unix_times);
+               f->handle->write_time.update_forced = false;
+               f->handle->write_time.update_on_close = true;
+               unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
        }
 
        if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
@@ -1885,8 +2005,8 @@ bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *
        NTSTATUS status;
        bool del_on_close;
 
-       status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
-                                        &del_on_close);
+       status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
+                                   &del_on_close, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
                return false;