source: vendor/current/source3/rpc_server/epmapper/srv_epmapper.c@ 740

Last change on this file since 740 was 740, checked in by Silvan Scherrer, 12 years ago

Samba Server: update vendor to 3.6.0

File size: 28.2 KB
Line 
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 "librpc/gen_ndr/srv_epmapper.h"
26#include "srv_epmapper.h"
27#include "auth.h"
28
29typedef uint32_t error_status_t;
30
31/* An endpoint combined with an interface description */
32struct dcesrv_ep_iface {
33 const char *name;
34 struct ndr_syntax_id syntax_id;
35 struct epm_tower ep;
36};
37
38/* A rpc service interface like samr, lsarpc or netlogon */
39struct dcesrv_iface {
40 const char *name;
41 struct ndr_syntax_id syntax_id;
42};
43
44struct dcesrv_iface_list {
45 struct dcesrv_iface_list *next, *prev;
46 struct dcesrv_iface *iface;
47};
48
49/*
50 * An endpoint can serve multiple rpc services interfaces.
51 * For example \\pipe\netlogon can be used by lsarpc and netlogon.
52 */
53struct dcesrv_endpoint {
54 struct dcesrv_endpoint *next, *prev;
55
56 /* The type and the location of the endpoint */
57 struct dcerpc_binding *ep_description;
58
59 /* A list of rpc services able to connect to the endpoint */
60 struct dcesrv_iface_list *iface_list;
61};
62
63struct dcesrv_ep_entry_list {
64 struct dcesrv_ep_entry_list *next, *prev;
65
66 uint32_t num_ents;
67 struct epm_entry_t *entries;
68};
69
70struct rpc_eps {
71 struct dcesrv_ep_iface *e;
72 uint32_t count;
73};
74
75static struct dcesrv_endpoint *endpoint_table;
76
77/*
78 * Check if the UUID and if_version match to an interface.
79 */
80static bool interface_match(const struct dcesrv_iface *if1,
81 const struct dcesrv_iface *if2)
82{
83 return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
84}
85
86/*
87 * Find the interface operations on an endpoint.
88 */
89static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
90 const struct dcesrv_iface *iface)
91{
92 struct dcesrv_iface_list *iflist;
93
94 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
95 if (interface_match(iflist->iface, iface)) {
96 return iflist->iface;
97 }
98 }
99
100 return NULL;
101}
102
103/*
104 * See if a uuid and if_version match to an interface
105 */
106static bool interface_match_by_uuid(const struct dcesrv_iface *iface,
107 const struct GUID *uuid)
108{
109 return GUID_equal(&iface->syntax_id.uuid, uuid);
110}
111
112static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
113 const struct dcesrv_iface *iface)
114{
115 struct dcesrv_iface_list *iflist;
116
117 for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
118 if (interface_match(iflist->iface, iface)) {
119 return iflist;
120 }
121 }
122
123 return NULL;
124}
125
126/*
127 * Check if two endpoints match.
128 */
129static bool endpoints_match(const struct dcerpc_binding *ep1,
130 const struct dcerpc_binding *ep2)
131{
132 if (ep1->transport != ep2->transport) {
133 return false;
134 }
135
136 if (!ep1->endpoint || !ep2->endpoint) {
137 return ep1->endpoint == ep2->endpoint;
138 }
139
140 if (!strequal(ep1->endpoint, ep2->endpoint)) {
141 return false;
142 }
143
144 return true;
145}
146
147static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
148 struct dcerpc_binding *ep_description) {
149 struct dcesrv_endpoint *ep;
150
151 for (ep = endpoint_list; ep != NULL; ep = ep->next) {
152 if (endpoints_match(ep->ep_description, ep_description)) {
153 return ep;
154 }
155 }
156
157 return NULL;
158}
159
160/*
161 * Build a list of all interfaces handled by all endpoint servers.
162 */
163static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
164 struct dcesrv_endpoint *endpoint_list,
165 const struct GUID *uuid,
166 const char *srv_addr,
167 struct dcesrv_ep_iface **peps)
168{
169 struct dcesrv_ep_iface *eps = NULL;
170 struct dcesrv_endpoint *d;
171 uint32_t total = 0;
172 NTSTATUS status;
173
174 *peps = NULL;
175
176 for (d = endpoint_list; d != NULL; d = d->next) {
177 struct dcesrv_iface_list *iface;
178 struct dcerpc_binding *description;
179
180 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
181 if (uuid && !interface_match_by_uuid(iface->iface, uuid)) {
182 continue;
183 }
184
185 eps = talloc_realloc(mem_ctx,
186 eps,
187 struct dcesrv_ep_iface,
188 total + 1);
189 if (eps == NULL) {
190 return 0;
191 }
192 eps[total].name = talloc_strdup(eps,
193 iface->iface->name);
194 eps[total].syntax_id = iface->iface->syntax_id;
195
196 description = dcerpc_binding_dup(mem_ctx, d->ep_description);
197 if (description == NULL) {
198 return 0;
199 }
200 description->object = iface->iface->syntax_id;
201 if (description->transport == NCACN_IP_TCP &&
202 srv_addr != NULL &&
203 (strcmp(description->host, "0.0.0.0") == 0 ||
204 strcmp(description->host, "::") == 0)) {
205 description->host = srv_addr;
206 }
207
208 status = dcerpc_binding_build_tower(eps,
209 description,
210 &eps[total].ep);
211 TALLOC_FREE(description);
212 if (NT_STATUS_IS_ERR(status)) {
213 DEBUG(1, ("Unable to build tower for %s\n",
214 iface->iface->name));
215 continue;
216 }
217 total++;
218 }
219 }
220
221 *peps = eps;
222
223 return total;
224}
225
226static bool is_priviledged_pipe(struct auth_serversupplied_info *info) {
227 /* If the user is not root, or has the system token, fail */
228 if ((info->utok.uid != sec_initial_uid()) &&
229 !security_token_is_system(info->security_token)) {
230 return false;
231 }
232
233 return true;
234}
235
236bool srv_epmapper_delete_endpoints(struct pipes_struct *p)
237{
238 struct epm_Delete r;
239 struct dcesrv_ep_entry_list *el = p->ep_entries;
240 error_status_t result;
241
242 while (el) {
243 struct dcesrv_ep_entry_list *next = el->next;
244
245 r.in.num_ents = el->num_ents;
246 r.in.entries = el->entries;
247
248 DEBUG(10, ("Delete_endpoints for: %s\n",
249 el->entries[0].annotation));
250
251 result = _epm_Delete(p, &r);
252 if (result != EPMAPPER_STATUS_OK) {
253 return false;
254 }
255
256 DLIST_REMOVE(p->ep_entries, el);
257 TALLOC_FREE(el);
258
259 el = next;
260 }
261
262 return true;
263}
264
265void srv_epmapper_cleanup(void)
266{
267 struct dcesrv_endpoint *ep = endpoint_table;
268
269 while (ep) {
270 struct dcesrv_endpoint *next = ep->next;
271
272 DLIST_REMOVE(endpoint_table, ep);
273 TALLOC_FREE(ep);
274
275 ep = next;
276 }
277}
278
279/*
280 * epm_Insert
281 *
282 * Add the specified entries to an endpoint map.
283 */
284error_status_t _epm_Insert(struct pipes_struct *p,
285 struct epm_Insert *r)
286{
287 TALLOC_CTX *tmp_ctx;
288 error_status_t rc;
289 NTSTATUS status;
290 uint32_t i;
291 struct dcerpc_binding *b;
292 struct dcesrv_endpoint *ep;
293 struct dcesrv_iface_list *iflist;
294 struct dcesrv_iface *iface;
295 bool add_ep;
296
297 /* If this is not a priviledged users, return */
298 if (p->transport != NCALRPC ||
299 !is_priviledged_pipe(p->session_info)) {
300 return EPMAPPER_STATUS_CANT_PERFORM_OP;
301 }
302
303 tmp_ctx = talloc_stackframe();
304 if (tmp_ctx == NULL) {
305 return EPMAPPER_STATUS_NO_MEMORY;
306 }
307
308 DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
309 r->in.num_ents));
310
311 for (i = 0; i < r->in.num_ents; i++) {
312 add_ep = false;
313 b = NULL;
314
315 status = dcerpc_binding_from_tower(tmp_ctx,
316 &r->in.entries[i].tower->tower,
317 &b);
318 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
319 rc = EPMAPPER_STATUS_NO_MEMORY;
320 goto done;
321 }
322 if (!NT_STATUS_IS_OK(status)) {
323 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
324 goto done;
325 }
326
327 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
328 derpc_transport_string_by_transport(b->transport),
329 r->in.entries[i].annotation));
330
331 /* Check if the entry already exits */
332 ep = find_endpoint(endpoint_table, b);
333 if (ep == NULL) {
334 /* No entry found, create it */
335 ep = talloc_zero(NULL, struct dcesrv_endpoint);
336 if (ep == NULL) {
337 rc = EPMAPPER_STATUS_NO_MEMORY;
338 goto done;
339 }
340 add_ep = true;
341
342 ep->ep_description = talloc_steal(ep, b);
343 }
344
345 /* TODO Replace the entry if the replace flag is set */
346
347 /* Create an interface */
348 iface = talloc(tmp_ctx, struct dcesrv_iface);
349 if (iface == NULL) {
350 rc = EPMAPPER_STATUS_NO_MEMORY;
351 goto done;
352 }
353
354 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
355 if (iface->name == NULL) {
356 rc = EPMAPPER_STATUS_NO_MEMORY;
357 goto done;
358 }
359 iface->syntax_id = b->object;
360
361 /*
362 * Check if the rpc service is alrady registered on the
363 * endpoint.
364 */
365 if (find_interface(ep, iface) != NULL) {
366 DEBUG(0, ("dcesrv_interface_register: interface '%s' "
367 "already registered on endpoint\n",
368 iface->name));
369 /* FIXME wrong error code? */
370 rc = EPMAPPER_STATUS_OK;
371 goto done;
372 }
373
374 /* Create an entry for the interface */
375 iflist = talloc(ep, struct dcesrv_iface_list);
376 if (iflist == NULL) {
377 rc = EPMAPPER_STATUS_NO_MEMORY;
378 goto done;
379 }
380 iflist->iface = talloc_move(iflist, &iface);
381
382 /* Finally add the interface on the endpoint */
383 DLIST_ADD(ep->iface_list, iflist);
384
385 /* If it's a new endpoint add it to the endpoint_table */
386 if (add_ep) {
387 DLIST_ADD(endpoint_table, ep);
388 }
389 }
390
391 if (r->in.num_ents > 0) {
392 struct dcesrv_ep_entry_list *el;
393
394 el = talloc_zero(p, struct dcesrv_ep_entry_list);
395 if (el == NULL) {
396 rc = EPMAPPER_STATUS_NO_MEMORY;
397 goto done;
398 }
399 el->num_ents = r->in.num_ents;
400 el->entries = talloc_move(el, &r->in.entries);
401
402 DLIST_ADD(p->ep_entries, el);
403 }
404
405 rc = EPMAPPER_STATUS_OK;
406done:
407 talloc_free(tmp_ctx);
408
409 return rc;
410}
411
412
413/*
414 * epm_Delete
415 *
416 * Delete the specified entries from an endpoint map.
417 */
418error_status_t _epm_Delete(struct pipes_struct *p,
419 struct epm_Delete *r)
420{
421 TALLOC_CTX *tmp_ctx;
422 error_status_t rc;
423 NTSTATUS status;
424 uint32_t i;
425 struct dcerpc_binding *b;
426 struct dcesrv_endpoint *ep;
427 struct dcesrv_iface iface;
428 struct dcesrv_iface_list *iflist;
429
430 DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
431 r->in.num_ents));
432
433 /* If this is not a priviledged users, return */
434 if (p->transport != NCALRPC ||
435 !is_priviledged_pipe(p->session_info)) {
436 return EPMAPPER_STATUS_CANT_PERFORM_OP;
437 }
438
439 tmp_ctx = talloc_stackframe();
440 if (tmp_ctx == NULL) {
441 return EPMAPPER_STATUS_NO_MEMORY;
442 }
443
444 for (i = 0; i < r->in.num_ents; i++) {
445 b = NULL;
446
447 status = dcerpc_binding_from_tower(tmp_ctx,
448 &r->in.entries[i].tower->tower,
449 &b);
450 if (!NT_STATUS_IS_OK(status)) {
451 rc = EPMAPPER_STATUS_NO_MEMORY;
452 goto done;
453 }
454
455 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
456 derpc_transport_string_by_transport(b->transport),
457 r->in.entries[i].annotation));
458
459 ep = find_endpoint(endpoint_table, b);
460 if (ep == NULL) {
461 rc = EPMAPPER_STATUS_OK;
462 goto done;
463 }
464
465 iface.name = r->in.entries[i].annotation;
466 iface.syntax_id = b->object;
467
468 iflist = find_interface_list(ep, &iface);
469 if (iflist == NULL) {
470 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
471 DLIST_REMOVE(endpoint_table, ep);
472 talloc_free(ep);
473
474 rc = EPMAPPER_STATUS_OK;
475 goto done;
476 }
477
478 DLIST_REMOVE(ep->iface_list, iflist);
479
480 if (ep->iface_list == NULL) {
481 DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
482 DLIST_REMOVE(endpoint_table, ep);
483 talloc_free(ep);
484
485 rc = EPMAPPER_STATUS_OK;
486 goto done;
487 }
488
489 }
490
491 rc = EPMAPPER_STATUS_OK;
492done:
493 talloc_free(tmp_ctx);
494
495 return rc;
496}
497
498
499/*
500 * epm_Lookup
501 *
502 * Lookup entries in an endpoint map.
503 */
504error_status_t _epm_Lookup(struct pipes_struct *p,
505 struct epm_Lookup *r)
506{
507 struct policy_handle *entry_handle;
508 struct rpc_eps *eps;
509 TALLOC_CTX *tmp_ctx;
510 error_status_t rc;
511 uint32_t count = 0;
512 uint32_t num_ents = 0;
513 uint32_t i;
514 bool match = false;
515 bool ok;
516
517 *r->out.num_ents = 0;
518 r->out.entries = NULL;
519
520 tmp_ctx = talloc_stackframe();
521 if (tmp_ctx == NULL) {
522 return EPMAPPER_STATUS_NO_MEMORY;
523 }
524
525 DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
526 r->in.max_ents));
527
528 if (r->in.entry_handle == NULL ||
529 policy_handle_empty(r->in.entry_handle)) {
530 struct GUID *obj;
531
532 DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n"));
533
534 eps = talloc_zero(tmp_ctx, struct rpc_eps);
535 if (eps == NULL) {
536 rc = EPMAPPER_STATUS_NO_MEMORY;
537 goto done;
538 }
539
540 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
541 obj = NULL;
542 } else {
543 obj = r->in.object;
544 }
545
546 switch (r->in.inquiry_type) {
547 case RPC_C_EP_ALL_ELTS:
548 /*
549 * Return all elements from the endpoint map. The
550 * interface_id, vers_option, and object parameters MUST
551 * be ignored.
552 */
553 eps->count = build_ep_list(eps,
554 endpoint_table,
555 NULL,
556 p->server_id == NULL ? NULL : p->server_id->addr,
557 &eps->e);
558 break;
559 case RPC_C_EP_MATCH_BY_IF:
560 /*
561 * Return endpoint map elements that contain the
562 * interface identifier specified by the interface_id
563 * and vers_option values.
564 *
565 * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
566 * need both the same endpoint list. There is a second
567 * check for the inquiry_type below which differentiates
568 * between them.
569 */
570 case RPC_C_EP_MATCH_BY_BOTH:
571 /*
572 * Return endpoint map elements that contain the
573 * interface identifier and object UUID specified by
574 * interface_id, vers_option, and object.
575 */
576 eps->count = build_ep_list(eps,
577 endpoint_table,
578 &r->in.interface_id->uuid,
579 p->server_id == NULL ? NULL : p->server_id->addr,
580 &eps->e);
581 break;
582 case RPC_C_EP_MATCH_BY_OBJ:
583 /*
584 * Return endpoint map elements that contain the object
585 * UUID specified by object.
586 */
587 eps->count = build_ep_list(eps,
588 endpoint_table,
589 r->in.object,
590 p->server_id == NULL ? NULL : p->server_id->addr,
591 &eps->e);
592 break;
593 default:
594 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
595 goto done;
596 }
597
598 if (eps->count == 0) {
599 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
600 goto done;
601 }
602
603 ok = create_policy_hnd(p, r->out.entry_handle, eps);
604 if (!ok) {
605 rc = EPMAPPER_STATUS_NO_MEMORY;
606 goto done;
607 }
608
609 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
610 if (!ok) {
611 rc = EPMAPPER_STATUS_NO_MEMORY;
612 goto done;
613 }
614 entry_handle = r->out.entry_handle;
615 } else {
616 DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n"));
617
618 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
619 if (!ok) {
620 rc = EPMAPPER_STATUS_NO_MEMORY;
621 goto done;
622 }
623 entry_handle = r->in.entry_handle;
624 }
625
626 if (eps == NULL || eps->e == NULL) {
627 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
628 goto done;
629 }
630
631 /* return the next N elements */
632 count = r->in.max_ents;
633 if (count > eps->count) {
634 count = eps->count;
635 }
636
637 DEBUG(3, ("_epm_Lookup: Find %u entries\n", count));
638
639 if (count == 0) {
640 close_policy_hnd(p, entry_handle);
641 ZERO_STRUCTP(r->out.entry_handle);
642
643 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
644 goto done;
645 }
646
647 r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
648 if (r->out.entries == NULL) {
649 rc = EPMAPPER_STATUS_NO_MEMORY;
650 goto done;
651 }
652
653 for (i = 0; i < count; i++) {
654 match = false;
655
656 switch (r->in.inquiry_type) {
657 case RPC_C_EP_ALL_ELTS:
658 /*
659 * Return all elements from the endpoint map. The
660 * interface_id, vers_option, and object parameters MUST
661 * be ignored.
662 */
663 match = true;
664 break;
665 case RPC_C_EP_MATCH_BY_IF:
666 /*
667 * Return endpoint map elements that contain the
668 * interface identifier specified by the interface_id
669 * and vers_option values.
670 */
671 if (GUID_equal(&r->in.interface_id->uuid,
672 &eps->e[i].syntax_id.uuid)) {
673 match = true;
674 }
675 break;
676 case RPC_C_EP_MATCH_BY_OBJ:
677 /*
678 * Return endpoint map elements that contain the object
679 * UUID specified by object.
680 */
681 if (GUID_equal(r->in.object,
682 &eps->e[i].syntax_id.uuid)) {
683 match = true;
684 }
685 break;
686 case RPC_C_EP_MATCH_BY_BOTH:
687 /*
688 * Return endpoint map elements that contain the
689 * interface identifier and object UUID specified by
690 * interface_id, vers_option, and object.
691 */
692 if (GUID_equal(&r->in.interface_id->uuid,
693 &eps->e[i].syntax_id.uuid) &&
694 GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
695 match = true;
696 }
697 break;
698 default:
699 return EPMAPPER_STATUS_CANT_PERFORM_OP;
700 }
701
702 if (match) {
703 if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
704 r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
705 /* Check inteface version */
706
707 match = false;
708 switch (r->in.vers_option) {
709 case RPC_C_VERS_ALL:
710 /*
711 * Return endpoint map elements that
712 * contain the specified interface UUID,
713 * regardless of the version numbers.
714 */
715 match = true;
716 break;
717 case RPC_C_VERS_COMPATIBLE:
718 /*
719 * Return the endpoint map elements that
720 * contain the same major versions of
721 * the specified interface UUID and a
722 * minor version greater than or equal
723 * to the minor version of the specified
724 * UUID.
725 */
726 if (r->in.interface_id->vers_major ==
727 (eps->e[i].syntax_id.if_version >> 16) &&
728 r->in.interface_id->vers_minor <=
729 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
730 match = true;
731 }
732 break;
733 case RPC_C_VERS_EXACT:
734 /*
735 * Return endpoint map elements that
736 * contain the specified version of the
737 * specified interface UUID.
738 */
739 if (r->in.interface_id->vers_major ==
740 (eps->e[i].syntax_id.if_version >> 16) &&
741 r->in.interface_id->vers_minor ==
742 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
743 match = true;
744 }
745 match = true;
746 break;
747 case RPC_C_VERS_MAJOR_ONLY:
748 /*
749 * Return endpoint map elements that
750 * contain the same version of the
751 * specified interface UUID and ignore
752 * the minor version.
753 */
754 if (r->in.interface_id->vers_major ==
755 (eps->e[i].syntax_id.if_version >> 16)) {
756 match = true;
757 }
758 match = true;
759 break;
760 case RPC_C_VERS_UPTO:
761 /*
762 * Return endpoint map elements that
763 * contain a version of the specified
764 * interface UUID less than or equal to
765 * the specified major and minor
766 * version.
767 */
768 if (r->in.interface_id->vers_major >
769 eps->e[i].syntax_id.if_version >> 16) {
770 match = true;
771 } else {
772 if (r->in.interface_id->vers_major ==
773 (eps->e[i].syntax_id.if_version >> 16) &&
774 r->in.interface_id->vers_minor >=
775 (eps->e[i].syntax_id.if_version && 0xFFFF)) {
776 match = true;
777 }
778 }
779 break;
780 default:
781 return EPMAPPER_STATUS_CANT_PERFORM_OP;
782 }
783 }
784 }
785
786 if (match) {
787 ZERO_STRUCT(r->out.entries[num_ents].object);
788
789 DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
790 eps->e[i].name));
791 r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
792 eps->e[i].name);
793 r->out.entries[num_ents].tower = talloc(r->out.entries,
794 struct epm_twr_t);
795 if (r->out.entries[num_ents].tower == NULL) {
796 rc = EPMAPPER_STATUS_NO_MEMORY;
797 goto done;
798 }
799 r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
800 r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
801 r->out.entries[num_ents].tower->tower_length = 0;
802
803 num_ents++;
804 }
805 } /* end for loop */
806
807 *r->out.num_ents = num_ents;
808
809 eps->count -= count;
810 eps->e += count;
811 if (eps->count == 0) {
812 close_policy_hnd(p, entry_handle);
813 ZERO_STRUCTP(r->out.entry_handle);
814 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
815 goto done;
816 }
817
818 rc = EPMAPPER_STATUS_OK;
819done:
820 talloc_free(tmp_ctx);
821
822 return rc;
823}
824
825/*
826 * epm_Map
827 *
828 * Apply some algorithm (using the fields in the map_tower) to an endpoint map
829 * to produce a list of protocol towers.
830 */
831error_status_t _epm_Map(struct pipes_struct *p,
832 struct epm_Map *r)
833{
834 struct policy_handle *entry_handle;
835 enum dcerpc_transport_t transport;
836 struct ndr_syntax_id ifid;
837 struct epm_floor *floors;
838 struct rpc_eps *eps;
839 TALLOC_CTX *tmp_ctx;
840 error_status_t rc;
841 uint32_t count = 0;
842 uint32_t num_towers = 0;
843 uint32_t num_floors = 0;
844 uint32_t i;
845 bool ok;
846
847 *r->out.num_towers = 0;
848 r->out.towers = NULL;
849
850 if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
851 r->in.map_tower->tower.num_floors < 3) {
852 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
853 }
854
855 tmp_ctx = talloc_stackframe();
856 if (tmp_ctx == NULL) {
857 return EPMAPPER_STATUS_NO_MEMORY;
858 }
859
860 ZERO_STRUCTP(r->out.entry_handle);
861
862 DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n",
863 r->in.max_towers));
864
865 /*
866 * A tower has normally up to 6 floors
867 *
868 * +-----------------------------------------------------------------+
869 * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
870 * | | netlogon) |
871 * +---------+-------------------------------------------------------+
872 * | Floor 2 | Transfer syntax (NDR endcoded) |
873 * +---------+-------------------------------------------------------+
874 * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
875 * +---------+-------------------------------------------------------+
876 * | Floor 4 | Port address (e.g. TCP Port: 49156) |
877 * +---------+-------------------------------------------------------+
878 * | Floor 5 | Transport (e.g. IP:192.168.51.10) |
879 * +---------+-------------------------------------------------------+
880 * | Floor 6 | Routing |
881 * +---------+-------------------------------------------------------+
882 */
883 num_floors = r->in.map_tower->tower.num_floors;
884 floors = r->in.map_tower->tower.floors;
885
886 /* We accept NDR as the transfer syntax */
887 dcerpc_floor_get_lhs_data(&floors[1], &ifid);
888
889 if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
890 !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) ||
891 ifid.if_version != ndr_transfer_syntax.if_version) {
892 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
893 goto done;
894 }
895
896 /* We only talk to sane transports */
897 transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
898 if (transport == NCA_UNKNOWN) {
899 DEBUG(2, ("epm_Map: Client requested unknown transport with"
900 "levels: "));
901 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
902 DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
903 }
904 DEBUG(2, ("\n"));
905 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
906 goto done;
907 }
908
909 if (r->in.entry_handle == NULL ||
910 policy_handle_empty(r->in.entry_handle)) {
911 struct GUID *obj;
912
913 DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n"));
914
915 eps = talloc_zero(tmp_ctx, struct rpc_eps);
916 if (eps == NULL) {
917 rc = EPMAPPER_STATUS_NO_MEMORY;
918 goto done;
919 }
920
921 /*
922 * *** ATTENTION ***
923 * CDE 1.1 states:
924 *
925 * ept_map()
926 * Apply some algorithm (using the fields in the map_tower)
927 * to an endpoint map to produce a list of protocol towers.
928 *
929 * The following code is the mysterious "some algorithm"!
930 */
931
932 /* Filter by object id if one was given. */
933 if (r->in.object == NULL || GUID_all_zero(r->in.object)) {
934 obj = NULL;
935 } else {
936 obj = r->in.object;
937 }
938
939 eps->count = build_ep_list(eps,
940 endpoint_table,
941 obj,
942 p->server_id == NULL ? NULL : p->server_id->addr,
943 &eps->e);
944 if (eps->count == 0) {
945 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
946 goto done;
947 }
948
949 /* Filter out endpoints which match the interface. */
950 {
951 struct rpc_eps *teps;
952 uint32_t total = 0;
953
954 teps = talloc_zero(tmp_ctx, struct rpc_eps);
955 if (teps == NULL) {
956 rc = EPMAPPER_STATUS_NO_MEMORY;
957 goto done;
958 }
959
960 for (i = 0; i < eps->count; i++) {
961 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
962 &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 ||
963 transport != dcerpc_transport_by_tower(&eps->e[i].ep)) {
964 continue;
965 }
966
967 teps->e = talloc_realloc(tmp_ctx,
968 teps->e,
969 struct dcesrv_ep_iface,
970 total + 1);
971 if (teps->e == NULL) {
972 return 0;
973 }
974
975 teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors);
976 teps->e[total].ep.num_floors = eps->e[i].ep.num_floors;
977 teps->e[total].name = talloc_move(teps, &eps->e[i].name);
978 teps->e[total].syntax_id = eps->e[i].syntax_id;
979
980 total++;
981 }
982
983 teps->count = total;
984 talloc_free(eps);
985 eps = teps;
986 }
987 /* end of "some algorithm" */
988
989 ok = create_policy_hnd(p, r->out.entry_handle, eps);
990 if (!ok) {
991 rc = EPMAPPER_STATUS_NO_MEMORY;
992 goto done;
993 }
994
995 ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps);
996 if (!ok) {
997 rc = EPMAPPER_STATUS_NO_MEMORY;
998 goto done;
999 }
1000 entry_handle = r->out.entry_handle;
1001 } else {
1002 DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n"));
1003
1004 ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps);
1005 if (!ok) {
1006 rc = EPMAPPER_STATUS_NO_MEMORY;
1007 goto done;
1008 }
1009 entry_handle = r->in.entry_handle;
1010 }
1011
1012 if (eps == NULL || eps->e == NULL) {
1013 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1014 goto done;
1015 }
1016
1017 /* return the next N elements */
1018 count = r->in.max_towers;
1019 if (count > eps->count) {
1020 count = eps->count;
1021 }
1022
1023 if (count == 0) {
1024 close_policy_hnd(p, entry_handle);
1025 ZERO_STRUCTP(r->out.entry_handle);
1026
1027 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
1028 goto done;
1029 }
1030
1031 r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
1032 if (r->out.towers == NULL) {
1033 rc = EPMAPPER_STATUS_NO_MEMORY;
1034 goto done;
1035 }
1036
1037 for (i = 0; i < count; i++) {
1038 DEBUG(5, ("_epm_Map: Map tower for '%s'\n",
1039 eps->e[i].name));
1040
1041 r->out.towers[num_towers].twr = talloc(r->out.towers,
1042 struct epm_twr_t);
1043 if (r->out.towers[num_towers].twr == NULL) {
1044 rc = EPMAPPER_STATUS_NO_MEMORY;
1045 goto done;
1046 }
1047 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
1048 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
1049 r->out.towers[num_towers].twr->tower_length = 0;
1050
1051 num_towers++;
1052 }
1053
1054 *r->out.num_towers = num_towers;
1055
1056 eps->count -= count;
1057 eps->e += count;
1058 if (eps->count == 0) {
1059 close_policy_hnd(p, entry_handle);
1060 ZERO_STRUCTP(r->out.entry_handle);
1061 }
1062
1063 rc = EPMAPPER_STATUS_OK;
1064done:
1065 talloc_free(tmp_ctx);
1066
1067 return rc;
1068}
1069
1070/*
1071 * epm_LookupHandleFree
1072 */
1073error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
1074 struct epm_LookupHandleFree *r)
1075{
1076 if (r->in.entry_handle == NULL) {
1077 return EPMAPPER_STATUS_OK;
1078 }
1079
1080 if (is_valid_policy_hnd(r->in.entry_handle)) {
1081 close_policy_hnd(p, r->in.entry_handle);
1082 }
1083
1084 r->out.entry_handle = r->in.entry_handle;
1085
1086 return EPMAPPER_STATUS_OK;
1087}
1088
1089
1090/*
1091 * epm_InqObject
1092 *
1093 * A client implementation SHOULD NOT call this method. These extensions do not
1094 * provide an alternative method.
1095 */
1096error_status_t _epm_InqObject(struct pipes_struct *p,
1097 struct epm_InqObject *r)
1098{
1099 p->rng_fault_state = true;
1100 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1101}
1102
1103
1104/*
1105 * epm_MgmtDelete
1106 *
1107 * A client implementation SHOULD NOT call this method. These extensions do not
1108 * provide an alternative method.
1109*/
1110error_status_t _epm_MgmtDelete(struct pipes_struct *p,
1111 struct epm_MgmtDelete *r)
1112{
1113 p->rng_fault_state = true;
1114 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1115}
1116
1117
1118/*
1119 epm_MapAuth
1120*/
1121error_status_t _epm_MapAuth(struct pipes_struct *p,
1122 struct epm_MapAuth *r)
1123{
1124 p->rng_fault_state = true;
1125 return EPMAPPER_STATUS_CANT_PERFORM_OP;
1126}
1127
1128/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
Note: See TracBrowser for help on using the repository browser.