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