1/* 2 Unix SMB/CIFS implementation. 3 4 SMB2 client transport context management functions 5 6 Copyright (C) Andrew Tridgell 2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "includes.h" 23#include "libcli/raw/libcliraw.h" 24#include "libcli/raw/raw_proto.h" 25#include "libcli/smb2/smb2.h" 26#include "libcli/smb2/smb2_calls.h" 27#include "lib/socket/socket.h" 28#include "lib/events/events.h" 29#include "lib/stream/packet.h" 30#include "../lib/util/dlinklist.h" 31 32 33/* 34 an event has happened on the socket 35*/ 36static void smb2_transport_event_handler(struct tevent_context *ev, 37 struct tevent_fd *fde, 38 uint16_t flags, void *private_data) 39{ 40 struct smb2_transport *transport = talloc_get_type(private_data, 41 struct smb2_transport); 42 if (flags & EVENT_FD_READ) { 43 packet_recv(transport->packet); 44 return; 45 } 46 if (flags & EVENT_FD_WRITE) { 47 packet_queue_run(transport->packet); 48 } 49} 50 51/* 52 destroy a transport 53 */ 54static int transport_destructor(struct smb2_transport *transport) 55{ 56 smb2_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT); 57 return 0; 58} 59 60 61/* 62 handle receive errors 63*/ 64static void smb2_transport_error(void *private_data, NTSTATUS status) 65{ 66 struct smb2_transport *transport = talloc_get_type(private_data, 67 struct smb2_transport); 68 smb2_transport_dead(transport, status); 69} 70 71static NTSTATUS smb2_transport_finish_recv(void *private_data, DATA_BLOB blob); 72 73/* 74 create a transport structure based on an established socket 75*/ 76struct smb2_transport *smb2_transport_init(struct smbcli_socket *sock, 77 TALLOC_CTX *parent_ctx, 78 struct smbcli_options *options) 79{ 80 struct smb2_transport *transport; 81 82 transport = talloc_zero(parent_ctx, struct smb2_transport); 83 if (!transport) return NULL; 84 85 transport->socket = talloc_steal(transport, sock); 86 transport->options = *options; 87 transport->credits.charge = 0; 88 transport->credits.ask_num = 1; 89 90 /* setup the stream -> packet parser */ 91 transport->packet = packet_init(transport); 92 if (transport->packet == NULL) { 93 talloc_free(transport); 94 return NULL; 95 } 96 packet_set_private(transport->packet, transport); 97 packet_set_socket(transport->packet, transport->socket->sock); 98 packet_set_callback(transport->packet, smb2_transport_finish_recv); 99 packet_set_full_request(transport->packet, packet_full_request_nbt); 100 packet_set_error_handler(transport->packet, smb2_transport_error); 101 packet_set_event_context(transport->packet, transport->socket->event.ctx); 102 packet_set_nofree(transport->packet); 103 104 /* take over event handling from the socket layer - it only 105 handles events up until we are connected */ 106 talloc_free(transport->socket->event.fde); 107 transport->socket->event.fde = event_add_fd(transport->socket->event.ctx, 108 transport->socket, 109 socket_get_fd(transport->socket->sock), 110 EVENT_FD_READ, 111 smb2_transport_event_handler, 112 transport); 113 114 packet_set_fde(transport->packet, transport->socket->event.fde); 115 packet_set_serialise(transport->packet); 116 117 talloc_set_destructor(transport, transport_destructor); 118 119 return transport; 120} 121 122/* 123 mark the transport as dead 124*/ 125void smb2_transport_dead(struct smb2_transport *transport, NTSTATUS status) 126{ 127 smbcli_sock_dead(transport->socket); 128 129 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { 130 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; 131 } 132 133 /* kill all pending receives */ 134 while (transport->pending_recv) { 135 struct smb2_request *req = transport->pending_recv; 136 req->state = SMB2_REQUEST_ERROR; 137 req->status = status; 138 DLIST_REMOVE(transport->pending_recv, req); 139 if (req->async.fn) { 140 req->async.fn(req); 141 } 142 } 143} 144 145static NTSTATUS smb2_handle_oplock_break(struct smb2_transport *transport, 146 const DATA_BLOB *blob) 147{ 148 uint8_t *hdr; 149 uint8_t *body; 150 uint16_t len, bloblen; 151 bool lease; 152 153 hdr = blob->data+NBT_HDR_SIZE; 154 body = hdr+SMB2_HDR_BODY; 155 bloblen = blob->length - SMB2_HDR_BODY; 156 157 if (bloblen < 2) { 158 DEBUG(1,("Discarding smb2 oplock reply of size %u\n", 159 (unsigned)blob->length)); 160 return NT_STATUS_INVALID_NETWORK_RESPONSE; 161 } 162 163 len = CVAL(body, 0x00); 164 if (len > bloblen) { 165 DEBUG(1,("Discarding smb2 oplock reply," 166 "packet claims %u byte body, only %u bytes seen\n", 167 len, bloblen)); 168 return NT_STATUS_INVALID_NETWORK_RESPONSE; 169 } 170 171 if (len == 24) { 172 lease = false; 173 } else if (len == 44) { 174 lease = true; 175 } else { 176 DEBUG(1,("Discarding smb2 oplock reply of invalid size %u\n", 177 (unsigned)blob->length)); 178 return NT_STATUS_INVALID_NETWORK_RESPONSE; 179 } 180 181 if (!lease && transport->oplock.handler) { 182 struct smb2_handle h; 183 uint8_t level; 184 185 level = CVAL(body, 0x02); 186 smb2_pull_handle(body+0x08, &h); 187 188 transport->oplock.handler(transport, &h, level, 189 transport->oplock.private_data); 190 } else if (lease && transport->lease.handler) { 191 struct smb2_lease_break lb; 192 193 ZERO_STRUCT(lb); 194 lb.break_flags = SVAL(body, 0x4); 195 memcpy(&lb.current_lease.lease_key, body+0x8, 196 sizeof(struct smb2_lease_key)); 197 lb.current_lease.lease_state = SVAL(body, 0x18); 198 lb.new_lease_state = SVAL(body, 0x1C); 199 lb.break_reason = SVAL(body, 0x20); 200 lb.access_mask_hint = SVAL(body, 0x24); 201 lb.share_mask_hint = SVAL(body, 0x28); 202 203 transport->lease.handler(transport, &lb, 204 transport->lease.private_data); 205 } else { 206 DEBUG(5,("Got SMB2 %s break with no handler\n", 207 lease ? "lease" : "oplock")); 208 } 209 210 return NT_STATUS_OK; 211} 212 213struct smb2_transport_compount_response_state { 214 struct smb2_transport *transport; 215 DATA_BLOB blob; 216}; 217 218static void smb2_transport_compound_response_handler(struct tevent_context *ctx, 219 struct tevent_immediate *im, 220 void *private_data) 221{ 222 struct smb2_transport_compount_response_state *state = 223 talloc_get_type_abort(private_data, 224 struct smb2_transport_compount_response_state); 225 struct smb2_transport *transport = state->transport; 226 NTSTATUS status; 227 228 status = smb2_transport_finish_recv(transport, state->blob); 229 TALLOC_FREE(state); 230 if (!NT_STATUS_IS_OK(status)) { 231 smb2_transport_error(transport, status); 232 } 233} 234 235/* 236 we have a full request in our receive buffer - match it to a pending request 237 and process 238 */ 239static NTSTATUS smb2_transport_finish_recv(void *private_data, DATA_BLOB blob) 240{ 241 struct smb2_transport *transport = talloc_get_type(private_data, 242 struct smb2_transport); 243 uint8_t *buffer, *hdr; 244 int len; 245 struct smb2_request *req = NULL; 246 uint64_t seqnum; 247 uint32_t flags; 248 uint16_t buffer_code; 249 uint32_t dynamic_size; 250 uint32_t i; 251 uint16_t opcode; 252 NTSTATUS status; 253 uint32_t next_ofs; 254 255 buffer = blob.data; 256 len = blob.length; 257 258 hdr = buffer+NBT_HDR_SIZE; 259 260 if (len < SMB2_MIN_SIZE) { 261 DEBUG(1,("Discarding smb2 reply of size %d\n", len)); 262 goto error; 263 } 264 265 flags = IVAL(hdr, SMB2_HDR_FLAGS); 266 seqnum = BVAL(hdr, SMB2_HDR_MESSAGE_ID); 267 opcode = SVAL(hdr, SMB2_HDR_OPCODE); 268 269 /* see MS-SMB2 3.2.5.19 */ 270 if (seqnum == UINT64_MAX) { 271 if (opcode != SMB2_OP_BREAK) { 272 DEBUG(1,("Discarding packet with invalid seqnum, " 273 "opcode %u\n", opcode)); 274 return NT_STATUS_INVALID_NETWORK_RESPONSE; 275 } 276 277 return smb2_handle_oplock_break(transport, &blob); 278 } 279 280 /* match the incoming request against the list of pending requests */ 281 for (req=transport->pending_recv; req; req=req->next) { 282 if (req->seqnum == seqnum) break; 283 } 284 285 if (!req) { 286 DEBUG(1,("Discarding unmatched reply with seqnum 0x%llx op %d\n", 287 (long long)seqnum, SVAL(hdr, SMB2_HDR_OPCODE))); 288 goto error; 289 } 290 291 /* fill in the 'in' portion of the matching request */ 292 req->in.buffer = buffer; 293 talloc_steal(req, buffer); 294 req->in.size = len; 295 req->in.allocated = req->in.size; 296 297 req->in.hdr = hdr; 298 req->in.body = hdr+SMB2_HDR_BODY; 299 req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE); 300 req->status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS)); 301 302 if ((flags & SMB2_HDR_FLAG_ASYNC) && 303 NT_STATUS_EQUAL(req->status, STATUS_PENDING)) { 304 req->cancel.can_cancel = true; 305 req->cancel.pending_id = IVAL(hdr, SMB2_HDR_PID); 306 for (i=0; i< req->cancel.do_cancel; i++) { 307 smb2_cancel(req); 308 } 309 talloc_free(buffer); 310 return NT_STATUS_OK; 311 } 312 313 next_ofs = IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND); 314 if (next_ofs > 0) { 315 if (smb2_oob(&req->in, req->in.hdr + next_ofs, SMB2_HDR_BODY + 2)) { 316 DEBUG(1,("SMB2 request invalid next offset 0x%x\n", 317 next_ofs)); 318 goto error; 319 } 320 321 req->in.size = NBT_HDR_SIZE + next_ofs; 322 req->in.body_size = req->in.size - (SMB2_HDR_BODY+NBT_HDR_SIZE); 323 } 324 325 if (req->session && req->session->signing_active) { 326 status = smb2_check_signature(&req->in, 327 req->session->session_key); 328 if (!NT_STATUS_IS_OK(status)) { 329 /* the spec says to ignore packets with a bad signature */ 330 talloc_free(buffer); 331 return status; 332 } 333 } 334 335 buffer_code = SVAL(req->in.body, 0); 336 req->in.body_fixed = (buffer_code & ~1); 337 req->in.dynamic = NULL; 338 dynamic_size = req->in.body_size - req->in.body_fixed; 339 if (dynamic_size != 0 && (buffer_code & 1)) { 340 req->in.dynamic = req->in.body + req->in.body_fixed; 341 if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) { 342 DEBUG(1,("SMB2 request invalid dynamic size 0x%x\n", 343 dynamic_size)); 344 goto error; 345 } 346 } 347 348 smb2_setup_bufinfo(req); 349 350 DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", (long long)req->seqnum)); 351 dump_data(5, req->in.body, req->in.body_size); 352 353 if (next_ofs > 0) { 354 struct tevent_immediate *im; 355 struct smb2_transport_compount_response_state *state; 356 357 state = talloc(transport, 358 struct smb2_transport_compount_response_state); 359 if (!state) { 360 goto error; 361 } 362 state->transport = transport; 363 364 state->blob = data_blob_talloc(state, NULL, 365 blob.length - next_ofs); 366 if (!state->blob.data) { 367 goto error; 368 } 369 im = tevent_create_immediate(state); 370 if (!im) { 371 TALLOC_FREE(state); 372 goto error; 373 } 374 _smb2_setlen(state->blob.data, state->blob.length - NBT_HDR_SIZE); 375 memcpy(state->blob.data + NBT_HDR_SIZE, 376 req->in.hdr + next_ofs, 377 req->in.allocated - req->in.size); 378 tevent_schedule_immediate(im, transport->socket->event.ctx, 379 smb2_transport_compound_response_handler, 380 state); 381 } 382 383 /* if this request has an async handler then call that to 384 notify that the reply has been received. This might destroy 385 the request so it must happen last */ 386 DLIST_REMOVE(transport->pending_recv, req); 387 req->state = SMB2_REQUEST_DONE; 388 if (req->async.fn) { 389 req->async.fn(req); 390 } 391 return NT_STATUS_OK; 392 393error: 394 dump_data(5, buffer, len); 395 if (req) { 396 DLIST_REMOVE(transport->pending_recv, req); 397 req->state = SMB2_REQUEST_ERROR; 398 if (req->async.fn) { 399 req->async.fn(req); 400 } 401 } else { 402 talloc_free(buffer); 403 } 404 return NT_STATUS_UNSUCCESSFUL; 405} 406 407/* 408 handle timeouts of individual smb requests 409*/ 410static void smb2_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 411 struct timeval t, void *private_data) 412{ 413 struct smb2_request *req = talloc_get_type(private_data, struct smb2_request); 414 415 if (req->state == SMB2_REQUEST_RECV) { 416 DLIST_REMOVE(req->transport->pending_recv, req); 417 } 418 req->status = NT_STATUS_IO_TIMEOUT; 419 req->state = SMB2_REQUEST_ERROR; 420 if (req->async.fn) { 421 req->async.fn(req); 422 } 423} 424 425 426/* 427 destroy a request 428*/ 429static int smb2_request_destructor(struct smb2_request *req) 430{ 431 if (req->state == SMB2_REQUEST_RECV) { 432 DLIST_REMOVE(req->transport->pending_recv, req); 433 } 434 return 0; 435} 436 437static NTSTATUS smb2_transport_raw_send(struct smb2_transport *transport, 438 struct smb2_request_buffer *buffer) 439{ 440 DATA_BLOB blob; 441 NTSTATUS status; 442 443 /* check if the transport is dead */ 444 if (transport->socket->sock == NULL) { 445 return NT_STATUS_NET_WRITE_FAULT; 446 } 447 448 _smb2_setlen(buffer->buffer, buffer->size - NBT_HDR_SIZE); 449 blob = data_blob_const(buffer->buffer, buffer->size); 450 status = packet_send(transport->packet, blob); 451 if (!NT_STATUS_IS_OK(status)) { 452 return status; 453 } 454 455 return NT_STATUS_OK; 456} 457 458/* 459 put a request into the send queue 460*/ 461void smb2_transport_send(struct smb2_request *req) 462{ 463 NTSTATUS status; 464 465 DEBUG(2, ("SMB2 send seqnum=0x%llx\n", (long long)req->seqnum)); 466 dump_data(5, req->out.body, req->out.body_size); 467 468 if (req->transport->compound.missing > 0) { 469 off_t next_ofs; 470 size_t pad = 0; 471 uint8_t *end; 472 473 end = req->out.buffer + req->out.size; 474 475 /* 476 * we need to set dynamic otherwise 477 * smb2_grow_buffer segfaults 478 */ 479 if (req->out.dynamic == NULL) { 480 req->out.dynamic = end; 481 } 482 483 next_ofs = end - req->out.hdr; 484 if ((next_ofs % 8) > 0) { 485 pad = 8 - (next_ofs % 8); 486 } 487 next_ofs += pad; 488 489 status = smb2_grow_buffer(&req->out, pad); 490 if (!NT_STATUS_IS_OK(status)) { 491 req->state = SMB2_REQUEST_ERROR; 492 req->status = status; 493 return; 494 } 495 req->out.size += pad; 496 497 SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, next_ofs); 498 } 499 500 /* possibly sign the message */ 501 if (req->session && req->session->signing_active) { 502 status = smb2_sign_message(&req->out, req->session->session_key); 503 if (!NT_STATUS_IS_OK(status)) { 504 req->state = SMB2_REQUEST_ERROR; 505 req->status = status; 506 return; 507 } 508 } 509 510 if (req->transport->compound.missing > 0) { 511 req->transport->compound.buffer = req->out; 512 } else { 513 status = smb2_transport_raw_send(req->transport, 514 &req->out); 515 if (!NT_STATUS_IS_OK(status)) { 516 req->state = SMB2_REQUEST_ERROR; 517 req->status = status; 518 return; 519 } 520 } 521 ZERO_STRUCT(req->out); 522 523 req->state = SMB2_REQUEST_RECV; 524 DLIST_ADD(req->transport->pending_recv, req); 525 526 /* add a timeout */ 527 if (req->transport->options.request_timeout) { 528 event_add_timed(req->transport->socket->event.ctx, req, 529 timeval_current_ofs(req->transport->options.request_timeout, 0), 530 smb2_timeout_handler, req); 531 } 532 533 talloc_set_destructor(req, smb2_request_destructor); 534} 535 536NTSTATUS smb2_transport_compound_start(struct smb2_transport *transport, 537 uint32_t num) 538{ 539 ZERO_STRUCT(transport->compound); 540 transport->compound.missing = num; 541 return NT_STATUS_OK; 542} 543 544void smb2_transport_compound_set_related(struct smb2_transport *transport, 545 bool related) 546{ 547 transport->compound.related = related; 548} 549 550void smb2_transport_credits_ask_num(struct smb2_transport *transport, 551 uint16_t ask_num) 552{ 553 transport->credits.ask_num = ask_num; 554} 555 556void smb2_transport_credits_set_charge(struct smb2_transport *transport, 557 uint16_t charge) 558{ 559 transport->credits.charge = charge; 560} 561 562static void idle_handler(struct tevent_context *ev, 563 struct tevent_timer *te, struct timeval t, void *private_data) 564{ 565 struct smb2_transport *transport = talloc_get_type(private_data, 566 struct smb2_transport); 567 struct timeval next = timeval_add(&t, 0, transport->idle.period); 568 transport->socket->event.te = event_add_timed(transport->socket->event.ctx, 569 transport, 570 next, 571 idle_handler, transport); 572 transport->idle.func(transport, transport->idle.private_data); 573} 574 575/* 576 setup the idle handler for a transport 577 the period is in microseconds 578*/ 579void smb2_transport_idle_handler(struct smb2_transport *transport, 580 void (*idle_func)(struct smb2_transport *, void *), 581 uint64_t period, 582 void *private_data) 583{ 584 transport->idle.func = idle_func; 585 transport->idle.private_data = private_data; 586 transport->idle.period = period; 587 588 if (transport->socket->event.te != NULL) { 589 talloc_free(transport->socket->event.te); 590 } 591 592 transport->socket->event.te = event_add_timed(transport->socket->event.ctx, 593 transport, 594 timeval_current_ofs(0, period), 595 idle_handler, transport); 596} 597