smbd: Rename lck2->rw_probe in brl_conflict_other
[Samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blob129ce520ce17f77f8f1709ee3c6a7e57659b57f1
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;
105 * See if a uuid and if_version match to an interface
107 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
108 const struct GUID *uuid)
110 return GUID_equal(&iface->syntax_id.uuid, uuid);
113 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
114 const struct dcesrv_iface *iface)
116 struct dcesrv_iface_list *iflist;
118 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
119 if (interface_match(iflist->iface, iface)) {
120 return iflist;
124 return NULL;
128 * Check if two endpoints match.
130 static bool endpoints_match(const struct dcerpc_binding *b1,
131 const struct dcerpc_binding *b2)
133 enum dcerpc_transport_t t1;
134 const char *ep1;
135 const char *h1;
136 enum dcerpc_transport_t t2;
137 const char *ep2;
138 const char *h2;
140 t1 = dcerpc_binding_get_transport(b1);
141 ep1 = dcerpc_binding_get_string_option(b1, "endpoint");
142 h1 = dcerpc_binding_get_string_option(b1, "host");
144 t2 = dcerpc_binding_get_transport(b2);
145 ep2 = dcerpc_binding_get_string_option(b2, "endpoint");
146 h2 = dcerpc_binding_get_string_option(b2, "host");
148 if (t1 != t2) {
149 return false;
152 if (!ep1 && ep2) {
153 return false;
156 if (ep1 && !ep2) {
157 return false;
160 if (ep1 && ep2) {
161 if (!strequal(ep1, ep2)) {
162 return false;
166 if (!h1 && h2) {
167 return false;
170 if (h1 && !h2) {
171 return false;
174 if (h1 && h2) {
175 if (!strequal(h1, h2)) {
176 return false;
180 return true;
183 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
184 struct dcerpc_binding *ep_description) {
185 struct dcesrv_endpoint *ep;
187 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
188 if (endpoints_match(ep->ep_description, ep_description)) {
189 return ep;
193 return NULL;
197 * Build a list of all interfaces handled by all endpoint servers.
199 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
200 struct dcesrv_endpoint *endpoint_list,
201 const struct GUID *uuid,
202 const char *srv_addr,
203 struct dcesrv_ep_iface **peps)
205 struct dcesrv_ep_iface *eps = NULL;
206 struct dcesrv_endpoint *d;
207 uint32_t total = 0;
208 NTSTATUS status;
210 *peps = NULL;
212 for (d = endpoint_list; d != NULL; d = d->next) {
213 struct dcesrv_iface_list *iface;
214 struct dcerpc_binding *description;
216 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
217 enum dcerpc_transport_t transport;
218 const char *host = NULL;
219 const char *host_addr = NULL;
221 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
222 continue;
225 eps = talloc_realloc(mem_ctx,
226 eps,
227 struct dcesrv_ep_iface,
228 total + 1);
229 if (eps == NULL) {
230 return 0;
232 eps[total].name = talloc_strdup(eps,
233 iface->iface->name);
234 if (eps[total].name == NULL) {
235 return 0;
237 eps[total].syntax_id = iface->iface->syntax_id;
239 description = dcerpc_binding_dup(mem_ctx, d->ep_description);
240 if (description == NULL) {
241 return 0;
244 status = dcerpc_binding_set_abstract_syntax(description,
245 &iface->iface->syntax_id);
246 if (!NT_STATUS_IS_OK(status)) {
247 return 0;
250 transport = dcerpc_binding_get_transport(description);
251 host = dcerpc_binding_get_string_option(description, "host");
253 if (transport == NCACN_IP_TCP) {
254 if (host == NULL) {
255 host_addr = srv_addr;
256 } else if (!is_ipaddress_v4(host)) {
257 host_addr = srv_addr;
258 } else if (strcmp(host, "0.0.0.0") == 0) {
259 host_addr = srv_addr;
263 if (host_addr != NULL) {
264 status = dcerpc_binding_set_string_option(description,
265 "host",
266 host_addr);
267 if (!NT_STATUS_IS_OK(status)) {
268 return 0;
272 status = dcerpc_binding_build_tower(eps,
273 description,
274 &eps[total].ep);
275 TALLOC_FREE(description);
276 if (NT_STATUS_IS_ERR(status)) {
277 DEBUG(1, ("Unable to build tower for %s\n",
278 iface->iface->name));
279 continue;
281 total++;
285 *peps = eps;
287 return total;
290 static bool is_privileged_pipe(struct auth_session_info *info) {
291 /* If the user is not root, or has the system token, fail */
292 if ((info->unix_token->uid != sec_initial_uid()) &&
293 !security_token_is_system(info->security_token)) {
294 return false;
297 return true;
300 bool srv_epmapper_delete_endpoints(struct pipes_struct *p)
302 struct epm_Delete r;
303 struct dcesrv_ep_entry_list *el = p->ep_entries;
304 error_status_t result;
306 while (el) {
307 struct dcesrv_ep_entry_list *next = el->next;
309 r.in.num_ents = el->num_ents;
310 r.in.entries = el->entries;
312 DEBUG(10, ("Delete_endpoints for: %s\n",
313 el->entries[0].annotation));
315 result = _epm_Delete(p, &r);
316 if (result != EPMAPPER_STATUS_OK) {
317 return false;
320 DLIST_REMOVE(p->ep_entries, el);
321 TALLOC_FREE(el);
323 el = next;
326 return true;
329 void srv_epmapper_cleanup(void)
331 struct dcesrv_endpoint *ep = endpoint_table;
333 while (ep) {
334 struct dcesrv_endpoint *next = ep->next;
336 DLIST_REMOVE(endpoint_table, ep);
337 TALLOC_FREE(ep);
339 ep = next;
344 * epm_Insert
346 * Add the specified entries to an endpoint map.
348 error_status_t _epm_Insert(struct pipes_struct *p,
349 struct epm_Insert *r)
351 TALLOC_CTX *tmp_ctx;
352 error_status_t rc;
353 NTSTATUS status;
354 uint32_t i;
355 struct dcerpc_binding *b;
356 struct dcesrv_endpoint *ep;
357 struct dcesrv_iface_list *iflist;
358 struct dcesrv_iface *iface;
359 bool add_ep;
361 /* If this is not a privileged users, return */
362 if (p->transport != NCALRPC ||
363 !is_privileged_pipe(p->session_info)) {
364 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
365 return EPMAPPER_STATUS_CANT_PERFORM_OP;
368 tmp_ctx = talloc_stackframe();
369 if (tmp_ctx == NULL) {
370 return EPMAPPER_STATUS_NO_MEMORY;
373 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
374 r->in.num_ents));
376 for (i = 0; i < r->in.num_ents; i++) {
377 enum dcerpc_transport_t transport;
378 add_ep = false;
379 b = NULL;
381 status = dcerpc_binding_from_tower(tmp_ctx,
382 &r->in.entries[i].tower->tower,
383 &b);
384 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
385 rc = EPMAPPER_STATUS_NO_MEMORY;
386 goto done;
388 if (!NT_STATUS_IS_OK(status)) {
389 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
390 goto done;
393 transport = dcerpc_binding_get_transport(b);
394 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
395 derpc_transport_string_by_transport(transport),
396 r->in.entries[i].annotation));
398 /* Check if the entry already exits */
399 ep = find_endpoint(endpoint_table, b);
400 if (ep == NULL) {
401 /* No entry found, create it */
402 ep = talloc_zero(NULL, struct dcesrv_endpoint);
403 if (ep == NULL) {
404 rc = EPMAPPER_STATUS_NO_MEMORY;
405 goto done;
407 add_ep = true;
409 ep->ep_description = talloc_steal(ep, b);
412 /* TODO Replace the entry if the replace flag is set */
414 /* Create an interface */
415 iface = talloc(tmp_ctx, struct dcesrv_iface);
416 if (iface == NULL) {
417 rc = EPMAPPER_STATUS_NO_MEMORY;
418 goto done;
421 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
422 if (iface->name == NULL) {
423 rc = EPMAPPER_STATUS_NO_MEMORY;
424 goto done;
426 iface->syntax_id = dcerpc_binding_get_abstract_syntax(b);
429 * Check if the rpc service is alrady registered on the
430 * endpoint.
432 if (find_interface(ep, iface) != NULL) {
433 DEBUG(8, ("dcesrv_interface_register: interface '%s' "
434 "already registered on endpoint\n",
435 iface->name));
436 /* FIXME wrong error code? */
437 rc = EPMAPPER_STATUS_OK;
438 goto done;
441 /* Create an entry for the interface */
442 iflist = talloc(ep, struct dcesrv_iface_list);
443 if (iflist == NULL) {
444 rc = EPMAPPER_STATUS_NO_MEMORY;
445 goto done;
447 iflist->iface = talloc_move(iflist, &iface);
449 /* Finally add the interface on the endpoint */
450 DLIST_ADD(ep->iface_list, iflist);
452 /* If it's a new endpoint add it to the endpoint_table */
453 if (add_ep) {
454 DLIST_ADD(endpoint_table, ep);
458 if (r->in.num_ents > 0) {
459 struct dcesrv_ep_entry_list *el;
461 el = talloc_zero(p, struct dcesrv_ep_entry_list);
462 if (el == NULL) {
463 rc = EPMAPPER_STATUS_NO_MEMORY;
464 goto done;
466 el->num_ents = r->in.num_ents;
467 el->entries = talloc_move(el, &r->in.entries);
469 DLIST_ADD(p->ep_entries, el);
472 rc = EPMAPPER_STATUS_OK;
473 done:
474 talloc_free(tmp_ctx);
476 return rc;
481 * epm_Delete
483 * Delete the specified entries from an endpoint map.
485 error_status_t _epm_Delete(struct pipes_struct *p,
486 struct epm_Delete *r)
488 TALLOC_CTX *tmp_ctx;
489 error_status_t rc;
490 NTSTATUS status;
491 uint32_t i;
492 struct dcerpc_binding *b;
493 struct dcesrv_endpoint *ep;
494 struct dcesrv_iface iface;
495 struct dcesrv_iface_list *iflist;
497 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
498 r->in.num_ents));
500 /* If this is not a privileged users, return */
501 if (p->transport != NCALRPC ||
502 !is_privileged_pipe(p->session_info)) {
503 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
504 return EPMAPPER_STATUS_CANT_PERFORM_OP;
507 tmp_ctx = talloc_stackframe();
508 if (tmp_ctx == NULL) {
509 return EPMAPPER_STATUS_NO_MEMORY;
512 for (i = 0; i < r->in.num_ents; i++) {
513 enum dcerpc_transport_t transport;
515 b = NULL;
517 status = dcerpc_binding_from_tower(tmp_ctx,
518 &r->in.entries[i].tower->tower,
519 &b);
520 if (!NT_STATUS_IS_OK(status)) {
521 rc = EPMAPPER_STATUS_NO_MEMORY;
522 goto done;
525 transport = dcerpc_binding_get_transport(b);
526 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
527 derpc_transport_string_by_transport(transport),
528 r->in.entries[i].annotation));
530 ep = find_endpoint(endpoint_table, b);
531 if (ep == NULL) {
532 rc = EPMAPPER_STATUS_OK;
533 goto done;
536 iface.name = r->in.entries[i].annotation;
537 iface.syntax_id = dcerpc_binding_get_abstract_syntax(b);
539 iflist = find_interface_list(ep, &iface);
540 if (iflist == NULL) {
541 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
542 DLIST_REMOVE(endpoint_table, ep);
543 talloc_free(ep);
545 rc = EPMAPPER_STATUS_OK;
546 goto done;
549 DLIST_REMOVE(ep->iface_list, iflist);
551 if (ep->iface_list == NULL) {
552 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
553 DLIST_REMOVE(endpoint_table, ep);
554 talloc_free(ep);
556 rc = EPMAPPER_STATUS_OK;
557 goto done;
562 rc = EPMAPPER_STATUS_OK;
563 done:
564 talloc_free(tmp_ctx);
566 return rc;
571 * epm_Lookup
573 * Lookup entries in an endpoint map.
575 error_status_t _epm_Lookup(struct pipes_struct *p,
576 struct epm_Lookup *r)
578 struct policy_handle *entry_handle;
579 struct rpc_eps *eps;
580 TALLOC_CTX *tmp_ctx;
581 error_status_t rc;
582 uint32_t count = 0;
583 uint32_t num_ents = 0;
584 uint32_t i;
585 bool match = false;
586 bool ok;
588 *r->out.num_ents = 0;
589 r->out.entries = NULL;
591 tmp_ctx = talloc_stackframe();
592 if (tmp_ctx == NULL) {
593 return EPMAPPER_STATUS_NO_MEMORY;
596 DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
597 r->in.max_ents));
599 if (r->in.entry_handle == NULL ||
600 ndr_policy_handle_empty(r->in.entry_handle)) {
601 char *srv_addr = NULL;
603 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
605 eps = talloc_zero(tmp_ctx, struct rpc_eps);
606 if (eps == NULL) {
607 rc = EPMAPPER_STATUS_NO_MEMORY;
608 goto done;
611 if (p->local_address != NULL &&
612 tsocket_address_is_inet(p->local_address, "ipv4"))
614 srv_addr = tsocket_address_inet_addr_string(p->local_address,
615 tmp_ctx);
618 switch (r->in.inquiry_type) {
619 case RPC_C_EP_ALL_ELTS:
621 * Return all elements from the endpoint map. The
622 * interface_id, vers_option, and object parameters MUST
623 * be ignored.
625 eps->count = build_ep_list(eps,
626 endpoint_table,
627 NULL,
628 srv_addr,
629 &eps->e);
630 break;
631 case RPC_C_EP_MATCH_BY_IF:
633 * Return endpoint map elements that contain the
634 * interface identifier specified by the interface_id
635 * and vers_option values.
637 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
638 * need both the same endpoint list. There is a second
639 * check for the inquiry_type below which differentiates
640 * between them.
642 case RPC_C_EP_MATCH_BY_BOTH:
644 * Return endpoint map elements that contain the
645 * interface identifier and object UUID specified by
646 * interface_id, vers_option, and object.
648 eps->count = build_ep_list(eps,
649 endpoint_table,
650 &r->in.interface_id->uuid,
651 srv_addr,
652 &eps->e);
653 break;
654 case RPC_C_EP_MATCH_BY_OBJ:
656 * Return endpoint map elements that contain the object
657 * UUID specified by object.
659 eps->count = build_ep_list(eps,
660 endpoint_table,
661 r->in.object,
662 srv_addr,
663 &eps->e);
664 break;
665 default:
666 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
667 goto done;
670 if (eps->count == 0) {
671 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
672 goto done;
675 ok = create_policy_hnd(p, r->out.entry_handle, eps);
676 if (!ok) {
677 rc = EPMAPPER_STATUS_NO_MEMORY;
678 goto done;
681 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
682 if (!ok) {
683 rc = EPMAPPER_STATUS_NO_MEMORY;
684 goto done;
686 entry_handle = r->out.entry_handle;
687 } else {
688 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
690 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
691 if (!ok) {
692 rc = EPMAPPER_STATUS_NO_MEMORY;
693 goto done;
695 entry_handle = r->in.entry_handle;
698 if (eps == NULL || eps->e == NULL) {
699 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
700 goto done;
703 /* return the next N elements */
704 count = r->in.max_ents;
705 if (count > eps->count) {
706 count = eps->count;
709 DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
711 if (count == 0) {
712 close_policy_hnd(p, entry_handle);
713 ZERO_STRUCTP(r->out.entry_handle);
715 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
716 goto done;
719 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
720 if (r->out.entries == NULL) {
721 rc = EPMAPPER_STATUS_NO_MEMORY;
722 goto done;
725 for (i = 0; i < count; i++) {
726 match = false;
728 switch (r->in.inquiry_type) {
729 case RPC_C_EP_ALL_ELTS:
731 * Return all elements from the endpoint map. The
732 * interface_id, vers_option, and object parameters MUST
733 * be ignored.
735 match = true;
736 break;
737 case RPC_C_EP_MATCH_BY_IF:
739 * Return endpoint map elements that contain the
740 * interface identifier specified by the interface_id
741 * and vers_option values.
743 if (GUID_equal(&r->in.interface_id->uuid,
744 &eps->e[i].syntax_id.uuid)) {
745 match = true;
747 break;
748 case RPC_C_EP_MATCH_BY_OBJ:
750 * Return endpoint map elements that contain the object
751 * UUID specified by object.
753 if (GUID_equal(r->in.object,
754 &eps->e[i].syntax_id.uuid)) {
755 match = true;
757 break;
758 case RPC_C_EP_MATCH_BY_BOTH:
760 * Return endpoint map elements that contain the
761 * interface identifier and object UUID specified by
762 * interface_id, vers_option, and object.
764 if (GUID_equal(&r->in.interface_id->uuid,
765 &eps->e[i].syntax_id.uuid) &&
766 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
767 match = true;
769 break;
770 default:
771 return EPMAPPER_STATUS_CANT_PERFORM_OP;
774 if (match) {
775 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
776 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
777 /* Check inteface version */
779 match = false;
780 switch (r->in.vers_option) {
781 case RPC_C_VERS_ALL:
783 * Return endpoint map elements that
784 * contain the specified interface UUID,
785 * regardless of the version numbers.
787 match = true;
788 break;
789 case RPC_C_VERS_COMPATIBLE:
791 * Return the endpoint map elements that
792 * contain the same major versions of
793 * the specified interface UUID and a
794 * minor version greater than or equal
795 * to the minor version of the specified
796 * UUID.
798 if (r->in.interface_id->vers_major ==
799 (eps->e[i].syntax_id.if_version >> 16) &&
800 r->in.interface_id->vers_minor <=
801 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
802 match = true;
804 break;
805 case RPC_C_VERS_EXACT:
807 * Return endpoint map elements that
808 * contain the specified version of the
809 * specified interface UUID.
811 if (r->in.interface_id->vers_major ==
812 (eps->e[i].syntax_id.if_version >> 16) &&
813 r->in.interface_id->vers_minor ==
814 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
815 match = true;
817 match = true;
818 break;
819 case RPC_C_VERS_MAJOR_ONLY:
821 * Return endpoint map elements that
822 * contain the same version of the
823 * specified interface UUID and ignore
824 * the minor version.
826 if (r->in.interface_id->vers_major ==
827 (eps->e[i].syntax_id.if_version >> 16)) {
828 match = true;
830 match = true;
831 break;
832 case RPC_C_VERS_UPTO:
834 * Return endpoint map elements that
835 * contain a version of the specified
836 * interface UUID less than or equal to
837 * the specified major and minor
838 * version.
840 if (r->in.interface_id->vers_major >
841 eps->e[i].syntax_id.if_version >> 16) {
842 match = true;
843 } else {
844 if (r->in.interface_id->vers_major ==
845 (eps->e[i].syntax_id.if_version >> 16) &&
846 r->in.interface_id->vers_minor >=
847 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
848 match = true;
851 break;
852 default:
853 return EPMAPPER_STATUS_CANT_PERFORM_OP;
858 if (match) {
859 ZERO_STRUCT(r->out.entries[num_ents].object);
861 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
862 eps->e[i].name));
863 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
864 eps->e[i].name);
865 r->out.entries[num_ents].tower = talloc(r->out.entries,
866 struct epm_twr_t);
867 if (r->out.entries[num_ents].tower == NULL) {
868 rc = EPMAPPER_STATUS_NO_MEMORY;
869 goto done;
871 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
872 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
873 r->out.entries[num_ents].tower->tower_length = 0;
875 num_ents++;
877 } /* end for loop */
879 *r->out.num_ents = num_ents;
881 eps->count -= count;
882 eps->e += count;
883 if (eps->count == 0) {
884 close_policy_hnd(p, entry_handle);
885 ZERO_STRUCTP(r->out.entry_handle);
886 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
887 goto done;
890 rc = EPMAPPER_STATUS_OK;
891 done:
892 talloc_free(tmp_ctx);
894 return rc;
898 * epm_Map
900 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
901 * to produce a list of protocol towers.
903 error_status_t _epm_Map(struct pipes_struct *p,
904 struct epm_Map *r)
906 struct policy_handle *entry_handle;
907 enum dcerpc_transport_t transport;
908 struct ndr_syntax_id ifid;
909 struct epm_floor *floors;
910 struct rpc_eps *eps;
911 TALLOC_CTX *tmp_ctx;
912 error_status_t rc;
913 uint32_t count = 0;
914 uint32_t num_towers = 0;
915 uint32_t i;
916 bool ok;
918 *r->out.num_towers = 0;
919 r->out.towers = NULL;
921 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
922 r->in.map_tower->tower.num_floors < 3) {
923 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
926 tmp_ctx = talloc_stackframe();
927 if (tmp_ctx == NULL) {
928 return EPMAPPER_STATUS_NO_MEMORY;
931 ZERO_STRUCTP(r->out.entry_handle);
933 DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
934 r->in.max_towers));
937 * A tower has normally up to 6 floors
939 * +-----------------------------------------------------------------+
940 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
941 * | | netlogon) |
942 * +---------+-------------------------------------------------------+
943 * | Floor 2 | Transfer syntax (NDR endcoded) |
944 * +---------+-------------------------------------------------------+
945 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
946 * +---------+-------------------------------------------------------+
947 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
948 * +---------+-------------------------------------------------------+
949 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
950 * +---------+-------------------------------------------------------+
951 * | Floor 6 | Routing |
952 * +---------+-------------------------------------------------------+
954 floors = r->in.map_tower->tower.floors;
956 /* We accept NDR as the transfer syntax */
957 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
959 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
960 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax_ndr.uuid) ||
961 ifid.if_version != ndr_transfer_syntax_ndr.if_version) {
962 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
963 goto done;
966 /* We only talk to sane transports */
967 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
968 if (transport == NCA_UNKNOWN) {
969 DEBUG(2, ("epm_Map: Client requested unknown transport with"
970 "levels: "));
971 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
972 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
974 DEBUG(2, ("\n"));
975 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
976 goto done;
979 if (r->in.entry_handle == NULL ||
980 ndr_policy_handle_empty(r->in.entry_handle)) {
981 struct GUID *obj;
982 char *srv_addr = NULL;
984 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
986 eps = talloc_zero(tmp_ctx, struct rpc_eps);
987 if (eps == NULL) {
988 rc = EPMAPPER_STATUS_NO_MEMORY;
989 goto done;
993 * *** ATTENTION ***
994 * CDE 1.1 states:
996 * ept_map()
997 * Apply some algorithm (using the fields in the map_tower)
998 * to an endpoint map to produce a list of protocol towers.
1000 * The following code is the mysterious "some algorithm"!
1003 /* Filter by object id if one was given. */
1004 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
1005 obj = NULL;
1006 } else {
1007 obj = r->in.object;
1010 if (p->local_address != NULL &&
1011 tsocket_address_is_inet(p->local_address, "ipv4"))
1013 srv_addr = tsocket_address_inet_addr_string(p->local_address,
1014 tmp_ctx);
1017 eps->count = build_ep_list(eps,
1018 endpoint_table,
1019 obj,
1020 srv_addr,
1021 &eps->e);
1022 if (eps->count == 0) {
1023 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1024 goto done;
1027 /* Filter out endpoints which match the interface. */
1029 struct rpc_eps *teps;
1030 uint32_t total = 0;
1032 teps = talloc_zero(tmp_ctx, struct rpc_eps);
1033 if (teps == NULL) {
1034 rc = EPMAPPER_STATUS_NO_MEMORY;
1035 goto done;
1038 for (i = 0; i < eps->count; i++) {
1039 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
1040 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
1041 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
1042 continue;
1045 teps->e = talloc_realloc(tmp_ctx,
1046 teps->e,
1047 struct dcesrv_ep_iface,
1048 total + 1);
1049 if (teps->e == NULL) {
1050 return 0;
1053 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
1054 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
1055 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
1056 teps->e[total].syntax_id = eps->e[i].syntax_id;
1058 total++;
1061 teps->count = total;
1062 talloc_free(eps);
1063 eps = teps;
1065 /* end of "some algorithm" */
1067 ok = create_policy_hnd(p, r->out.entry_handle, eps);
1068 if (!ok) {
1069 rc = EPMAPPER_STATUS_NO_MEMORY;
1070 goto done;
1073 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
1074 if (!ok) {
1075 rc = EPMAPPER_STATUS_NO_MEMORY;
1076 goto done;
1078 entry_handle = r->out.entry_handle;
1079 } else {
1080 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
1082 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
1083 if (!ok) {
1084 rc = EPMAPPER_STATUS_NO_MEMORY;
1085 goto done;
1087 entry_handle = r->in.entry_handle;
1090 if (eps == NULL || eps->e == NULL) {
1091 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1092 goto done;
1095 /* return the next N elements */
1096 count = r->in.max_towers;
1097 if (count > eps->count) {
1098 count = eps->count;
1101 if (count == 0) {
1102 close_policy_hnd(p, entry_handle);
1103 ZERO_STRUCTP(r->out.entry_handle);
1105 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1106 goto done;
1109 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1110 if (r->out.towers == NULL) {
1111 rc = EPMAPPER_STATUS_NO_MEMORY;
1112 goto done;
1115 for (i = 0; i < count; i++) {
1116 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
1117 eps->e[i].name));
1119 r->out.towers[num_towers].twr = talloc(r->out.towers,
1120 struct epm_twr_t);
1121 if (r->out.towers[num_towers].twr == NULL) {
1122 rc = EPMAPPER_STATUS_NO_MEMORY;
1123 goto done;
1125 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1126 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1127 r->out.towers[num_towers].twr->tower_length = 0;
1129 num_towers++;
1132 *r->out.num_towers = num_towers;
1134 eps->count -= count;
1135 eps->e += count;
1136 if (eps->count == 0) {
1137 close_policy_hnd(p, entry_handle);
1138 ZERO_STRUCTP(r->out.entry_handle);
1141 rc = EPMAPPER_STATUS_OK;
1142 done:
1143 talloc_free(tmp_ctx);
1145 return rc;
1149 * epm_LookupHandleFree
1151 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1152 struct epm_LookupHandleFree *r)
1154 if (r->in.entry_handle == NULL) {
1155 return EPMAPPER_STATUS_OK;
1158 if (is_valid_policy_hnd(r->in.entry_handle)) {
1159 close_policy_hnd(p, r->in.entry_handle);
1162 r->out.entry_handle = r->in.entry_handle;
1164 return EPMAPPER_STATUS_OK;
1169 * epm_InqObject
1171 * A client implementation SHOULD NOT call this method. These extensions do not
1172 * provide an alternative method.
1174 error_status_t _epm_InqObject(struct pipes_struct *p,
1175 struct epm_InqObject *r)
1177 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1178 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1183 * epm_MgmtDelete
1185 * A client implementation SHOULD NOT call this method. These extensions do not
1186 * provide an alternative method.
1188 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1189 struct epm_MgmtDelete *r)
1191 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1192 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1197 epm_MapAuth
1199 error_status_t _epm_MapAuth(struct pipes_struct *p,
1200 struct epm_MapAuth *r)
1202 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1203 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1206 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */