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