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