diff options
author | Jeremy Allison <jra@samba.org> | 2000-12-11 21:09:48 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2000-12-11 21:09:48 +0000 |
commit | ccb5cbf175c43455a956d42b2815a4529ab9383f (patch) | |
tree | 814b327242a7655db0ea0b991c06f8715fb3706a /source3 | |
parent | a95ccc27790cb8275f44df76fa6dc33a6a17c12e (diff) | |
download | samba-ccb5cbf175c43455a956d42b2815a4529ab9383f.tar.gz samba-ccb5cbf175c43455a956d42b2815a4529ab9383f.tar.xz 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)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/smbd/open.c | 30 | ||||
-rw-r--r-- | source3/utils/torture.c | 71 |
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}}; |