libcli/cldap: make use of samba_tevent_context_init()
[Samba/gebeck_regimport.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blob17db5a43f990402eed8131e0ffb88ff0da9756c9
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 *ep1,
131 const struct dcerpc_binding *ep2)
133 if (ep1->transport != ep2->transport) {
134 return false;
137 if (!ep1->endpoint || !ep2->endpoint) {
138 return ep1->endpoint == ep2->endpoint;
141 if (!strequal(ep1->endpoint, ep2->endpoint)) {
142 return false;
145 if (!ep1->host || !ep2->host) {
146 return ep1->endpoint == ep2->endpoint;
149 if (!strequal(ep1->host, ep2->host)) {
150 return false;
153 return true;
156 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
157 struct dcerpc_binding *ep_description) {
158 struct dcesrv_endpoint *ep;
160 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
161 if (endpoints_match(ep->ep_description, ep_description)) {
162 return ep;
166 return NULL;
170 * Build a list of all interfaces handled by all endpoint servers.
172 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
173 struct dcesrv_endpoint *endpoint_list,
174 const struct GUID *uuid,
175 const char *srv_addr,
176 struct dcesrv_ep_iface **peps)
178 struct dcesrv_ep_iface *eps = NULL;
179 struct dcesrv_endpoint *d;
180 uint32_t total = 0;
181 NTSTATUS status;
183 *peps = NULL;
185 for (d = endpoint_list; d != NULL; d = d->next) {
186 struct dcesrv_iface_list *iface;
187 struct dcerpc_binding *description;
189 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
190 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
191 continue;
194 eps = talloc_realloc(mem_ctx,
195 eps,
196 struct dcesrv_ep_iface,
197 total + 1);
198 if (eps == NULL) {
199 return 0;
201 eps[total].name = talloc_strdup(eps,
202 iface->iface->name);
203 eps[total].syntax_id = iface->iface->syntax_id;
205 description = dcerpc_binding_dup(mem_ctx, d->ep_description);
206 if (description == NULL) {
207 return 0;
209 description->object = iface->iface->syntax_id;
210 if (description->transport == NCACN_IP_TCP &&
211 srv_addr != NULL &&
212 (strcmp(description->host, "0.0.0.0") == 0 ||
213 strcmp(description->host, "::") == 0)) {
214 description->host = srv_addr;
217 status = dcerpc_binding_build_tower(eps,
218 description,
219 &eps[total].ep);
220 TALLOC_FREE(description);
221 if (NT_STATUS_IS_ERR(status)) {
222 DEBUG(1, ("Unable to build tower for %s\n",
223 iface->iface->name));
224 continue;
226 total++;
230 *peps = eps;
232 return total;
235 static bool is_privileged_pipe(struct auth_session_info *info) {
236 /* If the user is not root, or has the system token, fail */
237 if ((info->unix_token->uid != sec_initial_uid()) &&
238 !security_token_is_system(info->security_token)) {
239 return false;
242 return true;
245 bool srv_epmapper_delete_endpoints(struct pipes_struct *p)
247 struct epm_Delete r;
248 struct dcesrv_ep_entry_list *el = p->ep_entries;
249 error_status_t result;
251 while (el) {
252 struct dcesrv_ep_entry_list *next = el->next;
254 r.in.num_ents = el->num_ents;
255 r.in.entries = el->entries;
257 DEBUG(10, ("Delete_endpoints for: %s\n",
258 el->entries[0].annotation));
260 result = _epm_Delete(p, &r);
261 if (result != EPMAPPER_STATUS_OK) {
262 return false;
265 DLIST_REMOVE(p->ep_entries, el);
266 TALLOC_FREE(el);
268 el = next;
271 return true;
274 void srv_epmapper_cleanup(void)
276 struct dcesrv_endpoint *ep = endpoint_table;
278 while (ep) {
279 struct dcesrv_endpoint *next = ep->next;
281 DLIST_REMOVE(endpoint_table, ep);
282 TALLOC_FREE(ep);
284 ep = next;
289 * epm_Insert
291 * Add the specified entries to an endpoint map.
293 error_status_t _epm_Insert(struct pipes_struct *p,
294 struct epm_Insert *r)
296 TALLOC_CTX *tmp_ctx;
297 error_status_t rc;
298 NTSTATUS status;
299 uint32_t i;
300 struct dcerpc_binding *b;
301 struct dcesrv_endpoint *ep;
302 struct dcesrv_iface_list *iflist;
303 struct dcesrv_iface *iface;
304 bool add_ep;
306 /* If this is not a privileged users, return */
307 if (p->transport != NCALRPC ||
308 !is_privileged_pipe(p->session_info)) {
309 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
310 return EPMAPPER_STATUS_CANT_PERFORM_OP;
313 tmp_ctx = talloc_stackframe();
314 if (tmp_ctx == NULL) {
315 return EPMAPPER_STATUS_NO_MEMORY;
318 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
319 r->in.num_ents));
321 for (i = 0; i < r->in.num_ents; i++) {
322 add_ep = false;
323 b = NULL;
325 status = dcerpc_binding_from_tower(tmp_ctx,
326 &r->in.entries[i].tower->tower,
327 &b);
328 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
329 rc = EPMAPPER_STATUS_NO_MEMORY;
330 goto done;
332 if (!NT_STATUS_IS_OK(status)) {
333 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
334 goto done;
337 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
338 derpc_transport_string_by_transport(b->transport),
339 r->in.entries[i].annotation));
341 /* Check if the entry already exits */
342 ep = find_endpoint(endpoint_table, b);
343 if (ep == NULL) {
344 /* No entry found, create it */
345 ep = talloc_zero(NULL, struct dcesrv_endpoint);
346 if (ep == NULL) {
347 rc = EPMAPPER_STATUS_NO_MEMORY;
348 goto done;
350 add_ep = true;
352 ep->ep_description = talloc_steal(ep, b);
355 /* TODO Replace the entry if the replace flag is set */
357 /* Create an interface */
358 iface = talloc(tmp_ctx, struct dcesrv_iface);
359 if (iface == NULL) {
360 rc = EPMAPPER_STATUS_NO_MEMORY;
361 goto done;
364 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
365 if (iface->name == NULL) {
366 rc = EPMAPPER_STATUS_NO_MEMORY;
367 goto done;
369 iface->syntax_id = b->object;
372 * Check if the rpc service is alrady registered on the
373 * endpoint.
375 if (find_interface(ep, iface) != NULL) {
376 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
377 "already registered on endpoint\n",
378 iface->name));
379 /* FIXME wrong error code? */
380 rc = EPMAPPER_STATUS_OK;
381 goto done;
384 /* Create an entry for the interface */
385 iflist = talloc(ep, struct dcesrv_iface_list);
386 if (iflist == NULL) {
387 rc = EPMAPPER_STATUS_NO_MEMORY;
388 goto done;
390 iflist->iface = talloc_move(iflist, &iface);
392 /* Finally add the interface on the endpoint */
393 DLIST_ADD(ep->iface_list, iflist);
395 /* If it's a new endpoint add it to the endpoint_table */
396 if (add_ep) {
397 DLIST_ADD(endpoint_table, ep);
401 if (r->in.num_ents > 0) {
402 struct dcesrv_ep_entry_list *el;
404 el = talloc_zero(p, struct dcesrv_ep_entry_list);
405 if (el == NULL) {
406 rc = EPMAPPER_STATUS_NO_MEMORY;
407 goto done;
409 el->num_ents = r->in.num_ents;
410 el->entries = talloc_move(el, &r->in.entries);
412 DLIST_ADD(p->ep_entries, el);
415 rc = EPMAPPER_STATUS_OK;
416 done:
417 talloc_free(tmp_ctx);
419 return rc;
424 * epm_Delete
426 * Delete the specified entries from an endpoint map.
428 error_status_t _epm_Delete(struct pipes_struct *p,
429 struct epm_Delete *r)
431 TALLOC_CTX *tmp_ctx;
432 error_status_t rc;
433 NTSTATUS status;
434 uint32_t i;
435 struct dcerpc_binding *b;
436 struct dcesrv_endpoint *ep;
437 struct dcesrv_iface iface;
438 struct dcesrv_iface_list *iflist;
440 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
441 r->in.num_ents));
443 /* If this is not a privileged users, return */
444 if (p->transport != NCALRPC ||
445 !is_privileged_pipe(p->session_info)) {
446 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
447 return EPMAPPER_STATUS_CANT_PERFORM_OP;
450 tmp_ctx = talloc_stackframe();
451 if (tmp_ctx == NULL) {
452 return EPMAPPER_STATUS_NO_MEMORY;
455 for (i = 0; i < r->in.num_ents; i++) {
456 b = NULL;
458 status = dcerpc_binding_from_tower(tmp_ctx,
459 &r->in.entries[i].tower->tower,
460 &b);
461 if (!NT_STATUS_IS_OK(status)) {
462 rc = EPMAPPER_STATUS_NO_MEMORY;
463 goto done;
466 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
467 derpc_transport_string_by_transport(b->transport),
468 r->in.entries[i].annotation));
470 ep = find_endpoint(endpoint_table, b);
471 if (ep == NULL) {
472 rc = EPMAPPER_STATUS_OK;
473 goto done;
476 iface.name = r->in.entries[i].annotation;
477 iface.syntax_id = b->object;
479 iflist = find_interface_list(ep, &iface);
480 if (iflist == NULL) {
481 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
482 DLIST_REMOVE(endpoint_table, ep);
483 talloc_free(ep);
485 rc = EPMAPPER_STATUS_OK;
486 goto done;
489 DLIST_REMOVE(ep->iface_list, iflist);
491 if (ep->iface_list == NULL) {
492 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
493 DLIST_REMOVE(endpoint_table, ep);
494 talloc_free(ep);
496 rc = EPMAPPER_STATUS_OK;
497 goto done;
502 rc = EPMAPPER_STATUS_OK;
503 done:
504 talloc_free(tmp_ctx);
506 return rc;
511 * epm_Lookup
513 * Lookup entries in an endpoint map.
515 error_status_t _epm_Lookup(struct pipes_struct *p,
516 struct epm_Lookup *r)
518 struct policy_handle *entry_handle;
519 struct rpc_eps *eps;
520 TALLOC_CTX *tmp_ctx;
521 error_status_t rc;
522 uint32_t count = 0;
523 uint32_t num_ents = 0;
524 uint32_t i;
525 bool match = false;
526 bool ok;
528 *r->out.num_ents = 0;
529 r->out.entries = NULL;
531 tmp_ctx = talloc_stackframe();
532 if (tmp_ctx == NULL) {
533 return EPMAPPER_STATUS_NO_MEMORY;
536 DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
537 r->in.max_ents));
539 if (r->in.entry_handle == NULL ||
540 ndr_policy_handle_empty(r->in.entry_handle)) {
541 char *srv_addr = NULL;
543 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
545 eps = talloc_zero(tmp_ctx, struct rpc_eps);
546 if (eps == NULL) {
547 rc = EPMAPPER_STATUS_NO_MEMORY;
548 goto done;
551 if (p->local_address != NULL) {
552 srv_addr = tsocket_address_inet_addr_string(p->local_address,
553 tmp_ctx);
556 switch (r->in.inquiry_type) {
557 case RPC_C_EP_ALL_ELTS:
559 * Return all elements from the endpoint map. The
560 * interface_id, vers_option, and object parameters MUST
561 * be ignored.
563 eps->count = build_ep_list(eps,
564 endpoint_table,
565 NULL,
566 srv_addr,
567 &eps->e);
568 break;
569 case RPC_C_EP_MATCH_BY_IF:
571 * Return endpoint map elements that contain the
572 * interface identifier specified by the interface_id
573 * and vers_option values.
575 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
576 * need both the same endpoint list. There is a second
577 * check for the inquiry_type below which differentiates
578 * between them.
580 case RPC_C_EP_MATCH_BY_BOTH:
582 * Return endpoint map elements that contain the
583 * interface identifier and object UUID specified by
584 * interface_id, vers_option, and object.
586 eps->count = build_ep_list(eps,
587 endpoint_table,
588 &r->in.interface_id->uuid,
589 srv_addr,
590 &eps->e);
591 break;
592 case RPC_C_EP_MATCH_BY_OBJ:
594 * Return endpoint map elements that contain the object
595 * UUID specified by object.
597 eps->count = build_ep_list(eps,
598 endpoint_table,
599 r->in.object,
600 srv_addr,
601 &eps->e);
602 break;
603 default:
604 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
605 goto done;
608 if (eps->count == 0) {
609 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
610 goto done;
613 ok = create_policy_hnd(p, r->out.entry_handle, eps);
614 if (!ok) {
615 rc = EPMAPPER_STATUS_NO_MEMORY;
616 goto done;
619 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
620 if (!ok) {
621 rc = EPMAPPER_STATUS_NO_MEMORY;
622 goto done;
624 entry_handle = r->out.entry_handle;
625 } else {
626 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
628 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
629 if (!ok) {
630 rc = EPMAPPER_STATUS_NO_MEMORY;
631 goto done;
633 entry_handle = r->in.entry_handle;
636 if (eps == NULL || eps->e == NULL) {
637 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
638 goto done;
641 /* return the next N elements */
642 count = r->in.max_ents;
643 if (count > eps->count) {
644 count = eps->count;
647 DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
649 if (count == 0) {
650 close_policy_hnd(p, entry_handle);
651 ZERO_STRUCTP(r->out.entry_handle);
653 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
654 goto done;
657 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
658 if (r->out.entries == NULL) {
659 rc = EPMAPPER_STATUS_NO_MEMORY;
660 goto done;
663 for (i = 0; i < count; i++) {
664 match = false;
666 switch (r->in.inquiry_type) {
667 case RPC_C_EP_ALL_ELTS:
669 * Return all elements from the endpoint map. The
670 * interface_id, vers_option, and object parameters MUST
671 * be ignored.
673 match = true;
674 break;
675 case RPC_C_EP_MATCH_BY_IF:
677 * Return endpoint map elements that contain the
678 * interface identifier specified by the interface_id
679 * and vers_option values.
681 if (GUID_equal(&r->in.interface_id->uuid,
682 &eps->e[i].syntax_id.uuid)) {
683 match = true;
685 break;
686 case RPC_C_EP_MATCH_BY_OBJ:
688 * Return endpoint map elements that contain the object
689 * UUID specified by object.
691 if (GUID_equal(r->in.object,
692 &eps->e[i].syntax_id.uuid)) {
693 match = true;
695 break;
696 case RPC_C_EP_MATCH_BY_BOTH:
698 * Return endpoint map elements that contain the
699 * interface identifier and object UUID specified by
700 * interface_id, vers_option, and object.
702 if (GUID_equal(&r->in.interface_id->uuid,
703 &eps->e[i].syntax_id.uuid) &&
704 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
705 match = true;
707 break;
708 default:
709 return EPMAPPER_STATUS_CANT_PERFORM_OP;
712 if (match) {
713 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
714 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
715 /* Check inteface version */
717 match = false;
718 switch (r->in.vers_option) {
719 case RPC_C_VERS_ALL:
721 * Return endpoint map elements that
722 * contain the specified interface UUID,
723 * regardless of the version numbers.
725 match = true;
726 break;
727 case RPC_C_VERS_COMPATIBLE:
729 * Return the endpoint map elements that
730 * contain the same major versions of
731 * the specified interface UUID and a
732 * minor version greater than or equal
733 * to the minor version of the specified
734 * UUID.
736 if (r->in.interface_id->vers_major ==
737 (eps->e[i].syntax_id.if_version >> 16) &&
738 r->in.interface_id->vers_minor <=
739 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
740 match = true;
742 break;
743 case RPC_C_VERS_EXACT:
745 * Return endpoint map elements that
746 * contain the specified version of the
747 * specified interface UUID.
749 if (r->in.interface_id->vers_major ==
750 (eps->e[i].syntax_id.if_version >> 16) &&
751 r->in.interface_id->vers_minor ==
752 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
753 match = true;
755 match = true;
756 break;
757 case RPC_C_VERS_MAJOR_ONLY:
759 * Return endpoint map elements that
760 * contain the same version of the
761 * specified interface UUID and ignore
762 * the minor version.
764 if (r->in.interface_id->vers_major ==
765 (eps->e[i].syntax_id.if_version >> 16)) {
766 match = true;
768 match = true;
769 break;
770 case RPC_C_VERS_UPTO:
772 * Return endpoint map elements that
773 * contain a version of the specified
774 * interface UUID less than or equal to
775 * the specified major and minor
776 * version.
778 if (r->in.interface_id->vers_major >
779 eps->e[i].syntax_id.if_version >> 16) {
780 match = true;
781 } else {
782 if (r->in.interface_id->vers_major ==
783 (eps->e[i].syntax_id.if_version >> 16) &&
784 r->in.interface_id->vers_minor >=
785 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
786 match = true;
789 break;
790 default:
791 return EPMAPPER_STATUS_CANT_PERFORM_OP;
796 if (match) {
797 ZERO_STRUCT(r->out.entries[num_ents].object);
799 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
800 eps->e[i].name));
801 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
802 eps->e[i].name);
803 r->out.entries[num_ents].tower = talloc(r->out.entries,
804 struct epm_twr_t);
805 if (r->out.entries[num_ents].tower == NULL) {
806 rc = EPMAPPER_STATUS_NO_MEMORY;
807 goto done;
809 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
810 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
811 r->out.entries[num_ents].tower->tower_length = 0;
813 num_ents++;
815 } /* end for loop */
817 *r->out.num_ents = num_ents;
819 eps->count -= count;
820 eps->e += count;
821 if (eps->count == 0) {
822 close_policy_hnd(p, entry_handle);
823 ZERO_STRUCTP(r->out.entry_handle);
824 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
825 goto done;
828 rc = EPMAPPER_STATUS_OK;
829 done:
830 talloc_free(tmp_ctx);
832 return rc;
836 * epm_Map
838 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
839 * to produce a list of protocol towers.
841 error_status_t _epm_Map(struct pipes_struct *p,
842 struct epm_Map *r)
844 struct policy_handle *entry_handle;
845 enum dcerpc_transport_t transport;
846 struct ndr_syntax_id ifid;
847 struct epm_floor *floors;
848 struct rpc_eps *eps;
849 TALLOC_CTX *tmp_ctx;
850 error_status_t rc;
851 uint32_t count = 0;
852 uint32_t num_towers = 0;
853 uint32_t i;
854 bool ok;
856 *r->out.num_towers = 0;
857 r->out.towers = NULL;
859 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
860 r->in.map_tower->tower.num_floors < 3) {
861 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
864 tmp_ctx = talloc_stackframe();
865 if (tmp_ctx == NULL) {
866 return EPMAPPER_STATUS_NO_MEMORY;
869 ZERO_STRUCTP(r->out.entry_handle);
871 DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
872 r->in.max_towers));
875 * A tower has normally up to 6 floors
877 * +-----------------------------------------------------------------+
878 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
879 * | | netlogon) |
880 * +---------+-------------------------------------------------------+
881 * | Floor 2 | Transfer syntax (NDR endcoded) |
882 * +---------+-------------------------------------------------------+
883 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
884 * +---------+-------------------------------------------------------+
885 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
886 * +---------+-------------------------------------------------------+
887 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
888 * +---------+-------------------------------------------------------+
889 * | Floor 6 | Routing |
890 * +---------+-------------------------------------------------------+
892 floors = r->in.map_tower->tower.floors;
894 /* We accept NDR as the transfer syntax */
895 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
897 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
898 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax_ndr.uuid) ||
899 ifid.if_version != ndr_transfer_syntax_ndr.if_version) {
900 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
901 goto done;
904 /* We only talk to sane transports */
905 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
906 if (transport == NCA_UNKNOWN) {
907 DEBUG(2, ("epm_Map: Client requested unknown transport with"
908 "levels: "));
909 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
910 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
912 DEBUG(2, ("\n"));
913 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
914 goto done;
917 if (r->in.entry_handle == NULL ||
918 ndr_policy_handle_empty(r->in.entry_handle)) {
919 struct GUID *obj;
920 char *srv_addr = NULL;
922 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
924 eps = talloc_zero(tmp_ctx, struct rpc_eps);
925 if (eps == NULL) {
926 rc = EPMAPPER_STATUS_NO_MEMORY;
927 goto done;
931 * *** ATTENTION ***
932 * CDE 1.1 states:
934 * ept_map()
935 * Apply some algorithm (using the fields in the map_tower)
936 * to an endpoint map to produce a list of protocol towers.
938 * The following code is the mysterious "some algorithm"!
941 /* Filter by object id if one was given. */
942 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
943 obj = NULL;
944 } else {
945 obj = r->in.object;
948 if (p->local_address != NULL) {
949 srv_addr = tsocket_address_inet_addr_string(p->local_address,
950 tmp_ctx);
953 eps->count = build_ep_list(eps,
954 endpoint_table,
955 obj,
956 srv_addr,
957 &eps->e);
958 if (eps->count == 0) {
959 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
960 goto done;
963 /* Filter out endpoints which match the interface. */
965 struct rpc_eps *teps;
966 uint32_t total = 0;
968 teps = talloc_zero(tmp_ctx, struct rpc_eps);
969 if (teps == NULL) {
970 rc = EPMAPPER_STATUS_NO_MEMORY;
971 goto done;
974 for (i = 0; i < eps->count; i++) {
975 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
976 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
977 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
978 continue;
981 teps->e = talloc_realloc(tmp_ctx,
982 teps->e,
983 struct dcesrv_ep_iface,
984 total + 1);
985 if (teps->e == NULL) {
986 return 0;
989 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
990 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
991 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
992 teps->e[total].syntax_id = eps->e[i].syntax_id;
994 total++;
997 teps->count = total;
998 talloc_free(eps);
999 eps = teps;
1001 /* end of "some algorithm" */
1003 ok = create_policy_hnd(p, r->out.entry_handle, eps);
1004 if (!ok) {
1005 rc = EPMAPPER_STATUS_NO_MEMORY;
1006 goto done;
1009 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
1010 if (!ok) {
1011 rc = EPMAPPER_STATUS_NO_MEMORY;
1012 goto done;
1014 entry_handle = r->out.entry_handle;
1015 } else {
1016 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
1018 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
1019 if (!ok) {
1020 rc = EPMAPPER_STATUS_NO_MEMORY;
1021 goto done;
1023 entry_handle = r->in.entry_handle;
1026 if (eps == NULL || eps->e == NULL) {
1027 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1028 goto done;
1031 /* return the next N elements */
1032 count = r->in.max_towers;
1033 if (count > eps->count) {
1034 count = eps->count;
1037 if (count == 0) {
1038 close_policy_hnd(p, entry_handle);
1039 ZERO_STRUCTP(r->out.entry_handle);
1041 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1042 goto done;
1045 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1046 if (r->out.towers == NULL) {
1047 rc = EPMAPPER_STATUS_NO_MEMORY;
1048 goto done;
1051 for (i = 0; i < count; i++) {
1052 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
1053 eps->e[i].name));
1055 r->out.towers[num_towers].twr = talloc(r->out.towers,
1056 struct epm_twr_t);
1057 if (r->out.towers[num_towers].twr == NULL) {
1058 rc = EPMAPPER_STATUS_NO_MEMORY;
1059 goto done;
1061 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1062 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1063 r->out.towers[num_towers].twr->tower_length = 0;
1065 num_towers++;
1068 *r->out.num_towers = num_towers;
1070 eps->count -= count;
1071 eps->e += count;
1072 if (eps->count == 0) {
1073 close_policy_hnd(p, entry_handle);
1074 ZERO_STRUCTP(r->out.entry_handle);
1077 rc = EPMAPPER_STATUS_OK;
1078 done:
1079 talloc_free(tmp_ctx);
1081 return rc;
1085 * epm_LookupHandleFree
1087 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1088 struct epm_LookupHandleFree *r)
1090 if (r->in.entry_handle == NULL) {
1091 return EPMAPPER_STATUS_OK;
1094 if (is_valid_policy_hnd(r->in.entry_handle)) {
1095 close_policy_hnd(p, r->in.entry_handle);
1098 r->out.entry_handle = r->in.entry_handle;
1100 return EPMAPPER_STATUS_OK;
1105 * epm_InqObject
1107 * A client implementation SHOULD NOT call this method. These extensions do not
1108 * provide an alternative method.
1110 error_status_t _epm_InqObject(struct pipes_struct *p,
1111 struct epm_InqObject *r)
1113 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1114 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1119 * epm_MgmtDelete
1121 * A client implementation SHOULD NOT call this method. These extensions do not
1122 * provide an alternative method.
1124 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1125 struct epm_MgmtDelete *r)
1127 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1128 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1133 epm_MapAuth
1135 error_status_t _epm_MapAuth(struct pipes_struct *p,
1136 struct epm_MapAuth *r)
1138 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1139 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1142 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */