Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
if((xfer=malloc(sizeof(xfer_t)))==NULL) {
lprintf("%04d !MALLOC FAILURE LINE %d",ctrl_sock,__LINE__);
sockprintf(ctrl_sock,"425 MALLOC FAILURE");
break;
}
memset(xfer,0,sizeof(xfer_t));
xfer->ctrl_sock=ctrl_sock;
xfer->data_sock=data_sock;
xfer->inprogress=inprogress;
xfer->aborted=aborted;
xfer->delfile=delfile;
xfer->tmpfile=tmpfile;
xfer->append=append;
xfer->filepos=filepos;
xfer->credits=credits;
xfer->lastactive=lastactive;
xfer->user=user;
xfer->dir=dir;
xfer->desc=desc;
SAFECOPY(xfer->filename,filename);
if(receiving)
result=_beginthread(receive_thread,0,(void*)xfer);
else
result=_beginthread(send_thread,0,(void*)xfer);
if(result!=-1)
return; /* success */
} while(0);
/* failure */
if(tmpfile)
remove(filename);
*inprogress=FALSE;
/* convert "user name" to "user.name" or "mr. user" to "mr._user" */
char* dotname(char* in, char* out)
{
char ch;
int i;
if(strchr(in,'.')==NULL)
ch='.';
else
ch='_';
for(i=0;in[i];i++)
if(in[i]<=' ')
else
out[i]=in[i];
out[i]=0;
return(out);
}
void parsepath(char** pp, user_t* user, int* curlib, int* curdir)
{
char* p;
char* tp;
char path[MAX_PATH+1];
int dir=*curdir;
int lib=*curlib;
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
p=path;
if(*p=='/') {
p++;
lib=-1;
}
else if(!strncmp(p,"./",2))
p+=2;
if(!strncmp(p,"..",2)) {
p+=2;
if(dir>=0)
dir=-1;
else if(lib>=0)
lib=-1;
if(*p=='/')
p++;
}
if(*p==0) {
*curlib=lib;
*curdir=dir;
return;
}
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
tp=strchr(p,'/');
if(tp) *tp=0;
for(lib=0;lib<scfg.total_libs;lib++) {
if(!chk_ar(&scfg,scfg.lib[lib]->ar,user))
continue;
if(!stricmp(scfg.lib[lib]->sname,p))
break;
}
if(lib>=scfg.total_libs) { /* not found */
*curlib=-1;
return;
}
*curlib=lib;
if(tp==NULL) {
*curdir=-1;
return;
}
p=tp+1;
}
tp=strchr(p,'/');
if(tp!=NULL) {
*tp=0;
tp++;
} else
tp=p+strlen(p);
for(dir=0;dir<scfg.total_dirs;dir++) {
if(scfg.dir[dir]->lib!=lib)
continue;
if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[dir]->ar,user))
if(!stricmp(scfg.dir[dir]->code_suffix,p))
break;
}
if(dir>=scfg.total_dirs) /* not found */
return;
*curdir=dir;
*pp+=tp-path; /* skip "lib/dir/" */
}
static BOOL ftpalias(char* fullalias, char* filename, user_t* user, int* curdir)
{
char* p;
char* tp;
char* fname="";
char line[512];
char alias[512];
char aliasfile[MAX_PATH+1];
int dir=-1;
FILE* fp;
BOOL result=FALSE;

rswindell
committed
sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
if((fp=fopen(aliasfile,"r"))==NULL)
return(FALSE);
p=strrchr(alias+1,'/');
if(p) {
*p=0;
fname=p+1;
}
if(filename==NULL /* directory */ && *fname /* filename specified */)
return(FALSE);
if(!fgets(line,sizeof(line),fp))
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
break;
p=line; /* alias */
while(*p && *p<=' ') p++;
if(*p==';') /* comment */
continue;
tp=p; /* terminator */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
if(stricmp(p,alias)) /* Not a match */
continue;
p=tp+1; /* filename */
while(*p && *p<=' ') p++;
tp=p; /* terminator */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user))<0) {
lprintf("0000 !Invalid virtual path (%s) for %s",p,user->alias);
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
/* invalid or no access */
continue;
}
p=strrchr(p,'/');
if(p!=NULL) p++;
if(p!=NULL && filename!=NULL) {
if(*p)
sprintf(filename,"%s%s",scfg.dir[dir]->path,p);
else
sprintf(filename,"%s%s",scfg.dir[dir]->path,fname);
}
} else if(filename!=NULL)
strcpy(filename,p);
result=TRUE; /* success */
break;
}
fclose(fp);
if(curdir!=NULL)
*curdir=dir;
return(result);
}
char* root_dir(char* path)
{
char* p;
static char root[MAX_PATH+1];
if(!strncmp(root,"\\\\",2)) { /* network path */
p=strchr(root+2,'\\');
if(p) p=strchr(p+1,'\\');
if(p) *(p+1)=0; /* truncate at \\computer\sharename\ */
}
else if(!strncmp(root+1,":/",2) || !strncmp(root+1,":\\",2))
root[3]=0;
else if(*root=='/' || *root=='\\')
root[1]=0;
return(root);
}
char* vpath(int lib, int dir, char* str)
{
strcpy(str,"/");
if(lib<0)
return(str);
strcat(str,scfg.lib[lib]->sname);
if(dir<0)
return(str);
strcat(str,scfg.dir[dir]->code_suffix);
return(str);
}
static BOOL badlogin(SOCKET sock, ulong* login_attempts)
{
mswait(5000); /* As recommended by RFC2577 */
if(++(*login_attempts)>=3) {
sockprintf(sock,"421 Too many failed login attempts.");
return(TRUE);
}
sockprintf(sock,"530 Invalid login.");
return(FALSE);
}
static char* ftp_tmpfname(char* str, SOCKET sock)
{
sprintf(str,"%sftp%u%u.tx",scfg.data_dir,getpid(),sock);
return(str);
}
static void ctrl_thread(void* arg)
{
char buf[512];
char str[128];
char* cmd;
char* p;
char* np;
char* tp;
char password[64];
char fname[MAX_PATH+1];
char qwkfile[MAX_PATH+1];
char aliasfile[MAX_PATH+1];
char aliasline[512];
char desc[501]="";
char sys_pass[128];
char* host_name;
char host_ip[64];
char path[MAX_PATH+1];
char local_dir[MAX_PATH+1];
char ren_from[MAX_PATH+1]="";
char html_index_ext[MAX_PATH+1];
WORD port;
ulong ip_addr;
DWORD h1,h2,h3,h4;
u_short p1,p2; /* For PORT command */
int i;
int rd;
int file;
int result;
int lib;
int dir;
int curlib=-1;
int curdir=-1;
int orglib;
int orgdir;
long filepos=0L;
long timeleft;
ulong l;
ulong login_attempts=0;
ulong avail; /* disk space */
ulong count;
BOOL detail;
BOOL success;
BOOL getdate;
BOOL getsize;

rswindell
committed
BOOL delecmd;
BOOL delfile;
BOOL tmpfile;
BOOL credits;
BOOL filedat=FALSE;
BOOL transfer_inprogress;
BOOL transfer_aborted;
BOOL sysop=FALSE;
BOOL local_fsys=FALSE;
BOOL alias_dir;
FILE* fp;
FILE* alias_fp;
SOCKET sock;
SOCKET tmp_sock;
SOCKET pasv_sock=INVALID_SOCKET;
SOCKET data_sock=INVALID_SOCKET;
HOSTENT* host;
SOCKADDR_IN addr;
SOCKADDR_IN data_addr;
SOCKADDR_IN pasv_addr;
ftp_t ftp=*(ftp_t*)arg;
user_t user;
time_t t;
time_t now;
time_t logintime=0;
time_t lastactive;
file_t f;

rswindell
committed
glob_t g;
node_t node;
client_t client;
struct tm tm;
struct tm cur_tm;

rswindell
committed
JSRuntime* js_runtime=NULL;
JSObject* js_ftp;
thread_up(TRUE /* setuid */);
lastactive=time(NULL);
sock=ftp.socket;
data_addr=ftp.client_addr;
/* Default data port is ctrl port-1 */
data_addr.sin_port=ntohs(data_addr.sin_port)-1;
data_addr.sin_port=htons(data_addr.sin_port);
lprintf("%04d CTRL thread started", sock);
free(arg); /* unexplicable assertion here on July 26, 2001 */
if(startup->answer_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME);

rswindell
committed
transfer_inprogress = FALSE;
transfer_aborted = FALSE;
l=1;
if((i=ioctlsocket(sock, FIONBIO, &l))!=0) {
lprintf("%04d !ERROR %d (%d) disabling socket blocking"
,sock, i, ERROR_VALUE);
sockprintf(sock,"425 Error %d disabling socket blocking"
,ERROR_VALUE);

rswindell
committed
ftp_close_socket(&sock,__LINE__);
thread_down();
return;
}
memset(&user,0,sizeof(user));
SAFECOPY(host_ip,inet_ntoa(ftp.client_addr.sin_addr));
lprintf ("%04d CTRL connection accepted from: %s port %u"
,sock, host_ip, ntohs(ftp.client_addr.sin_port));
if(startup->options&FTP_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr ((char *)&ftp.client_addr.sin_addr
,sizeof(ftp.client_addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
host_name=host->h_name;
else
host_name="<no name>";
if(!(startup->options&FTP_OPT_NO_HOST_LOOKUP)) {
lprintf("%04d Hostname: %s", sock, host_name);
for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
lprintf("%04d HostAlias: %s", sock, host->h_aliases[i]);
}
if(trashcan(&scfg,host_ip,"ip")) {
lprintf("%04d !CLIENT BLOCKED in ip.can: %s", sock, host_ip);
sockprintf(sock,"550 Access denied.");

rswindell
committed
ftp_close_socket(&sock,__LINE__);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host")) {
lprintf("%04d !CLIENT BLOCKED in host.can: %s", sock, host_name);
sockprintf(sock,"550 Access denied.");

rswindell
committed
ftp_close_socket(&sock,__LINE__);
thread_down();
return;
}
/* For PASV mode */
addr_len=sizeof(pasv_addr);
if((result=getsockname(sock, (struct sockaddr *)&pasv_addr,&addr_len))!=0) {
lprintf("%04d !ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE);
sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);

rswindell
committed
ftp_close_socket(&sock,__LINE__);
thread_down();
return;
}
active_clients++;
update_clients();
/* Initialize client display */
client.size=sizeof(client);
client.time=time(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.port=ntohs(ftp.client_addr.sin_port);
client.protocol="FTP";
client.user="<unknown>";
client_on(sock,&client,FALSE /* update */);
sockprintf(sock,"220-%s (%s)",scfg.sys_name, startup->host_name);
sockprintf(sock," Synchronet FTP Server %s-%s Ready"
,revision,PLATFORM_DESC);

rswindell
committed
sprintf(str,"%sftplogin.txt",scfg.text_dir);
if((fp=fopen(str,"rb"))!=NULL) {
while(!feof(fp)) {
if(!fgets(buf,sizeof(buf),fp))
break;
truncsp(buf);
sockprintf(sock," %s",buf);
}
fclose(fp);
}
sockprintf(sock,"220 Please enter your user name.");
socket_debug[sock]|=SOCKET_DEBUG_CTRL;
socket_debug[sock]|=SOCKET_DEBUG_READLINE;
rd = sockreadline(sock, buf, sizeof(buf), &lastactive);
socket_debug[sock]&=~SOCKET_DEBUG_READLINE;
if(transfer_inprogress==TRUE) {
lprintf("%04d Aborting transfer due to receive error",sock);
}
truncsp(buf);
lastactive=time(NULL);
cmd=buf;
while(((BYTE)*cmd)==TELNET_IAC) {
cmd++;
lprintf("%04d RX: Telnet cmd: %s",sock,telnet_cmd_desc(*cmd));
cmd++;
}
while(*cmd && *cmd<' ') {
lprintf("%04d RX: %d (0x%02X)",sock,(BYTE)*cmd,(BYTE)*cmd);
cmd++;
}
if(!(*cmd))
continue;
if(startup->options&FTP_OPT_DEBUG_RX)
lprintf("%04d RX: %s", sock, cmd);
if(!stricmp(cmd, "NOOP")) {
sockprintf(sock,"200 NOOP command successful.");
continue;
}
if(!stricmp(cmd, "HELP SITE") || !stricmp(cmd, "SITE HELP")) {
sockprintf(sock,"214-The following SITE commands are recognized (* => unimplemented):");
sockprintf(sock," HELP VER WHO UPTIME");
if(user.level>=SYSOP_LEVEL)
sockprintf(sock,
" RECYCLE [ALL]");
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
continue;
}
if(!strnicmp(cmd, "HELP",4)) {
sockprintf(sock,"214-The following commands are recognized (* => unimplemented, # => extension):");
sockprintf(sock," USER PASS CWD XCWD CDUP XCUP PWD XPWD");
sockprintf(sock," QUIT REIN PORT PASV LIST NLST NOOP HELP");
sockprintf(sock," SIZE MDTM RETR STOR REST ALLO ABOR SYST");
sockprintf(sock," TYPE STRU MODE SITE RNFR* RNTO* DELE* DESC#");
sockprintf(sock," FEAT# OPTS#");
sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr);
continue;
}
if(!stricmp(cmd, "FEAT")) {
sockprintf(sock,"211-The following additional (post-RFC949) features are supported:");
sockprintf(sock," DESC");
sockprintf(sock," MDTM");
sockprintf(sock," SIZE");
sockprintf(sock," REST STREAM");
sockprintf(sock,"211 End");
continue;
}
if(!strnicmp(cmd, "OPTS",4)) {
sockprintf(sock,"501 No options supported.");
continue;
}
if(!stricmp(cmd, "QUIT")) {

rswindell
committed
sprintf(str,"%sftpbye.txt",scfg.text_dir);
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
if((fp=fopen(str,"rb"))!=NULL) {
i=0;
while(!feof(fp)) {
if(!fgets(buf,sizeof(buf),fp))
break;
truncsp(buf);
if(!i)
sockprintf(sock,"221-%s",buf);
else
sockprintf(sock," %s",buf);
i++;
}
fclose(fp);
}
sockprintf(sock,"221 Goodbye. Closing control connection.");
break;
}
if(!strnicmp(cmd, "USER ",5)) {
sysop=FALSE;
user.number=0;
p=cmd+5;
while(*p && *p<=' ') p++;
truncsp(p);
user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/);
if(!user.number && !stricmp(user.alias,"anonymous"))
user.number=matchuser(&scfg,"guest",FALSE);
if(user.number && getuserdat(&scfg, &user)==0 && user.pass[0]==0)
sockprintf(sock,"331 User name okay, give your full e-mail address as password.");
else
sockprintf(sock,"331 User name okay, need password.");
continue;
}
if(!strnicmp(cmd, "PASS ",5) && user.alias[0]) {
user.number=0;
p=cmd+5;
while(*p && *p<=' ') p++;
user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/);
if(scfg.sys_misc&SM_ECHO_PW)
lprintf("%04d !UNKNOWN USER: %s, Password: %s",sock,user.alias,p);
else
lprintf("%04d !UNKNOWN USER: %s",sock,user.alias);
if(badlogin(sock,&login_attempts))
break;
continue;
}
if((i=getuserdat(&scfg, &user))!=0) {
lprintf("%04d !ERROR %d getting data for user #%d (%s)"
,sock,i,user.number,user.alias);
sockprintf(sock,"530 Database error %d",i);
user.number=0;
continue;
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf("%04d !DELETED or INACTIVE user #%d (%s)"
,sock,user.number,user.alias);
user.number=0;
if(badlogin(sock,&login_attempts))
break;
continue;
}
if(user.rest&FLAG('T')) {
lprintf("%04d !T RESTRICTED user #%d (%s)"
,sock,user.number,user.alias);
user.number=0;
if(badlogin(sock,&login_attempts))
break;
continue;
}
if(user.ltoday>scfg.level_callsperday[user.level]
&& !(user.exempt&FLAG('L'))) {
lprintf("%04d !MAXIMUM LOGONS (%d) reached for %s"
,sock,scfg.level_callsperday[user.level],user.alias);
sockprintf(sock,"530 Maximum logons reached.");
user.number=0;
continue;
}
if(user.rest&FLAG('L') && user.ltoday>1) {
lprintf("%04d !L RESTRICTED user #%d (%s) already on today"
,sock,user.number,user.alias);
sockprintf(sock,"530 Maximum logons reached.");
user.number=0;
continue;
}
sprintf(sys_pass,"%s:%s",user.pass,scfg.sys_pass);
if(!user.pass[0]) { /* Guest/Anonymous */
if(trashcan(&scfg,password,"email")) {
lprintf("%04d !BLOCKED e-mail address: %s",sock,password);
user.number=0;
if(badlogin(sock,&login_attempts))
break;
continue;
}
lprintf("%04d %s: <%s>",sock,user.alias,password);
putuserrec(&scfg,user.number,U_NETMAIL,LEN_NETMAIL,password);
}
else if(user.level>=SYSOP_LEVEL && !stricmp(password,sys_pass)) {
lprintf("%04d Sysop access granted to %s", sock, user.alias);
sysop=TRUE;
}
else if(stricmp(password,user.pass)) {

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf("%04d !FAILED Password attempt for user %s: '%s' expected '%s'"

rswindell
committed
,sock, user.alias, password, user.pass);
else
lprintf("%04d !FAILED Password attempt for user %s"

rswindell
committed
,sock, user.alias);
if(badlogin(sock,&login_attempts))
break;
continue;
}
/* Update client display */
if(user.pass[0])
client.user=user.alias;
else { /* anonymous */
sprintf(str,"%s <%.32s>",user.alias,password);
client.user=str;
}
client_on(sock,&client,TRUE /* update */);
logintime=time(NULL);
timeleft=gettimeleft(&scfg,&user,logintime);

rswindell
committed
sprintf(str,"%sftphello.txt",scfg.text_dir);
if((fp=fopen(str,"rb"))!=NULL) {
i=0;
while(!feof(fp)) {
if(!fgets(buf,sizeof(buf),fp))
break;
truncsp(buf);
if(!i)
sockprintf(sock,"230-%s",buf);
else
sockprintf(sock," %s",buf);
i++;
}
fclose(fp);
}
#ifdef JAVASCRIPT
#ifdef JS_CX_PER_SESSION
if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
lprintf("%04d !JavaScript ERROR creating user class",sock);
if(js_CreateUserObject(js_cx, js_glob, &scfg, "user", user.number)==NULL)
lprintf("%04d !JavaScript ERROR creating user object",sock);
if(js_CreateClientObject(js_cx, js_glob, "client", &client, sock)==NULL)
lprintf("%04d !JavaScript ERROR creating client object",sock);
if(js_CreateFileAreaObject(js_cx, js_glob, &scfg, &user
,startup->html_index_file)==NULL)
lprintf("%04d !JavaScript ERROR creating file area object",sock);
#endif
if(sysop)
sockprintf(sock,"230-Sysop access granted.");
sockprintf(sock,"230-%s logged in.",user.alias);
if(!(user.exempt&FLAG('D')) && (user.cdt+user.freecdt)>0)
sockprintf(sock,"230-You have %lu download credits."
,user.cdt+user.freecdt);
sockprintf(sock,"230 You are allowed %lu minutes of use for this session."

rswindell
committed
sprintf(qwkfile,"%sfile/%04d.qwk",scfg.data_dir,user.number);
/* Adjust User Total Logons/Logons Today */
adjustuserrec(&scfg,user.number,U_LOGONS,5,1);
putuserrec(&scfg,user.number,U_LTODAY,5,ultoa(user.ltoday+1,str,10));
putuserrec(&scfg,user.number,U_MODEM,LEN_MODEM,"FTP");
putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip);
getuserdat(&scfg, &user); /* make user current */
continue;
}
if(!user.number) {
sockprintf(sock,"530 Please login with USER and PASS.");
continue;
}
getuserdat(&scfg, &user); /* get current user data */
if((timeleft=gettimeleft(&scfg,&user,logintime))<1L) {
sockprintf(sock,"421 Sorry, you've run out of time.");
lprintf("%04d Out of time, disconnecting",sock);
break;
}
/********************************/
/* These commands require login */
/********************************/
if(!stricmp(cmd, "REIN")) {
lprintf("%04d %s reinitialized control session",sock,user.alias);
user.number=0;
sysop=FALSE;
filepos=0;
sockprintf(sock,"220 Control session re-initialized. Ready for re-login.");
continue;
}
if(!stricmp(cmd, "SITE WHO")) {
sockprintf(sock,"211-Active Telnet Nodes:");
for(i=0;i<scfg.sys_nodes && i<scfg.sys_lastnode;i++) {
if((result=getnodedat(&scfg, i+1, &node, 0))!=0) {
sockprintf(sock," Error %d getting data for Telnet Node %d",result,i+1);
continue;
}
if(node.status==NODE_INUSE)
sockprintf(sock," Node %3d: %s",i+1, username(&scfg,node.useron,str));
sockprintf(sock,"211 End (%d active FTP clients)", active_clients);
continue;
}
if(!stricmp(cmd, "SITE VER")) {
sockprintf(sock,"211 %s",ftp_ver());
if(!stricmp(cmd, "SITE UPTIME")) {
sockprintf(sock,"211 %s (%lu served)",sectostr(time(NULL)-uptime,str),served);
continue;
}
if(!stricmp(cmd, "SITE RECYCLE") && user.level>=SYSOP_LEVEL) {
startup->recycle_now=TRUE;
sockprintf(sock,"211 server will recycle when not in-use");
continue;
}
if(!stricmp(cmd, "SITE RECYCLE ALL") && user.level>=SYSOP_LEVEL) {
refresh_cfg(&scfg);
sockprintf(sock,"211 ALL servers/nodes will recycle when not in-use");
continue;
}
if(!stricmp(cmd, "SITE DEBUG")) {
sockprintf(sock,"211-Debug");
for(i=0;i<sizeof(socket_debug);i++)
if(socket_debug[i]!=0)
sockprintf(sock,"211-socket %d = 0x%X",i,socket_debug[i]);
sockprintf(sock,"211 End");
continue;
}
if(!strnicmp(cmd, "PORT ",5)) {
p=cmd+5;
while(*p && *p<=' ') p++;
sscanf(p,"%ld,%ld,%ld,%ld,%hd,%hd",&h1,&h2,&h3,&h4,&p1,&p2);
data_addr.sin_addr.s_addr=htonl((h1<<24)|(h2<<16)|(h3<<8)|h4);
data_addr.sin_port=(u_short)((p1<<8)|p2);
if(data_addr.sin_port<1024) {
lprintf("%04d !SUSPECTED BOUNCE ATTACK ATTEMPT by %s to %s port %u"
,sock,user.alias
,inet_ntoa(data_addr.sin_addr),data_addr.sin_port);
hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
sockprintf(sock,"504 Bad port number.");
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
continue; /* As recommended by RFC2577 */
}
data_addr.sin_port=htons(data_addr.sin_port);
sockprintf(sock,"200 PORT Command successful.");
continue;
}
if(!stricmp(cmd, "PASV")) {
if(pasv_sock!=INVALID_SOCKET)

rswindell
committed
ftp_close_socket(&pasv_sock,__LINE__);

rswindell
committed
if((pasv_sock=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
lprintf("%04d !PASV ERROR %d opening socket", sock,ERROR_VALUE);
sockprintf(sock,"425 Error %d opening PASV data socket", ERROR_VALUE);
continue;
}
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf("%04d PASV DATA socket %d opened",sock,pasv_sock);
pasv_addr.sin_port = 0;
result=bind(pasv_sock, (struct sockaddr *) &pasv_addr,sizeof(pasv_addr));
if(result!= 0) {
lprintf("%04d !PASV ERROR %d (%d) binding socket", sock, result, ERROR_VALUE);
sockprintf(sock,"425 Error %d binding data socket",ERROR_VALUE);

rswindell
committed
ftp_close_socket(&pasv_sock,__LINE__);
continue;
}
addr_len=sizeof(addr);
if((result=getsockname(pasv_sock, (struct sockaddr *)&addr,&addr_len))!=0) {
lprintf("%04d !PASV ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE);
sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE);

rswindell
committed
ftp_close_socket(&pasv_sock,__LINE__);
continue;
}
if((result=listen(pasv_sock, 1))!= 0) {
lprintf("%04d !PASV ERROR %d (%d) listening on socket", sock, result, ERROR_VALUE);
sockprintf(sock,"425 Error %d listening on data socket",ERROR_VALUE);

rswindell
committed
ftp_close_socket(&pasv_sock,__LINE__);
ip_addr=ntohl(pasv_addr.sin_addr.s_addr);
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
port=ntohs(addr.sin_port);
sockprintf(sock,"227 Entering Passive Mode (%d,%d,%d,%d,%hd,%hd)"
,(ip_addr>>24)&0xff
,(ip_addr>>16)&0xff
,(ip_addr>>8)&0xff
,ip_addr&0xff
,(port>>8)&0xff
,port&0xff
);
continue;
}
if(!strnicmp(cmd, "TYPE ",5)) {
sockprintf(sock,"200 All files sent in BINARY mode.");
continue;
}
if(!strnicmp(cmd, "ALLO",4)) {
p=cmd+5;
while(*p && *p<=' ') p++;
if(*p)
l=atol(p);
else
l=0;
if(local_fsys)
avail=getfreediskspace(local_dir,0);
avail=getfreediskspace(scfg.data_dir,0); /* Change to temp_dir? */
sockprintf(sock,"504 Only %lu bytes available.",avail);
sockprintf(sock,"200 %lu bytes available.",avail);
continue;
}
if(!strnicmp(cmd, "REST",4)) {
p=cmd+4;
while(*p && *p<=' ') p++;
if(*p)
filepos=atol(p);
else
filepos=0;
sockprintf(sock,"350 Restarting at %lu. Send STORE or RETRIEVE to initiate transfer."
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
continue;
}
if(!strnicmp(cmd, "MODE ",5)) {
p=cmd+5;
while(*p && *p<=' ') p++;
if(toupper(*p)!='S')
sockprintf(sock,"504 Only STREAM mode supported.");
else
sockprintf(sock,"200 STREAM mode.");
continue;
}
if(!strnicmp(cmd, "STRU ",5)) {
p=cmd+5;
while(*p && *p<=' ') p++;
if(toupper(*p)!='F')
sockprintf(sock,"504 Only FILE structure supported.");
else
sockprintf(sock,"200 FILE structure.");
continue;
}
if(!stricmp(cmd, "SYST")) {
sockprintf(sock,"215 UNIX Type: L8");
continue;
}
if(!stricmp(cmd, "ABOR")) {
if(!transfer_inprogress)
sockprintf(sock,"226 No tranfer in progress.");
else {
lprintf("%04d %s aborting transfer"
,sock,user.alias);
YIELD(); /* give send thread time to abort */
sockprintf(sock,"226 Transfer aborted.");
}
continue;
}
if(!strnicmp(cmd,"SMNT ",5) && sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
p=cmd+5;
while(*p && *p<=' ') p++;
if(!stricmp(p,BBS_FSYS_DIR))
local_fsys=FALSE;
else {
if(!direxist(p)) {
sockprintf(sock,"550 Directory does not exist.");
lprintf("%04d !%s attempted to mount invalid directory: %s"
,sock, user.alias, p);
continue;
}
local_fsys=TRUE;
}
sockprintf(sock,"250 %s file system mounted."
,local_fsys ? "Local" : "BBS");
lprintf("%04d %s mounted %s file system"
,sock, user.alias, local_fsys ? "local" : "BBS");
continue;
}
/****************************/
/* Local File System Access */
/****************************/
if(sysop && local_fsys && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) {
if(local_dir[0]
&& local_dir[strlen(local_dir)-1]!='\\'
&& local_dir[strlen(local_dir)-1]!='/')
strcat(local_dir,"/");
if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {
if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) {
lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
sockprintf(sock, "451 Insufficient system storage");
continue;
}
if(!strnicmp(cmd, "LIST", 4))
detail=TRUE;
else
detail=FALSE;
p=cmd+4;
while(*p && *p<=' ') p++;

rswindell
committed
sprintf(path,"%s%s",local_dir, *p ? p : "*");
lprintf("%04d %s listing: %s", sock, user.alias, path);
sockprintf(sock, "150 Directory of %s%s", local_dir, p);
now=time(NULL);
if(localtime_r(&now,&cur_tm)==NULL)
memset(&cur_tm,0,sizeof(cur_tm));

rswindell
committed
glob(path,0,NULL,&g);
for(i=0;i<(int)g.gl_pathc;i++) {

rswindell
committed
f.size=flength(g.gl_pathv[i]);