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