Newer
Older
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
} /* Local STOR */
}
if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) {
dir=curdir;
lib=curlib;
if(cmd[4]!=0)
lprintf("%04d LIST/NLST: %s",sock,cmd);
/* path specified? */
p=cmd+4;
while(*p && *p<=' ') p++;
if(*p=='-') { /* -Letc */
while(*p && *p>' ') p++;
while(*p && *p<=' ') p++;
}
parsepath(&p,&user,&lib,&dir);
sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
if((fp=fopen(fname,"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;
sockprintf(sock,"150 Opening ASCII mode data connection for /bin/ls.");
now=time(NULL);
tm_p=localtime(&now);
if(tm_p==NULL)
memset(&cur_tm,0,sizeof(cur_tm));
else
cur_tm=*tm_p;
if(startup->options&FTP_OPT_INDEX_FILE && startup->index_file_name[0]
&& (!stricmp(p,startup->index_file_name) || *p==0 || *p=='*')) {
if(detail)
fprintf(fp,"-rw-r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,lib<0 ? scfg.sys_id : dir<0
? scfg.lib[lib]->sname : scfg.dir[dir]->code
,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,startup->index_file_name);
else
fprintf(fp,"%s\r\n",startup->index_file_name);
}
/* HTML Index File */
if(startup->options&FTP_OPT_HTML_INDEX_FILE && startup->html_index_file[0]
&& (!stricmp(p,startup->html_index_file) || *p==0 || *p=='*')) {
if(detail)
fprintf(fp,"-rw-r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,lib<0 ? scfg.sys_id : dir<0
? scfg.lib[lib]->sname : scfg.dir[dir]->code
,512L
,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,startup->html_index_file);
else
fprintf(fp,"%s\r\n",startup->html_index_file);
}
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
if(lib<0) { /* Root dir */
lprintf("%04d %s listing: root",sock,user.alias);
/* QWK Packet */
if(startup->options&FTP_OPT_ALLOW_QWK/* && fexist(qwkfile)*/) {
if(detail) {
if(fexist(qwkfile)) {
t=fdate(qwkfile);
l=flength(qwkfile);
} else {
t=time(NULL);
l=10240;
};
tm_p=localtime(&t);
if(tm_p==NULL)
memset(&tm,0,sizeof(tm));
else
tm=*tm_p;
fprintf(fp,"-rw-r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s.qwk\r\n"
,NAME_LEN
,scfg.sys_id
,scfg.sys_id
,l
,mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
,scfg.sys_id);
} else
fprintf(fp,"%s.qwk\r\n",scfg.sys_id);
}
/* File Aliases */

rswindell
committed
sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
while(!feof(alias_fp)) {
if(!fgets(aliasline,sizeof(aliasline)-1,alias_fp))
break;
alias_dir=FALSE;
p=aliasline; /* alias pointer */
while(*p && *p<=' ') p++;
if(*p==';') /* comment */
continue;
tp=p; /* terminator pointer */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
np=tp+1; /* filename pointer */
while(*np && *np<=' ') np++;
tp=np; /* terminator pointer */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
/* Virtual Path? */
if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user))<0)
continue; /* No access or invalid virtual path */
tp=strrchr(np,'/');
if(tp==NULL)
continue;
tp++;
if(*tp) {
sprintf(aliasfile,"%s%s",scfg.dir[dir]->path,tp);
np=aliasfile;
}
else
alias_dir=TRUE;
}
if(!alias_dir && !fexist(np))
continue;
if(detail) {
if(alias_dir==TRUE) {
fprintf(fp,"drwxr-xr-x 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,scfg.lib[scfg.dir[dir]->lib]->sname
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,p);
}
else {
t=fdate(np);
tm_p=localtime(&t);
if(tm_p==NULL)
memset(&tm,0,sizeof(tm));
else
tm=*tm_p;
fprintf(fp,"-rw-r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,scfg.sys_id
,flength(np)
,mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min
,p);
}
} else
fprintf(fp,"%s\r\n",p);
}
fclose(alias_fp);
}
/* Library folders */
for(i=0;i<scfg.total_libs;i++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
continue;
if(detail)
fprintf(fp,"drwxr-xr-x 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,scfg.sys_id
,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,scfg.lib[i]->sname);
else
fprintf(fp,"%s\r\n",scfg.lib[i]->sname);
}
} else if(dir<0) {
lprintf("%04d %s listing: %s library",sock,user.alias,scfg.lib[lib]->sname);
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=lib)
continue;
if(i!=scfg.sysop_dir && i!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[i]->ar,&user))
continue;
if(detail)
fprintf(fp,"drwxr-xr-x 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n"
,NAME_LEN
,scfg.sys_id
,scfg.lib[lib]->sname
,mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min
,scfg.dir[i]->code);
else
fprintf(fp,"%s\r\n",scfg.dir[i]->code);
}
} else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
lprintf("%04d %s listing: %s/%s directory"
,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code);
sprintf(path,"%s%s",scfg.dir[dir]->path,*p ? p : "*");

rswindell
committed
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
strcpy(str,g.gl_pathv[i]);
#endif
padfname(getfname(str),f.name);
strupr(f.name);
f.dir=dir;

rswindell
committed
if((filedat=getfileixb(&scfg,&f))==FALSE
&& !(startup->options&FTP_OPT_DIR_FILES))
continue;
if(detail) {
f.size=flength(g.gl_pathv[i]);
getfiledat(&scfg,&f);
t=fdate(g.gl_pathv[i]);
tm_p=localtime(&t);
if(tm_p==NULL)
memset(&tm,0,sizeof(tm));
else
tm=*tm_p;
if(filedat) {
if(f.misc&FM_ANON)
strcpy(str,ANONYMOUS);
else
dotname(f.uler,str);
} else
strcpy(str,scfg.sys_id);

rswindell
committed
fprintf(fp,"-rw-r--r-- 1 %-*s %-8s %9ld %s %2d "
,NAME_LEN

rswindell
committed
,scfg.dir[dir]->code
,f.size
,mon[tm.tm_mon],tm.tm_mday);
if(tm.tm_year==cur_tm.tm_year)
fprintf(fp,"%02d:%02d %s\r\n"
,tm.tm_hour,tm.tm_min
,getfname(g.gl_pathv[i]));
else
fprintf(fp,"%5d %s\r\n"
,1900+tm.tm_year
,getfname(g.gl_pathv[i]));
} else
fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i]));

rswindell
committed
globfree(&g);

rswindell
committed
lprintf("%04d %s listing: %s/%s directory (empty - no access)"
,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code);
fclose(fp);
filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L
,&transfer_inprogress,&transfer_aborted
,TRUE /* delfile */
,TRUE /* tmpfile */
,&lastactive,&user,dir,FALSE,FALSE,FALSE,NULL);
continue;
}

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;
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;
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
if(!getsize && !getdate && user.rest&FLAG('D')) {
sockprintf(sock,"550 Insufficient access.");
filepos=0;
continue;
}
credits=TRUE;
success=FALSE;
delfile=FALSE;
tmpfile=FALSE;
lib=curlib;
dir=curdir;
p=cmd+5;
while(*p && *p<=' ') 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 && alias(p, fname, &user, &dir)==TRUE) {
success=TRUE;
credits=TRUE; /* include in d/l stats */
tmpfile=FALSE;
delfile=FALSE;
lprintf("%04d %s %.4s by alias: %s"
,sock,user.alias,cmd,p);
if(dir>=0)
lib=scfg.dir[dir]->lib;
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
}
if(!success && lib<0 && (tp=strchr(p,'/'))!=NULL) {
dir=-1;
*tp=0;
for(i=0;i<scfg.total_libs;i++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
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(!chk_ar(&scfg,scfg.dir[i]->ar,&user))
continue;
if(!stricmp(scfg.dir[i]->code,p))
break;
}
if(i<scfg.total_dirs)
dir=i;
p=tp+1;
}
sprintf(html_index_ext,"%s?",startup->html_index_file);
sprintf(str,"%s.qwk",scfg.sys_id);
if(lib<0 && startup->options&FTP_OPT_ALLOW_QWK

rswindell
committed
&& !stricmp(p,str) && !delecmd) {
lprintf("%04d %s creating/updating QWK packet...",sock,user.alias);

rswindell
committed
sprintf(str,"%spack%04u.now",scfg.data_dir,user.number);
if((file=open(str,O_WRONLY|O_CREAT,S_IWRITE))==-1) {
lprintf("%04d !ERROR %d opening %s",sock, errno, str);
sockprintf(sock, "451 !ERROR %d creating semaphore file",errno);
filepos=0;
continue;
}
close(file);
t=time(NULL);
while(fexist(str)) {
if(time(NULL)-t>startup->qwk_timeout)
}
if(fexist(str)) {
lprintf("%04d !TIMEOUT waiting for QWK packet creation",sock);
sockprintf(sock,"451 Time-out waiting for packet creation.");
remove(str);
filepos=0;
continue;
}
if(!fexist(qwkfile)) {
lprintf("%04d No QWK Packet created (no new messages)",sock);
sockprintf(sock,"550 No QWK packet created (no new messages)");
filepos=0;
continue;
}
strcpy(fname,qwkfile);
success=TRUE;
delfile=TRUE;
credits=FALSE;
lprintf("%04d %s downloading QWK packet (%ld bytes) in %s mode"
,sock,user.alias,flength(fname)
,pasv_sock==INVALID_SOCKET ? "active":"passive");
} else if(startup->options&FTP_OPT_INDEX_FILE

rswindell
committed
&& !stricmp(p,startup->index_file_name)
&& !delecmd) {
sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
if((fp=fopen(fname,"w+b"))==NULL) {
lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
sockprintf(sock, "451 Insufficient system storage");
filepos=0;
continue;
}
if(!getsize && !getdate)
lprintf("%04d %s downloading index for %s in %s mode"
,sock,user.alias,vpath(lib,dir,str)
,pasv_sock==INVALID_SOCKET ? "active":"passive");
success=TRUE;
credits=FALSE;
tmpfile=TRUE;
fprintf(fp,"%-*s File/Folder Descriptions\r\n"
,INDEX_FNAME_LEN,startup->index_file_name);
if(startup->options&FTP_OPT_HTML_INDEX_FILE)
fprintf(fp,"%-*s File/Folder Descriptions (HTML)\r\n"
,INDEX_FNAME_LEN,startup->html_index_file);
if(lib<0) {
/* File Aliases */

rswindell
committed
sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
if((alias_fp=fopen(aliasfile,"r"))!=NULL) {
while(!feof(alias_fp)) {
if(!fgets(aliasline,sizeof(aliasline)-1,alias_fp))
break;
p=aliasline; /* alias pointer */
while(*p && *p<=' ') p++;
if(*p==';') /* comment */
continue;
tp=p; /* terminator pointer */
while(*tp && *tp>' ') tp++;
if(*tp) *tp=0;
np=tp+1; /* filename pointer */
while(*np && *np<=' ') np++;
np++; /* description pointer */
while(*np && *np>' ') 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++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
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!=scfg.sysop_dir && i!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[i]->ar,&user))
continue;
fprintf(fp,"%-*s %s\r\n"
,INDEX_FNAME_LEN,scfg.dir[i]->code,scfg.dir[i]->lname);
}

rswindell
committed
} else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)){

rswindell
committed
sprintf(cmd,"%s*",scfg.dir[dir]->path);

rswindell
committed
glob(cmd,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
strcpy(str,g.gl_pathv[i]);
#endif
padfname(getfname(str),f.name);
strupr(f.name);
f.dir=dir;

rswindell
committed
if(getfileixb(&scfg,&f)) {
f.size=flength(g.gl_pathv[i]);

rswindell
committed
fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN
,getfname(g.gl_pathv[i]),f.desc);

rswindell
committed
globfree(&g);
/* HTML Index File */
} else if(startup->options&FTP_OPT_HTML_INDEX_FILE
&& (!stricmp(p,startup->html_index_file)
|| !strnicmp(p,html_index_ext,strlen(html_index_ext)))
if(js_runtime==NULL) {
lprintf("%04d !JavaScript disabled, cannot generate %s",sock,fname);
sockprintf(sock, "451 JavaScript disabled");
filepos=0;
continue;
}
if(js_cx==NULL) { /* Context not yet created, create it now */
if(((js_cx=js_initcx(sock,&js_glob,&js_ftp))==NULL)) {
lprintf("%04d !ERROR initializing JavaScript context",sock);
sockprintf(sock,"451 Error initializing JavaScript context");
filepos=0;
continue;
}
JS_BeginRequest(js_cx); /* Required for multi-thread support */
if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
lprintf("%04d !JavaScript ERROR creating user class",sock);
if(js_CreateFileClass(js_cx, js_glob)==NULL)
lprintf("%04d !JavaScript ERROR creating file 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);
JS_EndRequest(js_cx); /* Required for multi-thread support */
}
JS_BeginRequest(js_cx); /* Required for multi-thread support */
js_val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, "name"));
JS_SetProperty(js_cx, js_ftp, "sort", &js_val);
JS_SetProperty(js_cx, js_ftp, "reverse", &js_val);
if(!strnicmp(p,html_index_ext,strlen(html_index_ext))) {
p+=strlen(html_index_ext);
tp=strrchr(p,'$');
if(tp!=NULL)
*tp=0;
if(!strnicmp(p,"ext=",4)) {
p+=4;
if(!strcmp(p,"on"))
user.misc|=EXTDESC;
else
user.misc&=~EXTDESC;
if(!(user.rest&FLAG('G')))
putuserrec(&scfg,user.number,U_MISC,8,ultoa(user.misc,str,16));
}
else if(!strnicmp(p,"sort=",5)) {
p+=5;
tp=strchr(p,'&');
if(tp!=NULL) {
*tp=0;
tp++;
if(!stricmp(tp,"reverse")) {
js_val=BOOLEAN_TO_JSVAL(TRUE);
JS_SetProperty(js_cx, js_ftp, "reverse", &js_val);
}
}
js_val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx, p));
JS_SetProperty(js_cx, js_ftp, "sort", &js_val);
JS_EndRequest(js_cx); /* Required for multi-thread support */
sprintf(fname,"%sftp%d.tx", scfg.data_dir, sock);
if((fp=fopen(fname,"w+b"))==NULL) {
lprintf("%04d !ERROR %d opening %s",sock,errno,fname);
sockprintf(sock, "451 Insufficient system storage");
filepos=0;
continue;
}
if(!getsize && !getdate)
lprintf("%04d %s downloading HTML index for %s in %s mode"
,sock,user.alias,vpath(lib,dir,str)
,pasv_sock==INVALID_SOCKET ? "active":"passive");
success=TRUE;
credits=FALSE;
tmpfile=TRUE;
delfile=TRUE;
JS_BeginRequest(js_cx); /* Required for multi-thread support */
js_val=INT_TO_JSVAL(timeleft);
if(!JS_SetProperty(js_cx, js_ftp, "time_left", &js_val))
lprintf("%04d !JavaScript ERROR setting user.time_left",sock);
js_generate_index(js_cx, js_ftp, sock, fp, lib, dir, &user);
JS_EndRequest(js_cx); /* Required for multi-thread support */
} else if(dir>=0) {
if(!chk_ar(&scfg,scfg.dir[dir]->ar,&user)) {
lprintf("%04d !%s has insufficient access to /%s/%s"
,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
sockprintf(sock,"550 Insufficient access.");
filepos=0;
continue;
}

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

rswindell
committed
if(delecmd && !dir_op(&scfg,&user,dir)) {
lprintf("%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);
sockprintf(sock,"550 Insufficient access.");
filepos=0;
continue;
}
sprintf(fname,"%s%s",scfg.dir[dir]->path,p);
GetShortPathName(fname, str, sizeof(str));
#else
strcpy(str,fname);
#endif
padfname(getfname(str),f.name);
strupr(f.name);
f.dir=dir;
f.cdt=0;
f.size=-1;
filedat=getfileixb(&scfg,&f);
if(!filedat && !(startup->options&FTP_OPT_DIR_FILES)) {
sockprintf(sock,"550 File not found: %s",p);
lprintf("%04d !%s file (%s%s) not in database for %.4s command"
,sock,user.alias,vpath(lib,dir,str),p,cmd);
filepos=0;
continue;
}

rswindell
committed
/* Verify credits */
if(!getsize && !getdate && !delecmd
&& !(scfg.dir[dir]->misc&DIR_FREE)
&& !(user.exempt&FLAG('D'))) {
if(filedat)
getfiledat(&scfg,&f);
else
f.cdt=flength(fname);
if(f.cdt>(user.cdt+user.freecdt)) {
lprintf("%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
,p
,f.cdt);
sockprintf(sock,"550 Insufficient credit (%lu required).",f.cdt);
filepos=0;
continue;
}
}
if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) {
success=FALSE;
lprintf("%04d !ILLEGAL FILENAME ATTEMPT by %s: %s"
hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
} else {
if(fexist(fname)) {
success=TRUE;

rswindell
committed
if(!getsize && !getdate && !delecmd)
lprintf("%04d %s downloading: %s (%ld bytes) in %s mode"
,sock,user.alias,fname,flength(fname)
,pasv_sock==INVALID_SOCKET ? "active":"passive");
socket_debug[sock]|=SOCKET_DEBUG_DOWNLOAD;
if(getsize && success)
sockprintf(sock,"213 %lu",flength(fname));
else if(getdate && success) {
t=fdate(fname);
tm_p=gmtime(&t);
if(tm_p==NULL)
memset(&tm,0,sizeof(tm));
else
tm=*tm_p;
sockprintf(sock,"213 %u%02u%02u%02u%02u%02u"
,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(remove(fname)!=0) {
lprintf("%04d !ERROR %d deleting %s",sock,errno,fname);
sockprintf(sock,"450 %s could not be deleted (error: %d)"
,fname,errno);
} else {
lprintf("%04d %s deleted %s",sock,user.alias,fname);
if(filedat)
removefiledat(&scfg,&f);
sockprintf(sock,"250 %s deleted.",fname);
}
} else if(success) {
sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
,&transfer_inprogress,&transfer_aborted,delfile,tmpfile
,&lastactive,&user,dir,FALSE,credits,FALSE,NULL);
}
sockprintf(sock,"550 File not found: %s",p);
lprintf("%04d !%s file (%s%s) not found for %.4s command"
,sock,user.alias,vpath(lib,dir,str),p,cmd);
socket_debug[sock]&=~SOCKET_DEBUG_DOWNLOAD;
continue;
}
if(!strnicmp(cmd, "DESC", 4)) {
if(user.rest&FLAG('U')) {
sockprintf(sock,"553 Insufficient access.");
continue;
}
p=cmd+4;
while(*p && *p<=' ') p++;
if(*p==0)
sockprintf(sock,"501 No file description given.");
else {
sprintf(desc,"%.*s",(int)sizeof(desc)-1,p);
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
sockprintf(sock,"200 File description set. Ready to STOR file.");
}
continue;
}
if(!strnicmp(cmd, "STOR ", 5)) {
if(user.rest&FLAG('U')) {
sockprintf(sock,"553 Insufficient access.");
continue;
}
if(transfer_inprogress==TRUE) {
lprintf("%04d !TRANSFER already in progress (%s)",sock,cmd);
sockprintf(sock,"425 Transfer already in progress.");
continue;
}
lib=curlib;
dir=curdir;
p=cmd+5;
while(*p && *p<=' ') 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++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
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!=scfg.sysop_dir && i!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[i]->ar,&user))
continue;
if(!stricmp(scfg.dir[i]->code,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("%04d !%s attempted to upload to invalid directory"
,sock,user.alias);
sockprintf(sock,"553 Invalid directory.");
continue;
}

rswindell
committed
sprintf(fname,"%sfile/%04d.rep",scfg.data_dir,user.number);
lprintf("%04d %s uploading: %s in %s mode"
,sock,user.alias,fname
,pasv_sock==INVALID_SOCKET ? "active":"passive");
} else {
if(!chk_ar(&scfg,scfg.dir[dir]->ul_ar,&user)) {
lprintf("%04d !%s has insufficient access to upload to /%s/%s"
,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname,scfg.dir[dir]->code);
sockprintf(sock,"553 Insufficient access.");
continue;
}
if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)
|| trashcan(&scfg,p,"file")) {
lprintf("%04d !ILLEGAL FILENAME ATTEMPT by %s: %s"
,sock,user.alias,p);
sockprintf(sock,"553 Illegal filename attempt");
hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
continue;
}
sprintf(fname,"%s%s",scfg.dir[dir]->path,p);
if(fexist(fname)
|| (startup->options&FTP_OPT_INDEX_FILE
&& !stricmp(p,startup->index_file_name))
|| (startup->options&FTP_OPT_HTML_INDEX_FILE
&& !stricmp(p,startup->html_index_file))
) {
lprintf("%04d !%s attempted to overwrite existing file: %s"
,sock,user.alias,fname);
sockprintf(sock,"553 File already exists.");
continue;
}
lprintf("%04d %s uploading: %s to %s (%s) in %s mode"
,sock,user.alias
,p /* filename */
,vpath(lib,dir,str) /* virtual path */
,scfg.dir[dir]->path /* actual path */
,pasv_sock==INVALID_SOCKET ? "active":"passive");
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
}
sockprintf(sock,"150 Opening BINARY mode data connection for file transfer.");
filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos
,&transfer_inprogress,&transfer_aborted,FALSE,FALSE
,&lastactive
,&user
,dir
,TRUE /* uploading */
,TRUE /* credits */
,FALSE /* append */
,desc
);
filepos=0;
continue;
}
if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) {
if(curdir<0)
curlib=-1;
else
curdir=-1;
sockprintf(sock,"200 CDUP command successful.");
continue;
}
if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) {
p=cmd+4;
while(*p && *p<=' ') 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)) {
sockprintf(sock,"550 Directory does not exist.");
lprintf("%04d !%s attempted to mount invalid directory: %s"
,sock, user.alias, p);
continue;
}
sprintf(local_dir,"%.*s",(int)sizeof(local_dir)-1,p);
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
local_fsys=TRUE;
sockprintf(sock,"250 CWD command successful (local file system mounted).");
lprintf("%04d %s mounted local file system", sock, user.alias);
continue;
}
success=FALSE;
/* Directory Alias? */
if(curlib<0 && alias(p,NULL,&user,&curdir)==TRUE) {
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++) {
if(!chk_ar(&scfg,scfg.lib[i]->ar,&user))
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=strchr(p,'/');
if(tp) *tp=0;
for(i=0;i<scfg.total_dirs;i++) {
if(scfg.dir[i]->lib!=curlib)
continue;
if(i!=scfg.sysop_dir && i!=scfg.upload_dir
&& !chk_ar(&scfg,scfg.dir[i]->ar,&user))
continue;
if(!stricmp(scfg.dir[i]->code,p))
break;
}
if(i<scfg.total_dirs) {
curdir=i;
success=TRUE;
} else
success=FALSE;
}
if(success)
sockprintf(sock,"250 CWD command successful.");
else {
sockprintf(sock,"550 %s: No such file or directory.",p);
curlib=orglib;
curdir=orgdir;
}
continue;
}
if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) {
if(curlib<0)
sockprintf(sock,"257 \"/\" is current directory.");
else if(curdir<0)
sockprintf(sock,"257 \"/%s\" is current directory."
,scfg.lib[curlib]->sname);
else
sockprintf(sock,"257 \"/%s/%s\" is current directory."
,scfg.lib[curlib]->sname,scfg.dir[curdir]->code);