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