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