Line data Source code
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 "libds/common/roles.h"
37 :
38 : #include "lib/crypto/gnutls_helpers.h"
39 : #include <gnutls/gnutls.h>
40 : #include <gnutls/crypto.h>
41 :
42 : #undef DBGC_CLASS
43 : #define DBGC_CLASS DBGC_AUTH
44 :
45 : struct schannel_state {
46 : struct gensec_security *gensec;
47 : uint64_t seq_num;
48 : bool initiator;
49 : struct netlogon_creds_CredentialState *creds;
50 : struct auth_user_info_dc *user_info_dc;
51 : };
52 :
53 : #define SETUP_SEQNUM(state, buf, initiator) do { \
54 : uint8_t *_buf = buf; \
55 : uint32_t _seq_num_low = (state)->seq_num & UINT32_MAX; \
56 : uint32_t _seq_num_high = (state)->seq_num >> 32; \
57 : if (initiator) { \
58 : _seq_num_high |= 0x80000000; \
59 : } \
60 : RSIVAL(_buf, 0, _seq_num_low); \
61 : RSIVAL(_buf, 4, _seq_num_high); \
62 : } while(0)
63 :
64 4947 : static struct schannel_state *netsec_create_state(
65 : struct gensec_security *gensec,
66 : struct netlogon_creds_CredentialState *creds,
67 : bool initiator)
68 : {
69 640 : struct schannel_state *state;
70 :
71 4947 : state = talloc_zero(gensec, struct schannel_state);
72 4947 : if (state == NULL) {
73 0 : return NULL;
74 : }
75 :
76 4947 : state->gensec = gensec;
77 4947 : state->initiator = initiator;
78 4947 : state->creds = netlogon_creds_copy(state, creds);
79 4947 : if (state->creds == NULL) {
80 0 : talloc_free(state);
81 0 : return NULL;
82 : }
83 :
84 4947 : gensec->private_data = state;
85 :
86 4947 : return state;
87 : }
88 :
89 147025 : static void netsec_offset_and_sizes(struct schannel_state *state,
90 : bool do_seal,
91 : uint32_t *_min_sig_size,
92 : uint32_t *_used_sig_size,
93 : uint32_t *_checksum_length,
94 : uint32_t *_confounder_ofs)
95 : {
96 16044 : uint32_t min_sig_size;
97 16044 : uint32_t used_sig_size;
98 16044 : uint32_t checksum_length;
99 16044 : uint32_t confounder_ofs;
100 :
101 147025 : if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
102 69025 : min_sig_size = 48;
103 69025 : used_sig_size = 56;
104 : /*
105 : * Note: windows has a bug here and uses the old values...
106 : *
107 : * checksum_length = 32;
108 : * confounder_ofs = 48;
109 : */
110 69025 : checksum_length = 8;
111 69025 : confounder_ofs = 24;
112 : } else {
113 67260 : min_sig_size = 24;
114 67260 : used_sig_size = 32;
115 67260 : checksum_length = 8;
116 67260 : confounder_ofs = 24;
117 : }
118 :
119 136329 : if (do_seal) {
120 110543 : min_sig_size += 8;
121 : }
122 :
123 147025 : if (_min_sig_size) {
124 97996 : *_min_sig_size = min_sig_size;
125 : }
126 :
127 147025 : if (_used_sig_size) {
128 98058 : *_used_sig_size = used_sig_size;
129 : }
130 :
131 147025 : if (_checksum_length) {
132 97996 : *_checksum_length = checksum_length;
133 : }
134 :
135 147025 : if (_confounder_ofs) {
136 97996 : *_confounder_ofs = confounder_ofs;
137 : }
138 130981 : }
139 :
140 : /*******************************************************************
141 : Encode or Decode the sequence number (which is symmetric)
142 : ********************************************************************/
143 97996 : static NTSTATUS netsec_do_seq_num(struct schannel_state *state,
144 : const uint8_t *checksum,
145 : uint32_t checksum_length,
146 : uint8_t seq_num[8])
147 : {
148 97996 : if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
149 53170 : gnutls_cipher_hd_t cipher_hnd = NULL;
150 53170 : gnutls_datum_t key = {
151 53170 : .data = state->creds->session_key,
152 : .size = sizeof(state->creds->session_key),
153 : };
154 7160 : uint32_t iv_size =
155 53170 : gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
156 53170 : uint8_t _iv[iv_size];
157 53170 : gnutls_datum_t iv = {
158 : .data = _iv,
159 : .size = iv_size,
160 : };
161 7160 : int rc;
162 :
163 53170 : ZERO_ARRAY(_iv);
164 :
165 53170 : memcpy(iv.data + 0, checksum, 8);
166 53170 : memcpy(iv.data + 8, checksum, 8);
167 :
168 53170 : rc = gnutls_cipher_init(&cipher_hnd,
169 : GNUTLS_CIPHER_AES_128_CFB8,
170 : &key,
171 : &iv);
172 53170 : if (rc < 0) {
173 0 : return gnutls_error_to_ntstatus(rc,
174 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
175 : }
176 :
177 53170 : rc = gnutls_cipher_encrypt(cipher_hnd, seq_num, 8);
178 53170 : gnutls_cipher_deinit(cipher_hnd);
179 53170 : if (rc < 0) {
180 0 : return gnutls_error_to_ntstatus(rc,
181 : NT_STATUS_CRYPTO_SYSTEM_INVALID);
182 : }
183 :
184 : } else {
185 3536 : static const uint8_t zeros[4];
186 3536 : uint8_t _sequence_key[16];
187 3536 : gnutls_cipher_hd_t cipher_hnd;
188 44826 : gnutls_datum_t sequence_key = {
189 : .data = _sequence_key,
190 : .size = sizeof(_sequence_key),
191 : };
192 3536 : uint8_t digest1[16];
193 3536 : int rc;
194 :
195 48362 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
196 44826 : state->creds->session_key,
197 : sizeof(state->creds->session_key),
198 : zeros,
199 : sizeof(zeros),
200 : digest1);
201 44826 : if (rc < 0) {
202 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
203 : }
204 :
205 44826 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
206 : digest1,
207 : sizeof(digest1),
208 : checksum,
209 : checksum_length,
210 : _sequence_key);
211 44826 : ZERO_ARRAY(digest1);
212 44826 : if (rc < 0) {
213 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
214 : }
215 :
216 44826 : rc = gnutls_cipher_init(&cipher_hnd,
217 : GNUTLS_CIPHER_ARCFOUR_128,
218 : &sequence_key,
219 : NULL);
220 44826 : if (rc < 0) {
221 0 : ZERO_ARRAY(_sequence_key);
222 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
223 : }
224 :
225 44826 : rc = gnutls_cipher_encrypt(cipher_hnd,
226 : seq_num,
227 : 8);
228 44826 : gnutls_cipher_deinit(cipher_hnd);
229 44826 : ZERO_ARRAY(_sequence_key);
230 44826 : if (rc < 0) {
231 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
232 : }
233 : }
234 :
235 97996 : state->seq_num++;
236 :
237 97996 : return NT_STATUS_OK;
238 : }
239 :
240 69722 : static NTSTATUS netsec_do_seal(struct schannel_state *state,
241 : const uint8_t seq_num[8],
242 : uint8_t confounder[8],
243 : uint8_t *data, uint32_t length,
244 : bool forward)
245 : {
246 69722 : if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
247 33974 : gnutls_cipher_hd_t cipher_hnd = NULL;
248 33974 : uint8_t sess_kf0[16] = {0};
249 33974 : gnutls_datum_t key = {
250 : .data = sess_kf0,
251 : .size = sizeof(sess_kf0),
252 : };
253 3756 : uint32_t iv_size =
254 33974 : gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
255 33974 : uint8_t _iv[iv_size];
256 33974 : gnutls_datum_t iv = {
257 : .data = _iv,
258 : .size = iv_size,
259 : };
260 3756 : uint32_t i;
261 3756 : int rc;
262 :
263 577558 : for (i = 0; i < key.size; i++) {
264 543584 : key.data[i] = state->creds->session_key[i] ^ 0xf0;
265 : }
266 :
267 33974 : ZERO_ARRAY(_iv);
268 :
269 33974 : memcpy(iv.data + 0, seq_num, 8);
270 33974 : memcpy(iv.data + 8, seq_num, 8);
271 :
272 33974 : rc = gnutls_cipher_init(&cipher_hnd,
273 : GNUTLS_CIPHER_AES_128_CFB8,
274 : &key,
275 : &iv);
276 33974 : if (rc < 0) {
277 0 : DBG_ERR("ERROR: gnutls_cipher_init: %s\n",
278 : gnutls_strerror(rc));
279 0 : return NT_STATUS_NO_MEMORY;
280 : }
281 :
282 33974 : if (forward) {
283 16985 : rc = gnutls_cipher_encrypt(cipher_hnd,
284 : confounder,
285 : 8);
286 16985 : if (rc < 0) {
287 0 : gnutls_cipher_deinit(cipher_hnd);
288 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
289 : }
290 :
291 16985 : rc = gnutls_cipher_encrypt(cipher_hnd,
292 : data,
293 : length);
294 16985 : if (rc < 0) {
295 0 : gnutls_cipher_deinit(cipher_hnd);
296 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
297 : }
298 : } else {
299 :
300 : /*
301 : * Workaround bug present in gnutls 3.6.8:
302 : *
303 : * gnutls_cipher_decrypt() uses an optimization
304 : * internally that breaks decryption when processing
305 : * buffers with their length not being a multiple
306 : * of the blocksize.
307 : */
308 :
309 16989 : uint8_t tmp[16] = { 0, };
310 16989 : uint32_t tmp_dlength = MIN(length, sizeof(tmp) - 8);
311 :
312 16989 : memcpy(tmp, confounder, 8);
313 16989 : memcpy(tmp + 8, data, tmp_dlength);
314 :
315 18867 : rc = gnutls_cipher_decrypt(cipher_hnd,
316 : tmp,
317 16989 : 8 + tmp_dlength);
318 16989 : if (rc < 0) {
319 0 : ZERO_STRUCT(tmp);
320 0 : gnutls_cipher_deinit(cipher_hnd);
321 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
322 : }
323 :
324 16989 : memcpy(confounder, tmp, 8);
325 16989 : memcpy(data, tmp + 8, tmp_dlength);
326 16989 : ZERO_STRUCT(tmp);
327 :
328 16989 : if (length > tmp_dlength) {
329 18857 : rc = gnutls_cipher_decrypt(cipher_hnd,
330 16984 : data + tmp_dlength,
331 16984 : length - tmp_dlength);
332 16984 : if (rc < 0) {
333 0 : gnutls_cipher_deinit(cipher_hnd);
334 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
335 : }
336 : }
337 : }
338 33974 : gnutls_cipher_deinit(cipher_hnd);
339 : } else {
340 1924 : gnutls_cipher_hd_t cipher_hnd;
341 1924 : uint8_t _sealing_key[16];
342 35748 : gnutls_datum_t sealing_key = {
343 : .data = _sealing_key,
344 : .size = sizeof(_sealing_key),
345 : };
346 1924 : static const uint8_t zeros[4];
347 1924 : uint8_t digest2[16];
348 1924 : uint8_t sess_kf0[16];
349 1924 : int rc;
350 1924 : int i;
351 :
352 607716 : for (i = 0; i < 16; i++) {
353 571968 : sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
354 : }
355 :
356 35748 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
357 : sess_kf0,
358 : sizeof(sess_kf0),
359 : zeros,
360 : 4,
361 : digest2);
362 35748 : if (rc < 0) {
363 0 : ZERO_ARRAY(digest2);
364 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
365 : }
366 :
367 35748 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
368 : digest2,
369 : sizeof(digest2),
370 : seq_num,
371 : 8,
372 : _sealing_key);
373 :
374 35748 : ZERO_ARRAY(digest2);
375 35748 : if (rc < 0) {
376 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
377 : }
378 :
379 35748 : rc = gnutls_cipher_init(&cipher_hnd,
380 : GNUTLS_CIPHER_ARCFOUR_128,
381 : &sealing_key,
382 : NULL);
383 35748 : if (rc < 0) {
384 0 : ZERO_ARRAY(_sealing_key);
385 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
386 : }
387 35748 : rc = gnutls_cipher_encrypt(cipher_hnd,
388 : confounder,
389 : 8);
390 35748 : if (rc < 0) {
391 0 : ZERO_ARRAY(_sealing_key);
392 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
393 : }
394 35748 : gnutls_cipher_deinit(cipher_hnd);
395 35748 : rc = gnutls_cipher_init(&cipher_hnd,
396 : GNUTLS_CIPHER_ARCFOUR_128,
397 : &sealing_key,
398 : NULL);
399 35748 : if (rc < 0) {
400 0 : ZERO_ARRAY(_sealing_key);
401 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
402 : }
403 35748 : rc = gnutls_cipher_encrypt(cipher_hnd,
404 : data,
405 : length);
406 35748 : gnutls_cipher_deinit(cipher_hnd);
407 35748 : ZERO_ARRAY(_sealing_key);
408 35748 : if (rc < 0) {
409 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
410 : }
411 : }
412 :
413 69722 : return NT_STATUS_OK;
414 : }
415 :
416 : /*******************************************************************
417 : Create a digest over the entire packet (including the data), and
418 : MD5 it with the session key.
419 : ********************************************************************/
420 97996 : static NTSTATUS netsec_do_sign(struct schannel_state *state,
421 : const uint8_t *confounder,
422 : const uint8_t *data, size_t length,
423 : uint8_t header[8],
424 : uint8_t *checksum)
425 : {
426 97996 : if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
427 53170 : gnutls_hmac_hd_t hmac_hnd = NULL;
428 7160 : int rc;
429 :
430 60330 : rc = gnutls_hmac_init(&hmac_hnd,
431 : GNUTLS_MAC_SHA256,
432 53170 : state->creds->session_key,
433 : sizeof(state->creds->session_key));
434 53170 : if (rc < 0) {
435 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
436 : }
437 :
438 53170 : if (confounder) {
439 33954 : SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
440 33954 : SSVAL(header, 2, NL_SEAL_AES128);
441 33954 : SSVAL(header, 4, 0xFFFF);
442 33954 : SSVAL(header, 6, 0x0000);
443 :
444 33954 : rc = gnutls_hmac(hmac_hnd, header, 8);
445 33954 : if (rc < 0) {
446 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
447 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
448 : }
449 33954 : rc = gnutls_hmac(hmac_hnd, confounder, 8);
450 33954 : if (rc < 0) {
451 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
452 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
453 : }
454 : } else {
455 19216 : SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
456 19216 : SSVAL(header, 2, NL_SEAL_NONE);
457 19216 : SSVAL(header, 4, 0xFFFF);
458 19216 : SSVAL(header, 6, 0x0000);
459 :
460 19216 : rc = gnutls_hmac(hmac_hnd, header, 8);
461 19216 : if (rc < 0) {
462 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
463 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
464 : }
465 : }
466 :
467 53170 : rc = gnutls_hmac(hmac_hnd, data, length);
468 53170 : if (rc < 0) {
469 0 : gnutls_hmac_deinit(hmac_hnd, NULL);
470 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
471 : }
472 :
473 53170 : gnutls_hmac_deinit(hmac_hnd, checksum);
474 : } else {
475 3536 : uint8_t packet_digest[16];
476 3536 : static const uint8_t zeros[4];
477 44826 : gnutls_hash_hd_t hash_hnd = NULL;
478 3536 : int rc;
479 :
480 44826 : rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
481 44826 : if (rc < 0) {
482 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
483 : }
484 :
485 44826 : rc = gnutls_hash(hash_hnd, zeros, sizeof(zeros));
486 44826 : if (rc < 0) {
487 0 : gnutls_hash_deinit(hash_hnd, NULL);
488 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
489 : }
490 44826 : if (confounder) {
491 35728 : SSVAL(header, 0, NL_SIGN_HMAC_MD5);
492 35728 : SSVAL(header, 2, NL_SEAL_RC4);
493 35728 : SSVAL(header, 4, 0xFFFF);
494 35728 : SSVAL(header, 6, 0x0000);
495 :
496 35728 : rc = gnutls_hash(hash_hnd, header, 8);
497 35728 : if (rc < 0) {
498 0 : gnutls_hash_deinit(hash_hnd, NULL);
499 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
500 : }
501 35728 : rc = gnutls_hash(hash_hnd, confounder, 8);
502 35728 : if (rc < 0) {
503 0 : gnutls_hash_deinit(hash_hnd, NULL);
504 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
505 : }
506 : } else {
507 9098 : SSVAL(header, 0, NL_SIGN_HMAC_MD5);
508 9098 : SSVAL(header, 2, NL_SEAL_NONE);
509 9098 : SSVAL(header, 4, 0xFFFF);
510 9098 : SSVAL(header, 6, 0x0000);
511 :
512 9098 : rc = gnutls_hash(hash_hnd, header, 8);
513 9098 : if (rc < 0) {
514 0 : gnutls_hash_deinit(hash_hnd, NULL);
515 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
516 : }
517 : }
518 44826 : rc = gnutls_hash(hash_hnd, data, length);
519 44826 : if (rc < 0) {
520 0 : gnutls_hash_deinit(hash_hnd, NULL);
521 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
522 : }
523 44826 : gnutls_hash_deinit(hash_hnd, packet_digest);
524 :
525 48362 : rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
526 44826 : state->creds->session_key,
527 : sizeof(state->creds->session_key),
528 : packet_digest,
529 : sizeof(packet_digest),
530 : checksum);
531 44826 : ZERO_ARRAY(packet_digest);
532 44826 : if (rc < 0) {
533 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
534 : }
535 : }
536 :
537 97996 : return NT_STATUS_OK;
538 : }
539 :
540 48967 : static NTSTATUS netsec_incoming_packet(struct schannel_state *state,
541 : bool do_unseal,
542 : uint8_t *data, size_t length,
543 : const uint8_t *whole_pdu, size_t pdu_length,
544 : const DATA_BLOB *sig)
545 : {
546 48967 : uint32_t min_sig_size = 0;
547 5348 : uint8_t header[8];
548 5348 : uint8_t checksum[32];
549 48967 : uint32_t checksum_length = sizeof(checksum_length);
550 5348 : uint8_t _confounder[8];
551 48967 : uint8_t *confounder = NULL;
552 48967 : uint32_t confounder_ofs = 0;
553 5348 : uint8_t seq_num[8];
554 5348 : bool ret;
555 48967 : const uint8_t *sign_data = NULL;
556 48967 : size_t sign_length = 0;
557 5348 : NTSTATUS status;
558 :
559 48967 : netsec_offset_and_sizes(state,
560 : do_unseal,
561 : &min_sig_size,
562 : NULL,
563 : &checksum_length,
564 : &confounder_ofs);
565 :
566 48967 : if (sig->length < min_sig_size) {
567 0 : return NT_STATUS_ACCESS_DENIED;
568 : }
569 :
570 48967 : if (do_unseal) {
571 34831 : confounder = _confounder;
572 34831 : memcpy(confounder, sig->data+confounder_ofs, 8);
573 : } else {
574 11608 : confounder = NULL;
575 : }
576 :
577 48967 : SETUP_SEQNUM(state, seq_num, !state->initiator);
578 :
579 48967 : if (do_unseal) {
580 34831 : status = netsec_do_seal(state,
581 : seq_num,
582 : confounder,
583 : data,
584 : length,
585 : false);
586 34831 : if (!NT_STATUS_IS_OK(status)) {
587 0 : DBG_WARNING("netsec_do_seal failed: %s\n", nt_errstr(status));
588 0 : return NT_STATUS_ACCESS_DENIED;
589 : }
590 : }
591 :
592 48967 : if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
593 43409 : sign_data = whole_pdu;
594 43409 : sign_length = pdu_length;
595 : } else {
596 210 : sign_data = data;
597 210 : sign_length = length;
598 : }
599 :
600 48967 : status = netsec_do_sign(state,
601 : confounder,
602 : sign_data,
603 : sign_length,
604 : header,
605 : checksum);
606 48967 : if (!NT_STATUS_IS_OK(status)) {
607 0 : DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
608 0 : return NT_STATUS_ACCESS_DENIED;
609 : }
610 :
611 48967 : ret = mem_equal_const_time(checksum, sig->data+16, checksum_length);
612 48967 : if (!ret) {
613 0 : dump_data_pw("calc digest:", checksum, checksum_length);
614 0 : dump_data_pw("wire digest:", sig->data+16, checksum_length);
615 0 : return NT_STATUS_ACCESS_DENIED;
616 : }
617 :
618 48967 : status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
619 48967 : if (!NT_STATUS_IS_OK(status)) {
620 0 : DBG_WARNING("netsec_do_seq_num failed: %s\n",
621 : nt_errstr(status));
622 0 : return status;
623 : }
624 :
625 48967 : ZERO_ARRAY(checksum);
626 :
627 48967 : ret = mem_equal_const_time(seq_num, sig->data+8, 8);
628 48967 : if (!ret) {
629 0 : dump_data_pw("calc seq num:", seq_num, 8);
630 0 : dump_data_pw("wire seq num:", sig->data+8, 8);
631 0 : return NT_STATUS_ACCESS_DENIED;
632 : }
633 :
634 48967 : return NT_STATUS_OK;
635 : }
636 :
637 49029 : static uint32_t netsec_outgoing_sig_size(struct schannel_state *state)
638 : {
639 49029 : uint32_t sig_size = 0;
640 :
641 54377 : netsec_offset_and_sizes(state,
642 : true,
643 : NULL,
644 : &sig_size,
645 : NULL,
646 : NULL);
647 :
648 49029 : return sig_size;
649 : }
650 :
651 49029 : static NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
652 : TALLOC_CTX *mem_ctx,
653 : bool do_seal,
654 : uint8_t *data, size_t length,
655 : const uint8_t *whole_pdu, size_t pdu_length,
656 : DATA_BLOB *sig)
657 : {
658 49029 : uint32_t min_sig_size = 0;
659 49029 : uint32_t used_sig_size = 0;
660 5348 : uint8_t header[8];
661 5348 : uint8_t checksum[32];
662 49029 : uint32_t checksum_length = sizeof(checksum_length);
663 5348 : uint8_t _confounder[8];
664 49029 : uint8_t *confounder = NULL;
665 49029 : uint32_t confounder_ofs = 0;
666 5348 : uint8_t seq_num[8];
667 49029 : const uint8_t *sign_data = NULL;
668 49029 : size_t sign_length = 0;
669 5348 : NTSTATUS status;
670 :
671 49029 : netsec_offset_and_sizes(state,
672 : do_seal,
673 : &min_sig_size,
674 : &used_sig_size,
675 : &checksum_length,
676 : &confounder_ofs);
677 :
678 49029 : SETUP_SEQNUM(state, seq_num, state->initiator);
679 :
680 49029 : if (do_seal) {
681 34851 : confounder = _confounder;
682 34851 : generate_random_buffer(confounder, 8);
683 : } else {
684 11650 : confounder = NULL;
685 : }
686 :
687 49029 : if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
688 43471 : sign_data = whole_pdu;
689 43471 : sign_length = pdu_length;
690 : } else {
691 210 : sign_data = data;
692 210 : sign_length = length;
693 : }
694 :
695 49029 : status = netsec_do_sign(state,
696 : confounder,
697 : sign_data,
698 : sign_length,
699 : header,
700 : checksum);
701 49029 : if (!NT_STATUS_IS_OK(status)) {
702 0 : DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
703 0 : return NT_STATUS_ACCESS_DENIED;
704 : }
705 :
706 49029 : if (do_seal) {
707 34851 : status = netsec_do_seal(state,
708 : seq_num,
709 : confounder,
710 : data,
711 : length,
712 : true);
713 34851 : if (!NT_STATUS_IS_OK(status)) {
714 0 : DBG_WARNING("netsec_do_seal failed: %s\n",
715 : nt_errstr(status));
716 0 : return status;
717 : }
718 : }
719 :
720 49029 : status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
721 49029 : if (!NT_STATUS_IS_OK(status)) {
722 0 : DBG_WARNING("netsec_do_seq_num failed: %s\n",
723 : nt_errstr(status));
724 0 : return status;
725 : }
726 :
727 49029 : (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
728 :
729 49029 : memcpy(sig->data, header, 8);
730 49029 : memcpy(sig->data+8, seq_num, 8);
731 49029 : memcpy(sig->data+16, checksum, checksum_length);
732 :
733 49029 : if (confounder) {
734 34851 : memcpy(sig->data+confounder_ofs, confounder, 8);
735 : }
736 :
737 49029 : dump_data_pw("signature:", sig->data+ 0, 8);
738 49029 : dump_data_pw("seq_num :", sig->data+ 8, 8);
739 49029 : dump_data_pw("digest :", sig->data+16, checksum_length);
740 49029 : dump_data_pw("confound :", sig->data+confounder_ofs, 8);
741 :
742 49029 : return NT_STATUS_OK;
743 : }
744 :
745 : _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx);
746 :
747 49029 : static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
748 : {
749 5348 : struct schannel_state *state =
750 49029 : talloc_get_type_abort(gensec_security->private_data,
751 : struct schannel_state);
752 :
753 49029 : return netsec_outgoing_sig_size(state);
754 : }
755 :
756 : struct schannel_update_state {
757 : NTSTATUS status;
758 : DATA_BLOB out;
759 : };
760 :
761 : static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
762 : TALLOC_CTX *out_mem_ctx,
763 : const DATA_BLOB in, DATA_BLOB *out);
764 :
765 7403 : static struct tevent_req *schannel_update_send(TALLOC_CTX *mem_ctx,
766 : struct tevent_context *ev,
767 : struct gensec_security *gensec_security,
768 : const DATA_BLOB in)
769 : {
770 960 : struct tevent_req *req;
771 7403 : struct schannel_update_state *state = NULL;
772 960 : NTSTATUS status;
773 :
774 7403 : req = tevent_req_create(mem_ctx, &state,
775 : struct schannel_update_state);
776 7403 : if (req == NULL) {
777 0 : return NULL;
778 : }
779 :
780 8363 : status = schannel_update_internal(gensec_security,
781 : state, in,
782 7403 : &state->out);
783 7403 : state->status = status;
784 7403 : if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
785 2456 : status = NT_STATUS_OK;
786 : }
787 7403 : if (tevent_req_nterror(req, status)) {
788 0 : return tevent_req_post(req, ev);
789 : }
790 :
791 7403 : tevent_req_done(req);
792 7403 : return tevent_req_post(req, ev);
793 : }
794 :
795 7403 : static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
796 : TALLOC_CTX *out_mem_ctx,
797 : const DATA_BLOB in, DATA_BLOB *out)
798 : {
799 960 : struct schannel_state *state =
800 7403 : talloc_get_type(gensec_security->private_data,
801 : struct schannel_state);
802 960 : NTSTATUS status;
803 960 : enum ndr_err_code ndr_err;
804 7403 : struct NL_AUTH_MESSAGE bind_schannel = {
805 : .Flags = 0,
806 : };
807 960 : struct NL_AUTH_MESSAGE bind_schannel_ack;
808 960 : struct netlogon_creds_CredentialState *creds;
809 960 : const char *workstation;
810 960 : const char *domain;
811 :
812 7403 : *out = data_blob(NULL, 0);
813 :
814 7403 : if (gensec_security->dcerpc_auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
815 0 : switch (gensec_security->gensec_role) {
816 0 : case GENSEC_CLIENT:
817 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
818 0 : case GENSEC_SERVER:
819 0 : return NT_STATUS_INVALID_PARAMETER;
820 : }
821 0 : return NT_STATUS_INTERNAL_ERROR;
822 : }
823 :
824 7403 : switch (gensec_security->gensec_role) {
825 4912 : case GENSEC_CLIENT:
826 4912 : if (state != NULL) {
827 : /* we could parse the bind ack, but we don't know what it is yet */
828 2456 : return NT_STATUS_OK;
829 : }
830 :
831 2456 : creds = cli_credentials_get_netlogon_creds(gensec_security->credentials);
832 2456 : if (creds == NULL) {
833 0 : return NT_STATUS_INVALID_PARAMETER_MIX;
834 : }
835 :
836 2456 : state = netsec_create_state(gensec_security,
837 : creds, true /* initiator */);
838 2456 : if (state == NULL) {
839 0 : return NT_STATUS_NO_MEMORY;
840 : }
841 :
842 2456 : bind_schannel.MessageType = NL_NEGOTIATE_REQUEST;
843 :
844 2456 : bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
845 : NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
846 2456 : bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
847 2456 : bind_schannel.oem_netbios_computer.a = creds->computer_name;
848 :
849 2456 : if (creds->secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
850 72 : bind_schannel.Flags |= NL_FLAG_UTF8_DNS_DOMAIN_NAME;
851 72 : bind_schannel.utf8_dns_domain.u = cli_credentials_get_realm(gensec_security->credentials);
852 :
853 72 : bind_schannel.Flags |= NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME;
854 72 : bind_schannel.utf8_netbios_computer.u = creds->computer_name;
855 : }
856 :
857 2456 : ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
858 : (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
859 2456 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
860 0 : status = ndr_map_error2ntstatus(ndr_err);
861 0 : DEBUG(3, ("Could not create schannel bind: %s\n",
862 : nt_errstr(status)));
863 0 : return status;
864 : }
865 :
866 2456 : return NT_STATUS_MORE_PROCESSING_REQUIRED;
867 2491 : case GENSEC_SERVER:
868 :
869 2491 : if (state != NULL) {
870 : /* no third leg on this protocol */
871 0 : return NT_STATUS_INVALID_PARAMETER;
872 : }
873 :
874 : /* parse the schannel startup blob */
875 2491 : ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
876 : (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_MESSAGE);
877 2491 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
878 0 : status = ndr_map_error2ntstatus(ndr_err);
879 0 : DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
880 : nt_errstr(status)));
881 0 : return status;
882 : }
883 :
884 2491 : if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME) {
885 2491 : domain = bind_schannel.oem_netbios_domain.a;
886 2491 : if (strcasecmp_m(domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)) != 0) {
887 0 : DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
888 : domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)));
889 0 : return NT_STATUS_LOGON_FAILURE;
890 : }
891 0 : } else if (bind_schannel.Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME) {
892 0 : domain = bind_schannel.utf8_dns_domain.u;
893 0 : if (strcasecmp_m(domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)) != 0) {
894 0 : DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
895 : domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)));
896 0 : return NT_STATUS_LOGON_FAILURE;
897 : }
898 : } else {
899 0 : DEBUG(3, ("Request for schannel to without domain\n"));
900 0 : return NT_STATUS_LOGON_FAILURE;
901 : }
902 :
903 2491 : if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME) {
904 2491 : workstation = bind_schannel.oem_netbios_computer.a;
905 0 : } else if (bind_schannel.Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME) {
906 0 : workstation = bind_schannel.utf8_netbios_computer.u;
907 : } else {
908 0 : DEBUG(3, ("Request for schannel to without netbios workstation\n"));
909 0 : return NT_STATUS_LOGON_FAILURE;
910 : }
911 :
912 2811 : status = schannel_get_creds_state(out_mem_ctx,
913 2491 : gensec_security->settings->lp_ctx,
914 : workstation, &creds);
915 2491 : if (!NT_STATUS_IS_OK(status)) {
916 0 : DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
917 : workstation, nt_errstr(status)));
918 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
919 0 : return NT_STATUS_LOGON_FAILURE;
920 : }
921 0 : return status;
922 : }
923 :
924 2491 : state = netsec_create_state(gensec_security,
925 : creds, false /* not initiator */);
926 2491 : if (state == NULL) {
927 0 : return NT_STATUS_NO_MEMORY;
928 : }
929 :
930 2491 : status = auth_anonymous_user_info_dc(state,
931 2491 : lpcfg_netbios_name(gensec_security->settings->lp_ctx),
932 : &state->user_info_dc);
933 2491 : if (!NT_STATUS_IS_OK(status)) {
934 0 : return status;
935 : }
936 :
937 2491 : bind_schannel_ack.MessageType = NL_NEGOTIATE_RESPONSE;
938 2491 : bind_schannel_ack.Flags = 0;
939 2491 : bind_schannel_ack.Buffer.dummy = 0x6c0000; /* actually I think
940 : * this does not have
941 : * any meaning here
942 : * - gd */
943 :
944 2491 : ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
945 : (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
946 2491 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
947 0 : status = ndr_map_error2ntstatus(ndr_err);
948 0 : DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
949 : workstation, nt_errstr(status)));
950 0 : return status;
951 : }
952 :
953 2491 : return NT_STATUS_OK;
954 : }
955 0 : return NT_STATUS_INVALID_PARAMETER;
956 : }
957 :
958 7403 : static NTSTATUS schannel_update_recv(struct tevent_req *req,
959 : TALLOC_CTX *out_mem_ctx,
960 : DATA_BLOB *out)
961 : {
962 960 : struct schannel_update_state *state =
963 7403 : tevent_req_data(req,
964 : struct schannel_update_state);
965 960 : NTSTATUS status;
966 :
967 7403 : *out = data_blob_null;
968 :
969 7403 : if (tevent_req_is_nterror(req, &status)) {
970 0 : tevent_req_received(req);
971 0 : return status;
972 : }
973 :
974 7403 : status = state->status;
975 7403 : talloc_steal(out_mem_ctx, state->out.data);
976 7403 : *out = state->out;
977 7403 : tevent_req_received(req);
978 7403 : return status;
979 : }
980 :
981 : /**
982 : * Returns anonymous credentials for schannel, matching Win2k3.
983 : *
984 : */
985 :
986 2491 : static NTSTATUS schannel_session_info(struct gensec_security *gensec_security,
987 : TALLOC_CTX *mem_ctx,
988 : struct auth_session_info **_session_info)
989 : {
990 320 : struct schannel_state *state =
991 2491 : talloc_get_type(gensec_security->private_data,
992 : struct schannel_state);
993 2491 : struct auth4_context *auth_ctx = gensec_security->auth_context;
994 2491 : struct auth_session_info *session_info = NULL;
995 2491 : uint32_t session_info_flags = 0;
996 320 : NTSTATUS status;
997 :
998 2491 : if (auth_ctx == NULL) {
999 0 : DEBUG(0, ("Cannot generate a session_info without the auth_context\n"));
1000 0 : return NT_STATUS_INTERNAL_ERROR;
1001 : }
1002 :
1003 2491 : if (auth_ctx->generate_session_info == NULL) {
1004 0 : DEBUG(0, ("Cannot generate a session_info without the generate_session_info hook\n"));
1005 0 : return NT_STATUS_INTERNAL_ERROR;
1006 : }
1007 :
1008 2491 : if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
1009 0 : session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
1010 : }
1011 :
1012 2491 : session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
1013 :
1014 2491 : status = auth_ctx->generate_session_info(
1015 : auth_ctx,
1016 : mem_ctx,
1017 2171 : state->user_info_dc,
1018 2491 : state->user_info_dc->info->account_name,
1019 : session_info_flags,
1020 : &session_info);
1021 2491 : if (!NT_STATUS_IS_OK(status)) {
1022 0 : return status;
1023 : }
1024 :
1025 2491 : *_session_info = session_info;
1026 2491 : return NT_STATUS_OK;
1027 : }
1028 :
1029 : /*
1030 : * Reduce the attack surface by ensuring schannel is not available when
1031 : * we are not a DC
1032 : */
1033 2491 : static NTSTATUS schannel_server_start(struct gensec_security *gensec_security)
1034 : {
1035 2811 : enum server_role server_role
1036 2491 : = lpcfg_server_role(gensec_security->settings->lp_ctx);
1037 :
1038 2491 : switch (server_role) {
1039 2491 : case ROLE_DOMAIN_BDC:
1040 : case ROLE_DOMAIN_PDC:
1041 : case ROLE_ACTIVE_DIRECTORY_DC:
1042 : case ROLE_IPA_DC:
1043 2491 : return NT_STATUS_OK;
1044 0 : default:
1045 0 : return NT_STATUS_NOT_IMPLEMENTED;
1046 : }
1047 : }
1048 :
1049 2456 : static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
1050 : {
1051 2456 : return NT_STATUS_OK;
1052 : }
1053 :
1054 442064 : static bool schannel_have_feature(struct gensec_security *gensec_security,
1055 : uint32_t feature)
1056 : {
1057 442064 : if (gensec_security->dcerpc_auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1058 442064 : if (feature & GENSEC_FEATURE_SIGN) {
1059 138199 : return true;
1060 : }
1061 : }
1062 286845 : if (gensec_security->dcerpc_auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
1063 254303 : if (feature & GENSEC_FEATURE_SEAL) {
1064 100481 : return true;
1065 : }
1066 : }
1067 177400 : if (feature & GENSEC_FEATURE_DCE_STYLE) {
1068 96073 : return true;
1069 : }
1070 72867 : if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1071 7403 : return true;
1072 : }
1073 57148 : return false;
1074 : }
1075 :
1076 : /*
1077 : unseal a packet
1078 : */
1079 34831 : static NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security,
1080 : uint8_t *data, size_t length,
1081 : const uint8_t *whole_pdu, size_t pdu_length,
1082 : const DATA_BLOB *sig)
1083 : {
1084 2820 : struct schannel_state *state =
1085 34831 : talloc_get_type_abort(gensec_security->private_data,
1086 : struct schannel_state);
1087 :
1088 34831 : return netsec_incoming_packet(state, true,
1089 : discard_const_p(uint8_t, data),
1090 : length,
1091 : whole_pdu, pdu_length,
1092 : sig);
1093 : }
1094 :
1095 : /*
1096 : check the signature on a packet
1097 : */
1098 14136 : static NTSTATUS schannel_check_packet(struct gensec_security *gensec_security,
1099 : const uint8_t *data, size_t length,
1100 : const uint8_t *whole_pdu, size_t pdu_length,
1101 : const DATA_BLOB *sig)
1102 : {
1103 2528 : struct schannel_state *state =
1104 14136 : talloc_get_type_abort(gensec_security->private_data,
1105 : struct schannel_state);
1106 :
1107 14136 : return netsec_incoming_packet(state, false,
1108 : discard_const_p(uint8_t, data),
1109 : length,
1110 : whole_pdu, pdu_length,
1111 : sig);
1112 : }
1113 : /*
1114 : seal a packet
1115 : */
1116 34851 : static NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security,
1117 : TALLOC_CTX *mem_ctx,
1118 : uint8_t *data, size_t length,
1119 : const uint8_t *whole_pdu, size_t pdu_length,
1120 : DATA_BLOB *sig)
1121 : {
1122 2820 : struct schannel_state *state =
1123 34851 : talloc_get_type_abort(gensec_security->private_data,
1124 : struct schannel_state);
1125 :
1126 34851 : return netsec_outgoing_packet(state, mem_ctx, true,
1127 : data, length,
1128 : whole_pdu, pdu_length,
1129 : sig);
1130 : }
1131 :
1132 : /*
1133 : sign a packet
1134 : */
1135 14178 : static NTSTATUS schannel_sign_packet(struct gensec_security *gensec_security,
1136 : TALLOC_CTX *mem_ctx,
1137 : const uint8_t *data, size_t length,
1138 : const uint8_t *whole_pdu, size_t pdu_length,
1139 : DATA_BLOB *sig)
1140 : {
1141 2528 : struct schannel_state *state =
1142 14178 : talloc_get_type_abort(gensec_security->private_data,
1143 : struct schannel_state);
1144 :
1145 14178 : return netsec_outgoing_packet(state, mem_ctx, false,
1146 : discard_const_p(uint8_t, data),
1147 : length,
1148 : whole_pdu, pdu_length,
1149 : sig);
1150 : }
1151 :
1152 : static const struct gensec_security_ops gensec_schannel_security_ops = {
1153 : .name = "schannel",
1154 : .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
1155 : .client_start = schannel_client_start,
1156 : .server_start = schannel_server_start,
1157 : .update_send = schannel_update_send,
1158 : .update_recv = schannel_update_recv,
1159 : .seal_packet = schannel_seal_packet,
1160 : .sign_packet = schannel_sign_packet,
1161 : .check_packet = schannel_check_packet,
1162 : .unseal_packet = schannel_unseal_packet,
1163 : .session_info = schannel_session_info,
1164 : .sig_size = schannel_sig_size,
1165 : .have_feature = schannel_have_feature,
1166 : .enabled = true,
1167 : .priority = GENSEC_SCHANNEL
1168 : };
1169 :
1170 52291 : _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx)
1171 : {
1172 1208 : NTSTATUS ret;
1173 52291 : ret = gensec_register(ctx, &gensec_schannel_security_ops);
1174 52291 : if (!NT_STATUS_IS_OK(ret)) {
1175 0 : DEBUG(0,("Failed to register '%s' gensec backend!\n",
1176 : gensec_schannel_security_ops.name));
1177 0 : return ret;
1178 : }
1179 :
1180 52291 : return ret;
1181 : }
|