tests: Check symlinks are readable as reparse points
[samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
blobcf6b268efdca408141b090a130a486a4be261735
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 "auth.h"
28 #include "librpc/rpc/dcesrv_core.h"
29 #include "librpc/gen_ndr/ndr_epmapper.h"
30 #include "librpc/gen_ndr/ndr_epmapper_scompat.h"
31 #include "rpc_server/rpc_server.h"
32 #include "lib/tdb_wrap/tdb_wrap.h"
33 #include "lib/util/util_tdb.h"
34 #include "lib/util/strv.h"
36 static struct tdb_wrap *epmdb = NULL;
38 /* handle types for this module */
39 enum handle_types {HTYPE_LOOKUP};
41 typedef uint32_t error_status_t;
43 /* An endpoint combined with an interface description */
44 struct dcesrv_ep_iface {
45 const char *name;
46 struct ndr_syntax_id syntax_id;
47 struct epm_tower ep;
50 /* A rpc service interface like samr, lsarpc or netlogon */
51 struct dcesrv_iface {
52 const char *name;
53 struct ndr_syntax_id syntax_id;
56 struct dcesrv_iface_list {
57 struct dcesrv_iface_list *next, *prev;
58 struct dcesrv_iface *iface;
62 * An endpoint can serve multiple rpc services interfaces.
63 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
65 struct dcesrv_epm_endpoint {
66 struct dcesrv_epm_endpoint *next, *prev;
68 /* The type and the location of the endpoint */
69 struct dcerpc_binding *ep_description;
71 /* A list of rpc services able to connect to the endpoint */
72 struct dcesrv_iface_list *iface_list;
75 struct rpc_eps {
76 struct dcesrv_ep_iface *e;
77 uint32_t count;
80 struct build_ep_list_state {
81 const struct GUID *uuid;
82 const char *srv_addr;
83 TALLOC_CTX *mem_ctx;
84 struct dcesrv_ep_iface *ifaces;
87 static bool build_ep_list_fill_iface(
88 TALLOC_CTX *mem_ctx,
89 const struct ndr_syntax_id *syntax_id,
90 const char *endpoint,
91 const char *name,
92 const char *srv_addr,
93 struct dcesrv_ep_iface *dst)
95 struct dcesrv_ep_iface iface = {
96 .syntax_id = *syntax_id,
98 struct dcerpc_binding *binding = NULL;
99 enum dcerpc_transport_t transport;
100 char *name_dup = NULL;
101 const char *host_addr = NULL;
102 NTSTATUS status;
104 /* copy without const for error path TALLOC_FREE */
105 name_dup = talloc_strdup(mem_ctx, name);
106 if (name_dup == NULL) {
107 goto fail;
109 iface.name = name_dup;
111 status = dcerpc_parse_binding(mem_ctx, endpoint, &binding);
112 if (!NT_STATUS_IS_OK(status)) {
113 DBG_DEBUG("dcerpc_parse_binding failed: %s\n",
114 nt_errstr(status));
115 goto fail;
118 status = dcerpc_binding_set_abstract_syntax(binding, syntax_id);
119 if (!NT_STATUS_IS_OK(status)) {
120 DBG_DEBUG("dcerpc_binding_set_abstract_syntax failed: %s\n",
121 nt_errstr(status));
122 goto fail;
125 transport = dcerpc_binding_get_transport(binding);
126 if (transport == NCACN_IP_TCP) {
127 const char *host = NULL;
129 host = dcerpc_binding_get_string_option(binding, "host");
130 if (host == NULL) {
131 host_addr = srv_addr;
132 } else if (!is_ipaddress_v4(host)) {
133 host_addr = srv_addr;
134 } else if (strcmp(host, "0.0.0.0") == 0) {
135 host_addr = srv_addr;
139 if (host_addr != NULL) {
140 status = dcerpc_binding_set_string_option(
141 binding, "host", host_addr);
142 if (!NT_STATUS_IS_OK(status)) {
143 DBG_DEBUG("dcerpc_binding_set_string_option "
144 "failed: %s\n",
145 nt_errstr(status));
146 goto fail;
150 status = dcerpc_binding_build_tower(mem_ctx, binding, &iface.ep);
151 TALLOC_FREE(binding);
152 if (!NT_STATUS_IS_OK(status)) {
153 DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
154 nt_errstr(status));
155 goto fail;
158 *dst = iface;
159 return true;
161 fail:
162 TALLOC_FREE(binding);
163 TALLOC_FREE(name_dup);
164 TALLOC_FREE(iface.ep.floors);
165 return false;
168 static int build_ep_list_fn(
169 struct tdb_context *tdb,
170 TDB_DATA key,
171 TDB_DATA value,
172 void *private_data)
174 struct build_ep_list_state *state = private_data;
175 struct ndr_syntax_id syntax_id = { .if_version = 0 };
176 const char *name = NULL;
177 char *endpoints = NULL;
178 const char *endpoint = NULL;
179 bool ok;
181 if ((key.dsize == 0) || (key.dptr[key.dsize-1] != '\0') ||
182 (value.dsize == 0) || (value.dptr[value.dsize-1] != '\0')) {
183 DBG_DEBUG("Invalid record\n");
184 return 0;
187 ok = ndr_syntax_id_from_string((char *)key.dptr, &syntax_id);
188 if (!ok) {
189 DBG_DEBUG("Invalid interface: %s\n", (char *)key.dptr);
190 return 0;
193 endpoints = (char *)value.dptr;
194 endpoint = endpoints;
195 name = endpoints;
197 while ((endpoint = strv_len_next(endpoints, value.dsize, endpoint))) {
198 size_t num_ifaces = talloc_array_length(state->ifaces);
199 struct dcesrv_ep_iface *tmp = NULL;
201 if (num_ifaces+1 < num_ifaces) {
202 return 1;
205 tmp = talloc_realloc(
206 state->mem_ctx,
207 state->ifaces,
208 struct dcesrv_ep_iface,
209 num_ifaces+1);
210 if (tmp == NULL) {
211 return 1;
213 state->ifaces = tmp;
215 ok = build_ep_list_fill_iface(
216 state->ifaces,
217 &syntax_id,
218 endpoint,
219 name,
220 state->srv_addr,
221 &state->ifaces[num_ifaces]);
222 if (!ok) {
223 state->ifaces = talloc_realloc(
224 state->mem_ctx,
225 state->ifaces,
226 struct dcesrv_ep_iface,
227 num_ifaces);
231 return 0;
235 * Build a list of all interfaces handled by all endpoint servers.
237 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
238 const struct GUID *uuid,
239 const char *srv_addr,
240 struct dcesrv_ep_iface **peps)
242 struct build_ep_list_state state = {
243 .mem_ctx = mem_ctx, .uuid = uuid, .srv_addr = srv_addr,
245 int ret;
247 ret = tdb_traverse_read(epmdb->tdb, build_ep_list_fn, &state);
248 if (ret == -1) {
249 DBG_DEBUG("tdb_traverse_read failed\n");
250 return 0;
253 *peps = state.ifaces;
254 return talloc_array_length(*peps);
258 * epm_Insert
260 * Add the specified entries to an endpoint map.
262 error_status_t _epm_Insert(struct pipes_struct *p,
263 struct epm_Insert *r)
265 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
266 return EPMAPPER_STATUS_CANT_PERFORM_OP;
270 * epm_Delete
272 * Delete the specified entries from an endpoint map.
274 error_status_t _epm_Delete(struct pipes_struct *p,
275 struct epm_Delete *r)
277 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
278 return EPMAPPER_STATUS_CANT_PERFORM_OP;
282 * epm_Lookup
284 * Lookup entries in an endpoint map.
286 error_status_t _epm_Lookup(struct pipes_struct *p,
287 struct epm_Lookup *r)
289 struct dcesrv_call_state *dce_call = p->dce_call;
290 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
291 struct policy_handle *entry_handle;
292 struct rpc_eps *eps;
293 TALLOC_CTX *tmp_ctx;
294 error_status_t rc;
295 uint32_t count = 0;
296 uint32_t num_ents = 0;
297 uint32_t i;
298 bool match = false;
299 bool ok;
300 NTSTATUS status;
302 *r->out.num_ents = 0;
303 r->out.entries = NULL;
305 tmp_ctx = talloc_stackframe();
306 if (tmp_ctx == NULL) {
307 return EPMAPPER_STATUS_NO_MEMORY;
310 DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
311 r->in.max_ents));
313 if (r->in.entry_handle == NULL ||
314 ndr_policy_handle_empty(r->in.entry_handle)) {
315 const struct tsocket_address *local_address =
316 dcesrv_connection_get_local_address(dcesrv_conn);
317 char *srv_addr = NULL;
319 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
321 eps = talloc_zero(tmp_ctx, struct rpc_eps);
322 if (eps == NULL) {
323 rc = EPMAPPER_STATUS_NO_MEMORY;
324 goto done;
327 if (local_address != NULL &&
328 tsocket_address_is_inet(local_address, "ipv4"))
330 srv_addr = tsocket_address_inet_addr_string(
331 local_address, tmp_ctx);
334 switch (r->in.inquiry_type) {
335 case RPC_C_EP_ALL_ELTS:
337 * Return all elements from the endpoint map. The
338 * interface_id, vers_option, and object parameters MUST
339 * be ignored.
341 eps->count = build_ep_list(eps,
342 NULL,
343 srv_addr,
344 &eps->e);
345 break;
346 case RPC_C_EP_MATCH_BY_IF:
348 * Return endpoint map elements that contain the
349 * interface identifier specified by the interface_id
350 * and vers_option values.
352 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
353 * need both the same endpoint list. There is a second
354 * check for the inquiry_type below which differentiates
355 * between them.
357 case RPC_C_EP_MATCH_BY_BOTH:
359 * Return endpoint map elements that contain the
360 * interface identifier and object UUID specified by
361 * interface_id, vers_option, and object.
363 eps->count = build_ep_list(eps,
364 &r->in.interface_id->uuid,
365 srv_addr,
366 &eps->e);
367 break;
368 case RPC_C_EP_MATCH_BY_OBJ:
370 * Return endpoint map elements that contain the object
371 * UUID specified by object.
373 eps->count = build_ep_list(eps,
374 r->in.object,
375 srv_addr,
376 &eps->e);
377 break;
378 default:
379 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
380 goto done;
383 if (eps->count == 0) {
384 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
385 goto done;
388 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
389 if (!ok) {
390 rc = EPMAPPER_STATUS_NO_MEMORY;
391 goto done;
394 eps = find_policy_by_hnd(p,
395 r->out.entry_handle,
396 HTYPE_LOOKUP,
397 struct rpc_eps,
398 &status);
399 if (!NT_STATUS_IS_OK(status)) {
400 rc = EPMAPPER_STATUS_NO_MEMORY;
401 goto done;
403 entry_handle = r->out.entry_handle;
404 } else {
405 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
407 eps = find_policy_by_hnd(p,
408 r->in.entry_handle,
409 HTYPE_LOOKUP,
410 struct rpc_eps,
411 &status);
412 if (!NT_STATUS_IS_OK(status)) {
413 rc = EPMAPPER_STATUS_NO_MEMORY;
414 goto done;
416 entry_handle = r->in.entry_handle;
419 if (eps == NULL || eps->e == NULL) {
420 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
421 goto done;
424 /* return the next N elements */
425 count = r->in.max_ents;
426 if (count > eps->count) {
427 count = eps->count;
430 DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
432 if (count == 0) {
433 close_policy_hnd(p, entry_handle);
434 ZERO_STRUCTP(r->out.entry_handle);
436 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
437 goto done;
440 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
441 if (r->out.entries == NULL) {
442 rc = EPMAPPER_STATUS_NO_MEMORY;
443 goto done;
446 for (i = 0; i < count; i++) {
447 match = false;
449 switch (r->in.inquiry_type) {
450 case RPC_C_EP_ALL_ELTS:
452 * Return all elements from the endpoint map. The
453 * interface_id, vers_option, and object parameters MUST
454 * be ignored.
456 match = true;
457 break;
458 case RPC_C_EP_MATCH_BY_IF:
460 * Return endpoint map elements that contain the
461 * interface identifier specified by the interface_id
462 * and vers_option values.
464 if (GUID_equal(&r->in.interface_id->uuid,
465 &eps->e[i].syntax_id.uuid)) {
466 match = true;
468 break;
469 case RPC_C_EP_MATCH_BY_OBJ:
471 * Return endpoint map elements that contain the object
472 * UUID specified by object.
474 if (GUID_equal(r->in.object,
475 &eps->e[i].syntax_id.uuid)) {
476 match = true;
478 break;
479 case RPC_C_EP_MATCH_BY_BOTH:
481 * Return endpoint map elements that contain the
482 * interface identifier and object UUID specified by
483 * interface_id, vers_option, and object.
485 if (GUID_equal(&r->in.interface_id->uuid,
486 &eps->e[i].syntax_id.uuid) &&
487 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
488 match = true;
490 break;
491 default:
492 return EPMAPPER_STATUS_CANT_PERFORM_OP;
495 if (match) {
496 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
497 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
498 /* Check interface version */
500 match = false;
501 switch (r->in.vers_option) {
502 case RPC_C_VERS_ALL:
504 * Return endpoint map elements that
505 * contain the specified interface UUID,
506 * regardless of the version numbers.
508 match = true;
509 break;
510 case RPC_C_VERS_COMPATIBLE:
512 * Return the endpoint map elements that
513 * contain the same major versions of
514 * the specified interface UUID and a
515 * minor version greater than or equal
516 * to the minor version of the specified
517 * UUID.
519 if (r->in.interface_id->vers_major ==
520 (eps->e[i].syntax_id.if_version >> 16) &&
521 r->in.interface_id->vers_minor <=
522 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
523 match = true;
525 break;
526 case RPC_C_VERS_EXACT:
528 * Return endpoint map elements that
529 * contain the specified version of the
530 * specified interface UUID.
532 if (r->in.interface_id->vers_major ==
533 (eps->e[i].syntax_id.if_version >> 16) &&
534 r->in.interface_id->vers_minor ==
535 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
536 match = true;
538 match = true;
539 break;
540 case RPC_C_VERS_MAJOR_ONLY:
542 * Return endpoint map elements that
543 * contain the same version of the
544 * specified interface UUID and ignore
545 * the minor version.
547 if (r->in.interface_id->vers_major ==
548 (eps->e[i].syntax_id.if_version >> 16)) {
549 match = true;
551 match = true;
552 break;
553 case RPC_C_VERS_UPTO:
555 * Return endpoint map elements that
556 * contain a version of the specified
557 * interface UUID less than or equal to
558 * the specified major and minor
559 * version.
561 if (r->in.interface_id->vers_major >
562 eps->e[i].syntax_id.if_version >> 16) {
563 match = true;
564 } else {
565 if (r->in.interface_id->vers_major ==
566 (eps->e[i].syntax_id.if_version >> 16) &&
567 r->in.interface_id->vers_minor >=
568 (eps->e[i].syntax_id.if_version & 0xFFFF)) {
569 match = true;
572 break;
573 default:
574 return EPMAPPER_STATUS_CANT_PERFORM_OP;
579 if (match) {
580 ZERO_STRUCT(r->out.entries[num_ents].object);
582 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
583 eps->e[i].name));
584 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
585 eps->e[i].name);
586 r->out.entries[num_ents].tower = talloc(r->out.entries,
587 struct epm_twr_t);
588 if (r->out.entries[num_ents].tower == NULL) {
589 rc = EPMAPPER_STATUS_NO_MEMORY;
590 goto done;
592 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
593 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
594 r->out.entries[num_ents].tower->tower_length = 0;
596 num_ents++;
598 } /* end for loop */
600 *r->out.num_ents = num_ents;
602 eps->count -= count;
603 eps->e += count;
604 if (eps->count == 0) {
605 close_policy_hnd(p, entry_handle);
606 ZERO_STRUCTP(r->out.entry_handle);
607 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
608 goto done;
611 rc = EPMAPPER_STATUS_OK;
612 done:
613 talloc_free(tmp_ctx);
615 return rc;
618 static struct rpc_eps *epm_map_get_towers(
619 TALLOC_CTX *mem_ctx,
620 const struct ndr_syntax_id *iface,
621 enum dcerpc_transport_t transport,
622 const char *local_address)
624 struct ndr_syntax_id_buf idbuf;
625 char *iface_string = ndr_syntax_id_buf_string(iface, &idbuf);
626 struct rpc_eps *eps = NULL;
627 uint8_t *buf = NULL;
628 size_t buflen;
629 char *bindings = NULL;
630 char *binding = NULL;
631 char *name = NULL;
632 NTSTATUS status;
633 int ret;
635 DBG_DEBUG("Mapping interface %s\n", iface_string);
637 eps = talloc_zero(mem_ctx, struct rpc_eps);
638 if (eps == NULL) {
639 goto fail;
642 ret = tdb_fetch_talloc(
643 epmdb->tdb, string_term_tdb_data(iface_string), eps, &buf);
644 if (ret != 0) {
645 DBG_DEBUG("Could not find epm entry for %s: %s\n",
646 iface_string,
647 strerror(ret));
648 goto fail;
650 buflen = talloc_array_length(buf);
652 if ((buflen < 1) || (buf[buflen-1] != '\0')) {
653 DBG_DEBUG("epm entry for %s invalid\n", iface_string);
654 goto fail;
656 bindings = (char *)buf;
658 name = bindings; /* name comes first */
659 binding = name; /* strv_next will skip name */
661 while ((binding = strv_next(bindings, binding)) != NULL) {
662 struct dcerpc_binding *b = NULL;
663 enum dcerpc_transport_t found_transport;
664 struct dcesrv_ep_iface *tmp = NULL, *new_ep = NULL;
666 DBG_DEBUG("Found %s for %s\n", binding, name);
668 status = dcerpc_parse_binding(mem_ctx, binding, &b);
669 if (!NT_STATUS_IS_OK(status)) {
670 DBG_DEBUG("dcerpc_parse_binding() for %s failed: %s\n",
671 binding,
672 nt_errstr(status));
673 goto fail;
676 found_transport = dcerpc_binding_get_transport(b);
677 if (found_transport != transport) {
678 DBG_DEBUG("Transport %d does not match %d\n",
679 (int)found_transport,
680 (int)transport);
681 TALLOC_FREE(b);
682 continue;
685 if (found_transport == NCACN_IP_TCP) {
686 status = dcerpc_binding_set_string_option(
687 b, "host", local_address);
688 if (!NT_STATUS_IS_OK(status)) {
689 DBG_DEBUG("Could not set host: %s\n",
690 nt_errstr(status));
691 goto fail;
695 status = dcerpc_binding_set_abstract_syntax(b, iface);
696 if (!NT_STATUS_IS_OK(status)) {
697 DBG_DEBUG("Could not set abstract syntax: %s\n",
698 nt_errstr(status));
699 goto fail;
702 tmp = talloc_realloc(
703 eps,
704 eps->e,
705 struct dcesrv_ep_iface,
706 eps->count+1);
707 if (tmp == NULL) {
708 goto fail;
710 eps->e = tmp;
712 new_ep = &eps->e[eps->count];
714 new_ep->name = talloc_strdup(eps->e, name);
715 if (new_ep->name == NULL) {
716 goto fail;
718 new_ep->syntax_id = *iface;
720 status = dcerpc_binding_build_tower(eps->e, b, &new_ep->ep);
721 if (!NT_STATUS_IS_OK(status)) {
722 DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
723 nt_errstr(status));
724 goto fail;
727 eps->count += 1;
729 TALLOC_FREE(b);
731 return eps;
733 fail:
734 TALLOC_FREE(eps);
735 return NULL;
739 * epm_Map
741 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
742 * to produce a list of protocol towers.
744 error_status_t _epm_Map(struct pipes_struct *p,
745 struct epm_Map *r)
747 struct dcesrv_call_state *dce_call = p->dce_call;
748 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
749 struct policy_handle *entry_handle;
750 enum dcerpc_transport_t transport;
751 struct ndr_syntax_id ifid;
752 struct epm_floor *floors;
753 struct rpc_eps *eps;
754 TALLOC_CTX *tmp_ctx;
755 error_status_t rc;
756 uint32_t count = 0;
757 uint32_t num_towers = 0;
758 uint32_t i;
759 bool ok;
760 NTSTATUS status;
762 *r->out.num_towers = 0;
763 r->out.towers = NULL;
765 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
766 r->in.map_tower->tower.num_floors < 3) {
767 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
770 tmp_ctx = talloc_stackframe();
772 ZERO_STRUCTP(r->out.entry_handle);
774 DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
775 r->in.max_towers));
778 * A tower has normally up to 6 floors
780 * +-----------------------------------------------------------------+
781 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
782 * | | netlogon) |
783 * +---------+-------------------------------------------------------+
784 * | Floor 2 | Transfer syntax (NDR encoded) |
785 * +---------+-------------------------------------------------------+
786 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
787 * +---------+-------------------------------------------------------+
788 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
789 * +---------+-------------------------------------------------------+
790 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
791 * +---------+-------------------------------------------------------+
792 * | Floor 6 | Routing |
793 * +---------+-------------------------------------------------------+
795 floors = r->in.map_tower->tower.floors;
797 /* We accept NDR as the transfer syntax */
798 status = dcerpc_floor_get_uuid_full(&floors[1], &ifid);
799 if (!NT_STATUS_IS_OK(status)) {
800 DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
801 nt_errstr(status));
802 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
803 goto done;
806 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
807 !ndr_syntax_id_equal(&ifid, &ndr_transfer_syntax_ndr)) {
808 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
809 goto done;
812 /* We only talk to sane transports */
813 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
814 if (transport == NCA_UNKNOWN) {
815 DEBUG(2, ("epm_Map: Client requested unknown transport with "
816 "levels: "));
817 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
818 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
820 DEBUG(2, ("\n"));
821 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
822 goto done;
825 if (r->in.entry_handle == NULL ||
826 ndr_policy_handle_empty(r->in.entry_handle)) {
827 const struct tsocket_address *local_addr =
828 dcesrv_connection_get_local_address(dcesrv_conn);
829 char *local_address = NULL;
830 struct ndr_syntax_id_buf buf;
831 char *if_string = NULL;
833 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
835 status = dcerpc_floor_get_uuid_full(&floors[0], &ifid);
836 if (!NT_STATUS_IS_OK(status)) {
837 DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
838 nt_errstr(status));
839 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
840 goto done;
843 if_string = ndr_syntax_id_buf_string(&ifid, &buf);
845 DBG_INFO("Mapping interface %s\n", if_string);
847 if ((transport == NCACN_IP_TCP) &&
848 tsocket_address_is_inet(local_addr, "ip")) {
850 * We don't have the host ip in the epm
851 * database. For NCACN_IP_TCP, add the IP that
852 * the client connected to.
854 local_address = tsocket_address_inet_addr_string(
855 local_addr, tmp_ctx);
858 eps = epm_map_get_towers(
859 tmp_ctx, &ifid, transport, local_address);
860 if (eps == NULL) {
861 DBG_DEBUG("No bindings found\n");
862 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
863 goto done;
866 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
867 if (!ok) {
868 rc = EPMAPPER_STATUS_NO_MEMORY;
869 goto done;
872 eps = find_policy_by_hnd(p,
873 r->out.entry_handle,
874 HTYPE_LOOKUP,
875 struct rpc_eps,
876 &status);
877 if (!NT_STATUS_IS_OK(status)) {
878 rc = EPMAPPER_STATUS_NO_MEMORY;
879 goto done;
881 entry_handle = r->out.entry_handle;
882 } else {
883 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
885 eps = find_policy_by_hnd(p,
886 r->in.entry_handle,
887 HTYPE_LOOKUP,
888 struct rpc_eps,
889 &status);
890 if (!NT_STATUS_IS_OK(status)) {
891 rc = EPMAPPER_STATUS_NO_MEMORY;
892 goto done;
894 entry_handle = r->in.entry_handle;
897 if (eps == NULL || eps->e == NULL) {
898 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
899 goto done;
902 /* return the next N elements */
903 count = r->in.max_towers;
904 if (count > eps->count) {
905 count = eps->count;
908 if (count == 0) {
909 close_policy_hnd(p, entry_handle);
910 ZERO_STRUCTP(r->out.entry_handle);
912 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
913 goto done;
916 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
917 if (r->out.towers == NULL) {
918 rc = EPMAPPER_STATUS_NO_MEMORY;
919 goto done;
922 for (i = 0; i < count; i++) {
923 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
924 eps->e[i].name));
926 r->out.towers[num_towers].twr = talloc(r->out.towers,
927 struct epm_twr_t);
928 if (r->out.towers[num_towers].twr == NULL) {
929 rc = EPMAPPER_STATUS_NO_MEMORY;
930 goto done;
932 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
933 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
934 r->out.towers[num_towers].twr->tower_length = 0;
936 num_towers++;
939 *r->out.num_towers = num_towers;
941 eps->count -= count;
942 eps->e += count;
943 if (eps->count == 0) {
944 close_policy_hnd(p, entry_handle);
945 ZERO_STRUCTP(r->out.entry_handle);
948 rc = EPMAPPER_STATUS_OK;
949 done:
950 talloc_free(tmp_ctx);
952 return rc;
956 * epm_LookupHandleFree
958 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
959 struct epm_LookupHandleFree *r)
961 if (r->in.entry_handle == NULL) {
962 return EPMAPPER_STATUS_OK;
965 if (is_valid_policy_hnd(r->in.entry_handle)) {
966 close_policy_hnd(p, r->in.entry_handle);
969 r->out.entry_handle = r->in.entry_handle;
971 return EPMAPPER_STATUS_OK;
976 * epm_InqObject
978 * A client implementation SHOULD NOT call this method. These extensions do not
979 * provide an alternative method.
981 error_status_t _epm_InqObject(struct pipes_struct *p,
982 struct epm_InqObject *r)
984 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
985 return EPMAPPER_STATUS_CANT_PERFORM_OP;
990 * epm_MgmtDelete
992 * A client implementation SHOULD NOT call this method. These extensions do not
993 * provide an alternative method.
995 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
996 struct epm_MgmtDelete *r)
998 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
999 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1004 epm_MapAuth
1006 error_status_t _epm_MapAuth(struct pipes_struct *p,
1007 struct epm_MapAuth *r)
1009 p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1010 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1013 static NTSTATUS epmapper__op_shutdown_server(struct dcesrv_context *dce_ctx,
1014 const struct dcesrv_endpoint_server *ep_server);
1016 #define DCESRV_INTERFACE_EPMAPPER_SHUTDOWN_SERVER \
1017 epmapper_shutdown_server
1019 static NTSTATUS epmapper_shutdown_server(struct dcesrv_context *dce_ctx,
1020 const struct dcesrv_endpoint_server *ep_server)
1022 return epmapper__op_shutdown_server(dce_ctx, ep_server);
1025 static NTSTATUS epmapper__op_init_server(
1026 struct dcesrv_context *dce_ctx,
1027 const struct dcesrv_endpoint_server *ep_server);
1029 static NTSTATUS epmapper_init_server(
1030 struct dcesrv_context *dce_ctx,
1031 const struct dcesrv_endpoint_server *ep_server)
1033 char *epmdb_path = NULL;
1034 NTSTATUS status;
1036 epmdb_path = lock_path(dce_ctx, "epmdb.tdb");
1037 if (epmdb_path == NULL) {
1038 return NT_STATUS_NO_MEMORY;
1041 epmdb = tdb_wrap_open(
1042 dce_ctx,
1043 epmdb_path,
1045 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
1046 O_RDONLY,
1047 0644);
1048 if (epmdb == NULL) {
1049 DBG_DEBUG("Could not open epmdb.tdb: %s\n", strerror(errno));
1050 return map_nt_error_from_unix(errno);
1052 TALLOC_FREE(epmdb_path);
1054 status = epmapper__op_init_server(dce_ctx, ep_server);
1055 return status;
1058 #define DCESRV_INTERFACE_EPMAPPER_INIT_SERVER epmapper_init_server
1060 /* include the generated boilerplate */
1061 #include "librpc/gen_ndr/ndr_epmapper_scompat.c"
1063 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */