summaryrefslogtreecommitdiff
path: root/source4/ntvfs
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs')
-rw-r--r--source4/ntvfs/ntvfs_generic.c10
-rw-r--r--source4/ntvfs/posix/pvfs_open.c154
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c2
-rw-r--r--source4/ntvfs/posix/pvfs_read.c2
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c4
-rw-r--r--source4/ntvfs/posix/pvfs_write.c2
-rw-r--r--source4/ntvfs/posix/vfs_posix.h6
7 files changed, 135 insertions, 45 deletions
diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c
index 9ef2481d26..a9bc8120c8 100644
--- a/source4/ntvfs/ntvfs_generic.c
+++ b/source4/ntvfs/ntvfs_generic.c
@@ -117,7 +117,7 @@ static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS stat
see if a filename ends in EXE COM DLL or SYM. This is needed for the
DENY_DOS mapping for OpenX
*/
-static BOOL is_exe_file(const char *fname)
+BOOL is_exe_filename(const char *fname)
{
char *p;
p = strrchr(fname, '.');
@@ -315,7 +315,9 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
break;
case OPENX_MODE_DENY_DOS:
/* DENY_DOS is quite strange - it depends on the filename! */
- if (is_exe_file(io->openx.in.fname)) {
+ io2->generic.in.create_options |=
+ NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+ if (is_exe_filename(io->openx.in.fname)) {
io2->generic.in.share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE;
@@ -329,6 +331,8 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
}
break;
case OPENX_MODE_DENY_FCB:
+ io2->generic.in.create_options |=
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
break;
default:
@@ -400,7 +404,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
switch (io->openold.in.flags & OPEN_FLAGS_DENY_MASK) {
case OPEN_FLAGS_DENY_DOS:
/* DENY_DOS is quite strange - it depends on the filename! */
- if (is_exe_file(io->openold.in.fname)) {
+ if (is_exe_filename(io->openold.in.fname)) {
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
} else {
if ((io->openold.in.flags & OPEN_FLAGS_MODE_MASK) ==
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 5411f83e8d..cfd2b0f159 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -147,19 +147,20 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
- f->fnum = fnum;
- f->session = req->session;
- f->smbpid = req->smbpid;
- f->pvfs = pvfs;
- f->pending_list = NULL;
- f->lock_count = 0;
+ f->fnum = fnum;
+ f->session = req->session;
+ f->smbpid = req->smbpid;
+ f->pvfs = pvfs;
+ f->pending_list = NULL;
+ f->lock_count = 0;
+ f->share_access = io->generic.in.share_access;
+ f->impersonation = io->generic.in.impersonation;
f->handle->pvfs = pvfs;
f->handle->name = talloc_steal(f->handle, name);
f->handle->fd = -1;
f->handle->locking_key = data_blob(NULL, 0);
f->handle->create_options = io->generic.in.create_options;
- f->handle->share_access = io->generic.in.share_access;
f->handle->seek_offset = 0;
f->handle->position = 0;
f->handle->mode = 0;
@@ -326,11 +327,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE;
}
- if ((access_mask & SA_RIGHT_FILE_READ_EXEC) &&
- (access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+ if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
flags = O_RDWR;
- } else if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
- flags = O_WRONLY;
} else {
flags = O_RDONLY;
}
@@ -407,19 +405,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
return status;
}
- f->fnum = fnum;
- f->session = req->session;
- f->smbpid = req->smbpid;
- f->pvfs = pvfs;
- f->pending_list = NULL;
- f->lock_count = 0;
+ f->fnum = fnum;
+ f->session = req->session;
+ f->smbpid = req->smbpid;
+ f->pvfs = pvfs;
+ f->pending_list = NULL;
+ f->lock_count = 0;
+ f->share_access = io->generic.in.share_access;
+ f->access_mask = access_mask;
+ f->impersonation = io->generic.in.impersonation;
f->handle->pvfs = pvfs;
f->handle->name = talloc_steal(f->handle, name);
f->handle->fd = fd;
f->handle->create_options = io->generic.in.create_options;
- f->handle->share_access = io->generic.in.share_access;
- f->handle->access_mask = access_mask;
f->handle->seek_offset = 0;
f->handle->position = 0;
f->handle->mode = 0;
@@ -536,6 +535,86 @@ static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
/*
+ special handling for openx DENY_DOS semantics
+
+ This function attempts a reference open using an existing handle. If its allowed,
+ then it returns NT_STATUS_OK, otherwise it returns any other code and normal
+ open processing continues.
+*/
+static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
+ struct smbsrv_request *req, union smb_open *io,
+ struct pvfs_file *f, struct odb_lock *lck)
+{
+ struct pvfs_state *pvfs = ntvfs->private_data;
+ struct pvfs_file *f2;
+ struct pvfs_filename *name;
+
+ /* search for an existing open with the right parameters. Note
+ the magic ntcreatex options flag, which is set in the
+ generic mapping code. This might look ugly, but its
+ actually pretty much now w2k does it internally as well.
+
+ If you look at the BASE-DENYDOS test you will see that a
+ DENY_DOS is a very special case, and in the right
+ circumstances you actually get the _same_ handle back
+ twice, rather than a new handle.
+ */
+ for (f2=pvfs->open_files;f2;f2=f2->next) {
+ if (f2 != f &&
+ f2->session == req->session &&
+ f2->smbpid == req->smbpid &&
+ (f2->handle->create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
+ NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
+ (f2->access_mask & SA_RIGHT_FILE_WRITE_DATA) &&
+ StrCaseCmp(f2->handle->name->original_name,
+ io->generic.in.fname)==0) {
+ break;
+ }
+ }
+
+ if (!f2) {
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ /* quite an insane set of semantics ... */
+ if (is_exe_filename(io->generic.in.fname) &&
+ (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
+ return NT_STATUS_SHARING_VIOLATION;
+ }
+
+ /*
+ setup a reference to the existing handle
+ */
+ talloc_free(f->handle);
+ f->handle = talloc_reference(f, f2->handle);
+
+ talloc_free(lck);
+
+ name = f->handle->name;
+
+ io->generic.out.oplock_level = NO_OPLOCK;
+ io->generic.out.fnum = f->fnum;
+ io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
+ io->generic.out.create_time = name->dos.create_time;
+ io->generic.out.access_time = name->dos.access_time;
+ io->generic.out.write_time = name->dos.write_time;
+ io->generic.out.change_time = name->dos.change_time;
+ io->generic.out.attrib = name->dos.attrib;
+ io->generic.out.alloc_size = name->dos.alloc_size;
+ io->generic.out.size = name->st.st_size;
+ io->generic.out.file_type = FILE_TYPE_DISK;
+ io->generic.out.ipc_state = 0;
+ io->generic.out.is_directory = 0;
+
+ talloc_steal(f->pvfs, f);
+
+ return NT_STATUS_OK;
+}
+
+
+
+/*
setup for a open retry after a sharing violation
*/
static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
@@ -549,6 +628,16 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
NTSTATUS status;
struct timeval end_time;
+ if (io->generic.in.create_options &
+ (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
+ /* see if we can satisfy the request using the special DENY_DOS
+ code */
+ status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
r = talloc_p(req, struct pvfs_open_retry);
if (r == NULL) {
return NT_STATUS_NO_MEMORY;
@@ -638,10 +727,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
}
/* use the generic mapping code to avoid implementing all the
- different open calls. This won't allow openx to work
- perfectly as the mapping code has no way of knowing if two
- opens are on the same connection, so this will need to
- change eventually */
+ different open calls. */
if (io->generic.level != RAW_OPEN_GENERIC) {
return ntvfs_map_open(req, io, ntvfs);
}
@@ -715,11 +801,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_PARAMETER;
}
- if ((access_mask & SA_RIGHT_FILE_READ_EXEC) &&
- (access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+ if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
flags |= O_RDWR;
- } else if (access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
- flags |= O_WRONLY;
} else {
flags |= O_RDONLY;
}
@@ -766,19 +849,20 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return NT_STATUS_TOO_MANY_OPENED_FILES;
}
- f->fnum = fnum;
- f->session = req->session;
- f->smbpid = req->smbpid;
- f->pvfs = pvfs;
- f->pending_list = NULL;
- f->lock_count = 0;
+ f->fnum = fnum;
+ f->session = req->session;
+ f->smbpid = req->smbpid;
+ f->pvfs = pvfs;
+ f->pending_list = NULL;
+ f->lock_count = 0;
+ f->share_access = io->generic.in.share_access;
+ f->access_mask = access_mask;
+ f->impersonation = io->generic.in.impersonation;
f->handle->pvfs = pvfs;
f->handle->fd = -1;
f->handle->name = talloc_steal(f->handle, name);
f->handle->create_options = io->generic.in.create_options;
- f->handle->share_access = io->generic.in.share_access;
- f->handle->access_mask = access_mask;
f->handle->seek_offset = 0;
f->handle->position = 0;
f->handle->have_opendb_entry = False;
diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c
index fee3b19c9f..c8134939a3 100644
--- a/source4/ntvfs/posix/pvfs_qfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_qfileinfo.c
@@ -283,7 +283,7 @@ NTSTATUS pvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
break;
case RAW_FILEINFO_ACCESS_INFORMATION:
- info->access_information.out.access_flags = h->access_mask;
+ info->access_information.out.access_flags = f->access_mask;
break;
case RAW_FILEINFO_MODE_INFORMATION:
diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c
index b14a1e601c..5598ccfb08 100644
--- a/source4/ntvfs/posix/pvfs_read.c
+++ b/source4/ntvfs/posix/pvfs_read.c
@@ -54,7 +54,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs,
if (req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) {
mask |= SA_RIGHT_FILE_EXECUTE;
}
- if (!(f->handle->access_mask & mask)) {
+ if (!(f->access_mask & mask)) {
return NT_STATUS_ACCESS_DENIED;
}
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index cad51c751c..a550fb03e4 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -202,7 +202,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
case RAW_SFILEINFO_DISPOSITION_INFO:
case RAW_SFILEINFO_DISPOSITION_INFORMATION:
- if (!(h->access_mask & STD_RIGHT_DELETE_ACCESS)) {
+ if (!(f->access_mask & STD_RIGHT_DELETE_ACCESS)) {
return NT_STATUS_ACCESS_DENIED;
}
create_options = h->create_options;
@@ -255,7 +255,7 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
if (h->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
- if (h->access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
+ if (f->access_mask & SA_RIGHT_FILE_WRITE_APPEND) {
ret = ftruncate(h->fd, newstats.st.st_size);
} else {
ret = truncate(h->name->full_name, newstats.st.st_size);
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 7b38123971..6ebd9b70cf 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -48,7 +48,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
- if (!(f->handle->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
+ if (!(f->access_mask & SA_RIGHT_FILE_WRITE_APPEND)) {
return NT_STATUS_ACCESS_VIOLATION;
}
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 3f74de4b63..46cc38c1f8 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -100,8 +100,6 @@ struct pvfs_file_handle {
DATA_BLOB locking_key;
uint32_t create_options;
- uint32_t share_access;
- uint32_t access_mask;
/* this is set by the mode_information level. What does it do? */
uint32_t mode;
@@ -124,6 +122,10 @@ struct pvfs_file {
struct pvfs_state *pvfs;
+ uint32_t impersonation;
+ uint32_t share_access;
+ uint32_t access_mask;
+
/* we need to remember the session it was opened on,
as it is illegal to operate on someone elses fnum */
struct smbsrv_session *session;