530b0b7cc7f4e2771289b38ee8d680047c6a7fa2
[kai/samba.git] / source3 / rpc_server / epmapper / srv_epmapper.c
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 "../libcli/security/security.h"
24 #include "librpc/gen_ndr/ndr_epmapper.h"
25 #include "librpc/gen_ndr/srv_epmapper.h"
26 #include "srv_epmapper.h"
27 #include "auth.h"
28
29 typedef uint32_t error_status_t;
30
31 /* An endpoint combined with an interface description */
32 struct 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 */
39 struct dcesrv_iface {
40         const char *name;
41         struct ndr_syntax_id syntax_id;
42 };
43
44 struct 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  */
53 struct 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
63 struct 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
70 struct rpc_eps {
71         struct dcesrv_ep_iface *e;
72         uint32_t count;
73 };
74
75 static struct dcesrv_endpoint *endpoint_table;
76
77 /*
78  * Check if the UUID and if_version match to an interface.
79  */
80 static 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  */
89 static 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  */
106 static 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
112 static 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  */
129 static 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
147 static 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  */
163 static 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
226 static 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
236 bool 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
265 void 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  */
284 error_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;
406 done:
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  */
418 error_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;
492 done:
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  */
504 error_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(5, ("_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(7, ("_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(7, ("_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(5, ("_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;
819 done:
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  */
831 error_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(5, ("_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(7, ("_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(7, ("_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(7, ("_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;
1064 done:
1065         talloc_free(tmp_ctx);
1066
1067         return rc;
1068 }
1069
1070 /*
1071  * epm_LookupHandleFree
1072  */
1073 error_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  */
1096 error_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 */
1110 error_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 */
1121 error_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: */