quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

smb.c (37184B)


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