s3-epmapper: Added a cleanup function.
[Samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blobc43e351fdb3c86ad89337fcbdddbc2b73000e6fb
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 rpc_eps {
63 struct dcesrv_ep_iface *e;
64 uint32_t count;
67 static struct dcesrv_endpoint *endpoint_table;
70 * Check if the UUID and if_version match to an interface.
72 static bool interface_match(const struct dcesrv_iface *if1,
73 const struct dcesrv_iface *if2)
75 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
79 * Find the interface operations on an endpoint.
81 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
82 const struct dcesrv_iface *iface)
84 struct dcesrv_iface_list *iflist;
86 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
87 if (interface_match(iflist->iface, iface)) {
88 return iflist->iface;
92 return NULL;
96 * See if a uuid and if_version match to an interface
98 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
99 const struct GUID *uuid)
101 return GUID_equal(&iface->syntax_id.uuid, uuid);
104 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
105 const struct dcesrv_iface *iface)
107 struct dcesrv_iface_list *iflist;
109 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
110 if (interface_match(iflist->iface, iface)) {
111 return iflist;
115 return NULL;
119 * Check if two endpoints match.
121 static bool endpoints_match(const struct dcerpc_binding *ep1,
122 const struct dcerpc_binding *ep2)
124 if (ep1->transport != ep2->transport) {
125 return false;
128 if (!ep1->endpoint || !ep2->endpoint) {
129 return ep1->endpoint == ep2->endpoint;
132 if (!strequal(ep1->endpoint, ep2->endpoint)) {
133 return false;
136 return true;
139 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
140 struct dcerpc_binding *ep_description) {
141 struct dcesrv_endpoint *ep;
143 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
144 if (endpoints_match(ep->ep_description, ep_description)) {
145 return ep;
149 return NULL;
153 * Build a list of all interfaces handled by all endpoint servers.
155 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
156 struct dcesrv_endpoint *endpoint_list,
157 const struct GUID *uuid,
158 const char *srv_addr,
159 struct dcesrv_ep_iface **peps)
161 struct dcesrv_ep_iface *eps = NULL;
162 struct dcesrv_endpoint *d;
163 uint32_t total = 0;
164 NTSTATUS status;
166 *peps = NULL;
168 for (d = endpoint_list; d != NULL; d = d->next) {
169 struct dcesrv_iface_list *iface;
170 struct dcerpc_binding *description;
172 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
173 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
174 continue;
177 eps = talloc_realloc(mem_ctx,
178 eps,
179 struct dcesrv_ep_iface,
180 total + 1);
181 if (eps == NULL) {
182 return 0;
184 eps[total].name = talloc_strdup(eps,
185 iface->iface->name);
186 eps[total].syntax_id = iface->iface->syntax_id;
188 description = d->ep_description;
189 description->object = iface->iface->syntax_id;
190 if (description->transport == NCACN_IP_TCP &&
191 srv_addr != NULL &&
192 strequal(description->host, "0.0.0.0")) {
193 description->host = srv_addr;
196 status = dcerpc_binding_build_tower(eps,
197 description,
198 &eps[total].ep);
199 if (NT_STATUS_IS_ERR(status)) {
200 DEBUG(1, ("Unable to build tower for %s\n",
201 iface->iface->name));
202 continue;
204 total++;
208 *peps = eps;
210 return total;
213 static bool is_priviledged_pipe(struct auth_serversupplied_info *info) {
214 /* If the user is not root, or has the system token, fail */
215 if ((info->utok.uid != sec_initial_uid()) &&
216 !security_token_is_system(info->security_token)) {
217 return false;
220 return true;
223 void srv_epmapper_cleanup(void)
225 struct dcesrv_endpoint *ep;
227 for (ep = endpoint_table;
228 ep != NULL;
229 ep = endpoint_table) {
230 DLIST_REMOVE(endpoint_table, ep);
231 TALLOC_FREE(ep);
236 * epm_Insert
238 * Add the specified entries to an endpoint map.
240 error_status_t _epm_Insert(struct pipes_struct *p,
241 struct epm_Insert *r)
243 TALLOC_CTX *tmp_ctx;
244 error_status_t rc;
245 NTSTATUS status;
246 uint32_t i;
248 /* If this is not a priviledged users, return */
249 if (p->transport != NCALRPC ||
250 !is_priviledged_pipe(p->session_info)) {
251 return EPMAPPER_STATUS_CANT_PERFORM_OP;
254 tmp_ctx = talloc_stackframe();
255 if (tmp_ctx == NULL) {
256 return EPMAPPER_STATUS_NO_MEMORY;
259 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
260 r->in.num_ents));
262 for (i = 0; i < r->in.num_ents; i++) {
263 struct dcerpc_binding *b = NULL;
264 struct dcesrv_endpoint *ep;
265 struct dcesrv_iface_list *iflist;
266 struct dcesrv_iface *iface;
267 bool add_ep = false;
269 status = dcerpc_binding_from_tower(tmp_ctx,
270 &r->in.entries[i].tower->tower,
271 &b);
272 if (!NT_STATUS_IS_OK(status)) {
273 rc = EPMAPPER_STATUS_NO_MEMORY;
274 goto done;
277 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
278 derpc_transport_string_by_transport(b->transport),
279 r->in.entries[i].annotation));
281 /* Check if the entry already exits */
282 ep = find_endpoint(endpoint_table, b);
283 if (ep == NULL) {
284 /* No entry found, create it */
285 ep = talloc_zero(NULL, struct dcesrv_endpoint);
286 if (ep == NULL) {
287 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
288 goto done;
290 add_ep = true;
292 ep->ep_description = talloc_steal(ep, b);
295 /* TODO Replace the entry if the replace flag is set */
297 /* Create an interface */
298 iface = talloc(tmp_ctx, struct dcesrv_iface);
299 if (iface == NULL) {
300 rc = EPMAPPER_STATUS_NO_MEMORY;
301 goto done;
304 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
305 if (iface->name == NULL) {
306 rc = EPMAPPER_STATUS_NO_MEMORY;
307 goto done;
309 iface->syntax_id = b->object;
312 * Check if the rpc service is alrady registered on the
313 * endpoint.
315 if (find_interface(ep, iface) != NULL) {
316 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
317 "already registered on endpoint\n",
318 iface->name));
319 /* FIXME wrong error code? */
320 rc = EPMAPPER_STATUS_OK;
321 goto done;
324 /* Create an entry for the interface */
325 iflist = talloc(ep, struct dcesrv_iface_list);
326 if (iflist == NULL) {
327 rc = EPMAPPER_STATUS_NO_MEMORY;
328 goto done;
330 iflist->iface = talloc_move(iflist, &iface);
332 /* Finally add the interface on the endpoint */
333 DLIST_ADD(ep->iface_list, iflist);
335 /* If it's a new endpoint add it to the endpoint_table */
336 if (add_ep) {
337 DLIST_ADD(endpoint_table, ep);
341 rc = EPMAPPER_STATUS_OK;
342 done:
343 talloc_free(tmp_ctx);
345 return rc;
350 * epm_Delete
352 * Delete the specified entries from an endpoint map.
354 error_status_t _epm_Delete(struct pipes_struct *p,
355 struct epm_Delete *r)
357 TALLOC_CTX *tmp_ctx;
358 error_status_t rc;
359 NTSTATUS status;
360 uint32_t i;
362 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
363 r->in.num_ents));
365 /* If this is not a priviledged users, return */
366 if (p->transport != NCALRPC ||
367 !is_priviledged_pipe(p->session_info)) {
368 return EPMAPPER_STATUS_CANT_PERFORM_OP;
371 tmp_ctx = talloc_stackframe();
372 if (tmp_ctx == NULL) {
373 return EPMAPPER_STATUS_NO_MEMORY;
376 for (i = 0; i < r->in.num_ents; i++) {
377 struct dcerpc_binding *b = NULL;
378 struct dcesrv_endpoint *ep;
379 struct dcesrv_iface iface;
380 struct dcesrv_iface_list *iflist;
382 status = dcerpc_binding_from_tower(tmp_ctx,
383 &r->in.entries[i].tower->tower,
384 &b);
385 if (!NT_STATUS_IS_OK(status)) {
386 rc = EPMAPPER_STATUS_NO_MEMORY;
387 goto done;
390 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
391 derpc_transport_string_by_transport(b->transport),
392 r->in.entries[i].annotation));
394 ep = find_endpoint(endpoint_table, b);
395 if (ep == NULL) {
396 rc = EPMAPPER_STATUS_OK;
397 goto done;
400 iface.name = r->in.entries[i].annotation;
401 iface.syntax_id = b->object;
403 iflist = find_interface_list(ep, &iface);
404 if (iflist == NULL) {
405 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
406 DLIST_REMOVE(endpoint_table, ep);
407 talloc_free(ep);
409 rc = EPMAPPER_STATUS_OK;
410 goto done;
413 DLIST_REMOVE(ep->iface_list, iflist);
415 if (ep->iface_list == NULL) {
416 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
417 DLIST_REMOVE(endpoint_table, ep);
418 talloc_free(ep);
420 rc = EPMAPPER_STATUS_OK;
421 goto done;
426 rc = EPMAPPER_STATUS_OK;
427 done:
428 talloc_free(tmp_ctx);
430 return rc;
435 * epm_Lookup
437 * Lookup entries in an endpoint map.
439 error_status_t _epm_Lookup(struct pipes_struct *p,
440 struct epm_Lookup *r)
442 struct policy_handle *entry_handle;
443 struct rpc_eps *eps;
444 TALLOC_CTX *tmp_ctx;
445 error_status_t rc;
446 uint32_t count = 0;
447 uint32_t num_ents = 0;
448 uint32_t i;
449 bool match = false;
450 bool ok;
452 *r->out.num_ents = 0;
453 r->out.entries = NULL;
455 tmp_ctx = talloc_stackframe();
456 if (tmp_ctx == NULL) {
457 return EPMAPPER_STATUS_NO_MEMORY;
460 DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
461 r->in.max_ents));
463 if (r->in.entry_handle == NULL ||
464 policy_handle_empty(r->in.entry_handle)) {
465 struct GUID *obj;
467 DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n"));
469 eps = talloc_zero(tmp_ctx, struct rpc_eps);
470 if (eps == NULL) {
471 rc = EPMAPPER_STATUS_NO_MEMORY;
472 goto done;
475 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
476 obj = NULL;
477 } else {
478 obj = r->in.object;
481 switch (r->in.inquiry_type) {
482 case RPC_C_EP_ALL_ELTS:
484 * Return all elements from the endpoint map. The
485 * interface_id, vers_option, and object parameters MUST
486 * be ignored.
488 eps->count = build_ep_list(eps,
489 endpoint_table,
490 NULL,
491 p->server_id == NULL ? NULL : p->server_id->addr,
492 &eps->e);
493 break;
494 case RPC_C_EP_MATCH_BY_IF:
496 * Return endpoint map elements that contain the
497 * interface identifier specified by the interface_id
498 * and vers_option values.
500 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
501 * need both the same endpoint list. There is a second
502 * check for the inquiry_type below which differentiates
503 * between them.
505 case RPC_C_EP_MATCH_BY_BOTH:
507 * Return endpoint map elements that contain the
508 * interface identifier and object UUID specified by
509 * interface_id, vers_option, and object.
511 eps->count = build_ep_list(eps,
512 endpoint_table,
513 &r->in.interface_id->uuid,
514 p->server_id == NULL ? NULL : p->server_id->addr,
515 &eps->e);
516 break;
517 case RPC_C_EP_MATCH_BY_OBJ:
519 * Return endpoint map elements that contain the object
520 * UUID specified by object.
522 eps->count = build_ep_list(eps,
523 endpoint_table,
524 r->in.object,
525 p->server_id == NULL ? NULL : p->server_id->addr,
526 &eps->e);
527 break;
528 default:
529 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
530 goto done;
533 if (eps->count == 0) {
534 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
535 goto done;
538 ok = create_policy_hnd(p, r->out.entry_handle, eps);
539 if (!ok) {
540 rc = EPMAPPER_STATUS_NO_MEMORY;
541 goto done;
544 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
545 if (!ok) {
546 rc = EPMAPPER_STATUS_NO_MEMORY;
547 goto done;
549 entry_handle = r->out.entry_handle;
550 } else {
551 DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n"));
553 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
554 if (!ok) {
555 rc = EPMAPPER_STATUS_NO_MEMORY;
556 goto done;
558 entry_handle = r->in.entry_handle;
561 if (eps == NULL || eps->e == NULL) {
562 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
563 goto done;
566 /* return the next N elements */
567 count = r->in.max_ents;
568 if (count > eps->count) {
569 count = eps->count;
572 DEBUG(3, ("_epm_Lookup: Find %u entries\n", count));
574 if (count == 0) {
575 close_policy_hnd(p, entry_handle);
576 ZERO_STRUCTP(r->out.entry_handle);
578 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
579 goto done;
582 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
583 if (r->out.entries == NULL) {
584 rc = EPMAPPER_STATUS_NO_MEMORY;
585 goto done;
588 for (i = 0; i < count; i++) {
589 match = false;
591 switch (r->in.inquiry_type) {
592 case RPC_C_EP_ALL_ELTS:
594 * Return all elements from the endpoint map. The
595 * interface_id, vers_option, and object parameters MUST
596 * be ignored.
598 match = true;
599 break;
600 case RPC_C_EP_MATCH_BY_IF:
602 * Return endpoint map elements that contain the
603 * interface identifier specified by the interface_id
604 * and vers_option values.
606 if (GUID_equal(&r->in.interface_id->uuid,
607 &eps->e[i].syntax_id.uuid)) {
608 match = true;
610 break;
611 case RPC_C_EP_MATCH_BY_OBJ:
613 * Return endpoint map elements that contain the object
614 * UUID specified by object.
616 if (GUID_equal(r->in.object,
617 &eps->e[i].syntax_id.uuid)) {
618 match = true;
620 break;
621 case RPC_C_EP_MATCH_BY_BOTH:
623 * Return endpoint map elements that contain the
624 * interface identifier and object UUID specified by
625 * interface_id, vers_option, and object.
627 if (GUID_equal(&r->in.interface_id->uuid,
628 &eps->e[i].syntax_id.uuid) &&
629 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
630 match = true;
632 break;
633 default:
634 return EPMAPPER_STATUS_CANT_PERFORM_OP;
637 if (match) {
638 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
639 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
640 /* Check inteface version */
642 match = false;
643 switch (r->in.vers_option) {
644 case RPC_C_VERS_ALL:
646 * Return endpoint map elements that
647 * contain the specified interface UUID,
648 * regardless of the version numbers.
650 match = true;
651 break;
652 case RPC_C_VERS_COMPATIBLE:
654 * Return the endpoint map elements that
655 * contain the same major versions of
656 * the specified interface UUID and a
657 * minor version greater than or equal
658 * to the minor version of the specified
659 * UUID.
661 if (r->in.interface_id->vers_major ==
662 (eps->e[i].syntax_id.if_version >> 16) &&
663 r->in.interface_id->vers_minor <=
664 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
665 match = true;
667 break;
668 case RPC_C_VERS_EXACT:
670 * Return endpoint map elements that
671 * contain the specified version of the
672 * specified interface UUID.
674 if (r->in.interface_id->vers_major ==
675 (eps->e[i].syntax_id.if_version >> 16) &&
676 r->in.interface_id->vers_minor ==
677 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
678 match = true;
680 match = true;
681 break;
682 case RPC_C_VERS_MAJOR_ONLY:
684 * Return endpoint map elements that
685 * contain the same version of the
686 * specified interface UUID and ignore
687 * the minor version.
689 if (r->in.interface_id->vers_major ==
690 (eps->e[i].syntax_id.if_version >> 16)) {
691 match = true;
693 match = true;
694 break;
695 case RPC_C_VERS_UPTO:
697 * Return endpoint map elements that
698 * contain a version of the specified
699 * interface UUID less than or equal to
700 * the specified major and minor
701 * version.
703 if (r->in.interface_id->vers_major >
704 eps->e[i].syntax_id.if_version >> 16) {
705 match = true;
706 } else {
707 if (r->in.interface_id->vers_major ==
708 (eps->e[i].syntax_id.if_version >> 16) &&
709 r->in.interface_id->vers_minor >=
710 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
711 match = true;
714 break;
715 default:
716 return EPMAPPER_STATUS_CANT_PERFORM_OP;
721 if (match) {
722 ZERO_STRUCT(r->out.entries[num_ents].object);
724 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
725 eps->e[i].name));
726 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
727 eps->e[i].name);
728 r->out.entries[num_ents].tower = talloc(r->out.entries,
729 struct epm_twr_t);
730 if (r->out.entries[num_ents].tower == NULL) {
731 rc = EPMAPPER_STATUS_NO_MEMORY;
732 goto done;
734 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
735 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
736 r->out.entries[num_ents].tower->tower_length = 0;
738 num_ents++;
740 } /* end for loop */
742 *r->out.num_ents = num_ents;
744 eps->count -= count;
745 eps->e += count;
746 if (eps->count == 0) {
747 close_policy_hnd(p, entry_handle);
748 ZERO_STRUCTP(r->out.entry_handle);
749 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
750 goto done;
753 rc = EPMAPPER_STATUS_OK;
754 done:
755 talloc_free(tmp_ctx);
757 return rc;
761 * epm_Map
763 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
764 * to produce a list of protocol towers.
766 error_status_t _epm_Map(struct pipes_struct *p,
767 struct epm_Map *r)
769 struct policy_handle *entry_handle;
770 enum dcerpc_transport_t transport;
771 struct ndr_syntax_id ifid;
772 struct epm_floor *floors;
773 struct rpc_eps *eps;
774 TALLOC_CTX *tmp_ctx;
775 error_status_t rc;
776 uint32_t count = 0;
777 uint32_t num_towers = 0;
778 uint32_t num_floors = 0;
779 uint32_t i;
780 bool ok;
782 *r->out.num_towers = 0;
783 r->out.towers = NULL;
785 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
786 r->in.map_tower->tower.num_floors < 3) {
787 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
790 tmp_ctx = talloc_stackframe();
791 if (tmp_ctx == NULL) {
792 return EPMAPPER_STATUS_NO_MEMORY;
795 ZERO_STRUCTP(r->out.entry_handle);
797 DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n",
798 r->in.max_towers));
801 * A tower has normally up to 6 floors
803 * +-----------------------------------------------------------------+
804 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
805 * | | netlogon) |
806 * +---------+-------------------------------------------------------+
807 * | Floor 2 | Transfer syntax (NDR endcoded) |
808 * +---------+-------------------------------------------------------+
809 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
810 * +---------+-------------------------------------------------------+
811 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
812 * +---------+-------------------------------------------------------+
813 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
814 * +---------+-------------------------------------------------------+
815 * | Floor 6 | Routing |
816 * +---------+-------------------------------------------------------+
818 num_floors = r->in.map_tower->tower.num_floors;
819 floors = r->in.map_tower->tower.floors;
821 /* We accept NDR as the transfer syntax */
822 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
824 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
825 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) ||
826 ifid.if_version != ndr_transfer_syntax.if_version) {
827 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
828 goto done;
831 /* We only talk to sane transports */
832 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
833 if (transport == NCA_UNKNOWN) {
834 DEBUG(2, ("epm_Map: Client requested unknown transport with"
835 "levels: "));
836 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
837 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
839 DEBUG(2, ("\n"));
840 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
841 goto done;
844 if (r->in.entry_handle == NULL ||
845 policy_handle_empty(r->in.entry_handle)) {
846 struct GUID *obj;
848 DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n"));
850 eps = talloc_zero(tmp_ctx, struct rpc_eps);
851 if (eps == NULL) {
852 rc = EPMAPPER_STATUS_NO_MEMORY;
853 goto done;
857 * *** ATTENTION ***
858 * CDE 1.1 states:
860 * ept_map()
861 * Apply some algorithm (using the fields in the map_tower)
862 * to an endpoint map to produce a list of protocol towers.
864 * The following code is the mysterious "some algorithm"!
867 /* Filter by object id if one was given. */
868 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
869 obj = NULL;
870 } else {
871 obj = r->in.object;
874 eps->count = build_ep_list(eps,
875 endpoint_table,
876 obj,
877 p->server_id == NULL ? NULL : p->server_id->addr,
878 &eps->e);
879 if (eps->count == 0) {
880 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
881 goto done;
884 /* Filter out endpoints which match the interface. */
886 struct rpc_eps *teps;
887 uint32_t total = 0;
889 teps = talloc_zero(tmp_ctx, struct rpc_eps);
890 if (teps == NULL) {
891 rc = EPMAPPER_STATUS_NO_MEMORY;
892 goto done;
895 for (i = 0; i < eps->count; i++) {
896 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
897 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
898 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
899 continue;
902 teps->e = talloc_realloc(tmp_ctx,
903 teps->e,
904 struct dcesrv_ep_iface,
905 total + 1);
906 if (teps->e == NULL) {
907 return 0;
910 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
911 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
912 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
913 teps->e[total].syntax_id = eps->e[i].syntax_id;
915 total++;
918 teps->count = total;
919 talloc_free(eps);
920 eps = teps;
922 /* end of "some algorithm" */
924 ok = create_policy_hnd(p, r->out.entry_handle, eps);
925 if (!ok) {
926 rc = EPMAPPER_STATUS_NO_MEMORY;
927 goto done;
930 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
931 if (!ok) {
932 rc = EPMAPPER_STATUS_NO_MEMORY;
933 goto done;
935 entry_handle = r->out.entry_handle;
936 } else {
937 DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n"));
939 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
940 if (!ok) {
941 rc = EPMAPPER_STATUS_NO_MEMORY;
942 goto done;
944 entry_handle = r->in.entry_handle;
947 if (eps == NULL || eps->e == NULL) {
948 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
949 goto done;
952 /* return the next N elements */
953 count = r->in.max_towers;
954 if (count > eps->count) {
955 count = eps->count;
958 if (count == 0) {
959 close_policy_hnd(p, entry_handle);
960 ZERO_STRUCTP(r->out.entry_handle);
962 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
963 goto done;
966 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
967 if (r->out.towers == NULL) {
968 rc = EPMAPPER_STATUS_NO_MEMORY;
969 goto done;
972 for (i = 0; i < count; i++) {
973 DEBUG(5, ("_epm_Map: Map tower for '%s'\n",
974 eps->e[i].name));
976 r->out.towers[num_towers].twr = talloc(r->out.towers,
977 struct epm_twr_t);
978 if (r->out.towers[num_towers].twr == NULL) {
979 rc = EPMAPPER_STATUS_NO_MEMORY;
980 goto done;
982 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
983 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
984 r->out.towers[num_towers].twr->tower_length = 0;
986 num_towers++;
989 *r->out.num_towers = num_towers;
991 eps->count -= count;
992 eps->e += count;
993 if (eps->count == 0) {
994 close_policy_hnd(p, entry_handle);
995 ZERO_STRUCTP(r->out.entry_handle);
998 rc = EPMAPPER_STATUS_OK;
999 done:
1000 talloc_free(tmp_ctx);
1002 return rc;
1006 * epm_LookupHandleFree
1008 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1009 struct epm_LookupHandleFree *r)
1011 if (r->in.entry_handle == NULL) {
1012 return EPMAPPER_STATUS_OK;
1015 if (is_valid_policy_hnd(r->in.entry_handle)) {
1016 close_policy_hnd(p, r->in.entry_handle);
1019 r->out.entry_handle = r->in.entry_handle;
1021 return EPMAPPER_STATUS_OK;
1026 * epm_InqObject
1028 * A client implementation SHOULD NOT call this method. These extensions do not
1029 * provide an alternative method.
1031 error_status_t _epm_InqObject(struct pipes_struct *p,
1032 struct epm_InqObject *r)
1034 p->rng_fault_state = true;
1035 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1040 * epm_MgmtDelete
1042 * A client implementation SHOULD NOT call this method. These extensions do not
1043 * provide an alternative method.
1045 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1046 struct epm_MgmtDelete *r)
1048 p->rng_fault_state = true;
1049 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1054 epm_MapAuth
1056 error_status_t _epm_MapAuth(struct pipes_struct *p,
1057 struct epm_MapAuth *r)
1059 p->rng_fault_state = true;
1060 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1063 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */