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