diff options
Diffstat (limited to 'libs/libssh2/src/scp.c')
-rw-r--r-- | libs/libssh2/src/scp.c | 198 |
1 files changed, 118 insertions, 80 deletions
diff --git a/libs/libssh2/src/scp.c b/libs/libssh2/src/scp.c index a9d2db5354..ff20a80ae5 100644 --- a/libs/libssh2/src/scp.c +++ b/libs/libssh2/src/scp.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2009-2019 by Daniel Stenberg - * Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org> +/* Copyright (C) Daniel Stenberg + * Copyright (C) Sara Golemon <sarag@libssh2.org> * All rights reserved. * * Redistribution and use in source and binary forms, @@ -34,15 +34,24 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. + * + * SPDX-License-Identifier: BSD-3-Clause */ #include "libssh2_priv.h" -#include <errno.h> -#include <stdlib.h> #include "channel.h" #include "session.h" +#include <stdlib.h> /* strtoll(), _strtoi64(), strtol() */ + +#if defined(HAVE_STRTOLL) +#define scpsize_strtol strtoll +#elif defined(HAVE_STRTOI64) +#define scpsize_strtol _strtoi64 +#else +#define scpsize_strtol strtol +#endif /* Max. length of a quoted string after libssh2_shell_quotearg() processing */ #define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) @@ -65,13 +74,13 @@ current argument word, add the apostrophe in quotation marks "", and open a new argument word instead (_ indicate the input string characters): - _____ _ _ + _____ _ _ 'doesn' "'" 't' Sequences of apostrophes are combined in one pair of quotation marks: a'''b becomes - _ ___ _ + _ ___ _ 'a'"'''"'b' o If the string contains an exclamation mark (!), the C-Shell @@ -84,7 +93,7 @@ a!b become - _ _ _ + _ _ _ 'a'\!'b' The result buffer must be large enough for the expanded result. A @@ -112,7 +121,7 @@ References: o csh-compatible quotation (special handling for '!' etc.), see - http://www.grymoire.com/Unix/Csh.html#toc-uh-10 + https://www.grymoire.com/Unix/Csh.html#toc-uh-10 Return value: Length of the resulting string (not counting the terminating '\0'), @@ -122,9 +131,9 @@ until then it is kept static and in this source file. */ -static unsigned +static size_t shell_quotearg(const char *path, unsigned char *buf, - unsigned bufsize) + size_t bufsize) { const char *src; unsigned char *dst, *endp; @@ -270,7 +279,7 @@ shell_quotearg(const char *path, unsigned char *buf, static LIBSSH2_CHANNEL * scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -282,7 +291,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) session->scpRecv_atime = 0; session->scpRecv_command_len = - _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); + _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb ? 1 : 0); session->scpRecv_command = LIBSSH2_ALLOC(session, session->scpRecv_command_len); @@ -296,18 +305,30 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) snprintf((char *)session->scpRecv_command, session->scpRecv_command_len, - "scp -%sf ", sb?"p":""); + "scp -%sf ", sb ? "p" : ""); cmd_len = strlen((char *)session->scpRecv_command); - cmd_len += shell_quotearg(path, - &session->scpRecv_command[cmd_len], - session->scpRecv_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpRecv_command[cmd_len], path, path_len); + cmd_len += path_len; + } + else { + cmd_len += shell_quotearg(path, + &session->scpRecv_command[cmd_len], + session->scpRecv_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpRecv_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP receive"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP receive")); session->scpRecv_state = libssh2_NB_state_created; } @@ -356,7 +377,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) LIBSSH2_FREE(session, session->scpRecv_command); session->scpRecv_command = NULL; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sending initial wakeup")); /* SCP ACK */ session->scpRecv_response[0] = '\0'; @@ -364,8 +385,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent1) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending initial wakeup"); @@ -384,14 +405,15 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) if((session->scpRecv_state == libssh2_NB_state_sent2) || (session->scpRecv_state == libssh2_NB_state_sent3)) { while(sb && (session->scpRecv_response_len < - LIBSSH2_SCP_RESPONSE_BUFLEN)) { + LIBSSH2_SCP_RESPONSE_BUFLEN)) { unsigned char *s, *p; if(session->scpRecv_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); @@ -435,9 +457,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) /* zero terminate the error */ err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpRecv_response[0], - err_msg); + err_msg)); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Failed to recv file"); @@ -550,8 +572,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent3) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting to send SCP ACK"); @@ -561,9 +583,10 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mtime = %ld, atime = %ld", - session->scpRecv_mtime, session->scpRecv_atime); + session->scpRecv_mtime, + session->scpRecv_atime)); /* We *should* check that atime.usec is valid, but why let that stop use? */ @@ -586,17 +609,18 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) char *s, *p, *e = NULL; if(session->scpRecv_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_read(session->scpRecv_channel, 0, - (char *) session-> - scpRecv_response + - session->scpRecv_response_len, 1); + rc = (int)_libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for SCP response"); return NULL; } else if(rc < 0) { - /* error, bail out*/ + /* error, bail out */ _libssh2_error(session, rc, "Failed reading SCP response"); goto scp_recv_error; } @@ -678,7 +702,6 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) *(p++) = '\0'; /* Make sure we don't get fooled by leftover values */ - session->scpRecv_mode = strtol(s, &e, 8); if(e && *e) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -713,8 +736,8 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) } if(session->scpRecv_state == libssh2_NB_state_sent6) { - rc = _libssh2_channel_write(session->scpRecv_channel, 0, - session->scpRecv_response, 1); + rc = (int)_libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending SCP ACK"); @@ -723,9 +746,9 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else if(rc != 1) { goto scp_recv_error; } - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "mode = 0%lo size = %ld", session->scpRecv_mode, - session->scpRecv_size); + session->scpRecv_size)); /* We *should* check that basename is valid, but why let that stop us? */ @@ -741,14 +764,14 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) sb->st_mtime = session->scpRecv_mtime; sb->st_atime = session->scpRecv_atime; - sb->st_size = session->scpRecv_size; + sb->st_size = (libssh2_struct_stat_size)session->scpRecv_size; sb->st_mode = (unsigned short)session->scpRecv_mode; } session->scpRecv_state = libssh2_NB_state_idle; return session->scpRecv_channel; - scp_recv_empty_channel: +scp_recv_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpRecv_channel)) @@ -757,7 +780,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) else return session->scpRecv_channel; /* fall-through */ - scp_recv_error: +scp_recv_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpRecv_channel) == @@ -780,7 +803,7 @@ scp_recv(LIBSSH2_SESSION * session, const char *path, libssh2_struct_stat * sb) * */ LIBSSH2_API LIBSSH2_CHANNEL * -libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) +libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb) { LIBSSH2_CHANNEL *ptr; @@ -823,7 +846,7 @@ libssh2_scp_recv2(LIBSSH2_SESSION *session, const char *path, } /* - * scp_send() + * scp_send * * Send a file using SCP * @@ -832,7 +855,7 @@ static LIBSSH2_CHANNEL * scp_send(LIBSSH2_SESSION * session, const char *path, int mode, libssh2_int64_t size, time_t mtime, time_t atime) { - int cmd_len; + size_t cmd_len; int rc; int tmp_err_code; const char *tmp_err_msg; @@ -840,7 +863,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_idle) { session->scpSend_command_len = _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + - ((mtime || atime)?1:0); + ((mtime || atime) ? 1 : 0); session->scpSend_command = LIBSSH2_ALLOC(session, session->scpSend_command_len); @@ -854,18 +877,31 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *)session->scpSend_command, session->scpSend_command_len, - "scp -%st ", (mtime || atime)?"p":""); + "scp -%st ", (mtime || atime) ? "p" : ""); cmd_len = strlen((char *)session->scpSend_command); - cmd_len += shell_quotearg(path, - &session->scpSend_command[cmd_len], - session->scpSend_command_len - cmd_len); + + if(!session->flag.quote_paths) { + size_t path_len; + + path_len = strlen(path); + + /* no NUL-termination needed, so memcpy will do */ + memcpy(&session->scpSend_command[cmd_len], path, path_len); + cmd_len += path_len; + + } + else { + cmd_len += shell_quotearg(path, + &session->scpSend_command[cmd_len], + session->scpSend_command_len - cmd_len); + } /* the command to exec should _not_ be NUL-terminated */ session->scpSend_command_len = cmd_len; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, - "Opening channel for SCP send"); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP send")); /* Allocate a channel */ session->scpSend_state = libssh2_NB_state_created; @@ -922,8 +958,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent1) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response from remote"); @@ -936,7 +972,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote"); goto scp_send_error; @@ -947,8 +983,8 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, snprintf((char *) session->scpSend_response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", (long)mtime, (long)atime); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); } session->scpSend_state = libssh2_NB_state_sent2; @@ -957,9 +993,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, /* Send mtime and atime to be used for file */ if(mtime || atime) { if(session->scpSend_state == libssh2_NB_state_sent2) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending time data for SCP file"); @@ -976,8 +1012,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent3) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -990,7 +1027,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(!rc) /* remain in the same state */ goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid SCP ACK response"); goto scp_send_error; @@ -1018,16 +1055,16 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" LIBSSH2_INT64_T_FORMAT " %s\n", mode, size, base); - _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", - session->scpSend_response); + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response)); session->scpSend_state = libssh2_NB_state_sent5; } if(session->scpSend_state == libssh2_NB_state_sent5) { - rc = _libssh2_channel_write(session->scpSend_channel, 0, - session->scpSend_response, - session->scpSend_response_len); + rc = (int)_libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block send core file data for SCP file"); @@ -1044,8 +1081,9 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, if(session->scpSend_state == libssh2_NB_state_sent6) { /* Wait for ACK */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - (char *) session->scpSend_response, 1); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, + 1); if(rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block waiting for response"); @@ -1059,7 +1097,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else if(rc == 0) goto scp_send_empty_channel; - else if(session->scpSend_response[0] != 0) { + else if(session->scpSend_response[0]) { size_t err_len; char *err_msg; @@ -1073,13 +1111,13 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, } /* Read the remote error message */ - rc = _libssh2_channel_read(session->scpSend_channel, 0, - err_msg, err_len); + rc = (int)_libssh2_channel_read(session->scpSend_channel, 0, + err_msg, err_len); if(rc > 0) { err_msg[err_len] = 0; - _libssh2_debug(session, LIBSSH2_TRACE_SCP, + _libssh2_debug((session, LIBSSH2_TRACE_SCP, "got %02x %s", session->scpSend_response[0], - err_msg); + err_msg)); } LIBSSH2_FREE(session, err_msg); _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, @@ -1091,7 +1129,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, session->scpSend_state = libssh2_NB_state_idle; return session->scpSend_channel; - scp_send_empty_channel: +scp_send_empty_channel: /* the code only jumps here as a result of a zero read from channel_read() so we check EOF status to avoid getting stuck in a loop */ if(libssh2_channel_eof(session->scpSend_channel)) { @@ -1101,7 +1139,7 @@ scp_send(LIBSSH2_SESSION * session, const char *path, int mode, else return session->scpSend_channel; /* fall-through */ - scp_send_error: +scp_send_error: tmp_err_code = session->err_code; tmp_err_msg = session->err_msg; while(libssh2_channel_free(session->scpSend_channel) == |