winbindd: remove unused single_domains array
[Samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blobd0e2d546c4711e19213bf157b023bff57eb13916
1 /*
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/>.
22 #include "includes.h"
23 #include "ntdomain.h"
24 #include "../libcli/security/security.h"
25 #include "../lib/tsocket/tsocket.h"
26 #include "librpc/gen_ndr/srv_epmapper.h"
27 #include "srv_epmapper.h"
28 #include "auth.h"
30 typedef uint32_t error_status_t;
32 /* An endpoint combined with an interface description */
33 struct dcesrv_ep_iface {
34 const char *name;
35 struct ndr_syntax_id syntax_id;
36 struct epm_tower ep;
39 /* A rpc service interface like samr, lsarpc or netlogon */
40 struct dcesrv_iface {
41 const char *name;
42 struct ndr_syntax_id syntax_id;
45 struct dcesrv_iface_list {
46 struct dcesrv_iface_list *next, *prev;
47 struct dcesrv_iface *iface;
51 * An endpoint can serve multiple rpc services interfaces.
52 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
54 struct dcesrv_endpoint {
55 struct dcesrv_endpoint *next, *prev;
57 /* The type and the location of the endpoint */
58 struct dcerpc_binding *ep_description;
60 /* A list of rpc services able to connect to the endpoint */
61 struct dcesrv_iface_list *iface_list;
64 struct dcesrv_ep_entry_list {
65 struct dcesrv_ep_entry_list *next, *prev;
67 uint32_t num_ents;
68 struct epm_entry_t *entries;
71 struct rpc_eps {
72 struct dcesrv_ep_iface *e;
73 uint32_t count;
76 static struct dcesrv_endpoint *endpoint_table;
79 * Check if the UUID and if_version match to an interface.
81 static bool interface_match(const struct dcesrv_iface *if1,
82 const struct dcesrv_iface *if2)
84 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
88 * Find the interface operations on an endpoint.
90 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
91 const struct dcesrv_iface *iface)
93 struct dcesrv_iface_list *iflist;
95 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
96 if (interface_match(iflist->iface, iface)) {
97 return iflist->iface;
101 return NULL;
104 #if 0
106 * See if a uuid and if_version match to an interface
108 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
109 const struct GUID *uuid)
111 return GUID_equal(&iface->syntax_id.uuid, uuid);
113 #endif
115 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
116 const struct dcesrv_iface *iface)
118 struct dcesrv_iface_list *iflist;
120 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
121 if (interface_match(iflist->iface, iface)) {
122 return iflist;
126 return NULL;
130 * Check if two endpoints match.
132 static bool endpoints_match(const struct dcerpc_binding *b1,
133 const struct dcerpc_binding *b2)
135 enum dcerpc_transport_t t1;
136 const char *ep1;
137 const char *h1;
138 enum dcerpc_transport_t t2;
139 const char *ep2;
140 const char *h2;
142 t1 = dcerpc_binding_get_transport(b1);
143 ep1 = dcerpc_binding_get_string_option(b1, "endpoint");
144 h1 = dcerpc_binding_get_string_option(b1, "host");
146 t2 = dcerpc_binding_get_transport(b2);
147 ep2 = dcerpc_binding_get_string_option(b2, "endpoint");
148 h2 = dcerpc_binding_get_string_option(b2, "host");
150 if (t1 != t2) {
151 return false;
154 if (!ep1 && ep2) {
155 return false;
158 if (ep1 && !ep2) {
159 return false;
162 if (ep1 && ep2) {
163 if (!strequal(ep1, ep2)) {
164 return false;
168 if (!h1 && h2) {
169 return false;
172 if (h1 && !h2) {
173 return false;
176 if (h1 && h2) {
177 if (!strequal(h1, h2)) {
178 return false;
182 return true;
185 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
186 struct dcerpc_binding *ep_description) {
187 struct dcesrv_endpoint *ep;
189 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
190 if (endpoints_match(ep->ep_description, ep_description)) {
191 return ep;
195 return NULL;
199 * Build a list of all interfaces handled by all endpoint servers.
201 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
202 struct dcesrv_endpoint *endpoint_list,
203 const struct GUID *uuid,
204 const char *srv_addr,
205 struct dcesrv_ep_iface **peps)
207 struct dcesrv_ep_iface *eps = NULL;
208 struct dcesrv_endpoint *d;
209 uint32_t total = 0;
210 NTSTATUS status;
212 *peps = NULL;
214 for (d = endpoint_list; d != NULL; d = d->next) {
215 struct dcesrv_iface_list *iface;
216 struct dcerpc_binding *description;
218 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
219 enum dcerpc_transport_t transport;
220 const char *host = NULL;
221 const char *host_addr = NULL;
223 #if 0
225 * Windows ignores the object uuid by default. There is
226 * one corner case. It is checked for the mgmt
227 * interface, which we do not implement here yet.
229 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
230 continue;
232 #endif
234 eps = talloc_realloc(mem_ctx,
235 eps,
236 struct dcesrv_ep_iface,
237 total + 1);
238 if (eps == NULL) {
239 return 0;
241 eps[total].name = talloc_strdup(eps,
242 iface->iface->name);
243 if (eps[total].name == NULL) {
244 return 0;
246 eps[total].syntax_id = iface->iface->syntax_id;
248 description = dcerpc_binding_dup(mem_ctx, d->ep_description);
249 if (description == NULL) {
250 return 0;
253 status = dcerpc_binding_set_abstract_syntax(description,
254 &iface->iface->syntax_id);
255 if (!NT_STATUS_IS_OK(status)) {
256 return 0;
259 transport = dcerpc_binding_get_transport(description);
260 host = dcerpc_binding_get_string_option(description, "host");
262 if (transport == NCACN_IP_TCP) {
263 if (host == NULL) {
264 host_addr = srv_addr;
265 } else if (!is_ipaddress_v4(host)) {
266 host_addr = srv_addr;
267 } else if (strcmp(host, "0.0.0.0") == 0) {
268 host_addr = srv_addr;
272 if (host_addr != NULL) {
273 status = dcerpc_binding_set_string_option(description,
274 "host",
275 host_addr);
276 if (!NT_STATUS_IS_OK(status)) {
277 return 0;
281 status = dcerpc_binding_build_tower(eps,
282 description,
283 &eps[total].ep);
284 TALLOC_FREE(description);
285 if (NT_STATUS_IS_ERR(status)) {
286 DEBUG(1, ("Unable to build tower for %s\n",
287 iface->iface->name));
288 continue;
290 total++;
294 *peps = eps;
296 return total;
299 static bool is_privileged_pipe(struct auth_session_info *info) {
300 /* If the user is not root, or has the system token, fail */
301 if ((info->unix_token->uid != sec_initial_uid()) &&
302 !security_token_is_system(info->security_token)) {
303 return false;
306 return true;
309 bool srv_epmapper_delete_endpoints(struct pipes_struct *p)
311 struct epm_Delete r;
312 struct dcesrv_ep_entry_list *el = p->ep_entries;
313 error_status_t result;
315 while (el) {
316 struct dcesrv_ep_entry_list *next = el->next;
318 r.in.num_ents = el->num_ents;
319 r.in.entries = el->entries;
321 DEBUG(10, ("Delete_endpoints for: %s\n",
322 el->entries[0].annotation));
324 result = _epm_Delete(p, &r);
325 if (result != EPMAPPER_STATUS_OK) {
326 return false;
329 DLIST_REMOVE(p->ep_entries, el);
330 TALLOC_FREE(el);
332 el = next;
335 return true;
338 void srv_epmapper_cleanup(void)
340 struct dcesrv_endpoint *ep = endpoint_table;
342 while (ep) {
343 struct dcesrv_endpoint *next = ep->next;
345 DLIST_REMOVE(endpoint_table, ep);
346 TALLOC_FREE(ep);
348 ep = next;
353 * epm_Insert
355 * Add the specified entries to an endpoint map.
357 error_status_t _epm_Insert(struct pipes_struct *p,
358 struct epm_Insert *r)
360 TALLOC_CTX *tmp_ctx;
361 error_status_t rc;
362 NTSTATUS status;
363 uint32_t i;
364 struct dcerpc_binding *b;
365 struct dcesrv_endpoint *ep;
366 struct dcesrv_iface_list *iflist;
367 struct dcesrv_iface *iface;
368 bool add_ep;
370 /* If this is not a privileged users, return */
371 if (p->transport != NCALRPC ||
372 !is_privileged_pipe(p->session_info)) {
373 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
374 return EPMAPPER_STATUS_CANT_PERFORM_OP;
377 tmp_ctx = talloc_stackframe();
378 if (tmp_ctx == NULL) {
379 return EPMAPPER_STATUS_NO_MEMORY;
382 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
383 r->in.num_ents));
385 for (i = 0; i < r->in.num_ents; i++) {
386 enum dcerpc_transport_t transport;
387 add_ep = false;
388 b = NULL;
390 status = dcerpc_binding_from_tower(tmp_ctx,
391 &r->in.entries[i].tower->tower,
392 &b);
393 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
394 rc = EPMAPPER_STATUS_NO_MEMORY;
395 goto done;
397 if (!NT_STATUS_IS_OK(status)) {
398 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
399 goto done;
402 transport = dcerpc_binding_get_transport(b);
403 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
404 derpc_transport_string_by_transport(transport),
405 r->in.entries[i].annotation));
407 /* Check if the entry already exits */
408 ep = find_endpoint(endpoint_table, b);
409 if (ep == NULL) {
410 /* No entry found, create it */
411 ep = talloc_zero(NULL, struct dcesrv_endpoint);
412 if (ep == NULL) {
413 rc = EPMAPPER_STATUS_NO_MEMORY;
414 goto done;
416 add_ep = true;
418 ep->ep_description = talloc_steal(ep, b);
421 /* TODO Replace the entry if the replace flag is set */
423 /* Create an interface */
424 iface = talloc(tmp_ctx, struct dcesrv_iface);
425 if (iface == NULL) {
426 rc = EPMAPPER_STATUS_NO_MEMORY;
427 goto done;
430 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
431 if (iface->name == NULL) {
432 rc = EPMAPPER_STATUS_NO_MEMORY;
433 goto done;
435 iface->syntax_id = dcerpc_binding_get_abstract_syntax(b);
438 * Check if the rpc service is alrady registered on the
439 * endpoint.
441 if (find_interface(ep, iface) != NULL) {
442 DEBUG(8, ("dcesrv_interface_register: interface '%s' "
443 "already registered on endpoint\n",
444 iface->name));
445 /* FIXME wrong error code? */
446 rc = EPMAPPER_STATUS_OK;
447 goto done;
450 /* Create an entry for the interface */
451 iflist = talloc(ep, struct dcesrv_iface_list);
452 if (iflist == NULL) {
453 rc = EPMAPPER_STATUS_NO_MEMORY;
454 goto done;
456 iflist->iface = talloc_move(iflist, &iface);
458 /* Finally add the interface on the endpoint */
459 DLIST_ADD(ep->iface_list, iflist);
461 /* If it's a new endpoint add it to the endpoint_table */
462 if (add_ep) {
463 DLIST_ADD(endpoint_table, ep);
467 if (r->in.num_ents > 0) {
468 struct dcesrv_ep_entry_list *el;
470 el = talloc_zero(p, struct dcesrv_ep_entry_list);
471 if (el == NULL) {
472 rc = EPMAPPER_STATUS_NO_MEMORY;
473 goto done;
475 el->num_ents = r->in.num_ents;
476 el->entries = talloc_move(el, &r->in.entries);
478 DLIST_ADD(p->ep_entries, el);
481 rc = EPMAPPER_STATUS_OK;
482 done:
483 talloc_free(tmp_ctx);
485 return rc;
490 * epm_Delete
492 * Delete the specified entries from an endpoint map.
494 error_status_t _epm_Delete(struct pipes_struct *p,
495 struct epm_Delete *r)
497 TALLOC_CTX *tmp_ctx;
498 error_status_t rc;
499 NTSTATUS status;
500 uint32_t i;
501 struct dcerpc_binding *b;
502 struct dcesrv_endpoint *ep;
503 struct dcesrv_iface iface;
504 struct dcesrv_iface_list *iflist;
506 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
507 r->in.num_ents));
509 /* If this is not a privileged users, return */
510 if (p->transport != NCALRPC ||
511 !is_privileged_pipe(p->session_info)) {
512 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
513 return EPMAPPER_STATUS_CANT_PERFORM_OP;
516 tmp_ctx = talloc_stackframe();
517 if (tmp_ctx == NULL) {
518 return EPMAPPER_STATUS_NO_MEMORY;
521 for (i = 0; i < r->in.num_ents; i++) {
522 enum dcerpc_transport_t transport;
524 b = NULL;
526 status = dcerpc_binding_from_tower(tmp_ctx,
527 &r->in.entries[i].tower->tower,
528 &b);
529 if (!NT_STATUS_IS_OK(status)) {
530 rc = EPMAPPER_STATUS_NO_MEMORY;
531 goto done;
534 transport = dcerpc_binding_get_transport(b);
535 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
536 derpc_transport_string_by_transport(transport),
537 r->in.entries[i].annotation));
539 ep = find_endpoint(endpoint_table, b);
540 if (ep == NULL) {
541 rc = EPMAPPER_STATUS_OK;
542 goto done;
545 iface.name = r->in.entries[i].annotation;
546 iface.syntax_id = dcerpc_binding_get_abstract_syntax(b);
548 iflist = find_interface_list(ep, &iface);
549 if (iflist == NULL) {
550 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
551 DLIST_REMOVE(endpoint_table, ep);
552 talloc_free(ep);
554 rc = EPMAPPER_STATUS_OK;
555 goto done;
558 DLIST_REMOVE(ep->iface_list, iflist);
560 if (ep->iface_list == NULL) {
561 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
562 DLIST_REMOVE(endpoint_table, ep);
563 talloc_free(ep);
565 rc = EPMAPPER_STATUS_OK;
566 goto done;
571 rc = EPMAPPER_STATUS_OK;
572 done:
573 talloc_free(tmp_ctx);
575 return rc;
580 * epm_Lookup
582 * Lookup entries in an endpoint map.
584 error_status_t _epm_Lookup(struct pipes_struct *p,
585 struct epm_Lookup *r)
587 struct policy_handle *entry_handle;
588 struct rpc_eps *eps;
589 TALLOC_CTX *tmp_ctx;
590 error_status_t rc;
591 uint32_t count = 0;
592 uint32_t num_ents = 0;
593 uint32_t i;
594 bool match = false;
595 bool ok;
597 *r->out.num_ents = 0;
598 r->out.entries = NULL;
600 tmp_ctx = talloc_stackframe();
601 if (tmp_ctx == NULL) {
602 return EPMAPPER_STATUS_NO_MEMORY;
605 DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
606 r->in.max_ents));
608 if (r->in.entry_handle == NULL ||
609 ndr_policy_handle_empty(r->in.entry_handle)) {
610 char *srv_addr = NULL;
612 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
614 eps = talloc_zero(tmp_ctx, struct rpc_eps);
615 if (eps == NULL) {
616 rc = EPMAPPER_STATUS_NO_MEMORY;
617 goto done;
620 if (p->local_address != NULL &&
621 tsocket_address_is_inet(p->local_address, "ipv4"))
623 srv_addr = tsocket_address_inet_addr_string(p->local_address,
624 tmp_ctx);
627 switch (r->in.inquiry_type) {
628 case RPC_C_EP_ALL_ELTS:
630 * Return all elements from the endpoint map. The
631 * interface_id, vers_option, and object parameters MUST
632 * be ignored.
634 eps->count = build_ep_list(eps,
635 endpoint_table,
636 NULL,
637 srv_addr,
638 &eps->e);
639 break;
640 case RPC_C_EP_MATCH_BY_IF:
642 * Return endpoint map elements that contain the
643 * interface identifier specified by the interface_id
644 * and vers_option values.
646 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
647 * need both the same endpoint list. There is a second
648 * check for the inquiry_type below which differentiates
649 * between them.
651 case RPC_C_EP_MATCH_BY_BOTH:
653 * Return endpoint map elements that contain the
654 * interface identifier and object UUID specified by
655 * interface_id, vers_option, and object.
657 eps->count = build_ep_list(eps,
658 endpoint_table,
659 &r->in.interface_id->uuid,
660 srv_addr,
661 &eps->e);
662 break;
663 case RPC_C_EP_MATCH_BY_OBJ:
665 * Return endpoint map elements that contain the object
666 * UUID specified by object.
668 eps->count = build_ep_list(eps,
669 endpoint_table,
670 r->in.object,
671 srv_addr,
672 &eps->e);
673 break;
674 default:
675 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
676 goto done;
679 if (eps->count == 0) {
680 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
681 goto done;
684 ok = create_policy_hnd(p, r->out.entry_handle, eps);
685 if (!ok) {
686 rc = EPMAPPER_STATUS_NO_MEMORY;
687 goto done;
690 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
691 if (!ok) {
692 rc = EPMAPPER_STATUS_NO_MEMORY;
693 goto done;
695 entry_handle = r->out.entry_handle;
696 } else {
697 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
699 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
700 if (!ok) {
701 rc = EPMAPPER_STATUS_NO_MEMORY;
702 goto done;
704 entry_handle = r->in.entry_handle;
707 if (eps == NULL || eps->e == NULL) {
708 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
709 goto done;
712 /* return the next N elements */
713 count = r->in.max_ents;
714 if (count > eps->count) {
715 count = eps->count;
718 DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
720 if (count == 0) {
721 close_policy_hnd(p, entry_handle);
722 ZERO_STRUCTP(r->out.entry_handle);
724 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
725 goto done;
728 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
729 if (r->out.entries == NULL) {
730 rc = EPMAPPER_STATUS_NO_MEMORY;
731 goto done;
734 for (i = 0; i < count; i++) {
735 match = false;
737 switch (r->in.inquiry_type) {
738 case RPC_C_EP_ALL_ELTS:
740 * Return all elements from the endpoint map. The
741 * interface_id, vers_option, and object parameters MUST
742 * be ignored.
744 match = true;
745 break;
746 case RPC_C_EP_MATCH_BY_IF:
748 * Return endpoint map elements that contain the
749 * interface identifier specified by the interface_id
750 * and vers_option values.
752 if (GUID_equal(&r->in.interface_id->uuid,
753 &eps->e[i].syntax_id.uuid)) {
754 match = true;
756 break;
757 case RPC_C_EP_MATCH_BY_OBJ:
759 * Return endpoint map elements that contain the object
760 * UUID specified by object.
762 if (GUID_equal(r->in.object,
763 &eps->e[i].syntax_id.uuid)) {
764 match = true;
766 break;
767 case RPC_C_EP_MATCH_BY_BOTH:
769 * Return endpoint map elements that contain the
770 * interface identifier and object UUID specified by
771 * interface_id, vers_option, and object.
773 if (GUID_equal(&r->in.interface_id->uuid,
774 &eps->e[i].syntax_id.uuid) &&
775 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
776 match = true;
778 break;
779 default:
780 return EPMAPPER_STATUS_CANT_PERFORM_OP;
783 if (match) {
784 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
785 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
786 /* Check interface version */
788 match = false;
789 switch (r->in.vers_option) {
790 case RPC_C_VERS_ALL:
792 * Return endpoint map elements that
793 * contain the specified interface UUID,
794 * regardless of the version numbers.
796 match = true;
797 break;
798 case RPC_C_VERS_COMPATIBLE:
800 * Return the endpoint map elements that
801 * contain the same major versions of
802 * the specified interface UUID and a
803 * minor version greater than or equal
804 * to the minor version of the specified
805 * UUID.
807 if (r->in.interface_id->vers_major ==
808 (eps->e[i].syntax_id.if_version >> 16) &&
809 r->in.interface_id->vers_minor <=
810 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
811 match = true;
813 break;
814 case RPC_C_VERS_EXACT:
816 * Return endpoint map elements that
817 * contain the specified version of the
818 * specified interface UUID.
820 if (r->in.interface_id->vers_major ==
821 (eps->e[i].syntax_id.if_version >> 16) &&
822 r->in.interface_id->vers_minor ==
823 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
824 match = true;
826 match = true;
827 break;
828 case RPC_C_VERS_MAJOR_ONLY:
830 * Return endpoint map elements that
831 * contain the same version of the
832 * specified interface UUID and ignore
833 * the minor version.
835 if (r->in.interface_id->vers_major ==
836 (eps->e[i].syntax_id.if_version >> 16)) {
837 match = true;
839 match = true;
840 break;
841 case RPC_C_VERS_UPTO:
843 * Return endpoint map elements that
844 * contain a version of the specified
845 * interface UUID less than or equal to
846 * the specified major and minor
847 * version.
849 if (r->in.interface_id->vers_major >
850 eps->e[i].syntax_id.if_version >> 16) {
851 match = true;
852 } else {
853 if (r->in.interface_id->vers_major ==
854 (eps->e[i].syntax_id.if_version >> 16) &&
855 r->in.interface_id->vers_minor >=
856 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
857 match = true;
860 break;
861 default:
862 return EPMAPPER_STATUS_CANT_PERFORM_OP;
867 if (match) {
868 ZERO_STRUCT(r->out.entries[num_ents].object);
870 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
871 eps->e[i].name));
872 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
873 eps->e[i].name);
874 r->out.entries[num_ents].tower = talloc(r->out.entries,
875 struct epm_twr_t);
876 if (r->out.entries[num_ents].tower == NULL) {
877 rc = EPMAPPER_STATUS_NO_MEMORY;
878 goto done;
880 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
881 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
882 r->out.entries[num_ents].tower->tower_length = 0;
884 num_ents++;
886 } /* end for loop */
888 *r->out.num_ents = num_ents;
890 eps->count -= count;
891 eps->e += count;
892 if (eps->count == 0) {
893 close_policy_hnd(p, entry_handle);
894 ZERO_STRUCTP(r->out.entry_handle);
895 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
896 goto done;
899 rc = EPMAPPER_STATUS_OK;
900 done:
901 talloc_free(tmp_ctx);
903 return rc;
907 * epm_Map
909 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
910 * to produce a list of protocol towers.
912 error_status_t _epm_Map(struct pipes_struct *p,
913 struct epm_Map *r)
915 struct policy_handle *entry_handle;
916 enum dcerpc_transport_t transport;
917 struct ndr_syntax_id ifid;
918 struct epm_floor *floors;
919 struct rpc_eps *eps;
920 TALLOC_CTX *tmp_ctx;
921 error_status_t rc;
922 uint32_t count = 0;
923 uint32_t num_towers = 0;
924 uint32_t i;
925 bool ok;
927 *r->out.num_towers = 0;
928 r->out.towers = NULL;
930 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
931 r->in.map_tower->tower.num_floors < 3) {
932 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
935 tmp_ctx = talloc_stackframe();
936 if (tmp_ctx == NULL) {
937 return EPMAPPER_STATUS_NO_MEMORY;
940 ZERO_STRUCTP(r->out.entry_handle);
942 DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
943 r->in.max_towers));
946 * A tower has normally up to 6 floors
948 * +-----------------------------------------------------------------+
949 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
950 * | | netlogon) |
951 * +---------+-------------------------------------------------------+
952 * | Floor 2 | Transfer syntax (NDR endcoded) |
953 * +---------+-------------------------------------------------------+
954 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
955 * +---------+-------------------------------------------------------+
956 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
957 * +---------+-------------------------------------------------------+
958 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
959 * +---------+-------------------------------------------------------+
960 * | Floor 6 | Routing |
961 * +---------+-------------------------------------------------------+
963 floors = r->in.map_tower->tower.floors;
965 /* We accept NDR as the transfer syntax */
966 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
968 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
969 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax_ndr.uuid) ||
970 ifid.if_version != ndr_transfer_syntax_ndr.if_version) {
971 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
972 goto done;
975 /* We only talk to sane transports */
976 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
977 if (transport == NCA_UNKNOWN) {
978 DEBUG(2, ("epm_Map: Client requested unknown transport with"
979 "levels: "));
980 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
981 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
983 DEBUG(2, ("\n"));
984 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
985 goto done;
988 if (r->in.entry_handle == NULL ||
989 ndr_policy_handle_empty(r->in.entry_handle)) {
990 struct GUID *obj;
991 char *srv_addr = NULL;
993 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
995 eps = talloc_zero(tmp_ctx, struct rpc_eps);
996 if (eps == NULL) {
997 rc = EPMAPPER_STATUS_NO_MEMORY;
998 goto done;
1002 * *** ATTENTION ***
1003 * CDE 1.1 states:
1005 * ept_map()
1006 * Apply some algorithm (using the fields in the map_tower)
1007 * to an endpoint map to produce a list of protocol towers.
1009 * The following code is the mysterious "some algorithm"!
1012 /* Filter by object id if one was given. */
1013 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
1014 obj = NULL;
1015 } else {
1016 obj = r->in.object;
1019 if (p->local_address != NULL &&
1020 tsocket_address_is_inet(p->local_address, "ipv4"))
1022 srv_addr = tsocket_address_inet_addr_string(p->local_address,
1023 tmp_ctx);
1026 eps->count = build_ep_list(eps,
1027 endpoint_table,
1028 obj,
1029 srv_addr,
1030 &eps->e);
1031 if (eps->count == 0) {
1032 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1033 goto done;
1036 /* Filter out endpoints which match the interface. */
1038 struct rpc_eps *teps;
1039 uint32_t total = 0;
1041 teps = talloc_zero(tmp_ctx, struct rpc_eps);
1042 if (teps == NULL) {
1043 rc = EPMAPPER_STATUS_NO_MEMORY;
1044 goto done;
1047 for (i = 0; i < eps->count; i++) {
1048 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
1049 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
1050 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
1051 continue;
1054 teps->e = talloc_realloc(tmp_ctx,
1055 teps->e,
1056 struct dcesrv_ep_iface,
1057 total + 1);
1058 if (teps->e == NULL) {
1059 return 0;
1062 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
1063 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
1064 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
1065 teps->e[total].syntax_id = eps->e[i].syntax_id;
1067 total++;
1070 teps->count = total;
1071 talloc_free(eps);
1072 eps = teps;
1074 /* end of "some algorithm" */
1076 ok = create_policy_hnd(p, r->out.entry_handle, eps);
1077 if (!ok) {
1078 rc = EPMAPPER_STATUS_NO_MEMORY;
1079 goto done;
1082 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
1083 if (!ok) {
1084 rc = EPMAPPER_STATUS_NO_MEMORY;
1085 goto done;
1087 entry_handle = r->out.entry_handle;
1088 } else {
1089 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
1091 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
1092 if (!ok) {
1093 rc = EPMAPPER_STATUS_NO_MEMORY;
1094 goto done;
1096 entry_handle = r->in.entry_handle;
1099 if (eps == NULL || eps->e == NULL) {
1100 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1101 goto done;
1104 /* return the next N elements */
1105 count = r->in.max_towers;
1106 if (count > eps->count) {
1107 count = eps->count;
1110 if (count == 0) {
1111 close_policy_hnd(p, entry_handle);
1112 ZERO_STRUCTP(r->out.entry_handle);
1114 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1115 goto done;
1118 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1119 if (r->out.towers == NULL) {
1120 rc = EPMAPPER_STATUS_NO_MEMORY;
1121 goto done;
1124 for (i = 0; i < count; i++) {
1125 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
1126 eps->e[i].name));
1128 r->out.towers[num_towers].twr = talloc(r->out.towers,
1129 struct epm_twr_t);
1130 if (r->out.towers[num_towers].twr == NULL) {
1131 rc = EPMAPPER_STATUS_NO_MEMORY;
1132 goto done;
1134 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1135 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1136 r->out.towers[num_towers].twr->tower_length = 0;
1138 num_towers++;
1141 *r->out.num_towers = num_towers;
1143 eps->count -= count;
1144 eps->e += count;
1145 if (eps->count == 0) {
1146 close_policy_hnd(p, entry_handle);
1147 ZERO_STRUCTP(r->out.entry_handle);
1150 rc = EPMAPPER_STATUS_OK;
1151 done:
1152 talloc_free(tmp_ctx);
1154 return rc;
1158 * epm_LookupHandleFree
1160 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1161 struct epm_LookupHandleFree *r)
1163 if (r->in.entry_handle == NULL) {
1164 return EPMAPPER_STATUS_OK;
1167 if (is_valid_policy_hnd(r->in.entry_handle)) {
1168 close_policy_hnd(p, r->in.entry_handle);
1171 r->out.entry_handle = r->in.entry_handle;
1173 return EPMAPPER_STATUS_OK;
1178 * epm_InqObject
1180 * A client implementation SHOULD NOT call this method. These extensions do not
1181 * provide an alternative method.
1183 error_status_t _epm_InqObject(struct pipes_struct *p,
1184 struct epm_InqObject *r)
1186 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1187 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1192 * epm_MgmtDelete
1194 * A client implementation SHOULD NOT call this method. These extensions do not
1195 * provide an alternative method.
1197 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1198 struct epm_MgmtDelete *r)
1200 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1201 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1206 epm_MapAuth
1208 error_status_t _epm_MapAuth(struct pipes_struct *p,
1209 struct epm_MapAuth *r)
1211 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1212 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1215 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */