mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 10:40:27 +09:00
CVE-2019-14889: scp: Reformat scp.c
Fixes T181 Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
committed by
Andreas Schneider
parent
27bcac6845
commit
42c727d0c1
558
src/scp.c
558
src/scp.c
@@ -57,30 +57,47 @@
|
||||
*
|
||||
* @returns A ssh_scp handle, NULL if the creation was impossible.
|
||||
*/
|
||||
ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
|
||||
ssh_scp scp=malloc(sizeof(struct ssh_scp_struct));
|
||||
ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location)
|
||||
{
|
||||
ssh_scp scp = NULL;
|
||||
|
||||
if (session == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
scp = (ssh_scp)calloc(1, sizeof(struct ssh_scp_struct));
|
||||
if (scp == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
|
||||
return NULL;
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Error allocating memory for ssh_scp");
|
||||
goto error;
|
||||
}
|
||||
ZERO_STRUCTP(scp);
|
||||
if((mode&~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE && (mode &~SSH_SCP_RECURSIVE) != SSH_SCP_READ){
|
||||
ssh_set_error(session,SSH_FATAL,"Invalid mode %d for ssh_scp_new()",mode);
|
||||
ssh_scp_free(scp);
|
||||
return NULL;
|
||||
|
||||
if ((mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_WRITE &&
|
||||
(mode & ~SSH_SCP_RECURSIVE) != SSH_SCP_READ)
|
||||
{
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Invalid mode %d for ssh_scp_new()", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
scp->location = strdup(location);
|
||||
if (scp->location == NULL) {
|
||||
ssh_set_error(session,SSH_FATAL,"Error allocating memory for ssh_scp");
|
||||
ssh_scp_free(scp);
|
||||
return NULL;
|
||||
ssh_set_error(session, SSH_FATAL,
|
||||
"Error allocating memory for ssh_scp");
|
||||
goto error;
|
||||
}
|
||||
|
||||
scp->session = session;
|
||||
scp->mode = mode & ~SSH_SCP_RECURSIVE;
|
||||
scp->recursive = (mode & SSH_SCP_RECURSIVE) != 0;
|
||||
scp->channel = NULL;
|
||||
scp->state = SSH_SCP_NEW;
|
||||
|
||||
return scp;
|
||||
|
||||
error:
|
||||
ssh_scp_free(scp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,58 +111,77 @@ ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location){
|
||||
*/
|
||||
int ssh_scp_init(ssh_scp scp)
|
||||
{
|
||||
int r;
|
||||
char execbuffer[1024];
|
||||
int rc;
|
||||
char execbuffer[1024] = {0};
|
||||
uint8_t code;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
if(scp->state != SSH_SCP_NEW){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_init called under invalid state");
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"Initializing scp session %s %son location '%s'",
|
||||
|
||||
if (scp->state != SSH_SCP_NEW) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_init called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"Initializing scp session %s %son location '%s'",
|
||||
scp->mode == SSH_SCP_WRITE?"write":"read",
|
||||
scp->recursive?"recursive ":"",
|
||||
scp->location);
|
||||
|
||||
scp->channel = ssh_channel_new(scp->session);
|
||||
if (scp->channel == NULL) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r= ssh_channel_open_session(scp->channel);
|
||||
if(r==SSH_ERROR){
|
||||
|
||||
rc = ssh_channel_open_session(scp->channel);
|
||||
if (rc == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->mode == SSH_SCP_WRITE)
|
||||
|
||||
if (scp->mode == SSH_SCP_WRITE) {
|
||||
snprintf(execbuffer, sizeof(execbuffer), "scp -t %s %s",
|
||||
scp->recursive ? "-r":"", scp->location);
|
||||
else
|
||||
} else {
|
||||
snprintf(execbuffer, sizeof(execbuffer), "scp -f %s %s",
|
||||
scp->recursive ? "-r":"", scp->location);
|
||||
}
|
||||
|
||||
if (ssh_channel_request_exec(scp->channel, execbuffer) == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->mode == SSH_SCP_WRITE) {
|
||||
r=ssh_channel_read(scp->channel,&code,1,0);
|
||||
if(r<=0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Error reading status code: %s",
|
||||
ssh_get_error(scp->session));
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (code != 0) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"scp status code %ud not valid", code);
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
ssh_channel_write(scp->channel, "", 1);
|
||||
}
|
||||
if(scp->mode == SSH_SCP_WRITE)
|
||||
|
||||
if (scp->mode == SSH_SCP_WRITE) {
|
||||
scp->state = SSH_SCP_WRITE_INITED;
|
||||
else
|
||||
} else {
|
||||
scp->state = SSH_SCP_READ_INITED;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -160,10 +196,13 @@ int ssh_scp_init(ssh_scp scp)
|
||||
*/
|
||||
int ssh_scp_close(ssh_scp scp)
|
||||
{
|
||||
char buffer[128];
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
char buffer[128] = {0};
|
||||
int rc;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->channel != NULL) {
|
||||
if (ssh_channel_send_eof(scp->channel) == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
@@ -174,17 +213,21 @@ int ssh_scp_close(ssh_scp scp)
|
||||
* before we got the EOF back
|
||||
*/
|
||||
while (!ssh_channel_is_eof(scp->channel)) {
|
||||
err=ssh_channel_read(scp->channel,buffer,sizeof(buffer),0);
|
||||
if(err==SSH_ERROR || err==0)
|
||||
rc = ssh_channel_read(scp->channel, buffer, sizeof(buffer), 0);
|
||||
if (rc == SSH_ERROR || rc == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssh_channel_close(scp->channel) == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
ssh_channel_free(scp->channel);
|
||||
scp->channel = NULL;
|
||||
}
|
||||
|
||||
scp->state = SSH_SCP_NEW;
|
||||
return SSH_OK;
|
||||
}
|
||||
@@ -198,12 +241,18 @@ int ssh_scp_close(ssh_scp scp)
|
||||
*/
|
||||
void ssh_scp_free(ssh_scp scp)
|
||||
{
|
||||
if(scp==NULL)
|
||||
if (scp == NULL) {
|
||||
return;
|
||||
if(scp->state != SSH_SCP_NEW)
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_NEW) {
|
||||
ssh_scp_close(scp);
|
||||
if(scp->channel)
|
||||
}
|
||||
|
||||
if (scp->channel) {
|
||||
ssh_channel_free(scp->channel);
|
||||
}
|
||||
|
||||
SAFE_FREE(scp->location);
|
||||
SAFE_FREE(scp->request_name);
|
||||
SAFE_FREE(scp->warning);
|
||||
@@ -224,39 +273,52 @@ void ssh_scp_free(ssh_scp scp)
|
||||
*
|
||||
* @see ssh_scp_leave_directory()
|
||||
*/
|
||||
int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
||||
char buffer[1024];
|
||||
int r;
|
||||
int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode)
|
||||
{
|
||||
char buffer[1024] = {0};
|
||||
int rc;
|
||||
uint8_t code;
|
||||
char *dir;
|
||||
char *perms;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
if(scp->state != SSH_SCP_WRITE_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state");
|
||||
char *dir = NULL;
|
||||
char *perms = NULL;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_WRITE_INITED) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_push_directory called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
dir = ssh_basename(dirname);
|
||||
perms = ssh_scp_string_mode(mode);
|
||||
snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
|
||||
SAFE_FREE(dir);
|
||||
SAFE_FREE(perms);
|
||||
r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_channel_read(scp->channel,&code,1,0);
|
||||
if(r<=0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
|
||||
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Error reading status code: %s",
|
||||
ssh_get_error(scp->session));
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (code != 0) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
ssh_set_error(scp->session, SSH_FATAL, "scp status code %ud not valid",
|
||||
code);
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -268,37 +330,49 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
||||
*
|
||||
* @see ssh_scp_push_directory()
|
||||
*/
|
||||
int ssh_scp_leave_directory(ssh_scp scp){
|
||||
int ssh_scp_leave_directory(ssh_scp scp)
|
||||
{
|
||||
char buffer[] = "E\n";
|
||||
int r;
|
||||
int rc;
|
||||
uint8_t code;
|
||||
if(scp==NULL)
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_WRITE_INITED) {
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state");
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_leave_directory called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_channel_read(scp->channel,&code,1,0);
|
||||
if(r<=0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
|
||||
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL, "Error reading status code: %s",
|
||||
ssh_get_error(scp->session));
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (code != 0) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
ssh_set_error(scp->session, SSH_FATAL, "scp status code %ud not valid",
|
||||
code);
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the sending of a file to a scp in sink mode, using a 64-bit size.
|
||||
* @brief Initialize the sending of a file to a scp in sink mode, using a 64-bit
|
||||
* size.
|
||||
*
|
||||
* @param[in] scp The scp handle.
|
||||
*
|
||||
@@ -314,43 +388,60 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
||||
*
|
||||
* @see ssh_scp_push_file()
|
||||
*/
|
||||
int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, int mode){
|
||||
char buffer[1024];
|
||||
int r;
|
||||
int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size,
|
||||
int mode)
|
||||
{
|
||||
char buffer[1024] = {0};
|
||||
int rc;
|
||||
char *file = NULL;
|
||||
char *perms = NULL;
|
||||
uint8_t code;
|
||||
char *file;
|
||||
char *perms;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
if(scp->state != SSH_SCP_WRITE_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state");
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_WRITE_INITED) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_push_file called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
file = ssh_basename(filename);
|
||||
perms = ssh_scp_string_mode(mode);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",file,size,perms);
|
||||
SSH_LOG(SSH_LOG_PROTOCOL,
|
||||
"SCP pushing file %s, size %" PRIu64 " with permissions '%s'",
|
||||
file, size, perms);
|
||||
snprintf(buffer, sizeof(buffer), "C%s %" PRIu64 " %s\n", perms, size, file);
|
||||
SAFE_FREE(file);
|
||||
SAFE_FREE(perms);
|
||||
r=ssh_channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(r==SSH_ERROR){
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_channel_read(scp->channel,&code,1,0);
|
||||
if(r<=0){
|
||||
ssh_set_error(scp->session,SSH_FATAL, "Error reading status code: %s",ssh_get_error(scp->session));
|
||||
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc <= 0) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Error reading status code: %s",
|
||||
ssh_get_error(scp->session));
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (code != 0) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"scp status code %ud not valid", code);
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
scp->filelen = size;
|
||||
scp->processed = 0;
|
||||
scp->state = SSH_SCP_WRITE_WRITING;
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -369,7 +460,8 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, int mo
|
||||
* @returns SSH_OK if the file is ready to be sent, SSH_ERROR if an
|
||||
* error occured.
|
||||
*/
|
||||
int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
|
||||
int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode)
|
||||
{
|
||||
return ssh_scp_push_file64(scp, filename, (uint64_t) size, mode);
|
||||
}
|
||||
|
||||
@@ -385,39 +477,58 @@ int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, int mode){
|
||||
*
|
||||
* @returns The return code, SSH_ERROR a error occured.
|
||||
*/
|
||||
int ssh_scp_response(ssh_scp scp, char **response){
|
||||
int ssh_scp_response(ssh_scp scp, char **response)
|
||||
{
|
||||
unsigned char code;
|
||||
int r;
|
||||
char msg[128];
|
||||
if(scp==NULL)
|
||||
int rc;
|
||||
char msg[128] = {0};
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
r=ssh_channel_read(scp->channel,&code,1,0);
|
||||
if(r == SSH_ERROR)
|
||||
}
|
||||
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
if(code == 0)
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (code > 2) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "SCP: invalid status code %ud received", code);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"SCP: invalid status code %ud received", code);
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
r=ssh_scp_read_string(scp,msg,sizeof(msg));
|
||||
if(r==SSH_ERROR)
|
||||
return r;
|
||||
|
||||
rc = ssh_scp_read_string(scp, msg, sizeof(msg));
|
||||
if (rc == SSH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Warning */
|
||||
if (code == 1) {
|
||||
ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Warning: status code 1 received: %s", msg);
|
||||
SSH_LOG(SSH_LOG_RARE,"SCP: Warning: status code 1 received: %s", msg);
|
||||
if(response)
|
||||
ssh_set_error(scp->session, SSH_REQUEST_DENIED,
|
||||
"SCP: Warning: status code 1 received: %s", msg);
|
||||
SSH_LOG(SSH_LOG_RARE,
|
||||
"SCP: Warning: status code 1 received: %s", msg);
|
||||
if (response) {
|
||||
*response = strdup(msg);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (code == 2) {
|
||||
ssh_set_error(scp->session,SSH_FATAL, "SCP: Error: status code 2 received: %s", msg);
|
||||
if(response)
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"SCP: Error: status code 2 received: %s", msg);
|
||||
if (response) {
|
||||
*response = strdup(msg);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Not reached */
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -434,45 +545,58 @@ int ssh_scp_response(ssh_scp scp, char **response){
|
||||
* @returns SSH_OK if the write was successful, SSH_ERROR an error
|
||||
* occured while writing.
|
||||
*/
|
||||
int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
||||
int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len)
|
||||
{
|
||||
int w;
|
||||
int r;
|
||||
int rc;
|
||||
uint8_t code;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
if(scp->state != SSH_SCP_WRITE_WRITING){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_write called under invalid state");
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->processed + len > scp->filelen)
|
||||
|
||||
if (scp->state != SSH_SCP_WRITE_WRITING) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_write called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->processed + len > scp->filelen) {
|
||||
len = (size_t) (scp->filelen - scp->processed);
|
||||
}
|
||||
|
||||
/* hack to avoid waiting for window change */
|
||||
r = ssh_channel_poll(scp->channel, 0);
|
||||
if (r == SSH_ERROR) {
|
||||
rc = ssh_channel_poll(scp->channel, 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
w = ssh_channel_write(scp->channel, buffer, len);
|
||||
if(w != SSH_ERROR)
|
||||
if (w != SSH_ERROR) {
|
||||
scp->processed += w;
|
||||
else {
|
||||
} else {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
//return = channel_get_exit_status(scp->channel);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Far end sometimes send a status message, which we need to read
|
||||
* and handle */
|
||||
r = ssh_channel_poll(scp->channel,0);
|
||||
if(r > 0){
|
||||
r = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if(r == SSH_ERROR){
|
||||
rc = ssh_channel_poll(scp->channel, 0);
|
||||
if (rc > 0) {
|
||||
rc = ssh_channel_read(scp->channel, &code, 1, 0);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (code == 1 || code == 2) {
|
||||
ssh_set_error(scp->session,SSH_REQUEST_DENIED, "SCP: Error: status code %i received", code);
|
||||
ssh_set_error(scp->session, SSH_REQUEST_DENIED,
|
||||
"SCP: Error: status code %i received", code);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we arrived at end of file */
|
||||
if (scp->processed == scp->filelen) {
|
||||
code = 0;
|
||||
@@ -481,9 +605,11 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
scp->processed = scp->filelen = 0;
|
||||
scp->state = SSH_SCP_WRITE_INITED;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -501,26 +627,35 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
||||
* @returns SSH_OK if the string was read, SSH_ERROR if an error
|
||||
* occured while reading.
|
||||
*/
|
||||
int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
|
||||
size_t r=0;
|
||||
int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len)
|
||||
{
|
||||
size_t read = 0;
|
||||
int err = SSH_OK;
|
||||
if(scp==NULL)
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
while(r<len-1){
|
||||
err=ssh_channel_read(scp->channel,&buffer[r],1,0);
|
||||
}
|
||||
|
||||
while (read < len - 1) {
|
||||
err = ssh_channel_read(scp->channel, &buffer[read], 1, 0);
|
||||
if (err == SSH_ERROR) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
ssh_set_error(scp->session,SSH_FATAL,"End of file while reading string");
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"End of file while reading string");
|
||||
err = SSH_ERROR;
|
||||
break;
|
||||
}
|
||||
r++;
|
||||
if(buffer[r-1] == '\n')
|
||||
|
||||
read++;
|
||||
if (buffer[read - 1] == '\n') {
|
||||
break;
|
||||
}
|
||||
buffer[r]=0;
|
||||
}
|
||||
|
||||
buffer[read] = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -544,30 +679,39 @@ int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){
|
||||
* @see ssh_scp_accept_request()
|
||||
* @see ssh_scp_request_get_warning()
|
||||
*/
|
||||
int ssh_scp_pull_request(ssh_scp scp){
|
||||
int ssh_scp_pull_request(ssh_scp scp)
|
||||
{
|
||||
char buffer[MAX_BUF_SIZE] = {0};
|
||||
char *mode = NULL;
|
||||
char *p, *tmp;
|
||||
uint64_t size;
|
||||
char *name = NULL;
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
return SSH_ERROR;
|
||||
if(scp->state != SSH_SCP_READ_INITED){
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_pull_request called under invalid state");
|
||||
int rc;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
err=ssh_scp_read_string(scp,buffer,sizeof(buffer));
|
||||
if(err==SSH_ERROR){
|
||||
|
||||
if (scp->state != SSH_SCP_READ_INITED) {
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_pull_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = ssh_scp_read_string(scp, buffer, sizeof(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
if (ssh_channel_is_eof(scp->channel)) {
|
||||
scp->state = SSH_SCP_TERMINATED;
|
||||
return SSH_SCP_REQUEST_EOF;
|
||||
}
|
||||
return err;
|
||||
return rc;
|
||||
}
|
||||
|
||||
p = strchr(buffer, '\n');
|
||||
if(p!=NULL)
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PROTOCOL, "Received SCP request: '%s'", buffer);
|
||||
switch(buffer[0]) {
|
||||
case 'C':
|
||||
@@ -575,16 +719,18 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
case 'D':
|
||||
/* Directory */
|
||||
p = strchr(buffer, ' ');
|
||||
if(p==NULL)
|
||||
if (p == NULL) {
|
||||
goto error;
|
||||
}
|
||||
*p = '\0';
|
||||
p++;
|
||||
//mode = strdup(&buffer[1]);
|
||||
scp->request_mode = ssh_scp_integer_mode(&buffer[1]);
|
||||
tmp = p;
|
||||
p = strchr(p, ' ');
|
||||
if(p==NULL)
|
||||
if (p == NULL) {
|
||||
goto error;
|
||||
}
|
||||
*p = 0;
|
||||
size = strtoull(tmp, NULL, 10);
|
||||
p++;
|
||||
@@ -607,18 +753,21 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
ssh_channel_write(scp->channel, "", 1);
|
||||
return scp->request_type;
|
||||
case 0x1:
|
||||
ssh_set_error(scp->session,SSH_REQUEST_DENIED,"SCP: Warning: %s",&buffer[1]);
|
||||
ssh_set_error(scp->session, SSH_REQUEST_DENIED,
|
||||
"SCP: Warning: %s", &buffer[1]);
|
||||
scp->request_type = SSH_SCP_REQUEST_WARNING;
|
||||
SAFE_FREE(scp->warning);
|
||||
scp->warning = strdup(&buffer[1]);
|
||||
return scp->request_type;
|
||||
case 0x2:
|
||||
ssh_set_error(scp->session,SSH_FATAL,"SCP: Error: %s",&buffer[1]);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"SCP: Error: %s", &buffer[1]);
|
||||
return SSH_ERROR;
|
||||
case 'T':
|
||||
/* Timestamp */
|
||||
default:
|
||||
ssh_set_error(scp->session,SSH_FATAL,"Unhandled message: (%d)%s",buffer[0],buffer);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Unhandled message: (%d)%s", buffer[0], buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -626,7 +775,8 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
error:
|
||||
SAFE_FREE(name);
|
||||
SAFE_FREE(mode);
|
||||
ssh_set_error(scp->session,SSH_FATAL,"Parsing error while parsing message: %s",buffer);
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"Parsing error while parsing message: %s", buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
@@ -641,20 +791,27 @@ int ssh_scp_pull_request(ssh_scp scp){
|
||||
* @returns SSH_OK if the message was sent, SSH_ERROR if the sending
|
||||
* the message failed, or sending it in a bad state.
|
||||
*/
|
||||
int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
||||
char buffer[MAX_BUF_SIZE];
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
int ssh_scp_deny_request(ssh_scp scp, const char *reason)
|
||||
{
|
||||
char buffer[MAX_BUF_SIZE] = {0};
|
||||
int rc;
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_READ_REQUESTED) {
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_deny_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%c%s\n", 2, reason);
|
||||
err=ssh_channel_write(scp->channel,buffer,strlen(buffer));
|
||||
if(err==SSH_ERROR) {
|
||||
rc = ssh_channel_write(scp->channel, buffer, strlen(buffer));
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
else {
|
||||
scp->state = SSH_SCP_READ_INITED;
|
||||
return SSH_OK;
|
||||
@@ -670,23 +827,31 @@ int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
||||
* @returns SSH_OK if the message was sent, SSH_ERROR if sending the
|
||||
* message failed, or sending it in a bad state.
|
||||
*/
|
||||
int ssh_scp_accept_request(ssh_scp scp){
|
||||
int ssh_scp_accept_request(ssh_scp scp)
|
||||
{
|
||||
char buffer[] = {0x00};
|
||||
int err;
|
||||
if(scp==NULL)
|
||||
int rc;
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_READ_REQUESTED) {
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_deny_request called under invalid state");
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_deny_request called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
err=ssh_channel_write(scp->channel,buffer,1);
|
||||
if(err==SSH_ERROR) {
|
||||
|
||||
rc = ssh_channel_write(scp->channel, buffer, 1);
|
||||
if (rc == SSH_ERROR) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->request_type==SSH_SCP_REQUEST_NEWFILE)
|
||||
|
||||
if (scp->request_type == SSH_SCP_REQUEST_NEWFILE) {
|
||||
scp->state = SSH_SCP_READ_READING;
|
||||
else
|
||||
} else {
|
||||
scp->state = SSH_SCP_READ_INITED;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
@@ -700,31 +865,46 @@ int ssh_scp_accept_request(ssh_scp scp){
|
||||
* @returns The nNumber of bytes read, SSH_ERROR if an error occured
|
||||
* while reading.
|
||||
*/
|
||||
int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
|
||||
int r;
|
||||
int ssh_scp_read(ssh_scp scp, void *buffer, size_t size)
|
||||
{
|
||||
int rc;
|
||||
int code;
|
||||
if(scp==NULL)
|
||||
|
||||
if (scp == NULL) {
|
||||
return SSH_ERROR;
|
||||
if(scp->state == SSH_SCP_READ_REQUESTED && scp->request_type == SSH_SCP_REQUEST_NEWFILE){
|
||||
r=ssh_scp_accept_request(scp);
|
||||
if(r==SSH_ERROR)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (scp->state == SSH_SCP_READ_REQUESTED &&
|
||||
scp->request_type == SSH_SCP_REQUEST_NEWFILE)
|
||||
{
|
||||
rc = ssh_scp_accept_request(scp);
|
||||
if (rc == SSH_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (scp->state != SSH_SCP_READ_READING) {
|
||||
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_read called under invalid state");
|
||||
ssh_set_error(scp->session, SSH_FATAL,
|
||||
"ssh_scp_read called under invalid state");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
if(scp->processed + size > scp->filelen)
|
||||
|
||||
if (scp->processed + size > scp->filelen) {
|
||||
size = (size_t) (scp->filelen - scp->processed);
|
||||
if(size > 65536)
|
||||
}
|
||||
|
||||
if (size > 65536) {
|
||||
size = 65536; /* avoid too large reads */
|
||||
r=ssh_channel_read(scp->channel,buffer,size,0);
|
||||
if(r != SSH_ERROR)
|
||||
scp->processed += r;
|
||||
else {
|
||||
}
|
||||
|
||||
rc = ssh_channel_read(scp->channel, buffer, size, 0);
|
||||
if (rc != SSH_ERROR) {
|
||||
scp->processed += rc;
|
||||
} else {
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
/* Check if we arrived at end of file */
|
||||
if (scp->processed == scp->filelen) {
|
||||
scp->processed = scp->filelen = 0;
|
||||
@@ -732,7 +912,7 @@ int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
|
||||
code = ssh_scp_response(scp, NULL);
|
||||
if (code == 0) {
|
||||
scp->state = SSH_SCP_READ_INITED;
|
||||
return r;
|
||||
return rc;
|
||||
}
|
||||
if (code == 1) {
|
||||
scp->state = SSH_SCP_READ_INITED;
|
||||
@@ -741,7 +921,8 @@ int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
|
||||
scp->state = SSH_SCP_ERROR;
|
||||
return SSH_ERROR;
|
||||
}
|
||||
return r;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -751,9 +932,12 @@ int ssh_scp_read(ssh_scp scp, void *buffer, size_t size){
|
||||
* @returns The file name, NULL on error. The string should not be
|
||||
* freed.
|
||||
*/
|
||||
const char *ssh_scp_request_get_filename(ssh_scp scp){
|
||||
if(scp==NULL)
|
||||
const char *ssh_scp_request_get_filename(ssh_scp scp)
|
||||
{
|
||||
if (scp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return scp->request_name;
|
||||
}
|
||||
|
||||
@@ -763,9 +947,12 @@ const char *ssh_scp_request_get_filename(ssh_scp scp){
|
||||
*
|
||||
* @returns The UNIX permission, e.g 0644, -1 on error.
|
||||
*/
|
||||
int ssh_scp_request_get_permissions(ssh_scp scp){
|
||||
if(scp==NULL)
|
||||
int ssh_scp_request_get_permissions(ssh_scp scp)
|
||||
{
|
||||
if (scp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return scp->request_mode;
|
||||
}
|
||||
|
||||
@@ -776,9 +963,11 @@ int ssh_scp_request_get_permissions(ssh_scp scp){
|
||||
* be truncated.
|
||||
* @see ssh_scp_request_get_size64()
|
||||
*/
|
||||
size_t ssh_scp_request_get_size(ssh_scp scp){
|
||||
if(scp==NULL)
|
||||
size_t ssh_scp_request_get_size(ssh_scp scp)
|
||||
{
|
||||
if (scp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return (size_t)scp->filelen;
|
||||
}
|
||||
|
||||
@@ -786,9 +975,11 @@ size_t ssh_scp_request_get_size(ssh_scp scp){
|
||||
*
|
||||
* @returns The numeric size of the file being read.
|
||||
*/
|
||||
uint64_t ssh_scp_request_get_size64(ssh_scp scp){
|
||||
if(scp==NULL)
|
||||
uint64_t ssh_scp_request_get_size64(ssh_scp scp)
|
||||
{
|
||||
if (scp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return scp->filelen;
|
||||
}
|
||||
|
||||
@@ -799,7 +990,8 @@ uint64_t ssh_scp_request_get_size64(ssh_scp scp){
|
||||
*
|
||||
* @returns An integer value, e.g. 420 for "0644".
|
||||
*/
|
||||
int ssh_scp_integer_mode(const char *mode){
|
||||
int ssh_scp_integer_mode(const char *mode)
|
||||
{
|
||||
int value = strtoul(mode, NULL, 8) & 0xffff;
|
||||
return value;
|
||||
}
|
||||
@@ -812,8 +1004,9 @@ int ssh_scp_integer_mode(const char *mode){
|
||||
* @returns A pointer to a malloc'ed string containing the scp mode,
|
||||
* e.g. "0644".
|
||||
*/
|
||||
char *ssh_scp_string_mode(int mode){
|
||||
char buffer[16];
|
||||
char *ssh_scp_string_mode(int mode)
|
||||
{
|
||||
char buffer[16] = {0};
|
||||
snprintf(buffer, sizeof(buffer), "%.4o", mode);
|
||||
return strdup(buffer);
|
||||
}
|
||||
@@ -826,9 +1019,12 @@ char *ssh_scp_string_mode(int mode){
|
||||
* @returns A warning string, or NULL on error. The string should
|
||||
* not be freed.
|
||||
*/
|
||||
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
||||
if(scp==NULL)
|
||||
const char *ssh_scp_request_get_warning(ssh_scp scp)
|
||||
{
|
||||
if (scp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return scp->warning;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user