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