diff options
-rw-r--r-- | include/libssh/libssh.h | 9 | ||||
-rw-r--r-- | include/libssh/priv.h | 17 | ||||
-rw-r--r-- | libssh/scp.c | 109 |
3 files changed, 113 insertions, 22 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index 466fb5f..9707ba8 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -120,7 +120,6 @@ typedef struct ssh_agent_struct* ssh_agent; typedef struct ssh_session_struct* ssh_session; typedef struct ssh_kbdint_struct* ssh_kbdint; typedef struct ssh_scp_struct* ssh_scp; -typedef struct ssh_scp_request_struct* ssh_scp_request; /* Socket type */ #ifdef _WIN32 @@ -471,10 +470,11 @@ enum { enum ssh_scp_request_types { /** A new directory is going to be pulled */ - SSH_SCP_REQUEST_NEWDIR, + SSH_SCP_REQUEST_NEWDIR=1, /** A new file is going to be pulled */ SSH_SCP_REQUEST_NEWFILE }; + LIBSSH_API ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location); LIBSSH_API int ssh_scp_init(ssh_scp scp); LIBSSH_API int ssh_scp_close(ssh_scp scp); @@ -483,8 +483,9 @@ LIBSSH_API int ssh_scp_push_directory(ssh_scp scp, const char *dirname, const ch LIBSSH_API int ssh_scp_leave_directory(ssh_scp scp); LIBSSH_API int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, const char *perms); LIBSSH_API int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len); -LIBSSH_API ssh_scp_request ssh_scp_pull_request(ssh_scp scp); -LIBSSH_API int ssh_scp_deny_request(ssh_scp scp, ssh_scp_request request, const char *reason); +LIBSSH_API int ssh_scp_pull_request(ssh_scp scp); +LIBSSH_API int ssh_scp_deny_request(ssh_scp scp, const char *reason); +LIBSSH_API int ssh_scp_accept_request(ssh_scp scp); #ifdef __cplusplus } diff --git a/include/libssh/priv.h b/include/libssh/priv.h index 1cb3f64..83a004c 100644 --- a/include/libssh/priv.h +++ b/include/libssh/priv.h @@ -356,6 +356,7 @@ enum ssh_scp_states { SSH_SCP_WRITE_INITED, //Gave our intention to write SSH_SCP_WRITE_WRITING,//File was opened and currently writing SSH_SCP_READ_INITED, //Gave our intention to read + SSH_SCP_READ_REQUESTED, //We got a read request SSH_SCP_READ_READING, //File is opened and reading SSH_SCP_ERROR //Something bad happened }; @@ -368,16 +369,9 @@ struct ssh_scp_struct { enum ssh_scp_states state; size_t filelen; size_t processed; -}; - - -struct ssh_scp_request_struct { - ssh_scp scp; - enum ssh_scp_request_types type; - char *name; - char *mode; - size_t size; - int acked; + enum ssh_scp_request_types request_type; + char *request_name; + char *request_mode; }; struct ssh_message_struct; @@ -869,8 +863,7 @@ void message_handle(SSH_SESSION *session, uint32_t type); int ssh_execute_message_callbacks(SSH_SESSION *session); /* scp.c */ - -ssh_scp_request ssh_scp_request_new(void); +int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len); /* log.c */ diff --git a/libssh/scp.c b/libssh/scp.c index e4cb348..9cabe30 100644 --- a/libssh/scp.c +++ b/libssh/scp.c @@ -120,6 +120,8 @@ void ssh_scp_free(ssh_scp scp){ if(scp->channel) channel_free(scp->channel); SAFE_FREE(scp->location); + SAFE_FREE(scp->request_mode); + SAFE_FREE(scp->request_name); SAFE_FREE(scp); } @@ -267,11 +269,106 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){ return SSH_OK; } -ssh_scp_request ssh_scp_request_new(void){ - ssh_scp_request r=malloc(sizeof(struct ssh_scp_request_struct)); - if(r==NULL) - return NULL; - ZERO_STRUCTP(r); - return r; +/** + * @brief reads a string on a channel, terminated by '\n' + * @param buffer pointer to a buffer to place the string + * @param len size of the buffer in bytes. If the string is bigger + * than len-1, only len-1 bytes are read and the string + * is null-terminated. + * @returns SSH_OK The string was read + * @returns SSH_ERROR Error happened while reading + */ +int ssh_scp_read_string(ssh_scp scp, char *buffer, size_t len){ + size_t r=0; + int err=SSH_OK; + while(r<len-1){ + err=channel_read(scp->channel,&buffer[r],1,0); + if(err==SSH_ERROR){ + break; + } + if(err==0){ + ssh_set_error(scp->session,SSH_FATAL,"End of file while reading string"); + err=SSH_ERROR; + break; + } + r++; + if(buffer[r-1] == '\n') + break; + } + buffer[r]=0; + return err; } +/** @brief waits for a scp request (file, directory) + * @returns SSH_ERROR Some error happened + * @returns SSH_SCP_REQUEST_FILE The other side is sending a file + * @returns SSH_SCP_REQUEST_DIRECTORY The other side is sending a directory + * @returns SSH_SCP_REQUEST_END_DIRECTORY The other side has finished with the current directory + * @see ssh_scp_read + * @see ssh_scp_deny_request + * @see ssh_scp_accept_request + */ +int ssh_scp_pull_request(ssh_scp scp){ + char buffer[4096]; + char *mode=NULL; + char *p,*tmp; + size_t size; + char *name=NULL; + int err; + 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; + } + err=ssh_scp_read_string(scp,buffer,sizeof(buffer)); + if(err==SSH_ERROR) + return err; + switch(buffer[0]){ + case 'C': + /* File */ + case 'D': + /* Directory */ + p=strchr(buffer,' '); + if(p==NULL) + goto error; + *p='\0'; + p++; + mode=strdup(&buffer[1]); + tmp=p; + p=strchr(p,' '); + if(p==NULL) + goto error; + *p=0; + size=strtoull(tmp,NULL,10); + p++; + tmp=p; + p=strchr(p,'\n'); + if(p==NULL) + goto error; + *p=0; + name=strdup(tmp); + scp->request_mode=mode; + scp->request_name=name; + if(buffer[0]=='C'){ + scp->filelen=size; + scp->request_type=SSH_SCP_REQUEST_NEWFILE; + } else { + scp->filelen='0'; + scp->request_type=SSH_SCP_REQUEST_NEWDIR; + } + scp->state=SSH_SCP_READ_REQUESTED; + return scp->request_type; + break; + case 'T': + /* Timestamp */ + default: + ssh_set_error(scp->session,SSH_FATAL,"Unhandled message: %s",buffer); + return SSH_ERROR; + } + + /* a parsing error occured */ + error: + SAFE_FREE(name); + SAFE_FREE(mode); + ssh_set_error(scp->session,SSH_FATAL,"Parsing error while parsing message: %s",buffer); + return SSH_ERROR; +} |