aboutsummaryrefslogtreecommitdiff
path: root/sftp_server
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2005-08-29 14:53:44 +0000
committerAris Adamantiadis <aris@0xbadc0de.be>2005-08-29 14:53:44 +0000
commitf31e7a3bec432be88aa4bb82c7f53baa32c6ac28 (patch)
tree0123e8e4cecf7f20a7cbe5ff06c94d35b3fd81c2 /sftp_server
parentbcb6bf25fa132421672d0782b9bfdb82fd2c6600 (diff)
downloadlibssh-f31e7a3bec432be88aa4bb82c7f53baa32c6ac28.tar.gz
libssh-f31e7a3bec432be88aa4bb82c7f53baa32c6ac28.tar.xz
libssh-f31e7a3bec432be88aa4bb82c7f53baa32c6ac28.zip
removed obsolete debugging info, split main.c in 3, and now mercurius links with a statical libssh
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@26 7dcaeef0-15fb-0310-b436-a5af3365683c
Diffstat (limited to 'sftp_server')
-rw-r--r--sftp_server/Makefile11
-rw-r--r--sftp_server/Makefile.in11
-rw-r--r--sftp_server/config.c10
-rw-r--r--sftp_server/main.c535
-rw-r--r--sftp_server/protocol.c377
-rw-r--r--sftp_server/server.h10
-rw-r--r--sftp_server/userauth.c213
7 files changed, 619 insertions, 548 deletions
diff --git a/sftp_server/Makefile b/sftp_server/Makefile
index 8c554177..c2b77a05 100644
--- a/sftp_server/Makefile
+++ b/sftp_server/Makefile
@@ -1,4 +1,5 @@
-OBJECTS= main.o config.o list.o libconfig/libconfig.a
+OBJECTS= main.o config.o list.o protocol.o userauth.o \
+ libconfig/libconfig.a ../libssh/libssh.a
SHELL = /bin/sh
@@ -14,8 +15,8 @@ libdir = $(prefix)/lib/
mandir = $(prefix)/man/man1
CC = gcc
-CFLAGS = -g -O2 -Wall -g -I../include/ -Ilibconfig/
-LDFLAGS = -L../libssh/ -lssh
+CFLAGS = -g -O2 -Wall -I../include/ -Ilibconfig/
+LDFLAGS =
LIBS = -lz -lcrypto -lpam -lcrypto
INSTALL = /usr/bin/install -c
DYLIB_EXTENSION = so
@@ -28,9 +29,11 @@ list.o: server.h
config.o: server.h
libconfig/libconfig.a: libconfig/config.h
make -C libconfig/
+../libssh/libssh.a:
+ make -C ../libssh/ libssh.a
libconfig/config.h:
cd libconfig ; ./configure ; cd ..
-sftp_server: $(OBJECTS) ../libssh/libssh.$(DYLIB_EXTENSION)
+sftp_server: $(OBJECTS)
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
install: all
diff --git a/sftp_server/Makefile.in b/sftp_server/Makefile.in
index 901f18a6..adf7f24e 100644
--- a/sftp_server/Makefile.in
+++ b/sftp_server/Makefile.in
@@ -1,4 +1,5 @@
-OBJECTS= main.o config.o list.o libconfig/libconfig.a
+OBJECTS= main.o config.o list.o protocol.o userauth.o \
+ libconfig/libconfig.a ../libssh/libssh.a
SHELL = /bin/sh
VPATH = @srcdir@
@@ -14,8 +15,8 @@ libdir = $(prefix)/lib/
mandir = $(prefix)/man/man1
CC = @CC@
-CFLAGS = @CFLAGS@ -Wall -g -I../include/ -Ilibconfig/
-LDFLAGS = -L../libssh/ -lssh
+CFLAGS = @CFLAGS@ -Wall -I../include/ -Ilibconfig/
+LDFLAGS =
LIBS = @LIBS@ -lpam -lcrypto
INSTALL = @INSTALL@
DYLIB_EXTENSION = @DYLIB_EXTENSION@
@@ -28,9 +29,11 @@ list.o: server.h
config.o: server.h
libconfig/libconfig.a: libconfig/config.h
make -C libconfig/
+../libssh/libssh.a:
+ make -C ../libssh/ libssh.a
libconfig/config.h:
cd libconfig ; ./configure ; cd ..
-sftp_server: $(OBJECTS) ../libssh/libssh.$(DYLIB_EXTENSION)
+sftp_server: $(OBJECTS)
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
install: all
diff --git a/sftp_server/config.c b/sftp_server/config.c
index 3dc2bc6f..f79e7390 100644
--- a/sftp_server/config.c
+++ b/sftp_server/config.c
@@ -42,7 +42,7 @@ char *current_group_name;
int add_user(char *user){
list *groups_from_user;
// list *the_user;
- printf("add_user(%s)\n",user);
+ //printf("add_user(%s)\n",user);
if(!list_find(current_group->users,user)){
current_group->users=list_add(current_group->users,user,strdup(user));
}
@@ -77,7 +77,7 @@ int add_group(char *group){
int group_callback(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra){
switch(flags){
case LC_FLAGS_SECTIONSTART:
- printf("new group %s\n",arguments);
+ //printf("new group %s\n",arguments);
if(current_group){
printf("can't include a section into a section\n");
return LC_CBRET_ERROR;
@@ -92,11 +92,11 @@ int group_callback(const char *shortvar, const char *var, const char *arguments,
current_group_name=strdup(arguments);
break;
case LC_FLAGS_SECTIONEND:
- printf("end of group\n\n");
+ //printf("end of group\n\n");
current_group=NULL;
break;
default:
- printf("%s - %s\n", shortvar, value);
+ //printf("%s - %s\n", shortvar, value);
if(!strcasecmp(shortvar,"user")){
char *ptr;
char *user=(char *)value;
@@ -291,7 +291,7 @@ int parse_config(char *file){
if(r<0)
printf("lc_process_file=%d,%s\n",r,lc_geterrstr());
lc_cleanup();
- list_config();
+ //list_config();
return 0;
}
diff --git a/sftp_server/main.c b/sftp_server/main.c
index 949b9979..91a5d7a4 100644
--- a/sftp_server/main.c
+++ b/sftp_server/main.c
@@ -25,544 +25,9 @@ MA 02111-1307, USA. */
#include <libssh/sftp.h>
#include <unistd.h>
#include <string.h>
-#include <limits.h>
-#include <dirent.h>
-#include <netdb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
#include <signal.h>
-#include <security/pam_appl.h>
-#include <pwd.h>
-
#include "server.h"
-#define SERVICE "sftp"
-
-#define TYPE_DIR 1
-#define TYPE_FILE 1
-struct sftp_handle {
- int type;
- int offset;
- char *name;
- int eof;
- DIR *dir;
- FILE *file;
-};
-
-char *user_password;
-int password_conv(int num_msg, const struct pam_message **msg,
- struct pam_response **resp, void *appdata)
-{
- int i=0;
- for(i=0;i<num_msg;++i){
- resp[i]=malloc(sizeof (struct pam_response));
- resp[i]->resp_retcode=0;
- switch(msg[i]->msg_style){
- case PAM_PROMPT_ECHO_ON:
- //printf("PAM: %s",msg[i]->msg);
- resp[i]->resp=strdup(user_password);
- break;
- case PAM_PROMPT_ECHO_OFF:
- //printf("PAM: %s",msg[i]->msg);
- resp[i]->resp=strdup(user_password);
- break;
- case PAM_ERROR_MSG:
- //printf("PAM_ERROR: %s",msg[i]->msg);
- break;
- case PAM_TEXT_INFO:
- //printf("PAM TEXT: %s",msg[i]->msg);
- break;
- default:
- break;
- }
- }
- return PAM_SUCCESS;
-}
-
-/* postauth_conf returns -1 on error, else 0 */
-int postauth_conf(char *user){
- /* first, find a chroot if any */
- char *root,*ptr;
- char *char_uid;
- char buffer[256];
- int uid;
- struct passwd *pw=getpwnam(user);
- root=user_chroot(user);
- if(root){
- if((ptr=strstr(root,"$HOME"))){
- if(!pw)
- return -1; // this user has no user directory
- *ptr=0;
- snprintf(buffer,sizeof(buffer),"%s%s/%s",
- root,pw->pw_dir,ptr+strlen("$HOME"));
- }
- else
- snprintf(buffer,sizeof(buffer),"%s",root);
- }
- /* we don't chroot right now because we still need getpwnam() */
- char_uid=user_uid(user);
- if(!char_uid){
- if(!pw)
- return -1; // user doesn't exist !
- char_uid=user;
- }
- uid=atoi(char_uid);
- if(uid==0 && char_uid[0]!=0){
- pw=getpwnam(char_uid);
- if(!pw)
- return -1;
- uid=pw->pw_uid;
- }
- if(root && chroot(buffer)){
- return -1; // cannot chroot
- }
- if(root){
- chdir("/");
- } else {
- if(pw)
- chdir(pw->pw_dir);
- else
- chdir("/");
- }
- if(setuid(uid)){
- return -1; // cannot setuid
- }
- return 0;
-}
-
-
-
-struct pam_conv pam_conv ={ password_conv, NULL };
-/* returns 1 if authenticated, 0 if failed,
- -1 if you must leave */
-int auth_password(char *user, char *password){
- pam_handle_t *pamh;
- int ret;
- static int tries=0;
- if(tries>3)
- return -1;
- tries++;
- user_password=password;
- ret=pam_start(SERVICE,user,&pam_conv,&pamh);
- if(ret==PAM_SUCCESS)
- ret=pam_authenticate(pamh,0);
- if(ret==PAM_SUCCESS)
- ret=pam_acct_mgmt(pamh,0);
- memset(password,0,strlen(password));
- if(ret==PAM_SUCCESS){
- pam_end(pamh,PAM_SUCCESS);
- if(postauth_conf(user))
- return -1;
- return 1;
- } else {
- pam_end(pamh,PAM_AUTH_ERR);
- return 0;
- }
-}
-
-int reply_status(SFTP_CLIENT_MESSAGE *msg){
- switch(errno){
- case EACCES:
- return sftp_reply_status(msg,SSH_FX_PERMISSION_DENIED,
- "permission denied");
- case ENOENT:
- return sftp_reply_status(msg,SSH_FX_NO_SUCH_FILE,
- "no such file or directory");
- case ENOTDIR:
- return sftp_reply_status(msg,SSH_FX_FAILURE,
- "not a directory");
- default:
- return sftp_reply_status(msg,SSH_FX_FAILURE,NULL);
- }
-}
-
-void handle_opendir(SFTP_CLIENT_MESSAGE *msg){
- DIR *dir=opendir(msg->filename);
- struct sftp_handle *hdl;
- STRING *handle;
- if(!dir){
- reply_status(msg);
- return;
- }
- hdl=malloc(sizeof(struct sftp_handle));
- memset(hdl,0,sizeof(struct sftp_handle));
- hdl->type=TYPE_DIR;
- hdl->offset=0;
- hdl->dir=dir;
- hdl->name=strdup(msg->filename);
- handle=sftp_handle_alloc(msg->sftp,hdl);
- sftp_reply_handle(msg,handle);
- free(handle);
-}
-
-SFTP_ATTRIBUTES *attr_from_stat(struct stat *statbuf){
- SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
- memset(attr,0,sizeof(*attr));
- attr->size=statbuf->st_size;
- attr->uid=statbuf->st_uid;
- attr->gid=statbuf->st_gid;
- attr->permissions=statbuf->st_mode;
- attr->atime=statbuf->st_atime;
- attr->mtime=statbuf->st_mtime;
- attr->flags=SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID
- | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME;
- return attr;
-}
-
-int handle_stat(SFTP_CLIENT_MESSAGE *msg,int follow){
- struct stat statbuf;
- SFTP_ATTRIBUTES *attr;
- int ret;
- if(follow)
- ret=stat(msg->filename,&statbuf);
- else
- ret=lstat(msg->filename,&statbuf);
- if(ret<0){
- reply_status(msg);
- return 0;
- }
- attr=attr_from_stat(&statbuf);
- sftp_reply_attr(msg, attr);
- sftp_attributes_free(attr);
- 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;
- if(!handle || handle->type!=TYPE_DIR){
- sftp_reply_status(msg,SSH_FX_BAD_MESSAGE,"invalid handle");
- return 0;
- }
- for(i=0; !handle->eof && i<50;++i){
- dir=readdir(handle->dir);
- if(!dir){
- handle->eof=1;
- break;
- }
- snprintf(file,sizeof(file),"%s/%s",handle->name,
- dir->d_name);
- if(lstat(file,&statbuf)){
- memset(&statbuf,0,sizeof(statbuf));
- }
- attr=attr_from_stat(&statbuf);
- 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 */
- if(i==0 && handle->eof){
- sftp_reply_status(msg,SSH_FX_EOF,NULL);
- return 0;
- }
- sftp_reply_names(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){
- sftp_reply_status(msg,SSH_FX_BAD_MESSAGE,"invalid handle");
- return 0;
- }
- sftp_handle_remove(msg->sftp,handle);
- if(handle->type==TYPE_DIR){
- closedir(handle->dir);
- } else {
- fclose(handle->file);
- }
- if(handle->name)
- free(handle->name);
- free(handle);
- sftp_reply_status(msg,SSH_FX_OK,NULL);
- 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];
- do {
- msg=sftp_get_client_message(sftp);
- if(!msg)
- break;
- switch(msg->type){
- case SFTP_REALPATH:
- ssh_say(1,"client realpath : %s\n",msg->filename);
- realpath(msg->filename,buffer);
- ssh_say(2,"responding %s\n",buffer);
- sftp_reply_name(msg, buffer, NULL);
- break;
- case SFTP_OPENDIR:
- ssh_say(1,"client opendir(%s)\n",msg->filename);
- handle_opendir(msg);
- break;
- case SFTP_LSTAT:
- case SFTP_STAT:
- ssh_say(1,"client stat(%s)\n",msg->filename);
- handle_stat(msg,msg->type==SFTP_STAT);
- break;
- case SFTP_READDIR:
- ssh_say(1,"client readdir\n");
- handle_readdir(msg);
- break;
- case SFTP_CLOSE:
- 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);
- if(!msg)
- return 1;
- return 0;
-}
-
-int do_auth(SSH_SESSION *session){
- SSH_MESSAGE *message;
- int auth=-1;
- do {
- message=ssh_message_get(session);
- if(!message)
- break;
- switch(ssh_message_type(message)){
- case SSH_AUTH_REQUEST:
- switch(ssh_message_subtype(message)){
- case SSH_AUTH_PASSWORD:
- ssh_say(1,"User %s wants to auth by password\n",
- ssh_message_auth_user(message));
- auth=auth_password(ssh_message_auth_user(message),
- ssh_message_auth_password(message));
- switch(auth){
- case 1:
- ssh_say(1,"Authentication success\n");
- ssh_message_auth_reply_success(message,0);
- break;
- case -1:
- ssh_say(1,"Too much tries\n");
- // too much auth tried
- ssh_disconnect(session);
- exit(1);
- case 0:
- ssh_say(1,"Auth refused\n");
- break;
- }
- if(auth==1){
- break;
- } else {
- ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
- ssh_message_reply_default(message);
- }
- break;
- // not authenticated, send default message
- case SSH_AUTH_NONE:
- if(user_nopassword(ssh_message_auth_user(message))){
- if(postauth_conf(ssh_message_auth_user(message))==0){
- ssh_message_auth_reply_success(message,0);
- auth=1;
- ssh_say(1,"Authentication success for %s(no password)\n",
- ssh_message_auth_user(message));
- break;
- } else {
- ssh_say(1,"Post-auth failed\n");
- ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
- ssh_message_reply_default(message);
- }
- } else {
- ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
- ssh_message_reply_default(message);
- }
- break;
- default:
- ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
- ssh_message_reply_default(message);
- break;
- }
- break;
- default:
- ssh_message_reply_default(message);
- }
- ssh_message_free(message);
- } while (auth!=1);
- return auth;
-}
CHANNEL *recv_channel(SSH_SESSION *session){
CHANNEL *chan=NULL;
diff --git a/sftp_server/protocol.c b/sftp_server/protocol.c
new file mode 100644
index 00000000..21c49941
--- /dev/null
+++ b/sftp_server/protocol.c
@@ -0,0 +1,377 @@
+/* protocol dependant part of Mercurius */
+/*
+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/server.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include "server.h"
+
+#define TYPE_DIR 1
+#define TYPE_FILE 1
+struct sftp_handle {
+ int type;
+ int offset;
+ char *name;
+ int eof;
+ DIR *dir;
+ FILE *file;
+};
+
+int reply_status(SFTP_CLIENT_MESSAGE *msg){
+ switch(errno){
+ case EACCES:
+ return sftp_reply_status(msg,SSH_FX_PERMISSION_DENIED,
+ "permission denied");
+ case ENOENT:
+ return sftp_reply_status(msg,SSH_FX_NO_SUCH_FILE,
+ "no such file or directory");
+ case ENOTDIR:
+ return sftp_reply_status(msg,SSH_FX_FAILURE,
+ "not a directory");
+ default:
+ return sftp_reply_status(msg,SSH_FX_FAILURE,NULL);
+ }
+}
+
+void handle_opendir(SFTP_CLIENT_MESSAGE *msg){
+ DIR *dir=opendir(msg->filename);
+ struct sftp_handle *hdl;
+ STRING *handle;
+ if(!dir){
+ reply_status(msg);
+ return;
+ }
+ hdl=malloc(sizeof(struct sftp_handle));
+ memset(hdl,0,sizeof(struct sftp_handle));
+ hdl->type=TYPE_DIR;
+ hdl->offset=0;
+ hdl->dir=dir;
+ hdl->name=strdup(msg->filename);
+ handle=sftp_handle_alloc(msg->sftp,hdl);
+ sftp_reply_handle(msg,handle);
+ free(handle);
+}
+
+SFTP_ATTRIBUTES *attr_from_stat(struct stat *statbuf){
+ SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
+ memset(attr,0,sizeof(*attr));
+ attr->size=statbuf->st_size;
+ attr->uid=statbuf->st_uid;
+ attr->gid=statbuf->st_gid;
+ attr->permissions=statbuf->st_mode;
+ attr->atime=statbuf->st_atime;
+ attr->mtime=statbuf->st_mtime;
+ attr->flags=SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID
+ | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME;
+ return attr;
+}
+
+int handle_stat(SFTP_CLIENT_MESSAGE *msg,int follow){
+ struct stat statbuf;
+ SFTP_ATTRIBUTES *attr;
+ int ret;
+ if(follow)
+ ret=stat(msg->filename,&statbuf);
+ else
+ ret=lstat(msg->filename,&statbuf);
+ if(ret<0){
+ reply_status(msg);
+ return 0;
+ }
+ attr=attr_from_stat(&statbuf);
+ sftp_reply_attr(msg, attr);
+ sftp_attributes_free(attr);
+ 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;
+ if(!handle || handle->type!=TYPE_DIR){
+ sftp_reply_status(msg,SSH_FX_BAD_MESSAGE,"invalid handle");
+ return 0;
+ }
+ for(i=0; !handle->eof && i<50;++i){
+ dir=readdir(handle->dir);
+ if(!dir){
+ handle->eof=1;
+ break;
+ }
+ snprintf(file,sizeof(file),"%s/%s",handle->name,
+ dir->d_name);
+ if(lstat(file,&statbuf)){
+ memset(&statbuf,0,sizeof(statbuf));
+ }
+ attr=attr_from_stat(&statbuf);
+ 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 */
+ if(i==0 && handle->eof){
+ sftp_reply_status(msg,SSH_FX_EOF,NULL);
+ return 0;
+ }
+ sftp_reply_names(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){
+ sftp_reply_status(msg,SSH_FX_BAD_MESSAGE,"invalid handle");
+ return 0;
+ }
+ sftp_handle_remove(msg->sftp,handle);
+ if(handle->type==TYPE_DIR){
+ closedir(handle->dir);
+ } else {
+ fclose(handle->file);
+ }
+ if(handle->name)
+ free(handle->name);
+ free(handle);
+ sftp_reply_status(msg,SSH_FX_OK,NULL);
+ 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];
+ do {
+ msg=sftp_get_client_message(sftp);
+ if(!msg)
+ break;
+ switch(msg->type){
+ case SFTP_REALPATH:
+ ssh_say(1,"client realpath : %s\n",msg->filename);
+ realpath(msg->filename,buffer);
+ ssh_say(2,"responding %s\n",buffer);
+ sftp_reply_name(msg, buffer, NULL);
+ break;
+ case SFTP_OPENDIR:
+ ssh_say(1,"client opendir(%s)\n",msg->filename);
+ handle_opendir(msg);
+ break;
+ case SFTP_LSTAT:
+ case SFTP_STAT:
+ ssh_say(1,"client stat(%s)\n",msg->filename);
+ handle_stat(msg,msg->type==SFTP_STAT);
+ break;
+ case SFTP_READDIR:
+ ssh_say(1,"client readdir\n");
+ handle_readdir(msg);
+ break;
+ case SFTP_CLOSE:
+ 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);
+ if(!msg)
+ return 1;
+ return 0;
+}
diff --git a/sftp_server/server.h b/sftp_server/server.h
index 1457e81f..460acbf3 100644
--- a/sftp_server/server.h
+++ b/sftp_server/server.h
@@ -1,3 +1,5 @@
+#include <libssh/libssh.h>
+#include <libssh/sftp.h>
/* server.h */
/* headers for the sftp server project */
int parse_config(char *file);
@@ -5,6 +7,14 @@ char *user_chroot(char *user);
char *user_uid(char *user);
int user_nopassword(char *user);
+/* userauth.c */
+int do_auth(SSH_SESSION *session);
+
+/* protocol.c */
+
+int sftploop(SSH_SESSION *session, SFTP_SESSION *sftp);
+
+/* list.c */
typedef struct list_struct {
struct list_struct *next;
char *key;
diff --git a/sftp_server/userauth.c b/sftp_server/userauth.c
new file mode 100644
index 00000000..37bdc04a
--- /dev/null
+++ b/sftp_server/userauth.c
@@ -0,0 +1,213 @@
+/* userauth.c */
+/* handle the authentication of the client */
+/*
+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/server.h>
+//#include <libssh/sftp.h>
+#include <security/pam_appl.h>
+#include <pwd.h>
+#include <string.h>
+#include "server.h"
+
+#define SERVICE "sftp"
+
+char *user_password;
+int password_conv(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata)
+{
+ int i=0;
+ for(i=0;i<num_msg;++i){
+ resp[i]=malloc(sizeof (struct pam_response));
+ resp[i]->resp_retcode=0;
+ switch(msg[i]->msg_style){
+ case PAM_PROMPT_ECHO_ON:
+ //printf("PAM: %s",msg[i]->msg);
+ resp[i]->resp=strdup(user_password);
+ break;
+ case PAM_PROMPT_ECHO_OFF:
+ //printf("PAM: %s",msg[i]->msg);
+ resp[i]->resp=strdup(user_password);
+ break;
+ case PAM_ERROR_MSG:
+ //printf("PAM_ERROR: %s",msg[i]->msg);
+ break;
+ case PAM_TEXT_INFO:
+ //printf("PAM TEXT: %s",msg[i]->msg);
+ break;
+ default:
+ break;
+ }
+ }
+ return PAM_SUCCESS;
+}
+
+/* postauth_conf returns -1 on error, else 0 */
+int postauth_conf(char *user){
+ /* first, find a chroot if any */
+ char *root,*ptr;
+ char *char_uid;
+ char buffer[256];
+ int uid;
+ struct passwd *pw=getpwnam(user);
+ root=user_chroot(user);
+ if(root){
+ if((ptr=strstr(root,"$HOME"))){
+ if(!pw)
+ return -1; // this user has no user directory
+ *ptr=0;
+ snprintf(buffer,sizeof(buffer),"%s%s/%s",
+ root,pw->pw_dir,ptr+strlen("$HOME"));
+ }
+ else
+ snprintf(buffer,sizeof(buffer),"%s",root);
+ }
+ /* we don't chroot right now because we still need getpwnam() */
+ char_uid=user_uid(user);
+ if(!char_uid){
+ if(!pw)
+ return -1; // user doesn't exist !
+ char_uid=user;
+ }
+ uid=atoi(char_uid);
+ if(uid==0 && char_uid[0]!=0){
+ pw=getpwnam(char_uid);
+ if(!pw)
+ return -1;
+ uid=pw->pw_uid;
+ }
+ if(root && chroot(buffer)){
+ return -1; // cannot chroot
+ }
+ if(root){
+ chdir("/");
+ } else {
+ if(pw)
+ chdir(pw->pw_dir);
+ else
+ chdir("/");
+ }
+ if(setuid(uid)){
+ return -1; // cannot setuid
+ }
+ return 0;
+}
+
+
+
+struct pam_conv pam_conv ={ password_conv, NULL };
+/* returns 1 if authenticated, 0 if failed,
+ -1 if you must leave */
+int auth_password(char *user, char *password){
+ pam_handle_t *pamh;
+ int ret;
+ static int tries=0;
+ if(tries>3)
+ return -1;
+ tries++;
+ user_password=password;
+ ret=pam_start(SERVICE,user,&pam_conv,&pamh);
+ if(ret==PAM_SUCCESS)
+ ret=pam_authenticate(pamh,0);
+ if(ret==PAM_SUCCESS)
+ ret=pam_acct_mgmt(pamh,0);
+ memset(password,0,strlen(password));
+ if(ret==PAM_SUCCESS){
+ pam_end(pamh,PAM_SUCCESS);
+ if(postauth_conf(user))
+ return -1;
+ return 1;
+ } else {
+ pam_end(pamh,PAM_AUTH_ERR);
+ return 0;
+ }
+}
+
+
+
+int do_auth(SSH_SESSION *session){
+ SSH_MESSAGE *message;
+ int auth=-1;
+ do {
+ message=ssh_message_get(session);
+ if(!message)
+ break;
+ switch(ssh_message_type(message)){
+ case SSH_AUTH_REQUEST:
+ switch(ssh_message_subtype(message)){
+ case SSH_AUTH_PASSWORD:
+ ssh_say(1,"User %s wants to auth by password\n",
+ ssh_message_auth_user(message));
+ auth=auth_password(ssh_message_auth_user(message),
+ ssh_message_auth_password(message));
+ switch(auth){
+ case 1:
+ ssh_say(1,"Authentication success\n");
+ ssh_message_auth_reply_success(message,0);
+ break;
+ case -1:
+ ssh_say(1,"Too much tries\n");
+ // too much auth tried
+ ssh_disconnect(session);
+ exit(1);
+ case 0:
+ ssh_say(1,"Auth refused\n");
+ break;
+ }
+ if(auth==1){
+ break;
+ } else {
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ break;
+ // not authenticated, send default message
+ case SSH_AUTH_NONE:
+ if(user_nopassword(ssh_message_auth_user(message))){
+ if(postauth_conf(ssh_message_auth_user(message))==0){
+ ssh_message_auth_reply_success(message,0);
+ auth=1;
+ ssh_say(1,"Authentication success for %s(no password)\n",
+ ssh_message_auth_user(message));
+ break;
+ } else {
+ ssh_say(1,"Post-auth failed\n");
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ } else {
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ }
+ break;
+ default:
+ ssh_message_auth_set_methods(message,SSH_AUTH_PASSWORD);
+ ssh_message_reply_default(message);
+ break;
+ }
+ break;
+ default:
+ ssh_message_reply_default(message);
+ }
+ ssh_message_free(message);
+ } while (auth!=1);
+ return auth;
+}