2 Unix SMB/CIFS implementation.
4 Endpoint server for the epmapper pipe
6 Copyright (C) 2010-2011 Andreas Schneider <asn@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../libcli/security/security.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "srv_epmapper.h"
29 #include "librpc/rpc/dcesrv_core.h"
30 #include "librpc/gen_ndr/ndr_epmapper.h"
31 #include "librpc/gen_ndr/ndr_epmapper_scompat.h"
32 #include "rpc_server/rpc_server.h"
34 /* handle types for this module */
35 enum handle_types {HTYPE_LOOKUP};
37 typedef uint32_t error_status_t;
39 /* An endpoint combined with an interface description */
40 struct dcesrv_ep_iface {
42 struct ndr_syntax_id syntax_id;
46 /* A rpc service interface like samr, lsarpc or netlogon */
49 struct ndr_syntax_id syntax_id;
52 struct dcesrv_iface_list {
53 struct dcesrv_iface_list *next, *prev;
54 struct dcesrv_iface *iface;
58 * An endpoint can serve multiple rpc services interfaces.
59 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
61 struct dcesrv_epm_endpoint {
62 struct dcesrv_epm_endpoint *next, *prev;
64 /* The type and the location of the endpoint */
65 struct dcerpc_binding *ep_description;
67 /* A list of rpc services able to connect to the endpoint */
68 struct dcesrv_iface_list *iface_list;
71 struct dcesrv_ep_entry_list {
72 struct dcesrv_ep_entry_list *next, *prev;
75 struct epm_entry_t *entries;
79 struct dcesrv_ep_iface *e;
83 static struct dcesrv_epm_endpoint *endpoint_table = NULL;
86 * Check if the UUID and if_version match to an interface.
88 static bool interface_match(const struct dcesrv_iface *if1,
89 const struct dcesrv_iface *if2)
91 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
95 * Find the interface operations on an endpoint.
97 static const struct dcesrv_iface *find_interface(const struct dcesrv_epm_endpoint *endpoint,
98 const struct dcesrv_iface *iface)
100 struct dcesrv_iface_list *iflist;
102 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
103 if (interface_match(iflist->iface, iface)) {
104 return iflist->iface;
113 * See if a uuid and if_version match to an interface
115 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
116 const struct GUID *uuid)
118 return GUID_equal(&iface->syntax_id.uuid, uuid);
122 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_epm_endpoint *endpoint,
123 const struct dcesrv_iface *iface)
125 struct dcesrv_iface_list *iflist;
127 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
128 if (interface_match(iflist->iface, iface)) {
137 * Check if two endpoints match.
139 static bool endpoints_match(const struct dcerpc_binding *b1,
140 const struct dcerpc_binding *b2)
142 enum dcerpc_transport_t t1;
145 enum dcerpc_transport_t t2;
149 t1 = dcerpc_binding_get_transport(b1);
150 ep1 = dcerpc_binding_get_string_option(b1, "endpoint");
151 h1 = dcerpc_binding_get_string_option(b1, "host");
153 t2 = dcerpc_binding_get_transport(b2);
154 ep2 = dcerpc_binding_get_string_option(b2, "endpoint");
155 h2 = dcerpc_binding_get_string_option(b2, "host");
170 if (!strequal(ep1, ep2)) {
184 if (!strequal(h1, h2)) {
192 static struct dcesrv_epm_endpoint *find_endpoint(struct dcesrv_epm_endpoint *endpoint_list,
193 struct dcerpc_binding *ep_description) {
194 struct dcesrv_epm_endpoint *ep = NULL;
196 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
197 if (endpoints_match(ep->ep_description, ep_description)) {
206 * Build a list of all interfaces handled by all endpoint servers.
208 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
209 struct dcesrv_epm_endpoint *endpoint_list,
210 const struct GUID *uuid,
211 const char *srv_addr,
212 struct dcesrv_ep_iface **peps)
214 struct dcesrv_ep_iface *eps = NULL;
215 struct dcesrv_epm_endpoint *d = NULL;
221 for (d = endpoint_list; d != NULL; d = d->next) {
222 struct dcesrv_iface_list *iface;
223 struct dcerpc_binding *description;
225 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
226 enum dcerpc_transport_t transport;
227 const char *host = NULL;
228 const char *host_addr = NULL;
232 * Windows ignores the object uuid by default. There is
233 * one corner case. It is checked for the mgmt
234 * interface, which we do not implement here yet.
236 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
241 eps = talloc_realloc(mem_ctx,
243 struct dcesrv_ep_iface,
248 eps[total].name = talloc_strdup(eps,
250 if (eps[total].name == NULL) {
253 eps[total].syntax_id = iface->iface->syntax_id;
255 description = dcerpc_binding_dup(mem_ctx, d->ep_description);
256 if (description == NULL) {
260 status = dcerpc_binding_set_abstract_syntax(description,
261 &iface->iface->syntax_id);
262 if (!NT_STATUS_IS_OK(status)) {
266 transport = dcerpc_binding_get_transport(description);
267 host = dcerpc_binding_get_string_option(description, "host");
269 if (transport == NCACN_IP_TCP) {
271 host_addr = srv_addr;
272 } else if (!is_ipaddress_v4(host)) {
273 host_addr = srv_addr;
274 } else if (strcmp(host, "0.0.0.0") == 0) {
275 host_addr = srv_addr;
279 if (host_addr != NULL) {
280 status = dcerpc_binding_set_string_option(description,
283 if (!NT_STATUS_IS_OK(status)) {
288 status = dcerpc_binding_build_tower(eps,
291 TALLOC_FREE(description);
292 if (NT_STATUS_IS_ERR(status)) {
293 DEBUG(1, ("Unable to build tower for %s\n",
294 iface->iface->name));
306 static bool is_privileged_pipe(struct auth_session_info *info) {
307 /* If the user is not root, or has the system token, fail */
308 if ((info->unix_token->uid != sec_initial_uid()) &&
309 !security_token_is_system(info->security_token)) {
316 void srv_epmapper_delete_endpoints(struct dcesrv_connection *conn,
319 struct pipes_struct *p = dcesrv_get_pipes_struct(conn);
320 struct dcesrv_auth *auth = NULL;
322 struct dcesrv_ep_entry_list *el = p->ep_entries;
323 error_status_t result;
325 /* We have to set p->session_info to check if the connection is
326 * privileged and delete the endpoints registered by this connection.
327 * Set the default session info created at connection time as a
330 p->session_info = conn->default_auth_state->session_info;
332 /* Due to security context multiplexing we can have several states
333 * in the connection. Search the one of type NCALRPC_AS_SYSTEM to
334 * replace the default.
336 for (auth = conn->auth_states; auth != NULL; auth = auth->next) {
337 if (auth->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
338 p->session_info = auth->session_info;
343 struct dcesrv_ep_entry_list *next = el->next;
345 r.in.num_ents = el->num_ents;
346 r.in.entries = el->entries;
348 DEBUG(10, ("Delete_endpoints for: %s\n",
349 el->entries[0].annotation));
351 result = _epm_Delete(p, &r);
352 if (result != EPMAPPER_STATUS_OK) {
353 DBG_ERR("Failed to delete endpoint maps\n");
357 DLIST_REMOVE(p->ep_entries, el);
364 void srv_epmapper_cleanup(void)
366 struct dcesrv_epm_endpoint *ep = endpoint_table;
369 struct dcesrv_epm_endpoint *next = ep->next;
371 DLIST_REMOVE(endpoint_table, ep);
381 * Add the specified entries to an endpoint map.
383 error_status_t _epm_Insert(struct pipes_struct *p,
384 struct epm_Insert *r)
390 struct dcerpc_binding *b;
391 struct dcesrv_epm_endpoint *ep = NULL;
392 struct dcesrv_iface_list *iflist;
393 struct dcesrv_iface *iface;
396 /* If this is not a privileged users, return */
397 if (p->transport != NCALRPC ||
398 !is_privileged_pipe(p->session_info)) {
399 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
400 return EPMAPPER_STATUS_CANT_PERFORM_OP;
403 tmp_ctx = talloc_stackframe();
404 if (tmp_ctx == NULL) {
405 return EPMAPPER_STATUS_NO_MEMORY;
408 DBG_NOTICE("Trying to add %"PRIu32" new entries.\n",
411 for (i = 0; i < r->in.num_ents; i++) {
412 enum dcerpc_transport_t transport;
416 status = dcerpc_binding_from_tower(tmp_ctx,
417 &r->in.entries[i].tower->tower,
419 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
420 rc = EPMAPPER_STATUS_NO_MEMORY;
423 if (!NT_STATUS_IS_OK(status)) {
424 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
428 transport = dcerpc_binding_get_transport(b);
429 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
430 derpc_transport_string_by_transport(transport),
431 r->in.entries[i].annotation));
433 /* Check if the entry already exits */
434 ep = find_endpoint(endpoint_table, b);
436 /* No entry found, create it */
437 ep = talloc_zero(NULL, struct dcesrv_epm_endpoint);
439 rc = EPMAPPER_STATUS_NO_MEMORY;
444 ep->ep_description = talloc_steal(ep, b);
447 /* TODO Replace the entry if the replace flag is set */
449 /* Create an interface */
450 iface = talloc(tmp_ctx, struct dcesrv_iface);
452 rc = EPMAPPER_STATUS_NO_MEMORY;
456 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
457 if (iface->name == NULL) {
458 rc = EPMAPPER_STATUS_NO_MEMORY;
461 iface->syntax_id = dcerpc_binding_get_abstract_syntax(b);
464 * Check if the rpc service is alrady registered on the
467 if (find_interface(ep, iface) != NULL) {
468 DEBUG(8, ("dcesrv_interface_register: interface '%s' "
469 "already registered on endpoint\n",
471 /* FIXME wrong error code? */
472 rc = EPMAPPER_STATUS_OK;
476 /* Create an entry for the interface */
477 iflist = talloc(ep, struct dcesrv_iface_list);
478 if (iflist == NULL) {
479 rc = EPMAPPER_STATUS_NO_MEMORY;
482 iflist->iface = talloc_move(iflist, &iface);
484 /* Finally add the interface on the endpoint */
485 DLIST_ADD(ep->iface_list, iflist);
487 /* If it's a new endpoint add it to the endpoint_table */
489 DLIST_ADD(endpoint_table, ep);
493 if (r->in.num_ents > 0) {
494 struct dcesrv_ep_entry_list *el;
496 el = talloc_zero(p, struct dcesrv_ep_entry_list);
498 rc = EPMAPPER_STATUS_NO_MEMORY;
501 el->num_ents = r->in.num_ents;
502 el->entries = talloc_move(el, &r->in.entries);
504 DLIST_ADD(p->ep_entries, el);
507 rc = EPMAPPER_STATUS_OK;
509 talloc_free(tmp_ctx);
518 * Delete the specified entries from an endpoint map.
520 error_status_t _epm_Delete(struct pipes_struct *p,
521 struct epm_Delete *r)
527 struct dcerpc_binding *b;
528 struct dcesrv_epm_endpoint *ep = NULL;
529 struct dcesrv_iface iface;
530 struct dcesrv_iface_list *iflist;
532 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
535 /* If this is not a privileged users, return */
536 if (p->transport != NCALRPC ||
537 !is_privileged_pipe(p->session_info)) {
538 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
539 return EPMAPPER_STATUS_CANT_PERFORM_OP;
542 tmp_ctx = talloc_stackframe();
543 if (tmp_ctx == NULL) {
544 return EPMAPPER_STATUS_NO_MEMORY;
547 for (i = 0; i < r->in.num_ents; i++) {
548 enum dcerpc_transport_t transport;
552 status = dcerpc_binding_from_tower(tmp_ctx,
553 &r->in.entries[i].tower->tower,
555 if (!NT_STATUS_IS_OK(status)) {
556 rc = EPMAPPER_STATUS_NO_MEMORY;
560 transport = dcerpc_binding_get_transport(b);
561 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
562 derpc_transport_string_by_transport(transport),
563 r->in.entries[i].annotation));
565 ep = find_endpoint(endpoint_table, b);
567 rc = EPMAPPER_STATUS_OK;
571 iface.name = r->in.entries[i].annotation;
572 iface.syntax_id = dcerpc_binding_get_abstract_syntax(b);
574 iflist = find_interface_list(ep, &iface);
575 if (iflist == NULL) {
576 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
577 DLIST_REMOVE(endpoint_table, ep);
580 rc = EPMAPPER_STATUS_OK;
584 DLIST_REMOVE(ep->iface_list, iflist);
586 if (ep->iface_list == NULL) {
587 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
588 DLIST_REMOVE(endpoint_table, ep);
591 rc = EPMAPPER_STATUS_OK;
597 rc = EPMAPPER_STATUS_OK;
599 talloc_free(tmp_ctx);
608 * Lookup entries in an endpoint map.
610 error_status_t _epm_Lookup(struct pipes_struct *p,
611 struct epm_Lookup *r)
613 struct policy_handle *entry_handle;
618 uint32_t num_ents = 0;
624 *r->out.num_ents = 0;
625 r->out.entries = NULL;
627 tmp_ctx = talloc_stackframe();
628 if (tmp_ctx == NULL) {
629 return EPMAPPER_STATUS_NO_MEMORY;
632 DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
635 if (r->in.entry_handle == NULL ||
636 ndr_policy_handle_empty(r->in.entry_handle)) {
637 char *srv_addr = NULL;
639 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
641 eps = talloc_zero(tmp_ctx, struct rpc_eps);
643 rc = EPMAPPER_STATUS_NO_MEMORY;
647 if (p->local_address != NULL &&
648 tsocket_address_is_inet(p->local_address, "ipv4"))
650 srv_addr = tsocket_address_inet_addr_string(p->local_address,
654 switch (r->in.inquiry_type) {
655 case RPC_C_EP_ALL_ELTS:
657 * Return all elements from the endpoint map. The
658 * interface_id, vers_option, and object parameters MUST
661 eps->count = build_ep_list(eps,
667 case RPC_C_EP_MATCH_BY_IF:
669 * Return endpoint map elements that contain the
670 * interface identifier specified by the interface_id
671 * and vers_option values.
673 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
674 * need both the same endpoint list. There is a second
675 * check for the inquiry_type below which differentiates
678 case RPC_C_EP_MATCH_BY_BOTH:
680 * Return endpoint map elements that contain the
681 * interface identifier and object UUID specified by
682 * interface_id, vers_option, and object.
684 eps->count = build_ep_list(eps,
686 &r->in.interface_id->uuid,
690 case RPC_C_EP_MATCH_BY_OBJ:
692 * Return endpoint map elements that contain the object
693 * UUID specified by object.
695 eps->count = build_ep_list(eps,
702 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
706 if (eps->count == 0) {
707 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
711 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
713 rc = EPMAPPER_STATUS_NO_MEMORY;
717 eps = find_policy_by_hnd(p,
722 if (!NT_STATUS_IS_OK(status)) {
723 rc = EPMAPPER_STATUS_NO_MEMORY;
726 entry_handle = r->out.entry_handle;
728 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
730 eps = find_policy_by_hnd(p,
735 if (!NT_STATUS_IS_OK(status)) {
736 rc = EPMAPPER_STATUS_NO_MEMORY;
739 entry_handle = r->in.entry_handle;
742 if (eps == NULL || eps->e == NULL) {
743 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
747 /* return the next N elements */
748 count = r->in.max_ents;
749 if (count > eps->count) {
753 DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
756 close_policy_hnd(p, entry_handle);
757 ZERO_STRUCTP(r->out.entry_handle);
759 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
763 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
764 if (r->out.entries == NULL) {
765 rc = EPMAPPER_STATUS_NO_MEMORY;
769 for (i = 0; i < count; i++) {
772 switch (r->in.inquiry_type) {
773 case RPC_C_EP_ALL_ELTS:
775 * Return all elements from the endpoint map. The
776 * interface_id, vers_option, and object parameters MUST
781 case RPC_C_EP_MATCH_BY_IF:
783 * Return endpoint map elements that contain the
784 * interface identifier specified by the interface_id
785 * and vers_option values.
787 if (GUID_equal(&r->in.interface_id->uuid,
788 &eps->e[i].syntax_id.uuid)) {
792 case RPC_C_EP_MATCH_BY_OBJ:
794 * Return endpoint map elements that contain the object
795 * UUID specified by object.
797 if (GUID_equal(r->in.object,
798 &eps->e[i].syntax_id.uuid)) {
802 case RPC_C_EP_MATCH_BY_BOTH:
804 * Return endpoint map elements that contain the
805 * interface identifier and object UUID specified by
806 * interface_id, vers_option, and object.
808 if (GUID_equal(&r->in.interface_id->uuid,
809 &eps->e[i].syntax_id.uuid) &&
810 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
815 return EPMAPPER_STATUS_CANT_PERFORM_OP;
819 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
820 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
821 /* Check interface version */
824 switch (r->in.vers_option) {
827 * Return endpoint map elements that
828 * contain the specified interface UUID,
829 * regardless of the version numbers.
833 case RPC_C_VERS_COMPATIBLE:
835 * Return the endpoint map elements that
836 * contain the same major versions of
837 * the specified interface UUID and a
838 * minor version greater than or equal
839 * to the minor version of the specified
842 if (r->in.interface_id->vers_major ==
843 (eps->e[i].syntax_id.if_version >> 16) &&
844 r->in.interface_id->vers_minor <=
845 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
849 case RPC_C_VERS_EXACT:
851 * Return endpoint map elements that
852 * contain the specified version of the
853 * specified interface UUID.
855 if (r->in.interface_id->vers_major ==
856 (eps->e[i].syntax_id.if_version >> 16) &&
857 r->in.interface_id->vers_minor ==
858 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
863 case RPC_C_VERS_MAJOR_ONLY:
865 * Return endpoint map elements that
866 * contain the same version of the
867 * specified interface UUID and ignore
870 if (r->in.interface_id->vers_major ==
871 (eps->e[i].syntax_id.if_version >> 16)) {
876 case RPC_C_VERS_UPTO:
878 * Return endpoint map elements that
879 * contain a version of the specified
880 * interface UUID less than or equal to
881 * the specified major and minor
884 if (r->in.interface_id->vers_major >
885 eps->e[i].syntax_id.if_version >> 16) {
888 if (r->in.interface_id->vers_major ==
889 (eps->e[i].syntax_id.if_version >> 16) &&
890 r->in.interface_id->vers_minor >=
891 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
897 return EPMAPPER_STATUS_CANT_PERFORM_OP;
903 ZERO_STRUCT(r->out.entries[num_ents].object);
905 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
907 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
909 r->out.entries[num_ents].tower = talloc(r->out.entries,
911 if (r->out.entries[num_ents].tower == NULL) {
912 rc = EPMAPPER_STATUS_NO_MEMORY;
915 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
916 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
917 r->out.entries[num_ents].tower->tower_length = 0;
923 *r->out.num_ents = num_ents;
927 if (eps->count == 0) {
928 close_policy_hnd(p, entry_handle);
929 ZERO_STRUCTP(r->out.entry_handle);
930 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
934 rc = EPMAPPER_STATUS_OK;
936 talloc_free(tmp_ctx);
944 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
945 * to produce a list of protocol towers.
947 error_status_t _epm_Map(struct pipes_struct *p,
950 struct policy_handle *entry_handle;
951 enum dcerpc_transport_t transport;
952 struct ndr_syntax_id ifid;
953 struct epm_floor *floors;
958 uint32_t num_towers = 0;
963 *r->out.num_towers = 0;
964 r->out.towers = NULL;
966 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
967 r->in.map_tower->tower.num_floors < 3) {
968 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
971 tmp_ctx = talloc_stackframe();
972 if (tmp_ctx == NULL) {
973 return EPMAPPER_STATUS_NO_MEMORY;
976 ZERO_STRUCTP(r->out.entry_handle);
978 DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
982 * A tower has normally up to 6 floors
984 * +-----------------------------------------------------------------+
985 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
987 * +---------+-------------------------------------------------------+
988 * | Floor 2 | Transfer syntax (NDR endcoded) |
989 * +---------+-------------------------------------------------------+
990 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
991 * +---------+-------------------------------------------------------+
992 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
993 * +---------+-------------------------------------------------------+
994 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
995 * +---------+-------------------------------------------------------+
996 * | Floor 6 | Routing |
997 * +---------+-------------------------------------------------------+
999 floors = r->in.map_tower->tower.floors;
1001 /* We accept NDR as the transfer syntax */
1002 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
1004 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
1005 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax_ndr.uuid) ||
1006 ifid.if_version != ndr_transfer_syntax_ndr.if_version) {
1007 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1011 /* We only talk to sane transports */
1012 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
1013 if (transport == NCA_UNKNOWN) {
1014 DEBUG(2, ("epm_Map: Client requested unknown transport with"
1016 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
1017 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
1020 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1024 if (r->in.entry_handle == NULL ||
1025 ndr_policy_handle_empty(r->in.entry_handle)) {
1027 char *srv_addr = NULL;
1029 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
1031 eps = talloc_zero(tmp_ctx, struct rpc_eps);
1033 rc = EPMAPPER_STATUS_NO_MEMORY;
1042 * Apply some algorithm (using the fields in the map_tower)
1043 * to an endpoint map to produce a list of protocol towers.
1045 * The following code is the mysterious "some algorithm"!
1048 /* Filter by object id if one was given. */
1049 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
1055 if (p->local_address != NULL &&
1056 tsocket_address_is_inet(p->local_address, "ipv4"))
1058 srv_addr = tsocket_address_inet_addr_string(p->local_address,
1062 eps->count = build_ep_list(eps,
1067 if (eps->count == 0) {
1068 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1072 /* Filter out endpoints which match the interface. */
1074 struct rpc_eps *teps;
1077 teps = talloc_zero(tmp_ctx, struct rpc_eps);
1079 rc = EPMAPPER_STATUS_NO_MEMORY;
1083 for (i = 0; i < eps->count; i++) {
1084 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
1085 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
1086 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
1090 teps->e = talloc_realloc(tmp_ctx,
1092 struct dcesrv_ep_iface,
1094 if (teps->e == NULL) {
1098 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
1099 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
1100 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
1101 teps->e[total].syntax_id = eps->e[i].syntax_id;
1106 teps->count = total;
1110 /* end of "some algorithm" */
1112 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
1114 rc = EPMAPPER_STATUS_NO_MEMORY;
1118 eps = find_policy_by_hnd(p,
1119 r->out.entry_handle,
1123 if (!NT_STATUS_IS_OK(status)) {
1124 rc = EPMAPPER_STATUS_NO_MEMORY;
1127 entry_handle = r->out.entry_handle;
1129 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
1131 eps = find_policy_by_hnd(p,
1136 if (!NT_STATUS_IS_OK(status)) {
1137 rc = EPMAPPER_STATUS_NO_MEMORY;
1140 entry_handle = r->in.entry_handle;
1143 if (eps == NULL || eps->e == NULL) {
1144 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1148 /* return the next N elements */
1149 count = r->in.max_towers;
1150 if (count > eps->count) {
1155 close_policy_hnd(p, entry_handle);
1156 ZERO_STRUCTP(r->out.entry_handle);
1158 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1162 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1163 if (r->out.towers == NULL) {
1164 rc = EPMAPPER_STATUS_NO_MEMORY;
1168 for (i = 0; i < count; i++) {
1169 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
1172 r->out.towers[num_towers].twr = talloc(r->out.towers,
1174 if (r->out.towers[num_towers].twr == NULL) {
1175 rc = EPMAPPER_STATUS_NO_MEMORY;
1178 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1179 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1180 r->out.towers[num_towers].twr->tower_length = 0;
1185 *r->out.num_towers = num_towers;
1187 eps->count -= count;
1189 if (eps->count == 0) {
1190 close_policy_hnd(p, entry_handle);
1191 ZERO_STRUCTP(r->out.entry_handle);
1194 rc = EPMAPPER_STATUS_OK;
1196 talloc_free(tmp_ctx);
1202 * epm_LookupHandleFree
1204 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1205 struct epm_LookupHandleFree *r)
1207 if (r->in.entry_handle == NULL) {
1208 return EPMAPPER_STATUS_OK;
1211 if (is_valid_policy_hnd(r->in.entry_handle)) {
1212 close_policy_hnd(p, r->in.entry_handle);
1215 r->out.entry_handle = r->in.entry_handle;
1217 return EPMAPPER_STATUS_OK;
1224 * A client implementation SHOULD NOT call this method. These extensions do not
1225 * provide an alternative method.
1227 error_status_t _epm_InqObject(struct pipes_struct *p,
1228 struct epm_InqObject *r)
1230 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1231 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1238 * A client implementation SHOULD NOT call this method. These extensions do not
1239 * provide an alternative method.
1241 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1242 struct epm_MgmtDelete *r)
1244 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1245 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1252 error_status_t _epm_MapAuth(struct pipes_struct *p,
1253 struct epm_MapAuth *r)
1255 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1256 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1259 static NTSTATUS epmapper__op_shutdown_server(struct dcesrv_context *dce_ctx,
1260 const struct dcesrv_endpoint_server *ep_server);
1262 #define DCESRV_INTERFACE_EPMAPPER_SHUTDOWN_SERVER \
1263 epmapper_shutdown_server
1265 static NTSTATUS epmapper_shutdown_server(struct dcesrv_context *dce_ctx,
1266 const struct dcesrv_endpoint_server *ep_server)
1268 srv_epmapper_cleanup();
1270 return epmapper__op_shutdown_server(dce_ctx, ep_server);
1273 /* include the generated boilerplate */
1274 #include "librpc/gen_ndr/ndr_epmapper_scompat.c"
1276 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */