summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2000-12-11 21:09:48 +0000
committerJeremy Allison <jra@samba.org>2000-12-11 21:09:48 +0000
commitccb5cbf175c43455a956d42b2815a4529ab9383f (patch)
tree814b327242a7655db0ea0b991c06f8715fb3706a
parenta95ccc27790cb8275f44df76fa6dc33a6a17c12e (diff)
downloadsamba-ccb5cbf175c43455a956d42b2815a4529ab9383f.tar.gz
samba-ccb5cbf175c43455a956d42b2815a4529ab9383f.tar.bz2
samba-ccb5cbf175c43455a956d42b2815a4529ab9383f.zip
Fixed very subtle bug returning correct error on an open, when we have
a choice of invalid share mode and access denied. We must return the access denied by preference, but also remember to break the oplocks... This is needed for multi-user MS-Access. Jeremy. (This used to be commit 7eb7241442ea0f1e065b009c3cccd5821b89a8b6)
-rw-r--r--source3/smbd/open.c30
-rw-r--r--source3/utils/torture.c71
2 files changed, 91 insertions, 10 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 258e463ecf..b23da55542 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -649,6 +649,20 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
num_share_modes = open_mode_check(conn, fname, dev, inode, share_mode,
&flags, &oplock_request, &all_current_opens_are_level_II);
if(num_share_modes == -1) {
+
+ /*
+ * This next line is a subtlety we need for MS-Access. If a file open will
+ * fail due to share permissions and also for security (access)
+ * reasons, we need to return the access failed error, not the
+ * share error. This means we must attempt to open the file anyway
+ * in order to get the UNIX access error - even if we're going to
+ * fail the open for share reasons. This is bad, as we're burning
+ * another fd if there are existing locks but there's nothing else
+ * we can do. We also ensure we're not going to create or tuncate
+ * the file as we only want an access decision at this stage. JRA.
+ */
+ open_file(fsp,conn,fname,psbuf,flags|(flags2&~(O_TRUNC|O_CREAT)),mode);
+
unlock_share_entry(conn, dev, inode);
file_free(fsp);
return NULL;
@@ -676,14 +690,6 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
return NULL;
}
- /* not that we ignore failure for the following. It is
- basically a hack for NFS, and NFS will never set one of
- these only read them. Nobody but Samba can ever set a deny
- mode and we have already checked our more authoritative
- locking database for permission to set this deny mode. If
- the kernel refuses the operations then the kernel is wrong */
- kernel_flock(fsp, deny_mode);
-
/*
* Deal with the race condition where two smbd's detect the file doesn't
* exist and do the create at the same time. One of them will win and
@@ -710,6 +716,14 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
*/
}
+ /* note that we ignore failure for the following. It is
+ basically a hack for NFS, and NFS will never set one of
+ these only read them. Nobody but Samba can ever set a deny
+ mode and we have already checked our more authoritative
+ locking database for permission to set this deny mode. If
+ the kernel refuses the operations then the kernel is wrong */
+ kernel_flock(fsp, deny_mode);
+
/*
* At this point onwards, we can guarentee that the share entry
* is locked, whether we created the file or not, and that the
diff --git a/source3/utils/torture.c b/source3/utils/torture.c
index d9aa6bfca0..cd348f67fd 100644
--- a/source3/utils/torture.c
+++ b/source3/utils/torture.c
@@ -2010,7 +2010,7 @@ static void run_oplock2(int dummy)
printf("lock failed (%s)\n", cli_errstr(&cli1));
}
- cli_unlock(&cli, fnum1, 0, 4);
+ cli_unlock(&cli1, fnum1, 0, 4);
sleep(2);
@@ -2018,7 +2018,7 @@ static void run_oplock2(int dummy)
printf("lock failed (%s)\n", cli_errstr(&cli1));
}
- cli_unlock(&cli, fnum1, 0, 4);
+ cli_unlock(&cli1, fnum1, 0, 4);
sleep(2);
@@ -2045,6 +2045,72 @@ static void run_oplock2(int dummy)
printf("finished oplock test 2\n");
}
+/*
+ Test open mode returns on read-only files.
+ */
+static void run_opentest(int dummy)
+{
+ static struct cli_state cli1;
+ char *fname = "\\readonly.file";
+ int fnum1, fnum2;
+ uint8 eclass;
+ uint32 errnum;
+
+ printf("starting open test\n");
+
+ if (!open_connection(&cli1)) {
+ return;
+ }
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ cli_sockopt(&cli1, sockops);
+
+ fnum1 = cli_open(&cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_close(&cli1, fnum1)) {
+ printf("close2 failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ if (!cli_setatr(&cli1, fname, aRONLY, 0)) {
+ printf("cli_setatr failed (%s)\n", cli_errstr(&cli1));
+ return;
+ }
+
+ fnum1 = cli_open(&cli1, fname, O_RDONLY, DENY_WRITE);
+ if (fnum1 == -1) {
+ printf("open of %s failed (%s)\n", fname, cli_errstr(&cli1));
+ return;
+ }
+
+ /* This will fail - but the error should be ERRnoaccess, not ERRshare. */
+ fnum2 = cli_open(&cli1, fname, O_RDWR, DENY_ALL);
+
+ cli_error( &cli1, &eclass, &errnum, NULL);
+
+ if (eclass != ERRDOS || errnum != ERRnoaccess) {
+ printf("wrong error code (%x,%x) = %s\n", (unsigned int)eclass,
+ (unsigned int)errnum, cli_errstr(&cli1) );
+ } else {
+ printf("correct error code ERRDOS/ERRnoaccess returned\n");
+ }
+
+
+ cli_close(&cli1, fnum1);
+
+ cli_setatr(&cli1, fname, 0, 0);
+ cli_unlink(&cli1, fname);
+
+ close_connection(&cli1);
+
+ printf("finished open test 1\n");
+}
static void list_fn(file_info *finfo, const char *name)
{
@@ -2212,6 +2278,7 @@ static struct {
{"TCON", run_tcon_test, 0},
{"RW1", run_readwritetest, 0},
{"RW2", run_readwritemulti, FLAG_MULTIPROC},
+ {"OPEN", run_opentest, 0},
{NULL, NULL, 0}};