an initial fix for handling sparse files in smbd
[import/samba-cvsimport.git] / source / smbd / nttrans.c
index 923de7a197b375fbe603f9531e14a2d94ed47ee7..cf69dfddb049fa6044c56634d47a19ddaeb278dc 100644 (file)
@@ -1,6 +1,5 @@
 /*
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    SMB NT transaction handling
    Copyright (C) Jeremy Allison 1994-1998
 
 */
 
 #include "includes.h"
-#include "nterr.h"
 
-extern int DEBUGLEVEL;
 extern int Protocol;
-extern int Client;  
 extern int smb_read_error;
 extern int global_oplock_break;
-extern int chain_size;
 extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
 
-static void remove_pending_change_notify_requests_by_mid(int mid);
-
 static char *known_nt_pipes[] = {
-  "\\LANMAN",
-  "\\srvsvc",
-  "\\svcctl",
-  "\\samr",
-  "\\wkssvc",
-  "\\NETLOGON",
-  "\\ntlsa",
-  "\\ntsvcs",
-  "\\lsass",
-  "\\lsarpc",
-  "\\winreg",
-  NULL
+       "\\LANMAN",
+       "\\srvsvc",
+       "\\samr",
+       "\\wkssvc",
+       "\\NETLOGON",
+       "\\ntlsa",
+       "\\ntsvcs",
+       "\\lsass",
+       "\\lsarpc",
+       "\\winreg",
+       "\\spoolss",
+       "\\netdfs",
+       NULL
+};
+
+/* Map generic permissions to file object specific permissions */
+struct generic_mapping file_generic_mapping = {
+       FILE_GENERIC_READ,
+       FILE_GENERIC_WRITE,
+       FILE_GENERIC_EXECUTE,
+       FILE_GENERIC_ALL
 };
 
 /****************************************************************************
@@ -56,214 +59,186 @@ static char *known_nt_pipes[] = {
  HACK ! Always assumes smb_setup field is zero.
 ****************************************************************************/
 
-static int send_nt_replies(char *outbuf, int bufsize, char *params,
+static int send_nt_replies(char *inbuf, char *outbuf, int bufsize, NTSTATUS nt_error, char *params,
                            int paramsize, char *pdata, int datasize)
 {
-  extern int max_send;
-  int data_to_send = datasize;
-  int params_to_send = paramsize;
-  int useable_space;
-  char *pp = params;
-  char *pd = pdata;
-  int params_sent_thistime, data_sent_thistime, total_sent_thistime;
-  int alignment_offset = 3;
-  int data_alignment_offset = 0;
-
-  /*
-   * Initially set the wcnt area to be 18 - this is true for all
-   * transNT replies.
-   */
-
-  set_message(outbuf,18,0,True);
-
-  /* 
-   * If there genuinely are no parameters or data to send just send
-   * the empty packet.
-   */
-
-  if(params_to_send == 0 && data_to_send == 0) {
-    send_smb(Client,outbuf);
-    return 0;
-  }
-
-  /*
-   * When sending params and data ensure that both are nicely aligned.
-   * Only do this alignment when there is also data to send - else
-   * can cause NT redirector problems.
-   */
-
-  if (((params_to_send % 4) != 0) && (data_to_send != 0))
-    data_alignment_offset = 4 - (params_to_send % 4);
-
-  /* 
-   * Space is bufsize minus Netbios over TCP header minus SMB header.
-   * The alignment_offset is to align the param bytes on a four byte
-   * boundary (2 bytes for data len, one byte pad). 
-   * NT needs this to work correctly.
-   */
-
-  useable_space = bufsize - ((smb_buf(outbuf)+
-                    alignment_offset+data_alignment_offset) -
-                    outbuf);
-
-  /*
-   * useable_space can never be more than max_send minus the
-   * alignment offset.
-   */
-
-  useable_space = MIN(useable_space,
-                      max_send - (alignment_offset+data_alignment_offset));
-
-
-  while (params_to_send || data_to_send) {
-
-    /*
-     * Calculate whether we will totally or partially fill this packet.
-     */
-
-    total_sent_thistime = params_to_send + data_to_send +
-                            alignment_offset + data_alignment_offset;
-
-    /* 
-     * We can never send more than useable_space.
-     */
-
-    total_sent_thistime = MIN(total_sent_thistime, useable_space);
-
-    set_message(outbuf, 18, total_sent_thistime, True);
-
-    /*
-     * Set total params and data to be sent.
-     */
-
-    SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize);
-    SIVAL(outbuf,smb_ntr_TotalDataCount,datasize);
-
-    /* 
-     * Calculate how many parameters and data we can fit into
-     * this packet. Parameters get precedence.
-     */
-
-    params_sent_thistime = MIN(params_to_send,useable_space);
-    data_sent_thistime = useable_space - params_sent_thistime;
-    data_sent_thistime = MIN(data_sent_thistime,data_to_send);
-
-    SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime);
-
-    if(params_sent_thistime == 0) {
-      SIVAL(outbuf,smb_ntr_ParameterOffset,0);
-      SIVAL(outbuf,smb_ntr_ParameterDisplacement,0);
-    } else {
-      /*
-       * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the
-       * parameter bytes, however the first 4 bytes of outbuf are
-       * the Netbios over TCP header. Thus use smb_base() to subtract
-       * them from the calculation.
-       */
-
-      SIVAL(outbuf,smb_ntr_ParameterOffset,
-            ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
-      /* 
-       * Absolute displacement of param bytes sent in this packet.
-       */
-
-      SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params);
-    }
-
-    /*
-     * Deal with the data portion.
-     */
+       extern int max_send;
+       int data_to_send = datasize;
+       int params_to_send = paramsize;
+       int useable_space;
+       char *pp = params;
+       char *pd = pdata;
+       int params_sent_thistime, data_sent_thistime, total_sent_thistime;
+       int alignment_offset = 3;
+       int data_alignment_offset = 0;
 
-    SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime);
-
-    if(data_sent_thistime == 0) {
-      SIVAL(outbuf,smb_ntr_DataOffset,0);
-      SIVAL(outbuf,smb_ntr_DataDisplacement, 0);
-    } else {
-      /*
-       * The offset of the data bytes is the offset of the
-       * parameter bytes plus the number of parameters being sent this time.
-       */
-
-      SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) -
-            smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
-      SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata);
-    }
+       /*
+        * Initially set the wcnt area to be 18 - this is true for all
+        * transNT replies.
+        */
 
-    /* 
-     * Copy the param bytes into the packet.
-     */
+       set_message(outbuf,18,0,True);
 
-    if(params_sent_thistime)
-      memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
-
-    /*
-     * Copy in the data bytes
-     */
+       if (NT_STATUS_V(nt_error))
+               ERROR_NT(nt_error);
 
-    if(data_sent_thistime)
-      memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
-             data_alignment_offset,pd,data_sent_thistime);
-    
-    DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
-          params_sent_thistime, data_sent_thistime, useable_space));
-    DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
-          params_to_send, data_to_send, paramsize, datasize));
-    
-    /* Send the packet */
-    send_smb(Client,outbuf);
-    
-    pp += params_sent_thistime;
-    pd += data_sent_thistime;
-    
-    params_to_send -= params_sent_thistime;
-    data_to_send -= data_sent_thistime;
+       /* 
+        * If there genuinely are no parameters or data to send just send
+        * the empty packet.
+        */
 
-    /*
-     * Sanity check
-     */
+       if(params_to_send == 0 && data_to_send == 0) {
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("send_nt_replies: send_smb failed.");
+               return 0;
+       }
 
-    if(params_to_send < 0 || data_to_send < 0) {
-      DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!",
-            params_to_send, data_to_send));
-      return -1;
-    }
-  } 
+       /*
+        * When sending params and data ensure that both are nicely aligned.
+        * Only do this alignment when there is also data to send - else
+        * can cause NT redirector problems.
+        */
 
-  return 0;
-}
+       if (((params_to_send % 4) != 0) && (data_to_send != 0))
+               data_alignment_offset = 4 - (params_to_send % 4);
 
-/****************************************************************************
- (Hopefully) temporary call to fix bugs in NT5.0beta2. This OS sends unicode
- strings in NT calls AND DOESN'T SET THE UNICODE BIT !!!!!!!
-****************************************************************************/
+       /* 
+        * Space is bufsize minus Netbios over TCP header minus SMB header.
+        * The alignment_offset is to align the param bytes on a four byte
+        * boundary (2 bytes for data len, one byte pad). 
+        * NT needs this to work correctly.
+        */
 
-static void my_wcstombs(char *dst, uint16 *src, size_t len)
-{
-  size_t i;
+       useable_space = bufsize - ((smb_buf(outbuf)+
+                               alignment_offset+data_alignment_offset) -
+                               outbuf);
 
-  for(i = 0; i < len; i++)
-    dst[i] = (char)SVAL(src,i*2);
-}
+       /*
+        * useable_space can never be more than max_send minus the
+        * alignment offset.
+        */
 
-static void get_filename( char *fname, char *inbuf, int data_offset, int data_len, int fname_len)
-{
-  if(data_len - fname_len > 1) {
-    /*
-     * NT 5.0 Beta 2 has kindly sent us a UNICODE string
-     * without bothering to set the unicode bit. How kind.
-     *
-     * Firstly - ensure that the data offset is aligned
-     * on a 2 byte boundary - add one if not.
-     */
-    fname_len = fname_len/2;
-    if(data_offset & 1)
-      data_offset++;
-    my_wcstombs( fname, (uint16 *)(inbuf+data_offset), fname_len);
-  } else {
-    StrnCpy(fname,inbuf+data_offset,fname_len);
-  }
-  fname[fname_len] = '\0';
+       useable_space = MIN(useable_space,
+                               max_send - (alignment_offset+data_alignment_offset));
+
+
+       while (params_to_send || data_to_send) {
+
+               /*
+                * Calculate whether we will totally or partially fill this packet.
+                */
+
+               total_sent_thistime = params_to_send + data_to_send +
+                                       alignment_offset + data_alignment_offset;
+
+               /* 
+                * We can never send more than useable_space.
+                */
+
+               total_sent_thistime = MIN(total_sent_thistime, useable_space);
+
+               set_message(outbuf, 18, total_sent_thistime, True);
+
+               /*
+                * Set total params and data to be sent.
+                */
+
+               SIVAL(outbuf,smb_ntr_TotalParameterCount,paramsize);
+               SIVAL(outbuf,smb_ntr_TotalDataCount,datasize);
+
+               /* 
+                * Calculate how many parameters and data we can fit into
+                * this packet. Parameters get precedence.
+                */
+
+               params_sent_thistime = MIN(params_to_send,useable_space);
+               data_sent_thistime = useable_space - params_sent_thistime;
+               data_sent_thistime = MIN(data_sent_thistime,data_to_send);
+
+               SIVAL(outbuf,smb_ntr_ParameterCount,params_sent_thistime);
+
+               if(params_sent_thistime == 0) {
+                       SIVAL(outbuf,smb_ntr_ParameterOffset,0);
+                       SIVAL(outbuf,smb_ntr_ParameterDisplacement,0);
+               } else {
+                       /*
+                        * smb_ntr_ParameterOffset is the offset from the start of the SMB header to the
+                        * parameter bytes, however the first 4 bytes of outbuf are
+                        * the Netbios over TCP header. Thus use smb_base() to subtract
+                        * them from the calculation.
+                        */
+
+                       SIVAL(outbuf,smb_ntr_ParameterOffset,
+                               ((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
+                       /* 
+                        * Absolute displacement of param bytes sent in this packet.
+                        */
+
+                       SIVAL(outbuf,smb_ntr_ParameterDisplacement,pp - params);
+               }
+
+               /*
+                * Deal with the data portion.
+                */
+
+               SIVAL(outbuf,smb_ntr_DataCount, data_sent_thistime);
+
+               if(data_sent_thistime == 0) {
+                       SIVAL(outbuf,smb_ntr_DataOffset,0);
+                       SIVAL(outbuf,smb_ntr_DataDisplacement, 0);
+               } else {
+                       /*
+                        * The offset of the data bytes is the offset of the
+                        * parameter bytes plus the number of parameters being sent this time.
+                        */
+
+                       SIVAL(outbuf,smb_ntr_DataOffset,((smb_buf(outbuf)+alignment_offset) -
+                               smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
+                               SIVAL(outbuf,smb_ntr_DataDisplacement, pd - pdata);
+               }
+
+               /* 
+                * Copy the param bytes into the packet.
+                */
+
+               if(params_sent_thistime)
+                       memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
+
+               /*
+                * Copy in the data bytes
+                */
+
+               if(data_sent_thistime)
+                       memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
+                               data_alignment_offset,pd,data_sent_thistime);
+    
+               DEBUG(9,("nt_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
+                       params_sent_thistime, data_sent_thistime, useable_space));
+               DEBUG(9,("nt_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
+                       params_to_send, data_to_send, paramsize, datasize));
+    
+               /* Send the packet */
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("send_nt_replies: send_smb failed.");
+    
+               pp += params_sent_thistime;
+               pd += data_sent_thistime;
+    
+               params_to_send -= params_sent_thistime;
+               data_to_send -= data_sent_thistime;
+
+               /*
+                * Sanity check
+                */
+
+               if(params_to_send < 0 || data_to_send < 0) {
+                       DEBUG(0,("send_nt_replies failed sanity check pts = %d, dts = %d\n!!!",
+                               params_to_send, data_to_send));
+                       return -1;
+               }
+       } 
+
+       return 0;
 }
 
 /****************************************************************************
@@ -280,17 +255,17 @@ static BOOL saved_short_case_preserve;
 
 static void set_posix_case_semantics(uint32 file_attributes)
 {
-  if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
-    return;
+       if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+               return;
 
-  saved_case_sensitive = case_sensitive;
-  saved_case_preserve = case_preserve;
-  saved_short_case_preserve = short_case_preserve;
+       saved_case_sensitive = case_sensitive;
+       saved_case_preserve = case_preserve;
+       saved_short_case_preserve = short_case_preserve;
 
-  /* Set to POSIX. */
-  case_sensitive = True;
-  case_preserve = True;
-  short_case_preserve = True;
+       /* Set to POSIX. */
+       case_sensitive = True;
+       case_preserve = True;
+       short_case_preserve = True;
 }
 
 /****************************************************************************
@@ -299,12 +274,12 @@ static void set_posix_case_semantics(uint32 file_attributes)
 
 static void restore_case_semantics(uint32 file_attributes)
 {
-  if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
-    return;
+       if(!(file_attributes & FILE_FLAG_POSIX_SEMANTICS))
+               return;
 
-  case_sensitive = saved_case_sensitive;
-  case_preserve = saved_case_preserve;
-  short_case_preserve = saved_short_case_preserve;
+       case_sensitive = saved_case_sensitive;
+       case_preserve = saved_case_preserve;
+       short_case_preserve = saved_short_case_preserve;
 }
 
 /****************************************************************************
@@ -313,167 +288,176 @@ static void restore_case_semantics(uint32 file_attributes)
 
 static int map_create_disposition( uint32 create_disposition)
 {
-  int ret;
-
-  switch( create_disposition ) {
-  case FILE_CREATE:
-    /* create if not exist, fail if exist */
-    ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL);
-    break;
-  case FILE_SUPERSEDE:
-  case FILE_OVERWRITE_IF:
-    /* create if not exist, trunc if exist */
-    ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
-    break;
-  case FILE_OPEN:
-    /* fail if not exist, open if exists */
-    ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN);
-    break;
-  case FILE_OPEN_IF:
-    /* create if not exist, open if exists */
-    ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN);
-    break;
-  case FILE_OVERWRITE:
-    /* fail if not exist, truncate if exists */
-    ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
-    break;
-  default:
-    DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
-             create_disposition ));
-    return -1;
-  }
-
-  DEBUG(10,("map_create_disposition: Mapped create_disposition %lx to %x\n",
-        (unsigned long)create_disposition, ret ));
-
-  return ret;
+       int ret;
+
+       switch( create_disposition ) {
+               case FILE_CREATE:
+                       /* create if not exist, fail if exist */
+                       ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL);
+                       break;
+               case FILE_SUPERSEDE:
+               case FILE_OVERWRITE_IF:
+                       /* create if not exist, trunc if exist */
+                       ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+                       break;
+               case FILE_OPEN:
+                       /* fail if not exist, open if exists */
+                       ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+                       break;
+               case FILE_OPEN_IF:
+                       /* create if not exist, open if exists */
+                       ret = (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_OPEN);
+                       break;
+               case FILE_OVERWRITE:
+                       /* fail if not exist, truncate if exists */
+                       ret = (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE);
+                       break;
+               default:
+                       DEBUG(0,("map_create_disposition: Incorrect value for create_disposition = %d\n",
+                               create_disposition ));
+                       return -1;
+       }
+
+       DEBUG(10,("map_create_disposition: Mapped create_disposition 0x%lx to 0x%x\n",
+                       (unsigned long)create_disposition, ret ));
+
+       return ret;
 }
 
 /****************************************************************************
  Utility function to map share modes.
 ****************************************************************************/
 
-static int map_share_mode( char *fname, uint32 desired_access, uint32 share_access, uint32 file_attributes)
+static int map_share_mode( char *fname, uint32 create_options,
+                       uint32 *desired_access, uint32 share_access, uint32 file_attributes)
 {
-  int smb_open_mode = -1;
-
-  switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA) ) {
-  case FILE_READ_DATA:
-    smb_open_mode = DOS_OPEN_RDONLY;
-    break;
-  case FILE_WRITE_DATA:
-    smb_open_mode = DOS_OPEN_WRONLY;
-    break;
-  case FILE_READ_DATA|FILE_WRITE_DATA:
-    smb_open_mode = DOS_OPEN_RDWR;
-    break;
-  }
-
-  /*
-   * NB. For DELETE_ACCESS we should really check the
-   * directory permissions, as that is what controls
-   * delete, and for WRITE_DAC_ACCESS we should really
-   * check the ownership, as that is what controls the
-   * chmod. Note that this is *NOT* a security hole (this
-   * note is for you, Andrew) as we are not *allowing*
-   * the access at this point, the actual unlink or
-   * chown or chmod call would do this. We are just helping
-   * clients out by telling them if they have a hope
-   * of any of this succeeding. POSIX acls may still
-   * deny the real call. JRA.
-   */
-
-  if (smb_open_mode == -1) {
-    if(desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
-                              FILE_EXECUTE|FILE_READ_ATTRIBUTES|
-                              FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS))
-      smb_open_mode = DOS_OPEN_RDONLY;
-    else {
-      DEBUG(0,("map_share_mode: Incorrect value %lx for desired_access to file %s\n",
-             (unsigned long)desired_access, fname));
-      return -1;
-    }
-  }
-
-  /*
-   * Set the special bit that means allow share delete.
-   * This is held outside the normal share mode bits at 1<<15.
-   * JRA.
-   */
-
-  if(share_access & FILE_SHARE_DELETE)
-    smb_open_mode |= ALLOW_SHARE_DELETE;
-
-  /* Add in the requested share mode. */
-  switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
-  case FILE_SHARE_READ:
-    smb_open_mode |= SET_DENY_MODE(DENY_WRITE);
-    break;
-  case FILE_SHARE_WRITE:
-    smb_open_mode |= SET_DENY_MODE(DENY_READ);
-    break;
-  case (FILE_SHARE_READ|FILE_SHARE_WRITE):
-    smb_open_mode |= SET_DENY_MODE(DENY_NONE);
-    break;
-  case FILE_SHARE_NONE:
-    smb_open_mode |= SET_DENY_MODE(DENY_ALL);
-    break;
-  }
-
-  /*
-   * Handle an O_SYNC request.
-   */
-
-  if(file_attributes & FILE_FLAG_WRITE_THROUGH)
-    smb_open_mode |= FILE_SYNC_OPENMODE;
-
-  DEBUG(10,("map_share_mode: Mapped desired access %lx, share access %lx, file attributes %lx \
-to open_mode %x\n", (unsigned long)desired_access, (unsigned long)share_access,
-                    (unsigned long)file_attributes, smb_open_mode ));
-  return smb_open_mode;
-}
+       int smb_open_mode = -1;
 
-/*
- * This is a *disgusting* hack.
- * This is *so* bad that even I'm embarrassed (and I
- * have no shame). Here's the deal :
- * Until we get the correct SPOOLSS code into smbd
- * then when we're running with NT SMB support then
- * NT makes this call with a level of zero, and then
- * immediately follows it with an open request to
- * the \\SRVSVC pipe. If we allow that open to
- * succeed then NT barfs when it cannot open the
- * \\SPOOLSS pipe immediately after and continually
- * whines saying "Printer name is invalid" forever
- * after. If we cause *JUST THIS NEXT OPEN* of \\SRVSVC
- * to fail, then NT downgrades to using the downlevel code
- * and everything works as well as before. I hate
- * myself for adding this code.... JRA.
- *
- * The HACK_FAIL_TIME define allows only a 2
- * second window for this to occur, just in
- * case...
- */
-
-static BOOL fail_next_srvsvc = False;
-static time_t fail_time;
-#define HACK_FAIL_TIME 2 /* In seconds. */
-
-void fail_next_srvsvc_open(void)
-{
-  fail_next_srvsvc = True;
-  fail_time = time(NULL);
-  DEBUG(10,("fail_next_srvsvc_open: setting up timeout close of \\srvsvc pipe for print fix.\n"));
+       /*
+        * Convert GENERIC bits to specific bits.
+        */
+
+       se_map_generic(desired_access, &file_generic_mapping);
+
+       switch( *desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
+               case FILE_READ_DATA:
+                       smb_open_mode = DOS_OPEN_RDONLY;
+                       break;
+               case FILE_WRITE_DATA:
+               case FILE_APPEND_DATA:
+               case FILE_WRITE_DATA|FILE_APPEND_DATA:
+                       smb_open_mode = DOS_OPEN_WRONLY;
+                       break;
+               case FILE_READ_DATA|FILE_WRITE_DATA:
+               case FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA:
+               case FILE_READ_DATA|FILE_APPEND_DATA:
+                       smb_open_mode = DOS_OPEN_RDWR;
+                       break;
+       }
+
+       /*
+        * NB. For DELETE_ACCESS we should really check the
+        * directory permissions, as that is what controls
+        * delete, and for WRITE_DAC_ACCESS we should really
+        * check the ownership, as that is what controls the
+        * chmod. Note that this is *NOT* a security hole (this
+        * note is for you, Andrew) as we are not *allowing*
+        * the access at this point, the actual unlink or
+        * chown or chmod call would do this. We are just helping
+        * clients out by telling them if they have a hope
+        * of any of this succeeding. POSIX acls may still
+        * deny the real call. JRA.
+        */
+
+       if (smb_open_mode == -1) {
+
+               if(*desired_access & (DELETE_ACCESS|WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
+                                       FILE_EXECUTE|FILE_READ_ATTRIBUTES|
+                                       FILE_READ_EA|FILE_WRITE_EA|SYSTEM_SECURITY_ACCESS|
+                                       FILE_WRITE_ATTRIBUTES|READ_CONTROL_ACCESS)) {
+                       smb_open_mode = DOS_OPEN_RDONLY;
+               } else if(*desired_access == 0) {
+
+                       /* 
+                        * JRA - NT seems to sometimes send desired_access as zero. play it safe
+                        * and map to a stat open.
+                        */
+
+                       smb_open_mode = DOS_OPEN_RDONLY;
+
+               } else {
+                       DEBUG(0,("map_share_mode: Incorrect value 0x%lx for desired_access to file %s\n",
+                               (unsigned long)*desired_access, fname));
+                       return -1;
+               }
+       }
+
+       /*
+        * Set the special bit that means allow share delete.
+        * This is held outside the normal share mode bits at 1<<15.
+        * JRA.
+        */
+
+       if(share_access & FILE_SHARE_DELETE) {
+               smb_open_mode |= ALLOW_SHARE_DELETE;
+               DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = 0x%x\n", smb_open_mode));
+       }
+
+       /*
+        * We need to store the intent to open for Delete. This
+        * is what determines if a delete on close flag can be set.
+        * This is the wrong way (and place) to store this, but for 2.2 this
+        * is the only practical way. JRA.
+        */
+
+       if(*desired_access & DELETE_ACCESS) {
+               DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = 0x%x\n", smb_open_mode));
+       }
+
+       if (create_options & FILE_DELETE_ON_CLOSE) {
+               /* Implicit delete access is *NOT* requested... */
+               smb_open_mode |= DELETE_ON_CLOSE_FLAG;
+               DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = 0x%x\n", smb_open_mode));
+       }
+
+       /* Add in the requested share mode. */
+       switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
+               case FILE_SHARE_READ:
+                       smb_open_mode |= SET_DENY_MODE(DENY_WRITE);
+                       break;
+               case FILE_SHARE_WRITE:
+                       smb_open_mode |= SET_DENY_MODE(DENY_READ);
+                       break;
+               case (FILE_SHARE_READ|FILE_SHARE_WRITE):
+                       smb_open_mode |= SET_DENY_MODE(DENY_NONE);
+                       break;
+               case FILE_SHARE_NONE:
+                       smb_open_mode |= SET_DENY_MODE(DENY_ALL);
+                       break;
+       }
+
+       /*
+        * Handle an O_SYNC request.
+        */
+
+       if(file_attributes & FILE_FLAG_WRITE_THROUGH)
+               smb_open_mode |= FILE_SYNC_OPENMODE;
+
+       DEBUG(10,("map_share_mode: Mapped desired access 0x%lx, share access 0x%lx, file attributes 0x%lx \
+to open_mode 0x%x\n", (unsigned long)*desired_access, (unsigned long)share_access,
+               (unsigned long)file_attributes, smb_open_mode ));
+       return smb_open_mode;
 }
 
 /****************************************************************************
  Reply to an NT create and X call on a pipe.
 ****************************************************************************/
+
 static int nt_open_pipe(char *fname, connection_struct *conn,
                        char *inbuf, char *outbuf, int *ppnum)
 {
-       pipes_struct *p = NULL;
+       smb_np_struct *p = NULL;
 
        uint16 vuid = SVAL(inbuf, smb_uid);
        int i;
@@ -481,32 +465,16 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
        DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname));
     
        /* See if it is one we want to handle. */
+
+       if (lp_disable_spoolss() && strequal(fname, "\\spoolss"))
+               return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
+
        for( i = 0; known_nt_pipes[i]; i++ )
                if( strequal(fname,known_nt_pipes[i]))
                        break;
     
-       /*
-        * HACK alert.... see above - JRA.
-        */
-
-       if(fail_next_srvsvc && (time(NULL) > fail_time + HACK_FAIL_TIME)) {
-               fail_next_srvsvc = False;
-               fail_time = (time_t)0;
-               DEBUG(10,("nt_open_pipe: End of timeout close of \\srvsvc pipe for print fix.\n"));
-       }
-
-       if(fail_next_srvsvc && strequal(fname, "\\srvsvc")) {
-               fail_next_srvsvc = False;
-               DEBUG(10,("nt_open_pipe: Deliberately failing open of \\srvsvc pipe for print fix.\n"));
-               return(ERROR(ERRSRV,ERRaccess));
-       }
-
-       /*
-        * End hack alert.... see above - JRA.
-        */
-
        if ( known_nt_pipes[i] == NULL )
-               return(ERROR(ERRSRV,ERRaccess));
+               return(ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpipe));
     
        /* Strip \\ off the name. */
        fname++;
@@ -515,13 +483,55 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
 
        p = open_rpc_pipe_p(fname, conn, vuid);
        if (!p)
-               return(ERROR(ERRSRV,ERRnofids));
+               return(ERROR_DOS(ERRSRV,ERRnofids));
 
        *ppnum = p->pnum;
 
        return 0;
 }
 
+/****************************************************************************
+ Reply to an NT create and X call for pipes.
+****************************************************************************/
+
+static int do_ntcreate_pipe_open(connection_struct *conn,
+                        char *inbuf,char *outbuf,int length,int bufsize)
+{
+       pstring fname;
+       int ret;
+       int pnum = -1;
+       char *p = NULL;
+
+       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
+
+       if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+               return ret;
+
+       /*
+        * Deal with pipe return.
+        */  
+
+       set_message(outbuf,34,0,True);
+
+       p = outbuf + smb_vwv2;
+       p++;
+       SSVAL(p,0,pnum);
+       p += 2;
+       SIVAL(p,0,FILE_WAS_OPENED);
+       p += 4;
+       p += 32;
+       SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
+       p += 20;
+       /* File type. */
+       SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
+       /* Device state. */
+       SSVAL(p,2, 0x5FF); /* ? */
+
+       DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
+
+       return chain_reply(inbuf,outbuf,length,bufsize);
+}
+
 /****************************************************************************
  Reply to an NT create and X call.
 ****************************************************************************/
@@ -529,6 +539,7 @@ static int nt_open_pipe(char *fname, connection_struct *conn,
 int reply_ntcreate_and_X(connection_struct *conn,
                         char *inbuf,char *outbuf,int length,int bufsize)
 {  
+       int result;
        pstring fname;
        uint32 flags = IVAL(inbuf,smb_ntcreate_Flags);
        uint32 desired_access = IVAL(inbuf,smb_ntcreate_DesiredAccess);
@@ -536,8 +547,6 @@ int reply_ntcreate_and_X(connection_struct *conn,
        uint32 share_access = IVAL(inbuf,smb_ntcreate_ShareAccess);
        uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition);
        uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions);
-       uint32 fname_len = MIN(((uint32)SVAL(inbuf,smb_ntcreate_NameLength)),
-                              ((uint32)sizeof(fname)-1));
        uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid);
        int smb_ofun;
        int smb_open_mode;
@@ -545,8 +554,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
        /* Breakout the oplock request bits so we can set the
           reply bits separately. */
        int oplock_request = 0;
-    mode_t unixmode;
-       int pnum = -1;
+       mode_t unixmode;
        int fmode=0,rmode=0;
        SMB_OFF_T file_len = 0;
        SMB_STRUCT_STAT sbuf;
@@ -554,108 +562,110 @@ int reply_ntcreate_and_X(connection_struct *conn,
        BOOL bad_path = False;
        files_struct *fsp=NULL;
        char *p = NULL;
+       time_t c_time;
+       START_PROFILE(SMBntcreateX);
+
+       /* If it's an IPC, use the pipe handler. */
+
+       if (IS_IPC(conn)) {
+               if (lp_nt_pipe_support()) {
+                       END_PROFILE(SMBntcreateX);
+                       return do_ntcreate_pipe_open(conn,inbuf,outbuf,length,bufsize);
+               } else {
+                       END_PROFILE(SMBntcreateX);
+                       return(ERROR_DOS(ERRDOS,ERRbadaccess));
+               }
+       }
+                       
 
        /* 
         * We need to construct the open_and_X ofun value from the
         * NT values, as that's what our code is structured to accept.
         */    
        
-       if((smb_ofun = map_create_disposition( create_disposition )) == -1)
-               return(ERROR(ERRDOS,ERRbadaccess));
+       if((smb_ofun = map_create_disposition( create_disposition )) == -1) {
+               END_PROFILE(SMBntcreateX);
+               return(ERROR_DOS(ERRDOS,ERRbadaccess));
+       }
 
        /*
         * Get the file name.
         */
 
-    if(root_dir_fid != 0) {
-      /*
-       * This filename is relative to a directory fid.
-       */
-      files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
-      size_t dir_name_len;
+       if(root_dir_fid != 0) {
+               /*
+                * This filename is relative to a directory fid.
+                */
+               files_struct *dir_fsp = file_fsp(inbuf,smb_ntcreate_RootDirectoryFid);
+               size_t dir_name_len;
 
-      if(!dir_fsp || !dir_fsp->is_directory)
-        return(ERROR(ERRDOS,ERRbadfid));
+               if(!dir_fsp) {
+                       END_PROFILE(SMBntcreateX);
+                       return(ERROR_DOS(ERRDOS,ERRbadfid));
+               }
 
-      /*
-       * Copy in the base directory name.
-       */
+               if(!dir_fsp->is_directory) {
 
-      pstrcpy( fname, dir_fsp->fsp_name );
-      dir_name_len = strlen(fname);
+                       srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
 
-      /*
-       * Ensure it ends in a '\'.
-       */
+                       /* 
+                        * Check to see if this is a mac fork of some kind.
+                        */
 
-      if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
-        pstrcat(fname, "\\");
-        dir_name_len++;
-      }
+                       if( strchr_m(fname, ':')) {
+                               END_PROFILE(SMBntcreateX);
+                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+                       }
+                       END_PROFILE(SMBntcreateX);
+                       return(ERROR_DOS(ERRDOS,ERRbadfid));
+               }
 
-      if(fname_len + dir_name_len >= sizeof(pstring))
-        return(ERROR(ERRSRV,ERRfilespecs));
+               /*
+                * Copy in the base directory name.
+                */
 
-      get_filename(&fname[dir_name_len], inbuf, smb_buf(inbuf)-inbuf, 
-                   smb_buflen(inbuf),fname_len);
-#if 0
-      StrnCpy(&fname[dir_name_len], smb_buf(inbuf),fname_len);
-      fname[dir_name_len+fname_len] = '\0';
-#endif
+               pstrcpy( fname, dir_fsp->fsp_name );
+               dir_name_len = strlen(fname);
 
-    } else {
-      
-      get_filename(fname, inbuf, smb_buf(inbuf)-inbuf, 
-                   smb_buflen(inbuf),fname_len);
+               /*
+                * Ensure it ends in a '\'.
+                */
 
-#if 0
-         StrnCpy(fname,smb_buf(inbuf),fname_len);
-      fname[fname_len] = '\0';
-#endif
-    }
-       
-       /* If it's an IPC, use the pipe handler. */
+               if(fname[dir_name_len-1] != '\\' && fname[dir_name_len-1] != '/') {
+                       pstrcat(fname, "\\");
+                       dir_name_len++;
+               }
 
-       if (IS_IPC(conn) && lp_nt_pipe_support() && lp_security() != SEC_SHARE)
-       {
-               int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
-               if(ret != 0)
-                       return ret;
+               srvstr_pull_buf(inbuf, &fname[dir_name_len], smb_buf(inbuf), sizeof(fname)-dir_name_len, STR_TERMINATE);
+       } else {
+               srvstr_pull_buf(inbuf, fname, smb_buf(inbuf), sizeof(fname), STR_TERMINATE);
 
-               /*
-                * Deal with pipe return.
-                */  
+               /* 
+                * Check to see if this is a mac fork of some kind.
+                */
 
-               set_message(outbuf,34,0,True);
-       
-               p = outbuf + smb_vwv2;
-               p++;
-               SSVAL(p,0,pnum);
-               p += 2;
-               SIVAL(p,0,FILE_WAS_OPENED);
-               p += 4;
-               p += 32;
-               SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
-               p += 20;
-               /* File type. */
-               SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
-               /* Device state. */
-               SSVAL(p,2, 0x5FF); /* ? */
-
-               DEBUG(5,("reply_ntcreate_and_X: open pipe = %s\n", fname));
-
-               return chain_reply(inbuf,outbuf,length,bufsize);
+               if( strchr_m(fname, ':')) {
+                       END_PROFILE(SMBntcreateX);
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
        }
-
+       
        /*
         * Now contruct the smb_open_mode value from the filename, 
-     * desired access and the share access.
+        * desired access and the share access.
         */
-       
-       if((smb_open_mode = map_share_mode(fname, desired_access, 
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+       if((smb_open_mode = map_share_mode(fname, create_options, &desired_access, 
                                           share_access, 
                                           file_attributes)) == -1) {
-               return(ERROR(ERRDOS,ERRbadaccess));
+               END_PROFILE(SMBntcreateX);
+               return ERROR_DOS(ERRDOS,ERRbadaccess);
+       }
+
+       oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+       if (oplock_request) {
+               oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
        }
 
        /*
@@ -668,31 +678,10 @@ int reply_ntcreate_and_X(connection_struct *conn,
                
        set_posix_case_semantics(file_attributes);
                
-       unix_convert(fname,conn,0,&bad_path,NULL);
-               
-       fsp = file_new();
-       if (!fsp) {
-               restore_case_semantics(file_attributes);
-               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);
-               
-               restore_case_semantics(file_attributes);
-               
-               return(UNIXERROR(ERRDOS,ERRnoaccess));
-       } 
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
                
-       unixmode = unix_mode(conn,smb_attr | aARCH);
+       unixmode = unix_mode(conn,smb_attr | aARCH, fname);
     
-       oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
-       oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
-
        /* 
         * If it's a request for a directory open, deal with it separately.
         */
@@ -700,13 +689,13 @@ int reply_ntcreate_and_X(connection_struct *conn,
        if(create_options & FILE_DIRECTORY_FILE) {
                oplock_request = 0;
                
-               open_directory(fsp, conn, fname, smb_ofun, unixmode, 
-                              &smb_action);
+               fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
                        
                restore_case_semantics(file_attributes);
 
-               if(!fsp->open) {
-                       file_free(fsp);
+               if(!fsp) {
+                       set_bad_path_error(errno, bad_path);
+                       END_PROFILE(SMBntcreateX);
                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                }
        } else {
@@ -727,13 +716,15 @@ int reply_ntcreate_and_X(connection_struct *conn,
                 * before issuing an oplock break request to
                 * our client. JRA.  */
 
-               open_file_shared(fsp,conn,fname,smb_open_mode,
-                                smb_ofun,unixmode,
-                                oplock_request,&rmode,&smb_action);
+               fsp = open_file_shared1(conn,fname,&sbuf,
+                                       desired_access,
+                                       smb_open_mode,
+                                       smb_ofun,unixmode, oplock_request,
+                                       &rmode,&smb_action);
 
-               if (!fsp->open) { 
-                       /* We cheat here. The only case we
-                        * care about is a directory rename,
+               if (!fsp) { 
+                       /* We cheat here. There are two cases we
+                        * care about. One is a directory rename,
                         * where the NT client will attempt to
                         * open the source directory for
                         * DELETE access. Note that when the
@@ -746,51 +737,44 @@ int reply_ntcreate_and_X(connection_struct *conn,
                         * will generate an EISDIR error, so
                         * we can catch this here and open a
                         * pseudo handle that is flagged as a
-                        * directory. JRA.  */
+                        * directory. The second is an open
+                        * for a permissions read only, which
+                        * we handle in the open_file_stat case. JRA.
+                        */
 
                        if(errno == EISDIR) {
+
+                               /*
+                                * Fail the open if it was explicitly a non-directory file.
+                                */
+
+                               if (create_options & FILE_NON_DIRECTORY_FILE) {
+                                       restore_case_semantics(file_attributes);
+                                       SSVAL(outbuf, smb_flg2, 
+                                             SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+                                       END_PROFILE(SMBntcreateX);
+                                       return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+                               }
+       
                                oplock_request = 0;
+                               fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
                                
-                               open_directory(fsp, conn, fname, 
-                                              smb_ofun, unixmode, 
-                                              &smb_action);
-                               
-                               if(!fsp->open) {
-                                       file_free(fsp);
+                               if(!fsp) {
                                        restore_case_semantics(file_attributes);
+                                       set_bad_path_error(errno, bad_path);
+                                       END_PROFILE(SMBntcreateX);
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                                }
                        } else {
-                               if((errno == ENOENT) && bad_path) {
-                                       unix_ERR_class = ERRDOS;
-                                       unix_ERR_code = ERRbadpath;
-                               }
-                               
-                               file_free(fsp);
-                               
+
                                restore_case_semantics(file_attributes);
-                               
+                               set_bad_path_error(errno, bad_path);
+                               END_PROFILE(SMBntcreateX);
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
                        }
                } 
        }
                
-       if(fsp->is_directory) {
-               if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False),
-                                          &sbuf) != 0) {
-                       close_directory(fsp);
-                       restore_case_semantics(file_attributes);
-                       return(ERROR(ERRDOS,ERRnoaccess));
-               }
-       } else {
-               if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) 
-                   != 0) {
-                       close_file(fsp,False);
-                       restore_case_semantics(file_attributes);
-                       return(ERROR(ERRDOS,ERRnoaccess));
-               } 
-       }
-               
        restore_case_semantics(file_attributes);
                
        file_len = sbuf.st_size;
@@ -799,7 +783,8 @@ int reply_ntcreate_and_X(connection_struct *conn,
                fmode = FILE_ATTRIBUTE_NORMAL;
        if (!fsp->is_directory && (fmode & aDIR)) {
                close_file(fsp,False);
-               return(ERROR(ERRDOS,ERRnoaccess));
+               END_PROFILE(SMBntcreateX);
+               return ERROR_DOS(ERRDOS,ERRnoaccess);
        } 
        
        /* 
@@ -811,10 +796,15 @@ int reply_ntcreate_and_X(connection_struct *conn,
        if (oplock_request && lp_fake_oplocks(SNUM(conn)))
                smb_action |= EXTENDED_OPLOCK_GRANTED;
        
-       if(oplock_request && fsp->granted_oplock)
+       if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
                smb_action |= EXTENDED_OPLOCK_GRANTED;
-       
+
+#if 0
+       /* W2K sends back 42 words here ! If we do the same it breaks offline sync. Go figure... ? JRA. */
+       set_message(outbuf,42,0,True);
+#else
        set_message(outbuf,34,0,True);
+#endif
        
        p = outbuf + smb_vwv2;
        
@@ -822,8 +812,19 @@ int reply_ntcreate_and_X(connection_struct *conn,
         * Currently as we don't support level II oplocks we just report
         * exclusive & batch here.
         */
+
+       if (smb_action & EXTENDED_OPLOCK_GRANTED) {
+               if (flags & REQUEST_BATCH_OPLOCK) {
+                       SCVAL(p,0, BATCH_OPLOCK_RETURN);
+               } else {
+                       SCVAL(p,0, EXCLUSIVE_OPLOCK_RETURN);
+               }
+       } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+               SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+       } else {
+               SCVAL(p,0,NO_OPLOCK_RETURN);
+       }
        
-       SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
        p++;
        SSVAL(p,0,fsp->fnum);
        p += 2;
@@ -831,7 +832,16 @@ int reply_ntcreate_and_X(connection_struct *conn,
        p += 4;
        
        /* Create time. */  
-       put_long_date(p,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
+       c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+       if (lp_dos_filetime_resolution(SNUM(conn))) {
+               c_time &= ~1;
+               sbuf.st_atime &= ~1;
+               sbuf.st_mtime &= ~1;
+               sbuf.st_mtime &= ~1;
+       }
+
+       put_long_date(p,c_time);
        p += 8;
        put_long_date(p,sbuf.st_atime); /* access time */
        p += 8;
@@ -841,7 +851,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
        p += 8;
        SIVAL(p,0,fmode); /* File Attributes. */
        p += 4;
-       SOFF_T(p, 0, file_len);
+       SOFF_T(p, 0, get_allocation_size(&sbuf));
        p += 8;
        SOFF_T(p,0,file_len);
        p += 12;
@@ -849,274 +859,458 @@ int reply_ntcreate_and_X(connection_struct *conn,
        
        DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n", fsp->fnum, fsp->fsp_name));
 
-       return chain_reply(inbuf,outbuf,length,bufsize);
+       result = chain_reply(inbuf,outbuf,length,bufsize);
+       END_PROFILE(SMBntcreateX);
+       return result;
 }
 
 /****************************************************************************
- Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
+ Reply to a NT_TRANSACT_CREATE call to open a pipe.
 ****************************************************************************/
-static int call_nt_transact_create(connection_struct *conn,
-                                  char *inbuf, char *outbuf, int length, 
-                                   int bufsize
-                                   char **ppsetup, char **ppparams, 
-                                  char **ppdata)
+
+static int do_nt_transact_create_pipe( connection_struct *conn,
+                                       char *inbuf, char *outbuf, int length
+                                       int bufsize, char **ppsetup, char **ppparams, 
+                                       char **ppdata)
 {
-  pstring fname;
-  char *params = *ppparams;
-  uint32 flags = IVAL(params,0);
-  uint32 desired_access = IVAL(params,8);
-  uint32 file_attributes = IVAL(params,20);
-  uint32 share_access = IVAL(params,24);
-  uint32 create_disposition = IVAL(params,28);
-  uint32 create_options = IVAL(params,32);
-  uint32 fname_len = MIN(((uint32)IVAL(params,44)),
-                         ((uint32)sizeof(fname)-1));
-  uint16 root_dir_fid = (uint16)IVAL(params,4);
-  int smb_ofun;
-  int smb_open_mode;
-  int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
-  /* Breakout the oplock request bits so we can set the
-     reply bits separately. */
-  int oplock_request = 0;
-  mode_t unixmode;
-  int pnum = -1;
-  int fmode=0,rmode=0;
-  SMB_OFF_T file_len = 0;
-  SMB_STRUCT_STAT sbuf;
-  int smb_action = 0;
-  BOOL bad_path = False;
-  files_struct *fsp = NULL;
-  char *p = NULL;
-
-  /* 
-   * We need to construct the open_and_X ofun value from the
-   * NT values, as that's what our code is structured to accept.
-   */    
-
-  if((smb_ofun = map_create_disposition( create_disposition )) == -1)
-    return(ERROR(ERRDOS,ERRbadaccess));
-
-  /*
-   * Get the file name.
-   */
-
-  if(root_dir_fid != 0) {
-    /*
-     * This filename is relative to a directory fid.
-     */
-
-    files_struct *dir_fsp = file_fsp(params,4);
-    size_t dir_name_len;
-
-    if(!dir_fsp || !dir_fsp->is_directory)
-      return(ERROR(ERRDOS,ERRbadfid));
-
-    /*
-     * Copy in the base directory name.
-     */
-
-    pstrcpy( fname, dir_fsp->fsp_name );
-    dir_name_len = strlen(fname);
-
-    /*
-     * Ensure it ends in a '\'.
-     */
-
-    if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
-      pstrcat(fname, "\\");
-      dir_name_len++;
-    }
-
-    if(fname_len + dir_name_len >= sizeof(pstring))
-      return(ERROR(ERRSRV,ERRfilespecs));
-
-    StrnCpy(&fname[dir_name_len], params+53, fname_len);
-    fname[dir_name_len+fname_len] = '\0';
-
-  } else {
-    StrnCpy(fname,params+53,fname_len);
-    fname[fname_len] = '\0';
-  }
-
-  /* If it's an IPC, use the pipe handler. */
-  if (IS_IPC(conn)) {
-    int ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum);
-    if(ret != 0)
-      return ret;
-    smb_action = FILE_WAS_OPENED;
-  } else {
-    /*
-     * Check if POSIX semantics are wanted.
-     */
-
-    set_posix_case_semantics(file_attributes);
-
-    unix_convert(fname,conn,0,&bad_path,NULL);
-    
-    fsp = file_new();
-    if (!fsp) {
-           restore_case_semantics(file_attributes);
-           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);
-
-      restore_case_semantics(file_attributes);
-
-      return(UNIXERROR(ERRDOS,ERRnoaccess));
-    } 
-  
-    unixmode = unix_mode(conn,smb_attr | aARCH);
-    
-    oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
-    oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+       pstring fname;
+       int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount);
+       char *params = *ppparams;
+       int ret;
+       int pnum = -1;
+       char *p = NULL;
 
-    /*
-     * Now contruct the smb_open_mode value from the desired access
-     * and the share access.
-     */
+       /*
+        * Ensure minimum number of parameters sent.
+        */
 
-    if((smb_open_mode = map_share_mode( fname, desired_access, share_access, file_attributes)) == -1)
-      return(ERROR(ERRDOS,ERRbadaccess));
+       if(total_parameter_count < 54) {
+               DEBUG(0,("do_nt_transact_create_pipe - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
+               return ERROR_DOS(ERRDOS,ERRbadaccess);
+       }
 
-    /*
-     * If it's a request for a directory open, deal with it separately.
-     */
+       srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE);
 
-    if(create_options & FILE_DIRECTORY_FILE) {
+       if ((ret = nt_open_pipe(fname, conn, inbuf, outbuf, &pnum)) != 0)
+               return ret;
+       
+       /* Realloc the size of parameters and data we will return */
+       params = Realloc(*ppparams, 69);
+       if(params == NULL)
+               return ERROR_DOS(ERRDOS,ERRnomem);
+       
+       *ppparams = params;
+       
+       memset((char *)params,'\0',69);
+       
+       p = params;
+       SCVAL(p,0,NO_OPLOCK_RETURN);
+       
+       p += 2;
+       SSVAL(p,0,pnum);
+       p += 2;
+       SIVAL(p,0,FILE_WAS_OPENED);
+       p += 8;
+       
+       p += 32;
+       SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
+       p += 20;
+       /* File type. */
+       SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
+       /* Device state. */
+       SSVAL(p,2, 0x5FF); /* ? */
+       
+       DEBUG(5,("do_nt_transact_create_pipe: open name = %s\n", fname));
+       
+       /* Send the required number of replies */
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+       
+       return -1;
+}
 
-      oplock_request = 0;
+/****************************************************************************
+ Internal fn to set security descriptors.
+****************************************************************************/
 
-      /*
-       * We will get a create directory here if the Win32
-       * app specified a security descriptor in the 
-       * CreateDirectory() call.
-       */
+static NTSTATUS set_sd(files_struct *fsp, char *data, uint32 sd_len, uint32 security_info_sent)
+{
+       prs_struct pd;
+       SEC_DESC *psd = NULL;
+       TALLOC_CTX *mem_ctx;
+       BOOL ret;
+       
+       if (sd_len == 0) {
+               return NT_STATUS_OK;
+       }
 
-      open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
+       /*
+        * Init the parse struct we will unmarshall from.
+        */
 
-      if(!fsp->open) {
-        file_free(fsp);
-        return(UNIXERROR(ERRDOS,ERRnoaccess));
-      }
-    } else {
+       if ((mem_ctx = talloc_init()) == NULL) {
+               DEBUG(0,("set_sd: talloc_init failed.\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
 
-      /*
-       * Ordinary file case.
-       */
+       prs_init(&pd, 0, mem_ctx, UNMARSHALL);
 
-      open_file_shared(fsp,conn,fname,smb_open_mode,smb_ofun,
-                      unixmode,oplock_request,&rmode,&smb_action);
+       /*
+        * Setup the prs_struct to point at the memory we just
+        * allocated.
+        */
+       
+       prs_give_memory( &pd, data, sd_len, False);
 
-      if (!fsp->open) { 
-        if((errno == ENOENT) && bad_path) {
-          unix_ERR_class = ERRDOS;
-          unix_ERR_code = ERRbadpath;
-        }
-        file_free(fsp);
+       /*
+        * Finally, unmarshall from the data buffer.
+        */
 
-        restore_case_semantics(file_attributes);
+       if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+               DEBUG(0,("set_sd: Error in unmarshalling security descriptor.\n"));
+               /*
+                * Return access denied for want of a better error message..
+                */ 
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       if (psd->off_owner_sid==0)
+               security_info_sent &= ~OWNER_SECURITY_INFORMATION;
+       if (psd->off_grp_sid==0)
+               security_info_sent &= ~GROUP_SECURITY_INFORMATION;
+       if (psd->off_sacl==0)
+               security_info_sent &= ~SACL_SECURITY_INFORMATION;
+       if (psd->off_dacl==0)
+               security_info_sent &= ~DACL_SECURITY_INFORMATION;
+       
+       ret = fsp->conn->vfs_ops.fset_nt_acl( fsp, fsp->fd, security_info_sent, psd);
+       
+       if (!ret) {
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       
+       talloc_destroy(mem_ctx);
+       
+       return NT_STATUS_OK;
+}
 
-        return(UNIXERROR(ERRDOS,ERRnoaccess));
-      } 
-  
-      if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
-        close_file(fsp,False);
+/****************************************************************************
+ Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
+****************************************************************************/
 
-        restore_case_semantics(file_attributes);
+static int call_nt_transact_create(connection_struct *conn,
+                                       char *inbuf, char *outbuf, int length, 
+                                       int bufsize, char **ppsetup, char **ppparams, 
+                                       char **ppdata)
+{
+       pstring fname;
+       char *params = *ppparams;
+       char *data = *ppdata;
+       int total_parameter_count = (int)IVAL(inbuf, smb_nt_TotalParameterCount);
+       /* Breakout the oplock request bits so we can set the reply bits separately. */
+       int oplock_request = 0;
+       mode_t unixmode;
+       int fmode=0,rmode=0;
+       SMB_OFF_T file_len = 0;
+       SMB_STRUCT_STAT sbuf;
+       int smb_action = 0;
+       BOOL bad_path = False;
+       files_struct *fsp = NULL;
+       char *p = NULL;
+       uint32 flags;
+       uint32 desired_access;
+       uint32 file_attributes;
+       uint32 share_access;
+       uint32 create_disposition;
+       uint32 create_options;
+       uint32 sd_len;
+       uint16 root_dir_fid;
+       int smb_ofun;
+       int smb_open_mode;
+       int smb_attr;
+       time_t c_time;
+       NTSTATUS nt_status;
+
+       DEBUG(5,("call_nt_transact_create\n"));
+
+       /*
+        * If it's an IPC, use the pipe handler.
+        */
 
-        return(ERROR(ERRDOS,ERRnoaccess));
-      } 
+       if (IS_IPC(conn)) {
+               if (lp_nt_pipe_support())
+                       return do_nt_transact_create_pipe(conn, inbuf, outbuf, length, 
+                                       bufsize, ppsetup, ppparams, ppdata);
+               else
+                       return ERROR_DOS(ERRDOS,ERRbadaccess);
+       }
+
+       /*
+        * Ensure minimum number of parameters sent.
+        */
+
+       if(total_parameter_count < 54) {
+               DEBUG(0,("call_nt_transact_create - insufficient parameters (%u)\n", (unsigned int)total_parameter_count));
+               return ERROR_DOS(ERRDOS,ERRbadaccess);
+       }
+
+       flags = IVAL(params,0);
+       desired_access = IVAL(params,8);
+       file_attributes = IVAL(params,20);
+       share_access = IVAL(params,24);
+       create_disposition = IVAL(params,28);
+       create_options = IVAL(params,32);
+       sd_len = IVAL(params,36);
+       root_dir_fid = (uint16)IVAL(params,4);
+       smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK);
+
+       /* 
+        * We need to construct the open_and_X ofun value from the
+        * NT values, as that's what our code is structured to accept.
+        */    
+
+       if((smb_ofun = map_create_disposition( create_disposition )) == -1)
+               return ERROR_DOS(ERRDOS,ERRbadmem);
+
+       /*
+        * Get the file name.
+        */
+
+       if(root_dir_fid != 0) {
+               /*
+                * This filename is relative to a directory fid.
+                */
+
+               files_struct *dir_fsp = file_fsp(params,4);
+               size_t dir_name_len;
+
+               if(!dir_fsp)
+                       return ERROR_DOS(ERRDOS,ERRbadfid);
+
+               if(!dir_fsp->is_directory) {
+
+                       srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE);
+
+                       /*
+                        * Check to see if this is a mac fork of some kind.
+                        */
+
+                       if( strchr_m(fname, ':'))
+                               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+
+                       return ERROR_DOS(ERRDOS,ERRbadfid);
+               }
+
+               /*
+                * Copy in the base directory name.
+                */
+
+               pstrcpy( fname, dir_fsp->fsp_name );
+               dir_name_len = strlen(fname);
+
+               /*
+                * Ensure it ends in a '\'.
+                */
+
+               if((fname[dir_name_len-1] != '\\') && (fname[dir_name_len-1] != '/')) {
+                       pstrcat(fname, "\\");
+                       dir_name_len++;
+               }
+
+               srvstr_pull(inbuf, &fname[dir_name_len], params+53, sizeof(fname)-dir_name_len, 
+                               total_parameter_count-53, STR_TERMINATE);
+       } else {
+               srvstr_pull(inbuf, fname, params+53, sizeof(fname), total_parameter_count-53, STR_TERMINATE);
+
+               /*
+                * Check to see if this is a mac fork of some kind.
+                */
+
+               if( strchr_m(fname, ':'))
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
+
+       /*
+        * Now contruct the smb_open_mode value from the desired access
+        * and the share access.
+        */
+
+       if((smb_open_mode = map_share_mode( fname, create_options, &desired_access,
+                                               share_access, file_attributes)) == -1)
+               return ERROR_DOS(ERRDOS,ERRbadaccess);
+
+       oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+       oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+
+       /*
+        * Check if POSIX semantics are wanted.
+        */
+
+       set_posix_case_semantics(file_attributes);
+    
+       RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
+
+       unix_convert(fname,conn,0,&bad_path,&sbuf);
+    
+       unixmode = unix_mode(conn,smb_attr | aARCH, fname);
+   
+       /*
+        * If it's a request for a directory open, deal with it separately.
+        */
+
+       if(create_options & FILE_DIRECTORY_FILE) {
+
+               oplock_request = 0;
+
+               /*
+                * We will get a create directory here if the Win32
+                * app specified a security descriptor in the 
+                * CreateDirectory() call.
+                */
+
+               fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+
+               if(!fsp) {
+                       restore_case_semantics(file_attributes);
+                       set_bad_path_error(errno, bad_path);
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+
+       } else {
+
+               /*
+                * Ordinary file case.
+                */
+
+               fsp = open_file_shared1(conn,fname,&sbuf,desired_access,
+                                               smb_open_mode,smb_ofun,unixmode,
+                                               oplock_request,&rmode,&smb_action);
+
+               if (!fsp) { 
+
+                       if(errno == EISDIR) {
+
+                               /*
+                                * Fail the open if it was explicitly a non-directory file.
+                                */
+
+                               if (create_options & FILE_NON_DIRECTORY_FILE) {
+                                       restore_case_semantics(file_attributes);
+                                       SSVAL(outbuf, smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+                                       return ERROR_NT(NT_STATUS_FILE_IS_A_DIRECTORY);
+                               }
+       
+                               oplock_request = 0;
+                               fsp = open_directory(conn, fname, &sbuf, desired_access, smb_open_mode, smb_ofun, unixmode, &smb_action);
+                               
+                               if(!fsp) {
+                                       restore_case_semantics(file_attributes);
+                                       set_bad_path_error(errno, bad_path);
+                                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+                               }
+                       } else {
+                               restore_case_semantics(file_attributes);
+                               set_bad_path_error(errno, bad_path);
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
+               } 
   
-      file_len = sbuf.st_size;
-      fmode = dos_mode(conn,fname,&sbuf);
-      if(fmode == 0)
-        fmode = FILE_ATTRIBUTE_NORMAL;
-
-      if (fmode & aDIR) {
-        close_file(fsp,False);
-        restore_case_semantics(file_attributes);
-        return(ERROR(ERRDOS,ERRnoaccess));
-      } 
-
-      /* 
-       * If the caller set the extended oplock request bit
-       * and we granted one (by whatever means) - set the
-       * correct bit for extended oplock reply.
-       */
+               file_len = sbuf.st_size;
+               fmode = dos_mode(conn,fname,&sbuf);
+               if(fmode == 0)
+                       fmode = FILE_ATTRIBUTE_NORMAL;
+
+               if (fmode & aDIR) {
+                       close_file(fsp,False);
+                       restore_case_semantics(file_attributes);
+                       return ERROR_DOS(ERRDOS,ERRnoaccess);
+               
+
+               /* 
+                * If the caller set the extended oplock request bit
+                * and we granted one (by whatever means) - set the
+                * correct bit for extended oplock reply.
+                */
     
-      if (oplock_request && lp_fake_oplocks(SNUM(conn)))
-        smb_action |= EXTENDED_OPLOCK_GRANTED;
+               if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+                       smb_action |= EXTENDED_OPLOCK_GRANTED;
   
-      if(oplock_request && fsp->granted_oplock)
-        smb_action |= EXTENDED_OPLOCK_GRANTED;
-    }
-  }
-
-  restore_case_semantics(file_attributes);
-
-  /* Realloc the size of parameters and data we will return */
-  params = *ppparams = Realloc(*ppparams, 69);
-  if(params == NULL)
-    return(ERROR(ERRDOS,ERRnomem));
-
-  p = params;
-  SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? 1 : 0));
-  p += 2;
-  if (IS_IPC(conn)) {
-         SSVAL(p,0,pnum);
-  } else {
-         SSVAL(p,0,fsp->fnum);
-  }
-  p += 2;
-  SIVAL(p,0,smb_action);
-  p += 8;
-
-  if (IS_IPC(conn)) {
-    /*
-     * Deal with pipe return.
-     */  
-    p += 32;
-    SIVAL(p,0,FILE_ATTRIBUTE_NORMAL); /* File Attributes. */
-    p += 20;
-    /* File type. */
-    SSVAL(p,0,FILE_TYPE_MESSAGE_MODE_PIPE);
-    /* Device state. */
-    SSVAL(p,2, 0x5FF); /* ? */
-  } else {
-    /*
-     * Deal with file return.
-     */
-    /* Create time. */
-    put_long_date(p,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
-    p += 8;
-    put_long_date(p,sbuf.st_atime); /* access time */
-    p += 8;
-    put_long_date(p,sbuf.st_mtime); /* write time */
-    p += 8;
-    put_long_date(p,sbuf.st_mtime); /* change time */
-    p += 8;
-    SIVAL(p,0,fmode); /* File Attributes. */
-    p += 4;
-    SOFF_T(p,0,file_len);
-    p += 8;
-    SOFF_T(p,0,file_len);
-  }
-
-  /* Send the required number of replies */
-  send_nt_replies(outbuf, bufsize, params, 69, *ppdata, 0);
-
-  return -1;
+               if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+                       smb_action |= EXTENDED_OPLOCK_GRANTED;
+       }
+
+       /*
+        * Now try and apply the desired SD.
+        */
+
+       if (sd_len && !NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, sd_len, ALL_SECURITY_INFORMATION))) {
+               close_file(fsp,False);
+               restore_case_semantics(file_attributes);
+               return ERROR_NT(nt_status);
+       }
+       
+       restore_case_semantics(file_attributes);
+
+       /* Realloc the size of parameters and data we will return */
+       params = Realloc(*ppparams, 69);
+       if(params == NULL)
+               return ERROR_DOS(ERRDOS,ERRnomem);
+
+       *ppparams = params;
+
+       memset((char *)params,'\0',69);
+
+       p = params;
+       if (smb_action & EXTENDED_OPLOCK_GRANTED)       
+               SCVAL(p,0, BATCH_OPLOCK_RETURN);
+       else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+               SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+       else
+               SCVAL(p,0,NO_OPLOCK_RETURN);
+       
+       p += 2;
+       SSVAL(p,0,fsp->fnum);
+       p += 2;
+       SIVAL(p,0,smb_action);
+       p += 8;
+
+       /* Create time. */
+       c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+       if (lp_dos_filetime_resolution(SNUM(conn))) {
+               c_time &= ~1;
+               sbuf.st_atime &= ~1;
+               sbuf.st_mtime &= ~1;
+               sbuf.st_mtime &= ~1;
+       }
+
+       put_long_date(p,c_time);
+       p += 8;
+       put_long_date(p,sbuf.st_atime); /* access time */
+       p += 8;
+       put_long_date(p,sbuf.st_mtime); /* write time */
+       p += 8;
+       put_long_date(p,sbuf.st_mtime); /* change time */
+       p += 8;
+       SIVAL(p,0,fmode); /* File Attributes. */
+       p += 4;
+       SOFF_T(p, 0, get_allocation_size(&sbuf));
+       p += 8;
+       SOFF_T(p,0,file_len);
+
+       DEBUG(5,("call_nt_transact_create: open name = %s\n", fname));
+
+       /* Send the required number of replies */
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 69, *ppdata, 0);
+
+       return -1;
 }
 
 /****************************************************************************
  Reply to a NT CANCEL request.
 ****************************************************************************/
+
 int reply_ntcancel(connection_struct *conn,
                   char *inbuf,char *outbuf,int length,int bufsize)
 {
@@ -1125,572 +1319,538 @@ int reply_ntcancel(connection_struct *conn,
         */
        
        int mid = SVAL(inbuf,smb_mid);
+       START_PROFILE(SMBntcancel);
        remove_pending_change_notify_requests_by_mid(mid);
        remove_pending_lock_requests_by_mid(mid);
        
        DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", mid));
 
+       END_PROFILE(SMBntcancel);
        return(-1);
 }
 
 /****************************************************************************
  Reply to an unsolicited SMBNTtranss - just ignore it!
 ****************************************************************************/
+
 int reply_nttranss(connection_struct *conn,
                   char *inbuf,char *outbuf,int length,int bufsize)
 {
+       START_PROFILE(SMBnttranss);
        DEBUG(4,("Ignoring nttranss of length %d\n",length));
+       END_PROFILE(SMBnttranss);
        return(-1);
 }
 
 /****************************************************************************
- Reply to an NT transact rename command.
+ Reply to a notify change - queue the request and 
+ don't allow a directory to be opened.
 ****************************************************************************/
-static int call_nt_transact_rename(connection_struct *conn,
-                                  char *inbuf, char *outbuf, int length, 
-                                   int bufsize,
-                                   char **ppsetup, char **ppparams, char **ppdata)
-{
-  char *params = *ppparams;
-  pstring new_name;
-  files_struct *fsp = file_fsp(params, 0);
-  BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
-  uint32 fname_len = MIN((((uint32)IVAL(inbuf,smb_nt_TotalParameterCount)-4)),
-                         ((uint32)sizeof(new_name)-1));
-  int outsize = 0;
-
-  CHECK_FSP(fsp, conn);
-  StrnCpy(new_name,params+4,fname_len);
-  new_name[fname_len] = '\0';
-
-  outsize = rename_internals(conn, inbuf, outbuf, fsp->fsp_name,
-                             new_name, replace_if_exists);
-  if(outsize == 0) {
-    /*
-     * Rename was successful.
-     */
-    send_nt_replies(outbuf, bufsize, NULL, 0, NULL, 0);
-
-    DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", 
-          fsp->fsp_name, new_name));
-
-    outsize = -1;
-  }
-
-  return(outsize);
-}
-   
-/****************************************************************************
- This is the structure to queue to implement NT change
- notify. It consists of smb_size bytes stored from the
- transact command (to keep the mid, tid etc around).
- Plus the fid to examine and the time to check next.
-*****************************************************************************/
-
-typedef struct {
-  ubi_slNode msg_next;
-  files_struct *fsp;
-  connection_struct *conn;
-  time_t next_check_time;
-  time_t modify_time; /* Info from the directory we're monitoring. */ 
-  time_t status_time; /* Info from the directory we're monitoring. */
-  char request_buf[smb_size];
-} change_notify_buf;
-
-static ubi_slList change_notify_queue = { NULL, (ubi_slNodePtr)&change_notify_queue, 0};
-
-/****************************************************************************
- Setup the common parts of the return packet and send it.
-*****************************************************************************/
 
-static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
+static int call_nt_transact_notify_change(connection_struct *conn,
+                                  char *inbuf, char *outbuf, int length,
+                                  int bufsize, 
+                                  char **ppsetup, 
+                                  char **ppparams, char **ppdata)
 {
-  extern int Client;
-  char outbuf[smb_size+38];
+       char *setup = *ppsetup;
+       files_struct *fsp;
+       uint32 flags;
 
-  memset(outbuf, '\0', sizeof(outbuf));
-  construct_reply_common(inbuf, outbuf);
+       fsp = file_fsp(setup,4);
+       flags = IVAL(setup, 0);
 
-  /*
-   * If we're returning a 'too much in the directory changed' we need to
-   * set this is an NT error status flags. If we don't then the (probably
-   * untested) code in the NT redirector has a bug in that it doesn't re-issue
-   * the change notify.... Ah - I *love* it when I get so deeply into this I
-   * can even determine how MS failed to test stuff and why.... :-). JRA.
-   */
+       DEBUG(3,("call_nt_transact_notify_change\n"));
 
-  if(error_class == 0) /* NT Error. */
-    SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+       if(!fsp)
+               return ERROR_DOS(ERRDOS,ERRbadfid);
 
-  ERROR(error_class,error_code);
+       if((!fsp->is_directory) || (conn != fsp->conn))
+               return ERROR_DOS(ERRDOS,ERRbadfid);
 
-  /*
-   * Seems NT needs a transact command with an error code
-   * in it. This is a longer packet than a simple error.
-   */
-  set_message(outbuf,18,0,False);
+       if (!change_notify_set(inbuf, fsp, conn, flags))
+               return(UNIXERROR(ERRDOS,ERRbadfid));
 
-  send_smb(Client,outbuf);
-}
+       DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
+name = %s\n", fsp->fsp_name ));
 
-/****************************************************************************
- Delete entries by fnum from the change notify pending queue.
-*****************************************************************************/
-void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  while(cnbp != NULL) {
-    if(cnbp->fsp->fnum == fsp->fnum) {
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
+       return -1;
 }
 
 /****************************************************************************
Delete entries by mid from the change notify pending queue. Always send reply.
-*****************************************************************************/
Reply to an NT transact rename command.
+****************************************************************************/
 
-static void remove_pending_change_notify_requests_by_mid(int mid)
+static int call_nt_transact_rename(connection_struct *conn,
+                                  char *inbuf, char *outbuf, int length, 
+                                   int bufsize,
+                                   char **ppsetup, char **ppparams, char **ppdata)
 {
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  while(cnbp != NULL) {
-    if(SVAL(cnbp->request_buf,smb_mid) == mid) {
-      change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_CANCELLED);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-}
+       char *params = *ppparams;
+       pstring new_name;
+       files_struct *fsp = file_fsp(params, 0);
+       BOOL replace_if_exists = (SVAL(params,2) & RENAME_REPLACE_IF_EXISTS) ? True : False;
+       NTSTATUS status;
 
-/****************************************************************************
- Process the change notify queue. Note that this is only called as root.
-*****************************************************************************/
+       CHECK_FSP(fsp, conn);
+       srvstr_pull(inbuf, new_name, params+4, sizeof(new_name), -1, STR_TERMINATE);
 
-void process_pending_change_notify_queue(time_t t)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  if(cnbp == NULL)
-    return;
-
-  if(cnbp->next_check_time >= t)
-    return;
-
-  /*
-   * It's time to check. Go through the queue and see if
-   * the timestamps changed.
-   */
-
-  while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
-    SMB_STRUCT_STAT st;
-    files_struct *fsp = cnbp->fsp;
-    connection_struct *conn = cnbp->conn;
-    uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : 
-                  SVAL(cnbp->request_buf,smb_uid);
-
-    /*
-     * Ensure we don't have any old chain_fsp values
-     * sitting around....
-     */
-    chain_size = 0;
-    file_chain_reset();
-
-    if(!become_user(conn,vuid)) {
-      DEBUG(0,("process_pending_change_notify_queue: Unable to become user vuid=%d.\n",
-            vuid ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    if(!become_service(conn,True)) {
-           DEBUG(0,("process_pending_change_notify_queue: Unable to become service Error was %s.\n", strerror(errno) ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False), &st) < 0) {
-      DEBUG(0,("process_pending_change_notify_queue: Unable to stat directory %s. \
-Error was %s.\n", fsp->fsp_name, strerror(errno) ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    if(cnbp->modify_time != st.st_mtime ||
-       cnbp->status_time != st.st_ctime) {
-      /*
-       * Remove the entry and return a change notify to the client.
-       */
-      DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed\n",
-            fsp->fsp_name ));
-      change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    unbecome_user();
-
-    /*
-     * Move to the next in the list.
-     */
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-}
+       status = rename_internals(conn, fsp->fsp_name,
+                                 new_name, replace_if_exists);
+       if (!NT_STATUS_IS_OK(status))
+               return ERROR_NT(status);
 
-/****************************************************************************
- Reply to a notify change - queue the request and 
- don't allow a directory to be opened.
-****************************************************************************/
-static int call_nt_transact_notify_change(connection_struct *conn,
-                                         char *inbuf, char *outbuf, int length,
-                                          int bufsize, 
-                                          char **ppsetup, 
-                                         char **ppparams, char **ppdata)
-{
-  char *setup = *ppsetup;
-  files_struct *fsp;
-  change_notify_buf *cnbp;
-  SMB_STRUCT_STAT st;
-
-  fsp = file_fsp(setup,4);
-
-  DEBUG(3,("call_nt_transact_notify_change\n"));
-
-  if(!fsp)
-    return(ERROR(ERRDOS,ERRbadfid));
-
-  if((!fsp->open) || (!fsp->is_directory) || (conn != fsp->conn))
-    return(ERROR(ERRDOS,ERRbadfid));
-
-  /*
-   * Now queue an entry on the notify change stack. We timestamp
-   * the entry we are adding so that we know when to scan next.
-   * We only need to save smb_size bytes from this incoming packet
-   * as we will always by returning a 'read the directory yourself'
-   * error.
-   */
-
-  if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
-    DEBUG(0,("call_nt_transact_notify_change: Malloc fail (2) !\n" ));
-    return -1;
-  }
-
-  /* 
-   * Store the current timestamp on the directory we are monitoring.
-   */
-
-  if(fsp->conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name, False), &st) < 0) {
-    DEBUG(0,("call_nt_transact_notify_change: Unable to stat name = %s. \
-Error was %s\n", fsp->fsp_name, strerror(errno) ));
-    free((char *)cnbp);
-    return(UNIXERROR(ERRDOS,ERRbadfid));
-  }
-  memcpy(cnbp->request_buf, inbuf, smb_size);
-  cnbp->fsp = fsp;
-  cnbp->conn = conn;
-  cnbp->modify_time = st.st_mtime;
-  cnbp->status_time = st.st_ctime;
+       /*
+        * Rename was successful.
+        */
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+       
+       DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", 
+                fsp->fsp_name, new_name));
+       
+       /*
+        * Win2k needs a changenotify request response before it will
+        * update after a rename..
+        */
+       
+       process_pending_change_notify_queue((time_t)0);
 
-  cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
+       return -1;
+}
 
-  /*
-   * Adding to the tail enables us to check only
-   * the head when scanning for change, as this entry
-   * is forced to have the first timeout expiration.
-   */
+/******************************************************************************
+ Fake up a completely empty SD.
+*******************************************************************************/
 
-  ubi_slAddTail(&change_notify_queue, cnbp);
+static size_t get_null_nt_acl(TALLOC_CTX *mem_ctx, SEC_DESC **ppsd)
+{
+       extern DOM_SID global_sid_World;
+       size_t sd_size;
 
-  DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
-name = %s\n", fsp->fsp_name ));
+       *ppsd = make_standard_sec_desc( mem_ctx, &global_sid_World, &global_sid_World, NULL, &sd_size);
+       if(!*ppsd) {
+               DEBUG(0,("get_null_nt_acl: Unable to malloc space for security descriptor.\n"));
+               sd_size = 0;
+       }
 
-  return -1;
+       return sd_size;
 }
 
 /****************************************************************************
  Reply to query a security descriptor - currently this is not implemented (it
- is planned to be though).
+ is planned to be though). Right now it just returns the same thing NT would
+ when queried on a FAT filesystem. JRA.
 ****************************************************************************/
+
 static int call_nt_transact_query_security_desc(connection_struct *conn,
-                                               char *inbuf, char *outbuf, 
-                                               int length, 
-                                                int bufsize, 
+                                                char *inbuf, char *outbuf, 
+                                                int length, int bufsize, 
                                                 char **ppsetup, char **ppparams, char **ppdata)
 {
-  static BOOL logged_message = False;
+       uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+       char *params = *ppparams;
+       char *data = *ppdata;
+       prs_struct pd;
+       SEC_DESC *psd = NULL;
+       size_t sd_size;
+       TALLOC_CTX *mem_ctx;
+
+       files_struct *fsp = file_fsp(params,0);
+
+       if(!fsp)
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+
+       DEBUG(3,("call_nt_transact_query_security_desc: file = %s\n", fsp->fsp_name ));
+
+       params = Realloc(*ppparams, 4);
+       if(params == NULL)
+               return ERROR_DOS(ERRDOS,ERRnomem);
+
+       *ppparams = params;
+
+       if ((mem_ctx = talloc_init()) == NULL) {
+               DEBUG(0,("call_nt_transact_query_security_desc: talloc_init failed.\n"));
+               return ERROR_DOS(ERRDOS,ERRnomem);
+       }
+
+       /*
+        * Get the permissions to return.
+        */
+
+       if (!lp_nt_acl_support(SNUM(conn)))
+               sd_size = get_null_nt_acl(mem_ctx, &psd);
+       else
+               sd_size = conn->vfs_ops.fget_nt_acl(fsp, fsp->fd, &psd);
+
+       if (sd_size == 0) {
+               talloc_destroy(mem_ctx);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       DEBUG(3,("call_nt_transact_query_security_desc: sd_size = %d.\n",(int)sd_size));
+
+       SIVAL(params,0,(uint32)sd_size);
+
+       if(max_data_count < sd_size) {
+
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_BUFFER_TOO_SMALL,
+                       params, 4, *ppdata, 0);
+               talloc_destroy(mem_ctx);
+               return -1;
+       }
+
+       /*
+        * Allocate the data we will point this at.
+        */
+
+       data = Realloc(*ppdata, sd_size);
+       if(data == NULL) {
+               talloc_destroy(mem_ctx);
+               return ERROR_DOS(ERRDOS,ERRnomem);
+       }
+
+       *ppdata = data;
 
-  if(!logged_message) {
-    DEBUG(0,("call_nt_transact_query_security_desc: Currently not implemented.\n"));
-    logged_message = True; /* Only print this once... */
-  }
+       memset(data, '\0', sd_size);
 
-  return(ERROR(ERRSRV,ERRnosupport));
+       /*
+        * Init the parse struct we will marshall into.
+        */
+
+       prs_init(&pd, 0, mem_ctx, MARSHALL);
+
+       /*
+        * Setup the prs_struct to point at the memory we just
+        * allocated.
+        */
+
+       prs_give_memory( &pd, data, (uint32)sd_size, False);
+
+       /*
+        * Finally, linearize into the outgoing buffer.
+        */
+
+       if(!sec_io_desc( "sd data", &psd, &pd, 1)) {
+               DEBUG(0,("call_nt_transact_query_security_desc: Error in marshalling \
+security descriptor.\n"));
+               /*
+                * Return access denied for want of a better error message..
+                */ 
+               talloc_destroy(mem_ctx);
+               return(UNIXERROR(ERRDOS,ERRnoaccess));
+       }
+
+       /*
+        * Now we can delete the security descriptor.
+        */
+
+       talloc_destroy(mem_ctx);
+
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, params, 4, data, (int)sd_size);
+       return -1;
 }
-   
+
 /****************************************************************************
- Reply to set a security descriptor - currently this is not implemented (it
- is planned to be though).
+ Reply to set a security descriptor. Map to UNIX perms.
 ****************************************************************************/
+
 static int call_nt_transact_set_security_desc(connection_struct *conn,
-                                             char *inbuf, char *outbuf, 
-                                             int length,
-                                              int bufsize, 
-                                              char **ppsetup, 
-                                             char **ppparams, char **ppdata)
+                                                                       char *inbuf, char *outbuf, int length,
+                                                                       int bufsize, char **ppsetup, 
+                                                                       char **ppparams, char **ppdata)
 {
-  static BOOL logged_message = False;
+       uint32 total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+       char *params= *ppparams;
+       char *data = *ppdata;
+       uint32 total_data_count = (uint32)IVAL(inbuf, smb_nts_TotalDataCount);
+       files_struct *fsp = NULL;
+       uint32 security_info_sent = 0;
+       NTSTATUS nt_status;
+
+       if(total_parameter_count < 8)
+               return ERROR_DOS(ERRDOS,ERRbadfunc);
+
+       if((fsp = file_fsp(params,0)) == NULL)
+               return ERROR_DOS(ERRDOS,ERRbadfid);
+
+       if(!lp_nt_acl_support(SNUM(conn)))
+               goto done;
+
+       security_info_sent = IVAL(params,4);
+
+       DEBUG(3,("call_nt_transact_set_security_desc: file = %s, sent 0x%x\n", fsp->fsp_name,
+               (unsigned int)security_info_sent ));
 
-  if(!logged_message) {
-    DEBUG(0,("call_nt_transact_set_security_desc: Currently not implemented.\n"));
-    logged_message = True; /* Only print this once... */
-  }
-  return(ERROR(ERRSRV,ERRnosupport));
+       if (total_data_count == 0)
+               return ERROR_DOS(ERRDOS, ERRbadaccess);
+
+       if (!NT_STATUS_IS_OK(nt_status = set_sd( fsp, data, total_data_count, security_info_sent)))
+               return ERROR_NT(nt_status);
+
+  done:
+
+       send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+       return -1;
 }
    
 /****************************************************************************
- Reply to IOCTL - not implemented - no plans.
+ Reply to NT IOCTL
 ****************************************************************************/
 static int call_nt_transact_ioctl(connection_struct *conn,
                                  char *inbuf, char *outbuf, int length,
                                   int bufsize, 
-                                  char **ppsetup, char **ppparams, char **ppdata)
+                                  char **ppsetup, int setup_count,
+                                 char **ppparams, int parameter_count,
+                                 char **ppdata, int data_count)
 {
-  static BOOL logged_message = False;
+       unsigned fnum, control;
+       static BOOL logged_message;
 
-  if(!logged_message) {
-    DEBUG(0,("call_nt_transact_ioctl: Currently not implemented.\n"));
-    logged_message = True; /* Only print this once... */
-  }
-  return(ERROR(ERRSRV,ERRnosupport));
+       if (setup_count != 8) {
+               DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count));
+               return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+       }
+
+       fnum = SVAL(*ppsetup, 4);
+       control = IVAL(*ppsetup, 0);
+
+       DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n", 
+                fnum, control));
+
+       switch (control) {
+       case NTIOCTL_SET_SPARSE:
+               /* pretend this succeeded - tho strictly we should
+                  mark the file sparse (if the local fs supports it)
+                  so we can know if we need to pre-allocate or not */
+               send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
+               return -1;
+
+       default:
+               if (!logged_message) {
+                       logged_message = True; /* Only print this once... */
+                       DEBUG(3,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n",
+                                control));
+               }
+       }
+
+       return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
 }
    
 /****************************************************************************
  Reply to a SMBNTtrans.
 ****************************************************************************/
+
 int reply_nttrans(connection_struct *conn,
-                 char *inbuf,char *outbuf,int length,int bufsize)
+                       char *inbuf,char *outbuf,int length,int bufsize)
 {
-  int  outsize = 0;
+       int  outsize = 0;
 #if 0 /* Not used. */
-  uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
-  uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
-  uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
+       uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
+       uint32 max_parameter_count = IVAL(inbuf, smb_nt_MaxParameterCount);
+       uint32 max_data_count = IVAL(inbuf,smb_nt_MaxDataCount);
 #endif /* Not used. */
-  uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
-  uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
-  uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
-  uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
-  uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
-  uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
-  uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
-  uint16 function_code = SVAL( inbuf, smb_nt_Function);
-  char *params = NULL, *data = NULL, *setup = NULL;
-  uint32 num_params_sofar, num_data_sofar;
-
-  if(global_oplock_break && (function_code == NT_TRANSACT_CREATE)) {
-    /*
-     * Queue this open message as we are the process of an oplock break.
-     */
-
-    DEBUG(2,("reply_nttrans: queueing message NT_TRANSACT_CREATE \
-due to being in oplock break state.\n" ));
-
-    push_oplock_pending_smb_message( inbuf, length);
-    return -1;
-  }
-
-  outsize = set_message(outbuf,0,0,True);
-
-  /* 
-   * All nttrans messages we handle have smb_wct == 19 + setup_count.
-   * Ensure this is so as a sanity check.
-   */
-
-  if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
-    DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
-          CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
-    return(ERROR(ERRSRV,ERRerror));
-  }
+       uint32 total_parameter_count = IVAL(inbuf, smb_nt_TotalParameterCount);
+       uint32 total_data_count = IVAL(inbuf, smb_nt_TotalDataCount);
+       uint32 parameter_count = IVAL(inbuf,smb_nt_ParameterCount);
+       uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
+       uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
+       uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
+       uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
+       uint16 function_code = SVAL( inbuf, smb_nt_Function);
+       char *params = NULL, *data = NULL, *setup = NULL;
+       uint32 num_params_sofar, num_data_sofar;
+       START_PROFILE(SMBnttrans);
+
+       if(global_oplock_break &&
+                       ((function_code == NT_TRANSACT_CREATE) ||
+                        (function_code == NT_TRANSACT_RENAME))) {
+               /*
+                * Queue this open message as we are the process of an oplock break.
+                */
+
+               DEBUG(2,("reply_nttrans: queueing message code 0x%x \
+due to being in oplock break state.\n", (unsigned int)function_code ));
+
+               push_oplock_pending_smb_message( inbuf, length);
+               END_PROFILE(SMBnttrans);
+               return -1;
+       }
+
+       if (IS_IPC(conn) && (function_code != NT_TRANSACT_CREATE)) {
+               END_PROFILE(SMBnttrans);
+               return ERROR_DOS(ERRSRV,ERRaccess);
+       }
+
+       outsize = set_message(outbuf,0,0,True);
+
+       /* 
+        * All nttrans messages we handle have smb_wct == 19 + setup_count.
+        * Ensure this is so as a sanity check.
+        */
+
+       if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
+               DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
+                       CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
+               END_PROFILE(SMBnttrans);
+               return ERROR_DOS(ERRSRV,ERRerror);
+       }
     
-  /* Allocate the space for the setup, the maximum needed parameters and data */
-
-  if(setup_count > 0)
-    setup = (char *)malloc(setup_count);
-  if (total_parameter_count > 0)
-    params = (char *)malloc(total_parameter_count);
-  if (total_data_count > 0)
-    data = (char *)malloc(total_data_count);
+       /* Allocate the space for the setup, the maximum needed parameters and data */
+
+       if(setup_count > 0)
+               setup = (char *)malloc(setup_count);
+       if (total_parameter_count > 0)
+               params = (char *)malloc(total_parameter_count);
+       if (total_data_count > 0)
+               data = (char *)malloc(total_data_count);
  
-  if ((total_parameter_count && !params)  || (total_data_count && !data) ||
-      (setup_count && !setup)) {
-    DEBUG(0,("reply_nttrans : Out of memory\n"));
-    return(ERROR(ERRDOS,ERRnomem));
-  }
-
-  /* Copy the param and data bytes sent with this request into
-     the params buffer */
-  num_params_sofar = parameter_count;
-  num_data_sofar = data_count;
-
-  if (parameter_count > total_parameter_count || data_count > total_data_count)
-    exit_server("reply_nttrans: invalid sizes in packet.\n");
-
-  if(setup) {
-    memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
-    DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
-    dump_data(10, setup, setup_count);
-  }
-  if(params) {
-    memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
-    DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
-    dump_data(10, params, parameter_count);
-  }
-  if(data) {
-    memcpy( data, smb_base(inbuf) + data_offset, data_count);
-    DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
-    dump_data(10, data, data_count);
-  }
-
-  if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
-    /* We need to send an interim response then receive the rest
-       of the parameter/data bytes */
-    outsize = set_message(outbuf,0,0,True);
-    send_smb(Client,outbuf);
-
-    while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
-      BOOL ret;
-
-      ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
-      if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
-        outsize = set_message(outbuf,0,0,True);
-        if(ret) {
-               DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
-        } else {
-               DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
-                        (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
+       if ((total_parameter_count && !params)  || (total_data_count && !data) ||
+                               (setup_count && !setup)) {
+               SAFE_FREE(setup);
+               SAFE_FREE(params);
+               SAFE_FREE(data);
+               DEBUG(0,("reply_nttrans : Out of memory\n"));
+               END_PROFILE(SMBnttrans);
+               return ERROR_DOS(ERRDOS,ERRnomem);
        }
-        if(params)
-          free(params);
-        if(data)
-          free(data);
-        if(setup)
-          free(setup);
-        return(ERROR(ERRSRV,ERRerror));
-      }
+
+       /* Copy the param and data bytes sent with this request into the params buffer */
+       num_params_sofar = parameter_count;
+       num_data_sofar = data_count;
+
+       if (parameter_count > total_parameter_count || data_count > total_data_count)
+               exit_server("reply_nttrans: invalid sizes in packet.");
+
+       if(setup) {
+               memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
+               DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
+               dump_data(10, setup, setup_count);
+       }
+       if(params) {
+               memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
+               DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
+               dump_data(10, params, parameter_count);
+       }
+       if(data) {
+               memcpy( data, smb_base(inbuf) + data_offset, data_count);
+               DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
+               dump_data(10, data, data_count);
+       }
+
+       if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
+               /* We need to send an interim response then receive the rest
+                       of the parameter/data bytes */
+               outsize = set_message(outbuf,0,0,True);
+               if (!send_smb(smbd_server_fd(),outbuf))
+                       exit_server("reply_nttrans: send_smb failed.");
+
+               while( num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
+                       BOOL ret;
+
+                       ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+
+                       if((ret && (CVAL(inbuf, smb_com) != SMBnttranss)) || !ret) {
+                               outsize = set_message(outbuf,0,0,True);
+                               if(ret) {
+                                       DEBUG(0,("reply_nttrans: Invalid secondary nttrans packet\n"));
+                               } else {
+                                       DEBUG(0,("reply_nttrans: %s in getting secondary nttrans response.\n",
+                                               (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
+                               }
+                               SAFE_FREE(params);
+                               SAFE_FREE(data);
+                               SAFE_FREE(setup);
+                               END_PROFILE(SMBnttrans);
+                               return ERROR_DOS(ERRSRV,ERRerror);
+                       }
       
-      /* Revise total_params and total_data in case they have changed downwards */
-      total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
-      total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
-      num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount));
-      num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount));
-      if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
-        exit_server("reply_nttrans2: data overflow in secondary nttrans packet\n");
-
-      memcpy( &params[ IVAL(inbuf, smb_nts_ParameterDisplacement)], 
-              smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
-      memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)],
-              smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count);
-    }
-  }
-
-  if (Protocol >= PROTOCOL_NT1) {
-    uint16 flg2 = SVAL(outbuf,smb_flg2);
-    SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
-  }
-
-  /* Now we must call the relevant NT_TRANS function */
-  switch(function_code) {
-    case NT_TRANSACT_CREATE:
-      outsize = call_nt_transact_create(conn, inbuf, outbuf, length, bufsize, 
-                                        &setup, &params, &data);
-      break;
-    case NT_TRANSACT_IOCTL:
-      outsize = call_nt_transact_ioctl(conn, 
-                                      inbuf, outbuf, length, bufsize, 
-                                       &setup, &params, &data);
-      break;
-    case NT_TRANSACT_SET_SECURITY_DESC:
-      outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, 
-                                                  length, bufsize, 
-                                                   &setup, &params, &data);
-      break;
-    case NT_TRANSACT_NOTIFY_CHANGE:
-      outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, 
-                                              length, bufsize, 
-                                               &setup, &params, &data);
-      break;
-    case NT_TRANSACT_RENAME:
-      outsize = call_nt_transact_rename(conn, inbuf, outbuf, length, 
-                                       bufsize, 
-                                        &setup, &params, &data);
-      break;
-
-    case NT_TRANSACT_QUERY_SECURITY_DESC:
-      outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, 
-                                                    length, bufsize, 
-                                                     &setup, &params, &data);
-      break;
-  default:
-         /* Error in request */
-         DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
-         if(setup)
-                 free(setup);
-         if(params)
-                 free(params);
-         if(data)
-                 free(data);
-         return (ERROR(ERRSRV,ERRerror));
-  }
-
-  /* As we do not know how many data packets will need to be
-     returned here the various call_nt_transact_xxxx calls
-     must send their own. Thus a call_nt_transact_xxxx routine only
-     returns a value other than -1 when it wants to send
-     an error packet. 
-  */
-
-  if(setup)
-    free(setup);
-  if(params)
-    free(params);
-  if(data)
-    free(data);
-  return outsize; /* If a correct response was needed the call_nt_transact_xxxx 
-                    calls have already sent it. If outsize != -1 then it is
-                    returning an error packet. */
+                       /* Revise total_params and total_data in case they have changed downwards */
+                       total_parameter_count = IVAL(inbuf, smb_nts_TotalParameterCount);
+                       total_data_count = IVAL(inbuf, smb_nts_TotalDataCount);
+                       num_params_sofar += (parameter_count = IVAL(inbuf,smb_nts_ParameterCount));
+                       num_data_sofar += ( data_count = IVAL(inbuf, smb_nts_DataCount));
+                       if (num_params_sofar > total_parameter_count || num_data_sofar > total_data_count)
+                               exit_server("reply_nttrans2: data overflow in secondary nttrans packet");
+
+                       memcpy( &params[ IVAL(inbuf, smb_nts_ParameterDisplacement)], 
+                               smb_base(inbuf) + IVAL(inbuf, smb_nts_ParameterOffset), parameter_count);
+                       memcpy( &data[IVAL(inbuf, smb_nts_DataDisplacement)],
+                               smb_base(inbuf)+ IVAL(inbuf, smb_nts_DataOffset), data_count);
+               }
+       }
+
+       if (Protocol >= PROTOCOL_NT1)
+               SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_IS_LONG_NAME);
+
+       /* Now we must call the relevant NT_TRANS function */
+       switch(function_code) {
+               case NT_TRANSACT_CREATE:
+                       START_PROFILE_NESTED(NT_transact_create);
+                       outsize = call_nt_transact_create(conn, inbuf, outbuf,
+                                       length, bufsize, 
+                                       &setup, &params, &data);
+                       END_PROFILE_NESTED(NT_transact_create);
+                       break;
+               case NT_TRANSACT_IOCTL:
+                       START_PROFILE_NESTED(NT_transact_ioctl);
+                       outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
+                                                        length, bufsize, 
+                                                        &setup, setup_count,
+                                                        &params, parameter_count, 
+                                                        &data, data_count);
+                       END_PROFILE_NESTED(NT_transact_ioctl);
+                       break;
+               case NT_TRANSACT_SET_SECURITY_DESC:
+                       START_PROFILE_NESTED(NT_transact_set_security_desc);
+                       outsize = call_nt_transact_set_security_desc(conn, inbuf, outbuf, 
+                                       length, bufsize, 
+                                       &setup, &params, &data);
+                       END_PROFILE_NESTED(NT_transact_set_security_desc);
+                       break;
+               case NT_TRANSACT_NOTIFY_CHANGE:
+                       START_PROFILE_NESTED(NT_transact_notify_change);
+                       outsize = call_nt_transact_notify_change(conn, inbuf, outbuf, 
+                                       length, bufsize, 
+                                       &setup, &params, &data);
+                       END_PROFILE_NESTED(NT_transact_notify_change);
+                       break;
+               case NT_TRANSACT_RENAME:
+                       START_PROFILE_NESTED(NT_transact_rename);
+                       outsize = call_nt_transact_rename(conn, inbuf, outbuf,
+                                       length, bufsize,
+                                       &setup, &params, &data);
+                       END_PROFILE_NESTED(NT_transact_rename);
+                       break;
+
+               case NT_TRANSACT_QUERY_SECURITY_DESC:
+                       START_PROFILE_NESTED(NT_transact_query_security_desc);
+                       outsize = call_nt_transact_query_security_desc(conn, inbuf, outbuf, 
+                                       length, bufsize, 
+                                       &setup, &params, &data);
+                       END_PROFILE_NESTED(NT_transact_query_security_desc);
+                       break;
+               default:
+                       /* Error in request */
+                       DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
+                       SAFE_FREE(setup);
+                       SAFE_FREE(params);
+                       SAFE_FREE(data);
+                       END_PROFILE(SMBnttrans);
+                       return ERROR_DOS(ERRSRV,ERRerror);
+       }
+
+       /* As we do not know how many data packets will need to be
+               returned here the various call_nt_transact_xxxx calls
+               must send their own. Thus a call_nt_transact_xxxx routine only
+               returns a value other than -1 when it wants to send
+               an error packet. 
+       */
+
+       SAFE_FREE(setup);
+       SAFE_FREE(params);
+       SAFE_FREE(data);
+       END_PROFILE(SMBnttrans);
+       return outsize; /* If a correct response was needed the call_nt_transact_xxxx 
+                               calls have already sent it. If outsize != -1 then it is
+                               returning an error packet. */
 }