source: vendor/3.6.23/source3/libsmb/smb_seal.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 15.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 SMB Transport encryption (sealing) code.
4 Copyright (C) Jeremy Allison 2007.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21#include "../libcli/auth/ntlmssp.h"
22#include "smb_crypt.h"
23#include "libsmb/libsmb.h"
24
25/******************************************************************************
26 Pull out the encryption context for this packet. 0 means global context.
27******************************************************************************/
28
29NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num)
30{
31 if (smb_len(buf) < 8) {
32 return NT_STATUS_INVALID_BUFFER_SIZE;
33 }
34
35 if (buf[4] == 0xFF) {
36 if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
37 /* Not an encrypted buffer. */
38 return NT_STATUS_NOT_FOUND;
39 }
40 if (buf[5] == 'E') {
41 *p_enc_ctx_num = SVAL(buf,6);
42 return NT_STATUS_OK;
43 }
44 }
45 return NT_STATUS_INVALID_NETWORK_RESPONSE;
46}
47
48/******************************************************************************
49 Generic code for client and server.
50 Is encryption turned on ?
51******************************************************************************/
52
53bool common_encryption_on(struct smb_trans_enc_state *es)
54{
55 return ((es != NULL) && es->enc_on);
56}
57
58/******************************************************************************
59 Generic code for client and server.
60 NTLM decrypt an incoming buffer.
61 Abartlett tells me that SSPI puts the signature first before the encrypted
62 output, so cope with the same for compatibility.
63******************************************************************************/
64
65NTSTATUS common_ntlm_decrypt_buffer(struct ntlmssp_state *ntlmssp_state, char *buf)
66{
67 NTSTATUS status;
68 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
69 size_t data_len;
70 char *inbuf;
71 DATA_BLOB sig;
72
73 if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
74 return NT_STATUS_BUFFER_TOO_SMALL;
75 }
76
77 inbuf = (char *)smb_xmemdup(buf, buf_len);
78
79 /* Adjust for the signature. */
80 data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
81
82 /* Point at the signature. */
83 sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
84
85 status = ntlmssp_unseal_packet(ntlmssp_state,
86 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */
87 data_len,
88 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE,
89 data_len,
90 &sig);
91
92 if (!NT_STATUS_IS_OK(status)) {
93 SAFE_FREE(inbuf);
94 return status;
95 }
96
97 memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
98
99 /* Reset the length and overwrite the header. */
100 smb_setlen(buf,data_len + 4);
101
102 SAFE_FREE(inbuf);
103 return NT_STATUS_OK;
104}
105
106/******************************************************************************
107 Generic code for client and server.
108 NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
109 Abartlett tells me that SSPI puts the signature first before the encrypted
110 output, so do the same for compatibility.
111******************************************************************************/
112
113NTSTATUS common_ntlm_encrypt_buffer(struct ntlmssp_state *ntlmssp_state,
114 uint16 enc_ctx_num,
115 char *buf,
116 char **ppbuf_out)
117{
118 NTSTATUS status;
119 char *buf_out;
120 size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */
121 DATA_BLOB sig;
122 TALLOC_CTX *frame;
123 *ppbuf_out = NULL;
124
125 if (data_len == 0) {
126 return NT_STATUS_BUFFER_TOO_SMALL;
127 }
128
129 frame = talloc_stackframe();
130 /*
131 * We know smb_len can't return a value > 128k, so no int overflow
132 * check needed.
133 */
134
135 buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
136
137 /* Copy the data from the original buffer. */
138
139 memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len);
140
141 smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
142
143 ZERO_STRUCT(sig);
144
145 status = ntlmssp_seal_packet(ntlmssp_state,
146 frame,
147 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
148 data_len,
149 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE,
150 data_len,
151 &sig);
152
153 if (!NT_STATUS_IS_OK(status)) {
154 talloc_free(frame);
155 SAFE_FREE(buf_out);
156 return status;
157 }
158
159 /* First 16 data bytes are signature for SSPI compatibility. */
160 memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE);
161 talloc_free(frame);
162 *ppbuf_out = buf_out;
163 return NT_STATUS_OK;
164}
165
166/******************************************************************************
167 Generic code for client and server.
168 gss-api decrypt an incoming buffer. We insist that the size of the
169 unwrapped buffer must be smaller or identical to the incoming buffer.
170******************************************************************************/
171
172#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
173static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
174{
175 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
176 OM_uint32 ret = 0;
177 OM_uint32 minor = 0;
178 int flags_got = 0;
179 gss_buffer_desc in_buf, out_buf;
180 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
181
182 if (buf_len < 8) {
183 return NT_STATUS_BUFFER_TOO_SMALL;
184 }
185
186 in_buf.value = buf + 8;
187 in_buf.length = buf_len - 8;
188
189 ret = gss_unwrap(&minor,
190 gss_ctx,
191 &in_buf,
192 &out_buf,
193 &flags_got, /* did we get sign+seal ? */
194 (gss_qop_t *) NULL);
195
196 if (ret != GSS_S_COMPLETE) {
197 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
198 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
199 ads_errstr(adss) ));
200 return map_nt_error_from_gss(ret, minor);
201 }
202
203 if (out_buf.length > in_buf.length) {
204 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
205 (unsigned int)out_buf.length,
206 (unsigned int)in_buf.length ));
207 gss_release_buffer(&minor, &out_buf);
208 return NT_STATUS_INVALID_PARAMETER;
209 }
210
211 memcpy(buf + 8, out_buf.value, out_buf.length);
212 /* Reset the length and overwrite the header. */
213 smb_setlen(buf, out_buf.length + 4);
214
215 gss_release_buffer(&minor, &out_buf);
216 return NT_STATUS_OK;
217}
218
219/******************************************************************************
220 Generic code for client and server.
221 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
222******************************************************************************/
223
224static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
225 uint16 enc_ctx_num,
226 char *buf,
227 char **ppbuf_out)
228{
229 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
230 OM_uint32 ret = 0;
231 OM_uint32 minor = 0;
232 int flags_got = 0;
233 gss_buffer_desc in_buf, out_buf;
234 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
235
236 *ppbuf_out = NULL;
237
238 if (buf_len < 8) {
239 return NT_STATUS_BUFFER_TOO_SMALL;
240 }
241
242 in_buf.value = buf + 8;
243 in_buf.length = buf_len - 8;
244
245 ret = gss_wrap(&minor,
246 gss_ctx,
247 true, /* we want sign+seal. */
248 GSS_C_QOP_DEFAULT,
249 &in_buf,
250 &flags_got, /* did we get sign+seal ? */
251 &out_buf);
252
253 if (ret != GSS_S_COMPLETE) {
254 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
255 DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
256 ads_errstr(adss) ));
257 return map_nt_error_from_gss(ret, minor);
258 }
259
260 if (!flags_got) {
261 /* Sign+seal not supported. */
262 gss_release_buffer(&minor, &out_buf);
263 return NT_STATUS_NOT_SUPPORTED;
264 }
265
266 /* Ya see - this is why I *hate* gss-api. I don't
267 * want to have to malloc another buffer of the
268 * same size + 8 bytes just to get a continuous
269 * header + buffer, but gss won't let me pass in
270 * a pre-allocated buffer. Bastards (and you know
271 * who you are....). I might fix this by
272 * going to "encrypt_and_send" passing in a file
273 * descriptor and doing scatter-gather write with
274 * TCP cork on Linux. But I shouldn't have to
275 * bother :-*(. JRA.
276 */
277
278 *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
279 if (!*ppbuf_out) {
280 gss_release_buffer(&minor, &out_buf);
281 return NT_STATUS_NO_MEMORY;
282 }
283
284 memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
285 smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
286
287 gss_release_buffer(&minor, &out_buf);
288 return NT_STATUS_OK;
289}
290#endif
291
292/******************************************************************************
293 Generic code for client and server.
294 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
295******************************************************************************/
296
297NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
298{
299 if (!common_encryption_on(es)) {
300 /* Not encrypting. */
301 *buf_out = buffer;
302 return NT_STATUS_OK;
303 }
304
305 switch (es->smb_enc_type) {
306 case SMB_TRANS_ENC_NTLM:
307 return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
308#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
309 case SMB_TRANS_ENC_GSS:
310 return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
311#endif
312 default:
313 return NT_STATUS_NOT_SUPPORTED;
314 }
315}
316
317/******************************************************************************
318 Generic code for client and server.
319 Decrypt an incoming SMB buffer. Replaces the data within it.
320 New data must be less than or equal to the current length.
321******************************************************************************/
322
323NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
324{
325 if (!common_encryption_on(es)) {
326 /* Not decrypting. */
327 return NT_STATUS_OK;
328 }
329
330 switch (es->smb_enc_type) {
331 case SMB_TRANS_ENC_NTLM:
332 return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
333#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
334 case SMB_TRANS_ENC_GSS:
335 return common_gss_decrypt_buffer(es->s.gss_state, buf);
336#endif
337 default:
338 return NT_STATUS_NOT_SUPPORTED;
339 }
340}
341
342#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
343/******************************************************************************
344 Shutdown a gss encryption state.
345******************************************************************************/
346
347static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
348{
349 OM_uint32 minor = 0;
350 struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
351
352 if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
353 gss_release_cred(&minor, &gss_state->creds);
354 }
355 if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
356 gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
357 }
358 SAFE_FREE(*pp_gss_state);
359}
360#endif
361
362/******************************************************************************
363 Shutdown an encryption state.
364******************************************************************************/
365
366void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
367{
368 struct smb_trans_enc_state *es = *pp_es;
369
370 if (es == NULL) {
371 return;
372 }
373
374 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
375 if (es->s.ntlmssp_state) {
376 TALLOC_FREE(es->s.ntlmssp_state);
377 }
378 }
379#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
380 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
381 /* Free the gss context handle. */
382 if (es->s.gss_state) {
383 common_free_gss_state(&es->s.gss_state);
384 }
385 }
386#endif
387 SAFE_FREE(es);
388 *pp_es = NULL;
389}
390
391/******************************************************************************
392 Free an encryption-allocated buffer.
393******************************************************************************/
394
395void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
396{
397 uint16_t enc_ctx_num;
398
399 if (!common_encryption_on(es)) {
400 return;
401 }
402
403 if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
404 &enc_ctx_num))) {
405 return;
406 }
407
408 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
409 SAFE_FREE(buf);
410 return;
411 }
412
413#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
414 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
415 OM_uint32 min;
416 gss_buffer_desc rel_buf;
417 rel_buf.value = buf;
418 rel_buf.length = smb_len(buf) + 4;
419 gss_release_buffer(&min, &rel_buf);
420 }
421#endif
422}
423
424/******************************************************************************
425 Client side encryption.
426******************************************************************************/
427
428/******************************************************************************
429 Is client encryption on ?
430******************************************************************************/
431
432bool cli_encryption_on(struct cli_state *cli)
433{
434 /* If we supported multiple encrytion contexts
435 * here we'd look up based on tid.
436 */
437 return common_encryption_on(cli->trans_enc_state);
438}
439
440/******************************************************************************
441 Shutdown a client encryption state.
442******************************************************************************/
443
444void cli_free_encryption_context(struct cli_state *cli)
445{
446 common_free_encryption_state(&cli->trans_enc_state);
447}
448
449/******************************************************************************
450 Free an encryption-allocated buffer.
451******************************************************************************/
452
453void cli_free_enc_buffer(struct cli_state *cli, char *buf)
454{
455 /* We know this is an smb buffer, and we
456 * didn't malloc, only copy, for a keepalive,
457 * so ignore non-session messages. */
458
459 if(CVAL(buf,0)) {
460 return;
461 }
462
463 /* If we supported multiple encrytion contexts
464 * here we'd look up based on tid.
465 */
466 common_free_enc_buffer(cli->trans_enc_state, buf);
467}
468
469/******************************************************************************
470 Decrypt an incoming buffer.
471******************************************************************************/
472
473NTSTATUS cli_decrypt_message(struct cli_state *cli)
474{
475 NTSTATUS status;
476 uint16 enc_ctx_num;
477
478 /* Ignore non-session messages. */
479 if(CVAL(cli->inbuf,0)) {
480 return NT_STATUS_OK;
481 }
482
483 status = get_enc_ctx_num((const uint8_t *)cli->inbuf, &enc_ctx_num);
484 if (!NT_STATUS_IS_OK(status)) {
485 return status;
486 }
487
488 if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
489 return NT_STATUS_INVALID_HANDLE;
490 }
491
492 return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
493}
494
495/******************************************************************************
496 Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
497******************************************************************************/
498
499NTSTATUS cli_encrypt_message(struct cli_state *cli, char *buf, char **buf_out)
500{
501 /* Ignore non-session messages. */
502 if (CVAL(buf,0)) {
503 return NT_STATUS_OK;
504 }
505
506 /* If we supported multiple encrytion contexts
507 * here we'd look up based on tid.
508 */
509 return common_encrypt_buffer(cli->trans_enc_state, buf, buf_out);
510}
Note: See TracBrowser for help on using the repository browser.