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