Fixed nastly little bug where client was sending open_and_X call
authorJeremy Allison <jra@samba.org>
Tue, 23 Dec 1997 13:21:36 +0000 (13:21 +0000)
committerJeremy Allison <jra@samba.org>
Tue, 23 Dec 1997 13:21:36 +0000 (13:21 +0000)
with smb_mode (smb_vwv[3]) of 0x20 == DENY_WRITE + read-only-open.
and smb_ofun (smb_vwv[8]) of 0x11 == Create if not exist plus append
on a read-only share.
This was mapped into the strange unix flags of (O_RDONLY|O_CREAT)
- essentially O_CREAT as O_RDONLY == 0.
We were checking the unix flags directly against O_RDONLY instead
of masking off the open mode flag bits before doing the comparison,
so this open was being refused even though it was valid on a
read-only share.
Also ensured that the O_CREAT bit was masked out of the flags
bit if the open was done on a read-only share (as doing a unix
open( filename, O_RDONLY|O_CREAT, xxx) will create a zero length
file if the user had permission to write into the directory - which
should be denied on a read-only share.
Thanks to Mark Peek @ Whistle for giving me this test case.
Jeremy.

source/smbd/server.c

index 76a9fb272a04bcfa3dc9465d6419dcc5a1eb0584..5e5f129959ca1bd69e896400ad9c2391a17c2b2e 100644 (file)
@@ -1151,6 +1151,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   struct stat statbuf;
   file_fd_struct *fd_ptr;
   files_struct *fsp = &Files[fnum];
   struct stat statbuf;
   file_fd_struct *fd_ptr;
   files_struct *fsp = &Files[fnum];
+  int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
 
   fsp->open = False;
   fsp->fd_ptr = 0;
 
   fsp->open = False;
   fsp->fd_ptr = 0;
@@ -1160,12 +1161,32 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   pstrcpy(fname,fname1);
 
   /* check permissions */
   pstrcpy(fname,fname1);
 
   /* check permissions */
-  if ((flags != O_RDONLY) && !CAN_WRITE(cnum) && !Connections[cnum].printer)
-    {
+
+  /*
+   * This code was changed after seeing a client open request 
+   * containing the open mode of (DENY_WRITE/read-only) with
+   * the 'create if not exist' bit set. The previous code
+   * would fail to open the file read only on a read-only share
+   * as it was checking the flags parameter  directly against O_RDONLY,
+   * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
+   * JRA.
+   */
+
+  if (!CAN_WRITE(cnum) && !Connections[cnum].printer) {
+    /* It's a read-only share - fail if we wanted to write. */
+    if(accmode != O_RDONLY) {
       DEBUG(3,("Permission denied opening %s\n",fname));
       check_for_pipe(fname);
       return;
     }
       DEBUG(3,("Permission denied opening %s\n",fname));
       check_for_pipe(fname);
       return;
     }
+    else if(flags & O_CREAT) {
+      /* We don't want to write - but we must make sure that O_CREAT
+         doesn't create the file if we have write access into the
+         directory.
+       */
+      flags &= ~O_CREAT;
+    }
+  }
 
   /* this handles a bug in Win95 - it doesn't say to create the file when it 
      should */
 
   /* this handles a bug in Win95 - it doesn't say to create the file when it 
      should */
@@ -1203,8 +1224,6 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
    */
   if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
 
    */
   if((fd_ptr = fd_get_already_open(sbuf))!= 0) {
 
-    int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
-
     /* File was already open. */
     if((flags & O_CREAT) && (flags & O_EXCL)) {
       fd_ptr->ref_count--;
     /* File was already open. */
     if((flags & O_CREAT) && (flags & O_EXCL)) {
       fd_ptr->ref_count--;