libcli/smb Move smb_seal.h include to files that use it.
[Samba/gebeck_regimport.git] / libcli / smb / smb_seal.c
blob67a55126365fe98c77a348ce67843f9c0c8e2311
1 /*
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/>.
20 #include "includes.h"
21 #include "smb_common.h"
22 #include "libcli/auth/krb5_wrap.h"
23 #include "auth/gensec/gensec.h"
24 #include "libcli/smb/smb_seal.h"
26 #undef malloc
28 /******************************************************************************
29 Pull out the encryption context for this packet. 0 means global context.
30 ******************************************************************************/
32 NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num)
34 if (smb_len_nbt(buf) < 8) {
35 return NT_STATUS_INVALID_BUFFER_SIZE;
38 if (buf[4] == 0xFF) {
39 if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
40 /* Not an encrypted buffer. */
41 return NT_STATUS_NOT_FOUND;
43 if (buf[5] == 'E') {
44 *p_enc_ctx_num = SVAL(buf,6);
45 return NT_STATUS_OK;
48 return NT_STATUS_INVALID_NETWORK_RESPONSE;
51 /*******************************************************************
52 Set the length and marker of an encrypted smb packet.
53 ********************************************************************/
55 static void smb_set_enclen(char *buf,int len,uint16_t enc_ctx_num)
57 _smb_setlen_nbt(buf,len);
59 SCVAL(buf,4,0xFF);
60 SCVAL(buf,5,'E');
61 SSVAL(buf,6,enc_ctx_num);
64 /******************************************************************************
65 Generic code for client and server.
66 Is encryption turned on ?
67 ******************************************************************************/
69 bool common_encryption_on(struct smb_trans_enc_state *es)
71 return ((es != NULL) && es->enc_on);
74 /******************************************************************************
75 Generic code for client and server.
76 GENSEC decrypt an incoming buffer.
77 ******************************************************************************/
79 static NTSTATUS common_gensec_decrypt_buffer(struct gensec_security *gensec,
80 char *buf)
82 NTSTATUS status;
83 size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
84 DATA_BLOB in_buf, out_buf;
85 TALLOC_CTX *frame;
87 if (buf_len < 8) {
88 return NT_STATUS_BUFFER_TOO_SMALL;
91 frame = talloc_stackframe();
93 in_buf = data_blob_const(buf + 8, buf_len - 8);
95 status = gensec_unwrap(gensec, frame, &in_buf, &out_buf);
97 if (!NT_STATUS_IS_OK(status)) {
98 DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s\n",
99 nt_errstr(status)));
100 TALLOC_FREE(frame);
101 return status;
104 if (out_buf.length > in_buf.length) {
105 DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) !\n",
106 (unsigned int)out_buf.length,
107 (unsigned int)in_buf.length ));
108 TALLOC_FREE(frame);
109 return NT_STATUS_INVALID_PARAMETER;
112 memcpy(buf + 8, out_buf.data, out_buf.length);
114 /* Reset the length and overwrite the header. */
115 smb_setlen_nbt(buf, out_buf.length + 4);
117 TALLOC_FREE(frame);
119 return NT_STATUS_OK;
122 /******************************************************************************
123 Generic code for client and server.
124 NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
125 ******************************************************************************/
127 static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec,
128 uint16_t enc_ctx_num,
129 char *buf,
130 char **ppbuf_out)
132 NTSTATUS status;
133 DATA_BLOB in_buf, out_buf;
134 size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
135 TALLOC_CTX *frame;
137 *ppbuf_out = NULL;
139 if (buf_len < 8) {
140 return NT_STATUS_BUFFER_TOO_SMALL;
142 in_buf = data_blob_const(buf + 8, buf_len - 8);
144 frame = talloc_stackframe();
146 status = gensec_wrap(gensec, frame, &in_buf, &out_buf);
147 if (!NT_STATUS_IS_OK(status)) {
148 DEBUG(0,("common_gensec_encrypt_buffer: gensec_wrap failed. Error %s\n",
149 nt_errstr(status)));
150 TALLOC_FREE(frame);
151 return status;
154 *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
155 if (!*ppbuf_out) {
156 TALLOC_FREE(frame);
157 return NT_STATUS_NO_MEMORY;
160 memcpy(*ppbuf_out+8, out_buf.data, out_buf.length);
161 smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
163 TALLOC_FREE(frame);
165 return NT_STATUS_OK;
168 /******************************************************************************
169 Generic code for client and server.
170 gss-api decrypt an incoming buffer. We insist that the size of the
171 unwrapped buffer must be smaller or identical to the incoming buffer.
172 ******************************************************************************/
174 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
175 static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
177 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
178 OM_uint32 ret = 0;
179 OM_uint32 minor = 0;
180 int flags_got = 0;
181 gss_buffer_desc in_buf, out_buf;
182 size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
184 if (buf_len < 8) {
185 return NT_STATUS_BUFFER_TOO_SMALL;
188 in_buf.value = buf + 8;
189 in_buf.length = buf_len - 8;
191 ret = gss_unwrap(&minor,
192 gss_ctx,
193 &in_buf,
194 &out_buf,
195 &flags_got, /* did we get sign+seal ? */
196 (gss_qop_t *) NULL);
198 if (ret != GSS_S_COMPLETE) {
199 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
200 char *gss_err;
202 gss_err = gssapi_error_string(talloc_tos(),
203 ret, minor,
204 GSS_C_NULL_OID);
205 DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap failed. "
206 "Error [%d/%d] - %s - %s\n",
207 ret, minor, nt_errstr(status),
208 gss_err ? gss_err : "<unknown>"));
209 talloc_free(gss_err);
211 return status;
214 if (out_buf.length > in_buf.length) {
215 DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
216 (unsigned int)out_buf.length,
217 (unsigned int)in_buf.length ));
218 gss_release_buffer(&minor, &out_buf);
219 return NT_STATUS_INVALID_PARAMETER;
222 memcpy(buf + 8, out_buf.value, out_buf.length);
223 /* Reset the length and overwrite the header. */
224 smb_setlen_nbt(buf, out_buf.length + 4);
226 gss_release_buffer(&minor, &out_buf);
227 return NT_STATUS_OK;
230 /******************************************************************************
231 Generic code for client and server.
232 gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
233 ******************************************************************************/
235 static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
236 uint16_t enc_ctx_num,
237 char *buf,
238 char **ppbuf_out)
240 gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
241 OM_uint32 ret = 0;
242 OM_uint32 minor = 0;
243 int flags_got = 0;
244 gss_buffer_desc in_buf, out_buf;
245 size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
247 *ppbuf_out = NULL;
249 if (buf_len < 8) {
250 return NT_STATUS_BUFFER_TOO_SMALL;
253 in_buf.value = buf + 8;
254 in_buf.length = buf_len - 8;
256 ret = gss_wrap(&minor,
257 gss_ctx,
258 true, /* we want sign+seal. */
259 GSS_C_QOP_DEFAULT,
260 &in_buf,
261 &flags_got, /* did we get sign+seal ? */
262 &out_buf);
264 if (ret != GSS_S_COMPLETE) {
265 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
266 char *gss_err;
268 gss_err = gssapi_error_string(talloc_tos(),
269 ret, minor,
270 GSS_C_NULL_OID);
271 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. "
272 "Error [%d/%d] - %s - %s\n",
273 ret, minor, nt_errstr(status),
274 gss_err ? gss_err : "<unknown>"));
275 talloc_free(gss_err);
277 return status;
280 if (!flags_got) {
281 /* Sign+seal not supported. */
282 gss_release_buffer(&minor, &out_buf);
283 return NT_STATUS_NOT_SUPPORTED;
286 /* Ya see - this is why I *hate* gss-api. I don't
287 * want to have to malloc another buffer of the
288 * same size + 8 bytes just to get a continuous
289 * header + buffer, but gss won't let me pass in
290 * a pre-allocated buffer. Bastards (and you know
291 * who you are....). I might fix this by
292 * going to "encrypt_and_send" passing in a file
293 * descriptor and doing scatter-gather write with
294 * TCP cork on Linux. But I shouldn't have to
295 * bother :-*(. JRA.
298 *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
299 if (!*ppbuf_out) {
300 gss_release_buffer(&minor, &out_buf);
301 return NT_STATUS_NO_MEMORY;
304 memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
305 smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
307 gss_release_buffer(&minor, &out_buf);
308 return NT_STATUS_OK;
310 #endif
312 /******************************************************************************
313 Generic code for client and server.
314 Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
315 ******************************************************************************/
317 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
319 if (!common_encryption_on(es)) {
320 /* Not encrypting. */
321 *buf_out = buffer;
322 return NT_STATUS_OK;
325 switch (es->smb_enc_type) {
326 case SMB_TRANS_ENC_NTLM:
327 return common_gensec_encrypt_buffer(es->s.gensec_security, es->enc_ctx_num, buffer, buf_out);
328 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
329 case SMB_TRANS_ENC_GSS:
330 return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
331 #endif
332 default:
333 return NT_STATUS_NOT_SUPPORTED;
337 /******************************************************************************
338 Generic code for client and server.
339 Decrypt an incoming SMB buffer. Replaces the data within it.
340 New data must be less than or equal to the current length.
341 ******************************************************************************/
343 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
345 if (!common_encryption_on(es)) {
346 /* Not decrypting. */
347 return NT_STATUS_OK;
350 switch (es->smb_enc_type) {
351 case SMB_TRANS_ENC_NTLM:
352 return common_gensec_decrypt_buffer(es->s.gensec_security, buf);
353 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
354 case SMB_TRANS_ENC_GSS:
355 return common_gss_decrypt_buffer(es->s.gss_state, buf);
356 #endif
357 default:
358 return NT_STATUS_NOT_SUPPORTED;
362 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
363 /******************************************************************************
364 Shutdown a gss encryption state.
365 ******************************************************************************/
367 static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
369 OM_uint32 minor = 0;
370 struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
372 if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
373 gss_release_cred(&minor, &gss_state->creds);
375 if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
376 gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
378 SAFE_FREE(*pp_gss_state);
380 #endif
382 /******************************************************************************
383 Shutdown an encryption state.
384 ******************************************************************************/
386 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
388 struct smb_trans_enc_state *es = *pp_es;
390 if (es == NULL) {
391 return;
394 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
395 if (es->s.gensec_security) {
396 TALLOC_FREE(es->s.gensec_security);
399 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
400 if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
401 /* Free the gss context handle. */
402 if (es->s.gss_state) {
403 common_free_gss_state(&es->s.gss_state);
406 #endif
407 SAFE_FREE(es);
408 *pp_es = NULL;
411 /******************************************************************************
412 Free an encryption-allocated buffer.
413 ******************************************************************************/
415 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
417 uint16_t enc_ctx_num;
419 if (!common_encryption_on(es)) {
420 return;
423 if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
424 &enc_ctx_num))) {
425 return;
428 SAFE_FREE(buf);