1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2014, Bill Nagel <wnagel (at) tycoint.com>, Exacq Technologies 9 * Copyright (C) 2015, Daniel Stenberg, <daniel (at) haxx.se>, et al. 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 http://curl.haxx.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 ***************************************************************************/ 23 24 #include "curl_setup.h" 25 26 #if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ 27 (CURL_SIZEOF_CURL_OFF_T > 4) 28 29 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) 30 31 #define BUILDING_CURL_SMB_C 32 33 #ifdef HAVE_PROCESS_H 34 #include <process.h> 35 #define getpid _getpid 36 #endif 37 38 #include "smb.h" 39 #include "urldata.h" 40 #include "sendf.h" 41 #include "multiif.h" 42 #include "connect.h" 43 #include "progress.h" 44 #include "transfer.h" 45 #include "vtls/vtls.h" 46 #include "curl_ntlm_core.h" 47 #include "escape.h" 48 #include "curl_endian.h" 49 50 /* The last #include files should be: */ 51 #include "curl_memory.h" 52 #include "memdebug.h" 53 54 /* Local API functions */ 55 static CURLcode smb_setup_connection(struct connectdata *conn); 56 static CURLcode smb_connect(struct connectdata *conn, bool *done); 57 static CURLcode smb_connection_state(struct connectdata *conn, bool *done); 58 static CURLcode smb_request_state(struct connectdata *conn, bool *done); 59 static CURLcode smb_done(struct connectdata *conn, CURLcode status, 60 bool premature); 61 static CURLcode smb_disconnect(struct connectdata *conn, bool dead); 62 static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, 63 int numsocks); 64 static CURLcode smb_parse_url_path(struct connectdata *conn); 65 66 /* 67 * SMB handler interface 68 */ 69 const struct Curl_handler Curl_handler_smb = { 70 "SMB", /* scheme */ 71 smb_setup_connection, /* setup_connection */ 72 ZERO_NULL, /* do_it */ 73 smb_done, /* done */ 74 ZERO_NULL, /* do_more */ 75 smb_connect, /* connect_it */ 76 smb_connection_state, /* connecting */ 77 smb_request_state, /* doing */ 78 smb_getsock, /* proto_getsock */ 79 smb_getsock, /* doing_getsock */ 80 ZERO_NULL, /* domore_getsock */ 81 ZERO_NULL, /* perform_getsock */ 82 smb_disconnect, /* disconnect */ 83 ZERO_NULL, /* readwrite */ 84 PORT_SMB, /* defport */ 85 CURLPROTO_SMB, /* protocol */ 86 PROTOPT_NONE /* flags */ 87 }; 88 89 #ifdef USE_SSL 90 /* 91 * SMBS handler interface 92 */ 93 const struct Curl_handler Curl_handler_smbs = { 94 "SMBS", /* scheme */ 95 smb_setup_connection, /* setup_connection */ 96 ZERO_NULL, /* do_it */ 97 smb_done, /* done */ 98 ZERO_NULL, /* do_more */ 99 smb_connect, /* connect_it */ 100 smb_connection_state, /* connecting */ 101 smb_request_state, /* doing */ 102 smb_getsock, /* proto_getsock */ 103 smb_getsock, /* doing_getsock */ 104 ZERO_NULL, /* domore_getsock */ 105 ZERO_NULL, /* perform_getsock */ 106 smb_disconnect, /* disconnect */ 107 ZERO_NULL, /* readwrite */ 108 PORT_SMBS, /* defport */ 109 CURLPROTO_SMBS, /* protocol */ 110 PROTOPT_SSL /* flags */ 111 }; 112 #endif 113 114 #define MAX_PAYLOAD_SIZE 0x8000 115 #define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) 116 #define CLIENTNAME "curl" 117 #define SERVICENAME "?????" 118 119 /* Append a string to an SMB message */ 120 #define MSGCAT(str) \ 121 strcpy(p, (str)); \ 122 p += strlen(str); 123 124 /* Append a null-terminated string to an SMB message */ 125 #define MSGCATNULL(str) \ 126 strcpy(p, (str)); \ 127 p += strlen(str) + 1; 128 129 /* SMB is mostly little endian */ 130 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 131 defined(__OS400__) 132 static unsigned short smb_swap16(unsigned short x) 133 { 134 return (x << 8) | ((x >> 8) & 0xff); 135 } 136 137 static unsigned int smb_swap32(unsigned int x) 138 { 139 return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | 140 ((x >> 24) & 0xff); 141 } 142 143 #ifdef HAVE_LONGLONG 144 static unsigned long long smb_swap64(unsigned long long x) 145 { 146 return ((unsigned long long)smb_swap32(x) << 32) | smb_swap32(x >> 32); 147 } 148 #else 149 static unsigned __int64 smb_swap64(unsigned __int64 x) 150 { 151 return ((unsigned __int64)smb_swap32(x) << 32) | smb_swap32(x >> 32); 152 } 153 #endif 154 #else 155 # define smb_swap16(x) (x) 156 # define smb_swap32(x) (x) 157 # define smb_swap64(x) (x) 158 #endif 159 160 /* SMB request state */ 161 enum smb_req_state { 162 SMB_REQUESTING, 163 SMB_TREE_CONNECT, 164 SMB_OPEN, 165 SMB_DOWNLOAD, 166 SMB_UPLOAD, 167 SMB_CLOSE, 168 SMB_TREE_DISCONNECT, 169 SMB_DONE 170 }; 171 172 /* SMB request data */ 173 struct smb_request { 174 enum smb_req_state state; 175 char *share; 176 char *path; 177 unsigned short tid; /* Even if we connect to the same tree as another */ 178 unsigned short fid; /* request, the tid will be different */ 179 CURLcode result; 180 }; 181 182 static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) 183 { 184 struct smb_conn *smb = &conn->proto.smbc; 185 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 186 /* For debug purposes */ 187 static const char * const names[] = { 188 "SMB_NOT_CONNECTED", 189 "SMB_CONNECTING", 190 "SMB_NEGOTIATE", 191 "SMB_SETUP", 192 "SMB_CONNECTED", 193 /* LAST */ 194 }; 195 196 if(smb->state != newstate) 197 infof(conn->data, "SMB conn %p state change from %s to %s\n", 198 (void *)smb, names[smb->state], names[newstate]); 199 #endif 200 201 smb->state = newstate; 202 } 203 204 static void request_state(struct connectdata *conn, 205 enum smb_req_state newstate) 206 { 207 struct smb_request *req = conn->data->req.protop; 208 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 209 /* For debug purposes */ 210 static const char * const names[] = { 211 "SMB_REQUESTING", 212 "SMB_TREE_CONNECT", 213 "SMB_OPEN", 214 "SMB_DOWNLOAD", 215 "SMB_UPLOAD", 216 "SMB_CLOSE", 217 "SMB_TREE_DISCONNECT", 218 "SMB_DONE", 219 /* LAST */ 220 }; 221 222 if(req->state != newstate) 223 infof(conn->data, "SMB request %p state change from %s to %s\n", 224 (void *)req, names[req->state], names[newstate]); 225 #endif 226 227 req->state = newstate; 228 } 229 230 static CURLcode smb_setup_connection(struct connectdata *conn) 231 { 232 struct smb_request *req; 233 234 /* Initialize the request state */ 235 conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); 236 if(!req) 237 return CURLE_OUT_OF_MEMORY; 238 239 /* Parse the URL path */ 240 return smb_parse_url_path(conn); 241 } 242 243 static CURLcode smb_connect(struct connectdata *conn, bool *done) 244 { 245 struct smb_conn *smbc = &conn->proto.smbc; 246 char *slash; 247 248 (void) done; 249 250 /* Check we have a username and password to authenticate with */ 251 if(!conn->bits.user_passwd) 252 return CURLE_LOGIN_DENIED; 253 254 /* Initialize the connection state */ 255 memset(smbc, 0, sizeof(*smbc)); 256 smbc->state = SMB_CONNECTING; 257 smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); 258 if(!smbc->recv_buf) 259 return CURLE_OUT_OF_MEMORY; 260 261 /* Multiple requests are allowed with this connection */ 262 connkeep(conn, "SMB default"); 263 264 /* Parse the username, domain, and password */ 265 slash = strchr(conn->user, '/'); 266 if(!slash) 267 slash = strchr(conn->user, '\\'); 268 269 if(slash) { 270 smbc->user = slash + 1; 271 smbc->domain = strdup(conn->user); 272 if(!smbc->domain) 273 return CURLE_OUT_OF_MEMORY; 274 smbc->domain[slash - conn->user] = 0; 275 } 276 else { 277 smbc->user = conn->user; 278 smbc->domain = strdup(conn->host.name); 279 if(!smbc->domain) 280 return CURLE_OUT_OF_MEMORY; 281 } 282 283 return CURLE_OK; 284 } 285 286 static CURLcode smb_recv_message(struct connectdata *conn, void **msg) 287 { 288 struct smb_conn *smbc = &conn->proto.smbc; 289 char *buf = smbc->recv_buf; 290 ssize_t bytes_read; 291 size_t nbt_size; 292 size_t msg_size; 293 size_t len = MAX_MESSAGE_SIZE - smbc->got; 294 CURLcode result; 295 296 result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); 297 if(result) 298 return result; 299 300 if(!bytes_read) 301 return CURLE_OK; 302 303 smbc->got += bytes_read; 304 305 /* Check for a 32-bit nbt header */ 306 if(smbc->got < sizeof(unsigned int)) 307 return CURLE_OK; 308 309 nbt_size = Curl_read16_be((unsigned char *)(buf + sizeof(unsigned short))) + 310 sizeof(unsigned int); 311 if(smbc->got < nbt_size) 312 return CURLE_OK; 313 314 msg_size = sizeof(struct smb_header); 315 if(nbt_size >= msg_size + 1) { 316 /* Add the word count */ 317 msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); 318 if(nbt_size >= msg_size + sizeof(unsigned short)) { 319 /* Add the byte count */ 320 msg_size += sizeof(unsigned short) + 321 Curl_read16_le((unsigned char *)&buf[msg_size]); 322 if(nbt_size < msg_size) 323 return CURLE_READ_ERROR; 324 } 325 } 326 327 *msg = buf; 328 329 return CURLE_OK; 330 } 331 332 static void smb_pop_message(struct connectdata *conn) 333 { 334 struct smb_conn *smbc = &conn->proto.smbc; 335 336 smbc->got = 0; 337 } 338 339 static void smb_format_message(struct connectdata *conn, struct smb_header *h, 340 unsigned char cmd, size_t len) 341 { 342 struct smb_conn *smbc = &conn->proto.smbc; 343 struct smb_request *req = conn->data->req.protop; 344 unsigned int pid; 345 346 memset(h, 0, sizeof(*h)); 347 h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + 348 len)); 349 memcpy((char *)h->magic, "\xffSMB", 4); 350 h->command = cmd; 351 h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; 352 h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); 353 h->uid = smb_swap16(smbc->uid); 354 h->tid = smb_swap16(req->tid); 355 pid = getpid(); 356 h->pid_high = smb_swap16((unsigned short)(pid >> 16)); 357 h->pid = smb_swap16((unsigned short) pid); 358 } 359 360 static CURLcode smb_send(struct connectdata *conn, ssize_t len, 361 size_t upload_size) 362 { 363 struct smb_conn *smbc = &conn->proto.smbc; 364 ssize_t bytes_written; 365 CURLcode result; 366 367 result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer, 368 len, &bytes_written); 369 if(result) 370 return result; 371 372 if(bytes_written != len) { 373 smbc->send_size = len; 374 smbc->sent = bytes_written; 375 } 376 377 smbc->upload_size = upload_size; 378 379 return CURLE_OK; 380 } 381 382 static CURLcode smb_flush(struct connectdata *conn) 383 { 384 struct smb_conn *smbc = &conn->proto.smbc; 385 ssize_t bytes_written; 386 ssize_t len = smbc->send_size - smbc->sent; 387 CURLcode result; 388 389 if(!smbc->send_size) 390 return CURLE_OK; 391 392 result = Curl_write(conn, FIRSTSOCKET, 393 conn->data->state.uploadbuffer + smbc->sent, 394 len, &bytes_written); 395 if(result) 396 return result; 397 398 if(bytes_written != len) 399 smbc->sent += bytes_written; 400 else 401 smbc->send_size = 0; 402 403 return CURLE_OK; 404 } 405 406 static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd, 407 const void *msg, size_t msg_len) 408 { 409 smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer, 410 cmd, msg_len); 411 memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header), 412 msg, msg_len); 413 414 return smb_send(conn, sizeof(struct smb_header) + msg_len, 0); 415 } 416 417 static CURLcode smb_send_negotiate(struct connectdata *conn) 418 { 419 const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; 420 421 return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15); 422 } 423 424 static CURLcode smb_send_setup(struct connectdata *conn) 425 { 426 struct smb_conn *smbc = &conn->proto.smbc; 427 struct smb_setup msg; 428 char *p = msg.bytes; 429 unsigned char lm_hash[21]; 430 unsigned char lm[24]; 431 unsigned char nt_hash[21]; 432 unsigned char nt[24]; 433 434 size_t byte_count = sizeof(lm) + sizeof(nt); 435 byte_count += strlen(smbc->user) + strlen(smbc->domain); 436 byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ 437 if(byte_count > sizeof(msg.bytes)) 438 return CURLE_FILESIZE_EXCEEDED; 439 440 Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); 441 Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); 442 #if USE_NTRESPONSES 443 Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); 444 Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); 445 #else 446 memset(nt, 0, sizeof(nt)); 447 #endif 448 449 memset(&msg, 0, sizeof(msg)); 450 msg.word_count = SMB_WC_SETUP_ANDX; 451 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 452 msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); 453 msg.max_mpx_count = smb_swap16(1); 454 msg.vc_number = smb_swap16(1); 455 msg.session_key = smb_swap32(smbc->session_key); 456 msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); 457 msg.lengths[0] = smb_swap16(sizeof(lm)); 458 msg.lengths[1] = smb_swap16(sizeof(nt)); 459 memcpy(p, lm, sizeof(lm)); 460 p += sizeof(lm); 461 memcpy(p, nt, sizeof(nt)); 462 p += sizeof(nt); 463 MSGCATNULL(smbc->user); 464 MSGCATNULL(smbc->domain); 465 MSGCATNULL(OS); 466 MSGCATNULL(CLIENTNAME); 467 byte_count = p - msg.bytes; 468 msg.byte_count = smb_swap16((unsigned short)byte_count); 469 470 return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg, 471 sizeof(msg) - sizeof(msg.bytes) + byte_count); 472 } 473 474 static CURLcode smb_send_tree_connect(struct connectdata *conn) 475 { 476 struct smb_request *req = conn->data->req.protop; 477 struct smb_tree_connect msg; 478 char *p = msg.bytes; 479 480 size_t byte_count = strlen(conn->host.name) + strlen(req->share); 481 byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ 482 if(byte_count > sizeof(msg.bytes)) 483 return CURLE_FILESIZE_EXCEEDED; 484 485 memset(&msg, 0, sizeof(msg)); 486 msg.word_count = SMB_WC_TREE_CONNECT_ANDX; 487 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 488 msg.pw_len = 0; 489 MSGCAT("\\\\"); 490 MSGCAT(conn->host.name); 491 MSGCAT("\\"); 492 MSGCATNULL(req->share); 493 MSGCATNULL(SERVICENAME); /* Match any type of service */ 494 byte_count = p - msg.bytes; 495 msg.byte_count = smb_swap16((unsigned short)byte_count); 496 497 return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg, 498 sizeof(msg) - sizeof(msg.bytes) + byte_count); 499 } 500 501 static CURLcode smb_send_open(struct connectdata *conn) 502 { 503 struct smb_request *req = conn->data->req.protop; 504 struct smb_nt_create msg; 505 size_t byte_count; 506 507 if((strlen(req->path) + 1) > sizeof(msg.bytes)) 508 return CURLE_FILESIZE_EXCEEDED; 509 510 memset(&msg, 0, sizeof(msg)); 511 msg.word_count = SMB_WC_NT_CREATE_ANDX; 512 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 513 byte_count = strlen(req->path); 514 msg.name_length = smb_swap16((unsigned short)byte_count); 515 msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); 516 if(conn->data->set.upload) { 517 msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); 518 msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); 519 } 520 else { 521 msg.access = smb_swap32(SMB_GENERIC_READ); 522 msg.create_disposition = smb_swap32(SMB_FILE_OPEN); 523 } 524 msg.byte_count = smb_swap16((unsigned short) ++byte_count); 525 strcpy(msg.bytes, req->path); 526 527 return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg, 528 sizeof(msg) - sizeof(msg.bytes) + byte_count); 529 } 530 531 static CURLcode smb_send_close(struct connectdata *conn) 532 { 533 struct smb_request *req = conn->data->req.protop; 534 struct smb_close msg; 535 536 memset(&msg, 0, sizeof(msg)); 537 msg.word_count = SMB_WC_CLOSE; 538 msg.fid = smb_swap16(req->fid); 539 540 return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg)); 541 } 542 543 static CURLcode smb_send_tree_disconnect(struct connectdata *conn) 544 { 545 struct smb_tree_disconnect msg; 546 547 memset(&msg, 0, sizeof(msg)); 548 549 return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); 550 } 551 552 static CURLcode smb_send_read(struct connectdata *conn) 553 { 554 struct smb_request *req = conn->data->req.protop; 555 curl_off_t offset = conn->data->req.offset; 556 struct smb_read msg; 557 558 memset(&msg, 0, sizeof(msg)); 559 msg.word_count = SMB_WC_READ_ANDX; 560 msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 561 msg.fid = smb_swap16(req->fid); 562 msg.offset = smb_swap32((unsigned int) offset); 563 msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); 564 msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 565 msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 566 567 return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg)); 568 } 569 570 static CURLcode smb_send_write(struct connectdata *conn) 571 { 572 struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer; 573 struct smb_request *req = conn->data->req.protop; 574 curl_off_t offset = conn->data->req.offset; 575 576 curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount; 577 if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ 578 upload_size = MAX_PAYLOAD_SIZE - 1; 579 580 memset(msg, 0, sizeof(*msg)); 581 msg->word_count = SMB_WC_WRITE_ANDX; 582 msg->andx.command = SMB_COM_NO_ANDX_COMMAND; 583 msg->fid = smb_swap16(req->fid); 584 msg->offset = smb_swap32((unsigned int) offset); 585 msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); 586 msg->data_length = smb_swap16((unsigned short) upload_size); 587 msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); 588 msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); 589 590 smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX, 591 sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); 592 593 return smb_send(conn, sizeof(*msg), (size_t) upload_size); 594 } 595 596 static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) 597 { 598 struct smb_conn *smbc = &conn->proto.smbc; 599 CURLcode result; 600 601 /* Check if there is data in the transfer buffer */ 602 if(!smbc->send_size && smbc->upload_size) { 603 int nread = smbc->upload_size > BUFSIZE ? BUFSIZE : 604 (int) smbc->upload_size; 605 conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; 606 result = Curl_fillreadbuffer(conn, nread, &nread); 607 if(result && result != CURLE_AGAIN) 608 return result; 609 if(!nread) 610 return CURLE_OK; 611 612 smbc->upload_size -= nread; 613 smbc->send_size = nread; 614 smbc->sent = 0; 615 } 616 617 /* Check if there is data to send */ 618 if(smbc->send_size) { 619 result = smb_flush(conn); 620 if(result) 621 return result; 622 } 623 624 /* Check if there is still data to be sent */ 625 if(smbc->send_size || smbc->upload_size) 626 return CURLE_AGAIN; 627 628 return smb_recv_message(conn, msg); 629 } 630 631 static CURLcode smb_connection_state(struct connectdata *conn, bool *done) 632 { 633 struct smb_conn *smbc = &conn->proto.smbc; 634 struct smb_negotiate_response *nrsp; 635 struct smb_header *h; 636 CURLcode result; 637 void *msg = NULL; 638 639 if(smbc->state == SMB_CONNECTING) { 640 #ifdef USE_SSL 641 if((conn->handler->flags & PROTOPT_SSL)) { 642 bool ssl_done; 643 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done); 644 if(result && result != CURLE_AGAIN) 645 return result; 646 if(!ssl_done) 647 return CURLE_OK; 648 } 649 #endif 650 651 result = smb_send_negotiate(conn); 652 if(result) { 653 connclose(conn, "SMB: failed to send negotiate message"); 654 return result; 655 } 656 657 conn_state(conn, SMB_NEGOTIATE); 658 } 659 660 /* Send the previous message and check for a response */ 661 result = smb_send_and_recv(conn, &msg); 662 if(result && result != CURLE_AGAIN) { 663 connclose(conn, "SMB: failed to communicate"); 664 return result; 665 } 666 667 if(!msg) 668 return CURLE_OK; 669 670 h = msg; 671 672 switch(smbc->state) { 673 case SMB_NEGOTIATE: 674 if(h->status) { 675 connclose(conn, "SMB: negotiation failed"); 676 return CURLE_COULDNT_CONNECT; 677 } 678 nrsp = msg; 679 memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); 680 smbc->session_key = smb_swap32(nrsp->session_key); 681 result = smb_send_setup(conn); 682 if(result) { 683 connclose(conn, "SMB: failed to send setup message"); 684 return result; 685 } 686 conn_state(conn, SMB_SETUP); 687 break; 688 689 case SMB_SETUP: 690 if(h->status) { 691 connclose(conn, "SMB: authentication failed"); 692 return CURLE_LOGIN_DENIED; 693 } 694 smbc->uid = smb_swap16(h->uid); 695 conn_state(conn, SMB_CONNECTED); 696 *done = true; 697 break; 698 699 default: 700 smb_pop_message(conn); 701 return CURLE_OK; /* ignore */ 702 } 703 704 smb_pop_message(conn); 705 706 return CURLE_OK; 707 } 708 709 static CURLcode smb_request_state(struct connectdata *conn, bool *done) 710 { 711 struct smb_request *req = conn->data->req.protop; 712 struct smb_header *h; 713 enum smb_req_state next_state = SMB_DONE; 714 unsigned short len; 715 unsigned short off; 716 CURLcode result; 717 void *msg = NULL; 718 719 /* Start the request */ 720 if(req->state == SMB_REQUESTING) { 721 result = smb_send_tree_connect(conn); 722 if(result) { 723 connclose(conn, "SMB: failed to send tree connect message"); 724 return result; 725 } 726 727 request_state(conn, SMB_TREE_CONNECT); 728 } 729 730 /* Send the previous message and check for a response */ 731 result = smb_send_and_recv(conn, &msg); 732 if(result && result != CURLE_AGAIN) { 733 connclose(conn, "SMB: failed to communicate"); 734 return result; 735 } 736 737 if(!msg) 738 return CURLE_OK; 739 740 h = msg; 741 742 switch(req->state) { 743 case SMB_TREE_CONNECT: 744 if(h->status) { 745 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 746 if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 747 req->result = CURLE_REMOTE_ACCESS_DENIED; 748 break; 749 } 750 req->tid = smb_swap16(h->tid); 751 next_state = SMB_OPEN; 752 break; 753 754 case SMB_OPEN: 755 if(h->status) { 756 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 757 next_state = SMB_TREE_DISCONNECT; 758 break; 759 } 760 req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid); 761 conn->data->req.offset = 0; 762 if(conn->data->set.upload) { 763 conn->data->req.size = conn->data->state.infilesize; 764 Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); 765 next_state = SMB_UPLOAD; 766 } 767 else { 768 conn->data->req.size = 769 smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file); 770 Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); 771 next_state = SMB_DOWNLOAD; 772 } 773 break; 774 775 case SMB_DOWNLOAD: 776 if(h->status) { 777 req->result = CURLE_RECV_ERROR; 778 next_state = SMB_CLOSE; 779 break; 780 } 781 len = Curl_read16_le(((unsigned char *) msg) + 782 sizeof(struct smb_header) + 11); 783 off = Curl_read16_le(((unsigned char *) msg) + 784 sizeof(struct smb_header) + 13); 785 if(len > 0) { 786 struct smb_conn *smbc = &conn->proto.smbc; 787 if(off + sizeof(unsigned int) + len > smbc->got) { 788 failf(conn->data, "Invalid input packet"); 789 result = CURLE_RECV_ERROR; 790 } 791 else 792 result = Curl_client_write(conn, CLIENTWRITE_BODY, 793 (char *)msg + off + sizeof(unsigned int), 794 len); 795 if(result) { 796 req->result = result; 797 next_state = SMB_CLOSE; 798 break; 799 } 800 } 801 conn->data->req.bytecount += len; 802 conn->data->req.offset += len; 803 Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); 804 next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; 805 break; 806 807 case SMB_UPLOAD: 808 if(h->status) { 809 req->result = CURLE_UPLOAD_FAILED; 810 next_state = SMB_CLOSE; 811 break; 812 } 813 len = Curl_read16_le(((unsigned char *) msg) + 814 sizeof(struct smb_header) + 5); 815 conn->data->req.bytecount += len; 816 conn->data->req.offset += len; 817 Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); 818 if(conn->data->req.bytecount >= conn->data->req.size) 819 next_state = SMB_CLOSE; 820 else 821 next_state = SMB_UPLOAD; 822 break; 823 824 case SMB_CLOSE: 825 /* We don't care if the close failed, proceed to tree disconnect anyway */ 826 next_state = SMB_TREE_DISCONNECT; 827 break; 828 829 case SMB_TREE_DISCONNECT: 830 next_state = SMB_DONE; 831 break; 832 833 default: 834 smb_pop_message(conn); 835 return CURLE_OK; /* ignore */ 836 } 837 838 smb_pop_message(conn); 839 840 switch(next_state) { 841 case SMB_OPEN: 842 result = smb_send_open(conn); 843 break; 844 845 case SMB_DOWNLOAD: 846 result = smb_send_read(conn); 847 break; 848 849 case SMB_UPLOAD: 850 result = smb_send_write(conn); 851 break; 852 853 case SMB_CLOSE: 854 result = smb_send_close(conn); 855 break; 856 857 case SMB_TREE_DISCONNECT: 858 result = smb_send_tree_disconnect(conn); 859 break; 860 861 case SMB_DONE: 862 result = req->result; 863 *done = true; 864 break; 865 866 default: 867 break; 868 } 869 870 if(result) { 871 connclose(conn, "SMB: failed to send message"); 872 return result; 873 } 874 875 request_state(conn, next_state); 876 877 return CURLE_OK; 878 } 879 880 static CURLcode smb_done(struct connectdata *conn, CURLcode status, 881 bool premature) 882 { 883 struct smb_request *req = conn->data->req.protop; 884 885 (void) premature; 886 887 Curl_safefree(req->share); 888 Curl_safefree(conn->data->req.protop); 889 890 return status; 891 } 892 893 static CURLcode smb_disconnect(struct connectdata *conn, bool dead) 894 { 895 struct smb_conn *smbc = &conn->proto.smbc; 896 struct smb_request *req = conn->data->req.protop; 897 898 (void) dead; 899 900 Curl_safefree(smbc->domain); 901 Curl_safefree(smbc->recv_buf); 902 903 /* smb_done is not always called, so cleanup the request */ 904 if(req) { 905 Curl_safefree(req->share); 906 Curl_safefree(conn->data->req.protop); 907 } 908 909 return CURLE_OK; 910 } 911 912 static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, 913 int numsocks) 914 { 915 struct smb_conn *smbc = &conn->proto.smbc; 916 917 if(!numsocks) 918 return GETSOCK_BLANK; 919 920 socks[0] = conn->sock[FIRSTSOCKET]; 921 922 if(smbc->send_size || smbc->upload_size) 923 return GETSOCK_WRITESOCK(0); 924 925 return GETSOCK_READSOCK(0); 926 } 927 928 static CURLcode smb_parse_url_path(struct connectdata *conn) 929 { 930 CURLcode result = CURLE_OK; 931 struct SessionHandle *data = conn->data; 932 struct smb_request *req = data->req.protop; 933 char *path; 934 char *slash; 935 936 /* URL decode the path */ 937 result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); 938 if(result) 939 return result; 940 941 /* Parse the path for the share */ 942 req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); 943 if(!req->share) { 944 free(path); 945 946 return CURLE_OUT_OF_MEMORY; 947 } 948 949 slash = strchr(req->share, '/'); 950 if(!slash) 951 slash = strchr(req->share, '\\'); 952 953 /* The share must be present */ 954 if(!slash) { 955 free(path); 956 957 return CURLE_URL_MALFORMAT; 958 } 959 960 /* Parse the path for the file path converting any forward slashes into 961 backslashes */ 962 *slash++ = 0; 963 req->path = slash; 964 for(; *slash; slash++) { 965 if(*slash == '/') 966 *slash = '\\'; 967 } 968 969 free(path); 970 971 return CURLE_OK; 972 } 973 974 #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ 975 976 #endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ 977