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 185879 : static uint16_t srv_enc_ctx(const struct smb_trans_enc_state *es)
38 : {
39 185879 : return es->enc_ctx_num;
40 : }
41 :
42 : /******************************************************************************
43 : Is this an incoming encrypted packet ?
44 : ******************************************************************************/
45 :
46 1354281 : bool is_encrypted_packet(const uint8_t *inbuf)
47 : {
48 16710 : NTSTATUS status;
49 16710 : uint16_t enc_num;
50 :
51 : /* Ignore non-session messages or non 0xFF'E' messages. */
52 1354281 : if(CVAL(inbuf,0)
53 1354106 : || (smb_len(inbuf) < 8)
54 1354094 : || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
55 1151692 : return false;
56 : }
57 :
58 185879 : status = get_enc_ctx_num(inbuf, &enc_num);
59 185879 : if (!NT_STATUS_IS_OK(status)) {
60 0 : return false;
61 : }
62 :
63 : /* Encrypted messages are 0xFF'E'<ctx> */
64 185879 : if (srv_trans_enc_ctx && enc_num == srv_enc_ctx(srv_trans_enc_ctx)) {
65 185879 : return true;
66 : }
67 0 : return false;
68 : }
69 :
70 : /******************************************************************************
71 : Create an gensec_security and ensure pointer copy is correct.
72 : ******************************************************************************/
73 :
74 444 : 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 444 : status = auth_generic_prepare(es, remote_address,
81 : local_address,
82 : "SMB encryption",
83 : &es->gensec_security);
84 444 : if (!NT_STATUS_IS_OK(status)) {
85 0 : return nt_status_squash(status);
86 : }
87 :
88 444 : 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 444 : become_root();
95 :
96 444 : status = gensec_start_mech_by_oid(es->gensec_security, GENSEC_OID_SPNEGO);
97 :
98 444 : unbecome_root();
99 :
100 444 : if (!NT_STATUS_IS_OK(status)) {
101 0 : return nt_status_squash(status);
102 : }
103 :
104 444 : return status;
105 : }
106 :
107 : /******************************************************************************
108 : Create a server encryption context.
109 : ******************************************************************************/
110 :
111 444 : 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 444 : *pp_es = NULL;
119 :
120 444 : ZERO_STRUCTP(partial_srv_trans_enc_ctx);
121 444 : es = talloc_zero(NULL, struct smb_trans_enc_state);
122 444 : if (!es) {
123 0 : return NT_STATUS_NO_MEMORY;
124 : }
125 444 : status = make_auth_gensec(remote_address,
126 : local_address,
127 : es);
128 444 : if (!NT_STATUS_IS_OK(status)) {
129 0 : TALLOC_FREE(es);
130 0 : return status;
131 : }
132 444 : *pp_es = es;
133 444 : return NT_STATUS_OK;
134 : }
135 :
136 : /******************************************************************************
137 : Free an encryption-allocated buffer.
138 : ******************************************************************************/
139 :
140 653887 : 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 653887 : if(CVAL(buf,0)) {
147 1042 : return;
148 : }
149 :
150 652845 : if (srv_trans_enc_ctx) {
151 185883 : common_free_enc_buffer(srv_trans_enc_ctx, buf);
152 : }
153 : }
154 :
155 : /******************************************************************************
156 : Decrypt an incoming buffer.
157 : ******************************************************************************/
158 :
159 185879 : NTSTATUS srv_decrypt_buffer(struct smbXsrv_connection *xconn, char *buf)
160 : {
161 : /* Ignore non-session messages. */
162 185879 : if(CVAL(buf,0)) {
163 0 : return NT_STATUS_OK;
164 : }
165 :
166 185879 : if (srv_trans_enc_ctx) {
167 185879 : 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 185883 : NTSTATUS srv_encrypt_buffer(struct smbXsrv_connection *xconn, char *buf,
178 : char **buf_out)
179 : {
180 185883 : *buf_out = buf;
181 :
182 : /* Ignore non-session messages. */
183 185883 : if(CVAL(buf,0)) {
184 0 : return NT_STATUS_OK;
185 : }
186 :
187 185883 : if (srv_trans_enc_ctx) {
188 185883 : 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 888 : 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 888 : DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
206 888 : DATA_BLOB response = data_blob_null;
207 0 : struct smb_trans_enc_state *es;
208 :
209 888 : SAFE_FREE(*pparam);
210 888 : *p_param_size = 0;
211 :
212 888 : if (!partial_srv_trans_enc_ctx) {
213 : /* This is the initial step. */
214 444 : status = make_srv_encryption_context(conn->sconn->remote_address,
215 444 : conn->sconn->local_address,
216 : &partial_srv_trans_enc_ctx);
217 444 : if (!NT_STATUS_IS_OK(status)) {
218 0 : return status;
219 : }
220 : }
221 :
222 888 : es = partial_srv_trans_enc_ctx;
223 888 : 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 888 : become_root();
230 888 : status = gensec_update(es->gensec_security,
231 : talloc_tos(),
232 : blob, &response);
233 888 : unbecome_root();
234 888 : if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
235 444 : !NT_STATUS_IS_OK(status)) {
236 0 : TALLOC_FREE(partial_srv_trans_enc_ctx);
237 0 : return nt_status_squash(status);
238 : }
239 :
240 888 : if (NT_STATUS_IS_OK(status)) {
241 : /* Return the context we're using for this encryption state. */
242 444 : if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
243 0 : return NT_STATUS_NO_MEMORY;
244 : }
245 444 : SSVAL(*pparam, 0, es->enc_ctx_num);
246 444 : *p_param_size = 2;
247 : }
248 :
249 : /* Return the raw blob. */
250 888 : SAFE_FREE(*ppdata);
251 888 : *ppdata = (unsigned char *)smb_memdup(response.data, response.length);
252 888 : if ((*ppdata) == NULL && response.length > 0)
253 0 : return NT_STATUS_NO_MEMORY;
254 888 : *p_data_size = response.length;
255 888 : data_blob_free(&response);
256 888 : return status;
257 : }
258 :
259 : /******************************************************************************
260 : Negotiation was successful - turn on server-side encryption.
261 : ******************************************************************************/
262 :
263 444 : static NTSTATUS check_enc_good(struct smb_trans_enc_state *es)
264 : {
265 444 : if (!es) {
266 0 : return NT_STATUS_LOGON_FAILURE;
267 : }
268 :
269 444 : if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SIGN)) {
270 0 : return NT_STATUS_INVALID_PARAMETER;
271 : }
272 :
273 444 : if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SEAL)) {
274 0 : return NT_STATUS_INVALID_PARAMETER;
275 : }
276 444 : return NT_STATUS_OK;
277 : }
278 :
279 : /******************************************************************************
280 : Negotiation was successful - turn on server-side encryption.
281 : ******************************************************************************/
282 :
283 444 : NTSTATUS srv_encryption_start(connection_struct *conn)
284 : {
285 0 : NTSTATUS status;
286 :
287 : /* Check that we are really doing sign+seal. */
288 444 : status = check_enc_good(partial_srv_trans_enc_ctx);
289 444 : if (!NT_STATUS_IS_OK(status)) {
290 0 : return status;
291 : }
292 : /* Throw away the context we're using currently (if any). */
293 444 : TALLOC_FREE(srv_trans_enc_ctx);
294 :
295 : /* Steal the partial pointer. Deliberate shallow copy. */
296 444 : srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
297 444 : srv_trans_enc_ctx->enc_on = true;
298 :
299 444 : partial_srv_trans_enc_ctx = NULL;
300 :
301 444 : DEBUG(1,("srv_encryption_start: context negotiated\n"));
302 444 : 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 : }
|