From 88b07d3b7f084796cd843918b91f5cc4184cf9ef Mon Sep 17 00:00:00 2001 From: David Mulder Date: Mon, 21 Mar 2022 11:51:41 -0600 Subject: [PATCH] smbd: Move send_trans2_replies to smb1_trans2.c Signed-off-by: David Mulder Reviewed-by: Jeremy Allison --- source3/smbd/proto.h | 8 -- source3/smbd/smb1_trans2.c | 273 +++++++++++++++++++++++++++++++++++++ source3/smbd/smb1_trans2.h | 33 +++++ source3/smbd/smbd.h | 1 + source3/smbd/trans2.c | 225 ------------------------------ source3/wscript_build | 1 + 6 files changed, 308 insertions(+), 233 deletions(-) create mode 100644 source3/smbd/smb1_trans2.c create mode 100644 source3/smbd/smb1_trans2.h diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 7fb1a461368..e63e72e5ffe 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1096,14 +1096,6 @@ NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx, size_t *pnum_names); NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, struct ea_list *ea_list); -void send_trans2_replies(connection_struct *conn, - struct smb_request *req, - NTSTATUS status, - const char *params, - int paramsize, - const char *pdata, - int datasize, - int max_data_bytes); unsigned char *create_volume_objectid(connection_struct *conn, unsigned char objid[16]); NTSTATUS hardlink_internals(TALLOC_CTX *ctx, connection_struct *conn, diff --git a/source3/smbd/smb1_trans2.c b/source3/smbd/smb1_trans2.c new file mode 100644 index 00000000000..619cec0b0eb --- /dev/null +++ b/source3/smbd/smb1_trans2.c @@ -0,0 +1,273 @@ +/* + Unix SMB/CIFS implementation. + SMB transaction2 handling + Copyright (C) Jeremy Allison 1994-2007 + Copyright (C) Stefan (metze) Metzmacher 2003 + Copyright (C) Volker Lendecke 2005-2007 + Copyright (C) Steve French 2005 + Copyright (C) James Peach 2006-2007 + + Extensively modified by Andrew Tridgell, 1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "ntioctl.h" +#include "system/filesys.h" +#include "lib/util/time_basic.h" +#include "version.h" +#include "smbd/smbd.h" +#include "smbd/globals.h" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/xattr.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "libcli/security/security.h" +#include "trans2.h" +#include "auth.h" +#include "smbprofile.h" +#include "rpc_server/srv_pipe_hnd.h" +#include "printing.h" +#include "lib/util_ea.h" +#include "lib/readdir_attr.h" +#include "messages.h" +#include "libcli/smb/smb2_posix.h" +#include "lib/util/string_wrappers.h" +#include "source3/lib/substitute.h" +#include "source3/lib/adouble.h" + +/**************************************************************************** + Send the required number of replies back. + We assume all fields other than the data fields are + set correctly for the type of call. + HACK ! Always assumes smb_setup field is zero. +****************************************************************************/ + +void send_trans2_replies(connection_struct *conn, + struct smb_request *req, + NTSTATUS status, + const char *params, + int paramsize, + const char *pdata, + 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. + This takes precedence over the max_xmit field in the + global struct. These different max_xmit variables should + be merged as this is now too confusing */ + + int data_to_send = datasize; + int params_to_send = paramsize; + int useable_space; + const char *pp = params; + const char *pd = pdata; + int params_sent_thistime, data_sent_thistime, total_sent_thistime; + int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ + int data_alignment_offset = 0; + bool overflow = False; + struct smbXsrv_connection *xconn = req->xconn; + int max_send = xconn->smb1.sessions.max_send; + + /* 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; + overflow = True; + } + + /* If there genuinely are no parameters or data to send just send the empty packet */ + + if(params_to_send == 0 && data_to_send == 0) { + reply_outbuf(req, 10, 0); + if (NT_STATUS_V(status)) { + uint8_t eclass; + uint32_t ecode; + ntstatus_to_dos(status, &eclass, &ecode); + error_packet_set((char *)req->outbuf, + eclass, ecode, status, + __LINE__,__FILE__); + } + show_msg((char *)req->outbuf); + if (!srv_send_smb(xconn, + (char *)req->outbuf, + true, req->seqnum+1, + IS_CONN_ENCRYPTED(conn), + &req->pcd)) { + exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); + } + TALLOC_FREE(req->outbuf); + return; + } + + /* When sending params and data ensure that both are nicely aligned */ + /* Only do this alignment when there is also data to send - else + can cause NT redirector problems. */ + + if (((params_to_send % 4) != 0) && (data_to_send != 0)) + data_alignment_offset = 4 - (params_to_send % 4); + + /* Space is bufsize minus Netbios over TCP header minus SMB header */ + /* The alignment_offset is to align the param bytes on an even byte + boundary. NT 4.0 Beta needs this to work correctly. */ + + useable_space = max_send - (smb_size + + 2 * 10 /* wct */ + + alignment_offset + + data_alignment_offset); + + if (useable_space < 0) { + DEBUG(0, ("send_trans2_replies failed sanity useable_space " + "= %d!!!", useable_space)); + exit_server_cleanly("send_trans2_replies: Not enough space"); + } + + while (params_to_send || data_to_send) { + /* Calculate whether we will totally or partially fill this packet */ + + total_sent_thistime = params_to_send + data_to_send; + + /* We can never send more than useable_space */ + /* + * Note that 'useable_space' does not include the alignment offsets, + * but we must include the alignment offsets in the calculation of + * the length of the data we send over the wire, as the alignment offsets + * are sent here. Fix from Marc_Jacobsen@hp.com. + */ + + total_sent_thistime = MIN(total_sent_thistime, useable_space); + + reply_outbuf(req, 10, total_sent_thistime + alignment_offset + + data_alignment_offset); + + /* Set total params and data to be sent */ + SSVAL(req->outbuf,smb_tprcnt,paramsize); + SSVAL(req->outbuf,smb_tdrcnt,datasize); + + /* Calculate how many parameters and data we can fit into + * this packet. Parameters get precedence + */ + + params_sent_thistime = MIN(params_to_send,useable_space); + data_sent_thistime = useable_space - params_sent_thistime; + data_sent_thistime = MIN(data_sent_thistime,data_to_send); + + SSVAL(req->outbuf,smb_prcnt, params_sent_thistime); + + /* smb_proff is the offset from the start of the SMB header to the + parameter bytes, however the first 4 bytes of outbuf are + the Netbios over TCP header. Thus use smb_base() to subtract + them from the calculation */ + + SSVAL(req->outbuf,smb_proff, + ((smb_buf(req->outbuf)+alignment_offset) + - smb_base(req->outbuf))); + + if(params_sent_thistime == 0) + SSVAL(req->outbuf,smb_prdisp,0); + else + /* Absolute displacement of param bytes sent in this packet */ + SSVAL(req->outbuf,smb_prdisp,pp - params); + + SSVAL(req->outbuf,smb_drcnt, data_sent_thistime); + if(data_sent_thistime == 0) { + SSVAL(req->outbuf,smb_droff,0); + SSVAL(req->outbuf,smb_drdisp, 0); + } else { + /* The offset of the data bytes is the offset of the + parameter bytes plus the number of parameters being sent this time */ + SSVAL(req->outbuf, smb_droff, + ((smb_buf(req->outbuf)+alignment_offset) + - smb_base(req->outbuf)) + + params_sent_thistime + data_alignment_offset); + SSVAL(req->outbuf,smb_drdisp, pd - pdata); + } + + /* Initialize the padding for alignment */ + + if (alignment_offset != 0) { + memset(smb_buf(req->outbuf), 0, alignment_offset); + } + + /* Copy the param bytes into the packet */ + + if(params_sent_thistime) { + memcpy((smb_buf(req->outbuf)+alignment_offset), pp, + params_sent_thistime); + } + + /* Copy in the data bytes */ + if(data_sent_thistime) { + if (data_alignment_offset != 0) { + memset((smb_buf(req->outbuf)+alignment_offset+ + params_sent_thistime), 0, + data_alignment_offset); + } + memcpy(smb_buf(req->outbuf)+alignment_offset + +params_sent_thistime+data_alignment_offset, + pd,data_sent_thistime); + } + + DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", + params_sent_thistime, data_sent_thistime, useable_space)); + DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", + params_to_send, data_to_send, paramsize, datasize)); + + if (overflow) { + error_packet_set((char *)req->outbuf, + ERRDOS,ERRbufferoverflow, + STATUS_BUFFER_OVERFLOW, + __LINE__,__FILE__); + } else if (NT_STATUS_V(status)) { + uint8_t eclass; + uint32_t ecode; + ntstatus_to_dos(status, &eclass, &ecode); + error_packet_set((char *)req->outbuf, + eclass, ecode, status, + __LINE__,__FILE__); + } + + /* Send the packet */ + show_msg((char *)req->outbuf); + if (!srv_send_smb(xconn, + (char *)req->outbuf, + true, req->seqnum+1, + IS_CONN_ENCRYPTED(conn), + &req->pcd)) + exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); + + TALLOC_FREE(req->outbuf); + + pp += params_sent_thistime; + pd += data_sent_thistime; + + params_to_send -= params_sent_thistime; + data_to_send -= data_sent_thistime; + + /* Sanity check */ + if(params_to_send < 0 || data_to_send < 0) { + DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", + params_to_send, data_to_send)); + return; + } + } + + return; +} diff --git a/source3/smbd/smb1_trans2.h b/source3/smbd/smb1_trans2.h new file mode 100644 index 00000000000..6eee7ca4aa5 --- /dev/null +++ b/source3/smbd/smb1_trans2.h @@ -0,0 +1,33 @@ +/* + Unix SMB/CIFS implementation. + SMB transaction2 handling + Copyright (C) Jeremy Allison 1994-2007 + Copyright (C) Stefan (metze) Metzmacher 2003 + Copyright (C) Volker Lendecke 2005-2007 + Copyright (C) Steve French 2005 + Copyright (C) James Peach 2006-2007 + + Extensively modified by Andrew Tridgell, 1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +void send_trans2_replies(connection_struct *conn, + struct smb_request *req, + NTSTATUS status, + const char *params, + int paramsize, + const char *pdata, + int datasize, + int max_data_bytes); diff --git a/source3/smbd/smbd.h b/source3/smbd/smbd.h index 4a9cb183c74..f2c3abcda2d 100644 --- a/source3/smbd/smbd.h +++ b/source3/smbd/smbd.h @@ -41,6 +41,7 @@ struct dptr_struct; #include "smbd/smb1_signing.h" #include "smbd/smb1_process.h" #include "smbd/smb1_utils.h" +#include "smbd/smb1_trans2.h" #endif struct trans_state { diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f24a230d940..45544141adc 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -941,231 +941,6 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list * return name_list; } -/**************************************************************************** - Send the required number of replies back. - We assume all fields other than the data fields are - set correctly for the type of call. - HACK ! Always assumes smb_setup field is zero. -****************************************************************************/ - -void send_trans2_replies(connection_struct *conn, - struct smb_request *req, - NTSTATUS status, - const char *params, - int paramsize, - const char *pdata, - 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. - This takes precedence over the max_xmit field in the - global struct. These different max_xmit variables should - be merged as this is now too confusing */ - - int data_to_send = datasize; - int params_to_send = paramsize; - int useable_space; - const char *pp = params; - const char *pd = pdata; - int params_sent_thistime, data_sent_thistime, total_sent_thistime; - int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */ - int data_alignment_offset = 0; - bool overflow = False; - struct smbXsrv_connection *xconn = req->xconn; - int max_send = xconn->smb1.sessions.max_send; - - /* 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; - overflow = True; - } - - /* If there genuinely are no parameters or data to send just send the empty packet */ - - if(params_to_send == 0 && data_to_send == 0) { - reply_outbuf(req, 10, 0); - if (NT_STATUS_V(status)) { - uint8_t eclass; - uint32_t ecode; - ntstatus_to_dos(status, &eclass, &ecode); - error_packet_set((char *)req->outbuf, - eclass, ecode, status, - __LINE__,__FILE__); - } - show_msg((char *)req->outbuf); - if (!srv_send_smb(xconn, - (char *)req->outbuf, - true, req->seqnum+1, - IS_CONN_ENCRYPTED(conn), - &req->pcd)) { - exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); - } - TALLOC_FREE(req->outbuf); - return; - } - - /* When sending params and data ensure that both are nicely aligned */ - /* Only do this alignment when there is also data to send - else - can cause NT redirector problems. */ - - if (((params_to_send % 4) != 0) && (data_to_send != 0)) - data_alignment_offset = 4 - (params_to_send % 4); - - /* Space is bufsize minus Netbios over TCP header minus SMB header */ - /* The alignment_offset is to align the param bytes on an even byte - boundary. NT 4.0 Beta needs this to work correctly. */ - - useable_space = max_send - (smb_size - + 2 * 10 /* wct */ - + alignment_offset - + data_alignment_offset); - - if (useable_space < 0) { - DEBUG(0, ("send_trans2_replies failed sanity useable_space " - "= %d!!!", useable_space)); - exit_server_cleanly("send_trans2_replies: Not enough space"); - } - - while (params_to_send || data_to_send) { - /* Calculate whether we will totally or partially fill this packet */ - - total_sent_thistime = params_to_send + data_to_send; - - /* We can never send more than useable_space */ - /* - * Note that 'useable_space' does not include the alignment offsets, - * but we must include the alignment offsets in the calculation of - * the length of the data we send over the wire, as the alignment offsets - * are sent here. Fix from Marc_Jacobsen@hp.com. - */ - - total_sent_thistime = MIN(total_sent_thistime, useable_space); - - reply_outbuf(req, 10, total_sent_thistime + alignment_offset - + data_alignment_offset); - - /* Set total params and data to be sent */ - SSVAL(req->outbuf,smb_tprcnt,paramsize); - SSVAL(req->outbuf,smb_tdrcnt,datasize); - - /* Calculate how many parameters and data we can fit into - * this packet. Parameters get precedence - */ - - params_sent_thistime = MIN(params_to_send,useable_space); - data_sent_thistime = useable_space - params_sent_thistime; - data_sent_thistime = MIN(data_sent_thistime,data_to_send); - - SSVAL(req->outbuf,smb_prcnt, params_sent_thistime); - - /* smb_proff is the offset from the start of the SMB header to the - parameter bytes, however the first 4 bytes of outbuf are - the Netbios over TCP header. Thus use smb_base() to subtract - them from the calculation */ - - SSVAL(req->outbuf,smb_proff, - ((smb_buf(req->outbuf)+alignment_offset) - - smb_base(req->outbuf))); - - if(params_sent_thistime == 0) - SSVAL(req->outbuf,smb_prdisp,0); - else - /* Absolute displacement of param bytes sent in this packet */ - SSVAL(req->outbuf,smb_prdisp,pp - params); - - SSVAL(req->outbuf,smb_drcnt, data_sent_thistime); - if(data_sent_thistime == 0) { - SSVAL(req->outbuf,smb_droff,0); - SSVAL(req->outbuf,smb_drdisp, 0); - } else { - /* The offset of the data bytes is the offset of the - parameter bytes plus the number of parameters being sent this time */ - SSVAL(req->outbuf, smb_droff, - ((smb_buf(req->outbuf)+alignment_offset) - - smb_base(req->outbuf)) - + params_sent_thistime + data_alignment_offset); - SSVAL(req->outbuf,smb_drdisp, pd - pdata); - } - - /* Initialize the padding for alignment */ - - if (alignment_offset != 0) { - memset(smb_buf(req->outbuf), 0, alignment_offset); - } - - /* Copy the param bytes into the packet */ - - if(params_sent_thistime) { - memcpy((smb_buf(req->outbuf)+alignment_offset), pp, - params_sent_thistime); - } - - /* Copy in the data bytes */ - if(data_sent_thistime) { - if (data_alignment_offset != 0) { - memset((smb_buf(req->outbuf)+alignment_offset+ - params_sent_thistime), 0, - data_alignment_offset); - } - memcpy(smb_buf(req->outbuf)+alignment_offset - +params_sent_thistime+data_alignment_offset, - pd,data_sent_thistime); - } - - DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n", - params_sent_thistime, data_sent_thistime, useable_space)); - DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n", - params_to_send, data_to_send, paramsize, datasize)); - - if (overflow) { - error_packet_set((char *)req->outbuf, - ERRDOS,ERRbufferoverflow, - STATUS_BUFFER_OVERFLOW, - __LINE__,__FILE__); - } else if (NT_STATUS_V(status)) { - uint8_t eclass; - uint32_t ecode; - ntstatus_to_dos(status, &eclass, &ecode); - error_packet_set((char *)req->outbuf, - eclass, ecode, status, - __LINE__,__FILE__); - } - - /* Send the packet */ - show_msg((char *)req->outbuf); - if (!srv_send_smb(xconn, - (char *)req->outbuf, - true, req->seqnum+1, - IS_CONN_ENCRYPTED(conn), - &req->pcd)) - exit_server_cleanly("send_trans2_replies: srv_send_smb failed."); - - TALLOC_FREE(req->outbuf); - - pp += params_sent_thistime; - pd += data_sent_thistime; - - params_to_send -= params_sent_thistime; - data_to_send -= data_sent_thistime; - - /* Sanity check */ - if(params_to_send < 0 || data_to_send < 0) { - DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!", - params_to_send, data_to_send)); - return; - } - } - - return; -} - /**************************************************************************** Reply to a TRANSACT2_OPEN. ****************************************************************************/ diff --git a/source3/wscript_build b/source3/wscript_build index a5448d871ff..e3c4eddb94d 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -613,6 +613,7 @@ if bld.CONFIG_SET('WITH_SMB1SERVER'): smbd/smb1_service.c smbd/smb1_signing.c smbd/smb1_process.c + smbd/smb1_trans2.c ''' else: SMB1_SOURCES = ''