s3-rpc_server: Only allow epm insert and delete on NCALRPC.
[Samba/bjacke.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blobf0bd9c63f513fcb8f3b4134bc1c7488b97b43d95
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"
27 typedef uint32_t error_status_t;
29 /* An endpoint combined with an interface description */
30 struct dcesrv_ep_iface {
31 const char *name;
32 struct ndr_syntax_id syntax_id;
33 struct epm_tower ep;
36 /* A rpc service interface like samr, lsarpc or netlogon */
37 struct dcesrv_iface {
38 const char *name;
39 struct ndr_syntax_id syntax_id;
42 struct dcesrv_iface_list {
43 struct dcesrv_iface_list *next, *prev;
44 struct dcesrv_iface *iface;
48 * An endpoint can serve multiple rpc services interfaces.
49 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
51 struct dcesrv_endpoint {
52 struct dcesrv_endpoint *next, *prev;
54 /* The type and the location of the endpoint */
55 struct dcerpc_binding *ep_description;
57 /* A list of rpc services able to connect to the endpoint */
58 struct dcesrv_iface_list *iface_list;
61 struct rpc_eps {
62 struct dcesrv_ep_iface *e;
63 uint32_t count;
66 static struct dcesrv_endpoint *endpoint_table;
69 * Check if the UUID and if_version match to an interface.
71 static bool interface_match(const struct dcesrv_iface *if1,
72 const struct dcesrv_iface *if2)
74 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
78 * Find the interface operations on an endpoint.
80 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
81 const struct dcesrv_iface *iface)
83 struct dcesrv_iface_list *iflist;
85 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
86 if (interface_match(iflist->iface, iface)) {
87 return iflist->iface;
91 return NULL;
95 * See if a uuid and if_version match to an interface
97 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
98 const struct GUID *uuid)
100 return GUID_equal(&iface->syntax_id.uuid, uuid);
103 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
104 const struct dcesrv_iface *iface)
106 struct dcesrv_iface_list *iflist;
108 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
109 if (interface_match(iflist->iface, iface)) {
110 return iflist;
114 return NULL;
118 * Check if two endpoints match.
120 static bool endpoints_match(const struct dcerpc_binding *ep1,
121 const struct dcerpc_binding *ep2)
123 if (ep1->transport != ep2->transport) {
124 return false;
127 if (!ep1->endpoint || !ep2->endpoint) {
128 return ep1->endpoint == ep2->endpoint;
131 if (!strequal(ep1->endpoint, ep2->endpoint)) {
132 return false;
135 return true;
138 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
139 struct dcerpc_binding *ep_description) {
140 struct dcesrv_endpoint *ep;
142 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
143 if (endpoints_match(ep->ep_description, ep_description)) {
144 return ep;
148 return NULL;
152 * Build a list of all interfaces handled by all endpoint servers.
154 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
155 struct dcesrv_endpoint *endpoint_list,
156 const struct GUID *uuid,
157 const char *srv_addr,
158 struct dcesrv_ep_iface **peps)
160 struct dcesrv_ep_iface *eps = NULL;
161 struct dcesrv_endpoint *d;
162 uint32_t total = 0;
163 NTSTATUS status;
165 *peps = NULL;
167 for (d = endpoint_list; d != NULL; d = d->next) {
168 struct dcesrv_iface_list *iface;
169 struct dcerpc_binding *description;
171 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
172 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
173 continue;
176 eps = talloc_realloc(mem_ctx,
177 eps,
178 struct dcesrv_ep_iface,
179 total + 1);
180 if (eps == NULL) {
181 return 0;
183 eps[total].name = talloc_strdup(eps,
184 iface->iface->name);
185 eps[total].syntax_id = iface->iface->syntax_id;
187 description = d->ep_description;
188 description->object = iface->iface->syntax_id;
189 if (description->transport == NCACN_IP_TCP &&
190 srv_addr != NULL &&
191 strequal(description->host, "0.0.0.0")) {
192 description->host = srv_addr;
195 status = dcerpc_binding_build_tower(eps,
196 description,
197 &eps[total].ep);
198 if (NT_STATUS_IS_ERR(status)) {
199 DEBUG(1, ("Unable to build tower for %s\n",
200 iface->iface->name));
201 continue;
203 total++;
207 *peps = eps;
209 return total;
212 static bool is_priviledged_pipe(struct auth_serversupplied_info *info) {
213 /* If the user is not root, or has the system token, fail */
214 if ((info->utok.uid != sec_initial_uid()) &&
215 !security_token_is_system(info->security_token)) {
216 return false;
219 return true;
223 * epm_Insert
225 * Add the specified entries to an endpoint map.
227 error_status_t _epm_Insert(struct pipes_struct *p,
228 struct epm_Insert *r)
230 TALLOC_CTX *tmp_ctx;
231 error_status_t rc;
232 NTSTATUS status;
233 uint32_t i;
235 /* If this is not a priviledged users, return */
236 if (p->transport != NCALRPC ||
237 !is_priviledged_pipe(p->session_info)) {
238 return EPMAPPER_STATUS_CANT_PERFORM_OP;
241 tmp_ctx = talloc_stackframe();
242 if (tmp_ctx == NULL) {
243 return EPMAPPER_STATUS_NO_MEMORY;
246 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
247 r->in.num_ents));
249 for (i = 0; i < r->in.num_ents; i++) {
250 struct dcerpc_binding *b = NULL;
251 struct dcesrv_endpoint *ep;
252 struct dcesrv_iface_list *iflist;
253 struct dcesrv_iface *iface;
254 bool add_ep = false;
256 status = dcerpc_binding_from_tower(tmp_ctx,
257 &r->in.entries[i].tower->tower,
258 &b);
259 if (!NT_STATUS_IS_OK(status)) {
260 rc = EPMAPPER_STATUS_NO_MEMORY;
261 goto done;
264 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
265 derpc_transport_string_by_transport(b->transport),
266 r->in.entries[i].annotation));
268 /* Check if the entry already exits */
269 ep = find_endpoint(endpoint_table, b);
270 if (ep == NULL) {
271 /* No entry found, create it */
272 ep = talloc_zero(NULL, struct dcesrv_endpoint);
273 if (ep == NULL) {
274 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
275 goto done;
277 add_ep = true;
279 ep->ep_description = talloc_steal(ep, b);
282 /* TODO Replace the entry if the replace flag is set */
284 /* Create an interface */
285 iface = talloc(tmp_ctx, struct dcesrv_iface);
286 if (iface == NULL) {
287 rc = EPMAPPER_STATUS_NO_MEMORY;
288 goto done;
291 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
292 if (iface->name == NULL) {
293 rc = EPMAPPER_STATUS_NO_MEMORY;
294 goto done;
296 iface->syntax_id = b->object;
299 * Check if the rpc service is alrady registered on the
300 * endpoint.
302 if (find_interface(ep, iface) != NULL) {
303 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
304 "already registered on endpoint\n",
305 iface->name));
306 /* FIXME wrong error code? */
307 rc = EPMAPPER_STATUS_OK;
308 goto done;
311 /* Create an entry for the interface */
312 iflist = talloc(ep, struct dcesrv_iface_list);
313 if (iflist == NULL) {
314 rc = EPMAPPER_STATUS_NO_MEMORY;
315 goto done;
317 iflist->iface = talloc_move(iflist, &iface);
319 /* Finally add the interface on the endpoint */
320 DLIST_ADD(ep->iface_list, iflist);
322 /* If it's a new endpoint add it to the endpoint_table */
323 if (add_ep) {
324 DLIST_ADD(endpoint_table, ep);
328 rc = EPMAPPER_STATUS_OK;
329 done:
330 talloc_free(tmp_ctx);
332 return rc;
337 * epm_Delete
339 * Delete the specified entries from an endpoint map.
341 error_status_t _epm_Delete(struct pipes_struct *p,
342 struct epm_Delete *r)
344 TALLOC_CTX *tmp_ctx;
345 error_status_t rc;
346 NTSTATUS status;
347 uint32_t i;
349 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
350 r->in.num_ents));
352 /* If this is not a priviledged users, return */
353 if (p->transport != NCALRPC ||
354 !is_priviledged_pipe(p->session_info)) {
355 return EPMAPPER_STATUS_CANT_PERFORM_OP;
358 tmp_ctx = talloc_stackframe();
359 if (tmp_ctx == NULL) {
360 return EPMAPPER_STATUS_NO_MEMORY;
363 for (i = 0; i < r->in.num_ents; i++) {
364 struct dcerpc_binding *b = NULL;
365 struct dcesrv_endpoint *ep;
366 struct dcesrv_iface iface;
367 struct dcesrv_iface_list *iflist;
369 status = dcerpc_binding_from_tower(tmp_ctx,
370 &r->in.entries[i].tower->tower,
371 &b);
372 if (!NT_STATUS_IS_OK(status)) {
373 rc = EPMAPPER_STATUS_NO_MEMORY;
374 goto done;
377 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
378 derpc_transport_string_by_transport(b->transport),
379 r->in.entries[i].annotation));
381 ep = find_endpoint(endpoint_table, b);
382 if (ep == NULL) {
383 rc = EPMAPPER_STATUS_OK;
384 goto done;
387 iface.name = r->in.entries[i].annotation;
388 iface.syntax_id = b->object;
390 iflist = find_interface_list(ep, &iface);
391 if (iflist == NULL) {
392 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
393 DLIST_REMOVE(endpoint_table, ep);
394 talloc_free(ep);
396 rc = EPMAPPER_STATUS_OK;
397 goto done;
400 DLIST_REMOVE(ep->iface_list, iflist);
402 if (ep->iface_list == NULL) {
403 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
404 DLIST_REMOVE(endpoint_table, ep);
405 talloc_free(ep);
407 rc = EPMAPPER_STATUS_OK;
408 goto done;
413 rc = EPMAPPER_STATUS_OK;
414 done:
415 talloc_free(tmp_ctx);
417 return rc;
422 * epm_Lookup
424 * Lookup entries in an endpoint map.
426 error_status_t _epm_Lookup(struct pipes_struct *p,
427 struct epm_Lookup *r)
429 struct policy_handle *entry_handle;
430 struct rpc_eps *eps;
431 TALLOC_CTX *tmp_ctx;
432 error_status_t rc;
433 uint32_t count = 0;
434 uint32_t num_ents = 0;
435 uint32_t i;
436 bool match = false;
437 bool ok;
439 *r->out.num_ents = 0;
440 r->out.entries = NULL;
442 tmp_ctx = talloc_stackframe();
443 if (tmp_ctx == NULL) {
444 return EPMAPPER_STATUS_NO_MEMORY;
447 DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
448 r->in.max_ents));
450 if (r->in.entry_handle == NULL ||
451 policy_handle_empty(r->in.entry_handle)) {
452 struct GUID *obj;
454 DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n"));
456 eps = talloc_zero(tmp_ctx, struct rpc_eps);
457 if (eps == NULL) {
458 rc = EPMAPPER_STATUS_NO_MEMORY;
459 goto done;
462 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
463 obj = NULL;
464 } else {
465 obj = r->in.object;
468 switch (r->in.inquiry_type) {
469 case RPC_C_EP_ALL_ELTS:
471 * Return all elements from the endpoint map. The
472 * interface_id, vers_option, and object parameters MUST
473 * be ignored.
475 eps->count = build_ep_list(eps,
476 endpoint_table,
477 NULL,
478 p->server_id == NULL ? NULL : p->server_id->addr,
479 &eps->e);
480 break;
481 case RPC_C_EP_MATCH_BY_IF:
483 * Return endpoint map elements that contain the
484 * interface identifier specified by the interface_id
485 * and vers_option values.
487 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
488 * need both the same endpoint list. There is a second
489 * check for the inquiry_type below which differentiates
490 * between them.
492 case RPC_C_EP_MATCH_BY_BOTH:
494 * Return endpoint map elements that contain the
495 * interface identifier and object UUID specified by
496 * interface_id, vers_option, and object.
498 eps->count = build_ep_list(eps,
499 endpoint_table,
500 &r->in.interface_id->uuid,
501 p->server_id == NULL ? NULL : p->server_id->addr,
502 &eps->e);
503 break;
504 case RPC_C_EP_MATCH_BY_OBJ:
506 * Return endpoint map elements that contain the object
507 * UUID specified by object.
509 eps->count = build_ep_list(eps,
510 endpoint_table,
511 r->in.object,
512 p->server_id == NULL ? NULL : p->server_id->addr,
513 &eps->e);
514 break;
515 default:
516 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
517 goto done;
520 if (eps->count == 0) {
521 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
522 goto done;
525 ok = create_policy_hnd(p, r->out.entry_handle, eps);
526 if (!ok) {
527 rc = EPMAPPER_STATUS_NO_MEMORY;
528 goto done;
531 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
532 if (!ok) {
533 rc = EPMAPPER_STATUS_NO_MEMORY;
534 goto done;
536 entry_handle = r->out.entry_handle;
537 } else {
538 DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n"));
540 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
541 if (!ok) {
542 rc = EPMAPPER_STATUS_NO_MEMORY;
543 goto done;
545 entry_handle = r->in.entry_handle;
548 if (eps == NULL || eps->e == NULL) {
549 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
550 goto done;
553 /* return the next N elements */
554 count = r->in.max_ents;
555 if (count > eps->count) {
556 count = eps->count;
559 DEBUG(3, ("_epm_Lookup: Find %u entries\n", count));
561 if (count == 0) {
562 close_policy_hnd(p, entry_handle);
563 ZERO_STRUCTP(r->out.entry_handle);
565 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
566 goto done;
569 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
570 if (r->out.entries == NULL) {
571 rc = EPMAPPER_STATUS_NO_MEMORY;
572 goto done;
575 for (i = 0; i < count; i++) {
576 match = false;
578 switch (r->in.inquiry_type) {
579 case RPC_C_EP_ALL_ELTS:
581 * Return all elements from the endpoint map. The
582 * interface_id, vers_option, and object parameters MUST
583 * be ignored.
585 match = true;
586 break;
587 case RPC_C_EP_MATCH_BY_IF:
589 * Return endpoint map elements that contain the
590 * interface identifier specified by the interface_id
591 * and vers_option values.
593 if (GUID_equal(&r->in.interface_id->uuid,
594 &eps->e[i].syntax_id.uuid)) {
595 match = true;
597 break;
598 case RPC_C_EP_MATCH_BY_OBJ:
600 * Return endpoint map elements that contain the object
601 * UUID specified by object.
603 if (GUID_equal(r->in.object,
604 &eps->e[i].syntax_id.uuid)) {
605 match = true;
607 break;
608 case RPC_C_EP_MATCH_BY_BOTH:
610 * Return endpoint map elements that contain the
611 * interface identifier and object UUID specified by
612 * interface_id, vers_option, and object.
614 if (GUID_equal(&r->in.interface_id->uuid,
615 &eps->e[i].syntax_id.uuid) &&
616 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
617 match = true;
619 break;
620 default:
621 return EPMAPPER_STATUS_CANT_PERFORM_OP;
624 if (match) {
625 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
626 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
627 /* Check inteface version */
629 match = false;
630 switch (r->in.vers_option) {
631 case RPC_C_VERS_ALL:
633 * Return endpoint map elements that
634 * contain the specified interface UUID,
635 * regardless of the version numbers.
637 match = true;
638 break;
639 case RPC_C_VERS_COMPATIBLE:
641 * Return the endpoint map elements that
642 * contain the same major versions of
643 * the specified interface UUID and a
644 * minor version greater than or equal
645 * to the minor version of the specified
646 * UUID.
648 if (r->in.interface_id->vers_major ==
649 (eps->e[i].syntax_id.if_version >> 16) &&
650 r->in.interface_id->vers_minor <=
651 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
652 match = true;
654 break;
655 case RPC_C_VERS_EXACT:
657 * Return endpoint map elements that
658 * contain the specified version of the
659 * specified interface 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 match = true;
668 break;
669 case RPC_C_VERS_MAJOR_ONLY:
671 * Return endpoint map elements that
672 * contain the same version of the
673 * specified interface UUID and ignore
674 * the minor version.
676 if (r->in.interface_id->vers_major ==
677 (eps->e[i].syntax_id.if_version >> 16)) {
678 match = true;
680 match = true;
681 break;
682 case RPC_C_VERS_UPTO:
684 * Return endpoint map elements that
685 * contain a version of the specified
686 * interface UUID less than or equal to
687 * the specified major and minor
688 * version.
690 if (r->in.interface_id->vers_major >
691 eps->e[i].syntax_id.if_version >> 16) {
692 match = true;
693 } else {
694 if (r->in.interface_id->vers_major ==
695 (eps->e[i].syntax_id.if_version >> 16) &&
696 r->in.interface_id->vers_minor >=
697 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
698 match = true;
701 break;
702 default:
703 return EPMAPPER_STATUS_CANT_PERFORM_OP;
708 if (match) {
709 ZERO_STRUCT(r->out.entries[num_ents].object);
711 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
712 eps->e[i].name));
713 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
714 eps->e[i].name);
715 r->out.entries[num_ents].tower = talloc(r->out.entries,
716 struct epm_twr_t);
717 if (r->out.entries[num_ents].tower == NULL) {
718 rc = EPMAPPER_STATUS_NO_MEMORY;
719 goto done;
721 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
722 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
723 r->out.entries[num_ents].tower->tower_length = 0;
725 num_ents++;
727 } /* end for loop */
729 *r->out.num_ents = num_ents;
731 eps->count -= count;
732 eps->e += count;
733 if (eps->count == 0) {
734 close_policy_hnd(p, entry_handle);
735 ZERO_STRUCTP(r->out.entry_handle);
736 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
737 goto done;
740 rc = EPMAPPER_STATUS_OK;
741 done:
742 talloc_free(tmp_ctx);
744 return rc;
748 * epm_Map
750 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
751 * to produce a list of protocol towers.
753 error_status_t _epm_Map(struct pipes_struct *p,
754 struct epm_Map *r)
756 struct policy_handle *entry_handle;
757 enum dcerpc_transport_t transport;
758 struct ndr_syntax_id ifid;
759 struct epm_floor *floors;
760 struct rpc_eps *eps;
761 TALLOC_CTX *tmp_ctx;
762 error_status_t rc;
763 uint32_t count = 0;
764 uint32_t num_towers = 0;
765 uint32_t num_floors = 0;
766 uint32_t i;
767 bool ok;
769 *r->out.num_towers = 0;
770 r->out.towers = NULL;
772 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
773 r->in.map_tower->tower.num_floors < 3) {
774 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
777 tmp_ctx = talloc_stackframe();
778 if (tmp_ctx == NULL) {
779 return EPMAPPER_STATUS_NO_MEMORY;
782 ZERO_STRUCTP(r->out.entry_handle);
784 DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n",
785 r->in.max_towers));
788 * A tower has normally up to 6 floors
790 * +-----------------------------------------------------------------+
791 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
792 * | | netlogon) |
793 * +---------+-------------------------------------------------------+
794 * | Floor 2 | Transfer syntax (NDR endcoded) |
795 * +---------+-------------------------------------------------------+
796 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
797 * +---------+-------------------------------------------------------+
798 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
799 * +---------+-------------------------------------------------------+
800 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
801 * +---------+-------------------------------------------------------+
802 * | Floor 6 | Routing |
803 * +---------+-------------------------------------------------------+
805 num_floors = r->in.map_tower->tower.num_floors;
806 floors = r->in.map_tower->tower.floors;
808 /* We accept NDR as the transfer syntax */
809 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
811 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
812 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) ||
813 ifid.if_version != ndr_transfer_syntax.if_version) {
814 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
815 goto done;
818 /* We only talk to sane transports */
819 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
820 if (transport == NCA_UNKNOWN) {
821 DEBUG(2, ("epm_Map: Client requested unknown transport with"
822 "levels: "));
823 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
824 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
826 DEBUG(2, ("\n"));
827 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
828 goto done;
831 if (r->in.entry_handle == NULL ||
832 policy_handle_empty(r->in.entry_handle)) {
833 struct GUID *obj;
835 DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n"));
837 eps = talloc_zero(tmp_ctx, struct rpc_eps);
838 if (eps == NULL) {
839 rc = EPMAPPER_STATUS_NO_MEMORY;
840 goto done;
844 * *** ATTENTION ***
845 * CDE 1.1 states:
847 * ept_map()
848 * Apply some algorithm (using the fields in the map_tower)
849 * to an endpoint map to produce a list of protocol towers.
851 * The following code is the mysterious "some algorithm"!
854 /* Filter by object id if one was given. */
855 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
856 obj = NULL;
857 } else {
858 obj = r->in.object;
861 eps->count = build_ep_list(eps,
862 endpoint_table,
863 obj,
864 p->server_id == NULL ? NULL : p->server_id->addr,
865 &eps->e);
866 if (eps->count == 0) {
867 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
868 goto done;
871 /* Filter out endpoints which match the interface. */
873 struct rpc_eps *teps;
874 uint32_t total = 0;
876 teps = talloc_zero(tmp_ctx, struct rpc_eps);
877 if (teps == NULL) {
878 rc = EPMAPPER_STATUS_NO_MEMORY;
879 goto done;
882 for (i = 0; i < eps->count; i++) {
883 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
884 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
885 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
886 continue;
889 teps->e = talloc_realloc(tmp_ctx,
890 teps->e,
891 struct dcesrv_ep_iface,
892 total + 1);
893 if (teps->e == NULL) {
894 return 0;
897 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
898 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
899 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
900 teps->e[total].syntax_id = eps->e[i].syntax_id;
902 total++;
905 teps->count = total;
906 talloc_free(eps);
907 eps = teps;
909 /* end of "some algorithm" */
911 ok = create_policy_hnd(p, r->out.entry_handle, eps);
912 if (!ok) {
913 rc = EPMAPPER_STATUS_NO_MEMORY;
914 goto done;
917 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
918 if (!ok) {
919 rc = EPMAPPER_STATUS_NO_MEMORY;
920 goto done;
922 entry_handle = r->out.entry_handle;
923 } else {
924 DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n"));
926 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
927 if (!ok) {
928 rc = EPMAPPER_STATUS_NO_MEMORY;
929 goto done;
931 entry_handle = r->in.entry_handle;
934 if (eps == NULL || eps->e == NULL) {
935 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
936 goto done;
939 /* return the next N elements */
940 count = r->in.max_towers;
941 if (count > eps->count) {
942 count = eps->count;
945 if (count == 0) {
946 close_policy_hnd(p, entry_handle);
947 ZERO_STRUCTP(r->out.entry_handle);
949 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
950 goto done;
953 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
954 if (r->out.towers == NULL) {
955 rc = EPMAPPER_STATUS_NO_MEMORY;
956 goto done;
959 for (i = 0; i < count; i++) {
960 DEBUG(5, ("_epm_Map: Map tower for '%s'\n",
961 eps->e[i].name));
963 r->out.towers[num_towers].twr = talloc(r->out.towers,
964 struct epm_twr_t);
965 if (r->out.towers[num_towers].twr == NULL) {
966 rc = EPMAPPER_STATUS_NO_MEMORY;
967 goto done;
969 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
970 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
971 r->out.towers[num_towers].twr->tower_length = 0;
973 num_towers++;
976 *r->out.num_towers = num_towers;
978 eps->count -= count;
979 eps->e += count;
980 if (eps->count == 0) {
981 close_policy_hnd(p, entry_handle);
982 ZERO_STRUCTP(r->out.entry_handle);
985 rc = EPMAPPER_STATUS_OK;
986 done:
987 talloc_free(tmp_ctx);
989 return rc;
993 * epm_LookupHandleFree
995 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
996 struct epm_LookupHandleFree *r)
998 if (r->in.entry_handle == NULL) {
999 return EPMAPPER_STATUS_OK;
1002 if (is_valid_policy_hnd(r->in.entry_handle)) {
1003 close_policy_hnd(p, r->in.entry_handle);
1006 r->out.entry_handle = r->in.entry_handle;
1008 return EPMAPPER_STATUS_OK;
1013 * epm_InqObject
1015 * A client implementation SHOULD NOT call this method. These extensions do not
1016 * provide an alternative method.
1018 error_status_t _epm_InqObject(struct pipes_struct *p,
1019 struct epm_InqObject *r)
1021 p->rng_fault_state = true;
1022 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1027 * epm_MgmtDelete
1029 * A client implementation SHOULD NOT call this method. These extensions do not
1030 * provide an alternative method.
1032 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1033 struct epm_MgmtDelete *r)
1035 p->rng_fault_state = true;
1036 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1041 epm_MapAuth
1043 error_status_t _epm_MapAuth(struct pipes_struct *p,
1044 struct epm_MapAuth *r)
1046 p->rng_fault_state = true;
1047 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1050 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */