• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/librpc/rpc/
1/*
2   Unix SMB/CIFS implementation.
3
4   dcerpc connect functions
5
6   Copyright (C) Andrew Tridgell 2003
7   Copyright (C) Jelmer Vernooij 2004
8   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2007
9   Copyright (C) Rafal Szczesniak  2005
10
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 3 of the License, or
14   (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program.  If not, see <http://www.gnu.org/licenses/>.
23*/
24
25
26#include "includes.h"
27#include "libcli/composite/composite.h"
28#include "libcli/smb_composite/smb_composite.h"
29#include "lib/events/events.h"
30#include "libcli/smb2/smb2.h"
31#include "libcli/smb2/smb2_calls.h"
32#include "librpc/rpc/dcerpc.h"
33#include "librpc/rpc/dcerpc_proto.h"
34#include "auth/credentials/credentials.h"
35#include "param/param.h"
36#include "libcli/resolve/resolve.h"
37
38
39struct pipe_np_smb_state {
40	struct smb_composite_connect conn;
41	struct smbcli_tree *tree;
42	struct dcerpc_pipe_connect io;
43};
44
45
46/*
47  Stage 3 of ncacn_np_smb: Named pipe opened (or not)
48*/
49static void continue_pipe_open_smb(struct composite_context *ctx)
50{
51	struct composite_context *c = talloc_get_type(ctx->async.private_data,
52						      struct composite_context);
53
54	/* receive result of named pipe open request on smb */
55	c->status = dcerpc_pipe_open_smb_recv(ctx);
56	if (!composite_is_ok(c)) return;
57
58	composite_done(c);
59}
60
61
62/*
63  Stage 2 of ncacn_np_smb: Open a named pipe after successful smb connection
64*/
65static void continue_smb_connect(struct composite_context *ctx)
66{
67	struct composite_context *open_ctx;
68	struct composite_context *c = talloc_get_type(ctx->async.private_data,
69						      struct composite_context);
70	struct pipe_np_smb_state *s = talloc_get_type(c->private_data,
71						      struct pipe_np_smb_state);
72
73	/* receive result of smb connect request */
74	c->status = smb_composite_connect_recv(ctx, c);
75	if (!composite_is_ok(c)) return;
76
77	/* prepare named pipe open parameters */
78	s->tree         = s->conn.out.tree;
79	s->io.pipe_name = s->io.binding->endpoint;
80
81	/* send named pipe open request */
82	open_ctx = dcerpc_pipe_open_smb_send(s->io.pipe, s->tree, s->io.pipe_name);
83	if (composite_nomem(open_ctx, c)) return;
84
85	composite_continue(c, open_ctx, continue_pipe_open_smb, c);
86}
87
88
89/*
90  Initiate async open of a rpc connection to a rpc pipe on SMB using
91  the binding structure to determine the endpoint and options
92*/
93static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb_send(TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
94{
95	struct composite_context *c;
96	struct pipe_np_smb_state *s;
97	struct composite_context *conn_req;
98	struct smb_composite_connect *conn;
99
100	/* composite context allocation and setup */
101	c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
102	if (c == NULL) return NULL;
103
104	s = talloc_zero(c, struct pipe_np_smb_state);
105	if (composite_nomem(s, c)) return c;
106	c->private_data = s;
107
108	s->io  = *io;
109	conn   = &s->conn;
110
111	/* prepare smb connection parameters: we're connecting to IPC$ share on
112	   remote rpc server */
113	conn->in.dest_host              = s->io.binding->host;
114	conn->in.dest_ports                  = lp_smb_ports(lp_ctx);
115	if (s->io.binding->target_hostname == NULL)
116		conn->in.called_name = "*SMBSERVER"; /* FIXME: This is invalid */
117	else
118		conn->in.called_name            = s->io.binding->target_hostname;
119	conn->in.socket_options         = lp_socket_options(lp_ctx);
120	conn->in.service                = "IPC$";
121	conn->in.service_type           = NULL;
122	conn->in.workgroup		= lp_workgroup(lp_ctx);
123	conn->in.gensec_settings = lp_gensec_settings(conn, lp_ctx);
124	conn->in.iconv_convenience = lp_iconv_convenience(lp_ctx);
125
126	lp_smbcli_options(lp_ctx, &conn->in.options);
127	lp_smbcli_session_options(lp_ctx, &conn->in.session_options);
128
129	/*
130	 * provide proper credentials - user supplied, but allow a
131	 * fallback to anonymous if this is an schannel connection
132	 * (might be NT4 not allowing machine logins at session
133	 * setup) or if asked to do so by the caller (perhaps a SAMR password change?)
134	 */
135	s->conn.in.credentials = s->io.creds;
136	if (s->io.binding->flags & (DCERPC_SCHANNEL|DCERPC_ANON_FALLBACK)) {
137		conn->in.fallback_to_anonymous  = true;
138	} else {
139		conn->in.fallback_to_anonymous  = false;
140	}
141
142	/* send smb connect request */
143	conn_req = smb_composite_connect_send(conn, s->io.pipe->conn,
144					      s->io.resolve_ctx,
145					      s->io.pipe->conn->event_ctx);
146	if (composite_nomem(conn_req, c)) return c;
147
148	composite_continue(c, conn_req, continue_smb_connect, c);
149	return c;
150}
151
152
153/*
154  Receive result of a rpc connection to a rpc pipe on SMB
155*/
156static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb_recv(struct composite_context *c)
157{
158	NTSTATUS status = composite_wait(c);
159
160	talloc_free(c);
161	return status;
162}
163
164
165struct pipe_np_smb2_state {
166	struct smb2_tree *tree;
167	struct dcerpc_pipe_connect io;
168};
169
170
171/*
172  Stage 3 of ncacn_np_smb: Named pipe opened (or not)
173*/
174static void continue_pipe_open_smb2(struct composite_context *ctx)
175{
176	struct composite_context *c = talloc_get_type(ctx->async.private_data,
177						      struct composite_context);
178
179	/* receive result of named pipe open request on smb2 */
180	c->status = dcerpc_pipe_open_smb2_recv(ctx);
181	if (!composite_is_ok(c)) return;
182
183	composite_done(c);
184}
185
186
187/*
188  Stage 2 of ncacn_np_smb2: Open a named pipe after successful smb2 connection
189*/
190static void continue_smb2_connect(struct composite_context *ctx)
191{
192	struct composite_context *open_req;
193	struct composite_context *c = talloc_get_type(ctx->async.private_data,
194						      struct composite_context);
195	struct pipe_np_smb2_state *s = talloc_get_type(c->private_data,
196						       struct pipe_np_smb2_state);
197
198	/* receive result of smb2 connect request */
199	c->status = smb2_connect_recv(ctx, c, &s->tree);
200	if (!composite_is_ok(c)) return;
201
202	/* prepare named pipe open parameters */
203	s->io.pipe_name = s->io.binding->endpoint;
204
205	/* send named pipe open request */
206	open_req = dcerpc_pipe_open_smb2_send(s->io.pipe, s->tree, s->io.pipe_name);
207	if (composite_nomem(open_req, c)) return;
208
209	composite_continue(c, open_req, continue_pipe_open_smb2, c);
210}
211
212
213/*
214   Initiate async open of a rpc connection request on SMB2 using
215   the binding structure to determine the endpoint and options
216*/
217static struct composite_context *dcerpc_pipe_connect_ncacn_np_smb2_send(
218					TALLOC_CTX *mem_ctx,
219					struct dcerpc_pipe_connect *io,
220					struct loadparm_context *lp_ctx)
221{
222	struct composite_context *c;
223	struct pipe_np_smb2_state *s;
224	struct composite_context *conn_req;
225	struct smbcli_options options;
226
227	/* composite context allocation and setup */
228	c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
229	if (c == NULL) return NULL;
230
231	s = talloc_zero(c, struct pipe_np_smb2_state);
232	if (composite_nomem(s, c)) return c;
233	c->private_data = s;
234
235	s->io = *io;
236
237	/*
238	 * provide proper credentials - user supplied or anonymous in case this is
239	 * schannel connection
240	 */
241	if (s->io.binding->flags & DCERPC_SCHANNEL) {
242		s->io.creds = cli_credentials_init(mem_ctx);
243		if (composite_nomem(s->io.creds, c)) return c;
244
245		cli_credentials_guess(s->io.creds, lp_ctx);
246	}
247
248	lp_smbcli_options(lp_ctx, &options);
249
250	/* send smb2 connect request */
251	conn_req = smb2_connect_send(mem_ctx, s->io.binding->host,
252			lp_parm_string_list(mem_ctx, lp_ctx, NULL, "smb2", "ports", NULL),
253					"IPC$",
254				     s->io.resolve_ctx,
255				     s->io.creds,
256				     c->event_ctx,
257				     &options,
258					 lp_socket_options(lp_ctx),
259					 lp_gensec_settings(mem_ctx, lp_ctx)
260					 );
261	composite_continue(c, conn_req, continue_smb2_connect, c);
262	return c;
263}
264
265
266/*
267  Receive result of a rpc connection to a rpc pipe on SMB2
268*/
269static NTSTATUS dcerpc_pipe_connect_ncacn_np_smb2_recv(struct composite_context *c)
270{
271	NTSTATUS status = composite_wait(c);
272
273	talloc_free(c);
274	return status;
275}
276
277
278struct pipe_ip_tcp_state {
279	struct dcerpc_pipe_connect io;
280	const char *host;
281	const char *target_hostname;
282	uint32_t port;
283};
284
285
286/*
287  Stage 2 of ncacn_ip_tcp: rpc pipe opened (or not)
288*/
289static void continue_pipe_open_ncacn_ip_tcp(struct composite_context *ctx)
290{
291	struct composite_context *c = talloc_get_type(ctx->async.private_data,
292						      struct composite_context);
293
294	/* receive result of named pipe open request on tcp/ip */
295	c->status = dcerpc_pipe_open_tcp_recv(ctx);
296	if (!composite_is_ok(c)) return;
297
298	composite_done(c);
299}
300
301
302/*
303  Initiate async open of a rpc connection to a rpc pipe on TCP/IP using
304  the binding structure to determine the endpoint and options
305*/
306static struct composite_context* dcerpc_pipe_connect_ncacn_ip_tcp_send(TALLOC_CTX *mem_ctx,
307								       struct dcerpc_pipe_connect *io)
308{
309	struct composite_context *c;
310	struct pipe_ip_tcp_state *s;
311	struct composite_context *pipe_req;
312
313	/* composite context allocation and setup */
314	c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
315	if (c == NULL) return NULL;
316
317	s = talloc_zero(c, struct pipe_ip_tcp_state);
318	if (composite_nomem(s, c)) return c;
319	c->private_data = s;
320
321	/* store input parameters in state structure */
322	s->io               = *io;
323	s->host             = talloc_reference(c, io->binding->host);
324	s->target_hostname  = talloc_reference(c, io->binding->target_hostname);
325                             /* port number is a binding endpoint here */
326	s->port             = atoi(io->binding->endpoint);
327
328	/* send pipe open request on tcp/ip */
329	pipe_req = dcerpc_pipe_open_tcp_send(s->io.pipe->conn, s->host, s->target_hostname,
330					     s->port, io->resolve_ctx);
331	composite_continue(c, pipe_req, continue_pipe_open_ncacn_ip_tcp, c);
332	return c;
333}
334
335
336/*
337  Receive result of a rpc connection to a rpc pipe on TCP/IP
338*/
339static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *c)
340{
341	NTSTATUS status = composite_wait(c);
342
343	talloc_free(c);
344	return status;
345}
346
347
348struct pipe_unix_state {
349	struct dcerpc_pipe_connect io;
350	const char *path;
351};
352
353
354/*
355  Stage 2 of ncacn_unix: rpc pipe opened (or not)
356*/
357static void continue_pipe_open_ncacn_unix_stream(struct composite_context *ctx)
358{
359	struct composite_context *c = talloc_get_type(ctx->async.private_data,
360						      struct composite_context);
361
362	/* receive result of pipe open request on unix socket */
363	c->status = dcerpc_pipe_open_unix_stream_recv(ctx);
364	if (!composite_is_ok(c)) return;
365
366	composite_done(c);
367}
368
369
370/*
371  Initiate async open of a rpc connection to a rpc pipe on unix socket using
372  the binding structure to determine the endpoint and options
373*/
374static struct composite_context* dcerpc_pipe_connect_ncacn_unix_stream_send(TALLOC_CTX *mem_ctx,
375									    struct dcerpc_pipe_connect *io)
376{
377	struct composite_context *c;
378	struct pipe_unix_state *s;
379	struct composite_context *pipe_req;
380
381	/* composite context allocation and setup */
382	c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
383	if (c == NULL) return NULL;
384
385	s = talloc_zero(c, struct pipe_unix_state);
386	if (composite_nomem(s, c)) return c;
387	c->private_data = s;
388
389	/* prepare pipe open parameters and store them in state structure
390	   also, verify whether biding endpoint is not null */
391	s->io = *io;
392
393	if (!io->binding->endpoint) {
394		DEBUG(0, ("Path to unix socket not specified\n"));
395		composite_error(c, NT_STATUS_INVALID_PARAMETER);
396		return c;
397	}
398
399	s->path  = talloc_strdup(c, io->binding->endpoint);  /* path is a binding endpoint here */
400	if (composite_nomem(s->path, c)) return c;
401
402	/* send pipe open request on unix socket */
403	pipe_req = dcerpc_pipe_open_unix_stream_send(s->io.pipe->conn, s->path);
404	composite_continue(c, pipe_req, continue_pipe_open_ncacn_unix_stream, c);
405	return c;
406}
407
408
409/*
410  Receive result of a rpc connection to a pipe on unix socket
411*/
412static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream_recv(struct composite_context *c)
413{
414	NTSTATUS status = composite_wait(c);
415
416	talloc_free(c);
417	return status;
418}
419
420
421struct pipe_ncalrpc_state {
422	struct dcerpc_pipe_connect io;
423};
424
425static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c);
426
427/*
428  Stage 2 of ncalrpc: rpc pipe opened (or not)
429*/
430static void continue_pipe_open_ncalrpc(struct composite_context *ctx)
431{
432	struct composite_context *c = talloc_get_type(ctx->async.private_data,
433						      struct composite_context);
434
435	/* receive result of pipe open request on ncalrpc */
436	c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
437	if (!composite_is_ok(c)) return;
438
439	composite_done(c);
440}
441
442
443/*
444   Initiate async open of a rpc connection request on NCALRPC using
445   the binding structure to determine the endpoint and options
446*/
447static struct composite_context* dcerpc_pipe_connect_ncalrpc_send(TALLOC_CTX *mem_ctx,
448								  struct dcerpc_pipe_connect *io, struct loadparm_context *lp_ctx)
449{
450	struct composite_context *c;
451	struct pipe_ncalrpc_state *s;
452	struct composite_context *pipe_req;
453
454	/* composite context allocation and setup */
455	c = composite_create(mem_ctx, io->pipe->conn->event_ctx);
456	if (c == NULL) return NULL;
457
458	s = talloc_zero(c, struct pipe_ncalrpc_state);
459	if (composite_nomem(s, c)) return c;
460	c->private_data = s;
461
462	/* store input parameters in state structure */
463	s->io  = *io;
464
465	/* send pipe open request */
466	pipe_req = dcerpc_pipe_open_pipe_send(s->io.pipe->conn, lp_ncalrpc_dir(lp_ctx),
467					      s->io.binding->endpoint);
468	composite_continue(c, pipe_req, continue_pipe_open_ncalrpc, c);
469	return c;
470}
471
472
473/*
474  Receive result of a rpc connection to a rpc pipe on NCALRPC
475*/
476static NTSTATUS dcerpc_pipe_connect_ncalrpc_recv(struct composite_context *c)
477{
478	NTSTATUS status = composite_wait(c);
479
480	talloc_free(c);
481	return status;
482}
483
484
485struct pipe_connect_state {
486	struct dcerpc_pipe *pipe;
487	struct dcerpc_binding *binding;
488	const struct ndr_interface_table *table;
489	struct cli_credentials *credentials;
490	struct loadparm_context *lp_ctx;
491};
492
493
494static void continue_map_binding(struct composite_context *ctx);
495static void continue_connect(struct composite_context *c, struct pipe_connect_state *s);
496static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
497static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
498static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
499static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
500static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
501static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
502static void continue_pipe_auth(struct composite_context *ctx);
503
504
505/*
506  Stage 2 of pipe_connect_b: Receive result of endpoint mapping
507*/
508static void continue_map_binding(struct composite_context *ctx)
509{
510	struct composite_context *c = talloc_get_type(ctx->async.private_data,
511						      struct composite_context);
512	struct pipe_connect_state *s = talloc_get_type(c->private_data,
513						       struct pipe_connect_state);
514
515	c->status = dcerpc_epm_map_binding_recv(ctx);
516	if (!composite_is_ok(c)) return;
517
518	DEBUG(2,("Mapped to DCERPC endpoint %s\n", s->binding->endpoint));
519
520	continue_connect(c, s);
521}
522
523
524/*
525  Stage 2 of pipe_connect_b: Continue connection after endpoint is known
526*/
527static void continue_connect(struct composite_context *c, struct pipe_connect_state *s)
528{
529	struct dcerpc_pipe_connect pc;
530
531	/* potential exits to another stage by sending an async request */
532	struct composite_context *ncacn_np_smb2_req;
533	struct composite_context *ncacn_np_smb_req;
534	struct composite_context *ncacn_ip_tcp_req;
535	struct composite_context *ncacn_unix_req;
536	struct composite_context *ncalrpc_req;
537
538	/* dcerpc pipe connect input parameters */
539	pc.pipe         = s->pipe;
540	pc.binding      = s->binding;
541	pc.interface    = s->table;
542	pc.creds        = s->credentials;
543	pc.resolve_ctx  = lp_resolve_context(s->lp_ctx);
544
545	/* connect dcerpc pipe depending on required transport */
546	switch (s->binding->transport) {
547	case NCACN_NP:
548		if (pc.binding->flags & DCERPC_SMB2) {
549			/* new varient of SMB a.k.a. SMB2 */
550			ncacn_np_smb2_req = dcerpc_pipe_connect_ncacn_np_smb2_send(c, &pc, s->lp_ctx);
551			composite_continue(c, ncacn_np_smb2_req, continue_pipe_connect_ncacn_np_smb2, c);
552			return;
553
554		} else {
555			/* good old ordinary SMB */
556			ncacn_np_smb_req = dcerpc_pipe_connect_ncacn_np_smb_send(c, &pc, s->lp_ctx);
557			composite_continue(c, ncacn_np_smb_req, continue_pipe_connect_ncacn_np_smb, c);
558			return;
559		}
560		break;
561
562	case NCACN_IP_TCP:
563		ncacn_ip_tcp_req = dcerpc_pipe_connect_ncacn_ip_tcp_send(c, &pc);
564		composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
565		return;
566
567	case NCACN_UNIX_STREAM:
568		ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
569		composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
570		return;
571
572	case NCALRPC:
573		ncalrpc_req = dcerpc_pipe_connect_ncalrpc_send(c, &pc, s->lp_ctx);
574		composite_continue(c, ncalrpc_req, continue_pipe_connect_ncalrpc, c);
575		return;
576
577	default:
578		/* looks like a transport we don't support now */
579		composite_error(c, NT_STATUS_NOT_SUPPORTED);
580	}
581}
582
583
584/*
585  Stage 3 of pipe_connect_b: Receive result of pipe connect request on
586  named pipe on smb2
587*/
588static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx)
589{
590	struct composite_context *c = talloc_get_type(ctx->async.private_data,
591						      struct composite_context);
592	struct pipe_connect_state *s = talloc_get_type(c->private_data,
593						       struct pipe_connect_state);
594
595	c->status = dcerpc_pipe_connect_ncacn_np_smb2_recv(ctx);
596	if (!composite_is_ok(c)) return;
597
598	continue_pipe_connect(c, s);
599}
600
601
602/*
603  Stage 3 of pipe_connect_b: Receive result of pipe connect request on
604  named pipe on smb
605*/
606static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx)
607{
608	struct composite_context *c = talloc_get_type(ctx->async.private_data,
609						      struct composite_context);
610	struct pipe_connect_state *s = talloc_get_type(c->private_data,
611						       struct pipe_connect_state);
612
613	c->status = dcerpc_pipe_connect_ncacn_np_smb_recv(ctx);
614	if (!composite_is_ok(c)) return;
615
616	continue_pipe_connect(c, s);
617}
618
619
620/*
621  Stage 3 of pipe_connect_b: Receive result of pipe connect request on tcp/ip
622*/
623static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
624{
625	struct composite_context *c = talloc_get_type(ctx->async.private_data,
626						      struct composite_context);
627	struct pipe_connect_state *s = talloc_get_type(c->private_data,
628						       struct pipe_connect_state);
629
630	c->status = dcerpc_pipe_connect_ncacn_ip_tcp_recv(ctx);
631	if (!composite_is_ok(c)) return;
632
633	continue_pipe_connect(c, s);
634}
635
636
637/*
638  Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
639*/
640static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx)
641{
642	struct composite_context *c = talloc_get_type(ctx->async.private_data,
643						      struct composite_context);
644	struct pipe_connect_state *s = talloc_get_type(c->private_data,
645						       struct pipe_connect_state);
646
647	c->status = dcerpc_pipe_connect_ncacn_unix_stream_recv(ctx);
648	if (!composite_is_ok(c)) return;
649
650	continue_pipe_connect(c, s);
651}
652
653
654/*
655  Stage 3 of pipe_connect_b: Receive result of pipe connect request on local rpc
656*/
657static void continue_pipe_connect_ncalrpc(struct composite_context *ctx)
658{
659	struct composite_context *c = talloc_get_type(ctx->async.private_data,
660						      struct composite_context);
661	struct pipe_connect_state *s = talloc_get_type(c->private_data,
662						       struct pipe_connect_state);
663
664	c->status = dcerpc_pipe_connect_ncalrpc_recv(ctx);
665	if (!composite_is_ok(c)) return;
666
667	continue_pipe_connect(c, s);
668}
669
670
671/*
672  Stage 4 of pipe_connect_b: Start an authentication on connected dcerpc pipe
673  depending on credentials and binding flags passed.
674*/
675static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s)
676{
677	struct composite_context *auth_bind_req;
678
679	s->pipe->binding = s->binding;
680	if (!talloc_reference(s->pipe, s->binding)) {
681		composite_error(c, NT_STATUS_NO_MEMORY);
682		return;
683	}
684
685	auth_bind_req = dcerpc_pipe_auth_send(s->pipe, s->binding, s->table,
686					      s->credentials, s->lp_ctx);
687	composite_continue(c, auth_bind_req, continue_pipe_auth, c);
688}
689
690
691/*
692  Stage 5 of pipe_connect_b: Receive result of pipe authentication request
693  and say if all went ok
694*/
695static void continue_pipe_auth(struct composite_context *ctx)
696{
697	struct composite_context *c = talloc_get_type(ctx->async.private_data,
698						      struct composite_context);
699	struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
700
701	c->status = dcerpc_pipe_auth_recv(ctx, s, &s->pipe);
702	if (!composite_is_ok(c)) return;
703
704	composite_done(c);
705}
706
707
708/*
709  handle timeouts of a dcerpc connect
710*/
711static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
712					   struct timeval t, void *private_data)
713{
714	struct composite_context *c = talloc_get_type(private_data, struct composite_context);
715	composite_error(c, NT_STATUS_IO_TIMEOUT);
716}
717
718/*
719  start a request to open a rpc connection to a rpc pipe, using
720  specified binding structure to determine the endpoint and options
721*/
722_PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent_ctx,
723						     struct dcerpc_binding *binding,
724						     const struct ndr_interface_table *table,
725						     struct cli_credentials *credentials,
726						     struct tevent_context *ev,
727						     struct loadparm_context *lp_ctx)
728{
729	struct composite_context *c;
730	struct pipe_connect_state *s;
731	struct tevent_context *new_ev = NULL;
732
733	/* composite context allocation and setup */
734	c = composite_create(parent_ctx, ev);
735	if (c == NULL) {
736		talloc_free(new_ev);
737		return NULL;
738	}
739	talloc_steal(c, new_ev);
740
741	s = talloc_zero(c, struct pipe_connect_state);
742	if (composite_nomem(s, c)) return c;
743	c->private_data = s;
744
745	/* initialise dcerpc pipe structure */
746	s->pipe = dcerpc_pipe_init(c, ev, lp_iconv_convenience(lp_ctx));
747	if (composite_nomem(s->pipe, c)) return c;
748
749	if (DEBUGLEVEL >= 10)
750		s->pipe->conn->packet_log_dir = lp_lockdir(lp_ctx);
751
752	/* store parameters in state structure */
753	s->binding      = binding;
754	s->table        = table;
755	s->credentials  = credentials;
756	s->lp_ctx 	= lp_ctx;
757
758	event_add_timed(c->event_ctx, c,
759			timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
760			dcerpc_connect_timeout_handler, c);
761
762	switch (s->binding->transport) {
763	case NCA_UNKNOWN: {
764		struct composite_context *binding_req;
765		binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
766							  s->pipe->conn->event_ctx,
767							  s->lp_ctx);
768		composite_continue(c, binding_req, continue_map_binding, c);
769		return c;
770		}
771
772	case NCACN_NP:
773	case NCACN_IP_TCP:
774	case NCALRPC:
775		if (!s->binding->endpoint) {
776			struct composite_context *binding_req;
777			binding_req = dcerpc_epm_map_binding_send(c, s->binding, s->table,
778								  s->pipe->conn->event_ctx,
779								  s->lp_ctx);
780			composite_continue(c, binding_req, continue_map_binding, c);
781			return c;
782		}
783
784	default:
785		break;
786	}
787
788	continue_connect(c, s);
789	return c;
790}
791
792
793/*
794  receive result of a request to open a rpc connection to a rpc pipe
795*/
796_PUBLIC_ NTSTATUS dcerpc_pipe_connect_b_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
797				    struct dcerpc_pipe **p)
798{
799	NTSTATUS status;
800	struct pipe_connect_state *s;
801
802	status = composite_wait(c);
803
804	if (NT_STATUS_IS_OK(status)) {
805		s = talloc_get_type(c->private_data, struct pipe_connect_state);
806		talloc_steal(mem_ctx, s->pipe);
807		*p = s->pipe;
808	}
809	talloc_free(c);
810	return status;
811}
812
813
814/*
815  open a rpc connection to a rpc pipe, using the specified
816  binding structure to determine the endpoint and options - sync version
817*/
818_PUBLIC_ NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx,
819			       struct dcerpc_pipe **pp,
820			       struct dcerpc_binding *binding,
821			       const struct ndr_interface_table *table,
822			       struct cli_credentials *credentials,
823			       struct tevent_context *ev,
824			       struct loadparm_context *lp_ctx)
825{
826	struct composite_context *c;
827
828	c = dcerpc_pipe_connect_b_send(parent_ctx, binding, table,
829				       credentials, ev, lp_ctx);
830	return dcerpc_pipe_connect_b_recv(c, parent_ctx, pp);
831}
832
833
834struct pipe_conn_state {
835	struct dcerpc_pipe *pipe;
836};
837
838
839static void continue_pipe_connect_b(struct composite_context *ctx);
840
841
842/*
843  Initiate rpc connection to a rpc pipe, using the specified string
844  binding to determine the endpoint and options.
845  The string is to be parsed to a binding structure first.
846*/
847_PUBLIC_ struct composite_context* dcerpc_pipe_connect_send(TALLOC_CTX *parent_ctx,
848						   const char *binding,
849						   const struct ndr_interface_table *table,
850						   struct cli_credentials *credentials,
851						   struct tevent_context *ev, struct loadparm_context *lp_ctx)
852{
853	struct composite_context *c;
854	struct pipe_conn_state *s;
855	struct dcerpc_binding *b;
856	struct composite_context *pipe_conn_req;
857
858	/* composite context allocation and setup */
859	c = composite_create(parent_ctx, ev);
860	if (c == NULL) {
861		return NULL;
862	}
863
864	s = talloc_zero(c, struct pipe_conn_state);
865	if (composite_nomem(s, c)) return c;
866	c->private_data = s;
867
868	/* parse binding string to the structure */
869	c->status = dcerpc_parse_binding(c, binding, &b);
870	if (!NT_STATUS_IS_OK(c->status)) {
871		DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
872		composite_error(c, c->status);
873		return c;
874	}
875
876	DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(c, b)));
877
878	/*
879	   start connecting to a rpc pipe after binding structure
880	   is established
881	 */
882	pipe_conn_req = dcerpc_pipe_connect_b_send(c, b, table,
883						   credentials, ev, lp_ctx);
884	composite_continue(c, pipe_conn_req, continue_pipe_connect_b, c);
885	return c;
886}
887
888
889/*
890  Stage 2 of pipe_connect: Receive result of actual pipe connect request
891  and say if we're done ok
892*/
893static void continue_pipe_connect_b(struct composite_context *ctx)
894{
895	struct composite_context *c = talloc_get_type(ctx->async.private_data,
896						      struct composite_context);
897	struct pipe_conn_state *s = talloc_get_type(c->private_data,
898						    struct pipe_conn_state);
899
900	c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->pipe);
901	talloc_steal(s, s->pipe);
902	if (!composite_is_ok(c)) return;
903
904	composite_done(c);
905}
906
907
908/*
909  Receive result of pipe connect (using binding string) request
910  and return connected pipe structure.
911*/
912NTSTATUS dcerpc_pipe_connect_recv(struct composite_context *c,
913				  TALLOC_CTX *mem_ctx,
914				  struct dcerpc_pipe **pp)
915{
916	NTSTATUS status;
917	struct pipe_conn_state *s;
918
919	status = composite_wait(c);
920	if (NT_STATUS_IS_OK(status)) {
921		s = talloc_get_type(c->private_data, struct pipe_conn_state);
922		*pp = talloc_steal(mem_ctx, s->pipe);
923	}
924	talloc_free(c);
925	return status;
926}
927
928
929/*
930  Open a rpc connection to a rpc pipe, using the specified string
931  binding to determine the endpoint and options - sync version
932*/
933_PUBLIC_ NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx,
934			     struct dcerpc_pipe **pp,
935			     const char *binding,
936			     const struct ndr_interface_table *table,
937			     struct cli_credentials *credentials,
938			     struct tevent_context *ev,
939			     struct loadparm_context *lp_ctx)
940{
941	struct composite_context *c;
942	c = dcerpc_pipe_connect_send(parent_ctx, binding,
943				     table, credentials, ev, lp_ctx);
944	return dcerpc_pipe_connect_recv(c, parent_ctx, pp);
945}
946
947