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