*** empty log message ***
[samba.git] / source / smbd / reply.c
index 94839c227afcc448fc91c86dce78f545fde1d44b..7194f3b14465268cb6782ab26604c75a8102238f 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "includes.h"
 #include "trans2.h"
+#include "nterr.h"
 
 /* look in server.c for some explanation of these variables */
 extern int Protocol;
@@ -42,6 +43,7 @@ extern BOOL short_case_preserve;
 extern pstring sesssetup_user;
 extern fstring myworkgroup;
 extern int Client;
+extern int global_oplock_break;
 
 /* this macro should always be used to extract an fnum (smb_fid) from
 a packet to ensure chaining works correctly */
@@ -54,7 +56,7 @@ report a possible attack via the password buffer overflow bug
 static void overflow_attack(int len)
 {
        DEBUG(0,("ERROR: Invalid password length %d\n", len));
-       DEBUG(0,("you're machine may be under attack by a user exploiting an old bug\n"));
+       DEBUG(0,("your machine may be under attack by a user exploiting an old bug\n"));
        DEBUG(0,("Attack was from IP=%s\n", client_addr()));
        exit_server("possible attack");
 }
@@ -71,43 +73,54 @@ int reply_special(char *inbuf,char *outbuf)
        pstring name1,name2;
        extern fstring remote_machine;
        extern fstring local_machine;
-       char *p;
+       int len;
+       char name_type = 0;
        
        *name1 = *name2 = 0;
        
        smb_setlen(outbuf,0);
        
        switch (msg_type) {
-    case 0x81: /* session request */
-      CVAL(outbuf,0) = 0x82;
-      CVAL(outbuf,3) = 0;
-      if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
-             DEBUG(0,("Invalid name length in session request\n"));
-             return(0);
-      }
-      name_extract(inbuf,4,name1);
-      name_extract(inbuf,4 + name_len(inbuf + 4),name2);
+       case 0x81: /* session request */
+               CVAL(outbuf,0) = 0x82;
+               CVAL(outbuf,3) = 0;
+               if (name_len(inbuf+4) > 50 || 
+                   name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
+                       DEBUG(0,("Invalid name length in session request\n"));
+                       return(0);
+               }
+               name_extract(inbuf,4,name1);
+               name_extract(inbuf,4 + name_len(inbuf + 4),name2);
                DEBUG(2,("netbios connect: name1=%s name2=%s\n",
                         name1,name2));      
 
-      fstrcpy(remote_machine,name2);
-      trim_string(remote_machine," "," ");
-      p = strchr(remote_machine,' ');
-      strlower(remote_machine);
-      if (p) *p = 0;
+               fstrcpy(remote_machine,name2);
+               remote_machine[15] = 0;
+               trim_string(remote_machine," "," ");
+               strlower(remote_machine);
 
-      fstrcpy(local_machine,name1);
-      trim_string(local_machine," "," ");
-      p = strchr(local_machine,' ');
-      strlower(local_machine);
-      if (p) *p = 0;
+               fstrcpy(local_machine,name1);
+               len = strlen(local_machine);
+               if (len == 16) {
+                       name_type = local_machine[15];
+                       local_machine[15] = 0;
+               }
+               trim_string(local_machine," "," ");
+               strlower(local_machine);
+
+               if (name_type == 'R') {
+                       /* We are being asked for a pathworks session --- 
+                          no thanks! */
+                       CVAL(outbuf, 0) = 0x83;
+                       break;
+               }
 
-      add_session_user(remote_machine);
+               add_session_user(remote_machine);
 
-      reload_services(True);
-      reopen_logs();
+               reload_services(True);
+               reopen_logs();
 
-      break;
+               break;
                
        case 0x89: /* session keepalive request 
                      (some old clients produce this?) */
@@ -243,7 +256,6 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int connection_num;
   uint16 vuid = SVAL(inbuf,smb_uid);
   int passlen = SVAL(inbuf,smb_vwv3);
-  BOOL doencrypt = SMBENCRYPT();
 
   *service = *user = *password = *devicename = 0;
 
@@ -251,7 +263,7 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
     close_cnum(SVAL(inbuf,smb_tid),vuid);
 
-  if (passlen > MAX_PASSWORD_LENGTH) {
+  if (passlen > MAX_PASS_LEN) {
          overflow_attack(passlen);
   }
   
@@ -262,7 +274,7 @@ int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     password[passlen]=0;    
     path = smb_buf(inbuf) + passlen;
 
-    if (!doencrypt || passlen != 24) {
+    if (passlen != 24) {
       if (strequal(password," "))
        *password = 0;
       passlen = strlen(password);
@@ -377,8 +389,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   BOOL computer_id=False;
   static BOOL done_sesssetup = False;
   BOOL doencrypt = SMBENCRYPT();
+  char *domain = "";
 
   *smb_apasswd = 0;
+  *smb_ntpasswd = 0;
   
   smb_bufsize = SVAL(inbuf,smb_vwv2);
   smb_mpxmax = SVAL(inbuf,smb_vwv3);
@@ -387,13 +401,16 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
 
   if (Protocol < PROTOCOL_NT1) {
     smb_apasslen = SVAL(inbuf,smb_vwv7);
-    if (smb_apasslen > MAX_PASSWORD_LENGTH)
+    if (smb_apasslen > MAX_PASS_LEN)
+    {
            overflow_attack(smb_apasslen);
+    }
 
     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
+    smb_apasswd[smb_apasslen] = 0;
     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
 
-    if (lp_security() != SEC_SERVER && !doencrypt) {
+    if (!doencrypt && (lp_security() != SEC_SERVER)) {
            smb_apasslen = strlen(smb_apasswd);
     }
   } else {
@@ -420,19 +437,21 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     if (passlen1 != 24 && passlen2 != 24)
       doencrypt = False;
 
-    if (passlen1 > MAX_PASSWORD_LENGTH) {
+    if (passlen1 > MAX_PASS_LEN) {
            overflow_attack(passlen1);
     }
 
-    passlen1 = MIN(passlen1, MAX_PASSWORD_LENGTH);
-    passlen2 = MIN(passlen2, MAX_PASSWORD_LENGTH);
+    passlen1 = MIN(passlen1, MAX_PASS_LEN);
+    passlen2 = MIN(passlen2, MAX_PASS_LEN);
 
-    if(doencrypt) {
+    if(doencrypt || (lp_security() == SEC_SERVER)) {
       /* Save the lanman2 password and the NT md4 password. */
       smb_apasslen = passlen1;
       memcpy(smb_apasswd,p,smb_apasslen);
+      smb_apasswd[smb_apasslen] = 0;
       smb_ntpasslen = passlen2;
       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
+      smb_ntpasswd[smb_ntpasslen] = 0;
     } else {
       /* both Win95 and WinNT stuff up the password lengths for
         non-encrypting systems. Uggh. 
@@ -465,8 +484,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     
     p += passlen1 + passlen2;
     fstrcpy(user,p); p = skip_string(p,1);
+    domain = p;
+
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            p,skip_string(p,1),skip_string(p,2)));
+            domain,skip_string(p,1),skip_string(p,2)));
   }
 
 
@@ -475,9 +496,45 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   /* If name ends in $ then I think it's asking about whether a */
   /* computer with that name (minus the $) has access. For now */
   /* say yes to everything ending in $. */
-  if (user[strlen(user) - 1] == '$') {
-    computer_id = True;
+  if (user[strlen(user) - 1] == '$')
+  {
+#ifdef NTDOMAIN
+    struct smb_passwd *smb_pass; /* To check if machine account exists */
+/* 
+   PAXX: Ack. We don't want to do this. The workstation trust account
+   with a $ on the end should exist in the local password database
+   or be mapped to something generic, but not modified. For NT
+   domain support we must reject this used in certain circumstances
+   with a code to indicate to the client that it is an invalid use
+   of a workstation trust account. NTWKS needs this error to join
+   a domain. This may be the source of future bugs if we cannot
+   be sure whether to reject this or not.
+*/
+   /* non-null user name indicates search by username not by smb userid */
+   smb_pass = get_smbpwd_entry(user, 0);
+
+   if (!smb_pass)
+   {
+     /* lkclXXXX: if workstation entry doesn't exist, indicate logon failure */
+     DEBUG(4,("Workstation trust account %s doesn't exist.",user));
+     SSVAL(outbuf, smb_flg2, 0xc003); /* PAXX: Someone please unhack this */
+     CVAL(outbuf, smb_reh) = 1; /* PAXX: Someone please unhack this */
+     return(ERROR(NT_STATUS_LOGON_FAILURE, 0xc000)); /* decimal 109 NT error, 0xc000 */
+   }
+   else
+   {
+     /* PAXX: This is the NO LOGON workstation trust account stuff */
+     /* lkclXXXX: if the workstation *does* exist, indicate failure differently! */
+     DEBUG(4,("No Workstation trust account %s",user));
+     SSVAL(outbuf, smb_flg2, 0xc003); /* PAXX: Someone please unhack this */
+     CVAL(outbuf, smb_reh) = 1; /* PAXX: Someone please unhack this */
+     return(ERROR(NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, 0xc000)); /* decimal 409 NT error, 0xc000 */
+   }
+
+   computer_id = True;
+#else /* not NTDOMAIN, leave this in. PAXX: Someone get rid of this */
     user[strlen(user) - 1] = '\0';
+#endif
   }
 
 
@@ -506,7 +563,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
     guest = True;
 
-  if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+  if (!guest && !(lp_security() == SEC_SERVER && 
+                 server_validate(user, domain, 
+                                 smb_apasswd, smb_apasslen, 
+                                 smb_ntpasswd, smb_ntpasslen)) &&
       !check_hosts_equiv(user))
     {
 
@@ -596,7 +656,7 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if (!done_sesssetup)
     max_send = MIN(max_send,smb_bufsize);
 
-  DEBUG(1,(" Client requested max send size of %d\n", max_send));
+  DEBUG(6,("Client requested max send size of %d\n", max_send));
 
   done_sesssetup = True;
 
@@ -637,6 +697,17 @@ int reply_chkpth(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+
+#if 0
+    /* Ugly - NT specific hack - maybe not needed ? (JRA) */
+    if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
+       (get_remote_arch() == RA_WINNT))
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbaddirectory;
+    }
+#endif
+
     return(UNIXERROR(ERRDOS,ERRbadpath));
   }
  
@@ -751,7 +822,7 @@ int reply_setatr(char *inbuf,char *outbuf)
   if (check_name(fname,cnum))
     ok =  (dos_chmod(cnum,fname,mode,NULL) == 0);
   if (ok)
-    ok = set_filetime(fname,mtime);
+    ok = set_filetime(cnum,fname,mtime);
   
   if (!ok)
   {
@@ -1120,6 +1191,7 @@ int reply_open(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
@@ -1137,11 +1209,12 @@ int reply_open(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
   if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
     
@@ -1151,7 +1224,7 @@ int reply_open(char *inbuf,char *outbuf)
 
   if (fmode & aDIR) {
     DEBUG(3,("attempt to open a directory %s\n",fname));
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
   
@@ -1163,7 +1236,7 @@ int reply_open(char *inbuf,char *outbuf)
   SSVAL(outbuf,smb_vwv6,rmode);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
     
   if(fsp->granted_oplock)
@@ -1182,7 +1255,11 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int fnum = -1;
   int smb_mode = SVAL(inbuf,smb_vwv3);
   int smb_attr = SVAL(inbuf,smb_vwv5);
-  BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+  /* Breakout the oplock request bits so we can set the
+     reply bits separately. */
+  BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
+  BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
+  BOOL oplock_request = ex_oplock_request | core_oplock_request;
 #if 0
   int open_flags = SVAL(inbuf,smb_vwv2);
   int smb_sattr = SVAL(inbuf,smb_vwv4); 
@@ -1216,6 +1293,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1233,11 +1311,12 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
   if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1245,16 +1324,35 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   fmode = dos_mode(cnum,fname,&sbuf);
   mtime = sbuf.st_mtime;
   if (fmode & aDIR) {
-    close_file(fnum);
+    close_file(fnum,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+  /* If the caller set the extended oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for extended oplock reply.
+   */
+
+  if (ex_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    smb_action |= EXTENDED_OPLOCK_GRANTED;
   }
 
-  if(fsp->granted_oplock)
+  if(ex_oplock_request && fsp->granted_oplock) {
     smb_action |= EXTENDED_OPLOCK_GRANTED;
+  }
+
+  /* If the caller set the core oplock request bit
+     and we granted one (by whatever means) - set the
+     correct bit for core oplock reply.
+   */
+
+  if (core_oplock_request && lp_fake_oplocks(SNUM(cnum))) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  }
+
+  if(core_oplock_request && fsp->granted_oplock) {
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
+  }
 
   set_message(outbuf,15,0,True);
   SSVAL(outbuf,smb_vwv2,fnum);
@@ -1288,7 +1386,7 @@ int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
     int i;
     for (i=0;i<MAX_OPEN_FILES;i++)
       if (Files[i].uid == vuser->uid && Files[i].open) {
-       close_file(i);
+       close_file(i,False);
       }
   }
 
@@ -1343,6 +1441,7 @@ int reply_mknew(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1370,6 +1469,7 @@ int reply_mknew(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
@@ -1377,7 +1477,7 @@ int reply_mknew(char *inbuf,char *outbuf)
   SSVAL(outbuf,smb_vwv0,fnum);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
  
   if(fsp->granted_oplock)
@@ -1425,6 +1525,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1444,6 +1545,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
+    Files[fnum].reserved = False;
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1453,7 +1555,7 @@ int reply_ctemp(char *inbuf,char *outbuf)
   strcpy(smb_buf(outbuf) + 1,fname2);
 
   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
-    fsp->granted_oplock = True;
+    CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
   
   if(fsp->granted_oplock)
@@ -1606,6 +1708,20 @@ int reply_readbraw(char *inbuf, char *outbuf)
   int fd;
   char *fname;
 
+  /*
+   * Special check if an oplock break has been issued
+   * and the readraw request croses on the wire, we must
+   * return a zero length response here.
+   */
+
+  if(global_oplock_break)
+  {
+    _smb_setlen(header,0);
+    transfer_file(0,Client,0,header,4,0);
+    DEBUG(5,("readbraw - oplock break finished\n"));
+    return -1;
+  }
+
   cnum = SVAL(inbuf,smb_tid);
   fnum = GETFNUM(inbuf,smb_vwv0);
 
@@ -1660,8 +1776,10 @@ int reply_readbraw(char *inbuf, char *outbuf)
     int predict=0;
     _smb_setlen(header,nread);
 
+#if USE_READ_PREDICTION
     if (!Files[fnum].can_write)
       predict = read_predict(fd,startpos,header+4,NULL,nread);
+#endif
 
     if ((nread-predict) > 0)
       seek_file(fnum,startpos + predict);
@@ -2204,7 +2322,12 @@ int reply_close(char *inbuf,char *outbuf)
 
   cnum = SVAL(inbuf,smb_tid);
 
+  /* If it's an IPC, pass off to the pipe handler. */
+  if (IS_IPC(cnum))
+    return reply_pipe_close(inbuf,outbuf);
+
   fnum = GETFNUM(inbuf,smb_vwv0);
+
   CHECK_FNUM(fnum,cnum);
 
   if(HAS_CACHED_ERROR(fnum)) {
@@ -2215,9 +2338,9 @@ int reply_close(char *inbuf,char *outbuf)
   mtime = make_unix_date3(inbuf+smb_vwv1);
 
   /* try and set the date */
-  set_filetime(Files[fnum].name,mtime);
+  set_filetime(cnum, Files[fnum].name,mtime);
 
-  close_file(fnum);
+  close_file(fnum,True);
 
   /* We have a cached error */
   if(eclass || err)
@@ -2262,9 +2385,9 @@ int reply_writeclose(char *inbuf,char *outbuf)
       
   nwritten = write_file(fnum,data,numtowrite);
 
-  set_filetime(Files[fnum].name,mtime);
+  set_filetime(cnum, Files[fnum].name,mtime);
   
-  close_file(fnum);
+  close_file(fnum,True);
 
   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
           timestring(),fnum,cnum,numtowrite,nwritten,
@@ -2457,15 +2580,19 @@ int reply_printopen(char *inbuf,char *outbuf)
 
   strcpy(fname2,(char *)mktemp(fname));
 
-  if (!check_name(fname2,cnum))
-    return(ERROR(ERRDOS,ERRnoaccess));
+  if (!check_name(fname2,cnum)) {
+         Files[fnum].reserved = False;
+         return(ERROR(ERRDOS,ERRnoaccess));
+  }
 
   /* Open for exclusive use, write only. */
   open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
                    0, NULL, NULL);
 
-  if (!Files[fnum].open)
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
+  if (!Files[fnum].open) {
+         Files[fnum].reserved = False;
+         return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   /* force it to be a print file */
   Files[fnum].print_file = True;
@@ -2496,7 +2623,7 @@ int reply_printclose(char *inbuf,char *outbuf)
   if (!CAN_PRINT(cnum))
     return(ERROR(ERRDOS,ERRnoaccess));
   
-  close_file(fnum);
+  close_file(fnum,True);
   
   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
   
@@ -2552,7 +2679,7 @@ int reply_printqueue(char *inbuf,char *outbuf)
       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
     }
 
-  if (!become_user(cnum,vuid))
+  if (!become_user(&Connections[cnum], cnum, vuid))
     return(ERROR(ERRSRV,ERRinvnid));
 
   {
@@ -3061,14 +3188,23 @@ int reply_mv(char *inbuf,char *outbuf)
 
            error = ERRnoaccess;
            sprintf(fname,"%s/%s",directory,dname);
-           if (!can_rename(fname,cnum)) continue;
+           if (!can_rename(fname,cnum)) {
+                   DEBUG(6,("rename %s refused\n", fname));
+                   continue;
+           }
            pstrcpy(destname,newname);
 
-           if (!resolve_wildcards(fname,destname)) continue;
+           if (!resolve_wildcards(fname,destname)) {
+                   DEBUG(6,("resolve_wildcards %s %s failed\n", 
+                            fname, destname));
+                   continue;
+           }
 
            if (file_exist(destname,NULL)) {
-             error = 183;
-             continue;
+                   DEBUG(6,("file_exist %s\n", 
+                            destname));
+                   error = 183;
+                   continue;
            }
            if (!sys_rename(fname,destname)) count++;
            DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
@@ -3126,21 +3262,25 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
                   1,0,0,&Access,&action);
 
-  if (!Files[fnum1].open) return(False);
+  if (!Files[fnum1].open) {
+         Files[fnum1].reserved = False;
+         return(False);
+  }
 
   if (!target_is_directory && count)
     ofun = 1;
 
   fnum2 = find_free_file();
   if (fnum2<0) {
-    close_file(fnum1);
+    close_file(fnum1,False);
     return(False);
   }
   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
                   ofun,st.st_mode,0,&Access,&action);
 
   if (!Files[fnum2].open) {
-    close_file(fnum1);
+    close_file(fnum1,False);
+    Files[fnum2].reserved = False;
     return(False);
   }
 
@@ -3151,8 +3291,8 @@ static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
   if (st.st_size)
     ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
 
-  close_file(fnum1);
-  close_file(fnum2);
+  close_file(fnum1,False);
+  close_file(fnum2,False);
 
   return(ret == st.st_size);
 }
@@ -3339,7 +3479,10 @@ int reply_setdir(char *inbuf,char *outbuf)
 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
 {
   int fnum = GETFNUM(inbuf,smb_vwv2);
-  uint16 locktype = SVAL(inbuf,smb_vwv3);
+  unsigned char locktype = CVAL(inbuf,smb_vwv3);
+#if 0
+  unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
+#endif
   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
   uint16 num_locks = SVAL(inbuf,smb_vwv7);
   uint32 count, offset;
@@ -3356,6 +3499,55 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
   CHECK_ERROR(fnum);
 
   data = smb_buf(inbuf);
+
+  /* Check if this is an oplock break on a file
+     we have granted an oplock on.
+   */
+  if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
+  {
+    int token;
+    files_struct *fsp = &Files[fnum];
+    uint32 dev = fsp->fd_ptr->dev;
+    uint32 inode = fsp->fd_ptr->inode;
+
+    DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
+              fnum));
+    /*
+     * Make sure we have granted an oplock on this file.
+     */
+    if(!fsp->granted_oplock)
+    {
+      DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
+no oplock granted on this file.\n", fnum));
+      return ERROR(ERRDOS,ERRlock);
+    }
+
+    /* Remove the oplock flag from the sharemode. */
+    lock_share_entry(fsp->cnum, dev, inode, &token);
+    if(remove_share_oplock( fnum, token)==False) {
+           DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
+dev = %x, inode = %x\n", 
+                    fnum, dev, inode));
+           unlock_share_entry(fsp->cnum, dev, inode, token);
+    } else {
+           unlock_share_entry(fsp->cnum, dev, inode, token);
+
+           /* Clear the granted flag and return. */
+           fsp->granted_oplock = False;
+    }
+
+    /* if this is a pure oplock break request then don't send a reply */
+    if (num_locks == 0 && num_ulocks == 0)
+    {
+      /* Sanity check - ensure a pure oplock break is not a
+         chained request. */
+      if(CVAL(inbuf,smb_vwv0) != 0xff)
+        DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
+                 (unsigned int)CVAL(inbuf,smb_vwv0) ));
+      return -1;
+    }
+  }
+
   /* Data now points at the beginning of the list
      of smb_unlkrng structs */
   for(i = 0; i < (int)num_ulocks; i++) {
@@ -3390,7 +3582,7 @@ int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
   set_message(outbuf,2,0,True);
   
   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
-       timestring(),fnum,cnum,locktype,num_locks,num_ulocks));
+       timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
 
   chain_fnum = fnum;
 
@@ -3687,7 +3879,7 @@ not setting timestamps of 0\n",
   }
 
   /* Set the date on this file */
-  if(sys_utime(Files[fnum].name, &unix_times))
+  if(file_utime(cnum, Files[fnum].name, &unix_times))
     return(ERROR(ERRDOS,ERRnoaccess));
   
   DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",