diff options
Diffstat (limited to 'source4/libcli/raw/rawtrans.c')
-rw-r--r-- | source4/libcli/raw/rawtrans.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/source4/libcli/raw/rawtrans.c b/source4/libcli/raw/rawtrans.c new file mode 100644 index 0000000..de3e054 --- /dev/null +++ b/source4/libcli/raw/rawtrans.c @@ -0,0 +1,446 @@ +/* + Unix SMB/CIFS implementation. + raw trans/trans2/nttrans operations + + Copyright (C) James Myers 2003 <myersjj@samba.org> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include <tevent.h> +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "../libcli/smb/smbXcli_base.h" + +static void smb_raw_trans_backend_done(struct tevent_req *subreq); + +static struct smbcli_request *smb_raw_trans_backend_send(struct smbcli_tree *tree, + struct smb_trans2 *parms, + uint8_t command) +{ + struct smbcli_request *req; + uint8_t additional_flags; + uint8_t clear_flags; + uint16_t additional_flags2; + uint16_t clear_flags2; + uint32_t pid; + struct smbXcli_tcon *tcon = NULL; + struct smbXcli_session *session = NULL; + const char *pipe_name = NULL; + uint8_t s; + uint32_t timeout_msec; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, command, parms->in.setup_count, tmp); + if (req == NULL) { + return NULL; + } + + additional_flags = CVAL(req->out.hdr, HDR_FLG); + additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); + pid = SVAL(req->out.hdr, HDR_PID); + pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; + + if (req->session) { + session = req->session->smbXcli; + } + + if (req->tree) { + tcon = req->tree->smbXcli; + } + + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; + + timeout_msec = req->transport->options.request_timeout * 1000; + + for (s=0; s < parms->in.setup_count; s++) { + SSVAL(req->out.vwv, VWV(s), parms->in.setup[s]); + } + + if (parms->in.params.length > 0) { + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + } + if (parms->in.data.length > 0) { + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); + } + + if (command == SMBtrans && parms->in.trans_name) { + pipe_name = parms->in.trans_name; + } + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + command, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, + tcon, + session, + pipe_name, + 0xFFFF, /* fid */ + 0, /* function */ + parms->in.flags, + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { + talloc_free(req); + return NULL; + } + tevent_req_set_callback(req->subreqs[0], + smb_raw_trans_backend_done, + req); + + return req; +} + +static void smb_raw_trans_backend_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t s; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + req->trans2.out.setup_count = num_setup; + req->trans2.out.setup = talloc_array(req, uint16_t, num_setup); + if (req->trans2.out.setup == NULL) { + req->state = SMBCLI_REQUEST_ERROR; + req->status = NT_STATUS_NO_MEMORY; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + for (s = 0; s < num_setup; s++) { + req->trans2.out.setup[s] = SVAL(setup, VWV(s)); + } + + req->trans2.out.params.data = param; + req->trans2.out.params.length = num_param; + + req->trans2.out.data.data = data; + req->trans2.out.data.length = num_data; + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } +} + +static NTSTATUS smb_raw_trans_backend_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + parms->out = req->trans2.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); + +failed: + return smbcli_request_destroy(req); +} + +_PUBLIC_ struct smbcli_request *smb_raw_trans_send(struct smbcli_tree *tree, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_send(tree, parms, SMBtrans); +} + +_PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_recv(req, mem_ctx, parms); +} + +_PUBLIC_ NTSTATUS smb_raw_trans(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + struct smbcli_request *req; + req = smb_raw_trans_send(tree, parms); + if (!req) return NT_STATUS_UNSUCCESSFUL; + return smb_raw_trans_recv(req, mem_ctx, parms); +} + +struct smbcli_request *smb_raw_trans2_send(struct smbcli_tree *tree, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_send(tree, parms, SMBtrans2); +} + +NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + return smb_raw_trans_backend_recv(req, mem_ctx, parms); +} + +NTSTATUS smb_raw_trans2(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_trans2 *parms) +{ + struct smbcli_request *req; + req = smb_raw_trans2_send(tree, parms); + if (!req) return NT_STATUS_UNSUCCESSFUL; + return smb_raw_trans2_recv(req, mem_ctx, parms); +} + +static void smb_raw_nttrans_done(struct tevent_req *subreq); + +struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree, + struct smb_nttrans *parms) +{ + struct smbcli_request *req; + uint8_t additional_flags; + uint8_t clear_flags; + uint16_t additional_flags2; + uint16_t clear_flags2; + uint32_t pid; + struct smbXcli_tcon *tcon = NULL; + struct smbXcli_session *session = NULL; + uint32_t timeout_msec; + uint32_t tmp; + + tmp = parms->in.params.length + parms->in.data.length; + + req = smbcli_request_setup(tree, SMBnttrans, parms->in.setup_count, tmp); + if (req == NULL) { + return NULL; + } + + additional_flags = CVAL(req->out.hdr, HDR_FLG); + additional_flags2 = SVAL(req->out.hdr, HDR_FLG2); + pid = SVAL(req->out.hdr, HDR_PID); + pid |= SVAL(req->out.hdr, HDR_PIDHIGH)<<16; + + if (req->session) { + session = req->session->smbXcli; + } + + if (req->tree) { + tcon = req->tree->smbXcli; + } + + clear_flags = ~additional_flags; + clear_flags2 = ~additional_flags2; + + timeout_msec = req->transport->options.request_timeout * 1000; + + if (parms->in.setup_count > 0) { + memcpy( + req->out.vwv, parms->in.setup, parms->in.setup_count * 2); + } + + if (parms->in.params.length > 0) { + memcpy(req->out.data, + parms->in.params.data, + parms->in.params.length); + } + if (parms->in.data.length > 0) { + memcpy(req->out.data + parms->in.params.length, + parms->in.data.data, + parms->in.data.length); + } + + req->subreqs[0] = smb1cli_trans_send(req, + req->transport->ev, + req->transport->conn, + SMBnttrans, + additional_flags, + clear_flags, + additional_flags2, + clear_flags2, + timeout_msec, + pid, + tcon, + session, + NULL, /* pipe_name */ + 0xFFFF, /* fid */ + parms->in.function, + 0, /* flags */ + (uint16_t *)req->out.vwv, + parms->in.setup_count, + parms->in.max_setup, + req->out.data, + parms->in.params.length, + parms->in.max_param, + req->out.data+ + parms->in.params.length, + parms->in.data.length, + parms->in.max_data); + if (req->subreqs[0] == NULL) { + talloc_free(req); + return NULL; + } + tevent_req_set_callback(req->subreqs[0], + smb_raw_nttrans_done, + req); + + return req; +} + +static void smb_raw_nttrans_done(struct tevent_req *subreq) +{ + struct smbcli_request *req = + tevent_req_callback_data(subreq, + struct smbcli_request); + struct smbcli_transport *transport = req->transport; + uint16_t *setup = NULL; + uint8_t num_setup = 0; + uint8_t *param = NULL; + uint32_t num_param = 0; + uint8_t *data = NULL; + uint32_t num_data = 0; + + req->status = smb1cli_trans_recv(req->subreqs[0], req, + &req->flags2, + &setup, + 0, /* min_setup */ + &num_setup, + ¶m, + 0, /* min_param */ + &num_param, + &data, + 0, /* min_data */ + &num_data); + TALLOC_FREE(req->subreqs[0]); + if (NT_STATUS_IS_ERR(req->status)) { + req->state = SMBCLI_REQUEST_ERROR; + transport->error.e.nt_status = req->status; + transport->error.etype = ETYPE_SMB; + if (req->async.fn) { + req->async.fn(req); + } + return; + } + + req->nttrans.out.setup_count = num_setup; + req->nttrans.out.setup = (uint8_t *)setup; + + req->nttrans.out.params.data = param; + req->nttrans.out.params.length = num_param; + + req->nttrans.out.data.data = data; + req->nttrans.out.data.length = num_data; + + transport->error.e.nt_status = req->status; + if (NT_STATUS_IS_OK(req->status)) { + transport->error.etype = ETYPE_NONE; + } else { + transport->error.etype = ETYPE_SMB; + } + + req->state = SMBCLI_REQUEST_DONE; + if (req->async.fn) { + req->async.fn(req); + } +} + +NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req, + TALLOC_CTX *mem_ctx, + struct smb_nttrans *parms) +{ + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; + } + + parms->out = req->nttrans.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); + +failed: + return smbcli_request_destroy(req); +} + +/**************************************************************************** + receive a SMB nttrans response allocating the necessary memory + ****************************************************************************/ +NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree, + TALLOC_CTX *mem_ctx, + struct smb_nttrans *parms) +{ + struct smbcli_request *req; + + req = smb_raw_nttrans_send(tree, parms); + if (!req) { + return NT_STATUS_UNSUCCESSFUL; + } + + return smb_raw_nttrans_recv(req, mem_ctx, parms); +} |