s3-epmapper: Added epm_Insert function.
authorAndreas Schneider <asn@samba.org>
Thu, 16 Sep 2010 08:50:25 +0000 (10:50 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Wed, 2 Feb 2011 11:44:20 +0000 (12:44 +0100)
source3/rpc_server/srv_epmapper.c

index 7f67bffc2c8119b265161faf6375bcc9a6cbea9a..4629ec352e67d669f38cb403766ca710179e10ac 100644 (file)
 
 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;
 }