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