completed the linkage between the endpoint mapper and the dcerpc
[samba.git] / source4 / rpc_server / epmapper / rpc_epmapper.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the epmapper pipe
5
6    Copyright (C) Andrew Tridgell 2003
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25
26 /* handle types for this module */
27 enum handle_types {HTYPE_LOOKUP};
28
29
30 /*
31   simple routine to compare a GUID string to a GUID structure
32 */
33 static int guid_cmp(TALLOC_CTX *mem_ctx, const GUID *guid, const char *uuid_str)
34 {
35         const char *s = GUID_string(mem_ctx, guid);
36         if (!s || strcasecmp(s, uuid_str)) {
37                 return -1;
38         }
39         return 0;
40 }
41
42 /*
43   fill a protocol tower
44 */
45 static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr, 
46                                 struct dcesrv_ep_iface *e)
47 {
48         twr->num_floors = 5;
49         twr->floors = talloc_array_p(mem_ctx, struct epm_floor, 5);
50         if (!twr->floors) {
51                 return False;
52         }
53         
54         twr->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
55         GUID_from_string(e->uuid, &twr->floors[0].lhs.info.uuid.uuid);
56         twr->floors[0].lhs.info.uuid.version = e->if_version;
57         twr->floors[0].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
58         
59         /* encoded with NDR ... */
60         twr->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
61         GUID_from_string(NDR_GUID, &twr->floors[1].lhs.info.uuid.uuid);
62         twr->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
63         twr->floors[1].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
64         
65         /* on an RPC connection ... */
66         twr->floors[2].lhs.protocol = EPM_PROTOCOL_RPC_C;
67         twr->floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
68         twr->floors[2].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 2);
69
70         switch (e->endpoint.type) {
71         case ENDPOINT_SMB:
72                 /* on a SMB pipe ... */
73                 twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
74                 twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
75                 twr->floors[3].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\PIPE\\%s", 
76                                                                    e->endpoint.info.smb_pipe);
77                 twr->floors[3].rhs.rhs_data.length = strlen(twr->floors[3].rhs.rhs_data.data)+1;
78                 
79                 /* on an NetBIOS link ... */
80                 twr->floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
81                 twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
82                 twr->floors[4].rhs.rhs_data.data = talloc_asprintf(mem_ctx, "\\\\%s", 
83                                                                    lp_netbios_name());
84                 twr->floors[4].rhs.rhs_data.length = strlen(twr->floors[4].rhs.rhs_data.data)+1;
85                 break;
86
87         case ENDPOINT_TCP:
88                 /* on a TCP connection ... */
89                 twr->floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
90                 twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
91                 twr->floors[3].rhs.rhs_data = data_blob_talloc(mem_ctx, NULL, 2);
92                 RSSVAL(twr->floors[3].rhs.rhs_data.data, 0, e->endpoint.info.tcp_port);
93                 
94                 /* on an IP link ... */
95                 twr->floors[4].lhs.protocol = EPM_PROTOCOL_IP;
96                 twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
97                 twr->floors[4].rhs.rhs_data = data_blob_talloc_zero(mem_ctx, 4);
98                 break;
99         }
100
101         return True;
102 }
103
104
105 /*
106   build a list of all interfaces handled by all endpoint servers
107 */
108 static uint32 build_ep_list(TALLOC_CTX *mem_ctx,
109                             struct dce_endpoint *endpoint_list,
110                             struct dcesrv_ep_iface **eps)
111 {
112         struct dce_endpoint *d;
113         uint32 total = 0;
114
115         (*eps) = NULL;
116         
117         for (d=endpoint_list; d; d=d->next) {
118                 struct dcesrv_ep_iface *e;
119                 int count = d->endpoint_ops->lookup_endpoints(mem_ctx, &e);
120                 if (count > 0) {
121                         int i;
122                         for (i=0;i<count;i++) {
123                                 e[i].endpoint = d->endpoint;
124                         }
125                         (*eps) = talloc_realloc_p(mem_ctx, *eps, 
126                                                   struct dcesrv_ep_iface,
127                                                   total + count);
128                         if (!*eps) {
129                                 return 0;
130                         }
131                         memcpy((*eps) + total, e, sizeof(*e) * count);
132                         total += count;
133                 }
134         }
135
136         return total;
137 }
138
139
140 static NTSTATUS epm_Insert(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
141                            struct epm_Insert *r)
142 {
143         return NT_STATUS_NOT_IMPLEMENTED;
144 }
145
146 static NTSTATUS epm_Delete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
147                            struct epm_Delete *r)
148 {
149         return NT_STATUS_NOT_IMPLEMENTED;
150 }
151
152
153 /*
154   implement epm_Lookup. This call is used to enumerate the interfaces
155   available on a rpc server
156 */
157 static NTSTATUS epm_Lookup(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
158                            struct epm_Lookup *r)
159 {
160         struct dcesrv_handle *h;
161         struct rpc_eps {
162                 uint32 count;
163                 struct dcesrv_ep_iface *e;
164         } *eps;
165         uint32 num_ents;
166         int i;
167
168         h = dcesrv_handle_fetch(dce, r->in.entry_handle, HTYPE_LOOKUP);
169         if (!h) {
170                 return NT_STATUS_INVALID_HANDLE;
171         }
172
173         eps = h->data;
174
175         if (!eps) {
176                 /* this is the first call - fill the list. Subsequent calls 
177                    will feed from this list, stored in the handle */
178                 eps = talloc_p(h->mem_ctx, struct rpc_eps);
179                 if (!eps) {
180                         return NT_STATUS_NO_MEMORY;
181                 }
182                 h->data = eps;
183
184                 eps->count = build_ep_list(h->mem_ctx, dce->dce->endpoint_list, &eps->e);
185         }
186
187         /* return the next N elements */
188         num_ents = r->in.max_ents;
189         if (num_ents > eps->count) {
190                 num_ents = eps->count;
191         }
192
193         *r->out.entry_handle = h->wire_handle;
194         r->out.num_ents = num_ents;
195         r->out.status = 0;
196
197         if (num_ents == 0) {
198                 r->out.entries = NULL;
199                 r->out.status  = EPMAPPER_STATUS_NO_MORE_ENTRIES;
200                 ZERO_STRUCTP(r->out.entry_handle);
201                 dcesrv_handle_destroy(dce, h);
202                 return NT_STATUS_OK;
203         }
204
205         r->out.entries = talloc_array_p(mem_ctx, struct epm_entry_t, num_ents);
206         if (!r->out.entries) {
207                 return NT_STATUS_NO_MEMORY;
208         }
209
210         for (i=0;i<num_ents;i++) {
211                 ZERO_STRUCT(r->out.entries[i].object);
212                 r->out.entries[i].annotation = eps->e[i].name;
213                 r->out.entries[i].tower = talloc_p(mem_ctx, struct epm_twr_t);
214                 if (!r->out.entries[i].tower) {
215                         return NT_STATUS_NO_MEMORY;
216                 }
217
218                 if (!fill_protocol_tower(mem_ctx, &r->out.entries[i].tower->towers, &eps->e[i])) {
219                         return NT_STATUS_NO_MEMORY;
220                 }
221         }
222
223         eps->count -= num_ents;
224         eps->e += num_ents;
225
226         return NT_STATUS_OK;
227 }
228
229
230 /*
231   implement epm_Map. This is used to find the specific endpoint to talk to given
232   a generic protocol tower
233 */
234 static NTSTATUS epm_Map(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
235                         struct epm_Map *r)
236 {
237         uint32 count;
238         int i;
239         struct dcesrv_ep_iface *eps;
240         struct epm_floor *floors;
241
242         count = build_ep_list(mem_ctx, dce->dce->endpoint_list, &eps);
243
244         ZERO_STRUCTP(r->out.entry_handle);
245         r->out.num_towers = 1;
246         r->out.status = 0;
247         r->out.towers = talloc_p(mem_ctx, struct epm_twr_p_t);
248         if (!r->out.towers) {
249                 return NT_STATUS_NO_MEMORY;
250         }
251         r->out.towers->twr = talloc_p(mem_ctx, struct epm_twr_t);
252         if (!r->out.towers->twr) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255         
256         if (!r->in.map_tower || r->in.max_towers == 0 ||
257             r->in.map_tower->towers.num_floors != 5) {
258                 goto failed;
259         }
260
261         floors = r->in.map_tower->towers.floors;
262
263         if (floors[0].lhs.protocol != EPM_PROTOCOL_UUID ||
264             floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
265             guid_cmp(mem_ctx, &floors[1].lhs.info.uuid.uuid, NDR_GUID) != 0 ||
266             floors[1].lhs.info.uuid.version != NDR_GUID_VERSION ||
267             floors[2].lhs.protocol != EPM_PROTOCOL_RPC_C) {
268                 goto failed;
269         }
270         
271         for (i=0;i<count;i++) {
272                 if (guid_cmp(mem_ctx, &floors[0].lhs.info.uuid.uuid, eps[i].uuid) != 0 ||
273                     floors[0].lhs.info.uuid.version != eps[i].if_version) {
274                         continue;
275                 }
276                 switch (eps[i].endpoint.type) {
277                 case ENDPOINT_SMB:
278                         if (floors[3].lhs.protocol != EPM_PROTOCOL_SMB ||
279                             floors[4].lhs.protocol != EPM_PROTOCOL_NETBIOS) {
280                                 continue;
281                         }
282                         break;
283                 case ENDPOINT_TCP:
284                         if (floors[3].lhs.protocol != EPM_PROTOCOL_TCP ||
285                             floors[4].lhs.protocol != EPM_PROTOCOL_IP) {
286                                 continue;
287                         }
288                         break;
289                 }
290                 fill_protocol_tower(mem_ctx, &r->out.towers->twr->towers, &eps[i]);
291                 return NT_STATUS_OK;
292         }
293
294
295 failed:
296         r->out.num_towers = 0;
297         r->out.status = EPMAPPER_STATUS_NO_MORE_ENTRIES;
298         r->out.towers->twr = NULL;
299
300         return NT_STATUS_OK;
301 }
302
303 static NTSTATUS epm_LookupHandleFree(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
304                                      struct epm_LookupHandleFree *r)
305 {
306         return NT_STATUS_NOT_IMPLEMENTED;
307 }
308
309 static NTSTATUS epm_InqObject(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
310                               struct epm_InqObject *r)
311 {
312         return NT_STATUS_NOT_IMPLEMENTED;
313 }
314
315 static NTSTATUS epm_MgmtDelete(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, 
316                                struct epm_MgmtDelete *r)
317 {
318         return NT_STATUS_NOT_IMPLEMENTED;
319 }
320
321
322 /**************************************************************************
323   all the code below this point is boilerplate that will be auto-generated
324 ***************************************************************************/
325
326 static const dcesrv_dispatch_fn_t dispatch_table[] = {
327         (dcesrv_dispatch_fn_t)epm_Insert,
328         (dcesrv_dispatch_fn_t)epm_Delete,
329         (dcesrv_dispatch_fn_t)epm_Lookup,
330         (dcesrv_dispatch_fn_t)epm_Map,
331         (dcesrv_dispatch_fn_t)epm_LookupHandleFree,
332         (dcesrv_dispatch_fn_t)epm_InqObject,
333         (dcesrv_dispatch_fn_t)epm_MgmtDelete
334 };
335
336
337 /*
338   return True if we want to handle the given endpoint
339 */
340 static BOOL op_query_endpoint(const struct dcesrv_endpoint *ep)
341 {
342         return dcesrv_table_query(&dcerpc_table_epmapper, ep);
343 }
344
345 /*
346   setup for a particular rpc interface
347 */
348 static BOOL op_set_interface(struct dcesrv_state *dce, const char *uuid, uint32 if_version)
349 {
350         if (strcasecmp(uuid, dcerpc_table_epmapper.uuid) != 0 ||
351             if_version != dcerpc_table_epmapper.if_version) {
352                 DEBUG(2,("Attempt to use unknown interface %s/%d\n", uuid, if_version));
353                 return False;
354         }
355
356         dce->ndr = &dcerpc_table_epmapper;
357         dce->dispatch = dispatch_table;
358
359         return True;
360 }
361
362
363 /* op_connect is called when a connection is made to an endpoint */
364 static NTSTATUS op_connect(struct dcesrv_state *dce)
365 {
366         return NT_STATUS_OK;
367 }
368
369 static void op_disconnect(struct dcesrv_state *dce)
370 {
371         /* nothing to do */
372 }
373
374
375 static int op_lookup_endpoints(TALLOC_CTX *mem_ctx, struct dcesrv_ep_iface **e)
376 {
377         return dcesrv_lookup_endpoints(&dcerpc_table_epmapper, mem_ctx, e);
378 }
379
380
381 static const struct dcesrv_endpoint_ops rpc_epmapper_ops = {
382         op_query_endpoint,
383         op_set_interface,
384         op_connect,
385         op_disconnect,
386         op_lookup_endpoints
387 };
388
389 /*
390   register with the dcerpc server
391 */
392 void rpc_epmapper_init(struct dcesrv_context *dce)
393 {
394         if (!dcesrv_endpoint_register(dce, &rpc_epmapper_ops, &dcerpc_table_epmapper)) {
395                 DEBUG(1,("Failed to register epmapper endpoint\n"));
396         }
397 }