aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/sftp.h3
-rw-r--r--libssh/sftp.c4
-rw-r--r--libssh/sftpserver.c22
-rw-r--r--sftp_server/main.c188
4 files changed, 208 insertions, 9 deletions
diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h
index d4ac388e..e017b974 100644
--- a/include/libssh/sftp.h
+++ b/include/libssh/sftp.h
@@ -168,7 +168,7 @@ 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);
-
+SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname);
/* sftpserver.c */
SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp);
@@ -182,6 +182,7 @@ 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);
+int sftp_reply_data(SFTP_CLIENT_MESSAGE *msg, void *data, int len);
void sftp_handle_remove(SFTP_SESSION *sftp, void *handle);
/* SFTP commands and constants */
diff --git a/libssh/sftp.c b/libssh/sftp.c
index 0d08b3c0..3c7e7410 100644
--- a/libssh/sftp.c
+++ b/libssh/sftp.c
@@ -244,7 +244,7 @@ int sftp_init(SFTP_SESSION *sftp){
if(ext_data_s)
free(ext_data_s);
sftp_packet_free(packet);
- sftp->server_version=version;
+ sftp->version=sftp->server_version=version;
return 0;
}
@@ -643,7 +643,7 @@ void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){
SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){
- switch(session->server_version){
+ switch(session->version){
case 4:
return sftp_parse_attr_4(session,buf,expectname);
case 3:
diff --git a/libssh/sftpserver.c b/libssh/sftpserver.c
index fd759a12..bfbbc400 100644
--- a/libssh/sftpserver.c
+++ b/libssh/sftpserver.c
@@ -76,11 +76,11 @@ SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp){
tmp=buffer_get_ssh_string(payload);
msg->filename=string_to_char(tmp);
free(tmp);
-#warning attributes
+ msg->attr=sftp_parse_attr(sftp, payload,0);
break;
case SSH_FXP_FSETSTAT:
msg->handle=buffer_get_ssh_string(payload);
-#warning attributes
+ msg->attr=sftp_parse_attr(sftp, payload,0);
break;
case SSH_FXP_LSTAT:
case SSH_FXP_STAT:
@@ -90,6 +90,12 @@ SFTP_CLIENT_MESSAGE *sftp_get_client_message(SFTP_SESSION *sftp){
if(sftp->version >3)
buffer_get_u32(payload,&msg->flags);
break;
+ case SSH_FXP_OPEN:
+ tmp=buffer_get_ssh_string(payload);
+ msg->filename=string_to_char(tmp);
+ free(tmp);
+ buffer_get_u32(payload,&msg->flags);
+ msg->attr=sftp_parse_attr(sftp, payload,0);
case SSH_FXP_FSTAT:
msg->handle=buffer_get_ssh_string(payload);
buffer_get_u32(payload,&msg->flags);
@@ -198,6 +204,17 @@ int sftp_reply_status(SFTP_CLIENT_MESSAGE *msg, u32 status, char *message){
return r<0;
}
+int sftp_reply_data(SFTP_CLIENT_MESSAGE *msg, void *data, int len){
+ BUFFER *out=buffer_new();
+ int r;
+ buffer_add_u32(out,msg->id);
+ buffer_add_u32(out,ntohl(len));
+ buffer_add_data(out,data,len);
+ r=sftp_packet_write(msg->sftp,SSH_FXP_DATA,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
@@ -233,6 +250,7 @@ void *sftp_handle(SFTP_SESSION *sftp, STRING *handle){
return NULL;
return sftp->handles[val];
}
+
void sftp_handle_remove(SFTP_SESSION *sftp, void *handle){
int i;
for(i=0;i<SFTP_HANDLES;++i){
diff --git a/sftp_server/main.c b/sftp_server/main.c
index b829080e..19e7b864 100644
--- a/sftp_server/main.c
+++ b/sftp_server/main.c
@@ -31,6 +31,8 @@ MA 02111-1307, USA. */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
#define TYPE_DIR 1
#define TYPE_FILE 1
@@ -100,10 +102,15 @@ SFTP_ATTRIBUTES *attr_from_stat(struct stat *statbuf){
return attr;
}
-int handle_lstat(SFTP_CLIENT_MESSAGE *msg){
+int handle_stat(SFTP_CLIENT_MESSAGE *msg,int follow){
struct stat statbuf;
SFTP_ATTRIBUTES *attr;
- if(lstat(msg->filename,&statbuf)){
+ int ret;
+ if(follow)
+ ret=stat(msg->filename,&statbuf);
+ else
+ ret=lstat(msg->filename,&statbuf);
+ if(ret<0){
reply_status(msg);
return 0;
}
@@ -113,10 +120,80 @@ int handle_lstat(SFTP_CLIENT_MESSAGE *msg){
return 0;
}
+char *long_name(char *file, struct stat *statbuf){
+ static char buf[256];
+ char buf2[100];
+ int mode=statbuf->st_mode;
+ char *time,*ptr;
+ strcpy(buf,"");
+ switch(mode & S_IFMT){
+ case S_IFDIR:
+ strcat(buf,"d");
+ break;
+ default:
+ strcat(buf,"-");
+ break;
+ }
+ /* user */
+ if(mode & 0400)
+ strcat(buf,"r");
+ else
+ strcat(buf,"-");
+ if(mode & 0200)
+ strcat(buf,"w");
+ else
+ strcat(buf,"-");
+ if(mode & 0100){
+ if(mode & S_ISUID)
+ strcat(buf,"s");
+ else
+ strcat(buf,"x");
+ } else
+ strcat(buf,"-");
+ /*group*/
+ if(mode & 040)
+ strcat(buf,"r");
+ else
+ strcat(buf,"-");
+ if(mode & 020)
+ strcat(buf,"w");
+ else
+ strcat(buf,"-");
+ if(mode & 010)
+ strcat(buf,"x");
+ else
+ strcat(buf,"-");
+ /* other */
+ if(mode & 04)
+ strcat(buf,"r");
+ else
+ strcat(buf,"-");
+ if(mode & 02)
+ strcat(buf,"w");
+ else
+ strcat(buf,"-");
+ if(mode & 01)
+ strcat(buf,"x");
+ else
+ strcat(buf,"-");
+ strcat(buf," ");
+ snprintf(buf2,sizeof(buf2),"%3d %d %d %d",(int)statbuf->st_nlink,
+ (int)statbuf->st_uid,(int)statbuf->st_gid,(int)statbuf->st_size);
+ strcat(buf,buf2);
+ time=ctime(&statbuf->st_mtime)+4;
+ if((ptr=strchr(time,'\n')))
+ *ptr=0;
+ snprintf(buf2,sizeof(buf2)," %s %s",time,file);
+ // +4 to remove the "WED "
+ strcat(buf,buf2);
+ return buf;
+}
+
int handle_readdir(SFTP_CLIENT_MESSAGE *msg){
struct sftp_handle *handle=sftp_handle(msg->sftp,msg->handle);
SFTP_ATTRIBUTES *attr;
struct dirent *dir;
+ char *longname;
struct stat statbuf;
char file[1024];
int i;
@@ -136,7 +213,8 @@ int handle_readdir(SFTP_CLIENT_MESSAGE *msg){
memset(&statbuf,0,sizeof(statbuf));
}
attr=attr_from_stat(&statbuf);
- sftp_reply_names_add(msg,dir->d_name,file,attr);
+ longname=long_name(dir->d_name,&statbuf);
+ sftp_reply_names_add(msg,dir->d_name,longname,attr);
sftp_attributes_free(attr);
}
/* if there was at least one file, don't send the eof yet */
@@ -148,6 +226,36 @@ int handle_readdir(SFTP_CLIENT_MESSAGE *msg){
return 0;
}
+int handle_read(SFTP_CLIENT_MESSAGE *msg){
+ struct sftp_handle *handle=sftp_handle(msg->sftp,msg->handle);
+ u32 len=msg->len;
+ void *data;
+ int r;
+ if(!handle || handle->type!=TYPE_FILE){
+ sftp_reply_status(msg,SSH_FX_BAD_MESSAGE,"invalid handle");
+ return 0;
+ }
+ if(len>(2<<15)){
+ /* 32000 */
+ len=2<<15;
+ }
+ data=malloc(len);
+ fseeko(handle->file,msg->offset,SEEK_SET);
+ r=fread(data,1,len,handle->file);
+ ssh_say(2,"read %d bytes\n",r);
+ if(r<=0 && (len>0)){
+ if(feof(handle->file)){
+ sftp_reply_status(msg,SSH_FX_EOF,"End of file");
+ } else {
+ reply_status(msg);
+ }
+ return 0;
+ }
+ sftp_reply_data(msg,data,r);
+ free(data);
+ return 0;
+}
+
int handle_close(SFTP_CLIENT_MESSAGE *msg){
struct sftp_handle *handle=sftp_handle(msg->sftp,msg->handle);
if(!handle){
@@ -167,6 +275,66 @@ int handle_close(SFTP_CLIENT_MESSAGE *msg){
return 0;
}
+int handle_open(SFTP_CLIENT_MESSAGE *msg){
+ int flags=0;
+ int fd;
+ FILE *file;
+ char *mode="r";
+ struct sftp_handle *hdl;
+ STRING *handle;
+ if(msg->flags & SSH_FXF_READ)
+ flags |= O_RDONLY;
+ if(msg->flags & SSH_FXF_WRITE)
+ flags |= O_WRONLY;
+ if(msg->flags & SSH_FXF_APPEND)
+ flags |= O_APPEND;
+ if(msg->flags & SSH_FXF_TRUNC)
+ flags |= O_TRUNC;
+ if(msg->flags & SSH_FXF_EXCL)
+ flags |= O_EXCL;
+ if(msg->flags & SSH_FXF_CREAT)
+ flags |= O_CREAT;
+ fd=open(msg->filename,flags,msg->attr->permissions);
+ if(fd<0){
+ reply_status(msg);
+ return 0;
+ }
+ switch(flags& (O_RDONLY | O_WRONLY | O_APPEND | O_TRUNC)){
+ case O_RDONLY:
+ mode="r";
+ break;
+ case (O_WRONLY|O_RDONLY):
+ mode="r+";
+ break;
+ case (O_WRONLY|O_TRUNC):
+ mode="w";
+ break;
+ case (O_WRONLY | O_RDONLY | O_APPEND):
+ mode="a+";
+ break;
+ default:
+ switch(flags & (O_RDONLY | O_WRONLY)){
+ case O_RDONLY:
+ mode="r";
+ break;
+ case O_WRONLY:
+ mode="w";
+ break;
+ }
+ }
+ file=fdopen(fd,mode);
+ hdl=malloc(sizeof(struct sftp_handle));
+ memset(hdl,0,sizeof(struct sftp_handle));
+ hdl->type=TYPE_FILE;
+ hdl->offset=0;
+ hdl->file=file;
+ hdl->name=strdup(msg->filename);
+ handle=sftp_handle_alloc(msg->sftp,hdl);
+ sftp_reply_handle(msg,handle);
+ free(handle);
+ return 0;
+}
+
int sftploop(SSH_SESSION *session, SFTP_SESSION *sftp){
SFTP_CLIENT_MESSAGE *msg;
char buffer[PATH_MAX];
@@ -186,8 +354,9 @@ int sftploop(SSH_SESSION *session, SFTP_SESSION *sftp){
handle_opendir(msg);
break;
case SFTP_LSTAT:
+ case SFTP_STAT:
ssh_say(1,"client stat(%s)\n",msg->filename);
- handle_lstat(msg);
+ handle_stat(msg,msg->type==SFTP_STAT);
break;
case SFTP_READDIR:
ssh_say(1,"client readdir\n");
@@ -197,6 +366,17 @@ int sftploop(SSH_SESSION *session, SFTP_SESSION *sftp){
ssh_say(1,"client close\n");
handle_close(msg);
break;
+ case SFTP_OPEN:
+ ssh_say(1,"client open(%s)\n",msg->filename);
+ handle_open(msg);
+ break;
+ case SFTP_READ:
+ ssh_say(1,"client read(off=%ld,len=%d)\n",msg->offset,msg->len);
+ handle_read(msg);
+ break;
+ default:
+ ssh_say(1,"Unknown message %d\n",msg->type);
+ sftp_reply_status(msg,SSH_FX_OP_UNSUPPORTED,"Unsupported message");
}
sftp_client_message_free(msg);
} while (1);