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