113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * Copyright (C) Bill Nagel <wnagel@tycoint.com>, Exacq Technologies 1013498266Sopenharmony_ci * 1113498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1213498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1313498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1413498266Sopenharmony_ci * 1513498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1613498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1713498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1813498266Sopenharmony_ci * 1913498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 2013498266Sopenharmony_ci * KIND, either express or implied. 2113498266Sopenharmony_ci * 2213498266Sopenharmony_ci * SPDX-License-Identifier: curl 2313498266Sopenharmony_ci * 2413498266Sopenharmony_ci ***************************************************************************/ 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#include "curl_setup.h" 2713498266Sopenharmony_ci 2813498266Sopenharmony_ci#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci#ifdef _WIN32 3113498266Sopenharmony_ci#define getpid GetCurrentProcessId 3213498266Sopenharmony_ci#endif 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci#include "smb.h" 3513498266Sopenharmony_ci#include "urldata.h" 3613498266Sopenharmony_ci#include "sendf.h" 3713498266Sopenharmony_ci#include "multiif.h" 3813498266Sopenharmony_ci#include "cfilters.h" 3913498266Sopenharmony_ci#include "connect.h" 4013498266Sopenharmony_ci#include "progress.h" 4113498266Sopenharmony_ci#include "transfer.h" 4213498266Sopenharmony_ci#include "vtls/vtls.h" 4313498266Sopenharmony_ci#include "curl_ntlm_core.h" 4413498266Sopenharmony_ci#include "escape.h" 4513498266Sopenharmony_ci#include "curl_endian.h" 4613498266Sopenharmony_ci 4713498266Sopenharmony_ci/* The last #include files should be: */ 4813498266Sopenharmony_ci#include "curl_memory.h" 4913498266Sopenharmony_ci#include "memdebug.h" 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci/* 5213498266Sopenharmony_ci * Definitions for SMB protocol data structures 5313498266Sopenharmony_ci */ 5413498266Sopenharmony_ci#if defined(_MSC_VER) || defined(__ILEC400__) 5513498266Sopenharmony_ci# define PACK 5613498266Sopenharmony_ci# pragma pack(push) 5713498266Sopenharmony_ci# pragma pack(1) 5813498266Sopenharmony_ci#elif defined(__GNUC__) 5913498266Sopenharmony_ci# define PACK __attribute__((packed)) 6013498266Sopenharmony_ci#else 6113498266Sopenharmony_ci# define PACK 6213498266Sopenharmony_ci#endif 6313498266Sopenharmony_ci 6413498266Sopenharmony_ci#define SMB_COM_CLOSE 0x04 6513498266Sopenharmony_ci#define SMB_COM_READ_ANDX 0x2e 6613498266Sopenharmony_ci#define SMB_COM_WRITE_ANDX 0x2f 6713498266Sopenharmony_ci#define SMB_COM_TREE_DISCONNECT 0x71 6813498266Sopenharmony_ci#define SMB_COM_NEGOTIATE 0x72 6913498266Sopenharmony_ci#define SMB_COM_SETUP_ANDX 0x73 7013498266Sopenharmony_ci#define SMB_COM_TREE_CONNECT_ANDX 0x75 7113498266Sopenharmony_ci#define SMB_COM_NT_CREATE_ANDX 0xa2 7213498266Sopenharmony_ci#define SMB_COM_NO_ANDX_COMMAND 0xff 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci#define SMB_WC_CLOSE 0x03 7513498266Sopenharmony_ci#define SMB_WC_READ_ANDX 0x0c 7613498266Sopenharmony_ci#define SMB_WC_WRITE_ANDX 0x0e 7713498266Sopenharmony_ci#define SMB_WC_SETUP_ANDX 0x0d 7813498266Sopenharmony_ci#define SMB_WC_TREE_CONNECT_ANDX 0x04 7913498266Sopenharmony_ci#define SMB_WC_NT_CREATE_ANDX 0x18 8013498266Sopenharmony_ci 8113498266Sopenharmony_ci#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10 8213498266Sopenharmony_ci#define SMB_FLAGS_CASELESS_PATHNAMES 0x08 8313498266Sopenharmony_ci#define SMB_FLAGS2_UNICODE_STRINGS 0x8000 8413498266Sopenharmony_ci#define SMB_FLAGS2_IS_LONG_NAME 0x0040 8513498266Sopenharmony_ci#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001 8613498266Sopenharmony_ci 8713498266Sopenharmony_ci#define SMB_CAP_LARGE_FILES 0x08 8813498266Sopenharmony_ci#define SMB_GENERIC_WRITE 0x40000000 8913498266Sopenharmony_ci#define SMB_GENERIC_READ 0x80000000 9013498266Sopenharmony_ci#define SMB_FILE_SHARE_ALL 0x07 9113498266Sopenharmony_ci#define SMB_FILE_OPEN 0x01 9213498266Sopenharmony_ci#define SMB_FILE_OVERWRITE_IF 0x05 9313498266Sopenharmony_ci 9413498266Sopenharmony_ci#define SMB_ERR_NOACCESS 0x00050001 9513498266Sopenharmony_ci 9613498266Sopenharmony_cistruct smb_header { 9713498266Sopenharmony_ci unsigned char nbt_type; 9813498266Sopenharmony_ci unsigned char nbt_flags; 9913498266Sopenharmony_ci unsigned short nbt_length; 10013498266Sopenharmony_ci unsigned char magic[4]; 10113498266Sopenharmony_ci unsigned char command; 10213498266Sopenharmony_ci unsigned int status; 10313498266Sopenharmony_ci unsigned char flags; 10413498266Sopenharmony_ci unsigned short flags2; 10513498266Sopenharmony_ci unsigned short pid_high; 10613498266Sopenharmony_ci unsigned char signature[8]; 10713498266Sopenharmony_ci unsigned short pad; 10813498266Sopenharmony_ci unsigned short tid; 10913498266Sopenharmony_ci unsigned short pid; 11013498266Sopenharmony_ci unsigned short uid; 11113498266Sopenharmony_ci unsigned short mid; 11213498266Sopenharmony_ci} PACK; 11313498266Sopenharmony_ci 11413498266Sopenharmony_cistruct smb_negotiate_response { 11513498266Sopenharmony_ci struct smb_header h; 11613498266Sopenharmony_ci unsigned char word_count; 11713498266Sopenharmony_ci unsigned short dialect_index; 11813498266Sopenharmony_ci unsigned char security_mode; 11913498266Sopenharmony_ci unsigned short max_mpx_count; 12013498266Sopenharmony_ci unsigned short max_number_vcs; 12113498266Sopenharmony_ci unsigned int max_buffer_size; 12213498266Sopenharmony_ci unsigned int max_raw_size; 12313498266Sopenharmony_ci unsigned int session_key; 12413498266Sopenharmony_ci unsigned int capabilities; 12513498266Sopenharmony_ci unsigned int system_time_low; 12613498266Sopenharmony_ci unsigned int system_time_high; 12713498266Sopenharmony_ci unsigned short server_time_zone; 12813498266Sopenharmony_ci unsigned char encryption_key_length; 12913498266Sopenharmony_ci unsigned short byte_count; 13013498266Sopenharmony_ci char bytes[1]; 13113498266Sopenharmony_ci} PACK; 13213498266Sopenharmony_ci 13313498266Sopenharmony_cistruct andx { 13413498266Sopenharmony_ci unsigned char command; 13513498266Sopenharmony_ci unsigned char pad; 13613498266Sopenharmony_ci unsigned short offset; 13713498266Sopenharmony_ci} PACK; 13813498266Sopenharmony_ci 13913498266Sopenharmony_cistruct smb_setup { 14013498266Sopenharmony_ci unsigned char word_count; 14113498266Sopenharmony_ci struct andx andx; 14213498266Sopenharmony_ci unsigned short max_buffer_size; 14313498266Sopenharmony_ci unsigned short max_mpx_count; 14413498266Sopenharmony_ci unsigned short vc_number; 14513498266Sopenharmony_ci unsigned int session_key; 14613498266Sopenharmony_ci unsigned short lengths[2]; 14713498266Sopenharmony_ci unsigned int pad; 14813498266Sopenharmony_ci unsigned int capabilities; 14913498266Sopenharmony_ci unsigned short byte_count; 15013498266Sopenharmony_ci char bytes[1024]; 15113498266Sopenharmony_ci} PACK; 15213498266Sopenharmony_ci 15313498266Sopenharmony_cistruct smb_tree_connect { 15413498266Sopenharmony_ci unsigned char word_count; 15513498266Sopenharmony_ci struct andx andx; 15613498266Sopenharmony_ci unsigned short flags; 15713498266Sopenharmony_ci unsigned short pw_len; 15813498266Sopenharmony_ci unsigned short byte_count; 15913498266Sopenharmony_ci char bytes[1024]; 16013498266Sopenharmony_ci} PACK; 16113498266Sopenharmony_ci 16213498266Sopenharmony_cistruct smb_nt_create { 16313498266Sopenharmony_ci unsigned char word_count; 16413498266Sopenharmony_ci struct andx andx; 16513498266Sopenharmony_ci unsigned char pad; 16613498266Sopenharmony_ci unsigned short name_length; 16713498266Sopenharmony_ci unsigned int flags; 16813498266Sopenharmony_ci unsigned int root_fid; 16913498266Sopenharmony_ci unsigned int access; 17013498266Sopenharmony_ci curl_off_t allocation_size; 17113498266Sopenharmony_ci unsigned int ext_file_attributes; 17213498266Sopenharmony_ci unsigned int share_access; 17313498266Sopenharmony_ci unsigned int create_disposition; 17413498266Sopenharmony_ci unsigned int create_options; 17513498266Sopenharmony_ci unsigned int impersonation_level; 17613498266Sopenharmony_ci unsigned char security_flags; 17713498266Sopenharmony_ci unsigned short byte_count; 17813498266Sopenharmony_ci char bytes[1024]; 17913498266Sopenharmony_ci} PACK; 18013498266Sopenharmony_ci 18113498266Sopenharmony_cistruct smb_nt_create_response { 18213498266Sopenharmony_ci struct smb_header h; 18313498266Sopenharmony_ci unsigned char word_count; 18413498266Sopenharmony_ci struct andx andx; 18513498266Sopenharmony_ci unsigned char op_lock_level; 18613498266Sopenharmony_ci unsigned short fid; 18713498266Sopenharmony_ci unsigned int create_disposition; 18813498266Sopenharmony_ci 18913498266Sopenharmony_ci curl_off_t create_time; 19013498266Sopenharmony_ci curl_off_t last_access_time; 19113498266Sopenharmony_ci curl_off_t last_write_time; 19213498266Sopenharmony_ci curl_off_t last_change_time; 19313498266Sopenharmony_ci unsigned int ext_file_attributes; 19413498266Sopenharmony_ci curl_off_t allocation_size; 19513498266Sopenharmony_ci curl_off_t end_of_file; 19613498266Sopenharmony_ci} PACK; 19713498266Sopenharmony_ci 19813498266Sopenharmony_cistruct smb_read { 19913498266Sopenharmony_ci unsigned char word_count; 20013498266Sopenharmony_ci struct andx andx; 20113498266Sopenharmony_ci unsigned short fid; 20213498266Sopenharmony_ci unsigned int offset; 20313498266Sopenharmony_ci unsigned short max_bytes; 20413498266Sopenharmony_ci unsigned short min_bytes; 20513498266Sopenharmony_ci unsigned int timeout; 20613498266Sopenharmony_ci unsigned short remaining; 20713498266Sopenharmony_ci unsigned int offset_high; 20813498266Sopenharmony_ci unsigned short byte_count; 20913498266Sopenharmony_ci} PACK; 21013498266Sopenharmony_ci 21113498266Sopenharmony_cistruct smb_write { 21213498266Sopenharmony_ci struct smb_header h; 21313498266Sopenharmony_ci unsigned char word_count; 21413498266Sopenharmony_ci struct andx andx; 21513498266Sopenharmony_ci unsigned short fid; 21613498266Sopenharmony_ci unsigned int offset; 21713498266Sopenharmony_ci unsigned int timeout; 21813498266Sopenharmony_ci unsigned short write_mode; 21913498266Sopenharmony_ci unsigned short remaining; 22013498266Sopenharmony_ci unsigned short pad; 22113498266Sopenharmony_ci unsigned short data_length; 22213498266Sopenharmony_ci unsigned short data_offset; 22313498266Sopenharmony_ci unsigned int offset_high; 22413498266Sopenharmony_ci unsigned short byte_count; 22513498266Sopenharmony_ci unsigned char pad2; 22613498266Sopenharmony_ci} PACK; 22713498266Sopenharmony_ci 22813498266Sopenharmony_cistruct smb_close { 22913498266Sopenharmony_ci unsigned char word_count; 23013498266Sopenharmony_ci unsigned short fid; 23113498266Sopenharmony_ci unsigned int last_mtime; 23213498266Sopenharmony_ci unsigned short byte_count; 23313498266Sopenharmony_ci} PACK; 23413498266Sopenharmony_ci 23513498266Sopenharmony_cistruct smb_tree_disconnect { 23613498266Sopenharmony_ci unsigned char word_count; 23713498266Sopenharmony_ci unsigned short byte_count; 23813498266Sopenharmony_ci} PACK; 23913498266Sopenharmony_ci 24013498266Sopenharmony_ci#if defined(_MSC_VER) || defined(__ILEC400__) 24113498266Sopenharmony_ci# pragma pack(pop) 24213498266Sopenharmony_ci#endif 24313498266Sopenharmony_ci 24413498266Sopenharmony_ci/* Local API functions */ 24513498266Sopenharmony_cistatic CURLcode smb_setup_connection(struct Curl_easy *data, 24613498266Sopenharmony_ci struct connectdata *conn); 24713498266Sopenharmony_cistatic CURLcode smb_connect(struct Curl_easy *data, bool *done); 24813498266Sopenharmony_cistatic CURLcode smb_connection_state(struct Curl_easy *data, bool *done); 24913498266Sopenharmony_cistatic CURLcode smb_do(struct Curl_easy *data, bool *done); 25013498266Sopenharmony_cistatic CURLcode smb_request_state(struct Curl_easy *data, bool *done); 25113498266Sopenharmony_cistatic CURLcode smb_disconnect(struct Curl_easy *data, 25213498266Sopenharmony_ci struct connectdata *conn, bool dead); 25313498266Sopenharmony_cistatic int smb_getsock(struct Curl_easy *data, struct connectdata *conn, 25413498266Sopenharmony_ci curl_socket_t *socks); 25513498266Sopenharmony_cistatic CURLcode smb_parse_url_path(struct Curl_easy *data, 25613498266Sopenharmony_ci struct connectdata *conn); 25713498266Sopenharmony_ci 25813498266Sopenharmony_ci/* 25913498266Sopenharmony_ci * SMB handler interface 26013498266Sopenharmony_ci */ 26113498266Sopenharmony_ciconst struct Curl_handler Curl_handler_smb = { 26213498266Sopenharmony_ci "SMB", /* scheme */ 26313498266Sopenharmony_ci smb_setup_connection, /* setup_connection */ 26413498266Sopenharmony_ci smb_do, /* do_it */ 26513498266Sopenharmony_ci ZERO_NULL, /* done */ 26613498266Sopenharmony_ci ZERO_NULL, /* do_more */ 26713498266Sopenharmony_ci smb_connect, /* connect_it */ 26813498266Sopenharmony_ci smb_connection_state, /* connecting */ 26913498266Sopenharmony_ci smb_request_state, /* doing */ 27013498266Sopenharmony_ci smb_getsock, /* proto_getsock */ 27113498266Sopenharmony_ci smb_getsock, /* doing_getsock */ 27213498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 27313498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 27413498266Sopenharmony_ci smb_disconnect, /* disconnect */ 27513498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 27613498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 27713498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 27813498266Sopenharmony_ci PORT_SMB, /* defport */ 27913498266Sopenharmony_ci CURLPROTO_SMB, /* protocol */ 28013498266Sopenharmony_ci CURLPROTO_SMB, /* family */ 28113498266Sopenharmony_ci PROTOPT_NONE /* flags */ 28213498266Sopenharmony_ci}; 28313498266Sopenharmony_ci 28413498266Sopenharmony_ci#ifdef USE_SSL 28513498266Sopenharmony_ci/* 28613498266Sopenharmony_ci * SMBS handler interface 28713498266Sopenharmony_ci */ 28813498266Sopenharmony_ciconst struct Curl_handler Curl_handler_smbs = { 28913498266Sopenharmony_ci "SMBS", /* scheme */ 29013498266Sopenharmony_ci smb_setup_connection, /* setup_connection */ 29113498266Sopenharmony_ci smb_do, /* do_it */ 29213498266Sopenharmony_ci ZERO_NULL, /* done */ 29313498266Sopenharmony_ci ZERO_NULL, /* do_more */ 29413498266Sopenharmony_ci smb_connect, /* connect_it */ 29513498266Sopenharmony_ci smb_connection_state, /* connecting */ 29613498266Sopenharmony_ci smb_request_state, /* doing */ 29713498266Sopenharmony_ci smb_getsock, /* proto_getsock */ 29813498266Sopenharmony_ci smb_getsock, /* doing_getsock */ 29913498266Sopenharmony_ci ZERO_NULL, /* domore_getsock */ 30013498266Sopenharmony_ci ZERO_NULL, /* perform_getsock */ 30113498266Sopenharmony_ci smb_disconnect, /* disconnect */ 30213498266Sopenharmony_ci ZERO_NULL, /* write_resp */ 30313498266Sopenharmony_ci ZERO_NULL, /* connection_check */ 30413498266Sopenharmony_ci ZERO_NULL, /* attach connection */ 30513498266Sopenharmony_ci PORT_SMBS, /* defport */ 30613498266Sopenharmony_ci CURLPROTO_SMBS, /* protocol */ 30713498266Sopenharmony_ci CURLPROTO_SMB, /* family */ 30813498266Sopenharmony_ci PROTOPT_SSL /* flags */ 30913498266Sopenharmony_ci}; 31013498266Sopenharmony_ci#endif 31113498266Sopenharmony_ci 31213498266Sopenharmony_ci#define MAX_PAYLOAD_SIZE 0x8000 31313498266Sopenharmony_ci#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000) 31413498266Sopenharmony_ci#define CLIENTNAME "curl" 31513498266Sopenharmony_ci#define SERVICENAME "?????" 31613498266Sopenharmony_ci 31713498266Sopenharmony_ci/* Append a string to an SMB message */ 31813498266Sopenharmony_ci#define MSGCAT(str) \ 31913498266Sopenharmony_ci do { \ 32013498266Sopenharmony_ci strcpy(p, (str)); \ 32113498266Sopenharmony_ci p += strlen(str); \ 32213498266Sopenharmony_ci } while(0) 32313498266Sopenharmony_ci 32413498266Sopenharmony_ci/* Append a null-terminated string to an SMB message */ 32513498266Sopenharmony_ci#define MSGCATNULL(str) \ 32613498266Sopenharmony_ci do { \ 32713498266Sopenharmony_ci strcpy(p, (str)); \ 32813498266Sopenharmony_ci p += strlen(str) + 1; \ 32913498266Sopenharmony_ci } while(0) 33013498266Sopenharmony_ci 33113498266Sopenharmony_ci/* SMB is mostly little endian */ 33213498266Sopenharmony_ci#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 33313498266Sopenharmony_ci defined(__OS400__) 33413498266Sopenharmony_cistatic unsigned short smb_swap16(unsigned short x) 33513498266Sopenharmony_ci{ 33613498266Sopenharmony_ci return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); 33713498266Sopenharmony_ci} 33813498266Sopenharmony_ci 33913498266Sopenharmony_cistatic unsigned int smb_swap32(unsigned int x) 34013498266Sopenharmony_ci{ 34113498266Sopenharmony_ci return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | 34213498266Sopenharmony_ci ((x >> 24) & 0xff); 34313498266Sopenharmony_ci} 34413498266Sopenharmony_ci 34513498266Sopenharmony_cistatic curl_off_t smb_swap64(curl_off_t x) 34613498266Sopenharmony_ci{ 34713498266Sopenharmony_ci return ((curl_off_t) smb_swap32((unsigned int) x) << 32) | 34813498266Sopenharmony_ci smb_swap32((unsigned int) (x >> 32)); 34913498266Sopenharmony_ci} 35013498266Sopenharmony_ci 35113498266Sopenharmony_ci#else 35213498266Sopenharmony_ci# define smb_swap16(x) (x) 35313498266Sopenharmony_ci# define smb_swap32(x) (x) 35413498266Sopenharmony_ci# define smb_swap64(x) (x) 35513498266Sopenharmony_ci#endif 35613498266Sopenharmony_ci 35713498266Sopenharmony_ci/* SMB request state */ 35813498266Sopenharmony_cienum smb_req_state { 35913498266Sopenharmony_ci SMB_REQUESTING, 36013498266Sopenharmony_ci SMB_TREE_CONNECT, 36113498266Sopenharmony_ci SMB_OPEN, 36213498266Sopenharmony_ci SMB_DOWNLOAD, 36313498266Sopenharmony_ci SMB_UPLOAD, 36413498266Sopenharmony_ci SMB_CLOSE, 36513498266Sopenharmony_ci SMB_TREE_DISCONNECT, 36613498266Sopenharmony_ci SMB_DONE 36713498266Sopenharmony_ci}; 36813498266Sopenharmony_ci 36913498266Sopenharmony_ci/* SMB request data */ 37013498266Sopenharmony_cistruct smb_request { 37113498266Sopenharmony_ci enum smb_req_state state; 37213498266Sopenharmony_ci char *path; 37313498266Sopenharmony_ci unsigned short tid; /* Even if we connect to the same tree as another */ 37413498266Sopenharmony_ci unsigned short fid; /* request, the tid will be different */ 37513498266Sopenharmony_ci CURLcode result; 37613498266Sopenharmony_ci}; 37713498266Sopenharmony_ci 37813498266Sopenharmony_cistatic void conn_state(struct Curl_easy *data, enum smb_conn_state newstate) 37913498266Sopenharmony_ci{ 38013498266Sopenharmony_ci struct smb_conn *smbc = &data->conn->proto.smbc; 38113498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 38213498266Sopenharmony_ci /* For debug purposes */ 38313498266Sopenharmony_ci static const char * const names[] = { 38413498266Sopenharmony_ci "SMB_NOT_CONNECTED", 38513498266Sopenharmony_ci "SMB_CONNECTING", 38613498266Sopenharmony_ci "SMB_NEGOTIATE", 38713498266Sopenharmony_ci "SMB_SETUP", 38813498266Sopenharmony_ci "SMB_CONNECTED", 38913498266Sopenharmony_ci /* LAST */ 39013498266Sopenharmony_ci }; 39113498266Sopenharmony_ci 39213498266Sopenharmony_ci if(smbc->state != newstate) 39313498266Sopenharmony_ci infof(data, "SMB conn %p state change from %s to %s", 39413498266Sopenharmony_ci (void *)smbc, names[smbc->state], names[newstate]); 39513498266Sopenharmony_ci#endif 39613498266Sopenharmony_ci 39713498266Sopenharmony_ci smbc->state = newstate; 39813498266Sopenharmony_ci} 39913498266Sopenharmony_ci 40013498266Sopenharmony_cistatic void request_state(struct Curl_easy *data, 40113498266Sopenharmony_ci enum smb_req_state newstate) 40213498266Sopenharmony_ci{ 40313498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 40413498266Sopenharmony_ci#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) 40513498266Sopenharmony_ci /* For debug purposes */ 40613498266Sopenharmony_ci static const char * const names[] = { 40713498266Sopenharmony_ci "SMB_REQUESTING", 40813498266Sopenharmony_ci "SMB_TREE_CONNECT", 40913498266Sopenharmony_ci "SMB_OPEN", 41013498266Sopenharmony_ci "SMB_DOWNLOAD", 41113498266Sopenharmony_ci "SMB_UPLOAD", 41213498266Sopenharmony_ci "SMB_CLOSE", 41313498266Sopenharmony_ci "SMB_TREE_DISCONNECT", 41413498266Sopenharmony_ci "SMB_DONE", 41513498266Sopenharmony_ci /* LAST */ 41613498266Sopenharmony_ci }; 41713498266Sopenharmony_ci 41813498266Sopenharmony_ci if(req->state != newstate) 41913498266Sopenharmony_ci infof(data, "SMB request %p state change from %s to %s", 42013498266Sopenharmony_ci (void *)req, names[req->state], names[newstate]); 42113498266Sopenharmony_ci#endif 42213498266Sopenharmony_ci 42313498266Sopenharmony_ci req->state = newstate; 42413498266Sopenharmony_ci} 42513498266Sopenharmony_ci 42613498266Sopenharmony_ci/* this should setup things in the connection, not in the easy 42713498266Sopenharmony_ci handle */ 42813498266Sopenharmony_cistatic CURLcode smb_setup_connection(struct Curl_easy *data, 42913498266Sopenharmony_ci struct connectdata *conn) 43013498266Sopenharmony_ci{ 43113498266Sopenharmony_ci struct smb_request *req; 43213498266Sopenharmony_ci 43313498266Sopenharmony_ci /* Initialize the request state */ 43413498266Sopenharmony_ci data->req.p.smb = req = calloc(1, sizeof(struct smb_request)); 43513498266Sopenharmony_ci if(!req) 43613498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 43713498266Sopenharmony_ci 43813498266Sopenharmony_ci /* Parse the URL path */ 43913498266Sopenharmony_ci return smb_parse_url_path(data, conn); 44013498266Sopenharmony_ci} 44113498266Sopenharmony_ci 44213498266Sopenharmony_cistatic CURLcode smb_connect(struct Curl_easy *data, bool *done) 44313498266Sopenharmony_ci{ 44413498266Sopenharmony_ci struct connectdata *conn = data->conn; 44513498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 44613498266Sopenharmony_ci char *slash; 44713498266Sopenharmony_ci 44813498266Sopenharmony_ci (void) done; 44913498266Sopenharmony_ci 45013498266Sopenharmony_ci /* Check we have a username and password to authenticate with */ 45113498266Sopenharmony_ci if(!data->state.aptr.user) 45213498266Sopenharmony_ci return CURLE_LOGIN_DENIED; 45313498266Sopenharmony_ci 45413498266Sopenharmony_ci /* Initialize the connection state */ 45513498266Sopenharmony_ci smbc->state = SMB_CONNECTING; 45613498266Sopenharmony_ci smbc->recv_buf = malloc(MAX_MESSAGE_SIZE); 45713498266Sopenharmony_ci if(!smbc->recv_buf) 45813498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 45913498266Sopenharmony_ci 46013498266Sopenharmony_ci /* Multiple requests are allowed with this connection */ 46113498266Sopenharmony_ci connkeep(conn, "SMB default"); 46213498266Sopenharmony_ci 46313498266Sopenharmony_ci /* Parse the username, domain, and password */ 46413498266Sopenharmony_ci slash = strchr(conn->user, '/'); 46513498266Sopenharmony_ci if(!slash) 46613498266Sopenharmony_ci slash = strchr(conn->user, '\\'); 46713498266Sopenharmony_ci 46813498266Sopenharmony_ci if(slash) { 46913498266Sopenharmony_ci smbc->user = slash + 1; 47013498266Sopenharmony_ci smbc->domain = strdup(conn->user); 47113498266Sopenharmony_ci if(!smbc->domain) 47213498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 47313498266Sopenharmony_ci smbc->domain[slash - conn->user] = 0; 47413498266Sopenharmony_ci } 47513498266Sopenharmony_ci else { 47613498266Sopenharmony_ci smbc->user = conn->user; 47713498266Sopenharmony_ci smbc->domain = strdup(conn->host.name); 47813498266Sopenharmony_ci if(!smbc->domain) 47913498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 48013498266Sopenharmony_ci } 48113498266Sopenharmony_ci 48213498266Sopenharmony_ci return CURLE_OK; 48313498266Sopenharmony_ci} 48413498266Sopenharmony_ci 48513498266Sopenharmony_cistatic CURLcode smb_recv_message(struct Curl_easy *data, void **msg) 48613498266Sopenharmony_ci{ 48713498266Sopenharmony_ci struct connectdata *conn = data->conn; 48813498266Sopenharmony_ci curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; 48913498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 49013498266Sopenharmony_ci char *buf = smbc->recv_buf; 49113498266Sopenharmony_ci ssize_t bytes_read; 49213498266Sopenharmony_ci size_t nbt_size; 49313498266Sopenharmony_ci size_t msg_size; 49413498266Sopenharmony_ci size_t len = MAX_MESSAGE_SIZE - smbc->got; 49513498266Sopenharmony_ci CURLcode result; 49613498266Sopenharmony_ci 49713498266Sopenharmony_ci result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read); 49813498266Sopenharmony_ci if(result) 49913498266Sopenharmony_ci return result; 50013498266Sopenharmony_ci 50113498266Sopenharmony_ci if(!bytes_read) 50213498266Sopenharmony_ci return CURLE_OK; 50313498266Sopenharmony_ci 50413498266Sopenharmony_ci smbc->got += bytes_read; 50513498266Sopenharmony_ci 50613498266Sopenharmony_ci /* Check for a 32-bit nbt header */ 50713498266Sopenharmony_ci if(smbc->got < sizeof(unsigned int)) 50813498266Sopenharmony_ci return CURLE_OK; 50913498266Sopenharmony_ci 51013498266Sopenharmony_ci nbt_size = Curl_read16_be((const unsigned char *) 51113498266Sopenharmony_ci (buf + sizeof(unsigned short))) + 51213498266Sopenharmony_ci sizeof(unsigned int); 51313498266Sopenharmony_ci if(smbc->got < nbt_size) 51413498266Sopenharmony_ci return CURLE_OK; 51513498266Sopenharmony_ci 51613498266Sopenharmony_ci msg_size = sizeof(struct smb_header); 51713498266Sopenharmony_ci if(nbt_size >= msg_size + 1) { 51813498266Sopenharmony_ci /* Add the word count */ 51913498266Sopenharmony_ci msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short); 52013498266Sopenharmony_ci if(nbt_size >= msg_size + sizeof(unsigned short)) { 52113498266Sopenharmony_ci /* Add the byte count */ 52213498266Sopenharmony_ci msg_size += sizeof(unsigned short) + 52313498266Sopenharmony_ci Curl_read16_le((const unsigned char *)&buf[msg_size]); 52413498266Sopenharmony_ci if(nbt_size < msg_size) 52513498266Sopenharmony_ci return CURLE_READ_ERROR; 52613498266Sopenharmony_ci } 52713498266Sopenharmony_ci } 52813498266Sopenharmony_ci 52913498266Sopenharmony_ci *msg = buf; 53013498266Sopenharmony_ci 53113498266Sopenharmony_ci return CURLE_OK; 53213498266Sopenharmony_ci} 53313498266Sopenharmony_ci 53413498266Sopenharmony_cistatic void smb_pop_message(struct connectdata *conn) 53513498266Sopenharmony_ci{ 53613498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 53713498266Sopenharmony_ci 53813498266Sopenharmony_ci smbc->got = 0; 53913498266Sopenharmony_ci} 54013498266Sopenharmony_ci 54113498266Sopenharmony_cistatic void smb_format_message(struct Curl_easy *data, struct smb_header *h, 54213498266Sopenharmony_ci unsigned char cmd, size_t len) 54313498266Sopenharmony_ci{ 54413498266Sopenharmony_ci struct connectdata *conn = data->conn; 54513498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 54613498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 54713498266Sopenharmony_ci unsigned int pid; 54813498266Sopenharmony_ci 54913498266Sopenharmony_ci memset(h, 0, sizeof(*h)); 55013498266Sopenharmony_ci h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) + 55113498266Sopenharmony_ci len)); 55213498266Sopenharmony_ci memcpy((char *)h->magic, "\xffSMB", 4); 55313498266Sopenharmony_ci h->command = cmd; 55413498266Sopenharmony_ci h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES; 55513498266Sopenharmony_ci h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME); 55613498266Sopenharmony_ci h->uid = smb_swap16(smbc->uid); 55713498266Sopenharmony_ci h->tid = smb_swap16(req->tid); 55813498266Sopenharmony_ci pid = getpid(); 55913498266Sopenharmony_ci h->pid_high = smb_swap16((unsigned short)(pid >> 16)); 56013498266Sopenharmony_ci h->pid = smb_swap16((unsigned short) pid); 56113498266Sopenharmony_ci} 56213498266Sopenharmony_ci 56313498266Sopenharmony_cistatic CURLcode smb_send(struct Curl_easy *data, ssize_t len, 56413498266Sopenharmony_ci size_t upload_size) 56513498266Sopenharmony_ci{ 56613498266Sopenharmony_ci struct connectdata *conn = data->conn; 56713498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 56813498266Sopenharmony_ci ssize_t bytes_written; 56913498266Sopenharmony_ci CURLcode result; 57013498266Sopenharmony_ci 57113498266Sopenharmony_ci result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf, 57213498266Sopenharmony_ci len, &bytes_written); 57313498266Sopenharmony_ci if(result) 57413498266Sopenharmony_ci return result; 57513498266Sopenharmony_ci 57613498266Sopenharmony_ci if(bytes_written != len) { 57713498266Sopenharmony_ci smbc->send_size = len; 57813498266Sopenharmony_ci smbc->sent = bytes_written; 57913498266Sopenharmony_ci } 58013498266Sopenharmony_ci 58113498266Sopenharmony_ci smbc->upload_size = upload_size; 58213498266Sopenharmony_ci 58313498266Sopenharmony_ci return CURLE_OK; 58413498266Sopenharmony_ci} 58513498266Sopenharmony_ci 58613498266Sopenharmony_cistatic CURLcode smb_flush(struct Curl_easy *data) 58713498266Sopenharmony_ci{ 58813498266Sopenharmony_ci struct connectdata *conn = data->conn; 58913498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 59013498266Sopenharmony_ci ssize_t bytes_written; 59113498266Sopenharmony_ci ssize_t len = smbc->send_size - smbc->sent; 59213498266Sopenharmony_ci CURLcode result; 59313498266Sopenharmony_ci 59413498266Sopenharmony_ci if(!smbc->send_size) 59513498266Sopenharmony_ci return CURLE_OK; 59613498266Sopenharmony_ci 59713498266Sopenharmony_ci result = Curl_nwrite(data, FIRSTSOCKET, 59813498266Sopenharmony_ci data->state.ulbuf + smbc->sent, 59913498266Sopenharmony_ci len, &bytes_written); 60013498266Sopenharmony_ci if(result) 60113498266Sopenharmony_ci return result; 60213498266Sopenharmony_ci 60313498266Sopenharmony_ci if(bytes_written != len) 60413498266Sopenharmony_ci smbc->sent += bytes_written; 60513498266Sopenharmony_ci else 60613498266Sopenharmony_ci smbc->send_size = 0; 60713498266Sopenharmony_ci 60813498266Sopenharmony_ci return CURLE_OK; 60913498266Sopenharmony_ci} 61013498266Sopenharmony_ci 61113498266Sopenharmony_cistatic CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd, 61213498266Sopenharmony_ci const void *msg, size_t msg_len) 61313498266Sopenharmony_ci{ 61413498266Sopenharmony_ci CURLcode result = Curl_get_upload_buffer(data); 61513498266Sopenharmony_ci if(result) 61613498266Sopenharmony_ci return result; 61713498266Sopenharmony_ci smb_format_message(data, (struct smb_header *)data->state.ulbuf, 61813498266Sopenharmony_ci cmd, msg_len); 61913498266Sopenharmony_ci memcpy(data->state.ulbuf + sizeof(struct smb_header), 62013498266Sopenharmony_ci msg, msg_len); 62113498266Sopenharmony_ci 62213498266Sopenharmony_ci return smb_send(data, sizeof(struct smb_header) + msg_len, 0); 62313498266Sopenharmony_ci} 62413498266Sopenharmony_ci 62513498266Sopenharmony_cistatic CURLcode smb_send_negotiate(struct Curl_easy *data) 62613498266Sopenharmony_ci{ 62713498266Sopenharmony_ci const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; 62813498266Sopenharmony_ci 62913498266Sopenharmony_ci return smb_send_message(data, SMB_COM_NEGOTIATE, msg, 15); 63013498266Sopenharmony_ci} 63113498266Sopenharmony_ci 63213498266Sopenharmony_cistatic CURLcode smb_send_setup(struct Curl_easy *data) 63313498266Sopenharmony_ci{ 63413498266Sopenharmony_ci struct connectdata *conn = data->conn; 63513498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 63613498266Sopenharmony_ci struct smb_setup msg; 63713498266Sopenharmony_ci char *p = msg.bytes; 63813498266Sopenharmony_ci unsigned char lm_hash[21]; 63913498266Sopenharmony_ci unsigned char lm[24]; 64013498266Sopenharmony_ci unsigned char nt_hash[21]; 64113498266Sopenharmony_ci unsigned char nt[24]; 64213498266Sopenharmony_ci 64313498266Sopenharmony_ci size_t byte_count = sizeof(lm) + sizeof(nt); 64413498266Sopenharmony_ci byte_count += strlen(smbc->user) + strlen(smbc->domain); 64513498266Sopenharmony_ci byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ 64613498266Sopenharmony_ci if(byte_count > sizeof(msg.bytes)) 64713498266Sopenharmony_ci return CURLE_FILESIZE_EXCEEDED; 64813498266Sopenharmony_ci 64913498266Sopenharmony_ci Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash); 65013498266Sopenharmony_ci Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); 65113498266Sopenharmony_ci Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash); 65213498266Sopenharmony_ci Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); 65313498266Sopenharmony_ci 65413498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 65513498266Sopenharmony_ci msg.word_count = SMB_WC_SETUP_ANDX; 65613498266Sopenharmony_ci msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 65713498266Sopenharmony_ci msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE); 65813498266Sopenharmony_ci msg.max_mpx_count = smb_swap16(1); 65913498266Sopenharmony_ci msg.vc_number = smb_swap16(1); 66013498266Sopenharmony_ci msg.session_key = smb_swap32(smbc->session_key); 66113498266Sopenharmony_ci msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES); 66213498266Sopenharmony_ci msg.lengths[0] = smb_swap16(sizeof(lm)); 66313498266Sopenharmony_ci msg.lengths[1] = smb_swap16(sizeof(nt)); 66413498266Sopenharmony_ci memcpy(p, lm, sizeof(lm)); 66513498266Sopenharmony_ci p += sizeof(lm); 66613498266Sopenharmony_ci memcpy(p, nt, sizeof(nt)); 66713498266Sopenharmony_ci p += sizeof(nt); 66813498266Sopenharmony_ci MSGCATNULL(smbc->user); 66913498266Sopenharmony_ci MSGCATNULL(smbc->domain); 67013498266Sopenharmony_ci MSGCATNULL(OS); 67113498266Sopenharmony_ci MSGCATNULL(CLIENTNAME); 67213498266Sopenharmony_ci byte_count = p - msg.bytes; 67313498266Sopenharmony_ci msg.byte_count = smb_swap16((unsigned short)byte_count); 67413498266Sopenharmony_ci 67513498266Sopenharmony_ci return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg, 67613498266Sopenharmony_ci sizeof(msg) - sizeof(msg.bytes) + byte_count); 67713498266Sopenharmony_ci} 67813498266Sopenharmony_ci 67913498266Sopenharmony_cistatic CURLcode smb_send_tree_connect(struct Curl_easy *data) 68013498266Sopenharmony_ci{ 68113498266Sopenharmony_ci struct smb_tree_connect msg; 68213498266Sopenharmony_ci struct connectdata *conn = data->conn; 68313498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 68413498266Sopenharmony_ci char *p = msg.bytes; 68513498266Sopenharmony_ci 68613498266Sopenharmony_ci size_t byte_count = strlen(conn->host.name) + strlen(smbc->share); 68713498266Sopenharmony_ci byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ 68813498266Sopenharmony_ci if(byte_count > sizeof(msg.bytes)) 68913498266Sopenharmony_ci return CURLE_FILESIZE_EXCEEDED; 69013498266Sopenharmony_ci 69113498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 69213498266Sopenharmony_ci msg.word_count = SMB_WC_TREE_CONNECT_ANDX; 69313498266Sopenharmony_ci msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 69413498266Sopenharmony_ci msg.pw_len = 0; 69513498266Sopenharmony_ci MSGCAT("\\\\"); 69613498266Sopenharmony_ci MSGCAT(conn->host.name); 69713498266Sopenharmony_ci MSGCAT("\\"); 69813498266Sopenharmony_ci MSGCATNULL(smbc->share); 69913498266Sopenharmony_ci MSGCATNULL(SERVICENAME); /* Match any type of service */ 70013498266Sopenharmony_ci byte_count = p - msg.bytes; 70113498266Sopenharmony_ci msg.byte_count = smb_swap16((unsigned short)byte_count); 70213498266Sopenharmony_ci 70313498266Sopenharmony_ci return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg, 70413498266Sopenharmony_ci sizeof(msg) - sizeof(msg.bytes) + byte_count); 70513498266Sopenharmony_ci} 70613498266Sopenharmony_ci 70713498266Sopenharmony_cistatic CURLcode smb_send_open(struct Curl_easy *data) 70813498266Sopenharmony_ci{ 70913498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 71013498266Sopenharmony_ci struct smb_nt_create msg; 71113498266Sopenharmony_ci size_t byte_count; 71213498266Sopenharmony_ci 71313498266Sopenharmony_ci if((strlen(req->path) + 1) > sizeof(msg.bytes)) 71413498266Sopenharmony_ci return CURLE_FILESIZE_EXCEEDED; 71513498266Sopenharmony_ci 71613498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 71713498266Sopenharmony_ci msg.word_count = SMB_WC_NT_CREATE_ANDX; 71813498266Sopenharmony_ci msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 71913498266Sopenharmony_ci byte_count = strlen(req->path); 72013498266Sopenharmony_ci msg.name_length = smb_swap16((unsigned short)byte_count); 72113498266Sopenharmony_ci msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); 72213498266Sopenharmony_ci if(data->state.upload) { 72313498266Sopenharmony_ci msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); 72413498266Sopenharmony_ci msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); 72513498266Sopenharmony_ci } 72613498266Sopenharmony_ci else { 72713498266Sopenharmony_ci msg.access = smb_swap32(SMB_GENERIC_READ); 72813498266Sopenharmony_ci msg.create_disposition = smb_swap32(SMB_FILE_OPEN); 72913498266Sopenharmony_ci } 73013498266Sopenharmony_ci msg.byte_count = smb_swap16((unsigned short) ++byte_count); 73113498266Sopenharmony_ci strcpy(msg.bytes, req->path); 73213498266Sopenharmony_ci 73313498266Sopenharmony_ci return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg, 73413498266Sopenharmony_ci sizeof(msg) - sizeof(msg.bytes) + byte_count); 73513498266Sopenharmony_ci} 73613498266Sopenharmony_ci 73713498266Sopenharmony_cistatic CURLcode smb_send_close(struct Curl_easy *data) 73813498266Sopenharmony_ci{ 73913498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 74013498266Sopenharmony_ci struct smb_close msg; 74113498266Sopenharmony_ci 74213498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 74313498266Sopenharmony_ci msg.word_count = SMB_WC_CLOSE; 74413498266Sopenharmony_ci msg.fid = smb_swap16(req->fid); 74513498266Sopenharmony_ci 74613498266Sopenharmony_ci return smb_send_message(data, SMB_COM_CLOSE, &msg, sizeof(msg)); 74713498266Sopenharmony_ci} 74813498266Sopenharmony_ci 74913498266Sopenharmony_cistatic CURLcode smb_send_tree_disconnect(struct Curl_easy *data) 75013498266Sopenharmony_ci{ 75113498266Sopenharmony_ci struct smb_tree_disconnect msg; 75213498266Sopenharmony_ci 75313498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 75413498266Sopenharmony_ci 75513498266Sopenharmony_ci return smb_send_message(data, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg)); 75613498266Sopenharmony_ci} 75713498266Sopenharmony_ci 75813498266Sopenharmony_cistatic CURLcode smb_send_read(struct Curl_easy *data) 75913498266Sopenharmony_ci{ 76013498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 76113498266Sopenharmony_ci curl_off_t offset = data->req.offset; 76213498266Sopenharmony_ci struct smb_read msg; 76313498266Sopenharmony_ci 76413498266Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 76513498266Sopenharmony_ci msg.word_count = SMB_WC_READ_ANDX; 76613498266Sopenharmony_ci msg.andx.command = SMB_COM_NO_ANDX_COMMAND; 76713498266Sopenharmony_ci msg.fid = smb_swap16(req->fid); 76813498266Sopenharmony_ci msg.offset = smb_swap32((unsigned int) offset); 76913498266Sopenharmony_ci msg.offset_high = smb_swap32((unsigned int) (offset >> 32)); 77013498266Sopenharmony_ci msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 77113498266Sopenharmony_ci msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE); 77213498266Sopenharmony_ci 77313498266Sopenharmony_ci return smb_send_message(data, SMB_COM_READ_ANDX, &msg, sizeof(msg)); 77413498266Sopenharmony_ci} 77513498266Sopenharmony_ci 77613498266Sopenharmony_cistatic CURLcode smb_send_write(struct Curl_easy *data) 77713498266Sopenharmony_ci{ 77813498266Sopenharmony_ci struct smb_write *msg; 77913498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 78013498266Sopenharmony_ci curl_off_t offset = data->req.offset; 78113498266Sopenharmony_ci curl_off_t upload_size = data->req.size - data->req.bytecount; 78213498266Sopenharmony_ci CURLcode result = Curl_get_upload_buffer(data); 78313498266Sopenharmony_ci if(result) 78413498266Sopenharmony_ci return result; 78513498266Sopenharmony_ci msg = (struct smb_write *)data->state.ulbuf; 78613498266Sopenharmony_ci 78713498266Sopenharmony_ci if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */ 78813498266Sopenharmony_ci upload_size = MAX_PAYLOAD_SIZE - 1; 78913498266Sopenharmony_ci 79013498266Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 79113498266Sopenharmony_ci msg->word_count = SMB_WC_WRITE_ANDX; 79213498266Sopenharmony_ci msg->andx.command = SMB_COM_NO_ANDX_COMMAND; 79313498266Sopenharmony_ci msg->fid = smb_swap16(req->fid); 79413498266Sopenharmony_ci msg->offset = smb_swap32((unsigned int) offset); 79513498266Sopenharmony_ci msg->offset_high = smb_swap32((unsigned int) (offset >> 32)); 79613498266Sopenharmony_ci msg->data_length = smb_swap16((unsigned short) upload_size); 79713498266Sopenharmony_ci msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int)); 79813498266Sopenharmony_ci msg->byte_count = smb_swap16((unsigned short) (upload_size + 1)); 79913498266Sopenharmony_ci 80013498266Sopenharmony_ci smb_format_message(data, &msg->h, SMB_COM_WRITE_ANDX, 80113498266Sopenharmony_ci sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size); 80213498266Sopenharmony_ci 80313498266Sopenharmony_ci return smb_send(data, sizeof(*msg), (size_t) upload_size); 80413498266Sopenharmony_ci} 80513498266Sopenharmony_ci 80613498266Sopenharmony_cistatic CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg) 80713498266Sopenharmony_ci{ 80813498266Sopenharmony_ci struct connectdata *conn = data->conn; 80913498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 81013498266Sopenharmony_ci CURLcode result; 81113498266Sopenharmony_ci *msg = NULL; /* if it returns early */ 81213498266Sopenharmony_ci 81313498266Sopenharmony_ci /* Check if there is data in the transfer buffer */ 81413498266Sopenharmony_ci if(!smbc->send_size && smbc->upload_size) { 81513498266Sopenharmony_ci size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ? 81613498266Sopenharmony_ci (size_t)data->set.upload_buffer_size : smbc->upload_size; 81713498266Sopenharmony_ci data->req.upload_fromhere = data->state.ulbuf; 81813498266Sopenharmony_ci result = Curl_fillreadbuffer(data, nread, &nread); 81913498266Sopenharmony_ci if(result && result != CURLE_AGAIN) 82013498266Sopenharmony_ci return result; 82113498266Sopenharmony_ci if(!nread) 82213498266Sopenharmony_ci return CURLE_OK; 82313498266Sopenharmony_ci 82413498266Sopenharmony_ci smbc->upload_size -= nread; 82513498266Sopenharmony_ci smbc->send_size = nread; 82613498266Sopenharmony_ci smbc->sent = 0; 82713498266Sopenharmony_ci } 82813498266Sopenharmony_ci 82913498266Sopenharmony_ci /* Check if there is data to send */ 83013498266Sopenharmony_ci if(smbc->send_size) { 83113498266Sopenharmony_ci result = smb_flush(data); 83213498266Sopenharmony_ci if(result) 83313498266Sopenharmony_ci return result; 83413498266Sopenharmony_ci } 83513498266Sopenharmony_ci 83613498266Sopenharmony_ci /* Check if there is still data to be sent */ 83713498266Sopenharmony_ci if(smbc->send_size || smbc->upload_size) 83813498266Sopenharmony_ci return CURLE_AGAIN; 83913498266Sopenharmony_ci 84013498266Sopenharmony_ci return smb_recv_message(data, msg); 84113498266Sopenharmony_ci} 84213498266Sopenharmony_ci 84313498266Sopenharmony_cistatic CURLcode smb_connection_state(struct Curl_easy *data, bool *done) 84413498266Sopenharmony_ci{ 84513498266Sopenharmony_ci struct connectdata *conn = data->conn; 84613498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 84713498266Sopenharmony_ci struct smb_negotiate_response *nrsp; 84813498266Sopenharmony_ci struct smb_header *h; 84913498266Sopenharmony_ci CURLcode result; 85013498266Sopenharmony_ci void *msg = NULL; 85113498266Sopenharmony_ci 85213498266Sopenharmony_ci if(smbc->state == SMB_CONNECTING) { 85313498266Sopenharmony_ci#ifdef USE_SSL 85413498266Sopenharmony_ci if((conn->handler->flags & PROTOPT_SSL)) { 85513498266Sopenharmony_ci bool ssl_done = FALSE; 85613498266Sopenharmony_ci result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssl_done); 85713498266Sopenharmony_ci if(result && result != CURLE_AGAIN) 85813498266Sopenharmony_ci return result; 85913498266Sopenharmony_ci if(!ssl_done) 86013498266Sopenharmony_ci return CURLE_OK; 86113498266Sopenharmony_ci } 86213498266Sopenharmony_ci#endif 86313498266Sopenharmony_ci 86413498266Sopenharmony_ci result = smb_send_negotiate(data); 86513498266Sopenharmony_ci if(result) { 86613498266Sopenharmony_ci connclose(conn, "SMB: failed to send negotiate message"); 86713498266Sopenharmony_ci return result; 86813498266Sopenharmony_ci } 86913498266Sopenharmony_ci 87013498266Sopenharmony_ci conn_state(data, SMB_NEGOTIATE); 87113498266Sopenharmony_ci } 87213498266Sopenharmony_ci 87313498266Sopenharmony_ci /* Send the previous message and check for a response */ 87413498266Sopenharmony_ci result = smb_send_and_recv(data, &msg); 87513498266Sopenharmony_ci if(result && result != CURLE_AGAIN) { 87613498266Sopenharmony_ci connclose(conn, "SMB: failed to communicate"); 87713498266Sopenharmony_ci return result; 87813498266Sopenharmony_ci } 87913498266Sopenharmony_ci 88013498266Sopenharmony_ci if(!msg) 88113498266Sopenharmony_ci return CURLE_OK; 88213498266Sopenharmony_ci 88313498266Sopenharmony_ci h = msg; 88413498266Sopenharmony_ci 88513498266Sopenharmony_ci switch(smbc->state) { 88613498266Sopenharmony_ci case SMB_NEGOTIATE: 88713498266Sopenharmony_ci if((smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) || 88813498266Sopenharmony_ci h->status) { 88913498266Sopenharmony_ci connclose(conn, "SMB: negotiation failed"); 89013498266Sopenharmony_ci return CURLE_COULDNT_CONNECT; 89113498266Sopenharmony_ci } 89213498266Sopenharmony_ci nrsp = msg; 89313498266Sopenharmony_ci memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge)); 89413498266Sopenharmony_ci smbc->session_key = smb_swap32(nrsp->session_key); 89513498266Sopenharmony_ci result = smb_send_setup(data); 89613498266Sopenharmony_ci if(result) { 89713498266Sopenharmony_ci connclose(conn, "SMB: failed to send setup message"); 89813498266Sopenharmony_ci return result; 89913498266Sopenharmony_ci } 90013498266Sopenharmony_ci conn_state(data, SMB_SETUP); 90113498266Sopenharmony_ci break; 90213498266Sopenharmony_ci 90313498266Sopenharmony_ci case SMB_SETUP: 90413498266Sopenharmony_ci if(h->status) { 90513498266Sopenharmony_ci connclose(conn, "SMB: authentication failed"); 90613498266Sopenharmony_ci return CURLE_LOGIN_DENIED; 90713498266Sopenharmony_ci } 90813498266Sopenharmony_ci smbc->uid = smb_swap16(h->uid); 90913498266Sopenharmony_ci conn_state(data, SMB_CONNECTED); 91013498266Sopenharmony_ci *done = true; 91113498266Sopenharmony_ci break; 91213498266Sopenharmony_ci 91313498266Sopenharmony_ci default: 91413498266Sopenharmony_ci smb_pop_message(conn); 91513498266Sopenharmony_ci return CURLE_OK; /* ignore */ 91613498266Sopenharmony_ci } 91713498266Sopenharmony_ci 91813498266Sopenharmony_ci smb_pop_message(conn); 91913498266Sopenharmony_ci 92013498266Sopenharmony_ci return CURLE_OK; 92113498266Sopenharmony_ci} 92213498266Sopenharmony_ci 92313498266Sopenharmony_ci/* 92413498266Sopenharmony_ci * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601) 92513498266Sopenharmony_ci * to Posix time. Cap the output to fit within a time_t. 92613498266Sopenharmony_ci */ 92713498266Sopenharmony_cistatic void get_posix_time(time_t *out, curl_off_t timestamp) 92813498266Sopenharmony_ci{ 92913498266Sopenharmony_ci timestamp -= 116444736000000000; 93013498266Sopenharmony_ci timestamp /= 10000000; 93113498266Sopenharmony_ci#if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T 93213498266Sopenharmony_ci if(timestamp > TIME_T_MAX) 93313498266Sopenharmony_ci *out = TIME_T_MAX; 93413498266Sopenharmony_ci else if(timestamp < TIME_T_MIN) 93513498266Sopenharmony_ci *out = TIME_T_MIN; 93613498266Sopenharmony_ci else 93713498266Sopenharmony_ci#endif 93813498266Sopenharmony_ci *out = (time_t) timestamp; 93913498266Sopenharmony_ci} 94013498266Sopenharmony_ci 94113498266Sopenharmony_cistatic CURLcode smb_request_state(struct Curl_easy *data, bool *done) 94213498266Sopenharmony_ci{ 94313498266Sopenharmony_ci struct connectdata *conn = data->conn; 94413498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 94513498266Sopenharmony_ci struct smb_header *h; 94613498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 94713498266Sopenharmony_ci enum smb_req_state next_state = SMB_DONE; 94813498266Sopenharmony_ci unsigned short len; 94913498266Sopenharmony_ci unsigned short off; 95013498266Sopenharmony_ci CURLcode result; 95113498266Sopenharmony_ci void *msg = NULL; 95213498266Sopenharmony_ci const struct smb_nt_create_response *smb_m; 95313498266Sopenharmony_ci 95413498266Sopenharmony_ci if(data->state.upload && (data->state.infilesize < 0)) { 95513498266Sopenharmony_ci failf(data, "SMB upload needs to know the size up front"); 95613498266Sopenharmony_ci return CURLE_SEND_ERROR; 95713498266Sopenharmony_ci } 95813498266Sopenharmony_ci 95913498266Sopenharmony_ci /* Start the request */ 96013498266Sopenharmony_ci if(req->state == SMB_REQUESTING) { 96113498266Sopenharmony_ci result = smb_send_tree_connect(data); 96213498266Sopenharmony_ci if(result) { 96313498266Sopenharmony_ci connclose(conn, "SMB: failed to send tree connect message"); 96413498266Sopenharmony_ci return result; 96513498266Sopenharmony_ci } 96613498266Sopenharmony_ci 96713498266Sopenharmony_ci request_state(data, SMB_TREE_CONNECT); 96813498266Sopenharmony_ci } 96913498266Sopenharmony_ci 97013498266Sopenharmony_ci /* Send the previous message and check for a response */ 97113498266Sopenharmony_ci result = smb_send_and_recv(data, &msg); 97213498266Sopenharmony_ci if(result && result != CURLE_AGAIN) { 97313498266Sopenharmony_ci connclose(conn, "SMB: failed to communicate"); 97413498266Sopenharmony_ci return result; 97513498266Sopenharmony_ci } 97613498266Sopenharmony_ci 97713498266Sopenharmony_ci if(!msg) 97813498266Sopenharmony_ci return CURLE_OK; 97913498266Sopenharmony_ci 98013498266Sopenharmony_ci h = msg; 98113498266Sopenharmony_ci 98213498266Sopenharmony_ci switch(req->state) { 98313498266Sopenharmony_ci case SMB_TREE_CONNECT: 98413498266Sopenharmony_ci if(h->status) { 98513498266Sopenharmony_ci req->result = CURLE_REMOTE_FILE_NOT_FOUND; 98613498266Sopenharmony_ci if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 98713498266Sopenharmony_ci req->result = CURLE_REMOTE_ACCESS_DENIED; 98813498266Sopenharmony_ci break; 98913498266Sopenharmony_ci } 99013498266Sopenharmony_ci req->tid = smb_swap16(h->tid); 99113498266Sopenharmony_ci next_state = SMB_OPEN; 99213498266Sopenharmony_ci break; 99313498266Sopenharmony_ci 99413498266Sopenharmony_ci case SMB_OPEN: 99513498266Sopenharmony_ci if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { 99613498266Sopenharmony_ci req->result = CURLE_REMOTE_FILE_NOT_FOUND; 99713498266Sopenharmony_ci if(h->status == smb_swap32(SMB_ERR_NOACCESS)) 99813498266Sopenharmony_ci req->result = CURLE_REMOTE_ACCESS_DENIED; 99913498266Sopenharmony_ci next_state = SMB_TREE_DISCONNECT; 100013498266Sopenharmony_ci break; 100113498266Sopenharmony_ci } 100213498266Sopenharmony_ci smb_m = (const struct smb_nt_create_response*) msg; 100313498266Sopenharmony_ci req->fid = smb_swap16(smb_m->fid); 100413498266Sopenharmony_ci data->req.offset = 0; 100513498266Sopenharmony_ci if(data->state.upload) { 100613498266Sopenharmony_ci data->req.size = data->state.infilesize; 100713498266Sopenharmony_ci Curl_pgrsSetUploadSize(data, data->req.size); 100813498266Sopenharmony_ci next_state = SMB_UPLOAD; 100913498266Sopenharmony_ci } 101013498266Sopenharmony_ci else { 101113498266Sopenharmony_ci data->req.size = smb_swap64(smb_m->end_of_file); 101213498266Sopenharmony_ci if(data->req.size < 0) { 101313498266Sopenharmony_ci req->result = CURLE_WEIRD_SERVER_REPLY; 101413498266Sopenharmony_ci next_state = SMB_CLOSE; 101513498266Sopenharmony_ci } 101613498266Sopenharmony_ci else { 101713498266Sopenharmony_ci Curl_pgrsSetDownloadSize(data, data->req.size); 101813498266Sopenharmony_ci if(data->set.get_filetime) 101913498266Sopenharmony_ci get_posix_time(&data->info.filetime, smb_m->last_change_time); 102013498266Sopenharmony_ci next_state = SMB_DOWNLOAD; 102113498266Sopenharmony_ci } 102213498266Sopenharmony_ci } 102313498266Sopenharmony_ci break; 102413498266Sopenharmony_ci 102513498266Sopenharmony_ci case SMB_DOWNLOAD: 102613498266Sopenharmony_ci if(h->status || smbc->got < sizeof(struct smb_header) + 14) { 102713498266Sopenharmony_ci req->result = CURLE_RECV_ERROR; 102813498266Sopenharmony_ci next_state = SMB_CLOSE; 102913498266Sopenharmony_ci break; 103013498266Sopenharmony_ci } 103113498266Sopenharmony_ci len = Curl_read16_le(((const unsigned char *) msg) + 103213498266Sopenharmony_ci sizeof(struct smb_header) + 11); 103313498266Sopenharmony_ci off = Curl_read16_le(((const unsigned char *) msg) + 103413498266Sopenharmony_ci sizeof(struct smb_header) + 13); 103513498266Sopenharmony_ci if(len > 0) { 103613498266Sopenharmony_ci if(off + sizeof(unsigned int) + len > smbc->got) { 103713498266Sopenharmony_ci failf(data, "Invalid input packet"); 103813498266Sopenharmony_ci result = CURLE_RECV_ERROR; 103913498266Sopenharmony_ci } 104013498266Sopenharmony_ci else 104113498266Sopenharmony_ci result = Curl_client_write(data, CLIENTWRITE_BODY, 104213498266Sopenharmony_ci (char *)msg + off + sizeof(unsigned int), 104313498266Sopenharmony_ci len); 104413498266Sopenharmony_ci if(result) { 104513498266Sopenharmony_ci req->result = result; 104613498266Sopenharmony_ci next_state = SMB_CLOSE; 104713498266Sopenharmony_ci break; 104813498266Sopenharmony_ci } 104913498266Sopenharmony_ci } 105013498266Sopenharmony_ci data->req.offset += len; 105113498266Sopenharmony_ci next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD; 105213498266Sopenharmony_ci break; 105313498266Sopenharmony_ci 105413498266Sopenharmony_ci case SMB_UPLOAD: 105513498266Sopenharmony_ci if(h->status || smbc->got < sizeof(struct smb_header) + 6) { 105613498266Sopenharmony_ci req->result = CURLE_UPLOAD_FAILED; 105713498266Sopenharmony_ci next_state = SMB_CLOSE; 105813498266Sopenharmony_ci break; 105913498266Sopenharmony_ci } 106013498266Sopenharmony_ci len = Curl_read16_le(((const unsigned char *) msg) + 106113498266Sopenharmony_ci sizeof(struct smb_header) + 5); 106213498266Sopenharmony_ci data->req.bytecount += len; 106313498266Sopenharmony_ci data->req.offset += len; 106413498266Sopenharmony_ci Curl_pgrsSetUploadCounter(data, data->req.bytecount); 106513498266Sopenharmony_ci if(data->req.bytecount >= data->req.size) 106613498266Sopenharmony_ci next_state = SMB_CLOSE; 106713498266Sopenharmony_ci else 106813498266Sopenharmony_ci next_state = SMB_UPLOAD; 106913498266Sopenharmony_ci break; 107013498266Sopenharmony_ci 107113498266Sopenharmony_ci case SMB_CLOSE: 107213498266Sopenharmony_ci /* We don't care if the close failed, proceed to tree disconnect anyway */ 107313498266Sopenharmony_ci next_state = SMB_TREE_DISCONNECT; 107413498266Sopenharmony_ci break; 107513498266Sopenharmony_ci 107613498266Sopenharmony_ci case SMB_TREE_DISCONNECT: 107713498266Sopenharmony_ci next_state = SMB_DONE; 107813498266Sopenharmony_ci break; 107913498266Sopenharmony_ci 108013498266Sopenharmony_ci default: 108113498266Sopenharmony_ci smb_pop_message(conn); 108213498266Sopenharmony_ci return CURLE_OK; /* ignore */ 108313498266Sopenharmony_ci } 108413498266Sopenharmony_ci 108513498266Sopenharmony_ci smb_pop_message(conn); 108613498266Sopenharmony_ci 108713498266Sopenharmony_ci switch(next_state) { 108813498266Sopenharmony_ci case SMB_OPEN: 108913498266Sopenharmony_ci result = smb_send_open(data); 109013498266Sopenharmony_ci break; 109113498266Sopenharmony_ci 109213498266Sopenharmony_ci case SMB_DOWNLOAD: 109313498266Sopenharmony_ci result = smb_send_read(data); 109413498266Sopenharmony_ci break; 109513498266Sopenharmony_ci 109613498266Sopenharmony_ci case SMB_UPLOAD: 109713498266Sopenharmony_ci result = smb_send_write(data); 109813498266Sopenharmony_ci break; 109913498266Sopenharmony_ci 110013498266Sopenharmony_ci case SMB_CLOSE: 110113498266Sopenharmony_ci result = smb_send_close(data); 110213498266Sopenharmony_ci break; 110313498266Sopenharmony_ci 110413498266Sopenharmony_ci case SMB_TREE_DISCONNECT: 110513498266Sopenharmony_ci result = smb_send_tree_disconnect(data); 110613498266Sopenharmony_ci break; 110713498266Sopenharmony_ci 110813498266Sopenharmony_ci case SMB_DONE: 110913498266Sopenharmony_ci result = req->result; 111013498266Sopenharmony_ci *done = true; 111113498266Sopenharmony_ci break; 111213498266Sopenharmony_ci 111313498266Sopenharmony_ci default: 111413498266Sopenharmony_ci break; 111513498266Sopenharmony_ci } 111613498266Sopenharmony_ci 111713498266Sopenharmony_ci if(result) { 111813498266Sopenharmony_ci connclose(conn, "SMB: failed to send message"); 111913498266Sopenharmony_ci return result; 112013498266Sopenharmony_ci } 112113498266Sopenharmony_ci 112213498266Sopenharmony_ci request_state(data, next_state); 112313498266Sopenharmony_ci 112413498266Sopenharmony_ci return CURLE_OK; 112513498266Sopenharmony_ci} 112613498266Sopenharmony_ci 112713498266Sopenharmony_cistatic CURLcode smb_disconnect(struct Curl_easy *data, 112813498266Sopenharmony_ci struct connectdata *conn, bool dead) 112913498266Sopenharmony_ci{ 113013498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 113113498266Sopenharmony_ci (void) dead; 113213498266Sopenharmony_ci (void) data; 113313498266Sopenharmony_ci Curl_safefree(smbc->share); 113413498266Sopenharmony_ci Curl_safefree(smbc->domain); 113513498266Sopenharmony_ci Curl_safefree(smbc->recv_buf); 113613498266Sopenharmony_ci return CURLE_OK; 113713498266Sopenharmony_ci} 113813498266Sopenharmony_ci 113913498266Sopenharmony_cistatic int smb_getsock(struct Curl_easy *data, 114013498266Sopenharmony_ci struct connectdata *conn, curl_socket_t *socks) 114113498266Sopenharmony_ci{ 114213498266Sopenharmony_ci (void)data; 114313498266Sopenharmony_ci socks[0] = conn->sock[FIRSTSOCKET]; 114413498266Sopenharmony_ci return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); 114513498266Sopenharmony_ci} 114613498266Sopenharmony_ci 114713498266Sopenharmony_cistatic CURLcode smb_do(struct Curl_easy *data, bool *done) 114813498266Sopenharmony_ci{ 114913498266Sopenharmony_ci struct connectdata *conn = data->conn; 115013498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 115113498266Sopenharmony_ci 115213498266Sopenharmony_ci *done = FALSE; 115313498266Sopenharmony_ci if(smbc->share) { 115413498266Sopenharmony_ci return CURLE_OK; 115513498266Sopenharmony_ci } 115613498266Sopenharmony_ci return CURLE_URL_MALFORMAT; 115713498266Sopenharmony_ci} 115813498266Sopenharmony_ci 115913498266Sopenharmony_cistatic CURLcode smb_parse_url_path(struct Curl_easy *data, 116013498266Sopenharmony_ci struct connectdata *conn) 116113498266Sopenharmony_ci{ 116213498266Sopenharmony_ci struct smb_request *req = data->req.p.smb; 116313498266Sopenharmony_ci struct smb_conn *smbc = &conn->proto.smbc; 116413498266Sopenharmony_ci char *path; 116513498266Sopenharmony_ci char *slash; 116613498266Sopenharmony_ci 116713498266Sopenharmony_ci /* URL decode the path */ 116813498266Sopenharmony_ci CURLcode result = Curl_urldecode(data->state.up.path, 0, &path, NULL, 116913498266Sopenharmony_ci REJECT_CTRL); 117013498266Sopenharmony_ci if(result) 117113498266Sopenharmony_ci return result; 117213498266Sopenharmony_ci 117313498266Sopenharmony_ci /* Parse the path for the share */ 117413498266Sopenharmony_ci smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path); 117513498266Sopenharmony_ci free(path); 117613498266Sopenharmony_ci if(!smbc->share) 117713498266Sopenharmony_ci return CURLE_OUT_OF_MEMORY; 117813498266Sopenharmony_ci 117913498266Sopenharmony_ci slash = strchr(smbc->share, '/'); 118013498266Sopenharmony_ci if(!slash) 118113498266Sopenharmony_ci slash = strchr(smbc->share, '\\'); 118213498266Sopenharmony_ci 118313498266Sopenharmony_ci /* The share must be present */ 118413498266Sopenharmony_ci if(!slash) { 118513498266Sopenharmony_ci Curl_safefree(smbc->share); 118613498266Sopenharmony_ci failf(data, "missing share in URL path for SMB"); 118713498266Sopenharmony_ci return CURLE_URL_MALFORMAT; 118813498266Sopenharmony_ci } 118913498266Sopenharmony_ci 119013498266Sopenharmony_ci /* Parse the path for the file path converting any forward slashes into 119113498266Sopenharmony_ci backslashes */ 119213498266Sopenharmony_ci *slash++ = 0; 119313498266Sopenharmony_ci req->path = slash; 119413498266Sopenharmony_ci 119513498266Sopenharmony_ci for(; *slash; slash++) { 119613498266Sopenharmony_ci if(*slash == '/') 119713498266Sopenharmony_ci *slash = '\\'; 119813498266Sopenharmony_ci } 119913498266Sopenharmony_ci return CURLE_OK; 120013498266Sopenharmony_ci} 120113498266Sopenharmony_ci 120213498266Sopenharmony_ci#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && 120313498266Sopenharmony_ci SIZEOF_CURL_OFF_T > 4 */ 1204