r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[jra/samba/.git] / source3 / smbd / trans2.c
index 23272752c6b894a92254628a0ab798eff17fce6d..7269ab91579a16ae8e0e924ab02b83ffaa696858 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "includes.h"
 
-extern int Protocol;
+extern enum protocol_types Protocol;
 extern int smb_read_error;
 extern fstring local_machine;
 extern int global_oplock_break;
@@ -31,20 +31,43 @@ extern uint32 global_client_caps;
 extern struct current_user current_user;
 
 #define get_file_size(sbuf) ((sbuf).st_size)
+#define DIR_ENTRY_SAFETY_MARGIN 4096
+
+/********************************************************************
+ Roundup a value to the nearest SMB_ROUNDUP_ALLOCATION_SIZE boundary.
+ Only do this for Windows clients.
+********************************************************************/
+
+SMB_BIG_UINT smb_roundup(SMB_BIG_UINT val)
+{
+       /* Only roundup for Windows clients. */
+       enum remote_arch_types ra_type = get_remote_arch();
+       if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+               val = SMB_ROUNDUP(val,SMB_ROUNDUP_ALLOCATION_SIZE);
+       }
+       return val;
+}
+
+/********************************************************************
+ Given a stat buffer return the allocated size on disk, taking into
+ account sparse files.
+********************************************************************/
 
-/* given a stat buffer return the allocated size on disk, taking into
-   account sparse files */
 SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
 {
        SMB_BIG_UINT ret;
+
 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
        ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks;
 #else
        ret = (SMB_BIG_UINT)get_file_size(*sbuf);
 #endif
+
        if (!ret && fsp && fsp->initial_allocation_size)
                ret = fsp->initial_allocation_size;
-       ret = SMB_ROUNDUP(ret,SMB_ROUNDUP_ALLOCATION_SIZE);
+
+       ret = smb_roundup(ret);
+
        return ret;
 }
 
@@ -92,7 +115,7 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
 
  again:
 
-       val = talloc_realloc(mem_ctx, val, attr_size);
+       val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
        if (!val) {
                return False;
        }
@@ -146,8 +169,8 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                return NULL;
        }
 
-       for (i = 0, ea_namelist = talloc(mem_ctx, ea_namelist_size); i < 6;
-                       ea_namelist = talloc_realloc(mem_ctx, ea_namelist, ea_namelist_size), i++) {
+       for (i = 0, ea_namelist = TALLOC(mem_ctx, ea_namelist_size); i < 6;
+                       ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) {
                if (fsp && fsp->fd != -1) {
                        sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size);
                } else {
@@ -173,7 +196,7 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        if (strnequal(p, "system.", 7) || samba_private_attr_name(p))
                                continue;
                
-                       listp = talloc(mem_ctx, sizeof(struct ea_list));
+                       listp = TALLOC_P(mem_ctx, struct ea_list);
                        if (!listp)
                                return NULL;
 
@@ -561,7 +584,8 @@ static int send_trans2_replies(char *outbuf,
 ****************************************************************************/
 
 static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
-                          char **pparams, int total_params, char **ppdata, int total_data)
+                               char **pparams, int total_params, char **ppdata, int total_data,
+                               unsigned int max_data_bytes)
 {
        char *params = *pparams;
        int16 open_mode;
@@ -607,7 +631,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        if (IS_IPC(conn))
                return(ERROR_DOS(ERRSRV,ERRaccess));
 
-       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -618,6 +642,9 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        /* XXXX we need to handle passed times, sattr and flags */
 
        unix_convert(fname,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
     
        if (!check_name(fname,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
@@ -627,6 +654,11 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                oplock_request, &rmode,&smb_action);
       
        if (!fsp) {
+               if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+                       /* We have re-scheduled this call. */
+                       clear_cached_errors();
+                       return -1;
+               }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
@@ -640,7 +672,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        }
 
        /* Realloc the size of parameters and data we will return */
-       params = Realloc(*pparams, 28);
+       params = SMB_REALLOC(*pparams, 28);
        if( params == NULL )
                return(ERROR_DOS(ERRDOS,ERRnomem));
        *pparams = params;
@@ -725,32 +757,6 @@ static uint32 unix_filetype(mode_t mode)
        return UNIX_TYPE_UNKNOWN;
 }
 
-/****************************************************************************
- Return the major devicenumber for UNIX extensions.
-****************************************************************************/
-
-static uint32 unix_dev_major(SMB_DEV_T dev)
-{
-#if defined(HAVE_DEVICE_MAJOR_FN)
-       return (uint32)major(dev);
-#else
-       return (uint32)(dev >> 8);
-#endif
-}
-
-/****************************************************************************
- Return the minor devicenumber for UNIX extensions.
-****************************************************************************/
-
-static uint32 unix_dev_minor(SMB_DEV_T dev)
-{
-#if defined(HAVE_DEVICE_MINOR_FN)
-       return (uint32)minor(dev);
-#else
-       return (uint32)(dev & 0xff);
-#endif
-}
-
 /****************************************************************************
  Map wire perms onto standard UNIX permissions. Obey share restrictions.
 ****************************************************************************/
@@ -957,8 +963,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                adate &= ~1;
                        }
 
-                       if(mode & aDIR)
+                       if(mode & aDIR) {
+                               /* This is necessary, as otherwise the
+                                * desktop.ini file in this folder is
+                                * ignored */
+                               mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
                                file_size = 0;
+                       }
 
                        DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
          
@@ -1312,21 +1323,22 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 ****************************************************************************/
 
 static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
-                               char **pparams, int total_params, char **ppdata, int total_data)
+                               char **pparams, int total_params, char **ppdata, int total_data,
+                               unsigned int max_data_bytes)
 {
        /* We must be careful here that we don't return more than the
                allowed number of data bytes. If this means returning fewer than
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
-       uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        int dirtype = SVAL(params,0);
        int maxentries = SVAL(params,2);
-       BOOL close_after_first = BITSETW(params+4,0);
-       BOOL close_if_end = BITSETW(params+4,1);
-       BOOL requires_resume_key = BITSETW(params+4,2);
+       uint16 findfirst_flags = SVAL(params,4);
+       BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
+       BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+       BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
        int info_level = SVAL(params,6);
        pstring directory;
        pstring mask;
@@ -1352,7 +1364,12 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
                info_level, max_data_bytes));
-  
+
+       if (!maxentries) {
+               /* W2K3 seems to treat zero as 1. */
+               maxentries = 1;
+       }
        switch (info_level) {
                case SMB_INFO_STANDARD:
                case SMB_INFO_QUERY_EA_SIZE:
@@ -1371,7 +1388,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                        return(ERROR_DOS(ERRDOS,ERRunknownlevel));
        }
 
-       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -1379,6 +1396,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
        if(!check_name(directory,conn)) {
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
        }
@@ -1398,15 +1418,15 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
 
        DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
 
-       pdata = Realloc(*ppdata, max_data_bytes + 1024);
+       pdata = SMB_REALLOC(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if( pdata == NULL )
                return(ERROR_DOS(ERRDOS,ERRnomem));
 
        *ppdata = pdata;
-       memset((char *)pdata,'\0',max_data_bytes + 1024);
+       memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 
        /* Realloc the params space */
-       params = Realloc(*pparams, 10);
+       params = SMB_REALLOC(*pparams, 10);
        if (params == NULL)
                return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
@@ -1418,7 +1438,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        /* Save the wildcard match and attribs we are using on this directory - 
                needed as lanman2 assumes these are being saved between calls */
 
-       if(!(wcard = strdup(mask))) {
+       if(!(wcard = SMB_STRDUP(mask))) {
                dptr_close(&dptr_num);
                return ERROR_DOS(ERRDOS,ERRnomem);
        }
@@ -1528,24 +1548,25 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
 ****************************************************************************/
 
 static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        /* We must be careful here that we don't return more than the
                allowed number of data bytes. If this means returning fewer than
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        int dptr_num = SVAL(params,0);
        int maxentries = SVAL(params,2);
        uint16 info_level = SVAL(params,4);
        uint32 resume_key = IVAL(params,6);
-       BOOL close_after_request = BITSETW(params+10,0);
-       BOOL close_if_end = BITSETW(params+10,1);
-       BOOL requires_resume_key = BITSETW(params+10,2);
-       BOOL continue_bit = BITSETW(params+10,3);
+       uint16 findnext_flags = SVAL(params,10);
+       BOOL close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
+       BOOL close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+       BOOL requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+       BOOL continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
        pstring resume_name;
        pstring mask;
        pstring directory;
@@ -1564,7 +1585,7 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
 
        *mask = *directory = *resume_name = 0;
 
-       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus);
+       srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                return ERROR_NT(ntstatus);
        }
@@ -1575,6 +1596,11 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
                requires_resume_key, resume_key, resume_name, continue_bit, info_level));
 
+       if (!maxentries) {
+               /* W2K3 seems to treat zero as 1. */
+               maxentries = 1;
+       }
+
        switch (info_level) {
                case SMB_INFO_STANDARD:
                case SMB_INFO_QUERY_EA_SIZE:
@@ -1591,15 +1617,15 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
 
-       pdata = Realloc( *ppdata, max_data_bytes + 1024);
+       pdata = SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if(pdata == NULL)
                return ERROR_DOS(ERRDOS,ERRnomem);
 
        *ppdata = pdata;
-       memset((char *)pdata,'\0',max_data_bytes + 1024);
+       memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 
        /* Realloc the params space */
-       params = Realloc(*pparams, 6*SIZEOFWORD);
+       params = SMB_REALLOC(*pparams, 6*SIZEOFWORD);
        if( params == NULL )
                return ERROR_DOS(ERRDOS,ERRnomem);
 
@@ -1644,7 +1670,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
         * depend on the last file name instead.
         */
 
-       if(requires_resume_key && *resume_name && !continue_bit) {
+       if(*resume_name && !continue_bit) {
 
                /*
                 * Fix for NT redirector problem triggered by resume key indexes
@@ -1696,7 +1722,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                if(current_pos < 0) {
                        DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
                        SeekDir(dirptr, start_pos);
-                       for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) {
+                       for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
 
                                /*
                                 * Remember, mangle_map is called by
@@ -1719,7 +1745,11 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                                }
                        } /* end for */
                } /* end if current_pos */
-       } /* end if requires_resume_key && !continue_bit */
+               /* Can't find the name. Just resume from where we were... */
+               if (dname == 0) {
+                       SeekDir(dirptr, start_pos);
+               }
+       } /* end if resume_name && !continue_bit */
 
        for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
                BOOL got_exact_match = False;
@@ -1785,11 +1815,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
  Reply to a TRANS2_QFSINFO (query filesystem info).
 ****************************************************************************/
 
-static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, 
-                       int length, int bufsize,
-                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *pdata = *ppdata;
        char *params = *pparams;
        uint16 info_level = SVAL(params,0);
@@ -1807,12 +1836,12 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
 
-       pdata = Realloc(*ppdata, max_data_bytes + 1024);
+       pdata = SMB_REALLOC(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if ( pdata == NULL )
                return ERROR_DOS(ERRDOS,ERRnomem);
 
        *ppdata = pdata;
-       memset((char *)pdata,'\0',max_data_bytes + 1024);
+       memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 
        switch (info_level) {
                case SMB_INFO_ALLOCATION:
@@ -2062,7 +2091,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        data_len = 12;
                        SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
                        SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
-                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */
+                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)CIFS_UNIX_POSIX_ACLS_CAP)); /* We have POSIX ACLs. */
                        break;
 
                case SMB_MAC_QUERY_FS_INFO:
@@ -2093,9 +2122,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
  Reply to a TRANS2_SETFSINFO (set filesystem info).
 ****************************************************************************/
 
-static int call_trans2setfsinfo(connection_struct *conn,
-                               char *inbuf, char *outbuf, int length, int bufsize,
-                               char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *pdata = *ppdata;
        char *params = *pparams;
@@ -2203,8 +2232,8 @@ static int call_trans2setfsinfo(connection_struct *conn,
 #endif /* HAVE_SYS_QUOTAS */
 
 /****************************************************************************
*  Utility function to set bad path error.
- ****************************************************************************/
+ Utility function to set bad path error.
+****************************************************************************/
 
 int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code)
 {
@@ -2221,17 +2250,130 @@ int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint
        return UNIXERROR(def_class,def_code);
 }
 
+/****************************************************************************
+ Utility function to count the number of entries in a POSIX acl.
+****************************************************************************/
+
+static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
+{
+       unsigned int ace_count = 0;
+       int entry_id = SMB_ACL_FIRST_ENTRY;
+       SMB_ACL_ENTRY_T entry;
+
+       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+               /* get_next... */
+               if (entry_id == SMB_ACL_FIRST_ENTRY) {
+                       entry_id = SMB_ACL_NEXT_ENTRY;
+               }
+               ace_count++;
+       }
+       return ace_count;
+}
+
+/****************************************************************************
+ Utility function to marshall a POSIX acl into wire format.
+****************************************************************************/
+
+static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
+{
+       int entry_id = SMB_ACL_FIRST_ENTRY;
+       SMB_ACL_ENTRY_T entry;
+
+       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+               SMB_ACL_TAG_T tagtype;
+               SMB_ACL_PERMSET_T permset;
+               unsigned char perms = 0;
+               unsigned int own_grp;
+
+               /* get_next... */
+               if (entry_id == SMB_ACL_FIRST_ENTRY) {
+                       entry_id = SMB_ACL_NEXT_ENTRY;
+               }
+
+               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+                       DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
+                       return False;
+               }
+
+               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+                       DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
+                       return False;
+               }
+
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
+
+               SCVAL(pdata,1,perms);
+
+               switch (tagtype) {
+                       case SMB_ACL_USER_OBJ:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
+                               own_grp = (unsigned int)pst->st_uid;
+                               SIVAL(pdata,2,own_grp);
+                               SIVAL(pdata,6,0);
+                               break;
+                       case SMB_ACL_USER:
+                               {
+                                       uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       if (!puid) {
+                                               DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+                                       }
+                                       own_grp = (unsigned int)*puid;
+                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+                                       SCVAL(pdata,0,SMB_POSIX_ACL_USER);
+                                       SIVAL(pdata,2,own_grp);
+                                       SIVAL(pdata,6,0);
+                                       break;
+                               }
+                       case SMB_ACL_GROUP_OBJ:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
+                               own_grp = (unsigned int)pst->st_gid;
+                               SIVAL(pdata,2,own_grp);
+                               SIVAL(pdata,6,0);
+                               break;
+                       case SMB_ACL_GROUP:
+                               {
+                                       gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       if (!pgid) {
+                                               DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+                                       }
+                                       own_grp = (unsigned int)*pgid;
+                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+                                       SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
+                                       SIVAL(pdata,2,own_grp);
+                                       SIVAL(pdata,6,0);
+                                       break;
+                               }
+                       case SMB_ACL_MASK:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
+                               SIVAL(pdata,2,0xFFFFFFFF);
+                               SIVAL(pdata,6,0xFFFFFFFF);
+                               break;
+                       case SMB_ACL_OTHER:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
+                               SIVAL(pdata,2,0xFFFFFFFF);
+                               SIVAL(pdata,6,0xFFFFFFFF);
+                               break;
+                       default:
+                               DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
+                               return False;
+               }
+               pdata += SMB_POSIX_ACL_ENTRY_SIZE;
+       }
+
+       return True;
+}
+
 /****************************************************************************
  Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
  file name or file id).
 ****************************************************************************/
 
-static int call_trans2qfilepathinfo(connection_struct *conn,
-                                   char *inbuf, char *outbuf, int length, 
-                                   int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        uint16 tran_call = SVAL(inbuf, smb_setup0);
@@ -2257,6 +2399,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_QFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2272,11 +2416,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         */
                                                
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
+                       /* We know this name is ok, it's already passed the checks. */
                        
                } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
                        /*
@@ -2284,12 +2424,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                         * handle (returned from an NT SMB). NT5.0 seems
                         * to do this call. JRA.
                         */
+                       /* We know this name is ok, it's already passed the checks. */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
-                               return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
-                       }
                  
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
                                /* Always do lstat for UNIX calls. */
@@ -2297,12 +2433,12 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
                                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                                }
-                       } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+                       } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
                                DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
 
-                       delete_pending = fsp->directory_delete_on_close;
+                       delete_pending = fsp->is_directory ? fsp->directory_delete_on_close : 0;
                } else {
                        /*
                         * Original code - this is an open file.
@@ -2329,7 +2465,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
 
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
@@ -2337,6 +2473,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
 
                unix_convert(fname,conn,0,&bad_path,&sbuf);
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
                if (!check_name(fname,conn)) {
                        DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
@@ -2373,16 +2512,20 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        fullpathname = fname;
        file_size = get_file_size(sbuf);
        allocation_size = get_allocation_size(fsp,&sbuf);
-       if (mode & aDIR)
+       if (mode & aDIR) {
+               /* This is necessary, as otherwise the desktop.ini file in
+                * this folder is ignored */
+               mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
                file_size = 0;
+       }
 
-       params = Realloc(*pparams,2);
+       params = SMB_REALLOC(*pparams,2);
        if (params == NULL)
          return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
        memset((char *)params,'\0',2);
-       data_size = max_data_bytes + 1024;
-       pdata = Realloc(*ppdata, data_size); 
+       data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
+       pdata = SMB_REALLOC(*ppdata, data_size); 
        if ( pdata == NULL )
                return ERROR_DOS(ERRDOS,ERRnomem);
        *ppdata = pdata;
@@ -2397,6 +2540,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
        c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
 
+       if (fsp && fsp->pending_modtime) {
+               /* the pending modtime overrides the current modtime */
+               sbuf.st_mtime = fsp->pending_modtime;
+       }
+
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                c_time &= ~1;
                sbuf.st_atime &= ~1;
@@ -2781,6 +2929,83 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                break;
                        }
 
+               case SMB_QUERY_POSIX_ACL:
+                       {
+                               SMB_ACL_T file_acl = NULL;
+                               SMB_ACL_T def_acl = NULL;
+                               uint16 num_file_acls = 0;
+                               uint16 num_def_acls = 0;
+
+                               if (fsp && !fsp->is_directory && (fsp->fd != -1)) {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
+                               } else {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+                               }
+
+                               if (file_acl == NULL && no_acl_syscall_error(errno)) {
+                                       DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n",
+                                               fname ));
+                                       return ERROR_NT(NT_STATUS_NOT_IMPLEMENTED);
+                               }
+
+                               if (S_ISDIR(sbuf.st_mode)) {
+                                       if (fsp && fsp->is_directory) {
+                                               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+                                       } else {
+                                               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT);
+                                       }
+                                       def_acl = free_empty_sys_acl(conn, def_acl);
+                               }
+
+                               num_file_acls = count_acl_entries(conn, file_acl);
+                               num_def_acls = count_acl_entries(conn, def_acl);
+
+                               if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
+                                       DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n",
+                                               data_size,
+                                               (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
+                                                       SMB_POSIX_ACL_HEADER_SIZE) ));
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
+                               }
+
+                               SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
+                               SSVAL(pdata,2,num_file_acls);
+                               SSVAL(pdata,4,num_def_acls);
+                               if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) {
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+                               }
+                               if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) {
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+                               }
+
+                               if (file_acl) {
+                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                               }
+                               if (def_acl) {
+                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                               }
+                               data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
+                               break;
+                       }
+
                default:
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
@@ -2796,25 +3021,38 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
  open_file_shared. JRA.
 ****************************************************************************/
 
-NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close)
+NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, uint32 dosmode)
 {
-       /*
-        * Only allow delete on close for writable shares.
-        */
+       if (delete_on_close) {
+               /*
+                * Only allow delete on close for writable files.
+                */
 
-       if (delete_on_close && !CAN_WRITE(fsp->conn)) {
-               DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n",
+               if (dosmode & aRONLY) {
+                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n",
                                fsp->fsp_name ));
-                               return NT_STATUS_ACCESS_DENIED;
-       }
-       /*
-        * Only allow delete on close for files/directories opened with delete intent.
-        */
+                       return NT_STATUS_CANNOT_DELETE;
+               }
+
+               /*
+                * Only allow delete on close for writable shares.
+                */
 
-       if (delete_on_close && !(fsp->desired_access & DELETE_ACCESS)) {
-               DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",
+               if (!CAN_WRITE(fsp->conn)) {
+                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n",
                                fsp->fsp_name ));
-                               return NT_STATUS_ACCESS_DENIED;
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
+               /*
+                * Only allow delete on close for files/directories opened with delete intent.
+                */
+
+               if (!(fsp->desired_access & DELETE_ACCESS)) {
+                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",
+                               fsp->fsp_name ));
+                       return NT_STATUS_ACCESS_DENIED;
+               }
        }
 
        if(fsp->is_directory) {
@@ -2851,7 +3089,7 @@ NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close)
                return NT_STATUS_ACCESS_DENIED;
 
        if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
-               DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n",
+               DEBUG(0,("set_delete_on_close_over_all: failed to change delete on close flag for file %s\n",
                        fsp->fsp_name ));
                unlock_share_entry_fsp(fsp);
                return NT_STATUS_ACCESS_DENIED;
@@ -2871,7 +3109,6 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
        BOOL bad_path_oldname = False;
        BOOL bad_path_newname = False;
        SMB_STRUCT_STAT sbuf1, sbuf2;
-       BOOL rc, rcdest;
        pstring last_component_oldname;
        pstring last_component_newname;
        NTSTATUS status = NT_STATUS_OK;
@@ -2884,8 +3121,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
        }
 
-       rc = unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
-       if (!rc && bad_path_oldname) {
+       unix_convert(oldname,conn,last_component_oldname,&bad_path_oldname,&sbuf1);
+       if (bad_path_oldname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2905,8 +3142,8 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       rcdest = unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
-       if (!rcdest && bad_path_newname) {
+       unix_convert(newname,conn,last_component_newname,&bad_path_newname,&sbuf2);
+       if (bad_path_newname) {
                return NT_STATUS_OBJECT_PATH_NOT_FOUND;
        }
 
@@ -2950,9 +3187,9 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
  Reply to a TRANS2_SETFILEINFO (set file info by fileid).
 ****************************************************************************/
 
-static int call_trans2setfilepathinfo(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        char *pdata = *ppdata;
@@ -2974,6 +3211,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
+       ZERO_STRUCT(sbuf);
+
        if (tran_call == TRANSACT2_SETFILEINFO) {
                if (total_params < 4)
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
@@ -2988,8 +3227,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                         * to do this call. JRA.
                         */
                        pstrcpy(fname, fsp->fsp_name);
-                       unix_convert(fname,conn,0,&bad_path,&sbuf);
-                       if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
+                       if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
                                DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
@@ -3027,11 +3265,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
                info_level = SVAL(params,0);    
-               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status);
+               srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
                if (!NT_STATUS_IS_OK(status)) {
                        return ERROR_NT(status);
                }
                unix_convert(fname,conn,0,&bad_path,&sbuf);
+               if (bad_path) {
+                       return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+               }
 
                /*
                 * For CIFS UNIX extensions the target name may not exist.
@@ -3061,14 +3302,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,2);
+       params = SMB_REALLOC(*pparams,2);
        if(params == NULL)
                return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
 
        SSVAL(params,0,0);
 
-       if (fsp) {
+       if (fsp && fsp->pending_modtime) {
                /* the pending modtime overrides the current modtime */
                sbuf.st_mtime = fsp->pending_modtime;
        }
@@ -3178,7 +3419,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                        fname, (double)allocation_size ));
 
                        if (allocation_size)
-                               allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE);
+                               allocation_size = smb_roundup(allocation_size);
 
                        if(allocation_size != get_file_size(sbuf)) {
                                SMB_STRUCT_STAT new_sbuf;
@@ -3205,7 +3446,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                                                        SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                                        (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                                                                        FILE_ATTRIBUTE_NORMAL,
-                                                                       0, &access_mode, &action);
+                                                                       INTERNAL_OPEN_ONLY, &access_mode, &action);
  
                                        if (new_fsp == NULL)
                                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3268,7 +3509,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        if (fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadfid));
 
-                       status = set_delete_on_close_internal(fsp, delete_on_close);
+                       status = set_delete_on_close_internal(fsp, delete_on_close, dosmode);
  
                        if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
                                return ERROR_NT(status);
@@ -3347,16 +3588,15 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                 * a new info level should be used for mknod. JRA.
                                 */
 
-#if !defined(HAVE_MAKEDEV_FN)
-                               return(ERROR_DOS(ERRDOS,ERRnoaccess));
-#else /* HAVE_MAKEDEV_FN */
                                uint32 file_type = IVAL(pdata,0);
+#if defined(HAVE_MAKEDEV)
                                uint32 dev_major = IVAL(pdata,4);
                                uint32 dev_minor = IVAL(pdata,12);
+#endif
 
                                uid_t myuid = geteuid();
                                gid_t mygid = getegid();
-                               SMB_DEV_T dev;
+                               SMB_DEV_T dev = (SMB_DEV_T)0;
 
                                if (tran_call == TRANSACT2_SETFILEINFO)
                                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
@@ -3364,7 +3604,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                if (raw_unixmode == SMB_MODE_NO_CHANGE)
                                        return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
+#if defined(HAVE_MAKEDEV)
                                dev = makedev(dev_major, dev_minor);
+#endif
 
                                /* We can only create as the owner/group we are. */
 
@@ -3373,15 +3615,36 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                if ((set_grp != mygid) && (set_grp != (gid_t)SMB_GID_NO_CHANGE))
                                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
 
-                               if (file_type != UNIX_TYPE_CHARDEV && file_type != UNIX_TYPE_BLKDEV &&
-                                               file_type != UNIX_TYPE_FIFO)
-                                       return(ERROR_DOS(ERRDOS,ERRnoaccess));
+                               switch (file_type) {
+#if defined(S_IFIFO)
+                                       case UNIX_TYPE_FIFO:
+                                               unixmode |= S_IFIFO;
+                                               break;
+#endif
+#if defined(S_IFSOCK)
+                                       case UNIX_TYPE_SOCKET:
+                                               unixmode |= S_IFSOCK;
+                                               break;
+#endif
+#if defined(S_IFCHR)
+                                       case UNIX_TYPE_CHARDEV:
+                                               unixmode |= S_IFCHR;
+                                               break;
+#endif
+#if defined(S_IFBLK)
+                                       case UNIX_TYPE_BLKDEV:
+                                               unixmode |= S_IFBLK;
+                                               break;
+#endif
+                                       default:
+                                               return(ERROR_DOS(ERRDOS,ERRnoaccess));
+                               }
 
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
 0%o for file %s\n", (double)dev, unixmode, fname ));
 
                                /* Ok - do the mknod. */
-                               if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
+                               if (SMB_VFS_MKNOD(conn,fname, unixmode, dev) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
 
                                inherit_access_acl(conn, fname, unixmode);
@@ -3389,8 +3652,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                SSVAL(params,0,0);
                                send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
                                return(-1);
-#endif /* HAVE_MAKEDEV_FN */
-
                        }
 
                        /*
@@ -3482,7 +3743,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        char *newname = fname;
 
                        /* Set a hard link. */
-                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
+                       srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3515,7 +3776,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        overwrite = (CVAL(pdata,0) ? True : False);
                        root_fid = IVAL(pdata,4);
                        len = IVAL(pdata,8);
-                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
+                       srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, False);
                        if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
                        }
@@ -3538,7 +3799,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if (fsp) {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
                                        fsp->fnum, fsp->fsp_name, base_name ));
-                               status = rename_internals_fsp(conn, fsp, base_name, overwrite);
+                               status = rename_internals_fsp(conn, fsp, base_name, 0, overwrite);
                        } else {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
                                        fname, newname ));
@@ -3552,6 +3813,57 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
                        return(-1);
                }
+
+               case SMB_SET_POSIX_ACL:
+               {
+                       uint16 posix_acl_version;
+                       uint16 num_file_acls;
+                       uint16 num_def_acls;
+                       BOOL valid_file_acls = True;
+                       BOOL valid_def_acls = True;
+
+                       if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       }
+                       posix_acl_version = SVAL(pdata,0);
+                       num_file_acls = SVAL(pdata,2);
+                       num_def_acls = SVAL(pdata,4);
+
+                       if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+                               valid_file_acls = False;
+                               num_file_acls = 0;
+                       }
+
+                       if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+                               valid_def_acls = False;
+                               num_def_acls = 0;
+                       }
+
+                       if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
+                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       }
+
+                       if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
+                                       (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
+                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       }
+
+                       if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
+                                       pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
+
+                       if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, &sbuf, num_def_acls,
+                                       pdata + SMB_POSIX_ACL_HEADER_SIZE +
+                                       (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
+
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
+
                default:
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
@@ -3597,10 +3909,12 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                if(fsp != NULL) {
                        /*
                         * This was a setfileinfo on an open file.
-                        * NT does this a lot. It's actually pointless
-                        * setting the time here, as it will be overwritten
-                        * on the next write, so we save the request
-                        * away and will set it on file close. JRA.
+                        * NT does this a lot. We also need to 
+                        * set the time here, as it can be read by 
+                        * FindFirst/FindNext and with the patch for bug #2045
+                        * in smbd/fileio.c it ensures that this timestamp is
+                        * kept sticky even after a write. We save the request
+                        * away and will set it on file close and after a write. JRA.
                         */
 
                        if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
@@ -3608,12 +3922,11 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                fsp->pending_modtime = tvs.modtime;
                        }
 
-               } else {
-
                        DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
 
-                       if(file_utime(conn, fname, &tvs)!=0)
+                       if(file_utime(conn, fname, &tvs)!=0) {
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
                }
        }
 
@@ -3622,7 +3935,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode ));
 
-               if(file_set_dosmode(conn, fname, dosmode, NULL)) {
+               if(file_set_dosmode(conn, fname, dosmode, &sbuf, False)) {
                        DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno)));
                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                }
@@ -3654,7 +3967,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                                SET_OPEN_MODE(DOS_OPEN_RDWR),
                                                (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
                                                FILE_ATTRIBUTE_NORMAL,
-                                               0, &access_mode, &action);
+                                               INTERNAL_OPEN_ONLY, &access_mode, &action);
        
                        if (new_fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadpath));
@@ -3678,9 +3991,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
  Reply to a TRANS2_MKDIR (make directory with extended attributes).
 ****************************************************************************/
 
-static int call_trans2mkdir(connection_struct *conn,
-                           char *inbuf, char *outbuf, int length, int bufsize,
-                               char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        pstring directory;
@@ -3695,7 +4008,7 @@ static int call_trans2mkdir(connection_struct *conn,
        if (total_params < 4)
                return(ERROR_DOS(ERRDOS,ERRinvalidparam));
 
-       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status);
+       srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
@@ -3703,8 +4016,11 @@ static int call_trans2mkdir(connection_struct *conn,
        DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
+       if (bad_path) {
+               return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+       }
        if (check_name(directory,conn))
-               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
+               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
   
        if(ret < 0) {
                DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
@@ -3712,7 +4028,7 @@ static int call_trans2mkdir(connection_struct *conn,
        }
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,2);
+       params = SMB_REALLOC(*pparams,2);
        if(params == NULL)
                return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
@@ -3729,9 +4045,9 @@ static int call_trans2mkdir(connection_struct *conn,
  We don't actually do this - we just send a null response.
 ****************************************************************************/
 
-static int call_trans2findnotifyfirst(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        static uint16 fnf_handle = 257;
        char *params = *pparams;
@@ -3752,7 +4068,7 @@ static int call_trans2findnotifyfirst(connection_struct *conn,
        }
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,6);
+       params = SMB_REALLOC(*pparams,6);
        if(params == NULL) 
                return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
@@ -3776,16 +4092,16 @@ static int call_trans2findnotifyfirst(connection_struct *conn,
  changes). Currently this does nothing.
 ****************************************************************************/
 
-static int call_trans2findnotifynext(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
 
        DEBUG(3,("call_trans2findnotifynext\n"));
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,4);
+       params = SMB_REALLOC(*pparams,4);
        if(params == NULL)
                return ERROR_DOS(ERRDOS,ERRnomem);
        *pparams = params;
@@ -3802,9 +4118,9 @@ static int call_trans2findnotifynext(connection_struct *conn,
  Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
 ****************************************************************************/
 
-static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
-                                       char* outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        pstring pathname;
@@ -3838,9 +4154,9 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
  Reply to a TRANS2_IOCTL - used for OS/2 printing.
 ****************************************************************************/
 
-static int call_trans2ioctl(connection_struct *conn, char* inbuf,
-                                       char* outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *pdata = *ppdata;
        files_struct *fsp = file_fsp(inbuf,smb_vwv15);
@@ -3852,7 +4168,7 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf,
 
        if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
                        (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
-               pdata = Realloc(*ppdata, 32);
+               pdata = SMB_REALLOC(*ppdata, 32);
                if(pdata == NULL)
                        return ERROR_DOS(ERRDOS,ERRnomem);
                *ppdata = pdata;
@@ -3944,9 +4260,9 @@ int reply_trans2(connection_struct *conn,
        int outsize = 0;
        unsigned int total_params = SVAL(inbuf, smb_tpscnt);
        unsigned int total_data =SVAL(inbuf, smb_tdscnt);
+       unsigned int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
 #if 0
        unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
-       unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
        unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
        BOOL close_tid = BITSETW(inbuf+smb_flags,0);
        BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
@@ -4003,9 +4319,9 @@ int reply_trans2(connection_struct *conn,
     
        /* Allocate the space for the maximum needed parameters and data */
        if (total_params > 0)
-               params = (char *)malloc(total_params);
+               params = (char *)SMB_MALLOC(total_params);
        if (total_data > 0)
-               data = (char *)malloc(total_data);
+               data = (char *)SMB_MALLOC(total_data);
   
        if ((total_params && !params)  || (total_data && !data)) {
                DEBUG(2,("Out of memory in reply_trans2\n"));
@@ -4101,7 +4417,7 @@ int reply_trans2(connection_struct *conn,
                                goto bad_param;
                        
                        if (num_params) {
-                               if (param_disp + num_params >= total_params)
+                               if (param_disp + num_params > total_params)
                                        goto bad_param;
                                if ((param_disp + num_params < param_disp) ||
                                                (param_disp + num_params < num_params))
@@ -4117,7 +4433,7 @@ int reply_trans2(connection_struct *conn,
                                memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
                        }
                        if (num_data) {
-                               if (data_disp + num_data >= total_data)
+                               if (data_disp + num_data > total_data)
                                        goto bad_param;
                                if ((data_disp + num_data < data_disp) ||
                                                (data_disp + num_data < num_data))
@@ -4144,28 +4460,28 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_OPEN:
                START_PROFILE_NESTED(Trans2_open);
                outsize = call_trans2open(conn, inbuf, outbuf, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_open);
                break;
 
        case TRANSACT2_FINDFIRST:
                START_PROFILE_NESTED(Trans2_findfirst);
                outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findfirst);
                break;
 
        case TRANSACT2_FINDNEXT:
                START_PROFILE_NESTED(Trans2_findnext);
                outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnext);
                break;
 
        case TRANSACT2_QFSINFO:
                START_PROFILE_NESTED(Trans2_qfsinfo);
                outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_qfsinfo);
            break;
 
@@ -4173,7 +4489,7 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_SETFSINFO:
                START_PROFILE_NESTED(Trans2_setfsinfo);
                outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_setfsinfo);
                break;
 #endif
@@ -4181,47 +4497,47 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_QFILEINFO:
                START_PROFILE_NESTED(Trans2_qpathinfo);
                outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_qpathinfo);
                break;
        case TRANSACT2_SETPATHINFO:
        case TRANSACT2_SETFILEINFO:
                START_PROFILE_NESTED(Trans2_setpathinfo);
                outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_setpathinfo);
                break;
 
        case TRANSACT2_FINDNOTIFYFIRST:
                START_PROFILE_NESTED(Trans2_findnotifyfirst);
                outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnotifyfirst);
                break;
 
        case TRANSACT2_FINDNOTIFYNEXT:
                START_PROFILE_NESTED(Trans2_findnotifynext);
                outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnotifynext);
                break;
        case TRANSACT2_MKDIR:
                START_PROFILE_NESTED(Trans2_mkdir);
                outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_mkdir);
                break;
 
        case TRANSACT2_GET_DFS_REFERRAL:
                START_PROFILE_NESTED(Trans2_get_dfs_referral);
                outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_get_dfs_referral);
                break;
        case TRANSACT2_IOCTL:
                START_PROFILE_NESTED(Trans2_ioctl);
                outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_ioctl);
                break;
        default: