summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/ntvfs/common/opendb.c139
-rw-r--r--source4/ntvfs/posix/pvfs_open.c131
-rw-r--r--source4/ntvfs/posix/pvfs_read.c4
-rw-r--r--source4/ntvfs/posix/pvfs_write.c4
-rw-r--r--source4/ntvfs/posix/vfs_posix.h4
5 files changed, 241 insertions, 41 deletions
diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c
index 3b80145414..f074c31f6e 100644
--- a/source4/ntvfs/common/opendb.c
+++ b/source4/ntvfs/common/opendb.c
@@ -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;
+}
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 482f71b9a3..90de303a9d 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c
index 7256fd8e16..530fb82798 100644
--- a/source4/ntvfs/posix/pvfs_read.c
+++ b/source4/ntvfs/posix/pvfs_read.c
@@ -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,
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 8bbb4f8605..a7b7084a08 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -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,
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 59924b0b1b..0bd01f5377 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -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;
};