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