mirror of
https://github.com/samba-team/samba.git
synced 2025-11-02 20:23:50 +03:00
r3147: added basic share modes support for pvfs (or more precisely, ntcreatex
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 commit is contained in:
committed by
Gerald (Jerry) Carter
parent
18b471327b
commit
b5a6dd3cbf
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user