r3147: added basic share modes support for pvfs (or more precisely, ntcreatex
authorAndrew Tridgell <tridge@samba.org>
Sun, 24 Oct 2004 08:31:41 +0000 (08:31 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:02:25 +0000 (13:02 -0500)
share_access support).  This is enough for us to pass the BASE-DENY2
test, but is a long way from fully correct share modes.
(This used to be commit b5a6dd3cbf28a3a3b3a3656042ac8f50fca29e1c)

source4/ntvfs/common/opendb.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_read.c
source4/ntvfs/posix/pvfs_write.c
source4/ntvfs/posix/vfs_posix.h

index 3b80145414afc7bcd3cc9a0133662bf3a031a16d..f074c31f6eb5bb3316387b8bf342305aa14e0fe6 100644 (file)
@@ -56,8 +56,8 @@ struct odb_entry {
        uint16_t tid;
        uint16_t fnum;
        uint32_t share_access;
-       uint32_t desired_access;
        uint32_t create_options;
+       uint32_t access_mask;
 };
 
 
@@ -144,3 +144,140 @@ struct odb_lock *odb_lock(TALLOC_CTX *mem_ctx,
        
        return lck;
 }
+
+
+/*
+  determine if two odb_entry structures conflict
+*/
+static BOOL share_conflict(struct odb_entry *e1, struct odb_entry *e2)
+{
+       uint32_t m1, m2;
+
+       m1 = e1->access_mask & (SA_RIGHT_FILE_WRITE_DATA | SA_RIGHT_FILE_READ_DATA);
+       m2 = e2->share_access & 
+               (NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_READ);
+
+       if ((m1 & m2) != m1) {
+               return True;
+       }
+
+       m1 = e2->access_mask & (SA_RIGHT_FILE_WRITE_DATA | SA_RIGHT_FILE_READ_DATA);
+       m2 = e1->share_access & 
+               (NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_READ);
+
+       if ((m1 & m2) != m1) {
+               return True;
+       }
+
+       return False;
+}
+
+/*
+  register an open file in the open files database. This implements the share_access
+  rules
+*/
+NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum, 
+                      uint32_t share_access, uint32_t create_options,
+                      uint32_t access_mask)
+{
+       struct odb_context *odb = lck->odb;
+       TDB_DATA dbuf;
+       struct odb_entry e;
+       char *tp;
+       int i, count;
+       struct odb_entry *elist;
+               
+       dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+       e.server         = odb->server;
+       e.tid            = odb->tid;
+       e.fnum           = fnum;
+       e.share_access   = share_access;
+       e.create_options = create_options;
+       e.access_mask    = access_mask;
+
+       /* check the existing file opens to see if they
+          conflict */
+       elist = (struct odb_entry *)dbuf.dptr;
+       count = dbuf.dsize / sizeof(struct odb_entry);
+
+       for (i=0;i<count;i++) {
+               if (share_conflict(elist+i, &e)) {
+                       if (dbuf.dptr) free(dbuf.dptr);
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
+       }
+
+       tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry));
+       if (tp == NULL) {
+               if (dbuf.dptr) free(dbuf.dptr);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dbuf.dptr = tp;
+       dbuf.dsize = (count+1) * sizeof(struct odb_entry);
+
+       memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
+              &e, sizeof(struct odb_entry));
+
+       if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+               free(dbuf.dptr);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       free(dbuf.dptr);
+       return NT_STATUS_OK;
+}
+
+
+/*
+  remove a opendb entry
+*/
+NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
+{
+       struct odb_context *odb = lck->odb;
+       TDB_DATA dbuf;
+       struct odb_entry *elist;
+       int i, count;
+       NTSTATUS status;
+
+       dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+       if (dbuf.dptr == NULL) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       elist = (struct odb_entry *)dbuf.dptr;
+       count = dbuf.dsize / sizeof(struct odb_entry);
+
+       /* find the entry, and delete it */
+       for (i=0;i<count;i++) {
+               if (fnum == elist[i].fnum &&
+                   odb->server == elist[i].server &&
+                   odb->tid == elist[i].tid) {
+                       if (i < count-1) {
+                               memmove(elist+i, elist+i+1, count - (i+1));
+                       }
+                       break;
+               }
+       }
+
+       status = NT_STATUS_OK;
+
+       if (i == count) {
+               status = NT_STATUS_UNSUCCESSFUL;
+       } else if (count == 1) {
+               if (tdb_delete(odb->w->tdb, lck->key) != 0) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       } else {
+               dbuf.dsize = (count-1) * sizeof(struct odb_entry);
+               if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+                       status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       }
+
+       free(dbuf.dptr);
+
+       return status;
+}
index 482f71b9a3d753e765b264e843503118449de574..90de303a9d9762ac23d16525c34a734b7a3586e7 100644 (file)
@@ -78,30 +78,6 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
-       f = talloc_p(req, struct pvfs_file);
-       if (f == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
-       if (fnum == -1) {
-               talloc_free(f);
-               return NT_STATUS_TOO_MANY_OPENED_FILES;
-       }
-
-       f->fnum = fnum;
-       f->fd = -1;
-       f->name = talloc_steal(f, name);
-       f->session = req->session;
-       f->smbpid = req->smbpid;
-       f->pvfs = pvfs;
-       f->pending_list = NULL;
-       f->lock_count = 0;
-       f->locking_key = data_blob(NULL, 0);
-
-       /* setup a destructor to avoid leaks on abnormal termination */
-       talloc_set_destructor(f, pvfs_dir_fd_destructor);
-
        switch (io->generic.in.open_disposition) {
        case NTCREATEX_DISP_OPEN_IF:
                break;
@@ -125,6 +101,38 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       f = talloc_p(req, struct pvfs_file);
+       if (f == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       f->fnum = fnum;
+       f->fd = -1;
+       f->name = talloc_steal(f, name);
+       f->session = req->session;
+       f->smbpid = req->smbpid;
+       f->pvfs = pvfs;
+       f->pending_list = NULL;
+       f->lock_count = 0;
+       f->locking_key = data_blob(NULL, 0);
+       f->create_options = io->generic.in.create_options;
+       f->share_access = io->generic.in.share_access;
+
+       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+       if (fnum == -1) {
+               talloc_free(f);
+               return NT_STATUS_TOO_MANY_OPENED_FILES;
+       }
+
+       DLIST_ADD(pvfs->open_files, f);
+
+       /* TODO: should we check in the opendb? Do directory opens 
+          follow the share_access rules? */
+
+
+       /* setup a destructor to avoid leaks on abnormal termination */
+       talloc_set_destructor(f, pvfs_dir_fd_destructor);
+
        if (!name->exists) {
                if (mkdir(name->full_name, 0755) == -1) {
                        return pvfs_map_errno(pvfs,errno);
@@ -143,8 +151,6 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       DLIST_ADD(pvfs->open_files, f);
-
        /* the open succeeded, keep this handle permanently */
        talloc_steal(pvfs, f);
 
@@ -174,6 +180,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
 static int pvfs_fd_destructor(void *p)
 {
        struct pvfs_file *f = p;
+       struct odb_lock *lck;
+       NTSTATUS status;
 
        DLIST_REMOVE(f->pvfs->open_files, f);
 
@@ -186,6 +194,18 @@ static int pvfs_fd_destructor(void *p)
 
        idr_remove(f->pvfs->idtree_fnum, f->fnum);
 
+       lck = odb_lock(f, f->pvfs->odb_context, &f->locking_key);
+       if (lck == NULL) {
+               DEBUG(0,("Unabled to lock opendb for close\n"));
+               return 0;
+       }
+
+       status = odb_close_file(lck, f->fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Unabled to remove opendb entry for '%s' - %s\n", 
+                        f->name->full_name, nt_errstr(status)));
+       }
+
        return 0;
 }
 
@@ -228,7 +248,10 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        NTSTATUS status;
        int flags, fnum, fd;
        struct odb_lock *lck;
-
+       uint32_t create_options = io->generic.in.create_options;
+       uint32_t share_access = io->generic.in.share_access;
+       uint32_t access_mask = io->generic.in.access_mask;
+       
        flags = O_RDWR;
 
        f = talloc_p(req, struct pvfs_file);
@@ -252,6 +275,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        status = pvfs_resolve_name_fd(pvfs, fd, name);
        if (!NT_STATUS_IS_OK(status)) {
                idr_remove(pvfs->idtree_fnum, fnum);
+               close(fd);
                return status;
        }
 
@@ -260,6 +284,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        status = pvfs_locking_key(name, f, &f->locking_key);
        if (!NT_STATUS_IS_OK(status)) {
                idr_remove(pvfs->idtree_fnum, fnum);
+               close(fd);
                return status;
        }
 
@@ -271,9 +296,18 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                /* we were supposed to do a blocking lock, so something
                   is badly wrong! */
                idr_remove(pvfs->idtree_fnum, fnum);
+               close(fd);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
+       status = odb_open_file(lck, fnum, share_access, create_options, access_mask);
+       if (!NT_STATUS_IS_OK(status)) {
+               /* bad news, we must have hit a race */
+               idr_remove(pvfs->idtree_fnum, fnum);
+               close(fd);
+               return status;
+       }
+
        f->fnum = fnum;
        f->fd = fd;
        f->name = talloc_steal(f, name);
@@ -282,6 +316,9 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->pvfs = pvfs;
        f->pending_list = NULL;
        f->lock_count = 0;
+       f->create_options = io->generic.in.create_options;
+       f->share_access = io->generic.in.share_access;
+       f->access_mask = io->generic.in.access_mask;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -306,10 +343,6 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        /* success - keep the file handle */
        talloc_steal(pvfs, f);
 
-       /* release the opendb lock (in case a chained request
-          blocks) */
-       talloc_free(lck);
-
        return NT_STATUS_OK;
 }
 
@@ -327,6 +360,9 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        NTSTATUS status;
        int fnum;
        struct odb_lock *lck;
+       uint32_t create_options;
+       uint32_t share_access;
+       uint32_t access_mask;
 
        /* use the generic mapping code to avoid implementing all the
           different open calls. This won't allow openx to work
@@ -420,10 +456,17 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_NO_MEMORY;
        }
 
+       /* allocate a fnum */
+       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
+       if (fnum == -1) {
+               return NT_STATUS_TOO_MANY_OPENED_FILES;
+       }
+
        /* form the lock context used for byte range locking and
           opendb locking */
        status = pvfs_locking_key(name, f, &f->locking_key);
        if (!NT_STATUS_IS_OK(status)) {
+               idr_remove(pvfs->idtree_fnum, fnum);
                return status;
        }
 
@@ -434,9 +477,21 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                         name->full_name));
                /* we were supposed to do a blocking lock, so something
                   is badly wrong! */
+               idr_remove(pvfs->idtree_fnum, fnum);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
+       create_options = io->generic.in.create_options;
+       share_access   = io->generic.in.share_access;
+       access_mask    = io->generic.in.access_mask;
+
+       /* see if we are allowed to open at the same time as existing opens */
+       status = odb_open_file(lck, fnum, share_access, create_options, access_mask);
+       if (!NT_STATUS_IS_OK(status)) {
+               idr_remove(pvfs->idtree_fnum, fnum);
+               return status;
+       }
+
        /* do the actual open */
        fd = open(name->full_name, flags);
        if (fd == -1) {
@@ -446,15 +501,11 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        /* re-resolve the open fd */
        status = pvfs_resolve_name_fd(pvfs, fd, name);
        if (!NT_STATUS_IS_OK(status)) {
+               close(fd);
+               idr_remove(pvfs->idtree_fnum, fnum);
                return status;
        }
 
-       /* allocate a fnum */
-       fnum = idr_get_new(pvfs->idtree_fnum, f, UINT16_MAX);
-       if (fnum == -1) {
-               return NT_STATUS_TOO_MANY_OPENED_FILES;
-       }
-
        f->fnum = fnum;
        f->fd = fd;
        f->name = talloc_steal(f, name);
@@ -463,6 +514,9 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->pvfs = pvfs;
        f->pending_list = NULL;
        f->lock_count = 0;
+       f->create_options = io->generic.in.create_options;
+       f->share_access = io->generic.in.share_access;
+       f->access_mask = io->generic.in.access_mask;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -487,9 +541,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        /* success - keep the file handle */
        talloc_steal(pvfs, f);
 
-       /* unlock the locking database */
-       talloc_free(lck);
-
        return NT_STATUS_OK;
 }
 
index 7256fd8e169da7fdcda379bcaabc577de3b44b73..530fb8279840e38e6ed5563d246514dd1586dc89 100644 (file)
@@ -47,6 +47,10 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
+       if (!(f->access_mask & SA_RIGHT_FILE_READ_DATA)) {
+               return NT_STATUS_ACCESS_VIOLATION;
+       }
+
        status = pvfs_check_lock(pvfs, f, req->smbpid, 
                                 rd->readx.in.offset,
                                 rd->readx.in.maxcnt,
index 8bbb4f860555ec8efce513846cb3aeddb01dcdce..a7b7084a08619e4dfd82a64953c5a36ad57b28f1 100644 (file)
@@ -48,6 +48,10 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
+       if (!(f->access_mask & SA_RIGHT_FILE_WRITE_DATA)) {
+               return NT_STATUS_ACCESS_VIOLATION;
+       }
+
        status = pvfs_check_lock(pvfs, f, req->smbpid, 
                                 wr->writex.in.offset,
                                 wr->writex.in.count,
index 59924b0b1ba0ffa7c62677a81a5d33dc86b3d57d..0bd01f53777c311e788efbffb37c09072917d65f 100644 (file)
@@ -121,6 +121,10 @@ struct pvfs_file {
        /* a count of active locks - used to avoid calling brl_close on
           file close */
        uint64_t lock_count;
+
+       uint32_t create_options;
+       uint32_t share_access;
+       uint32_t access_mask;
 };