r3111: Add a few more protocol identifiers, rhs for ncalrpc
[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 #include "rpc_server/common/common.h"
25
26 typedef uint32_t error_status_t;
27
28 /* handle types for this module */
29 enum handle_types {HTYPE_LOOKUP};
30
31 /* a endpoint combined with an interface description */
32 struct dcesrv_ep_iface {
33         const char *name;
34         struct dcesrv_ep_description ep_description;
35         const char *uuid;
36         uint32_t if_version;
37 };
38
39 /*
40   simple routine to compare a GUID string to a GUID structure
41 */
42 static int guid_cmp(TALLOC_CTX *mem_ctx, const struct GUID *guid, const char *uuid_str)
43 {
44         const char *s = GUID_string(mem_ctx, guid);
45         if (!s || strcasecmp(s, uuid_str)) {
46                 return -1;
47         }
48         return 0;
49 }
50
51 /*
52   fill a protocol tower
53 */
54 static BOOL fill_protocol_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr, 
55                                 struct dcesrv_ep_iface *e)
56 {
57         twr->num_floors = 5;
58         twr->floors = talloc_array_p(mem_ctx, struct epm_floor, 5);
59         if (!twr->floors) {
60                 return False;
61         }
62         
63         twr->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
64         GUID_from_string(e->uuid, &twr->floors[0].lhs.info.uuid.uuid);
65         twr->floors[0].lhs.info.uuid.version = e->if_version;
66         twr->floors[0].rhs.uuid.unknown = 0;
67         
68         /* encoded with NDR ... */
69         twr->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
70         GUID_from_string(NDR_GUID, &twr->floors[1].lhs.info.uuid.uuid);
71         twr->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
72         twr->floors[1].rhs.uuid.unknown = 0;
73         
74         /* on an RPC connection ... */
75         twr->floors[2].lhs.protocol = EPM_PROTOCOL_NCACN;
76         twr->floors[2].lhs.info.lhs_data = data_blob(NULL, 0);
77         twr->floors[2].rhs.ncacn.minor_version = 0;
78
79         switch (e->ep_description.type) {
80         case ENDPOINT_SMB:
81                 /* on a SMB pipe ... */
82                 twr->floors[3].lhs.protocol = EPM_PROTOCOL_SMB;
83                 twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
84                 twr->floors[3].rhs.smb.unc = talloc_strdup(mem_ctx, e->ep_description.info.smb_pipe);
85                 
86                 /* on an NetBIOS link ... */
87                 twr->floors[4].lhs.protocol = EPM_PROTOCOL_NETBIOS;
88                 twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
89                 twr->floors[4].rhs.netbios.name = talloc_asprintf(mem_ctx, "\\\\%s", 
90                                                                    lp_netbios_name());
91                 break;
92
93         case ENDPOINT_TCP:
94                 /* on a TCP connection ... */
95                 twr->floors[3].lhs.protocol = EPM_PROTOCOL_TCP;
96                 twr->floors[3].lhs.info.lhs_data = data_blob(NULL, 0);
97                 twr->floors[3].rhs.tcp.port = e->ep_description.info.tcp_port;
98                 
99                 /* on an IP link ... */
100                 twr->floors[4].lhs.protocol = EPM_PROTOCOL_IP;
101                 twr->floors[4].lhs.info.lhs_data = data_blob(NULL, 0);
102                 twr->floors[4].rhs.ip.address = 0;
103                 /* TODO: we should fill in our IP address here as a hint to the 
104                    client */
105                 break;
106         }
107
108         return True;
109 }
110
111
112 /*
113   build a list of all interfaces handled by all endpoint servers
114 */
115 static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
116                               struct dcesrv_endpoint *endpoint_list,
117                               struct dcesrv_ep_iface **eps)
118 {
119         struct dcesrv_endpoint *d;
120         uint32_t total = 0;
121
122         *eps = NULL;
123
124         for (d=endpoint_list; d; d=d->next) {
125                 struct dcesrv_if_list *iface;
126
127                 for (iface=d->interface_list;iface;iface=iface->next) {
128                         (*eps) = talloc_realloc_p(mem_ctx, 
129                                                   *eps, 
130                                                   struct dcesrv_ep_iface,
131                                                   total + 1);
132                         if (!*eps) {
133                                 return 0;
134                         }
135                         (*eps)[total].name = iface->iface.ndr->name;
136                         (*eps)[total].uuid = iface->iface.ndr->uuid;
137                         (*eps)[total].if_version = iface->iface.ndr->if_version;
138                         (*eps)[total].ep_description = d->ep_description;
139                         total++;
140                 }
141         }
142
143         return total;
144 }
145
146
147 static error_status_t epm_Insert(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
148                                  struct epm_Insert *r)
149 {
150         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
151 }
152
153 static error_status_t epm_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
154                                  struct epm_Delete *r)
155 {
156         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
157 }
158
159
160 /*
161   implement epm_Lookup. This call is used to enumerate the interfaces
162   available on a rpc server
163 */
164 static error_status_t epm_Lookup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
165                                  struct epm_Lookup *r)
166 {
167         struct dcesrv_handle *h;
168         struct rpc_eps {
169                 uint32_t count;
170                 struct dcesrv_ep_iface *e;
171         } *eps;
172         uint32_t num_ents;
173         int i;
174
175         h = dcesrv_handle_fetch(dce_call->conn, r->in.entry_handle, HTYPE_LOOKUP);
176         DCESRV_CHECK_HANDLE(h);
177
178         eps = h->data;
179
180         if (!eps) {
181                 /* this is the first call - fill the list. Subsequent calls 
182                    will feed from this list, stored in the handle */
183                 eps = talloc_p(h, struct rpc_eps);
184                 if (!eps) {
185                         return EPMAPPER_STATUS_NO_MEMORY;
186                 }
187                 h->data = eps;
188
189                 eps->count = build_ep_list(h, dce_call->conn->dce_ctx->endpoint_list, &eps->e);
190         }
191
192         /* return the next N elements */
193         num_ents = r->in.max_ents;
194         if (num_ents > eps->count) {
195                 num_ents = eps->count;
196         }
197
198         *r->out.entry_handle = h->wire_handle;
199         r->out.num_ents = num_ents;
200
201         if (num_ents == 0) {
202                 r->out.entries = NULL;
203                 ZERO_STRUCTP(r->out.entry_handle);
204                 dcesrv_handle_destroy(dce_call->conn, h);
205                 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
206         }
207
208         r->out.entries = talloc_array_p(mem_ctx, struct epm_entry_t, num_ents);
209         if (!r->out.entries) {
210                 return EPMAPPER_STATUS_NO_MEMORY;
211         }
212
213         for (i=0;i<num_ents;i++) {
214                 ZERO_STRUCT(r->out.entries[i].object);
215                 r->out.entries[i].annotation = eps->e[i].name;
216                 r->out.entries[i].tower = talloc_p(mem_ctx, struct epm_twr_t);
217                 if (!r->out.entries[i].tower) {
218                         return EPMAPPER_STATUS_NO_MEMORY;
219                 }
220
221                 if (!fill_protocol_tower(mem_ctx, &r->out.entries[i].tower->tower, &eps->e[i])) {
222                         return EPMAPPER_STATUS_NO_MEMORY;
223                 }
224         }
225
226         eps->count -= num_ents;
227         eps->e += num_ents;
228
229         return EPMAPPER_STATUS_OK;
230 }
231
232
233 /*
234   implement epm_Map. This is used to find the specific endpoint to talk to given
235   a generic protocol tower
236 */
237 static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
238                               struct epm_Map *r)
239 {
240         uint32_t count;
241         int i;
242         struct dcesrv_ep_iface *eps;
243         struct epm_floor *floors;
244
245         count = build_ep_list(mem_ctx, dce_call->conn->dce_ctx->endpoint_list, &eps);
246
247         ZERO_STRUCT(*r->out.entry_handle);
248         r->out.num_towers = 1;
249         r->out.towers = talloc_p(mem_ctx, struct epm_twr_p_t);
250         if (!r->out.towers) {
251                 return EPMAPPER_STATUS_NO_MEMORY;
252         }
253         r->out.towers->twr = talloc_p(mem_ctx, struct epm_twr_t);
254         if (!r->out.towers->twr) {
255                 return EPMAPPER_STATUS_NO_MEMORY;
256         }
257         
258         if (!r->in.map_tower || r->in.max_towers == 0 ||
259             r->in.map_tower->tower.num_floors != 5) {
260                 goto failed;
261         }
262
263         floors = r->in.map_tower->tower.floors;
264
265         if (floors[0].lhs.protocol != EPM_PROTOCOL_UUID ||
266             floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
267             guid_cmp(mem_ctx, &floors[1].lhs.info.uuid.uuid, NDR_GUID) != 0 ||
268             floors[1].lhs.info.uuid.version != NDR_GUID_VERSION ||
269             floors[2].lhs.protocol != EPM_PROTOCOL_NCACN) {
270                 goto failed;
271         }
272         
273         for (i=0;i<count;i++) {
274                 if (guid_cmp(mem_ctx, &floors[0].lhs.info.uuid.uuid, eps[i].uuid) != 0 ||
275                     floors[0].lhs.info.uuid.version != eps[i].if_version) {
276                         continue;
277                 }
278                 switch (eps[i].ep_description.type) {
279                 case ENDPOINT_SMB:
280                         if (floors[3].lhs.protocol != EPM_PROTOCOL_SMB ||
281                             floors[4].lhs.protocol != EPM_PROTOCOL_NETBIOS) {
282                                 continue;
283                         }
284                         break;
285                 case ENDPOINT_TCP:
286                         if (floors[3].lhs.protocol != EPM_PROTOCOL_TCP ||
287                             floors[4].lhs.protocol != EPM_PROTOCOL_IP) {
288                                 continue;
289                         }
290                         break;
291                 }
292                 fill_protocol_tower(mem_ctx, &r->out.towers->twr->tower, &eps[i]);
293                 r->out.towers->twr->tower_length = 0;
294                 return EPMAPPER_STATUS_OK;
295         }
296
297
298 failed:
299         r->out.num_towers = 0;
300         r->out.towers->twr = NULL;
301
302         return EPMAPPER_STATUS_NO_MORE_ENTRIES;
303 }
304
305 static error_status_t epm_LookupHandleFree(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
306                                            struct epm_LookupHandleFree *r)
307 {
308         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
309 }
310
311 static error_status_t epm_InqObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
312                                     struct epm_InqObject *r)
313 {
314         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
315 }
316
317 static error_status_t epm_MgmtDelete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, 
318                                struct epm_MgmtDelete *r)
319 {
320         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
321 }
322
323 static error_status_t epm_MapAuth(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
324                             struct epm_MapAuth *r)
325 {
326         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
327 }
328
329 /* include the generated boilerplate */
330 #include "librpc/gen_ndr/ndr_epmapper_s.c"