r21994: Ignore keepalives in the correct buffer (out not in :-).
[Samba/bb.git] / source3 / libsmb / smb_seal.c
blobed2c66013e8d29c5cd782e05068de2ac67e71f40
1 /*
2 Unix SMB/CIFS implementation.
3 SMB Transport encryption (sealing) code.
4 Copyright (C) Jeremy Allison 2007.
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 2 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 /******************************************************************************
24 Pull out the encryption context for this packet. 0 means global context.
25 ******************************************************************************/
27 NTSTATUS get_enc_ctx_num(char *buf, uint16 *p_enc_ctx_num)
29 if (smb_len(buf) < 8) {
30 return NT_STATUS_INVALID_BUFFER_SIZE;
33 if (buf[4] == (char)0xFF && buf[5] == 'S') {
34 if (buf [6] == 'M' && buf[7] == 'B') {
35 /* Not an encrypted buffer. */
36 return NT_STATUS_NOT_FOUND;
38 *p_enc_ctx_num = SVAL(buf,6);
39 return NT_STATUS_OK;
41 return NT_STATUS_INVALID_NETWORK_RESPONSE;
44 /******************************************************************************
45 Generic code for client and server.
46 Is encryption turned on ?
47 ******************************************************************************/
49 BOOL common_encryption_on(struct smb_trans_enc_state *es)
51 return ((es != NULL) && es->enc_on);
54 /******************************************************************************
55 Generic code for client and server.
56 NTLM decrypt an incoming buffer.
57 ******************************************************************************/
59 NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
61 NTSTATUS status;
62 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
63 DATA_BLOB sig;
65 if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
66 return NT_STATUS_BUFFER_TOO_SMALL;
69 /* Adjust for the signature. */
70 buf_len -= NTLMSSP_SIG_SIZE;
72 /* Save off the signature. */
73 sig = data_blob(buf+buf_len, NTLMSSP_SIG_SIZE);
75 status = ntlmssp_unseal_packet(ntlmssp_state,
76 (unsigned char *)buf + 8, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
77 buf_len - 8,
78 (unsigned char *)buf + 8,
79 buf_len - 8,
80 &sig);
82 if (!NT_STATUS_IS_OK(status)) {
83 data_blob_free(&sig);
84 return status;
87 /* Reset the length. */
88 smb_setlen(buf, smb_len(buf) - NTLMSSP_SIG_SIZE);
89 return NT_STATUS_OK;
92 /******************************************************************************
93 Generic code for client and server.
94 NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
95 ******************************************************************************/
97 NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
98 uint16 enc_ctx_num,
99 char *buf,
100 char **ppbuf_out)
102 NTSTATUS status;
103 char *buf_out;
104 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
105 DATA_BLOB sig;
107 *ppbuf_out = NULL;
109 if (buf_len < 8) {
110 return NT_STATUS_BUFFER_TOO_SMALL;
114 * We know smb_len can't return a value > 128k, so no int overflow
115 * check needed.
118 /* Copy the original buffer. */
120 buf_out = SMB_XMALLOC_ARRAY(char, buf_len + NTLMSSP_SIG_SIZE);
121 memcpy(buf_out, buf, buf_len);
122 /* Last 16 bytes undefined here... */
124 smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
126 sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
128 status = ntlmssp_seal_packet(ntlmssp_state,
129 (unsigned char *)buf_out + 8, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
130 buf_len - 8,
131 (unsigned char *)buf_out + 8,
132 buf_len - 8,
133 &sig);
135 if (!NT_STATUS_IS_OK(status)) {
136 data_blob_free(&sig);
137 SAFE_FREE(buf_out);
138 return status;
141 memcpy(buf_out+buf_len, sig.data, NTLMSSP_SIG_SIZE);
142 *ppbuf_out = buf_out;
143 return NT_STATUS_OK;
146 /******************************************************************************
147 Generic code for client and server.
148 gss-api decrypt an incoming buffer. We insist that the size of the
149 unwrapped buffer must be smaller or identical to the incoming buffer.
150 ******************************************************************************/
152 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
153 NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
155 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
156 OM_uint32 ret = 0;
157 OM_uint32 minor = 0;
158 int flags_got = 0;
159 gss_buffer_desc in_buf, out_buf;
160 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
162 if (buf_len < 8) {
163 return NT_STATUS_BUFFER_TOO_SMALL;
166 in_buf.value = buf + 8;
167 in_buf.length = buf_len - 8;
169 ret = gss_unwrap(&minor,
170 gss_ctx,
171 &in_buf,
172 &out_buf,
173 &flags_got, /* did we get sign+seal ? */
174 (gss_qop_t *) NULL);
176 if (ret != GSS_S_COMPLETE) {
177 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
178 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
179 ads_errstr(adss) ));
180 /* Um - no mapping for gss-errs to NTSTATUS yet. */
181 return ads_ntstatus(adss);
184 if (out_buf.length > in_buf.length) {
185 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
186 (unsigned int)out_buf.length,
187 (unsigned int)in_buf.length ));
188 gss_release_buffer(&minor, &out_buf);
189 return NT_STATUS_INVALID_PARAMETER;
192 memcpy(buf + 8, out_buf.value, out_buf.length);
193 smb_setlen(buf, out_buf.length + 4);
195 gss_release_buffer(&minor, &out_buf);
196 return NT_STATUS_OK;
198 #endif
200 /******************************************************************************
201 Generic code for client and server.
202 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
203 ******************************************************************************/
205 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
206 NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
207 uint16 enc_ctx_num,
208 char *buf,
209 char **ppbuf_out)
211 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
212 OM_uint32 ret = 0;
213 OM_uint32 minor = 0;
214 int flags_got = 0;
215 gss_buffer_desc in_buf, out_buf;
216 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
218 *ppbuf_out = NULL;
220 if (buf_len < 8) {
221 return NT_STATUS_BUFFER_TOO_SMALL;
224 in_buf.value = buf + 8;
225 in_buf.length = buf_len - 8;
227 ret = gss_wrap(&minor,
228 gss_ctx,
229 True, /* we want sign+seal. */
230 GSS_C_QOP_DEFAULT,
231 &in_buf,
232 &flags_got, /* did we get sign+seal ? */
233 &out_buf);
235 if (ret != GSS_S_COMPLETE) {
236 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
237 DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
238 ads_errstr(adss) ));
239 /* Um - no mapping for gss-errs to NTSTATUS yet. */
240 return ads_ntstatus(adss);
243 if (!flags_got) {
244 /* Sign+seal not supported. */
245 gss_release_buffer(&minor, &out_buf);
246 return NT_STATUS_NOT_SUPPORTED;
249 /* Ya see - this is why I *hate* gss-api. I don't
250 * want to have to malloc another buffer of the
251 * same size + 8 bytes just to get a continuous
252 * header + buffer, but gss won't let me pass in
253 * a pre-allocated buffer. Bastards (and you know
254 * who you are....). I might fix this by
255 * going to "encrypt_and_send" passing in a file
256 * descriptor and doing scatter-gather write with
257 * TCP cork on Linux. But I shouldn't have to
258 * bother :-*(. JRA.
261 *ppbuf_out = SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
262 if (!*ppbuf_out) {
263 gss_release_buffer(&minor, &out_buf);
264 return NT_STATUS_NO_MEMORY;
267 memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
268 smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
270 gss_release_buffer(&minor, &out_buf);
271 return NT_STATUS_OK;
273 #endif
275 /******************************************************************************
276 Generic code for client and server.
277 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
278 ******************************************************************************/
280 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
282 if (!common_encryption_on(es)) {
283 /* Not encrypting. */
284 *buf_out = buffer;
285 return NT_STATUS_OK;
288 switch (es->smb_enc_type) {
289 case SMB_TRANS_ENC_NTLM:
290 return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
291 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
292 case SMB_TRANS_ENC_GSS:
293 return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
294 #endif
295 default:
296 return NT_STATUS_NOT_SUPPORTED;
300 /******************************************************************************
301 Generic code for client and server.
302 Decrypt an incoming SMB buffer. Replaces the data within it.
303 New data must be less than or equal to the current length.
304 ******************************************************************************/
306 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
308 if (!common_encryption_on(es)) {
309 /* Not decrypting. */
310 return NT_STATUS_OK;
313 switch (es->smb_enc_type) {
314 case SMB_TRANS_ENC_NTLM:
315 return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
316 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
317 case SMB_TRANS_ENC_GSS:
318 return common_gss_decrypt_buffer(es->s.gss_state, buf);
319 #endif
320 default:
321 return NT_STATUS_NOT_SUPPORTED;
325 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
326 /******************************************************************************
327 Shutdown a gss encryption state.
328 ******************************************************************************/
330 static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
332 OM_uint32 minor = 0;
333 struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
335 gss_release_cred(&minor, &gss_state->creds);
336 gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
337 SAFE_FREE(*pp_gss_state);
339 #endif
341 /******************************************************************************
342 Shutdown an encryption state.
343 ******************************************************************************/
345 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
347 struct smb_trans_enc_state *es = *pp_es;
349 if (es == NULL) {
350 return;
353 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
354 if (es->s.ntlmssp_state) {
355 ntlmssp_end(&es->s.ntlmssp_state);
358 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
359 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
360 /* Free the gss context handle. */
361 if (es->s.gss_state) {
362 common_free_gss_state(&es->s.gss_state);
365 #endif
366 SAFE_FREE(es);
367 *pp_es = NULL;
370 /******************************************************************************
371 Free an encryption-allocated buffer.
372 ******************************************************************************/
374 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
376 if (!common_encryption_on(es)) {
377 return;
380 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
381 SAFE_FREE(buf);
382 return;
385 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
386 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
387 OM_uint32 min;
388 gss_buffer_desc rel_buf;
389 rel_buf.value = buf;
390 rel_buf.length = smb_len(buf) + 4;
391 gss_release_buffer(&min, &rel_buf);
393 #endif
396 /******************************************************************************
397 Client side encryption.
398 ******************************************************************************/
400 /******************************************************************************
401 Is client encryption on ?
402 ******************************************************************************/
404 BOOL cli_encryption_on(struct cli_state *cli)
406 /* If we supported multiple encrytion contexts
407 * here we'd look up based on tid.
409 return common_encryption_on(cli->trans_enc_state);
412 /******************************************************************************
413 Shutdown a client encryption state.
414 ******************************************************************************/
416 void cli_free_encryption_context(struct cli_state *cli)
418 common_free_encryption_state(&cli->trans_enc_state);
421 /******************************************************************************
422 Free an encryption-allocated buffer.
423 ******************************************************************************/
425 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
427 /* We know this is an smb buffer, and we
428 * didn't malloc, only copy, for a keepalive,
429 * so ignore session keepalives. */
431 if(CVAL(buf,0) == SMBkeepalive) {
432 return;
435 /* If we supported multiple encrytion contexts
436 * here we'd look up based on tid.
438 common_free_enc_buffer(cli->trans_enc_state, buf);
441 /******************************************************************************
442 Decrypt an incoming buffer.
443 ******************************************************************************/
445 NTSTATUS cli_decrypt_message(struct cli_state *cli)
447 NTSTATUS status;
448 uint16 enc_ctx_num;
450 /* Ignore session keepalives. */
451 if(CVAL(cli->inbuf,0) == SMBkeepalive) {
452 return NT_STATUS_OK;
455 status = get_enc_ctx_num(cli->inbuf, &enc_ctx_num);
456 if (!NT_STATUS_IS_OK(status)) {
457 return status;
460 if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
461 return NT_STATUS_INVALID_HANDLE;
464 return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
467 /******************************************************************************
468 Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
469 ******************************************************************************/
471 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
473 /* Ignore session keepalives. */
474 if(CVAL(cli->outbuf,0) == SMBkeepalive) {
475 return NT_STATUS_OK;
478 /* If we supported multiple encrytion contexts
479 * here we'd look up based on tid.
481 return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);