round 1: ndr on top of trans2
Amin Azez
azez at ufomechanic.net
Thu Jan 17 17:29:40 GMT 2008
It'll be a new day before I can test this, but taken that it works (or
can be made to) is their anything architecturally offensive in it?
Have I missed any useful use of params (which I ignore)?
smbcli_ndr_request_trans2_send() sends (or at least constructs right
now) a trans2 smbcli_request based on an NDR representation produced by
gen_ndr generated code, and packed directly onto the smbcli_request, to
save tallocs and memcpy.
two helper functions are used:
ndr_push_init_smbcli_ctx() to "wrap" an smbcli_request in an ndr_push
_ndr_push_smbcli_update() to update the pointers and offsets in the
smbcli_request after ndr_push has finished with it.
/*
send a trans2 request based on a NDR encoding. Encodes directly to the
smbcli_request
*/
struct smbcli_request *smbcli_ndr_request_trans2_send(struct smbcli_tree
*tree,
uint32_t trans2_subop,
const struct ndr_interface_table *table,
uint32_t opnum,
void *r)
{
int setup_count=3; /* trans2_subop + opnum */
int wct = 14 + setup_count;
const struct ndr_interface_call *call;
struct ndr_push *push;
NTSTATUS status;
DATA_BLOB request;
struct smbcli_request *req;
/* set up a trans2 request */
req = smbcli_request_setup(tree, SMBtrans2, wct,
NDR_BASE_MARSHALL_SIZE);
if (! req) return NULL;
/* setup for a ndr_push_* call */
push = ndr_push_init_smbcli_ctx(req);
if (!push) {
return NULL;
}
/* fill out 3 bytes trans2 padding - "cos we do!"
BTW we know we have at least 3 bytes allocated so we didn't check */
req->out.data[0]=0;
req->out.data[1]=0;
req->out.data[2]=0;
push->offset+=3;
call = &table->calls[opnum];
if (0) {
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}
/* push the structure into a blob */
status = call->ndr_push(push, NDR_IN, r);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(2,("Unable to ndr_push structure in
dcerpc_ndr_request_send - %s\n",
nt_errstr(status)));
talloc_free(push);
return NULL;
}
ndr_push_smbcli_update(push);
/* retrieve the blob */
request = ndr_push_blob(push);
/* primary request */
SSVAL(req->out.vwv,VWV(0),0); /* param total */
/* does data length include the padding */
SSVAL(req->out.vwv,VWV(1),req->out.data_size - 3); /* data total */
SSVAL(req->out.vwv,VWV(2),0); /* max_param */
SSVAL(req->out.vwv,VWV(3),0); /* max_data what for?? */
SSVAL(req->out.vwv,VWV(4),0); /* max_setup */
SSVAL(req->out.vwv,VWV(5),0); /* flags */
SIVAL(req->out.vwv,VWV(6),0); /* timeout */
SSVAL(req->out.vwv,VWV(8),0); /* reserved */
SSVAL(req->out.vwv,VWV(9),0); /* param count */
SSVAL(req->out.vwv,VWV(10),0); /* param offset */
SSVAL(req->out.vwv,VWV(11),req->out.data_size - 3); /* data length */
SSVAL(req->out.vwv,VWV(12),PTR_DIFF(req->out.data,req->out.hdr)+3);
/* data offset */
SSVAL(req->out.vwv,VWV(13),setup_count); /* trans2 subpo and rpc
opnum */
/* setup[0] trans2 sub-op */
SSVAL(req->out.vwv,VWV(14),trans2_subop);
/* setup[1..2] rpc op */
SIVAL(req->out.vwv, VWV(16), opnum);
/* should we do anything with ndr->ptr_count */
DEBUG(10,("smbcli_request packet:\n"));
dump_data(10, request.data, request.length);
/* we can free push without freeing smbcli_request */
talloc_free(push);
if (!smbcli_request_send(req)) {
smbcli_request_destroy(req);
return NULL;
}
return req;
}
/* helper macro because ndr_*.h will be exposed to the caller but not to
rawrequest.c */
#define ndr_push_smbcli_update(ndr) \
_ndr_push_smbcli_update ((struct smbcli_request *)
talloc_parent(ndr), \
ndr->data, ndr->alloc_size, ndr->offset)
/===== to go in rawrequest.c */
/* create a ndr_push structure using the data portion of an intialized
smbcli_request */
_PUBLIC_ struct ndr_push *ndr_push_init_smbcli_ctx(struct smbcli_request
*req)
{
struct ndr_push *ndr;
ndr = talloc_zero(req, struct ndr_push);
if (!ndr) {
return NULL;
}
ndr->flags = 0;
ndr->alloc_size = req->out.allocated;
ndr->data = req->out.buffer;
ndr->offset=PTR_DIFF(req->out.data, req->out.buffer);
if (!ndr->data) {
return NULL;
}
return ndr;
}
/*
helper to update req->out after it has finished being "fronted" by
ndr_push.
As we don't want to import ndr_push, certain members are passed directly,
the ndr_push_smbcli_update macro helps with this
*/
void _ndr_push_smbcli_update(struct smbcli_request *req,
uint8_t* ndr_data,
uint32_t ndr_alloc_size,
uint32_t ndr_offset)
{
if (ndr_data != req->out.buffer) {
/* a re-alloc has occured */
req->out.allocated = ndr_alloc_size;
/* update the pointers into the packet */
req->out.data = ndr_data + PTR_DIFF(req->out.data, req->out.buffer);
req->out.ptr = ndr_data + PTR_DIFF(req->out.ptr, req->out.buffer);
req->out.vwv = ndr_data + PTR_DIFF(req->out.vwv, req->out.buffer);
req->out.hdr = ndr_data + PTR_DIFF(req->out.hdr, req->out.buffer);
req->out.buffer = ndr_data;
}
smbcli_req_grow_data(req, ndr_offset - PTR_DIFF(req->out.data,
req->out.buffer));
}
More information about the samba-technical
mailing list