DCE/RPC NamedPipe Transport emulation

Luke Kenneth Casson Leighton lkcl at samba-tng.org
Sun Sep 2 23:03:25 GMT 2001


dce/rpc is built in layers, where the majority of the
layers have negotiation phases for what to use.

this includes, at the very least, security, transports and data formats.

regarding transports for dce/rpc, there are several currently
in use.  the most popular are TCP, UDP and NT NamedPipes,
with HTTP a close runner-up, and NetBIOS, DECNet-3, unix
domain sockets and loop-back (ncalrpc) and many more as
the obscure ones out there.

this message is being sent on tng-technical, samba-technical
and freedce-dev, to initiate a discussion of how best to
implement the NamedPipe emulation for cross-platform and
cross-development-environment usage.  it's also turned
out so large that i'll post it on dcerpc.net, too.

first i'll describe the requirements.

the requirements are to be able to provide a server application
with a dynamic means to register with a transport on which
clients may contact the server.

the server may specify exactly _where_ on the transport
that the client may contact it (for example, in the TCP
and UDP transports, the server may specify the port number
or the port range(s)]

the server may leave it up to the dynamic registrar to
make the decision regarding the exact locations (in
the TCP and UDP case, this means the port number).

now, with respect to NamedPipes, there is nothing
ambiguous to specify: the name gives everything you
need to be able to contact the host.  there _are_
no ports - the name _is_ the exact endpoint.


the only information that needs to be communicated
over the NamedPipe emulation layer is:

- the name of the client host [not sure about this]

- the name of the pipe to which the application the client
wishes to connect

- the user's security context


second, i'll describe the current known implementations
and proposed implementations.

1) freedce - the OSF rpcd.

this is the reference implementation.  it's available
from http://sourceforge.net/projects/freedce.  active
develpoment has moved to dcerpc.net, we're just
setting up anon cvs: instructions available soon
[register on dcerpc.net for an account in the meantime]

rpcd is basically a DCE/RPC application that runs
at fixed - well-known - locations.  on TCP and
UDP, that's port 135.  on NamedPipes, it's epmapper.
see include/rpc/ep.idl for details.

so, that's:

- ncacn_tcp:hostname[135]
- ncadg_udp:hostname[135]
- ncan_np:hostname[epmapper]

there are a couple of others, including raw ip (!)
but there' academic for the purposes of this discussion.

basically, the rpcd application - as outlined by ep.idl,
is incredibly simple.  it's an implementation of:

ep_insert() - registers a server on a transport
ep_delete() - removes an entry from the epmapper database
ep_lookup() - returns an enum handle  for ep_map() to call
ep_map() - returns the transports where a server can be reached
ep_mgmt_delete() - deletes _all_ entries for a service.

this provides the dynamic contact point management.
it's a berkeley db implementation, it's used internally
as well as on-wire.

servers then register the endpoint on which they intend
to listen, clients contact the endpoint (if needed)
to find out where they are, drop the connection and make
a separate connection to the server, now that they kow
where it is.

there _isn't_ an implementation of NamedPipes in
freedce: i'm addig it, using 2), below.


2) TNG - samba, the next generation

available from http://www.samba-tng.org.

here we've chosen an optimisation.  basically there is
an implicit endpoint mapper.  for NamedPipes, no data
actually goes _to_ the endpoint mapper because in the
instance of NamedPipes, there's no need to contact
the endpoint mapper.

so you don't bother implementing one :)

what you get is a connection on-wire to the SMB IPC$
layer, from the client, and it specifies the pipe
name.

now, in the TNG implementation of smbd, it
prepends /$VARDIR/.msrpc/. to the pipename lowercased,
and connects to a unix-domain-socket at that name
[see lib/msrpc_client.c:ncalrpc_establish_connection.
please do not get confused by the name: this should
be ncacn_np_establish_connection.  sorry!]

what also happens in here - if you look closely
at ncalrpc_l_authenticate and ncalrpc_initialise -
is that the current security context is transferred
over the socket.

why is this?  well, it's because the SMB IPC$
session is authenticated.  therefore, the user
credentials have to be transferred between the
client and the server.  this is *essential*.
it is *not* an option to ignore the SMB user
session information.

also transferred is the name of the pipe: yes,
this is redundant.  also what probably
_should_ be transferred is the name of the
client host, because there may be some decisions
being made that are going on [y'know, i _swear_
i added this, 18 months ago.  oh well] at the
server end that require knowledge of the
client hostname.  there is a getsockname()
equivalent in the dce/rpc codebase, and at present
this would return blank / fake info.  whoops!


3) samba-ntdom (aka early tng)

available from http://samba.org

hard-coded.  horrible.  pain in the neck.

you want to add a service?  hack a Makefile.
add it into one big program, and only getting
bigger.

yuukkk.


4) samba (aka v. early ntdom)

available from http://samba.org

new proposal to have smb.conf options that can
specify pipename -> modulename.

when there is an incoming SMB IPC$ request,
the pipe name is looked up in smb.conf, the
modulename loaded as a dso, and read and
write functions 'made available' to the parent
loader program, over which communication may
occur.



advantages / disadvantages - afaict.

1) freedce.

having a working, fully comprehensive, runtime lib and
environment - esp.  such a high quality codebase, is 
a fantastic advantage.

adding new transports is trivial, given that wez
structured the code such that transports are now
dynamic loading modules (he moved a series of
existing functions behind a dso loader - that was
it!).

the transport functions are totally independent from
the underlying transport.  in theory, they could
be used to implement method 4), although i'd have
to investigate further.

at the moment, adding method 2) would be trivial.
i'm about 50% complete with the implementation,
it took about 3 days.

developing new client / server apps is trivial.
the addition of a namedpipe transport module
makes NamedPipe capability availably *instantly*
to *existing* applications, with a kill -HUP
or a service restart.

developing new client / server apps is easy.
very little code is needed to get started:
see the echo_client / echo_server demo
example.

perfect for getting round license incompatibilities.


2) TNG

the disadvantage of the existing TNG-only method
is that it can't be expanded such that a server
may register to listen on other transports such
as TCP [which you can do with freedce: it's
_multi_-transport independent].  can be used,
though, by any server, for any NamedPipe
pipename.

it has the advantage that an implementor of
a service may choose to do a totally independent
and better server framework: as long as
you're listening on the ux-dom-sock, who cares
what's at the other end?

it has the advantage that you need a minimum
amount of code - not as little as freedce -
to get started, and you have the option
of not even using that, if you have your own
marshalling libraries and server framework.

still not perfect.  still conceptually tied
in to the TNG legacy codebase.

lot of work to get round license incompatibilities.


3) samba-ntdom

worst of all worlds.  cannot register to listen
on other transports such as TCP.  cannot
dynamically add transports. existing pipenames
are hardcoded into one 150,000-line application.

locked into samba framework / monolith architecture,
which is frightening and daunting for anyone
who wishes to implement a client / server app of
one fiftieth of the total samba codebase.

why bother hunting through 350,000 lines of code
when you can install freedce as an rpm and
start development immediately?

the only advantage to this is that is _was_
the simplest approach to have implemented.  note that
i didn't say it's the simplest approach to implement
_with_, in fact completely the opposite.


4) samba

better than 3).  cannot register to listen on
other transports such as TCP.  _can_ register
different services under different pipenames
[but the existing proposal forgot to allow
regular expression matching, i don't
know all the details but it's probably one-to-one
as well].

cannot do dynamic registration.  

same disadvantage as samba-ntdom: locked into samba
framework / monolith application.  daunting,
frightening etc.

the only advantage is also the disadvantage:
you have access to the samba framework / functions,
but you can get those just as easily with static
linking of a few files as you can.

remember, the only information needed is the
client hostname, the client app pipename and
the client user security context.

in the samba monolith framework, that's one
global variable, one parameter that's passed
in to the proposed API, and a local variable
representing the connection context information.



regarding speed of the approaches.  well, let's
scratch 3) _right_ out because it was first
implementation, and compare to the rest, it totally
sucks.

regarding freedce and TNG, these are effectively
redirectors / proxies, a bit like mod_proxy in
apache.  data comes in over socket to proxy, gets sent on
socket to app, gets picked up by app, response is sent,
picked up by proxy, gets send out by proxy.

slow, memory copies on ux-dom-sock buffers.
but it's irrelevant: the data being sent and receivd
is ultimately going out over a network.

except when you get into delays of order 10 ms or 
above, speed is _not_ a factor, here.

a 1ms response time is acceptable, over a 10 or 100
mb/s network.

a 100ms response time - 1/10th of a second - is not
[which is what you get in TNG with debug log level
100!].


server application-wise: freedce is a threaded
architecture.  here, we're hit by limitations
on the threading library (it's the old POSIX
draft 4 model!) which we're investigating doing
an APR version of, to get full platform-independence,
even on NT and OS/2, but that's a _big_ project
to do properly.

but, threads offer a speed advantage: you can 'prep'
ten threads (the default) which never die, they just
are put to sleep and wake up on receipt of packets.

TNG is hit by a fork(), plus in order to emulate
smbd, has to call reload_services().  i'm positive
that this can be optimised, and some of the
reload_services() eliminated, with some careful
analysis, _if_ it was worthwhile doing.

given that TNG is slated for replacement with
freedce services, it doesn't bother me that it's
a 5-10ms response time, at best [compared to a 1-4ms
response time from NT of the same calls, last
time i checked].  so... irrelevant.

the proposed module-api of samba 4) doesn't have
the fork() and reload_services() time-related
disadvantages of TNG's architecture, yet as i
mentioned earlier, speed is irrelevant.

i was also party to some discussions that involved
speedup of smb.conf loading, which would make
reload_services() a heck of a lot faster than
it is today (especially for large sites).

so speed of fork() and reload_services() is
basically a moot point.


advantages regarding licensing of the three
remaining methods:

1) freedce.  freedce is released under an OSF/1
BSD-style license.

2) TNG.  TNG is GPL.  however, the other side
of the unix-domain-socket is up to the
implementor.  with a little bit of work, an
implementor could do their own dce/rpc marshalling
libraries, and have the start of a hand-coded application
up and running in three-to-four weeks.  not perfect,
but pretty good.
see http://sourceforge.net/projects/osexchange for
a good example.

3) samba.  samba is GPL.  you're expected to load
modules.  the module API is GPL.  the monolith
codebase you are expected to work with is GPL.

if you have GPL code, this is good.

if you don't, you will have to write a wrapper
API module that gets you out of the GPL
licensing restrictions.

i'm considering writing one that's TNG-compatible,
simply because that will allow TNG users to consider
using smbd from samba, with TNG daemons.

however, the API as it stands is too restrictive
to allow a simple bridge module to be written.


well, that was longer than i was expecting.  i've
left out a few bits which i am not too clear on
and am interested to hear clarifications and viewpoints
regarding the options 1-4 listed, points both
for and against.

btw, for those people who are not registered on dcerpc.net,
i'm happy to cross-post responses on the lists over to
the dcerpc.net article base.

luke




More information about the samba-technical mailing list