From f31e7a3bec432be88aa4bb82c7f53baa32c6ac28 Mon Sep 17 00:00:00 2001 From: Aris Adamantiadis Date: Mon, 29 Aug 2005 14:53:44 +0000 Subject: 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 --- sftp_server/Makefile | 11 +- sftp_server/Makefile.in | 11 +- sftp_server/config.c | 10 +- sftp_server/main.c | 535 ------------------------------------------------ sftp_server/protocol.c | 377 ++++++++++++++++++++++++++++++++++ sftp_server/server.h | 10 + sftp_server/userauth.c | 213 +++++++++++++++++++ 7 files changed, 619 insertions(+), 548 deletions(-) create mode 100644 sftp_server/protocol.c create mode 100644 sftp_server/userauth.c (limited to 'sftp_server') 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 #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include - #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;iresp_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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#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 +#include /* 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 +#include +//#include +#include +#include +#include +#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;iresp_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; +} -- cgit v1.2.3