r3618: - this adds the special case for DENY_DOS semantics, as shown by the BASE...
authorAndrew Tridgell <tridge@samba.org>
Mon, 8 Nov 2004 11:35:49 +0000 (11:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:40 +0000 (13:05 -0500)
- pvfs now passes BASE-DENY1 and BASE-DENYDOS.
(This used to be commit aa09df22ee729c02552638859236d9068e9748ae)

source4/include/smb.h
source4/ntvfs/ntvfs_generic.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_qfileinfo.c
source4/ntvfs/posix/pvfs_read.c
source4/ntvfs/posix/pvfs_setfileinfo.c
source4/ntvfs/posix/pvfs_write.c
source4/ntvfs/posix/vfs_posix.h
source4/script/tests/test_posix.sh

index 940af75671d27c3831d0ecdd7dd85975a7909ffd..1d13b06e2540f5975c240dbdefc4c7958a2a66a3 100644 (file)
@@ -152,17 +152,24 @@ enum smb_signing_state {SMB_SIGNING_OFF, SMB_SIGNING_SUPPORTED,
 #define NTCREATEX_DISP_OVERWRITE_IF 5  /* if exists overwrite, else create */
 
 /* ntcreatex create_options field */
-#define NTCREATEX_OPTIONS_DIRECTORY            0x0001
-#define NTCREATEX_OPTIONS_WRITE_THROUGH        0x0002
-#define NTCREATEX_OPTIONS_SEQUENTIAL_ONLY      0x0004
-#define NTCREATEX_OPTIONS_SYNC_ALERT          0x0010
-#define NTCREATEX_OPTIONS_ASYNC_ALERT         0x0020
-#define NTCREATEX_OPTIONS_NON_DIRECTORY_FILE   0x0040
-#define NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE      0x0200
-#define NTCREATEX_OPTIONS_EIGHT_DOT_THREE_ONLY 0x0400
-#define NTCREATEX_OPTIONS_RANDOM_ACCESS        0x0800
-#define NTCREATEX_OPTIONS_DELETE_ON_CLOSE      0x1000
-#define NTCREATEX_OPTIONS_OPEN_BY_FILE_ID      0x2000
+#define NTCREATEX_OPTIONS_DIRECTORY                0x0001
+#define NTCREATEX_OPTIONS_WRITE_THROUGH            0x0002
+#define NTCREATEX_OPTIONS_SEQUENTIAL_ONLY          0x0004
+#define NTCREATEX_OPTIONS_SYNC_ALERT              0x0010
+#define NTCREATEX_OPTIONS_ASYNC_ALERT             0x0020
+#define NTCREATEX_OPTIONS_NON_DIRECTORY_FILE       0x0040
+#define NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE          0x0200
+#define NTCREATEX_OPTIONS_EIGHT_DOT_THREE_ONLY     0x0400
+#define NTCREATEX_OPTIONS_RANDOM_ACCESS            0x0800
+#define NTCREATEX_OPTIONS_DELETE_ON_CLOSE          0x1000
+#define NTCREATEX_OPTIONS_OPEN_BY_FILE_ID          0x2000
+
+/* create options these bits are for private use by backends, they are
+   not valid on the wire */
+#define NTCREATEX_OPTIONS_PRIVATE_MASK         0xFF000000
+#define NTCREATEX_OPTIONS_PRIVATE_DENY_DOS     0x01000000
+#define NTCREATEX_OPTIONS_PRIVATE_DENY_FCB     0x02000000
+
 
 /* ntcreatex impersonation field */
 #define NTCREATEX_IMPERSONATION_ANONYMOUS      0
index 9ef2481d2625c6a26febc73d8db94fc5a83f6595..a9bc8120c83e3b8c63d6d912d3e176b595032838 100644 (file)
@@ -117,7 +117,7 @@ static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS stat
   see if a filename ends in EXE COM DLL or SYM. This is needed for the
   DENY_DOS mapping for OpenX
 */
-static BOOL is_exe_file(const char *fname)
+BOOL is_exe_filename(const char *fname)
 {
        char *p;
        p = strrchr(fname, '.');
@@ -315,7 +315,9 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                        break;
                case OPENX_MODE_DENY_DOS:
                        /* DENY_DOS is quite strange - it depends on the filename! */
-                       if (is_exe_file(io->openx.in.fname)) {
+                       io2->generic.in.create_options |= 
+                               NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+                       if (is_exe_filename(io->openx.in.fname)) {
                                io2->generic.in.share_access = 
                                        NTCREATEX_SHARE_ACCESS_READ | 
                                        NTCREATEX_SHARE_ACCESS_WRITE;
@@ -329,6 +331,8 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                        }
                        break;
                case OPENX_MODE_DENY_FCB:
+                       io2->generic.in.create_options |= 
+                               NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
                        io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                        break;
                default:
@@ -400,7 +404,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                switch (io->openold.in.flags & OPEN_FLAGS_DENY_MASK) {
                case OPEN_FLAGS_DENY_DOS:
                                /* DENY_DOS is quite strange - it depends on the filename! */
-                               if (is_exe_file(io->openold.in.fname)) {
+                               if (is_exe_filename(io->openold.in.fname)) {
                                        io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
                                } else {
                                        if ((io->openold.in.flags & OPEN_FLAGS_MODE_MASK) == 
index 5411f83e8db9aa53be5d7ef97d69805bd592340f..cfd2b0f159b7d71f70a30871693edd404328fdb9 100644 (file)
@@ -147,19 +147,20 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
-       f->fnum         = fnum;
-       f->session      = req->session;
-       f->smbpid       = req->smbpid;
-       f->pvfs         = pvfs;
-       f->pending_list = NULL;
-       f->lock_count   = 0;
+       f->fnum          = fnum;
+       f->session       = req->session;
+       f->smbpid        = req->smbpid;
+       f->pvfs          = pvfs;
+       f->pending_list  = NULL;
+       f->lock_count    = 0;
+       f->share_access  = io->generic.in.share_access;
+       f->impersonation = io->generic.in.impersonation;
 
        f->handle->pvfs           = pvfs;
        f->handle->name           = talloc_steal(f->handle, name);
        f->handle->fd             = -1;
        f->handle->locking_key    = data_blob(NULL, 0);
        f->handle->create_options = io->generic.in.create_options;
-       f->handle->share_access   = io->generic.in.share_access;
        f->handle->seek_offset    = 0;
        f->handle->position       = 0;
        f->handle->mode           = 0;
@@ -326,11 +327,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE;
        }
 
-       if ((access_mask & SA_RIGHT_FILE_READ_EXEC) &&
-           (access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+       if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
                flags = O_RDWR;
-       } else if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
-               flags = O_WRONLY;
        } else {
                flags = O_RDONLY;
        }
@@ -407,19 +405,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                return status;
        }
 
-       f->fnum = fnum;
-       f->session = req->session;
-       f->smbpid = req->smbpid;
-       f->pvfs = pvfs;
-       f->pending_list = NULL;
-       f->lock_count = 0;
+       f->fnum              = fnum;
+       f->session           = req->session;
+       f->smbpid            = req->smbpid;
+       f->pvfs              = pvfs;
+       f->pending_list      = NULL;
+       f->lock_count        = 0;
+       f->share_access      = io->generic.in.share_access;
+       f->access_mask       = access_mask;
+       f->impersonation     = io->generic.in.impersonation;
 
        f->handle->pvfs              = pvfs;
        f->handle->name              = talloc_steal(f->handle, name);
        f->handle->fd                = fd;
        f->handle->create_options    = io->generic.in.create_options;
-       f->handle->share_access      = io->generic.in.share_access;
-       f->handle->access_mask       = access_mask;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
@@ -535,6 +534,86 @@ static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
 }
 
 
+/*
+  special handling for openx DENY_DOS semantics
+
+  This function attempts a reference open using an existing handle. If its allowed,
+  then it returns NT_STATUS_OK, otherwise it returns any other code and normal
+  open processing continues.
+*/
+static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
+                                  struct smbsrv_request *req, union smb_open *io,
+                                  struct pvfs_file *f, struct odb_lock *lck)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_file *f2;
+       struct pvfs_filename *name;
+
+       /* search for an existing open with the right parameters. Note
+          the magic ntcreatex options flag, which is set in the
+          generic mapping code. This might look ugly, but its
+          actually pretty much now w2k does it internally as well. 
+          
+          If you look at the BASE-DENYDOS test you will see that a
+          DENY_DOS is a very special case, and in the right
+          circumstances you actually get the _same_ handle back
+          twice, rather than a new handle.
+       */
+       for (f2=pvfs->open_files;f2;f2=f2->next) {
+               if (f2 != f &&
+                   f2->session == req->session &&
+                   f2->smbpid == req->smbpid &&
+                   (f2->handle->create_options & 
+                    (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
+                     NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
+                   (f2->access_mask & SA_RIGHT_FILE_WRITE_DATA) &&
+                   StrCaseCmp(f2->handle->name->original_name, 
+                              io->generic.in.fname)==0) {
+                       break;
+               }
+       }
+
+       if (!f2) {
+               return NT_STATUS_SHARING_VIOLATION;
+       }
+
+       /* quite an insane set of semantics ... */
+       if (is_exe_filename(io->generic.in.fname) &&
+           (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+               return NT_STATUS_SHARING_VIOLATION;
+       }
+
+       /*
+         setup a reference to the existing handle
+        */
+       talloc_free(f->handle);
+       f->handle = talloc_reference(f, f2->handle);
+
+       talloc_free(lck);
+
+       name = f->handle->name;
+
+       io->generic.out.oplock_level  = NO_OPLOCK;
+       io->generic.out.fnum          = f->fnum;
+       io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
+       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;
+       io->generic.out.change_time   = name->dos.change_time;
+       io->generic.out.attrib        = name->dos.attrib;
+       io->generic.out.alloc_size    = name->dos.alloc_size;
+       io->generic.out.size          = name->st.st_size;
+       io->generic.out.file_type     = FILE_TYPE_DISK;
+       io->generic.out.ipc_state     = 0;
+       io->generic.out.is_directory  = 0;
+
+       talloc_steal(f->pvfs, f);
+
+       return NT_STATUS_OK;
+}
+
+
+
 /*
   setup for a open retry after a sharing violation
 */
@@ -549,6 +628,16 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
        NTSTATUS status;
        struct timeval end_time;
 
+       if (io->generic.in.create_options & 
+           (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+               /* see if we can satisfy the request using the special DENY_DOS
+                  code */
+               status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
+               if (NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
        r = talloc_p(req, struct pvfs_open_retry);
        if (r == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -638,10 +727,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        /* use the generic mapping code to avoid implementing all the
-          different open calls. This won't allow openx to work
-          perfectly as the mapping code has no way of knowing if two
-          opens are on the same connection, so this will need to
-          change eventually */    
+          different open calls. */
        if (io->generic.level != RAW_OPEN_GENERIC) {
                return ntvfs_map_open(req, io, ntvfs);
        }
@@ -715,11 +801,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if ((access_mask & SA_RIGHT_FILE_READ_EXEC) &&
-           (access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+       if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
                flags |= O_RDWR;
-       } else if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
-               flags |= O_WRONLY;
        } else {
                flags |= O_RDONLY;
        }
@@ -766,19 +849,20 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_TOO_MANY_OPENED_FILES;
        }
 
-       f->fnum         = fnum;
-       f->session      = req->session;
-       f->smbpid       = req->smbpid;
-       f->pvfs         = pvfs;
-       f->pending_list = NULL;
-       f->lock_count   = 0;
+       f->fnum          = fnum;
+       f->session       = req->session;
+       f->smbpid        = req->smbpid;
+       f->pvfs          = pvfs;
+       f->pending_list  = NULL;
+       f->lock_count    = 0;
+       f->share_access  = io->generic.in.share_access;
+       f->access_mask   = access_mask;
+       f->impersonation = io->generic.in.impersonation;
 
        f->handle->pvfs              = pvfs;
        f->handle->fd                = -1;
        f->handle->name              = talloc_steal(f->handle, name);
        f->handle->create_options    = io->generic.in.create_options;
-       f->handle->share_access      = io->generic.in.share_access;
-       f->handle->access_mask       = access_mask;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->have_opendb_entry = False;
index fee3b19c9f74f46f0a3e71c1b12dc0ab62925849..c8134939a3a3d959928e608a07019a49fd34d99f 100644 (file)
@@ -283,7 +283,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
                break;
 
        case RAW_FILEINFO_ACCESS_INFORMATION:
-               info->access_information.out.access_flags = h->access_mask;
+               info->access_information.out.access_flags = f->access_mask;
                break;
 
        case RAW_FILEINFO_MODE_INFORMATION:
index b14a1e601c6462febf3317ab8e4a17d5a11ecc69..5598ccfb08537d5d9e8f9d028f6be38c8cb0aaaf 100644 (file)
@@ -54,7 +54,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
        if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
                mask |= SA_RIGHT_FILE_EXECUTE;
        }
-       if (!(f->handle->access_mask & mask)) {
+       if (!(f->access_mask & mask)) {
                return NT_STATUS_ACCESS_DENIED;
        }
 
index cad51c751cc362364deae0b948eaae9659429b41..a550fb03e446228cec0455fb311dcb661d99b82e 100644 (file)
@@ -202,7 +202,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
 
        case RAW_SFILEINFO_DISPOSITION_INFO:
        case RAW_SFILEINFO_DISPOSITION_INFORMATION:
-               if (!(h->access_mask & STD_RIGHT_DELETE_ACCESS)) {
+               if (!(f->access_mask & STD_RIGHT_DELETE_ACCESS)) {
                        return NT_STATUS_ACCESS_DENIED;
                }
                create_options = h->create_options;
@@ -255,7 +255,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
                if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
                        return NT_STATUS_FILE_IS_A_DIRECTORY;
                }
-               if (h->access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
+               if (f->access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
                        ret = ftruncate(h->fd, newstats.st.st_size);
                } else {
                        ret = truncate(h->name->full_name, newstats.st.st_size);
index 7b3812397189e686b073226837a423a96e4db7a2..6ebd9b70cff4dd7cf635334a71ba2244919a8f88 100644 (file)
@@ -48,7 +48,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
-       if (!(f->handle->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+       if (!(f->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
                return NT_STATUS_ACCESS_VIOLATION;
        }
 
index 3f74de4b63e4f2d008a24bfbff6e3c82755cbbca..46cc38c1f8abe657d73cc1216f760478970be433 100644 (file)
@@ -100,8 +100,6 @@ struct pvfs_file_handle {
        DATA_BLOB locking_key;
 
        uint32_t create_options;
-       uint32_t share_access;
-       uint32_t access_mask;
 
        /* this is set by the mode_information level. What does it do? */
        uint32_t mode;
@@ -124,6 +122,10 @@ struct pvfs_file {
 
        struct pvfs_state *pvfs;
 
+       uint32_t impersonation;
+       uint32_t share_access;
+       uint32_t access_mask;
+
        /* we need to remember the session it was opened on,
           as it is illegal to operate on someone elses fnum */
        struct smbsrv_session *session;
index 92ed4fe52aa885967a90c3a8c2d61d35ea613841..e1d6201a72a0ee66ca68870ffed3ccecb2151ba1 100755 (executable)
@@ -33,8 +33,8 @@ testit() {
 tests="BASE-FDPASS BASE-LOCK1 BASE-LOCK2 BASE-LOCK3 BASE-LOCK4"
 tests="$tests BASE-LOCK5 BASE-LOCK6 BASE-LOCK7 BASE-UNLINK BASE-ATTR"
 tests="$tests BASE-NEGNOWAIT BASE-DIR1 BASE-DIR2 BASE-VUID"
-tests="$tests BASE-DENY2 BASE-TCON BASE-TCONDEV BASE-RW1"
-tests="$tests BASE-DENY3 BASE-XCOPY BASE-OPEN"
+tests="$tests BASE-DENY1 BASE-DENY2 BASE-TCON BASE-TCONDEV BASE-RW1"
+tests="$tests BASE-DENY3 BASE-XCOPY BASE-OPEN BASE-DENYDOS"
 tests="$tests BASE-DELETE BASE-PROPERTIES BASE-MANGLE"
 tests="$tests BASE-CHKPATH BASE-SECLEAK BASE-TRANS2"
 tests="$tests BASE-NTDENY1 BASE-NTDENY2  BASE-RENAME BASE-OPENATTR"
@@ -43,7 +43,7 @@ tests="$tests RAW-LOCK RAW-MKDIR RAW-SEEK RAW-CONTEXT RAW-MUX RAW-OPEN"
 tests="$tests RAW-UNLINK RAW-READ RAW-CLOSE RAW-IOCTL RAW-SEARCH RAW-CHKPATH"
 tests="$tests LOCAL-ICONV LOCAL-TALLOC LOCAL-MESSAGING LOCAL-BINDING LOCAL-IDTREE"
 
-soon="BASE-DENY1 BASE-CHARSET"
+soon="BASE-CHARSET"
 soon="$soon RAW-SFILEINFO RAW-OPLOCK RAW-NOTIFY"
 soon="$soon RAW-WRITE RAW-RENAME"