diff options
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/idl/epmapper.idl | 1 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc_util.c | 125 |
2 files changed, 118 insertions, 8 deletions
diff --git a/source4/librpc/idl/epmapper.idl b/source4/librpc/idl/epmapper.idl index e0d79a0fe1..cd70ca4431 100644 --- a/source4/librpc/idl/epmapper.idl +++ b/source4/librpc/idl/epmapper.idl @@ -36,6 +36,7 @@ interface epmapper const string NDR_GUID_VERSION = 2; const uint32 EPMAPPER_PORT = 135; + const string EPMAPPER_IDENTIFIER = "EPMAPPER"; typedef struct { GUID uuid; diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c index 48ae0eec92..3dacfee5f6 100644 --- a/source4/librpc/rpc/dcerpc_util.c +++ b/source4/librpc/rpc/dcerpc_util.c @@ -130,6 +130,100 @@ NTSTATUS dcerpc_epm_map_tcp_port(const char *server, return NT_STATUS_OK; } +NTSTATUS dcerpc_epm_map_ncalrpc(TALLOC_CTX *mem_ctx, + const char *uuid, uint_t version, const char **identifier) +{ + struct dcerpc_pipe *p; + NTSTATUS status; + struct epm_Map r; + struct policy_handle handle; + struct GUID guid; + struct epm_twr_t twr, *twr_r; + + if (strcasecmp(uuid, DCERPC_EPMAPPER_UUID) == 0 || + strcasecmp(uuid, DCERPC_MGMT_UUID) == 0) { + /* don't lookup epmapper via epmapper! */ + *identifier = talloc_strdup(mem_ctx, EPMAPPER_IDENTIFIER); + return NT_STATUS_OK; + } + + status = dcerpc_pipe_open_pipe(&p, EPMAPPER_IDENTIFIER); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* we can use the pipes memory context here as we will have a short + lived connection */ + status = dcerpc_bind_byuuid(p, p, + DCERPC_EPMAPPER_UUID, + DCERPC_EPMAPPER_VERSION); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(p); + return status; + } + + ZERO_STRUCT(handle); + ZERO_STRUCT(guid); + + twr.tower.num_floors = 4; + twr.tower.floors = talloc(p, sizeof(twr.tower.floors[0]) * 5); + + twr.tower.floors[0].lhs.protocol = EPM_PROTOCOL_UUID; + GUID_from_string(uuid, &twr.tower.floors[0].lhs.info.uuid.uuid); + twr.tower.floors[0].lhs.info.uuid.version = version; + twr.tower.floors[0].rhs.uuid.unknown = 0; + + twr.tower.floors[1].lhs.protocol = EPM_PROTOCOL_UUID; + GUID_from_string(NDR_GUID, &twr.tower.floors[1].lhs.info.uuid.uuid); + twr.tower.floors[1].lhs.info.uuid.version = NDR_GUID_VERSION; + twr.tower.floors[1].rhs.uuid.unknown = 0; + + twr.tower.floors[2].lhs.protocol = EPM_PROTOCOL_NCALRPC; + twr.tower.floors[2].lhs.info.lhs_data = data_blob(NULL, 0); + twr.tower.floors[2].rhs.ncalrpc.minor_version = 0; + + twr.tower.floors[3].lhs.protocol = EPM_PROTOCOL_PIPE; + twr.tower.floors[3].lhs.info.lhs_data = data_blob(NULL, 0); + twr.tower.floors[3].rhs.pipe.path = talloc_strdup(p, ""); + + /* with some nice pretty paper around it of course */ + r.in.object = &guid; + r.in.map_tower = &twr; + r.in.entry_handle = &handle; + r.in.max_towers = 1; + r.out.entry_handle = &handle; + + status = dcerpc_epm_Map(p, p, &r); + if (!NT_STATUS_IS_OK(status)) { + dcerpc_pipe_close(p); + return status; + } + if (r.out.result != 0 || r.out.num_towers != 1) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + twr_r = r.out.towers[0].twr; + if (!twr_r) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + if (twr_r->tower.num_floors != 4 || + twr_r->tower.floors[3].lhs.protocol != twr.tower.floors[3].lhs.protocol) { + dcerpc_pipe_close(p); + return NT_STATUS_PORT_UNREACHABLE; + } + + *identifier = talloc_strdup(mem_ctx, twr_r->tower.floors[3].rhs.pipe.path); + + dcerpc_pipe_close(p); + + return NT_STATUS_OK; +} + + + /* find the pipe name for a local IDL interface */ @@ -858,18 +952,32 @@ static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p, const char *password) { NTSTATUS status; + const char *identifier = NULL; + TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncalrpc"); - /* FIXME: Look up identifier using the epmapper */ - if (!binding->options || !binding->options[0]) { - DEBUG(0, ("Identifier not specified\n")); - return NT_STATUS_INVALID_PARAMETER; + if (binding->options) { + identifier = binding->options[0]; + } + + /* Look up identifier using the epmapper */ + if (!identifier) { + status = dcerpc_epm_map_ncalrpc(mem_ctx, pipe_uuid, pipe_version, + &identifier); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n", + pipe_uuid, nt_errstr(status))); + talloc_destroy(mem_ctx); + return status; + } + DEBUG(1,("Mapped to DCERPC/TCP identifier %s\n", identifier)); } - status = dcerpc_pipe_open_pipe(p, binding->options[0]); + status = dcerpc_pipe_open_pipe(p, identifier); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to open ncalrpc pipe '%s'\n", binding->options[0])); - return status; + DEBUG(0,("Failed to open ncalrpc pipe '%s'\n", identifier)); + talloc_destroy(mem_ctx); + return status; } (*p)->flags = binding->flags; @@ -891,9 +999,11 @@ static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p, pipe_uuid, nt_errstr(status))); dcerpc_pipe_close(*p); *p = NULL; + talloc_destroy(mem_ctx); return status; } + talloc_destroy(mem_ctx); return status; } @@ -911,7 +1021,6 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **p, { NTSTATUS status; - /* FIXME: Look up path via the epmapper */ if (!binding->options || !binding->options[0]) { DEBUG(0, ("Path to unix socket not specified\n")); return NT_STATUS_INVALID_PARAMETER; |