s3-epmapper: Added epm_Map function from Samba4.
[samba.git] / source3 / rpc_server / srv_epmapper.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Endpoint server for the epmapper pipe
5
6    Copyright (C) 2010      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 "librpc/gen_ndr/ndr_epmapper.h"
24 #include "librpc/gen_ndr/srv_epmapper.h"
25
26 typedef uint32_t error_status_t;
27
28 /* An endpoint combined with an interface description */
29 struct dcesrv_ep_iface {
30         const char *name;
31         struct epm_tower ep;
32 };
33
34 /* A rpc service interface like samr, lsarpc or netlogon */
35 struct dcesrv_iface {
36         const char *name;
37         struct ndr_syntax_id syntax_id;
38 };
39
40 struct dcesrv_iface_list {
41         struct dcesrv_iface_list *next, *prev;
42         struct dcesrv_iface *iface;
43 };
44
45 /*
46  * An endpoint can serve multiple rpc services interfaces.
47  * For example \\pipe\netlogon can be used by lsarpc and netlogon.
48  */
49 struct dcesrv_endpoint {
50         struct dcesrv_endpoint *next, *prev;
51
52         /* The type and the location of the endpoint */
53         struct dcerpc_binding *ep_description;
54
55         /* A list of rpc services able to connect to the endpoint */
56         struct dcesrv_iface_list *iface_list;
57 };
58
59 struct dcesrv_endpoint *endpoint_table;
60
61 /*
62  * Check if the UUID and if_version match to an interface.
63  */
64 static bool interface_match(const struct dcesrv_iface *if1,
65                             const struct dcesrv_iface *if2)
66 {
67         return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid);
68 }
69
70 /*
71  * Find the interface operations on an endpoint.
72  */
73 static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint,
74                                                  const struct dcesrv_iface *iface)
75 {
76         struct dcesrv_iface_list *iflist;
77
78         for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
79                 if (interface_match(iflist->iface, iface)) {
80                         return iflist->iface;
81                 }
82         }
83
84         return NULL;
85 }
86
87 static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint,
88                                                      const struct dcesrv_iface *iface)
89 {
90         struct dcesrv_iface_list *iflist;
91
92         for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) {
93                 if (interface_match(iflist->iface, iface)) {
94                         return iflist;
95                 }
96         }
97
98         return NULL;
99 }
100
101 /*
102  * Check if two endpoints match.
103  */
104 static bool endpoints_match(const struct dcerpc_binding *ep1,
105                             const struct dcerpc_binding *ep2)
106 {
107         if (ep1->transport != ep2->transport) {
108                 return false;
109         }
110
111         if (!ep1->endpoint || !ep2->endpoint) {
112                 return ep1->endpoint == ep2->endpoint;
113         }
114
115         if (!strequal(ep1->endpoint, ep2->endpoint)) {
116                 return false;
117         }
118
119         return true;
120 }
121
122 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list,
123                                              struct dcerpc_binding *ep_description) {
124         struct dcesrv_endpoint *ep;
125
126         for (ep = endpoint_list; ep != NULL; ep = ep->next) {
127                 if (endpoints_match(ep->ep_description, ep_description)) {
128                         return ep;
129                 }
130         }
131
132         return NULL;
133 }
134
135 /*
136  * Build a list of all interfaces handled by all endpoint servers.
137  */
138 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
139                               struct dcesrv_endpoint *endpoint_list,
140                               struct dcesrv_ep_iface **peps)
141 {
142         struct dcesrv_ep_iface *eps = NULL;
143         struct dcesrv_endpoint *d;
144         uint32_t total = 0;
145         NTSTATUS status;
146
147         *peps = NULL;
148
149         for (d = endpoint_list; d != NULL; d = d->next) {
150                 struct dcesrv_iface_list *iface;
151                 struct dcerpc_binding *description;
152
153                 for (iface = d->iface_list; iface != NULL; iface = iface->next) {
154                         eps = talloc_realloc(mem_ctx,
155                                              eps,
156                                              struct dcesrv_ep_iface,
157                                              total + 1);
158                         if (eps == NULL) {
159                                 return 0;
160                         }
161                         eps[total].name = iface->iface->name;
162
163                         description = d->ep_description;
164                         description->object = iface->iface->syntax_id;
165
166                         status = dcerpc_binding_build_tower(eps,
167                                                             description,
168                                                             &eps[total].ep);
169                         if (NT_STATUS_IS_ERR(status)) {
170                                 DEBUG(1, ("Unable to build tower for %s\n",
171                                           iface->iface->name));
172                                 continue;
173                         }
174                         total++;
175                 }
176         }
177
178         *peps = eps;
179
180         return total;
181 }
182
183 /*
184  * epm_Insert
185  *
186  * Add the specified entries to an endpoint map.
187  */
188 error_status_t _epm_Insert(struct pipes_struct *p,
189                            struct epm_Insert *r)
190 {
191         TALLOC_CTX *tmp_ctx;
192         error_status_t rc;
193         NTSTATUS status;
194         uint32_t i;
195
196         tmp_ctx = talloc_stackframe();
197         if (tmp_ctx == NULL) {
198                 return EPMAPPER_STATUS_NO_MEMORY;
199         }
200
201         DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n",
202                   r->in.num_ents));
203
204         /* TODO Check if we have a priviledged pipe/handle */
205
206         for (i = 0; i < r->in.num_ents; i++) {
207                 struct dcerpc_binding *b = NULL;
208                 struct dcesrv_endpoint *ep;
209                 struct dcesrv_iface_list *iflist;
210                 struct dcesrv_iface *iface;
211                 bool add_ep = false;
212
213                 status = dcerpc_binding_from_tower(tmp_ctx,
214                                                    &r->in.entries[i].tower->tower,
215                                                    &b);
216                 if (!NT_STATUS_IS_OK(status)) {
217                         rc = EPMAPPER_STATUS_NO_MEMORY;
218                         goto done;
219                 }
220
221                 DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n",
222                           derpc_transport_string_by_transport(b->transport),
223                           r->in.entries[i].annotation));
224
225                 /* Check if the entry already exits */
226                 ep = find_endpoint(endpoint_table, b);
227                 if (ep == NULL) {
228                         /* No entry found, create it */
229                         ep = talloc_zero(NULL, struct dcesrv_endpoint);
230                         if (ep == NULL) {
231                                 rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
232                                 goto done;
233                         }
234                         add_ep = true;
235
236                         ep->ep_description = talloc_steal(ep, b);
237                 }
238
239                 /* TODO Replace the entry if the replace flag is set */
240
241                 /* Create an interface */
242                 iface = talloc(tmp_ctx, struct dcesrv_iface);
243                 if (iface == NULL) {
244                         rc = EPMAPPER_STATUS_NO_MEMORY;
245                         goto done;
246                 }
247
248                 iface->name = talloc_strdup(iface, r->in.entries[i].annotation);
249                 if (iface->name == NULL) {
250                         rc = EPMAPPER_STATUS_NO_MEMORY;
251                         goto done;
252                 }
253                 iface->syntax_id = b->object;
254
255                 /*
256                  * Check if the rpc service is alrady registered on the
257                  * endpoint.
258                  */
259                 if (find_interface(ep, iface) != NULL) {
260                         DEBUG(0, ("dcesrv_interface_register: interface '%s' "
261                                   "already registered on endpoint\n",
262                                   iface->name));
263                         /* FIXME wrong error code? */
264                         rc = EPMAPPER_STATUS_OK;
265                         goto done;
266                 }
267
268                 /* Create an entry for the interface */
269                 iflist = talloc(ep, struct dcesrv_iface_list);
270                 if (iflist == NULL) {
271                         rc = EPMAPPER_STATUS_NO_MEMORY;
272                         goto done;
273                 }
274                 iflist->iface = talloc_move(iflist, &iface);
275
276                 /* Finally add the interface on the endpoint */
277                 DLIST_ADD(ep->iface_list, iflist);
278
279                 /* If it's a new endpoint add it to the endpoint_table */
280                 if (add_ep) {
281                         DLIST_ADD(endpoint_table, ep);
282                 }
283         }
284
285         rc = EPMAPPER_STATUS_OK;
286 done:
287         talloc_free(tmp_ctx);
288
289         return rc;
290 }
291
292
293 /*
294  * epm_Delete
295  *
296  * Delete the specified entries from an endpoint map.
297  */
298 error_status_t _epm_Delete(struct pipes_struct *p,
299                            struct epm_Delete *r)
300 {
301         TALLOC_CTX *tmp_ctx;
302         error_status_t rc;
303         NTSTATUS status;
304         uint32_t i;
305
306         DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n",
307                   r->in.num_ents));
308
309         tmp_ctx = talloc_stackframe();
310         if (tmp_ctx == NULL) {
311                 return EPMAPPER_STATUS_NO_MEMORY;
312         }
313
314         /* TODO Check if we have a priviledged pipe/handle */
315
316         for (i = 0; i < r->in.num_ents; i++) {
317                 struct dcerpc_binding *b = NULL;
318                 struct dcesrv_endpoint *ep;
319                 struct dcesrv_iface iface;
320                 struct dcesrv_iface_list *iflist;
321
322                 status = dcerpc_binding_from_tower(tmp_ctx,
323                                                    &r->in.entries[i].tower->tower,
324                                                    &b);
325                 if (!NT_STATUS_IS_OK(status)) {
326                         rc = EPMAPPER_STATUS_NO_MEMORY;
327                         goto done;
328                 }
329
330                 DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n",
331                           derpc_transport_string_by_transport(b->transport),
332                           r->in.entries[i].annotation));
333
334                 ep = find_endpoint(endpoint_table, b);
335                 if (ep == NULL) {
336                         rc = EPMAPPER_STATUS_OK;
337                         goto done;
338                 }
339
340                 iface.name = r->in.entries[i].annotation;
341                 iface.syntax_id = b->object;
342
343                 iflist = find_interface_list(ep, &iface);
344                 if (iflist == NULL) {
345                         DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
346                         DLIST_REMOVE(endpoint_table, ep);
347                         talloc_free(ep);
348
349                         rc = EPMAPPER_STATUS_OK;
350                         goto done;
351                 }
352
353                 DLIST_REMOVE(ep->iface_list, iflist);
354
355                 if (ep->iface_list == NULL) {
356                         DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n"));
357                         DLIST_REMOVE(endpoint_table, ep);
358                         talloc_free(ep);
359
360                         rc = EPMAPPER_STATUS_OK;
361                         goto done;
362                 }
363
364         }
365
366         rc = EPMAPPER_STATUS_OK;
367 done:
368         talloc_free(tmp_ctx);
369
370         return rc;
371 }
372
373
374 /*
375   epm_Lookup
376 */
377 error_status_t _epm_Lookup(struct pipes_struct *p,
378                    struct epm_Lookup *r)
379 {
380         p->rng_fault_state = true;
381         return EPMAPPER_STATUS_CANT_PERFORM_OP;
382 }
383
384 /*
385  * epm_Map
386  *
387  * Apply some algorithm (using the fields in the map_tower) to an endpoint map
388  * to produce a list of protocol towers.
389  */
390 error_status_t _epm_Map(struct pipes_struct *p,
391                         struct epm_Map *r)
392 {
393         enum dcerpc_transport_t transport;
394         struct ndr_syntax_id ndr_syntax;
395         struct dcesrv_ep_iface *eps;
396         struct epm_floor *floors;
397         uint32_t count, i;
398
399         count = build_ep_list(p->mem_ctx, endpoint_table, &eps);
400
401         ZERO_STRUCT(*r->out.entry_handle);
402         r->out.num_towers = talloc(p->mem_ctx, uint32_t);
403         if (r->out.num_towers == NULL) {
404                 return EPMAPPER_STATUS_NO_MEMORY;
405         }
406
407         *r->out.num_towers = 1;
408         r->out.towers = talloc(p->mem_ctx, struct epm_twr_p_t);
409         if (r->out.towers == NULL) {
410                 return EPMAPPER_STATUS_NO_MEMORY;
411         }
412
413         r->out.towers->twr = talloc(p->mem_ctx, struct epm_twr_t);
414         if (r->out.towers->twr == NULL) {
415                 return EPMAPPER_STATUS_NO_MEMORY;
416         }
417
418         if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
419                         r->in.map_tower->tower.num_floors < 3) {
420                 goto failed;
421         }
422
423         floors = r->in.map_tower->tower.floors;
424
425         dcerpc_floor_get_lhs_data(&r->in.map_tower->tower.floors[1], &ndr_syntax);
426
427         if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
428                         !GUID_equal(&ndr_syntax.uuid, &ndr_transfer_syntax.uuid) ||
429                         ndr_syntax.if_version != ndr_transfer_syntax.if_version) {
430                 goto failed;
431         }
432
433         transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
434         if (transport == -1) {
435                 DEBUG(2, ("epm_Insert: Client requested unknown transport with levels: "));
436                 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
437                         DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
438                 }
439                 DEBUG(2, ("\n"));
440                 goto failed;
441         }
442
443         for (i = 0; i < count; i++) {
444                 if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data,
445                                         &eps[i].ep.floors[0].lhs.lhs_data) != 0 ||
446                                 transport != dcerpc_transport_by_tower(&eps[i].ep)) {
447                         continue;
448                 }
449
450                 r->out.towers->twr->tower = eps[i].ep;
451                 r->out.towers->twr->tower_length = 0;
452
453                 return EPMAPPER_STATUS_OK;
454         }
455
456 failed:
457         *r->out.num_towers = 0;
458         r->out.towers->twr = NULL;
459
460         return EPMAPPER_STATUS_NO_MORE_ENTRIES;
461 }
462
463 /*
464   epm_LookupHandleFree
465 */
466 error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
467                              struct epm_LookupHandleFree *r)
468 {
469         p->rng_fault_state = true;
470         return EPMAPPER_STATUS_CANT_PERFORM_OP;
471 }
472
473
474 /*
475   epm_InqObject
476 */
477 error_status_t _epm_InqObject(struct pipes_struct *p,
478                       struct epm_InqObject *r)
479 {
480         p->rng_fault_state = true;
481         return EPMAPPER_STATUS_CANT_PERFORM_OP;
482 }
483
484
485 /*
486   epm_MgmtDelete
487 */
488 error_status_t _epm_MgmtDelete(struct pipes_struct *p,
489                        struct epm_MgmtDelete *r)
490 {
491         p->rng_fault_state = true;
492         return EPMAPPER_STATUS_CANT_PERFORM_OP;
493 }
494
495
496 /*
497   epm_MapAuth
498 */
499 error_status_t _epm_MapAuth(struct pipes_struct *p,
500                     struct epm_MapAuth *r)
501 {
502         p->rng_fault_state = true;
503         return EPMAPPER_STATUS_CANT_PERFORM_OP;
504 }
505
506 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */