9e40a974e0c05e878c617941229f90bde5dcb6d6
[samba.git] / source4 / rpc_server / remote / dcesrv_remote.c
1 /* 
2    Unix SMB/CIFS implementation.
3    remote dcerpc operations
4
5    Copyright (C) Stefan (metze) Metzmacher 2004
6    Copyright (C) Julien Kerihuel 2008-2009
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2010
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include <tevent.h>
25 #include "rpc_server/dcerpc_server.h"
26 #include "auth/auth.h"
27 #include "auth/credentials/credentials.h"
28 #include "librpc/ndr/ndr_table.h"
29 #include "param/param.h"
30
31 NTSTATUS dcerpc_server_remote_init(TALLOC_CTX *ctx);
32
33 struct dcesrv_remote_private {
34         struct dcerpc_pipe *c_pipe;
35 };
36
37 static NTSTATUS remote_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
38 {
39         return NT_STATUS_OK;
40 }
41
42 static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
43 {
44         NTSTATUS status;
45         const struct ndr_interface_table *table =
46                 (const struct ndr_interface_table *)dce_call->context->iface->private_data;
47         struct dcesrv_remote_private *priv;
48         const char *binding = NULL;
49         const char *user, *pass, *domain;
50         struct cli_credentials *credentials;
51         bool must_free_credentials = false;
52         bool machine_account;
53         bool allow_anonymous;
54         struct dcerpc_binding           *b;
55         struct composite_context        *pipe_conn_req;
56         uint32_t flags = 0;
57
58         priv = talloc(dce_call->conn, struct dcesrv_remote_private);
59         if (!priv) {
60                 return NT_STATUS_NO_MEMORY;     
61         }
62         
63         priv->c_pipe = NULL;
64         dce_call->context->private_data = priv;
65
66         binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx,
67                                     NULL,
68                                     "dcerpc_remote",
69                                     "binding");
70         if (binding == NULL) {
71                 DEBUG(0,("You must specify a DCE/RPC binding string\n"));
72                 return NT_STATUS_INVALID_PARAMETER;
73         }
74
75         user = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "user");
76         pass = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "password");
77         domain = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dceprc_remote", "domain");
78
79         machine_account = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
80                                           NULL,
81                                           "dcerpc_remote",
82                                           "use_machine_account",
83                                           false);
84         allow_anonymous = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
85                                           NULL,
86                                           "dcerpc_remote",
87                                           "allow_anonymous_fallback",
88                                           false);
89
90         credentials = dcesrv_call_credentials(dce_call);
91
92         if (user && pass) {
93                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
94                 credentials = cli_credentials_init(priv);
95                 if (!credentials) {
96                         return NT_STATUS_NO_MEMORY;
97                 }
98                 must_free_credentials = true;
99                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
100                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
101                 if (domain) {
102                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
103                 }
104                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
105         } else if (machine_account) {
106                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
107                 credentials = cli_credentials_init(priv);
108                 if (!credentials) {
109                         return NT_STATUS_NO_MEMORY;
110                 }
111                 must_free_credentials = true;
112                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
113                 if (domain) {
114                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
115                 }
116                 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
117                 if (!NT_STATUS_IS_OK(status)) {
118                         return status;
119                 }
120         } else if (credentials != NULL) {
121                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
122         } else if (allow_anonymous) {
123                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using anonymous\n"));
124                 credentials = cli_credentials_init_anon(priv);
125                 if (!credentials) {
126                         return NT_STATUS_NO_MEMORY;
127                 }
128                 must_free_credentials = true;
129         } else {
130                 DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
131                 return NT_STATUS_INVALID_PARAMETER;
132         }
133
134         /* parse binding string to the structure */
135         status = dcerpc_parse_binding(dce_call->context, binding, &b);
136         if (!NT_STATUS_IS_OK(status)) {
137                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
138                 return status;
139         }
140
141         /* If we already have a remote association group ID, then use that */
142         if (dce_call->conn->assoc_group->proxied_id != 0) {
143                 status = dcerpc_binding_set_assoc_group_id(b,
144                         dce_call->conn->assoc_group->proxied_id);
145                 if (!NT_STATUS_IS_OK(status)) {
146                         DEBUG(0, ("dcerpc_binding_set_assoc_group_id() - %s'\n",
147                                   nt_errstr(status)));
148                         return status;
149                 }
150         }
151
152         status = dcerpc_binding_set_abstract_syntax(b, &table->syntax_id);
153         if (!NT_STATUS_IS_OK(status)) {
154                 DEBUG(0, ("dcerpc_binding_set_abstract_syntax() - %s'\n",
155                           nt_errstr(status)));
156                 return status;
157         }
158
159         if (dce_call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
160                 status = dcerpc_binding_set_flags(b, DCERPC_CONCURRENT_MULTIPLEX, 0);
161                 if (!NT_STATUS_IS_OK(status)) {
162                         DEBUG(0, ("dcerpc_binding_set_flags(CONC_MPX) - %s'\n",
163                                   nt_errstr(status)));
164                         return status;
165                 }
166         }
167
168         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
169
170         pipe_conn_req = dcerpc_pipe_connect_b_send(dce_call->context, b, table,
171                                                    credentials, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
172         status = dcerpc_pipe_connect_b_recv(pipe_conn_req, dce_call->context, &(priv->c_pipe));
173         
174         if (must_free_credentials) {
175                 talloc_free(credentials);
176         }
177
178         if (!NT_STATUS_IS_OK(status)) {
179                 return status;
180         }
181
182         if (dce_call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
183                 flags = dcerpc_binding_get_flags(priv->c_pipe->binding);
184                 if (!(flags & DCERPC_CONCURRENT_MULTIPLEX)) {
185                         DEBUG(1,("dcerpc_remote: RPC Proxy: "
186                                  "Remote server doesn't support MPX\n"));
187                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
188                 }
189         }
190
191         if (dce_call->conn->assoc_group->proxied_id == 0) {
192                 dce_call->conn->assoc_group->proxied_id =
193                         dcerpc_binding_get_assoc_group_id(priv->c_pipe->binding);
194         }
195
196         if (!NT_STATUS_IS_OK(status)) {
197                 return status;
198         }
199
200         return NT_STATUS_OK;    
201 }
202
203 static NTSTATUS remote_get_private(struct dcesrv_call_state *dce_call,
204                                    struct dcesrv_remote_private **_priv)
205 {
206         void *ptr = NULL;
207         struct dcesrv_remote_private *priv = NULL;
208
209         ptr = dce_call->context->private_data;
210         priv = talloc_get_type_abort(ptr, struct dcesrv_remote_private);
211
212         *_priv = priv;
213         return NT_STATUS_OK;
214 }
215
216 static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
217 {
218         enum ndr_err_code ndr_err;
219         const struct ndr_interface_table *table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
220         uint16_t opnum = dce_call->pkt.u.request.opnum;
221
222         dce_call->fault_code = 0;
223
224         if (opnum >= table->num_calls) {
225                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
226                 return NT_STATUS_NET_WRITE_FAULT;
227         }
228
229         /*
230          * We don't have support for calls with pipes.
231          */
232         if (table->calls[opnum].in_pipes.num_pipes != 0) {
233                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
234                 return NT_STATUS_NET_WRITE_FAULT;
235         }
236         if (table->calls[opnum].out_pipes.num_pipes != 0) {
237                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
238                 return NT_STATUS_NET_WRITE_FAULT;
239         }
240
241         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
242         if (!*r) {
243                 return NT_STATUS_NO_MEMORY;
244         }
245
246         /* unravel the NDR for the packet */
247         ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
248         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
249                 dcerpc_log_packet(dce_call->conn->packet_log_dir,
250                                                   table, opnum, NDR_IN,
251                                   &dce_call->pkt.u.request.stub_and_verifier);
252                 dce_call->fault_code = DCERPC_FAULT_NDR;
253                 return NT_STATUS_NET_WRITE_FAULT;
254         }
255
256         return NT_STATUS_OK;
257 }
258
259 static void remote_op_dispatch_done(struct tevent_req *subreq);
260
261 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
262 {
263         struct dcesrv_remote_private *priv = NULL;
264         uint16_t opnum = dce_call->pkt.u.request.opnum;
265         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
266         const struct ndr_interface_call *call;
267         const char *name;
268         struct tevent_req *subreq;
269         NTSTATUS status;
270
271         status = remote_get_private(dce_call, &priv);
272         if (!NT_STATUS_IS_OK(status)) {
273                 return status;
274         }
275
276         name = table->calls[opnum].name;
277         call = &table->calls[opnum];
278
279         if (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
280                 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
281         }
282
283         priv->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
284
285         /* we didn't use the return code of this function as we only check the last_fault_code */
286         subreq = dcerpc_binding_handle_call_send(dce_call, dce_call->event_ctx,
287                                                  priv->c_pipe->binding_handle,
288                                                  NULL, table,
289                                                  opnum, mem_ctx, r);
290         if (subreq == NULL) {
291                 DEBUG(0,("dcesrv_remote: call[%s] dcerpc_binding_handle_call_send() failed!\n", name));
292                 return NT_STATUS_NO_MEMORY;
293         }
294         tevent_req_set_callback(subreq, remote_op_dispatch_done, dce_call);
295
296         dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
297         return NT_STATUS_OK;
298 }
299
300 static void remote_op_dispatch_done(struct tevent_req *subreq)
301 {
302         struct dcesrv_call_state *dce_call = tevent_req_callback_data(subreq,
303                                              struct dcesrv_call_state);
304         struct dcesrv_remote_private *priv = talloc_get_type_abort(dce_call->context->private_data,
305                                                                    struct dcesrv_remote_private);
306         uint16_t opnum = dce_call->pkt.u.request.opnum;
307         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
308         const struct ndr_interface_call *call;
309         const char *name;
310         NTSTATUS status;
311
312         name = table->calls[opnum].name;
313         call = &table->calls[opnum];
314
315         /* we didn't use the return code of this function as we only check the last_fault_code */
316         status = dcerpc_binding_handle_call_recv(subreq);
317         TALLOC_FREE(subreq);
318
319         dce_call->fault_code = priv->c_pipe->last_fault_code;
320         if (dce_call->fault_code != 0) {
321                 DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",
322                         name, dcerpc_errstr(dce_call, dce_call->fault_code)));
323                 goto reply;
324         }
325
326         if (NT_STATUS_IS_OK(status) &&
327             (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
328                 ndr_print_function_debug(call->ndr_print, name, NDR_OUT, dce_call->r);
329         }
330
331 reply:
332         status = dcesrv_reply(dce_call);
333         if (!NT_STATUS_IS_OK(status)) {
334                 DEBUG(0,("dcesrv_remote: call[%s]: dcesrv_reply() failed - %s\n",
335                         name, nt_errstr(status)));
336         }
337 }
338
339 static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
340 {
341         enum ndr_err_code ndr_err;
342         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
343         uint16_t opnum = dce_call->pkt.u.request.opnum;
344
345         /* unravel the NDR for the packet */
346         ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
347         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
348                 dce_call->fault_code = DCERPC_FAULT_NDR;
349                 return NT_STATUS_NET_WRITE_FAULT;
350         }
351
352         return NT_STATUS_OK;
353 }
354
355 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
356 {
357         unsigned int i;
358         const struct ndr_interface_table *table = iface->private_data;
359
360         for (i=0;i<table->endpoints->count;i++) {
361                 NTSTATUS ret;
362                 const char *name = table->endpoints->names[i];
363
364                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
365                 if (!NT_STATUS_IS_OK(ret)) {
366                         DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
367                         return ret;
368                 }
369         }
370
371         return NT_STATUS_OK;
372 }
373
374 static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
375 {
376         unsigned int i;
377         char **ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_remote", "interfaces"),NULL);
378
379         if (!ifaces) {
380                 DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
381                 return NT_STATUS_OK;
382         }
383
384         for (i=0;ifaces[i];i++) {
385                 NTSTATUS ret;
386                 struct dcesrv_interface iface;
387                 
388                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
389                         DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
390                         talloc_free(ifaces);
391                         return NT_STATUS_UNSUCCESSFUL;
392                 }
393
394                 ret = remote_register_one_iface(dce_ctx, &iface);
395                 if (!NT_STATUS_IS_OK(ret)) {
396                         DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
397                         talloc_free(ifaces);
398                         return ret;
399                 }
400         }
401
402         talloc_free(ifaces);
403         return NT_STATUS_OK;
404 }
405
406 static bool remote_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *if_tabl)
407 {
408         iface->name = if_tabl->name;
409         iface->syntax_id = if_tabl->syntax_id;
410         
411         iface->bind = remote_op_bind;
412         iface->unbind = NULL;
413
414         iface->ndr_pull = remote_op_ndr_pull;
415         iface->dispatch = remote_op_dispatch;
416         iface->reply = remote_op_reply;
417         iface->ndr_push = remote_op_ndr_push;
418
419         iface->private_data = if_tabl;
420         iface->flags = 0;
421
422         return true;
423 }
424
425 static bool remote_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
426 {
427         const struct ndr_interface_list *l;
428
429         for (l=ndr_table_list();l;l=l->next) {
430                 if (l->table->syntax_id.if_version == if_version &&
431                         GUID_equal(&l->table->syntax_id.uuid, uuid)==0) {
432                         return remote_fill_interface(iface, l->table);
433                 }
434         }
435
436         return false;   
437 }
438
439 static bool remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
440 {
441         const struct ndr_interface_table *tbl = ndr_table_by_name(name);
442
443         if (tbl)
444                 return remote_fill_interface(iface, tbl);
445
446         return false;   
447 }
448
449 NTSTATUS dcerpc_server_remote_init(TALLOC_CTX *ctx)
450 {
451         NTSTATUS ret;
452         static const struct dcesrv_endpoint_server ep_server = {
453                 /* fill in our name */
454                 .name = "remote",
455
456                 /* fill in all the operations */
457                 .init_server = remote_op_init_server,
458
459                 .interface_by_uuid = remote_op_interface_by_uuid,
460                 .interface_by_name = remote_op_interface_by_name
461         };
462
463         /* register ourselves with the DCERPC subsystem. */
464         ret = dcerpc_register_ep_server(&ep_server);
465         if (!NT_STATUS_IS_OK(ret)) {
466                 DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
467                 return ret;
468         }
469
470         /* We need the full DCE/RPC interface table */
471         ndr_table_init();
472
473         return ret;
474 }