/src/samba/libcli/smb/smbXcli_base.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Infrastructure for async SMB client requests |
4 | | Copyright (C) Volker Lendecke 2008 |
5 | | Copyright (C) Stefan Metzmacher 2011 |
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 "system/network.h" |
23 | | #include "../lib/async_req/async_sock.h" |
24 | | #include "../lib/util/tevent_ntstatus.h" |
25 | | #include "../lib/util/tevent_unix.h" |
26 | | #include "lib/tsocket/tsocket.h" |
27 | | #include "source3/lib/util_tsock.h" |
28 | | #include "lib/util/util_net.h" |
29 | | #include "lib/util/dlinklist.h" |
30 | | #include "lib/util/iov_buf.h" |
31 | | #include "../libcli/smb/smb_common.h" |
32 | | #include "../libcli/smb/smb_seal.h" |
33 | | #include "../libcli/smb/smb_signing.h" |
34 | | #include "../libcli/smb/read_smb.h" |
35 | | #include "smbXcli_base.h" |
36 | | #include "librpc/ndr/libndr.h" |
37 | | #include "libcli/smb/smb2_negotiate_context.h" |
38 | | #include "libcli/smb/smb2_signing.h" |
39 | | |
40 | | #include "lib/crypto/gnutls_helpers.h" |
41 | | #include <gnutls/gnutls.h> |
42 | | #include <gnutls/crypto.h> |
43 | | |
44 | | struct smbXcli_transport; |
45 | | struct smbXcli_conn; |
46 | | struct smbXcli_req; |
47 | | struct smbXcli_session; |
48 | | struct smbXcli_tcon; |
49 | | |
50 | | struct smbXcli_transport { |
51 | | struct smb_transport transport; |
52 | | int sock_fd; |
53 | | struct tstream_context *tstream; |
54 | | enum tls_verify_peer_state verify_peer; |
55 | | struct samba_sockaddr laddr; |
56 | | struct samba_sockaddr raddr; |
57 | | |
58 | | struct tevent_req *(*writev_send_fn)(TALLOC_CTX *mem_ctx, |
59 | | struct tevent_context *ev, |
60 | | struct smbXcli_transport *xtp, |
61 | | struct tevent_queue *queue, |
62 | | struct iovec *iov, |
63 | | int count); |
64 | | ssize_t (*writev_recv_fn)(struct tevent_req *req, int *perrno); |
65 | | |
66 | | struct tevent_req *(*read_smb_send_fn)(TALLOC_CTX *mem_ctx, |
67 | | struct tevent_context *ev, |
68 | | struct smbXcli_transport *xtp); |
69 | | ssize_t (*read_smb_recv_fn)(struct tevent_req *req, |
70 | | TALLOC_CTX *mem_ctx, |
71 | | uint8_t **pbuf, |
72 | | int *perrno); |
73 | | |
74 | | struct tevent_req *(*monitor_send_fn)(TALLOC_CTX *mem_ctx, |
75 | | struct tevent_context *ev, |
76 | | struct smbXcli_transport *xtp); |
77 | | int (*monitor_recv_fn)(struct tevent_req *req); |
78 | | }; |
79 | | |
80 | | struct smbXcli_conn { |
81 | | struct smbXcli_transport *transport; |
82 | | |
83 | | const char *remote_name; |
84 | | |
85 | | struct tevent_queue *outgoing; |
86 | | struct tevent_req **pending; |
87 | | struct tevent_req *read_smb_req; |
88 | | struct tevent_req *monitor_req; |
89 | | struct tevent_req *suicide_req; |
90 | | |
91 | | enum protocol_types min_protocol; |
92 | | enum protocol_types max_protocol; |
93 | | enum protocol_types protocol; |
94 | | bool allow_signing; |
95 | | bool desire_signing; |
96 | | bool mandatory_signing; |
97 | | |
98 | | /* |
99 | | * The incoming dispatch function should return: |
100 | | * - NT_STATUS_RETRY, if more incoming PDUs are expected. |
101 | | * - NT_STATUS_OK, if no more processing is desired, e.g. |
102 | | * the dispatch function called |
103 | | * tevent_req_done(). |
104 | | * - All other return values disconnect the connection. |
105 | | */ |
106 | | NTSTATUS (*dispatch_incoming)(struct smbXcli_conn *conn, |
107 | | TALLOC_CTX *tmp_mem, |
108 | | uint8_t *inbuf); |
109 | | |
110 | | struct { |
111 | | struct { |
112 | | uint32_t capabilities; |
113 | | uint32_t max_xmit; |
114 | | } client; |
115 | | |
116 | | struct { |
117 | | uint32_t capabilities; |
118 | | uint32_t max_xmit; |
119 | | uint16_t max_mux; |
120 | | uint16_t security_mode; |
121 | | bool readbraw; |
122 | | bool writebraw; |
123 | | bool lockread; |
124 | | bool writeunlock; |
125 | | uint32_t session_key; |
126 | | struct GUID guid; |
127 | | DATA_BLOB gss_blob; |
128 | | uint8_t challenge[8]; |
129 | | const char *workgroup; |
130 | | const char *name; |
131 | | int time_zone; |
132 | | NTTIME system_time; |
133 | | } server; |
134 | | |
135 | | uint32_t capabilities; |
136 | | uint32_t max_xmit; |
137 | | |
138 | | uint16_t mid; |
139 | | |
140 | | struct smb1_signing_state *signing; |
141 | | struct smb_trans_enc_state *trans_enc; |
142 | | |
143 | | struct tevent_req *read_braw_req; |
144 | | } smb1; |
145 | | |
146 | | struct { |
147 | | struct { |
148 | | uint32_t capabilities; |
149 | | uint16_t security_mode; |
150 | | struct GUID guid; |
151 | | struct smb311_capabilities smb3_capabilities; |
152 | | bool requested_transport_level_security; |
153 | | } client; |
154 | | |
155 | | struct { |
156 | | uint32_t capabilities; |
157 | | uint16_t security_mode; |
158 | | struct GUID guid; |
159 | | uint32_t max_trans_size; |
160 | | uint32_t max_read_size; |
161 | | uint32_t max_write_size; |
162 | | NTTIME system_time; |
163 | | NTTIME start_time; |
164 | | DATA_BLOB gss_blob; |
165 | | uint16_t sign_algo; |
166 | | uint16_t cipher; |
167 | | bool smb311_posix; |
168 | | bool transport_trusted; |
169 | | } server; |
170 | | |
171 | | uint64_t mid; |
172 | | uint16_t cur_credits; |
173 | | uint16_t max_credits; |
174 | | |
175 | | uint32_t cc_chunk_len; |
176 | | uint32_t cc_max_chunks; |
177 | | |
178 | | uint8_t io_priority; |
179 | | |
180 | | bool force_channel_sequence; |
181 | | |
182 | | uint8_t preauth_sha512[64]; |
183 | | } smb2; |
184 | | |
185 | | struct smbXcli_session *sessions; |
186 | | }; |
187 | | |
188 | | struct smb2cli_session { |
189 | | uint64_t session_id; |
190 | | uint16_t session_flags; |
191 | | struct smb2_signing_key *application_key; |
192 | | struct smb2_signing_key *signing_key; |
193 | | bool should_sign; |
194 | | bool should_encrypt; |
195 | | struct smb2_signing_key *encryption_key; |
196 | | struct smb2_signing_key *decryption_key; |
197 | | uint64_t nonce_high_random; |
198 | | uint64_t nonce_high_max; |
199 | | uint64_t nonce_high; |
200 | | uint64_t nonce_low; |
201 | | uint16_t channel_sequence; |
202 | | bool replay_active; |
203 | | bool require_signed_response; |
204 | | |
205 | | /* |
206 | | * The following are just for torture tests |
207 | | */ |
208 | | bool anonymous_signing; |
209 | | bool anonymous_encryption; |
210 | | bool no_signing_disconnect; |
211 | | }; |
212 | | |
213 | | struct smbXcli_session { |
214 | | struct smbXcli_session *prev, *next; |
215 | | struct smbXcli_conn *conn; |
216 | | |
217 | | struct { |
218 | | uint16_t session_id; |
219 | | uint16_t action; |
220 | | DATA_BLOB application_key; |
221 | | bool protected_key; |
222 | | } smb1; |
223 | | |
224 | | struct smb2cli_session *smb2; |
225 | | |
226 | | struct { |
227 | | struct smb2_signing_key *signing_key; |
228 | | uint8_t preauth_sha512[64]; |
229 | | } smb2_channel; |
230 | | |
231 | | /* |
232 | | * this should be a short term hack |
233 | | * until the upper layers have implemented |
234 | | * re-authentication. |
235 | | */ |
236 | | bool disconnect_expired; |
237 | | }; |
238 | | |
239 | | struct smbXcli_tcon { |
240 | | bool is_smb1; |
241 | | uint32_t fs_attributes; |
242 | | |
243 | | struct { |
244 | | uint16_t tcon_id; |
245 | | uint16_t optional_support; |
246 | | uint32_t maximal_access; |
247 | | uint32_t guest_maximal_access; |
248 | | char *service; |
249 | | char *fs_type; |
250 | | } smb1; |
251 | | |
252 | | struct { |
253 | | uint32_t tcon_id; |
254 | | uint8_t type; |
255 | | uint32_t flags; |
256 | | uint32_t capabilities; |
257 | | uint32_t maximal_access; |
258 | | bool should_sign; |
259 | | bool should_encrypt; |
260 | | } smb2; |
261 | | }; |
262 | | |
263 | | struct smbXcli_req_state { |
264 | | struct tevent_context *ev; |
265 | | struct smbXcli_conn *conn; |
266 | | struct smbXcli_session *session; /* maybe NULL */ |
267 | | struct smbXcli_tcon *tcon; /* maybe NULL */ |
268 | | |
269 | | uint8_t length_hdr[4]; |
270 | | |
271 | | bool one_way; |
272 | | |
273 | | uint8_t *inbuf; |
274 | | |
275 | | struct tevent_req *write_req; |
276 | | ssize_t (*writev_recv_fn)(struct tevent_req *req, int *perrno); |
277 | | |
278 | | struct timeval endtime; |
279 | | |
280 | | struct { |
281 | | /* Space for the header including the wct */ |
282 | | uint8_t hdr[HDR_VWV]; |
283 | | |
284 | | /* |
285 | | * For normal requests, smb1cli_req_send chooses a mid. |
286 | | * SecondaryV trans requests need to use the mid of the primary |
287 | | * request, so we need a place to store it. |
288 | | * Assume it is set if != 0. |
289 | | */ |
290 | | uint16_t mid; |
291 | | |
292 | | uint16_t *vwv; |
293 | | uint8_t bytecount_buf[2]; |
294 | | |
295 | 0 | #define MAX_SMB_IOV 10 |
296 | | /* length_hdr, hdr, words, byte_count, buffers */ |
297 | | struct iovec iov[1 + 3 + MAX_SMB_IOV]; |
298 | | int iov_count; |
299 | | |
300 | | bool one_way_seqnum; |
301 | | uint32_t seqnum; |
302 | | struct tevent_req **chained_requests; |
303 | | |
304 | | uint8_t recv_cmd; |
305 | | NTSTATUS recv_status; |
306 | | /* always an array of 3 talloc elements */ |
307 | | struct iovec *recv_iov; |
308 | | } smb1; |
309 | | |
310 | | struct { |
311 | | const uint8_t *fixed; |
312 | | uint16_t fixed_len; |
313 | | const uint8_t *dyn; |
314 | | uint32_t dyn_len; |
315 | | |
316 | | uint8_t transform[SMB2_TF_HDR_SIZE]; |
317 | | uint8_t hdr[SMB2_HDR_BODY]; |
318 | | uint8_t pad[7]; /* padding space for compounding */ |
319 | | |
320 | | /* |
321 | | * always an array of 3 talloc elements |
322 | | * (without a SMB2_TRANSFORM header!) |
323 | | * |
324 | | * HDR, BODY, DYN |
325 | | */ |
326 | | struct iovec *recv_iov; |
327 | | |
328 | | /* |
329 | | * the expected max for the response dyn_len |
330 | | */ |
331 | | uint32_t max_dyn_len; |
332 | | |
333 | | uint16_t credit_charge; |
334 | | |
335 | | bool should_sign; |
336 | | bool should_encrypt; |
337 | | uint64_t encryption_session_id; |
338 | | |
339 | | bool signing_skipped; |
340 | | bool require_signed_response; |
341 | | bool notify_async; |
342 | | bool got_async; |
343 | | uint16_t cancel_flags; |
344 | | uint64_t cancel_mid; |
345 | | uint64_t cancel_aid; |
346 | | } smb2; |
347 | | }; |
348 | | |
349 | | static int smbXcli_transport_destructor(struct smbXcli_transport *xtp) |
350 | 0 | { |
351 | 0 | if (xtp->sock_fd != -1) { |
352 | 0 | close(xtp->sock_fd); |
353 | 0 | xtp->sock_fd = -1; |
354 | 0 | } |
355 | 0 | TALLOC_FREE(xtp->tstream); |
356 | 0 | return 0; |
357 | 0 | } |
358 | | |
359 | | static struct tevent_req *smbXcli_transport_tstream_writev_send( |
360 | | TALLOC_CTX *mem_ctx, |
361 | | struct tevent_context *ev, |
362 | | struct smbXcli_transport *xtp, |
363 | | struct tevent_queue *queue, |
364 | | struct iovec *iov, |
365 | | int count) |
366 | 0 | { |
367 | 0 | return tstream_writev_queue_send(mem_ctx, |
368 | 0 | ev, |
369 | 0 | xtp->tstream, |
370 | 0 | queue, |
371 | 0 | iov, |
372 | 0 | count); |
373 | 0 | } |
374 | | |
375 | | static ssize_t smbXcli_transport_tstream_writev_recv(struct tevent_req *req, |
376 | | int *perrno) |
377 | 0 | { |
378 | 0 | return tstream_writev_queue_recv(req, perrno); |
379 | 0 | } |
380 | | |
381 | | static struct tevent_req *smbXcli_transport_tstream_read_smb_send( |
382 | | TALLOC_CTX *mem_ctx, |
383 | | struct tevent_context *ev, |
384 | | struct smbXcli_transport *xtp) |
385 | 0 | { |
386 | 0 | return tstream_read_packet_send(mem_ctx, |
387 | 0 | ev, |
388 | 0 | xtp->tstream, |
389 | 0 | 4, |
390 | 0 | read_smb_more, |
391 | 0 | NULL); |
392 | 0 | } |
393 | | |
394 | | static ssize_t smbXcli_transport_tstream_read_smb_recv( |
395 | | struct tevent_req *req, |
396 | | TALLOC_CTX *mem_ctx, |
397 | | uint8_t **pbuf, |
398 | | int *perrno) |
399 | 0 | { |
400 | 0 | return tstream_read_packet_recv(req, mem_ctx, pbuf, perrno); |
401 | 0 | } |
402 | | |
403 | | static struct tevent_req *smbXcli_transport_tstream_monitor_send( |
404 | | TALLOC_CTX *mem_ctx, |
405 | | struct tevent_context *ev, |
406 | | struct smbXcli_transport *xtp) |
407 | 0 | { |
408 | 0 | return tstream_monitor_send(mem_ctx, |
409 | 0 | ev, |
410 | 0 | xtp->tstream); |
411 | 0 | } |
412 | | |
413 | | static int smbXcli_transport_tstream_monitor_recv(struct tevent_req *req) |
414 | 0 | { |
415 | 0 | int sys_errno = 0; |
416 | 0 | int ret; |
417 | |
|
418 | 0 | ret = tstream_monitor_recv(req, &sys_errno); |
419 | 0 | if (ret == 0) { |
420 | 0 | sys_errno = EPIPE; |
421 | 0 | } |
422 | 0 | if (sys_errno == 0) { |
423 | 0 | sys_errno = EPIPE; |
424 | 0 | } |
425 | |
|
426 | 0 | return sys_errno; |
427 | 0 | } |
428 | | |
429 | | struct smbXcli_transport *smbXcli_transport_tstream( |
430 | | TALLOC_CTX *mem_ctx, |
431 | | struct tstream_context **pstream, |
432 | | enum tls_verify_peer_state verify_peer, |
433 | | const struct samba_sockaddr *laddr, |
434 | | const struct samba_sockaddr *raddr, |
435 | | const struct smb_transport *tp) |
436 | 0 | { |
437 | 0 | struct smbXcli_transport *xtp = NULL; |
438 | |
|
439 | 0 | xtp = talloc_zero(mem_ctx, struct smbXcli_transport); |
440 | 0 | if (xtp == NULL) { |
441 | 0 | return NULL; |
442 | 0 | } |
443 | | |
444 | 0 | xtp->transport = *tp; |
445 | 0 | xtp->sock_fd = -1; |
446 | 0 | xtp->verify_peer = verify_peer; |
447 | |
|
448 | 0 | xtp->laddr = *laddr; |
449 | 0 | xtp->raddr = *raddr; |
450 | |
|
451 | 0 | xtp->tstream = talloc_move(xtp, pstream); |
452 | |
|
453 | 0 | xtp->writev_send_fn = smbXcli_transport_tstream_writev_send; |
454 | 0 | xtp->writev_recv_fn = smbXcli_transport_tstream_writev_recv; |
455 | 0 | xtp->read_smb_send_fn = smbXcli_transport_tstream_read_smb_send; |
456 | 0 | xtp->read_smb_recv_fn = smbXcli_transport_tstream_read_smb_recv; |
457 | 0 | xtp->monitor_send_fn = smbXcli_transport_tstream_monitor_send; |
458 | 0 | xtp->monitor_recv_fn = smbXcli_transport_tstream_monitor_recv; |
459 | |
|
460 | 0 | talloc_set_destructor(xtp, smbXcli_transport_destructor); |
461 | 0 | return xtp; |
462 | 0 | } |
463 | | |
464 | | static struct tevent_req *smbXcli_transport_bsd_writev_send( |
465 | | TALLOC_CTX *mem_ctx, |
466 | | struct tevent_context *ev, |
467 | | struct smbXcli_transport *xtp, |
468 | | struct tevent_queue *queue, |
469 | | struct iovec *iov, |
470 | | int count) |
471 | 0 | { |
472 | 0 | return writev_send(mem_ctx, |
473 | 0 | ev, |
474 | 0 | queue, |
475 | 0 | xtp->sock_fd, |
476 | 0 | false, |
477 | 0 | iov, |
478 | 0 | count); |
479 | 0 | } |
480 | | |
481 | | static ssize_t smbXcli_transport_bsd_writev_recv(struct tevent_req *req, |
482 | | int *perrno) |
483 | 0 | { |
484 | 0 | return writev_recv(req, perrno); |
485 | 0 | } |
486 | | |
487 | | static struct tevent_req *smbXcli_transport_bsd_read_smb_send( |
488 | | TALLOC_CTX *mem_ctx, |
489 | | struct tevent_context *ev, |
490 | | struct smbXcli_transport *xtp) |
491 | 0 | { |
492 | 0 | return read_smb_send(mem_ctx, ev, xtp->sock_fd); |
493 | 0 | } |
494 | | |
495 | | static ssize_t smbXcli_transport_bsd_read_smb_recv( |
496 | | struct tevent_req *req, |
497 | | TALLOC_CTX *mem_ctx, |
498 | | uint8_t **pbuf, |
499 | | int *perrno) |
500 | 0 | { |
501 | 0 | return read_smb_recv(req, mem_ctx, pbuf, perrno); |
502 | 0 | } |
503 | | |
504 | | static struct tevent_req *smbXcli_transport_bsd_monitor_send( |
505 | | TALLOC_CTX *mem_ctx, |
506 | | struct tevent_context *ev, |
507 | | struct smbXcli_transport *xtp) |
508 | 0 | { |
509 | 0 | return wait_for_error_send(mem_ctx, ev, xtp->sock_fd); |
510 | 0 | } |
511 | | |
512 | | static int smbXcli_transport_bsd_monitor_recv(struct tevent_req *req) |
513 | 0 | { |
514 | 0 | return wait_for_error_recv(req); |
515 | 0 | } |
516 | | |
517 | | struct smbXcli_transport *smbXcli_transport_bsd( |
518 | | TALLOC_CTX *mem_ctx, |
519 | | int *_fd, |
520 | | enum tls_verify_peer_state verify_peer, |
521 | | const struct smb_transport *tp) |
522 | 0 | { |
523 | 0 | struct smbXcli_transport *xtp = NULL; |
524 | 0 | int fd = *_fd; |
525 | 0 | int ret; |
526 | |
|
527 | 0 | xtp = talloc_zero(mem_ctx, struct smbXcli_transport); |
528 | 0 | if (xtp == NULL) { |
529 | 0 | return NULL; |
530 | 0 | } |
531 | | |
532 | 0 | xtp->transport = *tp; |
533 | 0 | xtp->sock_fd = fd; |
534 | 0 | xtp->verify_peer = verify_peer; |
535 | |
|
536 | 0 | xtp->laddr.sa_socklen = sizeof(xtp->laddr.u); |
537 | 0 | ret = getsockname(fd, &xtp->laddr.u.sa, &xtp->laddr.sa_socklen); |
538 | 0 | if (ret == -1) { |
539 | 0 | TALLOC_FREE(xtp); |
540 | 0 | return NULL; |
541 | 0 | } |
542 | | |
543 | 0 | xtp->raddr.sa_socklen = sizeof(xtp->raddr.u); |
544 | 0 | ret = getpeername(fd, &xtp->raddr.u.sa, &xtp->raddr.sa_socklen); |
545 | 0 | if (ret == -1) { |
546 | 0 | TALLOC_FREE(xtp); |
547 | 0 | return NULL; |
548 | 0 | } |
549 | | |
550 | 0 | ret = set_blocking(fd, false); |
551 | 0 | if (ret < 0) { |
552 | 0 | TALLOC_FREE(xtp); |
553 | 0 | return NULL; |
554 | 0 | } |
555 | | |
556 | 0 | xtp->writev_send_fn = smbXcli_transport_bsd_writev_send; |
557 | 0 | xtp->writev_recv_fn = smbXcli_transport_bsd_writev_recv; |
558 | 0 | xtp->read_smb_send_fn = smbXcli_transport_bsd_read_smb_send; |
559 | 0 | xtp->read_smb_recv_fn = smbXcli_transport_bsd_read_smb_recv; |
560 | 0 | xtp->monitor_send_fn = smbXcli_transport_bsd_monitor_send; |
561 | 0 | xtp->monitor_recv_fn = smbXcli_transport_bsd_monitor_recv; |
562 | |
|
563 | 0 | *_fd = -1; |
564 | 0 | talloc_set_destructor(xtp, smbXcli_transport_destructor); |
565 | 0 | return xtp; |
566 | 0 | } |
567 | | |
568 | | struct smbXcli_transport *smbXcli_transport_bsd_tstream( |
569 | | TALLOC_CTX *mem_ctx, |
570 | | int *fd, |
571 | | enum tls_verify_peer_state verify_peer, |
572 | | const struct smb_transport *tp) |
573 | 0 | { |
574 | 0 | struct samba_sockaddr laddr = { |
575 | 0 | .sa_socklen = sizeof(struct sockaddr_storage), |
576 | 0 | }; |
577 | 0 | struct samba_sockaddr raddr = { |
578 | 0 | .sa_socklen = sizeof(struct sockaddr_storage), |
579 | 0 | }; |
580 | 0 | struct tstream_context *tstream = NULL; |
581 | 0 | struct smbXcli_transport *xtp = NULL; |
582 | 0 | int ret; |
583 | |
|
584 | 0 | ret = getsockname(*fd, &laddr.u.sa, &laddr.sa_socklen); |
585 | 0 | if (ret == -1) { |
586 | 0 | return NULL; |
587 | 0 | } |
588 | | |
589 | 0 | ret = getpeername(*fd, &raddr.u.sa, &raddr.sa_socklen); |
590 | 0 | if (ret == -1) { |
591 | 0 | return NULL; |
592 | 0 | } |
593 | | |
594 | 0 | ret = set_blocking(*fd, false); |
595 | 0 | if (ret < 0) { |
596 | 0 | return NULL; |
597 | 0 | } |
598 | | |
599 | 0 | ret = tstream_bsd_existing_socket(mem_ctx, *fd, &tstream); |
600 | 0 | if (ret == -1) { |
601 | 0 | return NULL; |
602 | 0 | } |
603 | 0 | *fd = -1; |
604 | 0 | tstream_bsd_optimize_readv(tstream, true); |
605 | |
|
606 | 0 | xtp = smbXcli_transport_tstream( |
607 | 0 | mem_ctx, &tstream, verify_peer, &laddr, &raddr, tp); |
608 | 0 | TALLOC_FREE(tstream); |
609 | 0 | return xtp; |
610 | 0 | } |
611 | | |
612 | | static int smbXcli_conn_destructor(struct smbXcli_conn *conn) |
613 | 0 | { |
614 | | /* |
615 | | * NT_STATUS_OK, means we do not notify the callers |
616 | | */ |
617 | 0 | smbXcli_conn_disconnect(conn, NT_STATUS_OK); |
618 | |
|
619 | 0 | while (conn->sessions) { |
620 | 0 | conn->sessions->conn = NULL; |
621 | 0 | DLIST_REMOVE(conn->sessions, conn->sessions); |
622 | 0 | } |
623 | |
|
624 | 0 | if (conn->smb1.trans_enc) { |
625 | 0 | TALLOC_FREE(conn->smb1.trans_enc); |
626 | 0 | } |
627 | |
|
628 | 0 | return 0; |
629 | 0 | } |
630 | | |
631 | | struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx, |
632 | | struct smbXcli_transport **ptransport, |
633 | | const char *remote_name, |
634 | | enum smb_signing_setting signing_state, |
635 | | uint32_t smb1_capabilities, |
636 | | struct GUID *client_guid, |
637 | | uint32_t smb2_capabilities, |
638 | | const struct smb311_capabilities *smb3_capabilities) |
639 | 0 | { |
640 | 0 | struct smbXcli_conn *conn = NULL; |
641 | |
|
642 | 0 | if (smb3_capabilities != NULL) { |
643 | 0 | const struct smb3_signing_capabilities *sign_algos = |
644 | 0 | &smb3_capabilities->signing; |
645 | 0 | const struct smb3_encryption_capabilities *ciphers = |
646 | 0 | &smb3_capabilities->encryption; |
647 | |
|
648 | 0 | SMB_ASSERT(sign_algos->num_algos <= SMB3_SIGNING_CAPABILITIES_MAX_ALGOS); |
649 | 0 | SMB_ASSERT(ciphers->num_algos <= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS); |
650 | 0 | } |
651 | | |
652 | 0 | conn = talloc_zero(mem_ctx, struct smbXcli_conn); |
653 | 0 | if (!conn) { |
654 | 0 | return NULL; |
655 | 0 | } |
656 | | |
657 | 0 | conn->transport = talloc_move(conn, ptransport); |
658 | |
|
659 | 0 | conn->remote_name = talloc_strdup(conn, remote_name); |
660 | 0 | if (conn->remote_name == NULL) { |
661 | 0 | goto error; |
662 | 0 | } |
663 | | |
664 | 0 | conn->outgoing = tevent_queue_create(conn, "smbXcli_outgoing"); |
665 | 0 | if (conn->outgoing == NULL) { |
666 | 0 | goto error; |
667 | 0 | } |
668 | 0 | conn->pending = NULL; |
669 | |
|
670 | 0 | conn->min_protocol = PROTOCOL_NONE; |
671 | 0 | conn->max_protocol = PROTOCOL_NONE; |
672 | 0 | conn->protocol = PROTOCOL_NONE; |
673 | |
|
674 | 0 | switch (signing_state) { |
675 | 0 | case SMB_SIGNING_OFF: |
676 | | /* never */ |
677 | 0 | conn->allow_signing = false; |
678 | 0 | conn->desire_signing = false; |
679 | 0 | conn->mandatory_signing = false; |
680 | 0 | break; |
681 | 0 | case SMB_SIGNING_DEFAULT: |
682 | 0 | case SMB_SIGNING_IF_REQUIRED: |
683 | | /* if the server requires it */ |
684 | 0 | conn->allow_signing = true; |
685 | 0 | conn->desire_signing = false; |
686 | 0 | conn->mandatory_signing = false; |
687 | 0 | break; |
688 | 0 | case SMB_SIGNING_DESIRED: |
689 | | /* if the server desires it */ |
690 | 0 | conn->allow_signing = true; |
691 | 0 | conn->desire_signing = true; |
692 | 0 | conn->mandatory_signing = false; |
693 | 0 | break; |
694 | 0 | case SMB_SIGNING_IPC_DEFAULT: |
695 | 0 | case SMB_SIGNING_REQUIRED: |
696 | | /* always */ |
697 | 0 | conn->allow_signing = true; |
698 | 0 | conn->desire_signing = true; |
699 | 0 | conn->mandatory_signing = true; |
700 | 0 | break; |
701 | 0 | } |
702 | | |
703 | 0 | conn->smb1.client.capabilities = smb1_capabilities; |
704 | 0 | conn->smb1.client.max_xmit = UINT16_MAX; |
705 | |
|
706 | 0 | conn->smb1.capabilities = conn->smb1.client.capabilities; |
707 | 0 | conn->smb1.max_xmit = 1024; |
708 | |
|
709 | 0 | conn->smb1.mid = 1; |
710 | | |
711 | | /* initialise signing */ |
712 | 0 | conn->smb1.signing = smb1_signing_init(conn, |
713 | 0 | conn->allow_signing, |
714 | 0 | conn->desire_signing, |
715 | 0 | conn->mandatory_signing); |
716 | 0 | if (!conn->smb1.signing) { |
717 | 0 | goto error; |
718 | 0 | } |
719 | | |
720 | 0 | conn->smb2.client.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; |
721 | 0 | if (conn->mandatory_signing) { |
722 | 0 | conn->smb2.client.security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; |
723 | 0 | } |
724 | 0 | if (client_guid) { |
725 | 0 | conn->smb2.client.guid = *client_guid; |
726 | 0 | } |
727 | 0 | conn->smb2.client.capabilities = smb2_capabilities; |
728 | 0 | if (smb3_capabilities != NULL) { |
729 | 0 | conn->smb2.client.smb3_capabilities = *smb3_capabilities; |
730 | 0 | } |
731 | |
|
732 | 0 | conn->smb2.cur_credits = 1; |
733 | 0 | conn->smb2.max_credits = 0; |
734 | 0 | conn->smb2.io_priority = 1; |
735 | | |
736 | | /* |
737 | | * Samba and Windows servers accept a maximum of 16 MiB with a maximum |
738 | | * chunk length of 1 MiB. |
739 | | */ |
740 | 0 | conn->smb2.cc_chunk_len = 1024 * 1024; |
741 | 0 | conn->smb2.cc_max_chunks = 16; |
742 | |
|
743 | 0 | talloc_set_destructor(conn, smbXcli_conn_destructor); |
744 | 0 | return conn; |
745 | | |
746 | 0 | error: |
747 | 0 | TALLOC_FREE(conn); |
748 | 0 | return NULL; |
749 | 0 | } |
750 | | |
751 | | bool smbXcli_conn_is_connected(struct smbXcli_conn *conn) |
752 | 0 | { |
753 | 0 | int ret; |
754 | |
|
755 | 0 | if (conn == NULL) { |
756 | 0 | return false; |
757 | 0 | } |
758 | | |
759 | 0 | if (conn->transport == NULL) { |
760 | 0 | return false; |
761 | 0 | } |
762 | | |
763 | 0 | if (conn->transport->tstream != NULL) { |
764 | 0 | ret = tstream_pending_bytes(conn->transport->tstream); |
765 | 0 | if (ret < 0) { |
766 | 0 | return false; |
767 | 0 | } |
768 | | |
769 | 0 | return true; |
770 | 0 | } |
771 | | |
772 | 0 | if (conn->transport->sock_fd == -1) { |
773 | 0 | return false; |
774 | 0 | } |
775 | | |
776 | 0 | ret = samba_socket_poll_or_sock_error(conn->transport->sock_fd); |
777 | 0 | if (ret < 0) { |
778 | 0 | return false; |
779 | 0 | } |
780 | | |
781 | 0 | return true; |
782 | 0 | } |
783 | | |
784 | | enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn) |
785 | 0 | { |
786 | 0 | return conn->protocol; |
787 | 0 | } |
788 | | |
789 | | bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn) |
790 | 0 | { |
791 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
792 | 0 | return true; |
793 | 0 | } |
794 | | |
795 | 0 | if (conn->smb1.capabilities & CAP_UNICODE) { |
796 | 0 | return true; |
797 | 0 | } |
798 | | |
799 | 0 | return false; |
800 | 0 | } |
801 | | |
802 | | bool smbXcli_conn_signing_mandatory(struct smbXcli_conn *conn) |
803 | 0 | { |
804 | 0 | return conn->mandatory_signing; |
805 | 0 | } |
806 | | |
807 | | bool smbXcli_conn_have_posix(struct smbXcli_conn *conn) |
808 | 0 | { |
809 | 0 | if (conn->protocol >= PROTOCOL_SMB3_11) { |
810 | 0 | return conn->smb2.server.smb311_posix; |
811 | 0 | } |
812 | 0 | if (conn->protocol <= PROTOCOL_NT1) { |
813 | 0 | return (conn->smb1.capabilities & CAP_UNIX); |
814 | 0 | } |
815 | 0 | return false; |
816 | 0 | } |
817 | | |
818 | | /* |
819 | | * [MS-SMB] 2.2.2.3.5 - SMB1 support for passing through |
820 | | * query/set commands to the file system |
821 | | */ |
822 | | bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn) |
823 | 0 | { |
824 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
825 | 0 | return true; |
826 | 0 | } |
827 | | |
828 | 0 | if (conn->smb1.capabilities & CAP_W2K_SMBS) { |
829 | 0 | return true; |
830 | 0 | } |
831 | | |
832 | 0 | return false; |
833 | 0 | } |
834 | | |
835 | | void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options) |
836 | 0 | { |
837 | 0 | if (conn->transport->sock_fd == -1) { |
838 | 0 | return; |
839 | 0 | } |
840 | | |
841 | 0 | set_socket_options(conn->transport->sock_fd, options); |
842 | 0 | } |
843 | | |
844 | | const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn) |
845 | 0 | { |
846 | 0 | return &conn->transport->laddr.u.ss; |
847 | 0 | } |
848 | | |
849 | | const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn) |
850 | 0 | { |
851 | 0 | return &conn->transport->raddr.u.ss; |
852 | 0 | } |
853 | | |
854 | | const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn) |
855 | 0 | { |
856 | 0 | return conn->remote_name; |
857 | 0 | } |
858 | | |
859 | | uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn) |
860 | 0 | { |
861 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
862 | | /* |
863 | | * TODO... |
864 | | */ |
865 | 0 | return 1; |
866 | 0 | } |
867 | | |
868 | 0 | return conn->smb1.server.max_mux; |
869 | 0 | } |
870 | | |
871 | | NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn) |
872 | 0 | { |
873 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
874 | 0 | return conn->smb2.server.system_time; |
875 | 0 | } |
876 | | |
877 | 0 | return conn->smb1.server.system_time; |
878 | 0 | } |
879 | | |
880 | | const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn) |
881 | 0 | { |
882 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
883 | 0 | return &conn->smb2.server.gss_blob; |
884 | 0 | } |
885 | | |
886 | 0 | return &conn->smb1.server.gss_blob; |
887 | 0 | } |
888 | | |
889 | | const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn) |
890 | 0 | { |
891 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
892 | 0 | return &conn->smb2.server.guid; |
893 | 0 | } |
894 | | |
895 | 0 | return &conn->smb1.server.guid; |
896 | 0 | } |
897 | | |
898 | | bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn) |
899 | 0 | { |
900 | 0 | return conn->smb2.force_channel_sequence; |
901 | 0 | } |
902 | | |
903 | | void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn, |
904 | | bool v) |
905 | 0 | { |
906 | 0 | conn->smb2.force_channel_sequence = v; |
907 | 0 | } |
908 | | |
909 | | struct smbXcli_conn_samba_suicide_state { |
910 | | struct smbXcli_conn *conn; |
911 | | struct iovec iov; |
912 | | uint8_t buf[9]; |
913 | | struct tevent_req *write_req; |
914 | | ssize_t (*writev_recv_fn)(struct tevent_req *req, int *perrno); |
915 | | }; |
916 | | |
917 | | static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req, |
918 | | enum tevent_req_state req_state); |
919 | | static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq); |
920 | | |
921 | | struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx, |
922 | | struct tevent_context *ev, |
923 | | struct smbXcli_conn *conn, |
924 | | uint8_t exitcode) |
925 | 0 | { |
926 | 0 | struct tevent_req *req, *subreq; |
927 | 0 | struct smbXcli_conn_samba_suicide_state *state; |
928 | 0 | struct smbXcli_transport *xtp = NULL; |
929 | |
|
930 | 0 | req = tevent_req_create(mem_ctx, &state, |
931 | 0 | struct smbXcli_conn_samba_suicide_state); |
932 | 0 | if (req == NULL) { |
933 | 0 | return NULL; |
934 | 0 | } |
935 | 0 | state->conn = conn; |
936 | 0 | SIVAL(state->buf, 4, SMB_SUICIDE_PACKET); |
937 | 0 | SCVAL(state->buf, 8, exitcode); |
938 | 0 | _smb_setlen_nbt(state->buf, sizeof(state->buf)-4); |
939 | |
|
940 | 0 | if (conn->suicide_req != NULL) { |
941 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); |
942 | 0 | return tevent_req_post(req, ev); |
943 | 0 | } |
944 | | |
945 | 0 | state->iov.iov_base = state->buf; |
946 | 0 | state->iov.iov_len = sizeof(state->buf); |
947 | |
|
948 | 0 | xtp = conn->transport; |
949 | 0 | subreq = xtp->writev_send_fn(state, |
950 | 0 | ev, |
951 | 0 | xtp, |
952 | 0 | conn->outgoing, |
953 | 0 | &state->iov, |
954 | 0 | 1); |
955 | 0 | if (tevent_req_nomem(subreq, req)) { |
956 | 0 | return tevent_req_post(req, ev); |
957 | 0 | } |
958 | 0 | state->writev_recv_fn = xtp->writev_recv_fn; |
959 | 0 | tevent_req_set_callback(subreq, smbXcli_conn_samba_suicide_done, req); |
960 | 0 | state->write_req = subreq; |
961 | |
|
962 | 0 | tevent_req_set_cleanup_fn(req, smbXcli_conn_samba_suicide_cleanup); |
963 | | |
964 | | /* |
965 | | * We need to use tevent_req_defer_callback() |
966 | | * in order to allow smbXcli_conn_disconnect() |
967 | | * to do a safe cleanup. |
968 | | */ |
969 | 0 | tevent_req_defer_callback(req, ev); |
970 | 0 | conn->suicide_req = req; |
971 | |
|
972 | 0 | return req; |
973 | 0 | } |
974 | | |
975 | | static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req, |
976 | | enum tevent_req_state req_state) |
977 | 0 | { |
978 | 0 | struct smbXcli_conn_samba_suicide_state *state = tevent_req_data( |
979 | 0 | req, struct smbXcli_conn_samba_suicide_state); |
980 | |
|
981 | 0 | TALLOC_FREE(state->write_req); |
982 | |
|
983 | 0 | if (state->conn == NULL) { |
984 | 0 | return; |
985 | 0 | } |
986 | | |
987 | 0 | if (state->conn->suicide_req == req) { |
988 | 0 | state->conn->suicide_req = NULL; |
989 | 0 | } |
990 | 0 | state->conn = NULL; |
991 | 0 | } |
992 | | |
993 | | static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq) |
994 | 0 | { |
995 | 0 | struct tevent_req *req = tevent_req_callback_data( |
996 | 0 | subreq, struct tevent_req); |
997 | 0 | struct smbXcli_conn_samba_suicide_state *state = tevent_req_data( |
998 | 0 | req, struct smbXcli_conn_samba_suicide_state); |
999 | 0 | ssize_t nwritten; |
1000 | 0 | int err; |
1001 | |
|
1002 | 0 | state->write_req = NULL; |
1003 | |
|
1004 | 0 | nwritten = state->writev_recv_fn(subreq, &err); |
1005 | 0 | TALLOC_FREE(subreq); |
1006 | 0 | if (nwritten == -1) { |
1007 | | /* here, we need to notify all pending requests */ |
1008 | 0 | NTSTATUS status = map_nt_error_from_unix_common(err); |
1009 | 0 | smbXcli_conn_disconnect(state->conn, status); |
1010 | 0 | return; |
1011 | 0 | } |
1012 | 0 | tevent_req_done(req); |
1013 | 0 | } |
1014 | | |
1015 | | NTSTATUS smbXcli_conn_samba_suicide_recv(struct tevent_req *req) |
1016 | 0 | { |
1017 | 0 | return tevent_req_simple_recv_ntstatus(req); |
1018 | 0 | } |
1019 | | |
1020 | | NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn, |
1021 | | uint8_t exitcode) |
1022 | 0 | { |
1023 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
1024 | 0 | struct tevent_context *ev; |
1025 | 0 | struct tevent_req *req; |
1026 | 0 | NTSTATUS status = NT_STATUS_NO_MEMORY; |
1027 | 0 | bool ok; |
1028 | |
|
1029 | 0 | if (smbXcli_conn_has_async_calls(conn)) { |
1030 | | /* |
1031 | | * Can't use sync call while an async call is in flight |
1032 | | */ |
1033 | 0 | status = NT_STATUS_INVALID_PARAMETER_MIX; |
1034 | 0 | goto fail; |
1035 | 0 | } |
1036 | 0 | ev = samba_tevent_context_init(frame); |
1037 | 0 | if (ev == NULL) { |
1038 | 0 | goto fail; |
1039 | 0 | } |
1040 | 0 | req = smbXcli_conn_samba_suicide_send(frame, ev, conn, exitcode); |
1041 | 0 | if (req == NULL) { |
1042 | 0 | goto fail; |
1043 | 0 | } |
1044 | 0 | ok = tevent_req_poll_ntstatus(req, ev, &status); |
1045 | 0 | if (!ok) { |
1046 | 0 | goto fail; |
1047 | 0 | } |
1048 | 0 | status = smbXcli_conn_samba_suicide_recv(req); |
1049 | 0 | fail: |
1050 | 0 | TALLOC_FREE(frame); |
1051 | 0 | return status; |
1052 | 0 | } |
1053 | | |
1054 | | uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn) |
1055 | 0 | { |
1056 | 0 | return conn->smb1.capabilities; |
1057 | 0 | } |
1058 | | |
1059 | | uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn) |
1060 | 0 | { |
1061 | 0 | return conn->smb1.max_xmit; |
1062 | 0 | } |
1063 | | |
1064 | | bool smb1cli_conn_req_possible(struct smbXcli_conn *conn) |
1065 | 0 | { |
1066 | 0 | size_t pending = talloc_array_length(conn->pending); |
1067 | 0 | uint16_t possible = conn->smb1.server.max_mux; |
1068 | |
|
1069 | 0 | if (pending >= possible) { |
1070 | 0 | return false; |
1071 | 0 | } |
1072 | | |
1073 | 0 | return true; |
1074 | 0 | } |
1075 | | |
1076 | | uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn) |
1077 | 0 | { |
1078 | 0 | return conn->smb1.server.session_key; |
1079 | 0 | } |
1080 | | |
1081 | | const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn) |
1082 | 0 | { |
1083 | 0 | return conn->smb1.server.challenge; |
1084 | 0 | } |
1085 | | |
1086 | | uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn) |
1087 | 0 | { |
1088 | 0 | return conn->smb1.server.security_mode; |
1089 | 0 | } |
1090 | | |
1091 | | bool smb1cli_conn_server_readbraw(struct smbXcli_conn *conn) |
1092 | 0 | { |
1093 | 0 | return conn->smb1.server.readbraw; |
1094 | 0 | } |
1095 | | |
1096 | | bool smb1cli_conn_server_writebraw(struct smbXcli_conn *conn) |
1097 | 0 | { |
1098 | 0 | return conn->smb1.server.writebraw; |
1099 | 0 | } |
1100 | | |
1101 | | bool smb1cli_conn_server_lockread(struct smbXcli_conn *conn) |
1102 | 0 | { |
1103 | 0 | return conn->smb1.server.lockread; |
1104 | 0 | } |
1105 | | |
1106 | | bool smb1cli_conn_server_writeunlock(struct smbXcli_conn *conn) |
1107 | 0 | { |
1108 | 0 | return conn->smb1.server.writeunlock; |
1109 | 0 | } |
1110 | | |
1111 | | int smb1cli_conn_server_time_zone(struct smbXcli_conn *conn) |
1112 | 0 | { |
1113 | 0 | return conn->smb1.server.time_zone; |
1114 | 0 | } |
1115 | | |
1116 | | bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn, |
1117 | | const DATA_BLOB user_session_key, |
1118 | | const DATA_BLOB response) |
1119 | 0 | { |
1120 | 0 | return smb1_signing_activate(conn->smb1.signing, |
1121 | 0 | user_session_key, |
1122 | 0 | response); |
1123 | 0 | } |
1124 | | |
1125 | | bool smb1cli_conn_check_signing(struct smbXcli_conn *conn, |
1126 | | const uint8_t *buf, uint32_t seqnum) |
1127 | 0 | { |
1128 | 0 | const uint8_t *hdr = buf + NBT_HDR_SIZE; |
1129 | 0 | size_t len = smb_len_nbt(buf); |
1130 | |
|
1131 | 0 | return smb1_signing_check_pdu(conn->smb1.signing, hdr, len, seqnum); |
1132 | 0 | } |
1133 | | |
1134 | | bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn) |
1135 | 0 | { |
1136 | 0 | return smb1_signing_is_active(conn->smb1.signing); |
1137 | 0 | } |
1138 | | |
1139 | | void smb1cli_conn_set_encryption(struct smbXcli_conn *conn, |
1140 | | struct smb_trans_enc_state *es) |
1141 | 0 | { |
1142 | | /* Replace the old state, if any. */ |
1143 | 0 | if (conn->smb1.trans_enc) { |
1144 | 0 | TALLOC_FREE(conn->smb1.trans_enc); |
1145 | 0 | } |
1146 | 0 | conn->smb1.trans_enc = es; |
1147 | 0 | } |
1148 | | |
1149 | | bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn) |
1150 | 0 | { |
1151 | 0 | return common_encryption_on(conn->smb1.trans_enc); |
1152 | 0 | } |
1153 | | |
1154 | | |
1155 | | static NTSTATUS smb1cli_pull_raw_error(const uint8_t *hdr) |
1156 | 0 | { |
1157 | 0 | uint32_t flags2 = SVAL(hdr, HDR_FLG2); |
1158 | 0 | NTSTATUS status = NT_STATUS(IVAL(hdr, HDR_RCLS)); |
1159 | |
|
1160 | 0 | if (NT_STATUS_IS_OK(status)) { |
1161 | 0 | return NT_STATUS_OK; |
1162 | 0 | } |
1163 | | |
1164 | 0 | if (flags2 & FLAGS2_32_BIT_ERROR_CODES) { |
1165 | 0 | return status; |
1166 | 0 | } |
1167 | | |
1168 | 0 | return NT_STATUS_DOS(CVAL(hdr, HDR_RCLS), SVAL(hdr, HDR_ERR)); |
1169 | 0 | } |
1170 | | |
1171 | | /** |
1172 | | * Is the SMB command able to hold an AND_X successor |
1173 | | * @param[in] cmd The SMB command in question |
1174 | | * @retval Can we add a chained request after "cmd"? |
1175 | | */ |
1176 | | bool smb1cli_is_andx_req(uint8_t cmd) |
1177 | 0 | { |
1178 | 0 | switch (cmd) { |
1179 | 0 | case SMBtconX: |
1180 | 0 | case SMBlockingX: |
1181 | 0 | case SMBopenX: |
1182 | 0 | case SMBreadX: |
1183 | 0 | case SMBwriteX: |
1184 | 0 | case SMBsesssetupX: |
1185 | 0 | case SMBulogoffX: |
1186 | 0 | case SMBntcreateX: |
1187 | 0 | return true; |
1188 | 0 | break; |
1189 | 0 | default: |
1190 | 0 | break; |
1191 | 0 | } |
1192 | | |
1193 | 0 | return false; |
1194 | 0 | } |
1195 | | |
1196 | | static uint16_t smb1cli_alloc_mid(struct smbXcli_conn *conn) |
1197 | 0 | { |
1198 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
1199 | 0 | uint16_t result; |
1200 | |
|
1201 | 0 | if (conn->protocol == PROTOCOL_NONE) { |
1202 | | /* |
1203 | | * This is what windows sends on the SMB1 Negprot request |
1204 | | * and some vendors reuse the SMB1 MID as SMB2 sequence number. |
1205 | | */ |
1206 | 0 | return 0; |
1207 | 0 | } |
1208 | | |
1209 | 0 | while (true) { |
1210 | 0 | size_t i; |
1211 | |
|
1212 | 0 | result = conn->smb1.mid++; |
1213 | 0 | if ((result == 0) || (result == 0xffff)) { |
1214 | 0 | continue; |
1215 | 0 | } |
1216 | | |
1217 | 0 | for (i=0; i<num_pending; i++) { |
1218 | 0 | if (result == smb1cli_req_mid(conn->pending[i])) { |
1219 | 0 | break; |
1220 | 0 | } |
1221 | 0 | } |
1222 | |
|
1223 | 0 | if (i == num_pending) { |
1224 | 0 | return result; |
1225 | 0 | } |
1226 | 0 | } |
1227 | 0 | } |
1228 | | |
1229 | | static NTSTATUS smbXcli_req_cancel_write_req(struct tevent_req *req) |
1230 | 0 | { |
1231 | 0 | struct smbXcli_req_state *state = |
1232 | 0 | tevent_req_data(req, |
1233 | 0 | struct smbXcli_req_state); |
1234 | 0 | struct smbXcli_conn *conn = state->conn; |
1235 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
1236 | 0 | ssize_t ret; |
1237 | 0 | int err; |
1238 | 0 | bool ok; |
1239 | |
|
1240 | 0 | if (state->write_req == NULL) { |
1241 | 0 | return NT_STATUS_OK; |
1242 | 0 | } |
1243 | | |
1244 | | /* |
1245 | | * Check if it's possible to cancel the request. |
1246 | | * If the result is true it's not too late. |
1247 | | * See writev_cancel(). |
1248 | | */ |
1249 | 0 | ok = tevent_req_cancel(state->write_req); |
1250 | 0 | if (ok) { |
1251 | 0 | TALLOC_FREE(state->write_req); |
1252 | |
|
1253 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
1254 | | /* |
1255 | | * SMB2 has a sane signing state. |
1256 | | */ |
1257 | 0 | return NT_STATUS_OK; |
1258 | 0 | } |
1259 | | |
1260 | 0 | if (num_pending > 1) { |
1261 | | /* |
1262 | | * We have more pending requests following us. This |
1263 | | * means the signing state will be broken for them. |
1264 | | * |
1265 | | * As a solution we could add the requests directly to |
1266 | | * our outgoing queue and do the signing in the trigger |
1267 | | * function and then use writev_send() without passing a |
1268 | | * queue. That way we'll only sign packets we're most |
1269 | | * likely send to the wire. |
1270 | | */ |
1271 | 0 | return NT_STATUS_REQUEST_OUT_OF_SEQUENCE; |
1272 | 0 | } |
1273 | | |
1274 | | /* |
1275 | | * If we're the only request that's |
1276 | | * pending, we're able to recover the signing |
1277 | | * state. |
1278 | | */ |
1279 | 0 | smb1_signing_cancel_reply(conn->smb1.signing, |
1280 | 0 | state->smb1.one_way_seqnum); |
1281 | 0 | return NT_STATUS_OK; |
1282 | 0 | } |
1283 | | |
1284 | 0 | ret = state->writev_recv_fn(state->write_req, &err); |
1285 | 0 | TALLOC_FREE(state->write_req); |
1286 | 0 | if (ret == -1) { |
1287 | 0 | return map_nt_error_from_unix_common(err); |
1288 | 0 | } |
1289 | | |
1290 | 0 | return NT_STATUS_OK; |
1291 | 0 | } |
1292 | | |
1293 | | void smbXcli_req_unset_pending(struct tevent_req *req) |
1294 | 0 | { |
1295 | 0 | struct smbXcli_req_state *state = |
1296 | 0 | tevent_req_data(req, |
1297 | 0 | struct smbXcli_req_state); |
1298 | 0 | struct smbXcli_conn *conn = state->conn; |
1299 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
1300 | 0 | size_t i; |
1301 | 0 | NTSTATUS cancel_status; |
1302 | |
|
1303 | 0 | cancel_status = smbXcli_req_cancel_write_req(req); |
1304 | |
|
1305 | 0 | if (state->smb1.mid != 0) { |
1306 | | /* |
1307 | | * This is a [nt]trans[2] request which waits |
1308 | | * for more than one reply. |
1309 | | */ |
1310 | 0 | if (!NT_STATUS_IS_OK(cancel_status)) { |
1311 | | /* |
1312 | | * If the write_req cancel didn't work |
1313 | | * we can't use the connection anymore. |
1314 | | */ |
1315 | 0 | smbXcli_conn_disconnect(conn, cancel_status); |
1316 | 0 | return; |
1317 | 0 | } |
1318 | 0 | return; |
1319 | 0 | } |
1320 | | |
1321 | 0 | tevent_req_set_cleanup_fn(req, NULL); |
1322 | |
|
1323 | 0 | if (num_pending == 1) { |
1324 | | /* |
1325 | | * The pending read_smb tevent_req is a child of |
1326 | | * conn->pending. So if nothing is pending anymore, we need to |
1327 | | * delete the socket read fde. |
1328 | | */ |
1329 | | /* TODO: smbXcli_conn_cancel_read_req */ |
1330 | 0 | TALLOC_FREE(conn->pending); |
1331 | 0 | conn->read_smb_req = NULL; |
1332 | |
|
1333 | 0 | if (!NT_STATUS_IS_OK(cancel_status)) { |
1334 | | /* |
1335 | | * If the write_req cancel didn't work |
1336 | | * we can't use the connection anymore. |
1337 | | */ |
1338 | 0 | smbXcli_conn_disconnect(conn, cancel_status); |
1339 | 0 | return; |
1340 | 0 | } |
1341 | 0 | return; |
1342 | 0 | } |
1343 | | |
1344 | 0 | for (i=0; i<num_pending; i++) { |
1345 | 0 | if (req == conn->pending[i]) { |
1346 | 0 | break; |
1347 | 0 | } |
1348 | 0 | } |
1349 | 0 | if (i == num_pending) { |
1350 | | /* |
1351 | | * Something's seriously broken. Just returning here is the |
1352 | | * right thing nevertheless, the point of this routine is to |
1353 | | * remove ourselves from conn->pending. |
1354 | | */ |
1355 | |
|
1356 | 0 | if (!NT_STATUS_IS_OK(cancel_status)) { |
1357 | | /* |
1358 | | * If the write_req cancel didn't work |
1359 | | * we can't use the connection anymore. |
1360 | | */ |
1361 | 0 | smbXcli_conn_disconnect(conn, cancel_status); |
1362 | 0 | return; |
1363 | 0 | } |
1364 | 0 | return; |
1365 | 0 | } |
1366 | | |
1367 | 0 | ARRAY_DEL_ELEMENT(conn->pending, i, num_pending); |
1368 | | |
1369 | | /* |
1370 | | * No NULL check here, we're shrinking by sizeof(void *), and |
1371 | | * talloc_realloc just adjusts the size for this. |
1372 | | */ |
1373 | 0 | conn->pending = talloc_realloc(NULL, conn->pending, struct tevent_req *, |
1374 | 0 | num_pending - 1); |
1375 | |
|
1376 | 0 | if (!NT_STATUS_IS_OK(cancel_status)) { |
1377 | | /* |
1378 | | * If the write_req cancel didn't work |
1379 | | * we can't use the connection anymore. |
1380 | | */ |
1381 | 0 | smbXcli_conn_disconnect(conn, cancel_status); |
1382 | 0 | return; |
1383 | 0 | } |
1384 | 0 | return; |
1385 | 0 | } |
1386 | | |
1387 | | static void smbXcli_req_cleanup(struct tevent_req *req, |
1388 | | enum tevent_req_state req_state) |
1389 | 0 | { |
1390 | 0 | struct smbXcli_req_state *state = |
1391 | 0 | tevent_req_data(req, |
1392 | 0 | struct smbXcli_req_state); |
1393 | 0 | struct smbXcli_conn *conn = state->conn; |
1394 | 0 | NTSTATUS cancel_status; |
1395 | |
|
1396 | 0 | switch (req_state) { |
1397 | 0 | case TEVENT_REQ_RECEIVED: |
1398 | | /* |
1399 | | * Make sure we really remove it from |
1400 | | * the pending array on destruction. |
1401 | | * |
1402 | | * smbXcli_req_unset_pending() calls |
1403 | | * smbXcli_req_cancel_write_req() internal |
1404 | | */ |
1405 | 0 | state->smb1.mid = 0; |
1406 | 0 | smbXcli_req_unset_pending(req); |
1407 | 0 | return; |
1408 | 0 | default: |
1409 | 0 | cancel_status = smbXcli_req_cancel_write_req(req); |
1410 | 0 | if (!NT_STATUS_IS_OK(cancel_status)) { |
1411 | | /* |
1412 | | * If the write_req cancel didn't work |
1413 | | * we can't use the connection anymore. |
1414 | | */ |
1415 | 0 | smbXcli_conn_disconnect(conn, cancel_status); |
1416 | 0 | return; |
1417 | 0 | } |
1418 | 0 | return; |
1419 | 0 | } |
1420 | 0 | } |
1421 | | |
1422 | | static bool smb1cli_req_cancel(struct tevent_req *req); |
1423 | | static bool smb2cli_req_cancel(struct tevent_req *req); |
1424 | | |
1425 | | static bool smbXcli_req_cancel(struct tevent_req *req) |
1426 | 0 | { |
1427 | 0 | struct smbXcli_req_state *state = |
1428 | 0 | tevent_req_data(req, |
1429 | 0 | struct smbXcli_req_state); |
1430 | |
|
1431 | 0 | if (!smbXcli_conn_is_connected(state->conn)) { |
1432 | 0 | return false; |
1433 | 0 | } |
1434 | | |
1435 | 0 | if (state->conn->protocol == PROTOCOL_NONE) { |
1436 | 0 | return false; |
1437 | 0 | } |
1438 | | |
1439 | 0 | if (state->conn->protocol >= PROTOCOL_SMB2_02) { |
1440 | 0 | return smb2cli_req_cancel(req); |
1441 | 0 | } |
1442 | | |
1443 | 0 | return smb1cli_req_cancel(req); |
1444 | 0 | } |
1445 | | |
1446 | | static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn); |
1447 | | |
1448 | | bool smbXcli_req_set_pending(struct tevent_req *req) |
1449 | 0 | { |
1450 | 0 | struct smbXcli_req_state *state = |
1451 | 0 | tevent_req_data(req, |
1452 | 0 | struct smbXcli_req_state); |
1453 | 0 | struct smbXcli_conn *conn = state->conn; |
1454 | 0 | struct tevent_req **pending = NULL; |
1455 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
1456 | |
|
1457 | 0 | if (!smbXcli_conn_is_connected(conn)) { |
1458 | 0 | return false; |
1459 | 0 | } |
1460 | | |
1461 | 0 | pending = talloc_realloc(conn, conn->pending, struct tevent_req *, |
1462 | 0 | num_pending+1); |
1463 | 0 | if (pending == NULL) { |
1464 | 0 | return false; |
1465 | 0 | } |
1466 | 0 | pending[num_pending] = req; |
1467 | 0 | conn->pending = pending; |
1468 | 0 | tevent_req_set_cleanup_fn(req, smbXcli_req_cleanup); |
1469 | 0 | tevent_req_set_cancel_fn(req, smbXcli_req_cancel); |
1470 | |
|
1471 | 0 | if (!smbXcli_conn_receive_next(conn)) { |
1472 | | /* |
1473 | | * the caller should notify the current request |
1474 | | * |
1475 | | * And all other pending requests get notified |
1476 | | * by smbXcli_conn_disconnect(). |
1477 | | */ |
1478 | 0 | smbXcli_req_unset_pending(req); |
1479 | 0 | smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY); |
1480 | 0 | return false; |
1481 | 0 | } |
1482 | | |
1483 | 0 | return true; |
1484 | 0 | } |
1485 | | |
1486 | | static void smbXcli_conn_received(struct tevent_req *subreq); |
1487 | | |
1488 | | static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn) |
1489 | 0 | { |
1490 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
1491 | 0 | struct tevent_req *req; |
1492 | 0 | struct smbXcli_req_state *state; |
1493 | 0 | struct smbXcli_transport *xtp = conn->transport; |
1494 | |
|
1495 | 0 | if (conn->read_smb_req != NULL) { |
1496 | 0 | return true; |
1497 | 0 | } |
1498 | | |
1499 | 0 | if (num_pending == 0) { |
1500 | 0 | if (conn->smb2.mid < UINT64_MAX) { |
1501 | | /* no more pending requests, so we are done for now */ |
1502 | 0 | return true; |
1503 | 0 | } |
1504 | | |
1505 | | /* |
1506 | | * If there are no more SMB2 requests possible, |
1507 | | * because we are out of message ids, |
1508 | | * we need to disconnect. |
1509 | | */ |
1510 | 0 | smbXcli_conn_disconnect(conn, NT_STATUS_CONNECTION_ABORTED); |
1511 | 0 | return true; |
1512 | 0 | } |
1513 | | |
1514 | 0 | req = conn->pending[0]; |
1515 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
1516 | | |
1517 | | /* |
1518 | | * We're the first ones, add the read_smb request that waits for the |
1519 | | * answer from the server |
1520 | | */ |
1521 | 0 | xtp = conn->transport; |
1522 | 0 | conn->read_smb_req = xtp->read_smb_send_fn(conn->pending, |
1523 | 0 | state->ev, |
1524 | 0 | xtp); |
1525 | 0 | if (conn->read_smb_req == NULL) { |
1526 | 0 | return false; |
1527 | 0 | } |
1528 | 0 | tevent_req_set_callback(conn->read_smb_req, smbXcli_conn_received, conn); |
1529 | 0 | return true; |
1530 | 0 | } |
1531 | | |
1532 | | void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status) |
1533 | 0 | { |
1534 | 0 | struct smbXcli_session *session; |
1535 | 0 | int sock_fd = conn->transport->sock_fd; |
1536 | 0 | struct tstream_context *tstream = conn->transport->tstream; |
1537 | |
|
1538 | 0 | tevent_queue_stop(conn->outgoing); |
1539 | |
|
1540 | 0 | conn->transport->sock_fd = -1; |
1541 | 0 | conn->transport->tstream = NULL; |
1542 | |
|
1543 | 0 | session = conn->sessions; |
1544 | 0 | if (talloc_array_length(conn->pending) == 0) { |
1545 | | /* |
1546 | | * if we do not have pending requests |
1547 | | * there is no need to update the channel_sequence |
1548 | | */ |
1549 | 0 | session = NULL; |
1550 | 0 | } |
1551 | 0 | for (; session; session = session->next) { |
1552 | 0 | smb2cli_session_increment_channel_sequence(session); |
1553 | 0 | } |
1554 | |
|
1555 | 0 | if (conn->monitor_req != NULL) { |
1556 | | /* |
1557 | | * smbXcli_conn_monitor_send() |
1558 | | * used tevent_req_defer_callback() already. |
1559 | | */ |
1560 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1561 | 0 | tevent_req_nterror(conn->monitor_req, status); |
1562 | 0 | } |
1563 | 0 | conn->monitor_req = NULL; |
1564 | 0 | } |
1565 | |
|
1566 | 0 | if (conn->suicide_req != NULL) { |
1567 | | /* |
1568 | | * smbXcli_conn_samba_suicide_send() |
1569 | | * used tevent_req_defer_callback() already. |
1570 | | */ |
1571 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1572 | 0 | tevent_req_nterror(conn->suicide_req, status); |
1573 | 0 | } |
1574 | 0 | conn->suicide_req = NULL; |
1575 | 0 | } |
1576 | | |
1577 | | /* |
1578 | | * Cancel all pending requests. We do not do a for-loop walking |
1579 | | * conn->pending because that array changes in |
1580 | | * smbXcli_req_unset_pending. |
1581 | | */ |
1582 | 0 | while (conn->pending != NULL && |
1583 | 0 | talloc_array_length(conn->pending) > 0) { |
1584 | 0 | struct tevent_req *req; |
1585 | 0 | struct smbXcli_req_state *state; |
1586 | 0 | struct tevent_req **chain; |
1587 | 0 | size_t num_chained; |
1588 | 0 | size_t i; |
1589 | |
|
1590 | 0 | req = conn->pending[0]; |
1591 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
1592 | |
|
1593 | 0 | if (state->smb1.chained_requests == NULL) { |
1594 | 0 | bool in_progress; |
1595 | | |
1596 | | /* |
1597 | | * We're dead. No point waiting for trans2 |
1598 | | * replies. |
1599 | | */ |
1600 | 0 | state->smb1.mid = 0; |
1601 | |
|
1602 | 0 | smbXcli_req_unset_pending(req); |
1603 | |
|
1604 | 0 | if (NT_STATUS_IS_OK(status)) { |
1605 | | /* do not notify the callers */ |
1606 | 0 | continue; |
1607 | 0 | } |
1608 | | |
1609 | 0 | in_progress = tevent_req_is_in_progress(req); |
1610 | 0 | if (!in_progress) { |
1611 | | /* |
1612 | | * already finished |
1613 | | */ |
1614 | 0 | continue; |
1615 | 0 | } |
1616 | | |
1617 | | /* |
1618 | | * we need to defer the callback, because we may notify |
1619 | | * more then one caller. |
1620 | | */ |
1621 | 0 | tevent_req_defer_callback(req, state->ev); |
1622 | 0 | tevent_req_nterror(req, status); |
1623 | 0 | continue; |
1624 | 0 | } |
1625 | | |
1626 | 0 | chain = talloc_move(conn, &state->smb1.chained_requests); |
1627 | 0 | num_chained = talloc_array_length(chain); |
1628 | |
|
1629 | 0 | for (i=0; i<num_chained; i++) { |
1630 | 0 | bool in_progress; |
1631 | |
|
1632 | 0 | req = chain[i]; |
1633 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
1634 | | |
1635 | | /* |
1636 | | * We're dead. No point waiting for trans2 |
1637 | | * replies. |
1638 | | */ |
1639 | 0 | state->smb1.mid = 0; |
1640 | |
|
1641 | 0 | smbXcli_req_unset_pending(req); |
1642 | |
|
1643 | 0 | if (NT_STATUS_IS_OK(status)) { |
1644 | | /* do not notify the callers */ |
1645 | 0 | continue; |
1646 | 0 | } |
1647 | | |
1648 | 0 | in_progress = tevent_req_is_in_progress(req); |
1649 | 0 | if (!in_progress) { |
1650 | | /* |
1651 | | * already finished |
1652 | | */ |
1653 | 0 | continue; |
1654 | 0 | } |
1655 | | |
1656 | | /* |
1657 | | * we need to defer the callback, because we may notify |
1658 | | * more than one caller. |
1659 | | */ |
1660 | 0 | tevent_req_defer_callback(req, state->ev); |
1661 | 0 | tevent_req_nterror(req, status); |
1662 | 0 | } |
1663 | 0 | TALLOC_FREE(chain); |
1664 | 0 | } |
1665 | |
|
1666 | 0 | if (sock_fd != -1) { |
1667 | 0 | close(sock_fd); |
1668 | 0 | } |
1669 | 0 | TALLOC_FREE(tstream); |
1670 | 0 | } |
1671 | | |
1672 | | struct smbXcli_conn_monitor_state { |
1673 | | struct smbXcli_conn *conn; |
1674 | | struct tevent_req *monitor_req; |
1675 | | int (*monitor_recv_fn)(struct tevent_req *req); |
1676 | | }; |
1677 | | |
1678 | | static void smbXcli_conn_monitor_cleanup(struct tevent_req *req, |
1679 | | enum tevent_req_state req_state); |
1680 | | static void smbXcli_conn_monitor_done(struct tevent_req *subreq); |
1681 | | |
1682 | | struct tevent_req *smbXcli_conn_monitor_send(TALLOC_CTX *mem_ctx, |
1683 | | struct tevent_context *ev, |
1684 | | struct smbXcli_conn *conn) |
1685 | 0 | { |
1686 | 0 | struct tevent_req *req = NULL; |
1687 | 0 | struct smbXcli_conn_monitor_state *state = NULL; |
1688 | 0 | struct tevent_req *subreq = NULL; |
1689 | 0 | struct smbXcli_transport *xtp = NULL; |
1690 | 0 | bool ok; |
1691 | |
|
1692 | 0 | req = tevent_req_create(mem_ctx, &state, |
1693 | 0 | struct smbXcli_conn_monitor_state); |
1694 | 0 | if (req == NULL) { |
1695 | 0 | return NULL; |
1696 | 0 | } |
1697 | 0 | state->conn = conn; |
1698 | |
|
1699 | 0 | if (conn->monitor_req != NULL) { |
1700 | 0 | tevent_req_nterror(req, NT_STATUS_ALREADY_REGISTERED); |
1701 | 0 | return tevent_req_post(req, ev); |
1702 | 0 | } |
1703 | | |
1704 | 0 | tevent_req_set_cleanup_fn(req, smbXcli_conn_monitor_cleanup); |
1705 | | |
1706 | | /* |
1707 | | * We need to use tevent_req_defer_callback() |
1708 | | * in order to allow smbXcli_conn_disconnect() |
1709 | | * to do a safe cleanup. |
1710 | | */ |
1711 | 0 | tevent_req_defer_callback(req, ev); |
1712 | 0 | conn->monitor_req = req; |
1713 | |
|
1714 | 0 | ok = smbXcli_conn_is_connected(conn); |
1715 | 0 | if (!ok) { |
1716 | 0 | smbXcli_conn_disconnect(conn, |
1717 | 0 | NT_STATUS_CONNECTION_DISCONNECTED); |
1718 | 0 | return tevent_req_post(req, ev); |
1719 | 0 | } |
1720 | | |
1721 | 0 | xtp = conn->transport; |
1722 | 0 | subreq = xtp->monitor_send_fn(state, ev, xtp); |
1723 | 0 | if (tevent_req_nomem(subreq, req)) { |
1724 | 0 | return tevent_req_post(req, ev); |
1725 | 0 | } |
1726 | 0 | state->monitor_recv_fn = xtp->monitor_recv_fn; |
1727 | 0 | tevent_req_set_callback(subreq, smbXcli_conn_monitor_done, req); |
1728 | 0 | state->monitor_req = subreq; |
1729 | |
|
1730 | 0 | return req; |
1731 | 0 | } |
1732 | | |
1733 | | static void smbXcli_conn_monitor_cleanup(struct tevent_req *req, |
1734 | | enum tevent_req_state req_state) |
1735 | 0 | { |
1736 | 0 | struct smbXcli_conn_monitor_state *state = tevent_req_data( |
1737 | 0 | req, struct smbXcli_conn_monitor_state); |
1738 | |
|
1739 | 0 | TALLOC_FREE(state->monitor_req); |
1740 | |
|
1741 | 0 | if (state->conn == NULL) { |
1742 | 0 | return; |
1743 | 0 | } |
1744 | | |
1745 | 0 | if (state->conn->monitor_req == req) { |
1746 | 0 | state->conn->monitor_req = NULL; |
1747 | 0 | } |
1748 | 0 | state->conn = NULL; |
1749 | 0 | } |
1750 | | |
1751 | | static void smbXcli_conn_monitor_done(struct tevent_req *subreq) |
1752 | 0 | { |
1753 | 0 | struct tevent_req *req = tevent_req_callback_data(subreq, |
1754 | 0 | struct tevent_req); |
1755 | 0 | struct smbXcli_conn_monitor_state *state = tevent_req_data( |
1756 | 0 | req, struct smbXcli_conn_monitor_state); |
1757 | 0 | NTSTATUS status; |
1758 | 0 | int err; |
1759 | |
|
1760 | 0 | state->monitor_req = NULL; |
1761 | |
|
1762 | 0 | err = state->monitor_recv_fn(subreq); |
1763 | 0 | TALLOC_FREE(subreq); |
1764 | | /* here, we need to notify all pending requests */ |
1765 | 0 | status = map_nt_error_from_unix_common(err); |
1766 | 0 | smbXcli_conn_disconnect(state->conn, status); |
1767 | 0 | } |
1768 | | |
1769 | | NTSTATUS smbXcli_conn_monitor_recv(struct tevent_req *req) |
1770 | 0 | { |
1771 | 0 | return tevent_req_simple_recv_ntstatus(req); |
1772 | 0 | } |
1773 | | |
1774 | | NTSTATUS smbXcli_conn_monitor_once(struct smbXcli_conn *conn) |
1775 | 0 | { |
1776 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
1777 | 0 | struct tevent_context *ev; |
1778 | 0 | struct tevent_req *req; |
1779 | 0 | NTSTATUS status = NT_STATUS_NO_MEMORY; |
1780 | 0 | bool ok; |
1781 | |
|
1782 | 0 | if (smbXcli_conn_has_async_calls(conn)) { |
1783 | | /* |
1784 | | * Can't use sync call while an async call is in flight |
1785 | | */ |
1786 | 0 | status = NT_STATUS_INVALID_PARAMETER_MIX; |
1787 | 0 | goto fail; |
1788 | 0 | } |
1789 | 0 | ev = samba_tevent_context_init(frame); |
1790 | 0 | if (ev == NULL) { |
1791 | 0 | goto fail; |
1792 | 0 | } |
1793 | | /* |
1794 | | * We want tevent_req_poll() |
1795 | | * to return -1 and errno=EAGAIN |
1796 | | * instead of blocking in [e]poll waiting |
1797 | | * for external events to happen. |
1798 | | * |
1799 | | * So we use tevent_context_set_wait_timeout(0) |
1800 | | * that will cause tevent_loop_once() in |
1801 | | * tevent_req_poll() to break with EAGAIN. |
1802 | | * It also means that tevent_req_is_in_progress() |
1803 | | * would still return true. |
1804 | | */ |
1805 | 0 | tevent_context_set_wait_timeout(ev, 0); |
1806 | 0 | req = smbXcli_conn_monitor_send(frame, ev, conn); |
1807 | 0 | if (req == NULL) { |
1808 | 0 | goto fail; |
1809 | 0 | } |
1810 | 0 | ok = tevent_req_poll(req, ev); |
1811 | 0 | if (!ok) { |
1812 | 0 | if (errno == EAGAIN) { |
1813 | | /* |
1814 | | * This is exactly what we want: |
1815 | | * no existing events happened |
1816 | | * and we avoid blocking in |
1817 | | * [e]poll waiting. |
1818 | | * |
1819 | | * See also the comment above before |
1820 | | * tevent_context_set_wait_timeout! |
1821 | | * |
1822 | | * We don't call smbXcli_conn_monitor_recv() |
1823 | | * and let TALLOC_FREE(frame) destroy req |
1824 | | * as well. |
1825 | | */ |
1826 | 0 | status = NT_STATUS_OK; |
1827 | 0 | goto fail; |
1828 | 0 | } |
1829 | 0 | status = map_nt_error_from_unix_common(errno); |
1830 | 0 | goto fail; |
1831 | 0 | } |
1832 | 0 | status = smbXcli_conn_monitor_recv(req); |
1833 | 0 | fail: |
1834 | 0 | TALLOC_FREE(frame); |
1835 | 0 | return status; |
1836 | 0 | } |
1837 | | |
1838 | | /* |
1839 | | * Fetch a smb request's mid. Only valid after the request has been sent by |
1840 | | * smb1cli_req_send(). |
1841 | | */ |
1842 | | uint16_t smb1cli_req_mid(struct tevent_req *req) |
1843 | 0 | { |
1844 | 0 | struct smbXcli_req_state *state = |
1845 | 0 | tevent_req_data(req, |
1846 | 0 | struct smbXcli_req_state); |
1847 | |
|
1848 | 0 | if (state->smb1.mid != 0) { |
1849 | 0 | return state->smb1.mid; |
1850 | 0 | } |
1851 | | |
1852 | 0 | return SVAL(state->smb1.hdr, HDR_MID); |
1853 | 0 | } |
1854 | | |
1855 | | void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid) |
1856 | 0 | { |
1857 | 0 | struct smbXcli_req_state *state = |
1858 | 0 | tevent_req_data(req, |
1859 | 0 | struct smbXcli_req_state); |
1860 | |
|
1861 | 0 | state->smb1.mid = mid; |
1862 | 0 | } |
1863 | | |
1864 | | uint32_t smb1cli_req_seqnum(struct tevent_req *req) |
1865 | 0 | { |
1866 | 0 | struct smbXcli_req_state *state = |
1867 | 0 | tevent_req_data(req, |
1868 | 0 | struct smbXcli_req_state); |
1869 | |
|
1870 | 0 | return state->smb1.seqnum; |
1871 | 0 | } |
1872 | | |
1873 | | void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum) |
1874 | 0 | { |
1875 | 0 | struct smbXcli_req_state *state = |
1876 | 0 | tevent_req_data(req, |
1877 | 0 | struct smbXcli_req_state); |
1878 | |
|
1879 | 0 | state->smb1.seqnum = seqnum; |
1880 | 0 | } |
1881 | | |
1882 | | static size_t smbXcli_iov_len(const struct iovec *iov, int count) |
1883 | 0 | { |
1884 | 0 | ssize_t ret = iov_buflen(iov, count); |
1885 | | |
1886 | | /* Ignore the overflow case for now ... */ |
1887 | 0 | return ret; |
1888 | 0 | } |
1889 | | |
1890 | | static void smb1cli_req_flags(enum protocol_types protocol, |
1891 | | uint32_t smb1_capabilities, |
1892 | | uint8_t smb_command, |
1893 | | uint8_t additional_flags, |
1894 | | uint8_t clear_flags, |
1895 | | uint8_t *_flags, |
1896 | | uint16_t additional_flags2, |
1897 | | uint16_t clear_flags2, |
1898 | | uint16_t *_flags2) |
1899 | 0 | { |
1900 | 0 | uint8_t flags = 0; |
1901 | 0 | uint16_t flags2 = 0; |
1902 | |
|
1903 | 0 | if (protocol >= PROTOCOL_LANMAN1) { |
1904 | 0 | flags |= FLAG_CASELESS_PATHNAMES; |
1905 | 0 | flags |= FLAG_CANONICAL_PATHNAMES; |
1906 | 0 | } |
1907 | |
|
1908 | 0 | if (protocol >= PROTOCOL_LANMAN2) { |
1909 | 0 | flags2 |= FLAGS2_LONG_PATH_COMPONENTS; |
1910 | 0 | flags2 |= FLAGS2_EXTENDED_ATTRIBUTES; |
1911 | 0 | } |
1912 | |
|
1913 | 0 | if (protocol >= PROTOCOL_NT1) { |
1914 | 0 | flags2 |= FLAGS2_IS_LONG_NAME; |
1915 | |
|
1916 | 0 | if (smb1_capabilities & CAP_UNICODE) { |
1917 | 0 | flags2 |= FLAGS2_UNICODE_STRINGS; |
1918 | 0 | } |
1919 | 0 | if (smb1_capabilities & CAP_STATUS32) { |
1920 | 0 | flags2 |= FLAGS2_32_BIT_ERROR_CODES; |
1921 | 0 | } |
1922 | 0 | if (smb1_capabilities & CAP_EXTENDED_SECURITY) { |
1923 | 0 | flags2 |= FLAGS2_EXTENDED_SECURITY; |
1924 | 0 | } |
1925 | 0 | } |
1926 | |
|
1927 | 0 | flags |= additional_flags; |
1928 | 0 | flags &= ~clear_flags; |
1929 | 0 | flags2 |= additional_flags2; |
1930 | 0 | flags2 &= ~clear_flags2; |
1931 | |
|
1932 | 0 | *_flags = flags; |
1933 | 0 | *_flags2 = flags2; |
1934 | 0 | } |
1935 | | |
1936 | | static void smb1cli_req_cancel_done(struct tevent_req *subreq); |
1937 | | |
1938 | | static bool smb1cli_req_cancel(struct tevent_req *req) |
1939 | 0 | { |
1940 | 0 | struct smbXcli_req_state *state = |
1941 | 0 | tevent_req_data(req, |
1942 | 0 | struct smbXcli_req_state); |
1943 | 0 | uint8_t flags; |
1944 | 0 | uint16_t flags2; |
1945 | 0 | uint32_t pid; |
1946 | 0 | uint16_t mid; |
1947 | 0 | struct tevent_req *subreq; |
1948 | 0 | NTSTATUS status; |
1949 | |
|
1950 | 0 | flags = CVAL(state->smb1.hdr, HDR_FLG); |
1951 | 0 | flags2 = SVAL(state->smb1.hdr, HDR_FLG2); |
1952 | 0 | pid = SVAL(state->smb1.hdr, HDR_PID); |
1953 | 0 | pid |= SVAL(state->smb1.hdr, HDR_PIDHIGH)<<16; |
1954 | 0 | mid = SVAL(state->smb1.hdr, HDR_MID); |
1955 | |
|
1956 | 0 | subreq = smb1cli_req_create(state, state->ev, |
1957 | 0 | state->conn, |
1958 | 0 | SMBntcancel, |
1959 | 0 | flags, 0, |
1960 | 0 | flags2, 0, |
1961 | 0 | 0, /* timeout */ |
1962 | 0 | pid, |
1963 | 0 | state->tcon, |
1964 | 0 | state->session, |
1965 | 0 | 0, NULL, /* vwv */ |
1966 | 0 | 0, NULL); /* bytes */ |
1967 | 0 | if (subreq == NULL) { |
1968 | 0 | return false; |
1969 | 0 | } |
1970 | 0 | smb1cli_req_set_mid(subreq, mid); |
1971 | |
|
1972 | 0 | status = smb1cli_req_chain_submit(&subreq, 1); |
1973 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1974 | 0 | TALLOC_FREE(subreq); |
1975 | 0 | return false; |
1976 | 0 | } |
1977 | 0 | smb1cli_req_set_mid(subreq, 0); |
1978 | |
|
1979 | 0 | tevent_req_set_callback(subreq, smb1cli_req_cancel_done, NULL); |
1980 | |
|
1981 | 0 | return true; |
1982 | 0 | } |
1983 | | |
1984 | | static void smb1cli_req_cancel_done(struct tevent_req *subreq) |
1985 | 0 | { |
1986 | | /* we do not care about the result */ |
1987 | 0 | TALLOC_FREE(subreq); |
1988 | 0 | } |
1989 | | |
1990 | | struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx, |
1991 | | struct tevent_context *ev, |
1992 | | struct smbXcli_conn *conn, |
1993 | | uint8_t smb_command, |
1994 | | uint8_t additional_flags, |
1995 | | uint8_t clear_flags, |
1996 | | uint16_t additional_flags2, |
1997 | | uint16_t clear_flags2, |
1998 | | uint32_t timeout_msec, |
1999 | | uint32_t pid, |
2000 | | struct smbXcli_tcon *tcon, |
2001 | | struct smbXcli_session *session, |
2002 | | uint8_t wct, uint16_t *vwv, |
2003 | | int iov_count, |
2004 | | struct iovec *bytes_iov) |
2005 | 0 | { |
2006 | 0 | struct tevent_req *req; |
2007 | 0 | struct smbXcli_req_state *state; |
2008 | 0 | uint8_t flags = 0; |
2009 | 0 | uint16_t flags2 = 0; |
2010 | 0 | uint16_t uid = 0; |
2011 | 0 | uint16_t tid = 0; |
2012 | 0 | ssize_t num_bytes; |
2013 | |
|
2014 | 0 | if (iov_count > MAX_SMB_IOV) { |
2015 | | /* |
2016 | | * Should not happen :-) |
2017 | | */ |
2018 | 0 | return NULL; |
2019 | 0 | } |
2020 | | |
2021 | 0 | req = tevent_req_create(mem_ctx, &state, |
2022 | 0 | struct smbXcli_req_state); |
2023 | 0 | if (req == NULL) { |
2024 | 0 | return NULL; |
2025 | 0 | } |
2026 | 0 | state->ev = ev; |
2027 | 0 | state->conn = conn; |
2028 | 0 | state->session = session; |
2029 | 0 | state->tcon = tcon; |
2030 | |
|
2031 | 0 | if (session) { |
2032 | 0 | uid = session->smb1.session_id; |
2033 | 0 | } |
2034 | |
|
2035 | 0 | if (tcon) { |
2036 | 0 | tid = tcon->smb1.tcon_id; |
2037 | |
|
2038 | 0 | if (tcon->fs_attributes & FILE_CASE_SENSITIVE_SEARCH) { |
2039 | 0 | clear_flags |= FLAG_CASELESS_PATHNAMES; |
2040 | 0 | } else { |
2041 | | /* Default setting, case insensitive. */ |
2042 | 0 | additional_flags |= FLAG_CASELESS_PATHNAMES; |
2043 | 0 | } |
2044 | |
|
2045 | 0 | if (smbXcli_conn_dfs_supported(conn) && |
2046 | 0 | smbXcli_tcon_is_dfs_share(tcon)) |
2047 | 0 | { |
2048 | 0 | additional_flags2 |= FLAGS2_DFS_PATHNAMES; |
2049 | 0 | } |
2050 | 0 | } |
2051 | |
|
2052 | 0 | state->smb1.recv_cmd = 0xFF; |
2053 | 0 | state->smb1.recv_status = NT_STATUS_INTERNAL_ERROR; |
2054 | 0 | state->smb1.recv_iov = talloc_zero_array(state, struct iovec, 3); |
2055 | 0 | if (state->smb1.recv_iov == NULL) { |
2056 | 0 | TALLOC_FREE(req); |
2057 | 0 | return NULL; |
2058 | 0 | } |
2059 | | |
2060 | 0 | smb1cli_req_flags(conn->protocol, |
2061 | 0 | conn->smb1.capabilities, |
2062 | 0 | smb_command, |
2063 | 0 | additional_flags, |
2064 | 0 | clear_flags, |
2065 | 0 | &flags, |
2066 | 0 | additional_flags2, |
2067 | 0 | clear_flags2, |
2068 | 0 | &flags2); |
2069 | |
|
2070 | 0 | SIVAL(state->smb1.hdr, 0, SMB_MAGIC); |
2071 | 0 | SCVAL(state->smb1.hdr, HDR_COM, smb_command); |
2072 | 0 | SIVAL(state->smb1.hdr, HDR_RCLS, NT_STATUS_V(NT_STATUS_OK)); |
2073 | 0 | SCVAL(state->smb1.hdr, HDR_FLG, flags); |
2074 | 0 | SSVAL(state->smb1.hdr, HDR_FLG2, flags2); |
2075 | 0 | SSVAL(state->smb1.hdr, HDR_PIDHIGH, pid >> 16); |
2076 | 0 | SSVAL(state->smb1.hdr, HDR_TID, tid); |
2077 | 0 | SSVAL(state->smb1.hdr, HDR_PID, pid); |
2078 | 0 | SSVAL(state->smb1.hdr, HDR_UID, uid); |
2079 | 0 | SSVAL(state->smb1.hdr, HDR_MID, 0); /* this comes later */ |
2080 | 0 | SCVAL(state->smb1.hdr, HDR_WCT, wct); |
2081 | |
|
2082 | 0 | state->smb1.vwv = vwv; |
2083 | |
|
2084 | 0 | num_bytes = iov_buflen(bytes_iov, iov_count); |
2085 | 0 | if (num_bytes == -1) { |
2086 | | /* |
2087 | | * I'd love to add a check for num_bytes<=UINT16_MAX here, but |
2088 | | * the smbclient->samba connections can lie and transfer more. |
2089 | | */ |
2090 | 0 | TALLOC_FREE(req); |
2091 | 0 | return NULL; |
2092 | 0 | } |
2093 | | |
2094 | 0 | SSVAL(state->smb1.bytecount_buf, 0, num_bytes); |
2095 | |
|
2096 | 0 | state->smb1.iov[0].iov_base = (void *)state->length_hdr; |
2097 | 0 | state->smb1.iov[0].iov_len = sizeof(state->length_hdr); |
2098 | 0 | state->smb1.iov[1].iov_base = (void *)state->smb1.hdr; |
2099 | 0 | state->smb1.iov[1].iov_len = sizeof(state->smb1.hdr); |
2100 | 0 | state->smb1.iov[2].iov_base = (void *)state->smb1.vwv; |
2101 | 0 | state->smb1.iov[2].iov_len = wct * sizeof(uint16_t); |
2102 | 0 | state->smb1.iov[3].iov_base = (void *)state->smb1.bytecount_buf; |
2103 | 0 | state->smb1.iov[3].iov_len = sizeof(uint16_t); |
2104 | |
|
2105 | 0 | if (iov_count != 0) { |
2106 | 0 | memcpy(&state->smb1.iov[4], bytes_iov, |
2107 | 0 | iov_count * sizeof(*bytes_iov)); |
2108 | 0 | } |
2109 | 0 | state->smb1.iov_count = iov_count + 4; |
2110 | |
|
2111 | 0 | if (timeout_msec > 0) { |
2112 | 0 | state->endtime = timeval_current_ofs_msec(timeout_msec); |
2113 | 0 | if (!tevent_req_set_endtime(req, ev, state->endtime)) { |
2114 | 0 | return req; |
2115 | 0 | } |
2116 | 0 | } |
2117 | | |
2118 | 0 | switch (smb_command) { |
2119 | 0 | case SMBtranss: |
2120 | 0 | case SMBtranss2: |
2121 | 0 | case SMBnttranss: |
2122 | 0 | state->one_way = true; |
2123 | 0 | break; |
2124 | 0 | case SMBntcancel: |
2125 | 0 | state->one_way = true; |
2126 | 0 | state->smb1.one_way_seqnum = true; |
2127 | 0 | break; |
2128 | 0 | case SMBlockingX: |
2129 | 0 | if ((wct == 8) && |
2130 | 0 | (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) { |
2131 | 0 | state->one_way = true; |
2132 | 0 | } |
2133 | 0 | break; |
2134 | 0 | } |
2135 | | |
2136 | 0 | return req; |
2137 | 0 | } |
2138 | | |
2139 | | static NTSTATUS smb1cli_conn_signv(struct smbXcli_conn *conn, |
2140 | | struct iovec *iov, int iov_count, |
2141 | | uint32_t *seqnum, |
2142 | | bool one_way_seqnum) |
2143 | 0 | { |
2144 | 0 | TALLOC_CTX *frame = NULL; |
2145 | 0 | NTSTATUS status; |
2146 | 0 | uint8_t *buf; |
2147 | | |
2148 | | /* |
2149 | | * Obvious optimization: Make cli_calculate_sign_mac work with struct |
2150 | | * iovec directly. MD5Update would do that just fine. |
2151 | | */ |
2152 | |
|
2153 | 0 | if (iov_count < 4) { |
2154 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2155 | 0 | } |
2156 | 0 | if (iov[0].iov_len != NBT_HDR_SIZE) { |
2157 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2158 | 0 | } |
2159 | 0 | if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) { |
2160 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2161 | 0 | } |
2162 | 0 | if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) { |
2163 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2164 | 0 | } |
2165 | 0 | if (iov[3].iov_len != sizeof(uint16_t)) { |
2166 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2167 | 0 | } |
2168 | | |
2169 | 0 | frame = talloc_stackframe(); |
2170 | |
|
2171 | 0 | buf = iov_concat(frame, &iov[1], iov_count - 1); |
2172 | 0 | if (buf == NULL) { |
2173 | 0 | return NT_STATUS_NO_MEMORY; |
2174 | 0 | } |
2175 | | |
2176 | 0 | *seqnum = smb1_signing_next_seqnum(conn->smb1.signing, |
2177 | 0 | one_way_seqnum); |
2178 | 0 | status = smb1_signing_sign_pdu(conn->smb1.signing, |
2179 | 0 | buf, |
2180 | 0 | talloc_get_size(buf), |
2181 | 0 | *seqnum); |
2182 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2183 | 0 | return status; |
2184 | 0 | } |
2185 | 0 | memcpy(iov[1].iov_base, buf, iov[1].iov_len); |
2186 | |
|
2187 | 0 | TALLOC_FREE(frame); |
2188 | 0 | return NT_STATUS_OK; |
2189 | 0 | } |
2190 | | |
2191 | | static void smb1cli_req_writev_done(struct tevent_req *subreq); |
2192 | | static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn, |
2193 | | TALLOC_CTX *tmp_mem, |
2194 | | uint8_t *inbuf); |
2195 | | |
2196 | | static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req, |
2197 | | struct smbXcli_req_state *state, |
2198 | | struct iovec *iov, int iov_count) |
2199 | 0 | { |
2200 | 0 | struct smbXcli_transport *xtp = NULL; |
2201 | 0 | struct tevent_req *subreq; |
2202 | 0 | NTSTATUS status; |
2203 | 0 | uint8_t cmd; |
2204 | 0 | uint16_t mid; |
2205 | 0 | ssize_t nbtlen; |
2206 | |
|
2207 | 0 | if (!smbXcli_conn_is_connected(state->conn)) { |
2208 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
2209 | 0 | } |
2210 | | |
2211 | 0 | if (state->conn->protocol > PROTOCOL_NT1) { |
2212 | 0 | DBG_ERR("called for dialect[%s] server[%s]\n", |
2213 | 0 | smb_protocol_types_string(state->conn->protocol), |
2214 | 0 | smbXcli_conn_remote_name(state->conn)); |
2215 | 0 | return NT_STATUS_REVISION_MISMATCH; |
2216 | 0 | } |
2217 | | |
2218 | 0 | if (iov_count < 4) { |
2219 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2220 | 0 | } |
2221 | 0 | if (iov[0].iov_len != NBT_HDR_SIZE) { |
2222 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2223 | 0 | } |
2224 | 0 | if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) { |
2225 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2226 | 0 | } |
2227 | 0 | if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) { |
2228 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2229 | 0 | } |
2230 | 0 | if (iov[3].iov_len != sizeof(uint16_t)) { |
2231 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2232 | 0 | } |
2233 | | |
2234 | 0 | cmd = CVAL(iov[1].iov_base, HDR_COM); |
2235 | 0 | if (cmd == SMBreadBraw) { |
2236 | 0 | if (smbXcli_conn_has_async_calls(state->conn)) { |
2237 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2238 | 0 | } |
2239 | 0 | state->conn->smb1.read_braw_req = req; |
2240 | 0 | } |
2241 | | |
2242 | 0 | if (state->smb1.mid != 0) { |
2243 | 0 | mid = state->smb1.mid; |
2244 | 0 | } else { |
2245 | 0 | mid = smb1cli_alloc_mid(state->conn); |
2246 | 0 | } |
2247 | 0 | SSVAL(iov[1].iov_base, HDR_MID, mid); |
2248 | |
|
2249 | 0 | nbtlen = iov_buflen(&iov[1], iov_count-1); |
2250 | 0 | if ((nbtlen == -1) || (nbtlen > 0x1FFFF)) { |
2251 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
2252 | 0 | } |
2253 | | |
2254 | 0 | _smb_setlen_nbt(iov[0].iov_base, nbtlen); |
2255 | |
|
2256 | 0 | status = smb1cli_conn_signv(state->conn, iov, iov_count, |
2257 | 0 | &state->smb1.seqnum, |
2258 | 0 | state->smb1.one_way_seqnum); |
2259 | |
|
2260 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2261 | 0 | return status; |
2262 | 0 | } |
2263 | | |
2264 | | /* |
2265 | | * If we supported multiple encryption contexts |
2266 | | * here we'd look up based on tid. |
2267 | | */ |
2268 | 0 | if (common_encryption_on(state->conn->smb1.trans_enc)) { |
2269 | 0 | char *buf, *enc_buf; |
2270 | |
|
2271 | 0 | buf = (char *)iov_concat(talloc_tos(), iov, iov_count); |
2272 | 0 | if (buf == NULL) { |
2273 | 0 | return NT_STATUS_NO_MEMORY; |
2274 | 0 | } |
2275 | 0 | status = common_encrypt_buffer(state->conn->smb1.trans_enc, |
2276 | 0 | (char *)buf, &enc_buf); |
2277 | 0 | TALLOC_FREE(buf); |
2278 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2279 | 0 | DEBUG(0, ("Error in encrypting client message: %s\n", |
2280 | 0 | nt_errstr(status))); |
2281 | 0 | return status; |
2282 | 0 | } |
2283 | 0 | buf = (char *)talloc_memdup(state, enc_buf, |
2284 | 0 | smb_len_nbt(enc_buf)+4); |
2285 | 0 | SAFE_FREE(enc_buf); |
2286 | 0 | if (buf == NULL) { |
2287 | 0 | return NT_STATUS_NO_MEMORY; |
2288 | 0 | } |
2289 | 0 | iov[0].iov_base = (void *)buf; |
2290 | 0 | iov[0].iov_len = talloc_get_size(buf); |
2291 | 0 | iov_count = 1; |
2292 | 0 | } |
2293 | | |
2294 | 0 | if (state->conn->dispatch_incoming == NULL) { |
2295 | 0 | state->conn->dispatch_incoming = smb1cli_conn_dispatch_incoming; |
2296 | 0 | } |
2297 | |
|
2298 | 0 | if (!smbXcli_req_set_pending(req)) { |
2299 | 0 | return NT_STATUS_NO_MEMORY; |
2300 | 0 | } |
2301 | | |
2302 | 0 | tevent_req_set_cancel_fn(req, smbXcli_req_cancel); |
2303 | |
|
2304 | 0 | xtp = state->conn->transport; |
2305 | 0 | subreq = xtp->writev_send_fn(state, |
2306 | 0 | state->ev, |
2307 | 0 | xtp, |
2308 | 0 | state->conn->outgoing, |
2309 | 0 | iov, |
2310 | 0 | iov_count); |
2311 | 0 | if (subreq == NULL) { |
2312 | 0 | return NT_STATUS_NO_MEMORY; |
2313 | 0 | } |
2314 | 0 | state->writev_recv_fn = xtp->writev_recv_fn; |
2315 | 0 | tevent_req_set_callback(subreq, smb1cli_req_writev_done, req); |
2316 | 0 | state->write_req = subreq; |
2317 | |
|
2318 | 0 | return NT_STATUS_OK; |
2319 | 0 | } |
2320 | | |
2321 | | struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx, |
2322 | | struct tevent_context *ev, |
2323 | | struct smbXcli_conn *conn, |
2324 | | uint8_t smb_command, |
2325 | | uint8_t additional_flags, |
2326 | | uint8_t clear_flags, |
2327 | | uint16_t additional_flags2, |
2328 | | uint16_t clear_flags2, |
2329 | | uint32_t timeout_msec, |
2330 | | uint32_t pid, |
2331 | | struct smbXcli_tcon *tcon, |
2332 | | struct smbXcli_session *session, |
2333 | | uint8_t wct, uint16_t *vwv, |
2334 | | uint32_t num_bytes, |
2335 | | const uint8_t *bytes) |
2336 | 0 | { |
2337 | 0 | struct tevent_req *req; |
2338 | 0 | struct iovec iov; |
2339 | 0 | NTSTATUS status; |
2340 | |
|
2341 | 0 | iov.iov_base = discard_const_p(void, bytes); |
2342 | 0 | iov.iov_len = num_bytes; |
2343 | |
|
2344 | 0 | req = smb1cli_req_create(mem_ctx, ev, conn, smb_command, |
2345 | 0 | additional_flags, clear_flags, |
2346 | 0 | additional_flags2, clear_flags2, |
2347 | 0 | timeout_msec, |
2348 | 0 | pid, tcon, session, |
2349 | 0 | wct, vwv, 1, &iov); |
2350 | 0 | if (req == NULL) { |
2351 | 0 | return NULL; |
2352 | 0 | } |
2353 | 0 | if (!tevent_req_is_in_progress(req)) { |
2354 | 0 | return tevent_req_post(req, ev); |
2355 | 0 | } |
2356 | 0 | status = smb1cli_req_chain_submit(&req, 1); |
2357 | 0 | if (tevent_req_nterror(req, status)) { |
2358 | 0 | return tevent_req_post(req, ev); |
2359 | 0 | } |
2360 | 0 | return req; |
2361 | 0 | } |
2362 | | |
2363 | | static void smb1cli_req_writev_done(struct tevent_req *subreq) |
2364 | 0 | { |
2365 | 0 | struct tevent_req *req = |
2366 | 0 | tevent_req_callback_data(subreq, |
2367 | 0 | struct tevent_req); |
2368 | 0 | struct smbXcli_req_state *state = |
2369 | 0 | tevent_req_data(req, |
2370 | 0 | struct smbXcli_req_state); |
2371 | 0 | ssize_t nwritten; |
2372 | 0 | int err; |
2373 | |
|
2374 | 0 | state->write_req = NULL; |
2375 | |
|
2376 | 0 | nwritten = state->writev_recv_fn(subreq, &err); |
2377 | 0 | TALLOC_FREE(subreq); |
2378 | 0 | if (nwritten == -1) { |
2379 | | /* here, we need to notify all pending requests */ |
2380 | 0 | NTSTATUS status = map_nt_error_from_unix_common(err); |
2381 | 0 | smbXcli_conn_disconnect(state->conn, status); |
2382 | 0 | return; |
2383 | 0 | } |
2384 | | |
2385 | 0 | if (state->one_way) { |
2386 | 0 | state->inbuf = NULL; |
2387 | 0 | tevent_req_done(req); |
2388 | 0 | return; |
2389 | 0 | } |
2390 | 0 | } |
2391 | | |
2392 | | static void smbXcli_conn_received(struct tevent_req *subreq) |
2393 | 0 | { |
2394 | 0 | struct smbXcli_conn *conn = |
2395 | 0 | tevent_req_callback_data(subreq, |
2396 | 0 | struct smbXcli_conn); |
2397 | 0 | struct smbXcli_transport *xtp = conn->transport; |
2398 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
2399 | 0 | NTSTATUS status; |
2400 | 0 | uint8_t *inbuf; |
2401 | 0 | ssize_t received; |
2402 | 0 | int err; |
2403 | |
|
2404 | 0 | if (subreq != conn->read_smb_req) { |
2405 | 0 | DEBUG(1, ("Internal error: cli_smb_received called with " |
2406 | 0 | "unexpected subreq\n")); |
2407 | 0 | smbXcli_conn_disconnect(conn, NT_STATUS_INTERNAL_ERROR); |
2408 | 0 | TALLOC_FREE(frame); |
2409 | 0 | return; |
2410 | 0 | } |
2411 | 0 | conn->read_smb_req = NULL; |
2412 | |
|
2413 | 0 | received = xtp->read_smb_recv_fn(subreq, frame, &inbuf, &err); |
2414 | 0 | TALLOC_FREE(subreq); |
2415 | 0 | if (received == -1) { |
2416 | 0 | status = map_nt_error_from_unix_common(err); |
2417 | 0 | smbXcli_conn_disconnect(conn, status); |
2418 | 0 | TALLOC_FREE(frame); |
2419 | 0 | return; |
2420 | 0 | } |
2421 | | |
2422 | 0 | status = conn->dispatch_incoming(conn, frame, inbuf); |
2423 | 0 | TALLOC_FREE(frame); |
2424 | 0 | if (NT_STATUS_IS_OK(status)) { |
2425 | | /* |
2426 | | * We should not do any more processing |
2427 | | * as the dispatch function called |
2428 | | * tevent_req_done(). |
2429 | | */ |
2430 | 0 | return; |
2431 | 0 | } |
2432 | | |
2433 | 0 | if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { |
2434 | | /* |
2435 | | * We got an error, so notify all pending requests |
2436 | | */ |
2437 | 0 | smbXcli_conn_disconnect(conn, status); |
2438 | 0 | return; |
2439 | 0 | } |
2440 | | |
2441 | | /* |
2442 | | * We got NT_STATUS_RETRY, so we may ask for a |
2443 | | * next incoming pdu. |
2444 | | */ |
2445 | 0 | if (!smbXcli_conn_receive_next(conn)) { |
2446 | 0 | smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY); |
2447 | 0 | } |
2448 | 0 | } |
2449 | | |
2450 | | static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx, |
2451 | | struct iovec **piov, int *pnum_iov) |
2452 | 0 | { |
2453 | 0 | struct iovec *iov; |
2454 | 0 | size_t num_iov; |
2455 | 0 | size_t buflen; |
2456 | 0 | size_t taken; |
2457 | 0 | size_t remaining; |
2458 | 0 | uint8_t *hdr; |
2459 | 0 | uint8_t cmd; |
2460 | 0 | uint32_t wct_ofs; |
2461 | 0 | NTSTATUS status; |
2462 | 0 | size_t min_size = MIN_SMB_SIZE; |
2463 | |
|
2464 | 0 | buflen = smb_len_tcp(buf); |
2465 | 0 | taken = 0; |
2466 | |
|
2467 | 0 | hdr = buf + NBT_HDR_SIZE; |
2468 | |
|
2469 | 0 | status = smb1cli_pull_raw_error(hdr); |
2470 | 0 | if (NT_STATUS_IS_ERR(status)) { |
2471 | | /* |
2472 | | * This is an ugly hack to support OS/2 |
2473 | | * which skips the byte_count in the DATA block |
2474 | | * on some error responses. |
2475 | | * |
2476 | | * See bug #9096 |
2477 | | */ |
2478 | 0 | min_size -= sizeof(uint16_t); |
2479 | 0 | } |
2480 | |
|
2481 | 0 | if (buflen < min_size) { |
2482 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
2483 | 0 | } |
2484 | | |
2485 | | /* |
2486 | | * This returns iovec elements in the following order: |
2487 | | * |
2488 | | * - SMB header |
2489 | | * |
2490 | | * - Parameter Block |
2491 | | * - Data Block |
2492 | | * |
2493 | | * - Parameter Block |
2494 | | * - Data Block |
2495 | | * |
2496 | | * - Parameter Block |
2497 | | * - Data Block |
2498 | | */ |
2499 | 0 | num_iov = 1; |
2500 | |
|
2501 | 0 | iov = talloc_array(mem_ctx, struct iovec, num_iov); |
2502 | 0 | if (iov == NULL) { |
2503 | 0 | return NT_STATUS_NO_MEMORY; |
2504 | 0 | } |
2505 | 0 | iov[0].iov_base = hdr; |
2506 | 0 | iov[0].iov_len = HDR_WCT; |
2507 | 0 | taken += HDR_WCT; |
2508 | |
|
2509 | 0 | cmd = CVAL(hdr, HDR_COM); |
2510 | 0 | wct_ofs = HDR_WCT; |
2511 | |
|
2512 | 0 | while (true) { |
2513 | 0 | size_t len = buflen - taken; |
2514 | 0 | struct iovec *cur; |
2515 | 0 | struct iovec *iov_tmp; |
2516 | 0 | uint8_t wct; |
2517 | 0 | uint32_t bcc_ofs; |
2518 | 0 | uint16_t bcc; |
2519 | 0 | size_t needed; |
2520 | | |
2521 | | /* |
2522 | | * we need at least WCT |
2523 | | */ |
2524 | 0 | needed = sizeof(uint8_t); |
2525 | 0 | if (len < needed) { |
2526 | 0 | DEBUG(10, ("%s: %d bytes left, expected at least %d\n", |
2527 | 0 | __location__, (int)len, (int)needed)); |
2528 | 0 | goto inval; |
2529 | 0 | } |
2530 | | |
2531 | | /* |
2532 | | * Now we check if the specified words are there |
2533 | | */ |
2534 | 0 | wct = CVAL(hdr, wct_ofs); |
2535 | 0 | needed += wct * sizeof(uint16_t); |
2536 | 0 | if (len < needed) { |
2537 | 0 | DEBUG(10, ("%s: %d bytes left, expected at least %d\n", |
2538 | 0 | __location__, (int)len, (int)needed)); |
2539 | 0 | goto inval; |
2540 | 0 | } |
2541 | | |
2542 | 0 | if ((num_iov == 1) && |
2543 | 0 | (len == needed) && |
2544 | 0 | NT_STATUS_IS_ERR(status)) |
2545 | 0 | { |
2546 | | /* |
2547 | | * This is an ugly hack to support OS/2 |
2548 | | * which skips the byte_count in the DATA block |
2549 | | * on some error responses. |
2550 | | * |
2551 | | * See bug #9096 |
2552 | | */ |
2553 | 0 | iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec, |
2554 | 0 | num_iov + 2); |
2555 | 0 | if (iov_tmp == NULL) { |
2556 | 0 | TALLOC_FREE(iov); |
2557 | 0 | return NT_STATUS_NO_MEMORY; |
2558 | 0 | } |
2559 | 0 | iov = iov_tmp; |
2560 | 0 | cur = &iov[num_iov]; |
2561 | 0 | num_iov += 2; |
2562 | |
|
2563 | 0 | cur[0].iov_len = 0; |
2564 | 0 | cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t)); |
2565 | 0 | cur[1].iov_len = 0; |
2566 | 0 | cur[1].iov_base = cur[0].iov_base; |
2567 | |
|
2568 | 0 | taken += needed; |
2569 | 0 | break; |
2570 | 0 | } |
2571 | | |
2572 | | /* |
2573 | | * we need at least BCC |
2574 | | */ |
2575 | 0 | needed += sizeof(uint16_t); |
2576 | 0 | if (len < needed) { |
2577 | 0 | DEBUG(10, ("%s: %d bytes left, expected at least %d\n", |
2578 | 0 | __location__, (int)len, (int)needed)); |
2579 | 0 | goto inval; |
2580 | 0 | } |
2581 | | |
2582 | | /* |
2583 | | * Now we check if the specified bytes are there |
2584 | | */ |
2585 | 0 | bcc_ofs = wct_ofs + sizeof(uint8_t) + wct * sizeof(uint16_t); |
2586 | 0 | bcc = SVAL(hdr, bcc_ofs); |
2587 | 0 | needed += bcc * sizeof(uint8_t); |
2588 | 0 | if (len < needed) { |
2589 | 0 | DEBUG(10, ("%s: %d bytes left, expected at least %d\n", |
2590 | 0 | __location__, (int)len, (int)needed)); |
2591 | 0 | goto inval; |
2592 | 0 | } |
2593 | | |
2594 | | /* |
2595 | | * we allocate 2 iovec structures for words and bytes |
2596 | | */ |
2597 | 0 | iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec, |
2598 | 0 | num_iov + 2); |
2599 | 0 | if (iov_tmp == NULL) { |
2600 | 0 | TALLOC_FREE(iov); |
2601 | 0 | return NT_STATUS_NO_MEMORY; |
2602 | 0 | } |
2603 | 0 | iov = iov_tmp; |
2604 | 0 | cur = &iov[num_iov]; |
2605 | 0 | num_iov += 2; |
2606 | |
|
2607 | 0 | cur[0].iov_len = wct * sizeof(uint16_t); |
2608 | 0 | cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t)); |
2609 | 0 | cur[1].iov_len = bcc * sizeof(uint8_t); |
2610 | 0 | cur[1].iov_base = hdr + (bcc_ofs + sizeof(uint16_t)); |
2611 | |
|
2612 | 0 | taken += needed; |
2613 | |
|
2614 | 0 | if (!smb1cli_is_andx_req(cmd)) { |
2615 | | /* |
2616 | | * If the current command does not have AndX chanining |
2617 | | * we are done. |
2618 | | */ |
2619 | 0 | break; |
2620 | 0 | } |
2621 | | |
2622 | 0 | if (wct == 0 && bcc == 0) { |
2623 | | /* |
2624 | | * An empty response also ends the chain, |
2625 | | * most likely with an error. |
2626 | | */ |
2627 | 0 | break; |
2628 | 0 | } |
2629 | | |
2630 | 0 | if (wct < 2) { |
2631 | 0 | DEBUG(10, ("%s: wct[%d] < 2 for cmd[0x%02X]\n", |
2632 | 0 | __location__, (int)wct, (int)cmd)); |
2633 | 0 | goto inval; |
2634 | 0 | } |
2635 | 0 | cmd = CVAL(cur[0].iov_base, 0); |
2636 | 0 | if (cmd == 0xFF) { |
2637 | | /* |
2638 | | * If it is the end of the chain we are also done. |
2639 | | */ |
2640 | 0 | break; |
2641 | 0 | } |
2642 | 0 | wct_ofs = SVAL(cur[0].iov_base, 2); |
2643 | |
|
2644 | 0 | if (wct_ofs < taken) { |
2645 | 0 | goto inval; |
2646 | 0 | } |
2647 | 0 | if (wct_ofs > buflen) { |
2648 | 0 | goto inval; |
2649 | 0 | } |
2650 | | |
2651 | | /* |
2652 | | * we consumed everything up to the start of the next |
2653 | | * parameter block. |
2654 | | */ |
2655 | 0 | taken = wct_ofs; |
2656 | 0 | } |
2657 | | |
2658 | 0 | remaining = buflen - taken; |
2659 | |
|
2660 | 0 | if (remaining > 0 && num_iov >= 3) { |
2661 | | /* |
2662 | | * The last DATA block gets the remaining |
2663 | | * bytes, this is needed to support |
2664 | | * CAP_LARGE_WRITEX and CAP_LARGE_READX. |
2665 | | */ |
2666 | 0 | iov[num_iov-1].iov_len += remaining; |
2667 | 0 | } |
2668 | |
|
2669 | 0 | *piov = iov; |
2670 | 0 | *pnum_iov = num_iov; |
2671 | 0 | return NT_STATUS_OK; |
2672 | | |
2673 | 0 | inval: |
2674 | 0 | TALLOC_FREE(iov); |
2675 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
2676 | 0 | } |
2677 | | |
2678 | | static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn, |
2679 | | TALLOC_CTX *tmp_mem, |
2680 | | uint8_t *inbuf) |
2681 | 0 | { |
2682 | 0 | struct tevent_req *req; |
2683 | 0 | struct smbXcli_req_state *state; |
2684 | 0 | NTSTATUS status; |
2685 | 0 | size_t num_pending; |
2686 | 0 | size_t i; |
2687 | 0 | uint8_t cmd; |
2688 | 0 | uint16_t mid; |
2689 | 0 | bool oplock_break; |
2690 | 0 | uint8_t *inhdr = inbuf + NBT_HDR_SIZE; |
2691 | 0 | size_t len = smb_len_tcp(inbuf); |
2692 | 0 | struct iovec *iov = NULL; |
2693 | 0 | int num_iov = 0; |
2694 | 0 | struct tevent_req **chain = NULL; |
2695 | 0 | size_t num_chained = 0; |
2696 | 0 | size_t num_responses = 0; |
2697 | |
|
2698 | 0 | if (conn->smb1.read_braw_req != NULL) { |
2699 | 0 | req = conn->smb1.read_braw_req; |
2700 | 0 | conn->smb1.read_braw_req = NULL; |
2701 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
2702 | |
|
2703 | 0 | smbXcli_req_unset_pending(req); |
2704 | |
|
2705 | 0 | if (state->smb1.recv_iov == NULL) { |
2706 | | /* |
2707 | | * For requests with more than |
2708 | | * one response, we have to readd the |
2709 | | * recv_iov array. |
2710 | | */ |
2711 | 0 | state->smb1.recv_iov = talloc_zero_array(state, |
2712 | 0 | struct iovec, |
2713 | 0 | 3); |
2714 | 0 | if (tevent_req_nomem(state->smb1.recv_iov, req)) { |
2715 | 0 | return NT_STATUS_OK; |
2716 | 0 | } |
2717 | 0 | } |
2718 | | |
2719 | 0 | state->smb1.recv_iov[0].iov_base = (void *)(inhdr); |
2720 | 0 | state->smb1.recv_iov[0].iov_len = len; |
2721 | 0 | ZERO_STRUCT(state->smb1.recv_iov[1]); |
2722 | 0 | ZERO_STRUCT(state->smb1.recv_iov[2]); |
2723 | |
|
2724 | 0 | state->smb1.recv_cmd = SMBreadBraw; |
2725 | 0 | state->smb1.recv_status = NT_STATUS_OK; |
2726 | 0 | state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf); |
2727 | |
|
2728 | 0 | tevent_req_done(req); |
2729 | 0 | return NT_STATUS_OK; |
2730 | 0 | } |
2731 | | |
2732 | 0 | if ((IVAL(inhdr, 0) != SMB_MAGIC) /* 0xFF"SMB" */ |
2733 | 0 | && (SVAL(inhdr, 0) != 0x45ff)) /* 0xFF"E" */ { |
2734 | 0 | DEBUG(10, ("Got non-SMB PDU\n")); |
2735 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
2736 | 0 | } |
2737 | | |
2738 | | /* |
2739 | | * If we supported multiple encryption contexts |
2740 | | * here we'd look up based on tid. |
2741 | | */ |
2742 | 0 | if (common_encryption_on(conn->smb1.trans_enc) |
2743 | 0 | && (CVAL(inbuf, 0) == 0)) { |
2744 | 0 | uint16_t enc_ctx_num; |
2745 | |
|
2746 | 0 | status = get_enc_ctx_num(inbuf, &enc_ctx_num); |
2747 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2748 | 0 | DEBUG(10, ("get_enc_ctx_num returned %s\n", |
2749 | 0 | nt_errstr(status))); |
2750 | 0 | return status; |
2751 | 0 | } |
2752 | | |
2753 | 0 | if (enc_ctx_num != conn->smb1.trans_enc->enc_ctx_num) { |
2754 | 0 | DEBUG(10, ("wrong enc_ctx %d, expected %d\n", |
2755 | 0 | enc_ctx_num, |
2756 | 0 | conn->smb1.trans_enc->enc_ctx_num)); |
2757 | 0 | return NT_STATUS_INVALID_HANDLE; |
2758 | 0 | } |
2759 | | |
2760 | 0 | status = common_decrypt_buffer(conn->smb1.trans_enc, |
2761 | 0 | (char *)inbuf); |
2762 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2763 | 0 | DEBUG(10, ("common_decrypt_buffer returned %s\n", |
2764 | 0 | nt_errstr(status))); |
2765 | 0 | return status; |
2766 | 0 | } |
2767 | 0 | inhdr = inbuf + NBT_HDR_SIZE; |
2768 | 0 | len = smb_len_nbt(inbuf); |
2769 | 0 | } |
2770 | | |
2771 | 0 | mid = SVAL(inhdr, HDR_MID); |
2772 | 0 | num_pending = talloc_array_length(conn->pending); |
2773 | |
|
2774 | 0 | for (i=0; i<num_pending; i++) { |
2775 | 0 | if (mid == smb1cli_req_mid(conn->pending[i])) { |
2776 | 0 | break; |
2777 | 0 | } |
2778 | 0 | } |
2779 | 0 | if (i == num_pending) { |
2780 | | /* Dump unexpected reply */ |
2781 | 0 | return NT_STATUS_RETRY; |
2782 | 0 | } |
2783 | | |
2784 | 0 | oplock_break = false; |
2785 | |
|
2786 | 0 | if (mid == 0xffff) { |
2787 | | /* |
2788 | | * Paranoia checks that this is really an oplock break request. |
2789 | | */ |
2790 | 0 | oplock_break = (len == 51); /* hdr + 8 words */ |
2791 | 0 | oplock_break &= ((CVAL(inhdr, HDR_FLG) & FLAG_REPLY) == 0); |
2792 | 0 | oplock_break &= (CVAL(inhdr, HDR_COM) == SMBlockingX); |
2793 | 0 | oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(6)) == 0); |
2794 | 0 | oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(7)) == 0); |
2795 | |
|
2796 | 0 | if (!oplock_break) { |
2797 | | /* Dump unexpected reply */ |
2798 | 0 | return NT_STATUS_RETRY; |
2799 | 0 | } |
2800 | 0 | } |
2801 | | |
2802 | 0 | req = conn->pending[i]; |
2803 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
2804 | |
|
2805 | 0 | if (!oplock_break /* oplock breaks are not signed */ |
2806 | 0 | && !smb1_signing_check_pdu(conn->smb1.signing, |
2807 | 0 | inhdr, len, state->smb1.seqnum+1)) { |
2808 | 0 | DEBUG(10, ("cli_check_sign_mac failed\n")); |
2809 | 0 | return NT_STATUS_ACCESS_DENIED; |
2810 | 0 | } |
2811 | | |
2812 | 0 | status = smb1cli_inbuf_parse_chain(inbuf, tmp_mem, |
2813 | 0 | &iov, &num_iov); |
2814 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2815 | 0 | DEBUG(10,("smb1cli_inbuf_parse_chain - %s\n", |
2816 | 0 | nt_errstr(status))); |
2817 | 0 | return status; |
2818 | 0 | } |
2819 | | |
2820 | 0 | cmd = CVAL(inhdr, HDR_COM); |
2821 | 0 | status = smb1cli_pull_raw_error(inhdr); |
2822 | |
|
2823 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) && |
2824 | 0 | (state->session != NULL) && state->session->disconnect_expired) |
2825 | 0 | { |
2826 | | /* |
2827 | | * this should be a short term hack |
2828 | | * until the upper layers have implemented |
2829 | | * re-authentication. |
2830 | | */ |
2831 | 0 | return status; |
2832 | 0 | } |
2833 | | |
2834 | 0 | if (state->smb1.chained_requests == NULL) { |
2835 | 0 | if (num_iov != 3) { |
2836 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
2837 | 0 | } |
2838 | | |
2839 | 0 | smbXcli_req_unset_pending(req); |
2840 | |
|
2841 | 0 | if (state->smb1.recv_iov == NULL) { |
2842 | | /* |
2843 | | * For requests with more than |
2844 | | * one response, we have to readd the |
2845 | | * recv_iov array. |
2846 | | */ |
2847 | 0 | state->smb1.recv_iov = talloc_zero_array(state, |
2848 | 0 | struct iovec, |
2849 | 0 | 3); |
2850 | 0 | if (tevent_req_nomem(state->smb1.recv_iov, req)) { |
2851 | 0 | return NT_STATUS_OK; |
2852 | 0 | } |
2853 | 0 | } |
2854 | | |
2855 | 0 | state->smb1.recv_cmd = cmd; |
2856 | 0 | state->smb1.recv_status = status; |
2857 | 0 | state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf); |
2858 | |
|
2859 | 0 | state->smb1.recv_iov[0] = iov[0]; |
2860 | 0 | state->smb1.recv_iov[1] = iov[1]; |
2861 | 0 | state->smb1.recv_iov[2] = iov[2]; |
2862 | |
|
2863 | 0 | if (talloc_array_length(conn->pending) == 0) { |
2864 | 0 | tevent_req_done(req); |
2865 | 0 | return NT_STATUS_OK; |
2866 | 0 | } |
2867 | | |
2868 | 0 | tevent_req_defer_callback(req, state->ev); |
2869 | 0 | tevent_req_done(req); |
2870 | 0 | return NT_STATUS_RETRY; |
2871 | 0 | } |
2872 | | |
2873 | 0 | chain = talloc_move(tmp_mem, &state->smb1.chained_requests); |
2874 | 0 | num_chained = talloc_array_length(chain); |
2875 | 0 | num_responses = (num_iov - 1)/2; |
2876 | |
|
2877 | 0 | if (num_responses > num_chained) { |
2878 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
2879 | 0 | } |
2880 | | |
2881 | 0 | for (i=0; i<num_chained; i++) { |
2882 | 0 | size_t iov_idx = 1 + (i*2); |
2883 | 0 | struct iovec *cur = &iov[iov_idx]; |
2884 | 0 | uint8_t *inbuf_ref; |
2885 | |
|
2886 | 0 | req = chain[i]; |
2887 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
2888 | |
|
2889 | 0 | smbXcli_req_unset_pending(req); |
2890 | | |
2891 | | /* |
2892 | | * as we finish multiple requests here |
2893 | | * we need to defer the callbacks as |
2894 | | * they could destroy our current stack state. |
2895 | | */ |
2896 | 0 | tevent_req_defer_callback(req, state->ev); |
2897 | |
|
2898 | 0 | if (i >= num_responses) { |
2899 | 0 | tevent_req_nterror(req, NT_STATUS_REQUEST_ABORTED); |
2900 | 0 | continue; |
2901 | 0 | } |
2902 | | |
2903 | 0 | if (state->smb1.recv_iov == NULL) { |
2904 | | /* |
2905 | | * For requests with more than |
2906 | | * one response, we have to readd the |
2907 | | * recv_iov array. |
2908 | | */ |
2909 | 0 | state->smb1.recv_iov = talloc_zero_array(state, |
2910 | 0 | struct iovec, |
2911 | 0 | 3); |
2912 | 0 | if (tevent_req_nomem(state->smb1.recv_iov, req)) { |
2913 | 0 | continue; |
2914 | 0 | } |
2915 | 0 | } |
2916 | | |
2917 | 0 | state->smb1.recv_cmd = cmd; |
2918 | |
|
2919 | 0 | if (i == (num_responses - 1)) { |
2920 | | /* |
2921 | | * The last request in the chain gets the status |
2922 | | */ |
2923 | 0 | state->smb1.recv_status = status; |
2924 | 0 | } else { |
2925 | 0 | cmd = CVAL(cur[0].iov_base, 0); |
2926 | 0 | state->smb1.recv_status = NT_STATUS_OK; |
2927 | 0 | } |
2928 | |
|
2929 | 0 | state->inbuf = inbuf; |
2930 | | |
2931 | | /* |
2932 | | * Note: here we use talloc_reference() in a way |
2933 | | * that does not expose it to the caller. |
2934 | | */ |
2935 | 0 | inbuf_ref = talloc_reference(state->smb1.recv_iov, inbuf); |
2936 | 0 | if (tevent_req_nomem(inbuf_ref, req)) { |
2937 | 0 | continue; |
2938 | 0 | } |
2939 | | |
2940 | | /* copy the related buffers */ |
2941 | 0 | state->smb1.recv_iov[0] = iov[0]; |
2942 | 0 | state->smb1.recv_iov[1] = cur[0]; |
2943 | 0 | state->smb1.recv_iov[2] = cur[1]; |
2944 | |
|
2945 | 0 | tevent_req_done(req); |
2946 | 0 | } |
2947 | |
|
2948 | 0 | return NT_STATUS_RETRY; |
2949 | 0 | } |
2950 | | |
2951 | | NTSTATUS smb1cli_req_recv(struct tevent_req *req, |
2952 | | TALLOC_CTX *mem_ctx, |
2953 | | struct iovec **piov, |
2954 | | uint8_t **phdr, |
2955 | | uint8_t *pwct, |
2956 | | uint16_t **pvwv, |
2957 | | uint32_t *pvwv_offset, |
2958 | | uint32_t *pnum_bytes, |
2959 | | uint8_t **pbytes, |
2960 | | uint32_t *pbytes_offset, |
2961 | | uint8_t **pinbuf, |
2962 | | const struct smb1cli_req_expected_response *expected, |
2963 | | size_t num_expected) |
2964 | 0 | { |
2965 | 0 | struct smbXcli_req_state *state = |
2966 | 0 | tevent_req_data(req, |
2967 | 0 | struct smbXcli_req_state); |
2968 | 0 | NTSTATUS status = NT_STATUS_OK; |
2969 | 0 | struct iovec *recv_iov = NULL; |
2970 | 0 | uint8_t *hdr = NULL; |
2971 | 0 | uint8_t wct = 0; |
2972 | 0 | uint32_t vwv_offset = 0; |
2973 | 0 | uint16_t *vwv = NULL; |
2974 | 0 | uint32_t num_bytes = 0; |
2975 | 0 | uint32_t bytes_offset = 0; |
2976 | 0 | uint8_t *bytes = NULL; |
2977 | 0 | size_t i; |
2978 | 0 | bool found_status = false; |
2979 | 0 | bool found_size = false; |
2980 | |
|
2981 | 0 | if (piov != NULL) { |
2982 | 0 | *piov = NULL; |
2983 | 0 | } |
2984 | 0 | if (phdr != NULL) { |
2985 | 0 | *phdr = 0; |
2986 | 0 | } |
2987 | 0 | if (pwct != NULL) { |
2988 | 0 | *pwct = 0; |
2989 | 0 | } |
2990 | 0 | if (pvwv != NULL) { |
2991 | 0 | *pvwv = NULL; |
2992 | 0 | } |
2993 | 0 | if (pvwv_offset != NULL) { |
2994 | 0 | *pvwv_offset = 0; |
2995 | 0 | } |
2996 | 0 | if (pnum_bytes != NULL) { |
2997 | 0 | *pnum_bytes = 0; |
2998 | 0 | } |
2999 | 0 | if (pbytes != NULL) { |
3000 | 0 | *pbytes = NULL; |
3001 | 0 | } |
3002 | 0 | if (pbytes_offset != NULL) { |
3003 | 0 | *pbytes_offset = 0; |
3004 | 0 | } |
3005 | 0 | if (pinbuf != NULL) { |
3006 | 0 | *pinbuf = NULL; |
3007 | 0 | } |
3008 | |
|
3009 | 0 | if (state->inbuf != NULL) { |
3010 | 0 | recv_iov = state->smb1.recv_iov; |
3011 | 0 | state->smb1.recv_iov = NULL; |
3012 | 0 | if (state->smb1.recv_cmd != SMBreadBraw) { |
3013 | 0 | hdr = (uint8_t *)recv_iov[0].iov_base; |
3014 | 0 | wct = recv_iov[1].iov_len/2; |
3015 | 0 | vwv = (uint16_t *)recv_iov[1].iov_base; |
3016 | 0 | vwv_offset = PTR_DIFF(vwv, hdr); |
3017 | 0 | num_bytes = recv_iov[2].iov_len; |
3018 | 0 | bytes = (uint8_t *)recv_iov[2].iov_base; |
3019 | 0 | bytes_offset = PTR_DIFF(bytes, hdr); |
3020 | 0 | } |
3021 | 0 | } |
3022 | |
|
3023 | 0 | if (tevent_req_is_nterror(req, &status)) { |
3024 | 0 | for (i=0; i < num_expected; i++) { |
3025 | 0 | if (NT_STATUS_EQUAL(status, expected[i].status)) { |
3026 | 0 | found_status = true; |
3027 | 0 | break; |
3028 | 0 | } |
3029 | 0 | } |
3030 | |
|
3031 | 0 | if (found_status) { |
3032 | 0 | return NT_STATUS_UNEXPECTED_NETWORK_ERROR; |
3033 | 0 | } |
3034 | | |
3035 | 0 | return status; |
3036 | 0 | } |
3037 | | |
3038 | 0 | if (num_expected == 0) { |
3039 | 0 | found_status = true; |
3040 | 0 | found_size = true; |
3041 | 0 | } |
3042 | |
|
3043 | 0 | status = state->smb1.recv_status; |
3044 | |
|
3045 | 0 | for (i=0; i < num_expected; i++) { |
3046 | 0 | if (!NT_STATUS_EQUAL(status, expected[i].status)) { |
3047 | 0 | continue; |
3048 | 0 | } |
3049 | | |
3050 | 0 | found_status = true; |
3051 | 0 | if (expected[i].wct == 0) { |
3052 | 0 | found_size = true; |
3053 | 0 | break; |
3054 | 0 | } |
3055 | | |
3056 | 0 | if (expected[i].wct == wct) { |
3057 | 0 | found_size = true; |
3058 | 0 | break; |
3059 | 0 | } |
3060 | 0 | } |
3061 | |
|
3062 | 0 | if (!found_status) { |
3063 | 0 | return status; |
3064 | 0 | } |
3065 | | |
3066 | 0 | if (!found_size) { |
3067 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
3068 | 0 | } |
3069 | | |
3070 | 0 | if (piov != NULL) { |
3071 | 0 | *piov = talloc_move(mem_ctx, &recv_iov); |
3072 | 0 | } |
3073 | |
|
3074 | 0 | if (phdr != NULL) { |
3075 | 0 | *phdr = hdr; |
3076 | 0 | } |
3077 | 0 | if (pwct != NULL) { |
3078 | 0 | *pwct = wct; |
3079 | 0 | } |
3080 | 0 | if (pvwv != NULL) { |
3081 | 0 | *pvwv = vwv; |
3082 | 0 | } |
3083 | 0 | if (pvwv_offset != NULL) { |
3084 | 0 | *pvwv_offset = vwv_offset; |
3085 | 0 | } |
3086 | 0 | if (pnum_bytes != NULL) { |
3087 | 0 | *pnum_bytes = num_bytes; |
3088 | 0 | } |
3089 | 0 | if (pbytes != NULL) { |
3090 | 0 | *pbytes = bytes; |
3091 | 0 | } |
3092 | 0 | if (pbytes_offset != NULL) { |
3093 | 0 | *pbytes_offset = bytes_offset; |
3094 | 0 | } |
3095 | 0 | if (pinbuf != NULL) { |
3096 | 0 | *pinbuf = state->inbuf; |
3097 | 0 | } |
3098 | |
|
3099 | 0 | return status; |
3100 | 0 | } |
3101 | | |
3102 | | size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs) |
3103 | 0 | { |
3104 | 0 | size_t wct_ofs; |
3105 | 0 | int i; |
3106 | |
|
3107 | 0 | wct_ofs = HDR_WCT; |
3108 | |
|
3109 | 0 | for (i=0; i<num_reqs; i++) { |
3110 | 0 | struct smbXcli_req_state *state; |
3111 | 0 | state = tevent_req_data(reqs[i], struct smbXcli_req_state); |
3112 | 0 | wct_ofs += smbXcli_iov_len(state->smb1.iov+2, |
3113 | 0 | state->smb1.iov_count-2); |
3114 | 0 | wct_ofs = (wct_ofs + 3) & ~3; |
3115 | 0 | } |
3116 | 0 | return wct_ofs; |
3117 | 0 | } |
3118 | | |
3119 | | NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs) |
3120 | 0 | { |
3121 | 0 | struct smbXcli_req_state *first_state = |
3122 | 0 | tevent_req_data(reqs[0], |
3123 | 0 | struct smbXcli_req_state); |
3124 | 0 | struct smbXcli_req_state *state; |
3125 | 0 | size_t wct_offset; |
3126 | 0 | size_t chain_padding = 0; |
3127 | 0 | int i, iovlen; |
3128 | 0 | struct iovec *iov = NULL; |
3129 | 0 | struct iovec *this_iov; |
3130 | 0 | NTSTATUS status; |
3131 | 0 | ssize_t nbt_len; |
3132 | |
|
3133 | 0 | if (num_reqs == 1) { |
3134 | 0 | return smb1cli_req_writev_submit(reqs[0], first_state, |
3135 | 0 | first_state->smb1.iov, |
3136 | 0 | first_state->smb1.iov_count); |
3137 | 0 | } |
3138 | | |
3139 | 0 | iovlen = 0; |
3140 | 0 | for (i=0; i<num_reqs; i++) { |
3141 | 0 | if (!tevent_req_is_in_progress(reqs[i])) { |
3142 | 0 | return NT_STATUS_INTERNAL_ERROR; |
3143 | 0 | } |
3144 | | |
3145 | 0 | state = tevent_req_data(reqs[i], struct smbXcli_req_state); |
3146 | |
|
3147 | 0 | if (state->smb1.iov_count < 4) { |
3148 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
3149 | 0 | } |
3150 | | |
3151 | 0 | if (i == 0) { |
3152 | | /* |
3153 | | * The NBT and SMB header |
3154 | | */ |
3155 | 0 | iovlen += 2; |
3156 | 0 | } else { |
3157 | | /* |
3158 | | * Chain padding |
3159 | | */ |
3160 | 0 | iovlen += 1; |
3161 | 0 | } |
3162 | | |
3163 | | /* |
3164 | | * words and bytes |
3165 | | */ |
3166 | 0 | iovlen += state->smb1.iov_count - 2; |
3167 | 0 | } |
3168 | | |
3169 | 0 | iov = talloc_zero_array(first_state, struct iovec, iovlen); |
3170 | 0 | if (iov == NULL) { |
3171 | 0 | return NT_STATUS_NO_MEMORY; |
3172 | 0 | } |
3173 | | |
3174 | 0 | first_state->smb1.chained_requests = (struct tevent_req **)talloc_memdup( |
3175 | 0 | first_state, reqs, sizeof(*reqs) * num_reqs); |
3176 | 0 | if (first_state->smb1.chained_requests == NULL) { |
3177 | 0 | TALLOC_FREE(iov); |
3178 | 0 | return NT_STATUS_NO_MEMORY; |
3179 | 0 | } |
3180 | | |
3181 | 0 | wct_offset = HDR_WCT; |
3182 | 0 | this_iov = iov; |
3183 | |
|
3184 | 0 | for (i=0; i<num_reqs; i++) { |
3185 | 0 | size_t next_padding = 0; |
3186 | 0 | uint16_t *vwv; |
3187 | |
|
3188 | 0 | state = tevent_req_data(reqs[i], struct smbXcli_req_state); |
3189 | |
|
3190 | 0 | if (i < num_reqs-1) { |
3191 | 0 | if (!smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM)) |
3192 | 0 | || CVAL(state->smb1.hdr, HDR_WCT) < 2) { |
3193 | 0 | TALLOC_FREE(iov); |
3194 | 0 | TALLOC_FREE(first_state->smb1.chained_requests); |
3195 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
3196 | 0 | } |
3197 | 0 | } |
3198 | | |
3199 | 0 | wct_offset += smbXcli_iov_len(state->smb1.iov+2, |
3200 | 0 | state->smb1.iov_count-2) + 1; |
3201 | 0 | if ((wct_offset % 4) != 0) { |
3202 | 0 | next_padding = 4 - (wct_offset % 4); |
3203 | 0 | } |
3204 | 0 | wct_offset += next_padding; |
3205 | 0 | vwv = state->smb1.vwv; |
3206 | |
|
3207 | 0 | if (i < num_reqs-1) { |
3208 | 0 | struct smbXcli_req_state *next_state = |
3209 | 0 | tevent_req_data(reqs[i+1], |
3210 | 0 | struct smbXcli_req_state); |
3211 | 0 | SCVAL(vwv+0, 0, CVAL(next_state->smb1.hdr, HDR_COM)); |
3212 | 0 | SCVAL(vwv+0, 1, 0); |
3213 | 0 | SSVAL(vwv+1, 0, wct_offset); |
3214 | 0 | } else if (smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))) { |
3215 | | /* properly end the chain */ |
3216 | 0 | SCVAL(vwv+0, 0, 0xff); |
3217 | 0 | SCVAL(vwv+0, 1, 0xff); |
3218 | 0 | SSVAL(vwv+1, 0, 0); |
3219 | 0 | } |
3220 | |
|
3221 | 0 | if (i == 0) { |
3222 | | /* |
3223 | | * The NBT and SMB header |
3224 | | */ |
3225 | 0 | this_iov[0] = state->smb1.iov[0]; |
3226 | 0 | this_iov[1] = state->smb1.iov[1]; |
3227 | 0 | this_iov += 2; |
3228 | 0 | } else { |
3229 | | /* |
3230 | | * This one is a bit subtle. We have to add |
3231 | | * chain_padding bytes between the requests, and we |
3232 | | * have to also include the wct field of the |
3233 | | * subsequent requests. We use the subsequent header |
3234 | | * for the padding, it contains the wct field in its |
3235 | | * last byte. |
3236 | | */ |
3237 | 0 | this_iov[0].iov_len = chain_padding+1; |
3238 | 0 | this_iov[0].iov_base = (void *)&state->smb1.hdr[ |
3239 | 0 | sizeof(state->smb1.hdr) - this_iov[0].iov_len]; |
3240 | 0 | memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1); |
3241 | 0 | this_iov += 1; |
3242 | 0 | } |
3243 | | |
3244 | | /* |
3245 | | * copy the words and bytes |
3246 | | */ |
3247 | 0 | memcpy(this_iov, state->smb1.iov+2, |
3248 | 0 | sizeof(struct iovec) * (state->smb1.iov_count-2)); |
3249 | 0 | this_iov += state->smb1.iov_count - 2; |
3250 | 0 | chain_padding = next_padding; |
3251 | 0 | } |
3252 | | |
3253 | 0 | nbt_len = iov_buflen(&iov[1], iovlen-1); |
3254 | 0 | if ((nbt_len == -1) || (nbt_len > first_state->conn->smb1.max_xmit)) { |
3255 | 0 | TALLOC_FREE(iov); |
3256 | 0 | TALLOC_FREE(first_state->smb1.chained_requests); |
3257 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
3258 | 0 | } |
3259 | | |
3260 | 0 | status = smb1cli_req_writev_submit(reqs[0], first_state, iov, iovlen); |
3261 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3262 | 0 | TALLOC_FREE(iov); |
3263 | 0 | TALLOC_FREE(first_state->smb1.chained_requests); |
3264 | 0 | return status; |
3265 | 0 | } |
3266 | | |
3267 | 0 | return NT_STATUS_OK; |
3268 | 0 | } |
3269 | | |
3270 | | struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn) |
3271 | 0 | { |
3272 | 0 | return conn->outgoing; |
3273 | 0 | } |
3274 | | |
3275 | | bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn) |
3276 | 0 | { |
3277 | 0 | return ((tevent_queue_length(conn->outgoing) != 0) |
3278 | 0 | || (talloc_array_length(conn->pending) != 0)); |
3279 | 0 | } |
3280 | | |
3281 | | bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn) |
3282 | 0 | { |
3283 | 0 | if (conn->protocol >= PROTOCOL_SMB2_02) { |
3284 | 0 | return (smb2cli_conn_server_capabilities(conn) & SMB2_CAP_DFS); |
3285 | 0 | } |
3286 | | |
3287 | 0 | return (smb1cli_conn_capabilities(conn) & CAP_DFS); |
3288 | 0 | } |
3289 | | |
3290 | | bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len) |
3291 | 0 | { |
3292 | 0 | uint16_t credits = 1; |
3293 | |
|
3294 | 0 | if (conn->smb2.cur_credits == 0) { |
3295 | 0 | if (max_dyn_len != NULL) { |
3296 | 0 | *max_dyn_len = 0; |
3297 | 0 | } |
3298 | 0 | return false; |
3299 | 0 | } |
3300 | | |
3301 | 0 | if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { |
3302 | 0 | credits = conn->smb2.cur_credits; |
3303 | 0 | } |
3304 | |
|
3305 | 0 | if (max_dyn_len != NULL) { |
3306 | 0 | *max_dyn_len = credits * 65536; |
3307 | 0 | } |
3308 | |
|
3309 | 0 | return true; |
3310 | 0 | } |
3311 | | |
3312 | | uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn) |
3313 | 0 | { |
3314 | 0 | return conn->smb2.server.capabilities; |
3315 | 0 | } |
3316 | | |
3317 | | uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn) |
3318 | 0 | { |
3319 | 0 | return conn->smb2.server.security_mode; |
3320 | 0 | } |
3321 | | |
3322 | | uint16_t smb2cli_conn_server_signing_algo(struct smbXcli_conn *conn) |
3323 | 0 | { |
3324 | 0 | return conn->smb2.server.sign_algo; |
3325 | 0 | } |
3326 | | |
3327 | | uint16_t smb2cli_conn_server_encryption_algo(struct smbXcli_conn *conn) |
3328 | 0 | { |
3329 | 0 | return conn->smb2.server.cipher; |
3330 | 0 | } |
3331 | | |
3332 | | uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn) |
3333 | 0 | { |
3334 | 0 | return conn->smb2.server.max_trans_size; |
3335 | 0 | } |
3336 | | |
3337 | | uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn) |
3338 | 0 | { |
3339 | 0 | return conn->smb2.server.max_read_size; |
3340 | 0 | } |
3341 | | |
3342 | | uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn) |
3343 | 0 | { |
3344 | 0 | return conn->smb2.server.max_write_size; |
3345 | 0 | } |
3346 | | |
3347 | | void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn, |
3348 | | uint16_t max_credits) |
3349 | 0 | { |
3350 | 0 | conn->smb2.max_credits = max_credits; |
3351 | 0 | } |
3352 | | |
3353 | | uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn) |
3354 | 0 | { |
3355 | 0 | return conn->smb2.cur_credits; |
3356 | 0 | } |
3357 | | |
3358 | | uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn) |
3359 | 0 | { |
3360 | 0 | if (conn->protocol < PROTOCOL_SMB3_11) { |
3361 | 0 | return 0; |
3362 | 0 | } |
3363 | | |
3364 | 0 | return conn->smb2.io_priority; |
3365 | 0 | } |
3366 | | |
3367 | | void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn, |
3368 | | uint8_t io_priority) |
3369 | 0 | { |
3370 | 0 | conn->smb2.io_priority = io_priority; |
3371 | 0 | } |
3372 | | |
3373 | | uint32_t smb2cli_conn_cc_chunk_len(struct smbXcli_conn *conn) |
3374 | 0 | { |
3375 | 0 | return conn->smb2.cc_chunk_len; |
3376 | 0 | } |
3377 | | |
3378 | | void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn, |
3379 | | uint32_t chunk_len) |
3380 | 0 | { |
3381 | 0 | conn->smb2.cc_chunk_len = chunk_len; |
3382 | 0 | } |
3383 | | |
3384 | | uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn) |
3385 | 0 | { |
3386 | 0 | return conn->smb2.cc_max_chunks; |
3387 | 0 | } |
3388 | | |
3389 | | void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn, |
3390 | | uint32_t max_chunks) |
3391 | 0 | { |
3392 | 0 | conn->smb2.cc_max_chunks = max_chunks; |
3393 | 0 | } |
3394 | | |
3395 | | static void smb2cli_req_cancel_done(struct tevent_req *subreq); |
3396 | | |
3397 | | static bool smb2cli_req_cancel(struct tevent_req *req) |
3398 | 0 | { |
3399 | 0 | struct smbXcli_req_state *state = |
3400 | 0 | tevent_req_data(req, |
3401 | 0 | struct smbXcli_req_state); |
3402 | 0 | struct smbXcli_tcon *tcon = state->tcon; |
3403 | 0 | struct smbXcli_session *session = state->session; |
3404 | 0 | uint8_t *fixed = state->smb2.pad; |
3405 | 0 | uint16_t fixed_len = 4; |
3406 | 0 | struct tevent_req *subreq; |
3407 | 0 | struct smbXcli_req_state *substate; |
3408 | 0 | NTSTATUS status; |
3409 | |
|
3410 | 0 | if (state->smb2.cancel_mid == UINT64_MAX) { |
3411 | | /* |
3412 | | * We already send a cancel, |
3413 | | * make sure we don't do it |
3414 | | * twice, otherwise we may |
3415 | | * expose the same NONCE for |
3416 | | * AES-128-GMAC signing |
3417 | | */ |
3418 | 0 | return true; |
3419 | 0 | } |
3420 | | |
3421 | 0 | SSVAL(fixed, 0, 0x04); |
3422 | 0 | SSVAL(fixed, 2, 0); |
3423 | |
|
3424 | 0 | subreq = smb2cli_req_create(state, state->ev, |
3425 | 0 | state->conn, |
3426 | 0 | SMB2_OP_CANCEL, |
3427 | 0 | 0, 0, /* flags */ |
3428 | 0 | 0, /* timeout */ |
3429 | 0 | tcon, session, |
3430 | 0 | fixed, fixed_len, |
3431 | 0 | NULL, 0, 0); |
3432 | 0 | if (subreq == NULL) { |
3433 | 0 | return false; |
3434 | 0 | } |
3435 | 0 | substate = tevent_req_data(subreq, struct smbXcli_req_state); |
3436 | |
|
3437 | 0 | substate->smb2.cancel_mid = BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID); |
3438 | |
|
3439 | 0 | SIVAL(substate->smb2.hdr, SMB2_HDR_FLAGS, state->smb2.cancel_flags); |
3440 | 0 | SBVAL(substate->smb2.hdr, SMB2_HDR_MESSAGE_ID, state->smb2.cancel_mid); |
3441 | 0 | SBVAL(substate->smb2.hdr, SMB2_HDR_ASYNC_ID, state->smb2.cancel_aid); |
3442 | | |
3443 | | /* |
3444 | | * remember that we don't send a cancel again |
3445 | | */ |
3446 | 0 | state->smb2.cancel_mid = UINT64_MAX; |
3447 | |
|
3448 | 0 | status = smb2cli_req_compound_submit(&subreq, 1); |
3449 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3450 | 0 | TALLOC_FREE(subreq); |
3451 | 0 | return false; |
3452 | 0 | } |
3453 | | |
3454 | 0 | tevent_req_set_callback(subreq, smb2cli_req_cancel_done, NULL); |
3455 | |
|
3456 | 0 | return true; |
3457 | 0 | } |
3458 | | |
3459 | | static void smb2cli_req_cancel_done(struct tevent_req *subreq) |
3460 | 0 | { |
3461 | | /* we do not care about the result */ |
3462 | 0 | TALLOC_FREE(subreq); |
3463 | 0 | } |
3464 | | |
3465 | | struct timeval smbXcli_req_endtime(struct tevent_req *req) |
3466 | 0 | { |
3467 | 0 | struct smbXcli_req_state *state = tevent_req_data( |
3468 | 0 | req, struct smbXcli_req_state); |
3469 | |
|
3470 | 0 | return state->endtime; |
3471 | 0 | } |
3472 | | |
3473 | | struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, |
3474 | | struct tevent_context *ev, |
3475 | | struct smbXcli_conn *conn, |
3476 | | uint16_t cmd, |
3477 | | uint32_t additional_flags, |
3478 | | uint32_t clear_flags, |
3479 | | uint32_t timeout_msec, |
3480 | | struct smbXcli_tcon *tcon, |
3481 | | struct smbXcli_session *session, |
3482 | | const uint8_t *fixed, |
3483 | | uint16_t fixed_len, |
3484 | | const uint8_t *dyn, |
3485 | | uint32_t dyn_len, |
3486 | | uint32_t max_dyn_len) |
3487 | 0 | { |
3488 | 0 | struct tevent_req *req; |
3489 | 0 | struct smbXcli_req_state *state; |
3490 | 0 | uint32_t flags = 0; |
3491 | 0 | uint32_t tid = 0; |
3492 | 0 | uint64_t uid = 0; |
3493 | 0 | bool use_channel_sequence = conn->smb2.force_channel_sequence; |
3494 | 0 | uint16_t channel_sequence = 0; |
3495 | 0 | bool use_replay_flag = false; |
3496 | 0 | enum protocol_types proto = smbXcli_conn_protocol(conn); |
3497 | |
|
3498 | 0 | req = tevent_req_create(mem_ctx, &state, |
3499 | 0 | struct smbXcli_req_state); |
3500 | 0 | if (req == NULL) { |
3501 | 0 | return NULL; |
3502 | 0 | } |
3503 | | |
3504 | 0 | if ((proto > PROTOCOL_NONE) && (proto < PROTOCOL_SMB2_02)) { |
3505 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); |
3506 | 0 | return req; |
3507 | 0 | } |
3508 | | |
3509 | 0 | state->ev = ev; |
3510 | 0 | state->conn = conn; |
3511 | 0 | state->session = session; |
3512 | 0 | state->tcon = tcon; |
3513 | |
|
3514 | 0 | if (conn->smb2.server.capabilities & SMB2_CAP_PERSISTENT_HANDLES) { |
3515 | 0 | use_channel_sequence = true; |
3516 | 0 | } else if (conn->smb2.server.capabilities & SMB2_CAP_MULTI_CHANNEL) { |
3517 | 0 | use_channel_sequence = true; |
3518 | 0 | } |
3519 | |
|
3520 | 0 | if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_00) { |
3521 | 0 | use_replay_flag = true; |
3522 | 0 | } |
3523 | |
|
3524 | 0 | if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) { |
3525 | 0 | flags |= SMB2_PRIORITY_VALUE_TO_MASK(conn->smb2.io_priority); |
3526 | 0 | } |
3527 | |
|
3528 | 0 | if (session) { |
3529 | 0 | uid = session->smb2->session_id; |
3530 | |
|
3531 | 0 | if (use_channel_sequence) { |
3532 | 0 | channel_sequence = session->smb2->channel_sequence; |
3533 | 0 | } |
3534 | |
|
3535 | 0 | if (use_replay_flag && session->smb2->replay_active) { |
3536 | 0 | additional_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION; |
3537 | 0 | } |
3538 | |
|
3539 | 0 | state->smb2.should_sign = session->smb2->should_sign; |
3540 | 0 | state->smb2.should_encrypt = session->smb2->should_encrypt; |
3541 | 0 | state->smb2.require_signed_response = |
3542 | 0 | session->smb2->require_signed_response; |
3543 | |
|
3544 | 0 | if (cmd == SMB2_OP_SESSSETUP && |
3545 | 0 | !smb2_signing_key_valid(session->smb2_channel.signing_key) && |
3546 | 0 | smb2_signing_key_valid(session->smb2->signing_key)) |
3547 | 0 | { |
3548 | | /* |
3549 | | * a session bind needs to be signed |
3550 | | */ |
3551 | 0 | state->smb2.should_sign = true; |
3552 | 0 | } |
3553 | |
|
3554 | 0 | if (cmd == SMB2_OP_SESSSETUP && |
3555 | 0 | !smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
3556 | 0 | state->smb2.should_encrypt = false; |
3557 | 0 | } |
3558 | |
|
3559 | 0 | if (additional_flags & SMB2_HDR_FLAG_SIGNED) { |
3560 | 0 | if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
3561 | 0 | tevent_req_nterror(req, NT_STATUS_NO_USER_SESSION_KEY); |
3562 | 0 | return req; |
3563 | 0 | } |
3564 | | |
3565 | 0 | additional_flags &= ~SMB2_HDR_FLAG_SIGNED; |
3566 | 0 | state->smb2.should_sign = true; |
3567 | 0 | } |
3568 | 0 | } |
3569 | | |
3570 | 0 | if (tcon) { |
3571 | 0 | tid = tcon->smb2.tcon_id; |
3572 | |
|
3573 | 0 | if (tcon->smb2.should_sign) { |
3574 | 0 | state->smb2.should_sign = true; |
3575 | 0 | } |
3576 | 0 | if (tcon->smb2.should_encrypt) { |
3577 | 0 | state->smb2.should_encrypt = true; |
3578 | 0 | } |
3579 | 0 | } |
3580 | |
|
3581 | 0 | if (conn->smb2.server.transport_trusted) { |
3582 | | /* |
3583 | | * We as a client agreed with the server that quic |
3584 | | * encryption is enough |
3585 | | */ |
3586 | 0 | state->smb2.should_encrypt = false; |
3587 | 0 | } |
3588 | |
|
3589 | 0 | if (state->smb2.should_encrypt) { |
3590 | 0 | state->smb2.should_sign = false; |
3591 | 0 | } |
3592 | |
|
3593 | 0 | state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3); |
3594 | 0 | if (tevent_req_nomem(state->smb2.recv_iov, req)) { |
3595 | 0 | return req; |
3596 | 0 | } |
3597 | | |
3598 | 0 | flags |= additional_flags; |
3599 | 0 | flags &= ~clear_flags; |
3600 | |
|
3601 | 0 | state->smb2.fixed = fixed; |
3602 | 0 | state->smb2.fixed_len = fixed_len; |
3603 | 0 | state->smb2.dyn = dyn; |
3604 | 0 | state->smb2.dyn_len = dyn_len; |
3605 | 0 | state->smb2.max_dyn_len = max_dyn_len; |
3606 | |
|
3607 | 0 | if (state->smb2.should_encrypt) { |
3608 | 0 | SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC); |
3609 | 0 | SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID, uid); |
3610 | 0 | } |
3611 | |
|
3612 | 0 | SIVAL(state->smb2.hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); |
3613 | 0 | SSVAL(state->smb2.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); |
3614 | 0 | SSVAL(state->smb2.hdr, SMB2_HDR_OPCODE, cmd); |
3615 | 0 | SSVAL(state->smb2.hdr, SMB2_HDR_CHANNEL_SEQUENCE, channel_sequence); |
3616 | 0 | SIVAL(state->smb2.hdr, SMB2_HDR_FLAGS, flags); |
3617 | 0 | SIVAL(state->smb2.hdr, SMB2_HDR_PID, 0); /* reserved */ |
3618 | 0 | SIVAL(state->smb2.hdr, SMB2_HDR_TID, tid); |
3619 | 0 | SBVAL(state->smb2.hdr, SMB2_HDR_SESSION_ID, uid); |
3620 | |
|
3621 | 0 | switch (cmd) { |
3622 | 0 | case SMB2_OP_CANCEL: |
3623 | 0 | state->one_way = true; |
3624 | 0 | break; |
3625 | 0 | case SMB2_OP_BREAK: |
3626 | | /* |
3627 | | * If this is a dummy request, it will have |
3628 | | * UINT64_MAX as message id. |
3629 | | * If we send on break acknowledgement, |
3630 | | * this gets overwritten later. |
3631 | | */ |
3632 | 0 | SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX); |
3633 | 0 | break; |
3634 | 0 | } |
3635 | | |
3636 | 0 | if (timeout_msec > 0) { |
3637 | 0 | state->endtime = timeval_current_ofs_msec(timeout_msec); |
3638 | 0 | if (!tevent_req_set_endtime(req, ev, state->endtime)) { |
3639 | 0 | return req; |
3640 | 0 | } |
3641 | 0 | } |
3642 | | |
3643 | 0 | return req; |
3644 | 0 | } |
3645 | | |
3646 | | void smb2cli_req_set_notify_async(struct tevent_req *req) |
3647 | 0 | { |
3648 | 0 | struct smbXcli_req_state *state = |
3649 | 0 | tevent_req_data(req, |
3650 | 0 | struct smbXcli_req_state); |
3651 | |
|
3652 | 0 | state->smb2.notify_async = true; |
3653 | 0 | } |
3654 | | |
3655 | | static void smb2cli_req_writev_done(struct tevent_req *subreq); |
3656 | | static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, |
3657 | | TALLOC_CTX *tmp_mem, |
3658 | | uint8_t *inbuf); |
3659 | | |
3660 | | NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs, |
3661 | | int num_reqs) |
3662 | 0 | { |
3663 | 0 | struct smbXcli_transport *xtp = NULL; |
3664 | 0 | struct smbXcli_req_state *state; |
3665 | 0 | struct tevent_req *subreq; |
3666 | 0 | struct iovec *iov; |
3667 | 0 | int i, num_iov, nbt_len; |
3668 | 0 | int tf_iov = -1; |
3669 | 0 | struct smb2_signing_key *encryption_key = NULL; |
3670 | 0 | uint64_t encryption_session_id = 0; |
3671 | 0 | uint64_t nonce_high = UINT64_MAX; |
3672 | 0 | uint64_t nonce_low = UINT64_MAX; |
3673 | | |
3674 | | /* |
3675 | | * 1 for the nbt length, optional TRANSFORM |
3676 | | * per request: HDR, fixed, dyn, padding |
3677 | | * -1 because the last one does not need padding |
3678 | | */ |
3679 | |
|
3680 | 0 | iov = talloc_array(reqs[0], struct iovec, 1 + 1 + 4*num_reqs - 1); |
3681 | 0 | if (iov == NULL) { |
3682 | 0 | return NT_STATUS_NO_MEMORY; |
3683 | 0 | } |
3684 | | |
3685 | 0 | num_iov = 1; |
3686 | 0 | nbt_len = 0; |
3687 | | |
3688 | | /* |
3689 | | * the session of the first request that requires encryption |
3690 | | * specifies the encryption key. |
3691 | | */ |
3692 | 0 | for (i=0; i<num_reqs; i++) { |
3693 | 0 | if (!tevent_req_is_in_progress(reqs[i])) { |
3694 | 0 | return NT_STATUS_INTERNAL_ERROR; |
3695 | 0 | } |
3696 | | |
3697 | 0 | state = tevent_req_data(reqs[i], struct smbXcli_req_state); |
3698 | |
|
3699 | 0 | if (!smbXcli_conn_is_connected(state->conn)) { |
3700 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
3701 | 0 | } |
3702 | | |
3703 | 0 | if ((state->conn->protocol != PROTOCOL_NONE) && |
3704 | 0 | (state->conn->protocol < PROTOCOL_SMB2_02)) { |
3705 | 0 | return NT_STATUS_REVISION_MISMATCH; |
3706 | 0 | } |
3707 | | |
3708 | 0 | if (state->session == NULL) { |
3709 | 0 | continue; |
3710 | 0 | } |
3711 | | |
3712 | 0 | if (!state->smb2.should_encrypt) { |
3713 | 0 | continue; |
3714 | 0 | } |
3715 | | |
3716 | 0 | encryption_key = state->session->smb2->encryption_key; |
3717 | 0 | if (!smb2_signing_key_valid(encryption_key)) { |
3718 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
3719 | 0 | } |
3720 | | |
3721 | 0 | encryption_session_id = state->session->smb2->session_id; |
3722 | |
|
3723 | 0 | state->session->smb2->nonce_low += 1; |
3724 | 0 | if (state->session->smb2->nonce_low == 0) { |
3725 | 0 | state->session->smb2->nonce_high += 1; |
3726 | 0 | state->session->smb2->nonce_low += 1; |
3727 | 0 | } |
3728 | | |
3729 | | /* |
3730 | | * CCM and GCM algorithms must never have their |
3731 | | * nonce wrap, or the security of the whole |
3732 | | * communication and the keys is destroyed. |
3733 | | * We must drop the connection once we have |
3734 | | * transferred too much data. |
3735 | | * |
3736 | | * NOTE: We assume nonces greater than 8 bytes. |
3737 | | */ |
3738 | 0 | if (state->session->smb2->nonce_high >= |
3739 | 0 | state->session->smb2->nonce_high_max) |
3740 | 0 | { |
3741 | 0 | return NT_STATUS_ENCRYPTION_FAILED; |
3742 | 0 | } |
3743 | | |
3744 | 0 | nonce_high = state->session->smb2->nonce_high_random; |
3745 | 0 | nonce_high += state->session->smb2->nonce_high; |
3746 | 0 | nonce_low = state->session->smb2->nonce_low; |
3747 | |
|
3748 | 0 | tf_iov = num_iov; |
3749 | 0 | iov[num_iov].iov_base = state->smb2.transform; |
3750 | 0 | iov[num_iov].iov_len = sizeof(state->smb2.transform); |
3751 | 0 | num_iov += 1; |
3752 | |
|
3753 | 0 | SBVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC); |
3754 | 0 | SBVAL(state->smb2.transform, SMB2_TF_NONCE, |
3755 | 0 | nonce_low); |
3756 | 0 | SBVAL(state->smb2.transform, SMB2_TF_NONCE+8, |
3757 | 0 | nonce_high); |
3758 | 0 | SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID, |
3759 | 0 | encryption_session_id); |
3760 | |
|
3761 | 0 | nbt_len += SMB2_TF_HDR_SIZE; |
3762 | 0 | break; |
3763 | 0 | } |
3764 | | |
3765 | 0 | for (i=0; i<num_reqs; i++) { |
3766 | 0 | int hdr_iov; |
3767 | 0 | size_t reqlen; |
3768 | 0 | bool ret; |
3769 | 0 | uint16_t opcode; |
3770 | 0 | uint64_t avail; |
3771 | 0 | uint16_t charge; |
3772 | 0 | uint16_t credits; |
3773 | 0 | uint64_t mid; |
3774 | 0 | struct smb2_signing_key *signing_key = NULL; |
3775 | |
|
3776 | 0 | if (!tevent_req_is_in_progress(reqs[i])) { |
3777 | 0 | return NT_STATUS_INTERNAL_ERROR; |
3778 | 0 | } |
3779 | | |
3780 | 0 | state = tevent_req_data(reqs[i], struct smbXcli_req_state); |
3781 | |
|
3782 | 0 | if (!smbXcli_conn_is_connected(state->conn)) { |
3783 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
3784 | 0 | } |
3785 | | |
3786 | 0 | if ((state->conn->protocol != PROTOCOL_NONE) && |
3787 | 0 | (state->conn->protocol < PROTOCOL_SMB2_02)) { |
3788 | 0 | return NT_STATUS_REVISION_MISMATCH; |
3789 | 0 | } |
3790 | | |
3791 | 0 | opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE); |
3792 | 0 | if (opcode == SMB2_OP_CANCEL) { |
3793 | 0 | goto skip_credits; |
3794 | 0 | } |
3795 | | |
3796 | 0 | avail = UINT64_MAX - state->conn->smb2.mid; |
3797 | 0 | if (avail < 1) { |
3798 | 0 | return NT_STATUS_CONNECTION_ABORTED; |
3799 | 0 | } |
3800 | | |
3801 | 0 | if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { |
3802 | 0 | uint32_t max_dyn_len = 1; |
3803 | |
|
3804 | 0 | max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len); |
3805 | 0 | max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len); |
3806 | |
|
3807 | 0 | charge = (max_dyn_len - 1)/ 65536 + 1; |
3808 | 0 | } else { |
3809 | 0 | charge = 1; |
3810 | 0 | } |
3811 | |
|
3812 | 0 | charge = MAX(state->smb2.credit_charge, charge); |
3813 | |
|
3814 | 0 | avail = MIN(avail, state->conn->smb2.cur_credits); |
3815 | 0 | if (avail < charge) { |
3816 | 0 | DBG_ERR("Insufficient credits. " |
3817 | 0 | "%"PRIu64" available, %"PRIu16" needed\n", |
3818 | 0 | avail, charge); |
3819 | 0 | return NT_STATUS_INTERNAL_ERROR; |
3820 | 0 | } |
3821 | | |
3822 | 0 | credits = 0; |
3823 | 0 | if (state->conn->smb2.max_credits > state->conn->smb2.cur_credits) { |
3824 | 0 | credits = state->conn->smb2.max_credits - |
3825 | 0 | state->conn->smb2.cur_credits; |
3826 | 0 | } |
3827 | 0 | if (state->conn->smb2.max_credits >= state->conn->smb2.cur_credits) { |
3828 | 0 | credits += 1; |
3829 | 0 | } |
3830 | |
|
3831 | 0 | mid = state->conn->smb2.mid; |
3832 | 0 | state->conn->smb2.mid += charge; |
3833 | 0 | state->conn->smb2.cur_credits -= charge; |
3834 | |
|
3835 | 0 | if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { |
3836 | 0 | SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT_CHARGE, charge); |
3837 | 0 | } |
3838 | 0 | SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT, credits); |
3839 | 0 | SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, mid); |
3840 | |
|
3841 | 0 | state->smb2.cancel_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS); |
3842 | 0 | state->smb2.cancel_flags &= ~SMB2_HDR_FLAG_CHAINED; |
3843 | 0 | if (state->conn->smb2.server.sign_algo >= SMB2_SIGNING_AES128_GMAC) { |
3844 | 0 | state->smb2.cancel_mid = mid; |
3845 | 0 | } else { |
3846 | 0 | state->smb2.cancel_mid = 0; |
3847 | 0 | } |
3848 | 0 | state->smb2.cancel_aid = 0; |
3849 | |
|
3850 | 0 | skip_credits: |
3851 | 0 | if (state->session && encryption_key == NULL) { |
3852 | | /* |
3853 | | * We prefer the channel signing key if it is |
3854 | | * already there. |
3855 | | */ |
3856 | 0 | if (state->smb2.should_sign) { |
3857 | 0 | signing_key = state->session->smb2_channel.signing_key; |
3858 | 0 | } |
3859 | | |
3860 | | /* |
3861 | | * If it is a channel binding, we already have the main |
3862 | | * signing key and try that one. |
3863 | | */ |
3864 | 0 | if (signing_key != NULL && |
3865 | 0 | !smb2_signing_key_valid(signing_key)) { |
3866 | 0 | signing_key = state->session->smb2->signing_key; |
3867 | 0 | } |
3868 | | |
3869 | | /* |
3870 | | * If we do not have any session key yet, we skip the |
3871 | | * signing of SMB2_OP_SESSSETUP requests. |
3872 | | */ |
3873 | 0 | if (signing_key != NULL && |
3874 | 0 | !smb2_signing_key_valid(signing_key)) { |
3875 | 0 | signing_key = NULL; |
3876 | 0 | } |
3877 | 0 | } |
3878 | |
|
3879 | 0 | hdr_iov = num_iov; |
3880 | 0 | iov[num_iov].iov_base = state->smb2.hdr; |
3881 | 0 | iov[num_iov].iov_len = sizeof(state->smb2.hdr); |
3882 | 0 | num_iov += 1; |
3883 | |
|
3884 | 0 | iov[num_iov].iov_base = discard_const(state->smb2.fixed); |
3885 | 0 | iov[num_iov].iov_len = state->smb2.fixed_len; |
3886 | 0 | num_iov += 1; |
3887 | |
|
3888 | 0 | if (state->smb2.dyn != NULL) { |
3889 | 0 | iov[num_iov].iov_base = discard_const(state->smb2.dyn); |
3890 | 0 | iov[num_iov].iov_len = state->smb2.dyn_len; |
3891 | 0 | num_iov += 1; |
3892 | 0 | } |
3893 | |
|
3894 | 0 | reqlen = sizeof(state->smb2.hdr); |
3895 | 0 | reqlen += state->smb2.fixed_len; |
3896 | 0 | reqlen += state->smb2.dyn_len; |
3897 | |
|
3898 | 0 | if (i < num_reqs-1) { |
3899 | 0 | if ((reqlen % 8) > 0) { |
3900 | 0 | uint8_t pad = 8 - (reqlen % 8); |
3901 | 0 | iov[num_iov].iov_base = state->smb2.pad; |
3902 | 0 | iov[num_iov].iov_len = pad; |
3903 | 0 | num_iov += 1; |
3904 | 0 | reqlen += pad; |
3905 | 0 | } |
3906 | 0 | SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen); |
3907 | 0 | } |
3908 | |
|
3909 | 0 | state->smb2.encryption_session_id = encryption_session_id; |
3910 | |
|
3911 | 0 | if (signing_key != NULL) { |
3912 | 0 | NTSTATUS status; |
3913 | |
|
3914 | 0 | status = smb2_signing_sign_pdu(signing_key, |
3915 | 0 | &iov[hdr_iov], num_iov - hdr_iov); |
3916 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3917 | 0 | return status; |
3918 | 0 | } |
3919 | 0 | } |
3920 | | |
3921 | 0 | nbt_len += reqlen; |
3922 | |
|
3923 | 0 | ret = smbXcli_req_set_pending(reqs[i]); |
3924 | 0 | if (!ret) { |
3925 | 0 | return NT_STATUS_NO_MEMORY; |
3926 | 0 | } |
3927 | 0 | } |
3928 | | |
3929 | 0 | state = tevent_req_data(reqs[0], struct smbXcli_req_state); |
3930 | 0 | _smb_setlen_tcp(state->length_hdr, nbt_len); |
3931 | 0 | iov[0].iov_base = state->length_hdr; |
3932 | 0 | iov[0].iov_len = sizeof(state->length_hdr); |
3933 | |
|
3934 | 0 | if (encryption_key != NULL) { |
3935 | 0 | NTSTATUS status; |
3936 | 0 | size_t buflen = nbt_len - SMB2_TF_HDR_SIZE; |
3937 | 0 | uint8_t *buf; |
3938 | 0 | int vi; |
3939 | |
|
3940 | 0 | buf = talloc_array(iov, uint8_t, buflen); |
3941 | 0 | if (buf == NULL) { |
3942 | 0 | return NT_STATUS_NO_MEMORY; |
3943 | 0 | } |
3944 | | |
3945 | | /* |
3946 | | * We copy the buffers before encrypting them, |
3947 | | * this is at least currently needed for the |
3948 | | * to keep state->smb2.hdr. |
3949 | | * |
3950 | | * Also the callers may expect there buffers |
3951 | | * to be const. |
3952 | | */ |
3953 | 0 | for (vi = tf_iov + 1; vi < num_iov; vi++) { |
3954 | 0 | struct iovec *v = &iov[vi]; |
3955 | 0 | const uint8_t *o = (const uint8_t *)v->iov_base; |
3956 | |
|
3957 | 0 | memcpy(buf, o, v->iov_len); |
3958 | 0 | v->iov_base = (void *)buf; |
3959 | 0 | buf += v->iov_len; |
3960 | 0 | } |
3961 | |
|
3962 | 0 | status = smb2_signing_encrypt_pdu(encryption_key, |
3963 | 0 | &iov[tf_iov], num_iov - tf_iov); |
3964 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3965 | 0 | return status; |
3966 | 0 | } |
3967 | 0 | } |
3968 | | |
3969 | 0 | if (state->conn->dispatch_incoming == NULL) { |
3970 | 0 | state->conn->dispatch_incoming = smb2cli_conn_dispatch_incoming; |
3971 | 0 | } |
3972 | |
|
3973 | 0 | xtp = state->conn->transport; |
3974 | 0 | subreq = xtp->writev_send_fn(state, |
3975 | 0 | state->ev, |
3976 | 0 | xtp, |
3977 | 0 | state->conn->outgoing, |
3978 | 0 | iov, |
3979 | 0 | num_iov); |
3980 | 0 | if (subreq == NULL) { |
3981 | 0 | return NT_STATUS_NO_MEMORY; |
3982 | 0 | } |
3983 | 0 | state->writev_recv_fn = xtp->writev_recv_fn; |
3984 | 0 | tevent_req_set_callback(subreq, smb2cli_req_writev_done, reqs[0]); |
3985 | 0 | state->write_req = subreq; |
3986 | |
|
3987 | 0 | return NT_STATUS_OK; |
3988 | 0 | } |
3989 | | |
3990 | | void smb2cli_req_set_credit_charge(struct tevent_req *req, uint16_t charge) |
3991 | 0 | { |
3992 | 0 | struct smbXcli_req_state *state = |
3993 | 0 | tevent_req_data(req, |
3994 | 0 | struct smbXcli_req_state); |
3995 | |
|
3996 | 0 | state->smb2.credit_charge = charge; |
3997 | 0 | } |
3998 | | |
3999 | | struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, |
4000 | | struct tevent_context *ev, |
4001 | | struct smbXcli_conn *conn, |
4002 | | uint16_t cmd, |
4003 | | uint32_t additional_flags, |
4004 | | uint32_t clear_flags, |
4005 | | uint32_t timeout_msec, |
4006 | | struct smbXcli_tcon *tcon, |
4007 | | struct smbXcli_session *session, |
4008 | | const uint8_t *fixed, |
4009 | | uint16_t fixed_len, |
4010 | | const uint8_t *dyn, |
4011 | | uint32_t dyn_len, |
4012 | | uint32_t max_dyn_len) |
4013 | 0 | { |
4014 | 0 | struct tevent_req *req; |
4015 | 0 | NTSTATUS status; |
4016 | |
|
4017 | 0 | req = smb2cli_req_create(mem_ctx, ev, conn, cmd, |
4018 | 0 | additional_flags, clear_flags, |
4019 | 0 | timeout_msec, |
4020 | 0 | tcon, session, |
4021 | 0 | fixed, fixed_len, |
4022 | 0 | dyn, dyn_len, |
4023 | 0 | max_dyn_len); |
4024 | 0 | if (req == NULL) { |
4025 | 0 | return NULL; |
4026 | 0 | } |
4027 | 0 | if (!tevent_req_is_in_progress(req)) { |
4028 | 0 | return tevent_req_post(req, ev); |
4029 | 0 | } |
4030 | 0 | status = smb2cli_req_compound_submit(&req, 1); |
4031 | 0 | if (tevent_req_nterror(req, status)) { |
4032 | 0 | return tevent_req_post(req, ev); |
4033 | 0 | } |
4034 | 0 | return req; |
4035 | 0 | } |
4036 | | |
4037 | | static void smb2cli_req_writev_done(struct tevent_req *subreq) |
4038 | 0 | { |
4039 | 0 | struct tevent_req *req = |
4040 | 0 | tevent_req_callback_data(subreq, |
4041 | 0 | struct tevent_req); |
4042 | 0 | struct smbXcli_req_state *state = |
4043 | 0 | tevent_req_data(req, |
4044 | 0 | struct smbXcli_req_state); |
4045 | 0 | ssize_t nwritten; |
4046 | 0 | int err; |
4047 | |
|
4048 | 0 | state->write_req = NULL; |
4049 | |
|
4050 | 0 | nwritten = state->writev_recv_fn(subreq, &err); |
4051 | 0 | TALLOC_FREE(subreq); |
4052 | 0 | if (nwritten == -1) { |
4053 | | /* here, we need to notify all pending requests */ |
4054 | 0 | NTSTATUS status = map_nt_error_from_unix_common(err); |
4055 | 0 | smbXcli_conn_disconnect(state->conn, status); |
4056 | 0 | return; |
4057 | 0 | } |
4058 | 0 | } |
4059 | | |
4060 | | static struct smbXcli_session* smbXcli_session_by_uid(struct smbXcli_conn *conn, |
4061 | | uint64_t uid) |
4062 | 0 | { |
4063 | 0 | struct smbXcli_session *s = conn->sessions; |
4064 | |
|
4065 | 0 | for (; s; s = s->next) { |
4066 | 0 | if (s->smb2->session_id != uid) { |
4067 | 0 | continue; |
4068 | 0 | } |
4069 | 0 | break; |
4070 | 0 | } |
4071 | |
|
4072 | 0 | return s; |
4073 | 0 | } |
4074 | | |
4075 | | static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn, |
4076 | | uint8_t *buf, |
4077 | | size_t buflen, |
4078 | | TALLOC_CTX *mem_ctx, |
4079 | | struct iovec **piov, |
4080 | | size_t *pnum_iov) |
4081 | 0 | { |
4082 | 0 | struct iovec *iov; |
4083 | 0 | int num_iov = 0; |
4084 | 0 | size_t taken = 0; |
4085 | 0 | uint8_t *first_hdr = buf; |
4086 | 0 | size_t verified_buflen = 0; |
4087 | 0 | uint8_t *tf = NULL; |
4088 | 0 | size_t tf_len = 0; |
4089 | |
|
4090 | 0 | iov = talloc_array(mem_ctx, struct iovec, num_iov); |
4091 | 0 | if (iov == NULL) { |
4092 | 0 | return NT_STATUS_NO_MEMORY; |
4093 | 0 | } |
4094 | | |
4095 | 0 | while (taken < buflen) { |
4096 | 0 | size_t len = buflen - taken; |
4097 | 0 | uint8_t *hdr = first_hdr + taken; |
4098 | 0 | struct iovec *cur; |
4099 | 0 | size_t full_size; |
4100 | 0 | size_t next_command_ofs; |
4101 | 0 | uint16_t body_size; |
4102 | 0 | struct iovec *iov_tmp; |
4103 | |
|
4104 | 0 | if (verified_buflen > taken) { |
4105 | 0 | len = verified_buflen - taken; |
4106 | 0 | } else { |
4107 | 0 | tf = NULL; |
4108 | 0 | tf_len = 0; |
4109 | 0 | } |
4110 | |
|
4111 | 0 | if (len < 4) { |
4112 | 0 | DEBUG(10, ("%d bytes left, expected at least %d\n", |
4113 | 0 | (int)len, 4)); |
4114 | 0 | goto inval; |
4115 | 0 | } |
4116 | 0 | if (IVAL(hdr, 0) == SMB2_TF_MAGIC) { |
4117 | 0 | struct smbXcli_session *s; |
4118 | 0 | uint64_t uid; |
4119 | 0 | struct iovec tf_iov[2]; |
4120 | 0 | size_t enc_len; |
4121 | 0 | NTSTATUS status; |
4122 | |
|
4123 | 0 | if (len < SMB2_TF_HDR_SIZE) { |
4124 | 0 | DEBUG(10, ("%d bytes left, expected at least %d\n", |
4125 | 0 | (int)len, SMB2_TF_HDR_SIZE)); |
4126 | 0 | goto inval; |
4127 | 0 | } |
4128 | 0 | tf = hdr; |
4129 | 0 | tf_len = SMB2_TF_HDR_SIZE; |
4130 | 0 | taken += tf_len; |
4131 | |
|
4132 | 0 | hdr = first_hdr + taken; |
4133 | 0 | enc_len = IVAL(tf, SMB2_TF_MSG_SIZE); |
4134 | 0 | uid = BVAL(tf, SMB2_TF_SESSION_ID); |
4135 | |
|
4136 | 0 | if (len < SMB2_TF_HDR_SIZE + enc_len) { |
4137 | 0 | DEBUG(10, ("%d bytes left, expected at least %d\n", |
4138 | 0 | (int)len, |
4139 | 0 | (int)(SMB2_TF_HDR_SIZE + enc_len))); |
4140 | 0 | goto inval; |
4141 | 0 | } |
4142 | | |
4143 | 0 | s = smbXcli_session_by_uid(conn, uid); |
4144 | 0 | if (s == NULL) { |
4145 | 0 | DEBUG(10, ("unknown session_id %llu\n", |
4146 | 0 | (unsigned long long)uid)); |
4147 | 0 | goto inval; |
4148 | 0 | } |
4149 | | |
4150 | 0 | tf_iov[0].iov_base = (void *)tf; |
4151 | 0 | tf_iov[0].iov_len = tf_len; |
4152 | 0 | tf_iov[1].iov_base = (void *)hdr; |
4153 | 0 | tf_iov[1].iov_len = enc_len; |
4154 | |
|
4155 | 0 | status = smb2_signing_decrypt_pdu(s->smb2->decryption_key, |
4156 | 0 | tf_iov, 2); |
4157 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4158 | 0 | TALLOC_FREE(iov); |
4159 | 0 | return status; |
4160 | 0 | } |
4161 | | |
4162 | 0 | verified_buflen = taken + enc_len; |
4163 | 0 | len = enc_len; |
4164 | 0 | } |
4165 | | |
4166 | | /* |
4167 | | * We need the header plus the body length field |
4168 | | */ |
4169 | | |
4170 | 0 | if (len < SMB2_HDR_BODY + 2) { |
4171 | 0 | DEBUG(10, ("%d bytes left, expected at least %d\n", |
4172 | 0 | (int)len, SMB2_HDR_BODY)); |
4173 | 0 | goto inval; |
4174 | 0 | } |
4175 | 0 | if (IVAL(hdr, 0) != SMB2_MAGIC) { |
4176 | 0 | DEBUG(10, ("Got non-SMB2 PDU: %x\n", |
4177 | 0 | IVAL(hdr, 0))); |
4178 | 0 | goto inval; |
4179 | 0 | } |
4180 | 0 | if (SVAL(hdr, 4) != SMB2_HDR_BODY) { |
4181 | 0 | DEBUG(10, ("Got HDR len %d, expected %d\n", |
4182 | 0 | SVAL(hdr, 4), SMB2_HDR_BODY)); |
4183 | 0 | goto inval; |
4184 | 0 | } |
4185 | | |
4186 | 0 | full_size = len; |
4187 | 0 | next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND); |
4188 | 0 | body_size = SVAL(hdr, SMB2_HDR_BODY); |
4189 | |
|
4190 | 0 | if (next_command_ofs != 0) { |
4191 | 0 | if (next_command_ofs < (SMB2_HDR_BODY + 2)) { |
4192 | 0 | goto inval; |
4193 | 0 | } |
4194 | 0 | if (next_command_ofs > full_size) { |
4195 | 0 | goto inval; |
4196 | 0 | } |
4197 | 0 | full_size = next_command_ofs; |
4198 | 0 | } |
4199 | 0 | if (body_size < 2) { |
4200 | 0 | goto inval; |
4201 | 0 | } |
4202 | 0 | body_size &= 0xfffe; |
4203 | |
|
4204 | 0 | if (body_size > (full_size - SMB2_HDR_BODY)) { |
4205 | 0 | goto inval; |
4206 | 0 | } |
4207 | | |
4208 | 0 | iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec, |
4209 | 0 | num_iov + 4); |
4210 | 0 | if (iov_tmp == NULL) { |
4211 | 0 | TALLOC_FREE(iov); |
4212 | 0 | return NT_STATUS_NO_MEMORY; |
4213 | 0 | } |
4214 | 0 | iov = iov_tmp; |
4215 | 0 | cur = &iov[num_iov]; |
4216 | 0 | num_iov += 4; |
4217 | |
|
4218 | 0 | cur[0].iov_base = tf; |
4219 | 0 | cur[0].iov_len = tf_len; |
4220 | 0 | cur[1].iov_base = hdr; |
4221 | 0 | cur[1].iov_len = SMB2_HDR_BODY; |
4222 | 0 | cur[2].iov_base = hdr + SMB2_HDR_BODY; |
4223 | 0 | cur[2].iov_len = body_size; |
4224 | 0 | cur[3].iov_base = hdr + SMB2_HDR_BODY + body_size; |
4225 | 0 | cur[3].iov_len = full_size - (SMB2_HDR_BODY + body_size); |
4226 | |
|
4227 | 0 | taken += full_size; |
4228 | 0 | } |
4229 | | |
4230 | 0 | *piov = iov; |
4231 | 0 | *pnum_iov = num_iov; |
4232 | 0 | return NT_STATUS_OK; |
4233 | | |
4234 | 0 | inval: |
4235 | 0 | TALLOC_FREE(iov); |
4236 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4237 | 0 | } |
4238 | | |
4239 | | static struct tevent_req *smb2cli_conn_find_pending(struct smbXcli_conn *conn, |
4240 | | uint64_t mid) |
4241 | 0 | { |
4242 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
4243 | 0 | size_t i; |
4244 | |
|
4245 | 0 | for (i=0; i<num_pending; i++) { |
4246 | 0 | struct tevent_req *req = conn->pending[i]; |
4247 | 0 | struct smbXcli_req_state *state = |
4248 | 0 | tevent_req_data(req, |
4249 | 0 | struct smbXcli_req_state); |
4250 | |
|
4251 | 0 | if (mid == BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID)) { |
4252 | 0 | return req; |
4253 | 0 | } |
4254 | 0 | } |
4255 | 0 | return NULL; |
4256 | 0 | } |
4257 | | |
4258 | | static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn, |
4259 | | TALLOC_CTX *tmp_mem, |
4260 | | uint8_t *inbuf) |
4261 | 0 | { |
4262 | 0 | struct tevent_req *req; |
4263 | 0 | struct smbXcli_req_state *state = NULL; |
4264 | 0 | struct iovec *iov = NULL; |
4265 | 0 | size_t i, num_iov = 0; |
4266 | 0 | NTSTATUS status; |
4267 | 0 | bool defer = true; |
4268 | 0 | struct smbXcli_session *last_session = NULL; |
4269 | 0 | size_t inbuf_len = smb_len_tcp(inbuf); |
4270 | |
|
4271 | 0 | status = smb2cli_inbuf_parse_compound(conn, |
4272 | 0 | inbuf + NBT_HDR_SIZE, |
4273 | 0 | inbuf_len, |
4274 | 0 | tmp_mem, |
4275 | 0 | &iov, &num_iov); |
4276 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4277 | 0 | return status; |
4278 | 0 | } |
4279 | | |
4280 | 0 | for (i=0; i<num_iov; i+=4) { |
4281 | 0 | uint8_t *inbuf_ref = NULL; |
4282 | 0 | struct iovec *cur = &iov[i]; |
4283 | 0 | uint8_t *inhdr = (uint8_t *)cur[1].iov_base; |
4284 | 0 | uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE); |
4285 | 0 | uint32_t flags = IVAL(inhdr, SMB2_HDR_FLAGS); |
4286 | 0 | uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID); |
4287 | 0 | uint16_t req_opcode; |
4288 | 0 | uint32_t req_flags; |
4289 | 0 | uint16_t credits = SVAL(inhdr, SMB2_HDR_CREDIT); |
4290 | 0 | uint32_t new_credits; |
4291 | 0 | struct smbXcli_session *session = NULL; |
4292 | 0 | struct smb2_signing_key *signing_key = NULL; |
4293 | 0 | bool was_encrypted = false; |
4294 | |
|
4295 | 0 | new_credits = conn->smb2.cur_credits; |
4296 | 0 | new_credits += credits; |
4297 | 0 | if (new_credits > UINT16_MAX) { |
4298 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4299 | 0 | } |
4300 | 0 | conn->smb2.cur_credits += credits; |
4301 | |
|
4302 | 0 | req = smb2cli_conn_find_pending(conn, mid); |
4303 | 0 | if (req == NULL) { |
4304 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4305 | 0 | } |
4306 | 0 | state = tevent_req_data(req, struct smbXcli_req_state); |
4307 | |
|
4308 | 0 | req_opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE); |
4309 | 0 | if (opcode != req_opcode) { |
4310 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4311 | 0 | } |
4312 | 0 | req_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS); |
4313 | |
|
4314 | 0 | if (!(flags & SMB2_HDR_FLAG_REDIRECT)) { |
4315 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4316 | 0 | } |
4317 | | |
4318 | 0 | status = NT_STATUS(IVAL(inhdr, SMB2_HDR_STATUS)); |
4319 | 0 | if ((flags & SMB2_HDR_FLAG_ASYNC) && |
4320 | 0 | NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) { |
4321 | 0 | uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID); |
4322 | |
|
4323 | 0 | if (state->smb2.got_async) { |
4324 | | /* We only expect one STATUS_PENDING response */ |
4325 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4326 | 0 | } |
4327 | 0 | state->smb2.got_async = true; |
4328 | | |
4329 | | /* |
4330 | | * async interim responses are not signed, |
4331 | | * even if the SMB2_HDR_FLAG_SIGNED flag |
4332 | | * is set. |
4333 | | */ |
4334 | 0 | state->smb2.cancel_flags |= SMB2_HDR_FLAG_ASYNC; |
4335 | 0 | state->smb2.cancel_aid = async_id; |
4336 | |
|
4337 | 0 | if (state->smb2.notify_async) { |
4338 | 0 | tevent_req_defer_callback(req, state->ev); |
4339 | 0 | tevent_req_notify_callback(req); |
4340 | 0 | } |
4341 | 0 | continue; |
4342 | 0 | } |
4343 | | |
4344 | 0 | session = state->session; |
4345 | 0 | if (req_flags & SMB2_HDR_FLAG_CHAINED) { |
4346 | 0 | session = last_session; |
4347 | 0 | } |
4348 | 0 | last_session = session; |
4349 | |
|
4350 | 0 | if (flags & SMB2_HDR_FLAG_SIGNED) { |
4351 | 0 | uint64_t uid = BVAL(inhdr, SMB2_HDR_SESSION_ID); |
4352 | |
|
4353 | 0 | if (session == NULL) { |
4354 | 0 | session = smbXcli_session_by_uid(state->conn, |
4355 | 0 | uid); |
4356 | 0 | } |
4357 | |
|
4358 | 0 | if (session == NULL) { |
4359 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4360 | 0 | } |
4361 | | |
4362 | 0 | last_session = session; |
4363 | 0 | signing_key = session->smb2_channel.signing_key; |
4364 | 0 | } |
4365 | | |
4366 | 0 | if (opcode == SMB2_OP_SESSSETUP) { |
4367 | | /* |
4368 | | * We prefer the channel signing key, if it is |
4369 | | * already there. |
4370 | | * |
4371 | | * If we do not have a channel signing key yet, |
4372 | | * we try the main signing key, if it is not |
4373 | | * the final response. |
4374 | | */ |
4375 | 0 | if (signing_key != NULL && |
4376 | 0 | !smb2_signing_key_valid(signing_key) && |
4377 | 0 | !NT_STATUS_IS_OK(status)) { |
4378 | 0 | signing_key = session->smb2->signing_key; |
4379 | 0 | } |
4380 | |
|
4381 | 0 | if (signing_key != NULL && |
4382 | 0 | !smb2_signing_key_valid(signing_key)) { |
4383 | | /* |
4384 | | * If we do not have a session key to |
4385 | | * verify the signature, we defer the |
4386 | | * signing check to the caller. |
4387 | | * |
4388 | | * The caller gets NT_STATUS_OK, it |
4389 | | * has to call |
4390 | | * smb2cli_session_set_session_key() |
4391 | | * or |
4392 | | * smb2cli_session_set_channel_key() |
4393 | | * which will check the signature |
4394 | | * with the channel signing key. |
4395 | | */ |
4396 | 0 | signing_key = NULL; |
4397 | 0 | } |
4398 | |
|
4399 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4400 | | /* |
4401 | | * Only check the signature of the last response |
4402 | | * of a successful session auth. This matches |
4403 | | * Windows behaviour for NTLM auth and reauth. |
4404 | | */ |
4405 | 0 | state->smb2.require_signed_response = false; |
4406 | 0 | } |
4407 | 0 | } |
4408 | |
|
4409 | 0 | if (state->smb2.should_sign || |
4410 | 0 | state->smb2.require_signed_response) |
4411 | 0 | { |
4412 | 0 | if (!(flags & SMB2_HDR_FLAG_SIGNED)) { |
4413 | 0 | return NT_STATUS_ACCESS_DENIED; |
4414 | 0 | } |
4415 | 0 | } |
4416 | | |
4417 | 0 | if (!smb2_signing_key_valid(signing_key) && |
4418 | 0 | state->smb2.require_signed_response) { |
4419 | 0 | signing_key = session->smb2_channel.signing_key; |
4420 | 0 | } |
4421 | |
|
4422 | 0 | if (cur[0].iov_len == SMB2_TF_HDR_SIZE) { |
4423 | 0 | const uint8_t *tf = (const uint8_t *)cur[0].iov_base; |
4424 | 0 | uint64_t uid = BVAL(tf, SMB2_TF_SESSION_ID); |
4425 | | |
4426 | | /* |
4427 | | * If the response was encrypted in a SMB2_TRANSFORM |
4428 | | * pdu, which belongs to the correct session, |
4429 | | * we do not need to do signing checks |
4430 | | * |
4431 | | * It could be the session the response belongs to |
4432 | | * or the session that was used to encrypt the |
4433 | | * SMB2_TRANSFORM request. |
4434 | | */ |
4435 | 0 | if ((session && session->smb2->session_id == uid) || |
4436 | 0 | (state->smb2.encryption_session_id == uid)) { |
4437 | 0 | signing_key = NULL; |
4438 | 0 | was_encrypted = true; |
4439 | 0 | } |
4440 | 0 | } |
4441 | |
|
4442 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { |
4443 | | /* |
4444 | | * if the server returns NT_STATUS_USER_SESSION_DELETED |
4445 | | * the response is not signed and we should |
4446 | | * propagate the NT_STATUS_USER_SESSION_DELETED |
4447 | | * status to the caller. |
4448 | | */ |
4449 | 0 | state->smb2.signing_skipped = true; |
4450 | 0 | signing_key = NULL; |
4451 | 0 | } |
4452 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_REQUEST_OUT_OF_SEQUENCE)) { |
4453 | | /* |
4454 | | * if the server returns |
4455 | | * NT_STATUS_REQUEST_OUT_OF_SEQUENCE for a session setup |
4456 | | * request, the response is not signed and we should |
4457 | | * propagate the NT_STATUS_REQUEST_OUT_OF_SEQUENCE |
4458 | | * status to the caller |
4459 | | */ |
4460 | 0 | if (opcode == SMB2_OP_SESSSETUP) { |
4461 | 0 | state->smb2.signing_skipped = true; |
4462 | 0 | signing_key = NULL; |
4463 | 0 | } |
4464 | 0 | } |
4465 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { |
4466 | | /* |
4467 | | * if the server returns NT_STATUS_NOT_SUPPORTED |
4468 | | * for a session setup request, the response is not |
4469 | | * signed and we should propagate the NT_STATUS_NOT_SUPPORTED |
4470 | | * status to the caller. |
4471 | | */ |
4472 | 0 | if (opcode == SMB2_OP_SESSSETUP) { |
4473 | 0 | state->smb2.signing_skipped = true; |
4474 | 0 | signing_key = NULL; |
4475 | 0 | } |
4476 | 0 | } |
4477 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { |
4478 | | /* |
4479 | | * if the server returns |
4480 | | * NT_STATUS_ACCESS_DENIED for a session setup |
4481 | | * request, the response is not signed and we should |
4482 | | * propagate the NT_STATUS_ACCESS_DENIED |
4483 | | * status to the caller without disconnecting |
4484 | | * the connection because we where not able to |
4485 | | * verify the response signature. |
4486 | | */ |
4487 | 0 | if (opcode == SMB2_OP_SESSSETUP) { |
4488 | 0 | state->smb2.signing_skipped = true; |
4489 | 0 | signing_key = NULL; |
4490 | 0 | } |
4491 | 0 | } |
4492 | |
|
4493 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { |
4494 | | /* |
4495 | | * if the server returns |
4496 | | * NT_STATUS_INVALID_PARAMETER |
4497 | | * the response might not be encrypted. |
4498 | | */ |
4499 | 0 | if (state->smb2.should_encrypt && !was_encrypted) { |
4500 | 0 | state->smb2.signing_skipped = true; |
4501 | 0 | signing_key = NULL; |
4502 | 0 | } |
4503 | 0 | } |
4504 | |
|
4505 | 0 | if (state->smb2.should_encrypt && !was_encrypted) { |
4506 | 0 | if (!state->smb2.signing_skipped) { |
4507 | 0 | return NT_STATUS_ACCESS_DENIED; |
4508 | 0 | } |
4509 | 0 | } |
4510 | | |
4511 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) || |
4512 | 0 | NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) || |
4513 | 0 | (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && |
4514 | 0 | session != NULL && |
4515 | 0 | session->smb2->no_signing_disconnect) || |
4516 | 0 | NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { |
4517 | | /* |
4518 | | * if the server returns |
4519 | | * NT_STATUS_NETWORK_NAME_DELETED |
4520 | | * NT_STATUS_FILE_CLOSED |
4521 | | * NT_STATUS_INVALID_PARAMETER |
4522 | | * the response might not be signed |
4523 | | * as this happens before the signing checks. |
4524 | | * |
4525 | | * If server echos the signature (or all zeros) |
4526 | | * we should report the status from the server |
4527 | | * to the caller. |
4528 | | */ |
4529 | 0 | if (signing_key) { |
4530 | 0 | bool cmp; |
4531 | |
|
4532 | 0 | cmp = mem_equal_const_time(inhdr+SMB2_HDR_SIGNATURE, |
4533 | 0 | state->smb2.hdr+SMB2_HDR_SIGNATURE, |
4534 | 0 | 16); |
4535 | 0 | if (cmp) { |
4536 | 0 | state->smb2.signing_skipped = true; |
4537 | 0 | signing_key = NULL; |
4538 | 0 | } |
4539 | 0 | } |
4540 | 0 | if (signing_key) { |
4541 | 0 | bool zero; |
4542 | 0 | zero = all_zero(inhdr+SMB2_HDR_SIGNATURE, 16); |
4543 | 0 | if (zero) { |
4544 | 0 | state->smb2.signing_skipped = true; |
4545 | 0 | signing_key = NULL; |
4546 | 0 | } |
4547 | 0 | } |
4548 | 0 | } |
4549 | |
|
4550 | 0 | if (signing_key) { |
4551 | 0 | NTSTATUS signing_status; |
4552 | |
|
4553 | 0 | signing_status = smb2_signing_check_pdu(signing_key, |
4554 | 0 | &cur[1], 3); |
4555 | 0 | if (!NT_STATUS_IS_OK(signing_status)) { |
4556 | | /* |
4557 | | * If the signing check fails, we disconnect |
4558 | | * the connection. |
4559 | | * |
4560 | | * Unless |
4561 | | * smb2cli_session_torture_no_signing_disconnect |
4562 | | * was called in torture tests |
4563 | | */ |
4564 | |
|
4565 | 0 | if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { |
4566 | 0 | return signing_status; |
4567 | 0 | } |
4568 | | |
4569 | 0 | if (!NT_STATUS_EQUAL(status, signing_status)) { |
4570 | 0 | return signing_status; |
4571 | 0 | } |
4572 | | |
4573 | 0 | if (session == NULL) { |
4574 | 0 | return signing_status; |
4575 | 0 | } |
4576 | | |
4577 | 0 | if (!session->smb2->no_signing_disconnect) { |
4578 | 0 | return signing_status; |
4579 | 0 | } |
4580 | | |
4581 | 0 | state->smb2.signing_skipped = true; |
4582 | 0 | } |
4583 | 0 | } |
4584 | | |
4585 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) && |
4586 | 0 | (session != NULL) && session->disconnect_expired) |
4587 | 0 | { |
4588 | | /* |
4589 | | * this should be a short term hack |
4590 | | * until the upper layers have implemented |
4591 | | * re-authentication. |
4592 | | */ |
4593 | 0 | return status; |
4594 | 0 | } |
4595 | | |
4596 | 0 | smbXcli_req_unset_pending(req); |
4597 | | |
4598 | | /* |
4599 | | * There might be more than one response |
4600 | | * we need to defer the notifications |
4601 | | */ |
4602 | 0 | if ((num_iov == 5) && (talloc_array_length(conn->pending) == 0)) { |
4603 | 0 | defer = false; |
4604 | 0 | } |
4605 | |
|
4606 | 0 | if (defer) { |
4607 | 0 | tevent_req_defer_callback(req, state->ev); |
4608 | 0 | } |
4609 | | |
4610 | | /* |
4611 | | * Note: here we use talloc_reference() in a way |
4612 | | * that does not expose it to the caller. |
4613 | | */ |
4614 | 0 | inbuf_ref = talloc_reference(state->smb2.recv_iov, inbuf); |
4615 | 0 | if (tevent_req_nomem(inbuf_ref, req)) { |
4616 | 0 | continue; |
4617 | 0 | } |
4618 | | |
4619 | | /* copy the related buffers */ |
4620 | 0 | state->smb2.recv_iov[0] = cur[1]; |
4621 | 0 | state->smb2.recv_iov[1] = cur[2]; |
4622 | 0 | state->smb2.recv_iov[2] = cur[3]; |
4623 | |
|
4624 | 0 | tevent_req_done(req); |
4625 | 0 | } |
4626 | | |
4627 | 0 | if (defer) { |
4628 | 0 | return NT_STATUS_RETRY; |
4629 | 0 | } |
4630 | | |
4631 | 0 | return NT_STATUS_OK; |
4632 | 0 | } |
4633 | | |
4634 | | NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, |
4635 | | struct iovec **piov, |
4636 | | const struct smb2cli_req_expected_response *expected, |
4637 | | size_t num_expected) |
4638 | 0 | { |
4639 | 0 | struct smbXcli_req_state *state = |
4640 | 0 | tevent_req_data(req, |
4641 | 0 | struct smbXcli_req_state); |
4642 | 0 | NTSTATUS status; |
4643 | 0 | size_t body_size; |
4644 | 0 | bool found_status = false; |
4645 | 0 | bool found_size = false; |
4646 | 0 | size_t i; |
4647 | |
|
4648 | 0 | if (piov != NULL) { |
4649 | 0 | *piov = NULL; |
4650 | 0 | } |
4651 | |
|
4652 | 0 | if (tevent_req_is_in_progress(req) && state->smb2.got_async) { |
4653 | 0 | return NT_STATUS_PENDING; |
4654 | 0 | } |
4655 | | |
4656 | 0 | if (tevent_req_is_nterror(req, &status)) { |
4657 | 0 | for (i=0; i < num_expected; i++) { |
4658 | 0 | if (NT_STATUS_EQUAL(status, expected[i].status)) { |
4659 | 0 | return NT_STATUS_UNEXPECTED_NETWORK_ERROR; |
4660 | 0 | } |
4661 | 0 | } |
4662 | | |
4663 | 0 | return status; |
4664 | 0 | } |
4665 | | |
4666 | 0 | if (num_expected == 0) { |
4667 | 0 | found_status = true; |
4668 | 0 | found_size = true; |
4669 | 0 | } |
4670 | |
|
4671 | 0 | status = NT_STATUS(IVAL(state->smb2.recv_iov[0].iov_base, SMB2_HDR_STATUS)); |
4672 | 0 | body_size = SVAL(state->smb2.recv_iov[1].iov_base, 0); |
4673 | |
|
4674 | 0 | for (i=0; i < num_expected; i++) { |
4675 | 0 | if (!NT_STATUS_EQUAL(status, expected[i].status)) { |
4676 | 0 | continue; |
4677 | 0 | } |
4678 | | |
4679 | 0 | found_status = true; |
4680 | 0 | if (expected[i].body_size == 0) { |
4681 | 0 | found_size = true; |
4682 | 0 | break; |
4683 | 0 | } |
4684 | | |
4685 | 0 | if (expected[i].body_size == body_size) { |
4686 | 0 | found_size = true; |
4687 | 0 | break; |
4688 | 0 | } |
4689 | 0 | } |
4690 | |
|
4691 | 0 | if (!found_status) { |
4692 | 0 | return status; |
4693 | 0 | } |
4694 | | |
4695 | 0 | if (state->smb2.signing_skipped) { |
4696 | 0 | if (num_expected > 0) { |
4697 | 0 | return NT_STATUS_ACCESS_DENIED; |
4698 | 0 | } |
4699 | 0 | if (!NT_STATUS_IS_ERR(status)) { |
4700 | 0 | return NT_STATUS_ACCESS_DENIED; |
4701 | 0 | } |
4702 | 0 | } |
4703 | | |
4704 | 0 | if (!found_size) { |
4705 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
4706 | 0 | } |
4707 | | |
4708 | 0 | if (piov != NULL) { |
4709 | 0 | *piov = talloc_move(mem_ctx, &state->smb2.recv_iov); |
4710 | 0 | } |
4711 | |
|
4712 | 0 | return status; |
4713 | 0 | } |
4714 | | |
4715 | | NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req, |
4716 | | struct iovec *sent_iov) |
4717 | 0 | { |
4718 | 0 | struct smbXcli_req_state *state = |
4719 | 0 | tevent_req_data(req, |
4720 | 0 | struct smbXcli_req_state); |
4721 | |
|
4722 | 0 | if (tevent_req_is_in_progress(req)) { |
4723 | 0 | return NT_STATUS_PENDING; |
4724 | 0 | } |
4725 | | |
4726 | 0 | sent_iov[0].iov_base = state->smb2.hdr; |
4727 | 0 | sent_iov[0].iov_len = sizeof(state->smb2.hdr); |
4728 | |
|
4729 | 0 | sent_iov[1].iov_base = discard_const(state->smb2.fixed); |
4730 | 0 | sent_iov[1].iov_len = state->smb2.fixed_len; |
4731 | |
|
4732 | 0 | if (state->smb2.dyn != NULL) { |
4733 | 0 | sent_iov[2].iov_base = discard_const(state->smb2.dyn); |
4734 | 0 | sent_iov[2].iov_len = state->smb2.dyn_len; |
4735 | 0 | } else { |
4736 | 0 | sent_iov[2].iov_base = NULL; |
4737 | 0 | sent_iov[2].iov_len = 0; |
4738 | 0 | } |
4739 | |
|
4740 | 0 | return NT_STATUS_OK; |
4741 | 0 | } |
4742 | | |
4743 | | static const struct { |
4744 | | enum protocol_types proto; |
4745 | | const char smb1_name[24]; /* strlen("MICROSOFT NETWORKS 1.03") == 23 */ |
4746 | | } smb1cli_prots[] = { |
4747 | | {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, |
4748 | | {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"}, |
4749 | | {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"}, |
4750 | | {PROTOCOL_LANMAN1, "LANMAN1.0"}, |
4751 | | {PROTOCOL_LANMAN2, "LM1.2X002"}, |
4752 | | {PROTOCOL_LANMAN2, "DOS LANMAN2.1"}, |
4753 | | {PROTOCOL_LANMAN2, "LANMAN2.1"}, |
4754 | | {PROTOCOL_LANMAN2, "Samba"}, |
4755 | | {PROTOCOL_NT1, "NT LANMAN 1.0"}, |
4756 | | {PROTOCOL_NT1, "NT LM 0.12"}, |
4757 | | {PROTOCOL_SMB2_02, "SMB 2.002"}, |
4758 | | {PROTOCOL_SMB2_10, "SMB 2.???"}, |
4759 | | }; |
4760 | | |
4761 | | static const struct { |
4762 | | enum protocol_types proto; |
4763 | | uint16_t smb2_dialect; |
4764 | | } smb2cli_prots[] = { |
4765 | | {PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202}, |
4766 | | {PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210}, |
4767 | | {PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300}, |
4768 | | {PROTOCOL_SMB3_02, SMB3_DIALECT_REVISION_302}, |
4769 | | {PROTOCOL_SMB3_11, SMB3_DIALECT_REVISION_311}, |
4770 | | }; |
4771 | | |
4772 | | struct smbXcli_negprot_state { |
4773 | | struct smbXcli_conn *conn; |
4774 | | struct tevent_context *ev; |
4775 | | struct smb2_negotiate_contexts *in_ctx; |
4776 | | struct smb2_negotiate_contexts *out_ctx; |
4777 | | uint32_t timeout_msec; |
4778 | | |
4779 | | struct { |
4780 | | uint8_t fixed[36]; |
4781 | | } smb2; |
4782 | | }; |
4783 | | |
4784 | | static void smbXcli_negprot_invalid_done(struct tevent_req *subreq); |
4785 | | static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state); |
4786 | | static void smbXcli_negprot_smb1_done(struct tevent_req *subreq); |
4787 | | static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state); |
4788 | | static void smbXcli_negprot_smb2_done(struct tevent_req *subreq); |
4789 | | static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn, |
4790 | | TALLOC_CTX *frame, |
4791 | | uint8_t *inbuf); |
4792 | | |
4793 | | struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx, |
4794 | | struct tevent_context *ev, |
4795 | | struct smbXcli_conn *conn, |
4796 | | uint32_t timeout_msec, |
4797 | | enum protocol_types min_protocol, |
4798 | | enum protocol_types max_protocol, |
4799 | | uint16_t max_credits, |
4800 | | struct smb2_negotiate_contexts *in_ctx) |
4801 | 0 | { |
4802 | 0 | struct tevent_req *req, *subreq; |
4803 | 0 | struct smbXcli_negprot_state *state; |
4804 | |
|
4805 | 0 | req = tevent_req_create(mem_ctx, &state, |
4806 | 0 | struct smbXcli_negprot_state); |
4807 | 0 | if (req == NULL) { |
4808 | 0 | return NULL; |
4809 | 0 | } |
4810 | 0 | state->conn = conn; |
4811 | 0 | state->ev = ev; |
4812 | 0 | state->in_ctx = in_ctx; |
4813 | 0 | state->timeout_msec = timeout_msec; |
4814 | |
|
4815 | 0 | if (min_protocol == PROTOCOL_NONE) { |
4816 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); |
4817 | 0 | return tevent_req_post(req, ev); |
4818 | 0 | } |
4819 | | |
4820 | 0 | if (max_protocol == PROTOCOL_NONE) { |
4821 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); |
4822 | 0 | return tevent_req_post(req, ev); |
4823 | 0 | } |
4824 | | |
4825 | 0 | if (min_protocol > max_protocol) { |
4826 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); |
4827 | 0 | return tevent_req_post(req, ev); |
4828 | 0 | } |
4829 | | |
4830 | 0 | conn->min_protocol = min_protocol; |
4831 | 0 | conn->max_protocol = max_protocol; |
4832 | 0 | conn->protocol = PROTOCOL_NONE; |
4833 | |
|
4834 | 0 | if (max_protocol >= PROTOCOL_SMB2_02) { |
4835 | 0 | conn->smb2.max_credits = max_credits; |
4836 | 0 | } |
4837 | |
|
4838 | 0 | if ((min_protocol < PROTOCOL_SMB2_02) && |
4839 | 0 | (max_protocol < PROTOCOL_SMB2_02)) { |
4840 | | /* |
4841 | | * SMB1 only... |
4842 | | */ |
4843 | 0 | conn->dispatch_incoming = smb1cli_conn_dispatch_incoming; |
4844 | |
|
4845 | 0 | subreq = smbXcli_negprot_smb1_subreq(state); |
4846 | 0 | if (tevent_req_nomem(subreq, req)) { |
4847 | 0 | return tevent_req_post(req, ev); |
4848 | 0 | } |
4849 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req); |
4850 | 0 | return req; |
4851 | 0 | } |
4852 | | |
4853 | 0 | if ((min_protocol >= PROTOCOL_SMB2_02) && |
4854 | 0 | (max_protocol >= PROTOCOL_SMB2_02)) { |
4855 | | /* |
4856 | | * SMB2 only... |
4857 | | */ |
4858 | 0 | conn->dispatch_incoming = smb2cli_conn_dispatch_incoming; |
4859 | |
|
4860 | 0 | subreq = smbXcli_negprot_smb2_subreq(state); |
4861 | 0 | if (tevent_req_nomem(subreq, req)) { |
4862 | 0 | return tevent_req_post(req, ev); |
4863 | 0 | } |
4864 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req); |
4865 | 0 | return req; |
4866 | 0 | } |
4867 | | |
4868 | | /* |
4869 | | * We send an SMB1 negprot with the SMB2 dialects |
4870 | | * and expect a SMB1 or a SMB2 response. |
4871 | | * |
4872 | | * smbXcli_negprot_dispatch_incoming() will fix the |
4873 | | * callback to match protocol of the response. |
4874 | | */ |
4875 | 0 | conn->dispatch_incoming = smbXcli_negprot_dispatch_incoming; |
4876 | |
|
4877 | 0 | subreq = smbXcli_negprot_smb1_subreq(state); |
4878 | 0 | if (tevent_req_nomem(subreq, req)) { |
4879 | 0 | return tevent_req_post(req, ev); |
4880 | 0 | } |
4881 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_invalid_done, req); |
4882 | 0 | return req; |
4883 | 0 | } |
4884 | | |
4885 | | static void smbXcli_negprot_invalid_done(struct tevent_req *subreq) |
4886 | 0 | { |
4887 | 0 | struct tevent_req *req = |
4888 | 0 | tevent_req_callback_data(subreq, |
4889 | 0 | struct tevent_req); |
4890 | 0 | NTSTATUS status; |
4891 | | |
4892 | | /* |
4893 | | * we just want the low level error |
4894 | | */ |
4895 | 0 | status = tevent_req_simple_recv_ntstatus(subreq); |
4896 | 0 | TALLOC_FREE(subreq); |
4897 | 0 | if (tevent_req_nterror(req, status)) { |
4898 | 0 | return; |
4899 | 0 | } |
4900 | | |
4901 | | /* this should never happen */ |
4902 | 0 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); |
4903 | 0 | } |
4904 | | |
4905 | | static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state) |
4906 | 0 | { |
4907 | 0 | size_t i; |
4908 | 0 | DATA_BLOB bytes = data_blob_null; |
4909 | 0 | uint8_t flags; |
4910 | 0 | uint16_t flags2; |
4911 | | |
4912 | | /* setup the protocol strings */ |
4913 | 0 | for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) { |
4914 | 0 | uint8_t c = 2; |
4915 | 0 | bool ok; |
4916 | |
|
4917 | 0 | if (smb1cli_prots[i].proto < state->conn->min_protocol) { |
4918 | 0 | continue; |
4919 | 0 | } |
4920 | | |
4921 | 0 | if (smb1cli_prots[i].proto > state->conn->max_protocol) { |
4922 | 0 | continue; |
4923 | 0 | } |
4924 | | |
4925 | 0 | ok = data_blob_append(state, &bytes, &c, sizeof(c)); |
4926 | 0 | if (!ok) { |
4927 | 0 | return NULL; |
4928 | 0 | } |
4929 | | |
4930 | | /* |
4931 | | * We know it is already ascii and |
4932 | | * we want NULL termination. |
4933 | | */ |
4934 | 0 | ok = data_blob_append(state, &bytes, |
4935 | 0 | smb1cli_prots[i].smb1_name, |
4936 | 0 | strlen(smb1cli_prots[i].smb1_name)+1); |
4937 | 0 | if (!ok) { |
4938 | 0 | return NULL; |
4939 | 0 | } |
4940 | 0 | } |
4941 | | |
4942 | 0 | smb1cli_req_flags(state->conn->max_protocol, |
4943 | 0 | state->conn->smb1.client.capabilities, |
4944 | 0 | SMBnegprot, |
4945 | 0 | 0, 0, &flags, |
4946 | 0 | 0, 0, &flags2); |
4947 | |
|
4948 | 0 | return smb1cli_req_send(state, state->ev, state->conn, |
4949 | 0 | SMBnegprot, |
4950 | 0 | flags, ~flags, |
4951 | 0 | flags2, ~flags2, |
4952 | 0 | state->timeout_msec, |
4953 | 0 | 0xFFFE, 0, NULL, /* pid, tid, session */ |
4954 | 0 | 0, NULL, /* wct, vwv */ |
4955 | 0 | bytes.length, bytes.data); |
4956 | 0 | } |
4957 | | |
4958 | | static void smbXcli_negprot_smb1_done(struct tevent_req *subreq) |
4959 | 0 | { |
4960 | 0 | struct tevent_req *req = |
4961 | 0 | tevent_req_callback_data(subreq, |
4962 | 0 | struct tevent_req); |
4963 | 0 | struct smbXcli_negprot_state *state = |
4964 | 0 | tevent_req_data(req, |
4965 | 0 | struct smbXcli_negprot_state); |
4966 | 0 | struct smbXcli_conn *conn = state->conn; |
4967 | 0 | struct iovec *recv_iov = NULL; |
4968 | 0 | uint8_t *inhdr = NULL; |
4969 | 0 | uint8_t wct; |
4970 | 0 | uint16_t *vwv; |
4971 | 0 | uint32_t num_bytes; |
4972 | 0 | uint8_t *bytes; |
4973 | 0 | NTSTATUS status; |
4974 | 0 | uint16_t protnum; |
4975 | 0 | size_t i; |
4976 | 0 | size_t num_prots = 0; |
4977 | 0 | uint8_t flags; |
4978 | 0 | uint32_t client_capabilities = conn->smb1.client.capabilities; |
4979 | 0 | uint32_t both_capabilities; |
4980 | 0 | uint32_t server_capabilities = 0; |
4981 | 0 | uint32_t capabilities; |
4982 | 0 | uint32_t client_max_xmit = conn->smb1.client.max_xmit; |
4983 | 0 | uint32_t server_max_xmit = 0; |
4984 | 0 | uint32_t max_xmit; |
4985 | 0 | uint32_t server_max_mux = 0; |
4986 | 0 | uint16_t server_security_mode = 0; |
4987 | 0 | uint32_t server_session_key = 0; |
4988 | 0 | bool server_readbraw = false; |
4989 | 0 | bool server_writebraw = false; |
4990 | 0 | bool server_lockread = false; |
4991 | 0 | bool server_writeunlock = false; |
4992 | 0 | struct GUID server_guid = GUID_zero(); |
4993 | 0 | DATA_BLOB server_gss_blob = data_blob_null; |
4994 | 0 | uint8_t server_challenge[8] = {}; |
4995 | 0 | char *server_workgroup = NULL; |
4996 | 0 | char *server_name = NULL; |
4997 | 0 | int server_time_zone = 0; |
4998 | 0 | NTTIME server_system_time = 0; |
4999 | 0 | static const struct smb1cli_req_expected_response expected[] = { |
5000 | 0 | { |
5001 | 0 | .status = NT_STATUS_OK, |
5002 | 0 | .wct = 0x11, /* NT1 */ |
5003 | 0 | }, |
5004 | 0 | { |
5005 | 0 | .status = NT_STATUS_OK, |
5006 | 0 | .wct = 0x0D, /* LM */ |
5007 | 0 | }, |
5008 | 0 | { |
5009 | 0 | .status = NT_STATUS_OK, |
5010 | 0 | .wct = 0x01, /* CORE */ |
5011 | 0 | } |
5012 | 0 | }; |
5013 | |
|
5014 | 0 | status = smb1cli_req_recv(subreq, state, |
5015 | 0 | &recv_iov, |
5016 | 0 | &inhdr, |
5017 | 0 | &wct, |
5018 | 0 | &vwv, |
5019 | 0 | NULL, /* pvwv_offset */ |
5020 | 0 | &num_bytes, |
5021 | 0 | &bytes, |
5022 | 0 | NULL, /* pbytes_offset */ |
5023 | 0 | NULL, /* pinbuf */ |
5024 | 0 | expected, ARRAY_SIZE(expected)); |
5025 | 0 | TALLOC_FREE(subreq); |
5026 | 0 | if (tevent_req_nterror(req, status)) { |
5027 | 0 | return; |
5028 | 0 | } |
5029 | 0 | if (inhdr == NULL) { |
5030 | 0 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); |
5031 | 0 | return; |
5032 | 0 | } |
5033 | | |
5034 | 0 | flags = CVAL(inhdr, HDR_FLG); |
5035 | |
|
5036 | 0 | protnum = SVAL(vwv, 0); |
5037 | |
|
5038 | 0 | for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) { |
5039 | 0 | if (smb1cli_prots[i].proto < state->conn->min_protocol) { |
5040 | 0 | continue; |
5041 | 0 | } |
5042 | | |
5043 | 0 | if (smb1cli_prots[i].proto > state->conn->max_protocol) { |
5044 | 0 | continue; |
5045 | 0 | } |
5046 | | |
5047 | 0 | if (protnum != num_prots) { |
5048 | 0 | num_prots++; |
5049 | 0 | continue; |
5050 | 0 | } |
5051 | | |
5052 | 0 | conn->protocol = smb1cli_prots[i].proto; |
5053 | 0 | break; |
5054 | 0 | } |
5055 | |
|
5056 | 0 | if (conn->protocol == PROTOCOL_NONE) { |
5057 | 0 | DBG_ERR("No compatible protocol selected by server.\n"); |
5058 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5059 | 0 | return; |
5060 | 0 | } |
5061 | | |
5062 | 0 | if ((conn->protocol < PROTOCOL_NT1) && conn->mandatory_signing) { |
5063 | 0 | DEBUG(0,("smbXcli_negprot: SMB signing is mandatory " |
5064 | 0 | "and the selected protocol level doesn't support it.\n")); |
5065 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
5066 | 0 | return; |
5067 | 0 | } |
5068 | | |
5069 | 0 | if (flags & FLAG_SUPPORT_LOCKREAD) { |
5070 | 0 | server_lockread = true; |
5071 | 0 | server_writeunlock = true; |
5072 | 0 | } |
5073 | |
|
5074 | 0 | if (conn->protocol >= PROTOCOL_NT1) { |
5075 | 0 | const char *client_signing = NULL; |
5076 | 0 | bool server_mandatory = false; |
5077 | 0 | bool server_allowed = false; |
5078 | 0 | const char *server_signing = NULL; |
5079 | 0 | bool ok; |
5080 | 0 | uint8_t key_len; |
5081 | |
|
5082 | 0 | if (wct != 0x11) { |
5083 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5084 | 0 | return; |
5085 | 0 | } |
5086 | | |
5087 | | /* NT protocol */ |
5088 | 0 | server_security_mode = CVAL(vwv + 1, 0); |
5089 | 0 | server_max_mux = SVAL(vwv + 1, 1); |
5090 | 0 | server_max_xmit = IVAL(vwv + 3, 1); |
5091 | 0 | server_session_key = IVAL(vwv + 7, 1); |
5092 | 0 | server_time_zone = SVALS(vwv + 15, 1); |
5093 | 0 | server_time_zone *= 60; |
5094 | | /* this time arrives in real GMT */ |
5095 | 0 | server_system_time = BVAL(vwv + 11, 1); |
5096 | 0 | server_capabilities = IVAL(vwv + 9, 1); |
5097 | |
|
5098 | 0 | key_len = CVAL(vwv + 16, 1); |
5099 | |
|
5100 | 0 | if (server_capabilities & CAP_RAW_MODE) { |
5101 | 0 | server_readbraw = true; |
5102 | 0 | server_writebraw = true; |
5103 | 0 | } |
5104 | 0 | if (server_capabilities & CAP_LOCK_AND_READ) { |
5105 | 0 | server_lockread = true; |
5106 | 0 | } |
5107 | |
|
5108 | 0 | if (server_capabilities & CAP_EXTENDED_SECURITY) { |
5109 | 0 | DATA_BLOB blob1, blob2; |
5110 | |
|
5111 | 0 | if (num_bytes < 16) { |
5112 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5113 | 0 | return; |
5114 | 0 | } |
5115 | | |
5116 | 0 | blob1 = data_blob_const(bytes, 16); |
5117 | 0 | status = GUID_from_data_blob(&blob1, &server_guid); |
5118 | 0 | if (tevent_req_nterror(req, status)) { |
5119 | 0 | return; |
5120 | 0 | } |
5121 | | |
5122 | 0 | blob1 = data_blob_const(bytes+16, num_bytes-16); |
5123 | 0 | blob2 = data_blob_dup_talloc_s(state, blob1); |
5124 | 0 | if (blob1.length > 0 && |
5125 | 0 | tevent_req_nomem(blob2.data, req)) { |
5126 | 0 | return; |
5127 | 0 | } |
5128 | 0 | server_gss_blob = blob2; |
5129 | 0 | } else { |
5130 | 0 | DATA_BLOB blob1, blob2; |
5131 | |
|
5132 | 0 | if (num_bytes < key_len) { |
5133 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5134 | 0 | return; |
5135 | 0 | } |
5136 | | |
5137 | 0 | if (key_len != 0 && key_len != 8) { |
5138 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5139 | 0 | return; |
5140 | 0 | } |
5141 | | |
5142 | 0 | if (key_len == 8) { |
5143 | 0 | memcpy(server_challenge, bytes, 8); |
5144 | 0 | } |
5145 | |
|
5146 | 0 | blob1 = data_blob_const(bytes+key_len, num_bytes-key_len); |
5147 | 0 | blob2 = data_blob_const(bytes+key_len, num_bytes-key_len); |
5148 | 0 | if (blob1.length > 0) { |
5149 | 0 | size_t len; |
5150 | |
|
5151 | 0 | len = utf16_null_terminated_len_n(blob1.data, |
5152 | 0 | blob1.length); |
5153 | 0 | blob1.length = len; |
5154 | |
|
5155 | 0 | ok = convert_string_talloc(state, |
5156 | 0 | CH_UTF16LE, |
5157 | 0 | CH_UNIX, |
5158 | 0 | blob1.data, |
5159 | 0 | blob1.length, |
5160 | 0 | &server_workgroup, |
5161 | 0 | &len); |
5162 | 0 | if (!ok) { |
5163 | 0 | status = map_nt_error_from_unix_common(errno); |
5164 | 0 | tevent_req_nterror(req, status); |
5165 | 0 | return; |
5166 | 0 | } |
5167 | 0 | } |
5168 | | |
5169 | 0 | blob2.data += blob1.length; |
5170 | 0 | blob2.length -= blob1.length; |
5171 | 0 | if (blob2.length > 0) { |
5172 | 0 | size_t len; |
5173 | |
|
5174 | 0 | ok = convert_string_talloc(state, |
5175 | 0 | CH_UTF16LE, |
5176 | 0 | CH_UNIX, |
5177 | 0 | blob2.data, |
5178 | 0 | blob2.length, |
5179 | 0 | &server_name, |
5180 | 0 | &len); |
5181 | 0 | if (!ok) { |
5182 | 0 | status = map_nt_error_from_unix_common(errno); |
5183 | 0 | tevent_req_nterror(req, status); |
5184 | 0 | return; |
5185 | 0 | } |
5186 | 0 | } |
5187 | 0 | } |
5188 | | |
5189 | 0 | client_signing = "disabled"; |
5190 | 0 | if (conn->allow_signing) { |
5191 | 0 | client_signing = "allowed"; |
5192 | 0 | } |
5193 | 0 | if (conn->mandatory_signing) { |
5194 | 0 | client_signing = "required"; |
5195 | 0 | } |
5196 | |
|
5197 | 0 | server_signing = "not supported"; |
5198 | 0 | if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { |
5199 | 0 | server_signing = "supported"; |
5200 | 0 | server_allowed = true; |
5201 | 0 | } else if (conn->mandatory_signing) { |
5202 | | /* |
5203 | | * We have mandatory signing as client |
5204 | | * lets assume the server will look at our |
5205 | | * FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED |
5206 | | * flag in the session setup |
5207 | | */ |
5208 | 0 | server_signing = "not announced"; |
5209 | 0 | server_allowed = true; |
5210 | 0 | } |
5211 | 0 | if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) { |
5212 | 0 | server_signing = "required"; |
5213 | 0 | server_mandatory = true; |
5214 | 0 | } |
5215 | |
|
5216 | 0 | ok = smb1_signing_set_negotiated(conn->smb1.signing, |
5217 | 0 | server_allowed, |
5218 | 0 | server_mandatory); |
5219 | 0 | if (!ok) { |
5220 | 0 | DEBUG(1,("cli_negprot: SMB signing is required, " |
5221 | 0 | "but client[%s] and server[%s] mismatch\n", |
5222 | 0 | client_signing, server_signing)); |
5223 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
5224 | 0 | return; |
5225 | 0 | } |
5226 | |
|
5227 | 0 | } else if (conn->protocol >= PROTOCOL_LANMAN1) { |
5228 | 0 | DATA_BLOB blob1; |
5229 | 0 | uint8_t key_len; |
5230 | 0 | time_t t; |
5231 | |
|
5232 | 0 | if (wct != 0x0D) { |
5233 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5234 | 0 | return; |
5235 | 0 | } |
5236 | | |
5237 | 0 | server_security_mode = SVAL(vwv + 1, 0); |
5238 | 0 | server_max_xmit = SVAL(vwv + 2, 0); |
5239 | 0 | server_max_mux = SVAL(vwv + 3, 0); |
5240 | 0 | server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0); |
5241 | 0 | server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0); |
5242 | 0 | server_session_key = IVAL(vwv + 6, 0); |
5243 | 0 | server_time_zone = SVALS(vwv + 10, 0); |
5244 | 0 | server_time_zone *= 60; |
5245 | | /* this time is converted to GMT by make_unix_date */ |
5246 | 0 | t = pull_dos_date((const uint8_t *)(vwv + 8), server_time_zone); |
5247 | 0 | unix_to_nt_time(&server_system_time, t); |
5248 | 0 | key_len = SVAL(vwv + 11, 0); |
5249 | |
|
5250 | 0 | if (num_bytes < key_len) { |
5251 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5252 | 0 | return; |
5253 | 0 | } |
5254 | | |
5255 | 0 | if (key_len != 0 && key_len != 8) { |
5256 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5257 | 0 | return; |
5258 | 0 | } |
5259 | | |
5260 | 0 | if (key_len == 8) { |
5261 | 0 | memcpy(server_challenge, bytes, 8); |
5262 | 0 | } |
5263 | |
|
5264 | 0 | blob1 = data_blob_const(bytes+key_len, num_bytes-key_len); |
5265 | 0 | if (blob1.length > 0) { |
5266 | 0 | size_t len; |
5267 | 0 | bool ok; |
5268 | |
|
5269 | 0 | len = utf16_null_terminated_len_n(blob1.data, |
5270 | 0 | blob1.length); |
5271 | 0 | blob1.length = len; |
5272 | |
|
5273 | 0 | ok = convert_string_talloc(state, |
5274 | 0 | CH_DOS, |
5275 | 0 | CH_UNIX, |
5276 | 0 | blob1.data, |
5277 | 0 | blob1.length, |
5278 | 0 | &server_workgroup, |
5279 | 0 | &len); |
5280 | 0 | if (!ok) { |
5281 | 0 | status = map_nt_error_from_unix_common(errno); |
5282 | 0 | tevent_req_nterror(req, status); |
5283 | 0 | return; |
5284 | 0 | } |
5285 | 0 | } |
5286 | |
|
5287 | 0 | } else { |
5288 | | /* the old core protocol */ |
5289 | 0 | server_time_zone = get_time_zone(time(NULL)); |
5290 | 0 | server_max_xmit = 1024; |
5291 | 0 | server_max_mux = 1; |
5292 | 0 | } |
5293 | | |
5294 | 0 | if (server_max_xmit < 1024) { |
5295 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5296 | 0 | return; |
5297 | 0 | } |
5298 | | |
5299 | 0 | if (server_max_mux < 1) { |
5300 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5301 | 0 | return; |
5302 | 0 | } |
5303 | | |
5304 | | /* |
5305 | | * Now calculate the negotiated capabilities |
5306 | | * based on the mask for: |
5307 | | * - client only flags |
5308 | | * - flags used in both directions |
5309 | | * - server only flags |
5310 | | */ |
5311 | 0 | both_capabilities = client_capabilities & server_capabilities; |
5312 | 0 | capabilities = client_capabilities & SMB_CAP_CLIENT_MASK; |
5313 | 0 | capabilities |= both_capabilities & SMB_CAP_BOTH_MASK; |
5314 | 0 | capabilities |= server_capabilities & SMB_CAP_SERVER_MASK; |
5315 | |
|
5316 | 0 | max_xmit = MIN(client_max_xmit, server_max_xmit); |
5317 | |
|
5318 | 0 | conn->smb1.server.capabilities = server_capabilities; |
5319 | 0 | conn->smb1.capabilities = capabilities; |
5320 | |
|
5321 | 0 | conn->smb1.server.max_xmit = server_max_xmit; |
5322 | 0 | conn->smb1.max_xmit = max_xmit; |
5323 | |
|
5324 | 0 | conn->smb1.server.max_mux = server_max_mux; |
5325 | |
|
5326 | 0 | conn->smb1.server.security_mode = server_security_mode; |
5327 | |
|
5328 | 0 | conn->smb1.server.readbraw = server_readbraw; |
5329 | 0 | conn->smb1.server.writebraw = server_writebraw; |
5330 | 0 | conn->smb1.server.lockread = server_lockread; |
5331 | 0 | conn->smb1.server.writeunlock = server_writeunlock; |
5332 | |
|
5333 | 0 | conn->smb1.server.session_key = server_session_key; |
5334 | |
|
5335 | 0 | talloc_steal(conn, server_gss_blob.data); |
5336 | 0 | conn->smb1.server.gss_blob = server_gss_blob; |
5337 | 0 | conn->smb1.server.guid = server_guid; |
5338 | 0 | memcpy(conn->smb1.server.challenge, server_challenge, 8); |
5339 | 0 | conn->smb1.server.workgroup = talloc_move(conn, &server_workgroup); |
5340 | 0 | conn->smb1.server.name = talloc_move(conn, &server_name); |
5341 | |
|
5342 | 0 | conn->smb1.server.time_zone = server_time_zone; |
5343 | 0 | conn->smb1.server.system_time = server_system_time; |
5344 | |
|
5345 | 0 | tevent_req_done(req); |
5346 | 0 | } |
5347 | | |
5348 | | static size_t smbXcli_padding_helper(uint32_t offset, size_t n) |
5349 | 0 | { |
5350 | 0 | if ((offset & (n-1)) == 0) return 0; |
5351 | 0 | return n - (offset & (n-1)); |
5352 | 0 | } |
5353 | | |
5354 | | static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state) |
5355 | 0 | { |
5356 | 0 | struct smbXcli_conn *conn = state->conn; |
5357 | 0 | size_t i; |
5358 | 0 | uint8_t *buf; |
5359 | 0 | uint16_t dialect_count = 0; |
5360 | 0 | DATA_BLOB dyn = data_blob_null; |
5361 | |
|
5362 | 0 | for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) { |
5363 | 0 | bool ok; |
5364 | 0 | uint8_t val[2]; |
5365 | |
|
5366 | 0 | if (smb2cli_prots[i].proto < conn->min_protocol) { |
5367 | 0 | continue; |
5368 | 0 | } |
5369 | | |
5370 | 0 | if (smb2cli_prots[i].proto > conn->max_protocol) { |
5371 | 0 | continue; |
5372 | 0 | } |
5373 | | |
5374 | 0 | SSVAL(val, 0, smb2cli_prots[i].smb2_dialect); |
5375 | |
|
5376 | 0 | ok = data_blob_append(state, &dyn, val, sizeof(val)); |
5377 | 0 | if (!ok) { |
5378 | 0 | return NULL; |
5379 | 0 | } |
5380 | | |
5381 | 0 | dialect_count++; |
5382 | 0 | } |
5383 | | |
5384 | 0 | buf = state->smb2.fixed; |
5385 | 0 | SSVAL(buf, 0, 36); |
5386 | 0 | SSVAL(buf, 2, dialect_count); |
5387 | 0 | SSVAL(buf, 4, conn->smb2.client.security_mode); |
5388 | 0 | SSVAL(buf, 6, 0); /* Reserved */ |
5389 | 0 | if (conn->max_protocol >= PROTOCOL_SMB3_00) { |
5390 | 0 | SIVAL(buf, 8, conn->smb2.client.capabilities); |
5391 | 0 | } else { |
5392 | 0 | SIVAL(buf, 8, 0); /* Capabilities */ |
5393 | 0 | } |
5394 | 0 | if (conn->max_protocol >= PROTOCOL_SMB2_10) { |
5395 | 0 | struct GUID_ndr_buf guid_buf = { .buf = {0}, }; |
5396 | |
|
5397 | 0 | GUID_to_ndr_buf(&conn->smb2.client.guid, &guid_buf); |
5398 | 0 | memcpy(buf+12, guid_buf.buf, 16); /* ClientGuid */ |
5399 | 0 | } else { |
5400 | 0 | memset(buf+12, 0, 16); /* ClientGuid */ |
5401 | 0 | } |
5402 | |
|
5403 | 0 | if (conn->max_protocol >= PROTOCOL_SMB3_11) { |
5404 | 0 | const struct smb3_signing_capabilities *client_sign_algos = |
5405 | 0 | &conn->smb2.client.smb3_capabilities.signing; |
5406 | 0 | const struct smb3_encryption_capabilities *client_ciphers = |
5407 | 0 | &conn->smb2.client.smb3_capabilities.encryption; |
5408 | 0 | enum tls_verify_peer_state verify_peer; |
5409 | 0 | NTSTATUS status; |
5410 | 0 | struct smb2_negotiate_contexts c = { .num_contexts = 0, }; |
5411 | 0 | uint8_t *netname_utf16 = NULL; |
5412 | 0 | size_t netname_utf16_len = 0; |
5413 | 0 | uint32_t offset; |
5414 | 0 | DATA_BLOB b; |
5415 | 0 | uint8_t p[38]; |
5416 | 0 | static const uint8_t zeros[8] = {0, }; |
5417 | 0 | size_t pad; |
5418 | 0 | bool ok; |
5419 | |
|
5420 | 0 | SSVAL(p, 0, 1); /* HashAlgorithmCount */ |
5421 | 0 | SSVAL(p, 2, 32); /* SaltLength */ |
5422 | 0 | SSVAL(p, 4, SMB2_PREAUTH_INTEGRITY_SHA512); |
5423 | 0 | generate_random_buffer(p + 6, 32); |
5424 | |
|
5425 | 0 | status = smb2_negotiate_context_add( |
5426 | 0 | state, &c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES, p, 38); |
5427 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5428 | 0 | return NULL; |
5429 | 0 | } |
5430 | | |
5431 | 0 | if (client_ciphers->num_algos > 0) { |
5432 | 0 | size_t ofs = 0; |
5433 | 0 | SSVAL(p, ofs, client_ciphers->num_algos); |
5434 | 0 | ofs += 2; |
5435 | |
|
5436 | 0 | for (i = 0; i < client_ciphers->num_algos; i++) { |
5437 | 0 | size_t next_ofs = ofs + 2; |
5438 | 0 | SMB_ASSERT(next_ofs < ARRAY_SIZE(p)); |
5439 | 0 | SSVAL(p, ofs, client_ciphers->algos[i]); |
5440 | 0 | ofs = next_ofs; |
5441 | 0 | } |
5442 | | |
5443 | 0 | status = smb2_negotiate_context_add( |
5444 | 0 | state, &c, SMB2_ENCRYPTION_CAPABILITIES, p, ofs); |
5445 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5446 | 0 | return NULL; |
5447 | 0 | } |
5448 | 0 | } |
5449 | | |
5450 | 0 | if (client_sign_algos->num_algos > 0) { |
5451 | 0 | size_t ofs = 0; |
5452 | 0 | SSVAL(p, ofs, client_sign_algos->num_algos); |
5453 | 0 | ofs += 2; |
5454 | |
|
5455 | 0 | for (i = 0; i < client_sign_algos->num_algos; i++) { |
5456 | 0 | size_t next_ofs = ofs + 2; |
5457 | 0 | SMB_ASSERT(next_ofs < ARRAY_SIZE(p)); |
5458 | 0 | SSVAL(p, ofs, client_sign_algos->algos[i]); |
5459 | 0 | ofs = next_ofs; |
5460 | 0 | } |
5461 | | |
5462 | 0 | status = smb2_negotiate_context_add( |
5463 | 0 | state, &c, SMB2_SIGNING_CAPABILITIES, p, ofs); |
5464 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5465 | 0 | return NULL; |
5466 | 0 | } |
5467 | 0 | } |
5468 | | |
5469 | 0 | verify_peer = conn->transport->verify_peer; |
5470 | |
|
5471 | 0 | if (tstream_tls_verify_peer_trusted(verify_peer) && |
5472 | 0 | !conn->smb2.client.smb3_capabilities |
5473 | 0 | .smb_encryption_over_quic) |
5474 | 0 | { |
5475 | 0 | uint8_t cap_buf[sizeof(uint32_t)]; |
5476 | |
|
5477 | 0 | PUSH_LE_U32(cap_buf, |
5478 | 0 | 0, |
5479 | 0 | SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY); |
5480 | |
|
5481 | 0 | status = smb2_negotiate_context_add( |
5482 | 0 | state, |
5483 | 0 | &c, |
5484 | 0 | SMB2_TRANSPORT_CAPABILITIES, |
5485 | 0 | cap_buf, |
5486 | 0 | sizeof(cap_buf)); |
5487 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5488 | 0 | return NULL; |
5489 | 0 | } |
5490 | 0 | conn->smb2.client |
5491 | 0 | .requested_transport_level_security = true; |
5492 | 0 | } |
5493 | | |
5494 | 0 | ok = convert_string_talloc(state, |
5495 | 0 | CH_UNIX, |
5496 | 0 | CH_UTF16, |
5497 | 0 | conn->remote_name, |
5498 | 0 | strlen(conn->remote_name), |
5499 | 0 | &netname_utf16, |
5500 | 0 | &netname_utf16_len); |
5501 | 0 | if (!ok) { |
5502 | 0 | return NULL; |
5503 | 0 | } |
5504 | | |
5505 | 0 | status = smb2_negotiate_context_add(state, &c, |
5506 | 0 | SMB2_NETNAME_NEGOTIATE_CONTEXT_ID, |
5507 | 0 | netname_utf16, netname_utf16_len); |
5508 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5509 | 0 | return NULL; |
5510 | 0 | } |
5511 | | |
5512 | 0 | if (state->in_ctx != NULL) { |
5513 | 0 | struct smb2_negotiate_contexts *ctxs = state->in_ctx; |
5514 | |
|
5515 | 0 | for (i=0; i<ctxs->num_contexts; i++) { |
5516 | 0 | struct smb2_negotiate_context *ctx = |
5517 | 0 | &ctxs->contexts[i]; |
5518 | |
|
5519 | 0 | status = smb2_negotiate_context_add( |
5520 | 0 | state, |
5521 | 0 | &c, |
5522 | 0 | ctx->type, |
5523 | 0 | ctx->data.data, |
5524 | 0 | ctx->data.length); |
5525 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5526 | 0 | return NULL; |
5527 | 0 | } |
5528 | 0 | } |
5529 | 0 | } |
5530 | | |
5531 | 0 | status = smb2_negotiate_context_push(state, &b, c); |
5532 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5533 | 0 | return NULL; |
5534 | 0 | } |
5535 | | |
5536 | 0 | offset = SMB2_HDR_BODY + sizeof(state->smb2.fixed) + dyn.length; |
5537 | 0 | pad = smbXcli_padding_helper(offset, 8); |
5538 | |
|
5539 | 0 | ok = data_blob_append(state, &dyn, zeros, pad); |
5540 | 0 | if (!ok) { |
5541 | 0 | return NULL; |
5542 | 0 | } |
5543 | 0 | offset += pad; |
5544 | |
|
5545 | 0 | ok = data_blob_append(state, &dyn, b.data, b.length); |
5546 | 0 | if (!ok) { |
5547 | 0 | return NULL; |
5548 | 0 | } |
5549 | | |
5550 | 0 | SIVAL(buf, 28, offset); /* NegotiateContextOffset */ |
5551 | 0 | SSVAL(buf, 32, c.num_contexts); /* NegotiateContextCount */ |
5552 | 0 | SSVAL(buf, 34, 0); /* Reserved */ |
5553 | 0 | } else { |
5554 | 0 | SBVAL(buf, 28, 0); /* Reserved/ClientStartTime */ |
5555 | 0 | } |
5556 | | |
5557 | 0 | return smb2cli_req_send(state, |
5558 | 0 | state->ev, |
5559 | 0 | conn, |
5560 | 0 | SMB2_OP_NEGPROT, |
5561 | 0 | 0, /* additional_flags */ |
5562 | 0 | 0, /* clear_flags */ |
5563 | 0 | state->timeout_msec, |
5564 | 0 | NULL, /* tcon */ |
5565 | 0 | NULL, /* session */ |
5566 | 0 | state->smb2.fixed, |
5567 | 0 | sizeof(state->smb2.fixed), |
5568 | 0 | dyn.data, |
5569 | 0 | dyn.length, |
5570 | 0 | UINT16_MAX); /* max_dyn_len */ |
5571 | 0 | } |
5572 | | |
5573 | | static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req); |
5574 | | |
5575 | | static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) |
5576 | 0 | { |
5577 | 0 | struct tevent_req *req = |
5578 | 0 | tevent_req_callback_data(subreq, |
5579 | 0 | struct tevent_req); |
5580 | 0 | struct smbXcli_negprot_state *state = |
5581 | 0 | tevent_req_data(req, |
5582 | 0 | struct smbXcli_negprot_state); |
5583 | 0 | struct smbXcli_conn *conn = state->conn; |
5584 | 0 | size_t security_offset, security_length; |
5585 | 0 | DATA_BLOB blob; |
5586 | 0 | NTSTATUS status; |
5587 | 0 | struct iovec *iov = NULL; |
5588 | 0 | uint8_t *body; |
5589 | 0 | size_t i; |
5590 | 0 | uint16_t dialect_revision; |
5591 | 0 | uint32_t negotiate_context_offset = 0; |
5592 | 0 | uint16_t negotiate_context_count = 0; |
5593 | 0 | DATA_BLOB negotiate_context_blob = data_blob_null; |
5594 | 0 | size_t avail; |
5595 | 0 | size_t ctx_ofs; |
5596 | 0 | size_t needed; |
5597 | 0 | struct smb2_negotiate_context *preauth = NULL; |
5598 | 0 | uint16_t hash_count; |
5599 | 0 | uint16_t salt_length; |
5600 | 0 | uint16_t hash_selected; |
5601 | 0 | gnutls_hash_hd_t hash_hnd = NULL; |
5602 | 0 | struct smb2_negotiate_context *sign_algo = NULL; |
5603 | 0 | struct smb2_negotiate_context *cipher = NULL; |
5604 | 0 | struct smb2_negotiate_context *posix = NULL; |
5605 | 0 | struct smb2_negotiate_context *transport_caps = NULL; |
5606 | 0 | struct iovec sent_iov[3] = {{0}, {0}, {0}}; |
5607 | 0 | static const struct smb2cli_req_expected_response expected[] = { |
5608 | 0 | { |
5609 | 0 | .status = NT_STATUS_OK, |
5610 | 0 | .body_size = 0x41 |
5611 | 0 | } |
5612 | 0 | }; |
5613 | 0 | int rc; |
5614 | |
|
5615 | 0 | status = smb2cli_req_recv(subreq, state, &iov, |
5616 | 0 | expected, ARRAY_SIZE(expected)); |
5617 | 0 | if (tevent_req_nterror(req, status)) { |
5618 | 0 | return; |
5619 | 0 | } |
5620 | 0 | if (iov == NULL) { |
5621 | 0 | tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); |
5622 | 0 | return; |
5623 | 0 | } |
5624 | | |
5625 | 0 | body = (uint8_t *)iov[1].iov_base; |
5626 | |
|
5627 | 0 | dialect_revision = SVAL(body, 4); |
5628 | |
|
5629 | 0 | for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) { |
5630 | 0 | if (smb2cli_prots[i].proto < state->conn->min_protocol) { |
5631 | 0 | continue; |
5632 | 0 | } |
5633 | | |
5634 | 0 | if (smb2cli_prots[i].proto > state->conn->max_protocol) { |
5635 | 0 | continue; |
5636 | 0 | } |
5637 | | |
5638 | 0 | if (smb2cli_prots[i].smb2_dialect != dialect_revision) { |
5639 | 0 | continue; |
5640 | 0 | } |
5641 | | |
5642 | 0 | conn->protocol = smb2cli_prots[i].proto; |
5643 | 0 | break; |
5644 | 0 | } |
5645 | |
|
5646 | 0 | if (conn->protocol == PROTOCOL_NONE) { |
5647 | 0 | TALLOC_FREE(subreq); |
5648 | |
|
5649 | 0 | if (state->conn->min_protocol >= PROTOCOL_SMB2_02) { |
5650 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5651 | 0 | return; |
5652 | 0 | } |
5653 | | |
5654 | 0 | if (dialect_revision != SMB2_DIALECT_REVISION_2FF) { |
5655 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5656 | 0 | return; |
5657 | 0 | } |
5658 | | |
5659 | | /* make sure we do not loop forever */ |
5660 | 0 | state->conn->min_protocol = PROTOCOL_SMB2_02; |
5661 | | |
5662 | | /* |
5663 | | * send a SMB2 negprot, in order to negotiate |
5664 | | * the SMB2 dialect. |
5665 | | */ |
5666 | 0 | subreq = smbXcli_negprot_smb2_subreq(state); |
5667 | 0 | if (tevent_req_nomem(subreq, req)) { |
5668 | 0 | return; |
5669 | 0 | } |
5670 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req); |
5671 | 0 | return; |
5672 | 0 | } |
5673 | | |
5674 | 0 | conn->smb2.server.security_mode = SVAL(body, 2); |
5675 | 0 | if (conn->protocol >= PROTOCOL_SMB3_11) { |
5676 | 0 | negotiate_context_count = SVAL(body, 6); |
5677 | 0 | } |
5678 | |
|
5679 | 0 | blob = data_blob_const(body + 8, 16); |
5680 | 0 | status = GUID_from_data_blob(&blob, &conn->smb2.server.guid); |
5681 | 0 | if (tevent_req_nterror(req, status)) { |
5682 | 0 | return; |
5683 | 0 | } |
5684 | | |
5685 | 0 | conn->smb2.server.capabilities = IVAL(body, 24); |
5686 | 0 | conn->smb2.server.max_trans_size= IVAL(body, 28); |
5687 | 0 | conn->smb2.server.max_read_size = IVAL(body, 32); |
5688 | 0 | conn->smb2.server.max_write_size= IVAL(body, 36); |
5689 | 0 | conn->smb2.server.system_time = BVAL(body, 40); |
5690 | 0 | conn->smb2.server.start_time = BVAL(body, 48); |
5691 | |
|
5692 | 0 | if (conn->smb2.server.max_trans_size == 0 || |
5693 | 0 | conn->smb2.server.max_read_size == 0 || |
5694 | 0 | conn->smb2.server.max_write_size == 0) { |
5695 | | /* |
5696 | | * We can't connect to servers we can't |
5697 | | * do any operations on. |
5698 | | */ |
5699 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5700 | 0 | return; |
5701 | 0 | } |
5702 | | |
5703 | 0 | security_offset = SVAL(body, 56); |
5704 | 0 | security_length = SVAL(body, 58); |
5705 | |
|
5706 | 0 | if (security_offset == 0) { |
5707 | | /* |
5708 | | * Azure sends security_offset = 0 and security_length = 0 |
5709 | | * |
5710 | | * We just set security_offset to the expected value |
5711 | | * in order to allow the further logic to work |
5712 | | * as before. |
5713 | | */ |
5714 | 0 | if (security_length != 0) { |
5715 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5716 | 0 | return; |
5717 | 0 | } |
5718 | 0 | security_offset = SMB2_HDR_BODY + iov[1].iov_len; |
5719 | 0 | } |
5720 | | |
5721 | 0 | if (security_offset != SMB2_HDR_BODY + iov[1].iov_len) { |
5722 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5723 | 0 | return; |
5724 | 0 | } |
5725 | | |
5726 | 0 | if (security_length > iov[2].iov_len) { |
5727 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5728 | 0 | return; |
5729 | 0 | } |
5730 | | |
5731 | 0 | conn->smb2.server.gss_blob = data_blob_talloc_s(conn, |
5732 | 0 | iov[2].iov_base, |
5733 | 0 | security_length); |
5734 | 0 | if (tevent_req_nomem(conn->smb2.server.gss_blob.data, req)) { |
5735 | 0 | return; |
5736 | 0 | } |
5737 | | |
5738 | 0 | if (conn->protocol >= PROTOCOL_SMB3_00) { |
5739 | 0 | conn->smb2.server.sign_algo = SMB2_SIGNING_AES128_CMAC; |
5740 | 0 | } else { |
5741 | 0 | conn->smb2.server.sign_algo = SMB2_SIGNING_HMAC_SHA256; |
5742 | 0 | } |
5743 | |
|
5744 | 0 | if (conn->protocol < PROTOCOL_SMB3_11) { |
5745 | 0 | TALLOC_FREE(subreq); |
5746 | |
|
5747 | 0 | if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) { |
5748 | 0 | conn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM; |
5749 | 0 | } |
5750 | |
|
5751 | 0 | status = smbXcli_negprot_smb3_check_capabilities(req); |
5752 | 0 | if (tevent_req_nterror(req, status)) { |
5753 | 0 | return; |
5754 | 0 | } |
5755 | | |
5756 | 0 | tevent_req_done(req); |
5757 | 0 | return; |
5758 | 0 | } |
5759 | | |
5760 | | /* |
5761 | | * Here we are now at SMB3_11, so encryption should be |
5762 | | * negotiated via context, not capabilities. |
5763 | | */ |
5764 | | |
5765 | 0 | if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) { |
5766 | | /* |
5767 | | * Server set SMB2_CAP_ENCRYPTION capability, |
5768 | | * but *SHOULD* not, not *MUST* not. Just mask it off. |
5769 | | * NetApp seems to do this: |
5770 | | * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13009 |
5771 | | */ |
5772 | 0 | conn->smb2.server.capabilities &= ~SMB2_CAP_ENCRYPTION; |
5773 | 0 | } |
5774 | |
|
5775 | 0 | negotiate_context_offset = IVAL(body, 60); |
5776 | 0 | if (negotiate_context_offset < security_offset) { |
5777 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5778 | 0 | return; |
5779 | 0 | } |
5780 | | |
5781 | 0 | ctx_ofs = negotiate_context_offset - security_offset; |
5782 | 0 | if (ctx_ofs > iov[2].iov_len) { |
5783 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5784 | 0 | return; |
5785 | 0 | } |
5786 | 0 | avail = iov[2].iov_len - security_length; |
5787 | 0 | needed = iov[2].iov_len - ctx_ofs; |
5788 | 0 | if (needed > avail) { |
5789 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5790 | 0 | return; |
5791 | 0 | } |
5792 | | |
5793 | 0 | negotiate_context_blob.data = (uint8_t *)iov[2].iov_base; |
5794 | 0 | negotiate_context_blob.length = iov[2].iov_len; |
5795 | |
|
5796 | 0 | negotiate_context_blob.data += ctx_ofs; |
5797 | 0 | negotiate_context_blob.length -= ctx_ofs; |
5798 | |
|
5799 | 0 | state->out_ctx = talloc_zero(state, struct smb2_negotiate_contexts); |
5800 | 0 | if (tevent_req_nomem(state->out_ctx, req)) { |
5801 | 0 | return; |
5802 | 0 | } |
5803 | | |
5804 | 0 | status = smb2_negotiate_context_parse(state->out_ctx, |
5805 | 0 | negotiate_context_blob, |
5806 | 0 | negotiate_context_count, |
5807 | 0 | state->out_ctx); |
5808 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { |
5809 | 0 | status = NT_STATUS_INVALID_NETWORK_RESPONSE; |
5810 | 0 | } |
5811 | 0 | if (tevent_req_nterror(req, status)) { |
5812 | 0 | return; |
5813 | 0 | } |
5814 | | |
5815 | 0 | preauth = smb2_negotiate_context_find( |
5816 | 0 | state->out_ctx, SMB2_PREAUTH_INTEGRITY_CAPABILITIES); |
5817 | 0 | if (preauth == NULL) { |
5818 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5819 | 0 | return; |
5820 | 0 | } |
5821 | | |
5822 | 0 | if (preauth->data.length < 6) { |
5823 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5824 | 0 | return; |
5825 | 0 | } |
5826 | | |
5827 | 0 | hash_count = SVAL(preauth->data.data, 0); |
5828 | 0 | salt_length = SVAL(preauth->data.data, 2); |
5829 | 0 | hash_selected = SVAL(preauth->data.data, 4); |
5830 | |
|
5831 | 0 | if (hash_count != 1) { |
5832 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5833 | 0 | return; |
5834 | 0 | } |
5835 | | |
5836 | 0 | if (preauth->data.length != (6 + salt_length)) { |
5837 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5838 | 0 | return; |
5839 | 0 | } |
5840 | | |
5841 | 0 | if (hash_selected != SMB2_PREAUTH_INTEGRITY_SHA512) { |
5842 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
5843 | 0 | return; |
5844 | 0 | } |
5845 | | |
5846 | 0 | sign_algo = smb2_negotiate_context_find( |
5847 | 0 | state->out_ctx, SMB2_SIGNING_CAPABILITIES); |
5848 | 0 | if (sign_algo != NULL) { |
5849 | 0 | const struct smb3_signing_capabilities *client_sign_algos = |
5850 | 0 | &state->conn->smb2.client.smb3_capabilities.signing; |
5851 | 0 | bool found_selected = false; |
5852 | 0 | uint16_t sign_algo_count; |
5853 | 0 | uint16_t sign_algo_selected; |
5854 | |
|
5855 | 0 | if (client_sign_algos->num_algos == 0) { |
5856 | | /* |
5857 | | * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES |
5858 | | */ |
5859 | 0 | tevent_req_nterror(req, |
5860 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5861 | 0 | return; |
5862 | 0 | } |
5863 | | |
5864 | 0 | if (sign_algo->data.length < 2) { |
5865 | 0 | tevent_req_nterror(req, |
5866 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5867 | 0 | return; |
5868 | 0 | } |
5869 | | |
5870 | 0 | sign_algo_count = SVAL(sign_algo->data.data, 0); |
5871 | 0 | if (sign_algo_count != 1) { |
5872 | 0 | tevent_req_nterror(req, |
5873 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5874 | 0 | return; |
5875 | 0 | } |
5876 | | |
5877 | 0 | if (sign_algo->data.length < (2 + 2 * sign_algo_count)) { |
5878 | 0 | tevent_req_nterror(req, |
5879 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5880 | 0 | return; |
5881 | 0 | } |
5882 | 0 | sign_algo_selected = SVAL(sign_algo->data.data, 2); |
5883 | |
|
5884 | 0 | for (i = 0; i < client_sign_algos->num_algos; i++) { |
5885 | 0 | if (client_sign_algos->algos[i] == sign_algo_selected) { |
5886 | | /* |
5887 | | * We found a match |
5888 | | */ |
5889 | 0 | found_selected = true; |
5890 | 0 | break; |
5891 | 0 | } |
5892 | 0 | } |
5893 | |
|
5894 | 0 | if (!found_selected) { |
5895 | | /* |
5896 | | * The server send a sign_algo we didn't offer. |
5897 | | */ |
5898 | 0 | tevent_req_nterror(req, |
5899 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5900 | 0 | return; |
5901 | 0 | } |
5902 | | |
5903 | 0 | conn->smb2.server.sign_algo = sign_algo_selected; |
5904 | 0 | } |
5905 | | |
5906 | 0 | cipher = smb2_negotiate_context_find( |
5907 | 0 | state->out_ctx, SMB2_ENCRYPTION_CAPABILITIES); |
5908 | 0 | if (cipher != NULL) { |
5909 | 0 | const struct smb3_encryption_capabilities *client_ciphers = |
5910 | 0 | &state->conn->smb2.client.smb3_capabilities.encryption; |
5911 | 0 | bool found_selected = false; |
5912 | 0 | uint16_t cipher_count; |
5913 | 0 | uint16_t cipher_selected; |
5914 | |
|
5915 | 0 | if (client_ciphers->num_algos == 0) { |
5916 | | /* |
5917 | | * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES |
5918 | | */ |
5919 | 0 | tevent_req_nterror(req, |
5920 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5921 | 0 | return; |
5922 | 0 | } |
5923 | | |
5924 | 0 | if (cipher->data.length < 2) { |
5925 | 0 | tevent_req_nterror(req, |
5926 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5927 | 0 | return; |
5928 | 0 | } |
5929 | | |
5930 | 0 | cipher_count = SVAL(cipher->data.data, 0); |
5931 | 0 | if (cipher_count != 1) { |
5932 | 0 | tevent_req_nterror(req, |
5933 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5934 | 0 | return; |
5935 | 0 | } |
5936 | | |
5937 | 0 | if (cipher->data.length < (2 + 2 * cipher_count)) { |
5938 | 0 | tevent_req_nterror(req, |
5939 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5940 | 0 | return; |
5941 | 0 | } |
5942 | 0 | cipher_selected = SVAL(cipher->data.data, 2); |
5943 | |
|
5944 | 0 | for (i = 0; i < client_ciphers->num_algos; i++) { |
5945 | 0 | if (cipher_selected == SMB2_ENCRYPTION_NONE) { |
5946 | | /* |
5947 | | * encryption not supported |
5948 | | */ |
5949 | 0 | found_selected = true; |
5950 | 0 | break; |
5951 | 0 | } |
5952 | 0 | if (client_ciphers->algos[i] == cipher_selected) { |
5953 | | /* |
5954 | | * We found a match |
5955 | | */ |
5956 | 0 | found_selected = true; |
5957 | 0 | break; |
5958 | 0 | } |
5959 | 0 | } |
5960 | |
|
5961 | 0 | if (!found_selected) { |
5962 | | /* |
5963 | | * The server send a cipher we didn't offer. |
5964 | | */ |
5965 | 0 | tevent_req_nterror(req, |
5966 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5967 | 0 | return; |
5968 | 0 | } |
5969 | | |
5970 | 0 | conn->smb2.server.cipher = cipher_selected; |
5971 | 0 | } |
5972 | | |
5973 | 0 | if (conn->smb2.client.requested_transport_level_security) { |
5974 | 0 | transport_caps = smb2_negotiate_context_find( |
5975 | 0 | state->out_ctx, SMB2_TRANSPORT_CAPABILITIES); |
5976 | 0 | } |
5977 | 0 | if (transport_caps != NULL) { |
5978 | 0 | uint32_t caps; |
5979 | |
|
5980 | 0 | if (transport_caps->data.length != sizeof(uint32_t)) { |
5981 | 0 | tevent_req_nterror(req, |
5982 | 0 | NT_STATUS_INVALID_NETWORK_RESPONSE); |
5983 | 0 | return; |
5984 | 0 | } |
5985 | | |
5986 | 0 | caps = PULL_LE_U32(transport_caps->data.data, 0); |
5987 | |
|
5988 | 0 | conn->smb2.server.transport_trusted = |
5989 | 0 | (caps & SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY) != 0; |
5990 | 0 | } |
5991 | | |
5992 | 0 | posix = smb2_negotiate_context_find( |
5993 | 0 | state->out_ctx, SMB2_POSIX_EXTENSIONS_AVAILABLE); |
5994 | 0 | if (posix != NULL) { |
5995 | 0 | DATA_BLOB posix_blob = data_blob_const( |
5996 | 0 | SMB2_CREATE_TAG_POSIX, strlen(SMB2_CREATE_TAG_POSIX)); |
5997 | 0 | int cmp = data_blob_cmp(&posix->data, &posix_blob); |
5998 | |
|
5999 | 0 | conn->smb2.server.smb311_posix = (cmp == 0); |
6000 | 0 | } |
6001 | | |
6002 | | |
6003 | | /* First we hash the request */ |
6004 | 0 | smb2cli_req_get_sent_iov(subreq, sent_iov); |
6005 | |
|
6006 | 0 | rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512); |
6007 | 0 | if (rc < 0) { |
6008 | 0 | tevent_req_nterror(req, |
6009 | 0 | gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED)); |
6010 | 0 | return; |
6011 | 0 | } |
6012 | | |
6013 | 0 | rc = gnutls_hash(hash_hnd, |
6014 | 0 | conn->smb2.preauth_sha512, |
6015 | 0 | sizeof(conn->smb2.preauth_sha512)); |
6016 | 0 | if (rc < 0) { |
6017 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6018 | 0 | tevent_req_nterror(req, |
6019 | 0 | gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED)); |
6020 | 0 | return; |
6021 | 0 | } |
6022 | 0 | for (i = 0; i < 3; i++) { |
6023 | 0 | rc = gnutls_hash(hash_hnd, |
6024 | 0 | sent_iov[i].iov_base, |
6025 | 0 | sent_iov[i].iov_len); |
6026 | 0 | if (rc < 0) { |
6027 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6028 | 0 | tevent_req_nterror(req, |
6029 | 0 | gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED)); |
6030 | 0 | return; |
6031 | 0 | } |
6032 | 0 | } |
6033 | | |
6034 | | /* This resets the hash state */ |
6035 | 0 | gnutls_hash_output(hash_hnd, conn->smb2.preauth_sha512); |
6036 | 0 | TALLOC_FREE(subreq); |
6037 | | |
6038 | | /* And now we hash the response */ |
6039 | 0 | rc = gnutls_hash(hash_hnd, |
6040 | 0 | conn->smb2.preauth_sha512, |
6041 | 0 | sizeof(conn->smb2.preauth_sha512)); |
6042 | 0 | if (rc < 0) { |
6043 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6044 | 0 | tevent_req_nterror(req, |
6045 | 0 | gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED)); |
6046 | 0 | return; |
6047 | 0 | } |
6048 | 0 | for (i = 0; i < 3; i++) { |
6049 | 0 | rc = gnutls_hash(hash_hnd, |
6050 | 0 | iov[i].iov_base, |
6051 | 0 | iov[i].iov_len); |
6052 | 0 | if (rc < 0) { |
6053 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6054 | 0 | tevent_req_nterror(req, |
6055 | 0 | gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED)); |
6056 | 0 | return; |
6057 | 0 | } |
6058 | 0 | } |
6059 | 0 | gnutls_hash_deinit(hash_hnd, conn->smb2.preauth_sha512); |
6060 | 0 | if (rc < 0) { |
6061 | 0 | tevent_req_nterror(req, |
6062 | 0 | NT_STATUS_UNSUCCESSFUL); |
6063 | 0 | return; |
6064 | 0 | } |
6065 | | |
6066 | 0 | status = smbXcli_negprot_smb3_check_capabilities(req); |
6067 | 0 | if (tevent_req_nterror(req, status)) { |
6068 | 0 | return; |
6069 | 0 | } |
6070 | | |
6071 | 0 | tevent_req_done(req); |
6072 | 0 | } |
6073 | | |
6074 | | static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req) |
6075 | 0 | { |
6076 | 0 | struct smbXcli_negprot_state *state = |
6077 | 0 | tevent_req_data(req, |
6078 | 0 | struct smbXcli_negprot_state); |
6079 | 0 | struct smbXcli_conn *conn = state->conn; |
6080 | |
|
6081 | 0 | return smb311_capabilities_check(&conn->smb2.client.smb3_capabilities, |
6082 | 0 | "smbXcli_negprot", |
6083 | 0 | DBGLVL_ERR, |
6084 | 0 | NT_STATUS_ACCESS_DENIED, |
6085 | 0 | "client", |
6086 | 0 | conn->protocol, |
6087 | 0 | conn->smb2.server.sign_algo, |
6088 | 0 | conn->smb2.server.cipher); |
6089 | 0 | } |
6090 | | |
6091 | | static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn, |
6092 | | TALLOC_CTX *tmp_mem, |
6093 | | uint8_t *inbuf) |
6094 | 0 | { |
6095 | 0 | size_t num_pending = talloc_array_length(conn->pending); |
6096 | 0 | struct tevent_req *subreq; |
6097 | 0 | struct smbXcli_req_state *substate; |
6098 | 0 | struct tevent_req *req; |
6099 | 0 | uint32_t protocol_magic; |
6100 | 0 | size_t inbuf_len = smb_len_nbt(inbuf); |
6101 | |
|
6102 | 0 | if (num_pending != 1) { |
6103 | 0 | return NT_STATUS_INTERNAL_ERROR; |
6104 | 0 | } |
6105 | | |
6106 | 0 | if (inbuf_len < 4) { |
6107 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
6108 | 0 | } |
6109 | | |
6110 | 0 | subreq = conn->pending[0]; |
6111 | 0 | substate = tevent_req_data(subreq, struct smbXcli_req_state); |
6112 | 0 | req = tevent_req_callback_data(subreq, struct tevent_req); |
6113 | |
|
6114 | 0 | protocol_magic = IVAL(inbuf, 4); |
6115 | |
|
6116 | 0 | switch (protocol_magic) { |
6117 | 0 | case SMB_MAGIC: |
6118 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req); |
6119 | 0 | conn->dispatch_incoming = smb1cli_conn_dispatch_incoming; |
6120 | 0 | return smb1cli_conn_dispatch_incoming(conn, tmp_mem, inbuf); |
6121 | | |
6122 | 0 | case SMB2_MAGIC: |
6123 | 0 | if (substate->smb2.recv_iov == NULL) { |
6124 | | /* |
6125 | | * For the SMB1 negprot we have move it. |
6126 | | */ |
6127 | 0 | substate->smb2.recv_iov = substate->smb1.recv_iov; |
6128 | 0 | substate->smb1.recv_iov = NULL; |
6129 | 0 | } |
6130 | | |
6131 | | /* |
6132 | | * we got an SMB2 answer, which consumed sequence number 0 |
6133 | | * so we need to use 1 as the next one. |
6134 | | * |
6135 | | * we also need to set the current credits to 0 |
6136 | | * as we consumed the initial one. The SMB2 answer |
6137 | | * hopefully grant us a new credit. |
6138 | | */ |
6139 | 0 | conn->smb2.mid = 1; |
6140 | 0 | conn->smb2.cur_credits = 0; |
6141 | 0 | tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req); |
6142 | 0 | conn->dispatch_incoming = smb2cli_conn_dispatch_incoming; |
6143 | 0 | return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf); |
6144 | 0 | } |
6145 | | |
6146 | 0 | DEBUG(10, ("Got non-SMB PDU\n")); |
6147 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
6148 | 0 | } |
6149 | | |
6150 | | NTSTATUS smbXcli_negprot_recv( |
6151 | | struct tevent_req *req, |
6152 | | TALLOC_CTX *mem_ctx, |
6153 | | struct smb2_negotiate_contexts **out_ctx) |
6154 | 0 | { |
6155 | 0 | struct smbXcli_negprot_state *state = tevent_req_data( |
6156 | 0 | req, struct smbXcli_negprot_state); |
6157 | 0 | NTSTATUS status; |
6158 | |
|
6159 | 0 | if (tevent_req_is_nterror(req, &status)) { |
6160 | 0 | tevent_req_received(req); |
6161 | 0 | return status; |
6162 | 0 | } |
6163 | | |
6164 | 0 | if (out_ctx != NULL) { |
6165 | 0 | *out_ctx = talloc_move(mem_ctx, &state->out_ctx); |
6166 | 0 | } |
6167 | |
|
6168 | 0 | tevent_req_received(req); |
6169 | 0 | return NT_STATUS_OK; |
6170 | 0 | } |
6171 | | |
6172 | | NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn, |
6173 | | uint32_t timeout_msec, |
6174 | | enum protocol_types min_protocol, |
6175 | | enum protocol_types max_protocol, |
6176 | | struct smb2_negotiate_contexts *in_ctx, |
6177 | | TALLOC_CTX *mem_ctx, |
6178 | | struct smb2_negotiate_contexts **out_ctx) |
6179 | 0 | { |
6180 | 0 | TALLOC_CTX *frame = talloc_stackframe(); |
6181 | 0 | struct tevent_context *ev; |
6182 | 0 | struct tevent_req *req; |
6183 | 0 | NTSTATUS status = NT_STATUS_NO_MEMORY; |
6184 | 0 | bool ok; |
6185 | |
|
6186 | 0 | if (smbXcli_conn_has_async_calls(conn)) { |
6187 | | /* |
6188 | | * Can't use sync call while an async call is in flight |
6189 | | */ |
6190 | 0 | status = NT_STATUS_INVALID_PARAMETER_MIX; |
6191 | 0 | goto fail; |
6192 | 0 | } |
6193 | 0 | ev = samba_tevent_context_init(frame); |
6194 | 0 | if (ev == NULL) { |
6195 | 0 | goto fail; |
6196 | 0 | } |
6197 | 0 | req = smbXcli_negprot_send( |
6198 | 0 | frame, |
6199 | 0 | ev, |
6200 | 0 | conn, |
6201 | 0 | timeout_msec, |
6202 | 0 | min_protocol, |
6203 | 0 | max_protocol, |
6204 | 0 | WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK, |
6205 | 0 | in_ctx); |
6206 | 0 | if (req == NULL) { |
6207 | 0 | goto fail; |
6208 | 0 | } |
6209 | 0 | ok = tevent_req_poll_ntstatus(req, ev, &status); |
6210 | 0 | if (!ok) { |
6211 | 0 | goto fail; |
6212 | 0 | } |
6213 | 0 | status = smbXcli_negprot_recv(req, mem_ctx, out_ctx); |
6214 | 0 | fail: |
6215 | 0 | TALLOC_FREE(frame); |
6216 | 0 | return status; |
6217 | 0 | } |
6218 | | |
6219 | | struct smb2cli_validate_negotiate_info_state { |
6220 | | struct smbXcli_conn *conn; |
6221 | | DATA_BLOB in_input_buffer; |
6222 | | DATA_BLOB in_output_buffer; |
6223 | | DATA_BLOB out_input_buffer; |
6224 | | DATA_BLOB out_output_buffer; |
6225 | | uint16_t dialect; |
6226 | | }; |
6227 | | |
6228 | | static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq); |
6229 | | |
6230 | | struct tevent_req *smb2cli_validate_negotiate_info_send(TALLOC_CTX *mem_ctx, |
6231 | | struct tevent_context *ev, |
6232 | | struct smbXcli_conn *conn, |
6233 | | uint32_t timeout_msec, |
6234 | | struct smbXcli_session *session, |
6235 | | struct smbXcli_tcon *tcon) |
6236 | 0 | { |
6237 | 0 | struct tevent_req *req; |
6238 | 0 | struct smb2cli_validate_negotiate_info_state *state; |
6239 | 0 | uint8_t *buf; |
6240 | 0 | uint16_t dialect_count = 0; |
6241 | 0 | struct tevent_req *subreq; |
6242 | 0 | bool _save_should_sign; |
6243 | 0 | size_t i; |
6244 | |
|
6245 | 0 | req = tevent_req_create(mem_ctx, &state, |
6246 | 0 | struct smb2cli_validate_negotiate_info_state); |
6247 | 0 | if (req == NULL) { |
6248 | 0 | return NULL; |
6249 | 0 | } |
6250 | 0 | state->conn = conn; |
6251 | |
|
6252 | 0 | state->in_input_buffer = data_blob_talloc_zero(state, |
6253 | 0 | 4 + 16 + 1 + 1 + 2); |
6254 | 0 | if (tevent_req_nomem(state->in_input_buffer.data, req)) { |
6255 | 0 | return tevent_req_post(req, ev); |
6256 | 0 | } |
6257 | 0 | buf = state->in_input_buffer.data; |
6258 | |
|
6259 | 0 | if (state->conn->max_protocol >= PROTOCOL_SMB3_00) { |
6260 | 0 | SIVAL(buf, 0, conn->smb2.client.capabilities); |
6261 | 0 | } else { |
6262 | 0 | SIVAL(buf, 0, 0); /* Capabilities */ |
6263 | 0 | } |
6264 | 0 | if (state->conn->max_protocol >= PROTOCOL_SMB2_10) { |
6265 | 0 | struct GUID_ndr_buf guid_buf = { .buf = {0}, }; |
6266 | |
|
6267 | 0 | GUID_to_ndr_buf(&conn->smb2.client.guid, &guid_buf); |
6268 | 0 | memcpy(buf+4, guid_buf.buf, 16); /* ClientGuid */ |
6269 | 0 | } else { |
6270 | 0 | memset(buf+4, 0, 16); /* ClientGuid */ |
6271 | 0 | } |
6272 | 0 | if (state->conn->min_protocol >= PROTOCOL_SMB2_02) { |
6273 | 0 | SCVAL(buf, 20, conn->smb2.client.security_mode); |
6274 | 0 | } else { |
6275 | 0 | SCVAL(buf, 20, 0); |
6276 | 0 | } |
6277 | 0 | SCVAL(buf, 21, 0); /* reserved */ |
6278 | |
|
6279 | 0 | for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) { |
6280 | 0 | bool ok; |
6281 | 0 | size_t ofs; |
6282 | |
|
6283 | 0 | if (smb2cli_prots[i].proto < state->conn->min_protocol) { |
6284 | 0 | continue; |
6285 | 0 | } |
6286 | | |
6287 | 0 | if (smb2cli_prots[i].proto > state->conn->max_protocol) { |
6288 | 0 | continue; |
6289 | 0 | } |
6290 | | |
6291 | 0 | if (smb2cli_prots[i].proto == state->conn->protocol) { |
6292 | 0 | state->dialect = smb2cli_prots[i].smb2_dialect; |
6293 | 0 | } |
6294 | |
|
6295 | 0 | ofs = state->in_input_buffer.length; |
6296 | 0 | ok = data_blob_realloc(state, &state->in_input_buffer, |
6297 | 0 | ofs + 2); |
6298 | 0 | if (!ok) { |
6299 | 0 | tevent_req_oom(req); |
6300 | 0 | return tevent_req_post(req, ev); |
6301 | 0 | } |
6302 | | |
6303 | 0 | buf = state->in_input_buffer.data; |
6304 | 0 | SSVAL(buf, ofs, smb2cli_prots[i].smb2_dialect); |
6305 | |
|
6306 | 0 | dialect_count++; |
6307 | 0 | } |
6308 | 0 | buf = state->in_input_buffer.data; |
6309 | 0 | SSVAL(buf, 22, dialect_count); |
6310 | |
|
6311 | 0 | _save_should_sign = smb2cli_tcon_is_signing_on(tcon); |
6312 | 0 | smb2cli_tcon_should_sign(tcon, true); |
6313 | 0 | subreq = smb2cli_ioctl_send(state, ev, conn, |
6314 | 0 | timeout_msec, session, tcon, |
6315 | 0 | UINT64_MAX, /* in_fid_persistent */ |
6316 | 0 | UINT64_MAX, /* in_fid_volatile */ |
6317 | 0 | FSCTL_VALIDATE_NEGOTIATE_INFO, |
6318 | 0 | 0, /* in_max_input_length */ |
6319 | 0 | &state->in_input_buffer, |
6320 | 0 | 24, /* in_max_output_length */ |
6321 | 0 | &state->in_output_buffer, |
6322 | 0 | SMB2_IOCTL_FLAG_IS_FSCTL); |
6323 | 0 | smb2cli_tcon_should_sign(tcon, _save_should_sign); |
6324 | 0 | if (tevent_req_nomem(subreq, req)) { |
6325 | 0 | return tevent_req_post(req, ev); |
6326 | 0 | } |
6327 | 0 | tevent_req_set_callback(subreq, |
6328 | 0 | smb2cli_validate_negotiate_info_done, |
6329 | 0 | req); |
6330 | |
|
6331 | 0 | return req; |
6332 | 0 | } |
6333 | | |
6334 | | static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq) |
6335 | 0 | { |
6336 | 0 | struct tevent_req *req = |
6337 | 0 | tevent_req_callback_data(subreq, |
6338 | 0 | struct tevent_req); |
6339 | 0 | struct smb2cli_validate_negotiate_info_state *state = |
6340 | 0 | tevent_req_data(req, |
6341 | 0 | struct smb2cli_validate_negotiate_info_state); |
6342 | 0 | NTSTATUS status; |
6343 | 0 | const uint8_t *buf; |
6344 | 0 | uint32_t capabilities; |
6345 | 0 | DATA_BLOB guid_blob; |
6346 | 0 | struct GUID server_guid; |
6347 | 0 | uint16_t security_mode; |
6348 | 0 | uint16_t dialect; |
6349 | |
|
6350 | 0 | status = smb2cli_ioctl_recv(subreq, state, |
6351 | 0 | &state->out_input_buffer, |
6352 | 0 | &state->out_output_buffer); |
6353 | 0 | TALLOC_FREE(subreq); |
6354 | | |
6355 | | /* |
6356 | | * This response must be signed correctly for |
6357 | | * these "normal" error codes to be processed. |
6358 | | * If the packet wasn't signed correctly we will get |
6359 | | * NT_STATUS_ACCESS_DENIED or NT_STATUS_HMAC_NOT_SUPPORTED, |
6360 | | * or NT_STATUS_INVALID_NETWORK_RESPONSE |
6361 | | * from smb2_signing_check_pdu(). |
6362 | | * |
6363 | | * We must never ignore the above errors here. |
6364 | | */ |
6365 | |
|
6366 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) { |
6367 | | /* |
6368 | | * The response was signed, but not supported |
6369 | | * |
6370 | | * Older Windows and Samba releases return |
6371 | | * NT_STATUS_FILE_CLOSED. |
6372 | | */ |
6373 | 0 | tevent_req_done(req); |
6374 | 0 | return; |
6375 | 0 | } |
6376 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) { |
6377 | | /* |
6378 | | * The response was signed, but not supported |
6379 | | * |
6380 | | * This is returned by the NTVFS based Samba 4.x file server |
6381 | | * for file shares. |
6382 | | */ |
6383 | 0 | tevent_req_done(req); |
6384 | 0 | return; |
6385 | 0 | } |
6386 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED)) { |
6387 | | /* |
6388 | | * The response was signed, but not supported |
6389 | | * |
6390 | | * This is returned by the NTVFS based Samba 4.x file server |
6391 | | * for ipc shares. |
6392 | | */ |
6393 | 0 | tevent_req_done(req); |
6394 | 0 | return; |
6395 | 0 | } |
6396 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) { |
6397 | | /* |
6398 | | * The response was signed, but not supported |
6399 | | * |
6400 | | * This might be returned by older Windows versions or by |
6401 | | * NetApp SMB server implementations. |
6402 | | * |
6403 | | * See |
6404 | | * |
6405 | | * https://blogs.msdn.microsoft.com/openspecification/2012/06/28/smb3-secure-dialect-negotiation/ |
6406 | | * |
6407 | | */ |
6408 | 0 | tevent_req_done(req); |
6409 | 0 | return; |
6410 | 0 | } |
6411 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { |
6412 | | /* |
6413 | | * The response was signed, but not supported |
6414 | | * |
6415 | | * This might be returned by NetApp Ontap 7.3.7 SMB server |
6416 | | * implementations. |
6417 | | * |
6418 | | * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607 |
6419 | | * |
6420 | | */ |
6421 | 0 | tevent_req_done(req); |
6422 | 0 | return; |
6423 | 0 | } |
6424 | 0 | if (tevent_req_nterror(req, status)) { |
6425 | 0 | return; |
6426 | 0 | } |
6427 | | |
6428 | 0 | if (state->out_output_buffer.length != 24) { |
6429 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); |
6430 | 0 | return; |
6431 | 0 | } |
6432 | | |
6433 | 0 | buf = state->out_output_buffer.data; |
6434 | |
|
6435 | 0 | capabilities = IVAL(buf, 0); |
6436 | 0 | guid_blob = data_blob_const(buf + 4, 16); |
6437 | 0 | status = GUID_from_data_blob(&guid_blob, &server_guid); |
6438 | 0 | if (tevent_req_nterror(req, status)) { |
6439 | 0 | return; |
6440 | 0 | } |
6441 | 0 | security_mode = CVAL(buf, 20); |
6442 | 0 | dialect = SVAL(buf, 22); |
6443 | |
|
6444 | 0 | if (capabilities != state->conn->smb2.server.capabilities) { |
6445 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
6446 | 0 | return; |
6447 | 0 | } |
6448 | | |
6449 | 0 | if (!GUID_equal(&server_guid, &state->conn->smb2.server.guid)) { |
6450 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
6451 | 0 | return; |
6452 | 0 | } |
6453 | | |
6454 | 0 | if (security_mode != state->conn->smb2.server.security_mode) { |
6455 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
6456 | 0 | return; |
6457 | 0 | } |
6458 | | |
6459 | 0 | if (dialect != state->dialect) { |
6460 | 0 | tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); |
6461 | 0 | return; |
6462 | 0 | } |
6463 | | |
6464 | 0 | tevent_req_done(req); |
6465 | 0 | } |
6466 | | |
6467 | | NTSTATUS smb2cli_validate_negotiate_info_recv(struct tevent_req *req) |
6468 | 0 | { |
6469 | 0 | return tevent_req_simple_recv_ntstatus(req); |
6470 | 0 | } |
6471 | | |
6472 | | static int smbXcli_session_destructor(struct smbXcli_session *session) |
6473 | 0 | { |
6474 | 0 | if (session->conn == NULL) { |
6475 | 0 | return 0; |
6476 | 0 | } |
6477 | | |
6478 | 0 | DLIST_REMOVE(session->conn->sessions, session); |
6479 | 0 | return 0; |
6480 | 0 | } |
6481 | | |
6482 | | struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx, |
6483 | | struct smbXcli_conn *conn) |
6484 | 0 | { |
6485 | 0 | struct smbXcli_session *session; |
6486 | 0 | NTSTATUS status; |
6487 | |
|
6488 | 0 | session = talloc_zero(mem_ctx, struct smbXcli_session); |
6489 | 0 | if (session == NULL) { |
6490 | 0 | return NULL; |
6491 | 0 | } |
6492 | 0 | session->smb2 = talloc_zero(session, struct smb2cli_session); |
6493 | 0 | if (session->smb2 == NULL) { |
6494 | 0 | talloc_free(session); |
6495 | 0 | return NULL; |
6496 | 0 | } |
6497 | 0 | talloc_set_destructor(session, smbXcli_session_destructor); |
6498 | |
|
6499 | 0 | status = smb2_signing_key_sign_create(session->smb2, |
6500 | 0 | conn->smb2.server.sign_algo, |
6501 | 0 | NULL, /* no master key */ |
6502 | 0 | NULL, /* derivations */ |
6503 | 0 | &session->smb2->signing_key); |
6504 | 0 | if (!NT_STATUS_IS_OK(status)) { |
6505 | 0 | talloc_free(session); |
6506 | 0 | return NULL; |
6507 | 0 | } |
6508 | | |
6509 | 0 | DLIST_ADD_END(conn->sessions, session); |
6510 | 0 | session->conn = conn; |
6511 | |
|
6512 | 0 | status = smb2_signing_key_sign_create(session, |
6513 | 0 | conn->smb2.server.sign_algo, |
6514 | 0 | NULL, /* no master key */ |
6515 | 0 | NULL, /* derivations */ |
6516 | 0 | &session->smb2_channel.signing_key); |
6517 | 0 | if (!NT_STATUS_IS_OK(status)) { |
6518 | 0 | talloc_free(session); |
6519 | 0 | return NULL; |
6520 | 0 | } |
6521 | | |
6522 | 0 | memcpy(session->smb2_channel.preauth_sha512, |
6523 | 0 | conn->smb2.preauth_sha512, |
6524 | 0 | sizeof(session->smb2_channel.preauth_sha512)); |
6525 | |
|
6526 | 0 | return session; |
6527 | 0 | } |
6528 | | |
6529 | | struct smbXcli_session *smbXcli_session_shallow_copy(TALLOC_CTX *mem_ctx, |
6530 | | struct smbXcli_session *src) |
6531 | 0 | { |
6532 | 0 | struct smbXcli_session *session; |
6533 | 0 | struct timespec ts; |
6534 | 0 | NTTIME nt; |
6535 | |
|
6536 | 0 | session = talloc_zero(mem_ctx, struct smbXcli_session); |
6537 | 0 | if (session == NULL) { |
6538 | 0 | return NULL; |
6539 | 0 | } |
6540 | 0 | session->smb2 = talloc_zero(session, struct smb2cli_session); |
6541 | 0 | if (session->smb2 == NULL) { |
6542 | 0 | talloc_free(session); |
6543 | 0 | return NULL; |
6544 | 0 | } |
6545 | | |
6546 | | /* |
6547 | | * Note we keep a pointer to the session keys of the |
6548 | | * main session and rely on the caller to free the |
6549 | | * shallow copy first! |
6550 | | */ |
6551 | 0 | session->conn = src->conn; |
6552 | 0 | *session->smb2 = *src->smb2; |
6553 | 0 | session->smb2_channel = src->smb2_channel; |
6554 | 0 | session->disconnect_expired = src->disconnect_expired; |
6555 | | |
6556 | | /* |
6557 | | * This is only supposed to be called in test code |
6558 | | * but we should not reuse nonces! |
6559 | | * |
6560 | | * Add the current timestamp as NTTIME to nonce_high |
6561 | | * and set nonce_low to a value we can recognize in captures. |
6562 | | */ |
6563 | 0 | clock_gettime_mono(&ts); |
6564 | 0 | nt = unix_timespec_to_nt_time(ts); |
6565 | 0 | nt &= session->smb2->nonce_high_max; |
6566 | 0 | if (nt == session->smb2->nonce_high_max || nt < UINT8_MAX) { |
6567 | 0 | talloc_free(session); |
6568 | 0 | return NULL; |
6569 | 0 | } |
6570 | 0 | session->smb2->nonce_high += nt; |
6571 | 0 | session->smb2->nonce_low = UINT32_MAX; |
6572 | |
|
6573 | 0 | DLIST_ADD_END(src->conn->sessions, session); |
6574 | 0 | talloc_set_destructor(session, smbXcli_session_destructor); |
6575 | |
|
6576 | 0 | return session; |
6577 | 0 | } |
6578 | | |
6579 | | bool smbXcli_session_is_guest(struct smbXcli_session *session) |
6580 | 0 | { |
6581 | 0 | if (session == NULL) { |
6582 | 0 | return false; |
6583 | 0 | } |
6584 | | |
6585 | 0 | if (session->conn == NULL) { |
6586 | 0 | return false; |
6587 | 0 | } |
6588 | | |
6589 | 0 | if (session->conn->mandatory_signing) { |
6590 | 0 | return false; |
6591 | 0 | } |
6592 | | |
6593 | 0 | if (session->conn->protocol >= PROTOCOL_SMB2_02) { |
6594 | 0 | if (session->smb2->session_flags & SMB2_SESSION_FLAG_IS_GUEST) { |
6595 | 0 | return true; |
6596 | 0 | } |
6597 | 0 | return false; |
6598 | 0 | } |
6599 | | |
6600 | 0 | if (session->smb1.action & SMB_SETUP_GUEST) { |
6601 | 0 | return true; |
6602 | 0 | } |
6603 | | |
6604 | 0 | return false; |
6605 | 0 | } |
6606 | | |
6607 | | bool smbXcli_session_is_authenticated(struct smbXcli_session *session) |
6608 | 0 | { |
6609 | 0 | const DATA_BLOB *application_key; |
6610 | |
|
6611 | 0 | if (session == NULL) { |
6612 | 0 | return false; |
6613 | 0 | } |
6614 | | |
6615 | 0 | if (session->conn == NULL) { |
6616 | 0 | return false; |
6617 | 0 | } |
6618 | | |
6619 | | /* |
6620 | | * If we have an application key we had a session key negotiated |
6621 | | * at auth time. |
6622 | | */ |
6623 | 0 | if (session->conn->protocol >= PROTOCOL_SMB2_02) { |
6624 | 0 | if (!smb2_signing_key_valid(session->smb2->application_key)) { |
6625 | 0 | return false; |
6626 | 0 | } |
6627 | 0 | application_key = &session->smb2->application_key->blob; |
6628 | 0 | } else { |
6629 | 0 | application_key = &session->smb1.application_key; |
6630 | 0 | } |
6631 | | |
6632 | 0 | if (application_key->length == 0) { |
6633 | 0 | return false; |
6634 | 0 | } |
6635 | | |
6636 | 0 | return true; |
6637 | 0 | } |
6638 | | |
6639 | | NTSTATUS smb2cli_session_signing_key(struct smbXcli_session *session, |
6640 | | TALLOC_CTX *mem_ctx, |
6641 | | DATA_BLOB *key) |
6642 | 0 | { |
6643 | 0 | const struct smb2_signing_key *sig = NULL; |
6644 | |
|
6645 | 0 | if (session->conn == NULL) { |
6646 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6647 | 0 | } |
6648 | | |
6649 | | /* |
6650 | | * Use channel signing key if there is one, otherwise fallback |
6651 | | * to session. |
6652 | | */ |
6653 | | |
6654 | 0 | if (smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
6655 | 0 | sig = session->smb2_channel.signing_key; |
6656 | 0 | } else if (smb2_signing_key_valid(session->smb2->signing_key)) { |
6657 | 0 | sig = session->smb2->signing_key; |
6658 | 0 | } else { |
6659 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6660 | 0 | } |
6661 | | |
6662 | 0 | *key = data_blob_dup_talloc_s(mem_ctx, sig->blob); |
6663 | 0 | if (key->data == NULL) { |
6664 | 0 | return NT_STATUS_NO_MEMORY; |
6665 | 0 | } |
6666 | | |
6667 | 0 | return NT_STATUS_OK; |
6668 | 0 | } |
6669 | | |
6670 | | NTSTATUS smb2cli_session_encryption_key(struct smbXcli_session *session, |
6671 | | TALLOC_CTX *mem_ctx, |
6672 | | DATA_BLOB *key) |
6673 | 0 | { |
6674 | 0 | if (session->conn == NULL) { |
6675 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6676 | 0 | } |
6677 | | |
6678 | 0 | if (session->conn->protocol < PROTOCOL_SMB3_00) { |
6679 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6680 | 0 | } |
6681 | | |
6682 | 0 | if (!smb2_signing_key_valid(session->smb2->encryption_key)) { |
6683 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6684 | 0 | } |
6685 | | |
6686 | 0 | *key = data_blob_dup_talloc_s(mem_ctx, |
6687 | 0 | session->smb2->encryption_key->blob); |
6688 | 0 | if (key->data == NULL) { |
6689 | 0 | return NT_STATUS_NO_MEMORY; |
6690 | 0 | } |
6691 | | |
6692 | 0 | return NT_STATUS_OK; |
6693 | 0 | } |
6694 | | |
6695 | | NTSTATUS smb2cli_session_decryption_key(struct smbXcli_session *session, |
6696 | | TALLOC_CTX *mem_ctx, |
6697 | | DATA_BLOB *key) |
6698 | 0 | { |
6699 | 0 | if (session->conn == NULL) { |
6700 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6701 | 0 | } |
6702 | | |
6703 | 0 | if (session->conn->protocol < PROTOCOL_SMB3_00) { |
6704 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6705 | 0 | } |
6706 | | |
6707 | 0 | if (!smb2_signing_key_valid(session->smb2->decryption_key)) { |
6708 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6709 | 0 | } |
6710 | | |
6711 | 0 | *key = data_blob_dup_talloc_s(mem_ctx, |
6712 | 0 | session->smb2->decryption_key->blob); |
6713 | 0 | if (key->data == NULL) { |
6714 | 0 | return NT_STATUS_NO_MEMORY; |
6715 | 0 | } |
6716 | | |
6717 | 0 | return NT_STATUS_OK; |
6718 | 0 | } |
6719 | | |
6720 | | NTSTATUS smbXcli_session_application_key(struct smbXcli_session *session, |
6721 | | TALLOC_CTX *mem_ctx, |
6722 | | DATA_BLOB *key) |
6723 | 0 | { |
6724 | 0 | const DATA_BLOB *application_key; |
6725 | |
|
6726 | 0 | *key = data_blob_null; |
6727 | |
|
6728 | 0 | if (session->conn == NULL) { |
6729 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6730 | 0 | } |
6731 | | |
6732 | 0 | if (session->conn->protocol >= PROTOCOL_SMB2_02) { |
6733 | 0 | if (!smb2_signing_key_valid(session->smb2->application_key)) { |
6734 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6735 | 0 | } |
6736 | 0 | application_key = &session->smb2->application_key->blob; |
6737 | 0 | } else { |
6738 | 0 | application_key = &session->smb1.application_key; |
6739 | 0 | } |
6740 | | |
6741 | 0 | if (application_key->length == 0) { |
6742 | 0 | return NT_STATUS_NO_USER_SESSION_KEY; |
6743 | 0 | } |
6744 | | |
6745 | 0 | *key = data_blob_dup_talloc_s(mem_ctx, *application_key); |
6746 | 0 | if (key->data == NULL) { |
6747 | 0 | return NT_STATUS_NO_MEMORY; |
6748 | 0 | } |
6749 | | |
6750 | 0 | return NT_STATUS_OK; |
6751 | 0 | } |
6752 | | |
6753 | | void smbXcli_session_set_disconnect_expired(struct smbXcli_session *session) |
6754 | 0 | { |
6755 | 0 | session->disconnect_expired = true; |
6756 | 0 | } |
6757 | | |
6758 | | uint16_t smb1cli_session_current_id(struct smbXcli_session *session) |
6759 | 0 | { |
6760 | 0 | return session->smb1.session_id; |
6761 | 0 | } |
6762 | | |
6763 | | void smb1cli_session_set_id(struct smbXcli_session *session, |
6764 | | uint16_t session_id) |
6765 | 0 | { |
6766 | 0 | session->smb1.session_id = session_id; |
6767 | 0 | } |
6768 | | |
6769 | | void smb1cli_session_set_action(struct smbXcli_session *session, |
6770 | | uint16_t action) |
6771 | 0 | { |
6772 | 0 | session->smb1.action = action; |
6773 | 0 | } |
6774 | | |
6775 | | NTSTATUS smb1cli_session_set_session_key(struct smbXcli_session *session, |
6776 | | const DATA_BLOB _session_key) |
6777 | 0 | { |
6778 | 0 | struct smbXcli_conn *conn = session->conn; |
6779 | 0 | uint8_t session_key[16]; |
6780 | |
|
6781 | 0 | if (conn == NULL) { |
6782 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
6783 | 0 | } |
6784 | | |
6785 | 0 | if (session->smb1.application_key.length != 0) { |
6786 | | /* |
6787 | | * TODO: do not allow this... |
6788 | | * |
6789 | | * return NT_STATUS_INVALID_PARAMETER_MIX; |
6790 | | */ |
6791 | 0 | data_blob_clear_free(&session->smb1.application_key); |
6792 | 0 | session->smb1.protected_key = false; |
6793 | 0 | } |
6794 | |
|
6795 | 0 | if (_session_key.length == 0) { |
6796 | 0 | return NT_STATUS_OK; |
6797 | 0 | } |
6798 | | |
6799 | 0 | ZERO_STRUCT(session_key); |
6800 | 0 | memcpy(session_key, _session_key.data, |
6801 | 0 | MIN(_session_key.length, sizeof(session_key))); |
6802 | |
|
6803 | 0 | session->smb1.application_key = data_blob_talloc_s( |
6804 | 0 | session, session_key, sizeof(session_key)); |
6805 | 0 | ZERO_STRUCT(session_key); |
6806 | 0 | if (session->smb1.application_key.data == NULL) { |
6807 | 0 | return NT_STATUS_NO_MEMORY; |
6808 | 0 | } |
6809 | | |
6810 | 0 | session->smb1.protected_key = false; |
6811 | |
|
6812 | 0 | return NT_STATUS_OK; |
6813 | 0 | } |
6814 | | |
6815 | | NTSTATUS smb1cli_session_protect_session_key(struct smbXcli_session *session) |
6816 | 0 | { |
6817 | 0 | NTSTATUS status; |
6818 | |
|
6819 | 0 | if (session->smb1.protected_key) { |
6820 | | /* already protected */ |
6821 | 0 | return NT_STATUS_OK; |
6822 | 0 | } |
6823 | | |
6824 | 0 | if (session->smb1.application_key.length != 16) { |
6825 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
6826 | 0 | } |
6827 | | |
6828 | 0 | status = smb1_key_derivation(session->smb1.application_key.data, |
6829 | 0 | session->smb1.application_key.length, |
6830 | 0 | session->smb1.application_key.data); |
6831 | 0 | if (!NT_STATUS_IS_OK(status)) { |
6832 | 0 | return status; |
6833 | 0 | } |
6834 | | |
6835 | 0 | session->smb1.protected_key = true; |
6836 | |
|
6837 | 0 | return NT_STATUS_OK; |
6838 | 0 | } |
6839 | | |
6840 | | uint8_t smb2cli_session_security_mode(struct smbXcli_session *session) |
6841 | 0 | { |
6842 | 0 | struct smbXcli_conn *conn = session->conn; |
6843 | 0 | uint8_t security_mode = 0; |
6844 | |
|
6845 | 0 | if (conn == NULL) { |
6846 | 0 | return security_mode; |
6847 | 0 | } |
6848 | | |
6849 | 0 | security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED; |
6850 | 0 | if (conn->mandatory_signing) { |
6851 | 0 | security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; |
6852 | 0 | } |
6853 | 0 | if (session->smb2->should_sign) { |
6854 | 0 | security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; |
6855 | 0 | } |
6856 | |
|
6857 | 0 | return security_mode; |
6858 | 0 | } |
6859 | | |
6860 | | uint64_t smb2cli_session_current_id(struct smbXcli_session *session) |
6861 | 0 | { |
6862 | 0 | return session->smb2->session_id; |
6863 | 0 | } |
6864 | | |
6865 | | uint16_t smb2cli_session_get_flags(struct smbXcli_session *session) |
6866 | 0 | { |
6867 | 0 | return session->smb2->session_flags; |
6868 | 0 | } |
6869 | | |
6870 | | void smb2cli_session_set_id_and_flags(struct smbXcli_session *session, |
6871 | | uint64_t session_id, |
6872 | | uint16_t session_flags) |
6873 | 0 | { |
6874 | 0 | session->smb2->session_id = session_id; |
6875 | 0 | session->smb2->session_flags = session_flags; |
6876 | 0 | } |
6877 | | |
6878 | | void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session) |
6879 | 0 | { |
6880 | 0 | session->smb2->channel_sequence += 1; |
6881 | 0 | } |
6882 | | |
6883 | | uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session, |
6884 | | uint16_t channel_sequence) |
6885 | 0 | { |
6886 | 0 | uint16_t prev_cs; |
6887 | |
|
6888 | 0 | prev_cs = session->smb2->channel_sequence; |
6889 | 0 | session->smb2->channel_sequence = channel_sequence; |
6890 | |
|
6891 | 0 | return prev_cs; |
6892 | 0 | } |
6893 | | |
6894 | | uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session) |
6895 | 0 | { |
6896 | 0 | return session->smb2->channel_sequence; |
6897 | 0 | } |
6898 | | |
6899 | | void smb2cli_session_start_replay(struct smbXcli_session *session) |
6900 | 0 | { |
6901 | 0 | session->smb2->replay_active = true; |
6902 | 0 | } |
6903 | | |
6904 | | void smb2cli_session_stop_replay(struct smbXcli_session *session) |
6905 | 0 | { |
6906 | 0 | session->smb2->replay_active = false; |
6907 | 0 | } |
6908 | | |
6909 | | void smb2cli_session_require_signed_response(struct smbXcli_session *session, |
6910 | | bool require_signed_response) |
6911 | 0 | { |
6912 | 0 | session->smb2->require_signed_response = require_signed_response; |
6913 | 0 | } |
6914 | | |
6915 | | void smb2cli_session_torture_anonymous_signing(struct smbXcli_session *session, |
6916 | | bool anonymous_signing) |
6917 | 0 | { |
6918 | 0 | session->smb2->anonymous_signing = anonymous_signing; |
6919 | 0 | } |
6920 | | |
6921 | | void smb2cli_session_torture_anonymous_encryption(struct smbXcli_session *session, |
6922 | | bool anonymous_encryption) |
6923 | 0 | { |
6924 | 0 | session->smb2->anonymous_encryption = anonymous_encryption; |
6925 | 0 | } |
6926 | | |
6927 | | void smb2cli_session_torture_no_signing_disconnect(struct smbXcli_session *session) |
6928 | 0 | { |
6929 | 0 | session->smb2->no_signing_disconnect = true; |
6930 | 0 | } |
6931 | | |
6932 | | NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session, |
6933 | | const struct iovec *iov) |
6934 | 0 | { |
6935 | 0 | gnutls_hash_hd_t hash_hnd = NULL; |
6936 | 0 | size_t i; |
6937 | 0 | int rc; |
6938 | |
|
6939 | 0 | if (session->conn == NULL) { |
6940 | 0 | return NT_STATUS_INTERNAL_ERROR; |
6941 | 0 | } |
6942 | | |
6943 | 0 | if (session->conn->protocol < PROTOCOL_SMB3_11) { |
6944 | 0 | return NT_STATUS_OK; |
6945 | 0 | } |
6946 | | |
6947 | 0 | if (smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
6948 | 0 | return NT_STATUS_OK; |
6949 | 0 | } |
6950 | | |
6951 | 0 | rc = gnutls_hash_init(&hash_hnd, |
6952 | 0 | GNUTLS_DIG_SHA512); |
6953 | 0 | if (rc < 0) { |
6954 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
6955 | 0 | } |
6956 | | |
6957 | 0 | rc = gnutls_hash(hash_hnd, |
6958 | 0 | session->smb2_channel.preauth_sha512, |
6959 | 0 | sizeof(session->smb2_channel.preauth_sha512)); |
6960 | 0 | if (rc < 0) { |
6961 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6962 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
6963 | 0 | } |
6964 | 0 | for (i = 0; i < 3; i++) { |
6965 | 0 | rc = gnutls_hash(hash_hnd, |
6966 | 0 | iov[i].iov_base, |
6967 | 0 | iov[i].iov_len); |
6968 | 0 | if (rc < 0) { |
6969 | 0 | gnutls_hash_deinit(hash_hnd, NULL); |
6970 | 0 | return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED); |
6971 | 0 | } |
6972 | 0 | } |
6973 | 0 | gnutls_hash_deinit(hash_hnd, session->smb2_channel.preauth_sha512); |
6974 | |
|
6975 | 0 | return NT_STATUS_OK; |
6976 | 0 | } |
6977 | | |
6978 | | NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session, |
6979 | | const DATA_BLOB _session_key, |
6980 | | const struct iovec *recv_iov) |
6981 | 0 | { |
6982 | 0 | struct smbXcli_conn *conn = session->conn; |
6983 | 0 | uint16_t no_sign_flags = 0; |
6984 | 0 | bool check_signature = true; |
6985 | 0 | uint32_t hdr_flags; |
6986 | 0 | NTSTATUS status; |
6987 | 0 | struct smb2_signing_derivations derivations = { |
6988 | 0 | .signing = NULL, |
6989 | 0 | }; |
6990 | 0 | DATA_BLOB preauth_hash = data_blob_null; |
6991 | 0 | size_t nonce_size = 0; |
6992 | |
|
6993 | 0 | if (conn == NULL) { |
6994 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
6995 | 0 | } |
6996 | | |
6997 | 0 | if (recv_iov[0].iov_len != SMB2_HDR_BODY) { |
6998 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
6999 | 0 | } |
7000 | | |
7001 | 0 | if (!conn->mandatory_signing) { |
7002 | | /* |
7003 | | * only allow guest sessions without |
7004 | | * mandatory signing. |
7005 | | * |
7006 | | * If we try an authentication with username != "" |
7007 | | * and the server let us in without verifying the |
7008 | | * password we don't have a negotiated session key |
7009 | | * for signing. |
7010 | | */ |
7011 | 0 | no_sign_flags = SMB2_SESSION_FLAG_IS_GUEST; |
7012 | 0 | } |
7013 | |
|
7014 | 0 | if (session->smb2->session_flags & no_sign_flags) { |
7015 | 0 | session->smb2->should_sign = false; |
7016 | 0 | return NT_STATUS_OK; |
7017 | 0 | } |
7018 | | |
7019 | 0 | if (smb2_signing_key_valid(session->smb2->signing_key)) { |
7020 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7021 | 0 | } |
7022 | | |
7023 | 0 | if (conn->protocol >= PROTOCOL_SMB3_11) { |
7024 | 0 | preauth_hash = data_blob_const(session->smb2_channel.preauth_sha512, |
7025 | 0 | sizeof(session->smb2_channel.preauth_sha512)); |
7026 | 0 | } |
7027 | |
|
7028 | 0 | smb2_signing_derivations_fill_const_stack(&derivations, |
7029 | 0 | conn->protocol, |
7030 | 0 | preauth_hash); |
7031 | |
|
7032 | 0 | if (session->smb2->anonymous_encryption) { |
7033 | 0 | goto skip_signing_key; |
7034 | 0 | } |
7035 | | |
7036 | 0 | status = smb2_signing_key_sign_create(session->smb2, |
7037 | 0 | conn->smb2.server.sign_algo, |
7038 | 0 | &_session_key, |
7039 | 0 | derivations.signing, |
7040 | 0 | &session->smb2->signing_key); |
7041 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7042 | 0 | return status; |
7043 | 0 | } |
7044 | | |
7045 | 0 | if (session->smb2->anonymous_signing) { |
7046 | | /* |
7047 | | * skip encryption and application keys |
7048 | | */ |
7049 | 0 | goto skip_application_key; |
7050 | 0 | } |
7051 | | |
7052 | 0 | skip_signing_key: |
7053 | |
|
7054 | 0 | status = smb2_signing_key_cipher_create(session->smb2, |
7055 | 0 | conn->smb2.server.cipher, |
7056 | 0 | &_session_key, |
7057 | 0 | derivations.cipher_c2s, |
7058 | 0 | &session->smb2->encryption_key); |
7059 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7060 | 0 | return status; |
7061 | 0 | } |
7062 | | |
7063 | 0 | status = smb2_signing_key_cipher_create(session->smb2, |
7064 | 0 | conn->smb2.server.cipher, |
7065 | 0 | &_session_key, |
7066 | 0 | derivations.cipher_s2c, |
7067 | 0 | &session->smb2->decryption_key); |
7068 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7069 | 0 | return status; |
7070 | 0 | } |
7071 | | |
7072 | 0 | if (session->smb2->anonymous_encryption) { |
7073 | 0 | goto skip_application_key; |
7074 | 0 | } |
7075 | | |
7076 | 0 | status = smb2_signing_key_sign_create(session->smb2, |
7077 | 0 | conn->smb2.server.sign_algo, |
7078 | 0 | &_session_key, |
7079 | 0 | derivations.application, |
7080 | 0 | &session->smb2->application_key); |
7081 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7082 | 0 | return status; |
7083 | 0 | } |
7084 | | |
7085 | 0 | skip_application_key: |
7086 | |
|
7087 | 0 | status = smb2_signing_key_copy(session, |
7088 | 0 | session->smb2->signing_key, |
7089 | 0 | &session->smb2_channel.signing_key); |
7090 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7091 | 0 | return status; |
7092 | 0 | } |
7093 | | |
7094 | 0 | check_signature = conn->mandatory_signing; |
7095 | |
|
7096 | 0 | if (conn->protocol >= PROTOCOL_SMB3_11) { |
7097 | 0 | check_signature = true; |
7098 | 0 | } |
7099 | |
|
7100 | 0 | if (session->smb2->anonymous_signing) { |
7101 | 0 | check_signature = false; |
7102 | 0 | } |
7103 | |
|
7104 | 0 | if (session->smb2->anonymous_encryption) { |
7105 | 0 | check_signature = false; |
7106 | 0 | } |
7107 | |
|
7108 | 0 | hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS); |
7109 | 0 | if (hdr_flags & SMB2_HDR_FLAG_SIGNED) { |
7110 | | /* |
7111 | | * Sadly some vendors don't sign the |
7112 | | * final SMB2 session setup response |
7113 | | * |
7114 | | * At least Windows and Samba are always doing this |
7115 | | * if there's a session key available. |
7116 | | * |
7117 | | * We only check the signature if it's mandatory |
7118 | | * or SMB2_HDR_FLAG_SIGNED is provided. |
7119 | | */ |
7120 | 0 | check_signature = true; |
7121 | 0 | } |
7122 | |
|
7123 | 0 | if (check_signature) { |
7124 | 0 | status = smb2_signing_check_pdu(session->smb2_channel.signing_key, |
7125 | 0 | recv_iov, 3); |
7126 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7127 | 0 | return status; |
7128 | 0 | } |
7129 | 0 | } |
7130 | | |
7131 | 0 | session->smb2->should_sign = false; |
7132 | 0 | session->smb2->should_encrypt = false; |
7133 | |
|
7134 | 0 | if (conn->desire_signing) { |
7135 | 0 | session->smb2->should_sign = true; |
7136 | 0 | } |
7137 | |
|
7138 | 0 | if (conn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) { |
7139 | 0 | session->smb2->should_sign = true; |
7140 | 0 | } |
7141 | |
|
7142 | 0 | if (session->smb2->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) { |
7143 | 0 | session->smb2->should_encrypt = true; |
7144 | 0 | } |
7145 | |
|
7146 | 0 | if (conn->protocol < PROTOCOL_SMB3_00) { |
7147 | 0 | session->smb2->should_encrypt = false; |
7148 | 0 | } |
7149 | |
|
7150 | 0 | if (conn->smb2.server.cipher == 0) { |
7151 | 0 | session->smb2->should_encrypt = false; |
7152 | 0 | } |
7153 | |
|
7154 | 0 | if (session->smb2->anonymous_signing) { |
7155 | 0 | session->smb2->should_sign = true; |
7156 | 0 | } |
7157 | |
|
7158 | 0 | if (session->smb2->anonymous_encryption) { |
7159 | 0 | session->smb2->should_encrypt = true; |
7160 | 0 | session->smb2->should_sign = false; |
7161 | 0 | } |
7162 | | |
7163 | | /* |
7164 | | * CCM and GCM algorithms must never have their |
7165 | | * nonce wrap, or the security of the whole |
7166 | | * communication and the keys is destroyed. |
7167 | | * We must drop the connection once we have |
7168 | | * transferred too much data. |
7169 | | * |
7170 | | * NOTE: We assume nonces greater than 8 bytes. |
7171 | | */ |
7172 | 0 | generate_nonce_buffer((uint8_t *)&session->smb2->nonce_high_random, |
7173 | 0 | sizeof(session->smb2->nonce_high_random)); |
7174 | 0 | switch (conn->smb2.server.cipher) { |
7175 | 0 | case SMB2_ENCRYPTION_AES128_CCM: |
7176 | 0 | nonce_size = SMB2_AES_128_CCM_NONCE_SIZE; |
7177 | 0 | break; |
7178 | 0 | case SMB2_ENCRYPTION_AES128_GCM: |
7179 | 0 | nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_GCM); |
7180 | 0 | break; |
7181 | 0 | case SMB2_ENCRYPTION_AES256_CCM: |
7182 | 0 | nonce_size = SMB2_AES_128_CCM_NONCE_SIZE; |
7183 | 0 | break; |
7184 | 0 | case SMB2_ENCRYPTION_AES256_GCM: |
7185 | 0 | nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_256_GCM); |
7186 | 0 | break; |
7187 | 0 | default: |
7188 | 0 | nonce_size = 0; |
7189 | 0 | break; |
7190 | 0 | } |
7191 | 0 | session->smb2->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size); |
7192 | 0 | session->smb2->nonce_high = 0; |
7193 | 0 | session->smb2->nonce_low = 0; |
7194 | |
|
7195 | 0 | return NT_STATUS_OK; |
7196 | 0 | } |
7197 | | |
7198 | | NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx, |
7199 | | struct smbXcli_session *session1, |
7200 | | struct smbXcli_conn *conn, |
7201 | | struct smbXcli_session **_session2) |
7202 | 0 | { |
7203 | 0 | struct smbXcli_session *session2; |
7204 | 0 | NTSTATUS status; |
7205 | |
|
7206 | 0 | if (!smb2_signing_key_valid(session1->smb2->signing_key)) { |
7207 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7208 | 0 | } |
7209 | | |
7210 | 0 | if (conn == NULL) { |
7211 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7212 | 0 | } |
7213 | | |
7214 | 0 | session2 = talloc_zero(mem_ctx, struct smbXcli_session); |
7215 | 0 | if (session2 == NULL) { |
7216 | 0 | return NT_STATUS_NO_MEMORY; |
7217 | 0 | } |
7218 | 0 | session2->smb2 = talloc_reference(session2, session1->smb2); |
7219 | 0 | if (session2->smb2 == NULL) { |
7220 | 0 | talloc_free(session2); |
7221 | 0 | return NT_STATUS_NO_MEMORY; |
7222 | 0 | } |
7223 | | |
7224 | 0 | talloc_set_destructor(session2, smbXcli_session_destructor); |
7225 | 0 | DLIST_ADD_END(conn->sessions, session2); |
7226 | 0 | session2->conn = conn; |
7227 | |
|
7228 | 0 | status = smb2_signing_key_sign_create(session2, |
7229 | 0 | conn->smb2.server.sign_algo, |
7230 | 0 | NULL, /* no master key */ |
7231 | 0 | NULL, /* derivations */ |
7232 | 0 | &session2->smb2_channel.signing_key); |
7233 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7234 | 0 | talloc_free(session2); |
7235 | 0 | return NT_STATUS_NO_MEMORY; |
7236 | 0 | } |
7237 | | |
7238 | 0 | memcpy(session2->smb2_channel.preauth_sha512, |
7239 | 0 | conn->smb2.preauth_sha512, |
7240 | 0 | sizeof(session2->smb2_channel.preauth_sha512)); |
7241 | |
|
7242 | 0 | *_session2 = session2; |
7243 | 0 | return NT_STATUS_OK; |
7244 | 0 | } |
7245 | | |
7246 | | NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session, |
7247 | | const DATA_BLOB _channel_key, |
7248 | | const struct iovec *recv_iov) |
7249 | 0 | { |
7250 | 0 | struct smbXcli_conn *conn = session->conn; |
7251 | 0 | uint8_t channel_key[16]; |
7252 | 0 | NTSTATUS status; |
7253 | 0 | struct _derivation { |
7254 | 0 | DATA_BLOB label; |
7255 | 0 | DATA_BLOB context; |
7256 | 0 | }; |
7257 | 0 | struct { |
7258 | 0 | struct _derivation signing; |
7259 | 0 | } derivation = { |
7260 | 0 | .signing.label.length = 0, |
7261 | 0 | }; |
7262 | |
|
7263 | 0 | if (conn == NULL) { |
7264 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7265 | 0 | } |
7266 | | |
7267 | 0 | if (smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
7268 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7269 | 0 | } |
7270 | | |
7271 | 0 | if (conn->protocol >= PROTOCOL_SMB3_11) { |
7272 | 0 | struct _derivation *d; |
7273 | 0 | DATA_BLOB p; |
7274 | |
|
7275 | 0 | p = data_blob_const(session->smb2_channel.preauth_sha512, |
7276 | 0 | sizeof(session->smb2_channel.preauth_sha512)); |
7277 | |
|
7278 | 0 | d = &derivation.signing; |
7279 | 0 | d->label = data_blob_string_const_null("SMBSigningKey"); |
7280 | 0 | d->context = p; |
7281 | 0 | } else if (conn->protocol >= PROTOCOL_SMB3_00) { |
7282 | 0 | struct _derivation *d; |
7283 | |
|
7284 | 0 | d = &derivation.signing; |
7285 | 0 | d->label = data_blob_string_const_null("SMB2AESCMAC"); |
7286 | 0 | d->context = data_blob_string_const_null("SmbSign"); |
7287 | 0 | } |
7288 | |
|
7289 | 0 | ZERO_STRUCT(channel_key); |
7290 | 0 | memcpy(channel_key, _channel_key.data, |
7291 | 0 | MIN(_channel_key.length, sizeof(channel_key))); |
7292 | |
|
7293 | 0 | session->smb2_channel.signing_key->blob = data_blob_talloc_s( |
7294 | 0 | session->smb2_channel.signing_key, |
7295 | 0 | channel_key, |
7296 | 0 | sizeof(channel_key)); |
7297 | 0 | if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) { |
7298 | 0 | ZERO_STRUCT(channel_key); |
7299 | 0 | return NT_STATUS_NO_MEMORY; |
7300 | 0 | } |
7301 | | |
7302 | 0 | if (conn->protocol >= PROTOCOL_SMB3_00) { |
7303 | 0 | struct _derivation *d = &derivation.signing; |
7304 | |
|
7305 | 0 | status = samba_gnutls_sp800_108_derive_key( |
7306 | 0 | channel_key, |
7307 | 0 | sizeof(channel_key), |
7308 | 0 | NULL, |
7309 | 0 | 0, |
7310 | 0 | d->label.data, |
7311 | 0 | d->label.length, |
7312 | 0 | d->context.data, |
7313 | 0 | d->context.length, |
7314 | 0 | GNUTLS_MAC_SHA256, |
7315 | 0 | session->smb2_channel.signing_key->blob.data, |
7316 | 0 | session->smb2_channel.signing_key->blob.length); |
7317 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7318 | 0 | return status; |
7319 | 0 | } |
7320 | 0 | } |
7321 | 0 | ZERO_STRUCT(channel_key); |
7322 | |
|
7323 | 0 | status = smb2_signing_check_pdu(session->smb2_channel.signing_key, |
7324 | 0 | recv_iov, 3); |
7325 | 0 | if (!NT_STATUS_IS_OK(status)) { |
7326 | 0 | return status; |
7327 | 0 | } |
7328 | | |
7329 | 0 | return NT_STATUS_OK; |
7330 | 0 | } |
7331 | | |
7332 | | NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session) |
7333 | 0 | { |
7334 | 0 | if (session->smb2->anonymous_signing) { |
7335 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7336 | 0 | } |
7337 | | |
7338 | 0 | if (session->smb2->anonymous_encryption) { |
7339 | 0 | SMB_ASSERT(session->smb2->should_encrypt); |
7340 | 0 | SMB_ASSERT(!session->smb2->should_sign); |
7341 | 0 | return NT_STATUS_OK; |
7342 | 0 | } |
7343 | | |
7344 | 0 | if (!session->smb2->should_sign) { |
7345 | | /* |
7346 | | * We need required signing on the session |
7347 | | * in order to prevent man in the middle attacks. |
7348 | | */ |
7349 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
7350 | 0 | } |
7351 | | |
7352 | 0 | if (session->smb2->should_encrypt) { |
7353 | 0 | return NT_STATUS_OK; |
7354 | 0 | } |
7355 | | |
7356 | 0 | if (session->conn->protocol < PROTOCOL_SMB3_00) { |
7357 | 0 | return NT_STATUS_NOT_SUPPORTED; |
7358 | 0 | } |
7359 | | |
7360 | 0 | if (session->conn->smb2.server.cipher == 0) { |
7361 | 0 | return NT_STATUS_NOT_SUPPORTED; |
7362 | 0 | } |
7363 | | |
7364 | 0 | if (!smb2_signing_key_valid(session->smb2->signing_key)) { |
7365 | 0 | return NT_STATUS_NOT_SUPPORTED; |
7366 | 0 | } |
7367 | 0 | session->smb2->should_encrypt = true; |
7368 | 0 | return NT_STATUS_OK; |
7369 | 0 | } |
7370 | | |
7371 | | uint16_t smb2cli_session_get_encryption_cipher(struct smbXcli_session *session) |
7372 | 0 | { |
7373 | 0 | if (session->conn->protocol < PROTOCOL_SMB3_00) { |
7374 | 0 | return 0; |
7375 | 0 | } |
7376 | | |
7377 | 0 | if (!session->smb2->should_encrypt) { |
7378 | 0 | return 0; |
7379 | 0 | } |
7380 | | |
7381 | 0 | return session->conn->smb2.server.cipher; |
7382 | 0 | } |
7383 | | |
7384 | | struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx) |
7385 | 0 | { |
7386 | 0 | struct smbXcli_tcon *tcon; |
7387 | |
|
7388 | 0 | tcon = talloc_zero(mem_ctx, struct smbXcli_tcon); |
7389 | 0 | if (tcon == NULL) { |
7390 | 0 | return NULL; |
7391 | 0 | } |
7392 | | |
7393 | 0 | return tcon; |
7394 | 0 | } |
7395 | | |
7396 | | /* |
7397 | | * Return a deep structure copy of a struct smbXcli_tcon * |
7398 | | */ |
7399 | | |
7400 | | struct smbXcli_tcon *smbXcli_tcon_copy(TALLOC_CTX *mem_ctx, |
7401 | | const struct smbXcli_tcon *tcon_in) |
7402 | 0 | { |
7403 | 0 | struct smbXcli_tcon *tcon; |
7404 | |
|
7405 | 0 | tcon = talloc_memdup(mem_ctx, tcon_in, sizeof(struct smbXcli_tcon)); |
7406 | 0 | if (tcon == NULL) { |
7407 | 0 | return NULL; |
7408 | 0 | } |
7409 | | |
7410 | | /* Deal with the SMB1 strings. */ |
7411 | 0 | if (tcon_in->smb1.service != NULL) { |
7412 | 0 | tcon->smb1.service = talloc_strdup(tcon, tcon_in->smb1.service); |
7413 | 0 | if (tcon->smb1.service == NULL) { |
7414 | 0 | TALLOC_FREE(tcon); |
7415 | 0 | return NULL; |
7416 | 0 | } |
7417 | 0 | } |
7418 | 0 | if (tcon->smb1.fs_type != NULL) { |
7419 | 0 | tcon->smb1.fs_type = talloc_strdup(tcon, tcon_in->smb1.fs_type); |
7420 | 0 | if (tcon->smb1.fs_type == NULL) { |
7421 | 0 | TALLOC_FREE(tcon); |
7422 | 0 | return NULL; |
7423 | 0 | } |
7424 | 0 | } |
7425 | 0 | return tcon; |
7426 | 0 | } |
7427 | | |
7428 | | void smbXcli_tcon_set_fs_attributes(struct smbXcli_tcon *tcon, |
7429 | | uint32_t fs_attributes) |
7430 | 0 | { |
7431 | 0 | tcon->fs_attributes = fs_attributes; |
7432 | 0 | } |
7433 | | |
7434 | | uint32_t smbXcli_tcon_get_fs_attributes(struct smbXcli_tcon *tcon) |
7435 | 0 | { |
7436 | 0 | return tcon->fs_attributes; |
7437 | 0 | } |
7438 | | |
7439 | | bool smbXcli_tcon_is_dfs_share(struct smbXcli_tcon *tcon) |
7440 | 0 | { |
7441 | 0 | if (tcon == NULL) { |
7442 | 0 | return false; |
7443 | 0 | } |
7444 | | |
7445 | 0 | if (tcon->is_smb1) { |
7446 | 0 | if (tcon->smb1.optional_support & SMB_SHARE_IN_DFS) { |
7447 | 0 | return true; |
7448 | 0 | } |
7449 | | |
7450 | 0 | return false; |
7451 | 0 | } |
7452 | | |
7453 | 0 | if (tcon->smb2.capabilities & SMB2_SHARE_CAP_DFS) { |
7454 | 0 | return true; |
7455 | 0 | } |
7456 | | |
7457 | 0 | return false; |
7458 | 0 | } |
7459 | | |
7460 | | uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon) |
7461 | 0 | { |
7462 | 0 | return tcon->smb1.tcon_id; |
7463 | 0 | } |
7464 | | |
7465 | | void smb1cli_tcon_set_id(struct smbXcli_tcon *tcon, uint16_t tcon_id) |
7466 | 0 | { |
7467 | 0 | tcon->is_smb1 = true; |
7468 | 0 | tcon->smb1.tcon_id = tcon_id; |
7469 | 0 | } |
7470 | | |
7471 | | bool smb1cli_tcon_set_values(struct smbXcli_tcon *tcon, |
7472 | | uint16_t tcon_id, |
7473 | | uint16_t optional_support, |
7474 | | uint32_t maximal_access, |
7475 | | uint32_t guest_maximal_access, |
7476 | | const char *service, |
7477 | | const char *fs_type) |
7478 | 0 | { |
7479 | 0 | tcon->is_smb1 = true; |
7480 | 0 | tcon->fs_attributes = 0; |
7481 | 0 | tcon->smb1.tcon_id = tcon_id; |
7482 | 0 | tcon->smb1.optional_support = optional_support; |
7483 | 0 | tcon->smb1.maximal_access = maximal_access; |
7484 | 0 | tcon->smb1.guest_maximal_access = guest_maximal_access; |
7485 | |
|
7486 | 0 | TALLOC_FREE(tcon->smb1.service); |
7487 | 0 | tcon->smb1.service = talloc_strdup(tcon, service); |
7488 | 0 | if (service != NULL && tcon->smb1.service == NULL) { |
7489 | 0 | return false; |
7490 | 0 | } |
7491 | | |
7492 | 0 | TALLOC_FREE(tcon->smb1.fs_type); |
7493 | 0 | tcon->smb1.fs_type = talloc_strdup(tcon, fs_type); |
7494 | 0 | if (fs_type != NULL && tcon->smb1.fs_type == NULL) { |
7495 | 0 | return false; |
7496 | 0 | } |
7497 | | |
7498 | 0 | return true; |
7499 | 0 | } |
7500 | | |
7501 | | uint32_t smb2cli_tcon_current_id(struct smbXcli_tcon *tcon) |
7502 | 0 | { |
7503 | 0 | return tcon->smb2.tcon_id; |
7504 | 0 | } |
7505 | | |
7506 | | void smb2cli_tcon_set_id(struct smbXcli_tcon *tcon, uint32_t tcon_id) |
7507 | 0 | { |
7508 | 0 | tcon->smb2.tcon_id = tcon_id; |
7509 | 0 | } |
7510 | | |
7511 | | uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon) |
7512 | 0 | { |
7513 | 0 | return tcon->smb2.capabilities; |
7514 | 0 | } |
7515 | | |
7516 | | uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon) |
7517 | 0 | { |
7518 | 0 | return tcon->smb2.flags; |
7519 | 0 | } |
7520 | | |
7521 | | void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon, |
7522 | | struct smbXcli_session *session, |
7523 | | uint32_t tcon_id, |
7524 | | uint8_t type, |
7525 | | uint32_t flags, |
7526 | | uint32_t capabilities, |
7527 | | uint32_t maximal_access) |
7528 | 0 | { |
7529 | 0 | tcon->is_smb1 = false; |
7530 | 0 | tcon->fs_attributes = 0; |
7531 | 0 | tcon->smb2.tcon_id = tcon_id; |
7532 | 0 | tcon->smb2.type = type; |
7533 | 0 | tcon->smb2.flags = flags; |
7534 | 0 | tcon->smb2.capabilities = capabilities; |
7535 | 0 | tcon->smb2.maximal_access = maximal_access; |
7536 | |
|
7537 | 0 | tcon->smb2.should_sign = false; |
7538 | 0 | tcon->smb2.should_encrypt = false; |
7539 | |
|
7540 | 0 | if (session == NULL) { |
7541 | 0 | return; |
7542 | 0 | } |
7543 | | |
7544 | 0 | tcon->smb2.should_sign = session->smb2->should_sign; |
7545 | 0 | tcon->smb2.should_encrypt = session->smb2->should_encrypt; |
7546 | |
|
7547 | 0 | if (flags & SMB2_SHAREFLAG_ENCRYPT_DATA) { |
7548 | 0 | tcon->smb2.should_encrypt = true; |
7549 | 0 | } |
7550 | 0 | } |
7551 | | |
7552 | | void smb2cli_tcon_should_sign(struct smbXcli_tcon *tcon, |
7553 | | bool should_sign) |
7554 | 0 | { |
7555 | 0 | tcon->smb2.should_sign = should_sign; |
7556 | 0 | } |
7557 | | |
7558 | | bool smb2cli_tcon_is_signing_on(struct smbXcli_tcon *tcon) |
7559 | 0 | { |
7560 | 0 | if (tcon->smb2.should_encrypt) { |
7561 | 0 | return true; |
7562 | 0 | } |
7563 | | |
7564 | 0 | return tcon->smb2.should_sign; |
7565 | 0 | } |
7566 | | |
7567 | | void smb2cli_tcon_should_encrypt(struct smbXcli_tcon *tcon, |
7568 | | bool should_encrypt) |
7569 | 0 | { |
7570 | 0 | tcon->smb2.should_encrypt = should_encrypt; |
7571 | 0 | } |
7572 | | |
7573 | | bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon) |
7574 | 0 | { |
7575 | 0 | return tcon->smb2.should_encrypt; |
7576 | 0 | } |
7577 | | |
7578 | | void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid) |
7579 | 0 | { |
7580 | 0 | conn->smb2.mid = mid; |
7581 | 0 | } |
7582 | | |
7583 | | uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn) |
7584 | 0 | { |
7585 | 0 | return conn->smb2.mid; |
7586 | 0 | } |
7587 | | |
7588 | | NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset, |
7589 | | const DATA_BLOB dyn_buffer, |
7590 | | uint32_t min_offset, |
7591 | | uint32_t buffer_offset, |
7592 | | uint32_t buffer_length, |
7593 | | uint32_t max_length, |
7594 | | uint32_t *next_offset, |
7595 | | DATA_BLOB *buffer) |
7596 | 0 | { |
7597 | 0 | uint32_t offset; |
7598 | 0 | bool oob; |
7599 | |
|
7600 | 0 | *buffer = data_blob_null; |
7601 | 0 | *next_offset = dyn_offset; |
7602 | |
|
7603 | 0 | if (buffer_offset == 0) { |
7604 | | /* |
7605 | | * If the offset is 0, we better ignore |
7606 | | * the buffer_length field. |
7607 | | */ |
7608 | 0 | return NT_STATUS_OK; |
7609 | 0 | } |
7610 | | |
7611 | 0 | if (buffer_length == 0) { |
7612 | | /* |
7613 | | * If the length is 0, we better ignore |
7614 | | * the buffer_offset field. |
7615 | | */ |
7616 | 0 | return NT_STATUS_OK; |
7617 | 0 | } |
7618 | | |
7619 | 0 | if ((buffer_offset % 8) != 0) { |
7620 | | /* |
7621 | | * The offset needs to be 8 byte aligned. |
7622 | | */ |
7623 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
7624 | 0 | } |
7625 | | |
7626 | | /* |
7627 | | * We used to enforce buffer_offset to be |
7628 | | * an exact match of the expected minimum, |
7629 | | * but the NetApp Ontap 7.3.7 SMB server |
7630 | | * gets the padding wrong and aligns the |
7631 | | * input_buffer_offset by a value of 8. |
7632 | | * |
7633 | | * So we just enforce that the offset is |
7634 | | * not lower than the expected value. |
7635 | | */ |
7636 | 0 | SMB_ASSERT(min_offset >= dyn_offset); |
7637 | 0 | if (buffer_offset < min_offset) { |
7638 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
7639 | 0 | } |
7640 | | |
7641 | | /* |
7642 | | * Make [input|output]_buffer_offset relative to "dyn_buffer" |
7643 | | */ |
7644 | 0 | offset = buffer_offset - dyn_offset; |
7645 | 0 | oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length); |
7646 | 0 | if (oob) { |
7647 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
7648 | 0 | } |
7649 | | |
7650 | | /* |
7651 | | * Give the caller a hint what we consumed, |
7652 | | * the caller may need to add possible padding. |
7653 | | */ |
7654 | 0 | *next_offset = buffer_offset + buffer_length; |
7655 | |
|
7656 | 0 | if (max_length == 0) { |
7657 | | /* |
7658 | | * If max_input_length is 0 we ignore the |
7659 | | * input_buffer_length, because Windows 2008 echos the |
7660 | | * DCERPC request from the requested input_buffer to |
7661 | | * the response input_buffer. |
7662 | | * |
7663 | | * We just use the same logic also for max_output_length... |
7664 | | */ |
7665 | 0 | buffer_length = 0; |
7666 | 0 | } |
7667 | |
|
7668 | 0 | if (buffer_length > max_length) { |
7669 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
7670 | 0 | } |
7671 | | |
7672 | 0 | *buffer = (DATA_BLOB) { |
7673 | 0 | .data = dyn_buffer.data + offset, |
7674 | 0 | .length = buffer_length, |
7675 | 0 | }; |
7676 | 0 | return NT_STATUS_OK; |
7677 | 0 | } |
7678 | | |
7679 | | struct smbXcli_session_dump_cp_state { |
7680 | | char *s; |
7681 | | }; |
7682 | | |
7683 | | static void smbXcli_session_dump_keys_cb(const char *buf, void *private_data) |
7684 | 0 | { |
7685 | 0 | struct smbXcli_session_dump_cp_state *state = private_data; |
7686 | |
|
7687 | 0 | talloc_asprintf_addbuf(&state->s, "%s", buf); |
7688 | 0 | } |
7689 | | |
7690 | | void smbXcli_session_dump_keys(uint64_t session_id, |
7691 | | DATA_BLOB *session_key, |
7692 | | uint16_t signing_algo, |
7693 | | DATA_BLOB *signing_key, |
7694 | | DATA_BLOB *application_key, |
7695 | | DATA_BLOB *encryption_key, |
7696 | | DATA_BLOB *decryption_key, |
7697 | | const char *wireshark_keyfile) |
7698 | 0 | { |
7699 | 0 | struct smbXcli_session_dump_cp_state state = { |
7700 | 0 | .s = talloc_strdup(talloc_tos(), ""), |
7701 | 0 | }; |
7702 | 0 | DATA_BLOB sidb = { |
7703 | 0 | .data = (uint8_t *)&session_id, .length = sizeof(session_id) |
7704 | 0 | }; |
7705 | 0 | char *line = NULL; |
7706 | 0 | int fd = -1; |
7707 | 0 | ssize_t written; |
7708 | |
|
7709 | 0 | talloc_asprintf_addbuf(&state.s, "debug encryption: dumping generated session keys\n"); |
7710 | 0 | talloc_asprintf_addbuf(&state.s, "Session Id "); |
7711 | 0 | dump_data_cb((uint8_t*)&session_id, |
7712 | 0 | sizeof(session_id), |
7713 | 0 | false, |
7714 | 0 | smbXcli_session_dump_keys_cb, |
7715 | 0 | &state); |
7716 | 0 | talloc_asprintf_addbuf(&state.s, "Session Key "); |
7717 | 0 | dump_data_cb(session_key->data, |
7718 | 0 | session_key->length, |
7719 | 0 | false, |
7720 | 0 | smbXcli_session_dump_keys_cb, |
7721 | 0 | &state); |
7722 | 0 | talloc_asprintf_addbuf(&state.s, "Signing Algo: %u\n", signing_algo); |
7723 | 0 | talloc_asprintf_addbuf(&state.s, "Signing Key "); |
7724 | 0 | dump_data_cb(signing_key->data, |
7725 | 0 | signing_key->length, |
7726 | 0 | false, |
7727 | 0 | smbXcli_session_dump_keys_cb, |
7728 | 0 | &state); |
7729 | 0 | talloc_asprintf_addbuf(&state.s, "App Key "); |
7730 | 0 | dump_data_cb(application_key->data, |
7731 | 0 | application_key->length, |
7732 | 0 | false, |
7733 | 0 | smbXcli_session_dump_keys_cb, |
7734 | 0 | &state); |
7735 | | |
7736 | | /* In client code, ServerIn is the encryption key */ |
7737 | |
|
7738 | 0 | talloc_asprintf_addbuf(&state.s, "ServerIn Key "); |
7739 | 0 | dump_data_cb(encryption_key->data, |
7740 | 0 | encryption_key->length, |
7741 | 0 | false, |
7742 | 0 | smbXcli_session_dump_keys_cb, |
7743 | 0 | &state); |
7744 | 0 | talloc_asprintf_addbuf(&state.s, "ServerOut Key "); |
7745 | 0 | dump_data_cb(decryption_key->data, |
7746 | 0 | decryption_key->length, |
7747 | 0 | false, |
7748 | 0 | smbXcli_session_dump_keys_cb, |
7749 | 0 | &state); |
7750 | |
|
7751 | 0 | talloc_asprintf_addbuf(&state.s, "Wireshark configuration line:\n"); |
7752 | 0 | line = talloc_asprintf( |
7753 | 0 | talloc_tos(), |
7754 | 0 | "%s,%s,%s,%s\n", |
7755 | 0 | data_blob_hex_string_lower(state.s, &sidb), |
7756 | 0 | data_blob_hex_string_lower(state.s, session_key), |
7757 | 0 | data_blob_hex_string_lower(state.s, decryption_key), |
7758 | 0 | data_blob_hex_string_lower(state.s, encryption_key)); |
7759 | 0 | if (line == NULL) { |
7760 | 0 | goto done; |
7761 | 0 | } |
7762 | 0 | talloc_asprintf_addbuf(&state.s, "%s", line); |
7763 | |
|
7764 | 0 | DEBUG(0, ("%s", state.s)); |
7765 | |
|
7766 | 0 | if (wireshark_keyfile == NULL) { |
7767 | 0 | goto done; |
7768 | 0 | } |
7769 | 0 | fd = open(wireshark_keyfile, O_WRONLY | O_APPEND); |
7770 | 0 | if (fd == -1) { |
7771 | 0 | DBG_ERR("Failed to open '%s': %s\n", |
7772 | 0 | wireshark_keyfile, strerror(errno)); |
7773 | 0 | goto done; |
7774 | 0 | } |
7775 | | |
7776 | 0 | written = write(fd, line, strlen(line)); |
7777 | 0 | if (written != strlen(line)) { |
7778 | 0 | DBG_ERR("Failed to write '%s' to '%s', only wrote: %zd\n", |
7779 | 0 | line, wireshark_keyfile, written); |
7780 | 0 | goto done; |
7781 | 0 | } |
7782 | | |
7783 | 0 | done: |
7784 | 0 | TALLOC_FREE(line); |
7785 | 0 | TALLOC_FREE(state.s); |
7786 | 0 | if (fd != -1) { |
7787 | 0 | close(fd); |
7788 | 0 | } |
7789 | 0 | } |