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