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