s3:rpc_server: Do not use the default ncalrpc endpoint for external services
[linkinjeon/samba-autobuild/.git] / source3 / rpc_server / rpc_ncacn_np.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1998,
5  *  Largely re-written : 2005
6  *  Copyright (C) Jeremy Allison                1998 - 2005
7  *  Copyright (C) Simo Sorce                    2010
8  *  Copyright (C) Andrew Bartlett               2011
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 3 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "includes.h"
25 #include "rpc_client/cli_pipe.h"
26 #include "rpc_dce.h"
27 #include "../libcli/named_pipe_auth/npa_tstream.h"
28 #include "rpc_server/rpc_ncacn_np.h"
29 #include "librpc/gen_ndr/netlogon.h"
30 #include "librpc/gen_ndr/auth.h"
31 #include "../auth/auth_sam_reply.h"
32 #include "../auth/auth_util.h"
33 #include "auth.h"
34 #include "rpc_server/rpc_pipes.h"
35 #include "../lib/tsocket/tsocket.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "rpc_server/rpc_config.h"
38 #include "librpc/ndr/ndr_table.h"
39 #include "rpc_server/rpc_server.h"
40 #include "librpc/rpc/dcerpc_util.h"
41
42 #undef DBGC_CLASS
43 #define DBGC_CLASS DBGC_RPC_SRV
44
45 struct np_proxy_state {
46         uint16_t file_type;
47         uint16_t device_state;
48         uint64_t allocation_size;
49         struct tstream_context *npipe;
50         struct tevent_queue *read_queue;
51         struct tevent_queue *write_queue;
52 };
53
54 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
55                                 const char *pipe_name,
56                                 const struct tsocket_address *remote_address,
57                                 const struct tsocket_address *local_address,
58                                 const struct auth_session_info *session_info);
59
60 static struct npa_state *npa_state_init(TALLOC_CTX *mem_ctx)
61 {
62         struct npa_state *npa;
63
64         npa = talloc_zero(mem_ctx, struct npa_state);
65         if (npa == NULL) {
66                 return NULL;
67         }
68
69         npa->read_queue = tevent_queue_create(npa, "npa_cli_read");
70         if (npa->read_queue == NULL) {
71                 DEBUG(0, ("tevent_queue_create failed\n"));
72                 goto fail;
73         }
74
75         npa->write_queue = tevent_queue_create(npa, "npa_cli_write");
76         if (npa->write_queue == NULL) {
77                 DEBUG(0, ("tevent_queue_create failed\n"));
78                 goto fail;
79         }
80
81         return npa;
82 fail:
83         talloc_free(npa);
84         return NULL;
85 }
86
87 NTSTATUS make_internal_rpc_pipe_socketpair(
88         TALLOC_CTX *mem_ctx,
89         struct tevent_context *ev_ctx,
90         struct messaging_context *msg_ctx,
91         struct dcesrv_context *dce_ctx,
92         struct dcesrv_endpoint *endpoint,
93         const struct tsocket_address *remote_address,
94         const struct tsocket_address *local_address,
95         const struct auth_session_info *session_info,
96         struct npa_state **pnpa)
97 {
98         TALLOC_CTX *tmp_ctx = talloc_stackframe();
99         struct dcerpc_ncacn_conn *ncacn_conn = NULL;
100         struct dcesrv_connection *dcesrv_conn = NULL;
101         struct npa_state *npa;
102         NTSTATUS status;
103         int rc;
104         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
105                         endpoint->ep_description);
106         const char *pipe_name = dcerpc_binding_get_string_option(
107                         endpoint->ep_description, "endpoint");
108
109         DEBUG(4, ("Create of internal pipe %s requested\n", pipe_name));
110
111         npa = npa_state_init(tmp_ctx);
112         if (npa == NULL) {
113                 status = NT_STATUS_NO_MEMORY;
114                 goto out;
115         }
116
117         npa->file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
118         npa->device_state = 0xff | 0x0400 | 0x0100;
119         npa->allocation_size = 4096;
120
121         status = dcerpc_ncacn_conn_init(npa,
122                                         ev_ctx,
123                                         msg_ctx,
124                                         dce_ctx,
125                                         endpoint,
126                                         NULL, /* termination fn */
127                                         NULL, /* termination data */
128                                         &ncacn_conn);
129         if (!NT_STATUS_IS_OK(status)) {
130                 goto out;
131         }
132
133         npa->private_data = (void*)ncacn_conn;
134
135         rc = tstream_npa_socketpair(npa->file_type,
136                                     npa,
137                                     &npa->stream,
138                                     ncacn_conn,
139                                     &ncacn_conn->tstream);
140         if (rc == -1) {
141                 status = map_nt_error_from_unix(errno);
142                 goto out;
143         }
144
145         ncacn_conn->remote_client_addr = tsocket_address_copy(remote_address,
146                         ncacn_conn);
147         if (ncacn_conn->remote_client_addr == NULL) {
148                 status = NT_STATUS_NO_MEMORY;
149                 goto out;
150         }
151
152         ncacn_conn->remote_client_name = tsocket_address_inet_addr_string(
153                         ncacn_conn->remote_client_addr, ncacn_conn);
154         if (ncacn_conn->remote_client_name == NULL) {
155                 status = NT_STATUS_NO_MEMORY;
156                 goto out;
157         }
158
159         ncacn_conn->local_server_addr = tsocket_address_copy(local_address,
160                         ncacn_conn);
161         if (ncacn_conn->local_server_addr == NULL) {
162                 status = NT_STATUS_NO_MEMORY;
163                 goto out;
164         }
165
166         ncacn_conn->local_server_name = tsocket_address_inet_addr_string(
167                 ncacn_conn->local_server_addr, ncacn_conn);
168         if (ncacn_conn->local_server_name == NULL) {
169                 status = NT_STATUS_NO_MEMORY;
170                 goto out;
171         }
172
173         ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
174         if (ncacn_conn->session_info == NULL) {
175                 status = NT_STATUS_NO_MEMORY;
176                 goto out;
177         }
178
179         rc = make_base_pipes_struct(ncacn_conn,
180                                     ncacn_conn->msg_ctx,
181                                     pipe_name,
182                                     transport,
183                                     ncacn_conn->remote_client_addr,
184                                     ncacn_conn->local_server_addr,
185                                     &ncacn_conn->p);
186         if (rc != 0) {
187                 status = map_nt_error_from_unix(rc);
188                 goto out;
189         }
190
191         /*
192          * This fills in dcesrv_conn->endpoint with the endpoint
193          * associated with the socket.  From this point on we know
194          * which (group of) services we are handling, but not the
195          * specific interface.
196          */
197         status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
198                                          ncacn_conn,
199                                          ncacn_conn->endpoint,
200                                          ncacn_conn->session_info,
201                                          ncacn_conn->ev_ctx,
202                                          DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
203                                          &dcesrv_conn);
204         if (!NT_STATUS_IS_OK(status)) {
205                 DBG_ERR("Failed to connect to endpoint: %s\n",
206                         nt_errstr(status));
207                 goto out;
208         }
209
210         dcesrv_conn->transport.private_data = ncacn_conn;
211         dcesrv_conn->transport.report_output_data =
212                 dcesrv_sock_report_output_data;
213         dcesrv_conn->transport.terminate_connection =
214                 dcesrv_transport_terminate_connection;
215         dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
216                                                       "dcesrv send queue");
217         if (dcesrv_conn->send_queue == NULL) {
218                 status = NT_STATUS_NO_MEMORY;
219                 DBG_ERR("Failed to create send queue: %s\n",
220                         nt_errstr(status));
221                 goto out;
222         }
223
224         dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
225         dcesrv_conn->local_address = ncacn_conn->local_server_addr;
226         dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
227
228         status = dcesrv_connection_loop_start(dcesrv_conn);
229         if (!NT_STATUS_IS_OK(status)) {
230                 DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
231                         nt_errstr(status));
232                 goto out;
233         }
234
235         *pnpa = talloc_move(mem_ctx, &npa);
236         status = NT_STATUS_OK;
237 out:
238         talloc_free(tmp_ctx);
239         return status;
240 }
241
242 static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
243                                 const struct ndr_interface_table *table,
244                                 const struct tsocket_address *remote_address,
245                                 const struct tsocket_address *local_address,
246                                 const struct auth_session_info *session_info,
247                                 struct messaging_context *msg_ctx,
248                                 struct dcerpc_ncacn_conn **_out)
249 {
250         struct dcerpc_ncacn_conn *ncacn_conn = NULL;
251         const char *pipe_name = NULL;
252         NTSTATUS status;
253         int ret;
254
255         pipe_name = dcerpc_default_transport_endpoint(mem_ctx,
256                                                       NCACN_NP,
257                                                       table);
258
259         DBG_INFO("Create pipe requested %s\n", pipe_name);
260
261         ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
262         if (ncacn_conn == NULL) {
263                 return NT_STATUS_NO_MEMORY;
264         }
265
266         ncacn_conn->msg_ctx = msg_ctx;
267
268         if (remote_address != NULL) {
269                 ncacn_conn->remote_client_addr =
270                         tsocket_address_copy(remote_address, ncacn_conn);
271                 if (ncacn_conn->remote_client_addr == NULL) {
272                         status = NT_STATUS_NO_MEMORY;
273                         goto fail;
274                 }
275         }
276
277         if (local_address != NULL) {
278                 ncacn_conn->local_server_addr =
279                         tsocket_address_copy(local_address, ncacn_conn);
280                 if (ncacn_conn->local_server_addr == NULL) {
281                         status = NT_STATUS_NO_MEMORY;
282                         goto fail;
283                 }
284         }
285
286         ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
287         if (ncacn_conn->session_info == NULL) {
288                 status = NT_STATUS_NO_MEMORY;
289                 goto fail;
290         }
291
292         ret = make_base_pipes_struct(ncacn_conn,
293                                      msg_ctx,
294                                      pipe_name,
295                                      NCALRPC,
296                                      ncacn_conn->remote_client_addr,
297                                      ncacn_conn->local_server_addr,
298                                      &ncacn_conn->p);
299         if (ret) {
300                 DBG_ERR("No memory for pipes_struct!\n");
301                 status = NT_STATUS_NO_MEMORY;
302                 goto fail;
303         }
304
305         DEBUG(4,("Created internal pipe %s\n", pipe_name));
306
307         *_out = ncacn_conn;
308
309         return NT_STATUS_OK;
310
311 fail:
312         talloc_free(ncacn_conn);
313         return status;
314 }
315
316 static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
317                                 const struct ndr_interface_table *ndr_table,
318                                 struct dcesrv_endpoint **ep)
319 {
320         TALLOC_CTX *tmp_ctx = NULL;
321         struct dcerpc_binding *binding = NULL;
322         const char *ep_description = NULL;
323         NTSTATUS status;
324
325         tmp_ctx = talloc_new(dce_ctx);
326         if (tmp_ctx == NULL) {
327                 return NT_STATUS_NO_MEMORY;
328         }
329
330         if (rpc_service_mode(ndr_table->name) == RPC_SERVICE_MODE_EXTERNAL) {
331                 ep_description = talloc_asprintf(tmp_ctx, "ncalrpc:[%s]",
332                                 talloc_strdup_upper(tmp_ctx, ndr_table->name));
333                 if (ep_description == NULL) {
334                         status = NT_STATUS_NO_MEMORY;
335                         goto out;
336                 }
337
338                 status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
339                 if (!NT_STATUS_IS_OK(status)) {
340                         goto out;
341                 }
342
343                 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
344                 if (NT_STATUS_IS_OK(status)) {
345                         goto out;
346                 }
347         }
348
349         /*
350          * Some services use a rpcint binding handle in their initialization,
351          * before the server is fully initialized. Search the NCALRPC endpoint
352          * with and without endpoint
353          */
354         status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
355         if (!NT_STATUS_IS_OK(status)) {
356                 goto out;
357         }
358
359         status = dcesrv_find_endpoint(dce_ctx, binding, ep);
360         if (NT_STATUS_IS_OK(status)) {
361                 goto out;
362         }
363
364         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
365                 ep_description = "ncalrpc:[SMBD]";
366         } else {
367                 ep_description = "ncalrpc:[DEFAULT]";
368         }
369
370         status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
371         if (!NT_STATUS_IS_OK(status)) {
372                 goto out;
373         }
374
375         status = dcesrv_find_endpoint(dce_ctx, binding, ep);
376         if (!NT_STATUS_IS_OK(status)) {
377                 goto out;
378         }
379
380 out:
381         talloc_free(tmp_ctx);
382         return status;
383 }
384
385 static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
386                                 const struct ndr_interface_table *ndr_table,
387                                 struct dcerpc_ncacn_conn *ncacn_conn,
388                                 struct dcesrv_connection **_out)
389 {
390         struct dcesrv_connection *conn = NULL;
391         struct dcesrv_connection_context *context = NULL;
392         struct dcesrv_endpoint *endpoint = NULL;
393         NTSTATUS status;
394
395         conn = talloc_zero(mem_ctx, struct dcesrv_connection);
396         if (conn == NULL) {
397                 return NT_STATUS_NO_MEMORY;
398         }
399         conn->dce_ctx = global_dcesrv_context();
400         conn->preferred_transfer = &ndr_transfer_syntax_ndr;
401         conn->transport.private_data = ncacn_conn;
402
403         status = find_ncalrpc_default_endpoint(conn->dce_ctx, ndr_table, &endpoint);
404         if (!NT_STATUS_IS_OK(status)) {
405                 goto fail;
406         }
407         conn->endpoint = endpoint;
408
409         conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
410         if (conn->default_auth_state == NULL) {
411                 status = NT_STATUS_NO_MEMORY;
412                 goto fail;
413         }
414         conn->default_auth_state->session_info = ncacn_conn->session_info;
415         conn->default_auth_state->auth_finished = true;
416
417         context = talloc_zero(conn, struct dcesrv_connection_context);
418         if (context == NULL) {
419                 status = NT_STATUS_NO_MEMORY;
420                 goto fail;
421         }
422         context->conn = conn;
423         context->context_id = 0;
424         context->transfer_syntax = *(conn->preferred_transfer);
425         context->iface = find_interface_by_syntax_id(
426                 conn->endpoint, &ndr_table->syntax_id);
427         if (context->iface == NULL) {
428                 status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
429                 goto fail;
430         }
431
432         DLIST_ADD(conn->contexts, context);
433
434         *_out = conn;
435
436         return NT_STATUS_OK;
437 fail:
438         talloc_free(conn);
439         return status;
440 }
441
442 struct rpcint_bh_state {
443         struct dcesrv_connection *conn;
444 };
445
446 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
447 {
448         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
449                                      struct rpcint_bh_state);
450
451         if (hs->conn == NULL) {
452                 return false;
453         }
454
455         return true;
456 }
457
458 static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
459                                       uint32_t timeout)
460 {
461         /* TODO: implement timeouts */
462         return UINT32_MAX;
463 }
464
465 struct rpcint_bh_raw_call_state {
466         struct dcesrv_call_state *call;
467 };
468
469 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
470                                                   struct tevent_context *ev,
471                                                   struct dcerpc_binding_handle *h,
472                                                   const struct GUID *object,
473                                                   uint32_t opnum,
474                                                   uint32_t in_flags,
475                                                   const uint8_t *in_data,
476                                                   size_t in_length)
477 {
478         struct rpcint_bh_state *hs =
479                 dcerpc_binding_handle_data(h,
480                 struct rpcint_bh_state);
481         struct tevent_req *req;
482         struct rpcint_bh_raw_call_state *state;
483         struct dcesrv_context *dce_ctx = global_dcesrv_context();
484         bool ok;
485         NTSTATUS status;
486
487         req = tevent_req_create(mem_ctx, &state,
488                                 struct rpcint_bh_raw_call_state);
489         if (req == NULL) {
490                 return NULL;
491         }
492
493         ok = rpcint_bh_is_connected(h);
494         if (!ok) {
495                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
496                 return tevent_req_post(req, ev);
497         }
498
499         state->call = talloc_zero(state, struct dcesrv_call_state);
500         if (tevent_req_nomem(state->call, req)) {
501                 return tevent_req_post(req, ev);
502         }
503
504         state->call->event_ctx = ev;
505         state->call->conn = hs->conn;
506         state->call->context = hs->conn->contexts;
507         state->call->auth_state = hs->conn->default_auth_state;
508
509         if (hs->conn->assoc_group == NULL) {
510                 ZERO_STRUCT(state->call->pkt);
511                 state->call->pkt.u.bind.assoc_group_id = 0;
512                 status = dce_ctx->callbacks->assoc_group.find(
513                         state->call,
514                         dce_ctx->callbacks->assoc_group.private_data);
515                 if (tevent_req_nterror(req, status)) {
516                         return tevent_req_post(req, ev);
517                 }
518         }
519
520         ZERO_STRUCT(state->call->pkt);
521         state->call->pkt.u.request.opnum = opnum;
522         state->call->pkt.u.request.context_id = 0;
523         state->call->pkt.u.request.stub_and_verifier.data = discard_const_p(uint8_t, in_data);
524         state->call->pkt.u.request.stub_and_verifier.length = in_length;
525
526         /* TODO: allow async */
527         status = dcesrv_call_dispatch_local(state->call);
528         if (!NT_STATUS_IS_OK(status)) {
529                 tevent_req_nterror(req, status);
530                 return tevent_req_post(req, ev);
531         }
532
533         tevent_req_done(req);
534         return tevent_req_post(req, ev);
535 }
536
537 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
538                                         TALLOC_CTX *mem_ctx,
539                                         uint8_t **out_data,
540                                         size_t *out_length,
541                                         uint32_t *out_flags)
542 {
543         struct rpcint_bh_raw_call_state *state =
544                 tevent_req_data(req,
545                 struct rpcint_bh_raw_call_state);
546         struct data_blob_list_item *rep = NULL;
547         NTSTATUS status;
548
549         if (tevent_req_is_nterror(req, &status)) {
550                 tevent_req_received(req);
551                 return status;
552         }
553
554         rep = state->call->replies;
555         DLIST_REMOVE(state->call->replies, rep);
556
557         *out_data = talloc_steal(mem_ctx, rep->blob.data);
558         *out_length = rep->blob.length;
559         *out_flags = 0;
560
561         talloc_free(rep);
562
563         tevent_req_received(req);
564         return NT_STATUS_OK;
565 }
566
567 struct rpcint_bh_disconnect_state {
568         uint8_t _dummy;
569 };
570
571 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
572                                                 struct tevent_context *ev,
573                                                 struct dcerpc_binding_handle *h)
574 {
575         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
576                                      struct rpcint_bh_state);
577         struct tevent_req *req;
578         struct rpcint_bh_disconnect_state *state;
579         bool ok;
580
581         req = tevent_req_create(mem_ctx, &state,
582                                 struct rpcint_bh_disconnect_state);
583         if (req == NULL) {
584                 return NULL;
585         }
586
587         ok = rpcint_bh_is_connected(h);
588         if (!ok) {
589                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
590                 return tevent_req_post(req, ev);
591         }
592
593         /*
594          * TODO: do a real async disconnect ...
595          *
596          * For now the caller needs to free dcesrv_connection
597          */
598         hs->conn = NULL;
599
600         tevent_req_done(req);
601         return tevent_req_post(req, ev);
602 }
603
604 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
605 {
606         NTSTATUS status;
607
608         if (tevent_req_is_nterror(req, &status)) {
609                 tevent_req_received(req);
610                 return status;
611         }
612
613         tevent_req_received(req);
614         return NT_STATUS_OK;
615 }
616
617 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
618 {
619         return true;
620 }
621
622 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
623                                    int ndr_flags,
624                                    const void *_struct_ptr,
625                                    const struct ndr_interface_call *call)
626 {
627         void *struct_ptr = discard_const(_struct_ptr);
628
629         if (DEBUGLEVEL < 11) {
630                 return;
631         }
632
633         if (ndr_flags & NDR_IN) {
634                 ndr_print_function_debug(call->ndr_print,
635                                          call->name,
636                                          ndr_flags,
637                                          struct_ptr);
638         }
639         if (ndr_flags & NDR_OUT) {
640                 ndr_print_function_debug(call->ndr_print,
641                                          call->name,
642                                          ndr_flags,
643                                          struct_ptr);
644         }
645 }
646
647 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
648         .name                   = "rpcint",
649         .is_connected           = rpcint_bh_is_connected,
650         .set_timeout            = rpcint_bh_set_timeout,
651         .raw_call_send          = rpcint_bh_raw_call_send,
652         .raw_call_recv          = rpcint_bh_raw_call_recv,
653         .disconnect_send        = rpcint_bh_disconnect_send,
654         .disconnect_recv        = rpcint_bh_disconnect_recv,
655
656         .ref_alloc              = rpcint_bh_ref_alloc,
657         .do_ndr_print           = rpcint_bh_do_ndr_print,
658 };
659
660 static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
661                         const struct ndr_syntax_id *abstract_syntax,
662                         const struct ndr_interface_table *ndr_table,
663                         const struct tsocket_address *remote_address,
664                         const struct tsocket_address *local_address,
665                         const struct auth_session_info *session_info,
666                         struct messaging_context *msg_ctx,
667                         struct dcerpc_binding_handle **binding_handle)
668 {
669         struct dcerpc_binding_handle *h;
670         struct rpcint_bh_state *hs;
671         struct dcerpc_ncacn_conn *ncacn_conn = NULL;
672         NTSTATUS status;
673
674         h = dcerpc_binding_handle_create(mem_ctx,
675                                          &rpcint_bh_ops,
676                                          NULL,
677                                          ndr_table,
678                                          &hs,
679                                          struct rpcint_bh_state,
680                                          __location__);
681         if (h == NULL) {
682                 return NT_STATUS_NO_MEMORY;
683         }
684
685         status = make_internal_ncacn_conn(hs,
686                                           ndr_table,
687                                           remote_address,
688                                           local_address,
689                                           session_info,
690                                           msg_ctx,
691                                           &ncacn_conn);
692         if (!NT_STATUS_IS_OK(status)) {
693                 TALLOC_FREE(h);
694                 return status;
695         }
696
697         status = make_internal_dcesrv_connection(ncacn_conn,
698                                                  ndr_table,
699                                                  ncacn_conn,
700                                                  &hs->conn);
701         if (!NT_STATUS_IS_OK(status)) {
702                 TALLOC_FREE(h);
703                 return status;
704         }
705
706         *binding_handle = h;
707         return NT_STATUS_OK;
708 }
709 /**
710  * @brief Create a new DCERPC Binding Handle which uses a local dispatch function.
711  *
712  * @param[in]  mem_ctx  The memory context to use.
713  *
714  * @param[in]  ndr_table Normally the ndr_table_<name>.
715  *
716  * @param[in]  remote_address The info about the connected client.
717  *
718  * @param[in]  serversupplied_info The server supplied authentication function.
719  *
720  * @param[in]  msg_ctx   The messaging context that can be used by the server
721  *
722  * @param[out] binding_handle  A pointer to store the connected
723  *                             dcerpc_binding_handle
724  *
725  * @return              NT_STATUS_OK on success, a corresponding NT status if an
726  *                      error occurred.
727  *
728  * @code
729  *   struct dcerpc_binding_handle *winreg_binding;
730  *   NTSTATUS status;
731  *
732  *   status = rpcint_binding_handle(tmp_ctx,
733  *                                  &ndr_table_winreg,
734  *                                  p->remote_address,
735  *                                  p->session_info,
736  *                                  p->msg_ctx
737  *                                  &winreg_binding);
738  * @endcode
739  */
740 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
741                                const struct ndr_interface_table *ndr_table,
742                                const struct tsocket_address *remote_address,
743                                const struct tsocket_address *local_address,
744                                const struct auth_session_info *session_info,
745                                struct messaging_context *msg_ctx,
746                                struct dcerpc_binding_handle **binding_handle)
747 {
748         return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, remote_address,
749                                         local_address, session_info,
750                                         msg_ctx, binding_handle);
751 }
752
753 /**
754  * @internal
755  *
756  * @brief Create a new RPC client context which uses a local transport.
757  *
758  * This creates a local transport. It is a shortcut to directly call the server
759  * functions and avoid marshalling.
760  * NOTE: this function should be used only by rpc_pipe_open_interface()
761  *
762  * @param[in]  mem_ctx  The memory context to use.
763  *
764  * @param[in]  ndr_table the ndr_table_<name> structure.
765  *
766  * @param[in]  serversupplied_info The server supplied authentication function.
767  *
768  * @param[in]  remote_address The client address information.
769  *
770  * @param[in]  msg_ctx  The messaging context to use.
771  *
772  * @param[out] presult  A pointer to store the connected rpc client pipe.
773  *
774  * @return              NT_STATUS_OK on success, a corresponding NT status if an
775  *                      error occurred.
776  */
777 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
778                                 const struct ndr_interface_table *ndr_table,
779                                 const struct auth_session_info *session_info,
780                                 const struct tsocket_address *remote_address,
781                                 const struct tsocket_address *local_address,
782                                 struct messaging_context *msg_ctx,
783                                 struct rpc_pipe_client **presult)
784 {
785         struct rpc_pipe_client *result;
786         NTSTATUS status;
787
788         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
789         if (result == NULL) {
790                 return NT_STATUS_NO_MEMORY;
791         }
792
793         result->abstract_syntax = ndr_table->syntax_id;
794         result->transfer_syntax = ndr_transfer_syntax_ndr;
795
796         if (remote_address == NULL) {
797                 struct tsocket_address *local;
798                 int rc;
799
800                 rc = tsocket_address_inet_from_strings(mem_ctx,
801                                                        "ip",
802                                                        "127.0.0.1",
803                                                        0,
804                                                        &local);
805                 if (rc < 0) {
806                         TALLOC_FREE(result);
807                         return NT_STATUS_NO_MEMORY;
808                 }
809
810                 remote_address = local;
811         }
812
813         result->max_xmit_frag = -1;
814
815         status = rpcint_binding_handle(result,
816                                        ndr_table,
817                                        remote_address,
818                                        local_address,
819                                        session_info,
820                                        msg_ctx,
821                                        &result->binding_handle);
822         if (!NT_STATUS_IS_OK(status)) {
823                 TALLOC_FREE(result);
824                 return status;
825         }
826
827         *presult = result;
828         return NT_STATUS_OK;
829 }
830
831 /****************************************************************************
832  * External pipes functions
833  ***************************************************************************/
834
835 NTSTATUS make_external_rpc_pipe(TALLOC_CTX *mem_ctx,
836                                 const char *pipe_name,
837                                 const struct tsocket_address *remote_client_address,
838                                 const struct tsocket_address *local_server_address,
839                                 const struct auth_session_info *session_info,
840                                 struct npa_state **pnpa)
841 {
842         TALLOC_CTX *tmp_ctx = talloc_stackframe();
843         struct auth_session_info_transport *session_info_t;
844         struct tevent_context *ev_ctx;
845         struct tevent_req *subreq;
846         const char *socket_np_dir;
847         const char *socket_dir;
848         struct npa_state *npa;
849         int sys_errno;
850         NTSTATUS status;
851         int rc = -1;
852         bool ok;
853
854         npa = npa_state_init(tmp_ctx);
855         if (npa == NULL) {
856                 status = NT_STATUS_NO_MEMORY;
857                 goto out;
858         }
859
860         socket_dir = lp_parm_const_string(GLOBAL_SECTION_SNUM,
861                                           "external_rpc_pipe",
862                                           "socket_dir",
863                                           lp_ncalrpc_dir());
864         if (socket_dir == NULL) {
865                 DEBUG(0, ("external_rpc_pipe: socket_dir not set\n"));
866                 status = NT_STATUS_PIPE_NOT_AVAILABLE;
867                 goto out;
868         }
869
870         socket_np_dir = talloc_asprintf(tmp_ctx, "%s/np", socket_dir);
871         if (socket_np_dir == NULL) {
872                 DEBUG(0, ("talloc_asprintf failed\n"));
873                 status = NT_STATUS_NO_MEMORY;
874                 goto out;
875         }
876
877         session_info_t = talloc_zero(tmp_ctx,
878                                      struct auth_session_info_transport);
879         if (session_info_t == NULL) {
880                 DEBUG(0, ("talloc failed\n"));
881                 status = NT_STATUS_NO_MEMORY;
882                 goto out;
883         }
884
885         session_info_t->session_info = copy_session_info(session_info_t,
886                                                          session_info);
887         if (session_info_t->session_info == NULL) {
888                 DEBUG(0, ("copy_session_info failed\n"));
889                 status = NT_STATUS_NO_MEMORY;
890                 goto out;
891         }
892
893         ev_ctx = samba_tevent_context_init(tmp_ctx);
894         if (ev_ctx == NULL) {
895                 DEBUG(0, ("samba_tevent_context_init failed\n"));
896                 status = NT_STATUS_NO_MEMORY;
897                 goto out;
898         }
899
900         become_root();
901         subreq = tstream_npa_connect_send(tmp_ctx,
902                                           ev_ctx,
903                                           socket_np_dir,
904                                           pipe_name,
905                                           remote_client_address,
906                                           NULL, /* client_name */
907                                           local_server_address,
908                                           NULL, /* server_name */
909                                           session_info_t);
910         if (subreq == NULL) {
911                 unbecome_root();
912                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
913                           "user %s\\%s failed\n",
914                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
915                           session_info_t->session_info->info->account_name));
916                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
917                 goto out;
918         }
919         ok = tevent_req_poll(subreq, ev_ctx);
920         unbecome_root();
921         if (!ok) {
922                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
923                           "failed for tstream_npa_connect: %s\n",
924                           socket_np_dir,
925                           pipe_name,
926                           session_info_t->session_info->info->domain_name,
927                           session_info_t->session_info->info->account_name,
928                           strerror(errno)));
929                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
930                 goto out;
931         }
932
933         rc = tstream_npa_connect_recv(subreq,
934                                       &sys_errno,
935                                       npa,
936                                       &npa->stream,
937                                       &npa->file_type,
938                                       &npa->device_state,
939                                       &npa->allocation_size);
940         talloc_free(subreq);
941         if (rc != 0) {
942                 int l = 1;
943
944                 if (errno == ENOENT) {
945                         l = 2;
946                 }
947
948                 DEBUG(l, ("tstream_npa_connect_recv  to %s for pipe %s and "
949                           "user %s\\%s failed: %s\n",
950                           socket_np_dir,
951                           pipe_name,
952                           session_info_t->session_info->info->domain_name,
953                           session_info_t->session_info->info->account_name,
954                           strerror(sys_errno)));
955                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
956                 goto out;
957         }
958
959         *pnpa = talloc_steal(mem_ctx, npa);
960         status = NT_STATUS_OK;
961 out:
962         talloc_free(tmp_ctx);
963
964         return status;
965 }
966
967 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
968                                 const char *pipe_name,
969                                 const struct tsocket_address *remote_address,
970                                 const struct tsocket_address *local_address,
971                                 const struct auth_session_info *session_info)
972 {
973         struct np_proxy_state *result;
974         char *socket_np_dir;
975         const char *socket_dir;
976         struct tevent_context *ev;
977         struct tevent_req *subreq;
978         struct auth_session_info_transport *session_info_t;
979         bool ok;
980         int ret;
981         int sys_errno;
982
983         result = talloc(mem_ctx, struct np_proxy_state);
984         if (result == NULL) {
985                 DEBUG(0, ("talloc failed\n"));
986                 return NULL;
987         }
988
989         result->read_queue = tevent_queue_create(result, "np_read");
990         if (result->read_queue == NULL) {
991                 DEBUG(0, ("tevent_queue_create failed\n"));
992                 goto fail;
993         }
994
995         result->write_queue = tevent_queue_create(result, "np_write");
996         if (result->write_queue == NULL) {
997                 DEBUG(0, ("tevent_queue_create failed\n"));
998                 goto fail;
999         }
1000
1001         ev = samba_tevent_context_init(talloc_tos());
1002         if (ev == NULL) {
1003                 DEBUG(0, ("samba_tevent_context_init failed\n"));
1004                 goto fail;
1005         }
1006
1007         socket_dir = lp_parm_const_string(
1008                 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
1009                 lp_ncalrpc_dir());
1010         if (socket_dir == NULL) {
1011                 DEBUG(0, ("external_rpc_pipe:socket_dir not set\n"));
1012                 goto fail;
1013         }
1014         socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
1015         if (socket_np_dir == NULL) {
1016                 DEBUG(0, ("talloc_asprintf failed\n"));
1017                 goto fail;
1018         }
1019
1020         session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
1021         if (session_info_t == NULL) {
1022                 DEBUG(0, ("talloc failed\n"));
1023                 goto fail;
1024         }
1025
1026         session_info_t->session_info = copy_session_info(session_info_t,
1027                                                          session_info);
1028         if (session_info_t->session_info == NULL) {
1029                 DEBUG(0, ("copy_session_info failed\n"));
1030                 goto fail;
1031         }
1032
1033         become_root();
1034         subreq = tstream_npa_connect_send(talloc_tos(), ev,
1035                                           socket_np_dir,
1036                                           pipe_name,
1037                                           remote_address,
1038                                           NULL, /* client_name */
1039                                           local_address,
1040                                           NULL, /* server_name */
1041                                           session_info_t);
1042         if (subreq == NULL) {
1043                 unbecome_root();
1044                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
1045                           "user %s\\%s failed\n",
1046                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1047                           session_info_t->session_info->info->account_name));
1048                 goto fail;
1049         }
1050         ok = tevent_req_poll(subreq, ev);
1051         unbecome_root();
1052         if (!ok) {
1053                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
1054                           "failed for tstream_npa_connect: %s\n",
1055                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1056                           session_info_t->session_info->info->account_name,
1057                           strerror(errno)));
1058                 goto fail;
1059
1060         }
1061         ret = tstream_npa_connect_recv(subreq, &sys_errno,
1062                                        result,
1063                                        &result->npipe,
1064                                        &result->file_type,
1065                                        &result->device_state,
1066                                        &result->allocation_size);
1067         TALLOC_FREE(subreq);
1068         if (ret != 0) {
1069                 int l = 1;
1070                 if (sys_errno == ENOENT) {
1071                         l = 2;
1072                 }
1073                 DEBUG(l, ("tstream_npa_connect_recv  to %s for pipe %s and "
1074                           "user %s\\%s failed: %s\n",
1075                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1076                           session_info_t->session_info->info->account_name,
1077                           strerror(sys_errno)));
1078                 goto fail;
1079         }
1080
1081         return result;
1082
1083  fail:
1084         TALLOC_FREE(result);
1085         return NULL;
1086 }
1087
1088 static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
1089                                        const char *pipe_name,
1090                                        const struct ndr_interface_table *table,
1091                                        const struct auth_session_info *session_info,
1092                                        const struct tsocket_address *remote_client_address,
1093                                        const struct tsocket_address *local_server_address,
1094                                        struct rpc_pipe_client **_result)
1095 {
1096         struct rpc_pipe_client *result = NULL;
1097         struct np_proxy_state *proxy_state = NULL;
1098         struct pipe_auth_data *auth;
1099         struct tsocket_address *remote_client_addr;
1100         struct tsocket_address *local_server_addr;
1101         NTSTATUS status;
1102         int ret;
1103
1104         if (local_server_address == NULL) {
1105                 /* this is an internal connection, fake up ip addresses */
1106                 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1107                                                         NULL, 0, &local_server_addr);
1108                 if (ret) {
1109                         return NT_STATUS_NO_MEMORY;
1110                 }
1111                 local_server_address = local_server_addr;
1112         }
1113
1114         if (remote_client_address == NULL) {
1115                 /* this is an internal connection, fake up ip addresses */
1116                 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1117                                                         NULL, 0, &remote_client_addr);
1118                 if (ret) {
1119                         return NT_STATUS_NO_MEMORY;
1120                 }
1121                 remote_client_address = remote_client_addr;
1122         }
1123
1124         proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
1125                                                remote_client_address,
1126                                                local_server_address,
1127                                                session_info);
1128         if (!proxy_state) {
1129                 DEBUG(1, ("Unable to make proxy_state for connection to %s.\n", pipe_name));
1130                 return NT_STATUS_UNSUCCESSFUL;
1131         }
1132
1133         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
1134         if (result == NULL) {
1135                 status = NT_STATUS_NO_MEMORY;
1136                 goto done;
1137         }
1138
1139         result->abstract_syntax = table->syntax_id;
1140         result->transfer_syntax = ndr_transfer_syntax_ndr;
1141
1142         result->desthost = get_myname(result);
1143         result->srv_name_slash = talloc_asprintf_strupper_m(
1144                 result, "\\\\%s", result->desthost);
1145         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
1146                 status = NT_STATUS_NO_MEMORY;
1147                 goto done;
1148         }
1149
1150         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
1151
1152         status = rpc_transport_tstream_init(result,
1153                                             &proxy_state->npipe,
1154                                             &result->transport);
1155         if (!NT_STATUS_IS_OK(status)) {
1156                 goto done;
1157         }
1158
1159         result->binding_handle = rpccli_bh_create(result, NULL, table);
1160         if (result->binding_handle == NULL) {
1161                 status = NT_STATUS_NO_MEMORY;
1162                 DEBUG(0, ("Failed to create binding handle.\n"));
1163                 goto done;
1164         }
1165
1166         result->auth = talloc_zero(result, struct pipe_auth_data);
1167         if (!result->auth) {
1168                 status = NT_STATUS_NO_MEMORY;
1169                 goto done;
1170         }
1171         result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
1172         result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
1173         result->auth->auth_context_id = 0;
1174
1175         status = rpccli_anon_bind_data(result, &auth);
1176         if (!NT_STATUS_IS_OK(status)) {
1177                 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
1178                 goto done;
1179         }
1180
1181         status = rpc_pipe_bind(result, auth);
1182         if (!NT_STATUS_IS_OK(status)) {
1183                 DEBUG(0, ("Failed to bind external pipe.\n"));
1184                 goto done;
1185         }
1186
1187 done:
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 TALLOC_FREE(result);
1190         }
1191         TALLOC_FREE(proxy_state);
1192         *_result = result;
1193         return status;
1194 }
1195
1196 /**
1197  * @brief Create a new RPC client context which uses a local dispatch function
1198  *        or a remote transport, depending on rpc_server configuration for the
1199  *        specific service.
1200  *
1201  * @param[in]  mem_ctx  The memory context to use.
1202  *
1203  * @param[in]  abstract_syntax Normally the syntax_id of the autogenerated
1204  *                             ndr_table_<name>.
1205  *
1206  * @param[in]  serversupplied_info The server supplied authentication function.
1207  *
1208  * @param[in]  remote_address The client address information.
1209  *
1210  * @param[in]  msg_ctx  The messaging context to use.
1211  *
1212  * @param[out] presult  A pointer to store the connected rpc client pipe.
1213  *
1214  * @return              NT_STATUS_OK on success, a corresponding NT status if an
1215  *                      error occurred.
1216  *
1217  * @code
1218  *   struct rpc_pipe_client *winreg_pipe;
1219  *   NTSTATUS status;
1220  *
1221  *   status = rpc_pipe_open_interface(tmp_ctx,
1222  *                                    &ndr_table_winreg.syntax_id,
1223  *                                    p->session_info,
1224  *                                    remote_address,
1225  *                                    &winreg_pipe);
1226  * @endcode
1227  */
1228
1229 NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
1230                                  const struct ndr_interface_table *table,
1231                                  const struct auth_session_info *session_info,
1232                                  const struct tsocket_address *remote_address,
1233                                  const struct tsocket_address *local_address,
1234                                  struct messaging_context *msg_ctx,
1235                                  struct rpc_pipe_client **cli_pipe)
1236 {
1237         struct rpc_pipe_client *cli = NULL;
1238         enum rpc_service_mode_e pipe_mode;
1239         const char *pipe_name;
1240         NTSTATUS status;
1241         TALLOC_CTX *tmp_ctx;
1242
1243         if (cli_pipe != NULL) {
1244                 if (rpccli_is_connected(*cli_pipe)) {
1245                         return NT_STATUS_OK;
1246                 } else {
1247                         TALLOC_FREE(*cli_pipe);
1248                 }
1249         }
1250
1251         tmp_ctx = talloc_stackframe();
1252         if (tmp_ctx == NULL) {
1253                 return NT_STATUS_NO_MEMORY;
1254         }
1255
1256         pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
1257         if (pipe_name == NULL) {
1258                 DEBUG(1, ("Unable to find pipe name to forward %s to.\n", table->name));
1259                 status = NT_STATUS_INVALID_PARAMETER;
1260                 goto done;
1261         }
1262
1263         while (pipe_name[0] == '\\') {
1264                 pipe_name++;
1265         }
1266
1267         DEBUG(5, ("Connecting to %s pipe.\n", pipe_name));
1268
1269         pipe_mode = rpc_service_mode(pipe_name);
1270
1271         switch (pipe_mode) {
1272         case RPC_SERVICE_MODE_EMBEDDED:
1273                 status = rpc_pipe_open_internal(tmp_ctx,
1274                                                 table, session_info,
1275                                                 remote_address, local_address,
1276                                                 msg_ctx,
1277                                                 &cli);
1278                 if (!NT_STATUS_IS_OK(status)) {
1279                         goto done;
1280                 }
1281                 break;
1282         case RPC_SERVICE_MODE_EXTERNAL:
1283                 /* It would be nice to just use rpc_pipe_open_ncalrpc() but
1284                  * for now we need to use the special proxy setup to connect
1285                  * to spoolssd. */
1286
1287                 status = rpc_pipe_open_external(tmp_ctx,
1288                                                 pipe_name, table,
1289                                                 session_info,
1290                                                 remote_address, local_address,
1291                                                 &cli);
1292                 if (!NT_STATUS_IS_OK(status)) {
1293                         goto done;
1294                 }
1295                 break;
1296         case RPC_SERVICE_MODE_DISABLED:
1297                 status = NT_STATUS_NOT_IMPLEMENTED;
1298                 DEBUG(0, ("Service pipe %s is disabled in config file: %s",
1299                           pipe_name, nt_errstr(status)));
1300                 goto done;
1301         }
1302
1303         status = NT_STATUS_OK;
1304 done:
1305         if (NT_STATUS_IS_OK(status) && cli_pipe != NULL) {
1306                 *cli_pipe = talloc_move(mem_ctx, &cli);
1307         }
1308         TALLOC_FREE(tmp_ctx);
1309         return status;
1310 }