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