mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-11-30 13:01:23 +03:00
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
This commit is contained in:
@@ -186,7 +186,7 @@ int server_set_kex(SSH_SESSION * session) {
|
|||||||
if (!(wanted = options->wanted_methods[i]))
|
if (!(wanted = options->wanted_methods[i]))
|
||||||
wanted = supported_methods[i];
|
wanted = supported_methods[i];
|
||||||
server->methods[i] = strdup(wanted);
|
server->methods[i] = strdup(wanted);
|
||||||
printf("server->methods[%d]=%s\n",i,wanted);
|
//printf("server->methods[%d]=%s\n",i,wanted);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
SHELL = /bin/sh
|
||||||
|
|
||||||
|
|
||||||
@@ -14,8 +15,8 @@ libdir = $(prefix)/lib/
|
|||||||
mandir = $(prefix)/man/man1
|
mandir = $(prefix)/man/man1
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -g -O2 -Wall -g -I../include/ -Ilibconfig/
|
CFLAGS = -g -O2 -Wall -I../include/ -Ilibconfig/
|
||||||
LDFLAGS = -L../libssh/ -lssh
|
LDFLAGS =
|
||||||
LIBS = -lz -lcrypto -lpam -lcrypto
|
LIBS = -lz -lcrypto -lpam -lcrypto
|
||||||
INSTALL = /usr/bin/install -c
|
INSTALL = /usr/bin/install -c
|
||||||
DYLIB_EXTENSION = so
|
DYLIB_EXTENSION = so
|
||||||
@@ -28,9 +29,11 @@ list.o: server.h
|
|||||||
config.o: server.h
|
config.o: server.h
|
||||||
libconfig/libconfig.a: libconfig/config.h
|
libconfig/libconfig.a: libconfig/config.h
|
||||||
make -C libconfig/
|
make -C libconfig/
|
||||||
|
../libssh/libssh.a:
|
||||||
|
make -C ../libssh/ libssh.a
|
||||||
libconfig/config.h:
|
libconfig/config.h:
|
||||||
cd libconfig ; ./configure ; cd ..
|
cd libconfig ; ./configure ; cd ..
|
||||||
sftp_server: $(OBJECTS) ../libssh/libssh.$(DYLIB_EXTENSION)
|
sftp_server: $(OBJECTS)
|
||||||
|
|
||||||
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
|
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -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
|
SHELL = /bin/sh
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
@@ -14,8 +15,8 @@ libdir = $(prefix)/lib/
|
|||||||
mandir = $(prefix)/man/man1
|
mandir = $(prefix)/man/man1
|
||||||
|
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = @CFLAGS@ -Wall -g -I../include/ -Ilibconfig/
|
CFLAGS = @CFLAGS@ -Wall -I../include/ -Ilibconfig/
|
||||||
LDFLAGS = -L../libssh/ -lssh
|
LDFLAGS =
|
||||||
LIBS = @LIBS@ -lpam -lcrypto
|
LIBS = @LIBS@ -lpam -lcrypto
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
DYLIB_EXTENSION = @DYLIB_EXTENSION@
|
DYLIB_EXTENSION = @DYLIB_EXTENSION@
|
||||||
@@ -28,9 +29,11 @@ list.o: server.h
|
|||||||
config.o: server.h
|
config.o: server.h
|
||||||
libconfig/libconfig.a: libconfig/config.h
|
libconfig/libconfig.a: libconfig/config.h
|
||||||
make -C libconfig/
|
make -C libconfig/
|
||||||
|
../libssh/libssh.a:
|
||||||
|
make -C ../libssh/ libssh.a
|
||||||
libconfig/config.h:
|
libconfig/config.h:
|
||||||
cd libconfig ; ./configure ; cd ..
|
cd libconfig ; ./configure ; cd ..
|
||||||
sftp_server: $(OBJECTS) ../libssh/libssh.$(DYLIB_EXTENSION)
|
sftp_server: $(OBJECTS)
|
||||||
|
|
||||||
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
|
$(CC) -o sftp_server $(OBJECTS) $(LIBS) $(LDFLAGS)
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ char *current_group_name;
|
|||||||
int add_user(char *user){
|
int add_user(char *user){
|
||||||
list *groups_from_user;
|
list *groups_from_user;
|
||||||
// list *the_user;
|
// list *the_user;
|
||||||
printf("add_user(%s)\n",user);
|
//printf("add_user(%s)\n",user);
|
||||||
if(!list_find(current_group->users,user)){
|
if(!list_find(current_group->users,user)){
|
||||||
current_group->users=list_add(current_group->users,user,strdup(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){
|
int group_callback(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra){
|
||||||
switch(flags){
|
switch(flags){
|
||||||
case LC_FLAGS_SECTIONSTART:
|
case LC_FLAGS_SECTIONSTART:
|
||||||
printf("new group %s\n",arguments);
|
//printf("new group %s\n",arguments);
|
||||||
if(current_group){
|
if(current_group){
|
||||||
printf("can't include a section into a section\n");
|
printf("can't include a section into a section\n");
|
||||||
return LC_CBRET_ERROR;
|
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);
|
current_group_name=strdup(arguments);
|
||||||
break;
|
break;
|
||||||
case LC_FLAGS_SECTIONEND:
|
case LC_FLAGS_SECTIONEND:
|
||||||
printf("end of group\n\n");
|
//printf("end of group\n\n");
|
||||||
current_group=NULL;
|
current_group=NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("%s - %s\n", shortvar, value);
|
//printf("%s - %s\n", shortvar, value);
|
||||||
if(!strcasecmp(shortvar,"user")){
|
if(!strcasecmp(shortvar,"user")){
|
||||||
char *ptr;
|
char *ptr;
|
||||||
char *user=(char *)value;
|
char *user=(char *)value;
|
||||||
@@ -291,7 +291,7 @@ int parse_config(char *file){
|
|||||||
if(r<0)
|
if(r<0)
|
||||||
printf("lc_process_file=%d,%s\n",r,lc_geterrstr());
|
printf("lc_process_file=%d,%s\n",r,lc_geterrstr());
|
||||||
lc_cleanup();
|
lc_cleanup();
|
||||||
list_config();
|
//list_config();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,544 +25,9 @@ MA 02111-1307, USA. */
|
|||||||
#include <libssh/sftp.h>
|
#include <libssh/sftp.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.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 <signal.h>
|
||||||
#include <security/pam_appl.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
#include "server.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 *recv_channel(SSH_SESSION *session){
|
||||||
CHANNEL *chan=NULL;
|
CHANNEL *chan=NULL;
|
||||||
|
|||||||
377
sftp_server/protocol.c
Normal file
377
sftp_server/protocol.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/sftp.h>
|
||||||
/* server.h */
|
/* server.h */
|
||||||
/* headers for the sftp server project */
|
/* headers for the sftp server project */
|
||||||
int parse_config(char *file);
|
int parse_config(char *file);
|
||||||
@@ -5,6 +7,14 @@ char *user_chroot(char *user);
|
|||||||
char *user_uid(char *user);
|
char *user_uid(char *user);
|
||||||
int user_nopassword(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 {
|
typedef struct list_struct {
|
||||||
struct list_struct *next;
|
struct list_struct *next;
|
||||||
char *key;
|
char *key;
|
||||||
|
|||||||
213
sftp_server/userauth.c
Normal file
213
sftp_server/userauth.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user