From e2bdc2f66c85d4d1a38b2511cb98da105cafcc24 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Fri, 26 Aug 2005 00:25:01 +0000 Subject: sftp server implementation :) at this time, basic support of opendir, readdir, lstat, etc. just enough to "sftp" in and type ls. git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@16 7dcaeef0-15fb-0310-b436-a5af3365683c --- libssh/messages.c | 2 +- libssh/sftp.c | 9 +- libssh/sftpserver.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 libssh/sftpserver.c (limited to 'libssh') diff --git a/libssh/messages.c b/libssh/messages.c index 46dec52d..6523f1c7 100644 --- a/libssh/messages.c +++ b/libssh/messages.c @@ -282,7 +282,7 @@ int ssh_message_channel_request_reply_success(SSH_MESSAGE *msg){ u32 channel; if(msg->channel_request.want_reply){ channel=msg->channel_request.channel->remote_channel; - ssh_say(2,"Sending a default channel_success denied to channel %d\n",channel); + ssh_say(2,"Sending a channel_request success to channel %d\n",channel); packet_clear_out(msg->session); buffer_add_u8(msg->session->out_buffer,SSH2_MSG_CHANNEL_SUCCESS); buffer_add_u32(msg->session->out_buffer,htonl(channel)); diff --git a/libssh/sftp.c b/libssh/sftp.c index a78a4b08..0d08b3c0 100644 --- a/libssh/sftp.c +++ b/libssh/sftp.c @@ -39,11 +39,8 @@ MA 02111-1307, USA. */ /* functions */ -static void sftp_packet_free(SFTP_PACKET *packet); void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg); static void sftp_message_free(SFTP_MESSAGE *msg); -SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp); -int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload); SFTP_SESSION *sftp_new(SSH_SESSION *session){ SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION)); @@ -97,6 +94,10 @@ int sftp_server_init(SFTP_SESSION *sftp){ } buffer_free(reply); ssh_say(2,"server version sent\n"); + if(version > LIBSFTP_VERSION) + sftp->version=LIBSFTP_VERSION; + else + sftp->version=version; return 0; } #endif @@ -204,7 +205,7 @@ int sftp_read_and_dispatch(SFTP_SESSION *session){ return 0; } -static void sftp_packet_free(SFTP_PACKET *packet){ +void sftp_packet_free(SFTP_PACKET *packet){ if(packet->payload) buffer_free(packet->payload); free(packet); diff --git a/libssh/sftpserver.c b/libssh/sftpserver.c new file mode 100644 index 00000000..fd759a12 --- /dev/null +++ b/libssh/sftpserver.c @@ -0,0 +1,244 @@ +/* sftpserver.c contains server based function for the sftp protocol */ +/* +Copyright 2005 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. */ +#include "libssh/libssh.h" +#include "libssh/sftp.h" +#include "libssh/ssh2.h" +#include "libssh/priv.h" +#include +#include +#include +#include + +SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp){ + SFTP_PACKET *packet=sftp_packet_read(sftp); + SFTP_CLIENT_MESSAGE *msg=malloc(sizeof (SFTP_CLIENT_MESSAGE)); + BUFFER *payload; + STRING *tmp; + memset(msg,0,sizeof(SFTP_CLIENT_MESSAGE)); + if(!packet) + return NULL; + payload=packet->payload; + ssh_say(2,"received sftp packet type %d\n",packet->type); + msg->type=packet->type; + msg->sftp=sftp; + buffer_get_u32(payload,&msg->id); + switch(msg->type){ + case SSH_FXP_CLOSE: + case SSH_FXP_READDIR: + msg->handle=buffer_get_ssh_string(payload); + break; + case SSH_FXP_READ: + msg->handle=buffer_get_ssh_string(payload); + buffer_get_u64(payload,&msg->offset); + buffer_get_u32(payload,&msg->len); + break; + case SSH_FXP_WRITE: + msg->handle=buffer_get_ssh_string(payload); + buffer_get_u64(payload,&msg->offset); + msg->data=buffer_get_ssh_string(payload); + break; + case SSH_FXP_REMOVE: + case SSH_FXP_RMDIR: + case SSH_FXP_OPENDIR: + case SSH_FXP_READLINK: + case SSH_FXP_REALPATH: + tmp=buffer_get_ssh_string(payload); + msg->filename=string_to_char(tmp); + free(tmp); + break; + case SSH_FXP_RENAME: + case SSH_FXP_SYMLINK: + tmp=buffer_get_ssh_string(payload); + msg->filename=string_to_char(tmp); + free(tmp); + msg->data=buffer_get_ssh_string(payload); + break; + case SSH_FXP_MKDIR: + case SSH_FXP_SETSTAT: + tmp=buffer_get_ssh_string(payload); + msg->filename=string_to_char(tmp); + free(tmp); +#warning attributes + break; + case SSH_FXP_FSETSTAT: + msg->handle=buffer_get_ssh_string(payload); +#warning attributes + break; + case SSH_FXP_LSTAT: + case SSH_FXP_STAT: + tmp=buffer_get_ssh_string(payload); + msg->filename=string_to_char(tmp); + free(tmp); + if(sftp->version >3) + buffer_get_u32(payload,&msg->flags); + break; + case SSH_FXP_FSTAT: + msg->handle=buffer_get_ssh_string(payload); + buffer_get_u32(payload,&msg->flags); + break; + default: + printf("Received handled sftp message %d\n",msg->type); + } + msg->flags=ntohl(msg->flags); + msg->offset=ntohll(msg->offset); + msg->len=ntohl(msg->len); + sftp_packet_free(packet); + return msg; +} + +void sftp_client_message_free(SFTP_CLIENT_MESSAGE *msg){ + if(msg->filename) + free(msg->filename); + if(msg->data) + free(msg->data); + if(msg->attr) + sftp_attributes_free(msg->attr); + if(msg->handle) + free(msg->handle); + memset(msg,'X',sizeof(*msg)); + free(msg); +} + +int sftp_reply_name(SFTP_CLIENT_MESSAGE *msg, char *name, SFTP_ATTRIBUTES *attr){ + BUFFER *out=buffer_new(); + STRING *file=string_from_char(name); + int r; + buffer_add_u32(out,msg->id); + buffer_add_u32(out,htonl(1)); + buffer_add_ssh_string(out,file); + buffer_add_ssh_string(out,file); /* the protocol is broken here between 3 & 4 */ + free(file); + buffer_add_attributes(out,attr); + r=sftp_packet_write(msg->sftp,SSH_FXP_NAME,out); + buffer_free(out); + return r<0; +} + +int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle){ + BUFFER *out=buffer_new(); + int r; + buffer_add_u32(out,msg->id); + buffer_add_ssh_string(out,handle); + r=sftp_packet_write(msg->sftp,SSH_FXP_HANDLE,out); + buffer_free(out); + return r<0; +} + +int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr){ + BUFFER *out=buffer_new(); + int r; + buffer_add_u32(out,msg->id); + buffer_add_attributes(out,attr); + r=sftp_packet_write(msg->sftp,SSH_FXP_ATTRS,out); + buffer_free(out); + return r<0; +} + +int sftp_reply_names_add(SFTP_CLIENT_MESSAGE *msg, char *file, char *longname, + SFTP_ATTRIBUTES *attr){ + STRING *name=string_from_char(file); + if(!msg->attrbuf) + msg->attrbuf=buffer_new(); + buffer_add_ssh_string(msg->attrbuf,name); + free(name); + name=string_from_char(longname); + buffer_add_ssh_string(msg->attrbuf,name); + free(name); + buffer_add_attributes(msg->attrbuf,attr); + msg->attr_num++; + return 0; +} + +int sftp_reply_names(SFTP_CLIENT_MESSAGE *msg){ + BUFFER *out=buffer_new(); + int r; + buffer_add_u32(out,msg->id); + buffer_add_u32(out,htonl(msg->attr_num)); + buffer_add_data(out,buffer_get(msg->attrbuf), + buffer_get_len(msg->attrbuf)); + r=sftp_packet_write(msg->sftp,SSH_FXP_NAME,out); + buffer_free(out); + buffer_free(msg->attrbuf); + msg->attr_num=0; + msg->attrbuf=NULL; + return r<0; +} + + +int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status, char *message){ + BUFFER *out=buffer_new(); + int r; + STRING *s; + buffer_add_u32(out,msg->id); + buffer_add_u32(out,htonl(status)); + s=string_from_char(message?message:""); + buffer_add_ssh_string(out,s); + free(s); + buffer_add_u32(out,0); // language string + r=sftp_packet_write(msg->sftp,SSH_FXP_STATUS,out); + buffer_free(out); + return r<0; +} + +/* this function will return you a new handle to give the client. + * the function accepts an info that can be retrieved later with + * the handle. Care is given that a corrupted handle won't give a + * valid info (or worse). */ +STRING *sftp_handle_alloc(SFTP_SESSION *sftp, void *info){ + int i; + u32 val; + STRING *ret; + if(!sftp->handles){ + sftp->handles=malloc(sizeof(void *) * SFTP_HANDLES); + memset(sftp->handles,0,sizeof(void *)*SFTP_HANDLES); + } + for(i=0; ihandles[i]) + break; + if(i==SFTP_HANDLES) + return NULL; // no handle available + val=i; + ret=string_new(4); + memcpy(ret->string,&val,sizeof(u32)); + sftp->handles[i]=info; + return ret; +} + +void *sftp_handle(SFTP_SESSION *sftp, STRING *handle){ + u32 val; + if(!sftp->handles) + return NULL; + if(string_len(handle)!=sizeof(val)) + return NULL; + memcpy(&val,handle->string,sizeof(u32)); + if(val>SFTP_HANDLES) + return NULL; + return sftp->handles[val]; +} +void sftp_handle_remove(SFTP_SESSION *sftp, void *handle){ + int i; + for(i=0;ihandles[i]==handle){ + sftp->handles[i]=NULL; + break; + } + } +} -- cgit v1.2.3