Trying to understand epmapper registration

Andrew Bartlett abartlet at samba.org
Sat Mar 3 03:44:55 MST 2012


On Sat, 2012-03-03 at 10:47 +0100, Andreas Schneider wrote:
> On Saturday 03 March 2012 09:21:14 Andrew Bartlett wrote:
> > On Fri, 2012-03-02 at 15:23 +0100, Andreas Schneider wrote:
> > > On Friday 02 March 2012 17:36:33 Andrew Bartlett wrote:
> > > > Andreas,
> > > 
> > > Andrew,
> > > 
> > > > I've been trying to understand the endpoint mapper registration,
> > > > starting with the errors we currently get in the plugin_s4_dc
> > > > environment.
> > > 
> > > are you trying to register s3 endpoints on s4? This will not work cause s4
> > > doesn't implement epm_Insert().
> > 
> > No, I'm not trying to do that yet.  I am well aware of the endpoint
> > registration mechanism, and I'm hoping to either support epm_Insert()
> > one way or the other, to permit registration to a common endpoint
> > mapper.
> > 
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'dssetup'!
> > > > /data/samba-2/bin/smbd: ../source3/rpc_client/cli_pipe.c:461: Bind NACK
> > > > received from host obed!
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'wkssvc'!
> > > > /data/samba-2/bin/smbd: ../source3/rpc_client/cli_pipe.c:461: Bind NACK
> > > > received from host obed!
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'svcctl'!
> > > > /data/samba-2/bin/smbd: ../source3/rpc_client/cli_pipe.c:461: Bind NACK
> > > > received from host obed!
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'ntsvcs'!
> > > > /data/samba-2/bin/smbd: ../source3/rpc_client/cli_pipe.c:461: Bind NACK
> > > > received from host obed!
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'eventlog'!
> > > > /data/samba-2/bin/smbd: ../source3/rpc_client/cli_pipe.c:461: Bind NACK
> > > > received from host obed!
> > > > /data/samba-2/bin/smbd: Failed to register endpoint 'initshutdown'!
> > > > 
> > > > I've knocked up two patches, attached, which simplify the setup and
> > > > registration of the embedded rpc servers, but I would appreciate your
> > > > comment and direction.  I'm confused as to why this process is not
> > > > totally driven by the endpoint declarations in the IDL, as it appears to
> > > > be strongly influenced by it.
> > > 
> > > Why do you mean not driver by the endpoint decleration in the IDL? The
> > > client (smbd) registers the enpointer over ncalrpc calling epm_Insert()
> > > on the server (epmd). As epm_Insert() are only internal functions we
> > > extended the logic a bit. The client opens a ncalrpc connection and call
> > > epm_Insert() then it leave the connection open to sends something like
> > > keepalive. If epmd crashes or gets restarted it detects it and will
> > > reregister the endpoint.
> > 
> > What I mean is that the IDL declares the endpoints that a particular
> > service is available on.  The C code I was modifying appears to encode
> > in C the same information that is in the IDL file, that is should a
> > particular service be registered on ncalrpc, ncacn_ip_tcp or ncacn_np.
> > Indeed, the IDL is consulted to determine the named pipes to register,
> > but not for the other details.
> 
> Do you mean the table with the GUID, endpoint names, and on which endpoints it 
> should be available? I don't really get what you're talking about and what the 
> problem is :)

I'm sorry, clearly I have not been specific enough.  To continue using
dssetup as my example, here is the relevant fucntion in master:

static bool rpc_setup_dssetup(struct tevent_context *ev_ctx,
			      struct messaging_context *msg_ctx,
			      const struct dcerpc_binding_vector *v)
{
	const struct ndr_interface_table *t = &ndr_table_dssetup;
	const char *pipe_name = "dssetup";
	struct dcerpc_binding_vector *v2;
	enum rpc_service_mode_e epm_mode = rpc_epmapper_mode();
	NTSTATUS status;
	bool ok;

	status = rpc_dssetup_init(NULL);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	if (epm_mode != RPC_SERVICE_MODE_DISABLED) {
		v2 = dcerpc_binding_vector_dup(talloc_tos(), v);
		if (v2 == NULL) {
			return false;
		}

		status = dcerpc_binding_vector_replace_iface(t, v2);
		if (!NT_STATUS_IS_OK(status)) {
			return false;
		}

		status = dcerpc_binding_vector_add_np_default(t, v2);
		if (!NT_STATUS_IS_OK(status)) {
			return false;
		}

		ok = setup_dcerpc_ncalrpc_socket(ev_ctx,
						 msg_ctx,
						 pipe_name,
						 NULL);
		if (!ok) {
			return false;
		}

		status = dcerpc_binding_vector_add_unix(t, v2, pipe_name);
		if (!NT_STATUS_IS_OK(status)) {
			return false;
		}

		status = rpc_ep_register(ev_ctx,
					 msg_ctx,
					 t,
					 v2);
		if (!NT_STATUS_IS_OK(status)) {
			return false;
		}
	}

	return true;
}

The function does:
 - copies in the TCP/IP port bindings
 - registers ncacn_np pipes based on the IDL interface table
 - registers the ncaclrpc pipe

My question is:  Is there a reason why this is not entirely table
driven, based on this IDL interface table:

[
	uuid("3919286a-b10c-11d0-9ba8-00c04fd92ef5"),
	version(0.0),
	endpoint("ncacn_np:[\\pipe\\lsarpc]", "ncacn_np:[\\pipe\\lsass]",
"ncacn_ip_tcp:", "ncalrpc:"),
	pointer_default(unique),
	helpstring("Active Directory Setup")
] interface dssetup

(this is used by dcerpc_binding_vector_add_np_default already). 

I'm not trying to poke blame or suggest that hard-coding it was not the
most expedient option available at the time.  I'm just trying to
understand the why behind the code we have so far, as it seems I will be
needing to undertake some significant works in this area.  It helps to
understand not just the actions, but the intentions of those who have
been before me.  Naturally, I'll also keep you in the loop as I do the
work.  

> We need(ed) to call rpc_spoolss_init() or if you connect over a named pipe to 
> smbd, then smbd will tell the client that it doesn't know the rpc protocol and 
> drop the connection. This registration is (was) needed to accept the 
> connection and forward it over the named pipe proxy to the correct service, 
> spoolssd.
> 
> Maybe this has changed and isn't needed anymore. It was needed by the time I 
> was doing the work. I think we need to try it and maybe make sure it isn't 
> requried anymore.

I'll do that.  We should be able to put our RPC services into one of two
categories:  Services that are embedded in the forked smbd SMB child
process, and external services (the rest).  We should not need to
register external services except to the epmapper, and just fail
gracefully if we cannot find the socket. 

> > Given the support for automatically removing registrations when
> > processes shut down, I imagined it would need to be registred from the
> > same process.
> 
> Do you talk about registered endpoints in smbd or rpc_<rpc>_init() now?

I'm sorry, I was confused by the rpc_setup_lsarpc() call, being called
from main() -> dcesrv_ep_setup -> rpc_setup_lsarpc().  However, it is
guarded and the registration only applies in embedded mode. 

The rpc_lsarpc_init() function appears to be called from both that and
setup_lsasd().  I don't know if that matters.

> > 
> > The other problem is that even if the main daemon processes are
> > disabled, dcesrv_ep_setup() will still register "dssetup" (and a number
> > of other embedded services) unconditionally.  The problem is, dssetup is
> > declared to be "external" so that it can be forwarded across the named
> > pipes, and must be provided by Samba4's AD code, and so should not be
> > registered here.
> 
> We should differentiate between registering the process on epmd or make smbd 
> aware of handling the connection for dssetup and forwarding it. If you mean 
> the letter than we need to make sure that this will work.

If possible, I would like to make 'smbd' essentially unaware of external
rpc pipes, just working on what sockets exist in the ncaclrpc/np
directory.  Then epmd (wherever it is implemented) can deal with
registrations. 

Thanks,

Andrew Bartlett

-- 
Andrew Bartlett                                http://samba.org/~abartlet/
Authentication Developer, Samba Team           http://samba.org



More information about the samba-technical mailing list