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