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