Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB Transport encryption (sealing) code - server 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 "smbd/smbd.h"
22 : #include "smbd/globals.h"
23 : #include "../libcli/smb/smb_seal.h"
24 : #include "auth.h"
25 : #include "libsmb/libsmb.h"
26 : #include "../lib/tsocket/tsocket.h"
27 : #include "auth/gensec/gensec.h"
28 :
29 : /******************************************************************************
30 : Server side encryption.
31 : ******************************************************************************/
32 :
33 : /******************************************************************************
34 : Return global enc context - this must change if we ever do multiple contexts.
35 : ******************************************************************************/
36 :
37 185802 : static uint16_t srv_enc_ctx(const struct smb_trans_enc_state *es)
38 : {
39 185802 : return es->enc_ctx_num;
40 : }
41 :
42 : /******************************************************************************
43 : Is this an incoming encrypted packet ?
44 : ******************************************************************************/
45 :
46 1354896 : bool is_encrypted_packet(const uint8_t *inbuf)
47 : {
48 16730 : NTSTATUS status;
49 16730 : uint16_t enc_num;
50 :
51 : /* Ignore non-session messages or non 0xFF'E' messages. */
52 1354896 : if(CVAL(inbuf,0)
53 1354722 : || (smb_len(inbuf) < 8)
54 1354710 : || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
55 1152364 : return false;
56 : }
57 :
58 185802 : status = get_enc_ctx_num(inbuf, &enc_num);
59 185802 : if (!NT_STATUS_IS_OK(status)) {
60 0 : return false;
61 : }
62 :
63 : /* Encrypted messages are 0xFF'E'<ctx> */
64 185802 : if (srv_trans_enc_ctx && enc_num == srv_enc_ctx(srv_trans_enc_ctx)) {
65 185802 : return true;
66 : }
67 0 : return false;
68 : }
69 :
70 : /******************************************************************************
71 : Create an gensec_security and ensure pointer copy is correct.
72 : ******************************************************************************/
73 :
74 446 : static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
75 : const struct tsocket_address *local_address,
76 : struct smb_trans_enc_state *es)
77 : {
78 0 : NTSTATUS status;
79 :
80 446 : status = auth_generic_prepare(es, remote_address,
81 : local_address,
82 : "SMB encryption",
83 : &es->gensec_security);
84 446 : if (!NT_STATUS_IS_OK(status)) {
85 0 : return nt_status_squash(status);
86 : }
87 :
88 446 : gensec_want_feature(es->gensec_security, GENSEC_FEATURE_SEAL);
89 :
90 : /*
91 : * We could be accessing the secrets.tdb or krb5.keytab file here.
92 : * ensure we have permissions to do so.
93 : */
94 446 : become_root();
95 :
96 446 : status = gensec_start_mech_by_oid(es->gensec_security, GENSEC_OID_SPNEGO);
97 :
98 446 : unbecome_root();
99 :
100 446 : if (!NT_STATUS_IS_OK(status)) {
101 0 : return nt_status_squash(status);
102 : }
103 :
104 446 : return status;
105 : }
106 :
107 : /******************************************************************************
108 : Create a server encryption context.
109 : ******************************************************************************/
110 :
111 446 : static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote_address,
112 : const struct tsocket_address *local_address,
113 : struct smb_trans_enc_state **pp_es)
114 : {
115 0 : NTSTATUS status;
116 0 : struct smb_trans_enc_state *es;
117 :
118 446 : *pp_es = NULL;
119 :
120 446 : ZERO_STRUCTP(partial_srv_trans_enc_ctx);
121 446 : es = talloc_zero(NULL, struct smb_trans_enc_state);
122 446 : if (!es) {
123 0 : return NT_STATUS_NO_MEMORY;
124 : }
125 446 : status = make_auth_gensec(remote_address,
126 : local_address,
127 : es);
128 446 : if (!NT_STATUS_IS_OK(status)) {
129 0 : TALLOC_FREE(es);
130 0 : return status;
131 : }
132 446 : *pp_es = es;
133 446 : return NT_STATUS_OK;
134 : }
135 :
136 : /******************************************************************************
137 : Free an encryption-allocated buffer.
138 : ******************************************************************************/
139 :
140 654003 : void srv_free_enc_buffer(struct smbXsrv_connection *xconn, char *buf)
141 : {
142 : /* We know this is an smb buffer, and we
143 : * didn't malloc, only copy, for a keepalive,
144 : * so ignore non-session messages. */
145 :
146 654003 : if(CVAL(buf,0)) {
147 1056 : return;
148 : }
149 :
150 652947 : if (srv_trans_enc_ctx) {
151 185806 : common_free_enc_buffer(srv_trans_enc_ctx, buf);
152 : }
153 : }
154 :
155 : /******************************************************************************
156 : Decrypt an incoming buffer.
157 : ******************************************************************************/
158 :
159 185802 : NTSTATUS srv_decrypt_buffer(struct smbXsrv_connection *xconn, char *buf)
160 : {
161 : /* Ignore non-session messages. */
162 185802 : if(CVAL(buf,0)) {
163 0 : return NT_STATUS_OK;
164 : }
165 :
166 185802 : if (srv_trans_enc_ctx) {
167 185802 : return common_decrypt_buffer(srv_trans_enc_ctx, buf);
168 : }
169 :
170 0 : return NT_STATUS_OK;
171 : }
172 :
173 : /******************************************************************************
174 : Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
175 : ******************************************************************************/
176 :
177 185806 : NTSTATUS srv_encrypt_buffer(struct smbXsrv_connection *xconn, char *buf,
178 : char **buf_out)
179 : {
180 185806 : *buf_out = buf;
181 :
182 : /* Ignore non-session messages. */
183 185806 : if(CVAL(buf,0)) {
184 0 : return NT_STATUS_OK;
185 : }
186 :
187 185806 : if (srv_trans_enc_ctx) {
188 185806 : return common_encrypt_buffer(srv_trans_enc_ctx, buf, buf_out);
189 : }
190 : /* Not encrypting. */
191 0 : return NT_STATUS_OK;
192 : }
193 :
194 : /******************************************************************************
195 : Do the SPNEGO encryption negotiation. Parameters are in/out.
196 : ******************************************************************************/
197 :
198 892 : NTSTATUS srv_request_encryption_setup(connection_struct *conn,
199 : unsigned char **ppdata,
200 : size_t *p_data_size,
201 : unsigned char **pparam,
202 : size_t *p_param_size)
203 : {
204 0 : NTSTATUS status;
205 892 : DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
206 892 : DATA_BLOB response = data_blob_null;
207 0 : struct smb_trans_enc_state *es;
208 :
209 892 : SAFE_FREE(*pparam);
210 892 : *p_param_size = 0;
211 :
212 892 : if (!partial_srv_trans_enc_ctx) {
213 : /* This is the initial step. */
214 446 : status = make_srv_encryption_context(conn->sconn->remote_address,
215 446 : conn->sconn->local_address,
216 : &partial_srv_trans_enc_ctx);
217 446 : if (!NT_STATUS_IS_OK(status)) {
218 0 : return status;
219 : }
220 : }
221 :
222 892 : es = partial_srv_trans_enc_ctx;
223 892 : if (!es || es->gensec_security == NULL) {
224 0 : TALLOC_FREE(partial_srv_trans_enc_ctx);
225 0 : return NT_STATUS_INVALID_PARAMETER;
226 : }
227 :
228 : /* Second step. */
229 892 : become_root();
230 892 : status = gensec_update(es->gensec_security,
231 : talloc_tos(),
232 : blob, &response);
233 892 : unbecome_root();
234 892 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
235 446 : !NT_STATUS_IS_OK(status)) {
236 0 : TALLOC_FREE(partial_srv_trans_enc_ctx);
237 0 : return nt_status_squash(status);
238 : }
239 :
240 892 : if (NT_STATUS_IS_OK(status)) {
241 : /* Return the context we're using for this encryption state. */
242 446 : if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
243 0 : return NT_STATUS_NO_MEMORY;
244 : }
245 446 : SSVAL(*pparam, 0, es->enc_ctx_num);
246 446 : *p_param_size = 2;
247 : }
248 :
249 : /* Return the raw blob. */
250 892 : SAFE_FREE(*ppdata);
251 892 : *ppdata = (unsigned char *)smb_memdup(response.data, response.length);
252 892 : if ((*ppdata) == NULL && response.length > 0)
253 0 : return NT_STATUS_NO_MEMORY;
254 892 : *p_data_size = response.length;
255 892 : data_blob_free(&response);
256 892 : return status;
257 : }
258 :
259 : /******************************************************************************
260 : Negotiation was successful - turn on server-side encryption.
261 : ******************************************************************************/
262 :
263 446 : static NTSTATUS check_enc_good(struct smb_trans_enc_state *es)
264 : {
265 446 : if (!es) {
266 0 : return NT_STATUS_LOGON_FAILURE;
267 : }
268 :
269 446 : if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SIGN)) {
270 0 : return NT_STATUS_INVALID_PARAMETER;
271 : }
272 :
273 446 : if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SEAL)) {
274 0 : return NT_STATUS_INVALID_PARAMETER;
275 : }
276 446 : return NT_STATUS_OK;
277 : }
278 :
279 : /******************************************************************************
280 : Negotiation was successful - turn on server-side encryption.
281 : ******************************************************************************/
282 :
283 446 : NTSTATUS srv_encryption_start(connection_struct *conn)
284 : {
285 0 : NTSTATUS status;
286 :
287 : /* Check that we are really doing sign+seal. */
288 446 : status = check_enc_good(partial_srv_trans_enc_ctx);
289 446 : if (!NT_STATUS_IS_OK(status)) {
290 0 : return status;
291 : }
292 : /* Throw away the context we're using currently (if any). */
293 446 : TALLOC_FREE(srv_trans_enc_ctx);
294 :
295 : /* Steal the partial pointer. Deliberate shallow copy. */
296 446 : srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
297 446 : srv_trans_enc_ctx->enc_on = true;
298 :
299 446 : partial_srv_trans_enc_ctx = NULL;
300 :
301 446 : DEBUG(1,("srv_encryption_start: context negotiated\n"));
302 446 : return NT_STATUS_OK;
303 : }
304 :
305 : /******************************************************************************
306 : Shutdown all server contexts.
307 : ******************************************************************************/
308 :
309 0 : void server_encryption_shutdown(struct smbXsrv_connection *xconn)
310 : {
311 0 : TALLOC_FREE(partial_srv_trans_enc_ctx);
312 0 : TALLOC_FREE(srv_trans_enc_ctx);
313 0 : }
|