2 Unix SMB/CIFS implementation.
4 Endpoint server for the epmapper pipe
6 Copyright (C) 2010 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/>.
23 #include "librpc/gen_ndr/ndr_epmapper.h"
24 #include "librpc/gen_ndr/srv_epmapper.h"
26 typedef uint32_t error_status_t;
28 /* An endpoint combined with an interface description */
29 struct dcesrv_ep_iface {
34 /* A rpc service interface like samr, lsarpc or netlogon */
37 struct ndr_syntax_id syntax_id;
40 struct dcesrv_iface_list {
41 struct dcesrv_iface_list *next, *prev;
42 struct dcesrv_iface *iface;
46 * An endpoint can serve multiple rpc services interfaces.
47 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
49 struct dcesrv_endpoint {
50 struct dcesrv_endpoint *next, *prev;
52 /* The type and the location of the endpoint */
53 struct dcerpc_binding *ep_description;
55 /* A list of rpc services able to connect to the endpoint */
56 struct dcesrv_iface_list *iface_list;
59 struct dcesrv_endpoint *endpoint_table;
62 * Check if the UUID and if_version match to an interface.
64 static bool interface_match(const struct dcesrv_iface *if1,
65 const struct dcesrv_iface *if2)
67 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
71 * Find the interface operations on an endpoint.
73 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
74 const struct dcesrv_iface *iface)
76 struct dcesrv_iface_list *iflist;
78 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
79 if (interface_match(iflist->iface, iface)) {
88 * See if a uuid and if_version match to an interface
90 static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
91 const struct GUID *uuid)
93 return GUID_equal(&iface->syntax_id.uuid, uuid);
96 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
97 const struct dcesrv_iface *iface)
99 struct dcesrv_iface_list *iflist;
101 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
102 if (interface_match(iflist->iface, iface)) {
111 * Check if two endpoints match.
113 static bool endpoints_match(const struct dcerpc_binding *ep1,
114 const struct dcerpc_binding *ep2)
116 if (ep1->transport != ep2->transport) {
120 if (!ep1->endpoint || !ep2->endpoint) {
121 return ep1->endpoint == ep2->endpoint;
124 if (!strequal(ep1->endpoint, ep2->endpoint)) {
131 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
132 struct dcerpc_binding *ep_description) {
133 struct dcesrv_endpoint *ep;
135 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
136 if (endpoints_match(ep->ep_description, ep_description)) {
145 * Build a list of all interfaces handled by all endpoint servers.
147 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
148 struct dcesrv_endpoint *endpoint_list,
149 const struct GUID *uuid,
150 struct dcesrv_ep_iface **peps)
152 struct dcesrv_ep_iface *eps = NULL;
153 struct dcesrv_endpoint *d;
159 for (d = endpoint_list; d != NULL; d = d->next) {
160 struct dcesrv_iface_list *iface;
161 struct dcerpc_binding *description;
163 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
165 !interface_match_by_uuid(iface->iface, uuid)) {
169 eps = talloc_realloc(mem_ctx,
171 struct dcesrv_ep_iface,
176 eps[total].name = iface->iface->name;
178 description = d->ep_description;
179 description->object = iface->iface->syntax_id;
181 status = dcerpc_binding_build_tower(eps,
184 if (NT_STATUS_IS_ERR(status)) {
185 DEBUG(1, ("Unable to build tower for %s\n",
186 iface->iface->name));
201 * Add the specified entries to an endpoint map.
203 error_status_t _epm_Insert(struct pipes_struct *p,
204 struct epm_Insert *r)
211 tmp_ctx = talloc_stackframe();
212 if (tmp_ctx == NULL) {
213 return EPMAPPER_STATUS_NO_MEMORY;
216 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
219 /* TODO Check if we have a priviledged pipe/handle */
221 for (i = 0; i < r->in.num_ents; i++) {
222 struct dcerpc_binding *b = NULL;
223 struct dcesrv_endpoint *ep;
224 struct dcesrv_iface_list *iflist;
225 struct dcesrv_iface *iface;
228 status = dcerpc_binding_from_tower(tmp_ctx,
229 &r->in.entries[i].tower->tower,
231 if (!NT_STATUS_IS_OK(status)) {
232 rc = EPMAPPER_STATUS_NO_MEMORY;
236 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
237 derpc_transport_string_by_transport(b->transport),
238 r->in.entries[i].annotation));
240 /* Check if the entry already exits */
241 ep = find_endpoint(endpoint_table, b);
243 /* No entry found, create it */
244 ep = talloc_zero(NULL, struct dcesrv_endpoint);
246 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
251 ep->ep_description = talloc_steal(ep, b);
254 /* TODO Replace the entry if the replace flag is set */
256 /* Create an interface */
257 iface = talloc(tmp_ctx, struct dcesrv_iface);
259 rc = EPMAPPER_STATUS_NO_MEMORY;
263 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
264 if (iface->name == NULL) {
265 rc = EPMAPPER_STATUS_NO_MEMORY;
268 iface->syntax_id = b->object;
271 * Check if the rpc service is alrady registered on the
274 if (find_interface(ep, iface) != NULL) {
275 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
276 "already registered on endpoint\n",
278 /* FIXME wrong error code? */
279 rc = EPMAPPER_STATUS_OK;
283 /* Create an entry for the interface */
284 iflist = talloc(ep, struct dcesrv_iface_list);
285 if (iflist == NULL) {
286 rc = EPMAPPER_STATUS_NO_MEMORY;
289 iflist->iface = talloc_move(iflist, &iface);
291 /* Finally add the interface on the endpoint */
292 DLIST_ADD(ep->iface_list, iflist);
294 /* If it's a new endpoint add it to the endpoint_table */
296 DLIST_ADD(endpoint_table, ep);
300 rc = EPMAPPER_STATUS_OK;
302 talloc_free(tmp_ctx);
311 * Delete the specified entries from an endpoint map.
313 error_status_t _epm_Delete(struct pipes_struct *p,
314 struct epm_Delete *r)
321 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
324 tmp_ctx = talloc_stackframe();
325 if (tmp_ctx == NULL) {
326 return EPMAPPER_STATUS_NO_MEMORY;
329 /* TODO Check if we have a priviledged pipe/handle */
331 for (i = 0; i < r->in.num_ents; i++) {
332 struct dcerpc_binding *b = NULL;
333 struct dcesrv_endpoint *ep;
334 struct dcesrv_iface iface;
335 struct dcesrv_iface_list *iflist;
337 status = dcerpc_binding_from_tower(tmp_ctx,
338 &r->in.entries[i].tower->tower,
340 if (!NT_STATUS_IS_OK(status)) {
341 rc = EPMAPPER_STATUS_NO_MEMORY;
345 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
346 derpc_transport_string_by_transport(b->transport),
347 r->in.entries[i].annotation));
349 ep = find_endpoint(endpoint_table, b);
351 rc = EPMAPPER_STATUS_OK;
355 iface.name = r->in.entries[i].annotation;
356 iface.syntax_id = b->object;
358 iflist = find_interface_list(ep, &iface);
359 if (iflist == NULL) {
360 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
361 DLIST_REMOVE(endpoint_table, ep);
364 rc = EPMAPPER_STATUS_OK;
368 DLIST_REMOVE(ep->iface_list, iflist);
370 if (ep->iface_list == NULL) {
371 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
372 DLIST_REMOVE(endpoint_table, ep);
375 rc = EPMAPPER_STATUS_OK;
381 rc = EPMAPPER_STATUS_OK;
383 talloc_free(tmp_ctx);
392 error_status_t _epm_Lookup(struct pipes_struct *p,
393 struct epm_Lookup *r)
395 p->rng_fault_state = true;
396 return EPMAPPER_STATUS_CANT_PERFORM_OP;
402 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
403 * to produce a list of protocol towers.
405 error_status_t _epm_Map(struct pipes_struct *p,
408 enum dcerpc_transport_t transport;
409 struct ndr_syntax_id ndr_syntax;
410 struct dcesrv_ep_iface *eps;
411 struct epm_floor *floors;
414 count = build_ep_list(p->mem_ctx, endpoint_table, NULL, &eps);
416 ZERO_STRUCT(*r->out.entry_handle);
417 r->out.num_towers = talloc(p->mem_ctx, uint32_t);
418 if (r->out.num_towers == NULL) {
419 return EPMAPPER_STATUS_NO_MEMORY;
422 *r->out.num_towers = 1;
423 r->out.towers = talloc(p->mem_ctx, struct epm_twr_p_t);
424 if (r->out.towers == NULL) {
425 return EPMAPPER_STATUS_NO_MEMORY;
428 r->out.towers->twr = talloc(p->mem_ctx, struct epm_twr_t);
429 if (r->out.towers->twr == NULL) {
430 return EPMAPPER_STATUS_NO_MEMORY;
433 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
434 r->in.map_tower->tower.num_floors < 3) {
438 floors = r->in.map_tower->tower.floors;
440 dcerpc_floor_get_lhs_data(&r->in.map_tower->tower.floors[1], &ndr_syntax);
442 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
443 !GUID_equal(&ndr_syntax.uuid, &ndr_transfer_syntax.uuid) ||
444 ndr_syntax.if_version != ndr_transfer_syntax.if_version) {
448 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
449 if (transport == -1) {
450 DEBUG(2, ("epm_Insert: Client requested unknown transport with levels: "));
451 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
452 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
458 for (i = 0; i < count; i++) {
459 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
460 &eps[i].ep.floors[0].lhs.lhs_data) != 0 ||
461 transport != dcerpc_transport_by_tower(&eps[i].ep)) {
465 r->out.towers->twr->tower = eps[i].ep;
466 r->out.towers->twr->tower_length = 0;
468 return EPMAPPER_STATUS_OK;
472 *r->out.num_towers = 0;
473 r->out.towers->twr = NULL;
475 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
479 * epm_LookupHandleFree
481 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
482 struct epm_LookupHandleFree *r)
484 if (r->in.entry_handle == NULL) {
485 return EPMAPPER_STATUS_OK;
488 if (is_valid_policy_hnd(r->in.entry_handle)) {
489 close_policy_hnd(p, r->in.entry_handle);
492 r->out.entry_handle = r->in.entry_handle;
494 return EPMAPPER_STATUS_OK;
501 error_status_t _epm_InqObject(struct pipes_struct *p,
502 struct epm_InqObject *r)
504 p->rng_fault_state = true;
505 return EPMAPPER_STATUS_CANT_PERFORM_OP;
512 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
513 struct epm_MgmtDelete *r)
515 p->rng_fault_state = true;
516 return EPMAPPER_STATUS_CANT_PERFORM_OP;
523 error_status_t _epm_MapAuth(struct pipes_struct *p,
524 struct epm_MapAuth *r)
526 p->rng_fault_state = true;
527 return EPMAPPER_STATUS_CANT_PERFORM_OP;
530 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */