r19759: Allow a join to occour against ncacn_ip_tcp again (useful for torture
[sfrench/samba-autobuild/.git] / source4 / libnet / libnet_rpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Stefan Metzmacher  2004
5    Copyright (C) Rafal Szczesniak   2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "libnet/libnet.h"
24 #include "libcli/libcli.h"
25 #include "libcli/composite/composite.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/gen_ndr/ndr_lsa_c.h"
28 #include "librpc/gen_ndr/ndr_samr.h"
29
30
31 struct rpc_connect_srv_state {
32         struct libnet_context *ctx;
33         struct libnet_RpcConnect r;
34         const char *binding;
35 };
36
37
38 static void continue_pipe_connect(struct composite_context *ctx);
39
40
41 /**
42  * Initiates connection to rpc pipe on remote server
43  * 
44  * @param ctx initialised libnet context
45  * @param mem_ctx memory context of this call
46  * @param r data structure containing necessary parameters and return values
47  * @return composite context of this call
48  **/
49
50 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
51                                                            TALLOC_CTX *mem_ctx,
52                                                            struct libnet_RpcConnect *r)
53 {
54         struct composite_context *c;    
55         struct rpc_connect_srv_state *s;
56         struct dcerpc_binding *b;
57         struct composite_context *pipe_connect_req;
58
59         /* composite context allocation and setup */
60         c = talloc_zero(mem_ctx, struct composite_context);
61         if (c == NULL) return NULL;
62
63         s = talloc_zero(c, struct rpc_connect_srv_state);
64         if (composite_nomem(s, c)) return c;
65
66         c->state = COMPOSITE_STATE_IN_PROGRESS;
67         c->private_data = s;
68         c->event_ctx = ctx->event_ctx;
69
70         s->ctx = ctx;
71         s->r = *r;
72         ZERO_STRUCT(s->r.out);
73
74         /* prepare binding string */
75         switch (r->level) {
76         case LIBNET_RPC_CONNECT_SERVER:
77                 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
78                 break;
79         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
80                 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);
81                 break;
82
83         case LIBNET_RPC_CONNECT_BINDING:
84                 s->binding = talloc_strdup(s, r->in.binding);
85                 break;
86
87         case LIBNET_RPC_CONNECT_DC:
88         case LIBNET_RPC_CONNECT_PDC:
89                 /* this should never happen - DC and PDC level has a separate
90                    composite function */
91         case LIBNET_RPC_CONNECT_DC_INFO:
92                 /* this should never happen - DC_INFO level has a separate
93                    composite function */
94                 composite_error(c, NT_STATUS_INVALID_LEVEL);
95                 return c;
96         }
97
98         /* parse binding string to the structure */
99         c->status = dcerpc_parse_binding(c, s->binding, &b);
100         if (!NT_STATUS_IS_OK(c->status)) {
101                 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));
102                 composite_error(c, c->status);
103                 return c;
104         }
105
106         if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {
107                 b->target_hostname = talloc_reference(b, r->in.name);
108                 if (composite_nomem(b->target_hostname, c)) {
109                         return c;
110                 }
111         }
112
113         /* connect to remote dcerpc pipe */
114         pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
115                                                       ctx->cred, c->event_ctx);
116         if (composite_nomem(pipe_connect_req, c)) return c;
117
118         composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
119         return c;
120 }
121
122
123 /*
124   Step 2 of RpcConnectSrv - get rpc connection
125 */
126 static void continue_pipe_connect(struct composite_context *ctx)
127 {
128         struct composite_context *c;
129         struct rpc_connect_srv_state *s;
130
131         c = talloc_get_type(ctx->async.private_data, struct composite_context);
132         s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
133
134         /* receive result of rpc pipe connection */
135         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
136
137         composite_done(c);
138 }
139
140
141 /**
142  * Receives result of connection to rpc pipe on remote server
143  *
144  * @param c composite context
145  * @param ctx initialised libnet context
146  * @param mem_ctx memory context of this call
147  * @param r data structure containing necessary parameters and return values
148  * @return nt status of rpc connection
149  **/
150
151 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
152                                           struct libnet_context *ctx,
153                                           TALLOC_CTX *mem_ctx,
154                                           struct libnet_RpcConnect *r)
155 {
156         NTSTATUS status;
157         struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,
158                                           struct rpc_connect_srv_state);
159
160         status = composite_wait(c);
161         if (NT_STATUS_IS_OK(status)) {
162                 /* move the returned rpc pipe between memory contexts */
163                 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
164                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
165
166                 /* reference created pipe structure to long-term libnet_context
167                    so that it can be used by other api functions even after short-term
168                    mem_ctx is freed */
169                 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
170                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
171
172                 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
173                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
174                 }
175
176                 r->out.error_string = talloc_strdup(mem_ctx, "Success");
177
178         } else {
179                 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
180         }
181
182         talloc_free(c);
183         return status;
184 }
185
186
187 struct rpc_connect_dc_state {
188         struct libnet_context *ctx;
189         struct libnet_RpcConnect r;
190         struct libnet_RpcConnect r2;
191         struct libnet_LookupDCs f;
192         const char *connect_name;
193
194         /* information about the progress */
195         void (*monitor_fn)(struct monitor_msg *);
196 };
197
198
199 static void continue_lookup_dc(struct composite_context *ctx);
200 static void continue_rpc_connect(struct composite_context *ctx);
201
202
203 /**
204  * Initiates connection to rpc pipe on domain pdc
205  * 
206  * @param ctx initialised libnet context
207  * @param mem_ctx memory context of this call
208  * @param r data structure containing necessary parameters and return values
209  * @return composite context of this call
210  **/
211
212 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
213                                                           TALLOC_CTX *mem_ctx,
214                                                           struct libnet_RpcConnect *r)
215 {
216         struct composite_context *c;
217         struct rpc_connect_dc_state *s;
218         struct composite_context *lookup_dc_req;
219
220         /* composite context allocation and setup */
221         c = talloc_zero(mem_ctx, struct composite_context);
222         if (c == NULL) return NULL;
223
224         s = talloc_zero(c, struct rpc_connect_dc_state);
225         if (composite_nomem(s, c)) return c;
226
227         c->state = COMPOSITE_STATE_IN_PROGRESS;
228         c->private_data = s;
229         c->event_ctx = ctx->event_ctx;
230
231         s->ctx = ctx;
232         s->r   = *r;
233         ZERO_STRUCT(s->r.out);
234
235         switch (r->level) {
236         case LIBNET_RPC_CONNECT_PDC:
237                 s->f.in.name_type = NBT_NAME_PDC;
238                 break;
239
240         case LIBNET_RPC_CONNECT_DC:
241                 s->f.in.name_type = NBT_NAME_LOGON;
242                 break;
243
244         default:
245                 break;
246         }
247
248         s->f.in.domain_name = r->in.name;
249         s->f.out.num_dcs    = 0;
250         s->f.out.dcs        = NULL;
251
252         /* find the domain pdc first */
253         lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
254         if (composite_nomem(lookup_dc_req, c)) return c;
255
256         composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
257         return c;
258 }
259
260
261 /*
262   Step 2 of RpcConnectDC: get domain controller name and
263   initiate RpcConnect to it
264 */
265 static void continue_lookup_dc(struct composite_context *ctx)
266 {
267         struct composite_context *c;
268         struct rpc_connect_dc_state *s;
269         struct composite_context *rpc_connect_req;
270         struct monitor_msg msg;
271         struct msg_net_lookup_dc data;
272         
273         c = talloc_get_type(ctx->async.private_data, struct composite_context);
274         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
275         
276         /* receive result of domain controller lookup */
277         c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
278         if (!composite_is_ok(c)) return;
279
280         /* decide on preferred address type depending on DC type */
281         s->connect_name = s->f.out.dcs[0].name;
282
283         /* prepare a monitor message and post it */
284         msg.type         = net_lookup_dc;
285         msg.data         = &data;
286         msg.data_size    = sizeof(data);
287
288         data.domain_name = s->f.in.domain_name;
289         data.hostname    = s->f.out.dcs[0].name;
290         data.address     = s->f.out.dcs[0].address;
291         
292         if (s->monitor_fn) s->monitor_fn(&msg);
293
294         /* ok, pdc has been found so do attempt to rpc connect */
295         s->r2.level            = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
296
297         /* this will cause yet another name resolution, but at least
298          * we pass the right name down the stack now */
299         s->r2.in.name          = talloc_strdup(s, s->connect_name);
300         s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);
301         s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;  
302
303         /* send rpc connect request to the server */
304         rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2);
305         if (composite_nomem(rpc_connect_req, c)) return;
306
307         composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
308 }
309
310
311 /*
312   Step 3 of RpcConnectDC: get rpc connection to the server
313 */
314 static void continue_rpc_connect(struct composite_context *ctx)
315 {
316         struct composite_context *c;
317         struct rpc_connect_dc_state *s;
318         struct monitor_msg msg;
319         struct msg_net_pipe_connected data;
320
321         c = talloc_get_type(ctx->async.private_data, struct composite_context);
322         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
323
324         c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
325
326         /* error string is to be passed anyway */
327         s->r.out.error_string  = s->r2.out.error_string;
328         if (!composite_is_ok(c)) return;
329
330         s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
331
332         /* prepare a monitor message and post it */
333         msg.type       = net_pipe_connected;
334         msg.data       = NULL;
335         msg.data_size  = 0;
336
337         data.host      = s->r.out.dcerpc_pipe->binding->host;
338         data.endpoint  = s->r.out.dcerpc_pipe->binding->endpoint;
339         data.transport = s->r.out.dcerpc_pipe->binding->transport;
340
341         if (s->monitor_fn) s->monitor_fn(&msg);
342
343         composite_done(c);
344 }
345
346
347 /**
348  * Receives result of connection to rpc pipe on domain pdc
349  *
350  * @param c composite context
351  * @param ctx initialised libnet context
352  * @param mem_ctx memory context of this call
353  * @param r data structure containing necessary parameters and return values
354  * @return nt status of rpc connection
355  **/
356
357 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
358                                          struct libnet_context *ctx,
359                                          TALLOC_CTX *mem_ctx,
360                                          struct libnet_RpcConnect *r)
361 {
362         NTSTATUS status;
363         struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
364                                          struct rpc_connect_dc_state);
365
366         status = composite_wait(c);
367         if (NT_STATUS_IS_OK(status)) {
368                 /* move connected rpc pipe between memory contexts */
369                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
370
371                 /* reference created pipe structure to long-term libnet_context
372                    so that it can be used by other api functions even after short-term
373                    mem_ctx is freed */
374                 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
375                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
376
377                 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
378                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
379                 }
380
381         } else {
382                 r->out.error_string = talloc_asprintf(mem_ctx,
383                                                       "Failed to rpc connect: %s",
384                                                       nt_errstr(status));
385         }
386
387         talloc_free(c);
388         return status;
389 }
390
391
392
393 struct rpc_connect_dci_state {
394         struct libnet_context *ctx;
395         struct libnet_RpcConnect r;
396         struct libnet_RpcConnect rpc_conn;
397         struct policy_handle lsa_handle;
398         struct lsa_QosInfo qos;
399         struct lsa_ObjectAttribute attr;
400         struct lsa_OpenPolicy2 lsa_open_policy;
401         struct dcerpc_pipe *lsa_pipe;
402         struct lsa_QueryInfoPolicy2 lsa_query_info2;
403         struct lsa_QueryInfoPolicy lsa_query_info;
404         struct dcerpc_binding *final_binding;
405         struct dcerpc_pipe *final_pipe;
406 };
407
408
409 static void continue_dci_rpc_connect(struct composite_context *ctx);
410 static void continue_lsa_policy(struct rpc_request *req);
411 static void continue_lsa_query_info(struct rpc_request *req);
412 static void continue_lsa_query_info2(struct rpc_request *req);
413 static void continue_epm_map_binding(struct composite_context *ctx);
414 static void continue_secondary_conn(struct composite_context *ctx);
415 static void continue_epm_map_binding_send(struct composite_context *c);
416
417
418 /**
419  * Initiates connection to rpc pipe on remote server or pdc. Received result
420  * contains info on the domain name, domain sid and realm.
421  * 
422  * @param ctx initialised libnet context
423  * @param mem_ctx memory context of this call
424  * @param r data structure containing necessary parameters and return values. Must be a talloc context
425  * @return composite context of this call
426  **/
427
428 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
429                                                               TALLOC_CTX *mem_ctx,
430                                                               struct libnet_RpcConnect *r)
431 {
432         struct composite_context *c, *conn_req;
433         struct rpc_connect_dci_state *s;
434
435         /* composite context allocation and setup */
436         c = talloc_zero(mem_ctx, struct composite_context);
437         if (c == NULL) return NULL;
438
439         s = talloc_zero(c, struct rpc_connect_dci_state);
440         if (composite_nomem(s, c)) return c;
441
442         c->state = COMPOSITE_STATE_IN_PROGRESS;
443         c->private_data = s;
444         c->event_ctx = ctx->event_ctx;
445
446         s->ctx = ctx;
447         s->r   = *r;
448         ZERO_STRUCT(s->r.out);
449
450         /* proceed to pure rpc connection if the binding string is provided,
451            otherwise try to connect domain controller */
452         if (r->in.binding == NULL) {
453                 s->rpc_conn.in.name    = r->in.name;
454                 s->rpc_conn.level      = LIBNET_RPC_CONNECT_DC;
455         } else {
456                 s->rpc_conn.in.binding = r->in.binding;
457                 s->rpc_conn.level      = LIBNET_RPC_CONNECT_BINDING;
458         }
459
460         /* we need to query information on lsarpc interface first */
461         s->rpc_conn.in.dcerpc_iface    = &dcerpc_table_lsarpc;
462         
463         /* request connection to the lsa pipe on the pdc */
464         conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn);
465         if (composite_nomem(c, conn_req)) return c;
466
467         composite_continue(c, conn_req, continue_dci_rpc_connect, c);
468         return c;
469 }
470
471
472 /*
473   Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
474   lsa policy handle
475 */
476 static void continue_dci_rpc_connect(struct composite_context *ctx)
477 {
478         struct composite_context *c;
479         struct rpc_connect_dci_state *s;
480         struct rpc_request *open_pol_req;
481
482         c = talloc_get_type(ctx->async.private_data, struct composite_context);
483         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
484
485         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
486         if (!NT_STATUS_IS_OK(c->status)) {
487                 composite_error(c, c->status);
488                 return;
489         }
490
491         /* prepare to open a policy handle on lsa pipe */
492         s->lsa_pipe = s->ctx->lsa.pipe;
493         
494         s->qos.len                 = 0;
495         s->qos.impersonation_level = 2;
496         s->qos.context_mode        = 1;
497         s->qos.effective_only      = 0;
498
499         s->attr.sec_qos = &s->qos;
500
501         s->lsa_open_policy.in.attr        = &s->attr;
502         s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
503         if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
504
505         s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
506         s->lsa_open_policy.out.handle     = &s->lsa_handle;
507
508         open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
509         if (composite_nomem(open_pol_req, c)) return;
510
511         composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
512 }
513
514
515 /*
516   Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
517   for kerberos realm (dns name) and guid. The query may fail.
518 */
519 static void continue_lsa_policy(struct rpc_request *req)
520 {
521         struct composite_context *c;
522         struct rpc_connect_dci_state *s;
523         struct rpc_request *query_info_req;
524
525         c = talloc_get_type(req->async.private, struct composite_context);
526         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
527
528         c->status = dcerpc_ndr_request_recv(req);
529         if (!NT_STATUS_IS_OK(c->status)) {
530                 composite_error(c, c->status);
531                 return;
532         }
533
534         if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
535                 s->r.out.realm = NULL;
536                 s->r.out.guid  = NULL;
537                 s->r.out.domain_name = NULL;
538                 s->r.out.domain_sid  = NULL;
539                 /* Skip to the creating the actual connection, no info available on this transport */
540                 continue_epm_map_binding_send(c);
541                 return;
542         } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
543                 composite_error(c, s->lsa_open_policy.out.result);
544                 return;
545         }
546
547         /* query lsa info for dns domain name and guid */
548         s->lsa_query_info2.in.handle = &s->lsa_handle;
549         s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
550
551         query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
552         if (composite_nomem(query_info_req, c)) return;
553
554         composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
555 }
556
557
558 /*
559   Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
560   may result in failure) and query lsa info for domain name and sid.
561 */
562 static void continue_lsa_query_info2(struct rpc_request *req)
563 {       
564         struct composite_context *c;
565         struct rpc_connect_dci_state *s;
566         struct rpc_request *query_info_req;
567
568         c = talloc_get_type(req->async.private, struct composite_context);
569         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
570
571         c->status = dcerpc_ndr_request_recv(req);
572         
573         /* In case of error just null the realm and guid and proceed
574            to the next step. After all, it doesn't have to be AD domain
575            controller we talking to - NT-style PDC also counts */
576
577         if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
578                 s->r.out.realm = NULL;
579                 s->r.out.guid  = NULL;
580
581         } else {
582                 if (!NT_STATUS_IS_OK(c->status)) {
583                         s->r.out.error_string = talloc_asprintf(c,
584                                                                 "lsa_QueryInfoPolicy2 failed: %s",
585                                                                 nt_errstr(c->status));
586                         composite_error(c, c->status);
587                         return;
588                 }
589
590                 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
591                         s->r.out.error_string = talloc_asprintf(c,
592                                                                 "lsa_QueryInfoPolicy2 failed: %s",
593                                                                 nt_errstr(s->lsa_query_info2.out.result));
594                         composite_error(c, s->lsa_query_info2.out.result);
595                         return;
596                 }
597
598                 /* Copy the dns domain name and guid from the query result */
599
600                 /* this should actually be a conversion from lsa_StringLarge */
601                 s->r.out.realm = s->lsa_query_info2.out.info->dns.dns_domain.string;
602                 s->r.out.guid  = talloc(c, struct GUID);
603                 if (composite_nomem(s->r.out.guid, c)) {
604                         s->r.out.error_string = NULL;
605                         return;
606                 }
607                 *s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
608         }
609
610         /* query lsa info for domain name and sid */
611         s->lsa_query_info.in.handle = &s->lsa_handle;
612         s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
613
614         query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
615         if (composite_nomem(query_info_req, c)) return;
616
617         composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
618 }
619
620
621 /*
622   Step 5 of RpcConnectDCInfo: Get domain name and sid
623 */
624 static void continue_lsa_query_info(struct rpc_request *req)
625 {
626         struct composite_context *c;
627         struct rpc_connect_dci_state *s;
628
629         c = talloc_get_type(req->async.private, struct composite_context);
630         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
631
632         c->status = dcerpc_ndr_request_recv(req);
633         if (!NT_STATUS_IS_OK(c->status)) {
634                 s->r.out.error_string = talloc_asprintf(c,
635                                                         "lsa_QueryInfoPolicy failed: %s",
636                                                         nt_errstr(c->status));
637                 composite_error(c, c->status);
638                 return;
639         }
640
641         /* Copy the domain name and sid from the query result */
642         s->r.out.domain_sid  = s->lsa_query_info.out.info->domain.sid;
643         s->r.out.domain_name = s->lsa_query_info.out.info->domain.name.string;
644
645         continue_epm_map_binding_send(c);
646 }
647
648 /* 
649    Step 5 (continued) of RpcConnectDCInfo: request endpoint
650    map binding.
651
652    We may short-cut to this step if we dont' support LSA OpenPolicy on this transport
653 */
654 static void continue_epm_map_binding_send(struct composite_context *c)
655 {
656         struct rpc_connect_dci_state *s;
657         struct composite_context *epm_map_req;
658         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
659
660         /* prepare to get endpoint mapping for the requested interface */
661         s->final_binding = talloc(s, struct dcerpc_binding);
662         if (composite_nomem(s->final_binding, c)) return;
663         
664         *s->final_binding = *s->lsa_pipe->binding;
665         /* Ensure we keep hold of the member elements */
666         if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
667
668         epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
669                                                   s->lsa_pipe->conn->event_ctx);
670         if (composite_nomem(epm_map_req, c)) return;
671
672         composite_continue(c, epm_map_req, continue_epm_map_binding, c);
673 }
674
675 /*
676   Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
677   rpc connection derived from already used pipe but connected to the requested
678   one (as specified in libnet_RpcConnect structure)
679 */
680 static void continue_epm_map_binding(struct composite_context *ctx)
681 {
682         struct composite_context *c, *sec_conn_req;
683         struct rpc_connect_dci_state *s;
684
685         c = talloc_get_type(ctx->async.private_data, struct composite_context);
686         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
687
688         c->status = dcerpc_epm_map_binding_recv(ctx);
689         if (!NT_STATUS_IS_OK(c->status)) {
690                 s->r.out.error_string = talloc_asprintf(c,
691                                                         "failed to map pipe with endpoint mapper - %s",
692                                                         nt_errstr(c->status));
693                 composite_error(c, c->status);
694                 return;
695         }
696
697         /* create secondary connection derived from lsa pipe */
698         sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
699         if (composite_nomem(sec_conn_req, c)) return;
700
701         composite_continue(c, sec_conn_req, continue_secondary_conn, c);
702 }
703
704
705 /*
706   Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
707   and complete this composite call
708 */
709 static void continue_secondary_conn(struct composite_context *ctx)
710 {
711         struct composite_context *c;
712         struct rpc_connect_dci_state *s;
713
714         c = talloc_get_type(ctx->async.private_data, struct composite_context);
715         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
716
717         c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
718         if (!NT_STATUS_IS_OK(c->status)) {
719                 s->r.out.error_string = talloc_asprintf(c,
720                                                         "secondary connection failed: %s",
721                                                         nt_errstr(c->status));
722                 
723                 composite_error(c, c->status);
724                 return;
725         }
726
727         s->r.out.dcerpc_pipe = s->final_pipe;
728         composite_done(c);
729 }
730
731
732 /**
733  * Receives result of connection to rpc pipe and gets basic
734  * domain info (name, sid, realm, guid)
735  *
736  * @param c composite context
737  * @param ctx initialised libnet context
738  * @param mem_ctx memory context of this call
739  * @param r data structure containing return values
740  * @return nt status of rpc connection
741  **/
742
743 static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
744                                              TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
745 {
746         NTSTATUS status;
747         struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
748                                           struct rpc_connect_dci_state);
749
750         status = composite_wait(c);
751         if (NT_STATUS_IS_OK(status)) {
752                 r->out.realm        = talloc_steal(mem_ctx, s->r.out.realm);
753                 r->out.guid         = talloc_steal(mem_ctx, s->r.out.guid);
754                 r->out.domain_name  = talloc_steal(mem_ctx, s->r.out.domain_name);
755                 r->out.domain_sid   = talloc_steal(mem_ctx, s->r.out.domain_sid);
756
757                 r->out.dcerpc_pipe  = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
758
759                 /* reference created pipe structure to long-term libnet_context
760                    so that it can be used by other api functions even after short-term
761                    mem_ctx is freed */
762                 if (r->in.dcerpc_iface == &dcerpc_table_samr) {
763                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
764
765                 } else if (r->in.dcerpc_iface == &dcerpc_table_lsarpc) {
766                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
767                 }
768
769         } else {
770                 if (s->r.out.error_string) {
771                         r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
772                 } else {
773                         r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
774                 }
775         }
776
777         talloc_free(c);
778         return status;
779 }
780
781
782 /**
783  * Initiates connection to rpc pipe on remote server or pdc, optionally
784  * providing domain info
785  * 
786  * @param ctx initialised libnet context
787  * @param mem_ctx memory context of this call
788  * @param r data structure containing necessary parameters and return values
789  * @return composite context of this call
790  **/
791
792 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
793                                                  TALLOC_CTX *mem_ctx,
794                                                  struct libnet_RpcConnect *r)
795 {
796         struct composite_context *c;
797
798         switch (r->level) {
799         case LIBNET_RPC_CONNECT_SERVER:
800         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
801         case LIBNET_RPC_CONNECT_BINDING:
802                 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
803                 break;
804
805         case LIBNET_RPC_CONNECT_PDC:
806         case LIBNET_RPC_CONNECT_DC:
807                 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r);
808                 break;
809
810         case LIBNET_RPC_CONNECT_DC_INFO:
811                 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r);
812                 break;
813
814         default:
815                 c = talloc_zero(mem_ctx, struct composite_context);
816                 composite_error(c, NT_STATUS_INVALID_LEVEL);
817         }
818
819         return c;
820 }
821
822
823 /**
824  * Receives result of connection to rpc pipe on remote server or pdc
825  *
826  * @param c composite context
827  * @param ctx initialised libnet context
828  * @param mem_ctx memory context of this call
829  * @param r data structure containing necessary parameters and return values
830  * @return nt status of rpc connection
831  **/
832
833 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
834                                 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
835 {
836         switch (r->level) {
837         case LIBNET_RPC_CONNECT_SERVER:
838         case LIBNET_RPC_CONNECT_BINDING:
839                 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
840
841         case LIBNET_RPC_CONNECT_PDC:
842         case LIBNET_RPC_CONNECT_DC:
843                 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
844
845         case LIBNET_RPC_CONNECT_DC_INFO:
846                 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
847
848         default:
849                 ZERO_STRUCT(r->out);
850                 return NT_STATUS_INVALID_LEVEL;
851         }
852 }
853
854
855 /**
856  * Connect to a rpc pipe on a remote server - sync version
857  *
858  * @param ctx initialised libnet context
859  * @param mem_ctx memory context of this call
860  * @param r data structure containing necessary parameters and return values
861  * @return nt status of rpc connection
862  **/
863
864 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
865                            struct libnet_RpcConnect *r)
866 {
867         struct composite_context *c;
868         
869         c = libnet_RpcConnect_send(ctx, mem_ctx, r);
870         return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
871 }