Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Endpoint server for the epmapper pipe
5 :
6 : Copyright (C) 2010-2011 Andreas Schneider <asn@samba.org>
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "ntdomain.h"
24 : #include "../libcli/security/security.h"
25 : #include "../lib/tsocket/tsocket.h"
26 : #include "auth.h"
27 :
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"
35 :
36 : static struct tdb_wrap *epmdb = NULL;
37 :
38 : /* handle types for this module */
39 : enum handle_types {HTYPE_LOOKUP};
40 :
41 : typedef uint32_t error_status_t;
42 :
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;
48 : };
49 :
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;
54 : };
55 :
56 : struct dcesrv_iface_list {
57 : struct dcesrv_iface_list *next, *prev;
58 : struct dcesrv_iface *iface;
59 : };
60 :
61 : /*
62 : * An endpoint can serve multiple rpc services interfaces.
63 : * For example \\pipe\netlogon can be used by lsarpc and netlogon.
64 : */
65 : struct dcesrv_epm_endpoint {
66 : struct dcesrv_epm_endpoint *next, *prev;
67 :
68 : /* The type and the location of the endpoint */
69 : struct dcerpc_binding *ep_description;
70 :
71 : /* A list of rpc services able to connect to the endpoint */
72 : struct dcesrv_iface_list *iface_list;
73 : };
74 :
75 : struct rpc_eps {
76 : struct dcesrv_ep_iface *e;
77 : uint32_t count;
78 : };
79 :
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;
85 : };
86 :
87 352 : 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)
94 : {
95 352 : struct dcesrv_ep_iface iface = {
96 : .syntax_id = *syntax_id,
97 : };
98 352 : struct dcerpc_binding *binding = NULL;
99 0 : enum dcerpc_transport_t transport;
100 352 : char *name_dup = NULL;
101 352 : const char *host_addr = NULL;
102 0 : NTSTATUS status;
103 :
104 : /* copy without const for error path TALLOC_FREE */
105 352 : name_dup = talloc_strdup(mem_ctx, name);
106 352 : if (name_dup == NULL) {
107 0 : goto fail;
108 : }
109 352 : iface.name = name_dup;
110 :
111 352 : status = dcerpc_parse_binding(mem_ctx, endpoint, &binding);
112 352 : if (!NT_STATUS_IS_OK(status)) {
113 0 : DBG_DEBUG("dcerpc_parse_binding failed: %s\n",
114 : nt_errstr(status));
115 0 : goto fail;
116 : }
117 :
118 352 : status = dcerpc_binding_set_abstract_syntax(binding, syntax_id);
119 352 : if (!NT_STATUS_IS_OK(status)) {
120 0 : DBG_DEBUG("dcerpc_binding_set_abstract_syntax failed: %s\n",
121 : nt_errstr(status));
122 0 : goto fail;
123 : }
124 :
125 352 : transport = dcerpc_binding_get_transport(binding);
126 352 : if (transport == NCACN_IP_TCP) {
127 80 : const char *host = NULL;
128 :
129 80 : host = dcerpc_binding_get_string_option(binding, "host");
130 80 : if (host == NULL) {
131 80 : host_addr = srv_addr;
132 0 : } else if (!is_ipaddress_v4(host)) {
133 0 : host_addr = srv_addr;
134 0 : } else if (strcmp(host, "0.0.0.0") == 0) {
135 0 : host_addr = srv_addr;
136 : }
137 : }
138 :
139 352 : if (host_addr != NULL) {
140 20 : status = dcerpc_binding_set_string_option(
141 : binding, "host", host_addr);
142 20 : if (!NT_STATUS_IS_OK(status)) {
143 0 : DBG_DEBUG("dcerpc_binding_set_string_option "
144 : "failed: %s\n",
145 : nt_errstr(status));
146 0 : goto fail;
147 : }
148 : }
149 :
150 352 : status = dcerpc_binding_build_tower(mem_ctx, binding, &iface.ep);
151 352 : TALLOC_FREE(binding);
152 352 : if (!NT_STATUS_IS_OK(status)) {
153 0 : DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
154 : nt_errstr(status));
155 0 : goto fail;
156 : }
157 :
158 352 : *dst = iface;
159 352 : return true;
160 :
161 0 : fail:
162 0 : TALLOC_FREE(binding);
163 0 : TALLOC_FREE(name_dup);
164 0 : TALLOC_FREE(iface.ep.floors);
165 0 : return false;
166 : }
167 :
168 136 : static int build_ep_list_fn(
169 : struct tdb_context *tdb,
170 : TDB_DATA key,
171 : TDB_DATA value,
172 : void *private_data)
173 : {
174 136 : struct build_ep_list_state *state = private_data;
175 136 : struct ndr_syntax_id syntax_id = { .if_version = 0 };
176 136 : const char *name = NULL;
177 136 : char *endpoints = NULL;
178 136 : const char *endpoint = NULL;
179 0 : bool ok;
180 :
181 136 : if ((key.dsize == 0) || (key.dptr[key.dsize-1] != '\0') ||
182 136 : (value.dsize == 0) || (value.dptr[value.dsize-1] != '\0')) {
183 0 : DBG_DEBUG("Invalid record\n");
184 0 : return 0;
185 : }
186 :
187 136 : ok = ndr_syntax_id_from_string((char *)key.dptr, &syntax_id);
188 136 : if (!ok) {
189 0 : DBG_DEBUG("Invalid interface: %s\n", (char *)key.dptr);
190 0 : return 0;
191 : }
192 :
193 136 : endpoints = (char *)value.dptr;
194 136 : endpoint = endpoints;
195 136 : name = endpoints;
196 :
197 488 : while ((endpoint = strv_len_next(endpoints, value.dsize, endpoint))) {
198 352 : size_t num_ifaces = talloc_array_length(state->ifaces);
199 352 : struct dcesrv_ep_iface *tmp = NULL;
200 :
201 352 : if (num_ifaces+1 < num_ifaces) {
202 0 : return 1;
203 : }
204 :
205 352 : tmp = talloc_realloc(
206 : state->mem_ctx,
207 : state->ifaces,
208 : struct dcesrv_ep_iface,
209 : num_ifaces+1);
210 352 : if (tmp == NULL) {
211 0 : return 1;
212 : }
213 352 : state->ifaces = tmp;
214 :
215 352 : ok = build_ep_list_fill_iface(
216 352 : state->ifaces,
217 : &syntax_id,
218 : endpoint,
219 : name,
220 : state->srv_addr,
221 352 : &state->ifaces[num_ifaces]);
222 352 : if (!ok) {
223 0 : state->ifaces = talloc_realloc(
224 : state->mem_ctx,
225 : state->ifaces,
226 : struct dcesrv_ep_iface,
227 : num_ifaces);
228 : }
229 : }
230 :
231 136 : return 0;
232 : }
233 :
234 : /*
235 : * Build a list of all interfaces handled by all endpoint servers.
236 : */
237 8 : 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)
241 : {
242 8 : struct build_ep_list_state state = {
243 : .mem_ctx = mem_ctx, .uuid = uuid, .srv_addr = srv_addr,
244 : };
245 0 : int ret;
246 :
247 8 : ret = tdb_traverse_read(epmdb->tdb, build_ep_list_fn, &state);
248 8 : if (ret == -1) {
249 0 : DBG_DEBUG("tdb_traverse_read failed\n");
250 0 : return 0;
251 : }
252 :
253 8 : *peps = state.ifaces;
254 8 : return talloc_array_length(*peps);
255 : }
256 :
257 : /*
258 : * epm_Insert
259 : *
260 : * Add the specified entries to an endpoint map.
261 : */
262 4 : error_status_t _epm_Insert(struct pipes_struct *p,
263 : struct epm_Insert *r)
264 : {
265 4 : p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
266 4 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
267 : }
268 :
269 : /*
270 : * epm_Delete
271 : *
272 : * Delete the specified entries from an endpoint map.
273 : */
274 0 : error_status_t _epm_Delete(struct pipes_struct *p,
275 : struct epm_Delete *r)
276 : {
277 0 : p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
278 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
279 : }
280 :
281 : /*
282 : * epm_Lookup
283 : *
284 : * Lookup entries in an endpoint map.
285 : */
286 28 : error_status_t _epm_Lookup(struct pipes_struct *p,
287 : struct epm_Lookup *r)
288 : {
289 28 : struct dcesrv_call_state *dce_call = p->dce_call;
290 28 : struct dcesrv_connection *dcesrv_conn = dce_call->conn;
291 0 : struct policy_handle *entry_handle;
292 0 : struct rpc_eps *eps;
293 0 : TALLOC_CTX *tmp_ctx;
294 0 : error_status_t rc;
295 28 : uint32_t count = 0;
296 28 : uint32_t num_ents = 0;
297 0 : uint32_t i;
298 28 : bool match = false;
299 0 : bool ok;
300 0 : NTSTATUS status;
301 :
302 28 : *r->out.num_ents = 0;
303 28 : r->out.entries = NULL;
304 :
305 28 : tmp_ctx = talloc_stackframe();
306 28 : if (tmp_ctx == NULL) {
307 0 : return EPMAPPER_STATUS_NO_MEMORY;
308 : }
309 :
310 28 : DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
311 : r->in.max_ents));
312 :
313 56 : if (r->in.entry_handle == NULL ||
314 28 : ndr_policy_handle_empty(r->in.entry_handle)) {
315 0 : const struct tsocket_address *local_address =
316 8 : dcesrv_connection_get_local_address(dcesrv_conn);
317 8 : char *srv_addr = NULL;
318 :
319 8 : DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
320 :
321 8 : eps = talloc_zero(tmp_ctx, struct rpc_eps);
322 8 : if (eps == NULL) {
323 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
324 0 : goto done;
325 : }
326 :
327 16 : if (local_address != NULL &&
328 8 : tsocket_address_is_inet(local_address, "ipv4"))
329 : {
330 2 : srv_addr = tsocket_address_inet_addr_string(
331 : local_address, tmp_ctx);
332 : }
333 :
334 8 : switch (r->in.inquiry_type) {
335 8 : case RPC_C_EP_ALL_ELTS:
336 : /*
337 : * Return all elements from the endpoint map. The
338 : * interface_id, vers_option, and object parameters MUST
339 : * be ignored.
340 : */
341 8 : eps->count = build_ep_list(eps,
342 : NULL,
343 : srv_addr,
344 : &eps->e);
345 8 : break;
346 0 : case RPC_C_EP_MATCH_BY_IF:
347 : /*
348 : * Return endpoint map elements that contain the
349 : * interface identifier specified by the interface_id
350 : * and vers_option values.
351 : *
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.
356 : */
357 : case RPC_C_EP_MATCH_BY_BOTH:
358 : /*
359 : * Return endpoint map elements that contain the
360 : * interface identifier and object UUID specified by
361 : * interface_id, vers_option, and object.
362 : */
363 0 : eps->count = build_ep_list(eps,
364 0 : &r->in.interface_id->uuid,
365 : srv_addr,
366 : &eps->e);
367 0 : break;
368 0 : case RPC_C_EP_MATCH_BY_OBJ:
369 : /*
370 : * Return endpoint map elements that contain the object
371 : * UUID specified by object.
372 : */
373 0 : eps->count = build_ep_list(eps,
374 0 : r->in.object,
375 : srv_addr,
376 : &eps->e);
377 0 : break;
378 0 : default:
379 0 : rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
380 0 : goto done;
381 : }
382 :
383 8 : if (eps->count == 0) {
384 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
385 0 : goto done;
386 : }
387 :
388 8 : ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
389 8 : if (!ok) {
390 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
391 0 : goto done;
392 : }
393 :
394 8 : eps = find_policy_by_hnd(p,
395 : r->out.entry_handle,
396 : HTYPE_LOOKUP,
397 : struct rpc_eps,
398 0 : &status);
399 8 : if (!NT_STATUS_IS_OK(status)) {
400 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
401 0 : goto done;
402 : }
403 8 : entry_handle = r->out.entry_handle;
404 : } else {
405 20 : DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
406 :
407 20 : eps = find_policy_by_hnd(p,
408 : r->in.entry_handle,
409 : HTYPE_LOOKUP,
410 : struct rpc_eps,
411 0 : &status);
412 20 : if (!NT_STATUS_IS_OK(status)) {
413 2 : rc = EPMAPPER_STATUS_NO_MEMORY;
414 2 : goto done;
415 : }
416 18 : entry_handle = r->in.entry_handle;
417 : }
418 :
419 26 : if (eps == NULL || eps->e == NULL) {
420 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
421 0 : goto done;
422 : }
423 :
424 : /* return the next N elements */
425 26 : count = r->in.max_ents;
426 26 : if (count > eps->count) {
427 4 : count = eps->count;
428 : }
429 :
430 26 : DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
431 :
432 26 : if (count == 0) {
433 0 : close_policy_hnd(p, entry_handle);
434 0 : ZERO_STRUCTP(r->out.entry_handle);
435 :
436 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
437 0 : goto done;
438 : }
439 :
440 26 : r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
441 26 : if (r->out.entries == NULL) {
442 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
443 0 : goto done;
444 : }
445 :
446 210 : for (i = 0; i < count; i++) {
447 184 : match = false;
448 :
449 184 : switch (r->in.inquiry_type) {
450 184 : case RPC_C_EP_ALL_ELTS:
451 : /*
452 : * Return all elements from the endpoint map. The
453 : * interface_id, vers_option, and object parameters MUST
454 : * be ignored.
455 : */
456 184 : match = true;
457 184 : break;
458 0 : case RPC_C_EP_MATCH_BY_IF:
459 : /*
460 : * Return endpoint map elements that contain the
461 : * interface identifier specified by the interface_id
462 : * and vers_option values.
463 : */
464 0 : if (GUID_equal(&r->in.interface_id->uuid,
465 0 : &eps->e[i].syntax_id.uuid)) {
466 0 : match = true;
467 : }
468 0 : break;
469 0 : case RPC_C_EP_MATCH_BY_OBJ:
470 : /*
471 : * Return endpoint map elements that contain the object
472 : * UUID specified by object.
473 : */
474 0 : if (GUID_equal(r->in.object,
475 0 : &eps->e[i].syntax_id.uuid)) {
476 0 : match = true;
477 : }
478 0 : break;
479 0 : case RPC_C_EP_MATCH_BY_BOTH:
480 : /*
481 : * Return endpoint map elements that contain the
482 : * interface identifier and object UUID specified by
483 : * interface_id, vers_option, and object.
484 : */
485 0 : if (GUID_equal(&r->in.interface_id->uuid,
486 0 : &eps->e[i].syntax_id.uuid) &&
487 0 : GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
488 0 : match = true;
489 : }
490 0 : break;
491 0 : default:
492 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
493 : }
494 :
495 184 : if (match) {
496 184 : if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
497 184 : r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
498 : /* Check interface version */
499 :
500 0 : match = false;
501 0 : switch (r->in.vers_option) {
502 0 : case RPC_C_VERS_ALL:
503 : /*
504 : * Return endpoint map elements that
505 : * contain the specified interface UUID,
506 : * regardless of the version numbers.
507 : */
508 0 : match = true;
509 0 : break;
510 0 : case RPC_C_VERS_COMPATIBLE:
511 : /*
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.
518 : */
519 0 : if (r->in.interface_id->vers_major ==
520 0 : (eps->e[i].syntax_id.if_version >> 16) &&
521 0 : r->in.interface_id->vers_minor <=
522 0 : (eps->e[i].syntax_id.if_version & 0xFFFF)) {
523 0 : match = true;
524 : }
525 0 : break;
526 0 : case RPC_C_VERS_EXACT:
527 : /*
528 : * Return endpoint map elements that
529 : * contain the specified version of the
530 : * specified interface UUID.
531 : */
532 0 : if (r->in.interface_id->vers_major ==
533 0 : (eps->e[i].syntax_id.if_version >> 16) &&
534 0 : r->in.interface_id->vers_minor ==
535 0 : (eps->e[i].syntax_id.if_version & 0xFFFF)) {
536 0 : match = true;
537 : }
538 0 : match = true;
539 0 : break;
540 0 : case RPC_C_VERS_MAJOR_ONLY:
541 : /*
542 : * Return endpoint map elements that
543 : * contain the same version of the
544 : * specified interface UUID and ignore
545 : * the minor version.
546 : */
547 0 : if (r->in.interface_id->vers_major ==
548 0 : (eps->e[i].syntax_id.if_version >> 16)) {
549 0 : match = true;
550 : }
551 0 : match = true;
552 0 : break;
553 0 : case RPC_C_VERS_UPTO:
554 : /*
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.
560 : */
561 0 : if (r->in.interface_id->vers_major >
562 0 : eps->e[i].syntax_id.if_version >> 16) {
563 0 : match = true;
564 : } else {
565 0 : if (r->in.interface_id->vers_major ==
566 0 : (eps->e[i].syntax_id.if_version >> 16) &&
567 0 : r->in.interface_id->vers_minor >=
568 0 : (eps->e[i].syntax_id.if_version & 0xFFFF)) {
569 0 : match = true;
570 : }
571 : }
572 0 : break;
573 0 : default:
574 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
575 : }
576 : }
577 : }
578 :
579 184 : if (match) {
580 184 : ZERO_STRUCT(r->out.entries[num_ents].object);
581 :
582 184 : DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
583 : eps->e[i].name));
584 368 : r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
585 184 : eps->e[i].name);
586 184 : r->out.entries[num_ents].tower = talloc(r->out.entries,
587 : struct epm_twr_t);
588 184 : if (r->out.entries[num_ents].tower == NULL) {
589 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
590 0 : goto done;
591 : }
592 184 : r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
593 184 : r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
594 184 : r->out.entries[num_ents].tower->tower_length = 0;
595 :
596 184 : num_ents++;
597 : }
598 : } /* end for loop */
599 :
600 26 : *r->out.num_ents = num_ents;
601 :
602 26 : eps->count -= count;
603 26 : eps->e += count;
604 26 : if (eps->count == 0) {
605 4 : close_policy_hnd(p, entry_handle);
606 4 : ZERO_STRUCTP(r->out.entry_handle);
607 4 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
608 4 : goto done;
609 : }
610 :
611 22 : rc = EPMAPPER_STATUS_OK;
612 28 : done:
613 28 : talloc_free(tmp_ctx);
614 :
615 28 : return rc;
616 : }
617 :
618 720 : 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)
623 : {
624 0 : struct ndr_syntax_id_buf idbuf;
625 720 : char *iface_string = ndr_syntax_id_buf_string(iface, &idbuf);
626 720 : struct rpc_eps *eps = NULL;
627 720 : uint8_t *buf = NULL;
628 0 : size_t buflen;
629 720 : char *bindings = NULL;
630 720 : char *binding = NULL;
631 720 : char *name = NULL;
632 0 : NTSTATUS status;
633 0 : int ret;
634 :
635 720 : DBG_DEBUG("Mapping interface %s\n", iface_string);
636 :
637 720 : eps = talloc_zero(mem_ctx, struct rpc_eps);
638 720 : if (eps == NULL) {
639 0 : goto fail;
640 : }
641 :
642 720 : ret = tdb_fetch_talloc(
643 720 : epmdb->tdb, string_term_tdb_data(iface_string), eps, &buf);
644 720 : if (ret != 0) {
645 48 : DBG_DEBUG("Could not find epm entry for %s: %s\n",
646 : iface_string,
647 : strerror(ret));
648 48 : goto fail;
649 : }
650 672 : buflen = talloc_array_length(buf);
651 :
652 672 : if ((buflen < 1) || (buf[buflen-1] != '\0')) {
653 0 : DBG_DEBUG("epm entry for %s invalid\n", iface_string);
654 0 : goto fail;
655 : }
656 672 : bindings = (char *)buf;
657 :
658 672 : name = bindings; /* name comes first */
659 672 : binding = name; /* strv_next will skip name */
660 :
661 3046 : while ((binding = strv_next(bindings, binding)) != NULL) {
662 2374 : struct dcerpc_binding *b = NULL;
663 0 : enum dcerpc_transport_t found_transport;
664 2374 : struct dcesrv_ep_iface *tmp = NULL, *new_ep = NULL;
665 :
666 2374 : DBG_DEBUG("Found %s for %s\n", binding, name);
667 :
668 2374 : status = dcerpc_parse_binding(mem_ctx, binding, &b);
669 2374 : if (!NT_STATUS_IS_OK(status)) {
670 0 : DBG_DEBUG("dcerpc_parse_binding() for %s failed: %s\n",
671 : binding,
672 : nt_errstr(status));
673 0 : goto fail;
674 : }
675 :
676 2374 : found_transport = dcerpc_binding_get_transport(b);
677 2374 : if (found_transport != transport) {
678 1568 : DBG_DEBUG("Transport %d does not match %d\n",
679 : (int)found_transport,
680 : (int)transport);
681 1568 : TALLOC_FREE(b);
682 1568 : continue;
683 : }
684 :
685 806 : if (found_transport == NCACN_IP_TCP) {
686 210 : status = dcerpc_binding_set_string_option(
687 : b, "host", local_address);
688 210 : if (!NT_STATUS_IS_OK(status)) {
689 0 : DBG_DEBUG("Could not set host: %s\n",
690 : nt_errstr(status));
691 0 : goto fail;
692 : }
693 : }
694 :
695 806 : status = dcerpc_binding_set_abstract_syntax(b, iface);
696 806 : if (!NT_STATUS_IS_OK(status)) {
697 0 : DBG_DEBUG("Could not set abstract syntax: %s\n",
698 : nt_errstr(status));
699 0 : goto fail;
700 : }
701 :
702 806 : tmp = talloc_realloc(
703 : eps,
704 : eps->e,
705 : struct dcesrv_ep_iface,
706 : eps->count+1);
707 806 : if (tmp == NULL) {
708 0 : goto fail;
709 : }
710 806 : eps->e = tmp;
711 :
712 806 : new_ep = &eps->e[eps->count];
713 :
714 806 : new_ep->name = talloc_strdup(eps->e, name);
715 806 : if (new_ep->name == NULL) {
716 0 : goto fail;
717 : }
718 806 : new_ep->syntax_id = *iface;
719 :
720 806 : status = dcerpc_binding_build_tower(eps->e, b, &new_ep->ep);
721 806 : if (!NT_STATUS_IS_OK(status)) {
722 0 : DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
723 : nt_errstr(status));
724 0 : goto fail;
725 : }
726 :
727 806 : eps->count += 1;
728 :
729 806 : TALLOC_FREE(b);
730 : }
731 672 : return eps;
732 :
733 48 : fail:
734 48 : TALLOC_FREE(eps);
735 48 : return NULL;
736 : }
737 :
738 : /*
739 : * epm_Map
740 : *
741 : * Apply some algorithm (using the fields in the map_tower) to an endpoint map
742 : * to produce a list of protocol towers.
743 : */
744 720 : error_status_t _epm_Map(struct pipes_struct *p,
745 : struct epm_Map *r)
746 : {
747 720 : struct dcesrv_call_state *dce_call = p->dce_call;
748 720 : struct dcesrv_connection *dcesrv_conn = dce_call->conn;
749 0 : struct policy_handle *entry_handle;
750 0 : enum dcerpc_transport_t transport;
751 0 : struct ndr_syntax_id ifid;
752 0 : struct epm_floor *floors;
753 0 : struct rpc_eps *eps;
754 0 : TALLOC_CTX *tmp_ctx;
755 0 : error_status_t rc;
756 720 : uint32_t count = 0;
757 720 : uint32_t num_towers = 0;
758 0 : uint32_t i;
759 0 : bool ok;
760 0 : NTSTATUS status;
761 :
762 720 : *r->out.num_towers = 0;
763 720 : r->out.towers = NULL;
764 :
765 720 : if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
766 720 : r->in.map_tower->tower.num_floors < 3) {
767 0 : return EPMAPPER_STATUS_NO_MORE_ENTRIES;
768 : }
769 :
770 720 : tmp_ctx = talloc_stackframe();
771 :
772 720 : ZERO_STRUCTP(r->out.entry_handle);
773 :
774 720 : DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
775 : r->in.max_towers));
776 :
777 : /*
778 : * A tower has normally up to 6 floors
779 : *
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 : * +---------+-------------------------------------------------------+
794 : */
795 720 : floors = r->in.map_tower->tower.floors;
796 :
797 : /* We accept NDR as the transfer syntax */
798 720 : status = dcerpc_floor_get_uuid_full(&floors[1], &ifid);
799 720 : if (!NT_STATUS_IS_OK(status)) {
800 0 : DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
801 : nt_errstr(status));
802 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
803 0 : goto done;
804 : }
805 :
806 720 : if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
807 720 : !ndr_syntax_id_equal(&ifid, &ndr_transfer_syntax_ndr)) {
808 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
809 0 : goto done;
810 : }
811 :
812 : /* We only talk to sane transports */
813 720 : transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
814 720 : if (transport == NCA_UNKNOWN) {
815 0 : DEBUG(2, ("epm_Map: Client requested unknown transport with "
816 : "levels: "));
817 0 : for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
818 0 : DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
819 : }
820 0 : DEBUG(2, ("\n"));
821 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
822 0 : goto done;
823 : }
824 :
825 1440 : if (r->in.entry_handle == NULL ||
826 720 : ndr_policy_handle_empty(r->in.entry_handle)) {
827 0 : const struct tsocket_address *local_addr =
828 720 : dcesrv_connection_get_local_address(dcesrv_conn);
829 720 : char *local_address = NULL;
830 0 : struct ndr_syntax_id_buf buf;
831 720 : char *if_string = NULL;
832 :
833 720 : DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
834 :
835 720 : status = dcerpc_floor_get_uuid_full(&floors[0], &ifid);
836 720 : if (!NT_STATUS_IS_OK(status)) {
837 0 : DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
838 : nt_errstr(status));
839 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
840 48 : goto done;
841 : }
842 :
843 720 : if_string = ndr_syntax_id_buf_string(&ifid, &buf);
844 :
845 720 : DBG_INFO("Mapping interface %s\n", if_string);
846 :
847 978 : if ((transport == NCACN_IP_TCP) &&
848 258 : tsocket_address_is_inet(local_addr, "ip")) {
849 : /*
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.
853 : */
854 182 : local_address = tsocket_address_inet_addr_string(
855 : local_addr, tmp_ctx);
856 : }
857 :
858 720 : eps = epm_map_get_towers(
859 : tmp_ctx, &ifid, transport, local_address);
860 720 : if (eps == NULL) {
861 48 : DBG_DEBUG("No bindings found\n");
862 48 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
863 48 : goto done;
864 : }
865 :
866 672 : ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
867 672 : if (!ok) {
868 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
869 0 : goto done;
870 : }
871 :
872 672 : eps = find_policy_by_hnd(p,
873 : r->out.entry_handle,
874 : HTYPE_LOOKUP,
875 : struct rpc_eps,
876 0 : &status);
877 672 : if (!NT_STATUS_IS_OK(status)) {
878 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
879 0 : goto done;
880 : }
881 672 : entry_handle = r->out.entry_handle;
882 : } else {
883 0 : DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
884 :
885 0 : eps = find_policy_by_hnd(p,
886 : r->in.entry_handle,
887 : HTYPE_LOOKUP,
888 : struct rpc_eps,
889 0 : &status);
890 0 : if (!NT_STATUS_IS_OK(status)) {
891 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
892 0 : goto done;
893 : }
894 0 : entry_handle = r->in.entry_handle;
895 : }
896 :
897 672 : if (eps == NULL || eps->e == NULL) {
898 126 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
899 126 : goto done;
900 : }
901 :
902 : /* return the next N elements */
903 546 : count = r->in.max_towers;
904 546 : if (count > eps->count) {
905 396 : count = eps->count;
906 : }
907 :
908 546 : if (count == 0) {
909 0 : close_policy_hnd(p, entry_handle);
910 0 : ZERO_STRUCTP(r->out.entry_handle);
911 :
912 0 : rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
913 0 : goto done;
914 : }
915 :
916 546 : r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
917 546 : if (r->out.towers == NULL) {
918 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
919 0 : goto done;
920 : }
921 :
922 1352 : for (i = 0; i < count; i++) {
923 806 : DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
924 : eps->e[i].name));
925 :
926 806 : r->out.towers[num_towers].twr = talloc(r->out.towers,
927 : struct epm_twr_t);
928 806 : if (r->out.towers[num_towers].twr == NULL) {
929 0 : rc = EPMAPPER_STATUS_NO_MEMORY;
930 0 : goto done;
931 : }
932 806 : r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
933 806 : r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
934 806 : r->out.towers[num_towers].twr->tower_length = 0;
935 :
936 806 : num_towers++;
937 : }
938 :
939 546 : *r->out.num_towers = num_towers;
940 :
941 546 : eps->count -= count;
942 546 : eps->e += count;
943 546 : if (eps->count == 0) {
944 546 : close_policy_hnd(p, entry_handle);
945 546 : ZERO_STRUCTP(r->out.entry_handle);
946 : }
947 :
948 546 : rc = EPMAPPER_STATUS_OK;
949 720 : done:
950 720 : talloc_free(tmp_ctx);
951 :
952 720 : return rc;
953 : }
954 :
955 : /*
956 : * epm_LookupHandleFree
957 : */
958 4 : error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
959 : struct epm_LookupHandleFree *r)
960 : {
961 4 : if (r->in.entry_handle == NULL) {
962 0 : return EPMAPPER_STATUS_OK;
963 : }
964 :
965 4 : if (is_valid_policy_hnd(r->in.entry_handle)) {
966 4 : close_policy_hnd(p, r->in.entry_handle);
967 : }
968 :
969 4 : r->out.entry_handle = r->in.entry_handle;
970 :
971 4 : return EPMAPPER_STATUS_OK;
972 : }
973 :
974 :
975 : /*
976 : * epm_InqObject
977 : *
978 : * A client implementation SHOULD NOT call this method. These extensions do not
979 : * provide an alternative method.
980 : */
981 0 : error_status_t _epm_InqObject(struct pipes_struct *p,
982 : struct epm_InqObject *r)
983 : {
984 0 : p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
985 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
986 : }
987 :
988 :
989 : /*
990 : * epm_MgmtDelete
991 : *
992 : * A client implementation SHOULD NOT call this method. These extensions do not
993 : * provide an alternative method.
994 : */
995 0 : error_status_t _epm_MgmtDelete(struct pipes_struct *p,
996 : struct epm_MgmtDelete *r)
997 : {
998 0 : p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
999 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
1000 : }
1001 :
1002 :
1003 : /*
1004 : epm_MapAuth
1005 : */
1006 0 : error_status_t _epm_MapAuth(struct pipes_struct *p,
1007 : struct epm_MapAuth *r)
1008 : {
1009 0 : p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
1010 0 : return EPMAPPER_STATUS_CANT_PERFORM_OP;
1011 : }
1012 :
1013 : static NTSTATUS epmapper__op_shutdown_server(struct dcesrv_context *dce_ctx,
1014 : const struct dcesrv_endpoint_server *ep_server);
1015 :
1016 : #define DCESRV_INTERFACE_EPMAPPER_SHUTDOWN_SERVER \
1017 : epmapper_shutdown_server
1018 :
1019 30 : static NTSTATUS epmapper_shutdown_server(struct dcesrv_context *dce_ctx,
1020 : const struct dcesrv_endpoint_server *ep_server)
1021 : {
1022 30 : return epmapper__op_shutdown_server(dce_ctx, ep_server);
1023 : }
1024 :
1025 : static NTSTATUS epmapper__op_init_server(
1026 : struct dcesrv_context *dce_ctx,
1027 : const struct dcesrv_endpoint_server *ep_server);
1028 :
1029 30 : static NTSTATUS epmapper_init_server(
1030 : struct dcesrv_context *dce_ctx,
1031 : const struct dcesrv_endpoint_server *ep_server)
1032 : {
1033 30 : char *epmdb_path = NULL;
1034 0 : NTSTATUS status;
1035 :
1036 30 : epmdb_path = lock_path(dce_ctx, "epmdb.tdb");
1037 30 : if (epmdb_path == NULL) {
1038 0 : return NT_STATUS_NO_MEMORY;
1039 : }
1040 :
1041 30 : epmdb = tdb_wrap_open(
1042 : dce_ctx,
1043 : epmdb_path,
1044 : 0,
1045 : TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
1046 : O_RDONLY,
1047 : 0644);
1048 30 : if (epmdb == NULL) {
1049 0 : DBG_DEBUG("Could not open epmdb.tdb: %s\n", strerror(errno));
1050 0 : return map_nt_error_from_unix(errno);
1051 : }
1052 30 : TALLOC_FREE(epmdb_path);
1053 :
1054 30 : status = epmapper__op_init_server(dce_ctx, ep_server);
1055 30 : return status;
1056 : }
1057 :
1058 : #define DCESRV_INTERFACE_EPMAPPER_INIT_SERVER epmapper_init_server
1059 :
1060 : /* include the generated boilerplate */
1061 : #include "librpc/gen_ndr/ndr_epmapper_scompat.c"
1062 :
1063 : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
|