r21922: Fixed the build by rather horrid means. I really need
[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 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  Generic code for client and server.
25  Is encryption turned on ?
26 ******************************************************************************/
27
28 BOOL common_encryption_on(struct smb_trans_enc_state *es)
29 {
30         return ((es != NULL) && es->enc_on);
31 }
32
33 /******************************************************************************
34  Generic code for client and server.
35  NTLM decrypt an incoming buffer.
36 ******************************************************************************/
37
38 NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
39 {
40         NTSTATUS status;
41         size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
42         DATA_BLOB sig;
43
44         if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
45                 return NT_STATUS_BUFFER_TOO_SMALL;
46         }
47
48         /* Adjust for the signature. */
49         buf_len -= NTLMSSP_SIG_SIZE;
50
51         /* Save off the signature. */
52         sig = data_blob(buf+buf_len, NTLMSSP_SIG_SIZE);
53
54         status = ntlmssp_unseal_packet(ntlmssp_state,
55                 (unsigned char *)buf + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */
56                 buf_len - 8,
57                 (unsigned char *)buf + 8,
58                 buf_len - 8,
59                 &sig);
60
61         if (!NT_STATUS_IS_OK(status)) {
62                 data_blob_free(&sig);
63                 return status;
64         }
65
66         /* Reset the length. */
67         smb_setlen(buf, smb_len(buf) - NTLMSSP_SIG_SIZE);
68         return NT_STATUS_OK;
69 }
70
71 /******************************************************************************
72  Generic code for client and server.
73  NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
74 ******************************************************************************/
75
76 NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, char **ppbuf_out)
77 {
78         NTSTATUS status;
79         char *buf_out;
80         size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
81         DATA_BLOB sig;
82
83         *ppbuf_out = NULL;
84
85         if (buf_len < 8) {
86                 return NT_STATUS_BUFFER_TOO_SMALL;
87         }
88
89         /* 
90          * We know smb_len can't return a value > 128k, so no int overflow
91          * check needed.
92          */
93
94         /* Copy the original buffer. */
95
96         buf_out = SMB_XMALLOC_ARRAY(char, buf_len + NTLMSSP_SIG_SIZE);
97         memcpy(buf_out, buf, buf_len);
98         /* Last 16 bytes undefined here... */
99
100         smb_setlen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE);
101
102         sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
103
104         status = ntlmssp_seal_packet(ntlmssp_state,
105                 (unsigned char *)buf_out + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */
106                 buf_len - 8,
107                 (unsigned char *)buf_out + 8,
108                 buf_len - 8,
109                 &sig);
110
111         if (!NT_STATUS_IS_OK(status)) {
112                 data_blob_free(&sig);
113                 SAFE_FREE(buf_out);
114                 return status;
115         }
116
117         memcpy(buf_out+buf_len, sig.data, NTLMSSP_SIG_SIZE);
118         *ppbuf_out = buf_out;
119         return NT_STATUS_OK;
120 }
121
122 /******************************************************************************
123  Generic code for client and server.
124  gss-api decrypt an incoming buffer.
125 ******************************************************************************/
126
127 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
128  NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
129 {
130         return NT_STATUS_NOT_SUPPORTED;
131 }
132 #endif
133
134 /******************************************************************************
135  Generic code for client and server.
136  gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
137 ******************************************************************************/
138
139 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
140  NTSTATUS common_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **ppbuf_out)
141 {
142         OM_uint32 ret = 0;
143         OM_uint32 minor = 0;
144         int flags_got = 0;
145         gss_buffer_desc in_buf, out_buf;
146         size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
147
148         *ppbuf_out = NULL;
149
150         if (buf_len < 8) {
151                 return NT_STATUS_BUFFER_TOO_SMALL;
152         }
153
154         in_buf.value = buf + 8;
155         in_buf.length = buf_len - 8;
156
157         ret = gss_wrap(&minor,
158                         context_handle,
159                         True,                   /* we want sign+seal. */
160                         GSS_C_QOP_DEFAULT,
161                         &in_buf,
162                         &flags_got,             /* did we get sign+seal ? */
163                         &out_buf);
164
165         if (ret != GSS_S_COMPLETE) {
166                 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
167                 DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
168                         ads_errstr(adss) ));
169                 /* Um - no mapping for gss-errs to NTSTATUS yet. */
170                 return ads_ntstatus(adss);
171         }
172
173         if (!flags_got) {
174                 /* Sign+seal not supported. */
175                 gss_release_buffer(&minor, &out_buf);
176                 return NT_STATUS_NOT_SUPPORTED;
177         }
178
179         /* Ya see - this is why I *hate* gss-api. I don't 
180          * want to have to malloc another buffer of the
181          * same size + 8 bytes just to get a continuous
182          * header + buffer, but gss won't let me pass in
183          * a pre-allocated buffer. Bastards (and you know
184          * who you are....). I might fix this by
185          * going to "encrypt_and_send" passing in a file
186          * descriptor and doing scatter-gather write with
187          * TCP cork on Linux. But I shouldn't have to
188          * bother :-*(. JRA.
189          */
190
191         *ppbuf_out = SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
192         if (!*ppbuf_out) {
193                 gss_release_buffer(&minor, &out_buf);
194                 return NT_STATUS_NO_MEMORY;
195         }
196
197         smb_setlen(*ppbuf_out, out_buf.length + 8);
198         memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
199         gss_release_buffer(&minor, &out_buf);
200         return NT_STATUS_OK;
201 }
202 #endif
203
204 /******************************************************************************
205  Generic code for client and server.
206  Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
207 ******************************************************************************/
208
209 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
210 {
211         if (!common_encryption_on(es)) {
212                 /* Not encrypting. */
213                 *buf_out = buffer;
214                 return NT_STATUS_OK;
215         }
216
217         /* Ignore session keepalives. */
218         if(CVAL(buffer,0) == SMBkeepalive) {
219                 *buf_out = buffer;
220                 return NT_STATUS_OK;
221         }
222
223         switch (es->smb_enc_type) {
224                 case SMB_TRANS_ENC_NTLM:
225                         return common_ntlm_encrypt_buffer(es->ntlmssp_state, buffer, buf_out);
226 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
227                 case SMB_TRANS_ENC_GSS:
228                         return common_gss_encrypt_buffer(es->context_handle, buffer, buf_out);
229 #endif
230                 default:
231                         return NT_STATUS_NOT_SUPPORTED;
232         }
233 }
234
235 /******************************************************************************
236  Generic code for client and server.
237  Decrypt an incoming SMB buffer. Replaces the data within it.
238  New data must be less than or equal to the current length.
239 ******************************************************************************/
240
241 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
242 {
243         if (!common_encryption_on(es)) {
244                 /* Not decrypting. */
245                 return NT_STATUS_OK;
246         }
247
248         /* Ignore session keepalives. */
249         if(CVAL(buf,0) == SMBkeepalive) {
250                 return NT_STATUS_OK;
251         }
252
253         switch (es->smb_enc_type) {
254                 case SMB_TRANS_ENC_NTLM:
255                         return common_ntlm_decrypt_buffer(es->ntlmssp_state, buf);
256 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
257                 case SMB_TRANS_ENC_GSS:
258                         return common_gss_decrypt_buffer(es->context_handle, buf);
259 #endif
260                 default:
261                         return NT_STATUS_NOT_SUPPORTED;
262         }
263 }
264
265 /******************************************************************************
266  Shutdown an encryption state.
267 ******************************************************************************/
268
269 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
270 {
271         struct smb_trans_enc_state *es = *pp_es;
272
273         if (es == NULL) {
274                 return;
275         }
276
277         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
278                 if (es->ntlmssp_state) {
279                         ntlmssp_end(&es->ntlmssp_state);
280                 }
281         }
282 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
283         if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
284                 /* Free the gss context handle. */
285         }
286 #endif
287         SAFE_FREE(es);
288         *pp_es = NULL;
289 }
290
291 /******************************************************************************
292  Free an encryption-allocated buffer.
293 ******************************************************************************/
294
295 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
296 {
297         if (!common_encryption_on(es)) {
298                 return;
299         }
300
301         /* We know this is an smb buffer, and we
302          * didn't malloc, only copy, for a keepalive,
303          * so ignore session keepalives. */
304
305         if(CVAL(buf,0) == SMBkeepalive) {
306                 return;
307         }
308
309         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
310                 SAFE_FREE(buf);
311                 return;
312         }
313
314 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
315         /* gss-api free buffer.... */
316 #endif
317 }
318
319 /******************************************************************************
320  Client side encryption.
321 ******************************************************************************/
322
323 /******************************************************************************
324  Is client encryption on ?
325 ******************************************************************************/
326
327 BOOL cli_encryption_on(struct cli_state *cli)
328 {
329         return common_encryption_on(cli->trans_enc_state);
330 }
331
332 /******************************************************************************
333  Shutdown a client encryption state.
334 ******************************************************************************/
335
336 void cli_free_encryption_context(struct cli_state *cli)
337 {
338         common_free_encryption_state(&cli->trans_enc_state);
339 }
340
341 /******************************************************************************
342  Free an encryption-allocated buffer.
343 ******************************************************************************/
344
345 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
346 {
347         common_free_enc_buffer(cli->trans_enc_state, buf);
348 }
349
350 /******************************************************************************
351  Decrypt an incoming buffer.
352 ******************************************************************************/
353
354 NTSTATUS cli_decrypt_message(struct cli_state *cli)
355 {
356         return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
357 }
358
359 /******************************************************************************
360  Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
361 ******************************************************************************/
362
363 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
364 {
365         return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);
366 }