s3:libsmb/smb_seal: avoid ads_errstr() dependency and use gssapi_error_string()
[rusty/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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../auth/ntlmssp/ntlmssp.h"
22 #include "smb_crypt.h"
23 #include "libsmb/libsmb.h"
24 #include "ntlmssp_wrap.h"
25 #include "libcli/auth/krb5_wrap.h"
26
27
28 /******************************************************************************
29  Pull out the encryption context for this packet. 0 means global context.
30 ******************************************************************************/
31
32 NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num)
33 {
34         if (smb_len_nbt(buf) < 8) {
35                 return NT_STATUS_INVALID_BUFFER_SIZE;
36         }
37
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;
42                 }
43                 if (buf[5] == 'E') {
44                         *p_enc_ctx_num = SVAL(buf,6);
45                         return NT_STATUS_OK;
46                 }
47         }
48         return NT_STATUS_INVALID_NETWORK_RESPONSE;
49 }
50
51 /*******************************************************************
52  Set the length and marker of an encrypted smb packet.
53 ********************************************************************/
54
55 static void smb_set_enclen(char *buf,int len,uint16_t enc_ctx_num)
56 {
57         _smb_setlen_nbt(buf,len);
58
59         SCVAL(buf,4,0xFF);
60         SCVAL(buf,5,'E');
61         SSVAL(buf,6,enc_ctx_num);
62 }
63
64 /******************************************************************************
65  Generic code for client and server.
66  Is encryption turned on ?
67 ******************************************************************************/
68
69 bool common_encryption_on(struct smb_trans_enc_state *es)
70 {
71         return ((es != NULL) && es->enc_on);
72 }
73
74 /******************************************************************************
75  Generic code for client and server.
76  NTLM decrypt an incoming buffer.
77  Abartlett tells me that SSPI puts the signature first before the encrypted
78  output, so cope with the same for compatibility.
79 ******************************************************************************/
80
81 static NTSTATUS common_ntlm_decrypt_buffer(struct auth_ntlmssp_state *auth_ntlmssp_state, char *buf)
82 {
83         NTSTATUS status;
84         size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
85         size_t data_len;
86         char *inbuf;
87         DATA_BLOB sig;
88
89         if (buf_len < 8 + NTLMSSP_SIG_SIZE) {
90                 return NT_STATUS_BUFFER_TOO_SMALL;
91         }
92
93         inbuf = (char *)smb_xmemdup(buf, buf_len);
94
95         /* Adjust for the signature. */
96         data_len = buf_len - 8 - NTLMSSP_SIG_SIZE;
97
98         /* Point at the signature. */
99         sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE);
100
101         status = auth_ntlmssp_unseal_packet(auth_ntlmssp_state,
102                 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */
103                 data_len,
104                 (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE,
105                 data_len,
106                 &sig);
107
108         if (!NT_STATUS_IS_OK(status)) {
109                 SAFE_FREE(inbuf);
110                 return status;
111         }
112
113         memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
114
115         /* Reset the length and overwrite the header. */
116         smb_setlen_nbt(buf,data_len + 4);
117
118         SAFE_FREE(inbuf);
119         return NT_STATUS_OK;
120 }
121
122 /******************************************************************************
123  Generic code for client and server.
124  NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
125  Abartlett tells me that SSPI puts the signature first before the encrypted
126  output, so do the same for compatibility.
127 ******************************************************************************/
128
129 static NTSTATUS common_ntlm_encrypt_buffer(struct auth_ntlmssp_state *auth_ntlmssp_state,
130                                 uint16_t enc_ctx_num,
131                                 char *buf,
132                                 char **ppbuf_out)
133 {
134         NTSTATUS status;
135         char *buf_out;
136         size_t data_len = smb_len_nbt(buf) - 4; /* Ignore the 0xFF SMB bytes. */
137         DATA_BLOB sig;
138         TALLOC_CTX *frame;
139         *ppbuf_out = NULL;
140
141         if (data_len == 0) {
142                 return NT_STATUS_BUFFER_TOO_SMALL;
143         }
144
145         frame = talloc_stackframe();
146         /* 
147          * We know smb_len_nbt can't return a value > 128k, so no int overflow
148          * check needed.
149          */
150
151         buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len);
152
153         /* Copy the data from the original buffer. */
154
155         memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len);
156
157         smb_set_enclen(buf_out, smb_len_nbt(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num);
158
159         ZERO_STRUCT(sig);
160
161         status = auth_ntlmssp_seal_packet(auth_ntlmssp_state,
162                                      frame,
163                 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */
164                 data_len,
165                 (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE,
166                 data_len,
167                 &sig);
168
169         if (!NT_STATUS_IS_OK(status)) {
170                 talloc_free(frame);
171                 SAFE_FREE(buf_out);
172                 return status;
173         }
174
175         /* First 16 data bytes are signature for SSPI compatibility. */
176         memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE);
177         talloc_free(frame);
178         *ppbuf_out = buf_out;
179         return NT_STATUS_OK;
180 }
181
182 /******************************************************************************
183  Generic code for client and server.
184  gss-api decrypt an incoming buffer. We insist that the size of the
185  unwrapped buffer must be smaller or identical to the incoming buffer.
186 ******************************************************************************/
187
188 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
189 static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf)
190 {
191         gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
192         OM_uint32 ret = 0;
193         OM_uint32 minor = 0;
194         int flags_got = 0;
195         gss_buffer_desc in_buf, out_buf;
196         size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
197
198         if (buf_len < 8) {
199                 return NT_STATUS_BUFFER_TOO_SMALL;
200         }
201
202         in_buf.value = buf + 8;
203         in_buf.length = buf_len - 8;
204
205         ret = gss_unwrap(&minor,
206                         gss_ctx,
207                         &in_buf,
208                         &out_buf,
209                         &flags_got,             /* did we get sign+seal ? */
210                         (gss_qop_t *) NULL);    
211
212         if (ret != GSS_S_COMPLETE) {
213                 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
214                 char *gss_err;
215
216                 gss_err = gssapi_error_string(talloc_tos(),
217                                               ret, minor,
218                                               GSS_C_NULL_OID);
219                 DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap failed. "
220                          "Error [%d/%d] - %s - %s\n",
221                          ret, minor, nt_errstr(status),
222                          gss_err ? gss_err : "<unknown>"));
223                 talloc_free(gss_err);
224
225                 return status;
226         }
227
228         if (out_buf.length > in_buf.length) {
229                 DEBUG(0,("common_gss_decrypt_buffer: gss_unwrap size (%u) too large (%u) !\n",
230                         (unsigned int)out_buf.length,
231                         (unsigned int)in_buf.length ));
232                 gss_release_buffer(&minor, &out_buf);
233                 return NT_STATUS_INVALID_PARAMETER;
234         }
235
236         memcpy(buf + 8, out_buf.value, out_buf.length);
237         /* Reset the length and overwrite the header. */
238         smb_setlen_nbt(buf, out_buf.length + 4);
239
240         gss_release_buffer(&minor, &out_buf);
241         return NT_STATUS_OK;
242 }
243
244 /******************************************************************************
245  Generic code for client and server.
246  gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
247 ******************************************************************************/
248
249 static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state,
250                                         uint16_t enc_ctx_num,
251                                         char *buf,
252                                         char **ppbuf_out)
253 {
254         gss_ctx_id_t gss_ctx = gss_state->gss_ctx;
255         OM_uint32 ret = 0;
256         OM_uint32 minor = 0;
257         int flags_got = 0;
258         gss_buffer_desc in_buf, out_buf;
259         size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
260
261         *ppbuf_out = NULL;
262
263         if (buf_len < 8) {
264                 return NT_STATUS_BUFFER_TOO_SMALL;
265         }
266
267         in_buf.value = buf + 8;
268         in_buf.length = buf_len - 8;
269
270         ret = gss_wrap(&minor,
271                         gss_ctx,
272                         true,                   /* we want sign+seal. */
273                         GSS_C_QOP_DEFAULT,
274                         &in_buf,
275                         &flags_got,             /* did we get sign+seal ? */
276                         &out_buf);
277
278         if (ret != GSS_S_COMPLETE) {
279                 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
280                 char *gss_err;
281
282                 gss_err = gssapi_error_string(talloc_tos(),
283                                               ret, minor,
284                                               GSS_C_NULL_OID);
285                 DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. "
286                          "Error [%d/%d] - %s - %s\n",
287                          ret, minor, nt_errstr(status),
288                          gss_err ? gss_err : "<unknown>"));
289                 talloc_free(gss_err);
290
291                 return status;
292         }
293
294         if (!flags_got) {
295                 /* Sign+seal not supported. */
296                 gss_release_buffer(&minor, &out_buf);
297                 return NT_STATUS_NOT_SUPPORTED;
298         }
299
300         /* Ya see - this is why I *hate* gss-api. I don't 
301          * want to have to malloc another buffer of the
302          * same size + 8 bytes just to get a continuous
303          * header + buffer, but gss won't let me pass in
304          * a pre-allocated buffer. Bastards (and you know
305          * who you are....). I might fix this by
306          * going to "encrypt_and_send" passing in a file
307          * descriptor and doing scatter-gather write with
308          * TCP cork on Linux. But I shouldn't have to
309          * bother :-*(. JRA.
310          */
311
312         *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */
313         if (!*ppbuf_out) {
314                 gss_release_buffer(&minor, &out_buf);
315                 return NT_STATUS_NO_MEMORY;
316         }
317
318         memcpy(*ppbuf_out+8, out_buf.value, out_buf.length);
319         smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
320
321         gss_release_buffer(&minor, &out_buf);
322         return NT_STATUS_OK;
323 }
324 #endif
325
326 /******************************************************************************
327  Generic code for client and server.
328  Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
329 ******************************************************************************/
330
331 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
332 {
333         if (!common_encryption_on(es)) {
334                 /* Not encrypting. */
335                 *buf_out = buffer;
336                 return NT_STATUS_OK;
337         }
338
339         switch (es->smb_enc_type) {
340                 case SMB_TRANS_ENC_NTLM:
341                         return common_ntlm_encrypt_buffer(es->s.auth_ntlmssp_state, es->enc_ctx_num, buffer, buf_out);
342 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
343                 case SMB_TRANS_ENC_GSS:
344                         return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out);
345 #endif
346                 default:
347                         return NT_STATUS_NOT_SUPPORTED;
348         }
349 }
350
351 /******************************************************************************
352  Generic code for client and server.
353  Decrypt an incoming SMB buffer. Replaces the data within it.
354  New data must be less than or equal to the current length.
355 ******************************************************************************/
356
357 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
358 {
359         if (!common_encryption_on(es)) {
360                 /* Not decrypting. */
361                 return NT_STATUS_OK;
362         }
363
364         switch (es->smb_enc_type) {
365                 case SMB_TRANS_ENC_NTLM:
366                         return common_ntlm_decrypt_buffer(es->s.auth_ntlmssp_state, buf);
367 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
368                 case SMB_TRANS_ENC_GSS:
369                         return common_gss_decrypt_buffer(es->s.gss_state, buf);
370 #endif
371                 default:
372                         return NT_STATUS_NOT_SUPPORTED;
373         }
374 }
375
376 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
377 /******************************************************************************
378  Shutdown a gss encryption state.
379 ******************************************************************************/
380
381 static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state)
382 {
383         OM_uint32 minor = 0;
384         struct smb_tran_enc_state_gss *gss_state = *pp_gss_state;
385
386         if (gss_state->creds != GSS_C_NO_CREDENTIAL) {
387                 gss_release_cred(&minor, &gss_state->creds);
388         }
389         if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) {
390                 gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL);
391         }
392         SAFE_FREE(*pp_gss_state);
393 }
394 #endif
395
396 /******************************************************************************
397  Shutdown an encryption state.
398 ******************************************************************************/
399
400 void common_free_encryption_state(struct smb_trans_enc_state **pp_es)
401 {
402         struct smb_trans_enc_state *es = *pp_es;
403
404         if (es == NULL) {
405                 return;
406         }
407
408         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
409                 if (es->s.auth_ntlmssp_state) {
410                         TALLOC_FREE(es->s.auth_ntlmssp_state);
411                 }
412         }
413 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
414         if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
415                 /* Free the gss context handle. */
416                 if (es->s.gss_state) {
417                         common_free_gss_state(&es->s.gss_state);
418                 }
419         }
420 #endif
421         SAFE_FREE(es);
422         *pp_es = NULL;
423 }
424
425 /******************************************************************************
426  Free an encryption-allocated buffer.
427 ******************************************************************************/
428
429 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
430 {
431         uint16_t enc_ctx_num;
432
433         if (!common_encryption_on(es)) {
434                 return;
435         }
436
437         if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
438                         &enc_ctx_num))) {
439                 return;
440         }
441
442         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
443                 SAFE_FREE(buf);
444                 return;
445         }
446
447 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
448         if (es->smb_enc_type == SMB_TRANS_ENC_GSS) {
449                 OM_uint32 min;
450                 gss_buffer_desc rel_buf;
451                 rel_buf.value = buf;
452                 rel_buf.length = smb_len_nbt(buf) + 4;
453                 gss_release_buffer(&min, &rel_buf);
454         }
455 #endif
456 }