Line data Source code
1 : /*
2 : Unix SMB2 implementation.
3 :
4 : Copyright (C) Andrew Bartlett 2001-2005
5 : Copyright (C) Stefan Metzmacher 2005
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "auth/credentials/credentials.h"
23 : #include "auth/auth.h"
24 : #include "auth/gensec/gensec.h"
25 : #include "libcli/raw/libcliraw.h"
26 : #include "libcli/raw/raw_proto.h"
27 : #include "libcli/smb2/smb2.h"
28 : #include "libcli/smb2/smb2_calls.h"
29 : #include "smb_server/smb_server.h"
30 : #include "smb_server/smb2/smb2_server.h"
31 : #include "samba/service_stream.h"
32 : #include "param/param.h"
33 :
34 1611 : static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
35 : {
36 0 : struct gensec_security *gensec_security;
37 1611 : DATA_BLOB null_data_blob = data_blob(NULL, 0);
38 0 : DATA_BLOB blob;
39 0 : NTSTATUS nt_status;
40 0 : struct cli_credentials *server_credentials;
41 :
42 0 : server_credentials =
43 1611 : cli_credentials_init_server(req, req->smb_conn->lp_ctx);
44 1611 : if (server_credentials == NULL) {
45 2 : DBG_DEBUG("Failed to obtain server credentials, "
46 : "perhaps a standalone server?\n");
47 : /*
48 : * Create anon server credentials for for the
49 : * spoolss.notify test.
50 : */
51 2 : server_credentials = cli_credentials_init_anon(req);
52 2 : if (server_credentials == NULL) {
53 0 : smbsrv_terminate_connection(req->smb_conn,
54 : "Failed to init server credentials\n");
55 0 : return NT_STATUS_NO_MEMORY;
56 : }
57 : }
58 :
59 1611 : req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
60 :
61 1611 : nt_status = samba_server_gensec_start(req,
62 1611 : req->smb_conn->connection->event.ctx,
63 1611 : req->smb_conn->connection->msg_ctx,
64 1611 : req->smb_conn->lp_ctx,
65 : server_credentials,
66 : "cifs",
67 : &gensec_security);
68 1611 : if (!NT_STATUS_IS_OK(nt_status)) {
69 0 : DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
70 0 : smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
71 0 : return nt_status;
72 : }
73 :
74 1611 : gensec_set_target_service(gensec_security, "cifs");
75 :
76 1611 : gensec_set_credentials(gensec_security, server_credentials);
77 :
78 1611 : nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
79 1611 : if (!NT_STATUS_IS_OK(nt_status)) {
80 0 : DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status)));
81 0 : smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n");
82 0 : return nt_status;
83 : }
84 :
85 1611 : nt_status = gensec_update(gensec_security, req,
86 : null_data_blob, &blob);
87 1611 : if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
88 0 : DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status)));
89 0 : smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n");
90 0 : return nt_status;
91 : }
92 :
93 1611 : *_blob = blob;
94 1611 : return NT_STATUS_OK;
95 : }
96 :
97 1611 : static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2_negprot *io)
98 : {
99 0 : NTSTATUS status;
100 0 : struct timeval current_time;
101 0 : struct timeval boot_time;
102 0 : uint16_t i;
103 1611 : uint16_t dialect = 0;
104 0 : enum smb_signing_setting signing_setting;
105 1611 : struct loadparm_context *lp_ctx = req->smb_conn->lp_ctx;
106 :
107 : /* we only do one dialect for now */
108 1611 : if (io->in.dialect_count < 1) {
109 0 : return NT_STATUS_NOT_SUPPORTED;
110 : }
111 1611 : for (i=0; i < io->in.dialect_count; i++) {
112 1611 : dialect = io->in.dialects[i];
113 1611 : if (dialect == SMB2_DIALECT_REVISION_202) {
114 1611 : break;
115 : }
116 : }
117 1611 : if (dialect != SMB2_DIALECT_REVISION_202) {
118 0 : DEBUG(0,("Got unexpected SMB2 dialect %u\n", dialect));
119 0 : return NT_STATUS_NOT_SUPPORTED;
120 : }
121 :
122 1611 : req->smb_conn->negotiate.protocol = PROTOCOL_SMB2_02;
123 :
124 1611 : current_time = timeval_current(); /* TODO: handle timezone?! */
125 1611 : boot_time = timeval_current(); /* TODO: fix me */
126 :
127 1611 : ZERO_STRUCT(io->out);
128 :
129 1611 : signing_setting = lpcfg_server_signing(lp_ctx);
130 1611 : if (signing_setting == SMB_SIGNING_DEFAULT) {
131 : /*
132 : * If we are a domain controller, SMB signing is
133 : * really important, as it can prevent a number of
134 : * attacks on communications between us and the
135 : * clients
136 : *
137 : * However, it really sucks (no sendfile, CPU
138 : * overhead) performance-wise when used on a
139 : * file server, so disable it by default
140 : * on non-DCs
141 : */
142 :
143 1581 : if (lpcfg_server_role(lp_ctx) >= ROLE_ACTIVE_DIRECTORY_DC) {
144 1579 : signing_setting = SMB_SIGNING_REQUIRED;
145 : } else {
146 2 : signing_setting = SMB_SIGNING_OFF;
147 : }
148 : }
149 :
150 1611 : switch (signing_setting) {
151 0 : case SMB_SIGNING_DEFAULT:
152 : case SMB_SIGNING_IPC_DEFAULT:
153 0 : smb_panic(__location__);
154 0 : break;
155 2 : case SMB_SIGNING_OFF:
156 2 : io->out.security_mode = 0;
157 2 : break;
158 30 : case SMB_SIGNING_DESIRED:
159 : case SMB_SIGNING_IF_REQUIRED:
160 30 : io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
161 30 : break;
162 1579 : case SMB_SIGNING_REQUIRED:
163 1579 : io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
164 : /* force signing on immediately */
165 1579 : req->smb_conn->smb2_signing_required = true;
166 1579 : break;
167 : }
168 1611 : io->out.dialect_revision = dialect;
169 1611 : io->out.capabilities = 0;
170 1611 : io->out.max_transact_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
171 : "smb2", "max transaction size", 0x10000);
172 1611 : io->out.max_read_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
173 : "smb2", "max read size", 0x10000);
174 1611 : io->out.max_write_size = lpcfg_parm_ulong(req->smb_conn->lp_ctx, NULL,
175 : "smb2", "max write size", 0x10000);
176 1611 : io->out.system_time = timeval_to_nttime(¤t_time);
177 1611 : io->out.server_start_time = timeval_to_nttime(&boot_time);
178 1611 : io->out.reserved2 = 0;
179 1611 : status = smb2srv_negprot_secblob(req, &io->out.secblob);
180 1611 : NT_STATUS_NOT_OK_RETURN(status);
181 :
182 1611 : return NT_STATUS_OK;
183 : }
184 :
185 1611 : static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
186 : {
187 0 : NTSTATUS status;
188 :
189 1611 : if (NT_STATUS_IS_ERR(req->status)) {
190 0 : smb2srv_send_error(req, req->status); /* TODO: is this correct? */
191 0 : return;
192 : }
193 :
194 1611 : status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
195 1611 : if (!NT_STATUS_IS_OK(status)) {
196 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
197 0 : talloc_free(req);
198 0 : return;
199 : }
200 :
201 1611 : SSVAL(req->out.body, 0x02, io->out.security_mode);
202 1611 : SIVAL(req->out.body, 0x04, io->out.dialect_revision);
203 1611 : SIVAL(req->out.body, 0x06, io->out.reserved);
204 1611 : status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
205 1611 : if (!NT_STATUS_IS_OK(status)) {
206 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
207 0 : talloc_free(req);
208 0 : return;
209 : }
210 1611 : SIVAL(req->out.body, 0x18, io->out.capabilities);
211 1611 : SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
212 1611 : SIVAL(req->out.body, 0x20, io->out.max_read_size);
213 1611 : SIVAL(req->out.body, 0x24, io->out.max_write_size);
214 1611 : push_nttime(req->out.body, 0x28, io->out.system_time);
215 1611 : push_nttime(req->out.body, 0x30, io->out.server_start_time);
216 1611 : SIVAL(req->out.body, 0x3C, io->out.reserved2);
217 1611 : status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
218 1611 : if (!NT_STATUS_IS_OK(status)) {
219 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
220 0 : talloc_free(req);
221 0 : return;
222 : }
223 :
224 1611 : smb2srv_send_reply(req);
225 : }
226 :
227 1611 : void smb2srv_negprot_recv(struct smb2srv_request *req)
228 : {
229 0 : struct smb2_negprot *io;
230 0 : int i;
231 :
232 1611 : if (req->in.body_size < 0x26) {
233 0 : smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
234 0 : return;
235 : }
236 :
237 1611 : io = talloc(req, struct smb2_negprot);
238 1611 : if (!io) {
239 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
240 0 : talloc_free(req);
241 0 : return;
242 : }
243 :
244 1611 : io->in.dialect_count = SVAL(req->in.body, 0x02);
245 1611 : io->in.security_mode = SVAL(req->in.body, 0x04);
246 1611 : io->in.reserved = SVAL(req->in.body, 0x06);
247 1611 : io->in.capabilities = IVAL(req->in.body, 0x08);
248 1611 : req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
249 1611 : if (!NT_STATUS_IS_OK(req->status)) {
250 0 : smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
251 0 : talloc_free(req);
252 0 : return;
253 : }
254 1611 : io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
255 :
256 1611 : io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
257 1611 : if (io->in.dialects == NULL) {
258 0 : smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
259 0 : talloc_free(req);
260 0 : return;
261 : }
262 4782 : for (i=0;i<io->in.dialect_count;i++) {
263 3171 : io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
264 : }
265 :
266 1611 : req->status = smb2srv_negprot_backend(req, io);
267 :
268 1611 : if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
269 0 : talloc_free(req);
270 0 : return;
271 : }
272 1611 : smb2srv_negprot_send(req, io);
273 : }
274 :
275 : /*
276 : * reply to a SMB negprot request with dialect "SMB 2.002"
277 : */
278 1217 : void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
279 : {
280 0 : struct smb2srv_request *req;
281 1217 : uint32_t body_fixed_size = 0x26;
282 :
283 1217 : req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
284 1217 : if (!req) goto nomem;
285 1217 : req->smb_conn = smb_req->smb_conn;
286 1217 : req->request_time = smb_req->request_time;
287 1217 : talloc_steal(req, smb_req);
288 :
289 1217 : req->in.size = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
290 1217 : req->in.allocated = req->in.size;
291 1217 : req->in.buffer = talloc_array(req, uint8_t, req->in.allocated);
292 1217 : if (!req->in.buffer) goto nomem;
293 1217 : req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
294 1217 : req->in.body = req->in.hdr + SMB2_HDR_BODY;
295 1217 : req->in.body_size = body_fixed_size;
296 1217 : req->in.dynamic = NULL;
297 :
298 1217 : smb2srv_setup_bufinfo(req);
299 :
300 1217 : SIVAL(req->in.hdr, 0, SMB2_MAGIC);
301 1217 : SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
302 1217 : SSVAL(req->in.hdr, SMB2_HDR_EPOCH, 0);
303 1217 : SIVAL(req->in.hdr, SMB2_HDR_STATUS, 0);
304 1217 : SSVAL(req->in.hdr, SMB2_HDR_OPCODE, SMB2_OP_NEGPROT);
305 1217 : SSVAL(req->in.hdr, SMB2_HDR_CREDIT, 0);
306 1217 : SIVAL(req->in.hdr, SMB2_HDR_FLAGS, 0);
307 1217 : SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND, 0);
308 1217 : SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID, 0);
309 1217 : SIVAL(req->in.hdr, SMB2_HDR_PID, 0);
310 1217 : SIVAL(req->in.hdr, SMB2_HDR_TID, 0);
311 1217 : SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID, 0);
312 1217 : memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
313 :
314 : /* this seems to be a bug, they use 0x24 but the length is 0x26 */
315 1217 : SSVAL(req->in.body, 0x00, 0x24);
316 :
317 1217 : SSVAL(req->in.body, 0x02, 1);
318 1217 : memset(req->in.body+0x04, 0, 32);
319 1217 : SSVAL(req->in.body, 0x24, SMB2_DIALECT_REVISION_202);
320 :
321 1217 : smb2srv_negprot_recv(req);
322 1217 : return;
323 0 : nomem:
324 0 : smbsrv_terminate_connection(smb_req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
325 0 : talloc_free(req);
326 0 : return;
327 : }
|