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