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