Newer
Older
SAFEPRINTF(path,"%s*",scfg.dir[dir]->path);
rc=JS_SUSPENDREQUEST(js_cx);
glob(path,0,NULL,&g);
for(i=0;i<(int)g.gl_pathc;i++) {
if(isdir(g.gl_pathv[i]))
continue;
#ifdef _WIN32
GetShortPathName(g.gl_pathv[i], str, sizeof(str));
#else
SAFECOPY(str,g.gl_pathv[i]);
#endif
padfname(getfname(str),f.name);
f.dir=dir;
if(getfileixb(&scfg,&f)) {
f.size=0; /* flength(g.gl_pathv[i]); */
getfiledat(&scfg,&f);
if(f.misc&FM_EXTDESC) {
extdesc[0]=0;
getextdesc(&scfg, dir, f.datoffset, extdesc);
/* Remove Ctrl-A Codes and Ex-ASCII code */
SAFEPRINTF3(vpath,"/%s/%s/%s"
,scfg.dir[dir]->code_suffix
JS_RESUMEREQUEST(js_cx, rc);
js_add_file(js_cx
,file_array
,getfname(g.gl_pathv[i]) /* filename */
,f.desc /* description */
,f.misc&FM_EXTDESC ? extdesc : NULL
,f.size /* size */
,f.cdt /* credits */
,f.date /* time */
,f.dateuled /* uploaded */
,f.datedled /* last downloaded */
,f.timesdled /* times downloaded */
,f.misc /* misc */
,getfname(g.gl_pathv[i]) /* link */
rc=JS_SUSPENDREQUEST(js_cx);
JS_RESUMEREQUEST(js_cx, rc);
JS_ClearPendingException(js_cx);
if((js_script=JS_CompileFile(js_cx, parent, spath))==NULL) {
lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)",sock,spath);
js_PrepareToExecute(js_cx, parent, spath, /* startup_dir: */NULL, parent);
if((success=JS_ExecuteScript(js_cx, parent, js_script, &rval))!=TRUE) {
lprintf(LOG_ERR,"%04d !JavaScript FAILED to execute script (%s)",sock,spath);
lprintf(LOG_DEBUG,"%04d JavaScript: Done executing script: %s (%.2Lf seconds)"
,sock,spath,xp_timer()-start);
JS_DeleteProperty(js_cx, parent, "path");
JS_DeleteProperty(js_cx, parent, "sort");
JS_DeleteProperty(js_cx, parent, "reverse");
JS_DeleteProperty(js_cx, parent, "file_list");
JS_DeleteProperty(js_cx, parent, "dir_list");
JS_DeleteProperty(js_cx, parent, "curlib");
JS_DeleteProperty(js_cx, parent, "curdir");
JS_DeleteProperty(js_cx, parent, "html_index_file");
#endif /* ifdef JAVASCRIPT */
BOOL upload_stats(ulong bytes)
{
char str[MAX_PATH+1];

rswindell
committed
sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
if((file=nopen(str,O_RDWR))==-1)
return(FALSE);
lseek(file,20L,SEEK_SET); /* Skip timestamp, logons and logons today */
read(file,&val,4); /* Uploads today */
val++;
lseek(file,-4L,SEEK_CUR);
write(file,&val,4);
read(file,&val,4); /* Upload bytes today */
val+=bytes;
lseek(file,-4L,SEEK_CUR);
write(file,&val,4);
close(file);
return(TRUE);
}
BOOL download_stats(ulong bytes)
{
char str[MAX_PATH+1];

rswindell
committed
sprintf(str,"%sdsts.dab",scfg.ctrl_dir);
if((file=nopen(str,O_RDWR))==-1)
return(FALSE);
lseek(file,28L,SEEK_SET); /* Skip timestamp, logons and logons today */
read(file,&val,4); /* Downloads today */
val++;
lseek(file,-4L,SEEK_CUR);
write(file,&val,4);
read(file,&val,4); /* Download bytes today */
val+=bytes;
lseek(file,-4L,SEEK_CUR);
write(file,&val,4);
close(file);
return(TRUE);
}
void recverror(SOCKET socket, int rd, int line)
lprintf(LOG_NOTICE,"%04d Socket closed by peer on receive (line %u)"
lprintf(LOG_NOTICE,"%04d Connection reset by peer on receive (line %u)"
lprintf(LOG_NOTICE,"%04d Connection aborted by peer on receive (line %u)"
lprintf(LOG_NOTICE,"%04d !ERROR %d receiving on socket (line %u)"
lprintf(LOG_WARNING,"%04d !ERROR: recv on socket returned unexpected value: %d (line %u)"
static int sock_recvbyte(SOCKET sock, CRYPT_SESSION sess, char *buf, time_t *lastactive)

rswindell
committed
fd_set socket_set;
if(ftp_set==NULL || terminate_server) {
sockprintf(sock,sess,"421 Server downed, aborting.");
lprintf(LOG_WARNING,"%04d Server downed, aborting",sock);
return(0);
}
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
if (sess > -1) {
/* Try a read with no timeout first. */
cryptSetAttribute(sess, CRYPT_OPTION_NET_READTIMEOUT, 0);
while (1) {
ret = cryptPopData(sess, buf, 1, &len);
/* Successive reads will be with the full timeout after a select() */
cryptSetAttribute(sess, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity);
switch(ret) {
case CRYPT_OK:
break;
case CRYPT_ERROR_TIMEOUT:
lprintf(LOG_WARNING,"%04d !TIMEOUT in sock_recvbyte (%u seconds): INACTIVE SOCKET",sock,startup->max_inactivity);
return -1;
case CRYPT_ERROR_COMPLETE:
return 0;
default:
lprintf(LOG_WARNING,"%04d !Cryptlib error in sock_recvbyte: %d",sock,ret);
if (ret < -1)
return ret;
return -2;
}
if (len)
return len;
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)."
,startup->max_inactivity);
return(0);
}

rswindell
committed

rswindell
committed

rswindell
committed

rswindell
committed
if(i<1) {
if(i==0) {
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)."
,startup->max_inactivity);
return(0);
}
continue;
}
recverror(sock,i,__LINE__);
return(i);
}
}
else {
while (1) {
tv.tv_sec=startup->max_inactivity;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(sock,&socket_set);
i=select(sock+1,&socket_set,NULL,NULL,&tv);
if(i<1) {
if(i==0) {
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)."
,startup->max_inactivity);
return(0);
}
continue;
#ifdef SOCKET_DEBUG_RECV_CHAR
socket_debug[sock]|=SOCKET_DEBUG_RECV_CHAR;
#endif
i=recv(sock, buf, 1, 0);
#ifdef SOCKET_DEBUG_RECV_CHAR
socket_debug[sock]&=~SOCKET_DEBUG_RECV_CHAR;
#endif
return i;
}
}
int sockreadline(SOCKET socket, CRYPT_SESSION sess, char* buf, int len, time_t* lastactive)
{
char ch;
int i,rd=0;
buf[0]=0;
if(socket==INVALID_SOCKET) {
lprintf(LOG_WARNING,"INVALID SOCKET in call to sockreadline");
return(0);
}
while(rd<len-1) {
i = sock_recvbyte(socket, sess, &ch, lastactive);

rswindell
committed
return(i);
}
if(ch=='\n' /* && rd>=1 */) { /* Mar-9-2003: terminate on sole LF */
break;
}
buf[rd++]=ch;
}
if(rd>0 && buf[rd-1]=='\r')
buf[rd-1]=0;
else
buf[rd]=0;
void DLLCALL ftp_terminate(void)
terminate_server=TRUE;
int ftp_remove(SOCKET sock, int line, const char* fname)
{
int ret=0;
if(fexist(fname) && (ret=remove(fname))!=0) {
if(fexist(fname)) // In case there was a race condition (other host deleted file first)
lprintf(LOG_ERR,"%04d !ERROR %d (%s) (line %d) removing file: %s", sock, errno, STRERROR(errno), line, fname);
}
return ret;
}
BOOL* inprogress;
BOOL* aborted;
BOOL delfile;
BOOL tmpfile;
BOOL credits;
BOOL append;
long filepos;
char filename[MAX_PATH+1];
time_t* lastactive;
user_t* user;
client_t* client;
int dir;
char* desc;
} xfer_t;
static void send_thread(void* arg)
{
char buf[8192];
char fname[MAX_PATH+1];
char str[128];
char username[128];
long mod;
ulong l;
ulong last_total=0;
ulong dur;
ulong cps;
ulong length;
BOOL error=FALSE;
FILE* fp;
file_t f;
xfer_t xfer;
time_t now;
time_t start;
time_t last_report;
socklen_t addr_len;
fd_set socket_set;
struct timeval tv;
free(arg);
SetThreadName("sbbs/ftpSend");
thread_up(TRUE /* setuid */);
length=flength(xfer.filename);
if((fp=fnopen(NULL,xfer.filename,O_RDONLY|O_BINARY))==NULL /* non-shareable open failed */
&& (fp=fopen(xfer.filename,"rb"))==NULL) { /* shareable open failed */
lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"450 ERROR %d opening %s.",errno,xfer.filename);
if(xfer.tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename);
thread_down();
#ifdef SOCKET_DEBUG_SENDTHREAD
socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SENDTHREAD;
#endif
if(startup->options&FTP_OPT_DEBUG_DATA || xfer.filepos)
lprintf(LOG_DEBUG,"%04d DATA socket %d sending %s from offset %lu"
,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos);
fseek(fp,xfer.filepos,SEEK_SET);
last_report=start=time(NULL);
while((xfer.filepos+total)<length) {
/* Periodic progress report */
if(total && now>=last_report+XFER_REPORT_INTERVAL) {
if(xfer.filepos)
sprintf(str," from offset %lu",xfer.filepos);
else
str[0]=0;
lprintf(LOG_INFO,"%04d Sent %lu bytes (%lu total) of %s (%lu cps)%s"
,xfer.ctrl_sock,total,length,xfer.filename
,(ulong)((total-last_total)/(now-last_report))
,str);
last_total=total;
last_report=now;
}
lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 Transfer aborted.");
error=TRUE;
break;
}
lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 Transfer locally aborted.");
error=TRUE;
break;
}
/* Check socket for writability (using select) */
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(*xfer.data_sock,&socket_set);
i=select((*xfer.data_sock)+1,NULL,&socket_set,NULL,&tv);
if(i==SOCKET_ERROR) {
lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for send"
,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 Transfer error.");
error=TRUE;
break;
}
fseek(fp,xfer.filepos+total,SEEK_SET);
rd=fread(buf,sizeof(char),sizeof(buf),fp);
socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SEND;
#endif
if (*xfer.data_sess != -1) {
int status = cryptPushData(*xfer.data_sess, buf, rd, &wr);
if (status != CRYPT_OK) {
lprintf(LOG_DEBUG, "PushData() returned %d\n", status);
wr = -1;
}
else {
status = cryptFlushData(*xfer.data_sess);
if (status != CRYPT_OK) {
lprintf(LOG_DEBUG, "cryptFlushData() returned %d\n", status);
wr = -1;
}
}
}
else
wr=sendsocket(*xfer.data_sock,buf,rd);
socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SEND;
#endif
if(ERROR_VALUE==EWOULDBLOCK) {
/*lprintf(LOG_WARNING,"%04d DATA send would block, retrying",xfer.ctrl_sock);*/
YIELD();
continue;
}
else if(ERROR_VALUE==ECONNRESET)
lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, sending on socket %d"
,xfer.ctrl_sock,*xfer.data_sock);
lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, sending on socket %d"
lprintf(LOG_WARNING,"%04d !DATA ERROR %d sending on data socket %d"
,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);
/* Send NAK */
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 Error %d sending on DATA channel"
,ERROR_VALUE);
error=TRUE;
break;
}
if(wr==0) {
lprintf(LOG_WARNING,"%04d !DATA socket %d disconnected",xfer.ctrl_sock, *xfer.data_sock);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"426 DATA channel disconnected");
error=TRUE;
break;
}
lprintf(LOG_ERR,"%04d !DATA SEND ERROR %d (%d) on socket %d"
,xfer.ctrl_sock, wr, ERROR_VALUE, *xfer.data_sock);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"451 DATA send error");
error=TRUE;
break;
}
total+=wr;
*xfer.lastactive=time(NULL);
//YIELD();
if((i=ferror(fp))!=0)
lprintf(LOG_ERR,"%04d !FILE ERROR %d (%d)",xfer.ctrl_sock,i,errno);
ftp_close_socket(xfer.data_sock,xfer.data_sess,__LINE__); /* Signal end of file */
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d DATA socket closed",xfer.ctrl_sock);
dur=(long)(time(NULL)-start);
cps=dur ? total/dur : total*2;
lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes sent in %lu seconds (%lu cps)"
,xfer.ctrl_sock
,total,dur,cps);
sockprintf(xfer.ctrl_sock,xfer.ctrl_sess,"226 Download complete (%lu cps).",cps);
if(xfer.dir>=0) {
memset(&f,0,sizeof(f));
GetShortPathName(xfer.filename,fname,sizeof(fname));
SAFECOPY(fname,xfer.filename);
#endif
padfname(getfname(fname),f.name);
f.dir=xfer.dir;
f.size=total;
if(getfileixb(&scfg,&f)==TRUE && getfiledat(&scfg,&f)==TRUE) {
f.timesdled++;
putfiledat(&scfg,&f);
f.datedled=time32(NULL);
putfileixb(&scfg,&f);
lprintf(LOG_INFO,"%04d %s downloaded: %s (%lu times total)"
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
,xfer.ctrl_sock
,xfer.user->alias
,xfer.filename
,f.timesdled);
/**************************/
/* Update Uploader's Info */
/**************************/
uploader.number=matchuser(&scfg,f.uler,TRUE /*sysop_alias*/);
if(uploader.number
&& uploader.number!=xfer.user->number
&& getuserdat(&scfg,&uploader)==0
&& uploader.firston<f.dateuled) {
l=f.cdt;
if(!(scfg.dir[f.dir]->misc&DIR_CDTDL)) /* Don't give credits on d/l */
l=0;
if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) { /* Give min instead of cdt */
mod=((ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0))/cps)/60;
adjustuserrec(&scfg,uploader.number,U_MIN,10,mod);
sprintf(tmp,"%lu minute",mod);
} else {
mod=(ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0));
adjustuserrec(&scfg,uploader.number,U_CDT,10,mod);
ultoac(mod,tmp);
}
if(!(scfg.dir[f.dir]->misc&DIR_QUIET)) {
addr_len = sizeof(addr);
if(uploader.level>=SYSOP_LEVEL
&& getpeername(xfer.ctrl_sock,&addr.addr,&addr_len)==0
&& inet_addrtop(&addr, host_ip, sizeof(host_ip))!=NULL)
SAFEPRINTF2(username,"%s [%s]",xfer.user->alias,host_ip);
else
SAFECOPY(username,xfer.user->alias);
/* Inform uploader of downloaded file */
safe_snprintf(str,sizeof(str),text[DownloadUserMsg]
,getfname(xfer.filename)
,xfer.filepos ? "partially FTP-" : "FTP-"
,username,tmp);
putsmsg(&scfg,uploader.number,str);
}
if(!xfer.tmpfile && !xfer.delfile && !(scfg.dir[f.dir]->misc&DIR_NOSTAT))
download_stats(total);
}
if(xfer.credits) {
user_downloaded(&scfg, xfer.user, 1, total);
if(xfer.dir>=0 && !is_download_free(&scfg,xfer.dir,xfer.user,xfer.client))
subtract_cdt(&scfg, xfer.user, xfer.credits);
}
}
fclose(fp);
if(xfer.tmpfile) {
if(!(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename);
ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename);
#if defined(SOCKET_DEBUG_SENDTHREAD)
socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SENDTHREAD;
#endif
thread_down();
}
static void receive_thread(void* arg)
{
char* p;
char str[128];
char ext[F_EXBSIZE+1];
char desc[F_EXBSIZE+1];
char cmd[MAX_PATH*2];
char tmp[MAX_PATH+1];
char fname[MAX_PATH+1];
int rd;
int file;
ulong total=0;
ulong last_total=0;
ulong dur;
ulong cps;
BOOL error=FALSE;
FILE* fp;
file_t f;
xfer_t xfer;
time_t now;
time_t start;
time_t last_report;
fd_set socket_set;
struct timeval tv;
free(arg);
SetThreadName("sbbs/ftpReceive");
thread_up(TRUE /* setuid */);
if((fp=fopen(xfer.filename,xfer.append ? "ab" : "wb"))==NULL) {
lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename);
sockprintf(xfer.ctrl_sock,sess,"450 ERROR %d opening %s.",errno,xfer.filename);
ftp_close_socket(xfer.data_sock,xfer.data_sess,__LINE__);
thread_down();
if(xfer.append)
xfer.filepos=filelength(fileno(fp));

rswindell
committed
if(xfer.filepos || startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d DATA socket %d receiving %s from offset %lu"
,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos);
fseek(fp,xfer.filepos,SEEK_SET);
last_report=start=time(NULL);
while(1) {
now=time(NULL);
/* Periodic progress report */
if(total && now>=last_report+XFER_REPORT_INTERVAL) {
if(xfer.filepos)
sprintf(str," from offset %lu",xfer.filepos);
else
str[0]=0;
lprintf(LOG_INFO,"%04d Received %lu bytes of %s (%lu cps)%s"
,xfer.ctrl_sock,total,xfer.filename
,(ulong)((total-last_total)/(now-last_report))
,str);
last_total=total;
if(startup->max_fsize && (xfer.filepos+total) > startup->max_fsize) {
lprintf(LOG_WARNING,"%04d !DATA received %lu bytes of %s exceeds maximum allowed (%lu bytes)"
,xfer.ctrl_sock, xfer.filepos+total, xfer.filename, startup->max_fsize);
sockprintf(xfer.ctrl_sock,sess,"552 File size exceeds maximum allowed (%lu bytes)", startup->max_fsize);
error=TRUE;
break;
}
lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock);

rswindell
committed
/* Send NAK */
error=TRUE;
break;
}
lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock);

rswindell
committed
/* Send NAK */
sockprintf(xfer.ctrl_sock,sess,"426 Transfer locally aborted.");
error=TRUE;
break;
}
/* Check socket for readability (using select) */
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(*xfer.data_sock,&socket_set);
i=select((*xfer.data_sock)+1,&socket_set,NULL,NULL,&tv);
if(i==SOCKET_ERROR) {
lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for receive"
,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock);
error=TRUE;
break;
}
#if defined(SOCKET_DEBUG_RECV_BUF)
socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_RECV_BUF;
if (*xfer.data_sess != -1) {
int status = cryptPopData(*xfer.data_sess, buf, sizeof(buf), &rd);
if (status != CRYPT_OK)
rd = -1;
}
else {
rd=recv(*xfer.data_sock,buf,sizeof(buf),0);
}
#if defined(SOCKET_DEBUG_RECV_BUF)
socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_RECV_BUF;
if(rd<1) {
if(rd==0) { /* Socket closed */
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d DATA socket %d closed by client"
,xfer.ctrl_sock,*xfer.data_sock);
break;
}
if(rd==SOCKET_ERROR) {
if(ERROR_VALUE==EWOULDBLOCK) {
/*lprintf(LOG_WARNING,"%04d DATA recv would block, retrying",xfer.ctrl_sock);*/
YIELD();
continue;
}
else if(ERROR_VALUE==ECONNRESET)
lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, receiving on socket %d"
,xfer.ctrl_sock,*xfer.data_sock);
lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, receiving on socket %d"
lprintf(LOG_WARNING,"%04d !DATA ERROR %d receiving on data socket %d"
,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock);

rswindell
committed
/* Send NAK */
sockprintf(xfer.ctrl_sock,sess,"426 Error %d receiving on DATA channel"
,ERROR_VALUE);
error=TRUE;
break;
}
lprintf(LOG_ERR,"%04d !DATA ERROR recv returned %d on socket %d"
,xfer.ctrl_sock,rd,*xfer.data_sock);

rswindell
committed
/* Send NAK */
sockprintf(xfer.ctrl_sock,sess,"451 Unexpected socket error: %d",rd);
error=TRUE;
break;
}
fwrite(buf,1,rd,fp);
total+=rd;
*xfer.lastactive=time(NULL);
YIELD();

rswindell
committed
fclose(fp);
if(error && startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d DATA socket %d closed",xfer.ctrl_sock,*xfer.data_sock);
if(xfer.filepos+total < startup->min_fsize) {
lprintf(LOG_WARNING,"%04d DATA received %lu bytes for %s, less than minimum required (%lu bytes)"
,xfer.ctrl_sock, xfer.filepos+total, xfer.filename, startup->min_fsize);
sockprintf(xfer.ctrl_sock,sess,"550 File size less than minimum required (%lu bytes)"
,startup->min_fsize);
error=TRUE;
}
if(error) {
if(!xfer.append)
ftp_remove(xfer.ctrl_sock, __LINE__, xfer.filename);
} else {
dur=(long)(time(NULL)-start);
cps=dur ? total/dur : total*2;
lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes received in %lu seconds (%lu cps)"
,xfer.ctrl_sock
,total,dur,cps);
if(xfer.dir>=0) {
memset(&f,0,sizeof(f));
GetShortPathName(xfer.filename,fname,sizeof(fname));
SAFECOPY(fname,xfer.filename);
#endif
padfname(getfname(fname),f.name);
filedat=getfileixb(&scfg,&f);
if(scfg.dir[f.dir]->misc&DIR_AONLY) /* Forced anonymous */
f.misc|=FM_ANON;
f.cdt=flength(xfer.filename);
f.dateuled=time32(NULL);
/* Description specified with DESC command? */
if(xfer.desc!=NULL && *xfer.desc!=0)
/* Necessary for DIR and LIB ARS keyword support in subsequent chk_ar()'s */
SAFECOPY(xfer.user->curdir, scfg.dir[f.dir]->code);
p=strrchr(f.name,'.');
if(p!=NULL && scfg.dir[f.dir]->misc&DIR_DIZ) {
for(i=0;i<scfg.total_fextrs;i++)
if(!stricmp(scfg.fextr[i]->ext,p+1)
&& chk_ar(&scfg,scfg.fextr[i]->ar,xfer.user,xfer.client))
break;
if(i<scfg.total_fextrs) {
sprintf(tmp,"%sFILE_ID.DIZ",scfg.temp_dir);
if(fexistcase(tmp))
ftp_remove(xfer.ctrl_sock, __LINE__, tmp);
cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"FILE_ID.DIZ",cmd);
lprintf(LOG_DEBUG,"%04d Extracting DIZ: %s",xfer.ctrl_sock,cmd);
system(cmd);
if(!fexistcase(tmp)) {
sprintf(tmp,"%sDESC.SDI",scfg.temp_dir);
if(fexistcase(tmp))
ftp_remove(xfer.ctrl_sock, __LINE__, tmp);
cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"DESC.SDI",cmd);
lprintf(LOG_DEBUG,"%04d Extracting DIZ: %s",xfer.ctrl_sock,cmd);
system(cmd);
fexistcase(tmp); /* fixes filename case */
}
if((file=nopen(tmp,O_RDONLY))!=-1) {
lprintf(LOG_DEBUG,"%04d Parsing DIZ: %s",xfer.ctrl_sock,tmp);
memset(ext,0,sizeof(ext));
read(file,ext,sizeof(ext)-1);
for(i=sizeof(ext)-1;i;i--) /* trim trailing spaces */
if(!f.desc[0]) { /* use for normal description */
strip_exascii(desc, desc); /* strip extended ASCII chars */
prep_file_desc(desc, desc); /* strip control chars and dupe chars */
for(i=0;desc[i];i++) /* find approprate first char */
if(isalnum(desc[i]))
break;
ftp_remove(xfer.ctrl_sock, __LINE__, tmp);
} else
lprintf(LOG_DEBUG,"%04d DIZ Does not exist: %s",xfer.ctrl_sock,tmp);
}
} /* FILE_ID.DIZ support */
if(f.desc[0]==0) /* no description given, use (long) filename */
SAFECOPY(f.uler,xfer.user->alias); /* exception here, Aug-27-2002 */
if(filedat) {
if(!putfiledat(&scfg,&f))
lprintf(LOG_ERR,"%04d !ERROR updating file (%s) in database",xfer.ctrl_sock,f.name);
/* need to update the index here */
} else {
if(!addfiledat(&scfg,&f))
lprintf(LOG_ERR,"%04d !ERROR adding file (%s) to database",xfer.ctrl_sock,f.name);
if(f.misc&FM_EXTDESC)
putextdesc(&scfg,f.dir,f.datoffset,ext);
if(scfg.dir[f.dir]->upload_sem[0])
ftouch(scfg.dir[f.dir]->upload_sem);
/**************************/
/* Update Uploader's Info */
/**************************/
user_uploaded(&scfg, xfer.user, (!xfer.append && xfer.filepos==0) ? 1:0, total);
if(scfg.dir[f.dir]->up_pct && scfg.dir[f.dir]->misc&DIR_CDTUL) { /* credit for upload */
if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) /* Give min instead of cdt */
xfer.user->min=adjustuserrec(&scfg,xfer.user->number,U_MIN,10
,((ulong)(total*(scfg.dir[f.dir]->up_pct/100.0))/cps)/60);
else
xfer.user->cdt=adjustuserrec(&scfg,xfer.user->number,U_CDT,10
,(ulong)(f.cdt*(scfg.dir[f.dir]->up_pct/100.0)));
}
if(!(scfg.dir[f.dir]->misc&DIR_NOSTAT))
upload_stats(total);

rswindell
committed
/* Send ACK */
sockprintf(xfer.ctrl_sock,sess,"226 Upload complete (%lu cps).",cps);
*xfer.inprogress=FALSE;
static BOOL start_tls(SOCKET *sock, CRYPT_SESSION *sess, BOOL resp)
{
BOOL nodelay;
ulong nb;
int status;
char *estr;
if (get_ssl_cert(&scfg, NULL) == -1) {
lprintf(LOG_ERR, "Unable to get certificate");
if (resp)
sockprintf(*sock, *sess, "431 TLS not available");
return FALSE;
}
if (cryptCreateSession(sess, CRYPT_UNUSED, CRYPT_SESSION_SSL_SERVER) != CRYPT_OK) {
lprintf(LOG_ERR, "Unable to create TLS session");
if (resp)
sockprintf(*sock, *sess, "431 TLS not available");
return FALSE;
}
if (cryptSetAttribute(*sess, CRYPT_SESSINFO_SSL_OPTIONS, CRYPT_SSLOPTION_DISABLE_CERTVERIFY) != CRYPT_OK) {
lprintf(LOG_ERR, "Unable to disable certificate verification");
cryptDestroySession(*sess);
*sess = -1;
if(resp)
sockprintf(*sock, *sess, "431 TLS not available");
return FALSE;
}
if (cryptSetAttribute(*sess, CRYPT_SESSINFO_PRIVATEKEY, scfg.tls_certificate) != CRYPT_OK) {
lprintf(LOG_ERR, "Unable to set private key");
cryptDestroySession(*sess);
*sess = -1;
if (resp)
sockprintf(*sock, *sess, "431 TLS not available");
return FALSE;
}
nodelay = TRUE;
setsockopt(*sock,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
nb=0;
ioctlsocket(*sock,FIONBIO,&nb);
if (cryptSetAttribute(*sess, CRYPT_SESSINFO_NETWORKSOCKET, *sock) != CRYPT_OK) {
lprintf(LOG_ERR, "Unable to set network socket");
cryptDestroySession(*sess);
*sess = -1;
if (resp)
sockprintf(*sock, *sess, "431 TLS not available");
return TRUE;
}
if (resp)
sockprintf(*sock, -1, "234 Ready to start TLS");
if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) {
estr = get_crypt_error(*sess);
lprintf(LOG_ERR, "Unable to set session active (%d:%s)", status, estr);
free_crypt_attrstr(estr);
return TRUE;
}
if (startup->max_inactivity) {
if (cryptSetAttribute(*sess, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity) != CRYPT_OK) {
lprintf(LOG_ERR, "Unable to set max inactivity");
return TRUE;
}
}
return FALSE;
}
static void filexfer(union xp_sockaddr* addr, SOCKET ctrl_sock, CRYPT_SESSION ctrl_sess, SOCKET pasv_sock, CRYPT_SESSION pasv_sess, SOCKET* data_sock
,CRYPT_SESSION *data_sess, char* filename, long filepos, BOOL* inprogress, BOOL* aborted
,BOOL delfile, BOOL tmpfile
,time_t* lastactive
,user_t* user
,int dir
,BOOL receiving
,BOOL credits
,BOOL append
ulong l;
xfer_t* xfer;
struct timeval tv;
fd_set socket_set;
if((*inprogress)==TRUE) {
lprintf(LOG_WARNING,"%04d !TRANSFER already in progress",ctrl_sock);
sockprintf(ctrl_sock,ctrl_sess,"425 Transfer already in progress.");
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename);
return;
}
*inprogress=TRUE;