summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/smb.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/smb.c')
-rw-r--r--Utilities/cmcurl/lib/smb.c160
1 files changed, 90 insertions, 70 deletions
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index 5b1ffa9b7..76c99a230 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
- * Copyright (C) 2016-2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2016-2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -34,7 +34,7 @@
#include <process.h>
#ifdef CURL_WINDOWS_APP
#define getpid GetCurrentProcessId
-#else
+#elif !defined(MSDOS)
#define getpid _getpid
#endif
#endif
@@ -59,6 +59,7 @@
static CURLcode smb_setup_connection(struct connectdata *conn);
static CURLcode smb_connect(struct connectdata *conn, bool *done);
static CURLcode smb_connection_state(struct connectdata *conn, bool *done);
+static CURLcode smb_do(struct connectdata *conn, bool *done);
static CURLcode smb_request_state(struct connectdata *conn, bool *done);
static CURLcode smb_done(struct connectdata *conn, CURLcode status,
bool premature);
@@ -73,7 +74,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn);
const struct Curl_handler Curl_handler_smb = {
"SMB", /* scheme */
smb_setup_connection, /* setup_connection */
- ZERO_NULL, /* do_it */
+ smb_do, /* do_it */
smb_done, /* done */
ZERO_NULL, /* do_more */
smb_connect, /* connect_it */
@@ -85,6 +86,7 @@ const struct Curl_handler Curl_handler_smb = {
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
PORT_SMB, /* defport */
CURLPROTO_SMB, /* protocol */
PROTOPT_NONE /* flags */
@@ -97,7 +99,7 @@ const struct Curl_handler Curl_handler_smb = {
const struct Curl_handler Curl_handler_smbs = {
"SMBS", /* scheme */
smb_setup_connection, /* setup_connection */
- ZERO_NULL, /* do_it */
+ smb_do, /* do_it */
smb_done, /* done */
ZERO_NULL, /* do_more */
smb_connect, /* connect_it */
@@ -109,6 +111,7 @@ const struct Curl_handler Curl_handler_smbs = {
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
PORT_SMBS, /* defport */
CURLPROTO_SMBS, /* protocol */
PROTOPT_SSL /* flags */
@@ -144,19 +147,12 @@ static unsigned int smb_swap32(unsigned int x)
((x >> 24) & 0xff);
}
-#ifdef HAVE_LONGLONG
-static unsigned long long smb_swap64(unsigned long long x)
+static curl_off_t smb_swap64(curl_off_t x)
{
- return ((unsigned long long) smb_swap32((unsigned int) x) << 32) |
+ return ((curl_off_t) smb_swap32((unsigned int) x) << 32) |
smb_swap32((unsigned int) (x >> 32));
}
-#else
-static unsigned __int64 smb_swap64(unsigned __int64 x)
-{
- return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) |
- smb_swap32((unsigned int) (x >> 32));
-}
-#endif
+
#else
# define smb_swap16(x) (x)
# define smb_swap32(x) (x)
@@ -178,7 +174,6 @@ enum smb_req_state {
/* SMB request data */
struct smb_request {
enum smb_req_state state;
- char *share;
char *path;
unsigned short tid; /* Even if we connect to the same tree as another */
unsigned short fid; /* request, the tid will be different */
@@ -187,7 +182,7 @@ struct smb_request {
static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
{
- struct smb_conn *smb = &conn->proto.smbc;
+ struct smb_conn *smbc = &conn->proto.smbc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* For debug purposes */
static const char * const names[] = {
@@ -199,12 +194,12 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
/* LAST */
};
- if(smb->state != newstate)
+ if(smbc->state != newstate)
infof(conn->data, "SMB conn %p state change from %s to %s\n",
- (void *)smb, names[smb->state], names[newstate]);
+ (void *)smbc, names[smbc->state], names[newstate]);
#endif
- smb->state = newstate;
+ smbc->state = newstate;
}
static void request_state(struct connectdata *conn,
@@ -233,6 +228,8 @@ static void request_state(struct connectdata *conn,
req->state = newstate;
}
+/* this should setup things in the connection, not in the easy
+ handle */
static CURLcode smb_setup_connection(struct connectdata *conn)
{
struct smb_request *req;
@@ -258,7 +255,6 @@ static CURLcode smb_connect(struct connectdata *conn, bool *done)
return CURLE_LOGIN_DENIED;
/* Initialize the connection state */
- memset(smbc, 0, sizeof(*smbc));
smbc->state = SMB_CONNECTING;
smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
if(!smbc->recv_buf)
@@ -371,7 +367,7 @@ static CURLcode smb_send(struct connectdata *conn, ssize_t len,
ssize_t bytes_written;
CURLcode result;
- result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer,
+ result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf,
len, &bytes_written);
if(result)
return result;
@@ -397,7 +393,7 @@ static CURLcode smb_flush(struct connectdata *conn)
return CURLE_OK;
result = Curl_write(conn, FIRSTSOCKET,
- conn->data->state.uploadbuffer + smbc->sent,
+ conn->data->state.ulbuf + smbc->sent,
len, &bytes_written);
if(result)
return result;
@@ -413,9 +409,12 @@ static CURLcode smb_flush(struct connectdata *conn)
static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd,
const void *msg, size_t msg_len)
{
- smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer,
+ CURLcode result = Curl_get_upload_buffer(conn->data);
+ if(result)
+ return result;
+ smb_format_message(conn, (struct smb_header *)conn->data->state.ulbuf,
cmd, msg_len);
- memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header),
+ memcpy(conn->data->state.ulbuf + sizeof(struct smb_header),
msg, msg_len);
return smb_send(conn, sizeof(struct smb_header) + msg_len, 0);
@@ -480,11 +479,11 @@ static CURLcode smb_send_setup(struct connectdata *conn)
static CURLcode smb_send_tree_connect(struct connectdata *conn)
{
- struct smb_request *req = conn->data->req.protop;
struct smb_tree_connect msg;
+ struct smb_conn *smbc = &conn->proto.smbc;
char *p = msg.bytes;
- size_t byte_count = strlen(conn->host.name) + strlen(req->share);
+ size_t byte_count = strlen(conn->host.name) + strlen(smbc->share);
byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
if(byte_count > sizeof(msg.bytes))
return CURLE_FILESIZE_EXCEEDED;
@@ -496,7 +495,7 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
MSGCAT("\\\\");
MSGCAT(conn->host.name);
MSGCAT("\\");
- MSGCATNULL(req->share);
+ MSGCATNULL(smbc->share);
MSGCATNULL(SERVICENAME); /* Match any type of service */
byte_count = p - msg.bytes;
msg.byte_count = smb_swap16((unsigned short)byte_count);
@@ -576,11 +575,15 @@ static CURLcode smb_send_read(struct connectdata *conn)
static CURLcode smb_send_write(struct connectdata *conn)
{
- struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer;
+ struct smb_write *msg;
struct smb_request *req = conn->data->req.protop;
curl_off_t offset = conn->data->req.offset;
-
curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
+ CURLcode result = Curl_get_upload_buffer(conn->data);
+ if(result)
+ return result;
+ msg = (struct smb_write *)conn->data->state.ulbuf;
+
if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
upload_size = MAX_PAYLOAD_SIZE - 1;
@@ -607,9 +610,10 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
/* Check if there is data in the transfer buffer */
if(!smbc->send_size && smbc->upload_size) {
- int nread = smbc->upload_size > UPLOAD_BUFSIZE ? UPLOAD_BUFSIZE :
- (int) smbc->upload_size;
- conn->data->req.upload_fromhere = conn->data->state.uploadbuffer;
+ size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ?
+ conn->data->set.upload_buffer_size :
+ smbc->upload_size;
+ conn->data->req.upload_fromhere = conn->data->state.ulbuf;
result = Curl_fillreadbuffer(conn, nread, &nread);
if(result && result != CURLE_AGAIN)
return result;
@@ -646,7 +650,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
if(smbc->state == SMB_CONNECTING) {
#ifdef USE_SSL
if((conn->handler->flags & PROTOPT_SSL)) {
- bool ssl_done;
+ bool ssl_done = FALSE;
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
if(result && result != CURLE_AGAIN)
return result;
@@ -713,6 +717,24 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
return CURLE_OK;
}
+/*
+ * Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601)
+ * to Posix time. Cap the output to fit within a time_t.
+ */
+static void get_posix_time(time_t *out, curl_off_t timestamp)
+{
+ timestamp -= 116444736000000000;
+ timestamp /= 10000000;
+#if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T
+ if(timestamp > TIME_T_MAX)
+ *out = TIME_T_MAX;
+ else if(timestamp < TIME_T_MIN)
+ *out = TIME_T_MIN;
+ else
+#endif
+ *out = (time_t) timestamp;
+}
+
static CURLcode smb_request_state(struct connectdata *conn, bool *done)
{
struct smb_request *req = conn->data->req.protop;
@@ -723,6 +745,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
unsigned short off;
CURLcode result;
void *msg = NULL;
+ const struct smb_nt_create_response *smb_m;
/* Start the request */
if(req->state == SMB_REQUESTING) {
@@ -765,7 +788,8 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
next_state = SMB_TREE_DISCONNECT;
break;
}
- req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid);
+ smb_m = (const struct smb_nt_create_response*) msg;
+ req->fid = smb_swap16(smb_m->fid);
conn->data->req.offset = 0;
if(conn->data->set.upload) {
conn->data->req.size = conn->data->state.infilesize;
@@ -773,10 +797,18 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
next_state = SMB_UPLOAD;
}
else {
- conn->data->req.size =
- smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file);
- Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
- next_state = SMB_DOWNLOAD;
+ smb_m = (const struct smb_nt_create_response*) msg;
+ conn->data->req.size = smb_swap64(smb_m->end_of_file);
+ if(conn->data->req.size < 0) {
+ req->result = CURLE_WEIRD_SERVER_REPLY;
+ next_state = SMB_CLOSE;
+ }
+ else {
+ Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
+ if(conn->data->set.get_filetime)
+ get_posix_time(&conn->data->info.filetime, smb_m->last_change_time);
+ next_state = SMB_DOWNLOAD;
+ }
}
break;
@@ -887,48 +919,40 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
static CURLcode smb_done(struct connectdata *conn, CURLcode status,
bool premature)
{
- struct smb_request *req = conn->data->req.protop;
-
(void) premature;
-
- Curl_safefree(req->share);
Curl_safefree(conn->data->req.protop);
-
return status;
}
static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
{
struct smb_conn *smbc = &conn->proto.smbc;
- struct smb_request *req = conn->data->req.protop;
-
(void) dead;
-
+ Curl_safefree(smbc->share);
Curl_safefree(smbc->domain);
Curl_safefree(smbc->recv_buf);
-
- /* smb_done is not always called, so cleanup the request */
- if(req) {
- Curl_safefree(req->share);
- }
-
return CURLE_OK;
}
static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks)
{
- struct smb_conn *smbc = &conn->proto.smbc;
-
if(!numsocks)
return GETSOCK_BLANK;
socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
+}
- if(smbc->send_size || smbc->upload_size)
- return GETSOCK_WRITESOCK(0);
+static CURLcode smb_do(struct connectdata *conn, bool *done)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
- return GETSOCK_READSOCK(0);
+ *done = FALSE;
+ if(smbc->share) {
+ return CURLE_OK;
+ }
+ return CURLE_URL_MALFORMAT;
}
static CURLcode smb_parse_url_path(struct connectdata *conn)
@@ -936,30 +960,28 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct smb_request *req = data->req.protop;
+ struct smb_conn *smbc = &conn->proto.smbc;
char *path;
char *slash;
/* URL decode the path */
- result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE);
+ result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, TRUE);
if(result)
return result;
/* Parse the path for the share */
- req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path);
- if(!req->share) {
- free(path);
-
+ smbc->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path);
+ free(path);
+ if(!smbc->share)
return CURLE_OUT_OF_MEMORY;
- }
- slash = strchr(req->share, '/');
+ slash = strchr(smbc->share, '/');
if(!slash)
- slash = strchr(req->share, '\\');
+ slash = strchr(smbc->share, '\\');
/* The share must be present */
if(!slash) {
- free(path);
-
+ Curl_safefree(smbc->share);
return CURLE_URL_MALFORMAT;
}
@@ -967,13 +989,11 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
backslashes */
*slash++ = 0;
req->path = slash;
+
for(; *slash; slash++) {
if(*slash == '/')
*slash = '\\';
}
-
- free(path);
-
return CURLE_OK;
}