s4:librpc: make dcerpc_schannel_key_send/recv static
[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         /* 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 static 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 static 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 netlogon_creds_CredentialState save_creds_state;
389         struct netr_Authenticator auth;
390         struct netr_Authenticator return_auth;
391         union netr_Capabilities capabilities;
392         struct netr_LogonGetCapabilities c;
393 };
394
395
396 static void continue_bind_auth(struct composite_context *ctx);
397
398
399 /*
400   Stage 2 of auth_schannel: Receive schannel key and intitiate an
401   authenticated bind using received credentials
402  */
403 static void continue_schannel_key(struct composite_context *ctx)
404 {
405         struct composite_context *auth_req;
406         struct composite_context *c = talloc_get_type(ctx->async.private_data,
407                                                       struct composite_context);
408         struct auth_schannel_state *s = talloc_get_type(c->private_data,
409                                                         struct auth_schannel_state);
410         NTSTATUS status;
411
412         /* receive schannel key */
413         status = c->status = dcerpc_schannel_key_recv(ctx);
414         if (!composite_is_ok(c)) {
415                 DEBUG(1, ("Failed to setup credentials: %s\n", nt_errstr(status)));
416                 return;
417         }
418
419         /* send bind auth request with received creds */
420         auth_req = dcerpc_bind_auth_send(c, s->pipe, s->table, s->credentials, 
421                                          lpcfg_gensec_settings(c, s->lp_ctx),
422                                          DCERPC_AUTH_TYPE_SCHANNEL, s->auth_level,
423                                          NULL);
424         if (composite_nomem(auth_req, c)) return;
425         
426         composite_continue(c, auth_req, continue_bind_auth, c);
427 }
428
429
430 /*
431   Stage 3 of auth_schannel: Receivce result of authenticated bind
432   and say if we're done ok.
433 */
434 static void continue_bind_auth(struct composite_context *ctx)
435 {
436         struct composite_context *c = talloc_get_type(ctx->async.private_data,
437                                                       struct composite_context);
438         struct auth_schannel_state *s = talloc_get_type(c->private_data,
439                                                         struct auth_schannel_state);
440         struct tevent_req *subreq;
441
442         c->status = dcerpc_bind_auth_recv(ctx);
443         if (!composite_is_ok(c)) return;
444
445         /* if we have a AES encrypted connection, verify the capabilities */
446         if (ndr_syntax_id_equal(&s->table->syntax_id,
447                                 &ndr_table_netlogon.syntax_id)) {
448                 ZERO_STRUCT(s->return_auth);
449
450                 s->creds_state = cli_credentials_get_netlogon_creds(s->credentials);
451                 if (composite_nomem(s->creds_state, c)) return;
452
453                 s->save_creds_state = *s->creds_state;
454                 netlogon_creds_client_authenticator(&s->save_creds_state, &s->auth);
455
456                 s->c.in.server_name = talloc_asprintf(c,
457                                                       "\\\\%s",
458                                                       dcerpc_server_name(s->pipe));
459                 if (composite_nomem(s->c.in.server_name, c)) return;
460                 s->c.in.computer_name         = cli_credentials_get_workstation(s->credentials);
461                 s->c.in.credential            = &s->auth;
462                 s->c.in.return_authenticator  = &s->return_auth;
463                 s->c.in.query_level           = 1;
464
465                 s->c.out.capabilities         = &s->capabilities;
466                 s->c.out.return_authenticator = &s->return_auth;
467
468                 DEBUG(5, ("We established a AES connection, verifying logon "
469                           "capabilities\n"));
470
471                 subreq = dcerpc_netr_LogonGetCapabilities_r_send(s,
472                                                                  c->event_ctx,
473                                                                  s->pipe->binding_handle,
474                                                                  &s->c);
475                 if (composite_nomem(subreq, c)) return;
476
477                 tevent_req_set_callback(subreq, continue_get_capabilities, c);
478                 return;
479         }
480
481         composite_done(c);
482 }
483
484 /*
485   Stage 4 of auth_schannel: Get the Logon Capablities and verify them.
486 */
487 static void continue_get_capabilities(struct tevent_req *subreq)
488 {
489         struct composite_context *c;
490         struct auth_schannel_state *s;
491
492         c = tevent_req_callback_data(subreq, struct composite_context);
493         s = talloc_get_type(c->private_data, struct auth_schannel_state);
494
495         /* receive rpc request result */
496         c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s);
497         TALLOC_FREE(subreq);
498         if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
499                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
500                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
501                         return;
502                 } else {
503                         /* This is probably NT */
504                         composite_done(c);
505                         return;
506                 }
507         } else if (!composite_is_ok(c)) {
508                 return;
509         }
510
511         if (NT_STATUS_EQUAL(s->c.out.result, NT_STATUS_NOT_IMPLEMENTED)) {
512                 if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
513                         /* This means AES isn't supported. */
514                         composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
515                         return;
516                 }
517
518                 /* This is probably an old Samba version */
519                 composite_done(c);
520                 return;
521         }
522
523         /* verify credentials */
524         if (!netlogon_creds_client_check(&s->save_creds_state,
525                                          &s->c.out.return_authenticator->cred)) {
526                 composite_error(c, NT_STATUS_UNSUCCESSFUL);
527                 return;
528         }
529
530         *s->creds_state = s->save_creds_state;
531
532         if (!NT_STATUS_IS_OK(s->c.out.result)) {
533                 composite_error(c, s->c.out.result);
534                 return;
535         }
536
537         /* compare capabilities */
538         if (s->creds_state->negotiate_flags != s->capabilities.server_capabilities) {
539                 DEBUG(2, ("The client capabilities don't match the server "
540                           "capabilities: local[0x%08X] remote[0x%08X]\n",
541                           s->creds_state->negotiate_flags,
542                           s->capabilities.server_capabilities));
543                 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
544                 return;
545         }
546
547         /* TODO: Add downgrade dectection. */
548
549         composite_done(c);
550 }
551
552
553 /*
554   Initiate schannel authentication request
555 */
556 struct composite_context *dcerpc_bind_auth_schannel_send(TALLOC_CTX *tmp_ctx, 
557                                                          struct dcerpc_pipe *p,
558                                                          const struct ndr_interface_table *table,
559                                                          struct cli_credentials *credentials,
560                                                          struct loadparm_context *lp_ctx,
561                                                          uint8_t auth_level)
562 {
563         struct composite_context *c;
564         struct auth_schannel_state *s;
565         struct composite_context *schan_key_req;
566
567         /* composite context allocation and setup */
568         c = composite_create(tmp_ctx, p->conn->event_ctx);
569         if (c == NULL) return NULL;
570         
571         s = talloc_zero(c, struct auth_schannel_state);
572         if (composite_nomem(s, c)) return c;
573         c->private_data = s;
574
575         /* store parameters in the state structure */
576         s->pipe        = p;
577         s->credentials = credentials;
578         s->table       = table;
579         s->auth_level  = auth_level;
580         s->lp_ctx      = lp_ctx;
581
582         /* start getting schannel key first */
583         schan_key_req = dcerpc_schannel_key_send(c, p, credentials, lp_ctx);
584         if (composite_nomem(schan_key_req, c)) return c;
585
586         composite_continue(c, schan_key_req, continue_schannel_key, c);
587         return c;
588 }
589
590
591 /*
592   Receive result of schannel authentication request
593 */
594 NTSTATUS dcerpc_bind_auth_schannel_recv(struct composite_context *c)
595 {
596         NTSTATUS status = composite_wait(c);
597         
598         talloc_free(c);
599         return status;
600 }
601
602
603 /*
604   Perform schannel authenticated bind - sync version
605  */
606 _PUBLIC_ NTSTATUS dcerpc_bind_auth_schannel(TALLOC_CTX *tmp_ctx, 
607                                    struct dcerpc_pipe *p,
608                                    const struct ndr_interface_table *table,
609                                    struct cli_credentials *credentials,
610                                    struct loadparm_context *lp_ctx,
611                                    uint8_t auth_level)
612 {
613         struct composite_context *c;
614
615         c = dcerpc_bind_auth_schannel_send(tmp_ctx, p, table, credentials, lp_ctx,
616                                            auth_level);
617         return dcerpc_bind_auth_schannel_recv(c);
618 }