HACK b/source4/libnet/libnet_rpc.c if (1 || NT_STATUS_EQUAL(s->lsa_open_policy.out...
[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 #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 (1 || 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_auth_connection_send(s->lsa_pipe,
829                                                              s->final_binding,
830                                                              s->r.in.dcerpc_iface,
831                                                              s->ctx->cred,
832                                                              s->ctx->lp_ctx);
833         if (composite_nomem(sec_conn_req, c)) return;
834
835         composite_continue(c, sec_conn_req, continue_secondary_conn, c);
836 }
837
838
839 /*
840   Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
841   and complete this composite call
842 */
843 static void continue_secondary_conn(struct composite_context *ctx)
844 {
845         struct composite_context *c;
846         struct rpc_connect_dci_state *s;
847
848         c = talloc_get_type(ctx->async.private_data, struct composite_context);
849         s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
850
851         c->status = dcerpc_secondary_auth_connection_recv(ctx, s->lsa_pipe,
852                                                           &s->final_pipe);
853         if (!NT_STATUS_IS_OK(c->status)) {
854                 s->r.out.error_string = talloc_asprintf(c,
855                                                         "secondary connection failed: %s",
856                                                         nt_errstr(c->status));
857                 
858                 composite_error(c, c->status);
859                 return;
860         }
861
862         s->r.out.dcerpc_pipe = s->final_pipe;
863
864         /* post monitor message */
865         if (s->monitor_fn) {
866                 struct monitor_msg msg;
867                 struct msg_net_rpc_connect data;
868                 const struct dcerpc_binding *b = s->r.out.dcerpc_pipe->binding;
869
870                 /* prepare monitor message and post it */
871                 data.host        = dcerpc_binding_get_string_option(b, "host");
872                 data.endpoint    = dcerpc_binding_get_string_option(b, "endpoint");
873                 data.transport   = dcerpc_binding_get_transport(b);
874                 data.domain_name = dcerpc_binding_get_string_option(b, "target_hostname");
875
876                 msg.type      = mon_NetRpcConnect;
877                 msg.data      = (void*)&data;
878                 msg.data_size = sizeof(data);
879                 s->monitor_fn(&msg);
880         }
881
882         composite_done(c);
883 }
884
885
886 /**
887  * Receives result of connection to rpc pipe and gets basic
888  * domain info (name, sid, realm, guid)
889  *
890  * @param c composite context
891  * @param ctx initialised libnet context
892  * @param mem_ctx memory context of this call
893  * @param r data structure containing return values
894  * @return nt status of rpc connection
895  **/
896
897 static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
898                                              TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
899 {
900         NTSTATUS status;
901         struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
902                                           struct rpc_connect_dci_state);
903
904         status = composite_wait(c);
905         if (NT_STATUS_IS_OK(status)) {
906                 r->out.realm        = talloc_steal(mem_ctx, s->r.out.realm);
907                 r->out.guid         = talloc_steal(mem_ctx, s->r.out.guid);
908                 r->out.domain_name  = talloc_steal(mem_ctx, s->r.out.domain_name);
909                 r->out.domain_sid   = talloc_steal(mem_ctx, s->r.out.domain_sid);
910
911                 r->out.dcerpc_pipe  = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
912
913                 /* reference created pipe structure to long-term libnet_context
914                    so that it can be used by other api functions even after short-term
915                    mem_ctx is freed */
916                 if (r->in.dcerpc_iface == &ndr_table_samr) {
917                         ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
918                         ctx->samr.samr_handle = ctx->samr.pipe->binding_handle;
919
920                 } else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {
921                         ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);
922                         ctx->lsa.lsa_handle = ctx->lsa.pipe->binding_handle;
923                 }
924
925         } else {
926                 if (s->r.out.error_string) {
927                         r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
928                 } else if (r->in.binding == NULL) {
929                         r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
930                 } else {
931                         r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s", 
932                                                               r->in.binding, nt_errstr(status));
933                 }
934         }
935
936         talloc_free(c);
937         return status;
938 }
939
940
941 /**
942  * Initiates connection to rpc pipe on remote server or pdc, optionally
943  * providing domain info
944  * 
945  * @param ctx initialised libnet context
946  * @param mem_ctx memory context of this call
947  * @param r data structure containing necessary parameters and return values
948  * @return composite context of this call
949  **/
950
951 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
952                                                  TALLOC_CTX *mem_ctx,
953                                                  struct libnet_RpcConnect *r,
954                                                  void (*monitor)(struct monitor_msg*))
955 {
956         struct composite_context *c;
957
958         switch (r->level) {
959         case LIBNET_RPC_CONNECT_SERVER:
960         case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
961         case LIBNET_RPC_CONNECT_BINDING:
962                 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
963                 break;
964
965         case LIBNET_RPC_CONNECT_PDC:
966         case LIBNET_RPC_CONNECT_DC:
967                 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
968                 break;
969
970         case LIBNET_RPC_CONNECT_DC_INFO:
971                 c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
972                 break;
973
974         default:
975                 c = talloc_zero(mem_ctx, struct composite_context);
976                 composite_error(c, NT_STATUS_INVALID_LEVEL);
977         }
978
979         return c;
980 }
981
982
983 /**
984  * Receives result of connection to rpc pipe on remote server or pdc
985  *
986  * @param c composite context
987  * @param ctx initialised libnet context
988  * @param mem_ctx memory context of this call
989  * @param r data structure containing necessary parameters and return values
990  * @return nt status of rpc connection
991  **/
992
993 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
994                                 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
995 {
996         switch (r->level) {
997         case LIBNET_RPC_CONNECT_SERVER:
998         case LIBNET_RPC_CONNECT_BINDING:
999                 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
1000
1001         case LIBNET_RPC_CONNECT_PDC:
1002         case LIBNET_RPC_CONNECT_DC:
1003                 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
1004
1005         case LIBNET_RPC_CONNECT_DC_INFO:
1006                 return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
1007
1008         default:
1009                 ZERO_STRUCT(r->out);
1010                 return NT_STATUS_INVALID_LEVEL;
1011         }
1012 }
1013
1014
1015 /**
1016  * Connect to a rpc pipe on a remote server - sync version
1017  *
1018  * @param ctx initialised libnet context
1019  * @param mem_ctx memory context of this call
1020  * @param r data structure containing necessary parameters and return values
1021  * @return nt status of rpc connection
1022  **/
1023
1024 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
1025                            struct libnet_RpcConnect *r)
1026 {
1027         struct composite_context *c;
1028         
1029         c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
1030         return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
1031 }