diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/ntvfs/common/opendb.c | 139 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 131 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_read.c | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_write.c | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 4 |
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; }; |