1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source4/libcli/raw/rawtrans.c
Stefan Metzmacher b9100a7ac4 libcli/smb: pass down smbXcli_tcon to smb1cli_req_create/send() and smb1cli_trans*
metze

Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Tue Jul 24 21:22:44 CEST 2012 on sn-devel-104
2012-07-24 21:22:44 +02:00

438 lines
11 KiB
C

/*
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]);
}
memcpy(req->out.data,
parms->in.params.data,
parms->in.params.length);
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;
memcpy(req->out.vwv,
parms->in.setup,
parms->in.setup_count * 2);
memcpy(req->out.data,
parms->in.params.data,
parms->in.params.length);
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);
}