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