smb.c (37184B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * Copyright (C) Bill Nagel <wnagel@tycoint.com>, Exacq Technologies 10 * 11 * This software is licensed as described in the file COPYING, which 12 * you should have received as part of this distribution. The terms 13 * are also available at https://curl.se/docs/copyright.html. 14 * 15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 16 * copies of the Software, and permit persons to whom the Software is 17 * furnished to do so, under the terms of the COPYING file. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 * SPDX-License-Identifier: curl 23 * 24 ***************************************************************************/ 25 26 #include "curl_setup.h" 27 28 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) 29 30 #include "smb.h" 31 #include "urldata.h" 32 #include "url.h" 33 #include "sendf.h" 34 #include "multiif.h" 35 #include "cfilters.h" 36 #include "connect.h" 37 #include "progress.h" 38 #include "transfer.h" 39 #include "vtls/vtls.h" 40 #include "curl_ntlm_core.h" 41 #include "escape.h" 42 #include "curl_endian.h" 43 44 /* The last 3 #include files should be in this order */ 45 #include "curl_printf.h" 46 #include "curl_memory.h" 47 #include "memdebug.h" 48 49 50 /* meta key for storing protocol meta at easy handle */ 51 #define CURL_META_SMB_EASY "meta:proto:smb:easy" 52 /* meta key for storing protocol meta at connection */ 53 #define CURL_META_SMB_CONN "meta:proto:smb:conn" 54 55 enum smb_conn_state { 56 SMB_NOT_CONNECTED = 0, 57 SMB_CONNECTING, 58 SMB_NEGOTIATE, 59 SMB_SETUP, 60 SMB_CONNECTED 61 }; 62 63 /* SMB connection data, kept at connection */ 64 struct smb_conn { 65 enum smb_conn_state state; 66 char *user; 67 char *domain; 68 char *share; 69 unsigned char challenge[8]; 70 unsigned int session_key; 71 unsigned short uid; 72 char *recv_buf; 73 char *send_buf; 74 size_t upload_size; 75 size_t send_size; 76 size_t sent; 77 size_t got; 78 }; 79 80 /* SMB request state */ 81 enum smb_req_state { 82 SMB_REQUESTING, 83 SMB_TREE_CONNECT, 84 SMB_OPEN, 85 SMB_DOWNLOAD, 86 SMB_UPLOAD, 87 SMB_CLOSE, 88 SMB_TREE_DISCONNECT, 89 SMB_DONE 90 }; 91 92 /* SMB request data, kept at easy handle */ 93 struct smb_request { 94 enum smb_req_state state; 95 char *path; 96 unsigned short tid; /* Even if we connect to the same tree as another */ 97 unsigned short fid; /* request, the tid will be different */ 98 CURLcode result; 99 }; 100 101 /* 102 * Definitions for SMB protocol data structures 103 */ 104 #if defined(_MSC_VER) || defined(__ILEC400__) 105 # define PACK 106 # pragma pack(push) 107 # pragma pack(1) 108 #elif defined(__GNUC__) 109 # define PACK __attribute__((packed)) 110 #else 111 # define PACK 112 #endif 113 114 #define SMB_COM_CLOSE 0x04 115 #define SMB_COM_READ_ANDX 0x2e 116 #define SMB_COM_WRITE_ANDX 0x2f 117 #define SMB_COM_TREE_DISCONNECT 0x71 118 #define SMB_COM_NEGOTIATE 0x72 119 #define SMB_COM_SETUP_ANDX 0x73 120 #define SMB_COM_TREE_CONNECT_ANDX 0x75 121 #define SMB_COM_NT_CREATE_ANDX 0xa2 122 #define SMB_COM_NO_ANDX_COMMAND 0xff 123 124 #define SMB_WC_CLOSE 0x03 125 #define SMB_WC_READ_ANDX 0x0c 126 #define SMB_WC_WRITE_ANDX 0x0e 127 #define SMB_WC_SETUP_ANDX 0x0d 128 #define SMB_WC_TREE_CONNECT_ANDX 0x04 129 #define SMB_WC_NT_CREATE_ANDX 0x18 130 131 #define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 132 #define SMB_FLAGS_CASELESS_PATHNAMES 0x08 133 /* #define SMB_FLAGS2_UNICODE_STRINGS 0x8000 */ 134 #define SMB_FLAGS2_IS_LONG_NAME 0x0040 135 #define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 136 137 #define SMB_CAP_LARGE_FILES 0x08 138 #define SMB_GENERIC_WRITE 0x40000000 139 #define SMB_GENERIC_READ 0x80000000 140 #define SMB_FILE_SHARE_ALL 0x07 141 #define SMB_FILE_OPEN 0x01 142 #define SMB_FILE_OVERWRITE_IF 0x05 143 144 #define SMB_ERR_NOACCESS 0x00050001 145 146 struct smb_header { 147 unsigned char nbt_type; 148 unsigned char nbt_flags; 149 unsigned short nbt_length; 150 unsigned char magic[4]; 151 unsigned char command; 152 unsigned int status; 153 unsigned char flags; 154 unsigned short flags2; 155 unsigned short pid_high; 156 unsigned char signature[8]; 157 unsigned short pad; 158 unsigned short tid; 159 unsigned short pid; 160 unsigned short uid; 161 unsigned short mid; 162 } PACK; 163 164 struct smb_negotiate_response { 165 struct smb_header h; 166 unsigned char word_count; 167 unsigned short dialect_index; 168 unsigned char security_mode; 169 unsigned short max_mpx_count; 170 unsigned short max_number_vcs; 171 unsigned int max_buffer_size; 172 unsigned int max_raw_size; 173 unsigned int session_key; 174 unsigned int capabilities; 175 unsigned int system_time_low; 176 unsigned int system_time_high; 177 unsigned short server_time_zone; 178 unsigned char encryption_key_length; 179 unsigned short byte_count; 180 char bytes[1]; 181 } PACK; 182 183 struct andx { 184 unsigned char command; 185 unsigned char pad; 186 unsigned short offset; 187 } PACK; 188 189 struct smb_setup { 190 unsigned char word_count; 191 struct andx andx; 192 unsigned short max_buffer_size; 193 unsigned short max_mpx_count; 194 unsigned short vc_number; 195 unsigned int session_key; 196 unsigned short lengths[2]; 197 unsigned int pad; 198 unsigned int capabilities; 199 unsigned short byte_count; 200 char bytes[1024]; 201 } PACK; 202 203 struct smb_tree_connect { 204 unsigned char word_count; 205 struct andx andx; 206 unsigned short flags; 207 unsigned short pw_len; 208 unsigned short byte_count; 209 char bytes[1024]; 210 } PACK; 211 212 struct smb_nt_create { 213 unsigned char word_count; 214 struct andx andx; 215 unsigned char pad; 216 unsigned short name_length; 217 unsigned int flags; 218 unsigned int root_fid; 219 unsigned int access; 220 curl_off_t allocation_size; 221 unsigned int ext_file_attributes; 222 unsigned int share_access; 223 unsigned int create_disposition; 224 unsigned int create_options; 225 unsigned int impersonation_level; 226 unsigned char security_flags; 227 unsigned short byte_count; 228 char bytes[1024]; 229 } PACK; 230 231 struct smb_nt_create_response { 232 struct smb_header h; 233 unsigned char word_count; 234 struct andx andx; 235 unsigned char op_lock_level; 236 unsigned short fid; 237 unsigned int create_disposition; 238 239 curl_off_t create_time; 240 curl_off_t last_access_time; 241 curl_off_t last_write_time; 242 curl_off_t last_change_time; 243 unsigned int ext_file_attributes; 244 curl_off_t allocation_size; 245 curl_off_t end_of_file; 246 } PACK; 247 248 struct smb_read { 249 unsigned char word_count; 250 struct andx andx; 251 unsigned short fid; 252 unsigned int offset; 253 unsigned short max_bytes; 254 unsigned short min_bytes; 255 unsigned int timeout; 256 unsigned short remaining; 257 unsigned int offset_high; 258 unsigned short byte_count; 259 } PACK; 260 261 struct smb_write { 262 struct smb_header h; 263 unsigned char word_count; 264 struct andx andx; 265 unsigned short fid; 266 unsigned int offset; 267 unsigned int timeout; 268 unsigned short write_mode; 269 unsigned short remaining; 270 unsigned short pad; 271 unsigned short data_length; 272 unsigned short data_offset; 273 unsigned int offset_high; 274 unsigned short byte_count; 275 unsigned char pad2; 276 } PACK; 277 278 struct smb_close { 279 unsigned char word_count; 280 unsigned short fid; 281 unsigned int last_mtime; 282 unsigned short byte_count; 283 } PACK; 284 285 struct smb_tree_disconnect { 286 unsigned char word_count; 287 unsigned short byte_count; 288 } PACK; 289 290 #if defined(_MSC_VER) || defined(__ILEC400__) 291 # pragma pack(pop) 292 #endif 293 294 /* Local API functions */ 295 static CURLcode smb_setup_connection(struct Curl_easy *data, 296 struct connectdata *conn); 297 static CURLcode smb_connect(struct Curl_easy *data, bool *done); 298 static CURLcode smb_connection_state(struct Curl_easy *data, bool *done); 299 static CURLcode smb_do(struct Curl_easy *data, bool *done); 300 static CURLcode smb_request_state(struct Curl_easy *data, bool *done); 301 static int smb_getsock(struct Curl_easy *data, struct connectdata *conn, 302 curl_socket_t *socks); 303 static CURLcode smb_parse_url_path(struct Curl_easy *data, 304 struct smb_conn *smbc, 305 struct smb_request *req); 306 307 /* 308 * SMB handler interface 309 */ 310 const struct Curl_handler Curl_handler_smb = { 311 "smb", /* scheme */ 312 smb_setup_connection, /* setup_connection */ 313 smb_do, /* do_it */ 314 ZERO_NULL, /* done */ 315 ZERO_NULL, /* do_more */ 316 smb_connect, /* connect_it */ 317 smb_connection_state, /* connecting */ 318 smb_request_state, /* doing */ 319 smb_getsock, /* proto_getsock */ 320 smb_getsock, /* doing_getsock */ 321 ZERO_NULL, /* domore_getsock */ 322 ZERO_NULL, /* perform_getsock */ 323 ZERO_NULL, /* disconnect */ 324 ZERO_NULL, /* write_resp */ 325 ZERO_NULL, /* write_resp_hd */ 326 ZERO_NULL, /* connection_check */ 327 ZERO_NULL, /* attach connection */ 328 ZERO_NULL, /* follow */ 329 PORT_SMB, /* defport */ 330 CURLPROTO_SMB, /* protocol */ 331 CURLPROTO_SMB, /* family */ 332 PROTOPT_NONE /* flags */ 333 }; 334 335 #ifdef USE_SSL 336 /* 337 * SMBS handler interface 338 */ 339 const struct Curl_handler Curl_handler_smbs = { 340 "smbs", /* scheme */ 341 smb_setup_connection, /* setup_connection */ 342 smb_do, /* do_it */ 343 ZERO_NULL, /* done */ 344 ZERO_NULL, /* do_more */ 345 smb_connect, /* connect_it */ 346 smb_connection_state, /* connecting */ 347 smb_request_state, /* doing */ 348 smb_getsock, /* proto_getsock */ 349 smb_getsock, /* doing_getsock */ 350 ZERO_NULL, /* domore_getsock */ 351 ZERO_NULL, /* perform_getsock */ 352 ZERO_NULL, /* disconnect */ 353 ZERO_NULL, /* write_resp */ 354 ZERO_NULL, /* write_resp_hd */ 355 ZERO_NULL, /* connection_check */ 356 ZERO_NULL, /* attach connection */ 357 ZERO_NULL, /* follow */ 358 PORT_SMBS, /* defport */ 359 CURLPROTO_SMBS, /* protocol */ 360 CURLPROTO_SMB, /* family */ 361 PROTOPT_SSL /* flags */ 362 }; 363 #endif 364 365 #define MAX_PAYLOAD_SIZE 0x8000 366 #define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) 367 #define CLIENTNAME "curl" 368 #define SERVICENAME "?????" 369 370 /* SMB is mostly little endian */ 371 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 372 defined(__OS400__) 373 static unsigned short smb_swap16(unsigned short x) 374 { 375 return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); 376 } 377 378 static unsigned int smb_swap32(unsigned int x) 379 { 380 return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | 381 ((x >> 24) & 0xff); 382 } 383 384 static curl_off_t smb_swap64(curl_off_t x) 385 { 386 return ((curl_off_t) smb_swap32((unsigned int) x) << 32) | 387 smb_swap32((unsigned int) (x >> 32)); 388 } 389 390 #else 391 # define smb_swap16(x) (x) 392 # define smb_swap32(x) (x) 393 # define smb_swap64(x) (x) 394 #endif 395 396 static void conn_state(struct Curl_easy *data, struct smb_conn *smbc, 397 enum smb_conn_state newstate) 398 { 399 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 400 /* For debug purposes */ 401 static const char * const names[] = { 402 "SMB_NOT_CONNECTED", 403 "SMB_CONNECTING", 404 "SMB_NEGOTIATE", 405 "SMB_SETUP", 406 "SMB_CONNECTED", 407 /* LAST */ 408 }; 409 410 if(smbc->state != newstate) 411 infof(data, "SMB conn %p state change from %s to %s", 412 (void *)smbc, names[smbc->state], names[newstate]); 413 #endif 414 (void)data; 415 smbc->state = newstate; 416 } 417 418 static void request_state(struct Curl_easy *data, 419 enum smb_req_state newstate) 420 { 421 struct smb_request *req = Curl_meta_get(data, CURL_META_SMB_EASY); 422 if(req) { 423 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 424 /* For debug purposes */ 425 static const char * const names[] = { 426 "SMB_REQUESTING", 427 "SMB_TREE_CONNECT", 428 "SMB_OPEN", 429 "SMB_DOWNLOAD", 430 "SMB_UPLOAD", 431 "SMB_CLOSE", 432 "SMB_TREE_DISCONNECT", 433 "SMB_DONE", 434 /* LAST */ 435 }; 436 437 if(req->state != newstate) 438 infof(data, "SMB request %p state change from %s to %s", 439 (void *)req, names[req->state], names[newstate]); 440 #endif 441 442 req->state = newstate; 443 } 444 } 445 446 static void smb_easy_dtor(void *key, size_t klen, void *entry) 447 { 448 struct smb_request *req = entry; 449 (void)key; 450 (void)klen; 451 /* `req->path` points to somewhere in `struct smb_conn` which is 452 * kept at the connection meta. If the connection is destroyed first, 453 * req->path points to free'd memory. */ 454 free(req); 455 } 456 457 static void smb_conn_dtor(void *key, size_t klen, void *entry) 458 { 459 struct smb_conn *smbc = entry; 460 (void)key; 461 (void)klen; 462 Curl_safefree(smbc->share); 463 Curl_safefree(smbc->domain); 464 Curl_safefree(smbc->recv_buf); 465 Curl_safefree(smbc->send_buf); 466 free(smbc); 467 } 468 469 /* this should setup things in the connection, not in the easy 470 handle */ 471 static CURLcode smb_setup_connection(struct Curl_easy *data, 472 struct connectdata *conn) 473 { 474 struct smb_conn *smbc; 475 struct smb_request *req; 476 477 /* Initialize the connection state */ 478 smbc = calloc(1, sizeof(*smbc)); 479 if(!smbc || 480 Curl_conn_meta_set(conn, CURL_META_SMB_CONN, smbc, smb_conn_dtor)) 481 return CURLE_OUT_OF_MEMORY; 482 483 /* Initialize the request state */ 484 req = calloc(1, sizeof(*req)); 485 if(!req || 486 Curl_meta_set(data, CURL_META_SMB_EASY, req, smb_easy_dtor)) 487 return CURLE_OUT_OF_MEMORY; 488 489 /* Parse the URL path */ 490 return smb_parse_url_path(data, smbc, req); 491 } 492 493 static CURLcode smb_connect(struct Curl_easy *data, bool *done) 494 { 495 struct connectdata *conn = data->conn; 496 struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); 497 char *slash; 498 499 (void) done; 500 if(!smbc) 501 return CURLE_FAILED_INIT; 502 503 /* Check we have a username and password to authenticate with */ 504 if(!data->state.aptr.user) 505 return CURLE_LOGIN_DENIED; 506 507 /* Initialize the connection state */ 508 smbc->state = SMB_CONNECTING; 509 smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); 510 if(!smbc->recv_buf) 511 return CURLE_OUT_OF_MEMORY; 512 smbc->send_buf = malloc(MAX_MESSAGE_SIZE); 513 if(!smbc->send_buf) 514 return CURLE_OUT_OF_MEMORY; 515 516 /* Multiple requests are allowed with this connection */ 517 connkeep(conn, "SMB default"); 518 519 /* Parse the username, domain, and password */ 520 slash = strchr(conn->user, '/'); 521 if(!slash) 522 slash = strchr(conn->user, '\\'); 523 524 if(slash) { 525 smbc->user = slash + 1; 526 smbc->domain = strdup(conn->user); 527 if(!smbc->domain) 528 return CURLE_OUT_OF_MEMORY; 529 smbc->domain[slash - conn->user] = 0; 530 } 531 else { 532 smbc->user = conn->user; 533 smbc->domain = strdup(conn->host.name); 534 if(!smbc->domain) 535 return CURLE_OUT_OF_MEMORY; 536 } 537 538 return CURLE_OK; 539 } 540 541 static CURLcode smb_recv_message(struct Curl_easy *data, 542 struct smb_conn *smbc, 543 void **msg) 544 { 545 char *buf = smbc->recv_buf; 546 size_t bytes_read; 547 size_t nbt_size; 548 size_t msg_size; 549 size_t len = MAX_MESSAGE_SIZE - smbc->got; 550 CURLcode result; 551 552 result = Curl_xfer_recv(data, buf + smbc->got, len, &bytes_read); 553 if(result) 554 return result; 555 556 if(!bytes_read) 557 return CURLE_OK; 558 559 smbc->got += bytes_read; 560 561 /* Check for a 32-bit nbt header */ 562 if(smbc->got < sizeof(unsigned int)) 563 return CURLE_OK; 564 565 nbt_size = Curl_read16_be((const unsigned char *) 566 (buf + sizeof(unsigned short))) + 567 sizeof(unsigned int); 568 if(smbc->got < nbt_size) 569 return CURLE_OK; 570 571 msg_size = sizeof(struct smb_header); 572 if(nbt_size >= msg_size + 1) { 573 /* Add the word count */ 574 msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); 575 if(nbt_size >= msg_size + sizeof(unsigned short)) { 576 /* Add the byte count */ 577 msg_size += sizeof(unsigned short) + 578 Curl_read16_le((const unsigned char *)&buf[msg_size]); 579 if(nbt_size < msg_size) 580 return CURLE_READ_ERROR; 581 } 582 } 583 584 *msg = buf; 585 586 return CURLE_OK; 587 } 588 589 static void smb_pop_message(struct smb_conn *smbc) 590 { 591 smbc->got = 0; 592 } 593 594 static void smb_format_message(struct smb_conn *smbc, 595 struct smb_request *req, 596 struct smb_header *h, 597 unsigned char cmd, size_t len) 598 { 599 const unsigned int pid = 0xbad71d; /* made up */ 600 601 memset(h, 0, sizeof(*h)); 602 h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + 603 len)); 604 memcpy((char *)h->magic, "\xffSMB", 4); 605 h->command = cmd; 606 h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; 607 h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); 608 h->uid = smb_swap16(smbc->uid); 609 h->tid = smb_swap16(req->tid); 610 h->pid_high = smb_swap16((unsigned short)(pid >> 16)); 611 h->pid = smb_swap16((unsigned short) pid); 612 } 613 614 static CURLcode smb_send(struct Curl_easy *data, struct smb_conn *smbc, 615 size_t len, size_t upload_size) 616 { 617 size_t bytes_written; 618 CURLcode result; 619 620 result = Curl_xfer_send(data, smbc->send_buf, len, FALSE, &bytes_written); 621 if(result) 622 return result; 623 624 if(bytes_written != len) { 625 smbc->send_size = len; 626 smbc->sent = bytes_written; 627 } 628 629 smbc->upload_size = upload_size; 630 631 return CURLE_OK; 632 } 633 634 static CURLcode smb_flush(struct Curl_easy *data, struct smb_conn *smbc) 635 { 636 size_t bytes_written; 637 size_t len = smbc->send_size - smbc->sent; 638 CURLcode result; 639 640 if(!smbc->send_size) 641 return CURLE_OK; 642 643 result = Curl_xfer_send(data, smbc->send_buf + smbc->sent, len, FALSE, 644 &bytes_written); 645 if(result) 646 return result; 647 648 if(bytes_written != len) 649 smbc->sent += bytes_written; 650 else 651 smbc->send_size = 0; 652 653 return CURLE_OK; 654 } 655 656 static CURLcode smb_send_message(struct Curl_easy *data, 657 struct smb_conn *smbc, 658 struct smb_request *req, 659 unsigned char cmd, 660 const void *msg, size_t msg_len) 661 { 662 smb_format_message(smbc, req, (struct smb_header *)smbc->send_buf, 663 cmd, msg_len); 664 DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE); 665 memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len); 666 667 return smb_send(data, smbc, sizeof(struct smb_header) + msg_len, 0); 668 } 669 670 static CURLcode smb_send_negotiate(struct Curl_easy *data, 671 struct smb_conn *smbc, 672 struct smb_request *req) 673 { 674 const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; 675 676 return smb_send_message(data, smbc, req, SMB_COM_NEGOTIATE, msg, 15); 677 } 678 679 static CURLcode smb_send_setup(struct Curl_easy *data) 680 { 681 struct connectdata *conn = data->conn; 682 struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); 683 struct smb_request *req = Curl_meta_get(data, CURL_META_SMB_EASY); 684 struct smb_setup msg; 685 char *p = msg.bytes; 686 unsigned char lm_hash[21]; 687 unsigned char lm[24]; 688 unsigned char nt_hash[21]; 689 unsigned char nt[24]; 690 size_t byte_count; 691 692 if(!smbc || !req) 693 return CURLE_FAILED_INIT; 694 695 byte_count = sizeof(lm) + sizeof(nt) + 696 strlen(smbc->user) + strlen(smbc->domain) + 697 strlen(CURL_OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ 698 if(byte_count > sizeof(msg.bytes)) 699 return CURLE_FILESIZE_EXCEEDED; 700 701 Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash); 702 Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); 703 Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash); 704 Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); 705 706 memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes)); 707 msg.word_count = SMB_WC_SETUP_ANDX; 708 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 709 msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); 710 msg.max_mpx_count = smb_swap16(1); 711 msg.vc_number = smb_swap16(1); 712 msg.session_key = smb_swap32(smbc->session_key); 713 msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); 714 msg.lengths[0] = smb_swap16(sizeof(lm)); 715 msg.lengths[1] = smb_swap16(sizeof(nt)); 716 memcpy(p, lm, sizeof(lm)); 717 p += sizeof(lm); 718 memcpy(p, nt, sizeof(nt)); 719 p += sizeof(nt); 720 p += msnprintf(p, byte_count - sizeof(nt) - sizeof(lm), 721 "%s%c" /* user */ 722 "%s%c" /* domain */ 723 "%s%c" /* OS */ 724 "%s", /* client name */ 725 smbc->user, 0, smbc->domain, 0, CURL_OS, 0, CLIENTNAME); 726 p++; /* count the final null-termination */ 727 DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); 728 msg.byte_count = smb_swap16((unsigned short)byte_count); 729 730 return smb_send_message(data, smbc, req, SMB_COM_SETUP_ANDX, &msg, 731 sizeof(msg) - sizeof(msg.bytes) + byte_count); 732 } 733 734 static CURLcode smb_send_tree_connect(struct Curl_easy *data, 735 struct smb_conn *smbc, 736 struct smb_request *req) 737 { 738 struct smb_tree_connect msg; 739 struct connectdata *conn = data->conn; 740 char *p = msg.bytes; 741 const size_t byte_count = strlen(conn->host.name) + strlen(smbc->share) + 742 strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ 743 744 if(byte_count > sizeof(msg.bytes)) 745 return CURLE_FILESIZE_EXCEEDED; 746 747 memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes)); 748 msg.word_count = SMB_WC_TREE_CONNECT_ANDX; 749 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 750 msg.pw_len = 0; 751 752 p += msnprintf(p, byte_count, 753 "\\\\%s\\" /* hostname */ 754 "%s%c" /* share */ 755 "%s", /* service */ 756 conn->host.name, smbc->share, 0, SERVICENAME); 757 p++; /* count the final null-termination */ 758 DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); 759 msg.byte_count = smb_swap16((unsigned short)byte_count); 760 761 return smb_send_message(data, smbc, req, SMB_COM_TREE_CONNECT_ANDX, &msg, 762 sizeof(msg) - sizeof(msg.bytes) + byte_count); 763 } 764 765 static CURLcode smb_send_open(struct Curl_easy *data, 766 struct smb_conn *smbc, 767 struct smb_request *req) 768 { 769 struct smb_nt_create msg; 770 const size_t byte_count = strlen(req->path) + 1; 771 772 if(byte_count > sizeof(msg.bytes)) 773 return CURLE_FILESIZE_EXCEEDED; 774 775 memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes)); 776 msg.word_count = SMB_WC_NT_CREATE_ANDX; 777 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 778 msg.name_length = smb_swap16((unsigned short)(byte_count - 1)); 779 msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); 780 if(data->state.upload) { 781 msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); 782 msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); 783 } 784 else { 785 msg.access = smb_swap32(SMB_GENERIC_READ); 786 msg.create_disposition = smb_swap32(SMB_FILE_OPEN); 787 } 788 msg.byte_count = smb_swap16((unsigned short) byte_count); 789 strcpy(msg.bytes, req->path); 790 791 return smb_send_message(data, smbc, req, SMB_COM_NT_CREATE_ANDX, &msg, 792 sizeof(msg) - sizeof(msg.bytes) + byte_count); 793 } 794 795 static CURLcode smb_send_close(struct Curl_easy *data, 796 struct smb_conn *smbc, 797 struct smb_request *req) 798 { 799 struct smb_close msg; 800 801 memset(&msg, 0, sizeof(msg)); 802 msg.word_count = SMB_WC_CLOSE; 803 msg.fid = smb_swap16(req->fid); 804 805 return smb_send_message(data, smbc, req, SMB_COM_CLOSE, &msg, sizeof(msg)); 806 } 807 808 static CURLcode smb_send_tree_disconnect(struct Curl_easy *data, 809 struct smb_conn *smbc, 810 struct smb_request *req) 811 { 812 struct smb_tree_disconnect msg; 813 memset(&msg, 0, sizeof(msg)); 814 return smb_send_message(data, smbc, req, SMB_COM_TREE_DISCONNECT, 815 &msg, sizeof(msg)); 816 } 817 818 static CURLcode smb_send_read(struct Curl_easy *data, 819 struct smb_conn *smbc, 820 struct smb_request *req) 821 { 822 curl_off_t offset = data->req.offset; 823 struct smb_read msg; 824 825 memset(&msg, 0, sizeof(msg)); 826 msg.word_count = SMB_WC_READ_ANDX; 827 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 828 msg.fid = smb_swap16(req->fid); 829 msg.offset = smb_swap32((unsigned int) offset); 830 msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); 831 msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 832 msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 833 834 return smb_send_message(data, smbc, req, SMB_COM_READ_ANDX, 835 &msg, sizeof(msg)); 836 } 837 838 static CURLcode smb_send_write(struct Curl_easy *data, 839 struct smb_conn *smbc, 840 struct smb_request *req) 841 { 842 struct smb_write *msg; 843 curl_off_t offset = data->req.offset; 844 curl_off_t upload_size = data->req.size - data->req.bytecount; 845 846 msg = (struct smb_write *)smbc->send_buf; 847 if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ 848 upload_size = MAX_PAYLOAD_SIZE - 1; 849 850 memset(msg, 0, sizeof(*msg)); 851 msg->word_count = SMB_WC_WRITE_ANDX; 852 msg->andx.command = SMB_COM_NO_ANDX_COMMAND; 853 msg->fid = smb_swap16(req->fid); 854 msg->offset = smb_swap32((unsigned int) offset); 855 msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); 856 msg->data_length = smb_swap16((unsigned short) upload_size); 857 msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); 858 msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); 859 860 smb_format_message(smbc, req, &msg->h, SMB_COM_WRITE_ANDX, 861 sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); 862 863 return smb_send(data, smbc, sizeof(*msg), (size_t) upload_size); 864 } 865 866 static CURLcode smb_send_and_recv(struct Curl_easy *data, 867 struct smb_conn *smbc, void **msg) 868 { 869 CURLcode result; 870 *msg = NULL; /* if it returns early */ 871 872 /* Check if there is data in the transfer buffer */ 873 if(!smbc->send_size && smbc->upload_size) { 874 size_t nread = smbc->upload_size > (size_t)MAX_MESSAGE_SIZE ? 875 (size_t)MAX_MESSAGE_SIZE : smbc->upload_size; 876 bool eos; 877 878 result = Curl_client_read(data, smbc->send_buf, nread, &nread, &eos); 879 if(result && result != CURLE_AGAIN) 880 return result; 881 if(!nread) 882 return CURLE_OK; 883 884 smbc->upload_size -= nread; 885 smbc->send_size = nread; 886 smbc->sent = 0; 887 } 888 889 /* Check if there is data to send */ 890 if(smbc->send_size) { 891 result = smb_flush(data, smbc); 892 if(result) 893 return result; 894 } 895 896 /* Check if there is still data to be sent */ 897 if(smbc->send_size || smbc->upload_size) 898 return CURLE_AGAIN; 899 900 return smb_recv_message(data, smbc, msg); 901 } 902 903 static CURLcode smb_connection_state(struct Curl_easy *data, bool *done) 904 { 905 struct connectdata *conn = data->conn; 906 struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); 907 struct smb_request *req = Curl_meta_get(data, CURL_META_SMB_EASY); 908 struct smb_negotiate_response *nrsp; 909 struct smb_header *h; 910 CURLcode result; 911 void *msg = NULL; 912 913 if(!smbc || !req) 914 return CURLE_FAILED_INIT; 915 916 if(smbc->state == SMB_CONNECTING) { 917 #ifdef USE_SSL 918 if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) { 919 bool ssl_done = FALSE; 920 result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssl_done); 921 if(result && result != CURLE_AGAIN) 922 return result; 923 if(!ssl_done) 924 return CURLE_OK; 925 } 926 #endif 927 928 result = smb_send_negotiate(data, smbc, req); 929 if(result) { 930 connclose(conn, "SMB: failed to send negotiate message"); 931 return result; 932 } 933 934 conn_state(data, smbc, SMB_NEGOTIATE); 935 } 936 937 /* Send the previous message and check for a response */ 938 result = smb_send_and_recv(data, smbc, &msg); 939 if(result && result != CURLE_AGAIN) { 940 connclose(conn, "SMB: failed to communicate"); 941 return result; 942 } 943 944 if(!msg) 945 return CURLE_OK; 946 947 h = msg; 948 949 switch(smbc->state) { 950 case SMB_NEGOTIATE: 951 if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) || 952 h->status) { 953 connclose(conn, "SMB: negotiation failed"); 954 return CURLE_COULDNT_CONNECT; 955 } 956 nrsp = msg; 957 #if defined(__GNUC__) && __GNUC__ >= 13 958 #pragma GCC diagnostic push 959 /* error: 'memcpy' offset [74, 80] from the object at '<unknown>' is out of 960 the bounds of referenced subobject 'bytes' with type 'char[1]' */ 961 #pragma GCC diagnostic ignored "-Warray-bounds" 962 #endif 963 memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); 964 #if defined(__GNUC__) && __GNUC__ >= 13 965 #pragma GCC diagnostic pop 966 #endif 967 smbc->session_key = smb_swap32(nrsp->session_key); 968 result = smb_send_setup(data); 969 if(result) { 970 connclose(conn, "SMB: failed to send setup message"); 971 return result; 972 } 973 conn_state(data, smbc, SMB_SETUP); 974 break; 975 976 case SMB_SETUP: 977 if(h->status) { 978 connclose(conn, "SMB: authentication failed"); 979 return CURLE_LOGIN_DENIED; 980 } 981 smbc->uid = smb_swap16(h->uid); 982 conn_state(data, smbc, SMB_CONNECTED); 983 *done = TRUE; 984 break; 985 986 default: 987 smb_pop_message(smbc); 988 return CURLE_OK; /* ignore */ 989 } 990 991 smb_pop_message(smbc); 992 993 return CURLE_OK; 994 } 995 996 /* 997 * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601) 998 * to POSIX time. Cap the output to fit within a time_t. 999 */ 1000 static void get_posix_time(time_t *out, curl_off_t timestamp) 1001 { 1002 if(timestamp >= (curl_off_t)116444736000000000) { 1003 timestamp -= (curl_off_t)116444736000000000; 1004 timestamp /= 10000000; 1005 #if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T 1006 if(timestamp > TIME_T_MAX) 1007 *out = TIME_T_MAX; 1008 else if(timestamp < TIME_T_MIN) 1009 *out = TIME_T_MIN; 1010 else 1011 #endif 1012 *out = (time_t) timestamp; 1013 } 1014 else 1015 *out = 0; 1016 } 1017 1018 static CURLcode smb_request_state(struct Curl_easy *data, bool *done) 1019 { 1020 struct connectdata *conn = data->conn; 1021 struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); 1022 struct smb_request *req = Curl_meta_get(data, CURL_META_SMB_EASY); 1023 struct smb_header *h; 1024 enum smb_req_state next_state = SMB_DONE; 1025 unsigned short len; 1026 unsigned short off; 1027 CURLcode result; 1028 void *msg = NULL; 1029 const struct smb_nt_create_response *smb_m; 1030 1031 if(!smbc || !req) 1032 return CURLE_FAILED_INIT; 1033 1034 if(data->state.upload && (data->state.infilesize < 0)) { 1035 failf(data, "SMB upload needs to know the size up front"); 1036 return CURLE_SEND_ERROR; 1037 } 1038 1039 /* Start the request */ 1040 if(req->state == SMB_REQUESTING) { 1041 result = smb_send_tree_connect(data, smbc, req); 1042 if(result) { 1043 connclose(conn, "SMB: failed to send tree connect message"); 1044 return result; 1045 } 1046 1047 request_state(data, SMB_TREE_CONNECT); 1048 } 1049 1050 /* Send the previous message and check for a response */ 1051 result = smb_send_and_recv(data, smbc, &msg); 1052 if(result && result != CURLE_AGAIN) { 1053 connclose(conn, "SMB: failed to communicate"); 1054 return result; 1055 } 1056 1057 if(!msg) 1058 return CURLE_OK; 1059 1060 h = msg; 1061 1062 switch(req->state) { 1063 case SMB_TREE_CONNECT: 1064 if(h->status) { 1065 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 1066 if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 1067 req->result = CURLE_REMOTE_ACCESS_DENIED; 1068 break; 1069 } 1070 req->tid = smb_swap16(h->tid); 1071 next_state = SMB_OPEN; 1072 break; 1073 1074 case SMB_OPEN: 1075 if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { 1076 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 1077 if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 1078 req->result = CURLE_REMOTE_ACCESS_DENIED; 1079 next_state = SMB_TREE_DISCONNECT; 1080 break; 1081 } 1082 smb_m = (const struct smb_nt_create_response*) msg; 1083 req->fid = smb_swap16(smb_m->fid); 1084 data->req.offset = 0; 1085 if(data->state.upload) { 1086 data->req.size = data->state.infilesize; 1087 Curl_pgrsSetUploadSize(data, data->req.size); 1088 next_state = SMB_UPLOAD; 1089 } 1090 else { 1091 data->req.size = smb_swap64(smb_m->end_of_file); 1092 if(data->req.size < 0) { 1093 req->result = CURLE_WEIRD_SERVER_REPLY; 1094 next_state = SMB_CLOSE; 1095 } 1096 else { 1097 Curl_pgrsSetDownloadSize(data, data->req.size); 1098 if(data->set.get_filetime) 1099 get_posix_time(&data->info.filetime, smb_m->last_change_time); 1100 next_state = SMB_DOWNLOAD; 1101 } 1102 } 1103 break; 1104 1105 case SMB_DOWNLOAD: 1106 if(h->status || smbc->got < sizeof(struct smb_header) + 14) { 1107 req->result = CURLE_RECV_ERROR; 1108 next_state = SMB_CLOSE; 1109 break; 1110 } 1111 len = Curl_read16_le(((const unsigned char *) msg) + 1112 sizeof(struct smb_header) + 11); 1113 off = Curl_read16_le(((const unsigned char *) msg) + 1114 sizeof(struct smb_header) + 13); 1115 if(len > 0) { 1116 if(off + sizeof(unsigned int) + len > smbc->got) { 1117 failf(data, "Invalid input packet"); 1118 result = CURLE_RECV_ERROR; 1119 } 1120 else 1121 result = Curl_client_write(data, CLIENTWRITE_BODY, 1122 (char *)msg + off + sizeof(unsigned int), 1123 len); 1124 if(result) { 1125 req->result = result; 1126 next_state = SMB_CLOSE; 1127 break; 1128 } 1129 } 1130 data->req.offset += len; 1131 next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; 1132 break; 1133 1134 case SMB_UPLOAD: 1135 if(h->status || smbc->got < sizeof(struct smb_header) + 6) { 1136 req->result = CURLE_UPLOAD_FAILED; 1137 next_state = SMB_CLOSE; 1138 break; 1139 } 1140 len = Curl_read16_le(((const unsigned char *) msg) + 1141 sizeof(struct smb_header) + 5); 1142 data->req.bytecount += len; 1143 data->req.offset += len; 1144 Curl_pgrsSetUploadCounter(data, data->req.bytecount); 1145 if(data->req.bytecount >= data->req.size) 1146 next_state = SMB_CLOSE; 1147 else 1148 next_state = SMB_UPLOAD; 1149 break; 1150 1151 case SMB_CLOSE: 1152 /* We do not care if the close failed, proceed to tree disconnect anyway */ 1153 next_state = SMB_TREE_DISCONNECT; 1154 break; 1155 1156 case SMB_TREE_DISCONNECT: 1157 next_state = SMB_DONE; 1158 break; 1159 1160 default: 1161 smb_pop_message(smbc); 1162 return CURLE_OK; /* ignore */ 1163 } 1164 1165 smb_pop_message(smbc); 1166 1167 switch(next_state) { 1168 case SMB_OPEN: 1169 result = smb_send_open(data, smbc, req); 1170 break; 1171 1172 case SMB_DOWNLOAD: 1173 result = smb_send_read(data, smbc, req); 1174 break; 1175 1176 case SMB_UPLOAD: 1177 result = smb_send_write(data, smbc, req); 1178 break; 1179 1180 case SMB_CLOSE: 1181 result = smb_send_close(data, smbc, req); 1182 break; 1183 1184 case SMB_TREE_DISCONNECT: 1185 result = smb_send_tree_disconnect(data, smbc, req); 1186 break; 1187 1188 case SMB_DONE: 1189 result = req->result; 1190 *done = TRUE; 1191 break; 1192 1193 default: 1194 break; 1195 } 1196 1197 if(result) { 1198 connclose(conn, "SMB: failed to send message"); 1199 return result; 1200 } 1201 1202 request_state(data, next_state); 1203 1204 return CURLE_OK; 1205 } 1206 1207 static int smb_getsock(struct Curl_easy *data, 1208 struct connectdata *conn, curl_socket_t *socks) 1209 { 1210 (void)data; 1211 socks[0] = conn->sock[FIRSTSOCKET]; 1212 return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); 1213 } 1214 1215 static CURLcode smb_do(struct Curl_easy *data, bool *done) 1216 { 1217 struct connectdata *conn = data->conn; 1218 struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); 1219 1220 *done = FALSE; 1221 if(!smbc) 1222 return CURLE_FAILED_INIT; 1223 if(smbc->share) 1224 return CURLE_OK; 1225 return CURLE_URL_MALFORMAT; 1226 } 1227 1228 static CURLcode smb_parse_url_path(struct Curl_easy *data, 1229 struct smb_conn *smbc, 1230 struct smb_request *req) 1231 { 1232 char *path; 1233 char *slash; 1234 CURLcode result; 1235 1236 /* URL decode the path */ 1237 result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL); 1238 if(result) 1239 return result; 1240 1241 /* Parse the path for the share */ 1242 smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); 1243 free(path); 1244 if(!smbc->share) 1245 return CURLE_OUT_OF_MEMORY; 1246 1247 slash = strchr(smbc->share, '/'); 1248 if(!slash) 1249 slash = strchr(smbc->share, '\\'); 1250 1251 /* The share must be present */ 1252 if(!slash) { 1253 Curl_safefree(smbc->share); 1254 failf(data, "missing share in URL path for SMB"); 1255 return CURLE_URL_MALFORMAT; 1256 } 1257 1258 /* Parse the path for the file path converting any forward slashes into 1259 backslashes */ 1260 *slash++ = 0; 1261 req->path = slash; 1262 1263 for(; *slash; slash++) { 1264 if(*slash == '/') 1265 *slash = '\\'; 1266 } 1267 return CURLE_OK; 1268 } 1269 1270 #endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && 1271 SIZEOF_CURL_OFF_T > 4 */