summaryrefslogtreecommitdiff
path: root/source3/rpc_server/epmapper
diff options
context:
space:
mode:
authorGünther Deschner <gd@samba.org>2011-02-08 14:17:14 +0100
committerGünther Deschner <gd@samba.org>2011-02-10 22:13:17 +0100
commit4063bde3edd15b241f2b93bb5aedfef57ec4df91 (patch)
tree78ee85791d7f3a257c6775067562aee866d5305f /source3/rpc_server/epmapper
parent1fc14a6543bfc5f087ed0ddf02bc7ce28a4d9ed4 (diff)
downloadsamba-4063bde3edd15b241f2b93bb5aedfef57ec4df91.tar.gz
samba-4063bde3edd15b241f2b93bb5aedfef57ec4df91.tar.bz2
samba-4063bde3edd15b241f2b93bb5aedfef57ec4df91.zip
s3-rpc_server: move services into individual directories.
Guenther Autobuild-User: Günther Deschner <gd@samba.org> Autobuild-Date: Thu Feb 10 22:13:17 CET 2011 on sn-devel-104
Diffstat (limited to 'source3/rpc_server/epmapper')
-rw-r--r--source3/rpc_server/epmapper/srv_epmapper.c1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/source3/rpc_server/epmapper/srv_epmapper.c b/source3/rpc_server/epmapper/srv_epmapper.c
new file mode 100644
index 0000000000..5bfb176b84
--- /dev/null
+++ b/source3/rpc_server/epmapper/srv_epmapper.c
@@ -0,0 +1,1038 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Endpoint server for the epmapper pipe
+
+ Copyright (C) 2010-2011 Andreas Schneider <asn@samba.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "../libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/gen_ndr/srv_epmapper.h"
+
+typedef uint32_t error_status_t;
+
+/* An endpoint combined with an interface description */
+struct dcesrv_ep_iface {
+ const char *name;
+ struct ndr_syntax_id syntax_id;
+ struct epm_tower ep;
+};
+
+/* 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;
+};
+
+/*
+ * 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 rpc_eps {
+ struct dcesrv_ep_iface *e;
+ uint32_t count;
+};
+
+static 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;
+}
+
+/*
+ * See if a uuid and if_version match to an interface
+ */
+static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
+ const struct GUID *uuid)
+{
+ return GUID_equal(&iface->syntax_id.uuid, uuid);
+}
+
+static struct dcesrv_iface_list *find_interface_list(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;
+ }
+ }
+
+ 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,
+ const struct GUID *uuid,
+ struct dcesrv_ep_iface **peps)
+{
+ struct dcesrv_ep_iface *eps = NULL;
+ 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) {
+ if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
+ continue;
+ }
+
+ eps = talloc_realloc(mem_ctx,
+ eps,
+ struct dcesrv_ep_iface,
+ total + 1);
+ if (eps == NULL) {
+ return 0;
+ }
+ eps[total].name = talloc_strdup(eps,
+ iface->iface->name);
+ eps[total].syntax_id = iface->iface->syntax_id;
+
+ 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;
+}
+
+static bool is_priviledged_pipe(struct auth_serversupplied_info *info) {
+ /* If the user is not root, or has the system token, fail */
+ if ((info->utok.uid != sec_initial_uid()) &&
+ !security_token_is_system(info->security_token)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * epm_Insert
+ *
+ * Add the specified entries to an endpoint map.
+ */
+error_status_t _epm_Insert(struct pipes_struct *p,
+ struct epm_Insert *r)
+{
+ TALLOC_CTX *tmp_ctx;
+ error_status_t rc;
+ NTSTATUS status;
+ uint32_t i;
+
+ /* If this is not a priviledged users, return */
+ if (!is_priviledged_pipe(p->server_info)) {
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+
+ tmp_ctx = talloc_stackframe();
+ if (tmp_ctx == NULL) {
+ return EPMAPPER_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
+ r->in.num_ents));
+
+ 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;
+}
+
+
+/*
+ * epm_Delete
+ *
+ * Delete the specified entries from an endpoint map.
+ */
+error_status_t _epm_Delete(struct pipes_struct *p,
+ struct epm_Delete *r)
+{
+ TALLOC_CTX *tmp_ctx;
+ error_status_t rc;
+ NTSTATUS status;
+ uint32_t i;
+
+ DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
+ r->in.num_ents));
+
+ /* If this is not a priviledged users, return */
+ if (!is_priviledged_pipe(p->server_info)) {
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+
+ tmp_ctx = talloc_stackframe();
+ if (tmp_ctx == NULL) {
+ return EPMAPPER_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < r->in.num_ents; i++) {
+ struct dcerpc_binding *b = NULL;
+ struct dcesrv_endpoint *ep;
+ struct dcesrv_iface iface;
+ struct dcesrv_iface_list *iflist;
+
+ 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_Delete: Deleting transport '%s' for '%s'\n",
+ derpc_transport_string_by_transport(b->transport),
+ r->in.entries[i].annotation));
+
+ ep = find_endpoint(endpoint_table, b);
+ if (ep == NULL) {
+ rc = EPMAPPER_STATUS_OK;
+ goto done;
+ }
+
+ iface.name = r->in.entries[i].annotation;
+ iface.syntax_id = b->object;
+
+ iflist = find_interface_list(ep, &iface);
+ if (iflist == NULL) {
+ DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
+ DLIST_REMOVE(endpoint_table, ep);
+ talloc_free(ep);
+
+ rc = EPMAPPER_STATUS_OK;
+ goto done;
+ }
+
+ DLIST_REMOVE(ep->iface_list, iflist);
+
+ if (ep->iface_list == NULL) {
+ DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
+ DLIST_REMOVE(endpoint_table, ep);
+ talloc_free(ep);
+
+ rc = EPMAPPER_STATUS_OK;
+ goto done;
+ }
+
+ }
+
+ rc = EPMAPPER_STATUS_OK;
+done:
+ talloc_free(tmp_ctx);
+
+ return rc;
+}
+
+
+/*
+ * epm_Lookup
+ *
+ * Lookup entries in an endpoint map.
+ */
+error_status_t _epm_Lookup(struct pipes_struct *p,
+ struct epm_Lookup *r)
+{
+ struct policy_handle *entry_handle;
+ struct rpc_eps *eps;
+ TALLOC_CTX *tmp_ctx;
+ error_status_t rc;
+ uint32_t count = 0;
+ uint32_t num_ents = 0;
+ uint32_t i;
+ bool match = false;
+ bool ok;
+
+ *r->out.num_ents = 0;
+ r->out.entries = NULL;
+
+ tmp_ctx = talloc_stackframe();
+ if (tmp_ctx == NULL) {
+ return EPMAPPER_STATUS_NO_MEMORY;
+ }
+
+ DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
+ r->in.max_ents));
+
+ if (r->in.entry_handle == NULL ||
+ policy_handle_empty(r->in.entry_handle)) {
+ struct GUID *obj;
+
+ DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n"));
+
+ eps = talloc_zero(tmp_ctx, struct rpc_eps);
+ if (eps == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
+ obj = NULL;
+ } else {
+ obj = r->in.object;
+ }
+
+ switch (r->in.inquiry_type) {
+ case RPC_C_EP_ALL_ELTS:
+ /*
+ * Return all elements from the endpoint map. The
+ * interface_id, vers_option, and object parameters MUST
+ * be ignored.
+ */
+ eps->count = build_ep_list(eps,
+ endpoint_table,
+ NULL,
+ &eps->e);
+ break;
+ case RPC_C_EP_MATCH_BY_IF:
+ /*
+ * Return endpoint map elements that contain the
+ * interface identifier specified by the interface_id
+ * and vers_option values.
+ *
+ * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
+ * need both the same endpoint list. There is a second
+ * check for the inquiry_type below which differentiates
+ * between them.
+ */
+ case RPC_C_EP_MATCH_BY_BOTH:
+ /*
+ * Return endpoint map elements that contain the
+ * interface identifier and object UUID specified by
+ * interface_id, vers_option, and object.
+ */
+ eps->count = build_ep_list(eps,
+ endpoint_table,
+ &r->in.interface_id->uuid,
+ &eps->e);
+ break;
+ case RPC_C_EP_MATCH_BY_OBJ:
+ /*
+ * Return endpoint map elements that contain the object
+ * UUID specified by object.
+ */
+ eps->count = build_ep_list(eps,
+ endpoint_table,
+ r->in.object,
+ &eps->e);
+ break;
+ default:
+ rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
+ goto done;
+ }
+
+ if (eps->count == 0) {
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ ok = create_policy_hnd(p, r->out.entry_handle, eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ entry_handle = r->out.entry_handle;
+ } else {
+ DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n"));
+
+ ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ entry_handle = r->in.entry_handle;
+ }
+
+ if (eps == NULL || eps->e == NULL) {
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ /* return the next N elements */
+ count = r->in.max_ents;
+ if (count > eps->count) {
+ count = eps->count;
+ }
+
+ DEBUG(3, ("_epm_Lookup: Find %u entries\n", count));
+
+ if (count == 0) {
+ close_policy_hnd(p, entry_handle);
+ ZERO_STRUCTP(r->out.entry_handle);
+
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
+ if (r->out.entries == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ match = false;
+
+ switch (r->in.inquiry_type) {
+ case RPC_C_EP_ALL_ELTS:
+ /*
+ * Return all elements from the endpoint map. The
+ * interface_id, vers_option, and object parameters MUST
+ * be ignored.
+ */
+ match = true;
+ break;
+ case RPC_C_EP_MATCH_BY_IF:
+ /*
+ * Return endpoint map elements that contain the
+ * interface identifier specified by the interface_id
+ * and vers_option values.
+ */
+ if (GUID_equal(&r->in.interface_id->uuid,
+ &eps->e[i].syntax_id.uuid)) {
+ match = true;
+ }
+ break;
+ case RPC_C_EP_MATCH_BY_OBJ:
+ /*
+ * Return endpoint map elements that contain the object
+ * UUID specified by object.
+ */
+ if (GUID_equal(r->in.object,
+ &eps->e[i].syntax_id.uuid)) {
+ match = true;
+ }
+ break;
+ case RPC_C_EP_MATCH_BY_BOTH:
+ /*
+ * Return endpoint map elements that contain the
+ * interface identifier and object UUID specified by
+ * interface_id, vers_option, and object.
+ */
+ if (GUID_equal(&r->in.interface_id->uuid,
+ &eps->e[i].syntax_id.uuid) &&
+ GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
+ match = true;
+ }
+ break;
+ default:
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+
+ if (match) {
+ if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
+ r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
+ /* Check inteface version */
+
+ match = false;
+ switch (r->in.vers_option) {
+ case RPC_C_VERS_ALL:
+ /*
+ * Return endpoint map elements that
+ * contain the specified interface UUID,
+ * regardless of the version numbers.
+ */
+ match = true;
+ break;
+ case RPC_C_VERS_COMPATIBLE:
+ /*
+ * Return the endpoint map elements that
+ * contain the same major versions of
+ * the specified interface UUID and a
+ * minor version greater than or equal
+ * to the minor version of the specified
+ * UUID.
+ */
+ if (r->in.interface_id->vers_major ==
+ (eps->e[i].syntax_id.if_version >> 16) &&
+ r->in.interface_id->vers_minor <=
+ (eps->e[i].syntax_id.if_version && 0xFFFF)) {
+ match = true;
+ }
+ break;
+ case RPC_C_VERS_EXACT:
+ /*
+ * Return endpoint map elements that
+ * contain the specified version of the
+ * specified interface UUID.
+ */
+ if (r->in.interface_id->vers_major ==
+ (eps->e[i].syntax_id.if_version >> 16) &&
+ r->in.interface_id->vers_minor ==
+ (eps->e[i].syntax_id.if_version && 0xFFFF)) {
+ match = true;
+ }
+ match = true;
+ break;
+ case RPC_C_VERS_MAJOR_ONLY:
+ /*
+ * Return endpoint map elements that
+ * contain the same version of the
+ * specified interface UUID and ignore
+ * the minor version.
+ */
+ if (r->in.interface_id->vers_major ==
+ (eps->e[i].syntax_id.if_version >> 16)) {
+ match = true;
+ }
+ match = true;
+ break;
+ case RPC_C_VERS_UPTO:
+ /*
+ * Return endpoint map elements that
+ * contain a version of the specified
+ * interface UUID less than or equal to
+ * the specified major and minor
+ * version.
+ */
+ if (r->in.interface_id->vers_major >
+ eps->e[i].syntax_id.if_version >> 16) {
+ match = true;
+ } else {
+ if (r->in.interface_id->vers_major ==
+ (eps->e[i].syntax_id.if_version >> 16) &&
+ r->in.interface_id->vers_minor >=
+ (eps->e[i].syntax_id.if_version && 0xFFFF)) {
+ match = true;
+ }
+ }
+ break;
+ default:
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+ }
+ }
+ }
+
+ if (match) {
+ ZERO_STRUCT(r->out.entries[num_ents].object);
+
+ DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
+ eps->e[i].name));
+ r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
+ eps->e[i].name);
+ r->out.entries[num_ents].tower = talloc(r->out.entries,
+ struct epm_twr_t);
+ if (r->out.entries[num_ents].tower == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
+ r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
+ r->out.entries[num_ents].tower->tower_length = 0;
+
+ num_ents++;
+ }
+ } /* end for loop */
+
+ *r->out.num_ents = num_ents;
+
+ eps->count -= count;
+ eps->e += count;
+ if (eps->count == 0) {
+ close_policy_hnd(p, entry_handle);
+ ZERO_STRUCTP(r->out.entry_handle);
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ rc = EPMAPPER_STATUS_OK;
+done:
+ talloc_free(tmp_ctx);
+
+ return rc;
+}
+
+/*
+ * epm_Map
+ *
+ * Apply some algorithm (using the fields in the map_tower) to an endpoint map
+ * to produce a list of protocol towers.
+ */
+error_status_t _epm_Map(struct pipes_struct *p,
+ struct epm_Map *r)
+{
+ struct policy_handle *entry_handle;
+ enum dcerpc_transport_t transport;
+ struct ndr_syntax_id ifid;
+ struct epm_floor *floors;
+ struct rpc_eps *eps;
+ TALLOC_CTX *tmp_ctx;
+ error_status_t rc;
+ uint32_t count = 0;
+ uint32_t num_towers = 0;
+ uint32_t num_floors = 0;
+ uint32_t i;
+ bool ok;
+
+ *r->out.num_towers = 0;
+ r->out.towers = NULL;
+
+ if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
+ r->in.map_tower->tower.num_floors < 3) {
+ return EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ }
+
+ tmp_ctx = talloc_stackframe();
+ if (tmp_ctx == NULL) {
+ return EPMAPPER_STATUS_NO_MEMORY;
+ }
+
+ ZERO_STRUCTP(r->out.entry_handle);
+
+ DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n",
+ r->in.max_towers));
+
+ /*
+ * A tower has normally up to 6 floors
+ *
+ * +-----------------------------------------------------------------+
+ * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
+ * | | netlogon) |
+ * +---------+-------------------------------------------------------+
+ * | Floor 2 | Transfer syntax (NDR endcoded) |
+ * +---------+-------------------------------------------------------+
+ * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
+ * +---------+-------------------------------------------------------+
+ * | Floor 4 | Port address (e.g. TCP Port: 49156) |
+ * +---------+-------------------------------------------------------+
+ * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
+ * +---------+-------------------------------------------------------+
+ * | Floor 6 | Routing |
+ * +---------+-------------------------------------------------------+
+ */
+ num_floors = r->in.map_tower->tower.num_floors;
+ floors = r->in.map_tower->tower.floors;
+
+ /* We accept NDR as the transfer syntax */
+ dcerpc_floor_get_lhs_data(&floors[1], &ifid);
+
+ if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
+ !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) ||
+ ifid.if_version != ndr_transfer_syntax.if_version) {
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ /* We only talk to sane transports */
+ transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
+ if (transport == NCA_UNKNOWN) {
+ DEBUG(2, ("epm_Map: Client requested unknown transport with"
+ "levels: "));
+ for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
+ DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
+ }
+ DEBUG(2, ("\n"));
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ if (r->in.entry_handle == NULL ||
+ policy_handle_empty(r->in.entry_handle)) {
+ struct GUID *obj;
+
+ DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n"));
+
+ eps = talloc_zero(tmp_ctx, struct rpc_eps);
+ if (eps == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ /*
+ * *** ATTENTION ***
+ * CDE 1.1 states:
+ *
+ * ept_map()
+ * Apply some algorithm (using the fields in the map_tower)
+ * to an endpoint map to produce a list of protocol towers.
+ *
+ * The following code is the mysterious "some algorithm"!
+ */
+
+ /* Filter by object id if one was given. */
+ if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
+ obj = NULL;
+ } else {
+ obj = r->in.object;
+ }
+
+ eps->count = build_ep_list(eps,
+ endpoint_table,
+ obj,
+ &eps->e);
+ if (eps->count == 0) {
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ /* Filter out endpoints which match the interface. */
+ {
+ struct rpc_eps *teps;
+ uint32_t total = 0;
+
+ teps = talloc_zero(tmp_ctx, struct rpc_eps);
+ if (teps == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < eps->count; i++) {
+ if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
+ &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
+ transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
+ continue;
+ }
+
+ teps->e = talloc_realloc(tmp_ctx,
+ teps->e,
+ struct dcesrv_ep_iface,
+ total + 1);
+ if (teps->e == NULL) {
+ return 0;
+ }
+
+ teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
+ teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
+ teps->e[total].name = talloc_move(teps, &eps->e[i].name);
+ teps->e[total].syntax_id = eps->e[i].syntax_id;
+
+ total++;
+ }
+
+ teps->count = total;
+ talloc_free(eps);
+ eps = teps;
+ }
+ /* end of "some algorithm" */
+
+ ok = create_policy_hnd(p, r->out.entry_handle, eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ entry_handle = r->out.entry_handle;
+ } else {
+ DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n"));
+
+ ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
+ if (!ok) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ entry_handle = r->in.entry_handle;
+ }
+
+ if (eps == NULL || eps->e == NULL) {
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ /* return the next N elements */
+ count = r->in.max_towers;
+ if (count > eps->count) {
+ count = eps->count;
+ }
+
+ if (count == 0) {
+ close_policy_hnd(p, entry_handle);
+ ZERO_STRUCTP(r->out.entry_handle);
+
+ rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
+ goto done;
+ }
+
+ r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
+ if (r->out.towers == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i = 0; i < count; i++) {
+ DEBUG(5, ("_epm_Map: Map tower for '%s'\n",
+ eps->e[i].name));
+
+ r->out.towers[num_towers].twr = talloc(r->out.towers,
+ struct epm_twr_t);
+ if (r->out.towers[num_towers].twr == NULL) {
+ rc = EPMAPPER_STATUS_NO_MEMORY;
+ goto done;
+ }
+ r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
+ r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
+ r->out.towers[num_towers].twr->tower_length = 0;
+
+ num_towers++;
+ }
+
+ *r->out.num_towers = num_towers;
+
+ eps->count -= count;
+ eps->e += count;
+ if (eps->count == 0) {
+ close_policy_hnd(p, entry_handle);
+ ZERO_STRUCTP(r->out.entry_handle);
+ }
+
+ rc = EPMAPPER_STATUS_OK;
+done:
+ talloc_free(tmp_ctx);
+
+ return rc;
+}
+
+/*
+ * epm_LookupHandleFree
+ */
+error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
+ struct epm_LookupHandleFree *r)
+{
+ if (r->in.entry_handle == NULL) {
+ return EPMAPPER_STATUS_OK;
+ }
+
+ if (is_valid_policy_hnd(r->in.entry_handle)) {
+ close_policy_hnd(p, r->in.entry_handle);
+ }
+
+ r->out.entry_handle = r->in.entry_handle;
+
+ return EPMAPPER_STATUS_OK;
+}
+
+
+/*
+ * epm_InqObject
+ *
+ * A client implementation SHOULD NOT call this method. These extensions do not
+ * provide an alternative method.
+ */
+error_status_t _epm_InqObject(struct pipes_struct *p,
+ struct epm_InqObject *r)
+{
+ p->rng_fault_state = true;
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+}
+
+
+/*
+ * epm_MgmtDelete
+ *
+ * A client implementation SHOULD NOT call this method. These extensions do not
+ * provide an alternative method.
+*/
+error_status_t _epm_MgmtDelete(struct pipes_struct *p,
+ struct epm_MgmtDelete *r)
+{
+ p->rng_fault_state = true;
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+}
+
+
+/*
+ epm_MapAuth
+*/
+error_status_t _epm_MapAuth(struct pipes_struct *p,
+ struct epm_MapAuth *r)
+{
+ p->rng_fault_state = true;
+ return EPMAPPER_STATUS_CANT_PERFORM_OP;
+}
+
+/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */