Fixed an apparent typo:
[samba.git] / source3 / smbd / server.c
index 536e89bf186672b396509add605656982fe149a7..29a0d462f3d4df82eb143fd48b2d2cd8f4480f0e 100644 (file)
@@ -452,8 +452,20 @@ static BOOL scan_directory(char *path, char *name,int cnum,BOOL docache)
     return(True);
   }      
 
+#if 0 
+  /* 
+   * This code I believe is incorrect - and commenting it out
+   * is the correct fix for the bug mentioned below in the
+   * comment 'name2 here was changed to dname - since 1.9.16p2 - not sure of reason (jra)'.
+   * The incoming name can be mangled, and if we de-mangle it
+   * here it will not compare correctly against the filename (name2)
+   * read from the directory and then mangled by the name_map_mangle()
+   * call. We need to mangle both names or neither.
+   * (JRA).
+   */
   if (mangled)
     check_mangled_stack(name);
+#endif 
 
   /* open the directory */
   if (!(cur_dir = OpenDir(cnum, path, True))) 
@@ -1139,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];
+  int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
 
   fsp->open = False;
   fsp->fd_ptr = 0;
@@ -1148,12 +1161,32 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
   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;
     }
+    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 */
@@ -1191,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) {
 
-    int accmode = (flags & (O_RDONLY | O_WRONLY | O_RDWR));
-
     /* File was already open. */
     if((flags & O_CREAT) && (flags & O_EXCL)) {
       fd_ptr->ref_count--;
@@ -1326,6 +1357,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct
       fsp->print_file = Connections[cnum].printer;
       fsp->modified = False;
       fsp->granted_oplock = False;
+      fsp->sent_oplock_break = False;
       fsp->cnum = cnum;
       string_set(&fsp->name,dos_to_unix(fname,False));
       fsp->wbmpx_ptr = NULL;      
@@ -1476,6 +1508,8 @@ void close_file(int fnum, BOOL normal_close)
   if(fs_p->granted_oplock == True)
     global_oplocks_open--;
 
+  fs_p->sent_oplock_break = False;
+
   DEBUG(2,("%s %s closed file %s (numopen=%d)\n",
           timestring(),Connections[cnum].user,fs_p->name,
           Connections[cnum].num_files_open));
@@ -1935,6 +1969,7 @@ dev = %x, inode = %x\n", old_shares[i].op_type, fname, dev, inode));
              !IS_VETO_OPLOCK_PATH(cnum,fname))
       {
         fs_p->granted_oplock = True;
+        fs_p->sent_oplock_break = False;
         global_oplocks_open++;
         port = oplock_port;
 
@@ -2513,7 +2548,7 @@ max can be %d\n", num_interfaces, FD_SETSIZE));
           return True; 
         }
         close(Client); /* The parent doesn't need this socket */
-#endif /NO_FORK_DEBUG */
+#endif /NO_FORK_DEBUG */
       } /* end for num */
     } /* end while 1 */
   } /* end if is_daemon */
@@ -2579,6 +2614,8 @@ static void process_smb(char *inbuf, char *outbuf)
 
   if (msg_type == 0)
     show_msg(inbuf);
+  else if(msg_type == 0x85)
+    return; /* Keepalive packet. */
 
   nread = construct_reply(inbuf,outbuf,nread,max_send);
       
@@ -2772,22 +2809,6 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval)
   DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \
 global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
 
-  if(inbuf == NULL)
-  {
-    inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(inbuf == NULL) {
-      DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
-      return False;
-    } 
-    outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(outbuf == NULL) {
-      DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
-      free(inbuf);
-      inbuf = NULL;
-      return False;
-    }
-  } 
-
   /* We need to search the file open table for the
      entry containing this dev and inode, and ensure
      we have an oplock on it. */
@@ -2807,7 +2828,7 @@ global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open));
   if(fsp == NULL)
   {
     /* The file could have been closed in the meantime - return success. */
-    DEBUG(3,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
+    DEBUG(0,("%s oplock_break: cannot find open file with dev = %x, inode = %x (fnum = %d) \
 allowing break to succeed.\n", timestring(), dev, inode, fnum));
     return True;
   }
@@ -2823,15 +2844,42 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum));
 
   if(!fsp->granted_oplock)
   {
-    DEBUG(3,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. \
-Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, inode));
+    DEBUG(0,("%s oplock_break: file %s (fnum = %d, dev = %x, inode = %x) has no oplock. Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, inode));
     return True;
   }
 
+  /* mark the oplock break as sent - we don't want to send twice! */
+  if (fsp->sent_oplock_break)
+  {
+    DEBUG(0,("%s oplock_break: ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode));
+
+    /* We have to fail the open here as we cannot send another oplock break on this
+       file whilst we are awaiting a response from the client - neither can we
+       allow another open to succeed while we are waiting for the client. */
+    return False;
+  }
+
   /* Now comes the horrid part. We must send an oplock break to the client,
      and then process incoming messages until we get a close or oplock release.
+     At this point we know we need a new inbuf/outbuf buffer pair.
+     We cannot use these staticaly as we may recurse into here due to
+     messages crossing on the wire.
    */
 
+  if((inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+  {
+    DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
+    return False;
+  }
+
+  if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL)
+  {
+    DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
+    free(inbuf);
+    inbuf = NULL;
+    return False;
+  }
+
   /* Prepare the SMBlockingX message. */
   bzero(outbuf,smb_size);
   set_message(outbuf,8,0,True);
@@ -2849,6 +2897,9 @@ Allowing break to succeed regardless.\n", timestring(), fsp->name, fnum, dev, in
  
   send_smb(Client, outbuf);
 
+  /* Remember we just sent an oplock break on this file. */
+  fsp->sent_oplock_break = True;
+
   /* We need this in case a readraw crosses on the wire. */
   global_oplock_break = True;
  
@@ -2900,6 +2951,10 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
     }
   }
 
+  /* Free the buffers we've been using to recurse. */
+  free(inbuf);
+  free(outbuf);
+
   /* We need this in case a readraw crossed on the wire. */
   if(global_oplock_break)
     global_oplock_break = False;
@@ -2923,7 +2978,8 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode));
        from the sharemode. */
     /* Paranoia.... */
     fsp->granted_oplock = False;
-  global_oplocks_open--;
+    fsp->sent_oplock_break = False;
+    global_oplocks_open--;
   }
 
   /* Santity check - remove this later. JRA */
@@ -3107,6 +3163,13 @@ BOOL receive_next_smb(int smbfd, int oplockfd, char *inbuf, int bufsize, int tim
       process_local_message(oplock_sock, inbuf, bufsize);
       continue;
     }
+
+    if(ret && (CVAL(inbuf,0) == 0x85))
+    {
+      /* Keepalive packet. */
+      got_smb = False;
+    }
+
   }
   while(ret && !got_smb);
 
@@ -3595,14 +3658,35 @@ int make_connection(char *service,char *user,char *password, int pwlen, char *de
 ****************************************************************************/
 int find_free_file(void )
 {
-  int i;
-  /* we start at 1 here for an obscure reason I can't now remember,
-     but I think is important :-) */
-  for (i=1;i<MAX_OPEN_FILES;i++)
-    if (!Files[i].open)
-      return(i);
-  DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
-  return(-1);
+       int i;
+       static int first_file;
+
+       /* we want to give out file handles differently on each new
+          connection because of a common bug in MS clients where they try to
+          reuse a file descriptor from an earlier smb connection. This code
+          increases the chance that the errant client will get an error rather
+          than causing corruption */
+       if (first_file == 0) {
+               first_file = (getpid() ^ (int)time(NULL)) % MAX_OPEN_FILES;
+               if (first_file == 0) first_file = 1;
+       }
+
+       for (i=first_file;i<MAX_OPEN_FILES;i++)
+               if (!Files[i].open) {
+                       memset(&Files[i], 0, sizeof(Files[i]));
+                       return(i);
+               }
+
+       /* returning a file handle of 0 is a bad idea - so we start at 1 */
+       for (i=1;i<first_file;i++)
+               if (!Files[i].open) {
+                       memset(&Files[i], 0, sizeof(Files[i]));
+                       return(i);
+               }
+
+
+       DEBUG(1,("ERROR! Out of file structures - perhaps increase MAX_OPEN_FILES?\n"));
+       return(-1);
 }
 
 /****************************************************************************
@@ -4586,7 +4670,8 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
        {
          int cnum = SVAL(inbuf,smb_tid);
          int flags = smb_messages[match].flags;
-         uint16 session_tag = SVAL(inbuf,smb_uid);
+          /* In share mode security we must ignore the vuid. */
+         uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid);
 
          /* does this protocol need to be run as root? */
          if (!(flags & AS_USER))
@@ -5017,7 +5102,9 @@ static void usage(char *pname)
   int port = SMB_PORT;
   int opt;
   extern char *optarg;
-  char pidFile[100] = { 0 };
+  char pidFile[100];
+
+  *pidFile = '\0';
 
 #ifdef NEED_AUTH_PARAMETERS
   set_auth_parameters(argc,argv);
@@ -5157,7 +5244,18 @@ static void usage(char *pname)
 #ifndef NO_SIGNAL_TEST
   signal(SIGHUP,SIGNAL_CAST sig_hup);
 #endif
-  
+
+  /* Setup the signals that allow the debug log level
+     to by dynamically changed. */
+#if defined(SIGUSR1)
+  signal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
+   
+#if defined(SIGUSR2)
+  signal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+
   DEBUG(3,("%s loaded services\n",timestring()));
 
   if (!is_daemon && !is_a_socket(0))