r10853: Convert wbinfo -n to properly init the domain.
[amitay/samba.git] / source4 / winbind / wb_init_domain.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Volker Lendecke 2005
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 /*
21   a composite API for initializing a domain
22 */
23
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libcli/smb_composite/smb_composite.h"
27 #include "winbind/wb_async_helpers.h"
28 #include "winbind/wb_server.h"
29 #include "smbd/service_stream.h"
30
31 #include "librpc/gen_ndr/nbt.h"
32 #include "librpc/gen_ndr/samr.h"
33 #include "lib/messaging/irpc.h"
34 #include "librpc/gen_ndr/irpc.h"
35 #include "librpc/gen_ndr/ndr_irpc.h"
36 #include "libcli/raw/libcliraw.h"
37 #include "librpc/gen_ndr/ndr_netlogon.h"
38 #include "librpc/gen_ndr/ndr_lsa.h"
39 #include "libcli/auth/credentials.h"
40
41
42 /* Helper to initialize LSA with different auth methods and opening the lsa
43  * policy */
44
45 struct init_lsa_state {
46         struct composite_context *ctx;
47         struct dcerpc_pipe *lsa_pipe;
48
49         uint8_t auth_type;
50         struct cli_credentials *creds;
51
52         struct lsa_ObjectAttribute objectattr;
53         struct lsa_OpenPolicy2 openpolicy;
54         struct policy_handle *handle;
55 };
56
57 static void init_lsa_recv_pipe(struct composite_context *ctx);
58 static void init_lsa_recv_openpol(struct rpc_request *req);
59
60 static struct composite_context *wb_init_lsa_send(struct smbcli_tree *tree,
61                                                   uint8_t auth_type,
62                                                   struct cli_credentials *creds)
63 {
64         struct composite_context *result, *ctx;
65         struct init_lsa_state *state;
66
67         result = talloc(NULL, struct composite_context);
68         if (result == NULL) goto failed;
69         result->state = COMPOSITE_STATE_IN_PROGRESS;
70         result->event_ctx = tree->session->transport->socket->event.ctx;
71
72         state = talloc(result, struct init_lsa_state);
73         if (state == NULL) goto failed;
74         state->ctx = result;
75         result->private_data = state;
76
77         state->auth_type = auth_type;
78         state->creds = creds;
79
80         state->lsa_pipe = dcerpc_pipe_init(state, result->event_ctx);
81         if (state->lsa_pipe == NULL) goto failed;
82
83         ctx = dcerpc_pipe_open_smb_send(state->lsa_pipe->conn, tree,
84                                         "\\lsarpc");
85         ctx->async.fn = init_lsa_recv_pipe;
86         ctx->async.private_data = state;
87         return result;
88         
89  failed:
90         talloc_free(result);
91         return NULL;
92 }
93
94 static void init_lsa_recv_pipe(struct composite_context *ctx)
95 {
96         struct init_lsa_state *state =
97                 talloc_get_type(ctx->async.private_data,
98                                 struct init_lsa_state);
99         struct rpc_request *req;
100
101         state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
102         if (!comp_is_ok(state->ctx)) return;
103
104         switch (state->auth_type) {
105         case DCERPC_AUTH_TYPE_NONE:
106                 state->ctx->status =
107                         dcerpc_bind_auth_none(state->lsa_pipe,
108                                               DCERPC_LSARPC_UUID,
109                                               DCERPC_LSARPC_VERSION);
110                 break;
111         case DCERPC_AUTH_TYPE_NTLMSSP:
112         case DCERPC_AUTH_TYPE_SCHANNEL:
113                 if (state->creds == NULL) {
114                         comp_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
115                         return;
116                 }
117                 state->lsa_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
118                 state->ctx->status =
119                         dcerpc_bind_auth_password(state->lsa_pipe,
120                                                   DCERPC_LSARPC_UUID,
121                                                   DCERPC_LSARPC_VERSION,
122                                                   state->creds,
123                                                   state->auth_type,
124                                                   NULL);
125                 break;
126         default:
127                 state->ctx->status = NT_STATUS_INTERNAL_ERROR;
128                 
129         }
130                         
131         state->handle = talloc(state, struct policy_handle);
132         if (comp_nomem(state->handle, state->ctx)) return;
133
134         state->openpolicy.in.system_name =
135                 talloc_asprintf(state, "\\\\%s",
136                                 dcerpc_server_name(state->lsa_pipe));
137         ZERO_STRUCT(state->objectattr);
138         state->openpolicy.in.attr = &state->objectattr;
139         state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
140         state->openpolicy.out.handle = state->handle;
141
142         req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
143                                           &state->openpolicy);
144         rpc_cont(state->ctx, req, init_lsa_recv_openpol, state);
145 }
146
147 static void init_lsa_recv_openpol(struct rpc_request *req)
148 {
149         struct init_lsa_state *state =
150                 talloc_get_type(req->async.private,
151                                 struct init_lsa_state);
152
153         state->ctx->status = dcerpc_ndr_request_recv(req);
154         if (!comp_is_ok(state->ctx)) return;
155         state->ctx->status = state->openpolicy.out.result;
156         if (!comp_is_ok(state->ctx)) return;
157
158         comp_done(state->ctx);
159 }
160
161 static NTSTATUS wb_init_lsa_recv(struct composite_context *c,
162                                  TALLOC_CTX *mem_ctx,
163                                  struct dcerpc_pipe **lsa_pipe,
164                                  struct policy_handle **lsa_policy)
165 {
166         NTSTATUS status = composite_wait(c);
167         if (NT_STATUS_IS_OK(status)) {
168                 struct init_lsa_state *state =
169                         talloc_get_type(c->private_data,
170                                         struct init_lsa_state);
171                 *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
172                 *lsa_policy = talloc_steal(mem_ctx, state->handle);
173         }
174         talloc_free(c);
175         return status;
176 }
177
178 /*
179  * Initialize a domain:
180  *
181  * - With schannel credentials, try to open the SMB connection with the machine
182  *   creds. Fall back to anonymous.
183  *
184  * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
185  *   pipe.
186  *
187  * - Open LSA. If we have machine creds, try to open with ntlmssp. Fall back
188  *   to schannel and then to anon bind.
189  *
190  * - With queryinfopolicy, verify that we're talking to the right domain
191  *
192  * A bit complex, but with all the combinations I think it's the best we can
193  * get. NT4, W2k3 and W2k all have different combinations, but in the end we
194  * have a signed&sealed lsa connection on all of them.
195  *
196  * Not sure if it is overkill, but it seems to work.
197  */
198
199 struct init_domain_state {
200         struct composite_context *ctx;
201         struct wbsrv_domain *domain;
202
203         int num_dcs;
204         struct nbt_dc_name *dcs;
205
206         struct smb_composite_connect conn;
207
208         struct dcerpc_pipe *auth2_pipe;
209         struct dcerpc_pipe *netlogon_pipe;
210
211         struct dcerpc_pipe *lsa_pipe;
212         struct policy_handle *lsa_policy;
213
214         struct lsa_QueryInfoPolicy queryinfo;
215 };
216
217 static void init_domain_recv_dcs(struct composite_context *ctx);
218 static void init_domain_recv_authsmb(struct composite_context *ctx);
219 static void init_domain_anonsmb(struct init_domain_state *state);
220 static void init_domain_recv_anonsmb(struct composite_context *ctx);
221 static void init_domain_openpipes(struct init_domain_state *state);
222 static void init_domain_openlsa(struct init_domain_state *state);
223 static void init_domain_recv_netlogoncreds(struct composite_context *ctx);
224 static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
225 static void init_domain_recv_lsa_ntlmssp(struct composite_context *ctx);
226 static void init_domain_recv_lsa_schannel(struct composite_context *ctx);
227 static void init_domain_recv_lsa_none(struct composite_context *ctx);
228 static void init_domain_check_lsa(struct init_domain_state *state);
229 static void init_domain_recv_queryinfo(struct rpc_request *req);
230
231 struct composite_context *wb_init_domain_send(struct wbsrv_domain *domain,
232                                               struct event_context *event_ctx,
233                                               struct messaging_context *msg_ctx)
234 {
235         struct composite_context *result, *ctx;
236         struct init_domain_state *state;
237
238         result = talloc(domain, struct composite_context);
239         if (result == NULL) goto failed;
240         result->state = COMPOSITE_STATE_IN_PROGRESS;
241         result->async.fn = NULL;
242         result->event_ctx = event_ctx;
243
244         state = talloc_zero(result, struct init_domain_state);
245         if (state == NULL) goto failed;
246         state->ctx = result;
247         result->private_data = state;
248
249         state->domain = domain;
250
251         if (state->domain->schannel_creds != NULL) {
252                 talloc_free(state->domain->schannel_creds);
253         }
254
255         state->domain->schannel_creds = cli_credentials_init(state->domain);
256         if (state->domain->schannel_creds == NULL) goto failed;
257         cli_credentials_set_conf(state->domain->schannel_creds);
258         state->ctx->status =
259                 cli_credentials_set_machine_account(state->domain->
260                                                     schannel_creds);
261         if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
262
263         ctx = wb_finddcs_send(domain->name, domain->sid, event_ctx, msg_ctx);
264         if (ctx == NULL) goto failed;
265
266         ctx->async.fn = init_domain_recv_dcs;
267         ctx->async.private_data = state;
268         return result;
269
270  failed:
271         talloc_free(result);
272         return NULL;
273 }
274
275 static void init_domain_recv_dcs(struct composite_context *ctx)
276 {
277         struct init_domain_state *state =
278                 talloc_get_type(ctx->async.private_data,
279                                 struct init_domain_state);
280
281         state->ctx->status = wb_finddcs_recv(ctx, state, &state->num_dcs,
282                                              &state->dcs);
283         if (!comp_is_ok(state->ctx)) return;
284
285         if (state->num_dcs < 1) {
286                 comp_error(state->ctx, NT_STATUS_NO_LOGON_SERVERS);
287                 return;
288         }
289
290         state->conn.in.dest_host = state->dcs[0].address;
291         state->conn.in.port = 0;
292         state->conn.in.called_name = state->dcs[0].name;
293         state->conn.in.service = "IPC$";
294         state->conn.in.service_type = "IPC";
295         state->conn.in.workgroup = state->domain->name;
296
297         if (state->domain->schannel_creds != NULL) {
298                 /* Try to connect as workstation */
299                 state->conn.in.credentials = state->domain->schannel_creds;
300                 ctx = smb_composite_connect_send(&state->conn, state,
301                                                  state->ctx->event_ctx);
302                 comp_cont(state->ctx, ctx, init_domain_recv_authsmb, state);
303                 return;
304         }
305
306         init_domain_anonsmb(state);
307 }
308
309 static void init_domain_recv_authsmb(struct composite_context *ctx)
310 {
311         struct init_domain_state *state =
312                 talloc_get_type(ctx->async.private_data,
313                                 struct init_domain_state);
314
315         state->ctx->status = smb_composite_connect_recv(ctx, state);
316         if (NT_STATUS_IS_OK(state->ctx->status)) {
317                 init_domain_openpipes(state);
318                 return;
319         }
320
321         init_domain_anonsmb(state);
322 }
323
324 static void init_domain_anonsmb(struct init_domain_state *state)
325 {
326         struct composite_context *ctx;
327
328         state->conn.in.credentials = cli_credentials_init(state);
329         if (comp_nomem(state->conn.in.credentials, state->ctx)) return;
330         cli_credentials_set_conf(state->conn.in.credentials);
331         cli_credentials_set_anonymous(state->conn.in.credentials);
332         ctx = smb_composite_connect_send(&state->conn, state,
333                                          state->ctx->event_ctx);
334         comp_cont(state->ctx, ctx, init_domain_recv_anonsmb, state);
335 }
336
337 static void init_domain_recv_anonsmb(struct composite_context *ctx)
338 {
339         struct init_domain_state *state =
340                 talloc_get_type(ctx->async.private_data,
341                                 struct init_domain_state);
342
343         state->ctx->status = smb_composite_connect_recv(ctx, state);
344         if (!comp_is_ok(state->ctx)) return;
345
346         init_domain_openpipes(state);
347 }
348
349 static void init_domain_openpipes(struct init_domain_state *state)
350 {
351         struct composite_context *ctx;
352
353         if (state->domain->schannel_creds == NULL) {
354                 /* No chance to open netlogon */
355                 init_domain_openlsa(state);
356                 return;
357         }
358
359         ctx = wb_get_schannel_creds_send(state->domain->schannel_creds,
360                                          state->conn.out.tree,
361                                          state->ctx->event_ctx);
362         comp_cont(state->ctx, ctx, init_domain_recv_netlogoncreds, state);
363 }
364
365 static void init_domain_recv_netlogoncreds(struct composite_context *ctx)
366 {
367         struct init_domain_state *state =
368                 talloc_get_type(ctx->async.private_data,
369                                 struct init_domain_state);
370         struct smbcli_tree *tree = NULL;
371
372         state->ctx->status = wb_get_schannel_creds_recv(ctx, state,
373                                                         &state->auth2_pipe);
374         if (!comp_is_ok(state->ctx)) return;
375
376         talloc_unlink(state, state->conn.out.tree); /* The pipe owns it now */
377
378         state->netlogon_pipe = dcerpc_pipe_init(state, state->ctx->event_ctx);
379         if (comp_nomem(state->netlogon_pipe, state->ctx)) return;
380
381         if (state->auth2_pipe != NULL) {
382                 tree = dcerpc_smb_tree(state->auth2_pipe->conn);
383         }
384
385         if (tree == NULL) {
386                 comp_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
387                 return;
388         }
389
390         ctx = dcerpc_pipe_open_smb_send(state->netlogon_pipe->conn, tree,
391                                         "\\netlogon");
392         comp_cont(state->ctx, ctx, init_domain_recv_netlogonpipe, state);
393 }
394
395 static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
396 {
397         struct init_domain_state *state =
398                 talloc_get_type(ctx->async.private_data,
399                                 struct init_domain_state);
400
401         state->ctx->status = dcerpc_pipe_open_smb_recv(ctx);
402         if (!comp_is_ok(state->ctx)) return;
403
404         state->netlogon_pipe->conn->flags |= (DCERPC_SIGN | DCERPC_SEAL);
405         state->ctx->status =
406                 dcerpc_bind_auth_password(state->netlogon_pipe,
407                                           DCERPC_NETLOGON_UUID,
408                                           DCERPC_NETLOGON_VERSION, 
409                                           state->domain->schannel_creds,
410                                           DCERPC_AUTH_TYPE_SCHANNEL,
411                                           NULL);
412         if (!comp_is_ok(state->ctx)) return;
413
414         init_domain_openlsa(state);
415 }
416
417 static void init_domain_openlsa(struct init_domain_state *state)
418 {
419         struct composite_context *ctx;
420
421         if (state->domain->schannel_creds != NULL) {
422                 ctx = wb_init_lsa_send(state->conn.out.tree,
423                                        DCERPC_AUTH_TYPE_NTLMSSP,
424                                        state->domain->schannel_creds);
425                 comp_cont(state->ctx, ctx,
426                           init_domain_recv_lsa_ntlmssp, state);
427                 return;
428         }
429
430         ctx = wb_init_lsa_send(state->conn.out.tree, DCERPC_AUTH_TYPE_NONE,
431                                NULL);
432         comp_cont(state->ctx, ctx, init_domain_recv_lsa_none, state);
433 }
434
435 static void init_domain_recv_lsa_ntlmssp(struct composite_context *ctx)
436 {
437         struct init_domain_state *state =
438                 talloc_get_type(ctx->async.private_data,
439                                 struct init_domain_state);
440
441         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
442                                               &state->lsa_policy);
443         if (NT_STATUS_IS_OK(state->ctx->status)) {
444                 init_domain_check_lsa(state);
445                 return;
446         }
447
448         ctx = wb_init_lsa_send(state->conn.out.tree,
449                                DCERPC_AUTH_TYPE_SCHANNEL,
450                                state->domain->schannel_creds);
451         comp_cont(state->ctx, ctx, init_domain_recv_lsa_schannel, state);
452 }
453
454 static void init_domain_recv_lsa_schannel(struct composite_context *ctx)
455 {
456         struct init_domain_state *state =
457                 talloc_get_type(ctx->async.private_data,
458                                 struct init_domain_state);
459
460         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
461                                               &state->lsa_policy);
462         if (NT_STATUS_IS_OK(state->ctx->status)) {
463                 init_domain_check_lsa(state);
464                 return;
465         }
466
467         ctx = wb_init_lsa_send(state->conn.out.tree,
468                                DCERPC_AUTH_TYPE_NONE, NULL);
469         comp_cont(state->ctx, ctx, init_domain_recv_lsa_none, state);
470 }
471
472 static void init_domain_recv_lsa_none(struct composite_context *ctx)
473 {
474         struct init_domain_state *state =
475                 talloc_get_type(ctx->async.private_data,
476                                 struct init_domain_state);
477
478         state->ctx->status = wb_init_lsa_recv(ctx, state, &state->lsa_pipe,
479                                               &state->lsa_policy);
480         if (!comp_is_ok(state->ctx)) return;
481
482         init_domain_check_lsa(state);
483 }
484
485 static void init_domain_check_lsa(struct init_domain_state *state)
486 {
487         struct rpc_request *req;
488
489         if (state->auth2_pipe == NULL) {
490                 /* Give the tree to the LSA pipe, otherwise it has been given
491                  * to the auth2 pipe already */
492                 talloc_unlink(state, state->conn.out.tree);
493                 state->conn.out.tree = NULL;
494         }
495
496         state->queryinfo.in.handle = state->lsa_policy;
497         state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
498
499         req = dcerpc_lsa_QueryInfoPolicy_send(state->lsa_pipe, state,
500                                               &state->queryinfo);
501         rpc_cont(state->ctx, req, init_domain_recv_queryinfo, state);
502 }
503
504 static void init_domain_recv_queryinfo(struct rpc_request *req)
505 {
506         struct init_domain_state *state =
507                 talloc_get_type(req->async.private, struct init_domain_state);
508         struct lsa_DomainInfo *dominfo;
509
510         state->ctx->status = dcerpc_ndr_request_recv(req);
511         if (!comp_is_ok(state->ctx)) return;
512         state->ctx->status = state->queryinfo.out.result;
513         if (!comp_is_ok(state->ctx)) return;
514
515         dominfo = &state->queryinfo.out.info->account_domain;
516
517         if (strcasecmp(state->domain->name, dominfo->name.string) != 0) {
518                 DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
519                           state->domain->name,
520                           dcerpc_server_name(state->lsa_pipe),
521                           dominfo->name.string));
522                 comp_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
523                 return;
524         }
525
526         if (!dom_sid_equal(state->domain->sid, dominfo->sid)) {
527                 DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
528                           dom_sid_string(state, state->domain->sid),
529                           dcerpc_server_name(state->lsa_pipe),
530                           dom_sid_string(state, dominfo->sid)));
531                 comp_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
532                 return;
533         }
534
535         comp_done(state->ctx);
536 }
537
538 NTSTATUS wb_init_domain_recv(struct composite_context *c)
539 {
540         NTSTATUS status = composite_wait(c);
541         if (NT_STATUS_IS_OK(status)) {
542                 struct init_domain_state *state =
543                         talloc_get_type(c->private_data,
544                                         struct init_domain_state);
545                 struct wbsrv_domain *domain = state->domain;
546
547                 talloc_free(domain->netlogon_auth2_pipe);
548                 domain->netlogon_auth2_pipe =
549                         talloc_steal(domain, state->auth2_pipe);
550
551                 talloc_free(domain->netlogon_pipe);
552                 domain->netlogon_pipe =
553                         talloc_steal(domain, state->netlogon_pipe);
554
555                 talloc_free(domain->lsa_pipe);
556                 domain->lsa_pipe =
557                         talloc_steal(domain, state->lsa_pipe);
558
559                 talloc_free(domain->lsa_policy);
560                 domain->lsa_policy =
561                         talloc_steal(domain, state->lsa_policy);
562
563                 domain->initialized = True;
564         }
565         talloc_free(c);
566         return status;
567 }
568
569 NTSTATUS wb_init_domain(struct wbsrv_domain *domain,
570                         struct event_context *event_ctx,
571                         struct messaging_context *messaging_ctx)
572 {
573         struct composite_context *c =
574                 wb_init_domain_send(domain, event_ctx, messaging_ctx);
575         return wb_init_domain_recv(c);
576 }