Newer
Older
,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,scfg.dir[i]->code_suffix);
fprintf(fp,"%s\r\n",scfg.dir[i]->code_suffix);
} else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user,&client)) {
lprintf(LOG_INFO,"%04d <%s> %slisting: /%s/%s directory in %s mode"
,sock, user.alias, detail ? "detailed ":""
,scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, mode);
smb_t smb;
if((result = smb_open_dir(&scfg, &smb, dir)) != SMB_SUCCESS) {
lprintf(LOG_ERR, "ERROR %d (%s) opening %s", result, smb.last_error, smb.file);
continue;
}
time_t start = time(NULL);
size_t file_count = 0;
file_t* file_list = loadfiles(&smb
,filespec, /* time: */0, file_detail_normal, scfg.dir[dir]->sort, &file_count);
for(size_t i = 0; i < file_count; i++) {
file_t* f = &file_list[i];

rswindell
committed
if(detail) {
f->size = f->cost;
t = f->hdr.when_imported.time;
if(scfg.dir[dir]->misc&DIR_FCHK) {
struct stat st;
if(stat(getfilepath(&scfg, f, path), &st) != 0)
continue;
f->size = st.st_size;
t = st.st_mtime;
}
if(localtime_r(&t,&tm)==NULL)

rswindell
committed
memset(&tm,0,sizeof(tm));
if(f->hdr.attr & MSG_ANONYMOUS)
SAFECOPY(str,ANONYMOUS);
else
dotname(f->from,str);
fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9"PRId64" %s %2d "

rswindell
committed
,NAME_LEN
,scfg.dir[dir]->code_suffix
,(int64_t)f->size
,ftp_mon[tm.tm_mon],tm.tm_mday);

rswindell
committed
if(tm.tm_year==cur_tm.tm_year)
fprintf(fp,"%02d:%02d %s\r\n"
,tm.tm_hour,tm.tm_min
,f->name);

rswindell
committed
else
fprintf(fp,"%5d %s\r\n"
,1900+tm.tm_year
,f->name);

rswindell
committed
} else
fprintf(fp,"%s\r\n", f->name);
lprintf(LOG_INFO, "%04d <%s> %slisting (%ld bytes) of /%s/%s (%lu files) created in %ld seconds"
,sock, user.alias, detail ? "detailed ":"", ftell(fp), scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix
,(ulong)file_count, (long)time(NULL) - start);
freefiles(file_list, file_count);
smb_close(&smb);
lprintf(LOG_INFO,"%04d <%s> %slisting: /%s/%s directory in %s mode (empty - no access)"
,sock, user.alias, detail ? "detailed ":"", scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix, mode);
filexfer(&data_addr,sock,sess,pasv_sock,pasv_sess,&data_sock,&data_sess,fname,0L
,&transfer_inprogress,&transfer_aborted
,TRUE /* delfile */
,TRUE /* tmpfile */
,&lastactive,&user,&client,dir,FALSE,FALSE,FALSE,NULL,protection);

rswindell
committed
if(!strnicmp(cmd, "RETR ", 5)
|| !strnicmp(cmd, "SIZE ",5)
|| !strnicmp(cmd, "MDTM ",5)
|| !strnicmp(cmd, "DELE ",5)) {
getdate=FALSE;
getsize=FALSE;

rswindell
committed
delecmd=FALSE;
file_date=0;
file_size=-1;
if(!strnicmp(cmd,"SIZE ",5))
getsize=TRUE;
else if(!strnicmp(cmd,"MDTM ",5))
getdate=TRUE;

rswindell
committed
else if(!strnicmp(cmd,"DELE ",5))
delecmd=TRUE;
if(!getsize && !getdate && user.rest&FLAG('D')) {
filepos=0;
continue;
}
credits=TRUE;
success=FALSE;
delfile=FALSE;
tmpfile=FALSE;
lib=curlib;
dir=curdir;
p=cmd+5;
SKIP_WHITESPACE(p);
if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR)))
p+=strlen(BBS_FSYS_DIR); /* already mounted */
if(*p=='/') {
lib=-1;
p++;
}
else if(!strncmp(p,"./",2))
p+=2;
if(lib<0 && ftpalias(p, fname, &user, &client, &dir)==TRUE) {
success=TRUE;
credits=TRUE; /* include in d/l stats */
tmpfile=FALSE;
delfile=FALSE;
lprintf(LOG_INFO,"%04d <%s> %.4s by alias: %s"
if(dir>=0)
lib=scfg.dir[dir]->lib;
}
if(!success && lib<0 && (tp=strchr(p,'/'))!=NULL) {
dir=-1;
*tp=0;
for(i=0;i<scfg.total_libs;i++) {
continue;
if(!stricmp(scfg.lib[i]->sname,p))
break;
}
if(i<scfg.total_libs)
lib=i;
p=tp+1;
}
if(!success && dir<0 && (tp=strchr(p,'/'))!=NULL) {
*tp=0;
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=lib)
continue;
if(!stricmp(scfg.dir[i]->code_suffix,p))
break;
}
if(i<scfg.total_dirs)
dir=i;
p=tp+1;
}
sprintf(str,"%s.qwk",scfg.sys_id);
if(lib<0 && startup->options&FTP_OPT_ALLOW_QWK

rswindell
committed
&& !stricmp(p,str) && !delecmd) {
if(!fexistcase(qwkfile)) {
lprintf(LOG_INFO,"%04d <%s> creating QWK packet...",sock,user.alias);
sprintf(str,"%spack%04u.now",scfg.data_dir,user.number);
if(!fmutex(str, startup->host_name, /* max_age: */60 * 60)) {
lprintf(LOG_WARNING, "%04d <%s> !ERROR %d creating mutex-semaphore file: %s"
,sock, user.alias, errno, str);
sockprintf(sock,sess,"451 Packet creation already in progress (are you logged-in concurrently?)");
filepos=0;
continue;
}
t=time(NULL);
while(fexist(str) && !terminate_server) {
if(!socket_check(sock,NULL,NULL,0))
break;
if(time(NULL)-t>startup->qwk_timeout)
break;
mswait(1000);
}
if(!socket_check(sock,NULL,NULL,0)) {
lprintf(LOG_NOTICE,"%04d <%s> disconnected while waiting for QWK packet creation"
,sock, user.alias);
(void)ftp_remove(sock, __LINE__, str, user.alias);
continue;
}
if(fexist(str)) {
lprintf(LOG_WARNING,"%04d <%s> !TIMEOUT waiting for QWK packet creation", sock, user.alias);
sockprintf(sock,sess,"451 Time-out waiting for packet creation.");
(void)ftp_remove(sock, __LINE__, str, user.alias);
filepos=0;
continue;
}
if(!fexistcase(qwkfile)) {
lprintf(LOG_INFO,"%04d <%s> No QWK Packet created (no new messages)", sock, user.alias);
sockprintf(sock,sess,"550 No QWK packet created (no new messages)");
filepos=0;
continue;
}
file_size = flength(fname);
if(file_size < 1) {
lprintf(LOG_WARNING, "%04d <%s> Invalid QWK packet file size (%"PRIuOFF" bytes): %s"
,sock, user.alias, file_size, fname);
sockprintf(sock,sess,"550 Invalid QWK packet file size: %"PRIuOFF" bytes", file_size);
filepos=0;
continue;
}
success=TRUE;
delfile=TRUE;
credits=FALSE;
if(!getsize && !getdate)
lprintf(LOG_INFO,"%04d <%s> downloading QWK packet (%"PRIuOFF" bytes) in %s mode"
,sock,user.alias,file_size
,mode);
} else if(startup->options&FTP_OPT_INDEX_FILE

rswindell
committed
&& !stricmp(p,startup->index_file_name)
&& !delecmd) {
if(getsize) {
sockprintf(sock,sess, "550 Size not available for dynamically generated files");
continue;
}
if((fp=fopen(ftp_tmpfname(fname,"ndx",sock),"wb"))==NULL) {
lprintf(LOG_ERR,"%04d <%s> !ERROR %d (%s) line %d opening %s"
,sock, user.alias, errno, strerror(errno), __LINE__, fname);
filepos=0;
continue;
}
success=TRUE;
if(getdate)
file_date=time(NULL);
else {
lprintf(LOG_INFO,"%04d <%s> downloading %s for %s in %s mode"
,sock, user.alias, startup->index_file_name, genvpath(lib,dir,str)
,mode);
credits=FALSE;
tmpfile=TRUE;
delfile=TRUE;
fprintf(fp,"%-*s File/Folder Descriptions\r\n"
,INDEX_FNAME_LEN,startup->index_file_name);
if(lib<0) {
/* File Aliases */
sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
while(!feof(alias_fp)) {
if(!fgets(aliasline,sizeof(aliasline),alias_fp))
break;
p=aliasline; /* alias pointer */
SKIP_WHITESPACE(p);
if(*p==';') /* comment */
continue;
tp=p; /* terminator pointer */
FIND_WHITESPACE(tp);
if(*tp) *tp=0;
np=tp+1; /* filename pointer */
SKIP_WHITESPACE(np);
np++; /* description pointer */
FIND_WHITESPACE(np);
while(*np && *np<' ') np++;
truncsp(np);
fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN,p,np);
}
fclose(alias_fp);
}
/* QWK Packet */
if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) {
sprintf(str,"%s.qwk",scfg.sys_id);
fprintf(fp,"%-*s QWK Message Packet\r\n"
,INDEX_FNAME_LEN,str);
}
/* Library Folders */
for(i=0;i<scfg.total_libs;i++) {
continue;
fprintf(fp,"%-*s %s\r\n"
,INDEX_FNAME_LEN,scfg.lib[i]->sname,scfg.lib[i]->lname);
}
} else if(dir<0) {
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=lib)
continue;
if(i!=(int)scfg.sysop_dir && i!=(int)scfg.upload_dir
continue;
fprintf(fp,"%-*s %s\r\n"
,INDEX_FNAME_LEN,scfg.dir[i]->code_suffix,scfg.dir[i]->lname);
}
} else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user,&client)){
smb_t smb;
if((result = smb_open_dir(&scfg, &smb, dir)) != SMB_SUCCESS) {
lprintf(LOG_ERR, "ERROR %d (%s) opening %s", result, smb.last_error, smb.file);
continue;
}
time_t start = time(NULL);
size_t file_count = 0;
file_t* file_list = loadfiles(&smb
,/* filespec */NULL, /* time: */0, file_detail_normal, scfg.dir[dir]->sort, &file_count);
for(size_t i = 0; i < file_count; i++) {
file_t* f = &file_list[i];
fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN
,f->name, f->desc);
lprintf(LOG_INFO, "%04d <%s> index (%ld bytes) of /%s/%s (%lu files) created in %ld seconds"
,sock, user.alias, ftell(fp), scfg.lib[lib]->sname, scfg.dir[dir]->code_suffix
,(ulong)file_count, (long)time(NULL) - start);
freefiles(file_list, file_count);
smb_close(&smb);
fclose(fp);
}
} else if(dir>=0) {
lprintf(LOG_WARNING,"%04d <%s> has insufficient access to /%s/%s"
,sock,user.alias
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix);
filepos=0;
continue;
}

rswindell
committed
if(!getsize && !getdate && !delecmd
lprintf(LOG_WARNING,"%04d <%s> has insufficient access to download from /%s/%s"
,sock,user.alias
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix);
filepos=0;
continue;
}

rswindell
committed
if(delecmd && !dir_op(&scfg,&user,&client,dir) && !(user.exempt&FLAG('R'))) {
lprintf(LOG_WARNING,"%04d <%s> has insufficient access to delete files in /%s/%s"
,sock,user.alias
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix);

rswindell
committed
filepos=0;
continue;
}
SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p);
filedat=findfile(&scfg, dir, p, NULL);
if(!filedat) {
lprintf(LOG_WARNING,"%04d <%s> file (%s%s) not in database for %.4s command"
,sock,user.alias,genvpath(lib,dir,str),p,cmd);
filepos=0;
continue;
}

rswindell
committed
/* Verify credits */
if(!getsize && !getdate && !delecmd
loadfile(&scfg, dir, p, &f, file_detail_normal);
f.cost=(uint32_t)flength(fname);
if(f.cost>(user.cdt+user.freecdt)) {
lprintf(LOG_WARNING,"%04d <%s> has insufficient credit to download /%s/%s/%s (%lu credits)"
,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix
,(ulong)f.cost);
sockprintf(sock,sess,"550 Insufficient credit (%lu required).", (ulong)f.cost);
smb_freefilemem(&f);
smb_freefilemem(&f);
}
if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) {
success=FALSE;
lprintf(LOG_WARNING,"%04d <%s> !ILLEGAL FILENAME ATTEMPT by %s [%s]: %s"
,sock, user.alias, host_name, host_ip, p);
ftp_hacklog("FTP FILENAME", user.alias, cmd, host_name, &ftp.client_addr);
if(fexistcase(fname)) {

rswindell
committed
if(!getsize && !getdate && !delecmd)
lprintf(LOG_INFO,"%04d <%s> downloading: %s (%"PRIuOFF" bytes) in %s mode"
,sock,user.alias,fname,flength(fname)
,mode);
#if defined(SOCKET_DEBUG_DOWNLOAD)
socket_debug[sock]|=SOCKET_DEBUG_DOWNLOAD;
if(getsize && success)
else if(getdate && success) {
if(file_date==0)
file_date = fdate(fname);
if(gmtime_r(&file_date,&tm)==NULL) /* specifically use GMT/UTC representation */
,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday
,tm.tm_hour,tm.tm_min,tm.tm_sec);

rswindell
committed
} else if(delecmd && success) {
if(removecase(fname)!=0) {
lprintf(LOG_ERR,"%04d <%s> !ERROR %d (%s) deleting %s", sock, user.alias, errno, strerror(errno), fname);
sockprintf(sock,sess,"450 %s could not be deleted (error: %d)"

rswindell
committed
,fname,errno);
} else {
lprintf(LOG_NOTICE,"%04d <%s> deleted %s",sock,user.alias,fname);

rswindell
committed
if(filedat)
removefile(&scfg, dir, getfname(fname));

rswindell
committed
}
sockprintf(sock,sess,"150 Opening BINARY mode data connection for file transfer.");
filexfer(&data_addr,sock,sess,pasv_sock,pasv_sess,&data_sock,&data_sess,fname,filepos
,&transfer_inprogress,&transfer_aborted,delfile,tmpfile
,&lastactive,&user,&client,dir,FALSE,credits,FALSE,NULL,protection);
lprintf(LOG_WARNING,"%04d <%s> file (%s%s) not found for %.4s command"
,sock,user.alias,genvpath(lib,dir,str),p,cmd);
#if defined(SOCKET_DEBUG_DOWNLOAD)
socket_debug[sock]&=~SOCKET_DEBUG_DOWNLOAD;
continue;
}
if(!strnicmp(cmd, "DESC", 4)) {
if(user.rest&FLAG('U')) {
continue;
}
p=cmd+4;
SKIP_WHITESPACE(p);
sockprintf(sock,sess,"200 File description set. Ready to STOR file.");
if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) {
if(user.rest&FLAG('U')) {
continue;
}
if(transfer_inprogress==TRUE) {
lprintf(LOG_WARNING,"%04d <%s> !TRANSFER already in progress (%s)",sock, user.alias, cmd);
lib=curlib;
dir=curdir;
p=cmd+5;
SKIP_WHITESPACE(p);
if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR)))
p+=strlen(BBS_FSYS_DIR); /* already mounted */
if(*p=='/') {
lib=-1;
p++;
}
else if(!strncmp(p,"./",2))
p+=2;
/* Need to add support for uploading to aliased directories */
if(lib<0 && (tp=strchr(p,'/'))!=NULL) {
dir=-1;
*tp=0;
for(i=0;i<scfg.total_libs;i++) {
continue;
if(!stricmp(scfg.lib[i]->sname,p))
break;
}
if(i<scfg.total_libs)
lib=i;
p=tp+1;
}
if(dir<0 && (tp=strchr(p,'/'))!=NULL) {
*tp=0;
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=lib)
continue;
if(i!=(int)scfg.sysop_dir && i!=(int)scfg.upload_dir
if(!stricmp(scfg.dir[i]->code_suffix,p))
break;
}
if(i<scfg.total_dirs)
dir=i;
p=tp+1;
}
if(dir<0) {
sprintf(str,"%s.rep",scfg.sys_id);
if(!(startup->options&FTP_OPT_ALLOW_QWK)
|| stricmp(p,str)) {
lprintf(LOG_WARNING,"%04d <%s> !attempted to upload to invalid directory"

rswindell
committed
sprintf(fname,"%sfile/%04d.rep",scfg.data_dir,user.number);
lprintf(LOG_INFO,"%04d <%s> uploading: %s in %s mode"
,sock,user.alias,fname
,mode);
append=(strnicmp(cmd,"APPE",4)==0);
if(!dir_op(&scfg,&user,&client,dir) && !(user.exempt&FLAG('U'))) {
if(!chk_ar(&scfg,scfg.dir[dir]->ul_ar,&user,&client)) {
lprintf(LOG_WARNING,"%04d <%s> cannot upload to /%s/%s (insufficient access)"
,sock,user.alias
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix);
continue;
}
if(!append && scfg.dir[dir]->maxfiles && getfiles(&scfg,dir)>=scfg.dir[dir]->maxfiles) {
lprintf(LOG_WARNING,"%04d <%s> cannot upload to /%s/%s (directory full: %ld files)"
,sock,user.alias
,scfg.lib[scfg.dir[dir]->lib]->sname
,scfg.dir[dir]->code_suffix
,getfiles(&scfg,dir));
continue;
}
if(*p=='-'
|| strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)
|| trashcan(&scfg,p,"file")) {
lprintf(LOG_WARNING,"%04d <%s> !ILLEGAL FILENAME ATTEMPT by %s [%s]: %s"
,sock, user.alias, host_name, host_ip, p);
ftp_hacklog("FTP FILENAME", user.alias, cmd, host_name, &ftp.client_addr);
SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p);
if((!append && filepos==0 && fexist(fname))
|| (startup->options&FTP_OPT_INDEX_FILE
&& !stricmp(p,startup->index_file_name))
) {
lprintf(LOG_WARNING,"%04d <%s> attempted to overwrite existing file: %s"
if(append || filepos) { /* RESUME */
file_t f;
if(!loadfile(&scfg, dir, p, &f, file_detail_normal)) {
lprintf(LOG_WARNING,"%04d <%s> file (%s) not in database for %.4s command"
,sock,user.alias,fname,cmd);
continue;
}
append=FALSE;
}
/* Verify user is original uploader */
if((append || filepos) && stricmp(f.from, user.alias)) {
lprintf(LOG_WARNING,"%04d <%s> !cannot resume upload of %s, uploaded by %s"
,sock,user.alias,fname,f.from);
sockprintf(sock,sess,"553 Insufficient access (can't resume upload from different user).");
smb_freefilemem(&f);
smb_freefilemem(&f);
lprintf(LOG_INFO,"%04d <%s> uploading: %s to %s (%s) in %s mode"
,sock,user.alias
,p /* filename */
,genvpath(lib,dir,str) /* virtual path */
,scfg.dir[dir]->path /* actual path */
,mode);
sockprintf(sock,sess,"150 Opening BINARY mode data connection for file transfer.");
filexfer(&data_addr,sock,sess,pasv_sock,pasv_sess,&data_sock,&data_sess,fname,filepos
,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
,&lastactive
,&user
,dir
,TRUE /* uploading */
,TRUE /* credits */
);
filepos=0;
continue;
}
if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
if(curdir<0)
curlib=-1;
else
curdir=-1;
continue;
}
if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
p=cmd+4;
SKIP_WHITESPACE(p);
if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR)))
p+=strlen(BBS_FSYS_DIR); /* already mounted */
if(*p=='/') {
curlib=-1;
curdir=-1;
p++;
}
/* Local File System? */
if(sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)
&& !strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) {
p+=strlen(LOCAL_FSYS_DIR);
if(!direxist(p)) {
lprintf(LOG_WARNING,"%04d <%s> attempted to mount invalid directory: %s"
,sock, user.alias, p);
continue;
}
sockprintf(sock,sess,"250 CWD command successful (local file system mounted).");
lprintf(LOG_INFO,"%04d <%s> mounted local file system", sock, user.alias);
continue;
}
success=FALSE;
/* Directory Alias? */
if(curlib<0 && ftpalias(p,NULL,&user,&client,&curdir)==TRUE) {
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
if(curdir>=0)
curlib=scfg.dir[curdir]->lib;
success=TRUE;
}
orglib=curlib;
orgdir=curdir;
tp=0;
if(!strncmp(p,"...",3)) {
curlib=-1;
curdir=-1;
p+=3;
}
if(!strncmp(p,"./",2))
p+=2;
else if(!strncmp(p,"..",2)) {
if(curdir<0)
curlib=-1;
else
curdir=-1;
p+=2;
}
if(*p==0)
success=TRUE;
else if(!strcmp(p,"."))
success=TRUE;
if(!success && (curlib<0 || *p=='/')) { /* Root dir */
if(*p=='/') p++;
tp=strchr(p,'/');
if(tp) *tp=0;
for(i=0;i<scfg.total_libs;i++) {
continue;
if(!stricmp(scfg.lib[i]->sname,p))
break;
}
if(i<scfg.total_libs) {
curlib=i;
success=TRUE;
}
}
if((!success && curdir<0) || (success && tp && *(tp+1))) {
if(tp)
p=tp+1;
tp=lastchar(p);
if(tp && *tp=='/') *tp=0;
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=curlib)
continue;
if(i!=(int)scfg.sysop_dir && i!=(int)scfg.upload_dir
if(!stricmp(scfg.dir[i]->code_suffix,p))
break;
}
if(i<scfg.total_dirs) {
curdir=i;
success=TRUE;
} else
success=FALSE;
}
if(success)
sockprintf(sock,sess,"550 %s: No such directory.",p);
curlib=orglib;
curdir=orgdir;
}
continue;
}
if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
if(curlib<0)
,scfg.lib[curlib]->sname);
else
,scfg.lib[curlib]->sname
,scfg.dir[curdir]->code_suffix);
if(!strnicmp(cmd, "MKD", 3) ||
!strnicmp(cmd,"XMKD",4) ||
!strnicmp(cmd,"SITE EXEC",9)) {
lprintf(LOG_WARNING,"%04d <%s> !SUSPECTED HACK ATTEMPT: %s"
,sock,user.alias,cmd);
ftp_hacklog("FTP", user.alias, cmd, host_name, &ftp.client_addr);
// TODO: STAT is mandatory
lprintf(LOG_WARNING,"%04d <%s> !UNSUPPORTED COMMAND: %s"
,sock,user.alias,cmd);
} /* while(1) */
#if defined(SOCKET_DEBUG_TERMINATE)
socket_debug[sock]|=SOCKET_DEBUG_TERMINATE;
#endif
if(transfer_inprogress==TRUE) {
lprintf(LOG_DEBUG,"%04d Waiting for transfer to complete...",sock);
while(transfer_inprogress==TRUE) {
mswait(2000); /* allow xfer threads to terminate */
break;
}

rswindell
committed
if(!transfer_aborted) {
if(gettimeleft(&scfg,&user,logintime)<1) {
lprintf(LOG_WARNING,"%04d Out of time, disconnecting",sock);
sockprintf(sock,sess,"421 Sorry, you've run out of time.");
ftp_close_socket(&data_sock,&data_sess,__LINE__);

rswindell
committed
transfer_aborted=TRUE;
}
if((time(NULL)-lastactive)>startup->max_inactivity) {
lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock);
sockprintf(sock,sess,"421 Disconnecting due to inactivity (%u seconds)."

rswindell
committed
,startup->max_inactivity);

rswindell
committed
transfer_aborted=TRUE;
}
if(count && (count%60)==0)
lprintf(LOG_WARNING,"%04d Still waiting for transfer to complete "
"(count=%lu, aborted=%d, lastactive=%lX) ..."
,sock,count,transfer_aborted,lastactive);
count++;
mswait(1000);
lprintf(LOG_DEBUG,"%04d Done waiting for transfer to complete",sock);
if(user.number) {
/* Update User Statistics */
if(!logoutuserdat(&scfg, &user, time(NULL), logintime))
lprintf(LOG_ERR,"%04d <%s> !ERROR in logoutuserdat", sock, user.alias);
lprintf(LOG_INFO,"%04d <%s> logged off", sock, user.alias);
if(startup->hangup_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
/* status(STATUS_WFC); server thread should control status display */
if(pasv_sock!=INVALID_SOCKET)
if(data_sock!=INVALID_SOCKET)
client_off(sock);
socket_debug[sock]&=~SOCKET_DEBUG_CTRL;
#if defined(SOCKET_DEBUG_TERMINATE)
socket_debug[sock]&=~SOCKET_DEBUG_TERMINATE;
#endif
tmp_sock=sock;
int32_t clients = protected_uint32_adjust_fetch(&active_clients, -1);
int32_t threads = thread_down();
update_clients();
lprintf(LOG_INFO,"%04d CTRL thread terminated (%d clients and %d threads remain, %lu served)"
,sock, clients, threads, served);
lprintf(LOG_DEBUG,"0000 cleanup called from line %d",line);
if(protected_uint32_value(thread_count) > 1) {
lprintf(LOG_INFO, "0000 Waiting for %d child threads to terminate", protected_uint32_value(thread_count)-1);
while(protected_uint32_value(thread_count) > 1) {
mswait(100);
}
lprintf(LOG_INFO, "0000 Done waiting for child threads to terminate");
}
free_text(text);
semfile_list_free(&recycle_semfiles);
semfile_list_free(&shutdown_semfiles);
if(ftp_set != NULL) {
xpms_destroy(ftp_set, ftp_close_socket_cb, NULL);
ftp_set = NULL;
}
update_clients(); /* active_clients is destroyed below */
listFree(¤t_connections);
if(protected_uint32_value(active_clients))
lprintf(LOG_WARNING,"!!!! Terminating with %d active clients", protected_uint32_value(active_clients));
protected_uint32_destroy(active_clients);
#ifdef _WINSOCKAPI_
if(WSAInitialized && WSACleanup()!=0)
lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
if(terminate_server || code)
lprintf(LOG_INFO,"#### FTP Server thread terminated (%lu clients served)", served);
if(startup!=NULL && startup->terminated!=NULL)
startup->terminated(startup->cbdata,code);
{
static char ver[256];
char compiler[32];
safe_snprintf(ver, sizeof(ver), "%s %s%c%s "
"Compiled %s/%s %s %s with %s"
,VERSION, REVISION
#ifdef _DEBUG
," Debug"
#else
,""
#endif
,GIT_BRANCH, GIT_HASH
,__DATE__, __TIME__, compiler);
return(ver);
}
char* p;
char path[MAX_PATH+1];
char error[256];
char str[256];
socklen_t client_addr_len;
SOCKET client_socket;
int i;
time_t t;
time_t start;
time_t initialized=0;
startup=(ftp_startup_t*)arg;
SetThreadName("sbbs/ftpServer");
#ifdef _THREAD_SUID_BROKEN
if(thread_suid_broken)
startup->seteuid(TRUE);
#endif
sbbs_beep(100,500);
fprintf(stderr, "No startup structure passed!\n");
return;
}
if(startup->size!=sizeof(ftp_startup_t)) { /* verify size */
sbbs_beep(100,500);
sbbs_beep(300,500);
sbbs_beep(100,500);
fprintf(stderr, "Invalid startup structure!\n");
return;
}
uptime=0;
served=0;
startup->recycle_now=FALSE;
startup->shutdown_now=FALSE;
terminate_server=FALSE;
protected_uint32_init(&thread_count, 0);
listInit(¤t_connections, LINK_LIST_MUTEX);
protected_uint32_init(&active_clients, 0);
/* Setup intelligent defaults */
if(startup->port==0) startup->port=IPPORT_FTP;
if(startup->qwk_timeout==0) startup->qwk_timeout=FTP_DEFAULT_QWK_TIMEOUT; /* seconds */
if(startup->max_inactivity==0) startup->max_inactivity=FTP_DEFAULT_MAX_INACTIVITY; /* seconds */
if(startup->sem_chk_freq==0) startup->sem_chk_freq=DEFAULT_SEM_CHK_FREQ; /* seconds */
if(startup->index_file_name[0]==0) SAFECOPY(startup->index_file_name,"00index");
(void)protected_uint32_adjust(&thread_count,1);
thread_up(FALSE /* setuid */);
status("Initializing");
memset(&scfg, 0, sizeof(scfg));
lprintf(LOG_INFO,"Synchronet FTP Server Version %s%c%s"
,VERSION, REVISION
#ifdef _DEBUG
," Debug"
lprintf(LOG_INFO,"Compiled %s/%s %s %s with %s", GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, compiler);
sbbs_srand(); /* Seed random number generator */

rswindell
committed
if(!winsock_startup()) {
break;

rswindell
committed
}
t=time(NULL);
lprintf(LOG_INFO,"Initializing on %.24s with options: %x"
if(chdir(startup->ctrl_dir)!=0)