1480486c3206debe5994534a29a828f4a9210193
[metze/samba/wip.git] / source4 / librpc / rpc / dcerpc_schannel.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc schannel operations
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
8    Copyright (C) Rafal Szczesniak 2006
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include <tevent.h>
26 #include "auth/auth.h"
27 #include "libcli/composite/composite.h"
28 #include "libcli/auth/libcli_auth.h"
29 #include "librpc/gen_ndr/ndr_netlogon.h"
30 #include "librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "auth/credentials/credentials.h"
32 #include "librpc/rpc/dcerpc_proto.h"
33 #include "param/param.h"
34
35 struct schannel_key_state {
36         struct dcerpc_pipe *pipe;
37         struct dcerpc_pipe *pipe2;
38         struct dcerpc_binding *binding;
39         bool dcerpc_schannel_auto;
40         struct cli_credentials *credentials;
41         struct netlogon_creds_CredentialState *creds;
42         uint32_t local_negotiate_flags;
43         uint32_t remote_negotiate_flags;
44         struct netr_Credential credentials1;
45         struct netr_Credential credentials2;
46         struct netr_Credential credentials3;
47         struct netr_ServerReqChallenge r;
48         struct netr_ServerAuthenticate2 a;
49         const struct samr_Password *mach_pwd;
50 };
51
52
53 static void continue_secondary_connection(struct composite_context *ctx);
54 static void continue_bind_auth_none(struct composite_context *ctx);
55 static void continue_srv_challenge(struct tevent_req *subreq);
56 static void continue_srv_auth2(struct tevent_req *subreq);
57 static void continue_get_capabilities(struct tevent_req *subreq);
58
59
60 /*
61   Stage 2 of schannel_key: Receive endpoint mapping and request secondary
62   rpc connection
63 */
64 static void continue_epm_map_binding(struct composite_context *ctx)
65 {
66         struct composite_context *c;
67         struct schannel_key_state *s;
68         struct composite_context *sec_conn_req;
69
70         c = talloc_get_type(ctx->async.private_data, struct composite_context);
71         s = talloc_get_type(c->private_data, struct schannel_key_state);
72
73         /* receive endpoint mapping */
74         c->status = dcerpc_epm_map_binding_recv(ctx);
75         if (!NT_STATUS_IS_OK(c->status)) {
76                 DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n",
77                          NDR_NETLOGON_UUID, nt_errstr(c->status)));
78                 composite_error(c, c->status);
79                 return;
80         }
81
82         /* send a request for secondary rpc connection */
83         sec_conn_req = dcerpc_secondary_connection_send(s->pipe,
84                                                         s->binding);
85         if (composite_nomem(sec_conn_req, c)) return;
86
87         composite_continue(c, sec_conn_req, continue_secondary_connection, c);
88 }
89
90
91 /*
92   Stage 3 of schannel_key: Receive secondary rpc connection and perform
93   non-authenticated bind request
94 */
95 static void continue_secondary_connection(struct composite_context *ctx)
96 {
97         struct composite_context *c;
98         struct schannel_key_state *s;
99         struct composite_context *auth_none_req;
100
101         c = talloc_get_type(ctx->async.private_data, struct composite_context);
102         s = talloc_get_type(c->private_data, struct schannel_key_state);
103
104         /* receive secondary rpc connection */
105         c->status = dcerpc_secondary_connection_recv(ctx, &s->pipe2);
106         if (!composite_is_ok(c)) return;
107
108         talloc_steal(s, s->pipe2);
109
110         /* initiate a non-authenticated bind */
111         auth_none_req = dcerpc_bind_auth_none_send(c, s->pipe2, &ndr_table_netlogon);
112         if (composite_nomem(auth_none_req, c)) return;
113
114         composite_continue(c, auth_none_req, continue_bind_auth_none, c);
115 }
116
117
118 /*
119   Stage 4 of schannel_key: Receive non-authenticated bind and get
120   a netlogon challenge
121 */
122 static void continue_bind_auth_none(struct composite_context *ctx)
123 {
124         struct composite_context *c;
125         struct schannel_key_state *s;
126         struct tevent_req *subreq;
127
128         c = talloc_get_type(ctx->async.private_data, struct composite_context);
129         s = talloc_get_type(c->private_data, struct schannel_key_state);
130
131         /* receive result of non-authenticated bind request */
132         c->status = dcerpc_bind_auth_none_recv(ctx);
133         if (!composite_is_ok(c)) return;
134         
135         /* prepare a challenge request */
136         s->r.in.server_name   = talloc_asprintf(c, "\\\\%s", dcerpc_server_name(s->pipe));
137         if (composite_nomem(s->r.in.server_name, c)) return;
138         s->r.in.computer_name = cli_credentials_get_workstation(s->credentials);
139         s->r.in.credentials   = &s->credentials1;
140         s->r.out.return_credentials  = &s->credentials2;
141         
142         generate_random_buffer(s->credentials1.data, sizeof(s->credentials1.data));
143
144         /*
145           request a netlogon challenge - a rpc request over opened secondary pipe
146         */
147         subreq = dcerpc_netr_ServerReqChallenge_r_send(s, c->event_ctx,
148                                                        s->pipe2->binding_handle,
149                                                        &s->r);
150         if (composite_nomem(subreq, c)) return;
151
152         tevent_req_set_callback(subreq, continue_srv_challenge, c);
153 }
154
155
156 /*
157   Stage 5 of schannel_key: Receive a challenge and perform authentication
158   on the netlogon pipe
159 */
160 static void continue_srv_challenge(struct tevent_req *subreq)
161 {
162         struct composite_context *c;
163         struct schannel_key_state *s;
164
165         c = tevent_req_callback_data(subreq, struct composite_context);
166         s = talloc_get_type(c->private_data, struct schannel_key_state);
167
168         /* receive rpc request result - netlogon challenge */
169         c->status = dcerpc_netr_ServerReqChallenge_r_recv(subreq, s);
170         TALLOC_FREE(subreq);
171         if (!composite_is_ok(c)) return;
172
173         /* prepare credentials for auth2 request */
174         s->mach_pwd = cli_credentials_get_nt_hash(s->credentials, c);
175
176         /* auth2 request arguments */
177         s->a.in.server_name      = s->r.in.server_name;
178         s->a.in.account_name     = cli_credentials_get_username(s->credentials);
179         s->a.in.secure_channel_type =
180                 cli_credentials_get_secure_channel_type(s->credentials);
181         s->a.in.computer_name    = cli_credentials_get_workstation(s->credentials);
182         s->a.in.negotiate_flags  = &s->local_negotiate_flags;
183         s->a.in.credentials      = &s->credentials3;
184         s->a.out.negotiate_flags = &s->remote_negotiate_flags;
185         s->a.out.return_credentials     = &s->credentials3;
186
187         s->creds = netlogon_creds_client_init(s, 
188                                               s->a.in.account_name, 
189                                               s->a.in.computer_name,
190                                               s->a.in.secure_channel_type,
191                                               &s->credentials1, &s->credentials2,
192                                               s->mach_pwd, &s->credentials3,
193                                               s->local_negotiate_flags);
194         if (composite_nomem(s->creds, c)) {
195                 return;
196         }
197         /*
198           authenticate on the netlogon pipe - a rpc request over secondary pipe
199         */
200         subreq = dcerpc_netr_ServerAuthenticate2_r_send(s, c->event_ctx,
201                                                         s->pipe2->binding_handle,
202                                                         &s->a);
203         if (composite_nomem(subreq, c)) return;
204
205         tevent_req_set_callback(subreq, continue_srv_auth2, c);
206 }
207
208
209 /*
210   Stage 6 of schannel_key: Receive authentication request result and verify
211   received credentials
212 */
213 static void continue_srv_auth2(struct tevent_req *subreq)
214 {
215         struct composite_context *c;
216         struct schannel_key_state *s;
217
218         c = tevent_req_callback_data(subreq, struct composite_context);
219         s = talloc_get_type(c->private_data, struct schannel_key_state);
220
221         /* receive rpc request result - auth2 credentials */ 
222         c->status = dcerpc_netr_ServerAuthenticate2_r_recv(subreq, s);
223         TALLOC_FREE(subreq);
224         if (!composite_is_ok(c)) return;
225
226         if (!NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED) &&
227             !NT_STATUS_IS_OK(s->a.out.result)) {
228                 composite_error(c, s->a.out.result);
229                 return;
230         }
231
232         /*
233          * Strong keys could be unsupported (NT4) or disables. So retry with the
234          * flags returned by the server. - asn
235          */
236         if (NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED)) {
237                 uint32_t lf = s->local_negotiate_flags;
238                 const char *ln = NULL;
239                 uint32_t rf = s->remote_negotiate_flags;
240                 const char *rn = NULL;
241
242                 if (!s->dcerpc_schannel_auto) {
243                         composite_error(c, s->a.out.result);
244                         return;
245                 }
246                 s->dcerpc_schannel_auto = false;
247
248                 if (lf & NETLOGON_NEG_SUPPORTS_AES)  {
249                         ln = "aes";
250                         if (rf & NETLOGON_NEG_SUPPORTS_AES) {
251                                 composite_error(c, s->a.out.result);
252                                 return;
253                         }
254                 } else if (lf & NETLOGON_NEG_STRONG_KEYS) {
255                         ln = "strong";
256                         if (rf & NETLOGON_NEG_STRONG_KEYS) {
257                                 composite_error(c, s->a.out.result);
258                                 return;
259                         }
260                 } else {
261                         ln = "des";
262                 }
263
264                 if (rf & NETLOGON_NEG_SUPPORTS_AES)  {
265                         rn = "aes";
266                 } else if (rf & NETLOGON_NEG_STRONG_KEYS) {
267                         rn = "strong";
268                 } else {
269                         rn = "des";
270                 }
271
272                 DEBUG(3, ("Server doesn't support %s keys, downgrade to %s"
273                           "and retry! local[0x%08X] remote[0x%08X]\n",
274                           ln, rn, lf, rf));
275
276                 s->local_negotiate_flags = s->remote_negotiate_flags;
277
278                 generate_random_buffer(s->credentials1.data,
279                                        sizeof(s->credentials1.data));
280
281                 subreq = dcerpc_netr_ServerReqChallenge_r_send(s,
282                                                                c->event_ctx,
283                                                                s->pipe2->binding_handle,
284                                                                &s->r);
285                 if (composite_nomem(subreq, c)) return;
286
287                 tevent_req_set_callback(subreq, continue_srv_challenge, c);
288                 return;
289         }
290
291         s->creds->negotiate_flags = s->remote_negotiate_flags;
292
293         /* verify credentials */
294         if (!netlogon_creds_client_check(s->creds, s->a.out.return_credentials)) {
295                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
296                 return;
297         }
298
299         /* setup current netlogon credentials */
300         cli_credentials_set_netlogon_creds(s->credentials, s->creds);
301
302         composite_done(c);
303 }
304
305 /*
306   Initiate establishing a schannel key using netlogon challenge
307   on a secondary pipe
308 */
309 struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
310                                                    struct dcerpc_pipe *p,
311                                                    struct cli_credentials *credentials,
312                                                    struct loadparm_context *lp_ctx)
313 {
314         struct composite_context *c;
315         struct schannel_key_state *s;
316         struct composite_context *epm_map_req;
317         enum netr_SchannelType schannel_type = cli_credentials_get_secure_channel_type(credentials);
318         
319         /* composite context allocation and setup */
320         c = composite_create(mem_ctx, p->conn->event_ctx);
321         if (c == NULL) return NULL;
322
323         s = talloc_zero(c, struct schannel_key_state);
324         if (composite_nomem(s, c)) return c;
325         c->private_data = s;
326
327         /* store parameters in the state structure */
328         s->pipe        = p;
329         s->credentials = credentials;
330         s->local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
331
332         /* allocate credentials */
333         if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
334                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
335         }
336         if (s->pipe->conn->flags & DCERPC_SCHANNEL_AES) {
337                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
338                 s->local_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
339         }
340         if (s->pipe->conn->flags & DCERPC_SCHANNEL_AUTO) {
341                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
342                 s->local_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
343                 s->dcerpc_schannel_auto = true;
344         }
345
346         /* type of authentication depends on schannel type */
347         if (schannel_type == SEC_CHAN_RODC) {
348                 s->local_negotiate_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
349         }
350
351         /* allocate binding structure */
352         s->binding = talloc_zero(c, struct dcerpc_binding);
353         if (composite_nomem(s->binding, c)) return c;
354
355         *s->binding = *s->pipe->binding;
356
357         /* request the netlogon endpoint mapping */
358         epm_map_req = dcerpc_epm_map_binding_send(c, s->binding,
359                                                   &ndr_table_netlogon,
360                                                   s->pipe->conn->event_ctx,
361                                                   lp_ctx);
362         if (composite_nomem(epm_map_req, c)) return c;
363
364         composite_continue(c, epm_map_req, continue_epm_map_binding, c);
365         return c;
366 }
367
368
369 /*
370   Receive result of schannel key request
371  */
372 NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c)
373 {
374         NTSTATUS status = composite_wait(c);
375         
376         talloc_free(c);
377         return status;
378 }
379
380
381 struct auth_schannel_state {
382         struct dcerpc_pipe *pipe;
383         struct cli_credentials *credentials;
384         const struct ndr_interface_table *table;
385         struct loadparm_context *lp_ctx;
386         uint8_t auth_level;
387         struct netlogon_creds_CredentialState *creds_state;
388         struct netr_Authenticator auth;
389         struct netr_Authenticator return_auth;
390         union netr_Capabilities capabilities;
391         struct netr_LogonGetCapabilities c;
392 };
393
394
395 static void continue_bind_auth(struct composite_context *ctx);
396
397
398 /*
399   Stage 2 of auth_schannel: Receive schannel key and intitiate an
400   authenticated bind using received credentials
401  */
402 static void continue_schannel_key(struct composite_context *ctx)
403 {
404         struct composite_context *auth_req;
405         struct composite_context *c = talloc_get_type(ctx->async.private_data,
406                                                       struct composite_context);
407         struct auth_schannel_state *s = talloc_get_type(c->private_data,
408                                                         struct auth_schannel_state);
409         NTSTATUS status;
410
411         /* receive schannel key */
412         status = c->status = dcerpc_schannel_key_recv(ctx);
413         if (!composite_is_ok(c)) {
414                 DEBUG(1, ("Failed to setup credentials: %s\n", nt_errstr(status)));
415                 return;
416         }
417
418         /* send bind auth request with received creds */
419         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, 
420                                          lpcfg_gensec_settings(c, s->lp_ctx),
421                                          DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level,
422                                          NULL);
423         if (composite_nomem(auth_req, c)) return;
424         
425         composite_continue(c, auth_req, continue_bind_auth, c);
426 }
427
428
429 /*
430   Stage 3 of auth_schannel: Receivce result of authenticated bind
431   and say if we're done ok.
432 */
433 static void continue_bind_auth(struct composite_context *ctx)
434 {
435         struct composite_context *c = talloc_get_type(ctx->async.private_data,
436                                                       struct composite_context);
437         struct auth_schannel_state *s = talloc_get_type(c->private_data,
438                                                         struct auth_schannel_state);
439         struct tevent_req *subreq;
440
441         c->status = dcerpc_bind_auth_recv(ctx);
442         if (!composite_is_ok(c)) return;
443
444         /* if we have a AES encrypted connection, verify the capabilities */
445         if (ndr_syntax_id_equal(&s->table->syntax_id,
446                                 &ndr_table_netlogon.syntax_id)) {
447                 ZERO_STRUCT(s->return_auth);
448
449                 s->creds_state = cli_credentials_get_netlogon_creds(s->credentials);
450                 if (composite_nomem(s->creds_state, c)) return;
451
452                 netlogon_creds_client_authenticator(s->creds_state, &s->auth);
453
454                 s->c.in.server_name = talloc_asprintf(c,
455                                                       "\\\\%s",
456                                                       dcerpc_server_name(s->pipe));
457                 if (composite_nomem(s->c.in.server_name, c)) return;
458                 s->c.in.computer_name         = cli_credentials_get_workstation(s->credentials);
459                 s->c.in.credential            = &s->auth;
460                 s->c.in.return_authenticator  = &s->return_auth;
461                 s->c.in.query_level           = 1;
462
463                 s->c.out.capabilities         = &s->capabilities;
464                 s->c.out.return_authenticator = &s->return_auth;
465
466                 DEBUG(5, ("We established a AES connection, verifying logon "
467                           "capabilities\n"));
468
469                 subreq = dcerpc_netr_LogonGetCapabilities_r_send(s,
470                                                                  c->event_ctx,
471                                                                  s->pipe->binding_handle,
472                                                                  &s->c);
473                 if (composite_nomem(subreq, c)) return;
474
475                 tevent_req_set_callback(subreq, continue_get_capabilities, c);
476                 return;
477         }
478
479         composite_done(c);
480 }
481
482 /*
483   Stage 4 of auth_schannel: Get the Logon Capablities and verify them.
484 */
485 static void continue_get_capabilities(struct tevent_req *subreq)
486 {
487         struct composite_context *c;
488         struct auth_schannel_state *s;
489
490         c = tevent_req_callback_data(subreq, struct composite_context);
491         s = talloc_get_type(c->private_data, struct auth_schannel_state);
492
493         /* receive rpc request result */
494         c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s);
495         TALLOC_FREE(subreq);
496         if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
497                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
498                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
499                         return;
500                 } else {
501                         /* This is probably NT */
502                         composite_done(c);
503                         return;
504                 }
505         } else if (!composite_is_ok(c)) {
506                 return;
507         }
508
509         if (NT_STATUS_EQUAL(s->c.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
510                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
511                         /* This means AES isn't supported. */
512                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
513                         return;
514                 }
515
516                 /* This is probably an old Samba version */
517                 composite_done(c);
518                 return;
519         }
520
521         /* verify credentials */
522         if (!netlogon_creds_client_check(s->creds_state,
523                                          &s->c.out.return_authenticator->cred)) {
524                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
525                 return;
526         }
527
528         if (!NT_STATUS_IS_OK(s->c.out.result)) {
529                 composite_error(c, s->c.out.result);
530                 return;
531         }
532
533         /* compare capabilities */
534         if (s->creds_state->negotiate_flags != s->capabilities.server_capabilities) {
535                 DEBUG(2, ("The client capabilities don't match the server "
536                           "capabilities: local[0x%08X] remote[0x%08X]\n",
537                           s->creds_state->negotiate_flags,
538                           s->capabilities.server_capabilities));
539                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
540                 return;
541         }
542
543         /* TODO: Add downgrade dectection. */
544
545         composite_done(c);
546 }
547
548
549 /*
550   Initiate schannel authentication request
551 */
552 struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, 
553                                                          struct dcerpc_pipe *p,
554                                                          const struct ndr_interface_table *table,
555                                                          struct cli_credentials *credentials,
556                                                          struct loadparm_context *lp_ctx,
557                                                          uint8_t auth_level)
558 {
559         struct composite_context *c;
560         struct auth_schannel_state *s;
561         struct composite_context *schan_key_req;
562
563         /* composite context allocation and setup */
564         c = composite_create(tmp_ctx, p->conn->event_ctx);
565         if (c == NULL) return NULL;
566         
567         s = talloc_zero(c, struct auth_schannel_state);
568         if (composite_nomem(s, c)) return c;
569         c->private_data = s;
570
571         /* store parameters in the state structure */
572         s->pipe        = p;
573         s->credentials = credentials;
574         s->table       = table;
575         s->auth_level  = auth_level;
576         s->lp_ctx      = lp_ctx;
577
578         /* start getting schannel key first */
579         schan_key_req = dcerpc_schannel_key_send(c, p, credentials, lp_ctx);
580         if (composite_nomem(schan_key_req, c)) return c;
581
582         composite_continue(c, schan_key_req, continue_schannel_key, c);
583         return c;
584 }
585
586
587 /*
588   Receive result of schannel authentication request
589 */
590 NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
591 {
592         NTSTATUS status = composite_wait(c);
593         
594         talloc_free(c);
595         return status;
596 }
597
598
599 /*
600   Perform schannel authenticated bind - sync version
601  */
602 _PUBLIC_ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, 
603                                    struct dcerpc_pipe *p,
604                                    const struct ndr_interface_table *table,
605                                    struct cli_credentials *credentials,
606                                    struct loadparm_context *lp_ctx,
607                                    uint8_t auth_level)
608 {
609         struct composite_context *c;
610
611         c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, lp_ctx,
612                                            auth_level);
613         return dcerpc_bind_auth_schannel_recv(c);
614 }