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