fed5bc6c9dc63513efc5e64b342be310172bcc3c
[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         struct dcerpc_binding           *b;
54         struct composite_context        *pipe_conn_req;
55         uint32_t flags = 0;
56
57         priv = talloc(dce_call->conn, struct dcesrv_remote_private);
58         if (!priv) {
59                 return NT_STATUS_NO_MEMORY;     
60         }
61         
62         priv->c_pipe = NULL;
63         dce_call->context->private_data = priv;
64
65         binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx,
66                                     NULL,
67                                     "dcerpc_remote",
68                                     "binding");
69         if (binding == NULL) {
70                 DEBUG(0,("You must specify a DCE/RPC binding string\n"));
71                 return NT_STATUS_INVALID_PARAMETER;
72         }
73
74         user = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "user");
75         pass = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "password");
76         domain = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dceprc_remote", "domain");
77
78         machine_account = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx,
79                                           NULL,
80                                           "dcerpc_remote",
81                                           "use_machine_account",
82                                           false);
83
84         credentials = dcesrv_call_credentials(dce_call);
85
86         if (user && pass) {
87                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
88                 credentials = cli_credentials_init(priv);
89                 if (!credentials) {
90                         return NT_STATUS_NO_MEMORY;
91                 }
92                 must_free_credentials = true;
93                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
94                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
95                 if (domain) {
96                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
97                 }
98                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
99         } else if (machine_account) {
100                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
101                 credentials = cli_credentials_init(priv);
102                 if (!credentials) {
103                         return NT_STATUS_NO_MEMORY;
104                 }
105                 must_free_credentials = true;
106                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
107                 if (domain) {
108                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
109                 }
110                 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
111                 if (!NT_STATUS_IS_OK(status)) {
112                         return status;
113                 }
114         } else if (credentials != NULL) {
115                 DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
116         } else {
117                 DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
118                 return NT_STATUS_INVALID_PARAMETER;
119         }
120
121         /* parse binding string to the structure */
122         status = dcerpc_parse_binding(dce_call->context, binding, &b);
123         if (!NT_STATUS_IS_OK(status)) {
124                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
125                 return status;
126         }
127
128         /* If we already have a remote association group ID, then use that */
129         if (dce_call->conn->assoc_group->proxied_id != 0) {
130                 status = dcerpc_binding_set_assoc_group_id(b,
131                         dce_call->conn->assoc_group->proxied_id);
132                 if (!NT_STATUS_IS_OK(status)) {
133                         DEBUG(0, ("dcerpc_binding_set_assoc_group_id() - %s'\n",
134                                   nt_errstr(status)));
135                         return status;
136                 }
137         }
138
139         status = dcerpc_binding_set_abstract_syntax(b, &table->syntax_id);
140         if (!NT_STATUS_IS_OK(status)) {
141                 DEBUG(0, ("dcerpc_binding_set_abstract_syntax() - %s'\n",
142                           nt_errstr(status)));
143                 return status;
144         }
145
146         if (dce_call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
147                 status = dcerpc_binding_set_flags(b, DCERPC_CONCURRENT_MULTIPLEX, 0);
148                 if (!NT_STATUS_IS_OK(status)) {
149                         DEBUG(0, ("dcerpc_binding_set_flags(CONC_MPX) - %s'\n",
150                                   nt_errstr(status)));
151                         return status;
152                 }
153         }
154
155         DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
156
157         pipe_conn_req = dcerpc_pipe_connect_b_send(dce_call->context, b, table,
158                                                    credentials, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
159         status = dcerpc_pipe_connect_b_recv(pipe_conn_req, dce_call->context, &(priv->c_pipe));
160         
161         if (must_free_credentials) {
162                 talloc_free(credentials);
163         }
164
165         if (!NT_STATUS_IS_OK(status)) {
166                 return status;
167         }
168
169         flags = dcerpc_binding_get_flags(priv->c_pipe->binding);
170         if (!(flags & DCERPC_CONCURRENT_MULTIPLEX)) {
171                 dce_call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
172         }
173
174         if (dce_call->conn->assoc_group->proxied_id == 0) {
175                 dce_call->conn->assoc_group->proxied_id =
176                         dcerpc_binding_get_assoc_group_id(priv->c_pipe->binding);
177         }
178
179         if (!NT_STATUS_IS_OK(status)) {
180                 return status;
181         }
182
183         return NT_STATUS_OK;    
184 }
185
186 static NTSTATUS remote_get_private(struct dcesrv_call_state *dce_call,
187                                    struct dcesrv_remote_private **_priv)
188 {
189         void *ptr = NULL;
190         struct dcesrv_remote_private *priv = NULL;
191
192         ptr = dce_call->context->private_data;
193         priv = talloc_get_type_abort(ptr, struct dcesrv_remote_private);
194
195         *_priv = priv;
196         return NT_STATUS_OK;
197 }
198
199 static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
200 {
201         enum ndr_err_code ndr_err;
202         const struct ndr_interface_table *table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
203         uint16_t opnum = dce_call->pkt.u.request.opnum;
204
205         dce_call->fault_code = 0;
206
207         if (opnum >= table->num_calls) {
208                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
209                 return NT_STATUS_NET_WRITE_FAULT;
210         }
211
212         /*
213          * We don't have support for calls with pipes.
214          */
215         if (table->calls[opnum].in_pipes.num_pipes != 0) {
216                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
217                 return NT_STATUS_NET_WRITE_FAULT;
218         }
219         if (table->calls[opnum].out_pipes.num_pipes != 0) {
220                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
221                 return NT_STATUS_NET_WRITE_FAULT;
222         }
223
224         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
225         if (!*r) {
226                 return NT_STATUS_NO_MEMORY;
227         }
228
229         /* unravel the NDR for the packet */
230         ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
231         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232                 dcerpc_log_packet(dce_call->conn->packet_log_dir,
233                                                   table, opnum, NDR_IN,
234                                   &dce_call->pkt.u.request.stub_and_verifier);
235                 dce_call->fault_code = DCERPC_FAULT_NDR;
236                 return NT_STATUS_NET_WRITE_FAULT;
237         }
238
239         return NT_STATUS_OK;
240 }
241
242 static void remote_op_dispatch_done(struct tevent_req *subreq);
243
244 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
245 {
246         struct dcesrv_remote_private *priv = NULL;
247         uint16_t opnum = dce_call->pkt.u.request.opnum;
248         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
249         const struct ndr_interface_call *call;
250         const char *name;
251         struct tevent_req *subreq;
252         NTSTATUS status;
253
254         status = remote_get_private(dce_call, &priv);
255         if (!NT_STATUS_IS_OK(status)) {
256                 return status;
257         }
258
259         name = table->calls[opnum].name;
260         call = &table->calls[opnum];
261
262         if (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
263                 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
264         }
265
266         priv->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
267
268         /* we didn't use the return code of this function as we only check the last_fault_code */
269         subreq = dcerpc_binding_handle_call_send(dce_call, dce_call->event_ctx,
270                                                  priv->c_pipe->binding_handle,
271                                                  NULL, table,
272                                                  opnum, mem_ctx, r);
273         if (subreq == NULL) {
274                 DEBUG(0,("dcesrv_remote: call[%s] dcerpc_binding_handle_call_send() failed!\n", name));
275                 return NT_STATUS_NO_MEMORY;
276         }
277         tevent_req_set_callback(subreq, remote_op_dispatch_done, dce_call);
278
279         dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
280         return NT_STATUS_OK;
281 }
282
283 static void remote_op_dispatch_done(struct tevent_req *subreq)
284 {
285         struct dcesrv_call_state *dce_call = tevent_req_callback_data(subreq,
286                                              struct dcesrv_call_state);
287         struct dcesrv_remote_private *priv = talloc_get_type_abort(dce_call->context->private_data,
288                                                                    struct dcesrv_remote_private);
289         uint16_t opnum = dce_call->pkt.u.request.opnum;
290         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
291         const struct ndr_interface_call *call;
292         const char *name;
293         NTSTATUS status;
294
295         name = table->calls[opnum].name;
296         call = &table->calls[opnum];
297
298         /* we didn't use the return code of this function as we only check the last_fault_code */
299         status = dcerpc_binding_handle_call_recv(subreq);
300         TALLOC_FREE(subreq);
301
302         dce_call->fault_code = priv->c_pipe->last_fault_code;
303         if (dce_call->fault_code != 0) {
304                 DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",
305                         name, dcerpc_errstr(dce_call, dce_call->fault_code)));
306                 goto reply;
307         }
308
309         if (NT_STATUS_IS_OK(status) &&
310             (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
311                 ndr_print_function_debug(call->ndr_print, name, NDR_OUT, dce_call->r);
312         }
313
314 reply:
315         status = dcesrv_reply(dce_call);
316         if (!NT_STATUS_IS_OK(status)) {
317                 DEBUG(0,("dcesrv_remote: call[%s]: dcesrv_reply() failed - %s\n",
318                         name, nt_errstr(status)));
319         }
320 }
321
322 static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
323 {
324         enum ndr_err_code ndr_err;
325         const struct ndr_interface_table *table = dce_call->context->iface->private_data;
326         uint16_t opnum = dce_call->pkt.u.request.opnum;
327
328         /* unravel the NDR for the packet */
329         ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
330         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
331                 dce_call->fault_code = DCERPC_FAULT_NDR;
332                 return NT_STATUS_NET_WRITE_FAULT;
333         }
334
335         return NT_STATUS_OK;
336 }
337
338 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
339 {
340         unsigned int i;
341         const struct ndr_interface_table *table = iface->private_data;
342
343         for (i=0;i<table->endpoints->count;i++) {
344                 NTSTATUS ret;
345                 const char *name = table->endpoints->names[i];
346
347                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
348                 if (!NT_STATUS_IS_OK(ret)) {
349                         DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
350                         return ret;
351                 }
352         }
353
354         return NT_STATUS_OK;
355 }
356
357 static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
358 {
359         unsigned int i;
360         char **ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_remote", "interfaces"),NULL);
361
362         if (!ifaces) {
363                 DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
364                 return NT_STATUS_OK;
365         }
366
367         for (i=0;ifaces[i];i++) {
368                 NTSTATUS ret;
369                 struct dcesrv_interface iface;
370                 
371                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
372                         DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
373                         talloc_free(ifaces);
374                         return NT_STATUS_UNSUCCESSFUL;
375                 }
376
377                 ret = remote_register_one_iface(dce_ctx, &iface);
378                 if (!NT_STATUS_IS_OK(ret)) {
379                         DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
380                         talloc_free(ifaces);
381                         return ret;
382                 }
383         }
384
385         talloc_free(ifaces);
386         return NT_STATUS_OK;
387 }
388
389 static bool remote_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *if_tabl)
390 {
391         iface->name = if_tabl->name;
392         iface->syntax_id = if_tabl->syntax_id;
393         
394         iface->bind = remote_op_bind;
395         iface->unbind = NULL;
396
397         iface->ndr_pull = remote_op_ndr_pull;
398         iface->dispatch = remote_op_dispatch;
399         iface->reply = remote_op_reply;
400         iface->ndr_push = remote_op_ndr_push;
401
402         iface->private_data = if_tabl;
403         iface->flags = 0;
404
405         return true;
406 }
407
408 static bool remote_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
409 {
410         const struct ndr_interface_list *l;
411
412         for (l=ndr_table_list();l;l=l->next) {
413                 if (l->table->syntax_id.if_version == if_version &&
414                         GUID_equal(&l->table->syntax_id.uuid, uuid)==0) {
415                         return remote_fill_interface(iface, l->table);
416                 }
417         }
418
419         return false;   
420 }
421
422 static bool remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
423 {
424         const struct ndr_interface_table *tbl = ndr_table_by_name(name);
425
426         if (tbl)
427                 return remote_fill_interface(iface, tbl);
428
429         return false;   
430 }
431
432 NTSTATUS dcerpc_server_remote_init(TALLOC_CTX *ctx)
433 {
434         NTSTATUS ret;
435         static const struct dcesrv_endpoint_server ep_server = {
436                 /* fill in our name */
437                 .name = "remote",
438
439                 /* fill in all the operations */
440                 .init_server = remote_op_init_server,
441
442                 .interface_by_uuid = remote_op_interface_by_uuid,
443                 .interface_by_name = remote_op_interface_by_name
444         };
445
446         /* register ourselves with the DCERPC subsystem. */
447         ret = dcerpc_register_ep_server(&ep_server);
448         if (!NT_STATUS_IS_OK(ret)) {
449                 DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
450                 return ret;
451         }
452
453         /* We need the full DCE/RPC interface table */
454         ndr_table_init();
455
456         return ret;
457 }