dns: Use new DNS debugclass in DNS server
[kai/samba.git] / libcli / smb / 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 "smb_common.h"
22 #if HAVE_KRB5
23 #include "lib/krb5_wrap/krb5_samba.h"
24 #endif
25 #include "auth/gensec/gensec.h"
26 #include "libcli/smb/smb_seal.h"
27
28 #undef malloc
29
30 /******************************************************************************
31  Pull out the encryption context for this packet. 0 means global context.
32 ******************************************************************************/
33
34 NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num)
35 {
36         if (smb_len_nbt(buf) < 8) {
37                 return NT_STATUS_INVALID_BUFFER_SIZE;
38         }
39
40         if (buf[4] == 0xFF) {
41                 if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
42                         /* Not an encrypted buffer. */
43                         return NT_STATUS_NOT_FOUND;
44                 }
45                 if (buf[5] == 'E') {
46                         *p_enc_ctx_num = SVAL(buf,6);
47                         return NT_STATUS_OK;
48                 }
49         }
50         return NT_STATUS_INVALID_NETWORK_RESPONSE;
51 }
52
53 /*******************************************************************
54  Set the length and marker of an encrypted smb packet.
55 ********************************************************************/
56
57 static void smb_set_enclen(char *buf,int len,uint16_t enc_ctx_num)
58 {
59         _smb_setlen_tcp(buf,len);
60
61         SCVAL(buf,4,0xFF);
62         SCVAL(buf,5,'E');
63         SSVAL(buf,6,enc_ctx_num);
64 }
65
66 /******************************************************************************
67  Generic code for client and server.
68  Is encryption turned on ?
69 ******************************************************************************/
70
71 bool common_encryption_on(struct smb_trans_enc_state *es)
72 {
73         return ((es != NULL) && es->enc_on);
74 }
75
76 /******************************************************************************
77  Generic code for client and server.
78  GENSEC decrypt an incoming buffer.
79 ******************************************************************************/
80
81 static NTSTATUS common_gensec_decrypt_buffer(struct gensec_security *gensec,
82                                              char *buf)
83 {
84         NTSTATUS status;
85         size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
86         DATA_BLOB in_buf, out_buf;
87         TALLOC_CTX *frame;
88
89         if (buf_len < 8) {
90                 return NT_STATUS_BUFFER_TOO_SMALL;
91         }
92
93         frame = talloc_stackframe();
94
95         in_buf = data_blob_const(buf + 8, buf_len - 8);
96
97         status = gensec_unwrap(gensec, frame, &in_buf, &out_buf);
98
99         if (!NT_STATUS_IS_OK(status)) {
100                 DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s\n",
101                          nt_errstr(status)));
102                 TALLOC_FREE(frame);
103                 return status;
104         }
105
106         if (out_buf.length > in_buf.length) {
107                 DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) !\n",
108                         (unsigned int)out_buf.length,
109                         (unsigned int)in_buf.length ));
110                 TALLOC_FREE(frame);
111                 return NT_STATUS_INVALID_PARAMETER;
112         }
113
114         memcpy(buf + 8, out_buf.data, out_buf.length);
115
116         /* Reset the length and overwrite the header. */
117         smb_setlen_nbt(buf, out_buf.length + 4);
118
119         TALLOC_FREE(frame);
120
121         return NT_STATUS_OK;
122 }
123
124 /******************************************************************************
125  Generic code for client and server.
126  NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
127 ******************************************************************************/
128
129 static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec,
130                                       uint16_t enc_ctx_num,
131                                       char *buf,
132                                       char **ppbuf_out)
133 {
134         NTSTATUS status;
135         DATA_BLOB in_buf, out_buf;
136         size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
137         TALLOC_CTX *frame;
138
139         *ppbuf_out = NULL;
140
141         if (buf_len < 8) {
142                 return NT_STATUS_BUFFER_TOO_SMALL;
143         }
144         in_buf = data_blob_const(buf + 8, buf_len - 8);
145
146         frame = talloc_stackframe();
147
148         status = gensec_wrap(gensec, frame, &in_buf, &out_buf);
149         if (!NT_STATUS_IS_OK(status)) {
150                 DEBUG(0,("common_gensec_encrypt_buffer: gensec_wrap failed. Error %s\n",
151                          nt_errstr(status)));
152                 TALLOC_FREE(frame);
153                 return status;
154         }
155
156         *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
157         if (!*ppbuf_out) {
158                 TALLOC_FREE(frame);
159                 return NT_STATUS_NO_MEMORY;
160         }
161
162         memcpy(*ppbuf_out+8, out_buf.data, out_buf.length);
163         smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
164
165         TALLOC_FREE(frame);
166
167         return NT_STATUS_OK;
168 }
169
170 /******************************************************************************
171  Generic code for client and server.
172  Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
173 ******************************************************************************/
174
175 NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
176 {
177         if (!common_encryption_on(es)) {
178                 /* Not encrypting. */
179                 *buf_out = buffer;
180                 return NT_STATUS_OK;
181         }
182
183         return common_gensec_encrypt_buffer(es->gensec_security, es->enc_ctx_num, buffer, buf_out);
184 }
185
186 /******************************************************************************
187  Generic code for client and server.
188  Decrypt an incoming SMB buffer. Replaces the data within it.
189  New data must be less than or equal to the current length.
190 ******************************************************************************/
191
192 NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
193 {
194         if (!common_encryption_on(es)) {
195                 /* Not decrypting. */
196                 return NT_STATUS_OK;
197         }
198
199         return common_gensec_decrypt_buffer(es->gensec_security, buf);
200 }
201
202 /******************************************************************************
203  Free an encryption-allocated buffer.
204 ******************************************************************************/
205
206 void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
207 {
208         uint16_t enc_ctx_num;
209
210         if (!common_encryption_on(es)) {
211                 return;
212         }
213
214         if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
215                         &enc_ctx_num))) {
216                 return;
217         }
218
219         SAFE_FREE(buf);
220 }