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