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