lib/crypto: move gnutls error wrapper to own subsystem
[samba.git] / auth / gensec / 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
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "librpc/gen_ndr/ndr_schannel.h"
27 #include "auth/auth.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "auth/gensec/gensec_proto.h"
32 #include "../libcli/auth/schannel.h"
33 #include "librpc/gen_ndr/dcerpc.h"
34 #include "param/param.h"
35 #include "auth/gensec/gensec_toplevel_proto.h"
36 #include "lib/crypto/crypto.h"
37 #include "libds/common/roles.h"
38
39 #include "lib/crypto/gnutls_helpers.h"
40 #include <gnutls/gnutls.h>
41 #include <gnutls/crypto.h>
42
43 #undef DBGC_CLASS
44 #define DBGC_CLASS DBGC_AUTH
45
46 struct schannel_state {
47         struct gensec_security *gensec;
48         uint64_t seq_num;
49         bool initiator;
50         struct netlogon_creds_CredentialState *creds;
51         struct auth_user_info_dc *user_info_dc;
52 };
53
54 #define SETUP_SEQNUM(state, buf, initiator) do { \
55         uint8_t *_buf = buf; \
56         uint32_t _seq_num_low = (state)->seq_num & UINT32_MAX; \
57         uint32_t _seq_num_high = (state)->seq_num >> 32; \
58         if (initiator) { \
59                 _seq_num_high |= 0x80000000; \
60         } \
61         RSIVAL(_buf, 0, _seq_num_low); \
62         RSIVAL(_buf, 4, _seq_num_high); \
63 } while(0)
64
65 static struct schannel_state *netsec_create_state(
66                                 struct gensec_security *gensec,
67                                 struct netlogon_creds_CredentialState *creds,
68                                 bool initiator)
69 {
70         struct schannel_state *state;
71
72         state = talloc_zero(gensec, struct schannel_state);
73         if (state == NULL) {
74                 return NULL;
75         }
76
77         state->gensec = gensec;
78         state->initiator = initiator;
79         state->creds = netlogon_creds_copy(state, creds);
80         if (state->creds == NULL) {
81                 talloc_free(state);
82                 return NULL;
83         }
84
85         gensec->private_data = state;
86
87         return state;
88 }
89
90 static void netsec_offset_and_sizes(struct schannel_state *state,
91                                     bool do_seal,
92                                     uint32_t *_min_sig_size,
93                                     uint32_t *_used_sig_size,
94                                     uint32_t *_checksum_length,
95                                     uint32_t *_confounder_ofs)
96 {
97         uint32_t min_sig_size;
98         uint32_t used_sig_size;
99         uint32_t checksum_length;
100         uint32_t confounder_ofs;
101
102         if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
103                 min_sig_size = 48;
104                 used_sig_size = 56;
105                 /*
106                  * Note: windows has a bug here and uses the old values...
107                  *
108                  * checksum_length = 32;
109                  * confounder_ofs = 48;
110                  */
111                 checksum_length = 8;
112                 confounder_ofs = 24;
113         } else {
114                 min_sig_size = 24;
115                 used_sig_size = 32;
116                 checksum_length = 8;
117                 confounder_ofs = 24;
118         }
119
120         if (do_seal) {
121                 min_sig_size += 8;
122         }
123
124         if (_min_sig_size) {
125                 *_min_sig_size = min_sig_size;
126         }
127
128         if (_used_sig_size) {
129                 *_used_sig_size = used_sig_size;
130         }
131
132         if (_checksum_length) {
133                 *_checksum_length = checksum_length;
134         }
135
136         if (_confounder_ofs) {
137                 *_confounder_ofs = confounder_ofs;
138         }
139 }
140
141 /*******************************************************************
142  Encode or Decode the sequence number (which is symmetric)
143  ********************************************************************/
144 static NTSTATUS netsec_do_seq_num(struct schannel_state *state,
145                                   const uint8_t *checksum,
146                                   uint32_t checksum_length,
147                                   uint8_t seq_num[8])
148 {
149         if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
150                 AES_KEY key;
151                 uint8_t iv[AES_BLOCK_SIZE];
152
153                 AES_set_encrypt_key(state->creds->session_key, 128, &key);
154                 ZERO_STRUCT(iv);
155                 memcpy(iv+0, checksum, 8);
156                 memcpy(iv+8, checksum, 8);
157
158                 aes_cfb8_encrypt(seq_num, seq_num, 8, &key, iv, AES_ENCRYPT);
159         } else {
160                 static const uint8_t zeros[4];
161                 uint8_t sequence_key[16];
162                 uint8_t digest1[16];
163                 int rc;
164
165                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
166                                       state->creds->session_key,
167                                       sizeof(state->creds->session_key),
168                                       zeros,
169                                       sizeof(zeros),
170                                       digest1);
171                 if (rc < 0) {
172                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
173                 }
174
175                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
176                                       digest1,
177                                       sizeof(digest1),
178                                       checksum,
179                                       checksum_length,
180                                       sequence_key);
181                 if (rc < 0) {
182                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
183                 }
184
185                 ZERO_ARRAY(digest1);
186
187                 arcfour_crypt(seq_num, sequence_key, 8);
188
189                 ZERO_ARRAY(sequence_key);
190         }
191
192         state->seq_num++;
193
194         return NT_STATUS_OK;
195 }
196
197 static void netsec_do_seal(struct schannel_state *state,
198                            const uint8_t seq_num[8],
199                            uint8_t confounder[8],
200                            uint8_t *data, uint32_t length,
201                            bool forward)
202 {
203         if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
204                 AES_KEY key;
205                 uint8_t iv[AES_BLOCK_SIZE];
206                 uint8_t sess_kf0[16];
207                 int i;
208
209                 for (i = 0; i < 16; i++) {
210                         sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
211                 }
212
213                 AES_set_encrypt_key(sess_kf0, 128, &key);
214                 ZERO_STRUCT(iv);
215                 memcpy(iv+0, seq_num, 8);
216                 memcpy(iv+8, seq_num, 8);
217
218                 if (forward) {
219                         aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_ENCRYPT);
220                         aes_cfb8_encrypt(data, data, length, &key, iv, AES_ENCRYPT);
221                 } else {
222                         aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_DECRYPT);
223                         aes_cfb8_encrypt(data, data, length, &key, iv, AES_DECRYPT);
224                 }
225         } else {
226                 uint8_t sealing_key[16];
227                 static const uint8_t zeros[4];
228                 uint8_t digest2[16];
229                 uint8_t sess_kf0[16];
230                 int rc;
231                 int i;
232
233                 for (i = 0; i < 16; i++) {
234                         sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
235                 }
236
237                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
238                                       sess_kf0,
239                                       sizeof(sess_kf0),
240                                       zeros,
241                                       4,
242                                       digest2);
243                 if (rc < 0) {
244                         ZERO_ARRAY(digest2);
245                         return;
246                 }
247
248                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
249                                       digest2,
250                                       sizeof(digest2),
251                                       seq_num,
252                                       8,
253                                       sealing_key);
254                 ZERO_ARRAY(digest2);
255                 if (rc < 0) {
256                         return;
257                 }
258
259                 arcfour_crypt(confounder, sealing_key, 8);
260                 arcfour_crypt(data, sealing_key, length);
261
262                 ZERO_ARRAY(sealing_key);
263         }
264 }
265
266 /*******************************************************************
267  Create a digest over the entire packet (including the data), and
268  MD5 it with the session key.
269  ********************************************************************/
270 static NTSTATUS netsec_do_sign(struct schannel_state *state,
271                                const uint8_t *confounder,
272                                const uint8_t *data, size_t length,
273                                uint8_t header[8],
274                                uint8_t *checksum)
275 {
276         if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
277                 gnutls_hmac_hd_t hmac_hnd = NULL;
278                 int rc;
279
280                 rc = gnutls_hmac_init(&hmac_hnd,
281                                       GNUTLS_MAC_SHA256,
282                                       state->creds->session_key,
283                                       sizeof(state->creds->session_key));
284                 if (rc < 0) {
285                         return NT_STATUS_NO_MEMORY;
286                 }
287
288                 if (confounder) {
289                         SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
290                         SSVAL(header, 2, NL_SEAL_AES128);
291                         SSVAL(header, 4, 0xFFFF);
292                         SSVAL(header, 6, 0x0000);
293
294                         rc = gnutls_hmac(hmac_hnd, header, 8);
295                         if (rc < 0) {
296                                 gnutls_hmac_deinit(hmac_hnd, NULL);
297                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
298                         }
299                         rc = gnutls_hmac(hmac_hnd, confounder, 8);
300                         if (rc < 0) {
301                                 gnutls_hmac_deinit(hmac_hnd, NULL);
302                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
303                         }
304                 } else {
305                         SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
306                         SSVAL(header, 2, NL_SEAL_NONE);
307                         SSVAL(header, 4, 0xFFFF);
308                         SSVAL(header, 6, 0x0000);
309
310                         rc = gnutls_hmac(hmac_hnd, header, 8);
311                         if (rc < 0) {
312                                 gnutls_hmac_deinit(hmac_hnd, NULL);
313                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
314                         }
315                 }
316
317                 rc = gnutls_hmac(hmac_hnd, data, length);
318                 if (rc < 0) {
319                         gnutls_hmac_deinit(hmac_hnd, NULL);
320                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
321                 }
322
323                 gnutls_hmac_deinit(hmac_hnd, checksum);
324         } else {
325                 uint8_t packet_digest[16];
326                 static const uint8_t zeros[4];
327                 gnutls_hash_hd_t hash_hnd = NULL;
328                 int rc;
329
330                 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
331                 if (rc < 0) {
332                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
333                 }
334
335                 rc = gnutls_hash(hash_hnd, zeros, sizeof(zeros));
336                 if (rc < 0) {
337                         gnutls_hash_deinit(hash_hnd, NULL);
338                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
339                 }
340                 if (confounder) {
341                         SSVAL(header, 0, NL_SIGN_HMAC_MD5);
342                         SSVAL(header, 2, NL_SEAL_RC4);
343                         SSVAL(header, 4, 0xFFFF);
344                         SSVAL(header, 6, 0x0000);
345
346                         rc = gnutls_hash(hash_hnd, header, 8);
347                         if (rc < 0) {
348                                 gnutls_hash_deinit(hash_hnd, NULL);
349                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
350                         }
351                         rc = gnutls_hash(hash_hnd, confounder, 8);
352                         if (rc < 0) {
353                                 gnutls_hash_deinit(hash_hnd, NULL);
354                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
355                         }
356                 } else {
357                         SSVAL(header, 0, NL_SIGN_HMAC_MD5);
358                         SSVAL(header, 2, NL_SEAL_NONE);
359                         SSVAL(header, 4, 0xFFFF);
360                         SSVAL(header, 6, 0x0000);
361
362                         rc = gnutls_hash(hash_hnd, header, 8);
363                         if (rc < 0) {
364                                 gnutls_hash_deinit(hash_hnd, NULL);
365                                 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
366                         }
367                 }
368                 rc = gnutls_hash(hash_hnd, data, length);
369                 if (rc < 0) {
370                         gnutls_hash_deinit(hash_hnd, NULL);
371                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
372                 }
373                 gnutls_hash_deinit(hash_hnd, packet_digest);
374
375                 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
376                                       state->creds->session_key,
377                                       sizeof(state->creds->session_key),
378                                       packet_digest,
379                                       sizeof(packet_digest),
380                                       checksum);
381                 ZERO_ARRAY(packet_digest);
382                 if (rc < 0) {
383                         return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
384                 }
385         }
386
387         return NT_STATUS_OK;
388 }
389
390 static NTSTATUS netsec_incoming_packet(struct schannel_state *state,
391                                 bool do_unseal,
392                                 uint8_t *data, size_t length,
393                                 const uint8_t *whole_pdu, size_t pdu_length,
394                                 const DATA_BLOB *sig)
395 {
396         uint32_t min_sig_size = 0;
397         uint8_t header[8];
398         uint8_t checksum[32];
399         uint32_t checksum_length = sizeof(checksum_length);
400         uint8_t _confounder[8];
401         uint8_t *confounder = NULL;
402         uint32_t confounder_ofs = 0;
403         uint8_t seq_num[8];
404         int ret;
405         const uint8_t *sign_data = NULL;
406         size_t sign_length = 0;
407         NTSTATUS status;
408
409         netsec_offset_and_sizes(state,
410                                 do_unseal,
411                                 &min_sig_size,
412                                 NULL,
413                                 &checksum_length,
414                                 &confounder_ofs);
415
416         if (sig->length < min_sig_size) {
417                 return NT_STATUS_ACCESS_DENIED;
418         }
419
420         if (do_unseal) {
421                 confounder = _confounder;
422                 memcpy(confounder, sig->data+confounder_ofs, 8);
423         } else {
424                 confounder = NULL;
425         }
426
427         SETUP_SEQNUM(state, seq_num, !state->initiator);
428
429         if (do_unseal) {
430                 netsec_do_seal(state, seq_num,
431                                confounder,
432                                data, length,
433                                false);
434         }
435
436         if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
437                 sign_data = whole_pdu;
438                 sign_length = pdu_length;
439         } else {
440                 sign_data = data;
441                 sign_length = length;
442         }
443
444         status = netsec_do_sign(state,
445                                 confounder,
446                                 sign_data,
447                                 sign_length,
448                                 header,
449                                 checksum);
450         if (!NT_STATUS_IS_OK(status)) {
451                 DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
452                 return NT_STATUS_ACCESS_DENIED;
453         }
454
455         ret = memcmp(checksum, sig->data+16, checksum_length);
456         if (ret != 0) {
457                 dump_data_pw("calc digest:", checksum, checksum_length);
458                 dump_data_pw("wire digest:", sig->data+16, checksum_length);
459                 return NT_STATUS_ACCESS_DENIED;
460         }
461
462         status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
463         if (!NT_STATUS_IS_OK(status)) {
464                 DBG_WARNING("netsec_do_seq_num failed: %s\n",
465                             nt_errstr(status));
466                 return status;
467         }
468
469         ZERO_ARRAY(checksum);
470
471         ret = memcmp(seq_num, sig->data+8, 8);
472         if (ret != 0) {
473                 dump_data_pw("calc seq num:", seq_num, 8);
474                 dump_data_pw("wire seq num:", sig->data+8, 8);
475                 return NT_STATUS_ACCESS_DENIED;
476         }
477
478         return NT_STATUS_OK;
479 }
480
481 static uint32_t netsec_outgoing_sig_size(struct schannel_state *state)
482 {
483         uint32_t sig_size = 0;
484
485         netsec_offset_and_sizes(state,
486                                 true,
487                                 NULL,
488                                 &sig_size,
489                                 NULL,
490                                 NULL);
491
492         return sig_size;
493 }
494
495 static NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
496                                 TALLOC_CTX *mem_ctx,
497                                 bool do_seal,
498                                 uint8_t *data, size_t length,
499                                 const uint8_t *whole_pdu, size_t pdu_length,
500                                 DATA_BLOB *sig)
501 {
502         uint32_t min_sig_size = 0;
503         uint32_t used_sig_size = 0;
504         uint8_t header[8];
505         uint8_t checksum[32];
506         uint32_t checksum_length = sizeof(checksum_length);
507         uint8_t _confounder[8];
508         uint8_t *confounder = NULL;
509         uint32_t confounder_ofs = 0;
510         uint8_t seq_num[8];
511         const uint8_t *sign_data = NULL;
512         size_t sign_length = 0;
513         NTSTATUS status;
514
515         netsec_offset_and_sizes(state,
516                                 do_seal,
517                                 &min_sig_size,
518                                 &used_sig_size,
519                                 &checksum_length,
520                                 &confounder_ofs);
521
522         SETUP_SEQNUM(state, seq_num, state->initiator);
523
524         if (do_seal) {
525                 confounder = _confounder;
526                 generate_random_buffer(confounder, 8);
527         } else {
528                 confounder = NULL;
529         }
530
531         if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
532                 sign_data = whole_pdu;
533                 sign_length = pdu_length;
534         } else {
535                 sign_data = data;
536                 sign_length = length;
537         }
538
539         status = netsec_do_sign(state,
540                                 confounder,
541                                 sign_data,
542                                 sign_length,
543                                 header,
544                                 checksum);
545         if (!NT_STATUS_IS_OK(status)) {
546                 DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
547                 return NT_STATUS_ACCESS_DENIED;
548         }
549
550         if (do_seal) {
551                 netsec_do_seal(state, seq_num,
552                                confounder,
553                                data, length,
554                                true);
555         }
556
557         status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
558         if (!NT_STATUS_IS_OK(status)) {
559                 DBG_WARNING("netsec_do_seq_num failed: %s\n",
560                             nt_errstr(status));
561                 return status;
562         }
563
564         (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
565
566         memcpy(sig->data, header, 8);
567         memcpy(sig->data+8, seq_num, 8);
568         memcpy(sig->data+16, checksum, checksum_length);
569
570         if (confounder) {
571                 memcpy(sig->data+confounder_ofs, confounder, 8);
572         }
573
574         dump_data_pw("signature:", sig->data+ 0, 8);
575         dump_data_pw("seq_num  :", sig->data+ 8, 8);
576         dump_data_pw("digest   :", sig->data+16, checksum_length);
577         dump_data_pw("confound :", sig->data+confounder_ofs, 8);
578
579         return NT_STATUS_OK;
580 }
581
582 _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx);
583
584 static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
585 {
586         struct schannel_state *state =
587                 talloc_get_type_abort(gensec_security->private_data,
588                 struct schannel_state);
589
590         return netsec_outgoing_sig_size(state);
591 }
592
593 struct schannel_update_state {
594         NTSTATUS status;
595         DATA_BLOB out;
596 };
597
598 static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
599                                          TALLOC_CTX *out_mem_ctx,
600                                          const DATA_BLOB in, DATA_BLOB *out);
601
602 static struct tevent_req *schannel_update_send(TALLOC_CTX *mem_ctx,
603                                                struct tevent_context *ev,
604                                                struct gensec_security *gensec_security,
605                                                const DATA_BLOB in)
606 {
607         struct tevent_req *req;
608         struct schannel_update_state *state = NULL;
609         NTSTATUS status;
610
611         req = tevent_req_create(mem_ctx, &state,
612                                 struct schannel_update_state);
613         if (req == NULL) {
614                 return NULL;
615         }
616
617         status = schannel_update_internal(gensec_security,
618                                           state, in,
619                                           &state->out);
620         state->status = status;
621         if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
622                 status = NT_STATUS_OK;
623         }
624         if (tevent_req_nterror(req, status)) {
625                 return tevent_req_post(req, ev);
626         }
627
628         tevent_req_done(req);
629         return tevent_req_post(req, ev);
630 }
631
632 static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
633                                          TALLOC_CTX *out_mem_ctx,
634                                          const DATA_BLOB in, DATA_BLOB *out)
635 {
636         struct schannel_state *state =
637                 talloc_get_type(gensec_security->private_data,
638                 struct schannel_state);
639         NTSTATUS status;
640         enum ndr_err_code ndr_err;
641         struct NL_AUTH_MESSAGE bind_schannel = {
642                 .Flags = 0,
643         };
644         struct NL_AUTH_MESSAGE bind_schannel_ack;
645         struct netlogon_creds_CredentialState *creds;
646         const char *workstation;
647         const char *domain;
648
649         *out = data_blob(NULL, 0);
650
651         if (gensec_security->dcerpc_auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
652                 switch (gensec_security->gensec_role) {
653                 case GENSEC_CLIENT:
654                         return NT_STATUS_INVALID_PARAMETER_MIX;
655                 case GENSEC_SERVER:
656                         return NT_STATUS_INVALID_PARAMETER;
657                 }
658                 return NT_STATUS_INTERNAL_ERROR;
659         }
660
661         switch (gensec_security->gensec_role) {
662         case GENSEC_CLIENT:
663                 if (state != NULL) {
664                         /* we could parse the bind ack, but we don't know what it is yet */
665                         return NT_STATUS_OK;
666                 }
667
668                 creds = cli_credentials_get_netlogon_creds(gensec_security->credentials);
669                 if (creds == NULL) {
670                         return NT_STATUS_INVALID_PARAMETER_MIX;
671                 }
672
673                 state = netsec_create_state(gensec_security,
674                                             creds, true /* initiator */);
675                 if (state == NULL) {
676                         return NT_STATUS_NO_MEMORY;
677                 }
678
679                 bind_schannel.MessageType = NL_NEGOTIATE_REQUEST;
680
681                 bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
682                                       NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
683                 bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
684                 bind_schannel.oem_netbios_computer.a = creds->computer_name;
685
686                 if (creds->secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
687                         bind_schannel.Flags |= NL_FLAG_UTF8_DNS_DOMAIN_NAME;
688                         bind_schannel.utf8_dns_domain.u = cli_credentials_get_realm(gensec_security->credentials);
689
690                         bind_schannel.Flags |= NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME;
691                         bind_schannel.utf8_netbios_computer.u = creds->computer_name;
692                 }
693
694                 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
695                                                (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
696                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
697                         status = ndr_map_error2ntstatus(ndr_err);
698                         DEBUG(3, ("Could not create schannel bind: %s\n",
699                                   nt_errstr(status)));
700                         return status;
701                 }
702
703                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
704         case GENSEC_SERVER:
705
706                 if (state != NULL) {
707                         /* no third leg on this protocol */
708                         return NT_STATUS_INVALID_PARAMETER;
709                 }
710
711                 /* parse the schannel startup blob */
712                 ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
713                         (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_MESSAGE);
714                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
715                         status = ndr_map_error2ntstatus(ndr_err);
716                         DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
717                                   nt_errstr(status)));
718                         return status;
719                 }
720
721                 if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME) {
722                         domain = bind_schannel.oem_netbios_domain.a;
723                         if (strcasecmp_m(domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)) != 0) {
724                                 DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
725                                           domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)));
726                                 return NT_STATUS_LOGON_FAILURE;
727                         }
728                 } else if (bind_schannel.Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME) {
729                         domain = bind_schannel.utf8_dns_domain.u;
730                         if (strcasecmp_m(domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)) != 0) {
731                                 DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
732                                           domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)));
733                                 return NT_STATUS_LOGON_FAILURE;
734                         }
735                 } else {
736                         DEBUG(3, ("Request for schannel to without domain\n"));
737                         return NT_STATUS_LOGON_FAILURE;
738                 }
739
740                 if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME) {
741                         workstation = bind_schannel.oem_netbios_computer.a;
742                 } else if (bind_schannel.Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME) {
743                         workstation = bind_schannel.utf8_netbios_computer.u;
744                 } else {
745                         DEBUG(3, ("Request for schannel to without netbios workstation\n"));
746                         return NT_STATUS_LOGON_FAILURE;
747                 }
748
749                 status = schannel_get_creds_state(out_mem_ctx,
750                                                   gensec_security->settings->lp_ctx,
751                                                   workstation, &creds);
752                 if (!NT_STATUS_IS_OK(status)) {
753                         DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
754                                   workstation, nt_errstr(status)));
755                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
756                                 return NT_STATUS_LOGON_FAILURE;
757                         }
758                         return status;
759                 }
760
761                 state = netsec_create_state(gensec_security,
762                                             creds, false /* not initiator */);
763                 if (state == NULL) {
764                         return NT_STATUS_NO_MEMORY;
765                 }
766
767                 status = auth_anonymous_user_info_dc(state,
768                                 lpcfg_netbios_name(gensec_security->settings->lp_ctx),
769                                 &state->user_info_dc);
770                 if (!NT_STATUS_IS_OK(status)) {
771                         return status;
772                 }
773
774                 bind_schannel_ack.MessageType = NL_NEGOTIATE_RESPONSE;
775                 bind_schannel_ack.Flags = 0;
776                 bind_schannel_ack.Buffer.dummy = 0x6c0000; /* actually I think
777                                                             * this does not have
778                                                             * any meaning here
779                                                             * - gd */
780
781                 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
782                                                (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
783                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
784                         status = ndr_map_error2ntstatus(ndr_err);
785                         DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
786                                   workstation, nt_errstr(status)));
787                         return status;
788                 }
789
790                 return NT_STATUS_OK;
791         }
792         return NT_STATUS_INVALID_PARAMETER;
793 }
794
795 static NTSTATUS schannel_update_recv(struct tevent_req *req,
796                                      TALLOC_CTX *out_mem_ctx,
797                                      DATA_BLOB *out)
798 {
799         struct schannel_update_state *state =
800                 tevent_req_data(req,
801                 struct schannel_update_state);
802         NTSTATUS status;
803
804         *out = data_blob_null;
805
806         if (tevent_req_is_nterror(req, &status)) {
807                 tevent_req_received(req);
808                 return status;
809         }
810
811         status = state->status;
812         talloc_steal(out_mem_ctx, state->out.data);
813         *out = state->out;
814         tevent_req_received(req);
815         return status;
816 }
817
818 /**
819  * Returns anonymous credentials for schannel, matching Win2k3.
820  *
821  */
822
823 static NTSTATUS schannel_session_info(struct gensec_security *gensec_security,
824                                       TALLOC_CTX *mem_ctx,
825                                       struct auth_session_info **_session_info)
826 {
827         struct schannel_state *state =
828                 talloc_get_type(gensec_security->private_data,
829                 struct schannel_state);
830         struct auth4_context *auth_ctx = gensec_security->auth_context;
831         struct auth_session_info *session_info = NULL;
832         uint32_t session_info_flags = 0;
833         NTSTATUS status;
834
835         if (auth_ctx == NULL) {
836                 DEBUG(0, ("Cannot generate a session_info without the auth_context\n"));
837                 return NT_STATUS_INTERNAL_ERROR;
838         }
839
840         if (auth_ctx->generate_session_info == NULL) {
841                 DEBUG(0, ("Cannot generate a session_info without the generate_session_info hook\n"));
842                 return NT_STATUS_INTERNAL_ERROR;
843         }
844
845         if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
846                 session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
847         }
848
849         session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
850
851         status = auth_ctx->generate_session_info(
852                                 auth_ctx,
853                                 mem_ctx,
854                                 state->user_info_dc,
855                                 state->user_info_dc->info->account_name,
856                                 session_info_flags,
857                                 &session_info);
858         if (!NT_STATUS_IS_OK(status)) {
859                 return status;
860         }
861
862         *_session_info = session_info;
863         return NT_STATUS_OK;
864 }
865
866 /*
867  * Reduce the attack surface by ensuring schannel is not availble when
868  * we are not a DC
869  */
870 static NTSTATUS schannel_server_start(struct gensec_security *gensec_security)
871 {
872         enum server_role server_role
873                 = lpcfg_server_role(gensec_security->settings->lp_ctx);
874
875         switch (server_role) {
876         case ROLE_DOMAIN_BDC:
877         case ROLE_DOMAIN_PDC:
878         case ROLE_ACTIVE_DIRECTORY_DC:
879                 return NT_STATUS_OK;
880         default:
881                 return NT_STATUS_NOT_IMPLEMENTED;
882         }
883 }
884
885 static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
886 {
887         return NT_STATUS_OK;
888 }
889
890 static bool schannel_have_feature(struct gensec_security *gensec_security,
891                                          uint32_t feature)
892 {
893         if (gensec_security->dcerpc_auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
894                 if (feature & GENSEC_FEATURE_SIGN) {
895                         return true;
896                 }
897         }
898         if (gensec_security->dcerpc_auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
899                 if (feature & GENSEC_FEATURE_SEAL) {
900                         return true;
901                 }
902         }
903         if (feature & GENSEC_FEATURE_DCE_STYLE) {
904                 return true;
905         }
906         if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
907                 return true;
908         }
909         return false;
910 }
911
912 /*
913   unseal a packet
914 */
915 static NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security,
916                                        uint8_t *data, size_t length,
917                                        const uint8_t *whole_pdu, size_t pdu_length,
918                                        const DATA_BLOB *sig)
919 {
920         struct schannel_state *state =
921                 talloc_get_type_abort(gensec_security->private_data,
922                 struct schannel_state);
923
924         return netsec_incoming_packet(state, true,
925                                       discard_const_p(uint8_t, data),
926                                       length,
927                                       whole_pdu, pdu_length,
928                                       sig);
929 }
930
931 /*
932   check the signature on a packet
933 */
934 static NTSTATUS schannel_check_packet(struct gensec_security *gensec_security,
935                                       const uint8_t *data, size_t length,
936                                       const uint8_t *whole_pdu, size_t pdu_length,
937                                       const DATA_BLOB *sig)
938 {
939         struct schannel_state *state =
940                 talloc_get_type_abort(gensec_security->private_data,
941                 struct schannel_state);
942
943         return netsec_incoming_packet(state, false,
944                                       discard_const_p(uint8_t, data),
945                                       length,
946                                       whole_pdu, pdu_length,
947                                       sig);
948 }
949 /*
950   seal a packet
951 */
952 static NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security,
953                                      TALLOC_CTX *mem_ctx,
954                                      uint8_t *data, size_t length,
955                                      const uint8_t *whole_pdu, size_t pdu_length,
956                                      DATA_BLOB *sig)
957 {
958         struct schannel_state *state =
959                 talloc_get_type_abort(gensec_security->private_data,
960                 struct schannel_state);
961
962         return netsec_outgoing_packet(state, mem_ctx, true,
963                                       data, length,
964                                       whole_pdu, pdu_length,
965                                       sig);
966 }
967
968 /*
969   sign a packet
970 */
971 static NTSTATUS schannel_sign_packet(struct gensec_security *gensec_security,
972                                      TALLOC_CTX *mem_ctx,
973                                      const uint8_t *data, size_t length,
974                                      const uint8_t *whole_pdu, size_t pdu_length,
975                                      DATA_BLOB *sig)
976 {
977         struct schannel_state *state =
978                 talloc_get_type_abort(gensec_security->private_data,
979                 struct schannel_state);
980
981         return netsec_outgoing_packet(state, mem_ctx, false,
982                                       discard_const_p(uint8_t, data),
983                                       length,
984                                       whole_pdu, pdu_length,
985                                       sig);
986 }
987
988 static const struct gensec_security_ops gensec_schannel_security_ops = {
989         .name           = "schannel",
990         .auth_type      = DCERPC_AUTH_TYPE_SCHANNEL,
991         .client_start   = schannel_client_start,
992         .server_start   = schannel_server_start,
993         .update_send    = schannel_update_send,
994         .update_recv    = schannel_update_recv,
995         .seal_packet    = schannel_seal_packet,
996         .sign_packet    = schannel_sign_packet,
997         .check_packet   = schannel_check_packet,
998         .unseal_packet  = schannel_unseal_packet,
999         .session_info   = schannel_session_info,
1000         .sig_size       = schannel_sig_size,
1001         .have_feature   = schannel_have_feature,
1002         .enabled        = true,
1003         .priority       = GENSEC_SCHANNEL
1004 };
1005
1006 _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx)
1007 {
1008         NTSTATUS ret;
1009         ret = gensec_register(ctx, &gensec_schannel_security_ops);
1010         if (!NT_STATUS_IS_OK(ret)) {
1011                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1012                         gensec_schannel_security_ops.name));
1013                 return ret;
1014         }
1015
1016         return ret;
1017 }