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