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