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