diff options
Diffstat (limited to 'sftp_server/main.c')
-rw-r--r-- | sftp_server/main.c | 535 |
1 files changed, 0 insertions, 535 deletions
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; |