2 Unix SMB/CIFS implementation.
3 SMB Transport encryption (sealing) code.
4 Copyright (C) Jeremy Allison 2007.
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.
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.
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.
23 /******************************************************************************
24 Generic code for client and server.
25 Is encryption turned on ?
26 ******************************************************************************/
28 BOOL common_encryption_on(struct smb_trans_enc_state *es)
30 return ((es != NULL) && es->enc_on);
33 /******************************************************************************
34 Generic code for client and server.
35 NTLM decrypt an incoming buffer.
36 ******************************************************************************/
38 NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
41 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
44 if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
45 return NT_STATUS_BUFFER_TOO_SMALL;
48 /* Adjust for the signature. */
49 buf_len -= NTLMSSP_SIG_SIZE;
51 /* Save off the signature. */
52 sig = data_blob(buf+buf_len, NTLMSSP_SIG_SIZE);
54 status = ntlmssp_unseal_packet(ntlmssp_state,
55 (unsigned char *)buf + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */
57 (unsigned char *)buf + 8,
61 if (!NT_STATUS_IS_OK(status)) {
66 /* Reset the length. */
67 smb_setlen(buf, smb_len(buf) - NTLMSSP_SIG_SIZE);
71 /******************************************************************************
72 Generic code for client and server.
73 NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
74 ******************************************************************************/
76 NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf, char **ppbuf_out)
80 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
86 return NT_STATUS_BUFFER_TOO_SMALL;
90 * We know smb_len can't return a value > 128k, so no int overflow
94 /* Copy the original buffer. */
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... */
100 smb_setlen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE);
102 sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
104 status = ntlmssp_seal_packet(ntlmssp_state,
105 (unsigned char *)buf_out + 8, /* 4 byte len + 0xFF 'S' 'M' 'B' */
107 (unsigned char *)buf_out + 8,
111 if (!NT_STATUS_IS_OK(status)) {
112 data_blob_free(&sig);
117 memcpy(buf_out+buf_len, sig.data, NTLMSSP_SIG_SIZE);
118 *ppbuf_out = buf_out;
122 /******************************************************************************
123 Generic code for client and server.
124 gss-api decrypt an incoming buffer. We insist that the size of the
125 unwrapped buffer must be smaller or identical to the incoming buffer.
126 ******************************************************************************/
128 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
129 NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
134 gss_buffer_desc in_buf, out_buf;
135 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
138 return NT_STATUS_BUFFER_TOO_SMALL;
141 in_buf.value = buf + 8;
142 in_buf.length = buf_len - 8;
144 ret = gss_unwrap(&minor,
148 &flags_got, /* did we get sign+seal ? */
151 if (ret != GSS_S_COMPLETE) {
152 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
153 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
155 /* Um - no mapping for gss-errs to NTSTATUS yet. */
156 return ads_ntstatus(adss);
159 if (out_buf.length > in_buf.length) {
160 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
161 (unsigned int)out_buf.length,
162 (unsigned int)in_buf.length ));
163 gss_release_buffer(&minor, &out_buf);
164 return NT_STATUS_INVALID_PARAMETER;
167 memcpy(buf + 8, out_buf.value, out_buf.length);
168 smb_setlen(buf, out_buf.length + 4);
170 gss_release_buffer(&minor, &out_buf);
175 /******************************************************************************
176 Generic code for client and server.
177 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
178 ******************************************************************************/
180 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
181 NTSTATUS common_gss_encrypt_buffer(gss_ctx_id_t context_handle, char *buf, char **ppbuf_out)
186 gss_buffer_desc in_buf, out_buf;
187 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
192 return NT_STATUS_BUFFER_TOO_SMALL;
195 in_buf.value = buf + 8;
196 in_buf.length = buf_len - 8;
198 ret = gss_wrap(&minor,
200 True, /* we want sign+seal. */
203 &flags_got, /* did we get sign+seal ? */
206 if (ret != GSS_S_COMPLETE) {
207 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
208 DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
210 /* Um - no mapping for gss-errs to NTSTATUS yet. */
211 return ads_ntstatus(adss);
215 /* Sign+seal not supported. */
216 gss_release_buffer(&minor, &out_buf);
217 return NT_STATUS_NOT_SUPPORTED;
220 /* Ya see - this is why I *hate* gss-api. I don't
221 * want to have to malloc another buffer of the
222 * same size + 8 bytes just to get a continuous
223 * header + buffer, but gss won't let me pass in
224 * a pre-allocated buffer. Bastards (and you know
225 * who you are....). I might fix this by
226 * going to "encrypt_and_send" passing in a file
227 * descriptor and doing scatter-gather write with
228 * TCP cork on Linux. But I shouldn't have to
232 *ppbuf_out = SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
234 gss_release_buffer(&minor, &out_buf);
235 return NT_STATUS_NO_MEMORY;
238 memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
239 smb_setlen(*ppbuf_out, out_buf.length + 4);
241 gss_release_buffer(&minor, &out_buf);
246 /******************************************************************************
247 Generic code for client and server.
248 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
249 ******************************************************************************/
251 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
253 if (!common_encryption_on(es)) {
254 /* Not encrypting. */
259 /* Ignore session keepalives. */
260 if(CVAL(buffer,0) == SMBkeepalive) {
265 switch (es->smb_enc_type) {
266 case SMB_TRANS_ENC_NTLM:
267 return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, buffer, buf_out);
268 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
269 case SMB_TRANS_ENC_GSS:
270 return common_gss_encrypt_buffer(es->s.context_handle, buffer, buf_out);
273 return NT_STATUS_NOT_SUPPORTED;
277 /******************************************************************************
278 Generic code for client and server.
279 Decrypt an incoming SMB buffer. Replaces the data within it.
280 New data must be less than or equal to the current length.
281 ******************************************************************************/
283 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
285 if (!common_encryption_on(es)) {
286 /* Not decrypting. */
290 /* Ignore session keepalives. */
291 if(CVAL(buf,0) == SMBkeepalive) {
295 switch (es->smb_enc_type) {
296 case SMB_TRANS_ENC_NTLM:
297 return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
298 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
299 case SMB_TRANS_ENC_GSS:
300 return common_gss_decrypt_buffer(es->s.context_handle, buf);
303 return NT_STATUS_NOT_SUPPORTED;
307 /******************************************************************************
308 Shutdown an encryption state.
309 ******************************************************************************/
311 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
313 struct smb_trans_enc_state *es = *pp_es;
319 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
320 if (es->s.ntlmssp_state) {
321 ntlmssp_end(&es->s.ntlmssp_state);
324 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
325 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
326 /* Free the gss context handle. */
333 /******************************************************************************
334 Free an encryption-allocated buffer.
335 ******************************************************************************/
337 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
339 if (!common_encryption_on(es)) {
343 /* We know this is an smb buffer, and we
344 * didn't malloc, only copy, for a keepalive,
345 * so ignore session keepalives. */
347 if(CVAL(buf,0) == SMBkeepalive) {
351 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
356 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
357 /* gss-api free buffer.... */
361 /******************************************************************************
362 Client side encryption.
363 ******************************************************************************/
365 /******************************************************************************
366 Is client encryption on ?
367 ******************************************************************************/
369 BOOL cli_encryption_on(struct cli_state *cli)
371 return common_encryption_on(cli->trans_enc_state);
374 /******************************************************************************
375 Shutdown a client encryption state.
376 ******************************************************************************/
378 void cli_free_encryption_context(struct cli_state *cli)
380 common_free_encryption_state(&cli->trans_enc_state);
383 /******************************************************************************
384 Free an encryption-allocated buffer.
385 ******************************************************************************/
387 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
389 common_free_enc_buffer(cli->trans_enc_state, buf);
392 /******************************************************************************
393 Decrypt an incoming buffer.
394 ******************************************************************************/
396 NTSTATUS cli_decrypt_message(struct cli_state *cli)
398 return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
401 /******************************************************************************
402 Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
403 ******************************************************************************/
405 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
407 return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);