Update 4.2 Roadmap file
[mat/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 #include "auth/credentials/credentials.h"
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[target_hostname=%s]",
83                                              r->in.address, r->in.name);
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                 c->status = dcerpc_binding_set_flags(b, r->in.dcerpc_flags, 0);
113                 if (!composite_is_ok(c)) return c;
114                 break;
115         default:
116                 /* other types have already been checked before */
117                 break;
118         }
119
120         if (DEBUGLEVEL >= 10) {
121                 c->status = dcerpc_binding_set_flags(b, DCERPC_DEBUG_PRINT_BOTH, 0);
122                 if (!composite_is_ok(c)) return c;
123         }
124
125         /* connect to remote dcerpc pipe */
126         pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,
127                                                       ctx->cred, c->event_ctx,
128                                                       ctx->lp_ctx);
129         if (composite_nomem(pipe_connect_req, c)) return c;
130
131         composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
132         return c;
133 }
134
135
136 /*
137   Step 2 of RpcConnectSrv - get rpc connection
138 */
139 static void continue_pipe_connect(struct composite_context *ctx)
140 {
141         struct composite_context *c;
142         struct rpc_connect_srv_state *s;
143
144         c = talloc_get_type(ctx->async.private_data, struct composite_context);
145         s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
146
147         /* receive result of rpc pipe connection */
148         c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);
149         
150         /* post monitor message */
151         if (s->monitor_fn) {
152                 struct monitor_msg msg;
153                 struct msg_net_rpc_connect data;
154                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
155
156                 /* prepare monitor message and post it */
157                 data.host        = dcerpc_binding_get_string_option(b, "host");
158                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
159                 data.transport   = dcerpc_binding_get_transport(b);
160                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
161
162                 msg.type      = mon_NetRpcConnect;
163                 msg.data      = (void*)&data;
164                 msg.data_size = sizeof(data);
165                 s->monitor_fn(&msg);
166         }
167
168         composite_done(c);      
169 }
170
171
172 /**
173  * Receives result of connection to rpc pipe on remote server
174  *
175  * @param c composite context
176  * @param ctx initialised libnet context
177  * @param mem_ctx memory context of this call
178  * @param r data structure containing necessary parameters and return values
179  * @return nt status of rpc connection
180  **/
181
182 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
183                                           struct libnet_context *ctx,
184                                           TALLOC_CTX *mem_ctx,
185                                           struct libnet_RpcConnect *r)
186 {
187         NTSTATUS status;
188
189         status = composite_wait(c);
190         if (NT_STATUS_IS_OK(status)) {
191                 struct rpc_connect_srv_state *s;
192
193                 /* move the returned rpc pipe between memory contexts */
194                 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
195                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
196
197                 /* reference created pipe structure to long-term libnet_context
198                    so that it can be used by other api functions even after short-term
199                    mem_ctx is freed */
200                 if (r->in.dcerpc_iface == &ndr_table_samr) {
201                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
202                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
203
204                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
205                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
206                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
207                 }
208
209                 r->out.error_string = talloc_strdup(mem_ctx, "Success");
210
211         } else {
212                 r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
213         }
214
215         talloc_free(c);
216         return status;
217 }
218
219
220 struct rpc_connect_dc_state {
221         struct libnet_context *ctx;
222         struct libnet_RpcConnect r;
223         struct libnet_RpcConnect r2;
224         struct libnet_LookupDCs f;
225         const char *connect_name;
226
227         /* information about the progress */
228         void (*monitor_fn)(struct monitor_msg *);
229 };
230
231
232 static void continue_lookup_dc(struct tevent_req *req);
233 static void continue_rpc_connect(struct composite_context *ctx);
234
235
236 /**
237  * Initiates connection to rpc pipe on domain pdc
238  * 
239  * @param ctx initialised libnet context
240  * @param mem_ctx memory context of this call
241  * @param r data structure containing necessary parameters and return values
242  * @return composite context of this call
243  **/
244
245 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
246                                                           TALLOC_CTX *mem_ctx,
247                                                           struct libnet_RpcConnect *r,
248                                                           void (*monitor)(struct monitor_msg *msg))
249 {
250         struct composite_context *c;
251         struct rpc_connect_dc_state *s;
252         struct tevent_req *lookup_dc_req;
253
254         /* composite context allocation and setup */
255         c = composite_create(ctx, ctx->event_ctx);
256         if (c == NULL) return c;
257
258         s = talloc_zero(c, struct rpc_connect_dc_state);
259         if (composite_nomem(s, c)) return c;
260
261         c->private_data = s;
262         s->monitor_fn   = monitor;
263
264         s->ctx = ctx;
265         s->r   = *r;
266         ZERO_STRUCT(s->r.out);
267
268         switch (r->level) {
269         case LIBNET_RPC_CONNECT_PDC:
270                 s->f.in.name_type = NBT_NAME_PDC;
271                 break;
272
273         case LIBNET_RPC_CONNECT_DC:
274                 s->f.in.name_type = NBT_NAME_LOGON;
275                 break;
276
277         default:
278                 break;
279         }
280
281         s->f.in.domain_name = r->in.name;
282         s->f.out.num_dcs    = 0;
283         s->f.out.dcs        = NULL;
284
285         /* find the domain pdc first */
286         lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
287         if (composite_nomem(lookup_dc_req, c)) return c;
288
289         tevent_req_set_callback(lookup_dc_req, continue_lookup_dc, c);
290         return c;
291 }
292
293
294 /*
295   Step 2 of RpcConnectDC: get domain controller name and
296   initiate RpcConnect to it
297 */
298 static void continue_lookup_dc(struct tevent_req *req)
299 {
300         struct composite_context *c;
301         struct rpc_connect_dc_state *s;
302         struct composite_context *rpc_connect_req;
303         struct monitor_msg msg;
304         struct msg_net_lookup_dc data;
305
306         c = tevent_req_callback_data(req, struct composite_context);
307         s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state);
308         
309         /* receive result of domain controller lookup */
310         c->status = libnet_LookupDCs_recv(req, c, &s->f);
311         if (!composite_is_ok(c)) return;
312
313         /* decide on preferred address type depending on DC type */
314         s->connect_name = s->f.out.dcs[0].name;
315
316         /* post monitor message */
317         if (s->monitor_fn) {
318                 /* prepare a monitor message and post it */
319                 data.domain_name = s->f.in.domain_name;
320                 data.hostname    = s->f.out.dcs[0].name;
321                 data.address     = s->f.out.dcs[0].address;
322                 
323                 msg.type         = mon_NetLookupDc;
324                 msg.data         = &data;
325                 msg.data_size    = sizeof(data);
326                 s->monitor_fn(&msg);
327         }
328
329         /* ok, pdc has been found so do attempt to rpc connect */
330         s->r2.level            = LIBNET_RPC_CONNECT_SERVER_ADDRESS;
331
332         /* this will cause yet another name resolution, but at least
333          * we pass the right name down the stack now */
334         s->r2.in.name          = talloc_strdup(s, s->connect_name);
335         s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);
336         s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;  
337         s->r2.in.dcerpc_flags  = s->r.in.dcerpc_flags;
338
339         /* send rpc connect request to the server */
340         rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);
341         if (composite_nomem(rpc_connect_req, c)) return;
342
343         composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
344 }
345
346
347 /*
348   Step 3 of RpcConnectDC: get rpc connection to the server
349 */
350 static void continue_rpc_connect(struct composite_context *ctx)
351 {
352         struct composite_context *c;
353         struct rpc_connect_dc_state *s;
354
355         c = talloc_get_type(ctx->async.private_data, struct composite_context);
356         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
357
358         c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);
359
360         /* error string is to be passed anyway */
361         s->r.out.error_string  = s->r2.out.error_string;
362         if (!composite_is_ok(c)) return;
363
364         s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
365         
366         /* post monitor message */
367         if (s->monitor_fn) {
368                 struct monitor_msg msg;
369                 struct msg_net_rpc_connect data;
370                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
371
372                 data.host        = dcerpc_binding_get_string_option(b, "host");
373                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
374                 data.transport   = dcerpc_binding_get_transport(b);
375                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
376
377                 msg.type      = mon_NetRpcConnect;
378                 msg.data      = (void*)&data;
379                 msg.data_size = sizeof(data);
380                 s->monitor_fn(&msg);
381         }
382
383         composite_done(c);
384 }
385
386
387 /**
388  * Receives result of connection to rpc pipe on domain pdc
389  *
390  * @param c composite context
391  * @param ctx initialised libnet context
392  * @param mem_ctx memory context of this call
393  * @param r data structure containing necessary parameters and return values
394  * @return nt status of rpc connection
395  **/
396
397 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
398                                          struct libnet_context *ctx,
399                                          TALLOC_CTX *mem_ctx,
400                                          struct libnet_RpcConnect *r)
401 {
402         NTSTATUS status;
403         struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,
404                                          struct rpc_connect_dc_state);
405
406         status = composite_wait(c);
407         if (NT_STATUS_IS_OK(status)) {
408                 /* move connected rpc pipe between memory contexts 
409                    
410                    The use of talloc_reparent(talloc_parent(), ...) is
411                    bizarre, but it is needed because of the absolutely
412                    atrocious use of talloc in this code. We need to
413                    force the original parent to change, but finding
414                    the original parent is well nigh impossible at this
415                    point in the code (yes, I tried).
416                  */
417                 r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe), 
418                                                      mem_ctx, s->r.out.dcerpc_pipe);
419
420                 /* reference created pipe structure to long-term libnet_context
421                    so that it can be used by other api functions even after short-term
422                    mem_ctx is freed */
423                 if (r->in.dcerpc_iface == &ndr_table_samr) {
424                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
425                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
426                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
427                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
428                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
429                 }
430
431         } else {
432                 r->out.error_string = talloc_asprintf(mem_ctx,
433                                                       "Failed to rpc connect: %s",
434                                                       nt_errstr(status));
435         }
436
437         talloc_free(c);
438         return status;
439 }
440
441
442
443 struct rpc_connect_dci_state {
444         struct libnet_context *ctx;
445         struct libnet_RpcConnect r;
446         struct libnet_RpcConnect rpc_conn;
447         struct policy_handle lsa_handle;
448         struct lsa_QosInfo qos;
449         struct lsa_ObjectAttribute attr;
450         struct lsa_OpenPolicy2 lsa_open_policy;
451         struct dcerpc_pipe *lsa_pipe;
452         struct lsa_QueryInfoPolicy2 lsa_query_info2;
453         struct lsa_QueryInfoPolicy lsa_query_info;
454         struct dcerpc_binding *final_binding;
455         struct dcerpc_pipe *final_pipe;
456
457         /* information about the progress */
458         void (*monitor_fn)(struct monitor_msg*);
459 };
460
461
462 static void continue_dci_rpc_connect(struct composite_context *ctx);
463 static void continue_lsa_policy(struct tevent_req *subreq);
464 static void continue_lsa_query_info(struct tevent_req *subreq);
465 static void continue_lsa_query_info2(struct tevent_req *subreq);
466 static void continue_epm_map_binding(struct composite_context *ctx);
467 static void continue_secondary_conn(struct composite_context *ctx);
468 static void continue_epm_map_binding_send(struct composite_context *c);
469
470
471 /**
472  * Initiates connection to rpc pipe on remote server or pdc. Received result
473  * contains info on the domain name, domain sid and realm.
474  * 
475  * @param ctx initialised libnet context
476  * @param mem_ctx memory context of this call
477  * @param r data structure containing necessary parameters and return values. Must be a talloc context
478  * @return composite context of this call
479  **/
480
481 static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,
482                                                               TALLOC_CTX *mem_ctx,
483                                                               struct libnet_RpcConnect *r,
484                                                               void (*monitor)(struct monitor_msg*))
485 {
486         struct composite_context *c, *conn_req;
487         struct rpc_connect_dci_state *s;
488
489         /* composite context allocation and setup */
490         c = composite_create(ctx, ctx->event_ctx);
491         if (c == NULL) return c;
492
493         s = talloc_zero(c, struct rpc_connect_dci_state);
494         if (composite_nomem(s, c)) return c;
495
496         c->private_data = s;
497         s->monitor_fn   = monitor;
498
499         s->ctx = ctx;
500         s->r   = *r;
501         ZERO_STRUCT(s->r.out);
502
503
504         /* proceed to pure rpc connection if the binding string is provided,
505            otherwise try to connect domain controller */
506         if (r->in.binding == NULL) {
507                 /* Pass on any binding flags (such as anonymous fallback) that have been set */
508                 s->rpc_conn.in.dcerpc_flags = r->in.dcerpc_flags;
509
510                 s->rpc_conn.in.name         = r->in.name;
511                 s->rpc_conn.level           = LIBNET_RPC_CONNECT_DC;
512         } else {
513                 s->rpc_conn.in.binding      = r->in.binding;
514                 s->rpc_conn.level           = LIBNET_RPC_CONNECT_BINDING;
515         }
516
517         /* we need to query information on lsarpc interface first */
518         s->rpc_conn.in.dcerpc_iface    = &ndr_table_lsarpc;
519         
520         /* request connection to the lsa pipe on the pdc */
521         conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
522         if (composite_nomem(c, conn_req)) return c;
523
524         composite_continue(c, conn_req, continue_dci_rpc_connect, c);
525         return c;
526 }
527
528
529 /*
530   Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
531   lsa policy handle
532 */
533 static void continue_dci_rpc_connect(struct composite_context *ctx)
534 {
535         struct composite_context *c;
536         struct rpc_connect_dci_state *s;
537         struct tevent_req *subreq;
538         enum dcerpc_transport_t transport;
539
540         c = talloc_get_type(ctx->async.private_data, struct composite_context);
541         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
542
543         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
544         if (!NT_STATUS_IS_OK(c->status)) {
545                 composite_error(c, c->status);
546                 return;
547         }
548
549         /* post monitor message */
550         if (s->monitor_fn) {
551                 struct monitor_msg msg;
552                 struct msg_net_rpc_connect data;
553                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
554
555                 data.host        = dcerpc_binding_get_string_option(b, "host");
556                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
557                 data.transport   = dcerpc_binding_get_transport(b);
558                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
559
560                 msg.type      = mon_NetRpcConnect;
561                 msg.data      = (void*)&data;
562                 msg.data_size = sizeof(data);
563                 s->monitor_fn(&msg);
564         }
565
566         /* prepare to open a policy handle on lsa pipe */
567         s->lsa_pipe = s->ctx->lsa.pipe;
568         
569         s->qos.len                 = 0;
570         s->qos.impersonation_level = 2;
571         s->qos.context_mode        = 1;
572         s->qos.effective_only      = 0;
573
574         s->attr.sec_qos = &s->qos;
575
576         transport = dcerpc_binding_get_transport(s->lsa_pipe->binding);
577         if (transport == NCACN_IP_TCP) {
578                 /*
579                  * Skip to creating the actual connection. We can't open a
580                  * policy handle over tcpip.
581                  */
582                 continue_epm_map_binding_send(c);
583                 return;
584         }
585
586         s->lsa_open_policy.in.attr        = &s->attr;
587         s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
588         if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
589
590         s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
591         s->lsa_open_policy.out.handle     = &s->lsa_handle;
592
593         subreq = dcerpc_lsa_OpenPolicy2_r_send(s, c->event_ctx,
594                                                s->lsa_pipe->binding_handle,
595                                                &s->lsa_open_policy);
596         if (composite_nomem(subreq, c)) return;
597
598         tevent_req_set_callback(subreq, continue_lsa_policy, c);
599 }
600
601
602 /*
603   Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
604   for kerberos realm (dns name) and guid. The query may fail.
605 */
606 static void continue_lsa_policy(struct tevent_req *subreq)
607 {
608         struct composite_context *c;
609         struct rpc_connect_dci_state *s;
610
611         c = tevent_req_callback_data(subreq, struct composite_context);
612         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
613
614         c->status = dcerpc_lsa_OpenPolicy2_r_recv(subreq, s);
615         TALLOC_FREE(subreq);
616         if (!NT_STATUS_IS_OK(c->status)) {
617                 composite_error(c, c->status);
618                 return;
619         }
620
621         if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
622                 s->r.out.realm = NULL;
623                 s->r.out.guid  = NULL;
624                 s->r.out.domain_name = NULL;
625                 s->r.out.domain_sid  = NULL;
626
627                 /* Skip to the creating the actual connection, no info available on this transport */
628                 continue_epm_map_binding_send(c);
629                 return;
630
631         } else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
632                 composite_error(c, s->lsa_open_policy.out.result);
633                 return;
634         }
635
636         /* post monitor message */
637         if (s->monitor_fn) {
638                 struct monitor_msg msg;
639
640                 msg.type      = mon_LsaOpenPolicy;
641                 msg.data      = NULL;
642                 msg.data_size = 0;
643                 s->monitor_fn(&msg);
644         }
645
646         /* query lsa info for dns domain name and guid */
647         s->lsa_query_info2.in.handle = &s->lsa_handle;
648         s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
649         s->lsa_query_info2.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
650         if (composite_nomem(s->lsa_query_info2.out.info, c)) return;
651
652         subreq = dcerpc_lsa_QueryInfoPolicy2_r_send(s, c->event_ctx,
653                                                     s->lsa_pipe->binding_handle,
654                                                     &s->lsa_query_info2);
655         if (composite_nomem(subreq, c)) return;
656
657         tevent_req_set_callback(subreq, continue_lsa_query_info2, c);
658 }
659
660
661 /*
662   Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
663   may result in failure) and query lsa info for domain name and sid.
664 */
665 static void continue_lsa_query_info2(struct tevent_req *subreq)
666 {       
667         struct composite_context *c;
668         struct rpc_connect_dci_state *s;
669
670         c = tevent_req_callback_data(subreq, struct composite_context);
671         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
672
673         c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s);
674         TALLOC_FREE(subreq);
675         
676         /* In case of error just null the realm and guid and proceed
677            to the next step. After all, it doesn't have to be AD domain
678            controller we talking to - NT-style PDC also counts */
679
680         if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
681                 s->r.out.realm = NULL;
682                 s->r.out.guid  = NULL;
683
684         } else {
685                 if (!NT_STATUS_IS_OK(c->status)) {
686                         s->r.out.error_string = talloc_asprintf(c,
687                                                                 "lsa_QueryInfoPolicy2 failed: %s",
688                                                                 nt_errstr(c->status));
689                         composite_error(c, c->status);
690                         return;
691                 }
692
693                 if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
694                         s->r.out.error_string = talloc_asprintf(c,
695                                                                 "lsa_QueryInfoPolicy2 failed: %s",
696                                                                 nt_errstr(s->lsa_query_info2.out.result));
697                         composite_error(c, s->lsa_query_info2.out.result);
698                         return;
699                 }
700
701                 /* Copy the dns domain name and guid from the query result */
702
703                 /* this should actually be a conversion from lsa_StringLarge */
704                 s->r.out.realm = (*s->lsa_query_info2.out.info)->dns.dns_domain.string;
705                 s->r.out.guid  = talloc(c, struct GUID);
706                 if (composite_nomem(s->r.out.guid, c)) {
707                         s->r.out.error_string = NULL;
708                         return;
709                 }
710                 *s->r.out.guid = (*s->lsa_query_info2.out.info)->dns.domain_guid;
711         }
712
713         /* post monitor message */
714         if (s->monitor_fn) {
715                 struct monitor_msg msg;
716                 
717                 msg.type      = mon_LsaQueryPolicy;
718                 msg.data      = NULL;
719                 msg.data_size = 0;
720                 s->monitor_fn(&msg);
721         }
722
723         /* query lsa info for domain name and sid */
724         s->lsa_query_info.in.handle = &s->lsa_handle;
725         s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
726         s->lsa_query_info.out.info  = talloc_zero(c, union lsa_PolicyInformation *);
727         if (composite_nomem(s->lsa_query_info.out.info, c)) return;
728
729         subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
730                                                    s->lsa_pipe->binding_handle,
731                                                    &s->lsa_query_info);
732         if (composite_nomem(subreq, c)) return;
733
734         tevent_req_set_callback(subreq, continue_lsa_query_info, c);
735 }
736
737
738 /*
739   Step 5 of RpcConnectDCInfo: Get domain name and sid
740 */
741 static void continue_lsa_query_info(struct tevent_req *subreq)
742 {
743         struct composite_context *c;
744         struct rpc_connect_dci_state *s;
745
746         c = tevent_req_callback_data(subreq, struct composite_context);
747         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
748
749         c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
750         TALLOC_FREE(subreq);
751         if (!NT_STATUS_IS_OK(c->status)) {
752                 s->r.out.error_string = talloc_asprintf(c,
753                                                         "lsa_QueryInfoPolicy failed: %s",
754                                                         nt_errstr(c->status));
755                 composite_error(c, c->status);
756                 return;
757         }
758
759         /* post monitor message */
760         if (s->monitor_fn) {
761                 struct monitor_msg msg;
762                 
763                 msg.type      = mon_LsaQueryPolicy;
764                 msg.data      = NULL;
765                 msg.data_size = 0;
766                 s->monitor_fn(&msg);
767         }
768
769         /* Copy the domain name and sid from the query result */
770         s->r.out.domain_sid  = (*s->lsa_query_info.out.info)->domain.sid;
771         s->r.out.domain_name = (*s->lsa_query_info.out.info)->domain.name.string;
772
773         continue_epm_map_binding_send(c);
774 }
775
776 /* 
777    Step 5 (continued) of RpcConnectDCInfo: request endpoint
778    map binding.
779
780    We may short-cut to this step if we don't support LSA OpenPolicy on this transport
781 */
782 static void continue_epm_map_binding_send(struct composite_context *c)
783 {
784         struct rpc_connect_dci_state *s;
785         struct composite_context *epm_map_req;
786         struct cli_credentials *epm_creds = NULL;
787
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 = dcerpc_binding_dup(s, s->lsa_pipe->binding);
792         if (composite_nomem(s->final_binding, c)) return;
793
794         epm_creds = cli_credentials_init_anon(s);
795         if (composite_nomem(epm_creds, c)) return;
796
797         epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
798                                                   epm_creds,
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                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
864
865                 /* prepare monitor message and post it */
866                 data.host        = dcerpc_binding_get_string_option(b, "host");
867                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
868                 data.transport   = dcerpc_binding_get_transport(b);
869                 data.domain_name = dcerpc_binding_get_string_option(b, "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 }