- changed smb_getpwnam() to use winbind style usernames
[kai/samba.git] / source / smbd / reply.c
index 254fb32a51517f6e1e452b643149088ed67073fd..1fc377f36220d5ed704f85150142269df01647e2 100644 (file)
@@ -1,3 +1,4 @@
+#define OLD_NTDOMAIN 1
 /* 
    Unix SMB/Netbios implementation.
    Version 1.9.
@@ -25,8 +26,6 @@
 
 
 #include "includes.h"
-#include "trans2.h"
-#include "nterr.h"
 
 /* look in server.c for some explanation of these variables */
 extern int Protocol;
@@ -38,22 +37,24 @@ extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
 extern pstring sesssetup_user;
+extern pstring global_myname;
 extern fstring global_myworkgroup;
-extern int Client;
 extern int global_oplock_break;
+uint32 global_client_caps = 0;
+unsigned int smb_echo_count = 0;
 
 /****************************************************************************
 report a possible attack via the password buffer overflow bug
 ****************************************************************************/
+
 static void overflow_attack(int len)
 {
-        if( DEBUGLVL( 0 ) )
-          {
-         dbgtext( "ERROR: Invalid password length %d.\n", len );
-         dbgtext( "Your machine may be under attack by someone " );
-          dbgtext( "attempting to exploit an old bug.\n" );
-         dbgtext( "Attack was from IP = %s.\n", client_addr(Client) );
-          }
+       if( DEBUGLVL( 0 ) ) {
+               dbgtext( "ERROR: Invalid password length %d.\n", len );
+               dbgtext( "Your machine may be under attack by someone " );
+               dbgtext( "attempting to exploit an old bug.\n" );
+               dbgtext( "Attack was from IP = %s.\n", client_addr() );
+       }
        exit_server("possible attack");
 }
 
@@ -61,6 +62,7 @@ static void overflow_attack(int len)
 /****************************************************************************
   reply to an special message 
 ****************************************************************************/
+
 int reply_special(char *inbuf,char *outbuf)
 {
        int outsize = 4;
@@ -74,7 +76,7 @@ int reply_special(char *inbuf,char *outbuf)
        
        *name1 = *name2 = 0;
        
-       bzero(outbuf,smb_size);
+       memset(outbuf,'\0',smb_size);
 
        smb_setlen(outbuf,0);
        
@@ -119,7 +121,7 @@ int reply_special(char *inbuf,char *outbuf)
                reopen_logs();
 
                if (lp_status(-1)) {
-                       claim_connection(NULL,"STATUS.",MAXSTATUS,True);
+                       claim_connection(NULL,"",MAXSTATUS,True);
                }
 
                break;
@@ -151,11 +153,11 @@ int reply_special(char *inbuf,char *outbuf)
 /*******************************************************************
 work out what error to give to a failed connection
 ********************************************************************/
+
 static int connection_error(char *inbuf,char *outbuf,int ecode)
 {
-       if (ecode == ERRnoipc) {
+       if (ecode == ERRnoipc)
                return(ERROR(ERRDOS,ERRnoipc));
-       }
 
        return(ERROR(ERRSRV,ecode));
 }
@@ -196,15 +198,14 @@ static void parse_connect(char *p,char *service,char *user,
     }
 }
 
-
-
-
 /****************************************************************************
-  reply to a tcon
+ Reply to a tcon.
 ****************************************************************************/
+
 int reply_tcon(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
+       BOOL doencrypt = SMBENCRYPT();
        pstring service;
        pstring user;
        pstring password;
@@ -218,6 +219,14 @@ int reply_tcon(connection_struct *conn,
 
        parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
 
+    /*
+     * Ensure the user and password names are in UNIX codepage format.
+     */
+
+    dos_to_unix(user,True);
+       if (!doencrypt)
+       dos_to_unix(password,True);
+
        /*
         * Pass the user through the NT -> unix user mapping
         * function.
@@ -247,16 +256,16 @@ int reply_tcon(connection_struct *conn,
        return(outsize);
 }
 
-
 /****************************************************************************
-  reply to a tcon and X
+ Reply to a tcon and X.
 ****************************************************************************/
 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-       pstring service;
+       fstring service;
        pstring user;
        pstring password;
        pstring devicename;
+       BOOL doencrypt = SMBENCRYPT();
        int ecode = -1;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
@@ -273,7 +282,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        if (passlen > MAX_PASS_LEN) {
                overflow_attack(passlen);
        }
-  
        memcpy(password,smb_buf(inbuf),passlen);
        password[passlen]=0;    
        path = smb_buf(inbuf) + passlen;
@@ -284,11 +293,9 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                passlen = strlen(password);
        }
        
-       fstrcpy(service,path+2);
-       p = strchr(service,'\\');
+       p = strchr(path+2,'\\');
        if (!p)
                return(ERROR(ERRSRV,ERRinvnetname));
-       *p = 0;
        fstrcpy(service,p+1);
        p = strchr(service,'%');
        if (p) {
@@ -298,6 +305,14 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        StrnCpy(devicename,path + strlen(path) + 1,6);
        DEBUG(4,("Got device type %s\n",devicename));
 
+       /*
+        * Ensure the user and password names are in UNIX codepage format.
+        */
+
+       dos_to_unix(user,True);
+       if (!doencrypt)
+               dos_to_unix(password,True);
+
        /*
         * Pass the user through the NT -> unix user mapping
         * function.
@@ -332,7 +347,10 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
                SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); 
+               
+               init_dfsroot(conn, inbuf, outbuf);
        }
+
   
        DEBUG(3,("tconX service=%s user=%s\n",
                 service, user));
@@ -366,14 +384,40 @@ int reply_unknown(char *inbuf,char *outbuf)
 int reply_ioctl(connection_struct *conn,
                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       DEBUG(3,("ignoring ioctl\n"));
-#if 0
-       /* we just say it succeeds and hope its all OK. 
-          some day it would be nice to interpret them individually */
-       return set_message(outbuf,1,0,True); 
-#else
-       return(ERROR(ERRSRV,ERRnosupport));
-#endif
+       uint16 device     = SVAL(inbuf,smb_vwv1);
+       uint16 function   = SVAL(inbuf,smb_vwv2);
+       uint32 ioctl_code = (device << 16) + function;
+       int replysize, outsize;
+       char *p;
+       files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+
+       DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
+
+       switch (ioctl_code)
+       {
+           case IOCTL_QUERY_JOB_INFO:
+               replysize = 32;
+               break;
+           default:
+               return(ERROR(ERRSRV,ERRnosupport));
+       }
+
+       outsize = set_message(outbuf,8,replysize+1,True);
+       SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
+       SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
+       SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
+       p = smb_buf(outbuf) + 1;          /* Allow for alignment */
+
+       switch (ioctl_code)
+       {
+           case IOCTL_QUERY_JOB_INFO:              
+               SSVAL(p,0,fsp->print_jobid);             /* Job number */
+               StrnCpy(p+2, global_myname, 15);         /* Our NetBIOS name */
+               StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
+               break;
+       }
+
+       return outsize;
 }
 
 /****************************************************************************
@@ -411,7 +455,7 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
       return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
     }
 
-    if (!smb_password_ok(smb_trust_acct, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd))
+    if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd))
     {
       DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
@@ -445,15 +489,169 @@ static int session_trust_account(connection_struct *conn, char *inbuf, char *out
   return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
 }
 
+/****************************************************************************
+ Create a UNIX user on demand.
+****************************************************************************/
+
+static int smb_create_user(char *unix_user)
+{
+  pstring add_script;
+  int ret;
+
+  pstrcpy(add_script, lp_adduser_script());
+  if (! *add_script) return -1;
+  pstring_sub(add_script, "%u", unix_user);
+  ret = smbrun(add_script,NULL,False);
+  DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
+  return ret;
+}
+
+/****************************************************************************
+ Delete a UNIX user on demand.
+****************************************************************************/
+
+static int smb_delete_user(char *unix_user)
+{
+  pstring del_script;
+  int ret;
+
+  pstrcpy(del_script, lp_deluser_script());
+  if (! *del_script) return -1;
+  pstring_sub(del_script, "%u", unix_user);
+  ret = smbrun(del_script,NULL,False);
+  DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
+  return ret;
+}
+
+/****************************************************************************
+ Check user is in correct domain if required
+****************************************************************************/
+
+static BOOL check_domain_match(char *user, char *domain) 
+{
+  /*
+   * If we aren't serving to trusted domains, we must make sure that
+   * the validation request comes from an account in the same domain
+   * as the Samba server
+   */
+
+  if (!lp_allow_trusted_domains() &&
+      !strequal(lp_workgroup(), domain) ) {
+      DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
+      return False;
+  } else {
+      return True;
+  }
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=server mode.
+****************************************************************************/
+
+static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
+                                  char *smb_apasswd, int smb_apasslen,
+                                  char *smb_ntpasswd, int smb_ntpasslen)
+{
+  BOOL ret = False;
+
+  if(lp_security() != SEC_SERVER)
+    return False;
+
+  if (!check_domain_match(orig_user, domain))
+     return False;
+
+  ret = server_validate(orig_user, domain, 
+                            smb_apasswd, smb_apasslen, 
+                            smb_ntpasswd, smb_ntpasslen);
+  if(ret) {
+    /*
+     * User validated ok against Domain controller.
+     * If the admin wants us to try and create a UNIX
+     * user on the fly, do so.
+     * Note that we can never delete users when in server
+     * level security as we never know if it was a failure
+     * due to a bad password, or the user really doesn't exist.
+     */
+    if(lp_adduser_script() && !smb_getpwnam(unix_user,True)) {
+      smb_create_user(unix_user);
+    }
+  }
+
+  return ret;
+}
+
+/****************************************************************************
+ Check for a valid username and password in security=domain mode.
+****************************************************************************/
+
+static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, 
+                                  char *smb_apasswd, int smb_apasslen,
+                                  char *smb_ntpasswd, int smb_ntpasslen)
+{
+  BOOL ret = False;
+  BOOL user_exists = True;
+
+  if(lp_security() != SEC_DOMAIN)
+    return False;
+
+  if (!check_domain_match(orig_user, domain))
+     return False;
+
+  ret = domain_client_validate(orig_user, domain,
+                                smb_apasswd, smb_apasslen,
+                                smb_ntpasswd, smb_ntpasslen,
+                                &user_exists);
+
+  if(ret) {
+    /*
+     * User validated ok against Domain controller.
+     * If the admin wants us to try and create a UNIX
+     * user on the fly, do so.
+     */
+    if(user_exists && lp_adduser_script() && !smb_getpwnam(unix_user,True)) {
+      smb_create_user(unix_user);
+    }
+  } else {
+    /*
+     * User failed to validate ok against Domain controller.
+     * If the failure was "user doesn't exist" and admin 
+     * wants us to try and delete that UNIX user on the fly,
+     * do so.
+     */
+    if(!user_exists && lp_deluser_script() && smb_getpwnam(unix_user,True)) {
+      smb_delete_user(unix_user);
+    }
+  }
+
+  return ret;
+}
+
+/****************************************************************************
+ Return a bad password error configured for the correct client type.
+****************************************************************************/       
+
+static int bad_password_error(char *inbuf,char *outbuf)
+{
+  enum remote_arch_types ra_type = get_remote_arch();
+
+  if(((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)) &&
+      (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32 ))) {
+    SSVAL(outbuf,smb_flg2,FLAGS2_32_BIT_ERROR_CODES);
+    return(ERROR(0,0xc0000000|NT_STATUS_LOGON_FAILURE));
+  }
+
+  return(ERROR(ERRSRV,ERRbadpw));
+}
 
 /****************************************************************************
 reply to a session setup command
 ****************************************************************************/
+
 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
   uint16 sess_vuid;
-  int gid;
-  int uid;
+  gid_t gid;
+  uid_t uid;
   int   smb_bufsize;    
   int   smb_apasslen = 0;   
   pstring smb_apasswd;
@@ -475,43 +673,45 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
   if (Protocol < PROTOCOL_NT1) {
     smb_apasslen = SVAL(inbuf,smb_vwv7);
     if (smb_apasslen > MAX_PASS_LEN)
-    {
-           overflow_attack(smb_apasslen);
-    }
+      overflow_attack(smb_apasslen);
 
     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
     smb_apasswd[smb_apasslen] = 0;
     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
-
+    /*
+     * Incoming user is in DOS codepage format. Convert
+     * to UNIX.
+     */
+    dos_to_unix(user,True);
+  
     if (!doencrypt && (lp_security() != SEC_SERVER)) {
-           smb_apasslen = strlen(smb_apasswd);
+      smb_apasslen = strlen(smb_apasswd);
     }
   } else {
     uint16 passlen1 = SVAL(inbuf,smb_vwv7);
     uint16 passlen2 = SVAL(inbuf,smb_vwv8);
-    uint32 client_caps = IVAL(inbuf,smb_vwv11);
     enum remote_arch_types ra_type = get_remote_arch();
-
     char *p = smb_buf(inbuf);    
 
+    if(global_client_caps == 0)
+      global_client_caps = IVAL(inbuf,smb_vwv11);
+
     /* client_caps is used as final determination if client is NT or Win95. 
        This is needed to return the correct error codes in some
        circumstances.
      */
     
-    if(ra_type == RA_WINNT || ra_type == RA_WIN95)
-    {
-      if(client_caps & (CAP_NT_SMBS | CAP_STATUS32))
-        set_remote_arch( RA_WINNT);
-      else
+    if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
+      if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
         set_remote_arch( RA_WIN95);
+      }
     }
 
     if (passlen1 != 24 && passlen2 != 24)
       doencrypt = False;
 
     if (passlen1 > MAX_PASS_LEN) {
-           overflow_attack(passlen1);
+      overflow_attack(passlen1);
     }
 
     passlen1 = MIN(passlen1, MAX_PASS_LEN);
@@ -534,6 +734,26 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
         passlen2 = 0;
     }
 
+    if (lp_restrict_anonymous()) {
+      /* there seems to be no reason behind the differences in MS clients formatting
+       * various info like the domain, NativeOS, and NativeLanMan fields. Win95
+       * in particular seems to have an extra null byte between the username and the
+       * domain, or the password length calculation is wrong, which throws off the
+       * string extraction routines below.  This makes the value of domain be the
+       * empty string, which fails the restrict anonymous check further down.
+       * This compensates for that, and allows browsing to work in mixed NT and
+       * win95 environments even when restrict anonymous is true. AAB
+       */
+      dump_data(100, p, 0x70);
+      DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
+      if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
+        DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
+        DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
+        DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
+        passlen1 = 1;
+      }
+    }
+
     if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
       /* Save the lanman2 password and the NT md4 password. */
       smb_apasslen = passlen1;
@@ -542,23 +762,42 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
       smb_ntpasslen = passlen2;
       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
       smb_ntpasswd[smb_ntpasslen] = 0;
+
+      /*
+       * Ensure the plaintext passwords are in UNIX format.
+       */
+      if(!doencrypt) {
+        dos_to_unix(smb_apasswd,True);
+        dos_to_unix(smb_ntpasswd,True);
+      }
+
     } else {
       /* we use the first password that they gave */
       smb_apasslen = passlen1;
       StrnCpy(smb_apasswd,p,smb_apasslen);      
+      /*
+       * Ensure the plaintext password is in UNIX format.
+       */
+      dos_to_unix(smb_apasswd,True);
       
       /* trim the password */
       smb_apasslen = strlen(smb_apasswd);
 
       /* wfwg sometimes uses a space instead of a null */
       if (strequal(smb_apasswd," ")) {
-       smb_apasslen = 0;
-       *smb_apasswd = 0;
+        smb_apasslen = 0;
+        *smb_apasswd = 0;
       }
     }
     
     p += passlen1 + passlen2;
-    fstrcpy(user,p); p = skip_string(p,1);
+    fstrcpy(user,p);
+    p = skip_string(p,1);
+    /*
+     * Incoming user is in DOS codepage format. Convert
+     * to UNIX.
+     */
+    dos_to_unix(user,True);
     domain = p;
 
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
@@ -571,32 +810,38 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
   /* 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] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24))
-  {
+
+  if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
     return session_trust_account(conn, inbuf, outbuf, user, 
                                  smb_apasswd, smb_apasslen,
                                  smb_ntpasswd, smb_ntpasslen);
   }
 
-  /* If no username is sent use the guest account */
-  if (!*user)
-    {
-      pstrcpy(user,lp_guestaccount(-1));
-      /* If no user and no password then set guest flag. */
-      if( *smb_apasswd == 0)
-        guest = True;
+  if (done_sesssetup && lp_restrict_anonymous()) {
+    /* tests show that even if browsing is done over already validated connections
+     * without a username and password the domain is still provided, which it
+     * wouldn't be if it was a purely anonymous connection.  So, in order to
+     * restrict anonymous, we only deny connections that have no session
+     * information.  If a domain has been provided, then it's not a purely
+     * anonymous connection. AAB
+     */
+    if (!*user && !*smb_apasswd && !*domain) {
+      DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
+      return(ERROR(ERRDOS,ERRnoaccess));
     }
+  }
 
-  strlower(user);
+  /* If no username is sent use the guest account */
+  if (!*user) {
+    pstrcpy(user,lp_guestaccount(-1));
+    /* If no user and no password then set guest flag. */
+    if( *smb_apasswd == 0)
+      guest = True;
+  }
 
-  /*
-   * In share level security, only overwrite sesssetup_use if
-   * it's a non null-session share. Helps keep %U and %G
-   * working.
-   */
+  strlower(user);
 
-  if((lp_security() != SEC_SHARE) || *user)
-    pstrcpy(sesssetup_user,user);
+  pstrcpy(sesssetup_user,user);
 
   reload_services(True);
 
@@ -608,6 +853,17 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
 
   pstrcpy( orig_user, user);
 
+  /* if the username exists as a domain/username pair on the unix system then use 
+     that */
+  if (!Get_Pwnam(user, False)) {
+         pstring user2;
+         slprintf(user2,sizeof(user2),"%s/%s", domain, user);
+         if (Get_Pwnam(user2, True)) {
+                 DEBUG(3,("Using unix username %s\n", user2));
+                 pstrcpy(user, user2);
+         }
+  }
+
   /*
    * Pass the user through the NT -> unix user mapping
    * function.
@@ -618,7 +874,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
   /*
    * Do any UNIX username case mangling.
    */
-  (void)Get_Pwnam( user, True);
+  smb_getpwnam(user, True);
 
   add_session_user(user);
 
@@ -629,63 +885,86 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
     guest = True;
 
-  if (!guest && !(lp_security() == SEC_SERVER && 
-      /* Check with orig_user for security=server and
-         security=domain. */
-      server_validate(orig_user, domain, 
-                      smb_apasswd, smb_apasslen, 
-                      smb_ntpasswd, smb_ntpasslen)) &&
-      !(lp_security() == SEC_DOMAIN &&
-      domain_client_validate(orig_user, domain,
+  /* 
+   * Check with orig_user for security=server and
+   * security=domain.
+   */
+
+  if (!guest && 
+                         !check_server_security(orig_user, domain, user,
+                                                                        smb_apasswd, smb_apasslen,
+                                                                        smb_ntpasswd, smb_ntpasslen) &&
+                         !check_domain_security(orig_user, domain, user,
                              smb_apasswd, smb_apasslen,
-                            smb_ntpasswd, smb_ntpasslen)) &&
+                             smb_ntpasswd, smb_ntpasslen) &&
       !check_hosts_equiv(user)
      )
+  {
+
+    /* 
+     * If we get here then the user wasn't guest and the remote
+     * authentication methods failed. Check the authentication
+     * methods on this local server.
+     *
+     * If an NT password was supplied try and validate with that
+     * first. This is superior as the passwords are mixed case 
+     * 128 length unicode.
+      */
+
+    if(smb_ntpasslen)
     {
+      if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
+        DEBUG(2,("NT Password did not match for user '%s' ! Defaulting to Lanman\n", user));
+      else
+        valid_nt_password = True;
+    } 
 
-      /* now check if it's a valid username/password */
-      /* If an NT password was supplied try and validate with that
-        first. This is superior as the passwords are mixed case 
-         128 length unicode */
-      if(smb_ntpasslen)
-       {
-         if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
-           DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
-         else
-           valid_nt_password = True;
-       } 
-      if (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
-       {
-         if (lp_security() >= SEC_USER) {
-#if (GUEST_SESSSETUP == 0)
-           return(ERROR(ERRSRV,ERRbadpw));
-#endif
-#if (GUEST_SESSSETUP == 1)
-           if (Get_Pwnam(user,True))
-             return(ERROR(ERRSRV,ERRbadpw));
-#endif
-         }
-         if (*smb_apasswd || !Get_Pwnam(user,True))
-           pstrcpy(user,lp_guestaccount(-1));
-         DEBUG(3,("Registered username %s for guest access\n",user));
-         guest = True;
-       }
+    if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL))
+    {
+      if (lp_security() >= SEC_USER) 
+      {
+        if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
+        {
+          DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
+          return bad_password_error(inbuf,outbuf);
+        }
+
+        if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
+        {
+          if (smb_getpwnam(user,True))
+          {
+            DEBUG(1,("Rejecting user '%s': bad password\n", user));
+            return bad_password_error(inbuf,outbuf);
+          }
+        }
+
+        /*
+         * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
+         * Then always map to guest account - as done below.
+         */
+      }
+
+      if (*smb_apasswd || !smb_getpwnam(user,True))
+         pstrcpy(user,lp_guestaccount(-1));
+      DEBUG(3,("Registered username %s for guest access\n",user));
+      guest = True;
     }
+  }
 
-  if (!Get_Pwnam(user,True)) {
-    DEBUG(3,("No such user %s - using guest account\n",user));
+  if (!smb_getpwnam(user,True)) {
+    DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
     pstrcpy(user,lp_guestaccount(-1));
     guest = True;
   }
 
   if (!strequal(user,lp_guestaccount(-1)) &&
       lp_servicenumber(user) < 0)      
-    {
-      int homes = lp_servicenumber(HOMES_NAME);
-      char *home = get_home_dir(user);
-      if (homes >= 0 && home)
-       lp_add_home(user,homes,home);
-    }
+  {
+    int homes = lp_servicenumber(HOMES_NAME);
+    char *home = get_user_home_dir(user);
+    if (homes >= 0 && home)
+      lp_add_home(user,homes,home);
+  }
 
 
   /* it's ok - setup a reply */
@@ -707,10 +986,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
      user we should become.
      */
   {
-    struct passwd *pw = Get_Pwnam(user,False);
+    const struct passwd *pw = smb_getpwnam(user,False);
     if (!pw) {
       DEBUG(1,("Username %s is invalid on this system\n",user));
-      return(ERROR(ERRSRV,ERRbadpw));
+      return bad_password_error(inbuf,outbuf);
     }
     gid = pw->pw_gid;
     uid = pw->pw_uid;
@@ -721,7 +1000,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
 
   /* register the name and uid as being validated, so further connections
      to a uid can get through without a password, on the same VC */
-  sess_vuid = register_vuid(uid,gid,user,sesssetup_user,guest);
+  sess_vuid = register_vuid(uid,gid,user,sesssetup_user,domain,guest);
  
   SSVAL(outbuf,smb_uid,sess_vuid);
   SSVAL(inbuf,smb_uid,sess_vuid);
@@ -750,6 +1029,9 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   SMB_STRUCT_STAT st;
  
   pstrcpy(name,smb_buf(inbuf) + 1);
+
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
   unix_convert(name,conn,0,&bad_path,&st);
 
   mode = SVAL(inbuf,smb_vwv0);
@@ -758,7 +1040,7 @@ int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     if(VALID_STAT(st))
       ok = S_ISDIR(st.st_mode);
     else
-      ok = directory_exist(name,NULL);
+      ok = vfs_directory_exist(conn,name,NULL);
   }
 
   if (!ok)
@@ -810,19 +1092,24 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   BOOL bad_path = False;
  
   pstrcpy(fname,smb_buf(inbuf) + 1);
-  unix_convert(fname,conn,0,&bad_path,&sbuf);
 
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+  
+  /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf)); 
+   */
   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
      under WfWg - weird! */
   if (! (*fname))
-    {
-      mode = aHIDDEN | aDIR;
-      if (!CAN_WRITE(conn)) mode |= aRONLY;
-      size = 0;
-      mtime = 0;
-      ok = True;
-    }
+  {
+    mode = aHIDDEN | aDIR;
+    if (!CAN_WRITE(conn)) mode |= aRONLY;
+    size = 0;
+    mtime = 0;
+    ok = True;
+  }
   else
+  {
+    unix_convert(fname,conn,0,&bad_path,&sbuf);
     if (check_name(fname,conn))
     {
       if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
@@ -837,6 +1124,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
       else
         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
     }
+  }
   
   if (!ok)
   {
@@ -891,7 +1179,7 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   mode = SVAL(inbuf,smb_vwv0);
   mtime = make_unix_date3(inbuf+smb_vwv1);
   
-  if (VALID_STAT_OF_DIR(st) || directory_exist(fname,NULL))
+  if (VALID_STAT_OF_DIR(st) || vfs_directory_exist(conn, fname, NULL))
     mode |= aDIR;
   if (check_name(fname,conn))
     ok =  (file_chmod(conn,fname,mode,NULL) == 0);
@@ -925,7 +1213,7 @@ int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
   int outsize = 0;
   SMB_BIG_UINT dfree,dsize,bsize;
   
-  sys_disk_free(".",&bsize,&dfree,&dsize);
+  conn->vfs_ops.disk_free(".",True,&bsize,&dfree,&dsize);
   
   outsize = set_message(outbuf,5,0,True);
   
@@ -984,195 +1272,141 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   /* dirtype &= ~aDIR; */
   
-  DEBUG(5,("path=%s status_len=%d\n",path,status_len));
-
-  
   if (status_len == 0)
-    {
-      pstring dir2;
+  {
+    pstring dir2;
 
-      pstrcpy(directory,smb_buf(inbuf)+1);
-      pstrcpy(dir2,smb_buf(inbuf)+1);
-      unix_convert(directory,conn,0,&bad_path,NULL);
-      unix_format(dir2);
+    pstrcpy(directory,smb_buf(inbuf)+1);
+    pstrcpy(dir2,smb_buf(inbuf)+1);
+    unix_convert(directory,conn,0,&bad_path,NULL);
+    unix_format(dir2);
 
-      if (!check_name(directory,conn))
-        can_open = False;
+    if (!check_name(directory,conn))
+      can_open = False;
 
-      p = strrchr(dir2,'/');
-      if (p == NULL) 
-      {
-        pstrcpy(mask,dir2);
-        *dir2 = 0;
-      }
-      else
-      {
-        *p = 0;
-        pstrcpy(mask,p+1);
-      }
+    p = strrchr(dir2,'/');
+    if (p == NULL) 
+    {
+      pstrcpy(mask,dir2);
+      *dir2 = 0;
+    }
+    else
+    {
+      *p = 0;
+      pstrcpy(mask,p+1);
+    }
 
-      p = strrchr(directory,'/');
-      if (!p) 
-        *directory = 0;
-      else
-        *p = 0;
+    p = strrchr(directory,'/');
+    if (!p) 
+      *directory = 0;
+    else
+      *p = 0;
 
-      if (strlen(directory) == 0)
-        pstrcpy(directory,"./");
-      bzero(status,21);
-      CVAL(status,0) = dirtype;
-    }
+    if (strlen(directory) == 0)
+      pstrcpy(directory,"./");
+    memset((char *)status,'\0',21);
+    CVAL(status,0) = dirtype;
+  }
   else
-    {
-      memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
-      memcpy(mask,status+1,11);
-      mask[11] = 0;
-      dirtype = CVAL(status,0) & 0x1F;
-      conn->dirptr = dptr_fetch(status+12,&dptr_num);      
-      if (!conn->dirptr)
-       goto SearchEmpty;
-      string_set(&conn->dirpath,dptr_path(dptr_num));
-      if (!case_sensitive)
-       strnorm(mask);
-    }
-
-  /* turn strings of spaces into a . */  
   {
-    trim_string(mask,NULL," ");
-    if ((p = strrchr(mask,' ')))
-      {
-       fstring ext;
-       fstrcpy(ext,p+1);
-       *p = 0;
-       trim_string(mask,NULL," ");
-       pstrcat(mask,".");
-       pstrcat(mask,ext);
-      }
+    memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+    dirtype = CVAL(status,0) & 0x1F;
+    conn->dirptr = dptr_fetch(status+12,&dptr_num);      
+    if (!conn->dirptr)
+      goto SearchEmpty;
+    string_set(&conn->dirpath,dptr_path(dptr_num));
+    fstrcpy(mask, dptr_wcard(dptr_num));
   }
 
-  /* Convert the formatted mask. (This code lives in trans2.c) */
-  mask_convert(mask);
-
+  if (can_open)
   {
-    int skip;
-    p = mask;
-    while(*p)
+    p = smb_buf(outbuf) + 3;
+      
+    ok = True;
+     
+    if (status_len == 0)
     {
-      if((skip = skip_multibyte_char( *p )) != 0 )
+      dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+      if (dptr_num < 0)
       {
-        p += skip;
-      }
-      else
-      {
-        if (*p != '?' && *p != '*' && !isdoschar(*p))
+        if(dptr_num == -2)
         {
-          DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
-          *p = '?';
+          if((errno == ENOENT) && bad_path)
+          {
+            unix_ERR_class = ERRDOS;
+            unix_ERR_code = ERRbadpath;
+          }
+          return (UNIXERROR(ERRDOS,ERRnofids));
         }
-        p++;
+        return(ERROR(ERRDOS,ERRnofids));
       }
+      dptr_set_wcard(dptr_num, strdup(mask));
     }
-  }
 
-  if (!strchr(mask,'.') && strlen(mask)>8)
-    {
-      fstring tmp;
-      fstrcpy(tmp,&mask[8]);
-      mask[8] = '.';
-      mask[9] = 0;
-      pstrcat(mask,tmp);
-    }
+    DEBUG(4,("dptr_num is %d\n",dptr_num));
 
-  DEBUG(5,("mask=%s directory=%s\n",mask,directory));
-  
-  if (can_open)
+    if (ok)
     {
-      p = smb_buf(outbuf) + 3;
-      
-      ok = True;
-      
-      if (status_len == 0)
-       {
-         dptr_num = dptr_create(conn,directory,expect_close,SVAL(inbuf,smb_pid));
-         if (dptr_num < 0)
+      if ((dirtype&0x1F) == aVOLID)
+      {          
+        memcpy(p,status,21);
+        make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+        dptr_fill(p+12,dptr_num);
+        if (dptr_zero(p+12) && (status_len==0))
+          numentries = 1;
+        else
+          numentries = 0;
+        p += DIR_STRUCT_SIZE;
+      }
+      else 
+      {
+        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+              conn->dirpath,lp_dontdescend(SNUM(conn))));
+        if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+          check_descend = True;
+
+        for (i=numentries;(i<maxentries) && !finished;i++)
         {
-          if(dptr_num == -2)
+          finished = 
+            !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+          if (!finished)
           {
-            if((errno == ENOENT) && bad_path)
-            {
-              unix_ERR_class = ERRDOS;
-              unix_ERR_code = ERRbadpath;
-            }
-            return (UNIXERROR(ERRDOS,ERRnofids));
-          }
-          return(ERROR(ERRDOS,ERRnofids));
+            memcpy(p,status,21);
+            make_dir_struct(p,mask,fname,size,mode,date);
+            dptr_fill(p+12,dptr_num);
+            numentries++;
+         }
+         p += DIR_STRUCT_SIZE;
         }
-       }
-
-      DEBUG(4,("dptr_num is %d\n",dptr_num));
-
-      if (ok)
-       {
-         if ((dirtype&0x1F) == aVOLID)
-           {     
-             memcpy(p,status,21);
-             make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
-             dptr_fill(p+12,dptr_num);
-             if (dptr_zero(p+12) && (status_len==0))
-               numentries = 1;
-             else
-               numentries = 0;
-             p += DIR_STRUCT_SIZE;
-           }
-         else 
-           {
-             DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                      conn->dirpath,lp_dontdescend(SNUM(conn))));
-             if (in_list(conn->dirpath,
-                         lp_dontdescend(SNUM(conn)),True))
-               check_descend = True;
-
-             for (i=numentries;(i<maxentries) && !finished;i++)
-               {
-                 finished = 
-                   !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
-                 if (!finished)
-                   {
-                     memcpy(p,status,21);
-                     make_dir_struct(p,mask,fname,size,mode,date);
-                     dptr_fill(p+12,dptr_num);
-                     numentries++;
-                   }
-                 p += DIR_STRUCT_SIZE;
-               }
-           }
-       }
-    }
+      }
+       } /* if (ok ) */
+  }
 
 
- SearchEmpty:
 SearchEmpty:
 
   if (numentries == 0 || !ok)
-    {
-      CVAL(outbuf,smb_rcls) = ERRDOS;
-      SSVAL(outbuf,smb_err,ERRnofiles);
-    }
+  {
+    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SSVAL(outbuf,smb_err,ERRnofiles);
+    dptr_close(&dptr_num);
+  }
 
   /* If we were called as SMBffirst with smb_search_id == NULL
      and no entries were found then return error and close dirptr 
      (X/Open spec) */
 
   if(ok && expect_close && numentries == 0 && status_len == 0)
-    {
-      CVAL(outbuf,smb_rcls) = ERRDOS;
-      SSVAL(outbuf,smb_err,ERRnofiles);
-      /* Also close the dptr - we know it's gone */
-      dptr_close(dptr_num);
-    }
+  {
+    CVAL(outbuf,smb_rcls) = ERRDOS;
+    SSVAL(outbuf,smb_err,ERRnofiles);
+    /* Also close the dptr - we know it's gone */
+    dptr_close(&dptr_num);
+  }
 
   /* If we were called as SMBfunique, then we can close the dirptr now ! */
   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
-    dptr_close(dptr_num);
+    dptr_close(&dptr_num);
 
   SSVAL(outbuf,smb_vwv0,numentries);
   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -1191,8 +1425,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
 
   DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
-       smb_fn_name(CVAL(inbuf,smb_com)), 
-       mask, directory, dirtype, numentries, maxentries ) );
+        smb_fn_name(CVAL(inbuf,smb_com)), 
+        mask, directory, dirtype, numentries, maxentries ) );
 
   return(outsize);
 }
@@ -1207,7 +1441,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   int status_len;
   char *path;
   char status[21];
-  int dptr_num= -1;
+  int dptr_num= -2;
 
   outsize = set_message(outbuf,1,0,True);
   path = smb_buf(inbuf) + 1;
@@ -1221,7 +1455,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 
   if(dptr_fetch(status+12,&dptr_num)) {
     /*  Close the dptr - we know it's gone */
-    dptr_close(dptr_num);
+    dptr_close(&dptr_num);
   }
 
   SSVAL(outbuf,smb_vwv0,0);
@@ -1235,6 +1469,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 /****************************************************************************
   reply to an open
 ****************************************************************************/
+
 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
   pstring fname;
@@ -1253,40 +1488,27 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   share_mode = SVAL(inbuf,smb_vwv0);
 
   pstrcpy(fname,smb_buf(inbuf)+1);
+
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
   unix_convert(fname,conn,0,&bad_path,NULL);
     
-  fsp = file_new();
-  if (!fsp)
-    return(ERROR(ERRSRV,ERRnofids));
-
-  if (!check_name(fname,conn))
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    file_free(fsp);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-  unixmode = unix_mode(conn,aARCH);
+  unixmode = unix_mode(conn,aARCH,fname);
       
-  open_file_shared(fsp,conn,fname,share_mode,3,unixmode,
-                   oplock_request,&rmode,NULL);
+  fsp = open_file_shared(conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                   unixmode, oplock_request,&rmode,NULL);
 
-  if (!fsp->open)
+  if (!fsp)
   {
     if((errno == ENOENT) && bad_path)
     {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
-    file_free(fsp);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+  if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
     close_file(fsp,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
@@ -1315,7 +1537,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
     
-  if(fsp->granted_oplock)
+  if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   return(outsize);
 }
@@ -1349,46 +1571,33 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
   files_struct *fsp;
 
   /* If it's an IPC, pass off the pipe handler. */
-  if (IS_IPC(conn))
+  if (IS_IPC(conn) && lp_nt_pipe_support())
     return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
 
   /* XXXX we need to handle passed times, sattr and flags */
 
   pstrcpy(fname,smb_buf(inbuf));
-  unix_convert(fname,conn,0,&bad_path,NULL);
-    
-  fsp = file_new();
-  if (!fsp)
-    return(ERROR(ERRSRV,ERRnofids));
 
-  if (!check_name(fname,conn))
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    file_free(fsp);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
-  unixmode = unix_mode(conn,smb_attr | aARCH);
+  unix_convert(fname,conn,0,&bad_path,NULL);
+    
+  unixmode = unix_mode(conn,smb_attr | aARCH, fname);
       
-  open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
+  fsp = open_file_shared(conn,fname,smb_mode,smb_ofun,unixmode,
                       oplock_request, &rmode,&smb_action);
       
-  if (!fsp->open)
+  if (!fsp)
   {
     if((errno == ENOENT) && bad_path)
     {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
-    file_free(fsp);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
-  if (sys_fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
+  if (fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) {
     close_file(fsp,False);
     return(ERROR(ERRDOS,ERRnoaccess));
   }
@@ -1410,7 +1619,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
     smb_action |= EXTENDED_OPLOCK_GRANTED;
   }
 
-  if(ex_oplock_request && fsp->granted_oplock) {
+  if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     smb_action |= EXTENDED_OPLOCK_GRANTED;
   }
 
@@ -1423,7 +1632,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
-  if(core_oplock_request && fsp->granted_oplock) {
+  if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
 
@@ -1489,6 +1698,9 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 
   createmode = SVAL(inbuf,smb_vwv0);
   pstrcpy(fname,smb_buf(inbuf)+1);
+
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
   unix_convert(fname,conn,0,&bad_path,NULL);
 
   if (createmode & aVOLID)
@@ -1496,46 +1708,30 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
     }
   
-  unixmode = unix_mode(conn,createmode);
+  unixmode = unix_mode(conn,createmode,fname);
   
-  fsp = file_new();
-  if (!fsp)
-    return(ERROR(ERRSRV,ERRnofids));
-
-  if (!check_name(fname,conn))
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    file_free(fsp);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
   if(com == SMBmknew)
   {
     /* We should fail if file exists. */
-    ofun = 0x10;
+    ofun = FILE_CREATE_IF_NOT_EXIST;
   }
   else
   {
     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
-    ofun = 0x12;
+    ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
   }
 
   /* Open file in dos compatibility share mode. */
-  open_file_shared(fsp,conn,fname,(DENY_FCB<<4)|0xF, ofun, unixmode
-                   oplock_request, NULL, NULL);
+  fsp = open_file_shared(conn,fname,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB)
+                   ofun, unixmode, oplock_request, NULL, NULL);
   
-  if (!fsp->open)
+  if (!fsp)
   {
     if((errno == ENOENT) && bad_path) 
     {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
-    file_free(fsp);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
  
@@ -1546,12 +1742,12 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
  
-  if(fsp->granted_oplock)
+  if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
  
   DEBUG( 2, ( "new file %s\n", fname ) );
   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
-        fname, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
+        fname, fsp->fd, createmode, (int)unixmode ) );
 
   return(outsize);
 }
@@ -1574,40 +1770,27 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   createmode = SVAL(inbuf,smb_vwv0);
   pstrcpy(fname,smb_buf(inbuf)+1);
   pstrcat(fname,"/TMXXXXXX");
+
+  RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
   unix_convert(fname,conn,0,&bad_path,NULL);
   
-  unixmode = unix_mode(conn,createmode);
+  unixmode = unix_mode(conn,createmode,fname);
   
-  fsp = file_new();
-  if (fsp)
-    return(ERROR(ERRSRV,ERRnofids));
-
-  if (!check_name(fname,conn))
-  {
-    if((errno == ENOENT) && bad_path)
-    {
-      unix_ERR_class = ERRDOS;
-      unix_ERR_code = ERRbadpath;
-    }
-    file_free(fsp);
-    return(UNIXERROR(ERRDOS,ERRnoaccess));
-  }
-
-  pstrcpy(fname2,(char *)mktemp(fname));
+  pstrcpy(fname2,(char *)smbd_mktemp(fname));
 
   /* Open file in dos compatibility share mode. */
   /* We should fail if file exists. */
-  open_file_shared(fsp,conn,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode
-                   oplock_request, NULL, NULL);
+  fsp = open_file_shared(conn,fname2,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB)
+                   (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
 
-  if (!fsp->open)
+  if (!fsp)
   {
     if((errno == ENOENT) && bad_path)
     {
       unix_ERR_class = ERRDOS;
       unix_ERR_code = ERRbadpath;
     }
-    file_free(fsp);
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   }
 
@@ -1620,12 +1803,12 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
   }
   
-  if(fsp->granted_oplock)
+  if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
 
   DEBUG( 2, ( "created temp file %s\n", fname2 ) );
   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
-        fname2, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
+        fname2, fsp->fd, createmode, (int)unixmode ) );
 
   return(outsize);
 }
@@ -1641,7 +1824,7 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
 
   if (!CAN_WRITE(conn)) return(False);
 
-  if (dos_lstat(fname,&sbuf) != 0) return(False);
+  if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
   fmode = dos_mode(conn,fname,&sbuf);
   if (fmode & aDIR) return(False);
   if (!lp_delete_readonly(SNUM(conn))) {
@@ -1654,8 +1837,9 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
 }
 
 /****************************************************************************
 reply to a unlink
Reply to a unlink
 ****************************************************************************/
+
 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
   int outsize = 0;
@@ -1669,6 +1853,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   BOOL has_wild;
   BOOL exists=False;
   BOOL bad_path = False;
+  BOOL rc = True;
 
   *directory = *mask = 0;
 
@@ -1676,9 +1861,11 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   
   pstrcpy(name,smb_buf(inbuf) + 1);
    
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+
   DEBUG(3,("reply_unlink : %s\n",name));
    
-  unix_convert(name,conn,0,&bad_path,NULL);
+  rc = unix_convert(name,conn,0,&bad_path,NULL);
 
   p = strrchr(name,'/');
   if (!p) {
@@ -1690,16 +1877,27 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
     pstrcpy(mask,p+1);
   }
 
-  if (is_mangled(mask))
+  /*
+   * We should only check the mangled cache
+   * here if unix_convert failed. This means
+   * that the path in 'mask' doesn't exist
+   * on the file system and so we need to look
+   * for a possible mangle. This patch from
+   * Tine Smukavec <valentin.smukavec@hermes.si>.
+   */
+
+  if (!rc && is_mangled(mask))
     check_mangled_cache( mask );
 
-  has_wild = strchr(mask,'*') || strchr(mask,'?');
+  has_wild = ms_has_wild(mask);
 
   if (!has_wild) {
     pstrcat(directory,"/");
     pstrcat(directory,mask);
-    if (can_delete(directory,conn,dirtype) && !dos_unlink(directory)) count++;
-    if (!count) exists = file_exist(directory,NULL);    
+    if (can_delete(directory,conn,dirtype) && !dos_unlink(directory))
+      count++;
+    if (!count)
+      exists = vfs_file_exist(conn,directory,NULL);    
   } else {
     void *dirptr = NULL;
     char *dname;
@@ -1724,12 +1922,12 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
            pstring fname;
            pstrcpy(fname,dname);
            
-           if(!mask_match(fname, mask, case_sensitive, False)) continue;
+           if(!mask_match(fname, mask, case_sensitive)) continue;
 
            error = ERRnoaccess;
            slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
            if (!can_delete(fname,conn,dirtype)) continue;
-           if (!dos_unlink(fname)) count++;
+           if (!conn->vfs_ops.unlink(dos_to_unix(fname,False))) count++;
            DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
          }
        CloseDir(dirptr);
@@ -1759,6 +1957,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
 /****************************************************************************
    reply to a readbraw (core+ protocol)
 ****************************************************************************/
+
 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
 {
   size_t maxcount,mincount;
@@ -1777,29 +1976,60 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
   if(global_oplock_break)
   {
     _smb_setlen(header,0);
-    transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+    transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
     DEBUG(5,("readbraw - oplock break finished\n"));
     return -1;
   }
 
   fsp = file_fsp(inbuf,smb_vwv0);
 
+  if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
+         /*
+          * fsp could be NULL here so use the value from the packet. JRA.
+          */
+         DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
+         _smb_setlen(header,0);
+         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
+         return(-1);
+  }
+
+  CHECK_FSP(fsp,conn);
+
+  flush_write_cache(fsp, READRAW_FLUSH);
+
   startpos = IVAL(inbuf,smb_vwv1);
-#ifdef LARGE_SMB_OFF_T
   if(CVAL(inbuf,smb_wct) == 10) {
     /*
      * This is a large offset (64 bit) read.
      */
+#ifdef LARGE_SMB_OFF_T
+
     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
+
+#else /* !LARGE_SMB_OFF_T */
+
+    /*
+     * Ensure we haven't been sent a >32 bit offset.
+     */
+
+    if(IVAL(inbuf,smb_vwv8) != 0) {
+      DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
+      _smb_setlen(header,0);
+      transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
+      return(-1);
+    }
+
+#endif /* LARGE_SMB_OFF_T */
+
     if(startpos < 0) {
       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
             (double)startpos ));
          _smb_setlen(header,0);
-         transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
+         transfer_file(0,smbd_server_fd(),(SMB_OFF_T)0,header,4,0);
          return(-1);
     }      
   }
-#endif /* LARGE_SMB_OFF_T */
   maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
   mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
 
@@ -1807,14 +2037,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
   maxcount = MIN(65535,maxcount);
   maxcount = MAX(mincount,maxcount);
 
-  if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
-         DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fsp->fnum));
-         _smb_setlen(header,0);
-         transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
-         return(-1);
-  }
-
-  if (!is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
+  if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
   {
     SMB_OFF_T size = fsp->size;
     SMB_OFF_T sizeneeded = startpos + maxcount;
@@ -1822,7 +2045,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
     if (size < sizeneeded)
     {
       SMB_STRUCT_STAT st;
-      if (sys_fstat(fsp->fd_ptr->fd,&st) == 0)
+      if (fsp->conn->vfs_ops.fstat(fsp->fd,&st) == 0)
         size = st.st_size;
       if (!fsp->can_write) 
         fsp->size = size;
@@ -1836,23 +2059,31 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
   
   DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
              fsp->fnum, (double)startpos,
-             maxcount, mincount, nread ) );
+             (int)maxcount, (int)mincount, (int)nread ) );
   
 #if UNSAFE_READRAW
   {
+    BOOL seek_fail = False;
     int predict=0;
     _smb_setlen(header,nread);
 
 #if USE_READ_PREDICTION
     if (!fsp->can_write)
-      predict = read_predict(fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
+      predict = read_predict(fsp, fsp->fd,startpos,header+4,NULL,nread);
 #endif /* USE_READ_PREDICTION */
 
-    if ((nread-predict) > 0)
-      seek_file(fsp,startpos + predict);
-    
-    ret = (ssize_t)transfer_file(fsp->fd_ptr->fd,Client,(SMB_OFF_T)(nread-predict),header,4+predict,
-                       startpos+predict);
+    if ((nread-predict) > 0) {
+      if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
+        DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
+        ret = 0;
+        seek_fail = True;
+      } 
+    }
+
+    if(!seek_fail)
+      ret = (ssize_t)vfs_transfer_file(-1, fsp->fd, Client, NULL,
+                                   (SMB_OFF_T)(nread-predict),header,4+predict, 
+                                   startpos+predict);
   }
 
   if (ret != nread+4)
@@ -1864,7 +2095,7 @@ int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_s
   if (ret < mincount) ret = 0;
 
   _smb_setlen(header,ret);
-  transfer_file(0,Client,0,header,4+ret,0);
+  transfer_file(0,smbd_server_fd(),0,header,4+ret,0);
 #endif /* UNSAFE_READRAW */
 
   DEBUG(5,("readbraw finished\n"));
@@ -1896,8 +2127,15 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
   outsize = set_message(outbuf,5,3,True);
   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
   data = smb_buf(outbuf) + 3;
-  
-  if(!do_lock( fsp, conn, numtoread, startpos, F_RDLCK, &eclass, &ecode)) {
+  /*
+   * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
+   * protocol request that predates the read/write lock concept. 
+   * Thus instead of asking for a read lock here we need to ask
+   * for a write lock. JRA.
+   */
+
+  if(!do_lock( fsp, conn, (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &eclass, &ecode)) {
     if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
       /*
        * A blocking lock was requested. Package up
@@ -1921,7 +2159,7 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
   SSVAL(smb_buf(outbuf),1,nread);
 
   DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
-            fsp->fnum, numtoread, nread ) );
+            fsp->fnum, (int)numtoread, (int)nread ) );
 
   return(outsize);
 }
@@ -1930,7 +2168,8 @@ int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length
 /****************************************************************************
   reply to a read
 ****************************************************************************/
-int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   size_t numtoread;
   ssize_t nread = 0;
@@ -1950,7 +2189,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
   data = smb_buf(outbuf) + 3;
   
-  if (is_locked(fsp,conn,numtoread,startpos, F_RDLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK))
     return(ERROR(ERRDOS,ERRlock));     
 
   if (numtoread > 0)
@@ -1966,7 +2205,7 @@ int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   SSVAL(smb_buf(outbuf),1,nread);
   
   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
-            fsp->fnum, numtoread, nread ) );
+            fsp->fnum, (int)numtoread, (int)nread ) );
 
   return(outsize);
 }
@@ -1995,16 +2234,30 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
   set_message(outbuf,12,0,True);
   data = smb_buf(outbuf);
 
-#ifdef LARGE_SMB_OFF_T
   if(CVAL(inbuf,smb_wct) == 12) {
+#ifdef LARGE_SMB_OFF_T
     /*
      * This is a large offset (64 bit) read.
      */
     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
-  }
+
+#else /* !LARGE_SMB_OFF_T */
+
+    /*
+     * Ensure we haven't been sent a >32 bit offset.
+     */
+
+    if(IVAL(inbuf,smb_vwv10) != 0) {
+      DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
+      return(ERROR(ERRDOS,ERRbadaccess));
+    }
+
 #endif /* LARGE_SMB_OFF_T */
 
-  if (is_locked(fsp,conn,smb_maxcnt,startpos, F_RDLCK))
+  }
+
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK))
     return(ERROR(ERRDOS,ERRlock));
   nread = read_file(fsp,data,startpos,smb_maxcnt);
   
@@ -2016,7 +2269,7 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
   SSVAL(smb_buf(outbuf),-2,nread);
   
   DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
-             fsp->fnum, smb_mincnt, smb_maxcnt, nread ) );
+             fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
 
   return chain_reply(inbuf,outbuf,length,bufsize);
 }
@@ -2024,7 +2277,8 @@ int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
 /****************************************************************************
   reply to a writebraw (core+ or LANMAN1.0 protocol)
 ****************************************************************************/
-int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   ssize_t nwritten=0;
   ssize_t total_written=0;
@@ -2058,17 +2312,14 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
   CVAL(inbuf,smb_com) = SMBwritec;
   CVAL(outbuf,smb_com) = SMBwritec;
 
-  if (is_locked(fsp,conn,tcount,startpos, F_WRLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK))
     return(ERROR(ERRDOS,ERRlock));
 
-  if (seek_file(fsp,startpos) != startpos)
-    DEBUG(0,("couldn't seek to %.0f in writebraw\n",(double)startpos));
-
   if (numtowrite>0)
-    nwritten = write_file(fsp,data,numtowrite);
+    nwritten = write_file(fsp,data,startpos,numtowrite);
   
   DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
-          fsp->fnum, (double)startpos, numtowrite, nwritten, write_through));
+          fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
 
   if (nwritten < numtowrite) 
     return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -2080,10 +2331,10 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
   CVAL(outbuf,smb_com) = SMBwritebraw;
   SSVALS(outbuf,smb_vwv0,-1);
   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
-  send_smb(Client,outbuf);
+  send_smb(smbd_server_fd(),outbuf);
   
   /* Now read the raw data into the buffer and write it */
-  if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
+  if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
     exit_server("secondary writebraw failed");
   }
   
@@ -2093,11 +2344,12 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
 
   if (tcount > nwritten+numtowrite) {
     DEBUG(3,("Client overestimated the write %d %d %d\n",
-            tcount,nwritten,numtowrite));
+            (int)tcount,(int)nwritten,(int)numtowrite));
   }
 
-  nwritten = transfer_file(Client,fsp->fd_ptr->fd,(SMB_OFF_T)numtowrite,NULL,0,
-                          startpos+nwritten);
+  nwritten = vfs_transfer_file(smbd_server_fd(), NULL, -1, fsp,
+                              (SMB_OFF_T)numtowrite,NULL,0, 
+                              startpos+nwritten);
   total_written += nwritten;
   
   /* Set up outbuf to return the correct return */
@@ -2110,11 +2362,12 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
     SSVAL(outbuf,smb_err,ERRdiskfull);      
   }
 
-  if (lp_syncalways(SNUM(conn)) || write_through)
-    sync_file(conn,fsp);
+  if ((lp_syncalways(SNUM(conn)) || write_through) && 
+      lp_strict_sync(SNUM(conn)))
+      sync_file(conn,fsp);
 
   DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
-          fsp->fnum, (double)startpos, numtowrite, total_written));
+          fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
 
   /* we won't return a status if write through is not selected - this 
      follows what WfWg does */
@@ -2127,7 +2380,8 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
 /****************************************************************************
   reply to a writeunlock (core+)
 ****************************************************************************/
-int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   ssize_t nwritten = -1;
   size_t numtowrite;
@@ -2146,26 +2400,24 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
   startpos = IVAL(inbuf,smb_vwv2);
   data = smb_buf(inbuf) + 3;
   
-  if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
     return(ERROR(ERRDOS,ERRlock));
 
-  seek_file(fsp,startpos);
-
   /* The special X/Open SMB protocol handling of
      zero length writes is *NOT* done for
      this call */
   if(numtowrite == 0)
     nwritten = 0;
   else
-    nwritten = write_file(fsp,data,numtowrite);
+    nwritten = write_file(fsp,data,startpos,numtowrite);
   
   if (lp_syncalways(SNUM(conn)))
-    sync_file(conn,fsp);
+      sync_file(conn,fsp);
 
   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
     return(UNIXERROR(ERRDOS,ERRnoaccess));
 
-  if(!do_unlock(fsp, conn, numtowrite, startpos, &eclass, &ecode))
+  if(!do_unlock(fsp, conn, (SMB_BIG_UINT)numtowrite, (SMB_BIG_UINT)startpos, &eclass, &ecode))
     return(ERROR(eclass,ecode));
 
   outsize = set_message(outbuf,1,0,True);
@@ -2173,7 +2425,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
   SSVAL(outbuf,smb_vwv0,nwritten);
   
   DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
-             fsp->fnum, numtowrite, nwritten ) );
+             fsp->fnum, (int)numtowrite, (int)nwritten ) );
 
   return(outsize);
 }
@@ -2181,7 +2433,7 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int dum
 /****************************************************************************
   reply to a write
 ****************************************************************************/
-int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,int dum_buffsize)
+int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
 {
   size_t numtowrite;
   ssize_t nwritten = -1;
@@ -2190,6 +2442,10 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
   int outsize = 0;
 
+  /* If it's an IPC, pass off the pipe handler. */
+  if (IS_IPC(conn))
+    return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
+
   CHECK_FSP(fsp,conn);
   CHECK_WRITE(fsp);
   CHECK_ERROR(fsp);
@@ -2198,18 +2454,17 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
   startpos = IVAL(inbuf,smb_vwv2);
   data = smb_buf(inbuf) + 3;
   
-  if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
     return(ERROR(ERRDOS,ERRlock));
 
-  seek_file(fsp,startpos);
-
   /* X/Open SMB protocol says that if smb_vwv1 is
      zero then the file size should be extended or
      truncated to the size given in smb_vwv[2-3] */
-  if(numtowrite == 0)
-    nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos);
-  else
-    nwritten = write_file(fsp,data,numtowrite);
+  if(numtowrite == 0) {
+      if((nwritten = set_filelen(fsp->fd, (SMB_OFF_T)startpos)) >= 0) /* tpot vfs */
+      set_filelen_write_cache(fsp, startpos); 
+  } else
+    nwritten = write_file(fsp,data,startpos,numtowrite);
   
   if (lp_syncalways(SNUM(conn)))
     sync_file(conn,fsp);
@@ -2227,7 +2482,7 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int dum_size,i
   }
   
   DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, numtowrite, nwritten));
+          fsp->fnum, (int)numtowrite, (int)nwritten));
 
   return(outsize);
 }
@@ -2243,29 +2498,47 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
   size_t numtowrite = SVAL(inbuf,smb_vwv10);
   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
   ssize_t nwritten = -1;
-  int smb_doff = SVAL(inbuf,smb_vwv11);
+  unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
   char *data;
 
+  /* If it's an IPC, pass off the pipe handler. */
+  if (IS_IPC(conn))
+    return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
+
   CHECK_FSP(fsp,conn);
   CHECK_WRITE(fsp);
   CHECK_ERROR(fsp);
 
+  if(smb_doff > smb_len(inbuf))
+    return(ERROR(ERRDOS,ERRbadmem));
+
   data = smb_base(inbuf) + smb_doff;
 
-#ifdef LARGE_SMB_OFF_T
   if(CVAL(inbuf,smb_wct) == 14) {
+#ifdef LARGE_SMB_OFF_T
     /*
      * This is a large offset (64 bit) write.
      */
     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
-  }
+
+#else /* !LARGE_SMB_OFF_T */
+
+    /*
+     * Ensure we haven't been sent a >32 bit offset.
+     */
+
+    if(IVAL(inbuf,smb_vwv12) != 0) {
+      DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
+64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
+      return(ERROR(ERRDOS,ERRbadaccess));
+    }
+
 #endif /* LARGE_SMB_OFF_T */
+  }
 
-  if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
     return(ERROR(ERRDOS,ERRlock));
 
-  seek_file(fsp,startpos);
-  
   /* X/Open SMB protocol says that, unlike SMBwrite
      if the length is zero then NO truncation is
      done, just a write of zero. To truncate a file,
@@ -2273,7 +2546,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
   if(numtowrite == 0)
     nwritten = 0;
   else
-    nwritten = write_file(fsp,data,numtowrite);
+    nwritten = write_file(fsp,data,startpos,numtowrite);
   
   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
     return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2288,7 +2561,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
   }
 
   DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
-          fsp->fnum, numtowrite, nwritten));
+          fsp->fnum, (int)numtowrite, (int)nwritten));
 
   if (lp_syncalways(SNUM(conn)) || write_through)
     sync_file(conn,fsp);
@@ -2300,7 +2573,8 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
 /****************************************************************************
   reply to a lseek
 ****************************************************************************/
-int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   SMB_OFF_T startpos;
   SMB_OFF_T res= -1;
@@ -2311,11 +2585,12 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   CHECK_FSP(fsp,conn);
   CHECK_ERROR(fsp);
 
+  flush_write_cache(fsp, SEEK_FLUSH);
+
   mode = SVAL(inbuf,smb_vwv1) & 3;
-  startpos = IVAL(inbuf,smb_vwv2);
+  startpos = IVALS(inbuf,smb_vwv2);
 
-  switch (mode & 3) 
-  {
+  switch (mode) {
     case 0: umode = SEEK_SET; break;
     case 1: umode = SEEK_CUR; break;
     case 2: umode = SEEK_END; break;
@@ -2323,14 +2598,48 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
       umode = SEEK_SET; break;
   }
 
-  res = sys_lseek(fsp->fd_ptr->fd,startpos,umode);
+  if((res = conn->vfs_ops.lseek(fsp->fd,startpos,umode)) == -1) {
+    /*
+     * Check for the special case where a seek before the start
+     * of the file sets the offset to zero. Added in the CIFS spec,
+     * section 4.2.7.
+     */
+
+    if(errno == EINVAL) {
+      SMB_OFF_T current_pos = startpos;
+
+      if(umode == SEEK_CUR) {
+
+        if((current_pos = conn->vfs_ops.lseek(fsp->fd,0,SEEK_CUR)) == -1)
+          return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+        current_pos += startpos;
+
+      } else if (umode == SEEK_END) {
+
+        SMB_STRUCT_STAT sbuf;
+
+        if(conn->vfs_ops.fstat(fsp->fd, &sbuf) == -1)
+          return(UNIXERROR(ERRDOS,ERRnoaccess));
+
+        current_pos += sbuf.st_size;
+      }
+      if(current_pos < 0)
+        res = conn->vfs_ops.lseek(fsp->fd,0,SEEK_SET);
+    }
+
+    if(res == -1)
+      return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
+
   fsp->pos = res;
   
   outsize = set_message(outbuf,2,0,True);
-  SIVALS(outbuf,smb_vwv0,res);
+  SIVAL(outbuf,smb_vwv0,res);
   
-  DEBUG(3,("lseek fnum=%d ofs=%.0f mode=%d\n",
-          fsp->fnum, (double)startpos, mode));
+  DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
+          fsp->fnum, (double)startpos, (double)res, mode));
 
   return(outsize);
 }
@@ -2338,7 +2647,8 @@ int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 /****************************************************************************
   reply to a flush
 ****************************************************************************/
-int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   int outsize = set_message(outbuf,0,0,True);
   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -2351,7 +2661,7 @@ int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   if (!fsp) {
          file_sync_all(conn);
   } else {
-         sync_file(conn,fsp);
+               sync_file(conn,fsp);
   }
 
   DEBUG(3,("flush\n"));
@@ -2375,8 +2685,8 @@ int reply_exit(connection_struct *conn,
 /****************************************************************************
  Reply to a close - has to deal with closing a directory opened by NT SMB's.
 ****************************************************************************/
-int reply_close(connection_struct *conn,
-               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
+                int dum_buffsize)
 {
        int outsize = 0;
        time_t mtime;
@@ -2386,9 +2696,8 @@ int reply_close(connection_struct *conn,
        outsize = set_message(outbuf,0,0,True);
 
        /* If it's an IPC, pass off to the pipe handler. */
-       if (IS_IPC(conn)) {
+       if (IS_IPC(conn))
                return reply_pipe_close(conn, inbuf,outbuf);
-       }
 
        fsp = file_fsp(inbuf,smb_vwv0);
 
@@ -2396,35 +2705,56 @@ int reply_close(connection_struct *conn,
         * We can only use CHECK_FSP if we know it's not a directory.
         */
 
-    if(!fsp || !fsp->open || (fsp->conn != conn))
-      return(ERROR(ERRDOS,ERRbadfid));
+       if(!fsp || (fsp->conn != conn))
+               return(ERROR(ERRDOS,ERRbadfid));
 
        if(HAS_CACHED_ERROR(fsp)) {
                eclass = fsp->wbmpx_ptr->wr_errclass;
                err = fsp->wbmpx_ptr->wr_error;
        }
 
-       if(fsp->is_directory) {
+       if(fsp->is_directory || fsp->stat_open) {
                /*
-                * Special case - close NT SMB directory
+                * Special case - close NT SMB directory or stat file
                 * handle.
                 */
-               DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
-               close_directory(fsp);
+               DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
+               close_file(fsp,True);
        } else {
                /*
                 * Close ordinary file.
                 */
+               int close_err;
+
+               /*
+                * If there was a modify time outstanding,
+                * try and set it here.
+                */
+               if(fsp->pending_modtime)
+                       set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
+
+               /*
+                * Now take care of any time sent in the close.
+                */
                mtime = make_unix_date3(inbuf+smb_vwv1);
                
                /* try and set the date */
                set_filetime(conn, fsp->fsp_name,mtime);
 
                DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
-                        fsp->fd_ptr->fd, fsp->fnum,
+                        fsp->fd, fsp->fnum,
                         conn->num_files_open));
-  
-               close_file(fsp,True);
+               /*
+                * close_file() returns the unix errno if an error
+                * was detected on close - normally this is due to
+                * a disk full error. If not then it was probably an I/O error.
+                */
+               if((close_err = close_file(fsp,True)) != 0) {
+                       errno = close_err;
+                       return (UNIXERROR(ERRHRD,ERRgeneral));
+               }
        }  
 
        /* We have a cached error */
@@ -2438,12 +2768,14 @@ int reply_close(connection_struct *conn,
 /****************************************************************************
   reply to a writeclose (Core+ protocol)
 ****************************************************************************/
+
 int reply_writeclose(connection_struct *conn,
-                    char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+                    char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
        size_t numtowrite;
        ssize_t nwritten = -1;
        int outsize = 0;
+       int close_err = 0;
        SMB_OFF_T startpos;
        char *data;
        time_t mtime;
@@ -2458,24 +2790,27 @@ int reply_writeclose(connection_struct *conn,
        mtime = make_unix_date3(inbuf+smb_vwv4);
        data = smb_buf(inbuf) + 1;
   
-       if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
+       if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK))
                return(ERROR(ERRDOS,ERRlock));
-      
-       seek_file(fsp,startpos);
-      
-       nwritten = write_file(fsp,data,numtowrite);
+          
+       nwritten = write_file(fsp,data,startpos,numtowrite);
 
        set_filetime(conn, fsp->fsp_name,mtime);
   
-       close_file(fsp,True);
+       close_err = close_file(fsp,True);
 
        DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
-                fsp->fnum, numtowrite, nwritten,
+                fsp->fnum, (int)numtowrite, (int)nwritten,
                 conn->num_files_open));
   
        if (nwritten <= 0)
                return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+       if(close_err != 0) {
+               errno = close_err;
+               return(UNIXERROR(ERRHRD,ERRgeneral));
+       }
        outsize = set_message(outbuf,1,0,True);
   
        SSVAL(outbuf,smb_vwv0,nwritten);
@@ -2490,7 +2825,7 @@ int reply_lock(connection_struct *conn,
               char *inbuf,char *outbuf, int length, int dum_buffsize)
 {
        int outsize = set_message(outbuf,0,0,True);
-       SMB_OFF_T count,offset;
+       SMB_BIG_UINT count,offset;
        int eclass;
        uint32 ecode;
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -2498,13 +2833,13 @@ int reply_lock(connection_struct *conn,
        CHECK_FSP(fsp,conn);
        CHECK_ERROR(fsp);
 
-       count = IVAL(inbuf,smb_vwv1);
-       offset = IVAL(inbuf,smb_vwv3);
+       count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+       offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
 
        DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
-                fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
+                fsp->fd, fsp->fnum, (double)offset, (double)count));
 
-       if (!do_lock(fsp, conn, count, offset, F_WRLCK, &eclass, &ecode)) {
+       if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
       if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
         /*
          * A blocking lock was requested. Package up
@@ -2524,10 +2859,10 @@ int reply_lock(connection_struct *conn,
 /****************************************************************************
   reply to a unlock
 ****************************************************************************/
-int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   int outsize = set_message(outbuf,0,0,True);
-  SMB_OFF_T count,offset;
+  SMB_BIG_UINT count,offset;
   int eclass;
   uint32 ecode;
   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
@@ -2535,14 +2870,14 @@ int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   CHECK_FSP(fsp,conn);
   CHECK_ERROR(fsp);
 
-  count = IVAL(inbuf,smb_vwv1);
-  offset = IVAL(inbuf,smb_vwv3);
+  count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
+  offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
 
   if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
     return (ERROR(eclass,ecode));
 
   DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
-        fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count ) );
+        fsp->fd, fsp->fnum, (double)offset, (double)count ) );
   
   return(outsize);
 }
@@ -2581,9 +2916,11 @@ int reply_echo(connection_struct *conn,
 {
        int smb_reverb = SVAL(inbuf,smb_vwv0);
        int seq_num;
-       int data_len = smb_buflen(inbuf);
+       unsigned int data_len = smb_buflen(inbuf);
        int outsize = set_message(outbuf,1,data_len,True);
-       
+
+       data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
+
        /* copy any incoming data back out */
        if (data_len > 0)
                memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
@@ -2598,11 +2935,13 @@ int reply_echo(connection_struct *conn,
 
                smb_setlen(outbuf,outsize - 4);
 
-               send_smb(Client,outbuf);
+               send_smb(smbd_server_fd(),outbuf);
        }
 
        DEBUG(3,("echo %d times\n", smb_reverb));
 
+       smb_echo_count++;
+
        return -1;
 }
 
@@ -2613,61 +2952,24 @@ int reply_echo(connection_struct *conn,
 int reply_printopen(connection_struct *conn, 
                    char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
-       pstring fname;
-       pstring fname2;
        int outsize = 0;
        files_struct *fsp;
        
-       *fname = *fname2 = 0;
-       
        if (!CAN_PRINT(conn))
                return(ERROR(ERRDOS,ERRnoaccess));
 
-       {
-               pstring s;
-               char *p;
-               pstrcpy(s,smb_buf(inbuf)+1);
-               p = s;
-               while (*p) {
-                       if (!(isalnum((int)*p) || strchr("._-",*p)))
-                               *p = 'X';
-                       p++;
-               }
-
-               if (strlen(s) > 10) s[10] = 0;
-
-               slprintf(fname,sizeof(fname)-1, "%s.XXXXXX",s);  
-       }
-
-       fsp = file_new();
-       if (!fsp)
-               return(ERROR(ERRSRV,ERRnofids));
-       
-       pstrcpy(fname2,(char *)mktemp(fname));
-
-       if (!check_name(fname2,conn)) {
-               file_free(fsp);
-               return(ERROR(ERRDOS,ERRnoaccess));
-       }
-
        /* Open for exclusive use, write only. */
-       open_file_shared(fsp,conn,fname2,
-                        (DENY_ALL<<4)|1, 0x12, unix_mode(conn,0), 
-                        0, NULL, NULL);
+       fsp = print_fsp_open(conn,"dos.prn");
 
-       if (!fsp->open) {
-               file_free(fsp);
+       if (!fsp) {
                return(UNIXERROR(ERRDOS,ERRnoaccess));
        }
 
-       /* force it to be a print file */
-       fsp->print_file = True;
-  
        outsize = set_message(outbuf,1,0,True);
        SSVAL(outbuf,smb_vwv0,fsp->fnum);
   
-       DEBUG(3,("openprint %s fd=%d fnum=%d\n",
-                  fname2, fsp->fd_ptr->fd, fsp->fnum));
+       DEBUG(3,("openprint fd=%d fnum=%d\n",
+                fsp->fd, fsp->fnum));
 
        return(outsize);
 }
@@ -2681,6 +2983,7 @@ int reply_printclose(connection_struct *conn,
 {
        int outsize = set_message(outbuf,0,0,True);
        files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+       int close_err = 0;
 
        CHECK_FSP(fsp,conn);
        CHECK_ERROR(fsp);
@@ -2689,9 +2992,14 @@ int reply_printclose(connection_struct *conn,
                return(ERROR(ERRDOS,ERRnoaccess));
   
        DEBUG(3,("printclose fd=%d fnum=%d\n",
-                fsp->fd_ptr->fd,fsp->fnum));
+                fsp->fd,fsp->fnum));
   
-       close_file(fsp,True);
+       close_err = close_file(fsp,True);
+
+       if(close_err != 0) {
+               errno = close_err;
+               return(UNIXERROR(ERRHRD,ERRgeneral));
+       }
 
        return(outsize);
 }
@@ -2725,7 +3033,7 @@ int reply_printqueue(connection_struct *conn,
        {
                print_queue_struct *queue = NULL;
                char *p = smb_buf(outbuf) + 3;
-               int count = get_printqueue(SNUM(conn), conn,&queue,NULL);
+               int count = print_queue_status(SNUM(conn), &queue,NULL);
                int num_to_get = ABS(max_count);
                int first = (max_count>0?start_index:start_index+max_count+1);
                int i;
@@ -2739,8 +3047,7 @@ int reply_printqueue(connection_struct *conn,
                for (i=first;i<first+num_to_get;i++) {
                        put_dos_date2(p,0,queue[i].time);
                        CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
-                       SSVAL(p,5,printjob_encode(SNUM(conn), 
-                                                 queue[i].job));
+                       SSVAL(p,5, queue[i].job);
                        SIVAL(p,7,queue[i].size);
                        CVAL(p,11) = 0;
                        StrnCpy(p+12,queue[i].user,16);
@@ -2784,7 +3091,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
   numtowrite = SVAL(smb_buf(inbuf),1);
   data = smb_buf(inbuf) + 3;
   
-  if (write_file(fsp,data,numtowrite) != numtowrite)
+  if (write_file(fsp,data,-1,numtowrite) != numtowrite)
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   
   DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
@@ -2806,7 +3113,8 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   unix_convert(directory,conn,0,&bad_path,NULL);
   
   if (check_name(directory, conn))
-    ret = dos_mkdir(directory,unix_mode(conn,aDIR));
+    ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
+                             unix_mode(conn,aDIR,directory));
   
   if (ret < 0)
   {
@@ -2829,7 +3137,8 @@ int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
 Static function used by reply_rmdir to delete an entire directory
 tree recursively.
 ****************************************************************************/
-static BOOL recursive_rmdir(char *directory)
+
+static BOOL recursive_rmdir(connection_struct *conn, char *directory)
 {
   char *dname = NULL;
   BOOL ret = False;
@@ -2857,7 +3166,7 @@ static BOOL recursive_rmdir(char *directory)
     pstrcat(fullname, "/");
     pstrcat(fullname, dname);
 
-    if(dos_lstat(fullname, &st) != 0)
+    if(conn->vfs_ops.lstat(dos_to_unix(fullname,False), &st) != 0)
     {
       ret = True;
       break;
@@ -2865,18 +3174,18 @@ static BOOL recursive_rmdir(char *directory)
 
     if(st.st_mode & S_IFDIR)
     {
-      if(recursive_rmdir(fullname)!=0)
+      if(recursive_rmdir(conn, fullname)!=0)
       {
         ret = True;
         break;
       }
-      if(dos_rmdir(fullname) != 0)
+      if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
       {
         ret = True;
         break;
       }
     }
-    else if(dos_unlink(fullname) != 0)
+    else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
     {
       ret = True;
       break;
@@ -2887,8 +3196,97 @@ static BOOL recursive_rmdir(char *directory)
 }
 
 /****************************************************************************
-  reply to a rmdir
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+BOOL rmdir_internals(connection_struct *conn, char *directory)
+{
+  BOOL ok;
+
+  ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
+  if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
+  {
+    /* 
+     * Check to see if the only thing in this directory are
+     * vetoed files/directories. If so then delete them and
+     * retry. If we fail to delete any of them (and we *don't*
+     * do a recursive delete) then fail the rmdir.
+     */
+    BOOL all_veto_files = True;
+    char *dname;
+    void *dirptr = OpenDir(conn, directory, False);
+
+    if(dirptr != NULL)
+    {
+      int dirpos = TellDir(dirptr);
+      while ((dname = ReadDirName(dirptr)))
+      {
+        if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+          continue;
+        if(!IS_VETO_PATH(conn, dname))
+        {
+          all_veto_files = False;
+          break;
+        }
+      }
+      if(all_veto_files)
+      {
+        SeekDir(dirptr,dirpos);
+        while ((dname = ReadDirName(dirptr)))
+        {
+          pstring fullname;
+          SMB_STRUCT_STAT st;
+
+          if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
+            continue;
+
+          /* Construct the full name. */
+          if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
+          {
+            errno = ENOMEM;
+            break;
+          }
+          pstrcpy(fullname, directory);
+          pstrcat(fullname, "/");
+          pstrcat(fullname, dname);
+                     
+          if(conn->vfs_ops.lstat(dos_to_unix(fullname, False), &st) != 0)
+            break;
+          if(st.st_mode & S_IFDIR)
+          {
+            if(lp_recursive_veto_delete(SNUM(conn)))
+            {
+              if(recursive_rmdir(conn, fullname) != 0)
+                break;
+            }
+            if(conn->vfs_ops.rmdir(dos_to_unix(fullname, False)) != 0)
+              break;
+          }
+          else if(conn->vfs_ops.unlink(dos_to_unix(fullname, False)) != 0)
+            break;
+        }
+        CloseDir(dirptr);
+        /* Retry the rmdir */
+        ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
+      }
+      else
+        CloseDir(dirptr);
+    }
+    else
+      errno = ENOTEMPTY;
+  }
+          
+  if (!ok)
+    DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
+          directory,strerror(errno)));
+
+  return ok;
+}
+
+/****************************************************************************
+ Reply to a rmdir.
 ****************************************************************************/
+
 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
   pstring directory;
@@ -2897,87 +3295,16 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   BOOL bad_path = False;
 
   pstrcpy(directory,smb_buf(inbuf) + 1);
+
+  RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
+
   unix_convert(directory,conn, NULL,&bad_path,NULL);
   
   if (check_name(directory,conn))
-    {
-
-      dptr_closepath(directory,SVAL(inbuf,smb_pid));
-      ok = (dos_rmdir(directory) == 0);
-      if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(conn)))
-        {
-          /* Check to see if the only thing in this directory are
-             vetoed files/directories. If so then delete them and
-             retry. If we fail to delete any of them (and we *don't*
-             do a recursive delete) then fail the rmdir. */
-          BOOL all_veto_files = True;
-          char *dname;
-          void *dirptr = OpenDir(conn, directory, False);
-
-          if(dirptr != NULL)
-            {
-              int dirpos = TellDir(dirptr);
-                 while ((dname = ReadDirName(dirptr)))
-                   {
-                  if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-                    continue;
-                  if(!IS_VETO_PATH(conn, dname))
-                    {
-                      all_veto_files = False;
-                      break;
-                    }
-                }
-              if(all_veto_files)
-                {
-                  SeekDir(dirptr,dirpos);
-                  while ((dname = ReadDirName(dirptr)))
-                    {
-                      pstring fullname;
-                      SMB_STRUCT_STAT st;
-
-                      if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
-                        continue;
-
-                      /* Construct the full name. */
-                      if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
-                        {
-                          errno = ENOMEM;
-                          break;
-                        }
-                      pstrcpy(fullname, directory);
-                      pstrcat(fullname, "/");
-                      pstrcat(fullname, dname);
-                      
-                      if(dos_lstat(fullname, &st) != 0)
-                        break;
-                      if(st.st_mode & S_IFDIR)
-                      {
-                        if(lp_recursive_veto_delete(SNUM(conn)))
-                        {
-                          if(recursive_rmdir(fullname) != 0)
-                            break;
-                        }
-                        if(dos_rmdir(fullname) != 0)
-                          break;
-                      }
-                      else if(dos_unlink(fullname) != 0)
-                        break;
-                    }
-                  CloseDir(dirptr);
-                  /* Retry the rmdir */
-                  ok = (dos_rmdir(directory) == 0);
-                }
-              else
-                CloseDir(dirptr);
-            }
-          else
-            errno = ENOTEMPTY;
-         }
-          
-      if (!ok)
-        DEBUG(3,("couldn't remove directory %s : %s\n",
-                directory,strerror(errno)));
-    }
+  {
+    dptr_closepath(directory,SVAL(inbuf,smb_pid));
+    ok = rmdir_internals(conn, directory);
+  }
   
   if (!ok)
   {
@@ -3070,7 +3397,7 @@ static BOOL can_rename(char *fname,connection_struct *conn)
 
   if (!CAN_WRITE(conn)) return(False);
 
-  if (dos_lstat(fname,&sbuf) != 0) return(False);
+  if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
   if (!check_file_sharing(conn,fname,True)) return(False);
 
   return(True);
@@ -3094,10 +3421,12 @@ int rename_internals(connection_struct *conn,
        int count=0;
        int error = ERRnoaccess;
        BOOL exists=False;
+       BOOL rc = True;
+        pstring zdirectory;
 
        *directory = *mask = 0;
 
-       unix_convert(name,conn,0,&bad_path1,NULL);
+       rc = unix_convert(name,conn,0,&bad_path1,NULL);
        unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
 
        /*
@@ -3120,10 +3449,19 @@ int rename_internals(connection_struct *conn,
                *p = '/'; /* Replace needed for exceptional test below. */
        }
 
-       if (is_mangled(mask))
+       /*
+        * We should only check the mangled cache
+        * here if unix_convert failed. This means
+        * that the path in 'mask' doesn't exist
+        * on the file system and so we need to look
+        * for a possible mangle. This patch from
+        * Tine Smukavec <valentin.smukavec@hermes.si>.
+        */
+
+       if (!rc && is_mangled(mask))
                check_mangled_cache( mask );
 
-       has_wild = strchr(mask,'*') || strchr(mask,'?');
+       has_wild = ms_has_wild(mask);
 
        if (!has_wild) {
                /*
@@ -3182,31 +3520,34 @@ int rename_internals(connection_struct *conn,
                        }
                }
                
+                pstrcpy(zdirectory, dos_to_unix(directory, False));
                if(replace_if_exists) {
                        /*
                         * NT SMB specific flag - rename can overwrite
                         * file with the same name so don't check for
-                        * file_exist().
+                        * vfs_file_exist().
                         */
                        if(resolve_wildcards(directory,newname) &&
                           can_rename(directory,conn) &&
-                          !dos_rename(directory,newname))
+                          !conn->vfs_ops.rename(zdirectory,
+                                                dos_to_unix(newname,False)))
                                count++;
                } else {
                        if (resolve_wildcards(directory,newname) && 
                            can_rename(directory,conn) && 
-                           !file_exist(newname,NULL) &&
-                           !dos_rename(directory,newname))
+                           !vfs_file_exist(conn,newname,NULL) &&
+                           !conn->vfs_ops.rename(zdirectory,
+                                                 dos_to_unix(newname,False)))
                                count++;
                }
 
                DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
                          directory,newname));
                
-               if (!count) exists = file_exist(directory,NULL);
-               if (!count && exists && file_exist(newname,NULL)) {
+               if (!count) exists = vfs_file_exist(conn,directory,NULL);
+               if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
                        exists = True;
-                       error = 183;
+                       error = ERRrename;
                }
        } else {
                /*
@@ -3227,9 +3568,10 @@ int rename_internals(connection_struct *conn,
                        
                        while ((dname = ReadDirName(dirptr))) {
                                pstring fname;
+
                                pstrcpy(fname,dname);
                                
-                               if(!mask_match(fname, mask, case_sensitive, False))
+                               if(!mask_match(fname, mask, case_sensitive))
                                        continue;
                                
                                error = ERRnoaccess;
@@ -3241,17 +3583,20 @@ int rename_internals(connection_struct *conn,
                                pstrcpy(destname,newname);
                                
                                if (!resolve_wildcards(fname,destname)) {
-                                       DEBUG(6,("resolve_wildcards %s %s failed\n", fname, destname));
+                                       DEBUG(6,("resolve_wildcards %s %s failed\n", 
+                                                 fname, destname));
                                        continue;
                                }
                                
-                               if (!replace_if_exists && file_exist(destname,NULL)) {
+                               if (!replace_if_exists && 
+                                    vfs_file_exist(conn,destname, NULL)) {
                                        DEBUG(6,("file_exist %s\n", destname));
                                        error = 183;
                                        continue;
                                }
                                
-                               if (!dos_rename(fname,destname))
+                               if (!conn->vfs_ops.rename(dos_to_unix(fname,False),
+                                                          dos_to_unix(destname,False)))
                                        count++;
                                DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
                        }
@@ -3286,7 +3631,10 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, in
 
   pstrcpy(name,smb_buf(inbuf) + 1);
   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
-   
+
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+  RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
 
   outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
@@ -3299,15 +3647,18 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, in
 /*******************************************************************
   copy a file as part of a reply_copy
   ******************************************************************/
+
 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
-                     int count,BOOL target_is_directory)
+                     int count,BOOL target_is_directory, int *err_ret)
 {
   int Access,action;
   SMB_STRUCT_STAT st;
-  int ret=0;
+  SMB_OFF_T ret=-1;
   files_struct *fsp1,*fsp2;
   pstring dest;
   
+  *err_ret = 0;
+
   pstrcpy(dest,dest1);
   if (target_is_directory) {
     char *p = strrchr(src,'/');
@@ -3319,47 +3670,52 @@ static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
     pstrcat(dest,p);
   }
 
-  if (!file_exist(src,&st)) return(False);
+  if (!vfs_file_exist(conn,src,&st))
+    return(False);
 
-  fsp1 = file_new();
-  if (!fsp1) return(False);
-  open_file_shared(fsp1,conn,src,(DENY_NONE<<4),
-                  1,0,0,&Access,&action);
+  fsp1 = open_file_shared(conn,src,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
+                  (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
 
-  if (!fsp1->open) {
-         file_free(fsp1);
+  if (!fsp1) {
          return(False);
   }
 
   if (!target_is_directory && count)
     ofun = 1;
 
-  fsp2 = file_new();
-  if (!fsp2) {
-         close_file(fsp1,False);
-         return(False);
-  }
-  open_file_shared(fsp2,conn,dest,(DENY_NONE<<4)|1,
+  fsp2 = open_file_shared(conn,dest,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
                   ofun,st.st_mode,0,&Access,&action);
 
-  if (!fsp2->open) {
+  if (!fsp2) {
     close_file(fsp1,False);
-    file_free(fsp2);
     return(False);
   }
 
   if ((ofun&3) == 1) {
-    sys_lseek(fsp2->fd_ptr->fd,0,SEEK_END);
+    if(conn->vfs_ops.lseek(fsp2->fd,0,SEEK_END) == -1) {
+      DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
+               strerror(errno) ));
+      /*
+       * Stop the copy from occurring.
+       */
+      ret = -1;
+      st.st_size = 0;
+    }
   }
   
   if (st.st_size)
-    ret = transfer_file(fsp1->fd_ptr->fd,
-                        fsp2->fd_ptr->fd,st.st_size,NULL,0,0);
+    ret = vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size, NULL, 0, 0);
 
   close_file(fsp1,False);
-  close_file(fsp2,False);
+  /*
+   * As we are opening fsp1 read-only we only expect
+   * an error on close on fsp2 if we are out of space.
+   * Thus we don't look at the error return from the
+   * close of fsp1.
+   */
+  *err_ret = close_file(fsp2,False);
 
-  return(ret == st.st_size);
+  return(ret == (SMB_OFF_T)st.st_size);
 }
 
 
@@ -3376,6 +3732,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   char *p;
   int count=0;
   int error = ERRnoaccess;
+  int err = 0;
   BOOL has_wild;
   BOOL exists=False;
   int tid2 = SVAL(inbuf,smb_vwv0);
@@ -3384,6 +3741,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
   BOOL target_is_directory=False;
   BOOL bad_path1 = False;
   BOOL bad_path2 = False;
+  BOOL rc = True;
 
   *directory = *mask = 0;
 
@@ -3398,10 +3756,13 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     return(ERROR(ERRSRV,ERRinvdevice));
   }
 
-  unix_convert(name,conn,0,&bad_path1,NULL);
+  RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
+  RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+  rc = unix_convert(name,conn,0,&bad_path1,NULL);
   unix_convert(newname,conn,0,&bad_path2,NULL);
 
-  target_is_directory = directory_exist(newname,NULL);
+  target_is_directory = vfs_directory_exist(conn,False,NULL);
 
   if ((flags&1) && target_is_directory) {
     return(ERROR(ERRDOS,ERRbadfile));
@@ -3411,7 +3772,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     return(ERROR(ERRDOS,ERRbadpath));
   }
 
-  if ((flags&(1<<5)) && directory_exist(name,NULL)) {
+  if ((flags&(1<<5)) && vfs_directory_exist(conn,name,NULL)) {
     /* wants a tree copy! XXXX */
     DEBUG(3,("Rejecting tree copy\n"));
     return(ERROR(ERRSRV,ERRerror));    
@@ -3427,18 +3788,31 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     pstrcpy(mask,p+1);
   }
 
-  if (is_mangled(mask))
+  /*
+   * We should only check the mangled cache
+   * here if unix_convert failed. This means
+   * that the path in 'mask' doesn't exist
+   * on the file system and so we need to look
+   * for a possible mangle. This patch from
+   * Tine Smukavec <valentin.smukavec@hermes.si>.
+   */
+
+  if (!rc && is_mangled(mask))
     check_mangled_cache( mask );
 
-  has_wild = strchr(mask,'*') || strchr(mask,'?');
+  has_wild = ms_has_wild(mask);
 
   if (!has_wild) {
     pstrcat(directory,"/");
     pstrcat(directory,mask);
     if (resolve_wildcards(directory,newname) && 
        copy_file(directory,newname,conn,ofun,
-                 count,target_is_directory)) count++;
-    if (!count) exists = file_exist(directory,NULL);
+                 count,target_is_directory,&err)) count++;
+    if(!count && err) {
+               errno = err;
+               return(UNIXERROR(ERRHRD,ERRgeneral));
+       }
+    if (!count) exists = vfs_file_exist(conn,directory,NULL);
   } else {
     void *dirptr = NULL;
     char *dname;
@@ -3447,33 +3821,38 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
     if (check_name(directory,conn))
       dirptr = OpenDir(conn, directory, True);
 
-    if (dirptr)
-      {
+    if (dirptr) {
        error = ERRbadfile;
 
        if (strequal(mask,"????????.???"))
          pstrcpy(mask,"*");
 
-       while ((dname = ReadDirName(dirptr)))
-         {
+       while ((dname = ReadDirName(dirptr))) {
            pstring fname;
            pstrcpy(fname,dname);
            
-           if(!mask_match(fname, mask, case_sensitive, False)) continue;
+           if(!mask_match(fname, mask, case_sensitive))
+                       continue;
 
            error = ERRnoaccess;
            slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
            pstrcpy(destname,newname);
            if (resolve_wildcards(fname,destname) && 
-               copy_file(directory,newname,conn,ofun,
-                         count,target_is_directory)) count++;
+               copy_file(fname,destname,conn,ofun,
+                         count,target_is_directory,&err)) count++;
            DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
          }
        CloseDir(dirptr);
-      }
+    }
   }
   
   if (count == 0) {
+    if(err) {
+      /* Error on close... */
+      errno = err;
+      return(UNIXERROR(ERRHRD,ERRgeneral));
+    }
+
     if (exists)
       return(ERROR(ERRDOS,error));
     else
@@ -3513,7 +3892,7 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   if (strlen(newdir) == 0) {
          ok = True;
   } else {
-         ok = directory_exist(newdir,NULL);
+         ok = vfs_directory_exist(conn,newdir,NULL);
          if (ok) {
                  string_set(&conn->connectpath,newdir);
          }
@@ -3530,9 +3909,97 @@ int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
   return(outsize);
 }
 
+/****************************************************************************
+ Get a lock count, dealing with large count requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
+{
+  SMB_BIG_UINT count = 0;
+
+  if(!large_file_format) {
+    count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
+  } else {
+
+#if defined(HAVE_LONGLONG)
+    count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
+            ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+    /*
+     * NT4.x seems to be broken in that it sends large file (64 bit)
+     * lockingX calls even if the CAP_LARGE_FILES was *not*
+     * negotiated. For boxes without large unsigned ints truncate the
+     * lock count by dropping the top 32 bits.
+     */
+
+    if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
+      DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
+            (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
+            (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
+      SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
+    }
+
+    count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+  }
+
+  return count;
+}
+
+/****************************************************************************
+ Get a lock offset, dealing with large offset requests.
+****************************************************************************/
+
+SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
+{
+  SMB_BIG_UINT offset = 0;
+
+  *err = False;
+
+  if(!large_file_format) {
+    offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
+  } else {
+
+#if defined(HAVE_LONGLONG)
+    offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
+            ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
+#else /* HAVE_LONGLONG */
+
+    /*
+     * NT4.x seems to be broken in that it sends large file (64 bit)
+     * lockingX calls even if the CAP_LARGE_FILES was *not*
+     * negotiated. For boxes without large unsigned ints mangle the
+     * lock offset by mapping the top 32 bits onto the lower 32.
+     */
+      
+    if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
+      uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+      uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
+      uint32 new_low = 0;
+
+      if((new_low = map_lock_offset(high, low)) == 0) {
+        *err = True;
+        return (SMB_BIG_UINT)-1;
+      }
+
+      DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
+            (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
+      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
+      SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
+    }
+
+    offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
+#endif /* HAVE_LONGLONG */
+  }
+
+  return offset;
+}
+
 /****************************************************************************
   reply to a lockingX request
 ****************************************************************************/
+
 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
@@ -3542,13 +4009,15 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
 #endif
   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
   uint16 num_locks = SVAL(inbuf,smb_vwv7);
-  SMB_OFF_T count, offset;
+  SMB_BIG_UINT count = 0, offset = 0;
   int32 lock_timeout = IVAL(inbuf,smb_vwv4);
   int i;
   char *data;
   uint32 ecode=0, dummy2;
   int eclass=0, dummy1;
   BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
+  BOOL err;
+
   CHECK_FSP(fsp,conn);
   CHECK_ERROR(fsp);
 
@@ -3559,35 +4028,28 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
    */
   if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
   {
-    int token;
-    SMB_DEV_T dev = fsp->fd_ptr->dev;
-    SMB_INO_T inode = fsp->fd_ptr->inode;
-
     DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
               fsp->fnum));
+
     /*
-     * Make sure we have granted an oplock on this file.
+     * Make sure we have granted an exclusive or batch oplock on this file.
      */
-    if(!fsp->granted_oplock)
+
+    if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
     {
       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
-no oplock granted on this file.\n", fsp->fnum));
-      return ERROR(ERRDOS,ERRlock);
-    }
-
-    /* Remove the oplock flag from the sharemode. */
-    lock_share_entry(fsp->conn, dev, inode, &token);
-    if(remove_share_oplock(fsp, token)==False) {
+no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
 
-           DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
-dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
-
-           unlock_share_entry(fsp->conn, dev, inode, token);
-    } else {
-           unlock_share_entry(fsp->conn, dev, inode, token);
+      /* if this is a pure oplock break request then don't send a reply */
+      if (num_locks == 0 && num_ulocks == 0)
+        return -1;
+      else
+        return ERROR(ERRDOS,ERRlock);
+    }
 
-           /* Clear the granted flag and return. */
-           fsp->granted_oplock = False;
+    if (remove_oplock(fsp) == False) {
+      DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
+            fsp->fsp_name ));
     }
 
     /* if this is a pure oplock break request then don't send a reply */
@@ -3605,23 +4067,19 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
   /* Data now points at the beginning of the list
      of smb_unlkrng structs */
   for(i = 0; i < (int)num_ulocks; i++) {
-    if(!large_file_format) {
-      count = IVAL(data,SMB_LKLEN_OFFSET(i));
-      offset = IVAL(data,SMB_LKOFF_OFFSET(i));
-    }
-#ifdef LARGE_SMB_OFF_T
-    else {
-      count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
-              ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
-      offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
-               ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
-    }
-#endif /* LARGE_SMB_OFF_T */
+    count = get_lock_count( data, i, large_file_format);
+    offset = get_lock_offset( data, i, large_file_format, &err);
+
+    /*
+     * There is no error code marked "stupid client bug".... :-).
+     */
+    if(err)
+      return ERROR(ERRDOS,ERRnoaccess);
 
     DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
           (double)offset, (double)count, fsp->fsp_name ));
 
-    if(!do_unlock(fsp,conn,count,offset,&eclass, &ecode))
+    if(!do_unlock(fsp,conn,count,offset, &eclass, &ecode))
       return ERROR(eclass,ecode);
   }
 
@@ -3635,23 +4093,19 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
      of smb_lkrng structs */
 
   for(i = 0; i < (int)num_locks; i++) {
-    if(!large_file_format) {
-      count = IVAL(data,SMB_LKLEN_OFFSET(i)); 
-      offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
-    }
-#ifdef LARGE_SMB_OFF_T
-    else {
-      count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
-              ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
-      offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
-               ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
-    }
-#endif /* LARGE_SMB_OFF_T */
+    count = get_lock_count( data, i, large_file_format);
+    offset = get_lock_offset( data, i, large_file_format, &err);
+
+    /*
+     * There is no error code marked "stupid client bug".... :-).
+     */
+    if(err)
+      return ERROR(ERRDOS,ERRnoaccess);
  
     DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
           (double)offset, (double)count, fsp->fsp_name ));
 
-    if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? F_RDLCK : F_WRLCK),
+    if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
                 &eclass, &ecode)) {
       if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
         /*
@@ -3669,20 +4123,21 @@ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
   /* If any of the above locks failed, then we must unlock
      all of the previous locks (X/Open spec). */
   if(i != num_locks && num_locks != 0) {
-    for(; i >= 0; i--) {
-      if(!large_file_format) {
-        count = IVAL(data,SMB_LKLEN_OFFSET(i));  
-        offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
-      }
-#ifdef LARGE_SMB_OFF_T
-      else {
-        count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(i))) << 32) |
-                ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(i)));
-        offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(i))) << 32) |
-                 ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(i)));
-      }
-#endif /* LARGE_SMB_OFF_T */
+    /*
+     * Ensure we don't do a remove on the lock that just failed,
+     * as under POSIX rules, if we have a lock already there, we
+     * will delete it (and we shouldn't) .....
+     */
+    for(i--; i >= 0; i--) {
+      count = get_lock_count( data, i, large_file_format);
+      offset = get_lock_offset( data, i, large_file_format, &err);
 
+      /*
+       * There is no error code marked "stupid client bug".... :-).
+       */
+      if(err)
+        return ERROR(ERRDOS,ERRnoaccess);
       do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
     }
     return ERROR(eclass,ecode);
@@ -3735,7 +4190,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
   tcount = maxcount;
   total_read = 0;
 
-  if (is_locked(fsp,conn,maxcount,startpos, F_RDLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK))
     return(ERROR(ERRDOS,ERRlock));
        
   do
@@ -3755,7 +4210,7 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
       SSVAL(outbuf,smb_vwv6,nread);
       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
 
-      send_smb(Client,outbuf);
+      send_smb(smbd_server_fd(),outbuf);
 
       total_read += nread;
       startpos += nread;
@@ -3768,7 +4223,8 @@ int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,
 /****************************************************************************
   reply to a SMBwritebmpx (write block multiplex primary) request
 ****************************************************************************/
-int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   size_t numtowrite;
   ssize_t nwritten = -1;
@@ -3796,14 +4252,13 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
      not an SMBwritebmpx - set this up now so we don't forget */
   CVAL(outbuf,smb_com) = SMBwritec;
 
-  if (is_locked(fsp,conn,tcount,startpos,F_WRLCK))
+  if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK))
     return(ERROR(ERRDOS,ERRlock));
 
-  seek_file(fsp,startpos);
-  nwritten = write_file(fsp,data,numtowrite);
+  nwritten = write_file(fsp,data,startpos,numtowrite);
 
   if(lp_syncalways(SNUM(conn)) || write_through)
-    sync_file(conn,fsp);
+      sync_file(conn,fsp);
   
   if(nwritten < (ssize_t)numtowrite)
     return(UNIXERROR(ERRHRD,ERRdiskfull));
@@ -3841,12 +4296,12 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int dum_s
   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
   
   DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
-           fsp->fnum, numtowrite, nwritten ) );
+           fsp->fnum, (int)numtowrite, (int)nwritten ) );
 
   if (write_through && tcount==nwritten) {
     /* we need to send both a primary and a secondary response */
     smb_setlen(outbuf,outsize - 4);
-    send_smb(Client,outbuf);
+    send_smb(smbd_server_fd(),outbuf);
 
     /* now the secondary */
     outsize = set_message(outbuf,1,0,True);
@@ -3901,8 +4356,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
   if(wbms->wr_discard)
     return -1; /* Just discard the packet */
 
-  seek_file(fsp,startpos);
-  nwritten = write_file(fsp,data,numtowrite);
+  nwritten = write_file(fsp,data,startpos,numtowrite);
 
   if(lp_syncalways(SNUM(conn)) || write_through)
     sync_file(conn,fsp);
@@ -3945,7 +4399,8 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
 /****************************************************************************
   reply to a SMBsetattrE
 ****************************************************************************/
-int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   struct utimbuf unix_times;
   int outsize = 0;
@@ -3997,7 +4452,8 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
 /****************************************************************************
   reply to a SMBgetattrE
 ****************************************************************************/
-int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
+
+int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
 {
   SMB_STRUCT_STAT sbuf;
   int outsize = 0;
@@ -4010,7 +4466,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
   CHECK_ERROR(fsp);
 
   /* Do an fstat on this file */
-  if(sys_fstat(fsp->fd_ptr->fd, &sbuf))
+  if(fsp->conn->vfs_ops.fstat(fsp->fd, &sbuf))
     return(UNIXERROR(ERRDOS,ERRnoaccess));
   
   mode = dos_mode(conn,fsp->fsp_name,&sbuf);
@@ -4029,7 +4485,7 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
   else
     {
       SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
-      SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
+      SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
     }
   SSVAL(outbuf,smb_vwv10, mode);
   
@@ -4037,3 +4493,4 @@ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int dum_si
   
   return(outsize);
 }
+#undef OLD_NTDOMAIN