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