r14568: Remove unused function.
[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
28
29 struct rpc_connect_srv_state {
30         struct libnet_RpcConnect r;
31         const char *binding;
32 };
33
34
35 static void continue_pipe_connect(struct composite_context *ctx);
36
37
38 /**
39  * Initiates connection to rpc pipe on remote server
40  * 
41  * @param ctx initialised libnet context
42  * @param mem_ctx memory context of this call
43  * @param r data structure containing necessary parameters and return values
44  * @return nt status of the call
45  **/
46
47 static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,
48                                                            TALLOC_CTX *mem_ctx,
49                                                            struct libnet_RpcConnect *r)
50 {
51         struct composite_context *c;    
52         struct rpc_connect_srv_state *s;
53         struct composite_context *pipe_connect_req;
54
55         c = talloc_zero(mem_ctx, struct composite_context);
56         if (c == NULL) return NULL;
57
58         s = talloc_zero(c, struct rpc_connect_srv_state);
59         if (composite_nomem(s, c)) return c;
60
61         c->state = COMPOSITE_STATE_IN_PROGRESS;
62         c->private_data = s;
63         c->event_ctx = ctx->event_ctx;
64
65         s->r = *r;
66
67         /* prepare binding string */
68         switch (r->level) {
69         case LIBNET_RPC_CONNECT_DC:
70         case LIBNET_RPC_CONNECT_PDC:
71         case LIBNET_RPC_CONNECT_SERVER:
72                 s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);
73                 break;
74
75         case LIBNET_RPC_CONNECT_BINDING:
76                 s->binding = talloc_strdup(s, r->in.binding);
77                 break;
78         }
79
80         /* connect to remote dcerpc pipe */
81         pipe_connect_req = dcerpc_pipe_connect_send(c, &s->r.out.dcerpc_pipe,
82                                                     s->binding, r->in.dcerpc_iface,
83                                                     ctx->cred, c->event_ctx);
84         if (composite_nomem(pipe_connect_req, c)) return c;
85
86         composite_continue(c, pipe_connect_req, continue_pipe_connect, c);
87         return c;
88 }
89
90
91 static void continue_pipe_connect(struct composite_context *ctx)
92 {
93         struct composite_context *c;
94         struct rpc_connect_srv_state *s;
95
96         c = talloc_get_type(ctx->async.private_data, struct composite_context);
97         s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
98
99         c->status = dcerpc_pipe_connect_recv(ctx, c, &s->r.out.dcerpc_pipe);
100         if (!composite_is_ok(c)) return;
101
102         s->r.out.error_string = NULL;
103         composite_done(c);
104 }
105
106
107 /**
108  * Receives result of connection to rpc pipe on remote server
109  *
110  * @param c composite context
111  * @param ctx initialised libnet context
112  * @param mem_ctx memory context of this call
113  * @param r data structure containing necessary parameters and return values
114  * @return nt status of rpc connection
115  **/
116
117 static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,
118                                           struct libnet_context *ctx,
119                                           TALLOC_CTX *mem_ctx,
120                                           struct libnet_RpcConnect *r)
121 {
122         struct rpc_connect_srv_state *s;
123         NTSTATUS status = composite_wait(c);
124
125         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && r) {
126                 s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);
127                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
128                 ctx->pipe = r->out.dcerpc_pipe;
129         }
130
131         talloc_free(c);
132         return status;
133 }
134
135
136 struct rpc_connect_dc_state {
137         struct libnet_context *ctx;
138         struct libnet_RpcConnect r;
139         struct libnet_RpcConnect r2;
140         struct libnet_LookupDCs f;
141         const char *connect_name;
142 };
143
144
145 static void continue_lookup_dc(struct composite_context *ctx);
146 static void continue_rpc_connect(struct composite_context *ctx);
147
148
149 /**
150  * Initiates connection to rpc pipe on domain pdc
151  * 
152  * @param ctx initialised libnet context
153  * @param mem_ctx memory context of this call
154  * @param r data structure containing necessary parameters and return values
155  * @return composite context of this call
156  **/
157
158 static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,
159                                                           TALLOC_CTX *mem_ctx,
160                                                           struct libnet_RpcConnect *r)
161 {
162         struct composite_context *c;
163         struct rpc_connect_dc_state *s;
164         struct composite_context *lookup_dc_req;
165
166         c = talloc_zero(mem_ctx, struct composite_context);
167         if (c == NULL) return NULL;
168
169         s = talloc_zero(c, struct rpc_connect_dc_state);
170         if (composite_nomem(s, c)) return c;
171
172         c->state = COMPOSITE_STATE_IN_PROGRESS;
173         c->private_data = s;
174         c->event_ctx = ctx->event_ctx;
175
176         s->r   = *r;
177         s->ctx = ctx;
178
179         switch (r->level) {
180         case LIBNET_RPC_CONNECT_PDC:
181                 s->f.in.name_type = NBT_NAME_PDC;
182                 break;
183
184         case LIBNET_RPC_CONNECT_DC:
185                 s->f.in.name_type = NBT_NAME_LOGON;
186                 break;
187
188         default:
189                 break;
190         }
191         s->f.in.domain_name = r->in.name;
192         s->f.out.num_dcs    = 0;
193         s->f.out.dcs        = NULL;
194
195         /* find the domain pdc first */
196         lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);
197         if (composite_nomem(lookup_dc_req, c)) return c;
198
199         composite_continue(c, lookup_dc_req, continue_lookup_dc, c);
200         return c;
201 }
202
203
204 static void continue_lookup_dc(struct composite_context *ctx)
205 {
206         struct composite_context *c;
207         struct rpc_connect_dc_state *s;
208         struct composite_context *rpc_connect_req;
209         
210         c = talloc_get_type(ctx->async.private_data, struct composite_context);
211         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
212         
213         c->status = libnet_LookupDCs_recv(ctx, c, &s->f);
214         if (!composite_is_ok(c)) return;
215
216         /* we might not have got back a name.  Fall back to the IP */
217         if (s->f.out.dcs[0].name) {
218                 s->connect_name = s->f.out.dcs[0].name;
219         } else {
220                 s->connect_name = s->f.out.dcs[0].address;
221         }
222
223         /* ok, pdc has been found so do attempt to rpc connect */
224         s->r2.level            = LIBNET_RPC_CONNECT_SERVER;
225
226         /* this will cause yet another name resolution, but at least
227          * we pass the right name down the stack now */
228         s->r2.in.name          = talloc_strdup(c, s->connect_name);
229         s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;  
230
231         rpc_connect_req = libnet_RpcConnect_send(s->ctx, c, &s->r2);
232         if (composite_nomem(rpc_connect_req, c)) return;
233
234         composite_continue(c, rpc_connect_req, continue_rpc_connect, c);
235 }
236
237
238 static void continue_rpc_connect(struct composite_context *ctx)
239 {
240         struct composite_context *c;
241         struct rpc_connect_dc_state *s;
242
243         c = talloc_get_type(ctx->async.private_data, struct composite_context);
244         s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
245
246         c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->r2);
247
248         /* error string is to be passed anyway */
249         s->r.out.error_string  = s->r2.out.error_string;
250         if (!composite_is_ok(c)) return;
251
252         s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;
253
254         composite_done(c);
255 }
256
257
258 /**
259  * Receives result of connection to rpc pipe on domain pdc
260  *
261  * @param c composite context
262  * @param ctx initialised libnet context
263  * @param mem_ctx memory context of this call
264  * @param r data structure containing necessary parameters and return values
265  * @return nt status of rpc connection
266  **/
267
268 static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,
269                                          struct libnet_context *ctx,
270                                          TALLOC_CTX *mem_ctx,
271                                          struct libnet_RpcConnect *r)
272 {
273         NTSTATUS status;
274         struct rpc_connect_dc_state *s;
275         
276         status = composite_wait(c);
277
278         if (NT_STATUS_IS_OK(status) && ctx && mem_ctx && r) {
279                 s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);
280                 r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);
281                 ctx->pipe = r->out.dcerpc_pipe;
282         }
283
284         talloc_free(c);
285         return status;
286 }
287
288
289
290 /**
291  * Initiates connection to rpc pipe on remote server or pdc
292  * 
293  * @param ctx initialised libnet context
294  * @param mem_ctx memory context of this call
295  * @param r data structure containing necessary parameters and return values
296  * @return composite context of this call
297  **/
298
299 struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
300                                                  TALLOC_CTX *mem_ctx,
301                                                  struct libnet_RpcConnect *r)
302 {
303         struct composite_context *c;
304
305         switch (r->level) {
306         case LIBNET_RPC_CONNECT_SERVER:
307                 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
308                 break;
309
310         case LIBNET_RPC_CONNECT_BINDING:
311                 c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r);
312                 break;
313                         
314         case LIBNET_RPC_CONNECT_PDC:
315         case LIBNET_RPC_CONNECT_DC:
316                 c = libnet_RpcConnectDC_send(ctx, mem_ctx, r);
317                 break;
318
319         default:
320                 c = talloc_zero(mem_ctx, struct composite_context);
321                 composite_error(c, NT_STATUS_INVALID_LEVEL);
322         }
323
324         return c;
325 }
326
327
328 /**
329  * Receives result of connection to rpc pipe on remote server or pdc
330  *
331  * @param c composite context
332  * @param ctx initialised libnet context
333  * @param mem_ctx memory context of this call
334  * @param r data structure containing necessary parameters and return values
335  * @return nt status of rpc connection
336  **/
337
338 NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
339                                 TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
340 {
341         switch (r->level) {
342         case LIBNET_RPC_CONNECT_SERVER:
343         case LIBNET_RPC_CONNECT_BINDING:
344                 return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
345
346         case LIBNET_RPC_CONNECT_PDC:
347         case LIBNET_RPC_CONNECT_DC:
348                 return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
349
350         default:
351                 return NT_STATUS_INVALID_LEVEL;
352         }
353 }
354
355
356 NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
357                            struct libnet_RpcConnect *r)
358 {
359         struct composite_context *c;
360         
361         c = libnet_RpcConnect_send(ctx, mem_ctx, r);
362         return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
363 }
364
365
366 /**
367  * Connects to rpc pipe on remote server or pdc, and returns info on the domain name, domain sid and realm
368  * 
369  * @param ctx initialised libnet context
370  * @param r data structure containing necessary parameters and return values.  Must be a talloc context
371  * @return nt status of the call
372  **/
373
374 NTSTATUS libnet_RpcConnectDCInfo(struct libnet_context *ctx, 
375                                  struct libnet_RpcConnectDCInfo *r)
376 {
377         TALLOC_CTX *tmp_ctx;
378         NTSTATUS status;
379
380         struct libnet_RpcConnect *c;
381         struct lsa_ObjectAttribute attr;
382         struct lsa_QosInfo qos;
383         struct lsa_OpenPolicy2 lsa_open_policy;
384         struct policy_handle lsa_p_handle;
385         struct lsa_QueryInfoPolicy2 lsa_query_info2;
386         struct lsa_QueryInfoPolicy lsa_query_info;
387
388         struct dcerpc_pipe *lsa_pipe;
389
390         struct dcerpc_binding *final_binding;
391         struct dcerpc_pipe *final_pipe;
392
393         tmp_ctx = talloc_new(r);
394         if (!tmp_ctx) {
395                 r->out.error_string = NULL;
396                 return NT_STATUS_NO_MEMORY;
397         }
398         
399         c = talloc(tmp_ctx, struct libnet_RpcConnect);
400         if (!c) {
401                 r->out.error_string = NULL;
402                 talloc_free(tmp_ctx);
403                 return NT_STATUS_NO_MEMORY;
404         }
405         c->level              = r->level;
406
407         if (r->level != LIBNET_RPC_CONNECT_BINDING) {
408                 c->in.name    = r->in.name;
409         } else {
410                 c->in.binding = r->in.binding;
411         }
412         
413         c->in.dcerpc_iface    = &dcerpc_table_lsarpc;
414         
415         /* connect to the LSA pipe of the PDC */
416
417         status = libnet_RpcConnect(ctx, c, c);
418         if (!NT_STATUS_IS_OK(status)) {
419                 if (r->level != LIBNET_RPC_CONNECT_BINDING) {
420                         r->out.error_string = talloc_asprintf(r,
421                                                               "Connection to LSA pipe of DC failed: %s",
422                                                               c->out.error_string);
423                 } else {
424                         r->out.error_string = talloc_asprintf(r,
425                                                               "Connection to LSA pipe with binding '%s' failed: %s",
426                                                               r->in.binding, c->out.error_string);
427                 }
428                 talloc_free(tmp_ctx);
429                 return status;
430         }                       
431         lsa_pipe = c->out.dcerpc_pipe;
432         
433         /* Get an LSA policy handle */
434
435         ZERO_STRUCT(lsa_p_handle);
436         qos.len = 0;
437         qos.impersonation_level = 2;
438         qos.context_mode = 1;
439         qos.effective_only = 0;
440
441         attr.len = 0;
442         attr.root_dir = NULL;
443         attr.object_name = NULL;
444         attr.attributes = 0;
445         attr.sec_desc = NULL;
446         attr.sec_qos = &qos;
447
448         lsa_open_policy.in.attr = &attr;
449         
450         lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\"); 
451         if (!lsa_open_policy.in.system_name) {
452                 r->out.error_string = NULL;
453                 talloc_free(tmp_ctx);
454                 return NT_STATUS_NO_MEMORY;
455         }
456
457         lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
458         lsa_open_policy.out.handle = &lsa_p_handle;
459
460         status = dcerpc_lsa_OpenPolicy2(lsa_pipe, tmp_ctx, &lsa_open_policy); 
461
462         /* This now fails on ncacn_ip_tcp against Win2k3 SP1 */
463         if (NT_STATUS_IS_OK(status)) {
464                 /* Look to see if this is ADS (a fault indicates NT4 or Samba 3.0) */
465                 
466                 lsa_query_info2.in.handle = &lsa_p_handle;
467                 lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
468                 
469                 status = dcerpc_lsa_QueryInfoPolicy2(lsa_pipe, tmp_ctx,                 
470                                                      &lsa_query_info2);
471                 
472                 if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
473                         if (!NT_STATUS_IS_OK(status)) {
474                                 r->out.error_string = talloc_asprintf(r,
475                                                                       "lsa_QueryInfoPolicy2 failed: %s",
476                                                                       nt_errstr(status));
477                                 talloc_free(tmp_ctx);
478                                 return status;
479                         }
480                         r->out.realm = lsa_query_info2.out.info->dns.dns_domain.string;
481                         r->out.guid = talloc(r, struct GUID);
482                         if (!r->out.guid) {
483                                 r->out.error_string = NULL;
484                                 return NT_STATUS_NO_MEMORY;
485                         }
486                         *r->out.guid = lsa_query_info2.out.info->dns.domain_guid;
487                 } else {
488                         r->out.realm = NULL;
489                         r->out.guid = NULL;
490                 }
491                 
492                 /* Grab the domain SID (regardless of the result of the previous call */
493                 
494                 lsa_query_info.in.handle = &lsa_p_handle;
495                 lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
496                 
497                 status = dcerpc_lsa_QueryInfoPolicy(lsa_pipe, tmp_ctx, 
498                                                     &lsa_query_info);
499                 
500                 if (!NT_STATUS_IS_OK(status)) {
501                         r->out.error_string = talloc_asprintf(r,
502                                                               "lsa_QueryInfoPolicy2 failed: %s",
503                                                               nt_errstr(status));
504                         talloc_free(tmp_ctx);
505                         return status;
506                 }
507                 
508                 r->out.domain_sid = lsa_query_info.out.info->domain.sid;
509                 r->out.domain_name = lsa_query_info.out.info->domain.name.string;
510         } else {
511                 /* Cause the code further down to try this with just SAMR */
512                 r->out.domain_sid = NULL;
513                 r->out.domain_name = NULL;
514                 r->out.realm = NULL;
515         }
516
517         /* Find the original binding string */
518         final_binding = talloc(tmp_ctx, struct dcerpc_binding);
519         if (!final_binding) {
520                 return NT_STATUS_NO_MEMORY;
521         }
522         *final_binding = *lsa_pipe->binding;
523         /* Ensure we keep hold of the member elements */
524         talloc_reference(final_binding, lsa_pipe->binding);
525
526         /* Make binding string for samr, not the other pipe */
527         status = dcerpc_epm_map_binding(tmp_ctx, final_binding,                                         
528                                         r->in.dcerpc_iface,
529                                         lsa_pipe->conn->event_ctx);
530         if (!NT_STATUS_IS_OK(status)) {
531                 r->out.error_string = talloc_asprintf(r,
532                                                       "Failed to map pipe with endpoint mapper - %s",
533                                                       nt_errstr(status));
534                 talloc_free(tmp_ctx);
535                 return status;
536         }
537
538         /* Now that we have the info setup a final connection to the pipe they wanted */
539         status = dcerpc_secondary_connection(lsa_pipe, &final_pipe, final_binding);
540         if (!NT_STATUS_IS_OK(status)) {
541                 r->out.error_string = talloc_asprintf(r,
542                                                       "secondary connection failed: %s",
543                                                       nt_errstr(status));
544                 talloc_free(tmp_ctx);
545                 return status;
546         }
547         r->out.dcerpc_pipe = final_pipe;
548
549         talloc_steal(r, r->out.realm);
550         talloc_steal(r, r->out.domain_sid);
551         talloc_steal(r, r->out.domain_name);
552         talloc_steal(r, r->out.dcerpc_pipe);
553
554         /* This should close the LSA pipe, which we don't need now we have the info */
555         talloc_free(tmp_ctx);
556         return NT_STATUS_OK;
557 }
558