s4:librpc: let dcerpc_schannel_key_recv() return netlogon_creds_CredentialState
[mat/samba.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         composite_done(c);
300 }
301
302 /*
303   Initiate establishing a schannel key using netlogon challenge
304   on a secondary pipe
305 */
306 static struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx,
307                                                    struct dcerpc_pipe *p,
308                                                    struct cli_credentials *credentials,
309                                                    struct loadparm_context *lp_ctx)
310 {
311         struct composite_context *c;
312         struct schannel_key_state *s;
313         struct composite_context *epm_map_req;
314         enum netr_SchannelType schannel_type = cli_credentials_get_secure_channel_type(credentials);
315         
316         /* composite context allocation and setup */
317         c = composite_create(mem_ctx, p->conn->event_ctx);
318         if (c == NULL) return NULL;
319
320         s = talloc_zero(c, struct schannel_key_state);
321         if (composite_nomem(s, c)) return c;
322         c->private_data = s;
323
324         /* store parameters in the state structure */
325         s->pipe        = p;
326         s->credentials = credentials;
327         s->local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
328
329         /* allocate credentials */
330         if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) {
331                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
332         }
333         if (s->pipe->conn->flags & DCERPC_SCHANNEL_AES) {
334                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
335                 s->local_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
336         }
337         if (s->pipe->conn->flags & DCERPC_SCHANNEL_AUTO) {
338                 s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
339                 s->local_negotiate_flags |= NETLOGON_NEG_SUPPORTS_AES;
340                 s->dcerpc_schannel_auto = true;
341         }
342
343         /* type of authentication depends on schannel type */
344         if (schannel_type == SEC_CHAN_RODC) {
345                 s->local_negotiate_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
346         }
347
348         /* allocate binding structure */
349         s->binding = talloc_zero(c, struct dcerpc_binding);
350         if (composite_nomem(s->binding, c)) return c;
351
352         *s->binding = *s->pipe->binding;
353
354         /* request the netlogon endpoint mapping */
355         epm_map_req = dcerpc_epm_map_binding_send(c, s->binding,
356                                                   &ndr_table_netlogon,
357                                                   s->pipe->conn->event_ctx,
358                                                   lp_ctx);
359         if (composite_nomem(epm_map_req, c)) return c;
360
361         composite_continue(c, epm_map_req, continue_epm_map_binding, c);
362         return c;
363 }
364
365
366 /*
367   Receive result of schannel key request
368  */
369 static NTSTATUS dcerpc_schannel_key_recv(struct composite_context *c,
370                                 TALLOC_CTX *mem_ctx,
371                                 struct netlogon_creds_CredentialState **creds)
372 {
373         NTSTATUS status = composite_wait(c);
374
375         if (NT_STATUS_IS_OK(status)) {
376                 struct schannel_key_state *s =
377                         talloc_get_type_abort(c->private_data,
378                         struct schannel_key_state);
379                 *creds = talloc_move(mem_ctx, &s->creds);
380         }
381
382         talloc_free(c);
383         return status;
384 }
385
386
387 struct auth_schannel_state {
388         struct dcerpc_pipe *pipe;
389         struct cli_credentials *credentials;
390         const struct ndr_interface_table *table;
391         struct loadparm_context *lp_ctx;
392         uint8_t auth_level;
393         struct netlogon_creds_CredentialState *creds_state;
394         struct netlogon_creds_CredentialState save_creds_state;
395         struct netr_Authenticator auth;
396         struct netr_Authenticator return_auth;
397         union netr_Capabilities capabilities;
398         struct netr_LogonGetCapabilities c;
399 };
400
401
402 static void continue_bind_auth(struct composite_context *ctx);
403
404
405 /*
406   Stage 2 of auth_schannel: Receive schannel key and intitiate an
407   authenticated bind using received credentials
408  */
409 static void continue_schannel_key(struct composite_context *ctx)
410 {
411         struct composite_context *auth_req;
412         struct composite_context *c = talloc_get_type(ctx->async.private_data,
413                                                       struct composite_context);
414         struct auth_schannel_state *s = talloc_get_type(c->private_data,
415                                                         struct auth_schannel_state);
416         NTSTATUS status;
417
418         /* receive schannel key */
419         status = c->status = dcerpc_schannel_key_recv(ctx, s, &s->creds_state);
420         if (!composite_is_ok(c)) {
421                 DEBUG(1, ("Failed to setup credentials: %s\n", nt_errstr(status)));
422                 return;
423         }
424
425         /* send bind auth request with received creds */
426         cli_credentials_set_netlogon_creds(s->credentials, s->creds_state);
427
428         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, 
429                                          lpcfg_gensec_settings(c, s->lp_ctx),
430                                          DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level,
431                                          NULL);
432         if (composite_nomem(auth_req, c)) return;
433         
434         composite_continue(c, auth_req, continue_bind_auth, c);
435 }
436
437
438 /*
439   Stage 3 of auth_schannel: Receivce result of authenticated bind
440   and say if we're done ok.
441 */
442 static void continue_bind_auth(struct composite_context *ctx)
443 {
444         struct composite_context *c = talloc_get_type(ctx->async.private_data,
445                                                       struct composite_context);
446         struct auth_schannel_state *s = talloc_get_type(c->private_data,
447                                                         struct auth_schannel_state);
448         struct tevent_req *subreq;
449
450         c->status = dcerpc_bind_auth_recv(ctx);
451         if (!composite_is_ok(c)) return;
452
453         /* if we have a AES encrypted connection, verify the capabilities */
454         if (ndr_syntax_id_equal(&s->table->syntax_id,
455                                 &ndr_table_netlogon.syntax_id)) {
456                 ZERO_STRUCT(s->return_auth);
457
458                 s->save_creds_state = *s->creds_state;
459                 netlogon_creds_client_authenticator(&s->save_creds_state, &s->auth);
460
461                 s->c.in.server_name = talloc_asprintf(c,
462                                                       "\\\\%s",
463                                                       dcerpc_server_name(s->pipe));
464                 if (composite_nomem(s->c.in.server_name, c)) return;
465                 s->c.in.computer_name         = cli_credentials_get_workstation(s->credentials);
466                 s->c.in.credential            = &s->auth;
467                 s->c.in.return_authenticator  = &s->return_auth;
468                 s->c.in.query_level           = 1;
469
470                 s->c.out.capabilities         = &s->capabilities;
471                 s->c.out.return_authenticator = &s->return_auth;
472
473                 DEBUG(5, ("We established a AES connection, verifying logon "
474                           "capabilities\n"));
475
476                 subreq = dcerpc_netr_LogonGetCapabilities_r_send(s,
477                                                                  c->event_ctx,
478                                                                  s->pipe->binding_handle,
479                                                                  &s->c);
480                 if (composite_nomem(subreq, c)) return;
481
482                 tevent_req_set_callback(subreq, continue_get_capabilities, c);
483                 return;
484         }
485
486         composite_done(c);
487 }
488
489 /*
490   Stage 4 of auth_schannel: Get the Logon Capablities and verify them.
491 */
492 static void continue_get_capabilities(struct tevent_req *subreq)
493 {
494         struct composite_context *c;
495         struct auth_schannel_state *s;
496
497         c = tevent_req_callback_data(subreq, struct composite_context);
498         s = talloc_get_type(c->private_data, struct auth_schannel_state);
499
500         /* receive rpc request result */
501         c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s);
502         TALLOC_FREE(subreq);
503         if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
504                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
505                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
506                         return;
507                 } else {
508                         /* This is probably NT */
509                         composite_done(c);
510                         return;
511                 }
512         } else if (!composite_is_ok(c)) {
513                 return;
514         }
515
516         if (NT_STATUS_EQUAL(s->c.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
517                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
518                         /* This means AES isn't supported. */
519                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
520                         return;
521                 }
522
523                 /* This is probably an old Samba version */
524                 composite_done(c);
525                 return;
526         }
527
528         /* verify credentials */
529         if (!netlogon_creds_client_check(&s->save_creds_state,
530                                          &s->c.out.return_authenticator->cred)) {
531                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
532                 return;
533         }
534
535         *s->creds_state = s->save_creds_state;
536         cli_credentials_set_netlogon_creds(s->credentials, s->creds_state);
537
538         if (!NT_STATUS_IS_OK(s->c.out.result)) {
539                 composite_error(c, s->c.out.result);
540                 return;
541         }
542
543         /* compare capabilities */
544         if (s->creds_state->negotiate_flags != s->capabilities.server_capabilities) {
545                 DEBUG(2, ("The client capabilities don't match the server "
546                           "capabilities: local[0x%08X] remote[0x%08X]\n",
547                           s->creds_state->negotiate_flags,
548                           s->capabilities.server_capabilities));
549                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
550                 return;
551         }
552
553         /* TODO: Add downgrade dectection. */
554
555         composite_done(c);
556 }
557
558
559 /*
560   Initiate schannel authentication request
561 */
562 struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, 
563                                                          struct dcerpc_pipe *p,
564                                                          const struct ndr_interface_table *table,
565                                                          struct cli_credentials *credentials,
566                                                          struct loadparm_context *lp_ctx,
567                                                          uint8_t auth_level)
568 {
569         struct composite_context *c;
570         struct auth_schannel_state *s;
571         struct composite_context *schan_key_req;
572
573         /* composite context allocation and setup */
574         c = composite_create(tmp_ctx, p->conn->event_ctx);
575         if (c == NULL) return NULL;
576         
577         s = talloc_zero(c, struct auth_schannel_state);
578         if (composite_nomem(s, c)) return c;
579         c->private_data = s;
580
581         /* store parameters in the state structure */
582         s->pipe        = p;
583         s->credentials = credentials;
584         s->table       = table;
585         s->auth_level  = auth_level;
586         s->lp_ctx      = lp_ctx;
587
588         /* start getting schannel key first */
589         schan_key_req = dcerpc_schannel_key_send(c, p, credentials, lp_ctx);
590         if (composite_nomem(schan_key_req, c)) return c;
591
592         composite_continue(c, schan_key_req, continue_schannel_key, c);
593         return c;
594 }
595
596
597 /*
598   Receive result of schannel authentication request
599 */
600 NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
601 {
602         NTSTATUS status = composite_wait(c);
603         
604         talloc_free(c);
605         return status;
606 }
607
608
609 /*
610   Perform schannel authenticated bind - sync version
611  */
612 _PUBLIC_ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, 
613                                    struct dcerpc_pipe *p,
614                                    const struct ndr_interface_table *table,
615                                    struct cli_credentials *credentials,
616                                    struct loadparm_context *lp_ctx,
617                                    uint8_t auth_level)
618 {
619         struct composite_context *c;
620
621         c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, lp_ctx,
622                                            auth_level);
623         return dcerpc_bind_auth_schannel_recv(c);
624 }