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 3 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, see <http://www.gnu.org/licenses/>.
22 /******************************************************************************
23 Pull out the encryption context for this packet. 0 means global context.
24 ******************************************************************************/
26 NTSTATUS get_enc_ctx_num(char *buf, uint16 *p_enc_ctx_num)
28 if (smb_len(buf) < 8) {
29 return NT_STATUS_INVALID_BUFFER_SIZE;
32 if (buf[4] == (char)0xFF) {
33 if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
34 /* Not an encrypted buffer. */
35 return NT_STATUS_NOT_FOUND;
38 *p_enc_ctx_num = SVAL(buf,6);
42 return NT_STATUS_INVALID_NETWORK_RESPONSE;
45 /******************************************************************************
46 Generic code for client and server.
47 Is encryption turned on ?
48 ******************************************************************************/
50 BOOL common_encryption_on(struct smb_trans_enc_state *es)
52 return ((es != NULL) && es->enc_on);
55 /******************************************************************************
56 Generic code for client and server.
57 NTLM decrypt an incoming buffer.
58 Abartlett tells me that SSPI puts the signature first before the encrypted
59 output, so cope with the same for compatibility.
60 ******************************************************************************/
62 NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
65 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
70 if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
71 return NT_STATUS_BUFFER_TOO_SMALL;
74 inbuf = (char *)smb_xmemdup(buf, buf_len);
76 /* Adjust for the signature. */
77 data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
79 /* Point at the signature. */
80 sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
82 status = ntlmssp_unseal_packet(ntlmssp_state,
83 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */
85 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE,
89 if (!NT_STATUS_IS_OK(status)) {
94 memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
96 /* Reset the length. */
97 smb_setlen(inbuf, buf, data_len + 4);
103 /******************************************************************************
104 Generic code for client and server.
105 NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
106 Abartlett tells me that SSPI puts the signature first before the encrypted
107 output, so do the same for compatibility.
108 ******************************************************************************/
110 NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state,
117 size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */
123 return NT_STATUS_BUFFER_TOO_SMALL;
127 * We know smb_len can't return a value > 128k, so no int overflow
131 buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
133 /* Copy the data from the original buffer. */
135 memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len);
137 smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
139 sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
141 status = ntlmssp_seal_packet(ntlmssp_state,
142 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
144 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE,
148 if (!NT_STATUS_IS_OK(status)) {
149 data_blob_free(&sig);
154 /* First 16 data bytes are signature for SSPI compatibility. */
155 memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE);
156 *ppbuf_out = buf_out;
160 /******************************************************************************
161 Generic code for client and server.
162 gss-api decrypt an incoming buffer. We insist that the size of the
163 unwrapped buffer must be smaller or identical to the incoming buffer.
164 ******************************************************************************/
166 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
167 static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
169 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
173 gss_buffer_desc in_buf, out_buf;
174 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
177 return NT_STATUS_BUFFER_TOO_SMALL;
180 in_buf.value = buf + 8;
181 in_buf.length = buf_len - 8;
183 ret = gss_unwrap(&minor,
187 &flags_got, /* did we get sign+seal ? */
190 if (ret != GSS_S_COMPLETE) {
191 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
192 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n",
194 return map_nt_error_from_gss(ret, minor);
197 if (out_buf.length > in_buf.length) {
198 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
199 (unsigned int)out_buf.length,
200 (unsigned int)in_buf.length ));
201 gss_release_buffer(&minor, &out_buf);
202 return NT_STATUS_INVALID_PARAMETER;
205 memcpy(buf + 8, out_buf.value, out_buf.length);
206 smb_setlen((char *)out_buf.value, buf, out_buf.length + 4);
208 gss_release_buffer(&minor, &out_buf);
212 /******************************************************************************
213 Generic code for client and server.
214 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
215 ******************************************************************************/
217 static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
222 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
226 gss_buffer_desc in_buf, out_buf;
227 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
232 return NT_STATUS_BUFFER_TOO_SMALL;
235 in_buf.value = buf + 8;
236 in_buf.length = buf_len - 8;
238 ret = gss_wrap(&minor,
240 True, /* we want sign+seal. */
243 &flags_got, /* did we get sign+seal ? */
246 if (ret != GSS_S_COMPLETE) {
247 ADS_STATUS adss = ADS_ERROR_GSS(ret, minor);
248 DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n",
250 return map_nt_error_from_gss(ret, minor);
254 /* Sign+seal not supported. */
255 gss_release_buffer(&minor, &out_buf);
256 return NT_STATUS_NOT_SUPPORTED;
259 /* Ya see - this is why I *hate* gss-api. I don't
260 * want to have to malloc another buffer of the
261 * same size + 8 bytes just to get a continuous
262 * header + buffer, but gss won't let me pass in
263 * a pre-allocated buffer. Bastards (and you know
264 * who you are....). I might fix this by
265 * going to "encrypt_and_send" passing in a file
266 * descriptor and doing scatter-gather write with
267 * TCP cork on Linux. But I shouldn't have to
271 *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
273 gss_release_buffer(&minor, &out_buf);
274 return NT_STATUS_NO_MEMORY;
277 memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
278 smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
280 gss_release_buffer(&minor, &out_buf);
285 /******************************************************************************
286 Generic code for client and server.
287 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
288 ******************************************************************************/
290 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
292 if (!common_encryption_on(es)) {
293 /* Not encrypting. */
298 switch (es->smb_enc_type) {
299 case SMB_TRANS_ENC_NTLM:
300 return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
301 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
302 case SMB_TRANS_ENC_GSS:
303 return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
306 return NT_STATUS_NOT_SUPPORTED;
310 /******************************************************************************
311 Generic code for client and server.
312 Decrypt an incoming SMB buffer. Replaces the data within it.
313 New data must be less than or equal to the current length.
314 ******************************************************************************/
316 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
318 if (!common_encryption_on(es)) {
319 /* Not decrypting. */
323 switch (es->smb_enc_type) {
324 case SMB_TRANS_ENC_NTLM:
325 return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf);
326 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
327 case SMB_TRANS_ENC_GSS:
328 return common_gss_decrypt_buffer(es->s.gss_state, buf);
331 return NT_STATUS_NOT_SUPPORTED;
335 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
336 /******************************************************************************
337 Shutdown a gss encryption state.
338 ******************************************************************************/
340 static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
343 struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
345 if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
346 gss_release_cred(&minor, &gss_state->creds);
348 if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
349 gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
351 SAFE_FREE(*pp_gss_state);
355 /******************************************************************************
356 Shutdown an encryption state.
357 ******************************************************************************/
359 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
361 struct smb_trans_enc_state *es = *pp_es;
367 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
368 if (es->s.ntlmssp_state) {
369 ntlmssp_end(&es->s.ntlmssp_state);
372 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
373 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
374 /* Free the gss context handle. */
375 if (es->s.gss_state) {
376 common_free_gss_state(&es->s.gss_state);
384 /******************************************************************************
385 Free an encryption-allocated buffer.
386 ******************************************************************************/
388 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
390 if (!common_encryption_on(es)) {
394 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
399 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
400 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
402 gss_buffer_desc rel_buf;
404 rel_buf.length = smb_len(buf) + 4;
405 gss_release_buffer(&min, &rel_buf);
410 /******************************************************************************
411 Client side encryption.
412 ******************************************************************************/
414 /******************************************************************************
415 Is client encryption on ?
416 ******************************************************************************/
418 BOOL cli_encryption_on(struct cli_state *cli)
420 /* If we supported multiple encrytion contexts
421 * here we'd look up based on tid.
423 return common_encryption_on(cli->trans_enc_state);
426 /******************************************************************************
427 Shutdown a client encryption state.
428 ******************************************************************************/
430 void cli_free_encryption_context(struct cli_state *cli)
432 common_free_encryption_state(&cli->trans_enc_state);
435 /******************************************************************************
436 Free an encryption-allocated buffer.
437 ******************************************************************************/
439 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
441 /* We know this is an smb buffer, and we
442 * didn't malloc, only copy, for a keepalive,
443 * so ignore session keepalives. */
445 if(CVAL(buf,0) == SMBkeepalive) {
449 /* If we supported multiple encrytion contexts
450 * here we'd look up based on tid.
452 common_free_enc_buffer(cli->trans_enc_state, buf);
455 /******************************************************************************
456 Decrypt an incoming buffer.
457 ******************************************************************************/
459 NTSTATUS cli_decrypt_message(struct cli_state *cli)
464 /* Ignore session keepalives. */
465 if(CVAL(cli->inbuf,0) == SMBkeepalive) {
469 status = get_enc_ctx_num(cli->inbuf, &enc_ctx_num);
470 if (!NT_STATUS_IS_OK(status)) {
474 if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
475 return NT_STATUS_INVALID_HANDLE;
478 return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
481 /******************************************************************************
482 Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
483 ******************************************************************************/
485 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
487 /* Ignore session keepalives. */
488 if(CVAL(cli->outbuf,0) == SMBkeepalive) {
492 /* If we supported multiple encrytion contexts
493 * here we'd look up based on tid.
495 return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);