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