r17105: Fix the race Volker found - we had a non-locked
[ira/wip.git] / source3 / smbd / trans2.c
index 9cd2d44de5cb9c0921ecd1dbb3eb1ea502ee2d7d..5acce13e52d78e8ce15abbae9127ab41090afd56 100644 (file)
@@ -172,6 +172,11 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str
 
        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 (!ea_namelist) {
+                       return NULL;
+               }
+
                if (fsp && fsp->fh->fd != -1) {
                        sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fh->fd, ea_namelist, ea_namelist_size);
                } else {
@@ -563,7 +568,7 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *
   HACK ! Always assumes smb_setup field is zero.
 ****************************************************************************/
 
-static int send_trans2_replies(char *outbuf,
+int send_trans2_replies(char *outbuf,
                        int bufsize,
                        char *params, 
                        int paramsize,
@@ -727,7 +732,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        time_t open_time;
 #endif
        int open_ofun;
-       int32 open_size;
+       uint32 open_size;
        char *pname;
        pstring fname;
        SMB_OFF_T size=0;
@@ -832,16 +837,16 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
 
-       fsp = open_file_ntcreate(conn,fname,&sbuf,
+       status = open_file_ntcreate(conn,fname,&sbuf,
                access_mask,
                share_mode,
                create_disposition,
                create_options,
                open_attr,
                oplock_request,
-               &smb_action);
+               &smb_action, &fsp);
       
-       if (!fsp) {
+       if (!NT_STATUS_IS_OK(status)) {
                talloc_destroy(ctx);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
@@ -860,6 +865,30 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                return(ERROR_DOS(ERRDOS,ERRnoaccess));
        }
 
+       /* Save the requested allocation size. */
+       /* Allocate space for the file if a size hint is supplied */
+       if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) {
+               SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)open_size;
+               if (allocation_size && (allocation_size > (SMB_BIG_UINT)size)) {
+                        fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
+                        if (fsp->is_directory) {
+                                close_file(fsp,ERROR_CLOSE);
+                                /* Can't set allocation size on a directory. */
+                                return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+                        }
+                        if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
+                                close_file(fsp,ERROR_CLOSE);
+                                return ERROR_NT(NT_STATUS_DISK_FULL);
+                        }
+
+                       /* Adjust size here to return the right size in the reply.
+                          Windows does it this way. */
+                       size = fsp->initial_allocation_size;
+                } else {
+                        fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)size);
+                }
+       }
+
        if (total_data && smb_action == FILE_WAS_CREATED) {
                status = set_ea(conn, fsp, fname, ea_list);
                talloc_destroy(ctx);
@@ -1041,7 +1070,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        BOOL was_8_3;
        uint32 nt_extmode; /* Used for NT connections instead of mode */
        BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
-       BOOL check_mangled_names = lp_manglednames(SNUM(conn));
+       BOOL check_mangled_names = lp_manglednames(conn->params);
 
        *fname = 0;
        *out_of_space = False;
@@ -1062,6 +1091,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
        while (!found) {
                BOOL got_match;
+               BOOL ms_dfs_link = False;
+
                /* Needed if we run out of space */
                long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr);
                dname = dptr_ReadDirName(conn->dirptr,&curr_dirpos,&sbuf);
@@ -1086,7 +1117,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
                        got_match = mask_match(fname, mask, conn->case_sensitive);
 
-               if(!got_match && check_mangled_names && !mangle_is_8_3(fname, False, SNUM(conn))) {
+               if(!got_match && check_mangled_names &&
+                  !mangle_is_8_3(fname, False, conn->params)) {
 
                        /*
                         * It turns out that NT matches wildcards against
@@ -1097,7 +1129,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                        pstring newname;
                        pstrcpy( newname, fname);
-                       mangle_map( newname, True, False, SNUM(conn));
+                       mangle_map( newname, True, False, conn->params);
                        if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
                                got_match = mask_match(newname, mask, conn->case_sensitive);
                }
@@ -1125,8 +1157,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                                if(lp_host_msdfs() && 
                                   lp_msdfs_root(SNUM(conn)) &&
-                                  is_msdfs_link(NULL,conn, pathreal, NULL, NULL,
-                                                &sbuf)) {
+                                  ((ms_dfs_link = is_msdfs_link(NULL,conn, pathreal, NULL, NULL, &sbuf)) == True)) {
 
                                        DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
                                        sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
@@ -1139,7 +1170,11 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                }
                        }
 
-                       mode = dos_mode(conn,pathreal,&sbuf);
+                       if (ms_dfs_link) {
+                               mode = dos_mode_msdfs(conn,pathreal,&sbuf);
+                       } else {
+                               mode = dos_mode(conn,pathreal,&sbuf);
+                       }
 
                        if (!dir_check_ftype(conn,mode,dirtype)) {
                                DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
@@ -1163,10 +1198,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
          
                        found = True;
+
+                       dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos);
                }
        }
 
-       mangle_map(fname,False,True,SNUM(conn));
+       mangle_map(fname,False,True,conn->params);
 
        p = pdata;
        last_entry_ptr = p;
@@ -1302,7 +1339,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
                        DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
-                       was_8_3 = mangle_is_8_3(fname, True, SNUM(conn));
+                       was_8_3 = mangle_is_8_3(fname, True, conn->params);
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
@@ -1325,7 +1362,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        if (!was_8_3 && check_mangled_names) {
                                pstring mangled_name;
                                pstrcpy(mangled_name, fname);
-                               mangle_map(mangled_name,True,True,SNUM(conn));
+                               mangle_map(mangled_name,True,True,
+                                          conn->params);
                                mangled_name[12] = 0;
                                len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
                                if (len < 24) {
@@ -1444,7 +1482,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
                        DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
-                       was_8_3 = mangle_is_8_3(fname, True, SNUM(conn));
+                       was_8_3 = mangle_is_8_3(fname, True, conn->params);
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
@@ -1467,7 +1505,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        if (!was_8_3 && check_mangled_names) {
                                pstring mangled_name;
                                pstrcpy(mangled_name, fname);
-                               mangle_map(mangled_name,True,True,SNUM(conn));
+                               mangle_map(mangled_name,True,True,
+                                          conn->params);
                                mangled_name[12] = 0;
                                len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
                                SSVAL(p, 0, len);
@@ -1642,11 +1681,12 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
                        break;
                case SMB_FIND_FILE_UNIX:
-                       if (!lp_unix_extensions())
-                               return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+                       if (!lp_unix_extensions()) {
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
                        break;
                default:
-                       return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
        srvstr_get_path_wcard(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, &mask_contains_wcard);
@@ -1834,8 +1874,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
         * (see PR#13758). JRA.
         */
 
-       if(!mangle_is_8_3_wildcards( mask, False, SNUM(conn)))
-               mangle_map(mask, True, True, SNUM(conn));
+       if(!mangle_is_8_3_wildcards( mask, False, conn->params))
+               mangle_map(mask, True, True, conn->params);
 
        return(-1);
 }
@@ -1924,11 +1964,12 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
                        break;
                case SMB_FIND_FILE_UNIX:
-                       if (!lp_unix_extensions())
-                               return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+                       if (!lp_unix_extensions()) {
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
                        break;
                default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
        if (info_level == SMB_FIND_EA_LIST) {
@@ -2030,8 +2071,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                 * could be mangled. Ensure we check the unmangled name.
                 */
 
-               if (mangle_is_mangled(resume_name, SNUM(conn))) {
-                       mangle_check_cache(resume_name, sizeof(resume_name)-1, SNUM(conn));
+               if (mangle_is_mangled(resume_name, conn->params)) {
+                       mangle_check_cache(resume_name, sizeof(resume_name)-1,
+                                          conn->params);
                }
 
                /*
@@ -2396,13 +2438,17 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                 */
 
                case SMB_QUERY_CIFS_UNIX_INFO:
-                       if (!lp_unix_extensions())
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       if (!lp_unix_extensions()) {
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
                        data_len = 12;
                        SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
                        SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
-                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)(CIFS_UNIX_POSIX_ACLS_CAP|
-                                       CIFS_UNIX_POSIX_PATHNAMES_CAP))); /* We have POSIX ACLs and pathname capability. */
+                       /* We have POSIX ACLs, pathname and locking capability. */
+                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
+                                       CIFS_UNIX_POSIX_ACLS_CAP|
+                                       CIFS_UNIX_POSIX_PATHNAMES_CAP|
+                                       CIFS_UNIX_FCNTL_LOCKS_CAP)));
                        break;
 
                case SMB_QUERY_POSIX_FS_INFO:
@@ -2410,9 +2456,10 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        int rc;
                        vfs_statvfs_struct svfs;
 
-                       if (!lp_unix_extensions())
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
-                       
+                       if (!lp_unix_extensions()) {
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+                       }
+
                        rc = SMB_VFS_STATVFS(conn, ".", &svfs);
 
                        if (!rc) {
@@ -2428,7 +2475,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
 #ifdef EOPNOTSUPP
                        } else if (rc == EOPNOTSUPP) {
-                               return ERROR_DOS(ERRDOS, ERRunknownlevel);
+                               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
 #endif /* EOPNOTSUPP */
                        } else {
                                DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
@@ -2449,7 +2496,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        }
                        /* drop through */
                default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
 
@@ -2493,7 +2540,7 @@ static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outb
                                uint32 client_unix_cap_high;
 
                                if (!lp_unix_extensions()) {
-                                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
                                }
 
                                /* There should be 12 bytes of capabilities set. */
@@ -2513,8 +2560,14 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                                        (unsigned int)client_unix_cap_high ));
 
                                /* Here is where we must switch to posix pathname processing... */
-                               lp_set_posix_pathnames();
-                               mangle_change_to_posix();
+                               if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+                                       lp_set_posix_pathnames();
+                                       mangle_change_to_posix();
+                               }
+
+                               if (client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) {
+                                       lp_set_posix_cifsx_locktype(POSIX_LOCK);
+                               }
                                break;
                        }
                case SMB_FS_QUOTA_INFORMATION:
@@ -2591,7 +2644,7 @@ cap_low = 0x%x, cap_high = 0x%x\n",
                default:
                        DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
                                info_level));
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
                        break;
        }
 
@@ -2772,9 +2825,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
        int len;
        time_t c_time;
        files_struct *fsp = NULL;
-       TALLOC_CTX *ea_ctx = NULL;
+       TALLOC_CTX *data_ctx = NULL;
        struct ea_list *ea_list = NULL;
        uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
+       char *lock_data = NULL;
 
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
@@ -2891,8 +2945,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
                nlink -= 1;
        }
 
-       if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
-               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+       if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+       }
 
        DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
                fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
@@ -2911,40 +2966,69 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *
        if (!(mode & aDIR))
                file_size = get_file_size(sbuf);
 
-       /* Pull any EA list from the data portion. */
-       if (info_level == SMB_INFO_QUERY_EAS_FROM_LIST) {
-               uint32 ea_size;
+       /* Pull out any data sent here before we realloc. */
+       switch (info_level) {
+               case SMB_INFO_QUERY_EAS_FROM_LIST:
+               {
+                       /* Pull any EA list from the data portion. */
+                       uint32 ea_size;
 
-               if (total_data < 4) {
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-               }
-               ea_size = IVAL(pdata,0);
+                       if (total_data < 4) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       ea_size = IVAL(pdata,0);
 
-               if (total_data > 0 && ea_size != total_data) {
-                       DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
+                       if (total_data > 0 && ea_size != total_data) {
+                               DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-               }
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
-               if (!lp_ea_support(SNUM(conn))) {
-                       return ERROR_DOS(ERRDOS,ERReasnotsupported);
-               }
+                       if (!lp_ea_support(SNUM(conn))) {
+                               return ERROR_DOS(ERRDOS,ERReasnotsupported);
+                       }
 
-               if ((ea_ctx = talloc_init("ea_list")) == NULL) {
-                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       if ((data_ctx = talloc_init("ea_list")) == NULL) {
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
+
+                       /* Pull out the list of names. */
+                       ea_list = read_ea_name_list(data_ctx, pdata + 4, ea_size - 4);
+                       if (!ea_list) {
+                               talloc_destroy(data_ctx);
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       break;
                }
 
-               /* Pull out the list of names. */
-               ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
-               if (!ea_list) {
-                       talloc_destroy(ea_ctx);
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               case SMB_QUERY_POSIX_LOCK:
+               {
+                       if (fsp == NULL || fsp->fh->fd == -1) {
+                               return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+                       }
+
+                       if (total_data != POSIX_LOCK_DATA_SIZE) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if ((data_ctx = talloc_init("lock_request")) == NULL) {
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
+
+                       /* Copy the lock range data. */
+                       lock_data = talloc_memdup(data_ctx, pdata, total_data);
+                       if (!lock_data) {
+                               talloc_destroy(data_ctx);
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
                }
+               default:
+                       break;
        }
 
        *pparams = SMB_REALLOC(*pparams,2);
        if (*pparams == NULL) {
-               talloc_destroy(ea_ctx);
+               talloc_destroy(data_ctx);
                return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
        params = *pparams;
@@ -2952,7 +3036,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
        *ppdata = SMB_REALLOC(*ppdata, data_size); 
        if (*ppdata == NULL ) {
-               talloc_destroy(ea_ctx);
+               talloc_destroy(data_ctx);
                return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
        pdata = *ppdata;
@@ -3038,18 +3122,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
 
-                       ea_file_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+                       ea_file_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
                        ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
 
                        if (!ea_list || (total_ea_len > data_size)) {
-                               talloc_destroy(ea_ctx);
+                               talloc_destroy(data_ctx);
                                data_size = 4;
                                SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
                                break;
                        }
 
-                       data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
-                       talloc_destroy(ea_ctx);
+                       data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+                       talloc_destroy(data_ctx);
                        break;
                }
 
@@ -3060,21 +3144,21 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
 
-                       ea_ctx = talloc_init("ea_ctx");
-                       if (!ea_ctx) {
+                       data_ctx = talloc_init("ea_ctx");
+                       if (!data_ctx) {
                                return ERROR_NT(NT_STATUS_NO_MEMORY);
                        }
 
-                       ea_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+                       ea_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
                        if (!ea_list || (total_ea_len > data_size)) {
-                               talloc_destroy(ea_ctx);
+                               talloc_destroy(data_ctx);
                                data_size = 4;
                                SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
                                break;
                        }
 
-                       data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
-                       talloc_destroy(ea_ctx);
+                       data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
+                       talloc_destroy(data_ctx);
                        break;
                }
 
@@ -3138,8 +3222,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
                        pstrcpy(short_name,base_name);
                        /* Mangle if not already 8.3 */
-                       if(!mangle_is_8_3(short_name, True, SNUM(conn))) {
-                               mangle_map(short_name,True,True,SNUM(conn));
+                       if(!mangle_is_8_3(short_name, True, conn->params)) {
+                               mangle_map(short_name,True,True,conn->params);
                        }
                        len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_UNICODE);
                        data_size = 4 + len;
@@ -3221,7 +3305,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        /* Pathname with leading '\'. */
                        {
                                size_t byte_len;
-                               byte_len = dos_PutUniCode(pdata+4,dos_fname,max_data_bytes,False);
+                               byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
                                DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
                                SIVAL(pdata,0,byte_len);
                                data_size = 4 + byte_len;
@@ -3265,7 +3349,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        if (mode & aDIR) {
                                data_size = 0;
                        } else {
-                               size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
+                               size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", (size_t)0xE, False);
                                SIVAL(pdata,0,0); /* ??? */
                                SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
                                SOFF_T(pdata,8,file_size);
@@ -3352,12 +3436,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
                        SIVAL(pdata,0,sbuf.st_nlink);             /* number of hard links */
                        SIVAL(pdata,4,0);
-                       pdata += 8+1;
+                       pdata += 8;
                        data_size = PTR_DIFF(pdata,(*ppdata));
 
                        {
                                int i;
-                               DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC"));
+                               DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
 
                                for (i=0; i<100; i++)
                                        DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
@@ -3467,8 +3551,82 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        }
 #endif
 
+
+               case SMB_QUERY_POSIX_LOCK:
+               {
+                       NTSTATUS status = NT_STATUS_INVALID_LEVEL;
+                       SMB_BIG_UINT count;
+                       SMB_BIG_UINT offset;
+                       uint32 lock_pid;
+                       enum brl_type lock_type;
+
+                       if (total_data != POSIX_LOCK_DATA_SIZE) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+                               case POSIX_LOCK_TYPE_READ:
+                                       lock_type = READ_LOCK;
+                                       break;
+                               case POSIX_LOCK_TYPE_WRITE:
+                                       lock_type = WRITE_LOCK;
+                                       break;
+                               case POSIX_LOCK_TYPE_UNLOCK:
+                               default:
+                                       /* There's no point in asking for an unlock... */
+                                       talloc_destroy(data_ctx);
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+                       offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+                                       ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+                       count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+                                       ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+                       offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+                       count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+                       status = query_lock(fsp,
+                                       &lock_pid,
+                                       &count,
+                                       &offset,
+                                       &lock_type,
+                                       POSIX_LOCK);
+
+                       if (ERROR_WAS_LOCK_DENIED(status)) {
+                               /* Here we need to report who has it locked... */
+                               data_size = POSIX_LOCK_DATA_SIZE;
+
+                               SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
+                               SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
+                               SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
+#if defined(HAVE_LONGLONG)
+                               SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
+                               SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
+                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
+                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
+#else /* HAVE_LONGLONG */
+                               SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
+                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
+#endif /* HAVE_LONGLONG */
+
+                       } else if (NT_STATUS_IS_OK(status)) {
+                               /* For success we just return a copy of what we sent
+                                  with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
+                               data_size = POSIX_LOCK_DATA_SIZE;
+                               memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
+                               SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
+                       } else {
+                               return ERROR_NT(status);
+                       }
+                       break;
+               }
+
                default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
        send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
@@ -3672,8 +3830,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
        if (!CAN_WRITE(conn))
                return ERROR_DOS(ERRSRV,ERRaccess);
 
-       if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
-               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+       if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
+               return ERROR_NT(NT_STATUS_INVALID_LEVEL);
+       }
 
        if (VALID_STAT(sbuf))
                unixmode = sbuf.st_mode;
@@ -3841,8 +4000,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
 #ifdef LARGE_SMB_OFF_T
                        allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                       if (IVAL(pdata,4) != 0) /* more than 32 bits? */
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       if (IVAL(pdata,4) != 0) {
+                               /* more than 32 bits? */
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 #endif /* LARGE_SMB_OFF_T */
                        DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
                                        fname, (double)allocation_size ));
@@ -3860,17 +4021,21 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
                                if (fd == -1) {
                                        files_struct *new_fsp = NULL;
  
-                                       new_fsp = open_file_ntcreate(conn, fname, &sbuf,
+                                       status = open_file_ntcreate(conn, fname, &sbuf,
                                                                        FILE_WRITE_DATA,
-                                                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                                                       FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                                                                        FILE_OPEN,
                                                                        0,
                                                                        FILE_ATTRIBUTE_NORMAL,
-                                                                       INTERNAL_OPEN_ONLY,
-                                                                       NULL);
+                                                                       FORCE_OPLOCK_BREAK_TO_NONE,
+                                                                       NULL, &new_fsp);
  
-                                       if (new_fsp == NULL) {
-                                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                                       if (!NT_STATUS_IS_OK(status)) {
+                                               if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+                                                       /* We have re-scheduled this call. */
+                                                       return -1;
+                                               }
+                                               return(UNIXERROR(ERRDOS,ERRnoaccess));
                                        }
                                        ret = vfs_allocate_file_space(new_fsp, allocation_size);
                                        if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) {
@@ -3908,8 +4073,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
 #ifdef LARGE_SMB_OFF_T
                        size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                       if (IVAL(pdata,4) != 0) /* more than 32 bits? */
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       if (IVAL(pdata,4) != 0) {
+                               /* more than 32 bits? */
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 #endif /* LARGE_SMB_OFF_T */
                        DEBUG(10,("call_trans2setfilepathinfo: Set end of file info for file %s to %.0f\n", fname, (double)size ));
                        break;
@@ -3962,8 +4129,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
 #ifdef LARGE_SMB_OFF_T
                        position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                       if (IVAL(pdata,4) != 0) /* more than 32 bits? */
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       if (IVAL(pdata,4) != 0) {
+                               /* more than 32 bits? */
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 #endif /* LARGE_SMB_OFF_T */
                        DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n",
                                        fname, (double)position_information ));
@@ -4019,8 +4188,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char
 #ifdef LARGE_SMB_OFF_T
                                size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                               if (IVAL(pdata,4) != 0) /* more than 32 bits? */
-                                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                               if (IVAL(pdata,4) != 0) {
+                                       /* more than 32 bits? */
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
 #endif /* LARGE_SMB_OFF_T */
                        }
                        pdata+=24;          /* ctime & st_blocks are not changed */
@@ -4224,7 +4395,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                case SMB_FILE_RENAME_INFORMATION:
                {
                        BOOL overwrite;
-                       uint32 root_fid;
+                       /* uint32 root_fid; */  /* Not used */
                        uint32 len;
                        pstring newname;
                        pstring base_name;
@@ -4235,7 +4406,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        }
 
                        overwrite = (CVAL(pdata,0) ? True : False);
-                       root_fid = IVAL(pdata,4);
+                       /* root_fid = IVAL(pdata,4); */
                        len = IVAL(pdata,8);
                        srvstr_get_path(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -4327,8 +4498,113 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                }
 #endif
 
+               case SMB_SET_POSIX_LOCK:
+               {
+                       SMB_BIG_UINT count;
+                       SMB_BIG_UINT offset;
+                       uint32 lock_pid;
+                       BOOL blocking_lock = False;
+                       enum brl_type lock_type;
+
+                       if (fsp == NULL || fsp->fh->fd == -1) {
+                               return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+                       }
+
+                       if (total_data != POSIX_LOCK_DATA_SIZE) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
+                               case POSIX_LOCK_TYPE_READ:
+                                       lock_type = READ_LOCK;
+                                       break;
+                               case POSIX_LOCK_TYPE_WRITE:
+                                       /* Return the right POSIX-mappable error code for files opened read-only. */
+                                       if (!fsp->can_write) {
+                                               return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+                                       }
+                                       lock_type = WRITE_LOCK;
+                                       break;
+                               case POSIX_LOCK_TYPE_UNLOCK:
+                                       lock_type = UNLOCK_LOCK;
+                                       break;
+                               default:
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
+                               blocking_lock = False;
+                       } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
+                               blocking_lock = True;
+                       } else {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if (!lp_blocking_locks(SNUM(conn))) { 
+                               blocking_lock = False;
+                       }
+
+                       lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
+#if defined(HAVE_LONGLONG)
+                       offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
+                                       ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
+                       count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
+                                       ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
+#else /* HAVE_LONGLONG */
+                       offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
+                       count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
+#endif /* HAVE_LONGLONG */
+
+                       if (lock_type == UNLOCK_LOCK) {
+                               status = do_unlock(fsp,
+                                               lock_pid,
+                                               count,
+                                               offset,
+                                               POSIX_LOCK);
+                       } else {
+                               struct byte_range_lock *br_lck = do_lock(fsp,
+                                                                       lock_pid,
+                                                                       count,
+                                                                       offset,
+                                                                       lock_type,
+                                                                       blocking_lock,
+                                                                       POSIX_LOCK,
+                                                                       &status);
+
+                               if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
+                                       /*
+                                        * A blocking lock was requested. Package up
+                                        * this smb into a queued request and push it
+                                        * onto the blocking lock queue.
+                                        */
+                                       if(push_blocking_lock_request(br_lck,
+                                                               inbuf, length,
+                                                               fsp,
+                                                               -1, /* infinite timeout. */
+                                                               0,
+                                                               lock_pid,
+                                                               lock_type,
+                                                               POSIX_LOCK,
+                                                               offset,
+                                                               count)) {
+                                               TALLOC_FREE(br_lck);
+                                               return -1;
+                                       }
+                               }
+                               TALLOC_FREE(br_lck);
+                       }
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return ERROR_NT(status);
+                       }
+
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
+
                default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
        /* get some defaults (no modifications) if any info is zero or -1. */
@@ -4393,17 +4669,21 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                if (fd == -1) {
                        files_struct *new_fsp = NULL;
 
-                       new_fsp = open_file_ntcreate(conn, fname, &sbuf,
+                       status = open_file_ntcreate(conn, fname, &sbuf,
                                                FILE_WRITE_DATA,
-                                               FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                                                FILE_OPEN,
                                                0,
                                                FILE_ATTRIBUTE_NORMAL,
-                                               INTERNAL_OPEN_ONLY,
-                                               NULL);
+                                               FORCE_OPLOCK_BREAK_TO_NONE,
+                                               NULL, &new_fsp);
        
-                       if (new_fsp == NULL) {
-                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                       if (!NT_STATUS_IS_OK(status)) {
+                               if (open_was_deferred(SVAL(inbuf,smb_mid))) {
+                                       /* We have re-scheduled this call. */
+                                       return -1;
+                               }
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
                        }
                        ret = vfs_set_filelen(new_fsp, size);
                        close_file(new_fsp,NORMAL_CLOSE);
@@ -4580,7 +4860,7 @@ static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char
                case 2:
                        break;
                default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       return ERROR_NT(NT_STATUS_INVALID_LEVEL);
        }
 
        /* Realloc the parameter and data sizes */
@@ -4722,7 +5002,7 @@ int reply_findclose(connection_struct *conn,
 
        dptr_close(&dptr_num);
 
-       outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,False);
 
        DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
 
@@ -4749,7 +5029,7 @@ int reply_findnclose(connection_struct *conn,
           findnotifyfirst - so any dptr_num is ok here. 
           Just ignore it. */
 
-       outsize = set_message(outbuf,0,0,True);
+       outsize = set_message(outbuf,0,0,False);
 
        DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
 
@@ -4757,331 +5037,448 @@ int reply_findnclose(connection_struct *conn,
        return(outsize);
 }
 
-/****************************************************************************
- Reply to a SMBtranss2 - just ignore it!
-****************************************************************************/
-
-int reply_transs2(connection_struct *conn,
-                 char *inbuf,char *outbuf,int length,int bufsize)
-{
-       START_PROFILE(SMBtranss2);
-       DEBUG(4,("Ignoring transs2 of length %d\n",length));
-       END_PROFILE(SMBtranss2);
-       return(-1);
-}
-
-/****************************************************************************
- Reply to a SMBtrans2.
-****************************************************************************/
-
-int reply_trans2(connection_struct *conn,
-                char *inbuf,char *outbuf,int length,int bufsize)
+int handle_trans2(connection_struct *conn,
+                 struct trans_state *state,
+                 char *inbuf, char *outbuf, int size, int bufsize)
 {
-       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_setup_fields = SVAL(inbuf, smb_msrcnt);
-       BOOL close_tid = BITSETW(inbuf+smb_flags,0);
-       BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
-       int32 timeout = IVALS(inbuf,smb_timeout);
-#endif
-       unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
-       unsigned int tran_call = SVAL(inbuf, smb_setup0);
-       char *params = NULL, *data = NULL;
-       unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
-       START_PROFILE(SMBtrans2);
-
-       if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
-            && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
-               END_PROFILE(SMBtrans2);
-               return ERROR_DOS(ERRSRV,ERRaccess);
-       }
-
-       outsize = set_message(outbuf,0,0,True);
-
-       /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
-          is so as a sanity check */
-       if (suwcnt != 1) {
-               /*
-                * Need to have rc=0 for ioctl to get job id for OS/2.
-                *  Network printing will fail if function is not successful.
-                *  Similar function in reply.c will be used if protocol
-                *  is LANMAN1.0 instead of LM1.2X002.
-                *  Until DosPrintSetJobInfo with PRJINFO3 is supported,
-                *  outbuf doesn't have to be set(only job id is used).
-                */
-               if ( (suwcnt == 4) && (tran_call == TRANSACT2_IOCTL) &&
-                               (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
-                               (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
-                       DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
-               } else {
-                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
-                       DEBUG(2,("Transaction is %d\n",tran_call));
-                       END_PROFILE(SMBtrans2);
-                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
-               }
-       }
-    
-       /* Allocate the space for the maximum needed parameters and data */
-       if (total_params > 0)
-               params = (char *)SMB_MALLOC(total_params);
-       if (total_data > 0)
-               data = (char *)SMB_MALLOC(total_data);
-  
-       if ((total_params && !params)  || (total_data && !data)) {
-               DEBUG(2,("Out of memory in reply_trans2\n"));
-               SAFE_FREE(params);
-               SAFE_FREE(data); 
-               END_PROFILE(SMBtrans2);
-               return ERROR_NT(NT_STATUS_NO_MEMORY);
-       }
-
-       /* Copy the param and data bytes sent with this request into
-          the params buffer */
-       num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
-       num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
-
-       if (num_params > total_params || num_data > total_data)
-               exit_server("invalid params in reply_trans2");
-
-       if(params) {
-               unsigned int psoff = SVAL(inbuf, smb_psoff);
-               if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
-                       goto bad_param;
-               if ((smb_base(inbuf) + psoff + num_params > inbuf + length) ||
-                               (smb_base(inbuf) + psoff + num_params < smb_base(inbuf)))
-                       goto bad_param;
-               memcpy( params, smb_base(inbuf) + psoff, num_params);
-       }
-       if(data) {
-               unsigned int dsoff = SVAL(inbuf, smb_dsoff);
-               if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
-                       goto bad_param;
-               if ((smb_base(inbuf) + dsoff + num_data > inbuf + length) ||
-                               (smb_base(inbuf) + dsoff + num_data < smb_base(inbuf)))
-                       goto bad_param;
-               memcpy( data, smb_base(inbuf) + dsoff, num_data);
-       }
-
-       srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
-       if(num_data_sofar < total_data || num_params_sofar < total_params)  {
-               /* We need to send an interim response then receive the rest
-                  of the parameter/data bytes */
-               outsize = set_message(outbuf,0,0,True);
-               srv_signing_trans_stop();
-               show_msg(outbuf);
-               if (!send_smb(smbd_server_fd(),outbuf))
-                       exit_server("reply_trans2: send_smb failed.");
-
-               while (num_data_sofar < total_data || 
-                      num_params_sofar < total_params) {
-                       BOOL ret;
-                       unsigned int param_disp;
-                       unsigned int param_off;
-                       unsigned int data_disp;
-                       unsigned int data_off;
-
-                       ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
-
-                       /* We need to re-calcuate the new length after we've read the secondary packet. */
-                       length = smb_len(inbuf) + 4;
-                       
-                       /*
-                        * The sequence number for the trans reply is always
-                        * based on the last secondary received.
-                        */
+       int outsize;
 
-                       srv_signing_trans_start(SVAL(inbuf,smb_mid));
-
-                       if ((ret && 
-                            (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret) {
-                               outsize = set_message(outbuf,0,0,True);
-                               if(ret)
-                                       DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
-                               else
-                                       DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
-                                                (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
-                               goto bad_param;
-                       }
-      
-                       /* Revise total_params and total_data in case
-                           they have changed downwards */
-                       if (SVAL(inbuf, smb_tpscnt) < total_params)
-                               total_params = SVAL(inbuf, smb_tpscnt);
-                       if (SVAL(inbuf, smb_tdscnt) < total_data)
-                               total_data = SVAL(inbuf, smb_tdscnt);
-
-                       num_params = SVAL(inbuf,smb_spscnt);
-                       param_off = SVAL(inbuf, smb_spsoff);
-                       param_disp = SVAL(inbuf, smb_spsdisp);
-                       num_params_sofar += num_params;
-
-                       num_data = SVAL(inbuf, smb_sdscnt);
-                       data_off = SVAL(inbuf, smb_sdsoff);
-                       data_disp = SVAL(inbuf, smb_sdsdisp);
-                       num_data_sofar += num_data;
-
-                       if (num_params_sofar > total_params || num_data_sofar > total_data)
-                               goto bad_param;
-                       
-                       if (num_params) {
-                               if (param_disp + num_params > total_params)
-                                       goto bad_param;
-                               if ((param_disp + num_params < param_disp) ||
-                                               (param_disp + num_params < num_params))
-                                       goto bad_param;
-                               if (param_disp > total_params)
-                                       goto bad_param;
-                               if ((smb_base(inbuf) + param_off + num_params > inbuf + length) ||
-                                               (smb_base(inbuf) + param_off + num_params < smb_base(inbuf)))
-                                       goto bad_param;
-                               if (params + param_disp < params)
-                                       goto bad_param;
-
-                               memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
-                       }
-                       if (num_data) {
-                               if (data_disp + num_data > total_data)
-                                       goto bad_param;
-                               if ((data_disp + num_data < data_disp) ||
-                                               (data_disp + num_data < num_data))
-                                       goto bad_param;
-                               if (data_disp > total_data)
-                                       goto bad_param;
-                               if ((smb_base(inbuf) + data_off + num_data > inbuf + length) ||
-                                               (smb_base(inbuf) + data_off + num_data < smb_base(inbuf)))
-                                       goto bad_param;
-                               if (data + data_disp < data)
-                                       goto bad_param;
-
-                               memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data);
-                       }
-               }
-       }
-       
        if (Protocol >= PROTOCOL_NT1) {
                SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
        }
 
        /* Now we must call the relevant TRANS2 function */
-       switch(tran_call)  {
+       switch(state->call)  {
        case TRANSACT2_OPEN:
+       {
                START_PROFILE_NESTED(Trans2_open);
-               outsize = call_trans2open(conn, inbuf, outbuf, bufsize, 
-                                         &params, total_params, &data, total_data, max_data_bytes);
+               outsize = call_trans2open(
+                       conn, inbuf, outbuf, bufsize, 
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2findfirst(
+                       conn, inbuf, outbuf, bufsize,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2findnext(
+                       conn, inbuf, outbuf, size, bufsize, 
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2qfsinfo(
+                       conn, inbuf, outbuf, size, bufsize,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                END_PROFILE_NESTED(Trans2_qfsinfo);
            break;
+       }
 
        case TRANSACT2_SETFSINFO:
+       {
                START_PROFILE_NESTED(Trans2_setfsinfo);
-               outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data, max_data_bytes);
+               outsize = call_trans2setfsinfo(
+                       conn, inbuf, outbuf, size, bufsize, 
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                END_PROFILE_NESTED(Trans2_setfsinfo);
                break;
+       }
 
        case TRANSACT2_QPATHINFO:
        case TRANSACT2_QFILEINFO:
+       {
                START_PROFILE_NESTED(Trans2_qpathinfo);
-               outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
-                                         &params, total_params, &data, total_data, max_data_bytes);
+               outsize = call_trans2qfilepathinfo(
+                       conn, inbuf, outbuf, size, bufsize, state->call,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, tran_call,
-                                         &params, total_params, &data, total_data, max_data_bytes);
+               outsize = call_trans2setfilepathinfo(
+                       conn, inbuf, outbuf, size, bufsize, state->call,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2findnotifyfirst(
+                       conn, inbuf, outbuf, size, bufsize, 
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2findnotifynext(
+                       conn, inbuf, outbuf, size, bufsize, 
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2mkdir(
+                       conn, inbuf, outbuf, size, bufsize,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2getdfsreferral(
+                       conn, inbuf, outbuf, size, bufsize,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                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, max_data_bytes);
+               outsize = call_trans2ioctl(
+                       conn, inbuf, outbuf, size, bufsize,
+                       &state->param, state->total_param,
+                       &state->data, state->total_data,
+                       state->max_data_return);
                END_PROFILE_NESTED(Trans2_ioctl);
                break;
+       }
+
        default:
                /* Error in request */
-               DEBUG(2,("Unknown request %d in trans2 call\n", tran_call));
-               SAFE_FREE(params);
-               SAFE_FREE(data);
+               DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
+               outsize = ERROR_DOS(ERRSRV,ERRerror);
+       }
+
+       return outsize;
+}
+
+/****************************************************************************
+ Reply to a SMBtrans2.
+ ****************************************************************************/
+
+int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,
+                int size, int bufsize)
+{
+       int outsize = 0;
+       unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+       unsigned int dscnt = SVAL(inbuf, smb_dscnt);
+       unsigned int psoff = SVAL(inbuf, smb_psoff);
+       unsigned int pscnt = SVAL(inbuf, smb_pscnt);
+       unsigned int tran_call = SVAL(inbuf, smb_setup0);
+       struct trans_state *state;
+       NTSTATUS result;
+
+       START_PROFILE(SMBtrans2);
+
+       result = allow_new_trans(conn->pending_trans, SVAL(inbuf, smb_mid));
+       if (!NT_STATUS_IS_OK(result)) {
+               DEBUG(2, ("Got invalid trans2 request: %s\n",
+                         nt_errstr(result)));
                END_PROFILE(SMBtrans2);
-               srv_signing_trans_stop();
-               return ERROR_DOS(ERRSRV,ERRerror);
+               return ERROR_NT(result);
+       }
+
+       if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
+            && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
+               END_PROFILE(SMBtrans2);
+               return ERROR_DOS(ERRSRV,ERRaccess);
+       }
+
+       if ((state = TALLOC_P(NULL, struct trans_state)) == NULL) {
+               DEBUG(0, ("talloc failed\n"));
+               END_PROFILE(SMBtrans2);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
+
+       state->cmd = SMBtrans2;
+
+       state->mid = SVAL(inbuf, smb_mid);
+       state->vuid = SVAL(inbuf, smb_uid);
+       state->setup_count = SVAL(inbuf, smb_suwcnt);
+       state->total_param = SVAL(inbuf, smb_tpscnt);
+       state->param = NULL;
+       state->total_data =  SVAL(inbuf, smb_tdscnt);
+       state->data = NULL;
+       state->max_param_return = SVAL(inbuf, smb_mprcnt);
+       state->max_data_return  = SVAL(inbuf, smb_mdrcnt);
+       state->max_setup_return = SVAL(inbuf, smb_msrcnt);
+       state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
+       state->one_way = BITSETW(inbuf+smb_vwv5,1);
+
+       state->call = tran_call;
+
+       /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
+          is so as a sanity check */
+       if (state->setup_count != 1) {
+               /*
+                * Need to have rc=0 for ioctl to get job id for OS/2.
+                *  Network printing will fail if function is not successful.
+                *  Similar function in reply.c will be used if protocol
+                *  is LANMAN1.0 instead of LM1.2X002.
+                *  Until DosPrintSetJobInfo with PRJINFO3 is supported,
+                *  outbuf doesn't have to be set(only job id is used).
+                */
+               if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) &&
+                               (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
+                               (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
+                       DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
+               } else {
+                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
+                       DEBUG(2,("Transaction is %d\n",tran_call));
+                       TALLOC_FREE(state);
+                       END_PROFILE(SMBtrans2);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
        }
-       
-       /* As we do not know how many data packets will need to be
-          returned here the various call_trans2xxxx calls
-          must send their own. Thus a call_trans2xxx routine only
-          returns a value other than -1 when it wants to send
-          an error packet. 
-       */
-       
-       srv_signing_trans_stop();
 
-       SAFE_FREE(params);
-       SAFE_FREE(data);
+       if ((dscnt > state->total_data) || (pscnt > state->total_param))
+               goto bad_param;
+
+       if (state->total_data) {
+               /* Can't use talloc here, the core routines do realloc on the
+                * params and data. */
+               state->data = SMB_MALLOC(state->total_data);
+               if (state->data == NULL) {
+                       DEBUG(0,("reply_trans2: data malloc fail for %u "
+                                "bytes !\n", (unsigned int)state->total_data));
+                       TALLOC_FREE(state);
+                       END_PROFILE(SMBtrans2);
+                       return(ERROR_DOS(ERRDOS,ERRnomem));
+               }
+               if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
+                       goto bad_param;
+               if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
+                   (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
+                       goto bad_param;
+
+               memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
+       }
+
+       if (state->total_param) {
+               /* Can't use talloc here, the core routines do realloc on the
+                * params and data. */
+               state->param = SMB_MALLOC(state->total_param);
+               if (state->param == NULL) {
+                       DEBUG(0,("reply_trans: param malloc fail for %u "
+                                "bytes !\n", (unsigned int)state->total_param));
+                       SAFE_FREE(state->data);
+                       TALLOC_FREE(state);
+                       END_PROFILE(SMBtrans2);
+                       return(ERROR_DOS(ERRDOS,ERRnomem));
+               } 
+               if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
+                       goto bad_param;
+               if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
+                   (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
+                       goto bad_param;
+
+               memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
+       }
+
+       state->received_data  = dscnt;
+       state->received_param = pscnt;
+
+       if ((state->received_param == state->total_param) &&
+           (state->received_data == state->total_data)) {
+
+               outsize = handle_trans2(conn, state, inbuf, outbuf,
+                                       size, bufsize);
+               SAFE_FREE(state->data);
+               SAFE_FREE(state->param);
+               TALLOC_FREE(state);
+               END_PROFILE(SMBtrans2);
+               return outsize;
+       }
+
+       DLIST_ADD(conn->pending_trans, state);
+
+       /* We need to send an interim response then receive the rest
+          of the parameter/data bytes */
+       outsize = set_message(outbuf,0,0,False);
+       show_msg(outbuf);
        END_PROFILE(SMBtrans2);
-       return outsize; /* If a correct response was needed the
-                          call_trans2xxx calls have already sent
-                          it. If outsize != -1 then it is returning */
+       return outsize;
 
   bad_param:
 
-       srv_signing_trans_stop();
-       SAFE_FREE(params);
-       SAFE_FREE(data);
+       DEBUG(0,("reply_trans2: invalid trans parameters\n"));
+       SAFE_FREE(state->data);
+       SAFE_FREE(state->param);
+       TALLOC_FREE(state);
        END_PROFILE(SMBtrans2);
        return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 }
+
+
+/****************************************************************************
+ Reply to a SMBtranss2
+ ****************************************************************************/
+
+int reply_transs2(connection_struct *conn,
+                 char *inbuf,char *outbuf,int size,int bufsize)
+{
+       int outsize = 0;
+       unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
+       struct trans_state *state;
+
+       START_PROFILE(SMBtranss2);
+
+       show_msg(inbuf);
+
+       for (state = conn->pending_trans; state != NULL;
+            state = state->next) {
+               if (state->mid == SVAL(inbuf,smb_mid)) {
+                       break;
+               }
+       }
+
+       if ((state == NULL) || (state->cmd != SMBtrans2)) {
+               END_PROFILE(SMBtranss2);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
+
+       /* Revise state->total_param and state->total_data in case they have
+          changed downwards */
+
+       if (SVAL(inbuf, smb_tpscnt) < state->total_param)
+               state->total_param = SVAL(inbuf, smb_tpscnt);
+       if (SVAL(inbuf, smb_tdscnt) < state->total_data)
+               state->total_data = SVAL(inbuf, smb_tdscnt);
+
+       pcnt = SVAL(inbuf, smb_spscnt);
+       poff = SVAL(inbuf, smb_spsoff);
+       pdisp = SVAL(inbuf, smb_spsdisp);
+
+       dcnt = SVAL(inbuf, smb_sdscnt);
+       doff = SVAL(inbuf, smb_sdsoff);
+       ddisp = SVAL(inbuf, smb_sdsdisp);
+
+       state->received_param += pcnt;
+       state->received_data += dcnt;
+               
+       if ((state->received_data > state->total_data) ||
+           (state->received_param > state->total_param))
+               goto bad_param;
+
+       if (pcnt) {
+               if (pdisp+pcnt > state->total_param)
+                       goto bad_param;
+               if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
+                       goto bad_param;
+               if (pdisp > state->total_param)
+                       goto bad_param;
+               if ((smb_base(inbuf) + poff + pcnt > inbuf + size) ||
+                   (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
+                       goto bad_param;
+               if (state->param + pdisp < state->param)
+                       goto bad_param;
+
+               memcpy(state->param+pdisp,smb_base(inbuf)+poff,
+                      pcnt);
+       }
+
+       if (dcnt) {
+               if (ddisp+dcnt > state->total_data)
+                       goto bad_param;
+               if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
+                       goto bad_param;
+               if (ddisp > state->total_data)
+                       goto bad_param;
+               if ((smb_base(inbuf) + doff + dcnt > inbuf + size) ||
+                   (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
+                       goto bad_param;
+               if (state->data + ddisp < state->data)
+                       goto bad_param;
+
+               memcpy(state->data+ddisp, smb_base(inbuf)+doff,
+                      dcnt);      
+       }
+
+       if ((state->received_param < state->total_param) ||
+           (state->received_data < state->total_data)) {
+               END_PROFILE(SMBtranss2);
+               return -1;
+       }
+
+       /* construct_reply_common has done us the favor to pre-fill the
+        * command field with SMBtranss2 which is wrong :-)
+        */
+       SCVAL(outbuf,smb_com,SMBtrans2);
+
+       outsize = handle_trans2(conn, state, inbuf, outbuf, size, bufsize);
+
+       DLIST_REMOVE(conn->pending_trans, state);
+       SAFE_FREE(state->data);
+       SAFE_FREE(state->param);
+       TALLOC_FREE(state);
+
+       if (outsize == 0) {
+               END_PROFILE(SMBtranss2);
+               return(ERROR_DOS(ERRSRV,ERRnosupport));
+       }
+       
+       END_PROFILE(SMBtranss2);
+       return(outsize);
+
+  bad_param:
+
+       DEBUG(0,("reply_transs2: invalid trans parameters\n"));
+       DLIST_REMOVE(conn->pending_trans, state);
+       SAFE_FREE(state->data);
+       SAFE_FREE(state->param);
+       TALLOC_FREE(state);
+       END_PROFILE(SMBtranss2);
+       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+}