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