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