/* * FTP/HTTP daemon * fhttpd.cc Copyright (C) 1995, 96 Alex Belits * * This source/code is public free; you can distribute it and/or modify * it under terms of the GNU General Public License (published by the * Free Software Foundation) either version two of this License, or any * later version. * */ #include #include #ifdef NEED_SELECT_H #include #endif #include #ifndef NO_MMAP #include #endif #ifdef NEED_CRYPT_H #include #endif #ifdef USE_GETSPNAM #include #endif #include "fhttpd.h" #include "process.h" #include "log.h" #ifdef GETOPT_VARS_NOT_DEFINED extern char *optarg; extern int optind, opterr; #endif #ifdef AIX4 extern "C" int initgroups(const char *user, gid_t group); #endif #ifdef SOLARIS extern "C"{ void bzero(void *s, size_t n); int gethostname(char *name, int namelen); } #endif #include "wildmat.h" #include "sockobj.h" #include "lists.h" #include "configargs.h" extern char translateddir[MAXPATHLEN+1]; extern int reloadpasswdflag; char*commands[NCOMMANDS]={ "USER","PASS","ACCT","REIN","QUIT","PORT","PASV","TYPE","STRU","MODE","RETR","STOR","APPE", "MLFL","MAIL","MSND","MSOM","MSAM","MRSQ","MRCP","ALLO","REST","RNFR","RNTO","ABOR","DELE","CWD", "XCWD","LIST","NLST","SITE","STAT","HELP","NOOP","MKD","XMKD","RMD","XRMD","PWD","XPWD","CDUP", "XCUP","STOU","SYST","GET","POST","HEAD","PUT","CLIK","GET_CLIK","GET_HTTP/1.0","XGTH","XGET","XPST","XHED"}; char *commands4[NCOMMANDS]={ "USER","PASS","ACCT","REIN","QUIT","PORT","PASV","TYPE","STRU","MODE","RETR","STOR","APPE", "MLFL","MAIL","MSND","MSOM","MSAM","MRSQ","MRCP","ALLO","REST","RNFR","RNTO","ABOR","DELE","CWD ", "XCWD","LIST","NLST","SITE","STAT","HELP","NOOP","MKD ","XMKD","RMD ","XRMD","PWD ","XPWD","CDUP", "XCUP","STOU","SYST","GET ","POST","HEAD","PUT ","CLIK","GCLK","GETH","XGTH","XGET","XPST","XHED"}; char *processcommands[NPROCESSCOMMANDS]={"USER","PASS","APPLICATION","LOGAPPLICATION","QUIT"}; char *processcommands4[NPROCESSCOMMANDS]={"USER","PASS","APPL","LAPP","QUIT"}; time_t global_time=0; struct hostsstruct hosts[256]; int nhosts=0; int phosts=0; struct passwd *globalhttppw=NULL; char *diroverride=NULL,*original_rootdir=NULL; int max_content_length=MAX_CONTENT_LENGTH; int max_message_size=MAX_MESSAGE_SIZE; int max_totalsize=MAX_TOTALSIZE; int max_totallogmessagessize=MAX_TOTALMESSAGESIZE; int fhttpd_nconnections=0; int fhttpd_npipes=0; AddressRoot::AddressRoot(__s32 xaddress,char *xhostname,char *xrootdir){ address=xaddress; rootdir=NULL; if(xrootdir) rootdir=(char*)malloc(strlen(xrootdir)+1); if(rootdir) strcpy(rootdir,xrootdir); if(xhostname) hostname=(char*)malloc(strlen(xhostname)+1); if(hostname) strcpy(hostname,xhostname); } AddressRoot::~AddressRoot(void){ if(rootdir) free(rootdir); if(hostname) free(hostname); } ModeArgs::ModeArgs(int argc,char **args,int xmode,int abs):ConfigArgs(argc,args,abs){ mode=xmode; } DataFTPServer::DataFTPServer(char *xname,int xport,__s32 xlocaladdr):ServerSocket(xname,xport,-1,xlocaladdr){ } void ControlFTPServerApp::initanonymous(void){ struct sockaddr_in currsock; sockaddr_size_type currsockaddrlen=sizeof(currsock); auth=1; lastruleapplied1=0; lastruleapplied2=0; lastruleapplied3=0; gid=globalhttppw->pw_gid; userid=globalhttppw->pw_uid; type='I'; strcpy(cwd,"/"); strncpy(basedir,globalhttppw->pw_dir,256); basedir[255]=0; strncpy(username,globalhttppw->pw_name,128); username[128]=0; if(!getsockname(connection->gethandle(),(sockaddr*)&currsock,(socklen_t*)&currsockaddrlen)){ AddressRoot *curraddrroot=(AddressRoot*)addressroots.start; while(curraddrroot){ if((*((__s32*)&currsock.sin_addr))==curraddrroot->address){ if(curraddrroot->rootdir){ strncpy(basedir,curraddrroot->rootdir,256); basedir[255]=0; } if(curraddrroot->hostname){ strncpy(localhostname,curraddrroot->hostname,256); localhostname[255]=0; } curraddrroot=NULL; } if(curraddrroot) curraddrroot=(AddressRoot*)curraddrroot->next; } } } void ControlFTPServerApp::cleanexecenv(void){ int i; for(i=0;igetaddress())->sin_addr.s_addr){ strncpy(resolvedname,hosts[i].hostname,255); resolvedname[254]=0; i=nhosts; } } char tmpstr[11]; tmpstr[0]=0; struct sockaddr_in currsock; sockaddr_size_type currsockaddrlen=sizeof(currsock); if(c->socket){ sprintf(tmpstr,"%d",c->socket->port); LogMessage(this,NULL,NULL,NULL,0,"LOCAL_PORT",tmpstr); if(!getsockname(c->gethandle(),(sockaddr*)&currsock,(socklen_t*)&currsockaddrlen)){ LogMessage(this,NULL,NULL,NULL,0,"LOCAL_IP",inet_ntoa(currsock.sin_addr)); } LogMessage(this,NULL,NULL,NULL,0,"IP",inet_ntoa(((sockaddr_in*)c->getaddress())->sin_addr)); } if(resolvedname[0]) LogMessage(this,NULL,NULL,NULL,0,"HOSTNAME",resolvedname); } ControlFTPServerApp::~ControlFTPServerApp(void){ int i; CtrlAppPtrApplicationRequest *currptr; currptr=(CtrlAppPtrApplicationRequest *)requestptrs.start; while(currptr){ if(currptr->request){ if(currptr->request->ctrlapp==this&&!currptr->request->instance){ LogMessage(this,currptr->request,NULL,NULL,0,"DROPPED","Client disconnected, request was not passed to any server"); //cancelled request wasn't passed to the application instance -- //deleted quietly delete currptr->request; //delete non-queued to instances requests }else{ LogMessage(this,currptr->request,NULL,NULL,0,"DROPPED","Client disconnected, request was passed to some server"); delete currptr; //delete a pointer to request, cause request to lose ctrlapplication } }else delete currptr; //delete a pointer to request currptr=(CtrlAppPtrApplicationRequest *)requestptrs.start; } for(i=0;iapp){ if(servertype==ftp_server_port){ if(t-((ControlFTPServerApp*)client->app)->timestamp>=FTPTIMEOUT){ ((ControlFTPServerApp*)client->app)->timestamp=global_time; if(getexitafterresponse(client)){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"TIMEOUT2","FTP client timed out twice"); emptyresponse(client); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"TIMEOUT","FTP client timed out"); response(client,"421 Timeout (%d seconds): closing control connection.",FTPTIMEOUT); } setexitafterresponse(client,1); } }else{ if(t-((ControlFTPServerApp*)client->app)->timestamp>=HTTPTIMEOUT){ ((ControlFTPServerApp*)client->app)->timestamp=global_time; currptr=(CtrlAppPtrApplicationRequest *)(((ControlFTPServerApp*)client->app)->requestptrs).start; while(currptr&&!waiting){ if(currptr->request){ if(currptr->request->ctrlapp==(ControlFTPServerApp*)client->app&&currptr->request->instance){ waiting=1; } } currptr=(CtrlAppPtrApplicationRequest *)currptr->next; } if(waiting){ //HTTP application is running, not dropping the connection }else{ if(getexitafterresponse(client)){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"TIMEOUT2","HTTP client timed out twice"); emptyresponse(client); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"TIMEOUT","HTTP client timed out"); } setexitafterresponse(client,1); } } } } } void ControlFTPServer::connectfn(ServerConnection *client){ int a=32768; char tmphostname[256]; struct sockaddr_in currsock; sockaddr_size_type currsockaddrlen=sizeof(currsock); client->app=new ControlFTPServerApp(client); setsockopt(client->gethandle(),SOL_SOCKET,SO_RCVBUF,(char*)&a,sizeof(int)); setsockopt(client->gethandle(),SOL_SOCKET,SO_SNDBUF,(char*)&a,sizeof(int)); a=1; setsockopt(client->gethandle(),IPPROTO_TCP,TCP_NODELAY,(char*)&a,sizeof(int)); if(servertype==ftp_server_port){ strncpy(tmphostname,hostname,256); tmphostname[255]=0; if(!getsockname(client->gethandle(),(sockaddr*)&currsock,(socklen_t*)&currsockaddrlen)){ AddressRoot *curraddrroot=(AddressRoot*)addressroots.start; while(curraddrroot){ if((*((__s32*)&currsock.sin_addr))==curraddrroot->address){ if(curraddrroot->hostname){ strncpy(tmphostname,curraddrroot->hostname,256); tmphostname[255]=0; } curraddrroot=NULL; } if(curraddrroot) curraddrroot=(AddressRoot*)curraddrroot->next; } } if(wheel->fdarraysize-fhttpd_nconnections-fhttpd_npipes >=MIN_CONNECTIONS_LEFT){ response(client,"220 %s FTP server ready.",tmphostname); }else{ setexitafterresponse(client,1); } }else{ if(wheel->fdarraysize-fhttpd_nconnections-fhttpd_npipes app)->auth!=1){ swrite(client->gethandle(),"530 Authorization internal error.\r\n"); return -1; } if(setgid(((ControlFTPServerApp*)client->app)->gid)){ swrite(client->gethandle(),"530 Group authhorization internal error.\r\n"); return -1; } initgroups(((ControlFTPServerApp*)client->app)->username,((ControlFTPServerApp*)client->app)->gid); if(setuid(((ControlFTPServerApp*)client->app)->userid)){ swrite(client->gethandle(),"530 User authhorization internal error.\r\n"); return -1; } if(translatechdir(client,((ControlFTPServerApp*)client->app)->cwd)){ swrite(client->gethandle(),"550 Current directory unavailable.\r\n"); return -1; } return 0; } char *ControlFTPServer::translatename(ServerConnection *client,char *translatedname,char *srcname,int *map_uid){ char resolvedname[MAXPATHLEN+1],tmpstr[MAXNAMLEN+1],*p0,*p,*p1; int j,srclen,resolvedlen,baselen; int fatal=0,ignorebase=0; struct passwd *pwd; if(map_uid) *map_uid=-1; p0=srcname; srclen=strlen(srcname); if(srcname[0]=='/'){ if(map_username&&servertype==http_server_port&&srcname[1]=='~'){ p0=strchr(srcname+2,'/'); if(!p0) p0=srcname+srclen; if(p0-srcname>MAXNAMLEN){ translatedname[0]=0; return translatedname; } memcpy(tmpstr,srcname+2,p0-srcname-2); tmpstr[p0-srcname-2]=0; if(*tmpstr){ pwd=getpwnam(tmpstr); }else{ pwd=getpwuid(((ControlFTPServerApp*)client->app)->userid); } if(pwd&&pwd->pw_uid>0){ strncpy(resolvedname,pwd->pw_dir,MAXPATHLEN+1); if(map_uid) *map_uid=pwd->pw_uid; resolvedname[MAXPATHLEN]=0; j=strlen(resolvedname); if(j){ if(resolvedname[j-1]!='/'){ if(jMAXNAMLEN){ translatedname[0]=0; return translatedname; } memcpy(tmpstr,srcname+1,p0-srcname-1); tmpstr[p0-srcname-1]=0; if(*tmpstr){ pwd=getpwnam(tmpstr); }else{ pwd=getpwuid(((ControlFTPServerApp*)client->app)->userid); } if(pwd){ j=strlen(((ControlFTPServerApp*)client->app)->basedir); if((int)strlen(pwd->pw_dir)>=j){ if(!memcmp(pwd->pw_dir,((ControlFTPServerApp*)client->app)->basedir,j)){ if(j){ if(((ControlFTPServerApp*)client->app)->basedir[j-1]=='/') j--; } strncpy(resolvedname,pwd->pw_dir+j,MAXPATHLEN+1); resolvedname[MAXPATHLEN]=0; j=strlen(resolvedname); if(j){ j--; if(resolvedname[j]=='/') resolvedname[j]=0; } }else{ resolvedname[0]=0; fatal=1; } }else{ resolvedname[0]=0; fatal=1; } }else{ resolvedname[0]=0; fatal=1; } if(*p0) p0++; }else{ strncpy(resolvedname,((ControlFTPServerApp*)client->app)->cwd,MAXPATHLEN+1); resolvedname[MAXPATHLEN]=0; } } if(resolvedname[0]=='/'&&resolvedname[1]==0) resolvedname[0]=0; resolvedlen=strlen(resolvedname); do{ p=strchr(p0,'/'); if(!p) p=srcname+srclen; if(p-p0>MAXNAMLEN){ translatedname[0]=0; return translatedname; } memcpy(tmpstr,p0,p-p0); tmpstr[p-p0]=0; if(*tmpstr){ if(strcmp(tmpstr,".")){ if(!strcmp(tmpstr,"..")){ p1=strrchr(resolvedname,'/'); if(p1&&(!ignorebase||resolvedlen>baselen)){ *p1=0; resolvedlen=p1-resolvedname; } }else{ if(MAXPATHLEN>resolvedlen+1){ resolvedname[resolvedlen]='/'; strncpy(resolvedname+resolvedlen+1,tmpstr,MAXPATHLEN-resolvedlen-1); } resolvedname[MAXPATHLEN]=0; resolvedlen=strlen(resolvedname); } } } p0=p+1; }while(*p); if(!(*resolvedname)){ resolvedname[0]='/'; resolvedname[1]=0; } if(ignorebase){ /* must do something clever here -- it shouldn't allow to go above home, so it must be checked */ j=0; }else{ strncpy(translatedname,((ControlFTPServerApp*)client->app)->basedir, MAXPATHLEN); translatedname[MAXPATHLEN-1]=0; j=strlen(translatedname); } if(j){ if(translatedname[j-1]=='/') j--; } if(MAXPATHLEN-j>0){ strncpy(translatedname+j,resolvedname,MAXPATHLEN-j); } translatedname[MAXPATHLEN-1]=0; if(fatal){ translatedname[0]=0; } return translatedname; } int ControlFTPServer::isrestricted(ServerConnection *client,List *rightslist,char *string){ AccessRights *currrights,*nextrights; char translateddir[MAXPATHLEN+1]; int result=0; if(!string) return 1; translatename(client,translateddir,string); if(!(*translateddir)) return 1; if(rightslist){ if(rightslist->start){ currrights=(AccessRights*)(rightslist->start); while(currrights){ nextrights=(AccessRights*)(currrights->next); if(currrights->pattern){ if(wildmat(translateddir,currrights->pattern)){ if(currrights->realm){ result=1; }else{ result=strcasecmp(currrights->user,"allow"); } } } currrights=nextrights; } } }else result=1; return result; } int ControlFTPServer::checkrights(ServerConnection *client,List *rightslist, char *string,char *user,char *password,char *realm,int realmlen){ AccessRights *currrights,*nextrights; char translateddir[MAXPATHLEN+1]; int checkresult,result=1; *realm=0; if(!string||!user||!password){ return 0; } translatename(client,translateddir,string); if(!(*translateddir)){ return 0; } if(rightslist){ if(rightslist->start){ currrights=(AccessRights*)(rightslist->start); while(currrights){ nextrights=(AccessRights*)(currrights->next); if(currrights->pattern){ if(wildmat(translateddir,currrights->pattern)){ if(currrights->realm){ strncpy(realm,currrights->realm->realmname,realmlen); realm[realmlen-1]=0; if(currrights->user){ if(!strcmp(currrights->user,user)||!strcmp(currrights->user,":all:")){ checkresult=currrights->realm->CheckPassword(user,password); if(checkresult!=-1) result=checkresult; } }else result=0; }else{ *realm=0; result=!strcasecmp(currrights->user,"allow"); } } } currrights=nextrights; } } }else result=0; if(result) *realm=0; return result; } ConfigArgs *ControlFTPServer::findwildargs(ServerConnection *client,List *list,char *string){ ConfigArgs *currargs,*nextargs; char translateddir[MAXPATHLEN+1],translateddir1[MAXPATHLEN+1]; translatename(client,translateddir,string); if(!(*translateddir)) return NULL; if(list){ if(list->start){ currargs=(ConfigArgs*)(list->start); while(currargs){ nextargs=(ConfigArgs*)(currargs->next); if(currargs->params){ if(currargs->params[0]){ if(currargs->absolute){ if(wildmat(translateddir,currargs->params[0])){ return currargs; } }else{ translatename(client,translateddir1,currargs->params[0]); if(translateddir1){ if(wildmat(translateddir,translateddir1)){ return currargs; } } } } } currargs=nextargs; } } } return NULL; } ConfigArgs *ControlFTPServer::findwildargsreal(ServerConnection *client,List *list,char *string){ char translateddir[MAXPATHLEN+1]; translatename(client,translateddir,string); if(!(*translateddir)) return NULL; if(list){ return (ConfigArgs*)list->FindWildMatch(translateddir); } return NULL; } char translateddir[MAXPATHLEN+1]=""; int ControlFTPServer::translatechdir(ServerConnection *client,char *path){ translatename(client,translateddir,path); if(!(*translateddir)) return -1; return chdir(translateddir); } char *ControlFTPServer::translategetcwd(ServerConnection *client,char *buf,size_t size){ char *i; int j; if(!*translateddir){ i=getcwd(translateddir,MAXPATHLEN+1); }else i=translateddir; if(i){ j=strlen(((ControlFTPServerApp*)client->app)->basedir); if(j){ if(((ControlFTPServerApp*)client->app)->basedir[j-1]=='/') j--; } if(j>=0&&j<=(int)strlen(translateddir)){ if(strlen(translateddir+j)app,NULL,NULL,NULL,0,"DIRECTORY",dirbuffer); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FILEMASK",filemask); if(dirp){ translatename(client,translatedbuf,dirbuffer); if(translatedbuf[strlen(translatedbuf)-1]!='/') strcat(translatedbuf,"/"); translatedbuflen=strlen(translatedbuf); write(process->writehandle,"NLST",4); *syncexpected=1; tt=global_time; nentries=0; beginlist=NULL; chainitem=(char*)(&beginlist); while((mydirent=readdir(dirp))){ if(strcmp(mydirent->d_name,".")||i==LIST){ if(strcmp(mydirent->d_name,"..")||i==LIST){ if(wildmat(mydirent->d_name,filemask) ||filemask[0]=='*'&&filemask[1]==0 &&(!strcmp(mydirent->d_name,".")||!strcmp(mydirent->d_name,".."))){ strcpy(dirbuffer+dirbufferlen,mydirent->d_name); strcpy(translatedbuf+translatedbuflen,mydirent->d_name); if(!stat(translatedbuf,&statbuf)){ if(i==NLST){ if(!S_ISDIR(statbuf.st_mode)){ strncpy(buffer,mydirent->d_name,MAXNAMLEN+1); buffer[MAXNAMLEN+1]=0; namebegin=0; nameend=strlen(buffer); strcat(buffer,"\r\n"); tmpentry=(char*)malloc(strlen(buffer)+dirbufferlen+1+sizeof(char*)+2*sizeof(int)); if(tmpentry){ if(dirbufferlen==2&&dirbuffer[0]=='.'){ strcpy(tmpentry+sizeof(char*)+2*sizeof(int),buffer); }else{ memcpy(tmpentry+sizeof(char*)+2*sizeof(int),dirbuffer,dirbufferlen); strcpy(tmpentry+sizeof(char*)+2*sizeof(int)+dirbufferlen,buffer); } if(chainitem){ *(char**)chainitem=tmpentry; *(char**)(tmpentry)=NULL; *(int*)(tmpentry+sizeof(char*))=namebegin; *(int*)(tmpentry+sizeof(char*)+sizeof(int))=nameend; chainitem=tmpentry; nentries++; } } } }else{ totalsize+=statbuf.st_size; groupstr=getgrgid(statbuf.st_gid); userstr=getpwuid(statbuf.st_uid); strcpy(filetime,ctime(&(statbuf.st_mtime))); filetime[16]=0; if((long)tt>(long)statbuf.st_mtime+15552000l){ filetime[11]=' '; memcpy(filetime+12,filetime+20,4); } if(!groupstr) sprintf(ownergroup,"%d",statbuf.st_gid); else strncpy(ownergroup,groupstr->gr_name,9); ownergroup[8]=0; if(!userstr) sprintf(owneruser,"%d",statbuf.st_uid); else strncpy(owneruser,userstr->pw_name,9); owneruser[8]=0; sprintf(dirdisplaybuffer,"---------- %4d %-8s %-7s %8lu %12s %s", (int)statbuf.st_nlink,owneruser,ownergroup,(unsigned long)statbuf.st_size,filetime+4,mydirent->d_name); namebegin=55; nameend=strlen(dirdisplaybuffer); if(S_ISDIR(statbuf.st_mode)){ dirdisplaybuffer[0]='d'; #ifdef ADD_SLASHED_IN_FTP_LIST strcat(dirdisplaybuffer,"\r/\n"); nameend++; }else #else } #endif strcat(dirdisplaybuffer,"\r\n"); if(statbuf.st_mode&S_IXUSR) dirdisplaybuffer[3]='x'; if(statbuf.st_mode&S_IXGRP) dirdisplaybuffer[6]='x'; if(statbuf.st_mode&S_IXOTH) dirdisplaybuffer[9]='x'; if(S_ISBLK(statbuf.st_mode)) dirdisplaybuffer[0]='b'; if(S_ISCHR(statbuf.st_mode)) dirdisplaybuffer[0]='c'; if(S_ISFIFO(statbuf.st_mode)) dirdisplaybuffer[0]='p'; if(S_ISSOCK(statbuf.st_mode)) dirdisplaybuffer[0]='s'; if(statbuf.st_mode&S_IRUSR) dirdisplaybuffer[1]='r'; if(statbuf.st_mode&S_IWUSR) dirdisplaybuffer[2]='w'; if(statbuf.st_mode&S_IRGRP) dirdisplaybuffer[4]='r'; if(statbuf.st_mode&S_IWGRP) dirdisplaybuffer[5]='w'; if(statbuf.st_mode&S_IROTH) dirdisplaybuffer[7]='r'; if(statbuf.st_mode&S_IWOTH) dirdisplaybuffer[8]='w'; tmpentry=(char*)malloc(strlen(dirdisplaybuffer)+1+sizeof(char*)+2*sizeof(int)); if(tmpentry){ strcpy(tmpentry+sizeof(char*)+2*sizeof(int),dirdisplaybuffer); if(chainitem){ *(char**)chainitem=tmpentry; *(char**)(tmpentry)=NULL; *(int*)(tmpentry+sizeof(char*))=namebegin; *(int*)(tmpentry+sizeof(char*)+sizeof(int))=nameend; chainitem=tmpentry; nentries++; } } } } } } } } dirarray=(char**)malloc(nentries*sizeof(char*)); nentries=0; if(beginlist){ if(!dataconnection->connecttoserver()){ #ifdef SOCKOPTS_NEEDED setsockopt(dataconnection->h,SOL_SOCKET,SO_LINGER,(char*)&lingerdata,sizeof(lingerdata)); setsockopt(client->gethandle(),SOL_SOCKET,SO_KEEPALIVE,(char*)&a,sizeof(a)); #endif swrite(client->gethandle(),"150 ASCII data connection established.\r\n"); datah=dataconnection->h; while(beginlist){ dirarray[nentries++]=beginlist+sizeof(char*); beginlist=*(char**)beginlist; } qsort(dirarray,nentries,sizeof(char*),mycompar0); if(i!=NLST){ char tmptotalsizestring[sizeof(unsigned long)*3+1]; sprintf(tmptotalsizestring,"total %lu\r\n",totalsize/1024); swrite(datah,tmptotalsizestring); } while(nentries){ nentries--; swrite(datah,dirarray[nentries]+2*sizeof(int)); } dataconnection->disconnectfromserver(); swrite(client->gethandle(),"226 Transfer completed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_MESSAGE","Transfer completed"); }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } }else{ swrite(client->gethandle(),"550 No match.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","No match"); } closedir(dirp); }else{ swrite(client->gethandle(),"550 No such directory.\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","No such directory"); } }else{ swrite(client->gethandle(),"550 FTP is not allowed for this directory.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Not allowed"); } } delete dataconnection; }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } } void ControlFTPServerApp::process_get_line(char *inputline){ char *mp=NULL,*mp1,*httpvar_buffer; ConfigArgs *currule; int m,v0,v1,v2,v3,blength,processrules=0,rulecounter=0, newlastruleapplied1=0,newlastruleapplied2=0,newlastruleapplied3=0; if(inputline){ mp=strchr(inputline,':'); if(mp){ *mp=0; mp++; while(*mp==' '||*mp==9) mp++; if(!strcasecmp(inputline,"If-Modified-Since")){ ifmodifiedsince=timefromline(mp); }else{ if(!strcasecmp(inputline,"Authorization")){ if(!memcmp(mp,"Basic ",6)){ mp+=6; un64(mp); mp1=strchr(mp,':'); if(mp1){ *mp1=0; mp1++; strncpy(auth_user_buffer,mp,81); auth_user_buffer[80]=0; strncpy(auth_password_buffer,mp1,81); auth_password_buffer[80]=0; LogMessage(this,NULL,NULL,NULL,0,"AUTHORIZATION",mp); } } }else{ if(!strcasecmp(inputline,"Accept")){ if(!*http_accept_buffer){ strncpy(http_accept_buffer,mp,255); http_accept_buffer[254]=0; }else{ if(strlen(http_accept_buffer)+strlen(mp)+2<255){ strcat(http_accept_buffer,", "); strcat(http_accept_buffer,mp); } } }else{ if(!strcasecmp(inputline,"User-Agent")){ strncpy(http_user_agent_buffer,mp,255); http_user_agent_buffer[254]=0; }else{ if(!strcasecmp(inputline,"Content-Length")){ sscanf(mp,"%u",&content_length); if(content_length<0) content_length=0; }else{ if(!strcasecmp(inputline,"Content-Type")){ strncpy(query_type_buffer,mp,255); query_type_buffer[254]=0; }else{ if(honorkeepalive&&!keepalive&&!strcasecmp(inputline,"Connection")){ if(!strcasecmp(mp,"Keep-Alive")){ LogMessage(this,NULL,NULL,NULL,0,"KEEP_ALIVE","enabled"); keepalive=1; } }else{ httpvar_buffer=(char*)malloc(7+strlen(inputline)+strlen(mp)); if(httpvar_buffer){ strcpy(httpvar_buffer,"HTTP_"); strcpy(httpvar_buffer+5,inputline); for(m=5;httpvar_buffer[m];m++){ if(httpvar_buffer[m]>='a'&&httpvar_buffer[m]<='z') httpvar_buffer[m]&=0xdf; } strcat(httpvar_buffer,"="); strcat(httpvar_buffer,mp); setexecenv_noalloc(httpvar_buffer); } } } } } } processrules=1; } } } }else processrules=1; if(processrules){ currule=(ConfigArgs*)getrules.start; while(currule){ rulecounter++; processrules=0; if(currule->params){ if(currule->params[0]&&currule->params[1]&&currule->params[2] &&currule->params[3]&&currule->params[4]&&currule->params[5]){ if(inputline){ if(!strcasecmp(inputline,currule->params[0])){ v0=currule->params[1][0]=='E'; switch(currule->params[1][2]){ case 0: v1=wildmat(mp,currule->params[2]); break; case 'C': v1=wildmatcase(mp,currule->params[2]); break; default: v1=1; } if(strlen(currule->params[3])>4){ v2=currule->params[3][4]=='E'; }else v2=1; switch(currule->params[3][6]){ case 0: v3=wildmat(currule->absolute? translatedbuf:srcbuffer,currule->params[4]); break; case 'C': v3=wildmatcase(currule->absolute? translatedbuf:srcbuffer,currule->params[4]); break; default: v3=1; } processrules=(v0==v1&&v2==v3); } }else{ if(currule->params[1][0]=='U'){ if(strlen(currule->params[3])>4){ v2=currule->params[3][4]=='E'; }else v2=1; switch(currule->params[3][6]){ case 0: v3=wildmat(currule->absolute? translatedbuf:srcbuffer,currule->params[4]); break; case 'C': v3=wildmatcase(currule->absolute? translatedbuf:srcbuffer,currule->params[4]); break; default: v3=1; } processrules=(v2==v3); } } if(processrules){ switch(currule->params[5][0]){ case 'B': if(lastruleapplied1paramc==7){ if(currule->params[6]){ strncpy(currbasedir,currule->params[6],254); currbasedir[253]=0; }else{ strncpy(currbasedir,basedir,254); currbasedir[253]=0; } }else{ strncpy(currbasedir,basedir,254); currbasedir[253]=0; } } break; case 'C': if(lastruleapplied2paramc==7){ if(currule->params[6]){ strncpy(currcwd,currule->params[6],254); currcwd[253]=0; }else{ strncpy(currcwd,cwd,254); currcwd[253]=0; } }else{ strncpy(currcwd,cwd,254); currcwd[253]=0; } } break; default: if(lastruleapplied3paramc==7){ if(currule->params[6]){ strncpy(dstbuffer,currule->params[6],2047); dstbuffer[2046]=0; }else{ strncpy(dstbuffer,srcbuffer,2047); dstbuffer[2046]=0; } }else{ strncpy(dstbuffer,srcbuffer,2047); dstbuffer[2046]=0; } blength=strlen(dstbuffer); if(blength>0){ trailingslash=dstbuffer[blength-1]=='/'; }else trailingslash=1; } } } } } currule=(ConfigArgs*)currule->next; } if(newlastruleapplied1) lastruleapplied1=newlastruleapplied1; if(newlastruleapplied2) lastruleapplied2=newlastruleapplied2; if(newlastruleapplied3) lastruleapplied3=newlastruleapplied3; } } void ControlFTPServer::splitfn(ServerConnection *client,ServerProcess *process){ char buffer[MESSAGE_BUFFER_SIZE+4]; char *p,*p1,shell[129],*mark; char translatedbuf[4+MAXPATHLEN+2+MAXNAMLEN]; int errflag,blocksize=0,filesize=0; char dirbuffer[MAXPATHLEN+2+MAXNAMLEN]; struct passwd *pw; struct stat statbuf; ConfigArgs *args; #ifdef FCNTL_LOCK struct flock rdlck={F_RDLCK,SEEK_SET,0,0,0},wrlck={F_WRLCK,SEEK_SET,0,0,0}, unlck={F_UNLCK,SEEK_SET,0,0,0}; #endif ClientConnection *dataconnection; FILE *f; char c; int i,l,h; unsigned n1,n2,n3,n4,n5,n6; int procpipe1[2]; struct hostent *hentry; __s32 laddr; int syncexpected=0; char onebyte=0; int zerofound=0; int readboffset=0; #ifdef SOCKOPTS_NEEDED struct linger lingerdata={1,100}; int a=1; #endif char ipaddrbuffer[128]; if(!client->app){ return; } if(process->readhandle<0){ //no input required - finishing return; } do{ l=read(process->readhandle,buffer+readboffset,(MESSAGE_BUFFER_SIZE-1)-readboffset); if(l<0) l=0; readboffset+=l; if(readboffset>0){ if(!buffer[readboffset-1]){ zerofound=1; readboffset--; } } }while(!zerofound&&readboffset<(MESSAGE_BUFFER_SIZE-1)); l=readboffset; buffer[l]=0; for(i=0;iapp,NULL,NULL,NULL,0,"FORK",buffer); laddr=htonl(((sockaddr_in*)client->getaddress())->sin_addr.s_addr); n4=laddr&0xff; n3=(laddr>>8)&0xff; n2=(laddr>>16)&0xff; n1=(laddr>>24)&0xff; if(!((ControlFTPServerApp*)client->app)->resolvedname[0]){ //resolve hostname if it's not already resolved if(global_resolve_hostnames){ // ...and name resolution isn't disallowed hentry=gethostbyaddr((char*)(&((sockaddr_in*)client->getaddress())-> sin_addr.s_addr),4,AF_INET); }else hentry=NULL; if(hentry){ if(hentry->h_name){ strncpy(((ControlFTPServerApp*)client->app)->resolvedname,hentry->h_name,255); ((ControlFTPServerApp*)client->app)->resolvedname[254]=0; memcpy(translatedbuf,"HOST",5); strncpy(translatedbuf+4,((ControlFTPServerApp*)client->app)->resolvedname,MAXPATHLEN+2+MAXNAMLEN); translatedbuf[4+MAXPATHLEN+2+MAXNAMLEN-1]=0; write(process->writehandle,translatedbuf,strlen(translatedbuf)); read(process->readhandle,&onebyte,1); } } } switch(i){ case RETR: p=strchr(buffer+4,'-'); if(p){ p++; }else{ p=buffer+strlen(buffer); } sscanf(buffer+4,"%u,%u,%u,%u,%u,%u",&n1,&n2,&n3,&n4,&n5,&n6); sprintf(ipaddrbuffer,"%u.%u.%u.%u",n1,n2,n3,n4); dataconnection=new ClientConnection(ipaddrbuffer,((int)n5)<<8|n6,ftp_server_port-1); if(dataconnection){ if(!chdir_u_g(client)){ if(!isrestricted(client,&accessrights,p)){ args=findwildargs(client,&pipeoutexec,p); h=-1; if(args){ if(!pipe(procpipe1)){ signal(SIGCHLD,SIG_IGN); switch(!fork()){ case -1: h=-1; break; case 0: close(procpipe1[0]); if(procpipe1[1]!=1){ dup2(procpipe1[1],1); close(procpipe1[1]); } signal(SIGHUP,SIG_DFL); signal(SIGINT,SIG_DFL); signal(SIGQUIT,SIG_DFL); signal(SIGILL,SIG_DFL); signal(SIGTRAP,SIG_DFL); signal(SIGFPE,SIG_DFL); signal(SIGBUS,SIG_DFL); signal(SIGPIPE,SIG_DFL); signal(SIGALRM,SIG_DFL); signal(SIGTERM,SIG_DFL); signal(SIGURG,SIG_DFL); signal(SIGTSTP,SIG_DFL); signal(SIGCONT,SIG_DFL); signal(SIGCHLD,SIG_DFL); signal(SIGTTIN,SIG_DFL); signal(SIGTTOU,SIG_DFL); signal(SIGIO,SIG_DFL); /* signal(SIGXCPU,SIG_DFL); signal(SIGXFSZ,SIG_DFL); */ signal(SIGVTALRM,SIG_DFL); signal(SIGPROF,SIG_DFL); signal(SIGWINCH,SIG_DFL); signal(SIGUSR1,SIG_DFL); signal(SIGUSR2,SIG_DFL); mark=strrchr(args->params[1],'/'); if(mark){ *mark=0; chdir(args->params[1]); *mark='/'; } translatename(client,dirbuffer,p); for(i=1;args->params[i];i++){ if(!strcmp(args->params[i],"%s")) args->params[i]=dirbuffer; } ((ControlFTPServerApp*)client->app)->setexecenv_noalloc( "SERVER_PROTOCOL=FTP"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_EXEC_OUT",args->params[1]); execve(args->params[1],args->params+1,((ControlFTPServerApp*)client->app)->execenv); _exit(-1); break; default: close(procpipe1[1]); h=procpipe1[0]; } } } if(h<0) h=translateopen(client,p,O_RDONLY); if(h>=0){ p--; if(*p=='-') *p=0; if(!args){ if(!fstat(h,&statbuf)){ if(S_ISREG(statbuf.st_mode)){ #ifdef FLOCK if(!flock(h,LOCK_SH)) #else #ifdef FCNTL_LOCK if(!fcntl(h,F_SETLK,&rdlck)) #endif #endif { filesize=statbuf.st_size; blocksize=filesize; if(blocksize<=0||blocksize>MESSAGE_BUFFER_SIZE) blocksize=MESSAGE_BUFFER_SIZE; blocksize=(MESSAGE_BUFFER_SIZE/blocksize)*blocksize; if(blocksize>statbuf.st_size) blocksize=statbuf.st_size; } #if defined(FLOCK) || defined(FCNTL_LOCK) else{ close(h); h=-1; swrite(client->gethandle(),"550 File is locked.\r\n"); } #endif }else{ close(h); h=-1; swrite(client->gethandle(),"550 Not a plain file.\r\n"); } }else{ close(h); h=-1; swrite(client->gethandle(),"550 Not a plain file.\r\n"); } }else blocksize=MESSAGE_BUFFER_SIZE; if(h>=0){ if(!dataconnection->connecttoserver()){ #ifdef SOCKOPTS_NEEDED setsockopt(dataconnection->h,SOL_SOCKET,SO_LINGER,(char*)&lingerdata,sizeof(lingerdata)); setsockopt(client->gethandle(),SOL_SOCKET,SO_KEEPALIVE,(char*)&a,sizeof(a)); #endif if(((ControlFTPServerApp*)client->app)->type=='A'){ swrite(client->gethandle(),"150 ASCII data connection established.\r\n"); }else{ swrite(client->gethandle(),"150 BINARY data connection established.\r\n"); } write(process->writehandle,"RETR",4); syncexpected=1; errflag=0; if(((ControlFTPServerApp*)client->app)->type=='A' &&blocksize==MESSAGE_BUFFER_SIZE) blocksize--; #ifndef NO_MMAP if(args){ #endif while(!errflag&&(l=read(h,buffer,blocksize))>0){ switch(((ControlFTPServerApp*)client->app)->type){ case 'A': p=buffer; p1=p; c=0; while(p1-bufferh,p,p1-p)!=p1-p) errflag=1; write(process->writehandle,"PING",4); if(p1-bufferh,"\r\n",2)!=2) errflag=1; p1++; } p=p1; } break; default: if(write(dataconnection->h,buffer,l)!=l) errflag=1; write(process->writehandle,"PING",4); } } #ifndef NO_MMAP }else{ switch(((ControlFTPServerApp*)client->app)->type){ case 'A': while(!errflag&&(l=read(h,buffer,blocksize))>0){ p=buffer; p1=p; c=0; while(p1-bufferh,p,p1-p)!=p1-p) errflag=1; write(process->writehandle,"PING",4); if(p1-bufferh,"\r\n",2)!=2) errflag=1; p1++; } p=p1; } write(process->writehandle,"PING",4); } break; default: char *mmbuf=(char*)mmap(NULL,filesize,PROT_READ,MAP_SHARED|MAP_FILE,h,0); if((long)mmbuf!=-1){ p=mmbuf; while(p-mmbufwritehandle,"PING",4); l=filesize-(p-mmbuf); if(blocksizeh,p,l,0)!=l){ if(errno==EMSGSIZE){ if(write(dataconnection->h,p,l)!=l) errflag=1; }else errflag=1; } p+=l; } munmap(mmbuf,filesize); }else{ errflag=1; } write(process->writehandle,"PING",4); } } #endif dataconnection->disconnectfromserver(); swrite(client->gethandle(),"226 Transfer completed.\r\n"); // Transfer completed }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } #ifdef FLOCK flock(h,LOCK_UN); #else #ifdef FCNTL_LOCK fcntl(h,F_SETLK,&unlck); #endif #endif close(h); } }else{ swrite(client->gethandle(),"550 No such file or directory.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","No such file or directory"); } }else{ swrite(client->gethandle(),"550 FTP is not allowed for this file.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Not allowed"); } } delete dataconnection; }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } break; case STOR: case APPE: p=strchr(buffer+4,'-'); if(p){ *p=0; p++; }else{ p=buffer+strlen(buffer); } sscanf(buffer+4,"%u,%u,%u,%u,%u,%u",&n1,&n2,&n3,&n4,&n5,&n6); sprintf(buffer+4,"%u.%u.%u.%u",n1,n2,n3,n4); dataconnection=new ClientConnection(buffer+4,((int)n5)<<8|n6,ftp_server_port-1); if(dataconnection){ if(!chdir_u_g(client)){ args=findwildargs(client,&pipeinexec,p); h=-1; if(args){ if(!pipe(procpipe1)){ signal(SIGCHLD,SIG_IGN); switch(!fork()){ case -1: h=-1; break; case 0: close(procpipe1[1]); if(procpipe1[0]){ dup2(procpipe1[0],0); close(procpipe1[0]); } signal(SIGHUP,SIG_DFL); signal(SIGINT,SIG_DFL); signal(SIGQUIT,SIG_DFL); signal(SIGILL,SIG_DFL); signal(SIGTRAP,SIG_DFL); signal(SIGFPE,SIG_DFL); signal(SIGBUS,SIG_DFL); signal(SIGPIPE,SIG_DFL); signal(SIGALRM,SIG_DFL); signal(SIGTERM,SIG_DFL); signal(SIGURG,SIG_DFL); signal(SIGTSTP,SIG_DFL); signal(SIGCONT,SIG_DFL); signal(SIGCHLD,SIG_DFL); signal(SIGTTIN,SIG_DFL); signal(SIGTTOU,SIG_DFL); signal(SIGIO,SIG_DFL); /* signal(SIGXCPU,SIG_DFL); signal(SIGXFSZ,SIG_DFL); */ signal(SIGVTALRM,SIG_DFL); signal(SIGPROF,SIG_DFL); signal(SIGWINCH,SIG_DFL); signal(SIGUSR1,SIG_DFL); signal(SIGUSR2,SIG_DFL); mark=strrchr(args->params[1],'/'); if(mark){ *mark=0; chdir(args->params[1]); *mark='/'; } translatename(client,dirbuffer,p); for(i=1;args->params[i];i++){ if(!strcmp(args->params[i],"%s")) args->params[i]=dirbuffer; } ((ControlFTPServerApp*)client->app)->setexecenv_noalloc( "SERVER_PROTOCOL=FTP"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_EXEC_IN",args->params[1]); execve(args->params[1],args->params+1,((ControlFTPServerApp*)client->app)->execenv); _exit(-1); break; default: close(procpipe1[0]); h=procpipe1[1]; } } } if(h<0){ args=findwildargs(client,&inbounds,p); if(i==STOR){ if(args){ args=findwildargs(client,&stor_modelist,p); if(args) h=translateopen(client,p,O_CREAT|O_EXCL|O_WRONLY,((ModeArgs*)args)->mode); else h=translateopen(client,p,O_CREAT|O_EXCL|O_WRONLY,0); }else{ args=findwildargs(client,&stor_modelist,p); if(args) h=translateopen(client,p,O_CREAT|O_WRONLY|O_TRUNC,((ModeArgs*)args)->mode); else h=translateopen(client,p,O_CREAT|O_WRONLY|O_TRUNC,0600); } }else{ if(args) h=-1; else h=translateopen(client,p,O_WRONLY|O_APPEND); } } if(h>=0){ if(!args){ #ifdef FLOCK flock(h,LOCK_EX); #else #ifdef FCNTL_LOCK fcntl(h,F_SETLK,&wrlck); #endif #endif if(i==STOR) ftruncate(h,0); } if(!dataconnection->connecttoserver()){ #ifdef SOCKOPTS_NEEDED setsockopt(dataconnection->h,SOL_SOCKET,SO_LINGER,(char*)&lingerdata,sizeof(lingerdata)); setsockopt(client->gethandle(),SOL_SOCKET,SO_KEEPALIVE,(char*)&a,sizeof(a)); #endif if(((ControlFTPServerApp*)client->app)->type=='A'){ swrite(client->gethandle(),"150 ASCII data connection established.\r\n"); }else{ swrite(client->gethandle(),"150 BINARY data connection established.\r\n"); } write(process->writehandle,buffer/*"STOR"*/,4); syncexpected=1; c=0; blocksize=MESSAGE_BUFFER_SIZE; if(((ControlFTPServerApp*)client->app)->type=='A') blocksize--; while((l=read(dataconnection->h,buffer,blocksize))>0){ write(process->writehandle,"PING",4); switch(((ControlFTPServerApp*)client->app)->type){ case 'A': p=buffer; p1=p; while(p1-bufferdisconnectfromserver(); swrite(client->gethandle(),"226 Transfer completed.\r\n"); //Transfer completed }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } if(!args){ ftruncate(h,lseek(h,0,SEEK_CUR)); #ifdef FLOCK flock(h,LOCK_UN); #else #ifdef FCNTL_LOCK fcntl(h,F_SETLK,&unlck); #endif #endif } close(h); }else{ if(i==STOR){ swrite(client->gethandle(),"550 Can't create file.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Can't create file"); }else{ swrite(client->gethandle(),"550 Can't open file.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Can't open file"); } } } delete dataconnection; }else{ swrite(client->gethandle(),"425 Connect failed.\r\n"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"PROCESS_ERROR","Connect failed"); } break; case CWD: if(!chdir_u_g(client)){ if(!translatechdir(client,buffer+4)){ if(translategetcwd(client,buffer+4,(MESSAGE_BUFFER_SIZE-1)-4)){ buffer[(MESSAGE_BUFFER_SIZE-1)]=0; swrite(process->writehandle,buffer); syncexpected=1; swrite(client->gethandle(),"250 Directory changed.\r\n"); }else{ swrite(client->gethandle(),"550 Can't change directory.\r\n"); } }else{ swrite(client->gethandle(),"550 Can't change directory.\r\n"); } } break; case RNFR: if(!chdir_u_g(client)){ args=findwildargs(client,&inbounds,buffer+4); if(!args){ translatename(client,dirbuffer,buffer+4); if(*dirbuffer){ h=translateopen(client,buffer+4,O_RDWR); if(h>=0||errno==EACCES){ if(h>=0) close(h); strncpy(buffer+4,dirbuffer,256); buffer[4+255]=0; swrite(process->writehandle,buffer); syncexpected=1; swrite(client->gethandle(),"350 File exists, ready for destination name.\r\n"); }else{ swrite(client->gethandle(),"550 No such file.\r\n"); } }else{ swrite(client->gethandle(),"550 No such file.\r\n"); } }else{ swrite(client->gethandle(),"550 Permission denied.\r\n"); } } break; case RNTO: if(!chdir_u_g(client)){ args=findwildargs(client,&inbounds,buffer+4); if(!args){ translatename(client,dirbuffer,buffer+4); if(*dirbuffer){ if(!rename(((ControlFTPServerApp*)client->app)->rnfr,buffer+4)){ swrite(process->writehandle,buffer); syncexpected=1; swrite(client->gethandle(),"350 Renamed.\r\n"); }else{ swrite(client->gethandle(),"550 Can't rename file.\r\n"); } }else{ swrite(client->gethandle(),"550 No such file.\r\n"); } }else{ swrite(client->gethandle(),"550 Permission denied.\r\n"); } } break; case GET_CLIK: case CLIK: case LIST: case NLST: answer_to_list(buffer,i,&syncexpected,client,process); break; case DELE: if(!chdir_u_g(client)){ p=buffer+4; if(!p){ p=buffer+strlen(buffer); } args=findwildargs(client,&inbounds,p); if(!args){ h=translateunlink(client,p); if(!h){ swrite(client->gethandle(),"250 File deleted.\r\n"); write(process->writehandle,"DELE",4); syncexpected=1; }else{ swrite(client->gethandle(),"550 Can't delete.\r\n"); } }else{ swrite(client->gethandle(),"550 Permision denied.\r\n"); } } break; case MKD: if(!chdir_u_g(client)){ p=buffer+4; if(!p){ p=buffer+strlen(buffer); } args=findwildargs(client,&mkd_modelist,p); if(args) h=translatemkdir(client,p,((ModeArgs*)args)->mode); else h=translatemkdir(client,p,0700); if(!h){ swrite(client->gethandle(),"250 Directory created.\r\n"); write(process->writehandle,"MKD",4); syncexpected=1; }else{ swrite(client->gethandle(),"550 Can't create directory.\r\n"); } } break; case RMD: if(!chdir_u_g(client)){ p=buffer+4; if(!p){ p=buffer+strlen(buffer); } args=findwildargs(client,&inbounds,p); if(!args){ h=translatermdir(client,p); if(!h){ swrite(client->gethandle(),"250 Directory deleted.\r\n"); write(process->writehandle,"MKD",4); syncexpected=1; }else{ swrite(client->gethandle(),"550 Can't delete directory.\r\n"); } }else{ swrite(client->gethandle(),"550 Permision denied.\r\n"); } } break; case USER: if(!strcmp(buffer+4,"anonymous")) strcpy(buffer+4,"ftp"); pw=getpwnam(buffer+4); if(pw){ #ifdef USE_GETSPNAM struct spwd *spw=getspnam(buffer+4); if(spw){ #endif if(!strcmp(buffer+4,"ftp")){ *((int*)(buffer+4))=pw->pw_uid; *((int*)(buffer+4+sizeof(int)))=pw->pw_gid; *((int*)(buffer+4+2*sizeof(int)))=2;/*anonymous password needed*/ }else{ *((int*)(buffer+4))=pw->pw_uid; *((int*)(buffer+4+sizeof(int)))=pw->pw_gid; #ifdef USE_GETSPNAM if(spw->sp_pwdp&&spw->sp_pwdp[0]){ if(spw->sp_pwdp[0]=='*'){ #else if(pw->pw_passwd&&pw->pw_passwd[0]){ if(pw->pw_passwd[0]=='*'){ #endif swrite(client->gethandle(),"530 Account disabled.\r\n"); process->closeonexit=1; delete process; }else *((int*)(buffer+4+2*sizeof(int)))=1;/*password needed*/ }else{ f=fopen("/etc/shells","r"); if(f){ *((int*)(buffer+4+2*sizeof(int)))=1;/*no password needed?*/ while(fgets(shell,128,f)){ if((p=strchr(shell,'\n'))) *p=0; else if((p=strchr(shell,'\r'))) *p=0; else if((p=strchr(shell,026))) *p=0; if(!strcmp(shell,pw->pw_shell)){ *((int*)(buffer+4+2*sizeof(int)))=0; } } fclose(f); if(*((int*)(buffer+4+2*sizeof(int)))){ swrite(client->gethandle(),"530 Special account, FTP is not allowed.\r\n"); process->closeonexit=1; delete process; } }else{ swrite(client->gethandle(),"530 Special account, FTP is not allowed.\r\n"); process->closeonexit=1; delete process; } } } #ifdef USE_GETSPNAM }else{ swrite(client->gethandle(),"530 No such user.\r\n"); process->closeonexit=1; delete process; } #endif }else{ swrite(client->gethandle(),"530 No such user.\r\n"); process->closeonexit=1; delete process; } write(process->writehandle,buffer,4+3*sizeof(int)); syncexpected=1; break; case PASS: if(((ControlFTPServerApp*)client->app)->userid>=0){ pw=getpwnam(((ControlFTPServerApp*)client->app)->username); #ifdef USE_GETSPNAM struct spwd *spw=getspnam(((ControlFTPServerApp*)client->app)->username); #endif if(!strcmp(((ControlFTPServerApp*)client->app)->username,"ftp")){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_ANON_PASSWORD",buffer+4); *((int*)(buffer+4))=1; /*anonymous*/ }else{ #ifdef USE_GETSPNAM if(pw&&spw&&spw->sp_pwdp&&strlen(spw->sp_pwdp)>=2){ if(strcmp(crypt(buffer+4,spw->sp_pwdp),spw->sp_pwdp)){ #else if(pw&&pw->pw_passwd&&strlen(pw->pw_passwd)>=2){ if(strcmp(crypt(buffer+4,pw->pw_passwd),pw->pw_passwd)){ #endif *((int*)(buffer+4))=0; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_LOGIN_FAILURE",((ControlFTPServerApp*)client->app)->username); }else{ *((int*)(buffer+4))=1; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_LOGIN",((ControlFTPServerApp*)client->app)->username); } }else{ *((int*)(buffer+4))=0; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_LOGIN_FAILURE",((ControlFTPServerApp*)client->app)->username); } } write(process->writehandle,buffer,4+sizeof(int)); syncexpected=1; }else{ swrite(client->gethandle(),"500 No username.\r\n"); process->closeonexit=1; delete process; } break; case ABOR: write(process->writehandle,buffer,4+sizeof(ServerConnection*)); syncexpected=1; } if(syncexpected) read(process->readhandle,&onebyte,1); } /* void ControlFTPServer::splitparentfn(ServerConnection *client,ServerProcess *process){ } void ControlFTPServer::unsplitfn(ServerConnection *client,ServerProcess *process){ } void ControlFTPServer::afterunsplitfn(ServerConnection *client,ServerProcess *process){ } */ int ControlFTPServer::prioritydatafn(ServerConnection *client){ return datafn(client); } int ControlFTPServer::datafn(ServerConnection *client){ char *buffer,*param[5],a,*p,*dataleft=NULL,*mark,*qmark; ServerProcess *proc; struct sockaddr_in currsock; sockaddr_size_type currsockaddrlen=sizeof(currsock); LoadedFile *currloadedfile; Application *currapplication; ApplicationRequest *appreq; int i,l,l0,dl,nparam=0,j,jj,crlf,blength; unsigned n1,n2,n3,n4,n5,n6; int dataleftsize=0; struct passwd *pw; char auth_realm_buffer[81]; char tmpline[40]; l0=0; a=0; *auth_realm_buffer=0; if(!client->app) return 0; ((ControlFTPServerApp*)client->app)->timestamp=global_time; if(((ControlFTPServerApp*)client->app)->http_data_left){ dl=((ControlFTPServerApp*)client->app)->appreq->ReadData(client->gethandle(), ((ControlFTPServerApp*)client->app)->http_data_left); if(dl<0) dl=0; ((ControlFTPServerApp*)client->app)->http_data_left-=dl; if(!((ControlFTPServerApp*)client->app)->http_data_left){ ((ControlFTPServerApp*)client->app)->appreq->Ready(); ((ControlFTPServerApp*)client->app)->appreq=NULL; } return dl; } buffer=((ControlFTPServerApp*)client->app)->buffer; if(((ControlFTPServerApp*)client->app)->boffset>=2048) ((ControlFTPServerApp*)client->app)->boffset=0; dl=read(client->gethandle(),buffer+((ControlFTPServerApp*)client->app)->boffset, 2048-((ControlFTPServerApp*)client->app)->boffset); if(dl<0) dl=0; p=buffer+((ControlFTPServerApp*)client->app)->boffset; ((ControlFTPServerApp*)client->app)->boffset+=dl; if(dl){ l0+=dl; }else return 0; do{ l=0; if(((ControlFTPServerApp*)client->app)->boffset>0){ while((unsigned char)*p>=' '&&papp)->boffset-1) p++; a=*p; if((unsigned char)a<' '){ crlf=(a=='\n'&&((ControlFTPServerApp*)client->app)->lastchar=='\r'&&p==buffer); ((ControlFTPServerApp*)client->app)->lastchar=a; if(p<=buffer+((ControlFTPServerApp*)client->app)->boffset-1){ dataleft=p+1; dataleftsize=buffer+((ControlFTPServerApp*)client->app)->boffset-p-1; if(dataleftsize>0&&*p=='\r'){ if(p[1]=='\n'){ dataleft++; dataleftsize--; } } }else{ dataleftsize=0; } l=(p-buffer); buffer[l]=0; ((ControlFTPServerApp*)client->app)->bufflen=l; if(!crlf){ if(((ControlFTPServerApp*)client->app)->reading_http_req){ if(buffer[0]){ ((ControlFTPServerApp*)client->app)->process_get_line(buffer); }else{ ((ControlFTPServerApp*)client->app)->process_get_line(NULL); j=0; strcpy(((ControlFTPServerApp*)client->app)->srcbuffer, ((ControlFTPServerApp*)client->app)->dstbuffer); strncpy(((ControlFTPServerApp*)client->app)->cwd, ((ControlFTPServerApp*)client->app)->currcwd,254); ((ControlFTPServerApp*)client->app)->cwd[253]=0; strncpy(((ControlFTPServerApp*)client->app)->basedir, ((ControlFTPServerApp*)client->app)->currbasedir,254); ((ControlFTPServerApp*)client->app)->basedir[253]=0; translatename(client,((ControlFTPServerApp*)client->app)->translatedbuf, ((ControlFTPServerApp*)client->app)->dstbuffer,&(((ControlFTPServerApp*)client->app)->map_uid)); //Redundant processing removed here LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"TRANSLATEDNAME",((ControlFTPServerApp*)client->app)->translatedbuf); if(!*((ControlFTPServerApp*)client->app)->translatedbuf){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","Can't translate pathname"); response(client,"HTTP/1.0 404 Not Found\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

404 Not Found

"); setexitafterresponse(client,1); j=1; } if(!j&&!checkrights(client,&accessrights, ((ControlFTPServerApp*)client->app)->srcbuffer, ((ControlFTPServerApp*)client->app)->auth_user_buffer, ((ControlFTPServerApp*)client->app)->auth_password_buffer, auth_realm_buffer,81)){ if(*auth_realm_buffer){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","401 Authentication failed"); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_REALM",auth_realm_buffer); response(client,"HTTP/1.0 401 Unauthorized -- authentication failed\r\nWWW-Authenticate: Basic realm=\"%s\"", auth_realm_buffer); response(client,"Server: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

401 Unauthorized -- authentication failed

"); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","403 Forbidden"); response(client,"HTTP/1.0 403 Forbidden\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

403 Forbidden

"); } j=1; setexitafterresponse(client,1); } if(!j&&((ControlFTPServerApp*)client->app)->content_length >max_content_length){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","500 Server Error, Content-Length is too large"); response(client,"HTTP/1.0 500 Server Error\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

500 Server Error

"); setexitafterresponse(client,1); j=1; } if(!j){ currloadedfile=(LoadedFile*)loadedfiles.FindPath( ((ControlFTPServerApp*)client->app)->translatedbuf, (*((unsigned int*)&currsock.sin_addr)),NULL); if(currloadedfile){ if(!strcmp(currloadedfile->path,"-")) // special case -- "-" no remap ((ControlFTPServerApp*)client->app)->trailingslashmismatch=0; else ((ControlFTPServerApp*)client->app)->trailingslashmismatch= trailingslashcmp(((ControlFTPServerApp*)client->app)->urlbuffer,currloadedfile->path); ((ControlFTPServerApp*)client->app)->currloadedfile=currloadedfile; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"BUFFERED_URL",((ControlFTPServerApp*)client->app)->urlbuffer); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"BUFFERED_FILE",((ControlFTPServerApp*)client->app)->translatedbuf); if(((ControlFTPServerApp*)client->app)->trailingslashmismatch){ ((ControlFTPServerApp*)client->app)->trailingslash= hastrailingslash(((ControlFTPServerApp*)client->app)->urlbuffer); if(((ControlFTPServerApp*)client->app)->trailingslash){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Trailing slash"); response(client,"HTTP/1.0 404 Not Found\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

404 Not Found

"); }else{ qmark=strchr(((ControlFTPServerApp*)client->app)->urlbuffer,'?'); if(qmark) *qmark=0; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_REDIRECT","Trailing slash added"); response(client,"HTTP/1.0 302 Found\r\nServer: " SERVERSOFTWARE "\r\nLocation: http://%s%s/%s%s", ((ControlFTPServerApp*)client->app)->localhostname, ((ControlFTPServerApp*)client->app)->urlbuffer, qmark?"?":"",qmark?qmark+1:""); response(client,"Content-Type: text/html\r\n\r\n" "

Directory

\r\n" "This directory is located here",((ControlFTPServerApp*)client->app)->urlbuffer,qmark?"?":"",qmark?qmark+1:""); if(qmark) *qmark='?'; } setexitafterresponse(client,1); }else{ if(currloadedfile->filetime<= ((ControlFTPServerApp*)client->app)->ifmodifiedsince){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_MESSAGE","304 Not Modified"); if(((ControlFTPServerApp*)client->app)->keepalive){ response(client,"HTTP/1.0 304 Not modified\r\nConnection: Keep-Alive\r\nKeep-Alive: max=0, timeout=30\r\n\r\n"); }else{ response(client,"HTTP/1.0 304 Not modified\r\n\r\n"); } }else{ if(client->indexforwheel>=0){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_MESSAGE","200 OK"); if(((ControlFTPServerApp*)client->app)->keepalive){ if(((ControlFTPServerApp*)client->app)->method==HEAD){ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer(currloadedfile->buffer,NULL, currloadedfile->prefixbufferlength); sprintf(tmpline,"%ld", currloadedfile->size-currloadedfile->prefixbufferlength); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0, "BUFFERED_HEADER_CONTENT_LENGTH",tmpline); }else{ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer(currloadedfile->buffer,NULL, currloadedfile->size); sprintf(tmpline,"%ld", currloadedfile->size-currloadedfile->prefixbufferlength); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0, "BUFFERED_CONTENT_LENGTH",tmpline); } }else{ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer(currloadedfile->buffer,NULL, currloadedfile->headerwithoutkeepalivesize); if(((ControlFTPServerApp*)client->app)->method==HEAD){ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer( currloadedfile->buffer+currloadedfile->prefixbufferlength-2, NULL, 2); sprintf(tmpline,"%ld", currloadedfile->size-currloadedfile->prefixbufferlength); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0, "BUFFERED_HEADER_CONTENT_LENGTH",tmpline); }else{ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer( currloadedfile->buffer+currloadedfile->prefixbufferlength-2, NULL, currloadedfile->size-currloadedfile->prefixbufferlength+2); sprintf(tmpline,"%ld", currloadedfile->size-currloadedfile->prefixbufferlength); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0, "BUFFERED_CONTENT_LENGTH",tmpline); } } } } if(((ControlFTPServerApp*)client->app)->keepalive &&(wheel->fdarraysize-fhttpd_nconnections-fhttpd_npipes >=MIN_CONNECTIONS_KEEPALIVE_LEFT)){ suspendpollforresponse(client,1); }else{ setexitafterresponse(client,1); fhttpd_nconnections--; fhttpd_npipes--; } } j=1; } } if(!j){// Is it an application? currapplication=(Application*)applist.start; while(currapplication&&!j){ if((*((__s32*)&currsock.sin_addr))==currapplication->address||currapplication->address==-1){ if(wildmat(((ControlFTPServerApp*)client->app)->translatedbuf,currapplication->mappedname)){ if(!strcmp(currapplication->url,"-")) // special case -- "-" no remap ((ControlFTPServerApp*)client->app)->trailingslashmismatch=0; else ((ControlFTPServerApp*)client->app)->trailingslashmismatch= trailingslashcmp(((ControlFTPServerApp*)client->app)->urlbuffer,currapplication->url); ((ControlFTPServerApp*)client->app)->currapplication=currapplication; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"APPLICATION_USED",currapplication->appname); if(((ControlFTPServerApp*)client->app)->trailingslashmismatch){ ((ControlFTPServerApp*)client->app)->trailingslash= hastrailingslash(((ControlFTPServerApp*)client->app)->urlbuffer); if(((ControlFTPServerApp*)client->app)->trailingslash){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Trailing slash"); response(client,"HTTP/1.0 404 Not Found\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

404 Not Found

"); }else{ qmark=strchr(((ControlFTPServerApp*)client->app)->urlbuffer,'?'); if(qmark) *qmark=0; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_REDIRECT","Trailing slash added"); response(client,"HTTP/1.0 302 Found\r\nServer: " SERVERSOFTWARE "\r\nLocation: http://%s%s/%s%s", ((ControlFTPServerApp*)client->app)->localhostname, ((ControlFTPServerApp*)client->app)->urlbuffer, qmark?"?":"",qmark?qmark+1:""); response(client,"Content-Type: text/html\r\n\r\n" "

Directory

\r\n" "This directory is located here",((ControlFTPServerApp*)client->app)->urlbuffer,qmark?"?":"",qmark?qmark+1:""); if(qmark) *qmark='?'; } setexitafterresponse(client,1); }else{ //FIXME: process application appreq=new ApplicationRequest(((ControlFTPServerApp*)client->app)->currapplication,NULL, (ControlFTPServerApp*)client->app,dataleft,dataleftsize,((ControlFTPServerApp*)client->app)->map_uid); if(appreq){ if(dataleftsize<((ControlFTPServerApp*)client->app)->content_length){ ((ControlFTPServerApp*)client->app)->http_data_left=((ControlFTPServerApp*)client->app)->content_length-dataleftsize; ((ControlFTPServerApp*)client->app)->appreq=appreq; // some data may be left here -- discarded dataleftsize=0; }else{ appreq->Ready(); // some data may be left here -- discarded dataleftsize=0; } }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Can't create request"); response(client,"HTTP/1.0 404 Not Found\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

404 Not Found

"); setexitafterresponse(client,1); } } j=1; } } if(!j){ currapplication=(Application*)currapplication->next; } } } if(!j){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, No default application"); response(client,"HTTP/1.0 404 Not Found\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

404 Not Found

"); setexitafterresponse(client,1); j=1; } currapplication=NULL; currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currapplication=NULL; ((ControlFTPServerApp*)client->app)->reading_http_req=0; ((ControlFTPServerApp*)client->app)->cleanexecenv(); // some data may be left here -- discarded dataleftsize=0; } }else{ i=0; j=0; nparam=0; while(buffer[i]&&buffer[i]<=' '||(unsigned char)buffer[i]>127) i++; if(strncasecmp(buffer+i,"PASS",4)){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_COMMAND",buffer); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_COMMAND","PASS "); } do{ while(buffer[i]==' ') i++; param[nparam]=buffer+i; if(nparam==1&&j=' ';i++); }else{ for(;buffer[i]>' ';i++); if(buffer[i]==' '){ buffer[i]=0; i++; } } if(!nparam){ strupr(param[0]); for(j=0;j=GET||j==TYPE)?(nparam<5):(nparam<2)) &¶m[nparam-1][0]); if(nparam&&!param[nparam-1][0]) nparam--; i=j; if(i>=CLIK||(i>=GET&&servertype==ftp_server_port)){ if(servertype==ftp_server_port){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_FTP_ERROR","500 Command not understood"); response(client,"500 '%s': command not understood.",param[0]); }else{ if(nparam>1) response(client,"HTTP/1.0 400 Bad Request\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n"); if(*param[0]){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","400 Bad Request"); response(client,"

400 Bad Request

"); setexitafterresponse(client,1); // some data may be left here -- discarded dataleftsize=0; } } }else{ if(servertype==http_server_port&&iapp,NULL,NULL,NULL,0,"USER_ERROR","400 Bad Request"); if(nparam>2) response(client,"HTTP/1.0 400 Bad Request\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n"); response(client,"

400 Bad Request

"); setexitafterresponse(client,1); // some data may be left here -- discarded dataleftsize=0; }else{ switch(i){ case USER: if(nparam==2){ if(strlen(param[1])<127){ if(!strcmp(param[1],"anonymous")){ strcpy(((ControlFTPServerApp*)(client->app))->username,"ftp"); }else{ memcpy(((ControlFTPServerApp*)(client->app))->username,param[1],128); } proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("USER",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(((ControlFTPServerApp*)(client->app))->username, strlen(((ControlFTPServerApp*)(client->app))->username)); client->wheel->getbufferbynumber(proc->writehandlepos)->put("",1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"500 'USER': line too long."); } }else{ response(client,"500 'USER': syntax error."); } break; case PASS: proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("PASS",4); if(nparam==2){ client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else client->wheel->getbufferbynumber(proc->writehandlepos)->put("",1); }else{ proc->killme(); // delete proc; } } break; case ACCT: case REIN: case MLFL: case MAIL: case MSND: case MSOM: case MSAM: case MRSQ: case MRCP: case REST: case SITE: case CMD_STAT: response(client,"502 '%s' command not implemented.",param[0]); break; case QUIT: response(client,"221 Goodbye."); setexitafterresponse(client,1); break; case PORT: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ if(strlen(param[1])<40){ if(sscanf(param[1],"%u,%u,%u,%u,%u,%u",&n1,&n2,&n3,&n4,&n5,&n6)==6){ if(n1>255||n2>255||n3>255||n4>255||n5>255||n6>255){ response(client,"500 'PORT': incorrect number(s) in parameters."); }else{ memcpy(((ControlFTPServerApp*)(client->app))->portstring,param[1],40); ((ControlFTPServerApp*)(client->app))->portstring[39]=0; response(client,"200 PORT command successful."); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"FTP_PORT",((ControlFTPServerApp*)(client->app))->portstring); } }else{ response(client,"500 'PORT': incorrect number of parameters."); } }else{ response(client,"500 'PORT': line too long."); } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'PORT': syntax error."); } break; case PASV: response(client,"502 '%s' command not implemented (and must be!).",param[0]); break; case TYPE: if(nparam==2||nparam==3){ if(strlen(param[1])>1){ response(client,"500 'TYPE': syntax error."); }else{ param[1][0]=toupper(param[1][0]); switch(param[1][0]){ case 'A': case 'I': if(nparam==2){ ((ControlFTPServerApp*)client->app)->type=param[1][0]; response(client,"200 Type set to %c.",param[1][0]); }else{ if(strlen(param[2])==1&¶m[1][0]=='A'){ if(toupper(param[2][0])=='N'){ ((ControlFTPServerApp*)client->app)->type='A'; response(client,"200 Type set to A."); }else{ response(client,"504 Only format N supported."); } }else{ response(client,"500 'TYPE': syntax error."); } } break; case 'E': response(client,"504 What EBCDIC? Mainframe?"); break; case 'L': if(nparam==2){ ((ControlFTPServerApp*)client->app)->type='L'; response(client,"200 Type set to L."); }else{ j=0; for(i=0;param[2][i]!=0;i++){ if(!isdigit(param[2][i])){ response(client,"500 'TYPE': syntax error."); j=1; } } if(!j){ if(atoi(param[2])==8){ ((ControlFTPServerApp*)client->app)->type='L'; response(client,"200 Type set to L (byte size is 8)."); }else{ response(client,"504 This server doesn't support Martian standards."); } } } break; default: response(client,"500 No such TYPE."); } } }else{ response(client,"500 'TYPE': syntax error."); } break; case STRU: response(client,"502 Only file structure is supported."); break; case MODE: if(nparam==2){ if(strlen(param[1])>1){ response(client,"500 'MODE': syntax error."); }else{ param[1][0]=toupper(param[1][0]); switch(param[1][0]){ case 'S': response(client,"200 MODE S ok."); break; case 'B': case 'C': response(client,"502 Unimplemented MODE type."); break; default: response(client,"500 No such MODE type."); } } }else{ response(client,"500 'MODE': syntax error."); } break; case PUT: LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","501 Not Implemented"); response(client,"HTTP/1.0 501 Not Implemented\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

501 Not Implemented

"); setexitafterresponse(client,1); break; case HEAD: case POST: case GET: currapplication=NULL; currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->auth=0; ((ControlFTPServerApp*)client->app)->currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currapplication=NULL; if((nparam>=2&&i==GET)||nparam>2){ ((ControlFTPServerApp*)client->app)->trailingslashmismatch=0; strncpy(((ControlFTPServerApp*)client->app)->urlbuffer, param[1],254); ((ControlFTPServerApp*)client->app)->urlbuffer[253]=0; mark=strchr(param[1],'?'); if(mark) *mark=0; unescape(param[1]); blength=strlen(param[1]); if(blength>0){ ((ControlFTPServerApp*)client->app)->trailingslash=param[1][blength-1]=='/'; if(blength>253) param[1][253]=0; }else ((ControlFTPServerApp*)client->app)->trailingslash=1; j=0; if(getsockname(client->gethandle(),(sockaddr*)&currsock,(socklen_t*)&currsockaddrlen)){ (*((__s32*)&currsock.sin_addr))=-1; } pw=globalhttppw; if(!pw){ setexitafterresponse(client,1); dataleftsize=0; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","403 Forbidden, No anonymous user"); if(nparam>2) response(client,"HTTP/1.0 403 Forbidden\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n\r\n

403 Forbidden

"); else response(client,"

403 Forbidden

"); j=1; } if(!j){ ((ControlFTPServerApp*)client->app)->initanonymous(); } if(!j){ translatename(client,((ControlFTPServerApp*)client->app)->translatedbuf,param[1],&(((ControlFTPServerApp*)client->app)->map_uid)); ((ControlFTPServerApp*)client->app)->reading_http_req=1; ((ControlFTPServerApp*)client->app)->http_data_left=0; ((ControlFTPServerApp*)client->app)->method=i; ((ControlFTPServerApp*)client->app)->nparam=nparam; strncpy(((ControlFTPServerApp*)client->app)->srcbuffer, param[1],254); ((ControlFTPServerApp*)client->app)->srcbuffer[253]=0; strcpy(((ControlFTPServerApp*)client->app)->dstbuffer, ((ControlFTPServerApp*)client->app)->srcbuffer); strncpy(((ControlFTPServerApp*)client->app)->currbasedir, ((ControlFTPServerApp*)client->app)->basedir,254); ((ControlFTPServerApp*)client->app)->currbasedir[253]=0; strncpy(((ControlFTPServerApp*)client->app)->currcwd, ((ControlFTPServerApp*)client->app)->cwd,254); ((ControlFTPServerApp*)client->app)->currcwd[253]=0; *((ControlFTPServerApp*)client->app)->auth_user_buffer=0; *((ControlFTPServerApp*)client->app)->auth_password_buffer=0; *((ControlFTPServerApp*)client->app)->http_accept_buffer=0; *((ControlFTPServerApp*)client->app)->http_user_agent_buffer=0; ((ControlFTPServerApp*)client->app)->content_length=0; ((ControlFTPServerApp*)client->app)->ifmodifiedsince=0; *((ControlFTPServerApp*)client->app)->query_type_buffer=0; ((ControlFTPServerApp*)client->app)->keepalive=0; ((ControlFTPServerApp*)client->app)->currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currapplication=NULL; if(nparam<=2){ ((ControlFTPServerApp*)client->app)->process_get_line(NULL); strcpy(((ControlFTPServerApp*)client->app)->srcbuffer, ((ControlFTPServerApp*)client->app)->dstbuffer); strncpy(((ControlFTPServerApp*)client->app)->cwd, ((ControlFTPServerApp*)client->app)->currcwd,254); ((ControlFTPServerApp*)client->app)->cwd[253]=0; strncpy(((ControlFTPServerApp*)client->app)->basedir, ((ControlFTPServerApp*)client->app)->currbasedir,254); ((ControlFTPServerApp*)client->app)->basedir[253]=0; translatename(client,((ControlFTPServerApp*)client->app)->translatedbuf, ((ControlFTPServerApp*)client->app)->dstbuffer,&(((ControlFTPServerApp*)client->app)->map_uid)); if(isrestricted(client,&accessrights,((ControlFTPServerApp*)client->app)->srcbuffer)){ response(client,"

403 Forbidden

"); j=1; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","403 Forbidden, HTTP 0.9 has no authentication"); setexitafterresponse(client,1); } } } if(nparam<=2&&!j){ currloadedfile=(LoadedFile*)loadedfiles.FindPath( ((ControlFTPServerApp*)client->app)->translatedbuf, (*((unsigned int*)&currsock.sin_addr)),NULL); if(currloadedfile){ if(!strcmp(currloadedfile->path,"-")) // special case -- "-" no remap ((ControlFTPServerApp*)client->app)->trailingslashmismatch=0; else ((ControlFTPServerApp*)client->app)->trailingslashmismatch= trailingslashcmp(((ControlFTPServerApp*)client->app)->urlbuffer,currloadedfile->path); ((ControlFTPServerApp*)client->app)->currloadedfile=currloadedfile; j=1; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"BUFFERED_URL",((ControlFTPServerApp*)client->app)->urlbuffer); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"BUFFERED_FILE",((ControlFTPServerApp*)client->app)->translatedbuf); if(((ControlFTPServerApp*)client->app)->trailingslashmismatch){ ((ControlFTPServerApp*)client->app)->trailingslash= hastrailingslash(((ControlFTPServerApp*)client->app)->urlbuffer); if(((ControlFTPServerApp*)client->app)->trailingslash){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Trailing slash"); response(client,"

Not Found

"); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_REDIRECT","Trailing slash added"); response(client,"

Directory

\r\n" "This directory is located here", ((ControlFTPServerApp*)client->app)->urlbuffer); } }else{ if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)-> addexternalbuffer( currloadedfile->buffer+currloadedfile->prefixbufferlength, NULL, currloadedfile->size-currloadedfile->prefixbufferlength); sprintf(tmpline,"%ld", currloadedfile->size-currloadedfile->prefixbufferlength); LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0, "BUFFERED_CONTENT_LENGTH",tmpline); } } setexitafterresponse(client,1); } currapplication=(Application*)applist.start; while(currapplication&&!j){ //Application processing if((*((__s32*)&currsock.sin_addr))==currapplication->address||currapplication->address==-1){ if(wildmat(((ControlFTPServerApp*)client->app)->translatedbuf, currapplication->mappedname)){ if(!strcmp(currapplication->url,"-")) // special case -- "-" no remap ((ControlFTPServerApp*)client->app)->trailingslashmismatch=0; else ((ControlFTPServerApp*)client->app)->trailingslashmismatch= trailingslashcmp(((ControlFTPServerApp*)client->app)->urlbuffer,currapplication->url); ((ControlFTPServerApp*)client->app)->currapplication=currapplication; j=1; LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"APPLICATION_USED",currapplication->appname); if(((ControlFTPServerApp*)client->app)->trailingslashmismatch){ ((ControlFTPServerApp*)client->app)->trailingslash= hastrailingslash(((ControlFTPServerApp*)client->app)->urlbuffer); if(((ControlFTPServerApp*)client->app)->trailingslash){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Trailing slash"); response(client,"

Not Found

"); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_REDIRECT","Trailing slash added"); response(client,"

Directory

\r\n" "This directory is located here", ((ControlFTPServerApp*)client->app)->urlbuffer); } setexitafterresponse(client,1); }else{ //FIXME: process application appreq=new ApplicationRequest(((ControlFTPServerApp*)client->app)->currapplication,NULL, (ControlFTPServerApp*)client->app,NULL,0,((ControlFTPServerApp*)client->app)->map_uid); if(appreq){ appreq->Ready(); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, Can't create request"); response(client,"

404 Not Found

"); setexitafterresponse(client,1); } } } } if(currapplication&&!j) currapplication=(Application*)currapplication->next; } //More redundant processing removed currapplication=NULL; currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currloadedfile=NULL; ((ControlFTPServerApp*)client->app)->currapplication=NULL; ((ControlFTPServerApp*)client->app)->reading_http_req=0; ((ControlFTPServerApp*)client->app)->cleanexecenv(); // some data may be left here -- discarded dataleftsize=0; if(!j){ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","404 Not Found, No default application"); response(client,"

404 Not Found

"); j=1; ((ControlFTPServerApp*)client->app)->cleanexecenv(); setexitafterresponse(client,1); dataleftsize=0; } } }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"USER_ERROR","400 Bad Request"); if(nparam>1) response(client,"HTTP/1.0 400 Bad Request\r\nServer: " SERVERSOFTWARE "\r\nContent-Type: text/html\r\n"); response(client,"

400 Bad Request

"); setexitafterresponse(client,1); // some data may be left here -- discarded dataleftsize=0; } break; case RETR: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("RETR",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(((ControlFTPServerApp*)(client->app))->portstring,strlen(((ControlFTPServerApp*)(client->app))->portstring)); client->wheel->getbufferbynumber(proc->writehandlepos)->put("-",1); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'RETR': syntax error."); } break; case STOU: /*not completely implemented*/ case APPE: case STOR: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ if(i!=APPE){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("STOR",4); }else{ client->wheel->getbufferbynumber(proc->writehandlepos)->put("APPE",4); } client->wheel->getbufferbynumber(proc->writehandlepos)->put(((ControlFTPServerApp*)(client->app))->portstring,strlen(((ControlFTPServerApp*)(client->app))->portstring)); client->wheel->getbufferbynumber(proc->writehandlepos)->put("-",1); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'STOR': syntax error."); } break; case ALLO: if(nparam==2) response(client,"202 ALLO command ignored."); else response(client,"500 'ALLO': syntax error."); break; case MKD: case XMKD: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("MKD ",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'MKD': syntax error."); } break; case RMD: case XRMD: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("RMD ",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'RMD': syntax error."); } break; case RNFR: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("RNFR",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'RNFR': syntax error."); } break; case RNTO: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("RNTO",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'RNTO': syntax error."); } break; case DELE: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("DELE",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'DELE': syntax error."); } break; case ABOR: jj=0; for(j=0;jfdarraysize;j++){ if((proc=wheel->getprocess(j))){ if(proc->clientconnection==client){ jj=1; if(!(proc->destr)){ proc->killme(); // delete proc; } } } } response(client,"426 'ABOR': aborting."); if(jj){ response(client,"226 'ABOR': closing data connection."); }else{ response(client,"226 'ABOR': nothing to abort."); } break; case XCWD: case CWD: if(nparam==2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("CWD ",4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'CWD': syntax error."); } break; case CDUP: case XCUP: if(nparam==1){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put("CWD ..",7); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'CDUP': syntax error."); } break; case LIST: case NLST: #ifdef LS_OPTIONS_IGNORE if(nparam<=3&&i==LIST){ if(nparam>1){ if(param[1][0]=='-'){ param[1]=param[2]; nparam--; } } } #endif if(nparam<=2){ if(((ControlFTPServerApp*)client->app)->auth==1){ proc=new ServerProcess(client->wheel,client->indexforwheel,2048,1,0); if(proc){ if(proc->writehandlepos>=0){ client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[0],4); client->wheel->getbufferbynumber(proc->writehandlepos)->put(((ControlFTPServerApp*)(client->app))->portstring,strlen(((ControlFTPServerApp*)(client->app))->portstring)); client->wheel->getbufferbynumber(proc->writehandlepos)->put("-",1); if(nparam==2) client->wheel->getbufferbynumber(proc->writehandlepos)->put(param[1],strlen(param[1])+1); else client->wheel->getbufferbynumber(proc->writehandlepos)->put("",1); }else{ proc->killme(); // delete proc; } } }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'NLST': syntax error."); } break; case HELP: response(client,"214-The following commands are recognized (* =>'s unimplemented).\r\n" " USER PORT RETR MSND* ALLO DELE SITE* XMKD CDUP \r\n" " PASS PASV STOR MSOM* REST* CWD STAT* RMD XCUP \r\n" " ACCT* TYPE APPE MSAM* RNFR XCWD HELP XRMD STOU \r\n" " REIN* STRU MLFL* MRSQ* RNTO LIST NOOP PWD SYST\r\n" " QUIT MODE MAIL* MRCP* ABOR NLST MKD XPWD\r\n" "214 Direct comments to abelits@phobos.illtel.denver.co.us."); break; case NOOP: response(client,"200 NOOP command successful."); break; case SYST: response(client,"215 UNIX Type: L8"); break; case XPWD: case PWD: if(nparam==1){ if(((ControlFTPServerApp*)client->app)->auth==1){ response(client,"257 \"%s\" is current directory.",((ControlFTPServerApp*)client->app)->cwd); }else{ response(client,"530 Not logged in."); } }else{ response(client,"500 'PWD': no arguments accepted."); } break; } } } } } if(dataleftsize>0){ for(i=0;iapp)->boffset-=dataleft-buffer; }else ((ControlFTPServerApp*)client->app)->boffset=0; }else{ // some data may be left here -- discarded dataleftsize=0; } }else{ // some data may be left here -- discarded dataleftsize=0; } }while(dataleftsize>0); return l0; } int ControlFTPServer::pipeprioritydatafn(ServerConnection *client,ServerProcess *process){ return pipedatafn(client,process); } int ControlFTPServer::pipedatafn(ServerConnection *client,ServerProcess *process){ int l,i,j; struct passwd *pw; char buffer[MESSAGE_BUFFER_SIZE]; if(process->readhandle<0){ //handle doesn't exist return 0; } l=read(process->readhandle,buffer,(MESSAGE_BUFFER_SIZE-1)); if(l<0) l=0; buffer[l]=0; if((ControlFTPServerApp*)client->app){ ((ControlFTPServerApp*)client->app)->timestamp=global_time; if(l){ if(!memcmp(buffer,"LOG ",4)){ if(l-4>=(int)sizeof(__s32)){ if((int)htonl(*((__s32*)(buffer+4)))==l-4){ RelayLogMessage(buffer+4,l-4); }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"LOG_MESSAGE_TRUNCATED",NULL); } }else{ LogMessage((ControlFTPServerApp*)client->app,NULL,NULL,NULL,0,"LOG_MESSAGE_TRUNCATED",NULL); } }else{ if(!memcmp(buffer,"GET ",4)){ }else{ if(!memcmp(buffer,"RETR",4)){ client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"APPE",4)){ client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"STOR",4)){ client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"CWD ",4)){ buffer[256+4]=0; memcpy(((ControlFTPServerApp*)client->app)->cwd,buffer+4,256); ((ControlFTPServerApp*)client->app)->cwd[strlen(buffer+4)]=0; client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"RNFR",4)){ buffer[256+4]=0; memcpy(((ControlFTPServerApp*)client->app)->rnfr,buffer+4,256); ((ControlFTPServerApp*)client->app)->rnfr[strlen(buffer+4)]=0; client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"RNTO",4)){ ((ControlFTPServerApp*)client->app)->rnfr[0]=0; client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"NLST",4)){ client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"USER",4)&&l==4+3*sizeof(int)){ client->wheel->startpolling(client->indexforwheel); ((ControlFTPServerApp*)client->app)->userid=*((int*)(buffer+4)); ((ControlFTPServerApp*)client->app)->gid=*((int*)(buffer+4+sizeof(int))); pw=getpwuid(((ControlFTPServerApp*)client->app)->userid); ((ControlFTPServerApp*)client->app)->lastruleapplied1=0; ((ControlFTPServerApp*)client->app)->lastruleapplied2=0; ((ControlFTPServerApp*)client->app)->lastruleapplied3=0; ((ControlFTPServerApp*)client->app)->basedir[0]='/'; ((ControlFTPServerApp*)client->app)->basedir[1]=0; ((ControlFTPServerApp*)client->app)->cwd[0]='/'; ((ControlFTPServerApp*)client->app)->cwd[1]=0; if(pw){ if(strcmp(((ControlFTPServerApp*)client->app)->username,"ftp")){ strncpy(((ControlFTPServerApp*)client->app)->cwd,pw->pw_dir,256); ((ControlFTPServerApp*)client->app)->cwd[255]=0; j=strlen(((ControlFTPServerApp*)client->app)->cwd); if(j>1){ if(((ControlFTPServerApp*)client->app)->cwd[j-1]=='/') ((ControlFTPServerApp*)client->app)->cwd[j-1]=0; } }else{ strncpy(((ControlFTPServerApp*)client->app)->basedir,pw->pw_dir,256); ((ControlFTPServerApp*)client->app)->basedir[255]=0; struct sockaddr_in currsock; sockaddr_size_type currsockaddrlen=sizeof(currsock); if(!getsockname(client->gethandle(),(sockaddr*)&currsock,(socklen_t*)&currsockaddrlen)){ AddressRoot *curraddrroot=(AddressRoot*)addressroots.start; while(curraddrroot){ if((*((__s32*)&currsock.sin_addr))==curraddrroot->address){ if(curraddrroot->rootdir){ strncpy(((ControlFTPServerApp*)client->app)->basedir, curraddrroot->rootdir,256); ((ControlFTPServerApp*)client->app)->basedir[255]=0; } curraddrroot=NULL; } if(curraddrroot) curraddrroot=(AddressRoot*)curraddrroot->next; } } j=strlen(((ControlFTPServerApp*)client->app)->basedir); if(j){ if(((ControlFTPServerApp*)client->app)->basedir[j-1]=='/') ((ControlFTPServerApp*)client->app)->basedir[j-1]=0; } } }else{ strcpy(((ControlFTPServerApp*)client->app)->cwd,"/"); } ((ControlFTPServerApp*)client->app)->rnfr[0]=0; switch(*((int*)(buffer+4+2*sizeof(int)))){ case 2: ((ControlFTPServerApp*)client->app)->auth=0 ; response(client,"331 Anonymous FTP access is open, enter your address as a password."); break; case 1: ((ControlFTPServerApp*)client->app)->auth=0 ; response(client,"331 Password required for %s.",((ControlFTPServerApp*)client->app)->username); break; case 0: ((ControlFTPServerApp*)client->app)->auth=1; response(client,"230 User %s logged in.",((ControlFTPServerApp*)client->app)->username); } }else{ if(!memcmp(buffer,"PASS",4)&&l==4+sizeof(int)){ ((ControlFTPServerApp*)client->app)->auth=*((int*)(buffer+4)); if(((ControlFTPServerApp*)client->app)->auth){ response(client,"230 User %s logged in.",((ControlFTPServerApp*)client->app)->username); }else{ response(client,"530 Login incorrect."); } client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"DELE",4)&&l==4+sizeof(int)){ client->wheel->startpolling(client->indexforwheel); }else{ if(!memcmp(buffer,"HOST",4)&&l>4&&l<256+4){ //FIXME -- this thing is not protected against //truncated messages for(i=0;igetaddress())->sin_addr.s_addr){ i=nhosts+1; } } if(i<=nhosts){ if(phostsgetaddress())->sin_addr.s_addr; phosts++; if(nhosts=256) phosts=0; } memcpy(((ControlFTPServerApp*)client->app)->resolvedname,buffer+4,l-4); ((ControlFTPServerApp*)client->app)->resolvedname[l-4]=0; } }else{ if(!memcmp(buffer,"TOUT",4)){ //Transfer timeout defined ((ControlFTPServerApp*)client->app)->timestamp+=MAXTRANSFERTIME; } /*not implemented*/ } } } } } } } } } } } } } } } if(l&&memcmp(buffer,"PING",4)&&memcmp(buffer,"TOUT",4)){ if(process->writehandlepos>=0){ client->wheel->getbufferbynumber(process->writehandlepos)->put("*",1); } } return l; } void ControlFTPServer::response(ServerConnection *client,char *fmt,...){ char buffer[MESSAGE_BUFFER_SIZE]; va_list ap; va_start(ap,fmt); vsprintf(buffer,fmt,ap); strcat(buffer,"\r\n"); if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)->put(buffer,strlen(buffer)); } va_end(ap); } void ControlFTPServer::hugeresponse(ServerConnection *client,char *buffer,unsigned long size){ unsigned long l1,l2; if(client->indexforwheel>=0){ l1=client->wheel->getbufferbynumber(client->indexforwheel)->getsize(); l2=client->wheel->getbufferbynumber(client->indexforwheel)->query(); if(l1-l2wheel->getbufferbynumber(client->indexforwheel)->resize(l2+size)){ client->wheel->getbufferbynumber(client->indexforwheel)->put(buffer,size); } }else{ client->wheel->getbufferbynumber(client->indexforwheel)->put(buffer,size); } } } void ControlFTPServer::setexitafterresponse(ServerConnection *client,int closeonexit){ if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)->setcloseonexit(closeonexit); } } int ControlFTPServer::getexitafterresponse(ServerConnection *client){ if(client->indexforwheel>=0){ return client->wheel->getbufferbynumber(client->indexforwheel)->getcloseonexit(); }else return -1; } void ControlFTPServer::emptyresponse(ServerConnection *client){ if(client->indexforwheel>=0){ client->wheel->getbufferbynumber(client->indexforwheel)->empty(); } } void ControlFTPServer::suspendpollforresponse(ServerConnection *client,int startpollonexit){ if(client->indexforwheel>=0){ client->wheel->stoppollinput(client->indexforwheel); client->wheel->getbufferbynumber(client->indexforwheel)->setstartpollonexit(startpollonexit); } } void sigfn1(SIGACTARGS){ reloadpasswdflag=1; } void sighupfn(SIGACTARGS){ reloadpasswdflag=2; } char *makeabsfilename(char *filename,char *pathbuffer){ char *r; r=filename; if(*r!='/'){ r=(char*)malloc(strlen(filename)+strlen(pathbuffer)+2); if(!r){ return NULL; } strcpy(r,pathbuffer); strcat(r,"/"); strcat(r,filename); } return r; } int dpipe[2]={-1,-1}; void daemonforkexit(void){ char s[10]; int l,forkok=0; do{ errno=0; l=read(dpipe[0],s,10); if(l>0){ if(s[l-1]==1){ forkok=1; l--; } write(1,s,l); }else{ if(l<0&&errno==EINTR) l=1; /* Bug in Digital Unix? */ } }while(l>0||errno==EAGAIN); close(dpipe[0]); close(logfd); logfd=1; if(!forkok){ log("Server startup failed"); _exit(1); }else{ log("Server is running"); } } main(int argc,char **argv,char **env){ int h; char tmpstr[10],*pathbuffer,*logfilename=NULL; char *configfile=FHTTPD_CONFIG_FILE; char *pidfile=FHTTPD_PID_FILE; char *fhttpd_http_user=FHTTPD_HTTP_USER; struct passwd *tmphttppw; pathbuffer=(char*)malloc(MAXPATHLEN+1); if(!pathbuffer){ fprintf(stderr,"Insufficient memory\n"); return 1; } if(!getcwd(pathbuffer,MAXPATHLEN+1)){ fprintf(stderr,"Can't get current directory\n"); return 1; } int c; while((c=getopt(argc,argv,"c:p:l:d:vh"))!=-1){ switch(c){ case 'c': configfile=makeabsfilename(optarg,pathbuffer); if(!configfile){ fprintf(stderr,"Insufficient memory\n"); return 1; } break; case 'p': pidfile=makeabsfilename(optarg,pathbuffer); if(!pidfile){ fprintf(stderr,"Insufficient memory\n"); return 1; } break; case 'l': logfilename=makeabsfilename(optarg,pathbuffer); if(!logfilename){ fprintf(stderr,"Insufficient memory\n"); return 1; } break; case 'd': if(chdir(optarg)){ fprintf(stderr,"Can't find HTTP root directory"); return 1; } diroverride=(char*)malloc(MAXPATHLEN+1); if(!diroverride){ fprintf(stderr,"Insufficient memory\n"); return 1; } if(!getcwd(diroverride,MAXPATHLEN+1)){ fprintf(stderr,"Can't get current directory\n"); return 1; } chdir(pathbuffer); break; case 'v': printf(SERVERSOFTWARE " (C) Alex Belits, 1995-1997\n"); return 0; case 'h': printf( "Usage:\n" "%s [-c configfile] [-d directory] [-p pidfile] [-l logfile] [-v] [-h]\n", argv[0]); return 0; case ':': case '?': return 1; } } free(pathbuffer); if(optindpw_uid=tmphttppw->pw_uid; globalhttppw->pw_gid=tmphttppw->pw_gid; globalhttppw->pw_name=(char*)malloc(strlen(tmphttppw->pw_name)+1); globalhttppw->pw_passwd=(char*)malloc(strlen(tmphttppw->pw_passwd)+1); globalhttppw->pw_gecos=(char*)malloc(strlen(tmphttppw->pw_gecos)+1); original_rootdir=(char*)malloc(strlen(tmphttppw->pw_dir)+1); if(original_rootdir) strcpy(original_rootdir,tmphttppw->pw_dir); if(diroverride){ globalhttppw->pw_dir=(char*)malloc(strlen(diroverride)+1); }else{ globalhttppw->pw_dir=(char*)malloc(strlen(tmphttppw->pw_dir)+1); } globalhttppw->pw_shell=(char*)malloc(strlen(tmphttppw->pw_shell)+1); if(globalhttppw->pw_name&&globalhttppw->pw_passwd &&globalhttppw->pw_gecos&&globalhttppw->pw_dir &&globalhttppw->pw_shell&&original_rootdir){ strcpy(globalhttppw->pw_name,tmphttppw->pw_name); strcpy(globalhttppw->pw_passwd,tmphttppw->pw_passwd); strcpy(globalhttppw->pw_gecos,tmphttppw->pw_gecos); if(diroverride){ strcpy(globalhttppw->pw_dir,diroverride); }else{ strcpy(globalhttppw->pw_dir,tmphttppw->pw_dir); } strcpy(globalhttppw->pw_shell,tmphttppw->pw_shell); }else globalhttppw=NULL; } } readconfig(configfile); if(!ftp_server_port&&!http_server_port){ fprintf(stderr,"No FTP or HTTP server enabled, exiting\n"); return 1; } pipe(dpipe); tmplogfd=dpipe[1]; /* signal(SIGPIPE,exit); */ if(/*1||*/daemonize("fhttpd",logfilename,NULL,0,daemonforkexit)==0){ #ifdef DEBUG log("main: Started"); #endif ControlFTPServer *server=NULL,*webserver=NULL; if(ftp_server_port){ server=new ControlFTPServer("ftp-control",ftp_server_port,128, ftp_server_addr); if(!server){ log("main: ftp-control socket not created"); return 1; } if(!server->name){ log("main: ftp-control socket not created" ); return 1; } } if(http_server_port){ webserver=new ControlFTPServer("http",http_server_port,256,http_server_addr); if(!webserver){ log("main: http socket not created"); return 1; } if(!webserver->name){ log("main: http socket not created"); return 1; } } if(process_server_port){ processserver=new ProcessServer("process",process_server_port,128, process_server_addr); if(!processserver){ log("main: process server not created"); return 1; } if(!processserver->name){ log("main: process server not created"); return 1; } } Wheel *wheel=new Wheel(3,-1,WRITE_BUFFER_SIZE); if(!wheel){ log("main: can't create wheel"); return 1; } if(server){ if(wheel->addserversocket(server)<0){ log("main: can't add ftp-control server"); return 1; } } if(webserver){ if(wheel->addserversocket(webserver)<0){ log("main: can't add http server"); return 1; } } if(processserver){ if(wheel->addserversocket(processserver)<0){ log("main: can't add process server"); return 1; } sockaddr_in s; bzero((char*)&s,sizeof(sockaddr_in)); s.sin_family=AF_INET; ServerConnection *processemptyclient=new ServerConnection(0,(sockaddr*)(&s),sizeof(sockaddr_in),processserver); if(!processemptyclient){ log("main: empty client not created"); return 1; } if(wheel->addserverconnection(processemptyclient)<0){ log("main: can't add empty client"); return 1; } wheel->stoppolling(processemptyclient->indexforwheel); if(wheel->getbufferbynumber(processemptyclient->indexforwheel)) delete wheel->getbufferbynumber(processemptyclient->indexforwheel); wheel->setbufferbynumber(processemptyclient->indexforwheel,NULL); processserver->emptyclient=processemptyclient; } struct sigaction tmpsigaction; bzero((char*)&tmpsigaction,sizeof(struct sigaction)); tmpsigaction.sa_handler=sigfn1; sigaddset(&tmpsigaction.sa_mask,SIGUSR1); tmpsigaction.sa_flags=SA_RESTART; sigaction(SIGUSR1,&tmpsigaction,NULL); tmpsigaction.sa_handler=sighupfn; sigemptyset(&tmpsigaction.sa_mask); sigaddset(&tmpsigaction.sa_mask,SIGHUP); tmpsigaction.sa_flags=SA_RESTART; sigaction(SIGHUP,&tmpsigaction,NULL); unlink(pidfile); h=open(pidfile,O_WRONLY|O_APPEND|O_CREAT|O_EXCL,0644); if(h>=0){ sprintf(tmpstr,"%d\n",getpid()); write(h,tmpstr,strlen(tmpstr)); close(h); } log("FTP/HTTP daemon started"); Application *currapp; if(process_server_port){ currapp=(Application*)logapplications.start; ApplicationInstance *newloginstance; while(currapp){ currapp->server=processserver; // Real programmers write REAL kludges! if(currapp->pathname){ newloginstance=currapp->MakeInstance(); if(newloginstance) newloginstance->LogReportStatus(); } currapp=(Application*)currapp->next; } currapp=(Application*)applist.start; while(currapp){ currapp->server=processserver; // Real programmers write REAL kludges! if(currapp->pathname) currapp->MakeInstance(); currapp=(Application*)currapp->next; } }else{ //Remove applications if no server available while((currapp=(Application*)applist.start)){ delete currapp; } while((currapp=(Application*)logapplications.start)){ delete currapp; } } wheel->lflag=1; { char a; a=1; write(tmplogfd,&a,1); // "hey, console or whatever you are... we are ok here" } close(tmplogfd); tmplogfd=-1; umask(global_umask); do{ time(&global_time); fhttpd_nconnections=global_nconnections; fhttpd_npipes=global_npipes; wheel->onepass(); if(reloadpasswdflag){ if(reloadpasswdflag==2){ reloadpasswdflag=0; dup2(logfd,2); wheel->dropeveryone(); unconfig(); readconfig(configfile); umask(global_umask); close(2); dup2(1,2); currapp=(Application*)logapplications.start; ApplicationInstance *newloginstance; while(currapp&&processserver){ if(currapp->pathname){ newloginstance=currapp->MakeInstance(); if(newloginstance) newloginstance->LogReportStatus(); } currapp=(Application*)currapp->next; } currapp=(Application*)applist.start; while(currapp&&processserver){ if(currapp->pathname) currapp->MakeInstance(); currapp=(Application*)currapp->next; } }else{ reloadpasswdflag=0; AccessRealm *currrealm=(AccessRealm*)accessrealms.start; while(currrealm){ currrealm->readfile(); currrealm=(AccessRealm*)currrealm->next; } } } Application *application; application=(Application*)applist.start; while(application){ application->ProcessQueue(); application=(Application*)application->next; } ProcessLog(); }while(wheel->lflag); }else{ return 1; } return 0; }