Ethereal-dev: Re: [Ethereal-dev] Re: dissect_ndr_pointer() experimental unfinishedimplemen

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Ronnie Sahlberg" <sahlberg@xxxxxxxxxxxxxxxx>
Date: Mon, 14 Jan 2002 19:22:38 +1100
----- Original Message -----
From: "Todd Sabin"
Sent: Monday, January 14, 2002 12:06 PM
Subject: [Ethereal-dev] Re: dissect_ndr_pointer() experimental
unfinishedimplementation, comments wanted


> "Ronnie Sahlberg" writes:
>
> > Hi Todd, hi list
> >
>
> Hi.  (Sorry I never wrote back about the other ndr stuff.  I got
> diverted onto something else.  It seems Tim's way ahead of me,
> anyway.)

No worries. Got distracted myself as well.

>
> > After reading up a bit on how dcerpc encodes pointers into the pdu's
> > I came up with a crude dissect_ndr_pointer() function.
>
> Well, you've chosen a particularly nasty problem.  Be great if you
> solve it, though.

I will try.
Though I think the array stuff seems much more hairy to be honest,
especially the stuff like
when conformant arrays embedded deep inside a structure gets its header
moved to the beginning of the encoded data.

> The idea of passing a callback which is responsible for dissecting the
> pointed to object is, I think, the right approach.  However, the
> callback can't be put off until the child dissector has finished.  All
> deferred pointer referents are processed before moving on to the next
> arg in a function.  So, if you have, say

OK. I assumed that for function arguments, the same rules as for structures
were applied.
This should be an easy fix.
For this I assume that as parameters, only scalars and pointers can be used.
I.e. there can not be any top-level structures or other aggregate types?

>
> struct _foo {
>     [string] char *defer;
>     uint32 bar;
> };
>
> int hairy_rpc_func (struct _foo **pComplex, uint32 Flags);
>
> then what you'd have in the stub is 4 bytes for pComplex.  If not
> null, then 4 bytes for pComplex->defer and 4 bytes for pComplex->bar.
> Then, if pComplex->defer is not null, you'd have the data for that.
> Then, you'd have the 4 bytes for Flags, and 4 bytes for the return
> code.

But pComplex is a pointer to a pointer, would this not be encoded as (32 bit
quantities) :
[ (x)L ]       (pointer to *pComplex, i.e. the next 32 bit quantity in the
bytestream)
[ (x+1)L ]   (pointer to pComplex)
[ (x+2)L ]   (pointer to defer)
[ bar ]         (content of bar)
[ content of defer ...]
[ Flags ]    (second argument to function hairy_rpc_func )

In your description, why does **pComplex degenerate to one level of pointers
and not two levels of pointers?



>
> I hope that makes sense.  This stuff is too hard to describe in
> words. :)
>
> Some other things to think about/be aware of:
>
> Having a pointer_default in ethereal probably doesn't make sense.
> They're only used in the idl files.  Once the idl is written, every
> pointer is one of full, unique, or ref.  So the dissector for a given
> interface should know what they are.

You are correct. I will remove this and assume the idl compiler will handle
this instead.

>
> Full pointers from a request can be referred to in the reply. (!)
> Yes, that's going to be ugly, if you want to handle it correctly.

Ouch.
Well would the following work:
Assuming that for the request, if there are n different pointers in the byte
stream
the referral id's of these pointers will be inclusive between 1 and n? (is
this correct?)

For the matching response, all pointers whose data are encoded in the
bytestream of the response
the referral id's of those pointers would all be in the range (inclusive)
n+1 to n+m?
(is this correct?)

That means that by remembering n from the request to the response we can
distinguish between
referral id's in the response which points to a structure in the request pdu
(ref_id<=n) or if the representation is in
the datastram of the response (ref_id>n). Is this correct?
I guess dcerpc has a datastructure it keeps state between matched requests
and responses which could be extended to
remember n in ?

This would also meant that if we have a response where we HAVE NOT seen the
matching request, then it would
be impossible for us to determine if a referral-id would be the first
non-NULL occurence of the pointer or if it points
to a structure in the datastream for the request?
Ie we really would need to throw an exception here since we do not have
enough information to dissect the data?
Is this correct?
So the follwing could handle that for responses?
      if(pointer_is_non-NULL)
            if(we_have_not_seen_the_matching_request)
                        proto_tree_add_text("unable to defer pointer. no
matching request found")
                        throw-exception
            else if(ref_id <= requestpacket->max_n)
                        proto_tree_add_text("referral:0xABC  The
representation for this structure in the request in frame:Y");
            else
                      normal handling of pointer, the representation is in
the datastream of the response
            fi
    fi



>
> Despite what the specs say, unique pointers are not actually
> marshalled the same as full pointers.  At least, not by MS's runtime.
> [I don't know about other implementations.  If anyone has sniffs of
> AIX or HP-UX dcerpc traffic with or without associated idls, I'd love
> to see them.]  Either this is because MS deviates from the spec, or
> because the spec was updated, or something else :).  The specs on the
> opengroup's website describe transfer syntax 8a885d04..... _v1_, but
> if you look at the stuff you actually see on the wire with NT, it's
> actually _v2_ (check the bind packets).  Whether this v2 is official,
> unofficial, or an MS invention, I don't know.  Anyway, the only
> difference I've noticed is that with v2 unique pointers seem to be
> marshalled like a hybrid of the full and ref pointers.  They are
> always put on the wire (like full pointers, but not ref pointers), but
> their wire representation is the actual pointer value (like ref
> pointers, not full pointers).

I will try to make sense of this and change dissect_ndr_pointer() to support
this.

Thanks a lot for the explanations.
I will try to update the code for a next round of examination.