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