1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies 9 * Copyright (C) 2016-2018, Daniel Stenberg, <daniel@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 #ifdef CURL_WINDOWS_APP 36 #define getpid GetCurrentProcessId 37 #elif !defined(MSDOS) 38 #define getpid _getpid 39 #endif 40 #endif 41 42 #include "smb.h" 43 #include "urldata.h" 44 #include "sendf.h" 45 #include "multiif.h" 46 #include "connect.h" 47 #include "progress.h" 48 #include "transfer.h" 49 #include "vtls/vtls.h" 50 #include "curl_ntlm_core.h" 51 #include "escape.h" 52 #include "curl_endian.h" 53 54 /* The last #include files should be: */ 55 #include "curl_memory.h" 56 #include "memdebug.h" 57 58 /* Local API functions */ 59 static CURLcode smb_setup_connection(struct connectdata *conn); 60 static CURLcode smb_connect(struct connectdata *conn, bool *done); 61 static CURLcode smb_connection_state(struct connectdata *conn, bool *done); 62 static CURLcode smb_request_state(struct connectdata *conn, bool *done); 63 static CURLcode smb_done(struct connectdata *conn, CURLcode status, 64 bool premature); 65 static CURLcode smb_disconnect(struct connectdata *conn, bool dead); 66 static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, 67 int numsocks); 68 static CURLcode smb_parse_url_path(struct connectdata *conn); 69 70 /* 71 * SMB handler interface 72 */ 73 const struct Curl_handler Curl_handler_smb = { 74 "SMB", /* scheme */ 75 smb_setup_connection, /* setup_connection */ 76 ZERO_NULL, /* do_it */ 77 smb_done, /* done */ 78 ZERO_NULL, /* do_more */ 79 smb_connect, /* connect_it */ 80 smb_connection_state, /* connecting */ 81 smb_request_state, /* doing */ 82 smb_getsock, /* proto_getsock */ 83 smb_getsock, /* doing_getsock */ 84 ZERO_NULL, /* domore_getsock */ 85 ZERO_NULL, /* perform_getsock */ 86 smb_disconnect, /* disconnect */ 87 ZERO_NULL, /* readwrite */ 88 ZERO_NULL, /* connection_check */ 89 PORT_SMB, /* defport */ 90 CURLPROTO_SMB, /* protocol */ 91 PROTOPT_NONE /* flags */ 92 }; 93 94 #ifdef USE_SSL 95 /* 96 * SMBS handler interface 97 */ 98 const struct Curl_handler Curl_handler_smbs = { 99 "SMBS", /* scheme */ 100 smb_setup_connection, /* setup_connection */ 101 ZERO_NULL, /* do_it */ 102 smb_done, /* done */ 103 ZERO_NULL, /* do_more */ 104 smb_connect, /* connect_it */ 105 smb_connection_state, /* connecting */ 106 smb_request_state, /* doing */ 107 smb_getsock, /* proto_getsock */ 108 smb_getsock, /* doing_getsock */ 109 ZERO_NULL, /* domore_getsock */ 110 ZERO_NULL, /* perform_getsock */ 111 smb_disconnect, /* disconnect */ 112 ZERO_NULL, /* readwrite */ 113 ZERO_NULL, /* connection_check */ 114 PORT_SMBS, /* defport */ 115 CURLPROTO_SMBS, /* protocol */ 116 PROTOPT_SSL /* flags */ 117 }; 118 #endif 119 120 #define MAX_PAYLOAD_SIZE 0x8000 121 #define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) 122 #define CLIENTNAME "curl" 123 #define SERVICENAME "?????" 124 125 /* Append a string to an SMB message */ 126 #define MSGCAT(str) \ 127 strcpy(p, (str)); \ 128 p += strlen(str); 129 130 /* Append a null-terminated string to an SMB message */ 131 #define MSGCATNULL(str) \ 132 strcpy(p, (str)); \ 133 p += strlen(str) + 1; 134 135 /* SMB is mostly little endian */ 136 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 137 defined(__OS400__) smb_swap16(unsigned short x)138 static unsigned short smb_swap16(unsigned short x) 139 { 140 return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); 141 } 142 smb_swap32(unsigned int x)143 static unsigned int smb_swap32(unsigned int x) 144 { 145 return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | 146 ((x >> 24) & 0xff); 147 } 148 smb_swap64(curl_off_t x)149 static curl_off_t smb_swap64(curl_off_t x) 150 { 151 return ((curl_off_t) smb_swap32((unsigned int) x) << 32) | 152 smb_swap32((unsigned int) (x >> 32)); 153 } 154 155 #else 156 # define smb_swap16(x) (x) 157 # define smb_swap32(x) (x) 158 # define smb_swap64(x) (x) 159 #endif 160 161 /* SMB request state */ 162 enum smb_req_state { 163 SMB_REQUESTING, 164 SMB_TREE_CONNECT, 165 SMB_OPEN, 166 SMB_DOWNLOAD, 167 SMB_UPLOAD, 168 SMB_CLOSE, 169 SMB_TREE_DISCONNECT, 170 SMB_DONE 171 }; 172 173 /* SMB request data */ 174 struct smb_request { 175 enum smb_req_state state; 176 char *share; 177 char *path; 178 unsigned short tid; /* Even if we connect to the same tree as another */ 179 unsigned short fid; /* request, the tid will be different */ 180 CURLcode result; 181 }; 182 conn_state(struct connectdata * conn,enum smb_conn_state newstate)183 static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) 184 { 185 struct smb_conn *smb = &conn->proto.smbc; 186 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 187 /* For debug purposes */ 188 static const char * const names[] = { 189 "SMB_NOT_CONNECTED", 190 "SMB_CONNECTING", 191 "SMB_NEGOTIATE", 192 "SMB_SETUP", 193 "SMB_CONNECTED", 194 /* LAST */ 195 }; 196 197 if(smb->state != newstate) 198 infof(conn->data, "SMB conn %p state change from %s to %s\n", 199 (void *)smb, names[smb->state], names[newstate]); 200 #endif 201 202 smb->state = newstate; 203 } 204 request_state(struct connectdata * conn,enum smb_req_state newstate)205 static void request_state(struct connectdata *conn, 206 enum smb_req_state newstate) 207 { 208 struct smb_request *req = conn->data->req.protop; 209 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 210 /* For debug purposes */ 211 static const char * const names[] = { 212 "SMB_REQUESTING", 213 "SMB_TREE_CONNECT", 214 "SMB_OPEN", 215 "SMB_DOWNLOAD", 216 "SMB_UPLOAD", 217 "SMB_CLOSE", 218 "SMB_TREE_DISCONNECT", 219 "SMB_DONE", 220 /* LAST */ 221 }; 222 223 if(req->state != newstate) 224 infof(conn->data, "SMB request %p state change from %s to %s\n", 225 (void *)req, names[req->state], names[newstate]); 226 #endif 227 228 req->state = newstate; 229 } 230 smb_setup_connection(struct connectdata * conn)231 static CURLcode smb_setup_connection(struct connectdata *conn) 232 { 233 struct smb_request *req; 234 235 /* Initialize the request state */ 236 conn->data->req.protop = req = calloc(1, sizeof(struct smb_request)); 237 if(!req) 238 return CURLE_OUT_OF_MEMORY; 239 240 /* Parse the URL path */ 241 return smb_parse_url_path(conn); 242 } 243 smb_connect(struct connectdata * conn,bool * done)244 static CURLcode smb_connect(struct connectdata *conn, bool *done) 245 { 246 struct smb_conn *smbc = &conn->proto.smbc; 247 char *slash; 248 249 (void) done; 250 251 /* Check we have a username and password to authenticate with */ 252 if(!conn->bits.user_passwd) 253 return CURLE_LOGIN_DENIED; 254 255 /* Initialize the connection state */ 256 memset(smbc, 0, sizeof(*smbc)); 257 smbc->state = SMB_CONNECTING; 258 smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); 259 if(!smbc->recv_buf) 260 return CURLE_OUT_OF_MEMORY; 261 262 /* Multiple requests are allowed with this connection */ 263 connkeep(conn, "SMB default"); 264 265 /* Parse the username, domain, and password */ 266 slash = strchr(conn->user, '/'); 267 if(!slash) 268 slash = strchr(conn->user, '\\'); 269 270 if(slash) { 271 smbc->user = slash + 1; 272 smbc->domain = strdup(conn->user); 273 if(!smbc->domain) 274 return CURLE_OUT_OF_MEMORY; 275 smbc->domain[slash - conn->user] = 0; 276 } 277 else { 278 smbc->user = conn->user; 279 smbc->domain = strdup(conn->host.name); 280 if(!smbc->domain) 281 return CURLE_OUT_OF_MEMORY; 282 } 283 284 return CURLE_OK; 285 } 286 smb_recv_message(struct connectdata * conn,void ** msg)287 static CURLcode smb_recv_message(struct connectdata *conn, void **msg) 288 { 289 struct smb_conn *smbc = &conn->proto.smbc; 290 char *buf = smbc->recv_buf; 291 ssize_t bytes_read; 292 size_t nbt_size; 293 size_t msg_size; 294 size_t len = MAX_MESSAGE_SIZE - smbc->got; 295 CURLcode result; 296 297 result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read); 298 if(result) 299 return result; 300 301 if(!bytes_read) 302 return CURLE_OK; 303 304 smbc->got += bytes_read; 305 306 /* Check for a 32-bit nbt header */ 307 if(smbc->got < sizeof(unsigned int)) 308 return CURLE_OK; 309 310 nbt_size = Curl_read16_be((const unsigned char *) 311 (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((const 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 smb_pop_message(struct connectdata * conn)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 smb_format_message(struct connectdata * conn,struct smb_header * h,unsigned char cmd,size_t len)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 smb_send(struct connectdata * conn,ssize_t len,size_t upload_size)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 smb_flush(struct connectdata * conn)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 smb_send_message(struct connectdata * conn,unsigned char cmd,const void * msg,size_t msg_len)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 smb_send_negotiate(struct connectdata * conn)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 smb_send_setup(struct connectdata * conn)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 #ifdef 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 smb_send_tree_connect(struct connectdata * conn)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 smb_send_open(struct connectdata * conn)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 smb_send_close(struct connectdata * conn)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 smb_send_tree_disconnect(struct connectdata * conn)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 smb_send_read(struct connectdata * conn)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 smb_send_write(struct connectdata * conn)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 smb_send_and_recv(struct connectdata * conn,void ** msg)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 > UPLOAD_BUFSIZE ? UPLOAD_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 smb_connection_state(struct connectdata * conn,bool * done)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 = FALSE; 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 || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) { 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 /* 712 * Convert a timestamp from the Windows world (100 nsec units from 713 * 1 Jan 1601) to Posix time. 714 */ get_posix_time(long * out,curl_off_t timestamp)715 static void get_posix_time(long *out, curl_off_t timestamp) 716 { 717 timestamp -= 116444736000000000; 718 timestamp /= 10000000; 719 *out = (long) timestamp; 720 } 721 smb_request_state(struct connectdata * conn,bool * done)722 static CURLcode smb_request_state(struct connectdata *conn, bool *done) 723 { 724 struct smb_request *req = conn->data->req.protop; 725 struct smb_header *h; 726 struct smb_conn *smbc = &conn->proto.smbc; 727 enum smb_req_state next_state = SMB_DONE; 728 unsigned short len; 729 unsigned short off; 730 CURLcode result; 731 void *msg = NULL; 732 const struct smb_nt_create_response *smb_m; 733 734 /* Start the request */ 735 if(req->state == SMB_REQUESTING) { 736 result = smb_send_tree_connect(conn); 737 if(result) { 738 connclose(conn, "SMB: failed to send tree connect message"); 739 return result; 740 } 741 742 request_state(conn, SMB_TREE_CONNECT); 743 } 744 745 /* Send the previous message and check for a response */ 746 result = smb_send_and_recv(conn, &msg); 747 if(result && result != CURLE_AGAIN) { 748 connclose(conn, "SMB: failed to communicate"); 749 return result; 750 } 751 752 if(!msg) 753 return CURLE_OK; 754 755 h = msg; 756 757 switch(req->state) { 758 case SMB_TREE_CONNECT: 759 if(h->status) { 760 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 761 if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 762 req->result = CURLE_REMOTE_ACCESS_DENIED; 763 break; 764 } 765 req->tid = smb_swap16(h->tid); 766 next_state = SMB_OPEN; 767 break; 768 769 case SMB_OPEN: 770 if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { 771 req->result = CURLE_REMOTE_FILE_NOT_FOUND; 772 next_state = SMB_TREE_DISCONNECT; 773 break; 774 } 775 smb_m = (const struct smb_nt_create_response*) msg; 776 req->fid = smb_swap16(smb_m->fid); 777 conn->data->req.offset = 0; 778 if(conn->data->set.upload) { 779 conn->data->req.size = conn->data->state.infilesize; 780 Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); 781 next_state = SMB_UPLOAD; 782 } 783 else { 784 smb_m = (const struct smb_nt_create_response*) msg; 785 conn->data->req.size = smb_swap64(smb_m->end_of_file); 786 Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size); 787 if(conn->data->set.get_filetime) 788 get_posix_time(&conn->data->info.filetime, smb_m->last_change_time); 789 next_state = SMB_DOWNLOAD; 790 } 791 break; 792 793 case SMB_DOWNLOAD: 794 if(h->status || smbc->got < sizeof(struct smb_header) + 14) { 795 req->result = CURLE_RECV_ERROR; 796 next_state = SMB_CLOSE; 797 break; 798 } 799 len = Curl_read16_le(((const unsigned char *) msg) + 800 sizeof(struct smb_header) + 11); 801 off = Curl_read16_le(((const unsigned char *) msg) + 802 sizeof(struct smb_header) + 13); 803 if(len > 0) { 804 if(off + sizeof(unsigned int) + len > smbc->got) { 805 failf(conn->data, "Invalid input packet"); 806 result = CURLE_RECV_ERROR; 807 } 808 else 809 result = Curl_client_write(conn, CLIENTWRITE_BODY, 810 (char *)msg + off + sizeof(unsigned int), 811 len); 812 if(result) { 813 req->result = result; 814 next_state = SMB_CLOSE; 815 break; 816 } 817 } 818 conn->data->req.bytecount += len; 819 conn->data->req.offset += len; 820 Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount); 821 next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; 822 break; 823 824 case SMB_UPLOAD: 825 if(h->status || smbc->got < sizeof(struct smb_header) + 6) { 826 req->result = CURLE_UPLOAD_FAILED; 827 next_state = SMB_CLOSE; 828 break; 829 } 830 len = Curl_read16_le(((const unsigned char *) msg) + 831 sizeof(struct smb_header) + 5); 832 conn->data->req.bytecount += len; 833 conn->data->req.offset += len; 834 Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount); 835 if(conn->data->req.bytecount >= conn->data->req.size) 836 next_state = SMB_CLOSE; 837 else 838 next_state = SMB_UPLOAD; 839 break; 840 841 case SMB_CLOSE: 842 /* We don't care if the close failed, proceed to tree disconnect anyway */ 843 next_state = SMB_TREE_DISCONNECT; 844 break; 845 846 case SMB_TREE_DISCONNECT: 847 next_state = SMB_DONE; 848 break; 849 850 default: 851 smb_pop_message(conn); 852 return CURLE_OK; /* ignore */ 853 } 854 855 smb_pop_message(conn); 856 857 switch(next_state) { 858 case SMB_OPEN: 859 result = smb_send_open(conn); 860 break; 861 862 case SMB_DOWNLOAD: 863 result = smb_send_read(conn); 864 break; 865 866 case SMB_UPLOAD: 867 result = smb_send_write(conn); 868 break; 869 870 case SMB_CLOSE: 871 result = smb_send_close(conn); 872 break; 873 874 case SMB_TREE_DISCONNECT: 875 result = smb_send_tree_disconnect(conn); 876 break; 877 878 case SMB_DONE: 879 result = req->result; 880 *done = true; 881 break; 882 883 default: 884 break; 885 } 886 887 if(result) { 888 connclose(conn, "SMB: failed to send message"); 889 return result; 890 } 891 892 request_state(conn, next_state); 893 894 return CURLE_OK; 895 } 896 smb_done(struct connectdata * conn,CURLcode status,bool premature)897 static CURLcode smb_done(struct connectdata *conn, CURLcode status, 898 bool premature) 899 { 900 struct smb_request *req = conn->data->req.protop; 901 902 (void) premature; 903 904 Curl_safefree(req->share); 905 Curl_safefree(conn->data->req.protop); 906 907 return status; 908 } 909 smb_disconnect(struct connectdata * conn,bool dead)910 static CURLcode smb_disconnect(struct connectdata *conn, bool dead) 911 { 912 struct smb_conn *smbc = &conn->proto.smbc; 913 struct smb_request *req = conn->data->req.protop; 914 915 (void) dead; 916 917 Curl_safefree(smbc->domain); 918 Curl_safefree(smbc->recv_buf); 919 920 /* smb_done is not always called, so cleanup the request */ 921 if(req) { 922 Curl_safefree(req->share); 923 } 924 925 return CURLE_OK; 926 } 927 smb_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)928 static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, 929 int numsocks) 930 { 931 struct smb_conn *smbc = &conn->proto.smbc; 932 933 if(!numsocks) 934 return GETSOCK_BLANK; 935 936 socks[0] = conn->sock[FIRSTSOCKET]; 937 938 if(smbc->send_size || smbc->upload_size) 939 return GETSOCK_WRITESOCK(0); 940 941 return GETSOCK_READSOCK(0); 942 } 943 smb_parse_url_path(struct connectdata * conn)944 static CURLcode smb_parse_url_path(struct connectdata *conn) 945 { 946 CURLcode result = CURLE_OK; 947 struct Curl_easy *data = conn->data; 948 struct smb_request *req = data->req.protop; 949 char *path; 950 char *slash; 951 952 /* URL decode the path */ 953 result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); 954 if(result) 955 return result; 956 957 /* Parse the path for the share */ 958 req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); 959 if(!req->share) { 960 free(path); 961 962 return CURLE_OUT_OF_MEMORY; 963 } 964 965 slash = strchr(req->share, '/'); 966 if(!slash) 967 slash = strchr(req->share, '\\'); 968 969 /* The share must be present */ 970 if(!slash) { 971 free(path); 972 973 return CURLE_URL_MALFORMAT; 974 } 975 976 /* Parse the path for the file path converting any forward slashes into 977 backslashes */ 978 *slash++ = 0; 979 req->path = slash; 980 for(; *slash; slash++) { 981 if(*slash == '/') 982 *slash = '\\'; 983 } 984 985 free(path); 986 987 return CURLE_OK; 988 } 989 990 #endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */ 991 992 #endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */ 993