summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/rpc_server/srv_epmapper.c242
1 files changed, 234 insertions, 8 deletions
diff --git a/source3/rpc_server/srv_epmapper.c b/source3/rpc_server/srv_epmapper.c
index 7f67bffc2c..4629ec352e 100644
--- a/source3/rpc_server/srv_epmapper.c
+++ b/source3/rpc_server/srv_epmapper.c
@@ -25,22 +25,248 @@
typedef uint32_t error_status_t;
+/* A rpc service interface like samr, lsarpc or netlogon */
+struct dcesrv_iface {
+ const char *name;
+ struct ndr_syntax_id syntax_id;
+};
+
+struct dcesrv_iface_list {
+ struct dcesrv_iface_list *next, *prev;
+ struct dcesrv_iface *iface;
+};
+
/*
- epm_Insert
-*/
+ * An endpoint can serve multiple rpc services interfaces.
+ * For example \\pipe\netlogon can be used by lsarpc and netlogon.
+ */
+struct dcesrv_endpoint {
+ struct dcesrv_endpoint *next, *prev;
+
+ /* The type and the location of the endpoint */
+ struct dcerpc_binding *ep_description;
+
+ /* A list of rpc services able to connect to the endpoint */
+ struct dcesrv_iface_list *iface_list;
+};
+
+struct dcesrv_endpoint *endpoint_table;
+
+/*
+ * Check if the UUID and if_version match to an interface.
+ */
+static bool interface_match(const struct dcesrv_iface *if1,
+ const struct dcesrv_iface *if2)
+{
+ return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
+}
+
+/*
+ * Find the interface operations on an endpoint.
+ */
+static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
+ const struct dcesrv_iface *iface)
+{
+ struct dcesrv_iface_list *iflist;
+
+ for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
+ if (interface_match(iflist->iface, iface)) {
+ return iflist->iface;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Check if two endpoints match.
+ */
+static bool endpoints_match(const struct dcerpc_binding *ep1,
+ const struct dcerpc_binding *ep2)
+{
+ if (ep1->transport != ep2->transport) {
+ return false;
+ }
+
+ if (!ep1->endpoint || !ep2->endpoint) {
+ return ep1->endpoint == ep2->endpoint;
+ }
+
+ if (!strequal(ep1->endpoint, ep2->endpoint)) {
+ return false;
+ }
+
+ return true;
+}
+
+static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
+ struct dcerpc_binding *ep_description) {
+ struct dcesrv_endpoint *ep;
+
+ for (ep = endpoint_list; ep != NULL; ep = ep->next) {
+ if (endpoints_match(ep->ep_description, ep_description)) {
+ return ep;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Build a list of all interfaces handled by all endpoint servers.
+ */
+static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
+ struct dcesrv_endpoint *endpoint_list,
+ struct dcesrv_ep_iface **peps)
+{
+ struct dcesrv_ep_iface *eps;
+ struct dcesrv_endpoint *d;
+ uint32_t total = 0;
+ NTSTATUS status;
+
+ *peps = NULL;
+
+ for (d = endpoint_list; d != NULL; d = d->next) {
+ struct dcesrv_iface_list *iface;
+ struct dcerpc_binding *description;
+
+ for (iface = d->iface_list; iface != NULL; iface = iface->next) {
+ eps = talloc_realloc(mem_ctx,
+ eps,
+ struct dcesrv_ep_iface,
+ total + 1);
+ if (eps == NULL) {
+ return 0;
+ }
+ eps[total].name = iface->iface->name;
+
+ description = d->ep_description;
+ description->object = iface->iface->syntax_id;
+
+ status = dcerpc_binding_build_tower(eps,
+ description,
+ &eps[total].ep);
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(1, ("Unable to build tower for %s\n",
+ iface->iface->name));
+ continue;
+ }
+ total++;
+ }
+ }
+
+ *peps = eps;
+
+ return total;
+}
+
+/*
+ * epm_Insert
+ *
+ * Add the specified entries to an endpoint map.
+ */
error_status_t _epm_Insert(struct pipes_struct *p,
struct epm_Insert *r)
{
- /* Check if we have a priviledged pipe/handle */
+ TALLOC_CTX *tmp_ctx;
+ error_status_t rc;
+ NTSTATUS status;
+ uint32_t i;
- /* Check if the entry already exits */
+ tmp_ctx = talloc_stackframe();
+ if (tmp_ctx == NULL) {
+ return EPMAPPER_STATUS_NO_MEMORY;
+ }
- /* Replace the entry if flag is set */
+ DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
+ r->in.num_ents));
- /* Create new entry */
+ /* TODO Check if we have a priviledged pipe/handle */
- p->rng_fault_state = true;
- return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ for (i = 0; i < r->in.num_ents; i++) {
+ struct dcerpc_binding *b = NULL;
+ struct dcesrv_endpoint *ep;
+ struct dcesrv_iface_list *iflist;
+ struct dcesrv_iface *iface;
+ bool add_ep = false;
+
+ status = dcerpc_binding_from_tower(tmp_ctx,
+ &r->in.entries[i].tower->tower,
+ &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
+ derpc_transport_string_by_transport(b->transport),
+ r->in.entries[i].annotation));
+
+ /* Check if the entry already exits */
+ ep = find_endpoint(endpoint_table, b);
+ if (ep == NULL) {
+ /* No entry found, create it */
+ ep = talloc_zero(NULL, struct dcesrv_endpoint);
+ if (ep == NULL) {
+ rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
+ goto done;
+ }
+ add_ep = true;
+
+ ep->ep_description = talloc_steal(ep, b);
+ }
+
+ /* TODO Replace the entry if the replace flag is set */
+
+ /* Create an interface */
+ iface = talloc(tmp_ctx, struct dcesrv_iface);
+ if (iface == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
+ if (iface->name == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ iface->syntax_id = b->object;
+
+ /*
+ * Check if the rpc service is alrady registered on the
+ * endpoint.
+ */
+ if (find_interface(ep, iface) != NULL) {
+ DEBUG(0, ("dcesrv_interface_register: interface '%s' "
+ "already registered on endpoint\n",
+ iface->name));
+ /* FIXME wrong error code? */
+ rc = EPMAPPER_STATUS_OK;
+ goto done;
+ }
+
+ /* Create an entry for the interface */
+ iflist = talloc(ep, struct dcesrv_iface_list);
+ if (iflist == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ iflist->iface = talloc_move(iflist, &iface);
+
+ /* Finally add the interface on the endpoint */
+ DLIST_ADD(ep->iface_list, iflist);
+
+ /* If it's a new endpoint add it to the endpoint_table */
+ if (add_ep) {
+ DLIST_ADD(endpoint_table, ep);
+ }
+ }
+
+ rc = EPMAPPER_STATUS_OK;
+done:
+ talloc_free(tmp_ctx);
+
+ return rc;
}