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