s3-includes: only include ntdomain.h where needed.
[sfrench/samba-autobuild/.git] / source3 / rpc_server / rpc_ncacn_np.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1998,
5  *  Largely re-written : 2005
6  *  Copyright (C) Jeremy Allison                1998 - 2005
7  *  Copyright (C) Simo Sorce                    2010
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "includes.h"
24 #include "rpc_client/cli_pipe.h"
25 #include "rpc_server/srv_pipe_internal.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.h"
33 #include "ntdomain.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_RPC_SRV
37
38 static int pipes_open;
39
40 static struct pipes_struct *InternalPipes;
41
42 /* TODO
43  * the following prototypes are declared here to avoid
44  * code being moved about too much for a patch to be
45  * disrupted / less obvious.
46  *
47  * these functions, and associated functions that they
48  * call, should be moved behind a .so module-loading
49  * system _anyway_.  so that's the next step...
50  */
51
52 /****************************************************************************
53  Internal Pipe iterator functions.
54 ****************************************************************************/
55
56 struct pipes_struct *get_first_internal_pipe(void)
57 {
58         return InternalPipes;
59 }
60
61 struct pipes_struct *get_next_internal_pipe(struct pipes_struct *p)
62 {
63         return p->next;
64 }
65
66 static void free_pipe_rpc_context_internal( PIPE_RPC_FNS *list )
67 {
68         PIPE_RPC_FNS *tmp = list;
69         PIPE_RPC_FNS *tmp2;
70
71         while (tmp) {
72                 tmp2 = tmp->next;
73                 SAFE_FREE(tmp);
74                 tmp = tmp2;
75         }
76
77         return;
78 }
79
80 bool check_open_pipes(void)
81 {
82         struct pipes_struct *p;
83
84         for (p = InternalPipes; p != NULL; p = p->next) {
85                 if (num_pipe_handles(p) != 0) {
86                         return true;
87                 }
88         }
89         return false;
90 }
91
92 /****************************************************************************
93  Close an rpc pipe.
94 ****************************************************************************/
95
96 int close_internal_rpc_pipe_hnd(struct pipes_struct *p)
97 {
98         if (!p) {
99                 DEBUG(0,("Invalid pipe in close_internal_rpc_pipe_hnd\n"));
100                 return False;
101         }
102
103         TALLOC_FREE(p->auth.auth_ctx);
104
105         free_pipe_rpc_context_internal( p->contexts );
106
107         /* Free the handles database. */
108         close_policy_by_pipe(p);
109
110         DLIST_REMOVE(InternalPipes, p);
111
112         ZERO_STRUCTP(p);
113
114         return 0;
115 }
116
117 /****************************************************************************
118  Make an internal namedpipes structure
119 ****************************************************************************/
120
121 struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
122                                               const struct ndr_syntax_id *syntax,
123                                               struct client_address *client_id,
124                                               const struct auth_serversupplied_info *session_info,
125                                               struct messaging_context *msg_ctx)
126 {
127         struct pipes_struct *p;
128
129         DEBUG(4,("Create pipe requested %s\n",
130                  get_pipe_name_from_syntax(talloc_tos(), syntax)));
131
132         p = TALLOC_ZERO_P(mem_ctx, struct pipes_struct);
133
134         if (!p) {
135                 DEBUG(0,("ERROR! no memory for pipes_struct!\n"));
136                 return NULL;
137         }
138
139         p->mem_ctx = talloc_named(p, 0, "pipe %s %p",
140                                  get_pipe_name_from_syntax(talloc_tos(),
141                                                            syntax), p);
142         if (p->mem_ctx == NULL) {
143                 DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n"));
144                 TALLOC_FREE(p);
145                 return NULL;
146         }
147
148         if (!init_pipe_handles(p, syntax)) {
149                 DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n"));
150                 TALLOC_FREE(p);
151                 return NULL;
152         }
153
154         p->session_info = copy_serverinfo(p, session_info);
155         if (p->session_info == NULL) {
156                 DEBUG(0, ("open_rpc_pipe_p: copy_serverinfo failed\n"));
157                 close_policy_by_pipe(p);
158                 TALLOC_FREE(p);
159                 return NULL;
160         }
161
162         p->msg_ctx = msg_ctx;
163
164         DLIST_ADD(InternalPipes, p);
165
166         p->client_id = client_id;
167
168         p->endian = RPC_LITTLE_ENDIAN;
169
170         p->syntax = *syntax;
171         p->transport = NCALRPC;
172
173         DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n",
174                  get_pipe_name_from_syntax(talloc_tos(), syntax), pipes_open));
175
176         talloc_set_destructor(p, close_internal_rpc_pipe_hnd);
177
178         return p;
179 }
180
181 static NTSTATUS rpcint_dispatch(struct pipes_struct *p,
182                                 TALLOC_CTX *mem_ctx,
183                                 uint32_t opnum,
184                                 const DATA_BLOB *in_data,
185                                 DATA_BLOB *out_data)
186 {
187         uint32_t num_cmds = rpc_srv_get_pipe_num_cmds(&p->syntax);
188         const struct api_struct *cmds = rpc_srv_get_pipe_cmds(&p->syntax);
189         uint32_t i;
190         bool ok;
191
192         /* set opnum */
193         p->opnum = opnum;
194
195         for (i = 0; i < num_cmds; i++) {
196                 if (cmds[i].opnum == opnum && cmds[i].fn != NULL) {
197                         break;
198                 }
199         }
200
201         if (i == num_cmds) {
202                 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
203         }
204
205         p->in_data.data = *in_data;
206         p->out_data.rdata = data_blob_null;
207
208         ok = cmds[i].fn(p);
209         p->in_data.data = data_blob_null;
210         if (!ok) {
211                 data_blob_free(&p->out_data.rdata);
212                 talloc_free_children(p->mem_ctx);
213                 return NT_STATUS_RPC_CALL_FAILED;
214         }
215
216         if (p->fault_state) {
217                 p->fault_state = false;
218                 data_blob_free(&p->out_data.rdata);
219                 talloc_free_children(p->mem_ctx);
220                 return NT_STATUS_RPC_CALL_FAILED;
221         }
222
223         if (p->bad_handle_fault_state) {
224                 p->bad_handle_fault_state = false;
225                 data_blob_free(&p->out_data.rdata);
226                 talloc_free_children(p->mem_ctx);
227                 return NT_STATUS_RPC_SS_CONTEXT_MISMATCH;
228         }
229
230         if (p->rng_fault_state) {
231                 p->rng_fault_state = false;
232                 data_blob_free(&p->out_data.rdata);
233                 talloc_free_children(p->mem_ctx);
234                 return NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE;
235         }
236
237         *out_data = p->out_data.rdata;
238         talloc_steal(mem_ctx, out_data->data);
239         p->out_data.rdata = data_blob_null;
240
241         talloc_free_children(p->mem_ctx);
242         return NT_STATUS_OK;
243 }
244
245 struct rpcint_bh_state {
246         struct pipes_struct *p;
247 };
248
249 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
250 {
251         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
252                                      struct rpcint_bh_state);
253
254         if (!hs->p) {
255                 return false;
256         }
257
258         return true;
259 }
260
261 static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
262                                       uint32_t timeout)
263 {
264         /* TODO: implement timeouts */
265         return UINT32_MAX;
266 }
267
268 struct rpcint_bh_raw_call_state {
269         DATA_BLOB in_data;
270         DATA_BLOB out_data;
271         uint32_t out_flags;
272 };
273
274 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
275                                                   struct tevent_context *ev,
276                                                   struct dcerpc_binding_handle *h,
277                                                   const struct GUID *object,
278                                                   uint32_t opnum,
279                                                   uint32_t in_flags,
280                                                   const uint8_t *in_data,
281                                                   size_t in_length)
282 {
283         struct rpcint_bh_state *hs =
284                 dcerpc_binding_handle_data(h,
285                 struct rpcint_bh_state);
286         struct tevent_req *req;
287         struct rpcint_bh_raw_call_state *state;
288         bool ok;
289         NTSTATUS status;
290
291         req = tevent_req_create(mem_ctx, &state,
292                                 struct rpcint_bh_raw_call_state);
293         if (req == NULL) {
294                 return NULL;
295         }
296         state->in_data.data = discard_const_p(uint8_t, in_data);
297         state->in_data.length = in_length;
298
299         ok = rpcint_bh_is_connected(h);
300         if (!ok) {
301                 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
302                 return tevent_req_post(req, ev);
303         }
304
305         /* TODO: allow async */
306         status = rpcint_dispatch(hs->p, state, opnum,
307                                  &state->in_data,
308                                  &state->out_data);
309         if (!NT_STATUS_IS_OK(status)) {
310                 tevent_req_nterror(req, status);
311                 return tevent_req_post(req, ev);
312         }
313
314         tevent_req_done(req);
315         return tevent_req_post(req, ev);
316 }
317
318 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
319                                         TALLOC_CTX *mem_ctx,
320                                         uint8_t **out_data,
321                                         size_t *out_length,
322                                         uint32_t *out_flags)
323 {
324         struct rpcint_bh_raw_call_state *state =
325                 tevent_req_data(req,
326                 struct rpcint_bh_raw_call_state);
327         NTSTATUS status;
328
329         if (tevent_req_is_nterror(req, &status)) {
330                 tevent_req_received(req);
331                 return status;
332         }
333
334         *out_data = talloc_move(mem_ctx, &state->out_data.data);
335         *out_length = state->out_data.length;
336         *out_flags = 0;
337         tevent_req_received(req);
338         return NT_STATUS_OK;
339 }
340
341 struct rpcint_bh_disconnect_state {
342         uint8_t _dummy;
343 };
344
345 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
346                                                 struct tevent_context *ev,
347                                                 struct dcerpc_binding_handle *h)
348 {
349         struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
350                                      struct rpcint_bh_state);
351         struct tevent_req *req;
352         struct rpcint_bh_disconnect_state *state;
353         bool ok;
354
355         req = tevent_req_create(mem_ctx, &state,
356                                 struct rpcint_bh_disconnect_state);
357         if (req == NULL) {
358                 return NULL;
359         }
360
361         ok = rpcint_bh_is_connected(h);
362         if (!ok) {
363                 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
364                 return tevent_req_post(req, ev);
365         }
366
367         /*
368          * TODO: do a real async disconnect ...
369          *
370          * For now the caller needs to free pipes_struct
371          */
372         hs->p = NULL;
373
374         tevent_req_done(req);
375         return tevent_req_post(req, ev);
376 }
377
378 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
379 {
380         NTSTATUS status;
381
382         if (tevent_req_is_nterror(req, &status)) {
383                 tevent_req_received(req);
384                 return status;
385         }
386
387         tevent_req_received(req);
388         return NT_STATUS_OK;
389 }
390
391 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
392 {
393         return true;
394 }
395
396 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
397                                    int ndr_flags,
398                                    const void *_struct_ptr,
399                                    const struct ndr_interface_call *call)
400 {
401         void *struct_ptr = discard_const(_struct_ptr);
402
403         if (DEBUGLEVEL < 11) {
404                 return;
405         }
406
407         if (ndr_flags & NDR_IN) {
408                 ndr_print_function_debug(call->ndr_print,
409                                          call->name,
410                                          ndr_flags,
411                                          struct_ptr);
412         }
413         if (ndr_flags & NDR_OUT) {
414                 ndr_print_function_debug(call->ndr_print,
415                                          call->name,
416                                          ndr_flags,
417                                          struct_ptr);
418         }
419 }
420
421 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
422         .name                   = "rpcint",
423         .is_connected           = rpcint_bh_is_connected,
424         .set_timeout            = rpcint_bh_set_timeout,
425         .raw_call_send          = rpcint_bh_raw_call_send,
426         .raw_call_recv          = rpcint_bh_raw_call_recv,
427         .disconnect_send        = rpcint_bh_disconnect_send,
428         .disconnect_recv        = rpcint_bh_disconnect_recv,
429
430         .ref_alloc              = rpcint_bh_ref_alloc,
431         .do_ndr_print           = rpcint_bh_do_ndr_print,
432 };
433
434 static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
435                         const struct ndr_syntax_id *abstract_syntax,
436                         const struct ndr_interface_table *ndr_table,
437                         struct client_address *client_id,
438                         const struct auth_serversupplied_info *session_info,
439                         struct messaging_context *msg_ctx,
440                         struct dcerpc_binding_handle **binding_handle)
441 {
442         struct dcerpc_binding_handle *h;
443         struct rpcint_bh_state *hs;
444
445         if (ndr_table) {
446                 abstract_syntax = &ndr_table->syntax_id;
447         }
448
449         h = dcerpc_binding_handle_create(mem_ctx,
450                                          &rpcint_bh_ops,
451                                          NULL,
452                                          ndr_table,
453                                          &hs,
454                                          struct rpcint_bh_state,
455                                          __location__);
456         if (h == NULL) {
457                 return NT_STATUS_NO_MEMORY;
458         }
459         hs->p = make_internal_rpc_pipe_p(hs,
460                                          abstract_syntax,
461                                          client_id,
462                                          session_info,
463                                          msg_ctx);
464         if (hs->p == NULL) {
465                 TALLOC_FREE(h);
466                 return NT_STATUS_NO_MEMORY;
467         }
468
469         *binding_handle = h;
470         return NT_STATUS_OK;
471 }
472 /**
473  * @brief Create a new DCERPC Binding Handle which uses a local dispatch function.
474  *
475  * @param[in]  mem_ctx  The memory context to use.
476  *
477  * @param[in]  ndr_table Normally the ndr_table_<name>.
478  *
479  * @param[in]  client_id The info about the connected client.
480  *
481  * @param[in]  serversupplied_info The server supplied authentication function.
482  *
483  * @param[in]  msg_ctx   The messaging context that can be used by the server
484  *
485  * @param[out] binding_handle  A pointer to store the connected
486  *                             dcerpc_binding_handle
487  *
488  * @return              NT_STATUS_OK on success, a corresponding NT status if an
489  *                      error occured.
490  *
491  * @code
492  *   struct dcerpc_binding_handle *winreg_binding;
493  *   NTSTATUS status;
494  *
495  *   status = rpcint_binding_handle(tmp_ctx,
496  *                                  &ndr_table_winreg,
497  *                                  p->client_id,
498  *                                  p->session_info,
499  *                                  p->msg_ctx
500  *                                  &winreg_binding);
501  * @endcode
502  */
503 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
504                                const struct ndr_interface_table *ndr_table,
505                                struct client_address *client_id,
506                                const struct auth_serversupplied_info *session_info,
507                                struct messaging_context *msg_ctx,
508                                struct dcerpc_binding_handle **binding_handle)
509 {
510         return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, client_id,
511                                         session_info, msg_ctx, binding_handle);
512 }
513
514 /**
515  * @internal
516  *
517  * @brief Create a new RPC client context which uses a local transport.
518  *
519  * This creates a local transport. It is a shortcut to directly call the server
520  * functions and avoid marschalling.
521  *
522  * @param[in]  mem_ctx  The memory context to use.
523  *
524  * @param[in]  abstract_syntax Normally the syntax_id of the autogenerated
525  *                             ndr_table_<name>.
526  *
527  * @param[in]  serversupplied_info The server supplied authentication function.
528  *
529  * @param[in]  client_id The client address information.
530  *
531  * @param[in]  msg_ctx  The messaging context to use.
532  *
533  * @param[out] presult  A pointer to store the connected rpc client pipe.
534  *
535  * @return              NT_STATUS_OK on success, a corresponding NT status if an
536  *                      error occured.
537  *
538  * @code
539  *   struct rpc_pipe_client *winreg_pipe;
540  *   NTSTATUS status;
541  *
542  *   status = rpc_pipe_open_internal(tmp_ctx,
543  *                                   &ndr_table_winreg.syntax_id,
544  *                                   p->session_info,
545  *                                   client_id,
546  *                                   &winreg_pipe);
547  * @endcode
548  */
549 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
550                                 const struct ndr_syntax_id *abstract_syntax,
551                                 const struct auth_serversupplied_info *serversupplied_info,
552                                 struct client_address *client_id,
553                                 struct messaging_context *msg_ctx,
554                                 struct rpc_pipe_client **presult)
555 {
556         struct rpc_pipe_client *result;
557         NTSTATUS status;
558
559         result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
560         if (result == NULL) {
561                 return NT_STATUS_NO_MEMORY;
562         }
563
564         result->abstract_syntax = *abstract_syntax;
565         result->transfer_syntax = ndr_transfer_syntax;
566
567         if (client_id == NULL) {
568                 static struct client_address unknown;
569                 strlcpy(unknown.addr, "<UNKNOWN>", sizeof(unknown.addr));
570                 unknown.name = "<UNKNOWN>";
571                 client_id = &unknown;
572         }
573
574         result->max_xmit_frag = -1;
575         result->max_recv_frag = -1;
576
577         status = rpcint_binding_handle_ex(result,
578                                           abstract_syntax,
579                                           NULL,
580                                           client_id,
581                                           serversupplied_info,
582                                           msg_ctx,
583                                           &result->binding_handle);
584         if (!NT_STATUS_IS_OK(status)) {
585                 TALLOC_FREE(result);
586                 return status;
587         }
588
589         *presult = result;
590         return NT_STATUS_OK;
591 }
592
593 /****************************************************************************
594  * External pipes functions
595  ***************************************************************************/
596
597
598 struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
599                                 const char *pipe_name,
600                                 const struct tsocket_address *local_address,
601                                 const struct tsocket_address *remote_address,
602                                 const struct auth_serversupplied_info *session_info)
603 {
604         struct np_proxy_state *result;
605         char *socket_np_dir;
606         const char *socket_dir;
607         struct tevent_context *ev;
608         struct tevent_req *subreq;
609         struct auth_session_info_transport *session_info_t;
610         struct auth_user_info_dc *user_info_dc;
611         union netr_Validation val;
612         NTSTATUS status;
613         bool ok;
614         int ret;
615         int sys_errno;
616
617         result = talloc(mem_ctx, struct np_proxy_state);
618         if (result == NULL) {
619                 DEBUG(0, ("talloc failed\n"));
620                 return NULL;
621         }
622
623         result->read_queue = tevent_queue_create(result, "np_read");
624         if (result->read_queue == NULL) {
625                 DEBUG(0, ("tevent_queue_create failed\n"));
626                 goto fail;
627         }
628
629         result->write_queue = tevent_queue_create(result, "np_write");
630         if (result->write_queue == NULL) {
631                 DEBUG(0, ("tevent_queue_create failed\n"));
632                 goto fail;
633         }
634
635         ev = s3_tevent_context_init(talloc_tos());
636         if (ev == NULL) {
637                 DEBUG(0, ("s3_tevent_context_init failed\n"));
638                 goto fail;
639         }
640
641         socket_dir = lp_parm_const_string(
642                 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
643                 lp_ncalrpc_dir());
644         if (socket_dir == NULL) {
645                 DEBUG(0, ("externan_rpc_pipe:socket_dir not set\n"));
646                 goto fail;
647         }
648         socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
649         if (socket_np_dir == NULL) {
650                 DEBUG(0, ("talloc_asprintf failed\n"));
651                 goto fail;
652         }
653
654         session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
655         if (session_info_t == NULL) {
656                 DEBUG(0, ("talloc failed\n"));
657                 goto fail;
658         }
659
660         /* Send the named_pipe_auth server the user's full token */
661         session_info_t->security_token = session_info->security_token;
662         session_info_t->session_key = session_info->user_session_key;
663
664         val.sam3 = session_info->info3;
665
666         /* Convert into something we can build a struct
667          * auth_session_info_transport from.  Most of the work here
668          * will be to convert the SIDS, which we will then ignore, but
669          * this is the easier way to handle it */
670         status = make_user_info_dc_netlogon_validation(talloc_tos(), "", 3, &val, &user_info_dc);
671         if (!NT_STATUS_IS_OK(status)) {
672                 DEBUG(0, ("conversion of info3 into user_info_dc failed!\n"));
673                 goto fail;
674         }
675
676         session_info_t->info = talloc_move(session_info_t, &user_info_dc->info);
677         talloc_free(user_info_dc);
678
679         become_root();
680         subreq = tstream_npa_connect_send(talloc_tos(), ev,
681                                           socket_np_dir,
682                                           pipe_name,
683                                           remote_address, /* client_addr */
684                                           NULL, /* client_name */
685                                           local_address, /* server_addr */
686                                           NULL, /* server_name */
687                                           session_info_t);
688         if (subreq == NULL) {
689                 unbecome_root();
690                 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
691                           "user %s\\%s failed\n",
692                           socket_np_dir, pipe_name, session_info_t->info->domain_name,
693                           session_info_t->info->account_name));
694                 goto fail;
695         }
696         ok = tevent_req_poll(subreq, ev);
697         unbecome_root();
698         if (!ok) {
699                 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
700                           "failed for tstream_npa_connect: %s\n",
701                           socket_np_dir, pipe_name, session_info_t->info->domain_name,
702                           session_info_t->info->account_name,
703                           strerror(errno)));
704                 goto fail;
705
706         }
707         ret = tstream_npa_connect_recv(subreq, &sys_errno,
708                                        result,
709                                        &result->npipe,
710                                        &result->file_type,
711                                        &result->device_state,
712                                        &result->allocation_size);
713         TALLOC_FREE(subreq);
714         if (ret != 0) {
715                 DEBUG(0, ("tstream_npa_connect_recv  to %s for pipe %s and "
716                           "user %s\\%s failed: %s\n",
717                           socket_np_dir, pipe_name, session_info_t->info->domain_name,
718                           session_info_t->info->account_name,
719                           strerror(sys_errno)));
720                 goto fail;
721         }
722
723         return result;
724
725  fail:
726         TALLOC_FREE(result);
727         return NULL;
728 }
729
730 static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
731                                 const char *pipe_name,
732                                 const struct ndr_syntax_id *abstract_syntax,
733                                 const struct auth_serversupplied_info *session_info,
734                                 struct rpc_pipe_client **_result)
735 {
736         struct tsocket_address *local, *remote;
737         struct rpc_pipe_client *result = NULL;
738         struct np_proxy_state *proxy_state = NULL;
739         struct pipe_auth_data *auth;
740         NTSTATUS status;
741         int ret;
742
743         /* this is an internal connection, fake up ip addresses */
744         ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
745                                                 NULL, 0, &local);
746         if (ret) {
747                 return NT_STATUS_NO_MEMORY;
748         }
749         ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
750                                                 NULL, 0, &remote);
751         if (ret) {
752                 return NT_STATUS_NO_MEMORY;
753         }
754
755         proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
756                                                 local, remote, session_info);
757         if (!proxy_state) {
758                 return NT_STATUS_UNSUCCESSFUL;
759         }
760
761         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
762         if (result == NULL) {
763                 status = NT_STATUS_NO_MEMORY;
764                 goto done;
765         }
766
767         result->abstract_syntax = *abstract_syntax;
768         result->transfer_syntax = ndr_transfer_syntax;
769
770         result->desthost = get_myname(result);
771         result->srv_name_slash = talloc_asprintf_strupper_m(
772                 result, "\\\\%s", result->desthost);
773         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
774                 status = NT_STATUS_NO_MEMORY;
775                 goto done;
776         }
777
778         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
779         result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
780
781         status = rpc_transport_tstream_init(result,
782                                             &proxy_state->npipe,
783                                             &result->transport);
784         if (!NT_STATUS_IS_OK(status)) {
785                 goto done;
786         }
787
788         result->binding_handle = rpccli_bh_create(result);
789         if (result->binding_handle == NULL) {
790                 status = NT_STATUS_NO_MEMORY;
791                 DEBUG(0, ("Failed to create binding handle.\n"));
792                 goto done;
793         }
794
795         result->auth = talloc_zero(result, struct pipe_auth_data);
796         if (!result->auth) {
797                 status = NT_STATUS_NO_MEMORY;
798                 goto done;
799         }
800         result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
801         result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
802
803         status = rpccli_anon_bind_data(result, &auth);
804         if (!NT_STATUS_IS_OK(status)) {
805                 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
806                 goto done;
807         }
808
809         status = rpc_pipe_bind(result, auth);
810         if (!NT_STATUS_IS_OK(status)) {
811                 DEBUG(0, ("Failed to bind external pipe.\n"));
812                 goto done;
813         }
814
815 done:
816         if (!NT_STATUS_IS_OK(status)) {
817                 TALLOC_FREE(result);
818         }
819         TALLOC_FREE(proxy_state);
820         *_result = result;
821         return status;
822 }
823
824 /**
825  * @brief Create a new RPC client context which uses a local dispatch function.
826  *
827  * @param mem_ctx       The memory context on which thje pipe will ultimately
828  *                      be allocated
829  * @param name          The pipe name to connect to.
830  * @param session_info  Credentials to use for the connection.
831  * @param pipe          [in|out] Checks if a pipe is connected, and connects it
832  *                               if not
833  *
834  * @return              NT_STATUS_OK on success, a corresponding NT status if
835  *                      an error occured.
836  */
837
838 NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
839                                  const struct ndr_syntax_id *syntax,
840                                  const struct auth_serversupplied_info *session_info,
841                                  struct client_address *client_id,
842                                  struct messaging_context *msg_ctx,
843                                  struct rpc_pipe_client **cli_pipe)
844 {
845         struct rpc_pipe_client *cli = NULL;
846         const char *server_type;
847         const char *pipe_name;
848         NTSTATUS status;
849         TALLOC_CTX *tmp_ctx;
850
851         if (cli_pipe && rpccli_is_connected(*cli_pipe)) {
852                 return NT_STATUS_OK;
853         } else {
854                 TALLOC_FREE(*cli_pipe);
855         }
856
857         tmp_ctx = talloc_stackframe();
858         if (tmp_ctx == NULL) {
859                 return NT_STATUS_NO_MEMORY;
860         }
861
862         pipe_name = get_pipe_name_from_syntax(tmp_ctx, syntax);
863         if (pipe_name == NULL) {
864                 status = NT_STATUS_INVALID_PARAMETER;
865                 goto done;
866         }
867
868         while (pipe_name[0] == '\\') {
869                 pipe_name++;
870         }
871
872         DEBUG(5, ("Connecting to %s pipe.\n", pipe_name));
873
874         server_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
875                                            "rpc_server", pipe_name,
876                                            "embedded");
877
878         if (StrCaseCmp(server_type, "embedded") == 0) {
879                 status = rpc_pipe_open_internal(tmp_ctx,
880                                                 syntax, session_info,
881                                                 client_id, msg_ctx,
882                                                 &cli);
883                 if (!NT_STATUS_IS_OK(status)) {
884                         goto done;
885                 }
886         } else if (StrCaseCmp(server_type, "daemon") == 0 ||
887                    StrCaseCmp(server_type, "external") == 0) {
888                 /* It would be nice to just use rpc_pipe_open_ncalrpc() but
889                  * for now we need to use the special proxy setup to connect
890                  * to spoolssd. */
891
892                 status = rpc_pipe_open_external(tmp_ctx,
893                                                 pipe_name, syntax,
894                                                 session_info,
895                                                 &cli);
896                 if (!NT_STATUS_IS_OK(status)) {
897                         goto done;
898                 }
899         } else {
900                 status = NT_STATUS_NOT_IMPLEMENTED;
901                 DEBUG(0, ("Wrong servertype specified in config file: %s",
902                           nt_errstr(status)));
903                 goto done;
904         }
905
906         status = NT_STATUS_OK;
907 done:
908         if (NT_STATUS_IS_OK(status)) {
909                 *cli_pipe = talloc_move(mem_ctx, &cli);
910         }
911         TALLOC_FREE(tmp_ctx);
912         return status;
913 }