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.
125 ******************************************************************************/
127 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
128 NTSTATUS common_gss_decrypt_buffer(gss_ctx_id_t context_handle, char *buf)
130 return NT_STATUS_NOT_SUPPORTED;
134 /******************************************************************************
135 Generic code for client and server.
136 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
137 ******************************************************************************/
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)
145 gss_buffer_desc in_buf, out_buf;
146 size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */
151 return NT_STATUS_BUFFER_TOO_SMALL;
154 in_buf.value = buf + 8;
155 in_buf.length = buf_len - 8;
157 ret = gss_wrap(&minor,
159 True, /* we want sign+seal. */
162 &flags_got, /* did we get sign+seal ? */
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",
169 /* Um - no mapping for gss-errs to NTSTATUS yet. */
170 return ads_ntstatus(adss);
174 /* Sign+seal not supported. */
175 gss_release_buffer(&minor, &out_buf);
176 return NT_STATUS_NOT_SUPPORTED;
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
191 *ppbuf_out = SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
193 gss_release_buffer(&minor, &out_buf);
194 return NT_STATUS_NO_MEMORY;
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);
204 /******************************************************************************
205 Generic code for client and server.
206 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
207 ******************************************************************************/
209 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
211 if (!common_encryption_on(es)) {
212 /* Not encrypting. */
217 /* Ignore session keepalives. */
218 if(CVAL(buffer,0) == SMBkeepalive) {
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);
231 return NT_STATUS_NOT_SUPPORTED;
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 ******************************************************************************/
241 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
243 if (!common_encryption_on(es)) {
244 /* Not decrypting. */
248 /* Ignore session keepalives. */
249 if(CVAL(buf,0) == SMBkeepalive) {
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);
261 return NT_STATUS_NOT_SUPPORTED;
265 /******************************************************************************
266 Shutdown an encryption state.
267 ******************************************************************************/
269 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
271 struct smb_trans_enc_state *es = *pp_es;
277 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
278 if (es->ntlmssp_state) {
279 ntlmssp_end(&es->ntlmssp_state);
282 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
283 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
284 /* Free the gss context handle. */
291 /******************************************************************************
292 Free an encryption-allocated buffer.
293 ******************************************************************************/
295 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
297 if (!common_encryption_on(es)) {
301 /* We know this is an smb buffer, and we
302 * didn't malloc, only copy, for a keepalive,
303 * so ignore session keepalives. */
305 if(CVAL(buf,0) == SMBkeepalive) {
309 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
314 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
315 /* gss-api free buffer.... */
319 /******************************************************************************
320 Client side encryption.
321 ******************************************************************************/
323 /******************************************************************************
324 Is client encryption on ?
325 ******************************************************************************/
327 BOOL cli_encryption_on(struct cli_state *cli)
329 return common_encryption_on(cli->trans_enc_state);
332 /******************************************************************************
333 Shutdown a client encryption state.
334 ******************************************************************************/
336 void cli_free_encryption_context(struct cli_state *cli)
338 common_free_encryption_state(&cli->trans_enc_state);
341 /******************************************************************************
342 Free an encryption-allocated buffer.
343 ******************************************************************************/
345 void cli_free_enc_buffer(struct cli_state *cli, char *buf)
347 common_free_enc_buffer(cli->trans_enc_state, buf);
350 /******************************************************************************
351 Decrypt an incoming buffer.
352 ******************************************************************************/
354 NTSTATUS cli_decrypt_message(struct cli_state *cli)
356 return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf);
359 /******************************************************************************
360 Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
361 ******************************************************************************/
363 NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
365 return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out);