From 6fd4813ece5e03c92334acfa7e168cd7d0248919 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 14 Aug 2006 16:53:14 +0000 Subject: r17541: When returning a trans2 request, if the "max data bytes returned" is less than the amount we want to send, return what we can and set STATUS_BUFFER_OVERFLOW (doserror ERRDOS,ERRbufferoverflow). Required by OS/2 to handle EA's that are too large. It's hard to test this in Samba4 smbtorture as the max data bytes returned is hard coded at 0xffff (as it is in the Samba3 client libraries also). I used a custom version of Samba4 smbtorture to test this out. Might add a "max data bytes" param to make this testable in the build farm. Confirmed by "Guenter Kukkukk (sambaos2)" and Andreas Taegener that this fixes the issue. Jeremy. (This used to be commit ff2f1202b76991a404dae8df17c36f8135c8dc51) --- source3/include/doserr.h | 2 ++ source3/smbd/blocking.c | 3 ++- source3/smbd/error.c | 8 +++++-- source3/smbd/trans2.c | 61 +++++++++++++++++++++++++++++------------------- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/source3/include/doserr.h b/source3/include/doserr.h index 8f8ea06696..bc381e3351 100644 --- a/source3/include/doserr.h +++ b/source3/include/doserr.h @@ -44,6 +44,7 @@ #define ERRnomem 8 /* Out of memory */ #define ERRbadmem 9 /* Invalid memory block address */ #define ERRbadenv 10 /* Invalid environment */ +#define ERRbadformat 11 /* Bad Format */ #define ERRbadaccess 12 /* Invalid open mode */ #define ERRbaddata 13 /* Invalid data (only from ioctl call) */ #define ERRres 14 /* reserved */ @@ -60,6 +61,7 @@ #define ERRfilexists 80 /* File in operation already exists */ #define ERRinvalidparam 87 #define ERRcannotopen 110 /* Cannot open the file specified */ +#define ERRbufferoverflow 111 #define ERRinsufficientbuffer 122 #define ERRinvalidname 123 /* Invalid name */ #define ERRunknownlevel 124 diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 0304a6559f..2f89759ffd 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -458,7 +458,8 @@ static BOOL process_trans2(blocking_lock_record *blr) construct_reply_common(inbuf, outbuf); SCVAL(outbuf,smb_com,SMBtrans2); SSVAL(params,0,0); - send_trans2_replies(outbuf, max_send, params, 2, NULL, 0); + /* Fake up max_data_bytes here - we know it fits. */ + send_trans2_replies(outbuf, max_send, params, 2, NULL, 0, 0xffff); return True; } diff --git a/source3/smbd/error.c b/source3/smbd/error.c index 409781eaa9..0860b7d1d9 100644 --- a/source3/smbd/error.c +++ b/source3/smbd/error.c @@ -81,9 +81,8 @@ BOOL use_nt_status(void) If the override errors are set they take precedence over any passed in values. ****************************************************************************/ -int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) +void error_packet_set(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) { - int outsize = set_message(outbuf,0,0,True); BOOL force_nt_status = False; BOOL force_dos_status = False; @@ -125,6 +124,11 @@ int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, in eclass, ecode)); } +} +int error_packet(char *outbuf, uint8 eclass, uint32 ecode, NTSTATUS ntstatus, int line, const char *file) +{ + int outsize = set_message(outbuf,0,0,True); + error_packet_set(outbuf, eclass, ecode, ntstatus, line, file); return outsize; } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 82052127c9..d2806753d3 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -573,7 +573,8 @@ int send_trans2_replies(char *outbuf, char *params, int paramsize, char *pdata, - int datasize) + int datasize, + int max_data_bytes) { /* As we are using a protocol > LANMAN1 then the max_send variable must have been set in the sessetupX call. @@ -594,6 +595,18 @@ int send_trans2_replies(char *outbuf, set_message(outbuf,10,0,True); + /* Modify the data_to_send and datasize and set the error if + we're trying to send more than max_data_bytes. We still send + the part of the packet(s) that fit. Strange, but needed + for OS/2. */ + + if (max_data_bytes > 0 && datasize > max_data_bytes) { + DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n", + max_data_bytes, datasize )); + datasize = data_to_send = max_data_bytes; + error_packet_set(outbuf,ERRDOS,ERRbufferoverflow,STATUS_BUFFER_OVERFLOW,__LINE__,__FILE__); + } + /* If there genuinely are no parameters or data to send just send the empty packet */ if(params_to_send == 0 && data_to_send == 0) { @@ -932,7 +945,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i } /* Send the required number of replies */ - send_trans2_replies(outbuf, bufsize, params, 30, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 30, *ppdata, 0, max_data_bytes); return -1; } @@ -1858,7 +1871,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,6,0); /* Never an EA error */ SSVAL(params,8,last_entry_off); - send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata)); + send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); if ((! *directory) && dptr_path(dptr_num)) slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); @@ -2140,7 +2153,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,4,0); /* Never an EA error */ SSVAL(params,6,last_entry_off); - send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata)); + send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata), max_data_bytes); if ((! *directory) && dptr_path(dptr_num)) slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num)); @@ -2503,7 +2516,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned } - send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len); + send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) ); @@ -3633,7 +3646,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd return ERROR_NT(NT_STATUS_INVALID_LEVEL); } - send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size); + send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size, max_data_bytes); return(-1); } @@ -3782,7 +3795,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name )); SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } else return (UNIXERROR(ERRDOS,ERRbadpath)); @@ -3894,7 +3907,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char if ((total_data == 4) && (IVAL(pdata,0) == 4)) { /* We're done. We only get EA info in this call. */ SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -3925,7 +3938,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char /* We're done. We only get EA info in this call. */ SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4117,7 +4130,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4146,7 +4159,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char /* We're done. We only get position info in this call. */ SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4170,7 +4183,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char /* We're done. We only get mode info in this call. */ SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4285,7 +4298,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", inherit_access_acl(conn, fname, unixmode); SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4368,7 +4381,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) return(UNIXERROR(ERRDOS,ERRnoaccess)); SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4392,7 +4405,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4446,7 +4459,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } process_pending_change_notify_queue((time_t)0); SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4497,7 +4510,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } #endif @@ -4603,7 +4616,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4729,7 +4742,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", } SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4834,7 +4847,7 @@ static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, SSVAL(params,0,0); - send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes); return(-1); } @@ -4883,7 +4896,7 @@ static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char if(fnf_handle == 0) fnf_handle = 257; - send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0, max_data_bytes); return(-1); } @@ -4911,7 +4924,7 @@ static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char SSVAL(params,0,0); /* No changes */ SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0); + send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0, max_data_bytes); return(-1); } @@ -4945,7 +4958,7 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* return UNIXERROR(ERRDOS,ERRbadfile); SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size); + send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size, max_data_bytes); return(-1); } @@ -4983,7 +4996,7 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, SSVAL(pdata,0,fsp->rap_print_jobid); /* Job number */ srvstr_push( outbuf, pdata + 2, global_myname(), 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */ srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ - send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32); + send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32, max_data_bytes); return(-1); } else { DEBUG(2,("Unknown TRANS2_IOCTL\n")); -- cgit