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 --- include/libssh/sftp.h | 61 ++++++++++++- libssh/messages.c | 2 +- libssh/sftp.c | 9 +- libssh/sftpserver.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 310 insertions(+), 6 deletions(-) create mode 100644 libssh/sftpserver.c diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h index 428737f9..d4ac388e 100644 --- a/include/libssh/sftp.h +++ b/include/libssh/sftp.h @@ -31,8 +31,10 @@ typedef struct sftp_session_struct { CHANNEL *channel; int server_version; int client_version; + int version; struct request_queue *queue; u32 id_counter; + void **handles; } SFTP_SESSION ; typedef struct { @@ -67,6 +69,22 @@ typedef struct { u32 id; } SFTP_MESSAGE; +/* this is a bunch of all data that could be into a message */ +typedef struct sftp_client_message{ + SFTP_SESSION *sftp; + u8 type; + u32 id; + char *filename; /* can be "path" */ + u32 flags; + struct sftp_attributes *attr; + STRING *handle; + u64 offset; + u32 len; + int attr_num; + BUFFER *attrbuf; /* used by sftp_reply_attrs */ + STRING *data; /* can be newpath of rename() */ +} SFTP_CLIENT_MESSAGE; + typedef struct request_queue{ struct request_queue *next; SFTP_MESSAGE *message; @@ -83,7 +101,7 @@ typedef struct { } STATUS_MESSAGE; /* don't worry much of these aren't really used */ -typedef struct { +typedef struct sftp_attributes{ char *name; char *longname; /* some weird stuff */ u32 flags; @@ -144,6 +162,27 @@ SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan); int sftp_server_init(SFTP_SESSION *sftp); #endif +/* this is not a public interface */ +#define SFTP_HANDLES 256 +SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp); +int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload); +void sftp_packet_free(SFTP_PACKET *packet); +void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr); + +/* sftpserver.c */ + +SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp); +void sftp_client_message_free(SFTP_CLIENT_MESSAGE *msg); +int sftp_reply_name(SFTP_CLIENT_MESSAGE *msg, char *name, SFTP_ATTRIBUTES *attr); +int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle); +STRING *sftp_handle_alloc(SFTP_SESSION *sftp, void *info); +int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr); +void *sftp_handle(SFTP_SESSION *sftp, STRING *handle); +int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status, char *message); +int sftp_reply_names_add(SFTP_CLIENT_MESSAGE *msg, char *file, char *longname, + SFTP_ATTRIBUTES *attr); +int sftp_reply_names(SFTP_CLIENT_MESSAGE *msg); +void sftp_handle_remove(SFTP_SESSION *sftp, void *handle); /* SFTP commands and constants */ #define SSH_FXP_INIT 1 @@ -225,6 +264,26 @@ int sftp_server_init(SFTP_SESSION *sftp); #define SSH_FXF_EXCL 0x20 #define SSH_FXF_TEXT 0x40 +#define SFTP_OPEN SSH_FXP_OPEN +#define SFTP_CLOSE SSH_FXP_CLOSE +#define SFTP_READ SSH_FXP_READ +#define SFTP_WRITE SSH_FXP_WRITE +#define SFTP_LSTAT SSH_FXP_LSTAT +#define SFTP_FSTAT SSH_FXP_FSTAT +#define SFTP_SETSTAT SSH_FXP_SETSTAT +#define SFTP_FSETSTAT SSH_FXP_FSETSTAT +#define SFTP_OPENDIR SSH_FXP_OPENDIR +#define SFTP_READDIR SSH_FXP_READDIR +#define SFTP_REMOVE SSH_FXP_REMOVE +#define SFTP_MKDIR SSH_FXP_MKDIR +#define SFTP_RMDIR SSH_FXP_RMDIR +#define SFTP_REALPATH SSH_FXP_REALPATH +#define SFTP_STAT SSH_FXP_STAT +#define SFTP_RENAME SSH_FXP_RENAME +#define SFTP_READLINK SSH_FXP_READLINK +#define SFTP_SYMLINK SSH_FXP_SYMLINK + + #ifdef __cplusplus } ; #endif 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