1
0
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:
Andrew Tridgell
2004-10-24 08:31:41 +00:00
committed by Gerald (Jerry) Carter
parent 18b471327b
commit b5a6dd3cbf
5 changed files with 241 additions and 41 deletions

View 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;
}

View 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;
}

View 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,

View 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,

View 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;
};