torture3: Fix CID 1435119 Error handling issues (CHECKED_RETURN)
[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_server/srv_pipe_internal.h"
27 #include "rpc_dce.h"
28 #include "../libcli/named_pipe_auth/npa_tstream.h"
29 #include "rpc_server/rpc_ncacn_np.h"
30 #include "librpc/gen_ndr/netlogon.h"
31 #include "librpc/gen_ndr/auth.h"
32 #include "../auth/auth_sam_reply.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 static struct npa_state *npa_state_init(TALLOC_CTX *mem_ctx)
46 {
47         struct npa_state *npa;
48
49         npa = talloc_zero(mem_ctx, struct npa_state);
50         if (npa == NULL) {
51                 return NULL;
52         }
53
54         npa->read_queue = tevent_queue_create(npa, "npa_cli_read");
55         if (npa->read_queue == NULL) {
56                 DEBUG(0, ("tevent_queue_create failed\n"));
57                 goto fail;
58         }
59
60         npa->write_queue = tevent_queue_create(npa, "npa_cli_write");
61         if (npa->write_queue == NULL) {
62                 DEBUG(0, ("tevent_queue_create failed\n"));
63                 goto fail;
64         }
65
66         return npa;
67 fail:
68         talloc_free(npa);
69         return NULL;
70 }
71
72 NTSTATUS make_internal_rpc_pipe_socketpair(
73         TALLOC_CTX *mem_ctx,
74         struct tevent_context *ev_ctx,
75         struct messaging_context *msg_ctx,
76         const char *pipe_name,
77         const struct ndr_syntax_id *syntax,
78         const struct tsocket_address *remote_address,
79         const struct tsocket_address *local_address,
80         const struct auth_session_info *session_info,
81         struct npa_state **pnpa)
82 {
83         TALLOC_CTX *tmp_ctx = talloc_stackframe();
84         struct named_pipe_client *npc;
85         struct tevent_req *subreq;
86         struct npa_state *npa;
87         NTSTATUS status;
88         int error;
89         int rc;
90
91         DEBUG(4, ("Create of internal pipe %s requested\n", pipe_name));
92
93         npa = npa_state_init(tmp_ctx);
94         if (npa == NULL) {
95                 status = NT_STATUS_NO_MEMORY;
96                 goto out;
97         }
98
99         npa->file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
100         npa->device_state = 0xff | 0x0400 | 0x0100;
101         npa->allocation_size = 4096;
102
103         npc = named_pipe_client_init(npa,
104                                      ev_ctx,
105                                      msg_ctx,
106                                      pipe_name,
107                                      NULL, /* term_fn */
108                                      npa->file_type,
109                                      npa->device_state,
110                                      npa->allocation_size,
111                                      NULL); /* private_data */
112         if (npc == NULL) {
113                 status = NT_STATUS_NO_MEMORY;
114                 goto out;
115         }
116         npa->private_data = (void*) npc;
117
118         rc = tstream_npa_socketpair(npa->file_type,
119                                     npa,
120                                     &npa->stream,
121                                     npc,
122                                     &npc->tstream);
123         if (rc == -1) {
124                 status = map_nt_error_from_unix(errno);
125                 goto out;
126         }
127
128         npc->remote_client_addr = tsocket_address_copy(remote_address, npc);
129         if (npc->remote_client_addr == NULL) {
130                 status = NT_STATUS_NO_MEMORY;
131                 goto out;
132         }
133
134         npc->remote_client_name = tsocket_address_inet_addr_string(npc->remote_client_addr,
135                                                                    npc);
136         if (npc->remote_client_name == NULL) {
137                 status = NT_STATUS_NO_MEMORY;
138                 goto out;
139         }
140
141         npc->local_server_addr = tsocket_address_copy(local_address, npc);
142         if (npc->local_server_addr == NULL) {
143                 status = NT_STATUS_NO_MEMORY;
144                 goto out;
145         }
146
147         npc->local_server_name = tsocket_address_inet_addr_string(
148                 npc->local_server_addr, npc);
149         if (npc->local_server_name == NULL) {
150                 status = NT_STATUS_NO_MEMORY;
151                 goto out;
152         }
153
154         npc->session_info = copy_session_info(npc, session_info);
155         if (npc->session_info == NULL) {
156                 status = NT_STATUS_NO_MEMORY;
157                 goto out;
158         }
159
160         rc = make_server_pipes_struct(npc,
161                                       npc->msg_ctx,
162                                       npc->pipe_name,
163                                       NCACN_NP,
164                                       npc->remote_client_addr,
165                                       npc->local_server_addr,
166                                       npc->session_info,
167                                       &npc->p,
168                                       &error);
169         if (rc == -1) {
170                 status = map_nt_error_from_unix(error);
171                 goto out;
172         }
173
174         npc->write_queue = tevent_queue_create(npc, "npa_server_write_queue");
175         if (npc->write_queue == NULL) {
176                 status = NT_STATUS_NO_MEMORY;
177                 goto out;
178         }
179
180         subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream);
181         if (subreq == NULL) {
182                 DEBUG(2, ("Failed to start receving packets\n"));
183                 status = NT_STATUS_PIPE_BROKEN;
184                 goto out;
185         }
186         tevent_req_set_callback(subreq, named_pipe_packet_process, npc);
187
188         *pnpa = talloc_steal(mem_ctx, npa);
189         status = NT_STATUS_OK;
190 out:
191         talloc_free(tmp_ctx);
192         return status;
193 }
194
195 /****************************************************************************
196  Make an internal namedpipes structure
197 ****************************************************************************/
198
199 struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
200                                               const struct ndr_syntax_id *syntax,
201                                               const struct tsocket_address *remote_address,
202                                               const struct tsocket_address *local_address,
203                                               const struct auth_session_info *session_info,
204                                               struct messaging_context *msg_ctx)
205 {
206         struct pipes_struct *p;
207         struct pipe_rpc_fns *context_fns;
208         const char *pipe_name;
209         int ret;
210         const struct ndr_interface_table *table;
211
212         table = ndr_table_by_uuid(&syntax->uuid);
213         if (table == NULL) {
214                 DEBUG(0,("unknown interface\n"));
215                 return NULL;
216         }
217
218         pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
219
220         DEBUG(4,("Create pipe requested %s\n", pipe_name));
221
222         ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name,
223                                      NCALRPC, RPC_LITTLE_ENDIAN,
224                                      remote_address, local_address, &p);
225         if (ret) {
226                 DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
227                 return NULL;
228         }
229
230         if (!init_pipe_handles(p, syntax)) {
231                 DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
232                 TALLOC_FREE(p);
233                 return NULL;
234         }
235
236         p->session_info = copy_session_info(p, session_info);
237         if (p->session_info == NULL) {
238                 DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n"));
239                 close_policy_by_pipe(p);
240                 TALLOC_FREE(p);
241                 return NULL;
242         }
243
244         context_fns = talloc_zero(p, struct pipe_rpc_fns);
245         if (context_fns == NULL) {
246                 DEBUG(0,("talloc() failed!\n"));
247                 TALLOC_FREE(p);
248                 return NULL;
249         }
250
251         context_fns->next = context_fns->prev = NULL;
252         context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(syntax);
253         context_fns->cmds = rpc_srv_get_pipe_cmds(syntax);
254         context_fns->context_id = 0;
255         context_fns->syntax = *syntax;
256
257         /* add to the list of open contexts */
258         DLIST_ADD(p->contexts, context_fns);
259
260         DEBUG(4,("Created internal pipe %s\n", pipe_name));
261
262         return p;
263 }
264
265 static NTSTATUS rpcint_dispatch(struct pipes_struct *p,
266                                 TALLOC_CTX *mem_ctx,
267                                 uint32_t opnum,
268                                 const DATA_BLOB *in_data,
269                                 DATA_BLOB *out_data)
270 {
271         struct pipe_rpc_fns *fns = find_pipe_fns_by_context(p->contexts, 0);
272         uint32_t num_cmds = fns->n_cmds;
273         const struct api_struct *cmds = fns->cmds;
274         uint32_t i;
275         bool ok;
276
277         /* set opnum */
278         p->opnum = opnum;
279
280         for (i = 0; i < num_cmds; i++) {
281                 if (cmds[i].opnum == opnum && cmds[i].fn != NULL) {
282                         break;
283                 }
284         }
285
286         if (i == num_cmds) {
287                 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
288         }
289
290         p->in_data.data = *in_data;
291         p->out_data.rdata = data_blob_null;
292
293         ok = cmds[i].fn(p);
294         p->in_data.data = data_blob_null;
295         if (!ok) {
296                 data_blob_free(&p->out_data.rdata);
297                 talloc_free_children(p->mem_ctx);
298                 return NT_STATUS_RPC_CALL_FAILED;
299         }
300
301         if (p->fault_state) {
302                 NTSTATUS status;
303
304                 status = NT_STATUS(p->fault_state);
305                 p->fault_state = 0;
306                 data_blob_free(&p->out_data.rdata);
307                 talloc_free_children(p->mem_ctx);
308                 return status;
309         }
310
311         *out_data = p->out_data.rdata;
312         talloc_steal(mem_ctx, out_data->data);
313         p->out_data.rdata = data_blob_null;
314
315         talloc_free_children(p->mem_ctx);
316         return NT_STATUS_OK;
317 }
318
319 struct rpcint_bh_state {
320         struct pipes_struct *p;
321 };
322
323 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
324 {
325         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
326                                      struct rpcint_bh_state);
327
328         if (!hs->p) {
329                 return false;
330         }
331
332         return true;
333 }
334
335 static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
336                                       uint32_t timeout)
337 {
338         /* TODO: implement timeouts */
339         return UINT32_MAX;
340 }
341
342 struct rpcint_bh_raw_call_state {
343         DATA_BLOB in_data;
344         DATA_BLOB out_data;
345         uint32_t out_flags;
346 };
347
348 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
349                                                   struct tevent_context *ev,
350                                                   struct dcerpc_binding_handle *h,
351                                                   const struct GUID *object,
352                                                   uint32_t opnum,
353                                                   uint32_t in_flags,
354                                                   const uint8_t *in_data,
355                                                   size_t in_length)
356 {
357         struct rpcint_bh_state *hs =
358                 dcerpc_binding_handle_data(h,
359                 struct rpcint_bh_state);
360         struct tevent_req *req;
361         struct rpcint_bh_raw_call_state *state;
362         bool ok;
363         NTSTATUS status;
364
365         req = tevent_req_create(mem_ctx, &state,
366                                 struct rpcint_bh_raw_call_state);
367         if (req == NULL) {
368                 return NULL;
369         }
370         state->in_data.data = discard_const_p(uint8_t, in_data);
371         state->in_data.length = in_length;
372
373         ok = rpcint_bh_is_connected(h);
374         if (!ok) {
375                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
376                 return tevent_req_post(req, ev);
377         }
378
379         /* TODO: allow async */
380         status = rpcint_dispatch(hs->p, state, opnum,
381                                  &state->in_data,
382                                  &state->out_data);
383         if (!NT_STATUS_IS_OK(status)) {
384                 tevent_req_nterror(req, status);
385                 return tevent_req_post(req, ev);
386         }
387
388         tevent_req_done(req);
389         return tevent_req_post(req, ev);
390 }
391
392 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
393                                         TALLOC_CTX *mem_ctx,
394                                         uint8_t **out_data,
395                                         size_t *out_length,
396                                         uint32_t *out_flags)
397 {
398         struct rpcint_bh_raw_call_state *state =
399                 tevent_req_data(req,
400                 struct rpcint_bh_raw_call_state);
401         NTSTATUS status;
402
403         if (tevent_req_is_nterror(req, &status)) {
404                 tevent_req_received(req);
405                 return status;
406         }
407
408         *out_data = talloc_move(mem_ctx, &state->out_data.data);
409         *out_length = state->out_data.length;
410         *out_flags = 0;
411         tevent_req_received(req);
412         return NT_STATUS_OK;
413 }
414
415 struct rpcint_bh_disconnect_state {
416         uint8_t _dummy;
417 };
418
419 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
420                                                 struct tevent_context *ev,
421                                                 struct dcerpc_binding_handle *h)
422 {
423         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
424                                      struct rpcint_bh_state);
425         struct tevent_req *req;
426         struct rpcint_bh_disconnect_state *state;
427         bool ok;
428
429         req = tevent_req_create(mem_ctx, &state,
430                                 struct rpcint_bh_disconnect_state);
431         if (req == NULL) {
432                 return NULL;
433         }
434
435         ok = rpcint_bh_is_connected(h);
436         if (!ok) {
437                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
438                 return tevent_req_post(req, ev);
439         }
440
441         /*
442          * TODO: do a real async disconnect ...
443          *
444          * For now the caller needs to free pipes_struct
445          */
446         hs->p = NULL;
447
448         tevent_req_done(req);
449         return tevent_req_post(req, ev);
450 }
451
452 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
453 {
454         NTSTATUS status;
455
456         if (tevent_req_is_nterror(req, &status)) {
457                 tevent_req_received(req);
458                 return status;
459         }
460
461         tevent_req_received(req);
462         return NT_STATUS_OK;
463 }
464
465 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
466 {
467         return true;
468 }
469
470 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
471                                    int ndr_flags,
472                                    const void *_struct_ptr,
473                                    const struct ndr_interface_call *call)
474 {
475         void *struct_ptr = discard_const(_struct_ptr);
476
477         if (DEBUGLEVEL < 11) {
478                 return;
479         }
480
481         if (ndr_flags & NDR_IN) {
482                 ndr_print_function_debug(call->ndr_print,
483                                          call->name,
484                                          ndr_flags,
485                                          struct_ptr);
486         }
487         if (ndr_flags & NDR_OUT) {
488                 ndr_print_function_debug(call->ndr_print,
489                                          call->name,
490                                          ndr_flags,
491                                          struct_ptr);
492         }
493 }
494
495 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
496         .name                   = "rpcint",
497         .is_connected           = rpcint_bh_is_connected,
498         .set_timeout            = rpcint_bh_set_timeout,
499         .raw_call_send          = rpcint_bh_raw_call_send,
500         .raw_call_recv          = rpcint_bh_raw_call_recv,
501         .disconnect_send        = rpcint_bh_disconnect_send,
502         .disconnect_recv        = rpcint_bh_disconnect_recv,
503
504         .ref_alloc              = rpcint_bh_ref_alloc,
505         .do_ndr_print           = rpcint_bh_do_ndr_print,
506 };
507
508 static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
509                         const struct ndr_syntax_id *abstract_syntax,
510                         const struct ndr_interface_table *ndr_table,
511                         const struct tsocket_address *remote_address,
512                         const struct tsocket_address *local_address,
513                         const struct auth_session_info *session_info,
514                         struct messaging_context *msg_ctx,
515                         struct dcerpc_binding_handle **binding_handle)
516 {
517         struct dcerpc_binding_handle *h;
518         struct rpcint_bh_state *hs;
519
520         if (ndr_table) {
521                 abstract_syntax = &ndr_table->syntax_id;
522         }
523
524         h = dcerpc_binding_handle_create(mem_ctx,
525                                          &rpcint_bh_ops,
526                                          NULL,
527                                          ndr_table,
528                                          &hs,
529                                          struct rpcint_bh_state,
530                                          __location__);
531         if (h == NULL) {
532                 return NT_STATUS_NO_MEMORY;
533         }
534         hs->p = make_internal_rpc_pipe_p(hs,
535                                          abstract_syntax,
536                                          remote_address,
537                                          local_address,
538                                          session_info,
539                                          msg_ctx);
540         if (hs->p == NULL) {
541                 TALLOC_FREE(h);
542                 return NT_STATUS_NO_MEMORY;
543         }
544
545         *binding_handle = h;
546         return NT_STATUS_OK;
547 }
548 /**
549  * @brief Create a new DCERPC Binding Handle which uses a local dispatch function.
550  *
551  * @param[in]  mem_ctx  The memory context to use.
552  *
553  * @param[in]  ndr_table Normally the ndr_table_<name>.
554  *
555  * @param[in]  remote_address The info about the connected client.
556  *
557  * @param[in]  serversupplied_info The server supplied authentication function.
558  *
559  * @param[in]  msg_ctx   The messaging context that can be used by the server
560  *
561  * @param[out] binding_handle  A pointer to store the connected
562  *                             dcerpc_binding_handle
563  *
564  * @return              NT_STATUS_OK on success, a corresponding NT status if an
565  *                      error occurred.
566  *
567  * @code
568  *   struct dcerpc_binding_handle *winreg_binding;
569  *   NTSTATUS status;
570  *
571  *   status = rpcint_binding_handle(tmp_ctx,
572  *                                  &ndr_table_winreg,
573  *                                  p->remote_address,
574  *                                  p->session_info,
575  *                                  p->msg_ctx
576  *                                  &winreg_binding);
577  * @endcode
578  */
579 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
580                                const struct ndr_interface_table *ndr_table,
581                                const struct tsocket_address *remote_address,
582                                const struct tsocket_address *local_address,
583                                const struct auth_session_info *session_info,
584                                struct messaging_context *msg_ctx,
585                                struct dcerpc_binding_handle **binding_handle)
586 {
587         return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, remote_address,
588                                         local_address, session_info,
589                                         msg_ctx, binding_handle);
590 }
591
592 /**
593  * @internal
594  *
595  * @brief Create a new RPC client context which uses a local transport.
596  *
597  * This creates a local transport. It is a shortcut to directly call the server
598  * functions and avoid marshalling.
599  * NOTE: this function should be used only by rpc_pipe_open_interface()
600  *
601  * @param[in]  mem_ctx  The memory context to use.
602  *
603  * @param[in]  ndr_table the ndr_table_<name> structure.
604  *
605  * @param[in]  serversupplied_info The server supplied authentication function.
606  *
607  * @param[in]  remote_address The client address information.
608  *
609  * @param[in]  msg_ctx  The messaging context to use.
610  *
611  * @param[out] presult  A pointer to store the connected rpc client pipe.
612  *
613  * @return              NT_STATUS_OK on success, a corresponding NT status if an
614  *                      error occurred.
615  */
616 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
617                                 const struct ndr_interface_table *ndr_table,
618                                 const struct auth_session_info *session_info,
619                                 const struct tsocket_address *remote_address,
620                                 const struct tsocket_address *local_address,
621                                 struct messaging_context *msg_ctx,
622                                 struct rpc_pipe_client **presult)
623 {
624         struct rpc_pipe_client *result;
625         NTSTATUS status;
626
627         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
628         if (result == NULL) {
629                 return NT_STATUS_NO_MEMORY;
630         }
631
632         result->abstract_syntax = ndr_table->syntax_id;
633         result->transfer_syntax = ndr_transfer_syntax_ndr;
634
635         if (remote_address == NULL) {
636                 struct tsocket_address *local;
637                 int rc;
638
639                 rc = tsocket_address_inet_from_strings(mem_ctx,
640                                                        "ip",
641                                                        "127.0.0.1",
642                                                        0,
643                                                        &local);
644                 if (rc < 0) {
645                         TALLOC_FREE(result);
646                         return NT_STATUS_NO_MEMORY;
647                 }
648
649                 remote_address = local;
650         }
651
652         result->max_xmit_frag = -1;
653
654         status = rpcint_binding_handle(result,
655                                        ndr_table,
656                                        remote_address,
657                                        local_address,
658                                        session_info,
659                                        msg_ctx,
660                                        &result->binding_handle);
661         if (!NT_STATUS_IS_OK(status)) {
662                 TALLOC_FREE(result);
663                 return status;
664         }
665
666         *presult = result;
667         return NT_STATUS_OK;
668 }
669
670 /****************************************************************************
671  * External pipes functions
672  ***************************************************************************/
673
674 NTSTATUS make_external_rpc_pipe(TALLOC_CTX *mem_ctx,
675                                 const char *pipe_name,
676                                 const struct tsocket_address *remote_client_address,
677                                 const struct tsocket_address *local_server_address,
678                                 const struct auth_session_info *session_info,
679                                 struct npa_state **pnpa)
680 {
681         TALLOC_CTX *tmp_ctx = talloc_stackframe();
682         struct auth_session_info_transport *session_info_t;
683         struct tevent_context *ev_ctx;
684         struct tevent_req *subreq;
685         const char *socket_np_dir;
686         const char *socket_dir;
687         struct npa_state *npa;
688         int sys_errno;
689         NTSTATUS status;
690         int rc = -1;
691         bool ok;
692
693         npa = npa_state_init(tmp_ctx);
694         if (npa == NULL) {
695                 status = NT_STATUS_NO_MEMORY;
696                 goto out;
697         }
698
699         socket_dir = lp_parm_const_string(GLOBAL_SECTION_SNUM,
700                                           "external_rpc_pipe",
701                                           "socket_dir",
702                                           lp_ncalrpc_dir());
703         if (socket_dir == NULL) {
704                 DEBUG(0, ("external_rpc_pipe: socket_dir not set\n"));
705                 status = NT_STATUS_PIPE_NOT_AVAILABLE;
706                 goto out;
707         }
708
709         socket_np_dir = talloc_asprintf(tmp_ctx, "%s/np", socket_dir);
710         if (socket_np_dir == NULL) {
711                 DEBUG(0, ("talloc_asprintf failed\n"));
712                 status = NT_STATUS_NO_MEMORY;
713                 goto out;
714         }
715
716         session_info_t = talloc_zero(tmp_ctx,
717                                      struct auth_session_info_transport);
718         if (session_info_t == NULL) {
719                 DEBUG(0, ("talloc failed\n"));
720                 status = NT_STATUS_NO_MEMORY;
721                 goto out;
722         }
723
724         session_info_t->session_info = copy_session_info(session_info_t,
725                                                          session_info);
726         if (session_info_t->session_info == NULL) {
727                 DEBUG(0, ("copy_session_info failed\n"));
728                 status = NT_STATUS_NO_MEMORY;
729                 goto out;
730         }
731
732         ev_ctx = samba_tevent_context_init(tmp_ctx);
733         if (ev_ctx == NULL) {
734                 DEBUG(0, ("samba_tevent_context_init failed\n"));
735                 status = NT_STATUS_NO_MEMORY;
736                 goto out;
737         }
738
739         become_root();
740         subreq = tstream_npa_connect_send(tmp_ctx,
741                                           ev_ctx,
742                                           socket_np_dir,
743                                           pipe_name,
744                                           remote_client_address,
745                                           NULL, /* client_name */
746                                           local_server_address,
747                                           NULL, /* server_name */
748                                           session_info_t);
749         if (subreq == NULL) {
750                 unbecome_root();
751                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
752                           "user %s\\%s failed\n",
753                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
754                           session_info_t->session_info->info->account_name));
755                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
756                 goto out;
757         }
758         ok = tevent_req_poll(subreq, ev_ctx);
759         unbecome_root();
760         if (!ok) {
761                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
762                           "failed for tstream_npa_connect: %s\n",
763                           socket_np_dir,
764                           pipe_name,
765                           session_info_t->session_info->info->domain_name,
766                           session_info_t->session_info->info->account_name,
767                           strerror(errno)));
768                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
769                 goto out;
770         }
771
772         rc = tstream_npa_connect_recv(subreq,
773                                       &sys_errno,
774                                       npa,
775                                       &npa->stream,
776                                       &npa->file_type,
777                                       &npa->device_state,
778                                       &npa->allocation_size);
779         talloc_free(subreq);
780         if (rc != 0) {
781                 int l = 1;
782
783                 if (errno == ENOENT) {
784                         l = 2;
785                 }
786
787                 DEBUG(l, ("tstream_npa_connect_recv  to %s for pipe %s and "
788                           "user %s\\%s failed: %s\n",
789                           socket_np_dir,
790                           pipe_name,
791                           session_info_t->session_info->info->domain_name,
792                           session_info_t->session_info->info->account_name,
793                           strerror(sys_errno)));
794                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
795                 goto out;
796         }
797
798         *pnpa = talloc_steal(mem_ctx, npa);
799         status = NT_STATUS_OK;
800 out:
801         talloc_free(tmp_ctx);
802
803         return status;
804 }
805
806 struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
807                                 const char *pipe_name,
808                                 const struct tsocket_address *remote_client_address,
809                                 const struct tsocket_address *local_server_address,
810                                 const struct auth_session_info *session_info)
811 {
812         struct np_proxy_state *result;
813         char *socket_np_dir;
814         const char *socket_dir;
815         struct tevent_context *ev;
816         struct tevent_req *subreq;
817         struct auth_session_info_transport *session_info_t;
818         bool ok;
819         int ret;
820         int sys_errno;
821
822         result = talloc(mem_ctx, struct np_proxy_state);
823         if (result == NULL) {
824                 DEBUG(0, ("talloc failed\n"));
825                 return NULL;
826         }
827
828         result->read_queue = tevent_queue_create(result, "np_read");
829         if (result->read_queue == NULL) {
830                 DEBUG(0, ("tevent_queue_create failed\n"));
831                 goto fail;
832         }
833
834         result->write_queue = tevent_queue_create(result, "np_write");
835         if (result->write_queue == NULL) {
836                 DEBUG(0, ("tevent_queue_create failed\n"));
837                 goto fail;
838         }
839
840         ev = samba_tevent_context_init(talloc_tos());
841         if (ev == NULL) {
842                 DEBUG(0, ("samba_tevent_context_init failed\n"));
843                 goto fail;
844         }
845
846         socket_dir = lp_parm_const_string(
847                 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
848                 lp_ncalrpc_dir());
849         if (socket_dir == NULL) {
850                 DEBUG(0, ("external_rpc_pipe:socket_dir not set\n"));
851                 goto fail;
852         }
853         socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
854         if (socket_np_dir == NULL) {
855                 DEBUG(0, ("talloc_asprintf failed\n"));
856                 goto fail;
857         }
858
859         session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
860         if (session_info_t == NULL) {
861                 DEBUG(0, ("talloc failed\n"));
862                 goto fail;
863         }
864
865         session_info_t->session_info = copy_session_info(session_info_t,
866                                                          session_info);
867         if (session_info_t->session_info == NULL) {
868                 DEBUG(0, ("copy_session_info failed\n"));
869                 goto fail;
870         }
871
872         become_root();
873         subreq = tstream_npa_connect_send(talloc_tos(), ev,
874                                           socket_np_dir,
875                                           pipe_name,
876                                           remote_client_address,
877                                           NULL, /* client_name */
878                                           local_server_address,
879                                           NULL, /* server_name */
880                                           session_info_t);
881         if (subreq == NULL) {
882                 unbecome_root();
883                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
884                           "user %s\\%s failed\n",
885                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
886                           session_info_t->session_info->info->account_name));
887                 goto fail;
888         }
889         ok = tevent_req_poll(subreq, ev);
890         unbecome_root();
891         if (!ok) {
892                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
893                           "failed for tstream_npa_connect: %s\n",
894                           socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
895                           session_info_t->session_info->info->account_name,
896                           strerror(errno)));
897                 goto fail;
898
899         }
900         ret = tstream_npa_connect_recv(subreq, &sys_errno,
901                                        result,
902                                        &result->npipe,
903                                        &result->file_type,
904                                        &result->device_state,
905                                        &result->allocation_size);
906         TALLOC_FREE(subreq);
907         if (ret != 0) {
908                 int l = 1;
909                 if (errno == ENOENT) {
910                         l = 2;
911                 }
912                 DEBUG(l, ("tstream_npa_connect_recv  to %s for pipe %s and "
913                           "user %s\\%s failed: %s\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                           strerror(sys_errno)));
917                 goto fail;
918         }
919
920         return result;
921
922  fail:
923         TALLOC_FREE(result);
924         return NULL;
925 }
926
927 static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
928                                        const char *pipe_name,
929                                        const struct ndr_interface_table *table,
930                                        const struct auth_session_info *session_info,
931                                        const struct tsocket_address *remote_client_address,
932                                        const struct tsocket_address *local_server_address,
933                                        struct rpc_pipe_client **_result)
934 {
935         struct rpc_pipe_client *result = NULL;
936         struct np_proxy_state *proxy_state = NULL;
937         struct pipe_auth_data *auth;
938         struct tsocket_address *remote_client_addr;
939         struct tsocket_address *local_server_addr;
940         NTSTATUS status;
941         int ret;
942
943         if (local_server_address == NULL) {
944                 /* this is an internal connection, fake up ip addresses */
945                 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
946                                                         NULL, 0, &local_server_addr);
947                 if (ret) {
948                         return NT_STATUS_NO_MEMORY;
949                 }
950                 local_server_address = local_server_addr;
951         }
952
953         if (remote_client_address == NULL) {
954                 /* this is an internal connection, fake up ip addresses */
955                 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
956                                                         NULL, 0, &remote_client_addr);
957                 if (ret) {
958                         return NT_STATUS_NO_MEMORY;
959                 }
960                 remote_client_address = remote_client_addr;
961         }
962
963         proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
964                                                remote_client_address,
965                                                local_server_address,
966                                                session_info);
967         if (!proxy_state) {
968                 DEBUG(1, ("Unable to make proxy_state for connection to %s.\n", pipe_name));
969                 return NT_STATUS_UNSUCCESSFUL;
970         }
971
972         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
973         if (result == NULL) {
974                 status = NT_STATUS_NO_MEMORY;
975                 goto done;
976         }
977
978         result->abstract_syntax = table->syntax_id;
979         result->transfer_syntax = ndr_transfer_syntax_ndr;
980
981         result->desthost = get_myname(result);
982         result->srv_name_slash = talloc_asprintf_strupper_m(
983                 result, "\\\\%s", result->desthost);
984         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
985                 status = NT_STATUS_NO_MEMORY;
986                 goto done;
987         }
988
989         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
990
991         status = rpc_transport_tstream_init(result,
992                                             &proxy_state->npipe,
993                                             &result->transport);
994         if (!NT_STATUS_IS_OK(status)) {
995                 goto done;
996         }
997
998         result->binding_handle = rpccli_bh_create(result, NULL, table);
999         if (result->binding_handle == NULL) {
1000                 status = NT_STATUS_NO_MEMORY;
1001                 DEBUG(0, ("Failed to create binding handle.\n"));
1002                 goto done;
1003         }
1004
1005         result->auth = talloc_zero(result, struct pipe_auth_data);
1006         if (!result->auth) {
1007                 status = NT_STATUS_NO_MEMORY;
1008                 goto done;
1009         }
1010         result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
1011         result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
1012         result->auth->auth_context_id = 0;
1013
1014         status = rpccli_anon_bind_data(result, &auth);
1015         if (!NT_STATUS_IS_OK(status)) {
1016                 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
1017                 goto done;
1018         }
1019
1020         status = rpc_pipe_bind(result, auth);
1021         if (!NT_STATUS_IS_OK(status)) {
1022                 DEBUG(0, ("Failed to bind external pipe.\n"));
1023                 goto done;
1024         }
1025
1026 done:
1027         if (!NT_STATUS_IS_OK(status)) {
1028                 TALLOC_FREE(result);
1029         }
1030         TALLOC_FREE(proxy_state);
1031         *_result = result;
1032         return status;
1033 }
1034
1035 /**
1036  * @brief Create a new RPC client context which uses a local dispatch function
1037  *        or a remote transport, depending on rpc_server configuration for the
1038  *        specific service.
1039  *
1040  * @param[in]  mem_ctx  The memory context to use.
1041  *
1042  * @param[in]  abstract_syntax Normally the syntax_id of the autogenerated
1043  *                             ndr_table_<name>.
1044  *
1045  * @param[in]  serversupplied_info The server supplied authentication function.
1046  *
1047  * @param[in]  remote_address The client address information.
1048  *
1049  * @param[in]  msg_ctx  The messaging context to use.
1050  *
1051  * @param[out] presult  A pointer to store the connected rpc client pipe.
1052  *
1053  * @return              NT_STATUS_OK on success, a corresponding NT status if an
1054  *                      error occurred.
1055  *
1056  * @code
1057  *   struct rpc_pipe_client *winreg_pipe;
1058  *   NTSTATUS status;
1059  *
1060  *   status = rpc_pipe_open_interface(tmp_ctx,
1061  *                                    &ndr_table_winreg.syntax_id,
1062  *                                    p->session_info,
1063  *                                    remote_address,
1064  *                                    &winreg_pipe);
1065  * @endcode
1066  */
1067
1068 NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
1069                                  const struct ndr_interface_table *table,
1070                                  const struct auth_session_info *session_info,
1071                                  const struct tsocket_address *remote_address,
1072                                  const struct tsocket_address *local_address,
1073                                  struct messaging_context *msg_ctx,
1074                                  struct rpc_pipe_client **cli_pipe)
1075 {
1076         struct rpc_pipe_client *cli = NULL;
1077         enum rpc_service_mode_e pipe_mode;
1078         const char *pipe_name;
1079         NTSTATUS status;
1080         TALLOC_CTX *tmp_ctx;
1081
1082         if (cli_pipe != NULL) {
1083                 if (rpccli_is_connected(*cli_pipe)) {
1084                         return NT_STATUS_OK;
1085                 } else {
1086                         TALLOC_FREE(*cli_pipe);
1087                 }
1088         }
1089
1090         tmp_ctx = talloc_stackframe();
1091         if (tmp_ctx == NULL) {
1092                 return NT_STATUS_NO_MEMORY;
1093         }
1094
1095         pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
1096         if (pipe_name == NULL) {
1097                 DEBUG(1, ("Unable to find pipe name to forward %s to.\n", table->name));
1098                 status = NT_STATUS_INVALID_PARAMETER;
1099                 goto done;
1100         }
1101
1102         while (pipe_name[0] == '\\') {
1103                 pipe_name++;
1104         }
1105
1106         DEBUG(5, ("Connecting to %s pipe.\n", pipe_name));
1107
1108         pipe_mode = rpc_service_mode(pipe_name);
1109
1110         switch (pipe_mode) {
1111         case RPC_SERVICE_MODE_EMBEDDED:
1112                 status = rpc_pipe_open_internal(tmp_ctx,
1113                                                 table, session_info,
1114                                                 remote_address, local_address,
1115                                                 msg_ctx,
1116                                                 &cli);
1117                 if (!NT_STATUS_IS_OK(status)) {
1118                         goto done;
1119                 }
1120                 break;
1121         case RPC_SERVICE_MODE_EXTERNAL:
1122                 /* It would be nice to just use rpc_pipe_open_ncalrpc() but
1123                  * for now we need to use the special proxy setup to connect
1124                  * to spoolssd. */
1125
1126                 status = rpc_pipe_open_external(tmp_ctx,
1127                                                 pipe_name, table,
1128                                                 session_info,
1129                                                 remote_address, local_address,
1130                                                 &cli);
1131                 if (!NT_STATUS_IS_OK(status)) {
1132                         goto done;
1133                 }
1134                 break;
1135         case RPC_SERVICE_MODE_DISABLED:
1136                 status = NT_STATUS_NOT_IMPLEMENTED;
1137                 DEBUG(0, ("Service pipe %s is disabled in config file: %s",
1138                           pipe_name, nt_errstr(status)));
1139                 goto done;
1140         }
1141
1142         status = NT_STATUS_OK;
1143 done:
1144         if (NT_STATUS_IS_OK(status) && cli_pipe != NULL) {
1145                 *cli_pipe = talloc_move(mem_ctx, &cli);
1146         }
1147         TALLOC_FREE(tmp_ctx);
1148         return status;
1149 }