~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libsmb/smb_seal.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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