s3-epmapper: Added function to delete endpoint entries.
[Samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blobda998eb534348802dcc6b207f13876af9356cecb
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 "../libcli/security/security.h"
24 #include "librpc/gen_ndr/ndr_epmapper.h"
25 #include "librpc/gen_ndr/srv_epmapper.h"
26 #include "srv_epmapper.h"
28 typedef uint32_t error_status_t;
30 /* An endpoint combined with an interface description */
31 struct dcesrv_ep_iface {
32 const char *name;
33 struct ndr_syntax_id syntax_id;
34 struct epm_tower ep;
37 /* A rpc service interface like samr, lsarpc or netlogon */
38 struct dcesrv_iface {
39 const char *name;
40 struct ndr_syntax_id syntax_id;
43 struct dcesrv_iface_list {
44 struct dcesrv_iface_list *next, *prev;
45 struct dcesrv_iface *iface;
49 * An endpoint can serve multiple rpc services interfaces.
50 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
52 struct dcesrv_endpoint {
53 struct dcesrv_endpoint *next, *prev;
55 /* The type and the location of the endpoint */
56 struct dcerpc_binding *ep_description;
58 /* A list of rpc services able to connect to the endpoint */
59 struct dcesrv_iface_list *iface_list;
62 struct dcesrv_ep_entry_list {
63 struct dcesrv_ep_entry_list *next, *prev;
65 uint32_t num_ents;
66 struct epm_entry_t *entries;
69 struct rpc_eps {
70 struct dcesrv_ep_iface *e;
71 uint32_t count;
74 static struct dcesrv_endpoint *endpoint_table;
77 * Check if the UUID and if_version match to an interface.
79 static bool interface_match(const struct dcesrv_iface *if1,
80 const struct dcesrv_iface *if2)
82 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
86 * Find the interface operations on an endpoint.
88 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
89 const struct dcesrv_iface *iface)
91 struct dcesrv_iface_list *iflist;
93 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
94 if (interface_match(iflist->iface, iface)) {
95 return iflist->iface;
99 return NULL;
103 * See if a uuid and if_version match to an interface
105 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
106 const struct GUID *uuid)
108 return GUID_equal(&iface->syntax_id.uuid, uuid);
111 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
112 const struct dcesrv_iface *iface)
114 struct dcesrv_iface_list *iflist;
116 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
117 if (interface_match(iflist->iface, iface)) {
118 return iflist;
122 return NULL;
126 * Check if two endpoints match.
128 static bool endpoints_match(const struct dcerpc_binding *ep1,
129 const struct dcerpc_binding *ep2)
131 if (ep1->transport != ep2->transport) {
132 return false;
135 if (!ep1->endpoint || !ep2->endpoint) {
136 return ep1->endpoint == ep2->endpoint;
139 if (!strequal(ep1->endpoint, ep2->endpoint)) {
140 return false;
143 return true;
146 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
147 struct dcerpc_binding *ep_description) {
148 struct dcesrv_endpoint *ep;
150 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
151 if (endpoints_match(ep->ep_description, ep_description)) {
152 return ep;
156 return NULL;
160 * Build a list of all interfaces handled by all endpoint servers.
162 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
163 struct dcesrv_endpoint *endpoint_list,
164 const struct GUID *uuid,
165 const char *srv_addr,
166 struct dcesrv_ep_iface **peps)
168 struct dcesrv_ep_iface *eps = NULL;
169 struct dcesrv_endpoint *d;
170 uint32_t total = 0;
171 NTSTATUS status;
173 *peps = NULL;
175 for (d = endpoint_list; d != NULL; d = d->next) {
176 struct dcesrv_iface_list *iface;
177 struct dcerpc_binding *description;
179 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
180 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
181 continue;
184 eps = talloc_realloc(mem_ctx,
185 eps,
186 struct dcesrv_ep_iface,
187 total + 1);
188 if (eps == NULL) {
189 return 0;
191 eps[total].name = talloc_strdup(eps,
192 iface->iface->name);
193 eps[total].syntax_id = iface->iface->syntax_id;
195 description = d->ep_description;
196 description->object = iface->iface->syntax_id;
197 if (description->transport == NCACN_IP_TCP &&
198 srv_addr != NULL &&
199 strequal(description->host, "0.0.0.0")) {
200 description->host = srv_addr;
203 status = dcerpc_binding_build_tower(eps,
204 description,
205 &eps[total].ep);
206 if (NT_STATUS_IS_ERR(status)) {
207 DEBUG(1, ("Unable to build tower for %s\n",
208 iface->iface->name));
209 continue;
211 total++;
215 *peps = eps;
217 return total;
220 static bool is_priviledged_pipe(struct auth_serversupplied_info *info) {
221 /* If the user is not root, or has the system token, fail */
222 if ((info->utok.uid != sec_initial_uid()) &&
223 !security_token_is_system(info->security_token)) {
224 return false;
227 return true;
230 bool srv_epmapper_delete_endpoints(struct pipes_struct *p)
232 struct epm_Delete r;
233 struct dcesrv_ep_entry_list *el;
234 error_status_t result;
236 if (p->ep_entries == NULL) {
237 return true;
240 for (el = p->ep_entries;
241 el != NULL;
242 el = p->ep_entries) {
243 r.in.num_ents = el->num_ents;
244 r.in.entries = el->entries;
246 DEBUG(10, ("Delete_endpoints for: %s\n",
247 el->entries[0].annotation));
249 result = _epm_Delete(p, &r);
250 if (result != EPMAPPER_STATUS_OK) {
251 return false;
254 DLIST_REMOVE(p->ep_entries, el);
255 TALLOC_FREE(el);
258 return true;
261 void srv_epmapper_cleanup(void)
263 struct dcesrv_endpoint *ep;
265 for (ep = endpoint_table;
266 ep != NULL;
267 ep = endpoint_table) {
268 DLIST_REMOVE(endpoint_table, ep);
269 TALLOC_FREE(ep);
274 * epm_Insert
276 * Add the specified entries to an endpoint map.
278 error_status_t _epm_Insert(struct pipes_struct *p,
279 struct epm_Insert *r)
281 TALLOC_CTX *tmp_ctx;
282 error_status_t rc;
283 NTSTATUS status;
284 uint32_t i;
286 /* If this is not a priviledged users, return */
287 if (p->transport != NCALRPC ||
288 !is_priviledged_pipe(p->session_info)) {
289 return EPMAPPER_STATUS_CANT_PERFORM_OP;
292 tmp_ctx = talloc_stackframe();
293 if (tmp_ctx == NULL) {
294 return EPMAPPER_STATUS_NO_MEMORY;
297 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
298 r->in.num_ents));
300 for (i = 0; i < r->in.num_ents; i++) {
301 struct dcerpc_binding *b = NULL;
302 struct dcesrv_endpoint *ep;
303 struct dcesrv_iface_list *iflist;
304 struct dcesrv_iface *iface;
305 bool add_ep = false;
307 status = dcerpc_binding_from_tower(tmp_ctx,
308 &r->in.entries[i].tower->tower,
309 &b);
310 if (!NT_STATUS_IS_OK(status)) {
311 rc = EPMAPPER_STATUS_NO_MEMORY;
312 goto done;
315 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
316 derpc_transport_string_by_transport(b->transport),
317 r->in.entries[i].annotation));
319 /* Check if the entry already exits */
320 ep = find_endpoint(endpoint_table, b);
321 if (ep == NULL) {
322 /* No entry found, create it */
323 ep = talloc_zero(NULL, struct dcesrv_endpoint);
324 if (ep == NULL) {
325 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
326 goto done;
328 add_ep = true;
330 ep->ep_description = talloc_steal(ep, b);
333 /* TODO Replace the entry if the replace flag is set */
335 /* Create an interface */
336 iface = talloc(tmp_ctx, struct dcesrv_iface);
337 if (iface == NULL) {
338 rc = EPMAPPER_STATUS_NO_MEMORY;
339 goto done;
342 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
343 if (iface->name == NULL) {
344 rc = EPMAPPER_STATUS_NO_MEMORY;
345 goto done;
347 iface->syntax_id = b->object;
350 * Check if the rpc service is alrady registered on the
351 * endpoint.
353 if (find_interface(ep, iface) != NULL) {
354 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
355 "already registered on endpoint\n",
356 iface->name));
357 /* FIXME wrong error code? */
358 rc = EPMAPPER_STATUS_OK;
359 goto done;
362 /* Create an entry for the interface */
363 iflist = talloc(ep, struct dcesrv_iface_list);
364 if (iflist == NULL) {
365 rc = EPMAPPER_STATUS_NO_MEMORY;
366 goto done;
368 iflist->iface = talloc_move(iflist, &iface);
370 /* Finally add the interface on the endpoint */
371 DLIST_ADD(ep->iface_list, iflist);
373 /* If it's a new endpoint add it to the endpoint_table */
374 if (add_ep) {
375 DLIST_ADD(endpoint_table, ep);
379 if (r->in.num_ents > 0) {
380 struct dcesrv_ep_entry_list *el;
382 el = talloc_zero(p->mem_ctx, struct dcesrv_ep_entry_list);
383 if (el == NULL) {
384 rc = EPMAPPER_STATUS_NO_MEMORY;
385 goto done;
387 el->num_ents = r->in.num_ents;
388 el->entries = talloc_move(el, &r->in.entries);
390 DLIST_ADD(p->ep_entries, el);
393 rc = EPMAPPER_STATUS_OK;
394 done:
395 talloc_free(tmp_ctx);
397 return rc;
402 * epm_Delete
404 * Delete the specified entries from an endpoint map.
406 error_status_t _epm_Delete(struct pipes_struct *p,
407 struct epm_Delete *r)
409 TALLOC_CTX *tmp_ctx;
410 error_status_t rc;
411 NTSTATUS status;
412 uint32_t i;
414 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
415 r->in.num_ents));
417 /* If this is not a priviledged users, return */
418 if (p->transport != NCALRPC ||
419 !is_priviledged_pipe(p->session_info)) {
420 return EPMAPPER_STATUS_CANT_PERFORM_OP;
423 tmp_ctx = talloc_stackframe();
424 if (tmp_ctx == NULL) {
425 return EPMAPPER_STATUS_NO_MEMORY;
428 for (i = 0; i < r->in.num_ents; i++) {
429 struct dcerpc_binding *b = NULL;
430 struct dcesrv_endpoint *ep;
431 struct dcesrv_iface iface;
432 struct dcesrv_iface_list *iflist;
434 status = dcerpc_binding_from_tower(tmp_ctx,
435 &r->in.entries[i].tower->tower,
436 &b);
437 if (!NT_STATUS_IS_OK(status)) {
438 rc = EPMAPPER_STATUS_NO_MEMORY;
439 goto done;
442 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
443 derpc_transport_string_by_transport(b->transport),
444 r->in.entries[i].annotation));
446 ep = find_endpoint(endpoint_table, b);
447 if (ep == NULL) {
448 rc = EPMAPPER_STATUS_OK;
449 goto done;
452 iface.name = r->in.entries[i].annotation;
453 iface.syntax_id = b->object;
455 iflist = find_interface_list(ep, &iface);
456 if (iflist == NULL) {
457 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
458 DLIST_REMOVE(endpoint_table, ep);
459 talloc_free(ep);
461 rc = EPMAPPER_STATUS_OK;
462 goto done;
465 DLIST_REMOVE(ep->iface_list, iflist);
467 if (ep->iface_list == NULL) {
468 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
469 DLIST_REMOVE(endpoint_table, ep);
470 talloc_free(ep);
472 rc = EPMAPPER_STATUS_OK;
473 goto done;
478 rc = EPMAPPER_STATUS_OK;
479 done:
480 talloc_free(tmp_ctx);
482 return rc;
487 * epm_Lookup
489 * Lookup entries in an endpoint map.
491 error_status_t _epm_Lookup(struct pipes_struct *p,
492 struct epm_Lookup *r)
494 struct policy_handle *entry_handle;
495 struct rpc_eps *eps;
496 TALLOC_CTX *tmp_ctx;
497 error_status_t rc;
498 uint32_t count = 0;
499 uint32_t num_ents = 0;
500 uint32_t i;
501 bool match = false;
502 bool ok;
504 *r->out.num_ents = 0;
505 r->out.entries = NULL;
507 tmp_ctx = talloc_stackframe();
508 if (tmp_ctx == NULL) {
509 return EPMAPPER_STATUS_NO_MEMORY;
512 DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
513 r->in.max_ents));
515 if (r->in.entry_handle == NULL ||
516 policy_handle_empty(r->in.entry_handle)) {
517 struct GUID *obj;
519 DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n"));
521 eps = talloc_zero(tmp_ctx, struct rpc_eps);
522 if (eps == NULL) {
523 rc = EPMAPPER_STATUS_NO_MEMORY;
524 goto done;
527 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
528 obj = NULL;
529 } else {
530 obj = r->in.object;
533 switch (r->in.inquiry_type) {
534 case RPC_C_EP_ALL_ELTS:
536 * Return all elements from the endpoint map. The
537 * interface_id, vers_option, and object parameters MUST
538 * be ignored.
540 eps->count = build_ep_list(eps,
541 endpoint_table,
542 NULL,
543 p->server_id == NULL ? NULL : p->server_id->addr,
544 &eps->e);
545 break;
546 case RPC_C_EP_MATCH_BY_IF:
548 * Return endpoint map elements that contain the
549 * interface identifier specified by the interface_id
550 * and vers_option values.
552 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
553 * need both the same endpoint list. There is a second
554 * check for the inquiry_type below which differentiates
555 * between them.
557 case RPC_C_EP_MATCH_BY_BOTH:
559 * Return endpoint map elements that contain the
560 * interface identifier and object UUID specified by
561 * interface_id, vers_option, and object.
563 eps->count = build_ep_list(eps,
564 endpoint_table,
565 &r->in.interface_id->uuid,
566 p->server_id == NULL ? NULL : p->server_id->addr,
567 &eps->e);
568 break;
569 case RPC_C_EP_MATCH_BY_OBJ:
571 * Return endpoint map elements that contain the object
572 * UUID specified by object.
574 eps->count = build_ep_list(eps,
575 endpoint_table,
576 r->in.object,
577 p->server_id == NULL ? NULL : p->server_id->addr,
578 &eps->e);
579 break;
580 default:
581 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
582 goto done;
585 if (eps->count == 0) {
586 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
587 goto done;
590 ok = create_policy_hnd(p, r->out.entry_handle, eps);
591 if (!ok) {
592 rc = EPMAPPER_STATUS_NO_MEMORY;
593 goto done;
596 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
597 if (!ok) {
598 rc = EPMAPPER_STATUS_NO_MEMORY;
599 goto done;
601 entry_handle = r->out.entry_handle;
602 } else {
603 DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n"));
605 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
606 if (!ok) {
607 rc = EPMAPPER_STATUS_NO_MEMORY;
608 goto done;
610 entry_handle = r->in.entry_handle;
613 if (eps == NULL || eps->e == NULL) {
614 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
615 goto done;
618 /* return the next N elements */
619 count = r->in.max_ents;
620 if (count > eps->count) {
621 count = eps->count;
624 DEBUG(3, ("_epm_Lookup: Find %u entries\n", count));
626 if (count == 0) {
627 close_policy_hnd(p, entry_handle);
628 ZERO_STRUCTP(r->out.entry_handle);
630 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
631 goto done;
634 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
635 if (r->out.entries == NULL) {
636 rc = EPMAPPER_STATUS_NO_MEMORY;
637 goto done;
640 for (i = 0; i < count; i++) {
641 match = false;
643 switch (r->in.inquiry_type) {
644 case RPC_C_EP_ALL_ELTS:
646 * Return all elements from the endpoint map. The
647 * interface_id, vers_option, and object parameters MUST
648 * be ignored.
650 match = true;
651 break;
652 case RPC_C_EP_MATCH_BY_IF:
654 * Return endpoint map elements that contain the
655 * interface identifier specified by the interface_id
656 * and vers_option values.
658 if (GUID_equal(&r->in.interface_id->uuid,
659 &eps->e[i].syntax_id.uuid)) {
660 match = true;
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 if (GUID_equal(r->in.object,
669 &eps->e[i].syntax_id.uuid)) {
670 match = true;
672 break;
673 case RPC_C_EP_MATCH_BY_BOTH:
675 * Return endpoint map elements that contain the
676 * interface identifier and object UUID specified by
677 * interface_id, vers_option, and object.
679 if (GUID_equal(&r->in.interface_id->uuid,
680 &eps->e[i].syntax_id.uuid) &&
681 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
682 match = true;
684 break;
685 default:
686 return EPMAPPER_STATUS_CANT_PERFORM_OP;
689 if (match) {
690 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
691 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
692 /* Check inteface version */
694 match = false;
695 switch (r->in.vers_option) {
696 case RPC_C_VERS_ALL:
698 * Return endpoint map elements that
699 * contain the specified interface UUID,
700 * regardless of the version numbers.
702 match = true;
703 break;
704 case RPC_C_VERS_COMPATIBLE:
706 * Return the endpoint map elements that
707 * contain the same major versions of
708 * the specified interface UUID and a
709 * minor version greater than or equal
710 * to the minor version of the specified
711 * UUID.
713 if (r->in.interface_id->vers_major ==
714 (eps->e[i].syntax_id.if_version >> 16) &&
715 r->in.interface_id->vers_minor <=
716 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
717 match = true;
719 break;
720 case RPC_C_VERS_EXACT:
722 * Return endpoint map elements that
723 * contain the specified version of the
724 * specified interface UUID.
726 if (r->in.interface_id->vers_major ==
727 (eps->e[i].syntax_id.if_version >> 16) &&
728 r->in.interface_id->vers_minor ==
729 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
730 match = true;
732 match = true;
733 break;
734 case RPC_C_VERS_MAJOR_ONLY:
736 * Return endpoint map elements that
737 * contain the same version of the
738 * specified interface UUID and ignore
739 * the minor version.
741 if (r->in.interface_id->vers_major ==
742 (eps->e[i].syntax_id.if_version >> 16)) {
743 match = true;
745 match = true;
746 break;
747 case RPC_C_VERS_UPTO:
749 * Return endpoint map elements that
750 * contain a version of the specified
751 * interface UUID less than or equal to
752 * the specified major and minor
753 * version.
755 if (r->in.interface_id->vers_major >
756 eps->e[i].syntax_id.if_version >> 16) {
757 match = true;
758 } else {
759 if (r->in.interface_id->vers_major ==
760 (eps->e[i].syntax_id.if_version >> 16) &&
761 r->in.interface_id->vers_minor >=
762 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
763 match = true;
766 break;
767 default:
768 return EPMAPPER_STATUS_CANT_PERFORM_OP;
773 if (match) {
774 ZERO_STRUCT(r->out.entries[num_ents].object);
776 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
777 eps->e[i].name));
778 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
779 eps->e[i].name);
780 r->out.entries[num_ents].tower = talloc(r->out.entries,
781 struct epm_twr_t);
782 if (r->out.entries[num_ents].tower == NULL) {
783 rc = EPMAPPER_STATUS_NO_MEMORY;
784 goto done;
786 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
787 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
788 r->out.entries[num_ents].tower->tower_length = 0;
790 num_ents++;
792 } /* end for loop */
794 *r->out.num_ents = num_ents;
796 eps->count -= count;
797 eps->e += count;
798 if (eps->count == 0) {
799 close_policy_hnd(p, entry_handle);
800 ZERO_STRUCTP(r->out.entry_handle);
801 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
802 goto done;
805 rc = EPMAPPER_STATUS_OK;
806 done:
807 talloc_free(tmp_ctx);
809 return rc;
813 * epm_Map
815 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
816 * to produce a list of protocol towers.
818 error_status_t _epm_Map(struct pipes_struct *p,
819 struct epm_Map *r)
821 struct policy_handle *entry_handle;
822 enum dcerpc_transport_t transport;
823 struct ndr_syntax_id ifid;
824 struct epm_floor *floors;
825 struct rpc_eps *eps;
826 TALLOC_CTX *tmp_ctx;
827 error_status_t rc;
828 uint32_t count = 0;
829 uint32_t num_towers = 0;
830 uint32_t num_floors = 0;
831 uint32_t i;
832 bool ok;
834 *r->out.num_towers = 0;
835 r->out.towers = NULL;
837 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
838 r->in.map_tower->tower.num_floors < 3) {
839 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
842 tmp_ctx = talloc_stackframe();
843 if (tmp_ctx == NULL) {
844 return EPMAPPER_STATUS_NO_MEMORY;
847 ZERO_STRUCTP(r->out.entry_handle);
849 DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n",
850 r->in.max_towers));
853 * A tower has normally up to 6 floors
855 * +-----------------------------------------------------------------+
856 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
857 * | | netlogon) |
858 * +---------+-------------------------------------------------------+
859 * | Floor 2 | Transfer syntax (NDR endcoded) |
860 * +---------+-------------------------------------------------------+
861 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
862 * +---------+-------------------------------------------------------+
863 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
864 * +---------+-------------------------------------------------------+
865 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
866 * +---------+-------------------------------------------------------+
867 * | Floor 6 | Routing |
868 * +---------+-------------------------------------------------------+
870 num_floors = r->in.map_tower->tower.num_floors;
871 floors = r->in.map_tower->tower.floors;
873 /* We accept NDR as the transfer syntax */
874 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
876 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
877 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) ||
878 ifid.if_version != ndr_transfer_syntax.if_version) {
879 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
880 goto done;
883 /* We only talk to sane transports */
884 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
885 if (transport == NCA_UNKNOWN) {
886 DEBUG(2, ("epm_Map: Client requested unknown transport with"
887 "levels: "));
888 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
889 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
891 DEBUG(2, ("\n"));
892 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
893 goto done;
896 if (r->in.entry_handle == NULL ||
897 policy_handle_empty(r->in.entry_handle)) {
898 struct GUID *obj;
900 DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n"));
902 eps = talloc_zero(tmp_ctx, struct rpc_eps);
903 if (eps == NULL) {
904 rc = EPMAPPER_STATUS_NO_MEMORY;
905 goto done;
909 * *** ATTENTION ***
910 * CDE 1.1 states:
912 * ept_map()
913 * Apply some algorithm (using the fields in the map_tower)
914 * to an endpoint map to produce a list of protocol towers.
916 * The following code is the mysterious "some algorithm"!
919 /* Filter by object id if one was given. */
920 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
921 obj = NULL;
922 } else {
923 obj = r->in.object;
926 eps->count = build_ep_list(eps,
927 endpoint_table,
928 obj,
929 p->server_id == NULL ? NULL : p->server_id->addr,
930 &eps->e);
931 if (eps->count == 0) {
932 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
933 goto done;
936 /* Filter out endpoints which match the interface. */
938 struct rpc_eps *teps;
939 uint32_t total = 0;
941 teps = talloc_zero(tmp_ctx, struct rpc_eps);
942 if (teps == NULL) {
943 rc = EPMAPPER_STATUS_NO_MEMORY;
944 goto done;
947 for (i = 0; i < eps->count; i++) {
948 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
949 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
950 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
951 continue;
954 teps->e = talloc_realloc(tmp_ctx,
955 teps->e,
956 struct dcesrv_ep_iface,
957 total + 1);
958 if (teps->e == NULL) {
959 return 0;
962 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
963 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
964 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
965 teps->e[total].syntax_id = eps->e[i].syntax_id;
967 total++;
970 teps->count = total;
971 talloc_free(eps);
972 eps = teps;
974 /* end of "some algorithm" */
976 ok = create_policy_hnd(p, r->out.entry_handle, eps);
977 if (!ok) {
978 rc = EPMAPPER_STATUS_NO_MEMORY;
979 goto done;
982 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
983 if (!ok) {
984 rc = EPMAPPER_STATUS_NO_MEMORY;
985 goto done;
987 entry_handle = r->out.entry_handle;
988 } else {
989 DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n"));
991 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
992 if (!ok) {
993 rc = EPMAPPER_STATUS_NO_MEMORY;
994 goto done;
996 entry_handle = r->in.entry_handle;
999 if (eps == NULL || eps->e == NULL) {
1000 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1001 goto done;
1004 /* return the next N elements */
1005 count = r->in.max_towers;
1006 if (count > eps->count) {
1007 count = eps->count;
1010 if (count == 0) {
1011 close_policy_hnd(p, entry_handle);
1012 ZERO_STRUCTP(r->out.entry_handle);
1014 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1015 goto done;
1018 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1019 if (r->out.towers == NULL) {
1020 rc = EPMAPPER_STATUS_NO_MEMORY;
1021 goto done;
1024 for (i = 0; i < count; i++) {
1025 DEBUG(5, ("_epm_Map: Map tower for '%s'\n",
1026 eps->e[i].name));
1028 r->out.towers[num_towers].twr = talloc(r->out.towers,
1029 struct epm_twr_t);
1030 if (r->out.towers[num_towers].twr == NULL) {
1031 rc = EPMAPPER_STATUS_NO_MEMORY;
1032 goto done;
1034 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1035 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1036 r->out.towers[num_towers].twr->tower_length = 0;
1038 num_towers++;
1041 *r->out.num_towers = num_towers;
1043 eps->count -= count;
1044 eps->e += count;
1045 if (eps->count == 0) {
1046 close_policy_hnd(p, entry_handle);
1047 ZERO_STRUCTP(r->out.entry_handle);
1050 rc = EPMAPPER_STATUS_OK;
1051 done:
1052 talloc_free(tmp_ctx);
1054 return rc;
1058 * epm_LookupHandleFree
1060 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1061 struct epm_LookupHandleFree *r)
1063 if (r->in.entry_handle == NULL) {
1064 return EPMAPPER_STATUS_OK;
1067 if (is_valid_policy_hnd(r->in.entry_handle)) {
1068 close_policy_hnd(p, r->in.entry_handle);
1071 r->out.entry_handle = r->in.entry_handle;
1073 return EPMAPPER_STATUS_OK;
1078 * epm_InqObject
1080 * A client implementation SHOULD NOT call this method. These extensions do not
1081 * provide an alternative method.
1083 error_status_t _epm_InqObject(struct pipes_struct *p,
1084 struct epm_InqObject *r)
1086 p->rng_fault_state = true;
1087 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1092 * epm_MgmtDelete
1094 * A client implementation SHOULD NOT call this method. These extensions do not
1095 * provide an alternative method.
1097 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1098 struct epm_MgmtDelete *r)
1100 p->rng_fault_state = true;
1101 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1106 epm_MapAuth
1108 error_status_t _epm_MapAuth(struct pipes_struct *p,
1109 struct epm_MapAuth *r)
1111 p->rng_fault_state = true;
1112 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1115 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */