summaryrefslogtreecommitdiffstats
path: root/source4/libcli/raw/rawtrans.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source4/libcli/raw/rawtrans.c446
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..1a1c836
--- /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,
+ &param,
+ 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,
+ &param,
+ 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);
+}