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