Newer
Older
if ((status = cryptSetAttribute(*sess, CRYPT_SESSINFO_ACTIVE, 1)) != CRYPT_OK) {
GCES(status, *sock, *sess, estr, "setting session active");
if ((status = cryptSetAttribute(*sess, CRYPT_OPTION_NET_READTIMEOUT, startup->max_inactivity)) != CRYPT_OK) {
GCES(status, *sock, *sess, estr, "setting read timeout");
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 <%s> !DATA TRANSFER already in progress",ctrl_sock, user->alias);
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, user->alias);
return;
}
*inprogress=TRUE;
if(pasv_sock==INVALID_SOCKET) { /* !PASV */
if((*data_sock=socket(addr->addr.sa_family, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) {
lprintf(LOG_ERR,"%04d <%s> !DATA ERROR %d opening socket", ctrl_sock, user->alias, ERROR_VALUE);
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d opening socket",ERROR_VALUE);
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
*inprogress=FALSE;
return;
}
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d <%s> DATA socket %d opened",ctrl_sock, user->alias,*data_sock);
/* Use port-1 for all data connections */
reuseaddr=TRUE;
setsockopt(*data_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseaddr,sizeof(reuseaddr));
addr_len = sizeof(server_addr);
if((result=getsockname(ctrl_sock, &server_addr.addr,&addr_len))!=0) {
lprintf(LOG_ERR,"%04d <%s> !DATA ERROR %d (%d) getting address/port of command socket (%u)"
,ctrl_sock, user->alias,result,ERROR_VALUE,pasv_sock);
inet_setaddrport(&server_addr, inet_addrport(&server_addr)-1); /* 20? */
if(result!=0) {
inet_setaddrport(&server_addr, 0); /* any user port */
result=bind(*data_sock, &server_addr.addr,addr_len);
}
lprintf(LOG_ERR,"%04d <%s> DATA ERROR %d (%d) binding socket %d"
,ctrl_sock, user->alias, result, ERROR_VALUE, *data_sock);
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d binding socket",ERROR_VALUE);
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
if(result!=0) {
lprintf(LOG_WARNING,"%04d <%s> !DATA ERROR %d (%d) connecting to client %s port %u on socket %d"
,ctrl_sock, user->alias,result,ERROR_VALUE
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d connecting to socket",ERROR_VALUE);
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
return;
}
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d <%s> DATA socket %d connected to %s port %u"
,ctrl_sock, user->alias,*data_sock,host_ip,inet_addrport(addr));
if (protected) {
if (start_tls(data_sock, data_sess, FALSE) || *data_sess == -1) {
lprintf(LOG_DEBUG,"%04d <%s> !DATA ERROR activating TLS"
,ctrl_sock, user->alias);
sockprintf(ctrl_sock,ctrl_sess,"425 Error activating TLS");
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
*inprogress=FALSE;
ftp_close_socket(data_sock,data_sess,__LINE__);
return;
}
}
if(startup->options&FTP_OPT_DEBUG_DATA) {
lprintf(LOG_ERR,"%04d <%s> PASV !DATA ERROR %d (%d) getting address/port of passive socket (%u)"
,ctrl_sock, user->alias,result,ERROR_VALUE,pasv_sock);
else
lprintf(LOG_DEBUG,"%04d <%s> PASV DATA socket %d listening on %s port %u"
,ctrl_sock, user->alias,pasv_sock,host_ip,inet_addrport(addr));
/* Setup for select() */
tv.tv_sec=TIMEOUT_SOCKET_LISTEN;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(pasv_sock,&socket_set);
#if defined(SOCKET_DEBUG_SELECT)
socket_debug[ctrl_sock]|=SOCKET_DEBUG_SELECT;
result=select(pasv_sock+1,&socket_set,NULL,NULL,&tv);
#if defined(SOCKET_DEBUG_SELECT)
socket_debug[ctrl_sock]&=~SOCKET_DEBUG_SELECT;
if(result<1) {
lprintf(LOG_WARNING,"%04d <%s> PASV !DATA select returned %d (error: %d)"
,ctrl_sock, user->alias,result,ERROR_VALUE);
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d selecting socket for connection",ERROR_VALUE);
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
*inprogress=FALSE;
return;
}
socket_debug[ctrl_sock]|=SOCKET_DEBUG_ACCEPT;
socket_debug[ctrl_sock]&=~SOCKET_DEBUG_ACCEPT;
if(*data_sock==INVALID_SOCKET) {
lprintf(LOG_WARNING,"%04d <%s> PASV !DATA ERROR %d accepting connection on socket %d"
,ctrl_sock, user->alias,ERROR_VALUE,pasv_sock);
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d accepting connection",ERROR_VALUE);
if(tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
*inprogress=FALSE;
return;
}
if(startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
if(startup->options&FTP_OPT_DEBUG_DATA)
lprintf(LOG_DEBUG,"%04d <%s> PASV DATA socket %d connected to %s port %u"
,ctrl_sock, user->alias,*data_sock,host_ip,inet_addrport(addr));
if (protected) {
if (start_tls(data_sock, data_sess, FALSE) || *data_sess == -1) {
lprintf(LOG_WARNING,"%04d <%s> PASV !DATA ERROR starting TLS", pasv_sock, user->alias);
sockprintf(ctrl_sock,ctrl_sess,"425 Error negotiating TLS");
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
do {
l=1;
if(ioctlsocket(*data_sock, FIONBIO, &l)!=0) {
lprintf(LOG_ERR,"%04d <%s> !DATA ERROR %d disabling socket blocking"
,ctrl_sock, user->alias, ERROR_VALUE);
sockprintf(ctrl_sock,ctrl_sess,"425 Error %d disabling socket blocking"
,ERROR_VALUE);
break;
}
if((xfer=malloc(sizeof(xfer_t)))==NULL) {
lprintf(LOG_CRIT,"%04d <%s> !DATA MALLOC FAILURE LINE %d",ctrl_sock, user->alias,__LINE__);
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);
protected_uint32_adjust(&thread_count,1);
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 && !(startup->options&FTP_OPT_KEEP_TEMP_FILES))
ftp_remove(ctrl_sock, __LINE__, filename, user->alias);
*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);
}
static BOOL can_list(lib_t *lib, dir_t *dir, user_t *user, client_t *client)
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (dir->dirnum == scfg.sysop_dir)
return TRUE;
if (dir->dirnum == scfg.upload_dir)
return TRUE;
if (chk_ar(&scfg, dir->ar, user, client))
return TRUE;
return FALSE;
}
static BOOL ftpalias(char* fullalias, char* filename, user_t* user, client_t* client, 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;
SAFECOPY(alias,fullalias);
p = getfname(alias);
if(p) {
if(p != alias)
*(p-1) = 0;
if(*p) {
if(filename == NULL && p != alias) // CWD command and a filename specified
return FALSE;
fname = p;
}
SAFEPRINTF(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir);
if((fp=fopen(aliasfile,"r"))==NULL)
return FALSE;
while(!feof(fp)) {
if(!fgets(line,sizeof(line),fp))
break;
p=line; /* alias */
SKIP_WHITESPACE(p);
if(*p==';') /* comment */
continue;
tp=p; /* terminator */
FIND_WHITESPACE(tp);
if(*tp) *tp=0;
continue;
p=tp+1; /* filename */
SKIP_WHITESPACE(p);
tp=p; /* terminator */
FIND_WHITESPACE(tp);
if(*tp) *tp=0;
if(filename == NULL /* CWD? */ && (*lastchar(p) != '/' || (*fname != 0 && strcmp(fname, alias)))) {
fclose(fp);
return FALSE;
if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) {
if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user,client))<0) {
lprintf(LOG_WARNING,"0000 <%s> !Invalid virtual path: %s",user->alias, p);
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
/* 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);
}
/*
* Parses a path into *curlib, *curdir, and sets *pp to point to the filename
*/
static int parsepath(char** pp, user_t* user, client_t* client, int* curlib, int* curdir)
{
char filename[MAX_PATH+1];
int lib = *curlib;
int dir = *curdir;
char *p = *pp;
char *tmp;
char *fname = strchr(p, 0);
int ret = 0;
size_t len;
if (*p == '/') {
lib = -1;
dir = -1;
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
while (*p) {
/* Relative path stuff */
if (strcmp(p, "..") == 0) {
if (dir >= 0)
dir = -1;
else if (lib >= 0)
lib = -1;
else
ret = -1;
p += 2;
}
else if(strncmp(p, "../", 3) == 0) {
if (dir >= 0)
dir = -1;
else if (lib >= 0)
lib = -1;
else
ret = -1;
p += 3;
}
else if(strcmp(p, ".") == 0)
else if(strncmp(p, "./", 2) == 0)
p += 2;
/* Path component */
else if (lib < 0) {
for(lib=0;lib<scfg.total_libs;lib++) {
if(!chk_ar(&scfg,scfg.lib[lib]->ar,user,client))
continue;
len = strlen(scfg.lib[lib]->sname);
if (strlen(p) < len)
continue;
if (p[len] != 0 && p[len] != '/')
continue;
if(!strnicmp(scfg.lib[lib]->sname,p,len)) {
p += len;
if (*p)
p++;
break;
}
}
if (lib == scfg.total_libs) {
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
strcpy(filename, p);
tmp = strchr(filename, '/');
if (tmp != NULL)
*tmp = 0;
if (ftpalias(filename, filename, user, client, &dir) == TRUE) {
lib = scfg.dir[dir]->lib;
if (strchr(p, '/') != NULL) {
p = strchr(p, '/');
p++;
}
else
p = strchr(p, 0);
}
else {
ret = -1;
lib = -1;
if (strchr(p, '/') != NULL) {
p = strchr(p, '/');
p++;
}
else
p = strchr(p, 0);
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
else if (dir < 0) {
for(dir=0;dir<scfg.total_dirs;dir++) {
if(scfg.dir[dir]->lib!=lib)
continue;
if (!can_list(scfg.lib[lib], scfg.dir[dir], user, client))
continue;
len = strlen(scfg.dir[dir]->code_suffix);
if (strlen(p) < len)
continue;
if (p[len] != 0 && p[len] != '/')
continue;
if(!strnicmp(scfg.dir[dir]->code_suffix,p,len)) {
p += len;
if (*p)
p++;
break;
}
}
if (dir == scfg.total_dirs) {
ret = -1;
dir = -1;
if (strchr(p, '/') != NULL) {
p = strchr(p, '/');
p++;
}
else
p = strchr(p, 0);
else { // Filename
if (strchr(p, '/') != NULL) {
ret = -1;
p = strchr(p, '/');
p++;
}
else {
fname = p;
p += strlen(fname);
}
*curdir = dir;
*curlib = lib;
*pp = fname;
return ret;
}
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* genvpath(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);
}
void ftp_printfile(SOCKET sock, CRYPT_SESSION sess, const char* name, unsigned code)
{
char path[MAX_PATH+1];
char buf[512];
FILE* fp;
unsigned i;
SAFEPRINTF2(path,"%sftp%s.txt",scfg.text_dir,name);
if((fp=fopen(path,"rb"))!=NULL) {
i=0;
while(!feof(fp)) {
if(!fgets(buf,sizeof(buf),fp))
break;
truncsp(buf);
if(!i)
else
i++;
}
fclose(fp);
}
}
static BOOL ftp_hacklog(char* prot, char* user, char* text, char* host, union xp_sockaddr* addr)
{
#ifdef _WIN32
if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE))
PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
#endif
return hacklog(&scfg, prot, user, text, host, addr);
}
/****************************************************************************/
/* Consecutive failed login (possible password hack) attempt tracking */
/****************************************************************************/
static BOOL badlogin(SOCKET sock, CRYPT_SESSION sess, ulong* login_attempts, char* user, char* passwd, char* host, union xp_sockaddr* addr)
{
ulong count;
if(addr!=NULL) {
count=loginFailure(startup->login_attempt_list, addr, "FTP", user, passwd);
if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold)
ftp_hacklog("FTP LOGIN", user, passwd, host, addr);
if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) {
char reason[128];
SAFEPRINTF(reason, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS (%lu)", count);
filter_ip(&scfg, "FTP", reason, host, host_ip, user, /* fname: */NULL);
if(count > *login_attempts)
*login_attempts=count;
} else
(*login_attempts)++;
mswait(startup->login_attempt.delay); /* As recommended by RFC2577 */
return(TRUE);
}
ftp_printfile(sock,sess,"badlogin",530);
sockprintf(sock,sess,"530 Invalid login.");
return(FALSE);
}
static char* ftp_tmpfname(char* fname, char* ext, SOCKET sock)
safe_snprintf(fname,MAX_PATH,"%sSBBS_FTP.%x%x%x%lx.%s"
,scfg.temp_dir,getpid(),sock,rand(),clock(),ext);
return(fname);
#if defined(__GNUC__) // Catch printf-format errors
static BOOL send_mlsx(FILE *fp, SOCKET sock, CRYPT_SESSION sess, const char *format, ...) __attribute__ ((format (printf, 4, 5)));
#endif
static BOOL send_mlsx(FILE *fp, SOCKET sock, CRYPT_SESSION sess, const char *format, ...)
{
va_list va;
char *str;
if (fp == NULL && sock == INVALID_SOCKET)
return FALSE;
va_start(va, format);
if (vasprintf(&str, format, va) == -1)
return FALSE;
if (fp != NULL)
fprintf(fp, "%s\r\n", str);
else
sockprintf(sock, sess, " %s", str);
free(str);
return TRUE;
}
static char *get_unique(const char *path, char *uniq)
{
BYTE digest[MD5_DIGEST_SIZE];
if (path == NULL)
return NULL;
MD5_calc(digest, path, strlen(path));
MD5_hex((BYTE*)uniq, digest);
return uniq;
}
static BOOL send_mlsx_entry(FILE *fp, SOCKET sock, CRYPT_SESSION sess, unsigned feats, const char *type, const char *perm, uint64_t size, time_t modify, const char *owner, const char *unique, time_t ul, const char *fname)
{
char line[1024];
char *end;
BOOL need_owner = FALSE;
end=line;
*end=0;
if (type != NULL && (feats & MLSX_TYPE))
end += sprintf(end, "Type=%s;", type);
if (perm != NULL && (feats & MLSX_PERM))
end += sprintf(end, "Perm=%s;", perm);
if (size != UINT64_MAX && (feats & MLSX_SIZE))
end += sprintf(end, "Size=%" PRIu64 ";", size);
end += sprintf(end, "Modify=%04d%02d%02d%02d%02d%02d;",
t.tm_year+1900, t.tm_mon+1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec);
if (unique != NULL && (feats & MLSX_UNIQUE))
end += sprintf(end, "Unique=%s;", unique);
if (ul != 0 && (feats & MLSX_CREATE)) {
t = *gmtime(&modify);
end += sprintf(end, "Create=%04d%02d%02d%02d%02d%02d;",
t.tm_year+1900, t.tm_mon+1, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec);
}
// Owner can contain percents, so let send_mlsx() deal with it
if (owner != NULL && (feats & MLSX_OWNER)) {
strcat(end, "UNIX.ownername=%s;");
need_owner = TRUE;
}
strcat(end, " %s");
if (need_owner)
return send_mlsx(fp, sock, sess, line, owner, fname==NULL ? "" : fname);
return send_mlsx(fp, sock, sess, line, fname==NULL ? "" : fname);
}
static BOOL write_local_mlsx(FILE *fp, SOCKET sock, CRYPT_SESSION sess, unsigned feats, const char *path, BOOL full_path)
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
{
const char *type;
char permstr[11];
char *p;
BOOL is_file = FALSE;
if (!strcmp(path, "."))
type="cdir";
else if (!strcmp(path, ".."))
type="pdir";
else if (isdir(path))
type="dir";
else {
is_file = TRUE;
type="file";
}
// TODO: Check for deletability 'd'
// TODO: Check for renamability 'f'
p = permstr;
if (is_file) {
if (access(path, W_OK) == 0) {
// Can append ('a') and write ('w')
*(p++)='a';
*(p++)='w';
}
if (access(path, R_OK) == 0) {
// Can read ('r')
*(p++)='r';
}
}
else {
// TODO: Check these on Windows...
if (access(path, W_OK) == 0) {
// Can create files ('c'), directories ('m') and delete files ('p')
*(p++)='c';
*(p++)='m';
*(p++)='p';
}
if (access(path, R_OK) == 0) {
// Can change to the directory ('e'), and list files ('l')
*(p++)='e';
*(p++)='l';
}
}
*p=0;
if (is_file)
full_path = FALSE;
return send_mlsx_entry(fp, sock, sess, feats, type, permstr, (uint64_t)flength(path), fdate(path), NULL, NULL, 0, full_path ? path : getfname(path));
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
}
/*
* Nobody can do anything but list files and change to dirs.
*/
static void get_libperm(lib_t *lib, user_t *user, client_t *client, char *permstr)
{
char *p = permstr;
if (chk_ar(&scfg,lib->ar,user,client)) {
//*(p++) = 'a'; // File may be appended to
//*(p++) = 'c'; // Files may be created in dir
//*(p++) = 'd'; // Item may be depeted (dir or file)
*(p++) = 'e'; // Can change to the dir
//*(p++) = 'f'; // Item may be renamed
*(p++) = 'l'; // Directory contents can be listed
//*(p++) = 'm'; // New subdirectories may be created
//*(p++) = 'p'; // Files/Dirs in directory may be deleted
//*(p++) = 'r'; // File may be retrieved
//*(p++) = 'w'; // File may be overwritten
}
*p=0;
}
static BOOL can_upload(lib_t *lib, dir_t *dir, user_t *user, client_t *client)
{
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (user->rest & FLAG('U'))
return FALSE;
if (dir_op(&scfg, user, client, dir->dirnum))
return TRUE;
// The rest can only upload if there's room
if(dir->maxfiles && getfiles(&scfg,dir->dirnum)>=dir->maxfiles)
return FALSE;
if (dir->dirnum == scfg.sysop_dir)
return TRUE;
if (dir->dirnum == scfg.upload_dir)
return TRUE;
if (chk_ar(&scfg, dir->ul_ar,user,client))
return TRUE;
if ((user->exempt & FLAG('U')))
return TRUE;
return FALSE;
}
static BOOL can_delete_files(lib_t *lib, dir_t *dir, user_t *user, client_t *client)
{
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (user->rest&FLAG('D'))
return FALSE;
if (!chk_ar(&scfg,dir->ar,user,client))
return FALSE;
if (dir_op(&scfg,user,client,dir->dirnum))
return TRUE;
if (user->exempt&FLAG('R'))
return TRUE;
return FALSE;
}
static void get_dirperm(lib_t *lib, dir_t *dir, user_t *user, client_t *client, char *permstr)
{
char *p = permstr;
//*(p++) = 'a'; // File may be appended to
if (can_upload(lib, dir, user, client))
*(p++) = 'c'; // Files may be created in dir
//*(p++) = 'd'; // Item may be depeted (dir or file)
if (can_list(lib, dir, user, client)) {
*(p++) = 'e'; // Can change to the dir
//*(p++) = 'f'; // Item may be renamed
*(p++) = 'l'; // Directory contents can be listed
}
//*(p++) = 'm'; // New subdirectories may be created
if (can_delete_files(lib, dir, user, client))
*(p++) = 'p'; // Files/Dirs in directory may be deleted
//*(p++) = 'r'; // File may be retrieved
//*(p++) = 'w'; // File may be overwritten
*p=0;
}
static BOOL can_append(lib_t *lib, dir_t *dir, user_t *user, client_t *client, file_t *file)
{
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (user->rest&FLAG('U'))
return FALSE;
if (dir->dirnum != scfg.sysop_dir && dir->dirnum != scfg.upload_dir && !chk_ar(&scfg,dir->ar,user,client))
return FALSE;
if(!dir_op(&scfg,user,client,dir->dirnum) && !(user->exempt&FLAG('U'))) {
if(!chk_ar(&scfg,dir->ul_ar,user,client))
return FALSE;
}
if(!getfileixb(&scfg,file) || !getfiledat(&scfg,file))
return FALSE;
if (stricmp(file->uler,user->alias))
return FALSE;
// Check credits?
return TRUE;
}
static BOOL can_delete(lib_t *lib, dir_t *dir, user_t *user, client_t *client, file_t *file)
{
if (user->rest&FLAG('D'))
return FALSE;
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (!chk_ar(&scfg,dir->ar,user,client))
return FALSE;
if (!dir_op(&scfg, user, client, dir->dirnum))
return FALSE;
if (!(user->exempt&FLAG('R')))
return FALSE;
if(!getfileixb(&scfg,file) && !(startup->options&FTP_OPT_DIR_FILES) && !(dir->misc&DIR_FILES))
return FALSE;
return TRUE;
}
static BOOL can_download(lib_t *lib, dir_t *dir, user_t *user, client_t *client, file_t *file)
{
if (user->rest&FLAG('D'))
return FALSE;
if (!chk_ar(&scfg,lib->ar,user,client))
return FALSE;
if (!chk_ar(&scfg,dir->ar,user,client))
return FALSE;
if (!chk_ar(&scfg,dir->dl_ar,user,client))
return FALSE;
if(!getfileixb(&scfg,file) && !(startup->options&FTP_OPT_DIR_FILES) && !(dir->misc&DIR_FILES))
return FALSE;
// TODO: Verify credits
return TRUE;
}
static void get_fileperm(lib_t *lib, dir_t *dir, user_t *user, client_t *client, file_t *file, char *permstr)
{
char *p = permstr;
if (can_append(lib, dir, user, client, file))
*(p++) = 'a'; // File may be appended to
//*(p++) = 'c'; // Files may be created in dir
if (can_delete(lib, dir, user, client, file))
*(p++) = 'd'; // Item may be depeted (dir or file)
//*(p++) = 'e'; // Can change to the dir
//*(p++) = 'f'; // Item may be renamed
//*(p++) = 'l'; // Directory contents can be listed
//*(p++) = 'm'; // New subdirectories may be created
//*(p++) = 'p'; // Files/Dirs in directory may be deleted
if (can_download(lib, dir, user, client, file))
*(p++) = 'r'; // File may be retrieved
//*(p++) = 'w'; // File may be overwritten
*p = 0;
}
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
static void get_owner_name(file_t *file, char *namestr)
{
char *p;
if (file) {
if (file->misc & FM_ANON)
strcpy(namestr, ANONYMOUS);
else
strcpy(namestr, file->uler);
}
else
strcpy(namestr, scfg.sys_id);
// Now ensure it's an RCHAR string.
for (p=namestr; *p; p++) {
if (*p >= '!' && *p <= ')')
continue;
else if (*p >= '+' && *p <= ':')
continue;
else if (*p >= '?' && *p <= 'Z')
continue;
else if (*p == '\\')
continue;
else if (*p == '^')
continue;
else if (*p == '_')
continue;
else if (*p >= 'a' && *p <= 'z')
continue;
else if (*p == ' ')
*p = '.';
else
*p = '_';
}
}
static void ctrl_thread(void* arg)
{
unsigned mlsx_feats = (MLSX_TYPE | MLSX_PERM | MLSX_SIZE | MLSX_MODIFY | MLSX_OWNER | MLSX_UNIQUE | MLSX_CREATE);
char buf[512];
char str[128];
char uniq[33];
char* cmd;
char* p;
char* np;
char* tp;
char* dp;
char* ap;
char* filespec;
char* mode="active";
char old_char;
char fname[MAX_PATH+1];
char qwkfile[MAX_PATH+1];
char aliasfile[MAX_PATH+1];
char aliaspath[MAX_PATH+1];
char mls_path[MAX_PATH+1];
char *mls_fname;
char permstr[11];
char aliasline[512];
char desc[501]="";
char sys_pass[128];
char host_name[256];
char host_ip[INET6_ADDRSTRLEN];
char data_ip[INET6_ADDRSTRLEN];
uint16_t data_port;
char path[MAX_PATH+1];
char local_dir[MAX_PATH+1];
char ren_from[MAX_PATH+1]="";
char html_index_ext[MAX_PATH+1];

sbbs
committed
unsigned h1,h2,h3,h4;
u_short p1,p2; /* For PORT command */
int i;
int rd;
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;
BOOL reuseaddr;
FILE* fp;
FILE* alias_fp;
SOCKET sock;
SOCKET tmp_sock;
SOCKET pasv_sock=INVALID_SOCKET;
SOCKET data_sock=INVALID_SOCKET;
union xp_sockaddr addr;
union xp_sockaddr data_addr;
union xp_sockaddr pasv_addr;
ftp_t ftp=*(ftp_t*)arg;
user_t user;
time_t t;
time_t now;
time_t logintime=0;