|
|
1.1 ! root 1: /* ftpsrvr.c */ ! 2: ! 3: /* Synchronet FTP server */ ! 4: ! 5: /* $Id: ftpsrvr.c,v 1.313 2006/12/29 08:42:56 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: /* ANSI C Library headers */ ! 39: #include <stdio.h> ! 40: #include <stdlib.h> /* ltoa in GNU C lib */ ! 41: #include <stdarg.h> /* va_list, varargs */ ! 42: #include <string.h> /* strrchr */ ! 43: #include <fcntl.h> /* O_WRONLY, O_RDONLY, etc. */ ! 44: #include <errno.h> /* EACCES */ ! 45: #include <ctype.h> /* toupper */ ! 46: #include <sys/stat.h> /* S_IWRITE */ ! 47: ! 48: /* Synchronet-specific headers */ ! 49: #undef SBBS /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */ ! 50: #include "sbbs.h" ! 51: #include "text.h" /* TOTAL_TEXT */ ! 52: #include "ftpsrvr.h" ! 53: #include "telnet.h" ! 54: ! 55: /* Constants */ ! 56: ! 57: #define FTP_SERVER "Synchronet FTP Server" ! 58: ! 59: #define STATUS_WFC "Listening" ! 60: #define ANONYMOUS "anonymous" ! 61: ! 62: #define BBS_VIRTUAL_PATH "bbs:/""/" /* this is actually bbs:<slash><slash> */ ! 63: #define LOCAL_FSYS_DIR "local:" ! 64: #define BBS_FSYS_DIR "bbs:" ! 65: #define BBS_HIDDEN_ALIAS "hidden" ! 66: ! 67: #define TIMEOUT_THREAD_WAIT 60 /* Seconds */ ! 68: ! 69: #define TIMEOUT_SOCKET_LISTEN 30 /* Seconds */ ! 70: ! 71: #define XFER_REPORT_INTERVAL 60 /* Seconds */ ! 72: ! 73: #define INDEX_FNAME_LEN 15 ! 74: ! 75: #define NAME_LEN 15 /* User name length for listings */ ! 76: ! 77: static ftp_startup_t* startup=NULL; ! 78: static scfg_t scfg; ! 79: static SOCKET server_socket=INVALID_SOCKET; ! 80: static DWORD active_clients=0; ! 81: static DWORD sockets=0; ! 82: static DWORD thread_count=0; ! 83: static time_t uptime=0; ! 84: static DWORD served=0; ! 85: static BOOL terminate_server=FALSE; ! 86: static char revision[16]; ! 87: static char *text[TOTAL_TEXT]; ! 88: static str_list_t recycle_semfiles; ! 89: static str_list_t shutdown_semfiles; ! 90: ! 91: #ifdef _DEBUG ! 92: static BYTE socket_debug[0x10000]={0}; ! 93: ! 94: #define SOCKET_DEBUG_CTRL (1<<0) /* 0x01 */ ! 95: #define SOCKET_DEBUG_SEND (1<<1) /* 0x02 */ ! 96: #define SOCKET_DEBUG_READLINE (1<<2) /* 0x04 */ ! 97: #define SOCKET_DEBUG_ACCEPT (1<<3) /* 0x08 */ ! 98: #define SOCKET_DEBUG_SENDTHREAD (1<<4) /* 0x10 */ ! 99: #define SOCKET_DEBUG_TERMINATE (1<<5) /* 0x20 */ ! 100: #define SOCKET_DEBUG_RECV_CHAR (1<<6) /* 0x40 */ ! 101: #define SOCKET_DEBUG_FILEXFER (1<<7) /* 0x80 */ ! 102: #endif ! 103: ! 104: ! 105: typedef struct { ! 106: SOCKET socket; ! 107: SOCKADDR_IN client_addr; ! 108: } ftp_t; ! 109: ! 110: ! 111: static const char *ftp_mon[]={"Jan","Feb","Mar","Apr","May","Jun" ! 112: ,"Jul","Aug","Sep","Oct","Nov","Dec"}; ! 113: ! 114: BOOL direxist(char *dir) ! 115: { ! 116: if(access(dir,0)==0) ! 117: return(TRUE); ! 118: else ! 119: return(FALSE); ! 120: } ! 121: ! 122: BOOL dir_op(scfg_t* cfg, user_t* user, uint dirnum) ! 123: { ! 124: return(user->level>=SYSOP_LEVEL || user->exempt&FLAG('R') ! 125: || (cfg->dir[dirnum]->op_ar[0] && chk_ar(cfg,cfg->dir[dirnum]->op_ar,user))); ! 126: } ! 127: ! 128: static int lprintf(int level, char *fmt, ...) ! 129: { ! 130: int result; ! 131: va_list argptr; ! 132: char sbuf[1024]; ! 133: ! 134: if(startup==NULL || startup->lputs==NULL) ! 135: return(0); ! 136: ! 137: va_start(argptr,fmt); ! 138: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 139: sbuf[sizeof(sbuf)-1]=0; ! 140: va_end(argptr); ! 141: result=startup->lputs(startup->cbdata,level,sbuf); ! 142: ! 143: return(result); ! 144: } ! 145: ! 146: #ifdef _WINSOCKAPI_ ! 147: ! 148: static WSADATA WSAData; ! 149: #define SOCKLIB_DESC WSAData.szDescription ! 150: ! 151: static BOOL WSAInitialized=FALSE; ! 152: ! 153: static BOOL winsock_startup(void) ! 154: { ! 155: int status; /* Status Code */ ! 156: ! 157: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) { ! 158: lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus); ! 159: WSAInitialized=TRUE; ! 160: return (TRUE); ! 161: } ! 162: ! 163: lprintf(LOG_ERR,"!WinSock startup ERROR %d", status); ! 164: return (FALSE); ! 165: } ! 166: ! 167: #else /* No WINSOCK */ ! 168: ! 169: #define winsock_startup() (TRUE) ! 170: #define SOCKLIB_DESC NULL ! 171: ! 172: #endif ! 173: ! 174: static void status(char* str) ! 175: { ! 176: if(startup!=NULL && startup->status!=NULL) ! 177: startup->status(startup->cbdata,str); ! 178: } ! 179: ! 180: static void update_clients(void) ! 181: { ! 182: if(startup!=NULL && startup->clients!=NULL) ! 183: startup->clients(startup->cbdata,active_clients); ! 184: } ! 185: ! 186: static void client_on(SOCKET sock, client_t* client, BOOL update) ! 187: { ! 188: if(startup!=NULL && startup->client_on!=NULL) ! 189: startup->client_on(startup->cbdata,TRUE,sock,client,update); ! 190: } ! 191: ! 192: static void client_off(SOCKET sock) ! 193: { ! 194: if(startup!=NULL && startup->client_on!=NULL) ! 195: startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE); ! 196: } ! 197: ! 198: static void thread_up(BOOL setuid) ! 199: { ! 200: thread_count++; ! 201: if(startup!=NULL && startup->thread_up!=NULL) ! 202: startup->thread_up(startup->cbdata,TRUE, setuid); ! 203: } ! 204: ! 205: static void thread_down(void) ! 206: { ! 207: if(thread_count>0) ! 208: thread_count--; ! 209: if(startup!=NULL && startup->thread_up!=NULL) ! 210: startup->thread_up(startup->cbdata,FALSE, FALSE); ! 211: } ! 212: ! 213: static SOCKET ftp_open_socket(int type) ! 214: { ! 215: SOCKET sock; ! 216: char error[256]; ! 217: ! 218: sock=socket(AF_INET, type, IPPROTO_IP); ! 219: if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) ! 220: startup->socket_open(startup->cbdata,TRUE); ! 221: if(sock!=INVALID_SOCKET) { ! 222: if(set_socket_options(&scfg, sock, "FTP", error, sizeof(error))) ! 223: lprintf(LOG_ERR,"%04d !ERROR %s",sock, error); ! 224: sockets++; ! 225: #ifdef _DEBUG ! 226: lprintf(LOG_DEBUG,"%04d Socket opened (%u sockets in use)",sock,sockets); ! 227: #endif ! 228: } ! 229: return(sock); ! 230: } ! 231: ! 232: #ifdef __BORLANDC__ ! 233: #pragma argsused ! 234: #endif ! 235: static int ftp_close_socket(SOCKET* sock, int line) ! 236: { ! 237: int result; ! 238: ! 239: if((*sock)==INVALID_SOCKET) { ! 240: lprintf(LOG_WARNING,"0000 !INVALID_SOCKET in close_socket from line %u",line); ! 241: return(-1); ! 242: } ! 243: ! 244: shutdown(*sock,SHUT_RDWR); /* required on Unix */ ! 245: ! 246: result=closesocket(*sock); ! 247: if(startup!=NULL && startup->socket_open!=NULL) ! 248: startup->socket_open(startup->cbdata,FALSE); ! 249: ! 250: sockets--; ! 251: ! 252: if(result!=0) { ! 253: if(ERROR_VALUE!=ENOTSOCK) ! 254: lprintf(LOG_WARNING,"%04d !ERROR %d closing socket from line %u",*sock,ERROR_VALUE,line); ! 255: } else if(sock==&server_socket || *sock==server_socket) ! 256: lprintf(LOG_DEBUG,"%04d Server socket closed (%u sockets in use) from line %u",*sock,sockets,line); ! 257: #ifdef _DEBUG ! 258: else ! 259: lprintf(LOG_DEBUG,"%04d Socket closed (%u sockets in use) from line %u",*sock,sockets,line); ! 260: #endif ! 261: *sock=INVALID_SOCKET; ! 262: ! 263: return(result); ! 264: } ! 265: ! 266: static int sockprintf(SOCKET sock, char *fmt, ...) ! 267: { ! 268: int len; ! 269: int maxlen; ! 270: int result; ! 271: va_list argptr; ! 272: char sbuf[1024]; ! 273: fd_set socket_set; ! 274: struct timeval tv; ! 275: ! 276: va_start(argptr,fmt); ! 277: len=vsnprintf(sbuf,maxlen=sizeof(sbuf)-2,fmt,argptr); ! 278: va_end(argptr); ! 279: ! 280: if(len<0 || len>maxlen) /* format error or output truncated */ ! 281: len=maxlen; ! 282: if(startup!=NULL && startup->options&FTP_OPT_DEBUG_TX) ! 283: lprintf(LOG_DEBUG,"%04d TX: %.*s", sock, len, sbuf); ! 284: memcpy(sbuf+len,"\r\n",2); ! 285: len+=2; ! 286: ! 287: if(sock==INVALID_SOCKET) { ! 288: lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockprintf"); ! 289: return(0); ! 290: } ! 291: ! 292: /* Check socket for writability (using select) */ ! 293: tv.tv_sec=300; ! 294: tv.tv_usec=0; ! 295: ! 296: FD_ZERO(&socket_set); ! 297: FD_SET(sock,&socket_set); ! 298: ! 299: if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) { ! 300: if(result==0) ! 301: lprintf(LOG_WARNING,"%04d !TIMEOUT selecting socket for send" ! 302: ,sock); ! 303: else ! 304: lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket for send" ! 305: ,sock, ERROR_VALUE); ! 306: return(0); ! 307: } ! 308: while((result=sendsocket(sock,sbuf,len))!=len) { ! 309: if(result==SOCKET_ERROR) { ! 310: if(ERROR_VALUE==EWOULDBLOCK) { ! 311: YIELD(); ! 312: continue; ! 313: } ! 314: if(ERROR_VALUE==ECONNRESET) ! 315: lprintf(LOG_WARNING,"%04d Connection reset by peer on send",sock); ! 316: else if(ERROR_VALUE==ECONNABORTED) ! 317: lprintf(LOG_WARNING,"%04d Connection aborted by peer on send",sock); ! 318: else ! 319: lprintf(LOG_WARNING,"%04d !ERROR %d sending",sock,ERROR_VALUE); ! 320: return(0); ! 321: } ! 322: lprintf(LOG_WARNING,"%04d !ERROR: short send: %u instead of %u",sock,result,len); ! 323: } ! 324: return(len); ! 325: } ! 326: ! 327: ! 328: /* Returns the directory index of a virtual lib/dir path (e.g. main/games/filename) */ ! 329: int getdir(char* p, user_t* user) ! 330: { ! 331: char* tp; ! 332: char path[MAX_PATH+1]; ! 333: int dir; ! 334: int lib; ! 335: ! 336: SAFECOPY(path,p); ! 337: p=path; ! 338: ! 339: if(*p=='/') ! 340: p++; ! 341: else if(!strncmp(p,"./",2)) ! 342: p+=2; ! 343: ! 344: tp=strchr(p,'/'); ! 345: if(tp) *tp=0; ! 346: for(lib=0;lib<scfg.total_libs;lib++) { ! 347: if(!chk_ar(&scfg,scfg.lib[lib]->ar,user)) ! 348: continue; ! 349: if(!stricmp(scfg.lib[lib]->sname,p)) ! 350: break; ! 351: } ! 352: if(lib>=scfg.total_libs) ! 353: return(-1); ! 354: ! 355: if(tp!=NULL) ! 356: p=tp+1; ! 357: ! 358: tp=strchr(p,'/'); ! 359: if(tp) *tp=0; ! 360: for(dir=0;dir<scfg.total_dirs;dir++) { ! 361: if(scfg.dir[dir]->lib!=lib) ! 362: continue; ! 363: if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir ! 364: && !chk_ar(&scfg,scfg.dir[dir]->ar,user)) ! 365: continue; ! 366: if(!stricmp(scfg.dir[dir]->code_suffix,p)) ! 367: break; ! 368: } ! 369: if(dir>=scfg.total_dirs) ! 370: return(-1); ! 371: ! 372: return(dir); ! 373: } ! 374: ! 375: /*********************************/ ! 376: /* JavaScript Data and Functions */ ! 377: /*********************************/ ! 378: #ifdef JAVASCRIPT ! 379: ! 380: js_server_props_t js_server_props; ! 381: ! 382: static JSBool ! 383: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 384: { ! 385: uintN i; ! 386: JSString* str=NULL; ! 387: FILE* fp; ! 388: ! 389: if((fp=(FILE*)JS_GetContextPrivate(cx))==NULL) ! 390: return(JS_FALSE); ! 391: ! 392: for (i = 0; i < argc; i++) { ! 393: str = JS_ValueToString(cx, argv[i]); ! 394: if (!str) ! 395: return JS_FALSE; ! 396: fprintf(fp,"%s",JS_GetStringBytes(str)); ! 397: } ! 398: ! 399: if(str==NULL) ! 400: *rval = JSVAL_VOID; ! 401: else ! 402: *rval = STRING_TO_JSVAL(str); ! 403: return(JS_TRUE); ! 404: } ! 405: ! 406: static JSBool ! 407: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 408: { ! 409: FILE* fp; ! 410: ! 411: if((fp=(FILE*)JS_GetContextPrivate(cx))==NULL) ! 412: return(JS_FALSE); ! 413: ! 414: js_write(cx,obj,argc,argv,rval); ! 415: fprintf(fp,"\r\n"); ! 416: return(JS_TRUE); ! 417: } ! 418: ! 419: static JSFunctionSpec js_global_functions[] = { ! 420: {"write", js_write, 1}, /* write to HTML file */ ! 421: {"writeln", js_writeln, 1}, /* write to HTML file */ ! 422: {"print", js_writeln, 1}, /* alias for writeln */ ! 423: {0} ! 424: }; ! 425: ! 426: static void ! 427: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) ! 428: { ! 429: char line[64]; ! 430: char file[MAX_PATH+1]; ! 431: char* warning; ! 432: FILE* fp; ! 433: ! 434: fp=(FILE*)JS_GetContextPrivate(cx); ! 435: ! 436: if(report==NULL) { ! 437: lprintf(LOG_ERR,"!JavaScript: %s", message); ! 438: if(fp!=NULL) ! 439: fprintf(fp,"!JavaScript: %s", message); ! 440: return; ! 441: } ! 442: ! 443: if(report->filename) ! 444: sprintf(file," %s",report->filename); ! 445: else ! 446: file[0]=0; ! 447: ! 448: if(report->lineno) ! 449: sprintf(line," line %u",report->lineno); ! 450: else ! 451: line[0]=0; ! 452: ! 453: if(JSREPORT_IS_WARNING(report->flags)) { ! 454: if(JSREPORT_IS_STRICT(report->flags)) ! 455: warning="strict warning"; ! 456: else ! 457: warning="warning"; ! 458: } else ! 459: warning=""; ! 460: ! 461: lprintf(LOG_ERR,"!JavaScript %s%s%s: %s",warning,file,line,message); ! 462: if(fp!=NULL) ! 463: fprintf(fp,"!JavaScript %s%s%s: %s",warning,file,line,message); ! 464: } ! 465: ! 466: static JSContext* ! 467: js_initcx(JSRuntime* runtime, SOCKET sock, JSObject** glob, JSObject** ftp) ! 468: { ! 469: JSContext* js_cx; ! 470: JSObject* js_glob; ! 471: BOOL success=FALSE; ! 472: ! 473: lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)" ! 474: ,sock,startup->js.cx_stack); ! 475: ! 476: if((js_cx = JS_NewContext(runtime, startup->js.cx_stack))==NULL) ! 477: return(NULL); ! 478: ! 479: lprintf(LOG_DEBUG,"%04d JavaScript: Context created",sock); ! 480: ! 481: JS_SetErrorReporter(js_cx, js_ErrorReporter); ! 482: ! 483: do { ! 484: ! 485: lprintf(LOG_DEBUG,"%04d JavaScript: Initializing Global object",sock); ! 486: if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL) ! 487: break; ! 488: ! 489: if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions)) ! 490: break; ! 491: ! 492: lprintf(LOG_DEBUG,"%04d JavaScript: Initializing System object",sock); ! 493: if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL) ! 494: break; ! 495: ! 496: if((*ftp=JS_DefineObject(js_cx, js_glob, "ftp", NULL ! 497: ,NULL,JSPROP_ENUMERATE|JSPROP_READONLY))==NULL) ! 498: break; ! 499: ! 500: if(js_CreateServerObject(js_cx,js_glob,&js_server_props)==NULL) ! 501: break; ! 502: ! 503: if(glob!=NULL) ! 504: *glob=js_glob; ! 505: ! 506: success=TRUE; ! 507: ! 508: } while(0); ! 509: ! 510: if(!success) { ! 511: JS_DestroyContext(js_cx); ! 512: return(NULL); ! 513: } ! 514: ! 515: return(js_cx); ! 516: } ! 517: ! 518: BOOL js_add_file(JSContext* js_cx, JSObject* array, ! 519: char* name, char* desc, char* ext_desc, ! 520: ulong size, ulong credits, ! 521: time_t time, time_t uploaded, time_t last_downloaded, ! 522: ulong times_downloaded, ulong misc, ! 523: char* uploader, char* link) ! 524: { ! 525: JSObject* file; ! 526: JSString* js_str; ! 527: jsval val; ! 528: jsuint index; ! 529: ! 530: if((file=JS_NewObject(js_cx, NULL, NULL, NULL))==NULL) ! 531: return(FALSE); ! 532: ! 533: if((js_str=JS_NewStringCopyZ(js_cx, name))==NULL) ! 534: return(FALSE); ! 535: val=STRING_TO_JSVAL(js_str); ! 536: if(!JS_SetProperty(js_cx, file, "name", &val)) ! 537: return(FALSE); ! 538: ! 539: if((js_str=JS_NewStringCopyZ(js_cx, desc))==NULL) ! 540: return(FALSE); ! 541: val=STRING_TO_JSVAL(js_str); ! 542: if(!JS_SetProperty(js_cx, file, "description", &val)) ! 543: return(FALSE); ! 544: ! 545: if((js_str=JS_NewStringCopyZ(js_cx, ext_desc))==NULL) ! 546: return(FALSE); ! 547: val=STRING_TO_JSVAL(js_str); ! 548: if(!JS_SetProperty(js_cx, file, "extended_description", &val)) ! 549: return(FALSE); ! 550: ! 551: val=INT_TO_JSVAL(size); ! 552: if(!JS_SetProperty(js_cx, file, "size", &val)) ! 553: return(FALSE); ! 554: ! 555: val=INT_TO_JSVAL(credits); ! 556: if(!JS_SetProperty(js_cx, file, "credits", &val)) ! 557: return(FALSE); ! 558: ! 559: JS_NewNumberValue(js_cx,time,&val); ! 560: if(!JS_SetProperty(js_cx, file, "time", &val)) ! 561: return(FALSE); ! 562: ! 563: val=INT_TO_JSVAL(uploaded); ! 564: if(!JS_SetProperty(js_cx, file, "uploaded", &val)) ! 565: return(FALSE); ! 566: ! 567: val=INT_TO_JSVAL(last_downloaded); ! 568: if(!JS_SetProperty(js_cx, file, "last_downloaded", &val)) ! 569: return(FALSE); ! 570: ! 571: val=INT_TO_JSVAL(times_downloaded); ! 572: if(!JS_SetProperty(js_cx, file, "times_downloaded", &val)) ! 573: return(FALSE); ! 574: ! 575: if((js_str=JS_NewStringCopyZ(js_cx, uploader))==NULL) ! 576: return(FALSE); ! 577: val=STRING_TO_JSVAL(js_str); ! 578: if(!JS_SetProperty(js_cx, file, "uploader", &val)) ! 579: return(FALSE); ! 580: ! 581: val=INT_TO_JSVAL(misc); ! 582: if(!JS_SetProperty(js_cx, file, "settings", &val)) ! 583: return(FALSE); ! 584: ! 585: if((js_str=JS_NewStringCopyZ(js_cx, link))==NULL) ! 586: return(FALSE); ! 587: val=STRING_TO_JSVAL(js_str); ! 588: if(!JS_SetProperty(js_cx, file, "link", &val)) ! 589: return(FALSE); ! 590: ! 591: if(!JS_GetArrayLength(js_cx, array, &index)) ! 592: return(FALSE); ! 593: ! 594: val=OBJECT_TO_JSVAL(file); ! 595: return(JS_SetElement(js_cx, array, index, &val)); ! 596: } ! 597: ! 598: BOOL js_generate_index(JSContext* js_cx, JSObject* parent, ! 599: SOCKET sock, FILE* fp, int lib, int dir, user_t* user) ! 600: { ! 601: char str[256]; ! 602: char path[MAX_PATH+1]; ! 603: char spath[MAX_PATH+1]; /* script path */ ! 604: char vpath[MAX_PATH+1]; /* virtual path */ ! 605: char aliasfile[MAX_PATH+1]; ! 606: char extdesc[513]; ! 607: char* p; ! 608: char* tp; ! 609: char* np; ! 610: char* dp; ! 611: char aliasline[512]; ! 612: BOOL alias_dir; ! 613: BOOL success=FALSE; ! 614: FILE* alias_fp; ! 615: uint i; ! 616: file_t f; ! 617: glob_t g; ! 618: jsval val; ! 619: jsval rval; ! 620: JSObject* lib_obj=NULL; ! 621: JSObject* dir_obj=NULL; ! 622: JSObject* file_array=NULL; ! 623: JSObject* dir_array=NULL; ! 624: JSScript* js_script=NULL; ! 625: JSString* js_str; ! 626: ! 627: JS_SetContextPrivate(js_cx, fp); ! 628: ! 629: do { /* pseudo try/catch */ ! 630: ! 631: if((file_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) { ! 632: lprintf(LOG_ERR,"%04d !JavaScript FAILED to create file_array",sock); ! 633: break; ! 634: } ! 635: ! 636: /* file[] */ ! 637: val=OBJECT_TO_JSVAL(file_array); ! 638: if(!JS_SetProperty(js_cx, parent, "file_list", &val)) { ! 639: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set file property",sock); ! 640: break; ! 641: } ! 642: ! 643: if((dir_array=JS_NewArrayObject(js_cx, 0, NULL))==NULL) { ! 644: lprintf(LOG_ERR,"%04d !JavaScript FAILED to create dir_array",sock); ! 645: break; ! 646: } ! 647: ! 648: /* dir[] */ ! 649: val=OBJECT_TO_JSVAL(dir_array); ! 650: if(!JS_SetProperty(js_cx, parent, "dir_list", &val)) { ! 651: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set dir property",sock); ! 652: break; ! 653: } ! 654: ! 655: if(strcspn(startup->html_index_script,"/\\")==strlen(startup->html_index_script)) { ! 656: sprintf(spath,"%s%s",scfg.mods_dir,startup->html_index_script); ! 657: if(scfg.mods_dir[0]==0 || !fexist(spath)) ! 658: sprintf(spath,"%s%s",scfg.exec_dir,startup->html_index_script); ! 659: } else ! 660: sprintf(spath,"%.*s",(int)sizeof(spath)-4,startup->html_index_script); ! 661: /* Add extension if not specified */ ! 662: if(!strchr(spath,'.')) ! 663: strcat(spath,".js"); ! 664: ! 665: if(!fexist(spath)) { ! 666: lprintf(LOG_ERR,"%04d !HTML JavaScript (%s) doesn't exist",sock,spath); ! 667: break; ! 668: } ! 669: ! 670: if((js_str=JS_NewStringCopyZ(js_cx, startup->html_index_file))==NULL) ! 671: break; ! 672: val=STRING_TO_JSVAL(js_str); ! 673: if(!JS_SetProperty(js_cx, parent, "html_index_file", &val)) { ! 674: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set html_index_file property",sock); ! 675: break; ! 676: } ! 677: ! 678: /* curlib */ ! 679: if((lib_obj=JS_NewObject(js_cx, NULL, 0, NULL))==NULL) { ! 680: lprintf(LOG_ERR,"%04d !JavaScript FAILED to create lib_obj",sock); ! 681: break; ! 682: } ! 683: ! 684: val=OBJECT_TO_JSVAL(lib_obj); ! 685: if(!JS_SetProperty(js_cx, parent, "curlib", &val)) { ! 686: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib property",sock); ! 687: break; ! 688: } ! 689: ! 690: /* curdir */ ! 691: if((dir_obj=JS_NewObject(js_cx, NULL, 0, NULL))==NULL) { ! 692: lprintf(LOG_ERR,"%04d !JavaScript FAILED to create dir_obj",sock); ! 693: break; ! 694: } ! 695: ! 696: val=OBJECT_TO_JSVAL(dir_obj); ! 697: if(!JS_SetProperty(js_cx, parent, "curdir", &val)) { ! 698: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir property",sock); ! 699: break; ! 700: } ! 701: ! 702: SAFECOPY(vpath,"/"); ! 703: ! 704: if(lib>=0) { /* root */ ! 705: ! 706: strcat(vpath,scfg.lib[lib]->sname); ! 707: strcat(vpath,"/"); ! 708: ! 709: if((js_str=JS_NewStringCopyZ(js_cx, scfg.lib[lib]->sname))==NULL) ! 710: break; ! 711: val=STRING_TO_JSVAL(js_str); ! 712: if(!JS_SetProperty(js_cx, lib_obj, "name", &val)) { ! 713: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib.name property",sock); ! 714: break; ! 715: } ! 716: ! 717: if((js_str=JS_NewStringCopyZ(js_cx, scfg.lib[lib]->lname))==NULL) ! 718: break; ! 719: val=STRING_TO_JSVAL(js_str); ! 720: if(!JS_SetProperty(js_cx, lib_obj, "description", &val)) { ! 721: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curlib.desc property",sock); ! 722: break; ! 723: } ! 724: } ! 725: ! 726: if(dir>=0) { /* 1st level */ ! 727: strcat(vpath,scfg.dir[dir]->code_suffix); ! 728: strcat(vpath,"/"); ! 729: ! 730: if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->code))==NULL) ! 731: break; ! 732: val=STRING_TO_JSVAL(js_str); ! 733: if(!JS_SetProperty(js_cx, dir_obj, "code", &val)) { ! 734: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.code property",sock); ! 735: break; ! 736: } ! 737: ! 738: if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->sname))==NULL) ! 739: break; ! 740: val=STRING_TO_JSVAL(js_str); ! 741: if(!JS_SetProperty(js_cx, dir_obj, "name", &val)) { ! 742: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.name property",sock); ! 743: break; ! 744: } ! 745: ! 746: if((js_str=JS_NewStringCopyZ(js_cx, scfg.dir[dir]->lname))==NULL) ! 747: break; ! 748: val=STRING_TO_JSVAL(js_str); ! 749: if(!JS_SetProperty(js_cx, dir_obj, "description", &val)) { ! 750: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.desc property",sock); ! 751: break; ! 752: } ! 753: ! 754: val=INT_TO_JSVAL(scfg.dir[dir]->misc); ! 755: if(!JS_SetProperty(js_cx, dir_obj, "settings", &val)) { ! 756: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir.misc property",sock); ! 757: break; ! 758: } ! 759: } ! 760: ! 761: if((js_str=JS_NewStringCopyZ(js_cx, vpath))==NULL) ! 762: break; ! 763: val=STRING_TO_JSVAL(js_str); ! 764: if(!JS_SetProperty(js_cx, parent, "path", &val)) { ! 765: lprintf(LOG_ERR,"%04d !JavaScript FAILED to set curdir property",sock); ! 766: break; ! 767: } ! 768: ! 769: if(lib<0) { /* root dir */ ! 770: ! 771: /* File Aliases */ ! 772: sprintf(path,"%sftpalias.cfg",scfg.ctrl_dir); ! 773: if((alias_fp=fopen(path,"r"))!=NULL) { ! 774: ! 775: while(!feof(alias_fp)) { ! 776: if(!fgets(aliasline,sizeof(aliasline),alias_fp)) ! 777: break; ! 778: ! 779: p=aliasline; /* alias pointer */ ! 780: while(*p && *p<=' ') p++; ! 781: ! 782: if(*p==';') /* comment */ ! 783: continue; ! 784: ! 785: tp=p; /* terminator pointer */ ! 786: while(*tp && *tp>' ') tp++; ! 787: if(*tp) *tp=0; ! 788: ! 789: np=tp+1; /* filename pointer */ ! 790: while(*np && *np<=' ') np++; ! 791: ! 792: tp=np; /* terminator pointer */ ! 793: while(*tp && *tp>' ') tp++; ! 794: if(*tp) *tp=0; ! 795: ! 796: dp=tp+1; /* description pointer */ ! 797: while(*dp && *dp<=' ') dp++; ! 798: truncsp(dp); ! 799: ! 800: if(stricmp(dp,BBS_HIDDEN_ALIAS)==0) ! 801: continue; ! 802: ! 803: alias_dir=FALSE; ! 804: ! 805: /* Virtual Path? */ ! 806: if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) { ! 807: if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),user))<0) ! 808: continue; /* No access or invalid virtual path */ ! 809: tp=strrchr(np,'/'); ! 810: if(tp==NULL) ! 811: continue; ! 812: tp++; ! 813: if(*tp) { ! 814: SAFEPRINTF2(aliasfile,"%s%s",scfg.dir[dir]->path,tp); ! 815: np=aliasfile; ! 816: } ! 817: else ! 818: alias_dir=TRUE; ! 819: } ! 820: ! 821: if(!alias_dir && !fexist(np)) ! 822: continue; ! 823: ! 824: if(alias_dir) { ! 825: if(!chk_ar(&scfg,scfg.dir[dir]->ar,user)) ! 826: continue; ! 827: SAFEPRINTF2(vpath,"/%s/%s",p,startup->html_index_file); ! 828: } else ! 829: SAFECOPY(vpath,p); ! 830: js_add_file(js_cx ! 831: ,alias_dir ? dir_array : file_array ! 832: ,p /* filename */ ! 833: ,dp /* description */ ! 834: ,NULL /* extdesc */ ! 835: ,flength(np) /* size */ ! 836: ,0 /* credits */ ! 837: ,fdate(np) /* time */ ! 838: ,fdate(np) /* uploaded */ ! 839: ,0 /* last downloaded */ ! 840: ,0 /* times downloaded */ ! 841: ,0 /* misc */ ! 842: ,scfg.sys_id /* uploader */ ! 843: ,vpath /* link */ ! 844: ); ! 845: } ! 846: ! 847: fclose(alias_fp); ! 848: } ! 849: ! 850: /* QWK Packet */ ! 851: if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) { ! 852: sprintf(str,"%s.qwk",scfg.sys_id); ! 853: SAFEPRINTF(vpath,"/%s",str); ! 854: js_add_file(js_cx ! 855: ,file_array ! 856: ,str /* filename */ ! 857: ,"QWK Message Packet" /* description */ ! 858: ,NULL /* extdesc */ ! 859: ,10240 /* size */ ! 860: ,0 /* credits */ ! 861: ,time(NULL) /* time */ ! 862: ,0 /* uploaded */ ! 863: ,0 /* last downloaded */ ! 864: ,0 /* times downloaded */ ! 865: ,0 /* misc */ ! 866: ,scfg.sys_id /* uploader */ ! 867: ,str /* link */ ! 868: ); ! 869: } ! 870: ! 871: /* Library Folders */ ! 872: for(i=0;i<scfg.total_libs;i++) { ! 873: if(!chk_ar(&scfg,scfg.lib[i]->ar,user)) ! 874: continue; ! 875: SAFEPRINTF2(vpath,"/%s/%s",scfg.lib[i]->sname,startup->html_index_file); ! 876: js_add_file(js_cx ! 877: ,dir_array ! 878: ,scfg.lib[i]->sname /* filename */ ! 879: ,scfg.lib[i]->lname /* description */ ! 880: ,NULL /* extdesc */ ! 881: ,0,0,0,0,0,0,0 /* unused */ ! 882: ,scfg.sys_id /* uploader */ ! 883: ,vpath /* link */ ! 884: ); ! 885: } ! 886: } else if(dir<0) { ! 887: /* Directories */ ! 888: for(i=0;i<scfg.total_dirs;i++) { ! 889: if(scfg.dir[i]->lib!=lib) ! 890: continue; ! 891: if(/* i!=scfg.sysop_dir && i!=scfg.upload_dir && */ ! 892: !chk_ar(&scfg,scfg.dir[i]->ar,user)) ! 893: continue; ! 894: SAFEPRINTF3(vpath,"/%s/%s/%s" ! 895: ,scfg.lib[scfg.dir[i]->lib]->sname ! 896: ,scfg.dir[i]->code_suffix ! 897: ,startup->html_index_file); ! 898: js_add_file(js_cx ! 899: ,dir_array ! 900: ,scfg.dir[i]->sname /* filename */ ! 901: ,scfg.dir[i]->lname /* description */ ! 902: ,NULL /* extdesc */ ! 903: ,getfiles(&scfg,i) /* size */ ! 904: ,0,0,0,0,0 /* unused */ ! 905: ,scfg.dir[i]->misc /* misc */ ! 906: ,scfg.sys_id /* uploader */ ! 907: ,vpath /* link */ ! 908: ); ! 909: ! 910: } ! 911: } else if(chk_ar(&scfg,scfg.dir[dir]->ar,user)){ ! 912: SAFEPRINTF(path,"%s*",scfg.dir[dir]->path); ! 913: glob(path,0,NULL,&g); ! 914: for(i=0;i<(int)g.gl_pathc;i++) { ! 915: if(isdir(g.gl_pathv[i])) ! 916: continue; ! 917: #ifdef _WIN32 ! 918: GetShortPathName(g.gl_pathv[i], str, sizeof(str)); ! 919: #else ! 920: SAFECOPY(str,g.gl_pathv[i]); ! 921: #endif ! 922: padfname(getfname(str),f.name); ! 923: f.dir=dir; ! 924: if(getfileixb(&scfg,&f)) { ! 925: f.size=0; /* flength(g.gl_pathv[i]); */ ! 926: getfiledat(&scfg,&f); ! 927: if(f.misc&FM_EXTDESC) { ! 928: extdesc[0]=0; ! 929: getextdesc(&scfg, dir, f.datoffset, extdesc); ! 930: /* Remove Ctrl-A Codes and Ex-ASCII code */ ! 931: remove_ctrl_a(extdesc,NULL); ! 932: } ! 933: SAFEPRINTF3(vpath,"/%s/%s/%s" ! 934: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 935: ,scfg.dir[dir]->code_suffix ! 936: ,getfname(g.gl_pathv[i])); ! 937: js_add_file(js_cx ! 938: ,file_array ! 939: ,getfname(g.gl_pathv[i]) /* filename */ ! 940: ,f.desc /* description */ ! 941: ,f.misc&FM_EXTDESC ? extdesc : NULL ! 942: ,f.size /* size */ ! 943: ,f.cdt /* credits */ ! 944: ,f.date /* time */ ! 945: ,f.dateuled /* uploaded */ ! 946: ,f.datedled /* last downloaded */ ! 947: ,f.timesdled /* times downloaded */ ! 948: ,f.misc /* misc */ ! 949: ,f.uler /* uploader */ ! 950: ,getfname(g.gl_pathv[i]) /* link */ ! 951: ); ! 952: } ! 953: } ! 954: globfree(&g); ! 955: } ! 956: ! 957: ! 958: /* RUN SCRIPT */ ! 959: JS_ClearPendingException(js_cx); ! 960: ! 961: if((js_script=JS_CompileFile(js_cx, parent, spath))==NULL) { ! 962: lprintf(LOG_ERR,"%04d !JavaScript FAILED to compile script (%s)",sock,spath); ! 963: break; ! 964: } ! 965: ! 966: if((success=JS_ExecuteScript(js_cx, parent, js_script, &rval))!=TRUE) { ! 967: lprintf(LOG_ERR,"%04d !JavaScript FAILED to execute script (%s)",sock,spath); ! 968: break; ! 969: } ! 970: ! 971: } while(0); ! 972: ! 973: ! 974: if(js_script!=NULL) ! 975: JS_DestroyScript(js_cx, js_script); ! 976: ! 977: JS_DeleteProperty(js_cx, parent, "path"); ! 978: JS_DeleteProperty(js_cx, parent, "sort"); ! 979: JS_DeleteProperty(js_cx, parent, "reverse"); ! 980: JS_DeleteProperty(js_cx, parent, "file_list"); ! 981: JS_DeleteProperty(js_cx, parent, "dir_list"); ! 982: JS_DeleteProperty(js_cx, parent, "curlib"); ! 983: JS_DeleteProperty(js_cx, parent, "curdir"); ! 984: JS_DeleteProperty(js_cx, parent, "html_index_file"); ! 985: ! 986: return(success); ! 987: } ! 988: ! 989: ! 990: #endif /* ifdef JAVASCRIPT */ ! 991: ! 992: ! 993: time_t gettimeleft(scfg_t* cfg, user_t* user, time_t starttime) ! 994: { ! 995: time_t now; ! 996: long tleft; ! 997: time_t timeleft; ! 998: ! 999: now=time(NULL); ! 1000: ! 1001: if(user->exempt&FLAG('T')) { /* Time online exemption */ ! 1002: timeleft=cfg->level_timepercall[user->level]*60; ! 1003: if(timeleft<10) /* never get below 10 for exempt users */ ! 1004: timeleft=10; } ! 1005: else { ! 1006: tleft=(((long)cfg->level_timeperday[user->level]-user->ttoday) ! 1007: +user->textra)*60L; ! 1008: if(tleft<0) tleft=0; ! 1009: if(tleft>cfg->level_timepercall[user->level]*60) ! 1010: tleft=cfg->level_timepercall[user->level]*60; ! 1011: tleft+=user->min*60L; ! 1012: tleft-=now-starttime; ! 1013: if(tleft>0x7fffL) ! 1014: timeleft=0x7fff; ! 1015: else ! 1016: timeleft=tleft; } ! 1017: ! 1018: return(timeleft); ! 1019: } ! 1020: ! 1021: static time_t checktime(void) ! 1022: { ! 1023: struct tm tm; ! 1024: ! 1025: memset(&tm,0,sizeof(tm)); ! 1026: tm.tm_year=94; ! 1027: tm.tm_mday=1; ! 1028: return(mktime(&tm)-0x2D24BD00L); ! 1029: } ! 1030: ! 1031: BOOL upload_stats(ulong bytes) ! 1032: { ! 1033: char str[MAX_PATH+1]; ! 1034: int file; ! 1035: ulong val; ! 1036: ! 1037: sprintf(str,"%sdsts.dab",scfg.ctrl_dir); ! 1038: if((file=nopen(str,O_RDWR))==-1) ! 1039: return(FALSE); ! 1040: ! 1041: lseek(file,20L,SEEK_SET); /* Skip timestamp, logons and logons today */ ! 1042: read(file,&val,4); /* Uploads today */ ! 1043: val++; ! 1044: lseek(file,-4L,SEEK_CUR); ! 1045: write(file,&val,4); ! 1046: read(file,&val,4); /* Upload bytes today */ ! 1047: val+=bytes; ! 1048: lseek(file,-4L,SEEK_CUR); ! 1049: write(file,&val,4); ! 1050: close(file); ! 1051: return(TRUE); ! 1052: } ! 1053: ! 1054: BOOL download_stats(ulong bytes) ! 1055: { ! 1056: char str[MAX_PATH+1]; ! 1057: int file; ! 1058: ulong val; ! 1059: ! 1060: sprintf(str,"%sdsts.dab",scfg.ctrl_dir); ! 1061: if((file=nopen(str,O_RDWR))==-1) ! 1062: return(FALSE); ! 1063: ! 1064: lseek(file,28L,SEEK_SET); /* Skip timestamp, logons and logons today */ ! 1065: read(file,&val,4); /* Downloads today */ ! 1066: val++; ! 1067: lseek(file,-4L,SEEK_CUR); ! 1068: write(file,&val,4); ! 1069: read(file,&val,4); /* Download bytes today */ ! 1070: val+=bytes; ! 1071: lseek(file,-4L,SEEK_CUR); ! 1072: write(file,&val,4); ! 1073: close(file); ! 1074: return(TRUE); ! 1075: } ! 1076: ! 1077: void recverror(SOCKET socket, int rd, int line) ! 1078: { ! 1079: if(rd==0) ! 1080: lprintf(LOG_NOTICE,"%04d Socket closed by peer on receive (line %u)" ! 1081: ,socket, line); ! 1082: else if(rd==SOCKET_ERROR) { ! 1083: if(ERROR_VALUE==ECONNRESET) ! 1084: lprintf(LOG_NOTICE,"%04d Connection reset by peer on receive (line %u)" ! 1085: ,socket, line); ! 1086: else if(ERROR_VALUE==ECONNABORTED) ! 1087: lprintf(LOG_NOTICE,"%04d Connection aborted by peer on receive (line %u)" ! 1088: ,socket, line); ! 1089: else ! 1090: lprintf(LOG_NOTICE,"%04d !ERROR %d receiving on socket (line %u)" ! 1091: ,socket, ERROR_VALUE, line); ! 1092: } else ! 1093: lprintf(LOG_WARNING,"%04d !ERROR: recv on socket returned unexpected value: %d (line %u)" ! 1094: ,socket, rd, line); ! 1095: } ! 1096: ! 1097: int sockreadline(SOCKET socket, char* buf, int len, time_t* lastactive) ! 1098: { ! 1099: char ch; ! 1100: int i,rd=0; ! 1101: fd_set socket_set; ! 1102: struct timeval tv; ! 1103: ! 1104: buf[0]=0; ! 1105: ! 1106: if(socket==INVALID_SOCKET) { ! 1107: lprintf(LOG_WARNING,"INVALID SOCKET in call to sockreadline"); ! 1108: return(0); ! 1109: } ! 1110: ! 1111: while(rd<len-1) { ! 1112: ! 1113: tv.tv_sec=startup->max_inactivity; ! 1114: tv.tv_usec=0; ! 1115: ! 1116: FD_ZERO(&socket_set); ! 1117: FD_SET(socket,&socket_set); ! 1118: ! 1119: i=select(socket+1,&socket_set,NULL,NULL,&tv); ! 1120: ! 1121: if(server_socket==INVALID_SOCKET || terminate_server) { ! 1122: sockprintf(socket,"421 Server downed, aborting."); ! 1123: lprintf(LOG_WARNING,"%04d Server downed, aborting",socket); ! 1124: return(0); ! 1125: } ! 1126: if(i<1) { ! 1127: if(i==0) { ! 1128: if((time(NULL)-(*lastactive))>startup->max_inactivity) { ! 1129: lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",socket); ! 1130: sockprintf(socket,"421 Disconnecting due to inactivity (%u seconds)." ! 1131: ,startup->max_inactivity); ! 1132: return(0); ! 1133: } ! 1134: continue; ! 1135: } ! 1136: recverror(socket,i,__LINE__); ! 1137: return(i); ! 1138: } ! 1139: #ifdef SOCKET_DEBUG_RECV_CHAR ! 1140: socket_debug[socket]|=SOCKET_DEBUG_RECV_CHAR; ! 1141: #endif ! 1142: i=recv(socket, &ch, 1, 0); ! 1143: #ifdef SOCKET_DEBUG_RECV_CHAR ! 1144: socket_debug[socket]&=~SOCKET_DEBUG_RECV_CHAR; ! 1145: #endif ! 1146: if(i<1) { ! 1147: recverror(socket,i,__LINE__); ! 1148: return(i); ! 1149: } ! 1150: if(ch=='\n' /* && rd>=1 */) { /* Mar-9-2003: terminate on sole LF */ ! 1151: break; ! 1152: } ! 1153: buf[rd++]=ch; ! 1154: } ! 1155: if(rd>0 && buf[rd-1]=='\r') ! 1156: buf[rd-1]=0; ! 1157: else ! 1158: buf[rd]=0; ! 1159: ! 1160: return(rd); ! 1161: } ! 1162: ! 1163: #if 0 /* now exported from in xtrn.cpp */ ! 1164: /*****************************************************************************/ ! 1165: /* Returns command line generated from instr with %c replacments */ ! 1166: /*****************************************************************************/ ! 1167: static char* cmdstr(user_t* user, char *instr, char *fpath, char *fspec, char *cmd) ! 1168: { ! 1169: char str[256]; ! 1170: int i,j,len; ! 1171: #ifdef _WIN32 ! 1172: char sfpath[MAX_PATH+1]; ! 1173: #endif ! 1174: ! 1175: len=strlen(instr); ! 1176: for(i=j=0;i<len;i++) { ! 1177: if(instr[i]=='%') { ! 1178: i++; ! 1179: cmd[j]=0; ! 1180: switch(toupper(instr[i])) { ! 1181: case 'A': /* User alias */ ! 1182: strcat(cmd,user->alias); ! 1183: break; ! 1184: case 'B': /* Baud (DTE) Rate */ ! 1185: case 'C': /* Connect Description */ ! 1186: case 'D': /* Connect (DCE) Rate */ ! 1187: case 'E': /* Estimated Rate */ ! 1188: case 'H': /* Port Handle or Hardware Flow Control */ ! 1189: case 'P': /* COM Port */ ! 1190: case 'R': /* Rows */ ! 1191: case 'T': /* Time left in seconds */ ! 1192: case '&': /* Address of msr */ ! 1193: case 'Y': /* COMSPEC */ ! 1194: /* UNSUPPORTED */ ! 1195: break; ! 1196: case 'F': /* File path */ ! 1197: strcat(cmd,fpath); ! 1198: break; ! 1199: case 'G': /* Temp directory */ ! 1200: strcat(cmd,scfg.temp_dir); ! 1201: break; ! 1202: case 'I': /* UART IRQ Line */ ! 1203: strcat(cmd,ultoa(scfg.com_irq,str,10)); ! 1204: break; ! 1205: case 'J': ! 1206: strcat(cmd,scfg.data_dir); ! 1207: break; ! 1208: case 'K': ! 1209: strcat(cmd,scfg.ctrl_dir); ! 1210: break; ! 1211: case 'L': /* Lines per message */ ! 1212: strcat(cmd,ultoa(scfg.level_linespermsg[user->level],str,10)); ! 1213: break; ! 1214: case 'M': /* Minutes (credits) for user */ ! 1215: strcat(cmd,ultoa(user->min,str,10)); ! 1216: break; ! 1217: case 'N': /* Node Directory (same as SBBSNODE environment var) */ ! 1218: strcat(cmd,scfg.node_dir); ! 1219: break; ! 1220: case 'O': /* SysOp */ ! 1221: strcat(cmd,scfg.sys_op); ! 1222: break; ! 1223: case 'Q': /* QWK ID */ ! 1224: strcat(cmd,scfg.sys_id); ! 1225: break; ! 1226: case 'S': /* File Spec */ ! 1227: strcat(cmd,fspec); ! 1228: break; ! 1229: case 'U': /* UART I/O Address (in hex) */ ! 1230: strcat(cmd,ultoa(scfg.com_base,str,16)); ! 1231: break; ! 1232: case 'V': /* Synchronet Version */ ! 1233: sprintf(str,"%s%c",VERSION,REVISION); ! 1234: break; ! 1235: case 'W': /* Time-slice API type (mswtype) */ ! 1236: break; ! 1237: case 'X': ! 1238: strcat(cmd,scfg.shell[user->shell]->code); ! 1239: break; ! 1240: case 'Z': ! 1241: strcat(cmd,scfg.text_dir); ! 1242: break; ! 1243: case '~': /* DOS-compatible (8.3) filename */ ! 1244: #ifdef _WIN32 ! 1245: SAFECOPY(sfpath,fpath); ! 1246: GetShortPathName(fpath,sfpath,sizeof(sfpath)); ! 1247: strcat(cmd,sfpath); ! 1248: #else ! 1249: strcat(cmd,fpath); ! 1250: #endif ! 1251: break; ! 1252: case '!': /* EXEC Directory */ ! 1253: strcat(cmd,scfg.exec_dir); ! 1254: break; ! 1255: case '@': /* EXEC Directory for DOS/OS2/Win32, blank for Unix */ ! 1256: #ifndef __unix__ ! 1257: strcat(cmd,scfg.exec_dir); ! 1258: #endif ! 1259: break; ! 1260: case '#': /* Node number (same as SBBSNNUM environment var) */ ! 1261: sprintf(str,"%u",scfg.node_num); ! 1262: strcat(cmd,str); ! 1263: break; ! 1264: case '*': ! 1265: sprintf(str,"%03u",scfg.node_num); ! 1266: strcat(cmd,str); ! 1267: break; ! 1268: case '$': /* Credits */ ! 1269: strcat(cmd,ultoa(user->cdt+user->freecdt,str,10)); ! 1270: break; ! 1271: case '%': /* %% for percent sign */ ! 1272: strcat(cmd,"%"); ! 1273: break; ! 1274: case '?': /* Platform */ ! 1275: #ifdef __OS2__ ! 1276: SAFECOPY(str,"OS2"); ! 1277: #else ! 1278: SAFECOPY(str,PLATFORM_DESC); ! 1279: #endif ! 1280: strlwr(str); ! 1281: strcat(cmd,str); ! 1282: break; ! 1283: default: /* unknown specification */ ! 1284: if(isdigit(instr[i])) { ! 1285: sprintf(str,"%0*d",instr[i]&0xf,user->number); ! 1286: strcat(cmd,str); } ! 1287: break; } ! 1288: j=strlen(cmd); } ! 1289: else ! 1290: cmd[j++]=instr[i]; } ! 1291: cmd[j]=0; ! 1292: ! 1293: return(cmd); ! 1294: } ! 1295: #endif ! 1296: ! 1297: void DLLCALL ftp_terminate(void) ! 1298: { ! 1299: lprintf(LOG_DEBUG,"%04d FTP Server terminate",server_socket); ! 1300: terminate_server=TRUE; ! 1301: } ! 1302: ! 1303: ! 1304: typedef struct { ! 1305: SOCKET ctrl_sock; ! 1306: SOCKET* data_sock; ! 1307: BOOL* inprogress; ! 1308: BOOL* aborted; ! 1309: BOOL delfile; ! 1310: BOOL tmpfile; ! 1311: BOOL credits; ! 1312: BOOL append; ! 1313: long filepos; ! 1314: char filename[MAX_PATH+1]; ! 1315: time_t* lastactive; ! 1316: user_t* user; ! 1317: int dir; ! 1318: char* desc; ! 1319: } xfer_t; ! 1320: ! 1321: static void send_thread(void* arg) ! 1322: { ! 1323: char buf[8192]; ! 1324: char fname[MAX_PATH+1]; ! 1325: char str[128]; ! 1326: char tmp[128]; ! 1327: char username[128]; ! 1328: int i; ! 1329: int rd; ! 1330: int wr; ! 1331: long mod; ! 1332: ulong l; ! 1333: ulong total=0; ! 1334: ulong last_total=0; ! 1335: ulong dur; ! 1336: ulong cps; ! 1337: ulong length; ! 1338: BOOL error=FALSE; ! 1339: FILE* fp; ! 1340: file_t f; ! 1341: xfer_t xfer; ! 1342: time_t now; ! 1343: time_t start; ! 1344: time_t last_report; ! 1345: user_t uploader; ! 1346: SOCKADDR_IN addr; ! 1347: socklen_t addr_len; ! 1348: fd_set socket_set; ! 1349: struct timeval tv; ! 1350: ! 1351: xfer=*(xfer_t*)arg; ! 1352: free(arg); ! 1353: ! 1354: thread_up(TRUE /* setuid */); ! 1355: ! 1356: length=flength(xfer.filename); ! 1357: ! 1358: if((fp=fnopen(NULL,xfer.filename,O_RDONLY|O_BINARY))==NULL /* non-shareable open failed */ ! 1359: && (fp=fopen(xfer.filename,"rb"))==NULL) { /* shareable open failed */ ! 1360: lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename); ! 1361: sockprintf(xfer.ctrl_sock,"450 ERROR %d opening %s.",errno,xfer.filename); ! 1362: if(xfer.tmpfile && !(startup->options&FTP_OPT_KEEP_TEMP_FILES)) ! 1363: remove(xfer.filename); ! 1364: ftp_close_socket(xfer.data_sock,__LINE__); ! 1365: *xfer.inprogress=FALSE; ! 1366: thread_down(); ! 1367: return; ! 1368: } ! 1369: ! 1370: #ifdef SOCKET_DEBUG_SENDTHREAD ! 1371: socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SENDTHREAD; ! 1372: #endif ! 1373: ! 1374: *xfer.aborted=FALSE; ! 1375: if(startup->options&FTP_OPT_DEBUG_DATA || xfer.filepos) ! 1376: lprintf(LOG_DEBUG,"%04d DATA socket %d sending %s from offset %lu" ! 1377: ,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos); ! 1378: ! 1379: fseek(fp,xfer.filepos,SEEK_SET); ! 1380: last_report=start=time(NULL); ! 1381: while((xfer.filepos+total)<length) { ! 1382: ! 1383: now=time(NULL); ! 1384: ! 1385: /* Periodic progress report */ ! 1386: if(total && now>=last_report+XFER_REPORT_INTERVAL) { ! 1387: if(xfer.filepos) ! 1388: sprintf(str," from offset %lu",xfer.filepos); ! 1389: else ! 1390: str[0]=0; ! 1391: lprintf(LOG_INFO,"%04d Sent %lu bytes (%lu total) of %s (%lu cps)%s" ! 1392: ,xfer.ctrl_sock,total,length,xfer.filename ! 1393: ,(total-last_total)/(now-last_report) ! 1394: ,str); ! 1395: last_total=total; ! 1396: last_report=now; ! 1397: } ! 1398: ! 1399: if(*xfer.aborted==TRUE) { ! 1400: lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock); ! 1401: sockprintf(xfer.ctrl_sock,"426 Transfer aborted."); ! 1402: error=TRUE; ! 1403: break; ! 1404: } ! 1405: if(server_socket==INVALID_SOCKET || terminate_server) { ! 1406: lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock); ! 1407: sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted."); ! 1408: error=TRUE; ! 1409: break; ! 1410: } ! 1411: ! 1412: /* Check socket for writability (using select) */ ! 1413: tv.tv_sec=1; ! 1414: tv.tv_usec=0; ! 1415: ! 1416: FD_ZERO(&socket_set); ! 1417: FD_SET(*xfer.data_sock,&socket_set); ! 1418: ! 1419: i=select((*xfer.data_sock)+1,NULL,&socket_set,NULL,&tv); ! 1420: if(i==SOCKET_ERROR) { ! 1421: lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for send" ! 1422: ,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock); ! 1423: sockprintf(xfer.ctrl_sock,"426 Transfer error."); ! 1424: error=TRUE; ! 1425: break; ! 1426: } ! 1427: if(i<1) ! 1428: continue; ! 1429: ! 1430: fseek(fp,xfer.filepos+total,SEEK_SET); ! 1431: rd=fread(buf,sizeof(char),sizeof(buf),fp); ! 1432: if(rd<1) /* EOF or READ error */ ! 1433: break; ! 1434: ! 1435: #ifdef SOCKET_DEBUG_SEND ! 1436: socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_SEND; ! 1437: #endif ! 1438: wr=sendsocket(*xfer.data_sock,buf,rd); ! 1439: #ifdef SOCKET_DEBUG_SEND ! 1440: socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SEND; ! 1441: #endif ! 1442: if(wr<1) { ! 1443: if(wr==SOCKET_ERROR) { ! 1444: if(ERROR_VALUE==EWOULDBLOCK) { ! 1445: /*lprintf(LOG_WARNING,"%04d DATA send would block, retrying",xfer.ctrl_sock);*/ ! 1446: YIELD(); ! 1447: continue; ! 1448: } ! 1449: else if(ERROR_VALUE==ECONNRESET) ! 1450: lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, sending on socket %d" ! 1451: ,xfer.ctrl_sock,*xfer.data_sock); ! 1452: else if(ERROR_VALUE==ECONNABORTED) ! 1453: lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, sending on socket %d" ! 1454: ,xfer.ctrl_sock,*xfer.data_sock); ! 1455: else ! 1456: lprintf(LOG_WARNING,"%04d !DATA ERROR %d sending on data socket %d" ! 1457: ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock); ! 1458: /* Send NAK */ ! 1459: sockprintf(xfer.ctrl_sock,"426 Error %d sending on DATA channel" ! 1460: ,ERROR_VALUE); ! 1461: error=TRUE; ! 1462: break; ! 1463: } ! 1464: if(wr==0) { ! 1465: lprintf(LOG_WARNING,"%04d !DATA socket %d disconnected",xfer.ctrl_sock, *xfer.data_sock); ! 1466: sockprintf(xfer.ctrl_sock,"426 DATA channel disconnected"); ! 1467: error=TRUE; ! 1468: break; ! 1469: } ! 1470: lprintf(LOG_ERR,"%04d !DATA SEND ERROR %d (%d) on socket %d" ! 1471: ,xfer.ctrl_sock, wr, ERROR_VALUE, *xfer.data_sock); ! 1472: sockprintf(xfer.ctrl_sock,"451 DATA send error"); ! 1473: error=TRUE; ! 1474: break; ! 1475: } ! 1476: total+=wr; ! 1477: *xfer.lastactive=time(NULL); ! 1478: YIELD(); ! 1479: } ! 1480: ! 1481: if((i=ferror(fp))!=0) ! 1482: lprintf(LOG_ERR,"%04d !FILE ERROR %d (%d)",xfer.ctrl_sock,i,errno); ! 1483: ! 1484: ftp_close_socket(xfer.data_sock,__LINE__); /* Signal end of file */ ! 1485: if(startup->options&FTP_OPT_DEBUG_DATA) ! 1486: lprintf(LOG_DEBUG,"%04d DATA socket closed",xfer.ctrl_sock); ! 1487: ! 1488: if(!error) { ! 1489: dur=time(NULL)-start; ! 1490: cps=dur ? total/dur : total*2; ! 1491: lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes sent in %lu seconds (%lu cps)" ! 1492: ,xfer.ctrl_sock ! 1493: ,total,dur,cps); ! 1494: sockprintf(xfer.ctrl_sock,"226 Download complete (%lu cps).",cps); ! 1495: ! 1496: if(xfer.dir>=0) { ! 1497: memset(&f,0,sizeof(f)); ! 1498: #ifdef _WIN32 ! 1499: GetShortPathName(xfer.filename,fname,sizeof(fname)); ! 1500: #else ! 1501: SAFECOPY(fname,xfer.filename); ! 1502: #endif ! 1503: padfname(getfname(fname),f.name); ! 1504: f.dir=xfer.dir; ! 1505: f.size=total; ! 1506: if(getfileixb(&scfg,&f)==TRUE && getfiledat(&scfg,&f)==TRUE) { ! 1507: f.timesdled++; ! 1508: putfiledat(&scfg,&f); ! 1509: f.datedled=time(NULL); ! 1510: putfileixb(&scfg,&f); ! 1511: ! 1512: lprintf(LOG_INFO,"%04d %s downloaded: %s (%lu times total)" ! 1513: ,xfer.ctrl_sock ! 1514: ,xfer.user->alias ! 1515: ,xfer.filename ! 1516: ,f.timesdled); ! 1517: /**************************/ ! 1518: /* Update Uploader's Info */ ! 1519: /**************************/ ! 1520: uploader.number=matchuser(&scfg,f.uler,TRUE /*sysop_alias*/); ! 1521: if(uploader.number ! 1522: && uploader.number!=xfer.user->number ! 1523: && getuserdat(&scfg,&uploader)==0 ! 1524: && uploader.firston<f.dateuled) { ! 1525: l=f.cdt; ! 1526: if(!(scfg.dir[f.dir]->misc&DIR_CDTDL)) /* Don't give credits on d/l */ ! 1527: l=0; ! 1528: if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) { /* Give min instead of cdt */ ! 1529: mod=((ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0))/cps)/60; ! 1530: adjustuserrec(&scfg,uploader.number,U_MIN,10,mod); ! 1531: sprintf(tmp,"%lu minute",mod); ! 1532: } else { ! 1533: mod=(ulong)(l*(scfg.dir[f.dir]->dn_pct/100.0)); ! 1534: adjustuserrec(&scfg,uploader.number,U_CDT,10,mod); ! 1535: ultoac(mod,tmp); ! 1536: } ! 1537: if(!(scfg.dir[f.dir]->misc&DIR_QUIET)) { ! 1538: addr_len = sizeof(addr); ! 1539: if(uploader.level>=SYSOP_LEVEL ! 1540: && getpeername(xfer.ctrl_sock,(struct sockaddr *)&addr,&addr_len)==0) ! 1541: SAFEPRINTF2(username,"%s [%s]",xfer.user->alias,inet_ntoa(addr.sin_addr)); ! 1542: else ! 1543: SAFECOPY(username,xfer.user->alias); ! 1544: /* Inform uploader of downloaded file */ ! 1545: safe_snprintf(str,sizeof(str),text[DownloadUserMsg] ! 1546: ,getfname(xfer.filename) ! 1547: ,xfer.filepos ? "partially FTP-" : "FTP-" ! 1548: ,username,tmp); ! 1549: putsmsg(&scfg,uploader.number,str); ! 1550: } ! 1551: } ! 1552: } ! 1553: if(!xfer.tmpfile && !xfer.delfile && !(scfg.dir[f.dir]->misc&DIR_NOSTAT)) ! 1554: download_stats(total); ! 1555: } ! 1556: ! 1557: if(xfer.credits) { ! 1558: user_downloaded(&scfg, xfer.user, 1, total); ! 1559: if(xfer.dir>=0 && !is_download_free(&scfg,xfer.dir,xfer.user)) ! 1560: subtract_cdt(&scfg, xfer.user, xfer.credits); ! 1561: } ! 1562: } ! 1563: ! 1564: fclose(fp); ! 1565: if(server_socket!=INVALID_SOCKET && !terminate_server) ! 1566: *xfer.inprogress=FALSE; ! 1567: if(xfer.tmpfile) { ! 1568: if(!(startup->options&FTP_OPT_KEEP_TEMP_FILES)) ! 1569: remove(xfer.filename); ! 1570: } ! 1571: else if(xfer.delfile && !error) ! 1572: remove(xfer.filename); ! 1573: ! 1574: #if defined(SOCKET_DEBUG_SENDTHREAD) ! 1575: socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_SENDTHREAD; ! 1576: #endif ! 1577: ! 1578: thread_down(); ! 1579: } ! 1580: ! 1581: static void receive_thread(void* arg) ! 1582: { ! 1583: char* p; ! 1584: char str[128]; ! 1585: char buf[8192]; ! 1586: char ext[F_EXBSIZE+1]; ! 1587: char desc[F_EXBSIZE+1]; ! 1588: char cmd[MAX_PATH*2]; ! 1589: char tmp[MAX_PATH+1]; ! 1590: char fname[MAX_PATH+1]; ! 1591: int i; ! 1592: int rd; ! 1593: int file; ! 1594: ulong total=0; ! 1595: ulong last_total=0; ! 1596: ulong dur; ! 1597: ulong cps; ! 1598: BOOL error=FALSE; ! 1599: BOOL filedat; ! 1600: FILE* fp; ! 1601: file_t f; ! 1602: xfer_t xfer; ! 1603: time_t now; ! 1604: time_t start; ! 1605: time_t last_report; ! 1606: fd_set socket_set; ! 1607: struct timeval tv; ! 1608: ! 1609: xfer=*(xfer_t*)arg; ! 1610: free(arg); ! 1611: ! 1612: thread_up(TRUE /* setuid */); ! 1613: ! 1614: if((fp=fopen(xfer.filename,xfer.append ? "ab" : "wb"))==NULL) { ! 1615: lprintf(LOG_ERR,"%04d !DATA ERROR %d opening %s",xfer.ctrl_sock,errno,xfer.filename); ! 1616: sockprintf(xfer.ctrl_sock,"450 ERROR %d opening %s.",errno,xfer.filename); ! 1617: ftp_close_socket(xfer.data_sock,__LINE__); ! 1618: *xfer.inprogress=FALSE; ! 1619: thread_down(); ! 1620: return; ! 1621: } ! 1622: ! 1623: if(xfer.append) ! 1624: xfer.filepos=filelength(fileno(fp)); ! 1625: ! 1626: *xfer.aborted=FALSE; ! 1627: if(xfer.filepos || startup->options&FTP_OPT_DEBUG_DATA) ! 1628: lprintf(LOG_DEBUG,"%04d DATA socket %d receiving %s from offset %lu" ! 1629: ,xfer.ctrl_sock,*xfer.data_sock,xfer.filename,xfer.filepos); ! 1630: ! 1631: fseek(fp,xfer.filepos,SEEK_SET); ! 1632: last_report=start=time(NULL); ! 1633: while(1) { ! 1634: ! 1635: now=time(NULL); ! 1636: ! 1637: /* Periodic progress report */ ! 1638: if(total && now>=last_report+XFER_REPORT_INTERVAL) { ! 1639: if(xfer.filepos) ! 1640: sprintf(str," from offset %lu",xfer.filepos); ! 1641: else ! 1642: str[0]=0; ! 1643: lprintf(LOG_INFO,"%04d Received %lu bytes of %s (%lu cps)%s" ! 1644: ,xfer.ctrl_sock,total,xfer.filename ! 1645: ,(total-last_total)/(now-last_report) ! 1646: ,str); ! 1647: last_total=total; ! 1648: last_report=now; ! 1649: } ! 1650: if(*xfer.aborted==TRUE) { ! 1651: lprintf(LOG_WARNING,"%04d !DATA Transfer aborted",xfer.ctrl_sock); ! 1652: /* Send NAK */ ! 1653: sockprintf(xfer.ctrl_sock,"426 Transfer aborted."); ! 1654: error=TRUE; ! 1655: break; ! 1656: } ! 1657: if(server_socket==INVALID_SOCKET || terminate_server) { ! 1658: lprintf(LOG_WARNING,"%04d !DATA Transfer locally aborted",xfer.ctrl_sock); ! 1659: /* Send NAK */ ! 1660: sockprintf(xfer.ctrl_sock,"426 Transfer locally aborted."); ! 1661: error=TRUE; ! 1662: break; ! 1663: } ! 1664: ! 1665: /* Check socket for readability (using select) */ ! 1666: tv.tv_sec=1; ! 1667: tv.tv_usec=0; ! 1668: ! 1669: FD_ZERO(&socket_set); ! 1670: FD_SET(*xfer.data_sock,&socket_set); ! 1671: ! 1672: i=select((*xfer.data_sock)+1,&socket_set,NULL,NULL,&tv); ! 1673: if(i==SOCKET_ERROR) { ! 1674: lprintf(LOG_WARNING,"%04d !DATA ERROR %d selecting socket %d for receive" ! 1675: ,xfer.ctrl_sock, ERROR_VALUE, *xfer.data_sock); ! 1676: sockprintf(xfer.ctrl_sock,"426 Transfer error."); ! 1677: error=TRUE; ! 1678: break; ! 1679: } ! 1680: if(i<1) ! 1681: continue; ! 1682: ! 1683: #if defined(SOCKET_DEBUG_RECV_BUF) ! 1684: socket_debug[xfer.ctrl_sock]|=SOCKET_DEBUG_RECV_BUF; ! 1685: #endif ! 1686: rd=recv(*xfer.data_sock,buf,sizeof(buf),0); ! 1687: #if defined(SOCKET_DEBUG_RECV_BUF) ! 1688: socket_debug[xfer.ctrl_sock]&=~SOCKET_DEBUG_RECV_BUF; ! 1689: #endif ! 1690: if(rd<1) { ! 1691: if(rd==0) { /* Socket closed */ ! 1692: if(startup->options&FTP_OPT_DEBUG_DATA) ! 1693: lprintf(LOG_DEBUG,"%04d DATA socket %d closed by client" ! 1694: ,xfer.ctrl_sock,*xfer.data_sock); ! 1695: break; ! 1696: } ! 1697: if(rd==SOCKET_ERROR) { ! 1698: if(ERROR_VALUE==EWOULDBLOCK) { ! 1699: /*lprintf(LOG_WARNING,"%04d DATA recv would block, retrying",xfer.ctrl_sock);*/ ! 1700: YIELD(); ! 1701: continue; ! 1702: } ! 1703: else if(ERROR_VALUE==ECONNRESET) ! 1704: lprintf(LOG_WARNING,"%04d DATA Connection reset by peer, receiving on socket %d" ! 1705: ,xfer.ctrl_sock,*xfer.data_sock); ! 1706: else if(ERROR_VALUE==ECONNABORTED) ! 1707: lprintf(LOG_WARNING,"%04d DATA Connection aborted by peer, receiving on socket %d" ! 1708: ,xfer.ctrl_sock,*xfer.data_sock); ! 1709: else ! 1710: lprintf(LOG_WARNING,"%04d !DATA ERROR %d receiving on data socket %d" ! 1711: ,xfer.ctrl_sock,ERROR_VALUE,*xfer.data_sock); ! 1712: /* Send NAK */ ! 1713: sockprintf(xfer.ctrl_sock,"426 Error %d receiving on DATA channel" ! 1714: ,ERROR_VALUE); ! 1715: error=TRUE; ! 1716: break; ! 1717: } ! 1718: lprintf(LOG_ERR,"%04d !DATA ERROR recv returned %d on socket %d" ! 1719: ,xfer.ctrl_sock,rd,*xfer.data_sock); ! 1720: /* Send NAK */ ! 1721: sockprintf(xfer.ctrl_sock,"451 Unexpected socket error: %d",rd); ! 1722: error=TRUE; ! 1723: break; ! 1724: } ! 1725: fwrite(buf,1,rd,fp); ! 1726: total+=rd; ! 1727: *xfer.lastactive=time(NULL); ! 1728: YIELD(); ! 1729: } ! 1730: ! 1731: if(server_socket!=INVALID_SOCKET && !terminate_server) ! 1732: *xfer.inprogress=FALSE; ! 1733: fclose(fp); ! 1734: ! 1735: ftp_close_socket(xfer.data_sock,__LINE__); ! 1736: if(error && startup->options&FTP_OPT_DEBUG_DATA) ! 1737: lprintf(LOG_DEBUG,"%04d DATA socket %d closed",xfer.ctrl_sock,*xfer.data_sock); ! 1738: ! 1739: if(!error) { ! 1740: dur=time(NULL)-start; ! 1741: cps=dur ? total/dur : total*2; ! 1742: lprintf(LOG_INFO,"%04d Transfer successful: %lu bytes received in %lu seconds (%lu cps)" ! 1743: ,xfer.ctrl_sock ! 1744: ,total,dur,cps); ! 1745: ! 1746: if(xfer.dir>=0) { ! 1747: memset(&f,0,sizeof(f)); ! 1748: #ifdef _WIN32 ! 1749: GetShortPathName(xfer.filename,fname,sizeof(fname)); ! 1750: #else ! 1751: SAFECOPY(fname,xfer.filename); ! 1752: #endif ! 1753: padfname(getfname(fname),f.name); ! 1754: f.dir=xfer.dir; ! 1755: filedat=getfileixb(&scfg,&f); ! 1756: if(scfg.dir[f.dir]->misc&DIR_AONLY) /* Forced anonymous */ ! 1757: f.misc|=FM_ANON; ! 1758: f.cdt=flength(xfer.filename); ! 1759: f.dateuled=time(NULL); ! 1760: ! 1761: /* Desciption specified with DESC command? */ ! 1762: if(xfer.desc!=NULL && *xfer.desc!=0) ! 1763: SAFECOPY(f.desc,xfer.desc); ! 1764: ! 1765: /* Necessary for DIR and LIB ARS keyword support in subsequent chk_ar()'s */ ! 1766: SAFECOPY(xfer.user->curdir, scfg.dir[f.dir]->code); ! 1767: ! 1768: /* FILE_ID.DIZ support */ ! 1769: p=strrchr(f.name,'.'); ! 1770: if(p!=NULL && scfg.dir[f.dir]->misc&DIR_DIZ) { ! 1771: for(i=0;i<scfg.total_fextrs;i++) ! 1772: if(!stricmp(scfg.fextr[i]->ext,p+1) ! 1773: && chk_ar(&scfg,scfg.fextr[i]->ar,xfer.user)) ! 1774: break; ! 1775: if(i<scfg.total_fextrs) { ! 1776: sprintf(tmp,"%sFILE_ID.DIZ",scfg.temp_dir); ! 1777: if(fexistcase(tmp)) ! 1778: remove(tmp); ! 1779: system(cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"FILE_ID.DIZ",cmd)); ! 1780: if(!fexistcase(tmp)) { ! 1781: sprintf(tmp,"%sDESC.SDI",scfg.temp_dir); ! 1782: if(fexistcase(tmp)) ! 1783: remove(tmp); ! 1784: system(cmdstr(&scfg,xfer.user,scfg.fextr[i]->cmd,fname,"DESC.SDI",cmd)); ! 1785: fexistcase(tmp); /* fixes filename case */ ! 1786: } ! 1787: if((file=nopen(tmp,O_RDONLY))!=-1) { ! 1788: memset(ext,0,sizeof(ext)); ! 1789: read(file,ext,sizeof(ext)-1); ! 1790: for(i=sizeof(ext)-1;i;i--) /* trim trailing spaces */ ! 1791: if(ext[i-1]>' ') ! 1792: break; ! 1793: ext[i]=0; ! 1794: if(!f.desc[0]) { /* use for normal description */ ! 1795: SAFECOPY(desc,ext); ! 1796: strip_exascii(desc); /* strip extended ASCII chars */ ! 1797: prep_file_desc(desc); /* strip control chars and dupe chars */ ! 1798: for(i=0;desc[i];i++) /* find approprate first char */ ! 1799: if(isalnum(desc[i])) ! 1800: break; ! 1801: SAFECOPY(f.desc,desc+i); ! 1802: } ! 1803: close(file); ! 1804: remove(tmp); ! 1805: f.misc|=FM_EXTDESC; ! 1806: } ! 1807: } ! 1808: } /* FILE_ID.DIZ support */ ! 1809: ! 1810: if(f.desc[0]==0) /* no description given, use (long) filename */ ! 1811: SAFECOPY(f.desc,getfname(xfer.filename)); ! 1812: ! 1813: SAFECOPY(f.uler,xfer.user->alias); /* exception here, Aug-27-2002 */ ! 1814: if(filedat) { ! 1815: if(!putfiledat(&scfg,&f)) ! 1816: lprintf(LOG_ERR,"%04d !ERROR updating file (%s) in database",xfer.ctrl_sock,f.name); ! 1817: /* need to update the index here */ ! 1818: } else { ! 1819: if(!addfiledat(&scfg,&f)) ! 1820: lprintf(LOG_ERR,"%04d !ERROR adding file (%s) to database",xfer.ctrl_sock,f.name); ! 1821: } ! 1822: ! 1823: if(f.misc&FM_EXTDESC) ! 1824: putextdesc(&scfg,f.dir,f.datoffset,ext); ! 1825: ! 1826: if(scfg.dir[f.dir]->upload_sem[0]) ! 1827: ftouch(scfg.dir[f.dir]->upload_sem); ! 1828: /**************************/ ! 1829: /* Update Uploader's Info */ ! 1830: /**************************/ ! 1831: user_uploaded(&scfg, xfer.user, (!xfer.append && xfer.filepos==0) ? 1:0, total); ! 1832: if(scfg.dir[f.dir]->up_pct && scfg.dir[f.dir]->misc&DIR_CDTUL) { /* credit for upload */ ! 1833: if(scfg.dir[f.dir]->misc&DIR_CDTMIN && cps) /* Give min instead of cdt */ ! 1834: xfer.user->min=adjustuserrec(&scfg,xfer.user->number,U_MIN,10 ! 1835: ,((ulong)(total*(scfg.dir[f.dir]->up_pct/100.0))/cps)/60); ! 1836: else ! 1837: xfer.user->cdt=adjustuserrec(&scfg,xfer.user->number,U_CDT,10 ! 1838: ,(ulong)(f.cdt*(scfg.dir[f.dir]->up_pct/100.0))); ! 1839: } ! 1840: if(!(scfg.dir[f.dir]->misc&DIR_NOSTAT)) ! 1841: upload_stats(total); ! 1842: } ! 1843: /* Send ACK */ ! 1844: sockprintf(xfer.ctrl_sock,"226 Upload complete (%lu cps).",cps); ! 1845: } ! 1846: ! 1847: thread_down(); ! 1848: } ! 1849: ! 1850: ! 1851: ! 1852: static void filexfer(SOCKADDR_IN* addr, SOCKET ctrl_sock, SOCKET pasv_sock, SOCKET* data_sock ! 1853: ,char* filename, long filepos, BOOL* inprogress, BOOL* aborted ! 1854: ,BOOL delfile, BOOL tmpfile ! 1855: ,time_t* lastactive ! 1856: ,user_t* user ! 1857: ,int dir ! 1858: ,BOOL receiving ! 1859: ,BOOL credits ! 1860: ,BOOL append ! 1861: ,char* desc) ! 1862: { ! 1863: int result; ! 1864: ulong l; ! 1865: socklen_t addr_len; ! 1866: SOCKADDR_IN server_addr; ! 1867: BOOL reuseaddr; ! 1868: xfer_t* xfer; ! 1869: struct timeval tv; ! 1870: fd_set socket_set; ! 1871: ! 1872: if((*inprogress)==TRUE) { ! 1873: lprintf(LOG_WARNING,"%04d !TRANSFER already in progress",ctrl_sock); ! 1874: sockprintf(ctrl_sock,"425 Transfer already in progress."); ! 1875: return; ! 1876: } ! 1877: *inprogress=TRUE; ! 1878: ! 1879: if(*data_sock!=INVALID_SOCKET) ! 1880: ftp_close_socket(data_sock,__LINE__); ! 1881: ! 1882: if(pasv_sock==INVALID_SOCKET) { /* !PASV */ ! 1883: ! 1884: if((*data_sock=socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) == INVALID_SOCKET) { ! 1885: lprintf(LOG_ERR,"%04d !DATA ERROR %d opening socket", ctrl_sock, ERROR_VALUE); ! 1886: sockprintf(ctrl_sock,"425 Error %d opening socket",ERROR_VALUE); ! 1887: if(tmpfile) ! 1888: remove(filename); ! 1889: *inprogress=FALSE; ! 1890: return; ! 1891: } ! 1892: if(startup->socket_open!=NULL) ! 1893: startup->socket_open(startup->cbdata,TRUE); ! 1894: sockets++; ! 1895: if(startup->options&FTP_OPT_DEBUG_DATA) ! 1896: lprintf(LOG_DEBUG,"%04d DATA socket %d opened",ctrl_sock,*data_sock); ! 1897: ! 1898: /* Use port-1 for all data connections */ ! 1899: reuseaddr=TRUE; ! 1900: setsockopt(*data_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseaddr,sizeof(reuseaddr)); ! 1901: ! 1902: memset(&server_addr, 0, sizeof(server_addr)); ! 1903: ! 1904: server_addr.sin_addr.s_addr = htonl(startup->interface_addr); ! 1905: server_addr.sin_family = AF_INET; ! 1906: server_addr.sin_port = htons((WORD)(startup->port-1)); /* 20? */ ! 1907: ! 1908: result=bind(*data_sock, (struct sockaddr *) &server_addr,sizeof(server_addr)); ! 1909: if(result!=0) { ! 1910: server_addr.sin_port = 0; /* any user port */ ! 1911: result=bind(*data_sock, (struct sockaddr *) &server_addr,sizeof(server_addr)); ! 1912: } ! 1913: if(result!=0) { ! 1914: lprintf(LOG_ERR,"%04d !DATA ERROR %d (%d) binding socket %d" ! 1915: ,ctrl_sock, result, ERROR_VALUE, *data_sock); ! 1916: sockprintf(ctrl_sock,"425 Error %d binding socket",ERROR_VALUE); ! 1917: if(tmpfile) ! 1918: remove(filename); ! 1919: *inprogress=FALSE; ! 1920: ftp_close_socket(data_sock,__LINE__); ! 1921: return; ! 1922: } ! 1923: ! 1924: result=connect(*data_sock, (struct sockaddr *)addr,sizeof(struct sockaddr)); ! 1925: if(result!=0) { ! 1926: lprintf(LOG_WARNING,"%04d !DATA ERROR %d (%d) connecting to client %s port %u on socket %d" ! 1927: ,ctrl_sock,result,ERROR_VALUE ! 1928: ,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),*data_sock); ! 1929: sockprintf(ctrl_sock,"425 Error %d connecting to socket",ERROR_VALUE); ! 1930: if(tmpfile) ! 1931: remove(filename); ! 1932: *inprogress=FALSE; ! 1933: ftp_close_socket(data_sock,__LINE__); ! 1934: return; ! 1935: } ! 1936: if(startup->options&FTP_OPT_DEBUG_DATA) ! 1937: lprintf(LOG_DEBUG,"%04d DATA socket %d connected to %s port %u" ! 1938: ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port)); ! 1939: ! 1940: } else { /* PASV */ ! 1941: ! 1942: if(startup->options&FTP_OPT_DEBUG_DATA) { ! 1943: addr_len=sizeof(SOCKADDR_IN); ! 1944: if((result=getsockname(pasv_sock, (struct sockaddr *)addr,&addr_len))!=0) ! 1945: lprintf(LOG_ERR,"%04d !ERROR %d (%d) getting address/port of passive socket (%u)" ! 1946: ,ctrl_sock,result,ERROR_VALUE,pasv_sock); ! 1947: else ! 1948: lprintf(LOG_DEBUG,"%04d PASV DATA socket %d listening on %s port %u" ! 1949: ,ctrl_sock,pasv_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port)); ! 1950: } ! 1951: ! 1952: /* Setup for select() */ ! 1953: tv.tv_sec=TIMEOUT_SOCKET_LISTEN; ! 1954: tv.tv_usec=0; ! 1955: ! 1956: FD_ZERO(&socket_set); ! 1957: FD_SET(pasv_sock,&socket_set); ! 1958: ! 1959: #if defined(SOCKET_DEBUG_SELECT) ! 1960: socket_debug[ctrl_sock]|=SOCKET_DEBUG_SELECT; ! 1961: #endif ! 1962: result=select(pasv_sock+1,&socket_set,NULL,NULL,&tv); ! 1963: #if defined(SOCKET_DEBUG_SELECT) ! 1964: socket_debug[ctrl_sock]&=~SOCKET_DEBUG_SELECT; ! 1965: #endif ! 1966: if(result<1) { ! 1967: lprintf(LOG_WARNING,"%04d !PASV select returned %d (error: %d)",ctrl_sock,result,ERROR_VALUE); ! 1968: sockprintf(ctrl_sock,"425 Error %d selecting socket for connection",ERROR_VALUE); ! 1969: if(tmpfile) ! 1970: remove(filename); ! 1971: *inprogress=FALSE; ! 1972: return; ! 1973: } ! 1974: ! 1975: addr_len=sizeof(SOCKADDR_IN); ! 1976: #ifdef SOCKET_DEBUG_ACCEPT ! 1977: socket_debug[ctrl_sock]|=SOCKET_DEBUG_ACCEPT; ! 1978: #endif ! 1979: *data_sock=accept(pasv_sock,(struct sockaddr*)addr,&addr_len); ! 1980: #ifdef SOCKET_DEBUG_ACCEPT ! 1981: socket_debug[ctrl_sock]&=~SOCKET_DEBUG_ACCEPT; ! 1982: #endif ! 1983: if(*data_sock==INVALID_SOCKET) { ! 1984: lprintf(LOG_WARNING,"%04d !PASV DATA ERROR %d accepting connection on socket %d" ! 1985: ,ctrl_sock,ERROR_VALUE,pasv_sock); ! 1986: sockprintf(ctrl_sock,"425 Error %d accepting connection",ERROR_VALUE); ! 1987: if(tmpfile) ! 1988: remove(filename); ! 1989: *inprogress=FALSE; ! 1990: return; ! 1991: } ! 1992: if(startup->socket_open!=NULL) ! 1993: startup->socket_open(startup->cbdata,TRUE); ! 1994: sockets++; ! 1995: if(startup->options&FTP_OPT_DEBUG_DATA) ! 1996: lprintf(LOG_DEBUG,"%04d PASV DATA socket %d connected to %s port %u" ! 1997: ,ctrl_sock,*data_sock,inet_ntoa(addr->sin_addr),ntohs(addr->sin_port)); ! 1998: } ! 1999: ! 2000: do { ! 2001: ! 2002: l=1; ! 2003: ! 2004: if(ioctlsocket(*data_sock, FIONBIO, &l)!=0) { ! 2005: lprintf(LOG_ERR,"%04d !DATA ERROR %d disabling socket blocking" ! 2006: ,ctrl_sock, ERROR_VALUE); ! 2007: sockprintf(ctrl_sock,"425 Error %d disabling socket blocking" ! 2008: ,ERROR_VALUE); ! 2009: break; ! 2010: } ! 2011: ! 2012: if((xfer=malloc(sizeof(xfer_t)))==NULL) { ! 2013: lprintf(LOG_CRIT,"%04d !MALLOC FAILURE LINE %d",ctrl_sock,__LINE__); ! 2014: sockprintf(ctrl_sock,"425 MALLOC FAILURE"); ! 2015: break; ! 2016: } ! 2017: memset(xfer,0,sizeof(xfer_t)); ! 2018: xfer->ctrl_sock=ctrl_sock; ! 2019: xfer->data_sock=data_sock; ! 2020: xfer->inprogress=inprogress; ! 2021: xfer->aborted=aborted; ! 2022: xfer->delfile=delfile; ! 2023: xfer->tmpfile=tmpfile; ! 2024: xfer->append=append; ! 2025: xfer->filepos=filepos; ! 2026: xfer->credits=credits; ! 2027: xfer->lastactive=lastactive; ! 2028: xfer->user=user; ! 2029: xfer->dir=dir; ! 2030: xfer->desc=desc; ! 2031: SAFECOPY(xfer->filename,filename); ! 2032: if(receiving) ! 2033: result=_beginthread(receive_thread,0,(void*)xfer); ! 2034: else ! 2035: result=_beginthread(send_thread,0,(void*)xfer); ! 2036: ! 2037: if(result!=-1) ! 2038: return; /* success */ ! 2039: ! 2040: } while(0); ! 2041: ! 2042: /* failure */ ! 2043: if(tmpfile) ! 2044: remove(filename); ! 2045: *inprogress=FALSE; ! 2046: } ! 2047: ! 2048: /* convert "user name" to "user.name" or "mr. user" to "mr._user" */ ! 2049: char* dotname(char* in, char* out) ! 2050: { ! 2051: char ch; ! 2052: int i; ! 2053: ! 2054: if(strchr(in,'.')==NULL) ! 2055: ch='.'; ! 2056: else ! 2057: ch='_'; ! 2058: for(i=0;in[i];i++) ! 2059: if(in[i]<=' ') ! 2060: out[i]=ch; ! 2061: else ! 2062: out[i]=in[i]; ! 2063: out[i]=0; ! 2064: return(out); ! 2065: } ! 2066: ! 2067: void parsepath(char** pp, user_t* user, int* curlib, int* curdir) ! 2068: { ! 2069: char* p; ! 2070: char* tp; ! 2071: char path[MAX_PATH+1]; ! 2072: int dir=*curdir; ! 2073: int lib=*curlib; ! 2074: ! 2075: SAFECOPY(path,*pp); ! 2076: p=path; ! 2077: ! 2078: if(*p=='/') { ! 2079: p++; ! 2080: lib=-1; ! 2081: } ! 2082: else if(!strncmp(p,"./",2)) ! 2083: p+=2; ! 2084: ! 2085: if(!strncmp(p,"..",2)) { ! 2086: p+=2; ! 2087: if(dir>=0) ! 2088: dir=-1; ! 2089: else if(lib>=0) ! 2090: lib=-1; ! 2091: if(*p=='/') ! 2092: p++; ! 2093: } ! 2094: ! 2095: if(*p==0) { ! 2096: *curlib=lib; ! 2097: *curdir=dir; ! 2098: return; ! 2099: } ! 2100: ! 2101: if(lib<0) { /* root */ ! 2102: tp=strchr(p,'/'); ! 2103: if(tp) *tp=0; ! 2104: for(lib=0;lib<scfg.total_libs;lib++) { ! 2105: if(!chk_ar(&scfg,scfg.lib[lib]->ar,user)) ! 2106: continue; ! 2107: if(!stricmp(scfg.lib[lib]->sname,p)) ! 2108: break; ! 2109: } ! 2110: if(lib>=scfg.total_libs) { /* not found */ ! 2111: *curlib=-1; ! 2112: return; ! 2113: } ! 2114: *curlib=lib; ! 2115: ! 2116: if(tp==NULL) { ! 2117: *curdir=-1; ! 2118: return; ! 2119: } ! 2120: ! 2121: p=tp+1; ! 2122: } ! 2123: ! 2124: tp=strchr(p,'/'); ! 2125: if(tp!=NULL) { ! 2126: *tp=0; ! 2127: tp++; ! 2128: } else ! 2129: tp=p+strlen(p); ! 2130: ! 2131: for(dir=0;dir<scfg.total_dirs;dir++) { ! 2132: if(scfg.dir[dir]->lib!=lib) ! 2133: continue; ! 2134: if(dir!=scfg.sysop_dir && dir!=scfg.upload_dir ! 2135: && !chk_ar(&scfg,scfg.dir[dir]->ar,user)) ! 2136: continue; ! 2137: if(!stricmp(scfg.dir[dir]->code_suffix,p)) ! 2138: break; ! 2139: } ! 2140: ! 2141: if(dir>=scfg.total_dirs) /* not found */ ! 2142: return; ! 2143: ! 2144: *curdir=dir; ! 2145: ! 2146: *pp+=tp-path; /* skip "lib/dir/" */ ! 2147: } ! 2148: ! 2149: static BOOL ftpalias(char* fullalias, char* filename, user_t* user, int* curdir) ! 2150: { ! 2151: char* p; ! 2152: char* tp; ! 2153: char* fname=""; ! 2154: char line[512]; ! 2155: char alias[512]; ! 2156: char aliasfile[MAX_PATH+1]; ! 2157: int dir=-1; ! 2158: FILE* fp; ! 2159: BOOL result=FALSE; ! 2160: ! 2161: sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir); ! 2162: if((fp=fopen(aliasfile,"r"))==NULL) ! 2163: return(FALSE); ! 2164: ! 2165: SAFECOPY(alias,fullalias); ! 2166: p=strrchr(alias+1,'/'); ! 2167: if(p) { ! 2168: *p=0; ! 2169: fname=p+1; ! 2170: } ! 2171: ! 2172: if(filename==NULL /* directory */ && *fname /* filename specified */) { ! 2173: fclose(fp); ! 2174: return(FALSE); ! 2175: } ! 2176: ! 2177: while(!feof(fp)) { ! 2178: if(!fgets(line,sizeof(line),fp)) ! 2179: break; ! 2180: ! 2181: p=line; /* alias */ ! 2182: while(*p && *p<=' ') p++; ! 2183: if(*p==';') /* comment */ ! 2184: continue; ! 2185: ! 2186: tp=p; /* terminator */ ! 2187: while(*tp && *tp>' ') tp++; ! 2188: if(*tp) *tp=0; ! 2189: ! 2190: if(stricmp(p,alias)) /* Not a match */ ! 2191: continue; ! 2192: ! 2193: p=tp+1; /* filename */ ! 2194: while(*p && *p<=' ') p++; ! 2195: ! 2196: tp=p; /* terminator */ ! 2197: while(*tp && *tp>' ') tp++; ! 2198: if(*tp) *tp=0; ! 2199: ! 2200: if(!strnicmp(p,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) { ! 2201: if((dir=getdir(p+strlen(BBS_VIRTUAL_PATH),user))<0) { ! 2202: lprintf(LOG_WARNING,"0000 !Invalid virtual path (%s) for %s",p,user->alias); ! 2203: /* invalid or no access */ ! 2204: continue; ! 2205: } ! 2206: p=strrchr(p,'/'); ! 2207: if(p!=NULL) p++; ! 2208: if(p!=NULL && filename!=NULL) { ! 2209: if(*p) ! 2210: sprintf(filename,"%s%s",scfg.dir[dir]->path,p); ! 2211: else ! 2212: sprintf(filename,"%s%s",scfg.dir[dir]->path,fname); ! 2213: } ! 2214: } else if(filename!=NULL) ! 2215: strcpy(filename,p); ! 2216: ! 2217: result=TRUE; /* success */ ! 2218: break; ! 2219: } ! 2220: fclose(fp); ! 2221: if(curdir!=NULL) ! 2222: *curdir=dir; ! 2223: return(result); ! 2224: } ! 2225: ! 2226: char* root_dir(char* path) ! 2227: { ! 2228: char* p; ! 2229: static char root[MAX_PATH+1]; ! 2230: ! 2231: SAFECOPY(root,path); ! 2232: ! 2233: if(!strncmp(root,"\\\\",2)) { /* network path */ ! 2234: p=strchr(root+2,'\\'); ! 2235: if(p) p=strchr(p+1,'\\'); ! 2236: if(p) *(p+1)=0; /* truncate at \\computer\sharename\ */ ! 2237: } ! 2238: else if(!strncmp(root+1,":/",2) || !strncmp(root+1,":\\",2)) ! 2239: root[3]=0; ! 2240: else if(*root=='/' || *root=='\\') ! 2241: root[1]=0; ! 2242: ! 2243: return(root); ! 2244: } ! 2245: ! 2246: char* vpath(int lib, int dir, char* str) ! 2247: { ! 2248: strcpy(str,"/"); ! 2249: if(lib<0) ! 2250: return(str); ! 2251: strcat(str,scfg.lib[lib]->sname); ! 2252: strcat(str,"/"); ! 2253: if(dir<0) ! 2254: return(str); ! 2255: strcat(str,scfg.dir[dir]->code_suffix); ! 2256: strcat(str,"/"); ! 2257: return(str); ! 2258: } ! 2259: ! 2260: void ftp_printfile(SOCKET sock, const char* name, unsigned code) ! 2261: { ! 2262: char path[MAX_PATH+1]; ! 2263: char buf[512]; ! 2264: FILE* fp; ! 2265: unsigned i; ! 2266: ! 2267: SAFEPRINTF2(path,"%sftp%s.txt",scfg.text_dir,name); ! 2268: if((fp=fopen(path,"rb"))!=NULL) { ! 2269: i=0; ! 2270: while(!feof(fp)) { ! 2271: if(!fgets(buf,sizeof(buf),fp)) ! 2272: break; ! 2273: truncsp(buf); ! 2274: if(!i) ! 2275: sockprintf(sock,"%u-%s",code,buf); ! 2276: else ! 2277: sockprintf(sock," %s",buf); ! 2278: i++; ! 2279: } ! 2280: fclose(fp); ! 2281: } ! 2282: } ! 2283: ! 2284: static BOOL badlogin(SOCKET sock, ulong* login_attempts) ! 2285: { ! 2286: mswait(5000); /* As recommended by RFC2577 */ ! 2287: if(++(*login_attempts)>=3) { ! 2288: sockprintf(sock,"421 Too many failed login attempts."); ! 2289: return(TRUE); ! 2290: } ! 2291: ftp_printfile(sock,"badlogin",530); ! 2292: sockprintf(sock,"530 Invalid login."); ! 2293: return(FALSE); ! 2294: } ! 2295: ! 2296: static char* ftp_tmpfname(char* str, SOCKET sock) ! 2297: { ! 2298: safe_snprintf(str,MAX_PATH,"%sSBBS_FTP.%u.%u.tx",scfg.temp_dir,getpid(),sock); ! 2299: return(str); ! 2300: } ! 2301: ! 2302: static void ctrl_thread(void* arg) ! 2303: { ! 2304: char buf[512]; ! 2305: char str[128]; ! 2306: char* cmd; ! 2307: char* p; ! 2308: char* np; ! 2309: char* tp; ! 2310: char* dp; ! 2311: char* mode="active"; ! 2312: char password[64]; ! 2313: char fname[MAX_PATH+1]; ! 2314: char qwkfile[MAX_PATH+1]; ! 2315: char aliasfile[MAX_PATH+1]; ! 2316: char aliasline[512]; ! 2317: char desc[501]=""; ! 2318: char sys_pass[128]; ! 2319: char* host_name; ! 2320: char host_ip[64]; ! 2321: char path[MAX_PATH+1]; ! 2322: char local_dir[MAX_PATH+1]; ! 2323: char ren_from[MAX_PATH+1]=""; ! 2324: char html_index_ext[MAX_PATH+1]; ! 2325: WORD port; ! 2326: ulong ip_addr; ! 2327: socklen_t addr_len; ! 2328: DWORD h1,h2,h3,h4; ! 2329: u_short p1,p2; /* For PORT command */ ! 2330: int i; ! 2331: int rd; ! 2332: int result; ! 2333: int lib; ! 2334: int dir; ! 2335: int curlib=-1; ! 2336: int curdir=-1; ! 2337: int orglib; ! 2338: int orgdir; ! 2339: long filepos=0L; ! 2340: long timeleft; ! 2341: ulong l; ! 2342: ulong login_attempts=0; ! 2343: ulong avail; /* disk space */ ! 2344: ulong count; ! 2345: BOOL detail; ! 2346: BOOL success; ! 2347: BOOL getdate; ! 2348: BOOL getsize; ! 2349: BOOL delecmd; ! 2350: BOOL delfile; ! 2351: BOOL tmpfile; ! 2352: BOOL credits; ! 2353: BOOL filedat=FALSE; ! 2354: BOOL transfer_inprogress; ! 2355: BOOL transfer_aborted; ! 2356: BOOL sysop=FALSE; ! 2357: BOOL local_fsys=FALSE; ! 2358: BOOL alias_dir; ! 2359: BOOL append; ! 2360: BOOL reuseaddr; ! 2361: FILE* fp; ! 2362: FILE* alias_fp; ! 2363: SOCKET sock; ! 2364: SOCKET tmp_sock; ! 2365: SOCKET pasv_sock=INVALID_SOCKET; ! 2366: SOCKET data_sock=INVALID_SOCKET; ! 2367: HOSTENT* host; ! 2368: SOCKADDR_IN addr; ! 2369: SOCKADDR_IN data_addr; ! 2370: SOCKADDR_IN pasv_addr; ! 2371: ftp_t ftp=*(ftp_t*)arg; ! 2372: user_t user; ! 2373: time_t t; ! 2374: time_t now; ! 2375: time_t logintime=0; ! 2376: time_t lastactive; ! 2377: file_t f; ! 2378: glob_t g; ! 2379: node_t node; ! 2380: client_t client; ! 2381: struct tm tm; ! 2382: struct tm cur_tm; ! 2383: #ifdef JAVASCRIPT ! 2384: jsval js_val; ! 2385: JSRuntime* js_runtime=NULL; ! 2386: JSContext* js_cx=NULL; ! 2387: JSObject* js_glob; ! 2388: JSObject* js_ftp; ! 2389: JSString* js_str; ! 2390: #endif ! 2391: ! 2392: thread_up(TRUE /* setuid */); ! 2393: ! 2394: lastactive=time(NULL); ! 2395: ! 2396: sock=ftp.socket; ! 2397: data_addr=ftp.client_addr; ! 2398: /* Default data port is ctrl port-1 */ ! 2399: data_addr.sin_port=ntohs(data_addr.sin_port)-1; ! 2400: data_addr.sin_port=htons(data_addr.sin_port); ! 2401: ! 2402: lprintf(LOG_DEBUG,"%04d CTRL thread started", sock); ! 2403: ! 2404: free(arg); /* unexplicable assertion here on July 26, 2001 */ ! 2405: ! 2406: #ifdef _WIN32 ! 2407: if(startup->answer_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 2408: PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); ! 2409: #endif ! 2410: ! 2411: transfer_inprogress = FALSE; ! 2412: transfer_aborted = FALSE; ! 2413: ! 2414: l=1; ! 2415: ! 2416: if((i=ioctlsocket(sock, FIONBIO, &l))!=0) { ! 2417: lprintf(LOG_ERR,"%04d !ERROR %d (%d) disabling socket blocking" ! 2418: ,sock, i, ERROR_VALUE); ! 2419: sockprintf(sock,"425 Error %d disabling socket blocking" ! 2420: ,ERROR_VALUE); ! 2421: ftp_close_socket(&sock,__LINE__); ! 2422: thread_down(); ! 2423: return; ! 2424: } ! 2425: ! 2426: memset(&user,0,sizeof(user)); ! 2427: ! 2428: SAFECOPY(host_ip,inet_ntoa(ftp.client_addr.sin_addr)); ! 2429: ! 2430: lprintf(LOG_DEBUG,"%04d CTRL connection accepted from: %s port %u" ! 2431: ,sock, host_ip, ntohs(ftp.client_addr.sin_port)); ! 2432: ! 2433: if(startup->options&FTP_OPT_NO_HOST_LOOKUP) ! 2434: host=NULL; ! 2435: else ! 2436: host=gethostbyaddr ((char *)&ftp.client_addr.sin_addr ! 2437: ,sizeof(ftp.client_addr.sin_addr),AF_INET); ! 2438: ! 2439: if(host!=NULL && host->h_name!=NULL) ! 2440: host_name=host->h_name; ! 2441: else ! 2442: host_name="<no name>"; ! 2443: ! 2444: if(!(startup->options&FTP_OPT_NO_HOST_LOOKUP)) { ! 2445: lprintf(LOG_INFO,"%04d Hostname: %s", sock, host_name); ! 2446: for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++) ! 2447: lprintf(LOG_INFO,"%04d HostAlias: %s", sock, host->h_aliases[i]); ! 2448: } ! 2449: ! 2450: if(trashcan(&scfg,host_ip,"ip")) { ! 2451: lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", sock, host_ip); ! 2452: sockprintf(sock,"550 Access denied."); ! 2453: ftp_close_socket(&sock,__LINE__); ! 2454: thread_down(); ! 2455: return; ! 2456: } ! 2457: ! 2458: if(trashcan(&scfg,host_name,"host")) { ! 2459: lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in host.can: %s", sock, host_name); ! 2460: sockprintf(sock,"550 Access denied."); ! 2461: ftp_close_socket(&sock,__LINE__); ! 2462: thread_down(); ! 2463: return; ! 2464: } ! 2465: ! 2466: /* For PASV mode */ ! 2467: addr_len=sizeof(pasv_addr); ! 2468: if((result=getsockname(sock, (struct sockaddr *)&pasv_addr,&addr_len))!=0) { ! 2469: lprintf(LOG_ERR,"%04d !ERROR %d (%d) getting address/port", sock, result, ERROR_VALUE); ! 2470: sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE); ! 2471: ftp_close_socket(&sock,__LINE__); ! 2472: thread_down(); ! 2473: return; ! 2474: } ! 2475: ! 2476: active_clients++, update_clients(); ! 2477: ! 2478: /* Initialize client display */ ! 2479: client.size=sizeof(client); ! 2480: client.time=time(NULL); ! 2481: SAFECOPY(client.addr,host_ip); ! 2482: SAFECOPY(client.host,host_name); ! 2483: client.port=ntohs(ftp.client_addr.sin_port); ! 2484: client.protocol="FTP"; ! 2485: client.user="<unknown>"; ! 2486: client_on(sock,&client,FALSE /* update */); ! 2487: ! 2488: sockprintf(sock,"220-%s (%s)",scfg.sys_name, startup->host_name); ! 2489: sockprintf(sock," Synchronet FTP Server %s-%s Ready" ! 2490: ,revision,PLATFORM_DESC); ! 2491: sprintf(str,"%sftplogin.txt",scfg.text_dir); ! 2492: if((fp=fopen(str,"rb"))!=NULL) { ! 2493: while(!feof(fp)) { ! 2494: if(!fgets(buf,sizeof(buf),fp)) ! 2495: break; ! 2496: truncsp(buf); ! 2497: sockprintf(sock," %s",buf); ! 2498: } ! 2499: fclose(fp); ! 2500: } ! 2501: sockprintf(sock,"220 Please enter your user name."); ! 2502: ! 2503: #ifdef SOCKET_DEBUG_CTRL ! 2504: socket_debug[sock]|=SOCKET_DEBUG_CTRL; ! 2505: #endif ! 2506: while(1) { ! 2507: ! 2508: #ifdef SOCKET_DEBUG_READLINE ! 2509: socket_debug[sock]|=SOCKET_DEBUG_READLINE; ! 2510: #endif ! 2511: rd = sockreadline(sock, buf, sizeof(buf), &lastactive); ! 2512: #ifdef SOCKET_DEBUG_READLINE ! 2513: socket_debug[sock]&=~SOCKET_DEBUG_READLINE; ! 2514: #endif ! 2515: if(rd<1) { ! 2516: if(transfer_inprogress==TRUE) { ! 2517: lprintf(LOG_WARNING,"%04d Aborting transfer due to receive error",sock); ! 2518: transfer_aborted=TRUE; ! 2519: } ! 2520: break; ! 2521: } ! 2522: truncsp(buf); ! 2523: lastactive=time(NULL); ! 2524: cmd=buf; ! 2525: while(((BYTE)*cmd)==TELNET_IAC) { ! 2526: cmd++; ! 2527: lprintf(LOG_DEBUG,"%04d RX: Telnet cmd: %s",sock,telnet_cmd_desc(*cmd)); ! 2528: cmd++; ! 2529: } ! 2530: while(*cmd && *cmd<' ') { ! 2531: lprintf(LOG_DEBUG,"%04d RX: %d (0x%02X)",sock,(BYTE)*cmd,(BYTE)*cmd); ! 2532: cmd++; ! 2533: } ! 2534: if(!(*cmd)) ! 2535: continue; ! 2536: if(startup->options&FTP_OPT_DEBUG_RX) ! 2537: lprintf(LOG_DEBUG,"%04d RX: %s", sock, cmd); ! 2538: if(!stricmp(cmd, "NOOP")) { ! 2539: sockprintf(sock,"200 NOOP command successful."); ! 2540: continue; ! 2541: } ! 2542: if(!stricmp(cmd, "HELP SITE") || !stricmp(cmd, "SITE HELP")) { ! 2543: sockprintf(sock,"214-The following SITE commands are recognized (* => unimplemented):"); ! 2544: sockprintf(sock," HELP VER WHO UPTIME"); ! 2545: if(user.level>=SYSOP_LEVEL) ! 2546: sockprintf(sock, ! 2547: " RECYCLE [ALL]"); ! 2548: if(sysop) ! 2549: sockprintf(sock, ! 2550: " EXEC <cmd>"); ! 2551: sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr); ! 2552: continue; ! 2553: } ! 2554: if(!strnicmp(cmd, "HELP",4)) { ! 2555: sockprintf(sock,"214-The following commands are recognized (* => unimplemented, # => extension):"); ! 2556: sockprintf(sock," USER PASS CWD XCWD CDUP XCUP PWD XPWD"); ! 2557: sockprintf(sock," QUIT REIN PORT PASV LIST NLST NOOP HELP"); ! 2558: sockprintf(sock," SIZE MDTM RETR STOR REST ALLO ABOR SYST"); ! 2559: sockprintf(sock," TYPE STRU MODE SITE RNFR* RNTO* DELE* DESC#"); ! 2560: sockprintf(sock," FEAT# OPTS#"); ! 2561: sockprintf(sock,"214 Direct comments to sysop@%s.",scfg.sys_inetaddr); ! 2562: continue; ! 2563: } ! 2564: if(!stricmp(cmd, "FEAT")) { ! 2565: sockprintf(sock,"211-The following additional (post-RFC949) features are supported:"); ! 2566: sockprintf(sock," DESC"); ! 2567: sockprintf(sock," MDTM"); ! 2568: sockprintf(sock," SIZE"); ! 2569: sockprintf(sock," REST STREAM"); ! 2570: sockprintf(sock,"211 End"); ! 2571: continue; ! 2572: } ! 2573: if(!strnicmp(cmd, "OPTS",4)) { ! 2574: sockprintf(sock,"501 No options supported."); ! 2575: continue; ! 2576: } ! 2577: if(!stricmp(cmd, "QUIT")) { ! 2578: ftp_printfile(sock,"bye",221); ! 2579: sockprintf(sock,"221 Goodbye. Closing control connection."); ! 2580: break; ! 2581: } ! 2582: if(!strnicmp(cmd, "USER ",5)) { ! 2583: sysop=FALSE; ! 2584: user.number=0; ! 2585: p=cmd+5; ! 2586: while(*p && *p<=' ') p++; ! 2587: truncsp(p); ! 2588: SAFECOPY(user.alias,p); ! 2589: user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/); ! 2590: if(!user.number && !stricmp(user.alias,"anonymous")) ! 2591: user.number=matchuser(&scfg,"guest",FALSE); ! 2592: if(user.number && getuserdat(&scfg, &user)==0 && user.pass[0]==0) ! 2593: sockprintf(sock,"331 User name okay, give your full e-mail address as password."); ! 2594: else ! 2595: sockprintf(sock,"331 User name okay, need password."); ! 2596: user.number=0; ! 2597: continue; ! 2598: } ! 2599: if(!strnicmp(cmd, "PASS ",5) && user.alias[0]) { ! 2600: user.number=0; ! 2601: p=cmd+5; ! 2602: while(*p && *p<=' ') p++; ! 2603: ! 2604: SAFECOPY(password,p); ! 2605: user.number=matchuser(&scfg,user.alias,FALSE /*sysop_alias*/); ! 2606: if(!user.number) { ! 2607: if(scfg.sys_misc&SM_ECHO_PW) ! 2608: lprintf(LOG_WARNING,"%04d !UNKNOWN USER: %s, Password: %s",sock,user.alias,p); ! 2609: else ! 2610: lprintf(LOG_WARNING,"%04d !UNKNOWN USER: %s",sock,user.alias); ! 2611: if(badlogin(sock,&login_attempts)) ! 2612: break; ! 2613: continue; ! 2614: } ! 2615: if((i=getuserdat(&scfg, &user))!=0) { ! 2616: lprintf(LOG_ERR,"%04d !ERROR %d getting data for user #%d (%s)" ! 2617: ,sock,i,user.number,user.alias); ! 2618: sockprintf(sock,"530 Database error %d",i); ! 2619: user.number=0; ! 2620: continue; ! 2621: } ! 2622: if(user.misc&(DELETED|INACTIVE)) { ! 2623: lprintf(LOG_WARNING,"%04d !DELETED or INACTIVE user #%d (%s)" ! 2624: ,sock,user.number,user.alias); ! 2625: user.number=0; ! 2626: if(badlogin(sock,&login_attempts)) ! 2627: break; ! 2628: continue; ! 2629: } ! 2630: if(user.rest&FLAG('T')) { ! 2631: lprintf(LOG_WARNING,"%04d !T RESTRICTED user #%d (%s)" ! 2632: ,sock,user.number,user.alias); ! 2633: user.number=0; ! 2634: if(badlogin(sock,&login_attempts)) ! 2635: break; ! 2636: continue; ! 2637: } ! 2638: if(user.ltoday>scfg.level_callsperday[user.level] ! 2639: && !(user.exempt&FLAG('L'))) { ! 2640: lprintf(LOG_WARNING,"%04d !MAXIMUM LOGONS (%d) reached for %s" ! 2641: ,sock,scfg.level_callsperday[user.level],user.alias); ! 2642: sockprintf(sock,"530 Maximum logons reached."); ! 2643: user.number=0; ! 2644: continue; ! 2645: } ! 2646: if(user.rest&FLAG('L') && user.ltoday>1) { ! 2647: lprintf(LOG_WARNING,"%04d !L RESTRICTED user #%d (%s) already on today" ! 2648: ,sock,user.number,user.alias); ! 2649: sockprintf(sock,"530 Maximum logons reached."); ! 2650: user.number=0; ! 2651: continue; ! 2652: } ! 2653: ! 2654: SAFEPRINTF2(sys_pass,"%s:%s",user.pass,scfg.sys_pass); ! 2655: if(!user.pass[0]) { /* Guest/Anonymous */ ! 2656: if(trashcan(&scfg,password,"email")) { ! 2657: lprintf(LOG_NOTICE,"%04d !BLOCKED e-mail address: %s",sock,password); ! 2658: user.number=0; ! 2659: if(badlogin(sock,&login_attempts)) ! 2660: break; ! 2661: continue; ! 2662: } ! 2663: lprintf(LOG_INFO,"%04d %s: <%s>",sock,user.alias,password); ! 2664: putuserrec(&scfg,user.number,U_NETMAIL,LEN_NETMAIL,password); ! 2665: } ! 2666: else if(user.level>=SYSOP_LEVEL && !stricmp(password,sys_pass)) { ! 2667: lprintf(LOG_INFO,"%04d Sysop access granted to %s", sock, user.alias); ! 2668: sysop=TRUE; ! 2669: } ! 2670: else if(stricmp(password,user.pass)) { ! 2671: if(scfg.sys_misc&SM_ECHO_PW) ! 2672: lprintf(LOG_WARNING,"%04d !FAILED Password attempt for user %s: '%s' expected '%s'" ! 2673: ,sock, user.alias, password, user.pass); ! 2674: else ! 2675: lprintf(LOG_WARNING,"%04d !FAILED Password attempt for user %s" ! 2676: ,sock, user.alias); ! 2677: user.number=0; ! 2678: if(badlogin(sock,&login_attempts)) ! 2679: break; ! 2680: continue; ! 2681: } ! 2682: ! 2683: /* Update client display */ ! 2684: if(user.pass[0]) ! 2685: client.user=user.alias; ! 2686: else { /* anonymous */ ! 2687: sprintf(str,"%s <%.32s>",user.alias,password); ! 2688: client.user=str; ! 2689: } ! 2690: client_on(sock,&client,TRUE /* update */); ! 2691: ! 2692: ! 2693: lprintf(LOG_INFO,"%04d %s logged in",sock,user.alias); ! 2694: logintime=time(NULL); ! 2695: timeleft=gettimeleft(&scfg,&user,logintime); ! 2696: ftp_printfile(sock,"hello",230); ! 2697: ! 2698: #ifdef JAVASCRIPT ! 2699: #ifdef JS_CX_PER_SESSION ! 2700: if(js_cx!=NULL) { ! 2701: ! 2702: if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) ! 2703: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user class",sock); ! 2704: ! 2705: if(js_CreateUserObject(js_cx, js_glob, &scfg, "user", user.number)==NULL) ! 2706: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user object",sock); ! 2707: ! 2708: if(js_CreateClientObject(js_cx, js_glob, "client", &client, sock)==NULL) ! 2709: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating client object",sock); ! 2710: ! 2711: if(js_CreateFileAreaObject(js_cx, js_glob, &scfg, &user ! 2712: ,startup->html_index_file)==NULL) ! 2713: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file area object",sock); ! 2714: ! 2715: } ! 2716: #endif ! 2717: #endif ! 2718: ! 2719: if(sysop) ! 2720: sockprintf(sock,"230-Sysop access granted."); ! 2721: sockprintf(sock,"230-%s logged in.",user.alias); ! 2722: if(!(user.exempt&FLAG('D')) && (user.cdt+user.freecdt)>0) ! 2723: sockprintf(sock,"230-You have %lu download credits." ! 2724: ,user.cdt+user.freecdt); ! 2725: sockprintf(sock,"230 You are allowed %lu minutes of use for this session." ! 2726: ,timeleft/60); ! 2727: sprintf(qwkfile,"%sfile/%04d.qwk",scfg.data_dir,user.number); ! 2728: ! 2729: /* Adjust User Total Logons/Logons Today */ ! 2730: adjustuserrec(&scfg,user.number,U_LOGONS,5,1); ! 2731: putuserrec(&scfg,user.number,U_LTODAY,5,ultoa(user.ltoday+1,str,10)); ! 2732: putuserrec(&scfg,user.number,U_MODEM,LEN_MODEM,"FTP"); ! 2733: putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name); ! 2734: putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip); ! 2735: putuserrec(&scfg,user.number,U_LOGONTIME,0,ultoa(logintime,str,16)); ! 2736: getuserdat(&scfg, &user); /* make user current */ ! 2737: ! 2738: continue; ! 2739: } ! 2740: ! 2741: if(!user.number) { ! 2742: sockprintf(sock,"530 Please login with USER and PASS."); ! 2743: continue; ! 2744: } ! 2745: ! 2746: if(!(user.rest&FLAG('G'))) ! 2747: getuserdat(&scfg, &user); /* get current user data */ ! 2748: ! 2749: if((timeleft=gettimeleft(&scfg,&user,logintime))<1L) { ! 2750: sockprintf(sock,"421 Sorry, you've run out of time."); ! 2751: lprintf(LOG_WARNING,"%04d Out of time, disconnecting",sock); ! 2752: break; ! 2753: } ! 2754: ! 2755: /********************************/ ! 2756: /* These commands require login */ ! 2757: /********************************/ ! 2758: ! 2759: if(!stricmp(cmd, "REIN")) { ! 2760: lprintf(LOG_INFO,"%04d %s reinitialized control session",sock,user.alias); ! 2761: user.number=0; ! 2762: sysop=FALSE; ! 2763: filepos=0; ! 2764: sockprintf(sock,"220 Control session re-initialized. Ready for re-login."); ! 2765: continue; ! 2766: } ! 2767: ! 2768: if(!stricmp(cmd, "SITE WHO")) { ! 2769: sockprintf(sock,"211-Active Telnet Nodes:"); ! 2770: for(i=0;i<scfg.sys_nodes && i<scfg.sys_lastnode;i++) { ! 2771: if((result=getnodedat(&scfg, i+1, &node, 0))!=0) { ! 2772: sockprintf(sock," Error %d getting data for Telnet Node %d",result,i+1); ! 2773: continue; ! 2774: } ! 2775: if(node.status==NODE_INUSE) ! 2776: sockprintf(sock," Node %3d: %s",i+1, username(&scfg,node.useron,str)); ! 2777: } ! 2778: sockprintf(sock,"211 End (%d active FTP clients)", active_clients); ! 2779: continue; ! 2780: } ! 2781: if(!stricmp(cmd, "SITE VER")) { ! 2782: sockprintf(sock,"211 %s",ftp_ver()); ! 2783: continue; ! 2784: } ! 2785: if(!stricmp(cmd, "SITE UPTIME")) { ! 2786: sockprintf(sock,"211 %s (%lu served)",sectostr(time(NULL)-uptime,str),served); ! 2787: continue; ! 2788: } ! 2789: if(!stricmp(cmd, "SITE RECYCLE") && user.level>=SYSOP_LEVEL) { ! 2790: startup->recycle_now=TRUE; ! 2791: sockprintf(sock,"211 server will recycle when not in-use"); ! 2792: continue; ! 2793: } ! 2794: if(!stricmp(cmd, "SITE RECYCLE ALL") && user.level>=SYSOP_LEVEL) { ! 2795: refresh_cfg(&scfg); ! 2796: sockprintf(sock,"211 ALL servers/nodes will recycle when not in-use"); ! 2797: continue; ! 2798: } ! 2799: if(!strnicmp(cmd,"SITE EXEC ",10) && sysop) { ! 2800: p=cmd+10; ! 2801: while(*p && *p<=' ') p++; ! 2802: #ifdef __unix__ ! 2803: fp=popen(p,"r"); ! 2804: if(fp==NULL) ! 2805: sockprintf(sock,"500 Error %d opening pipe to: %s",errno,p); ! 2806: else { ! 2807: while(!feof(fp)) { ! 2808: if(fgets(str,sizeof(str),fp)==NULL) ! 2809: break; ! 2810: sockprintf(sock,"200-%s",str); ! 2811: } ! 2812: sockprintf(sock,"200 %s returned %d",p,pclose(fp)); ! 2813: } ! 2814: #else ! 2815: sockprintf(sock,"200 system(%s) returned %d",p,system(p)); ! 2816: #endif ! 2817: continue; ! 2818: } ! 2819: ! 2820: ! 2821: #ifdef SOCKET_DEBUG_CTRL ! 2822: if(!stricmp(cmd, "SITE DEBUG")) { ! 2823: sockprintf(sock,"211-Debug"); ! 2824: for(i=0;i<sizeof(socket_debug);i++) ! 2825: if(socket_debug[i]!=0) ! 2826: sockprintf(sock,"211-socket %d = 0x%X",i,socket_debug[i]); ! 2827: sockprintf(sock,"211 End"); ! 2828: continue; ! 2829: } ! 2830: #endif ! 2831: ! 2832: if(!strnicmp(cmd, "PORT ",5)) { ! 2833: ! 2834: if(pasv_sock!=INVALID_SOCKET) ! 2835: ftp_close_socket(&pasv_sock,__LINE__); ! 2836: ! 2837: p=cmd+5; ! 2838: while(*p && *p<=' ') p++; ! 2839: sscanf(p,"%ld,%ld,%ld,%ld,%hd,%hd",&h1,&h2,&h3,&h4,&p1,&p2); ! 2840: data_addr.sin_addr.s_addr=htonl((h1<<24)|(h2<<16)|(h3<<8)|h4); ! 2841: data_addr.sin_port=(u_short)((p1<<8)|p2); ! 2842: if(data_addr.sin_port< IPPORT_RESERVED) { ! 2843: lprintf(LOG_WARNING,"%04d !SUSPECTED BOUNCE ATTACK ATTEMPT by %s to %s port %u" ! 2844: ,sock,user.alias ! 2845: ,inet_ntoa(data_addr.sin_addr),data_addr.sin_port); ! 2846: hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr); ! 2847: sockprintf(sock,"504 Bad port number."); ! 2848: #ifdef _WIN32 ! 2849: if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 2850: PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); ! 2851: #endif ! 2852: continue; /* As recommended by RFC2577 */ ! 2853: } ! 2854: data_addr.sin_port=htons(data_addr.sin_port); ! 2855: sockprintf(sock,"200 PORT Command successful."); ! 2856: mode="active"; ! 2857: continue; ! 2858: } ! 2859: ! 2860: if(!stricmp(cmd, "PASV") ! 2861: || !stricmp(cmd, "P@SW")) { /* Kludge required for SMC Barricade V1.2 */ ! 2862: ! 2863: if(pasv_sock!=INVALID_SOCKET) ! 2864: ftp_close_socket(&pasv_sock,__LINE__); ! 2865: ! 2866: if((pasv_sock=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) { ! 2867: lprintf(LOG_WARNING,"%04d !PASV ERROR %d opening socket", sock,ERROR_VALUE); ! 2868: sockprintf(sock,"425 Error %d opening PASV data socket", ERROR_VALUE); ! 2869: continue; ! 2870: } ! 2871: ! 2872: reuseaddr=FALSE; ! 2873: if((result=setsockopt(pasv_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&reuseaddr,sizeof(reuseaddr)))!=0) { ! 2874: lprintf(LOG_WARNING,"%04d !PASV ERROR %d disabling REUSEADDR socket option" ! 2875: ,sock,ERROR_VALUE); ! 2876: sockprintf(sock,"425 Error %d disabling REUSEADDR socket option", ERROR_VALUE); ! 2877: continue; ! 2878: } ! 2879: ! 2880: if(startup->options&FTP_OPT_DEBUG_DATA) ! 2881: lprintf(LOG_DEBUG,"%04d PASV DATA socket %d opened",sock,pasv_sock); ! 2882: ! 2883: for(port=startup->pasv_port_low; port<=startup->pasv_port_high; port++) { ! 2884: ! 2885: if(startup->options&FTP_OPT_DEBUG_DATA) ! 2886: lprintf(LOG_DEBUG,"%04d PASV DATA trying to bind socket to port %u" ! 2887: ,sock,port); ! 2888: ! 2889: pasv_addr.sin_port = htons(port); ! 2890: ! 2891: if((result=bind(pasv_sock, (struct sockaddr *) &pasv_addr,sizeof(pasv_addr)))==0) ! 2892: break; ! 2893: } ! 2894: if(result!= 0) { ! 2895: lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) binding socket to port %u" ! 2896: ,sock, result, ERROR_VALUE, port); ! 2897: sockprintf(sock,"425 Error %d binding data socket",ERROR_VALUE); ! 2898: ftp_close_socket(&pasv_sock,__LINE__); ! 2899: continue; ! 2900: } ! 2901: if(startup->options&FTP_OPT_DEBUG_DATA) ! 2902: lprintf(LOG_DEBUG,"%04d PASV DATA socket %d bound to port %u",sock,pasv_sock,port); ! 2903: ! 2904: addr_len=sizeof(addr); ! 2905: if((result=getsockname(pasv_sock, (struct sockaddr *)&addr,&addr_len))!=0) { ! 2906: lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) getting address/port" ! 2907: ,sock, result, ERROR_VALUE); ! 2908: sockprintf(sock,"425 Error %d getting address/port",ERROR_VALUE); ! 2909: ftp_close_socket(&pasv_sock,__LINE__); ! 2910: continue; ! 2911: } ! 2912: ! 2913: if((result=listen(pasv_sock, 1))!= 0) { ! 2914: lprintf(LOG_ERR,"%04d !PASV ERROR %d (%d) listening on port %u" ! 2915: ,sock, result, ERROR_VALUE,port); ! 2916: sockprintf(sock,"425 Error %d listening on data socket",ERROR_VALUE); ! 2917: ftp_close_socket(&pasv_sock,__LINE__); ! 2918: continue; ! 2919: } ! 2920: ! 2921: /* Choose IP address to use in passive response */ ! 2922: ip_addr=0; ! 2923: if(startup->options&FTP_OPT_LOOKUP_PASV_IP ! 2924: && (host=gethostbyname(startup->host_name))!=NULL) ! 2925: ip_addr=ntohl(*((ulong*)host->h_addr_list[0])); ! 2926: if(ip_addr==0 && (ip_addr=startup->pasv_ip_addr)==0) ! 2927: ip_addr=ntohl(pasv_addr.sin_addr.s_addr); ! 2928: ! 2929: if(startup->options&FTP_OPT_DEBUG_DATA) ! 2930: lprintf(LOG_INFO,"%04d PASV DATA IP address in response: %u.%u.%u.%u (subject to NAT)" ! 2931: ,sock ! 2932: ,(ip_addr>>24)&0xff ! 2933: ,(ip_addr>>16)&0xff ! 2934: ,(ip_addr>>8)&0xff ! 2935: ,ip_addr&0xff ! 2936: ); ! 2937: port=ntohs(addr.sin_port); ! 2938: sockprintf(sock,"227 Entering Passive Mode (%u,%u,%u,%u,%hu,%hu)" ! 2939: ,(ip_addr>>24)&0xff ! 2940: ,(ip_addr>>16)&0xff ! 2941: ,(ip_addr>>8)&0xff ! 2942: ,ip_addr&0xff ! 2943: ,(port>>8)&0xff ! 2944: ,port&0xff ! 2945: ); ! 2946: mode="passive"; ! 2947: continue; ! 2948: } ! 2949: ! 2950: if(!strnicmp(cmd, "TYPE ",5)) { ! 2951: sockprintf(sock,"200 All files sent in BINARY mode."); ! 2952: continue; ! 2953: } ! 2954: ! 2955: if(!strnicmp(cmd, "ALLO",4)) { ! 2956: p=cmd+5; ! 2957: while(*p && *p<=' ') p++; ! 2958: if(*p) ! 2959: l=atol(p); ! 2960: else ! 2961: l=0; ! 2962: if(local_fsys) ! 2963: avail=getfreediskspace(local_dir,0); ! 2964: else ! 2965: avail=getfreediskspace(scfg.data_dir,0); /* Change to temp_dir? */ ! 2966: if(l && l>avail) ! 2967: sockprintf(sock,"504 Only %lu bytes available.",avail); ! 2968: else ! 2969: sockprintf(sock,"200 %lu bytes available.",avail); ! 2970: continue; ! 2971: } ! 2972: ! 2973: if(!strnicmp(cmd, "REST",4)) { ! 2974: p=cmd+4; ! 2975: while(*p && *p<=' ') p++; ! 2976: if(*p) ! 2977: filepos=atol(p); ! 2978: else ! 2979: filepos=0; ! 2980: sockprintf(sock,"350 Restarting at %lu. Send STORE or RETRIEVE to initiate transfer." ! 2981: ,filepos); ! 2982: continue; ! 2983: } ! 2984: ! 2985: if(!strnicmp(cmd, "MODE ",5)) { ! 2986: p=cmd+5; ! 2987: while(*p && *p<=' ') p++; ! 2988: if(toupper(*p)!='S') ! 2989: sockprintf(sock,"504 Only STREAM mode supported."); ! 2990: else ! 2991: sockprintf(sock,"200 STREAM mode."); ! 2992: continue; ! 2993: } ! 2994: ! 2995: if(!strnicmp(cmd, "STRU ",5)) { ! 2996: p=cmd+5; ! 2997: while(*p && *p<=' ') p++; ! 2998: if(toupper(*p)!='F') ! 2999: sockprintf(sock,"504 Only FILE structure supported."); ! 3000: else ! 3001: sockprintf(sock,"200 FILE structure."); ! 3002: continue; ! 3003: } ! 3004: ! 3005: if(!stricmp(cmd, "SYST")) { ! 3006: sockprintf(sock,"215 UNIX Type: L8"); ! 3007: continue; ! 3008: } ! 3009: ! 3010: if(!stricmp(cmd, "ABOR")) { ! 3011: if(!transfer_inprogress) ! 3012: sockprintf(sock,"226 No tranfer in progress."); ! 3013: else { ! 3014: lprintf(LOG_WARNING,"%04d %s aborting transfer" ! 3015: ,sock,user.alias); ! 3016: transfer_aborted=TRUE; ! 3017: YIELD(); /* give send thread time to abort */ ! 3018: sockprintf(sock,"226 Transfer aborted."); ! 3019: } ! 3020: continue; ! 3021: } ! 3022: ! 3023: if(!strnicmp(cmd,"SMNT ",5) && sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) { ! 3024: p=cmd+5; ! 3025: while(*p && *p<=' ') p++; ! 3026: if(!stricmp(p,BBS_FSYS_DIR)) ! 3027: local_fsys=FALSE; ! 3028: else { ! 3029: if(!direxist(p)) { ! 3030: sockprintf(sock,"550 Directory does not exist."); ! 3031: lprintf(LOG_WARNING,"%04d !%s attempted to mount invalid directory: %s" ! 3032: ,sock, user.alias, p); ! 3033: continue; ! 3034: } ! 3035: local_fsys=TRUE; ! 3036: SAFECOPY(local_dir,p); ! 3037: } ! 3038: sockprintf(sock,"250 %s file system mounted." ! 3039: ,local_fsys ? "Local" : "BBS"); ! 3040: lprintf(LOG_INFO,"%04d %s mounted %s file system" ! 3041: ,sock, user.alias, local_fsys ? "local" : "BBS"); ! 3042: continue; ! 3043: } ! 3044: ! 3045: /****************************/ ! 3046: /* Local File System Access */ ! 3047: /****************************/ ! 3048: if(sysop && local_fsys && !(startup->options&FTP_OPT_NO_LOCAL_FSYS)) { ! 3049: if(local_dir[0] ! 3050: && local_dir[strlen(local_dir)-1]!='\\' ! 3051: && local_dir[strlen(local_dir)-1]!='/') ! 3052: strcat(local_dir,"/"); ! 3053: ! 3054: if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) { ! 3055: if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) { ! 3056: lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname); ! 3057: sockprintf(sock, "451 Insufficient system storage"); ! 3058: continue; ! 3059: } ! 3060: if(!strnicmp(cmd, "LIST", 4)) ! 3061: detail=TRUE; ! 3062: else ! 3063: detail=FALSE; ! 3064: ! 3065: p=cmd+4; ! 3066: while(*p && *p<=' ') p++; ! 3067: ! 3068: if(*p=='-') { /* -Letc */ ! 3069: while(*p && *p>' ') p++; ! 3070: while(*p && *p<=' ') p++; ! 3071: } ! 3072: ! 3073: SAFEPRINTF2(path,"%s%s",local_dir, *p ? p : "*"); ! 3074: lprintf(LOG_INFO,"%04d %s listing: %s in %s mode", sock, user.alias, path, mode); ! 3075: sockprintf(sock, "150 Directory of %s%s", local_dir, p); ! 3076: ! 3077: now=time(NULL); ! 3078: if(localtime_r(&now,&cur_tm)==NULL) ! 3079: memset(&cur_tm,0,sizeof(cur_tm)); ! 3080: ! 3081: glob(path,0,NULL,&g); ! 3082: for(i=0;i<(int)g.gl_pathc;i++) { ! 3083: if(detail) { ! 3084: f.size=flength(g.gl_pathv[i]); ! 3085: t=fdate(g.gl_pathv[i]); ! 3086: if(localtime_r(&t,&tm)==NULL) ! 3087: memset(&tm,0,sizeof(tm)); ! 3088: fprintf(fp,"%crw-r--r-- 1 %-8s local %9ld %s %2d " ! 3089: ,isdir(g.gl_pathv[i]) ? 'd':'-' ! 3090: ,scfg.sys_id ! 3091: ,f.size ! 3092: ,ftp_mon[tm.tm_mon],tm.tm_mday); ! 3093: if(tm.tm_year==cur_tm.tm_year) ! 3094: fprintf(fp,"%02d:%02d %s\r\n" ! 3095: ,tm.tm_hour,tm.tm_min ! 3096: ,getfname(g.gl_pathv[i])); ! 3097: else ! 3098: fprintf(fp,"%5d %s\r\n" ! 3099: ,1900+tm.tm_year ! 3100: ,getfname(g.gl_pathv[i])); ! 3101: } else ! 3102: fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i])); ! 3103: } ! 3104: globfree(&g); ! 3105: fclose(fp); ! 3106: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L ! 3107: ,&transfer_inprogress,&transfer_aborted ! 3108: ,TRUE /* delfile */ ! 3109: ,TRUE /* tmpfile */ ! 3110: ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL); ! 3111: continue; ! 3112: } /* Local LIST/NLST */ ! 3113: ! 3114: if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) { ! 3115: if(!strnicmp(cmd,"CWD ",4)) ! 3116: p=cmd+4; ! 3117: else ! 3118: p=cmd+5; ! 3119: while(*p && *p<=' ') p++; ! 3120: tp=p; ! 3121: if(*tp=='/' || *tp=='\\') /* /local: and /bbs: are valid */ ! 3122: tp++; ! 3123: if(!strnicmp(tp,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) { ! 3124: local_fsys=FALSE; ! 3125: sockprintf(sock,"250 CWD command successful (BBS file system mounted)."); ! 3126: lprintf(LOG_INFO,"%04d %s mounted BBS file system", sock, user.alias); ! 3127: continue; ! 3128: } ! 3129: if(!strnicmp(tp,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) { ! 3130: tp+=strlen(LOCAL_FSYS_DIR); /* already mounted */ ! 3131: p=tp; ! 3132: } ! 3133: ! 3134: if(p[1]==':' || !strncmp(p,"\\\\",2)) ! 3135: SAFECOPY(path,p); ! 3136: else if(*p=='/' || *p=='\\') ! 3137: SAFEPRINTF2(path,"%s%s",root_dir(local_dir),p); ! 3138: else { ! 3139: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3140: FULLPATH(path,fname,sizeof(path)); ! 3141: } ! 3142: ! 3143: if(!direxist(path)) { ! 3144: sockprintf(sock,"550 Directory does not exist (%s).",path); ! 3145: lprintf(LOG_WARNING,"%04d !%s attempted to change to an invalid directory: %s" ! 3146: ,sock, user.alias, path); ! 3147: } else { ! 3148: SAFECOPY(local_dir,path); ! 3149: sockprintf(sock,"250 CWD command successful (%s).", local_dir); ! 3150: } ! 3151: continue; ! 3152: } /* Local CWD */ ! 3153: ! 3154: if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) { ! 3155: SAFEPRINTF(path,"%s..",local_dir); ! 3156: if(FULLPATH(local_dir,path,sizeof(local_dir))==NULL) ! 3157: sockprintf(sock,"550 Directory does not exist."); ! 3158: else ! 3159: sockprintf(sock,"200 CDUP command successful."); ! 3160: continue; ! 3161: } ! 3162: ! 3163: if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) { ! 3164: if(strlen(local_dir)>3) ! 3165: local_dir[strlen(local_dir)-1]=0; /* truncate '/' */ ! 3166: ! 3167: sockprintf(sock,"257 \"%s\" is current directory." ! 3168: ,local_dir); ! 3169: continue; ! 3170: } /* Local PWD */ ! 3171: ! 3172: if(!strnicmp(cmd, "MKD ", 4) || !strnicmp(cmd,"XMKD",4)) { ! 3173: p=cmd+4; ! 3174: while(*p && *p<=' ') p++; ! 3175: if(*p=='/') /* absolute */ ! 3176: SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1); ! 3177: else /* relative */ ! 3178: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3179: ! 3180: if((i=MKDIR(fname))==0) { ! 3181: sockprintf(sock,"257 \"%s\" directory created",fname); ! 3182: lprintf(LOG_NOTICE,"%04d %s created directory: %s",sock,user.alias,fname); ! 3183: } else { ! 3184: sockprintf(sock,"521 Error %d creating directory: %s",i,fname); ! 3185: lprintf(LOG_WARNING,"%04d !%s attempted to create directory: %s (Error %d)" ! 3186: ,sock,user.alias,fname,i); ! 3187: } ! 3188: continue; ! 3189: } ! 3190: ! 3191: if(!strnicmp(cmd, "RMD ", 4) || !strnicmp(cmd,"XRMD",4)) { ! 3192: p=cmd+4; ! 3193: while(*p && *p<=' ') p++; ! 3194: if(*p=='/') /* absolute */ ! 3195: SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1); ! 3196: else /* relative */ ! 3197: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3198: ! 3199: if((i=rmdir(fname))==0) { ! 3200: sockprintf(sock,"250 \"%s\" directory removed",fname); ! 3201: lprintf(LOG_NOTICE,"%04d %s removed directory: %s",sock,user.alias,fname); ! 3202: } else { ! 3203: sockprintf(sock,"450 Error %d removing directory: %s",i,fname); ! 3204: lprintf(LOG_WARNING,"%04d !%s attempted to remove directory: %s (Error %d)" ! 3205: ,sock,user.alias,fname,i); ! 3206: } ! 3207: continue; ! 3208: } ! 3209: ! 3210: if(!strnicmp(cmd, "RNFR ",5)) { ! 3211: p=cmd+5; ! 3212: while(*p && *p<=' ') p++; ! 3213: if(*p=='/') /* absolute */ ! 3214: SAFEPRINTF2(ren_from,"%s%s",root_dir(local_dir),p+1); ! 3215: else /* relative */ ! 3216: SAFEPRINTF2(ren_from,"%s%s",local_dir,p); ! 3217: if(!fexist(ren_from)) { ! 3218: sockprintf(sock,"550 File not found: %s",ren_from); ! 3219: lprintf(LOG_WARNING,"%04d !%s attempted to rename %s (not found)" ! 3220: ,sock,user.alias,ren_from); ! 3221: } else ! 3222: sockprintf(sock,"350 File exists, ready for destination name"); ! 3223: continue; ! 3224: } ! 3225: ! 3226: if(!strnicmp(cmd, "RNTO ",5)) { ! 3227: p=cmd+5; ! 3228: while(*p && *p<=' ') p++; ! 3229: if(*p=='/') /* absolute */ ! 3230: SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1); ! 3231: else /* relative */ ! 3232: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3233: ! 3234: if((i=rename(ren_from, fname))==0) { ! 3235: sockprintf(sock,"250 \"%s\" renamed to \"%s\"",ren_from,fname); ! 3236: lprintf(LOG_NOTICE,"%04d %s renamed %s to %s",sock,user.alias,ren_from,fname); ! 3237: } else { ! 3238: sockprintf(sock,"450 Error %d renaming file: %s",i,ren_from); ! 3239: lprintf(LOG_WARNING,"%04d !%s attempted to rename file: %s (Error %d)" ! 3240: ,sock,user.alias,ren_from,i); ! 3241: } ! 3242: continue; ! 3243: } ! 3244: ! 3245: ! 3246: if(!strnicmp(cmd, "RETR ", 5) || !strnicmp(cmd,"SIZE ",5) ! 3247: || !strnicmp(cmd, "MDTM ",5) || !strnicmp(cmd, "DELE ",5)) { ! 3248: p=cmd+5; ! 3249: while(*p && *p<=' ') p++; ! 3250: ! 3251: if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) ! 3252: p+=strlen(LOCAL_FSYS_DIR); /* already mounted */ ! 3253: ! 3254: if(p[1]==':') /* drive specified */ ! 3255: SAFECOPY(fname,p); ! 3256: else if(*p=='/') /* absolute, current drive */ ! 3257: SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1); ! 3258: else /* relative */ ! 3259: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3260: if(!fexist(fname)) { ! 3261: lprintf(LOG_WARNING,"%04d !%s file not found: %s",sock,user.alias,fname); ! 3262: sockprintf(sock,"550 File not found: %s",fname); ! 3263: continue; ! 3264: } ! 3265: if(!strnicmp(cmd,"SIZE ",5)) { ! 3266: sockprintf(sock,"213 %lu",flength(fname)); ! 3267: continue; ! 3268: } ! 3269: if(!strnicmp(cmd,"MDTM ",5)) { ! 3270: t=fdate(fname); ! 3271: if(gmtime_r(&t,&tm)==NULL) /* specifically use GMT/UTC representation */ ! 3272: memset(&tm,0,sizeof(tm)); ! 3273: sockprintf(sock,"213 %u%02u%02u%02u%02u%02u" ! 3274: ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday ! 3275: ,tm.tm_hour,tm.tm_min,tm.tm_sec); ! 3276: continue; ! 3277: } ! 3278: if(!strnicmp(cmd,"DELE ",5)) { ! 3279: if((i=remove(fname))==0) { ! 3280: sockprintf(sock,"250 \"%s\" removed successfully.",fname); ! 3281: lprintf(LOG_NOTICE,"%04d %s deleted file: %s",sock,user.alias,fname); ! 3282: } else { ! 3283: sockprintf(sock,"450 Error %d removing file: %s",i,fname); ! 3284: lprintf(LOG_WARNING,"%04d !%s attempted to delete file: %s (Error %d)" ! 3285: ,sock,user.alias,fname,i); ! 3286: } ! 3287: continue; ! 3288: } ! 3289: /* RETR */ ! 3290: lprintf(LOG_INFO,"%04d %s downloading: %s (%lu bytes) in %s mode" ! 3291: ,sock,user.alias,fname,flength(fname) ! 3292: ,mode); ! 3293: sockprintf(sock,"150 Opening BINARY mode data connection for file transfer."); ! 3294: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos ! 3295: ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE ! 3296: ,&lastactive,&user,-1,FALSE,FALSE,FALSE,NULL); ! 3297: continue; ! 3298: } /* Local RETR/SIZE/MDTM */ ! 3299: ! 3300: if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) { ! 3301: p=cmd+5; ! 3302: while(*p && *p<=' ') p++; ! 3303: ! 3304: if(!strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) ! 3305: p+=strlen(LOCAL_FSYS_DIR); /* already mounted */ ! 3306: ! 3307: if(p[1]==':') /* drive specified */ ! 3308: SAFECOPY(fname,p); ! 3309: else if(*p=='/') /* absolute, current drive */ ! 3310: SAFEPRINTF2(fname,"%s%s",root_dir(local_dir),p+1); ! 3311: else /* relative */ ! 3312: SAFEPRINTF2(fname,"%s%s",local_dir,p); ! 3313: ! 3314: lprintf(LOG_INFO,"%04d %s uploading: %s in %s mode", sock,user.alias,fname ! 3315: ,mode); ! 3316: sockprintf(sock,"150 Opening BINARY mode data connection for file transfer."); ! 3317: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos ! 3318: ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE ! 3319: ,&lastactive ! 3320: ,&user ! 3321: ,-1 /* dir */ ! 3322: ,TRUE /* uploading */ ! 3323: ,FALSE /* credits */ ! 3324: ,!strnicmp(cmd,"APPE",4) ? TRUE : FALSE /* append */ ! 3325: ,NULL /* desc */ ! 3326: ); ! 3327: filepos=0; ! 3328: continue; ! 3329: } /* Local STOR */ ! 3330: } ! 3331: ! 3332: if(!strnicmp(cmd, "LIST", 4) || !strnicmp(cmd, "NLST", 4)) { ! 3333: dir=curdir; ! 3334: lib=curlib; ! 3335: ! 3336: if(cmd[4]!=0) ! 3337: lprintf(LOG_DEBUG,"%04d LIST/NLST: %s",sock,cmd); ! 3338: ! 3339: /* path specified? */ ! 3340: p=cmd+4; ! 3341: while(*p && *p<=' ') p++; ! 3342: ! 3343: if(*p=='-') { /* -Letc */ ! 3344: while(*p && *p>' ') p++; ! 3345: while(*p && *p<=' ') p++; ! 3346: } ! 3347: ! 3348: parsepath(&p,&user,&lib,&dir); ! 3349: ! 3350: if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) { ! 3351: lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname); ! 3352: sockprintf(sock, "451 Insufficient system storage"); ! 3353: continue; ! 3354: } ! 3355: if(!strnicmp(cmd, "LIST", 4)) ! 3356: detail=TRUE; ! 3357: else ! 3358: detail=FALSE; ! 3359: sockprintf(sock,"150 Opening ASCII mode data connection for /bin/ls."); ! 3360: now=time(NULL); ! 3361: if(localtime_r(&now,&cur_tm)==NULL) ! 3362: memset(&cur_tm,0,sizeof(cur_tm)); ! 3363: ! 3364: /* ASCII Index File */ ! 3365: if(startup->options&FTP_OPT_INDEX_FILE && startup->index_file_name[0] ! 3366: && (!stricmp(p,startup->index_file_name) || *p==0 || *p=='*')) { ! 3367: if(detail) ! 3368: fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3369: ,NAME_LEN ! 3370: ,scfg.sys_id ! 3371: ,lib<0 ? scfg.sys_id : dir<0 ! 3372: ? scfg.lib[lib]->sname : scfg.dir[dir]->code_suffix ! 3373: ,512L ! 3374: ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min ! 3375: ,startup->index_file_name); ! 3376: else ! 3377: fprintf(fp,"%s\r\n",startup->index_file_name); ! 3378: } ! 3379: /* HTML Index File */ ! 3380: if(startup->options&FTP_OPT_HTML_INDEX_FILE && startup->html_index_file[0] ! 3381: && (!stricmp(p,startup->html_index_file) || *p==0 || *p=='*')) { ! 3382: if(detail) ! 3383: fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3384: ,NAME_LEN ! 3385: ,scfg.sys_id ! 3386: ,lib<0 ? scfg.sys_id : dir<0 ! 3387: ? scfg.lib[lib]->sname : scfg.dir[dir]->code_suffix ! 3388: ,512L ! 3389: ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min ! 3390: ,startup->html_index_file); ! 3391: else ! 3392: fprintf(fp,"%s\r\n",startup->html_index_file); ! 3393: } ! 3394: ! 3395: if(lib<0) { /* Root dir */ ! 3396: lprintf(LOG_INFO,"%04d %s listing: root in %s mode",sock,user.alias, mode); ! 3397: ! 3398: /* QWK Packet */ ! 3399: if(startup->options&FTP_OPT_ALLOW_QWK/* && fexist(qwkfile)*/) { ! 3400: if(detail) { ! 3401: if(fexistcase(qwkfile)) { ! 3402: t=fdate(qwkfile); ! 3403: l=flength(qwkfile); ! 3404: } else { ! 3405: t=time(NULL); ! 3406: l=10240; ! 3407: }; ! 3408: if(localtime_r(&t,&tm)==NULL) ! 3409: memset(&tm,0,sizeof(tm)); ! 3410: fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s.qwk\r\n" ! 3411: ,NAME_LEN ! 3412: ,scfg.sys_id ! 3413: ,scfg.sys_id ! 3414: ,l ! 3415: ,ftp_mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min ! 3416: ,scfg.sys_id); ! 3417: } else ! 3418: fprintf(fp,"%s.qwk\r\n",scfg.sys_id); ! 3419: } ! 3420: ! 3421: /* File Aliases */ ! 3422: sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir); ! 3423: if((alias_fp=fopen(aliasfile,"r"))!=NULL) { ! 3424: ! 3425: while(!feof(alias_fp)) { ! 3426: if(!fgets(aliasline,sizeof(aliasline),alias_fp)) ! 3427: break; ! 3428: ! 3429: alias_dir=FALSE; ! 3430: ! 3431: p=aliasline; /* alias pointer */ ! 3432: while(*p && *p<=' ') p++; ! 3433: ! 3434: if(*p==';') /* comment */ ! 3435: continue; ! 3436: ! 3437: tp=p; /* terminator pointer */ ! 3438: while(*tp && *tp>' ') tp++; ! 3439: if(*tp) *tp=0; ! 3440: ! 3441: np=tp+1; /* filename pointer */ ! 3442: while(*np && *np<=' ') np++; ! 3443: ! 3444: tp=np; /* terminator pointer */ ! 3445: while(*tp && *tp>' ') tp++; ! 3446: if(*tp) *tp=0; ! 3447: ! 3448: dp=tp+1; /* description pointer */ ! 3449: while(*dp && *dp<=' ') dp++; ! 3450: truncsp(dp); ! 3451: ! 3452: if(stricmp(dp,BBS_HIDDEN_ALIAS)==0) ! 3453: continue; ! 3454: ! 3455: /* Virtual Path? */ ! 3456: if(!strnicmp(np,BBS_VIRTUAL_PATH,strlen(BBS_VIRTUAL_PATH))) { ! 3457: if((dir=getdir(np+strlen(BBS_VIRTUAL_PATH),&user))<0) ! 3458: continue; /* No access or invalid virtual path */ ! 3459: tp=strrchr(np,'/'); ! 3460: if(tp==NULL) ! 3461: continue; ! 3462: tp++; ! 3463: if(*tp) { ! 3464: SAFEPRINTF2(aliasfile,"%s%s",scfg.dir[dir]->path,tp); ! 3465: np=aliasfile; ! 3466: } ! 3467: else ! 3468: alias_dir=TRUE; ! 3469: } ! 3470: ! 3471: if(!alias_dir && !fexist(np)) ! 3472: continue; ! 3473: ! 3474: if(detail) { ! 3475: ! 3476: if(alias_dir==TRUE) { ! 3477: fprintf(fp,"drwxrwxrwx 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3478: ,NAME_LEN ! 3479: ,scfg.sys_id ! 3480: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 3481: ,512L ! 3482: ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min ! 3483: ,p); ! 3484: } ! 3485: else { ! 3486: t=fdate(np); ! 3487: if(localtime_r(&t,&tm)==NULL) ! 3488: memset(&tm,0,sizeof(tm)); ! 3489: fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3490: ,NAME_LEN ! 3491: ,scfg.sys_id ! 3492: ,scfg.sys_id ! 3493: ,flength(np) ! 3494: ,ftp_mon[tm.tm_mon],tm.tm_mday,tm.tm_hour,tm.tm_min ! 3495: ,p); ! 3496: } ! 3497: } else ! 3498: fprintf(fp,"%s\r\n",p); ! 3499: ! 3500: } ! 3501: ! 3502: fclose(alias_fp); ! 3503: } ! 3504: ! 3505: /* Library folders */ ! 3506: for(i=0;i<scfg.total_libs;i++) { ! 3507: if(!chk_ar(&scfg,scfg.lib[i]->ar,&user)) ! 3508: continue; ! 3509: if(detail) ! 3510: fprintf(fp,"dr-xr-xr-x 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3511: ,NAME_LEN ! 3512: ,scfg.sys_id ! 3513: ,scfg.sys_id ! 3514: ,512L ! 3515: ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min ! 3516: ,scfg.lib[i]->sname); ! 3517: else ! 3518: fprintf(fp,"%s\r\n",scfg.lib[i]->sname); ! 3519: } ! 3520: } else if(dir<0) { ! 3521: lprintf(LOG_INFO,"%04d %s listing: %s library in %s mode" ! 3522: ,sock,user.alias,scfg.lib[lib]->sname,mode); ! 3523: for(i=0;i<scfg.total_dirs;i++) { ! 3524: if(scfg.dir[i]->lib!=lib) ! 3525: continue; ! 3526: if(i!=scfg.sysop_dir && i!=scfg.upload_dir ! 3527: && !chk_ar(&scfg,scfg.dir[i]->ar,&user)) ! 3528: continue; ! 3529: if(detail) ! 3530: fprintf(fp,"drwxrwxrwx 1 %-*s %-8s %9ld %s %2d %02d:%02d %s\r\n" ! 3531: ,NAME_LEN ! 3532: ,scfg.sys_id ! 3533: ,scfg.lib[lib]->sname ! 3534: ,512L ! 3535: ,ftp_mon[cur_tm.tm_mon],cur_tm.tm_mday,cur_tm.tm_hour,cur_tm.tm_min ! 3536: ,scfg.dir[i]->code_suffix); ! 3537: else ! 3538: fprintf(fp,"%s\r\n",scfg.dir[i]->code_suffix); ! 3539: } ! 3540: } else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)) { ! 3541: lprintf(LOG_INFO,"%04d %s listing: %s/%s directory in %s mode" ! 3542: ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code_suffix,mode); ! 3543: ! 3544: SAFEPRINTF2(path,"%s%s",scfg.dir[dir]->path,*p ? p : "*"); ! 3545: glob(path,0,NULL,&g); ! 3546: for(i=0;i<(int)g.gl_pathc;i++) { ! 3547: if(isdir(g.gl_pathv[i])) ! 3548: continue; ! 3549: #ifdef _WIN32 ! 3550: GetShortPathName(g.gl_pathv[i], str, sizeof(str)); ! 3551: #else ! 3552: SAFECOPY(str,g.gl_pathv[i]); ! 3553: #endif ! 3554: padfname(getfname(str),f.name); ! 3555: f.dir=dir; ! 3556: if((filedat=getfileixb(&scfg,&f))==FALSE ! 3557: && !(startup->options&FTP_OPT_DIR_FILES)) ! 3558: continue; ! 3559: if(detail) { ! 3560: f.size=flength(g.gl_pathv[i]); ! 3561: getfiledat(&scfg,&f); ! 3562: t=fdate(g.gl_pathv[i]); ! 3563: if(localtime_r(&t,&tm)==NULL) ! 3564: memset(&tm,0,sizeof(tm)); ! 3565: if(filedat) { ! 3566: if(f.misc&FM_ANON) ! 3567: SAFECOPY(str,ANONYMOUS); ! 3568: else ! 3569: dotname(f.uler,str); ! 3570: } else ! 3571: SAFECOPY(str,scfg.sys_id); ! 3572: fprintf(fp,"-r--r--r-- 1 %-*s %-8s %9ld %s %2d " ! 3573: ,NAME_LEN ! 3574: ,str ! 3575: ,scfg.dir[dir]->code_suffix ! 3576: ,f.size ! 3577: ,ftp_mon[tm.tm_mon],tm.tm_mday); ! 3578: if(tm.tm_year==cur_tm.tm_year) ! 3579: fprintf(fp,"%02d:%02d %s\r\n" ! 3580: ,tm.tm_hour,tm.tm_min ! 3581: ,getfname(g.gl_pathv[i])); ! 3582: else ! 3583: fprintf(fp,"%5d %s\r\n" ! 3584: ,1900+tm.tm_year ! 3585: ,getfname(g.gl_pathv[i])); ! 3586: } else ! 3587: fprintf(fp,"%s\r\n",getfname(g.gl_pathv[i])); ! 3588: } ! 3589: globfree(&g); ! 3590: } else ! 3591: lprintf(LOG_INFO,"%04d %s listing: %s/%s directory in %s mode (empty - no access)" ! 3592: ,sock,user.alias,scfg.lib[lib]->sname,scfg.dir[dir]->code_suffix,mode); ! 3593: ! 3594: fclose(fp); ! 3595: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,0L ! 3596: ,&transfer_inprogress,&transfer_aborted ! 3597: ,TRUE /* delfile */ ! 3598: ,TRUE /* tmpfile */ ! 3599: ,&lastactive,&user,dir,FALSE,FALSE,FALSE,NULL); ! 3600: continue; ! 3601: } ! 3602: ! 3603: if(!strnicmp(cmd, "RETR ", 5) ! 3604: || !strnicmp(cmd, "SIZE ",5) ! 3605: || !strnicmp(cmd, "MDTM ",5) ! 3606: || !strnicmp(cmd, "DELE ",5)) { ! 3607: getdate=FALSE; ! 3608: getsize=FALSE; ! 3609: delecmd=FALSE; ! 3610: if(!strnicmp(cmd,"SIZE ",5)) ! 3611: getsize=TRUE; ! 3612: else if(!strnicmp(cmd,"MDTM ",5)) ! 3613: getdate=TRUE; ! 3614: else if(!strnicmp(cmd,"DELE ",5)) ! 3615: delecmd=TRUE; ! 3616: ! 3617: if(!getsize && !getdate && user.rest&FLAG('D')) { ! 3618: sockprintf(sock,"550 Insufficient access."); ! 3619: filepos=0; ! 3620: continue; ! 3621: } ! 3622: credits=TRUE; ! 3623: success=FALSE; ! 3624: delfile=FALSE; ! 3625: tmpfile=FALSE; ! 3626: lib=curlib; ! 3627: dir=curdir; ! 3628: ! 3629: p=cmd+5; ! 3630: while(*p && *p<=' ') p++; ! 3631: ! 3632: if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) ! 3633: p+=strlen(BBS_FSYS_DIR); /* already mounted */ ! 3634: ! 3635: if(*p=='/') { ! 3636: lib=-1; ! 3637: p++; ! 3638: } ! 3639: else if(!strncmp(p,"./",2)) ! 3640: p+=2; ! 3641: ! 3642: if(lib<0 && ftpalias(p, fname, &user, &dir)==TRUE) { ! 3643: success=TRUE; ! 3644: credits=TRUE; /* include in d/l stats */ ! 3645: tmpfile=FALSE; ! 3646: delfile=FALSE; ! 3647: lprintf(LOG_INFO,"%04d %s %.4s by alias: %s" ! 3648: ,sock,user.alias,cmd,p); ! 3649: p=getfname(fname); ! 3650: if(dir>=0) ! 3651: lib=scfg.dir[dir]->lib; ! 3652: } ! 3653: if(!success && lib<0 && (tp=strchr(p,'/'))!=NULL) { ! 3654: dir=-1; ! 3655: *tp=0; ! 3656: for(i=0;i<scfg.total_libs;i++) { ! 3657: if(!chk_ar(&scfg,scfg.lib[i]->ar,&user)) ! 3658: continue; ! 3659: if(!stricmp(scfg.lib[i]->sname,p)) ! 3660: break; ! 3661: } ! 3662: if(i<scfg.total_libs) ! 3663: lib=i; ! 3664: p=tp+1; ! 3665: } ! 3666: if(!success && dir<0 && (tp=strchr(p,'/'))!=NULL) { ! 3667: *tp=0; ! 3668: for(i=0;i<scfg.total_dirs;i++) { ! 3669: if(scfg.dir[i]->lib!=lib) ! 3670: continue; ! 3671: if(!chk_ar(&scfg,scfg.dir[i]->ar,&user)) ! 3672: continue; ! 3673: if(!stricmp(scfg.dir[i]->code_suffix,p)) ! 3674: break; ! 3675: } ! 3676: if(i<scfg.total_dirs) ! 3677: dir=i; ! 3678: p=tp+1; ! 3679: } ! 3680: ! 3681: sprintf(html_index_ext,"%s?",startup->html_index_file); ! 3682: ! 3683: sprintf(str,"%s.qwk",scfg.sys_id); ! 3684: if(lib<0 && startup->options&FTP_OPT_ALLOW_QWK ! 3685: && !stricmp(p,str) && !delecmd) { ! 3686: if(!fexistcase(qwkfile)) { ! 3687: lprintf(LOG_INFO,"%04d %s creating QWK packet...",sock,user.alias); ! 3688: sprintf(str,"%spack%04u.now",scfg.data_dir,user.number); ! 3689: if(!ftouch(str)) ! 3690: lprintf(LOG_ERR,"%04d !ERROR creating semaphore file: %s" ! 3691: ,sock, str); ! 3692: t=time(NULL); ! 3693: while(fexist(str)) { ! 3694: if(time(NULL)-t>startup->qwk_timeout) ! 3695: break; ! 3696: mswait(1000); ! 3697: } ! 3698: if(fexist(str)) { ! 3699: lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for QWK packet creation",sock); ! 3700: sockprintf(sock,"451 Time-out waiting for packet creation."); ! 3701: remove(str); ! 3702: filepos=0; ! 3703: continue; ! 3704: } ! 3705: if(!fexistcase(qwkfile)) { ! 3706: lprintf(LOG_INFO,"%04d No QWK Packet created (no new messages)",sock); ! 3707: sockprintf(sock,"550 No QWK packet created (no new messages)"); ! 3708: filepos=0; ! 3709: continue; ! 3710: } ! 3711: } ! 3712: SAFECOPY(fname,qwkfile); ! 3713: success=TRUE; ! 3714: delfile=TRUE; ! 3715: credits=FALSE; ! 3716: if(!getsize && !getdate) ! 3717: lprintf(LOG_INFO,"%04d %s downloading QWK packet (%lu bytes) in %s mode" ! 3718: ,sock,user.alias,flength(fname) ! 3719: ,mode); ! 3720: /* ASCII Index File */ ! 3721: } else if(startup->options&FTP_OPT_INDEX_FILE ! 3722: && !stricmp(p,startup->index_file_name) ! 3723: && !delecmd) { ! 3724: if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) { ! 3725: lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname); ! 3726: sockprintf(sock, "451 Insufficient system storage"); ! 3727: filepos=0; ! 3728: continue; ! 3729: } ! 3730: if(!getsize && !getdate) ! 3731: lprintf(LOG_INFO,"%04d %s downloading index for %s in %s mode" ! 3732: ,sock,user.alias,vpath(lib,dir,str) ! 3733: ,mode); ! 3734: success=TRUE; ! 3735: credits=FALSE; ! 3736: tmpfile=TRUE; ! 3737: delfile=TRUE; ! 3738: fprintf(fp,"%-*s File/Folder Descriptions\r\n" ! 3739: ,INDEX_FNAME_LEN,startup->index_file_name); ! 3740: if(startup->options&FTP_OPT_HTML_INDEX_FILE) ! 3741: fprintf(fp,"%-*s File/Folder Descriptions (HTML)\r\n" ! 3742: ,INDEX_FNAME_LEN,startup->html_index_file); ! 3743: if(lib<0) { ! 3744: ! 3745: /* File Aliases */ ! 3746: sprintf(aliasfile,"%sftpalias.cfg",scfg.ctrl_dir); ! 3747: if((alias_fp=fopen(aliasfile,"r"))!=NULL) { ! 3748: ! 3749: while(!feof(alias_fp)) { ! 3750: if(!fgets(aliasline,sizeof(aliasline),alias_fp)) ! 3751: break; ! 3752: ! 3753: p=aliasline; /* alias pointer */ ! 3754: while(*p && *p<=' ') p++; ! 3755: ! 3756: if(*p==';') /* comment */ ! 3757: continue; ! 3758: ! 3759: tp=p; /* terminator pointer */ ! 3760: while(*tp && *tp>' ') tp++; ! 3761: if(*tp) *tp=0; ! 3762: ! 3763: np=tp+1; /* filename pointer */ ! 3764: while(*np && *np<=' ') np++; ! 3765: ! 3766: np++; /* description pointer */ ! 3767: while(*np && *np>' ') np++; ! 3768: ! 3769: while(*np && *np<' ') np++; ! 3770: ! 3771: truncsp(np); ! 3772: ! 3773: fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN,p,np); ! 3774: } ! 3775: ! 3776: fclose(alias_fp); ! 3777: } ! 3778: ! 3779: /* QWK Packet */ ! 3780: if(startup->options&FTP_OPT_ALLOW_QWK /* && fexist(qwkfile) */) { ! 3781: sprintf(str,"%s.qwk",scfg.sys_id); ! 3782: fprintf(fp,"%-*s QWK Message Packet\r\n" ! 3783: ,INDEX_FNAME_LEN,str); ! 3784: } ! 3785: ! 3786: /* Library Folders */ ! 3787: for(i=0;i<scfg.total_libs;i++) { ! 3788: if(!chk_ar(&scfg,scfg.lib[i]->ar,&user)) ! 3789: continue; ! 3790: fprintf(fp,"%-*s %s\r\n" ! 3791: ,INDEX_FNAME_LEN,scfg.lib[i]->sname,scfg.lib[i]->lname); ! 3792: } ! 3793: } else if(dir<0) { ! 3794: for(i=0;i<scfg.total_dirs;i++) { ! 3795: if(scfg.dir[i]->lib!=lib) ! 3796: continue; ! 3797: if(i!=scfg.sysop_dir && i!=scfg.upload_dir ! 3798: && !chk_ar(&scfg,scfg.dir[i]->ar,&user)) ! 3799: continue; ! 3800: fprintf(fp,"%-*s %s\r\n" ! 3801: ,INDEX_FNAME_LEN,scfg.dir[i]->code_suffix,scfg.dir[i]->lname); ! 3802: } ! 3803: } else if(chk_ar(&scfg,scfg.dir[dir]->ar,&user)){ ! 3804: sprintf(cmd,"%s*",scfg.dir[dir]->path); ! 3805: glob(cmd,0,NULL,&g); ! 3806: for(i=0;i<(int)g.gl_pathc;i++) { ! 3807: if(isdir(g.gl_pathv[i])) ! 3808: continue; ! 3809: #ifdef _WIN32 ! 3810: GetShortPathName(g.gl_pathv[i], str, sizeof(str)); ! 3811: #else ! 3812: SAFECOPY(str,g.gl_pathv[i]); ! 3813: #endif ! 3814: padfname(getfname(str),f.name); ! 3815: f.dir=dir; ! 3816: if(getfileixb(&scfg,&f)) { ! 3817: f.size=flength(g.gl_pathv[i]); ! 3818: getfiledat(&scfg,&f); ! 3819: fprintf(fp,"%-*s %s\r\n",INDEX_FNAME_LEN ! 3820: ,getfname(g.gl_pathv[i]),f.desc); ! 3821: } ! 3822: } ! 3823: globfree(&g); ! 3824: } ! 3825: fclose(fp); ! 3826: /* HTML Index File */ ! 3827: } else if(startup->options&FTP_OPT_HTML_INDEX_FILE ! 3828: && (!stricmp(p,startup->html_index_file) ! 3829: || !strnicmp(p,html_index_ext,strlen(html_index_ext))) ! 3830: && !delecmd) { ! 3831: #ifdef JAVASCRIPT ! 3832: if(startup->options&FTP_OPT_NO_JAVASCRIPT) { ! 3833: lprintf(LOG_ERR,"%04d !JavaScript disabled, cannot generate %s",sock,fname); ! 3834: sockprintf(sock, "451 JavaScript disabled"); ! 3835: filepos=0; ! 3836: continue; ! 3837: } ! 3838: if(js_runtime == NULL) { ! 3839: lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes" ! 3840: ,sock,startup->js.max_bytes); ! 3841: ! 3842: if((js_runtime = JS_NewRuntime(startup->js.max_bytes))==NULL) { ! 3843: lprintf(LOG_ERR,"%04d !ERROR creating JavaScript runtime",sock); ! 3844: sockprintf(sock,"451 Error creating JavaScript runtime"); ! 3845: filepos=0; ! 3846: continue; ! 3847: } ! 3848: } ! 3849: ! 3850: if(js_cx==NULL) { /* Context not yet created, create it now */ ! 3851: if(((js_cx=js_initcx(js_runtime, sock,&js_glob,&js_ftp))==NULL)) { ! 3852: lprintf(LOG_ERR,"%04d !ERROR initializing JavaScript context",sock); ! 3853: sockprintf(sock,"451 Error initializing JavaScript context"); ! 3854: filepos=0; ! 3855: continue; ! 3856: } ! 3857: if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL) ! 3858: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user class",sock); ! 3859: ! 3860: if(js_CreateFileClass(js_cx, js_glob)==NULL) ! 3861: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file class",sock); ! 3862: ! 3863: if(js_CreateUserObject(js_cx, js_glob, &scfg, "user", user.number)==NULL) ! 3864: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating user object",sock); ! 3865: ! 3866: if(js_CreateClientObject(js_cx, js_glob, "client", &client, sock)==NULL) ! 3867: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating client object",sock); ! 3868: ! 3869: if(js_CreateFileAreaObject(js_cx, js_glob, &scfg, &user ! 3870: ,startup->html_index_file)==NULL) ! 3871: lprintf(LOG_ERR,"%04d !JavaScript ERROR creating file area object",sock); ! 3872: } ! 3873: ! 3874: if((js_str=JS_NewStringCopyZ(js_cx, "name"))!=NULL) { ! 3875: js_val=STRING_TO_JSVAL(js_str); ! 3876: JS_SetProperty(js_cx, js_ftp, "sort", &js_val); ! 3877: } ! 3878: js_val=BOOLEAN_TO_JSVAL(FALSE); ! 3879: JS_SetProperty(js_cx, js_ftp, "reverse", &js_val); ! 3880: ! 3881: if(!strnicmp(p,html_index_ext,strlen(html_index_ext))) { ! 3882: p+=strlen(html_index_ext); ! 3883: tp=strrchr(p,'$'); ! 3884: if(tp!=NULL) ! 3885: *tp=0; ! 3886: if(!strnicmp(p,"ext=",4)) { ! 3887: p+=4; ! 3888: if(!strcmp(p,"on")) ! 3889: user.misc|=EXTDESC; ! 3890: else ! 3891: user.misc&=~EXTDESC; ! 3892: if(!(user.rest&FLAG('G'))) ! 3893: putuserrec(&scfg,user.number,U_MISC,8,ultoa(user.misc,str,16)); ! 3894: } ! 3895: else if(!strnicmp(p,"sort=",5)) { ! 3896: p+=5; ! 3897: tp=strchr(p,'&'); ! 3898: if(tp!=NULL) { ! 3899: *tp=0; ! 3900: tp++; ! 3901: if(!stricmp(tp,"reverse")) { ! 3902: js_val=BOOLEAN_TO_JSVAL(TRUE); ! 3903: JS_SetProperty(js_cx, js_ftp, "reverse", &js_val); ! 3904: } ! 3905: } ! 3906: if((js_str=JS_NewStringCopyZ(js_cx, p))!=NULL) { ! 3907: js_val=STRING_TO_JSVAL(js_str); ! 3908: JS_SetProperty(js_cx, js_ftp, "sort", &js_val); ! 3909: } ! 3910: } ! 3911: } ! 3912: ! 3913: js_val=BOOLEAN_TO_JSVAL(INT_TO_BOOL(user.misc&EXTDESC)); ! 3914: JS_SetProperty(js_cx, js_ftp, "extended_descriptions", &js_val); ! 3915: ! 3916: #endif ! 3917: if((fp=fopen(ftp_tmpfname(fname,sock),"w+b"))==NULL) { ! 3918: lprintf(LOG_ERR,"%04d !ERROR %d opening %s",sock,errno,fname); ! 3919: sockprintf(sock, "451 Insufficient system storage"); ! 3920: filepos=0; ! 3921: continue; ! 3922: } ! 3923: if(!getsize && !getdate) ! 3924: lprintf(LOG_INFO,"%04d %s downloading HTML index for %s in %s mode" ! 3925: ,sock,user.alias,vpath(lib,dir,str) ! 3926: ,mode); ! 3927: success=TRUE; ! 3928: credits=FALSE; ! 3929: tmpfile=TRUE; ! 3930: delfile=TRUE; ! 3931: #ifdef JAVASCRIPT ! 3932: js_val=INT_TO_JSVAL(timeleft); ! 3933: if(!JS_SetProperty(js_cx, js_ftp, "time_left", &js_val)) ! 3934: lprintf(LOG_ERR,"%04d !JavaScript ERROR setting user.time_left",sock); ! 3935: js_generate_index(js_cx, js_ftp, sock, fp, lib, dir, &user); ! 3936: #endif ! 3937: fclose(fp); ! 3938: } else if(dir>=0) { ! 3939: ! 3940: if(!chk_ar(&scfg,scfg.dir[dir]->ar,&user)) { ! 3941: lprintf(LOG_WARNING,"%04d !%s has insufficient access to /%s/%s" ! 3942: ,sock,user.alias ! 3943: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 3944: ,scfg.dir[dir]->code_suffix); ! 3945: sockprintf(sock,"550 Insufficient access."); ! 3946: filepos=0; ! 3947: continue; ! 3948: } ! 3949: ! 3950: if(!getsize && !getdate && !delecmd ! 3951: && !chk_ar(&scfg,scfg.dir[dir]->dl_ar,&user)) { ! 3952: lprintf(LOG_WARNING,"%04d !%s has insufficient access to download from /%s/%s" ! 3953: ,sock,user.alias ! 3954: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 3955: ,scfg.dir[dir]->code_suffix); ! 3956: sockprintf(sock,"550 Insufficient access."); ! 3957: filepos=0; ! 3958: continue; ! 3959: } ! 3960: ! 3961: if(delecmd && !dir_op(&scfg,&user,dir)) { ! 3962: lprintf(LOG_WARNING,"%04d !%s has insufficient access to delete files in /%s/%s" ! 3963: ,sock,user.alias ! 3964: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 3965: ,scfg.dir[dir]->code_suffix); ! 3966: sockprintf(sock,"550 Insufficient access."); ! 3967: filepos=0; ! 3968: continue; ! 3969: } ! 3970: SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p); ! 3971: #ifdef _WIN32 ! 3972: GetShortPathName(fname, str, sizeof(str)); ! 3973: #else ! 3974: SAFECOPY(str,fname); ! 3975: #endif ! 3976: padfname(getfname(str),f.name); ! 3977: f.dir=dir; ! 3978: f.cdt=0; ! 3979: f.size=-1; ! 3980: filedat=getfileixb(&scfg,&f); ! 3981: if(!filedat && !(startup->options&FTP_OPT_DIR_FILES)) { ! 3982: sockprintf(sock,"550 File not found: %s",p); ! 3983: lprintf(LOG_WARNING,"%04d !%s file (%s%s) not in database for %.4s command" ! 3984: ,sock,user.alias,vpath(lib,dir,str),p,cmd); ! 3985: filepos=0; ! 3986: continue; ! 3987: } ! 3988: ! 3989: /* Verify credits */ ! 3990: if(!getsize && !getdate && !delecmd ! 3991: && !is_download_free(&scfg,dir,&user)) { ! 3992: if(filedat) ! 3993: getfiledat(&scfg,&f); ! 3994: else ! 3995: f.cdt=flength(fname); ! 3996: if(f.cdt>(user.cdt+user.freecdt)) { ! 3997: lprintf(LOG_WARNING,"%04d !%s has insufficient credit to download /%s/%s/%s (%lu credits)" ! 3998: ,sock,user.alias,scfg.lib[scfg.dir[dir]->lib]->sname ! 3999: ,scfg.dir[dir]->code_suffix ! 4000: ,p ! 4001: ,f.cdt); ! 4002: sockprintf(sock,"550 Insufficient credit (%lu required).",f.cdt); ! 4003: filepos=0; ! 4004: continue; ! 4005: } ! 4006: } ! 4007: ! 4008: if(strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p)) { ! 4009: success=FALSE; ! 4010: lprintf(LOG_WARNING,"%04d !ILLEGAL FILENAME ATTEMPT by %s: %s" ! 4011: ,sock,user.alias,p); ! 4012: hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr); ! 4013: #ifdef _WIN32 ! 4014: if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 4015: PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); ! 4016: #endif ! 4017: } else { ! 4018: if(fexist(fname)) { ! 4019: success=TRUE; ! 4020: if(!getsize && !getdate && !delecmd) ! 4021: lprintf(LOG_INFO,"%04d %s downloading: %s (%lu bytes) in %s mode" ! 4022: ,sock,user.alias,fname,flength(fname) ! 4023: ,mode); ! 4024: } ! 4025: } ! 4026: } ! 4027: #if defined(SOCKET_DEBUG_DOWNLOAD) ! 4028: socket_debug[sock]|=SOCKET_DEBUG_DOWNLOAD; ! 4029: #endif ! 4030: ! 4031: if(getsize && success) ! 4032: sockprintf(sock,"213 %lu",flength(fname)); ! 4033: else if(getdate && success) { ! 4034: t=fdate(fname); ! 4035: if(gmtime_r(&t,&tm)==NULL) /* specifically use GMT/UTC representation */ ! 4036: memset(&tm,0,sizeof(tm)); ! 4037: sockprintf(sock,"213 %u%02u%02u%02u%02u%02u" ! 4038: ,1900+tm.tm_year,tm.tm_mon+1,tm.tm_mday ! 4039: ,tm.tm_hour,tm.tm_min,tm.tm_sec); ! 4040: } else if(delecmd && success) { ! 4041: if(remove(fname)!=0) { ! 4042: lprintf(LOG_ERR,"%04d !ERROR %d deleting %s",sock,errno,fname); ! 4043: sockprintf(sock,"450 %s could not be deleted (error: %d)" ! 4044: ,fname,errno); ! 4045: } else { ! 4046: lprintf(LOG_NOTICE,"%04d %s deleted %s",sock,user.alias,fname); ! 4047: if(filedat) ! 4048: removefiledat(&scfg,&f); ! 4049: sockprintf(sock,"250 %s deleted.",fname); ! 4050: } ! 4051: } else if(success) { ! 4052: sockprintf(sock,"150 Opening BINARY mode data connection for file transfer."); ! 4053: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos ! 4054: ,&transfer_inprogress,&transfer_aborted,delfile,tmpfile ! 4055: ,&lastactive,&user,dir,FALSE,credits,FALSE,NULL); ! 4056: } ! 4057: else { ! 4058: sockprintf(sock,"550 File not found: %s",p); ! 4059: lprintf(LOG_WARNING,"%04d !%s file (%s%s) not found for %.4s command" ! 4060: ,sock,user.alias,vpath(lib,dir,str),p,cmd); ! 4061: } ! 4062: filepos=0; ! 4063: #if defined(SOCKET_DEBUG_DOWNLOAD) ! 4064: socket_debug[sock]&=~SOCKET_DEBUG_DOWNLOAD; ! 4065: #endif ! 4066: continue; ! 4067: } ! 4068: ! 4069: if(!strnicmp(cmd, "DESC", 4)) { ! 4070: ! 4071: if(user.rest&FLAG('U')) { ! 4072: sockprintf(sock,"553 Insufficient access."); ! 4073: continue; ! 4074: } ! 4075: ! 4076: p=cmd+4; ! 4077: while(*p && *p<=' ') p++; ! 4078: ! 4079: if(*p==0) ! 4080: sockprintf(sock,"501 No file description given."); ! 4081: else { ! 4082: SAFECOPY(desc,p); ! 4083: sockprintf(sock,"200 File description set. Ready to STOR file."); ! 4084: } ! 4085: continue; ! 4086: } ! 4087: ! 4088: if(!strnicmp(cmd, "STOR ", 5) || !strnicmp(cmd, "APPE ", 5)) { ! 4089: ! 4090: if(user.rest&FLAG('U')) { ! 4091: sockprintf(sock,"553 Insufficient access."); ! 4092: continue; ! 4093: } ! 4094: ! 4095: if(transfer_inprogress==TRUE) { ! 4096: lprintf(LOG_WARNING,"%04d !TRANSFER already in progress (%s)",sock,cmd); ! 4097: sockprintf(sock,"425 Transfer already in progress."); ! 4098: continue; ! 4099: } ! 4100: ! 4101: append=FALSE; ! 4102: lib=curlib; ! 4103: dir=curdir; ! 4104: p=cmd+5; ! 4105: ! 4106: while(*p && *p<=' ') p++; ! 4107: ! 4108: if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) ! 4109: p+=strlen(BBS_FSYS_DIR); /* already mounted */ ! 4110: ! 4111: if(*p=='/') { ! 4112: lib=-1; ! 4113: p++; ! 4114: } ! 4115: else if(!strncmp(p,"./",2)) ! 4116: p+=2; ! 4117: /* Need to add support for uploading to aliased directories */ ! 4118: if(lib<0 && (tp=strchr(p,'/'))!=NULL) { ! 4119: dir=-1; ! 4120: *tp=0; ! 4121: for(i=0;i<scfg.total_libs;i++) { ! 4122: if(!chk_ar(&scfg,scfg.lib[i]->ar,&user)) ! 4123: continue; ! 4124: if(!stricmp(scfg.lib[i]->sname,p)) ! 4125: break; ! 4126: } ! 4127: if(i<scfg.total_libs) ! 4128: lib=i; ! 4129: p=tp+1; ! 4130: } ! 4131: if(dir<0 && (tp=strchr(p,'/'))!=NULL) { ! 4132: *tp=0; ! 4133: for(i=0;i<scfg.total_dirs;i++) { ! 4134: if(scfg.dir[i]->lib!=lib) ! 4135: continue; ! 4136: if(i!=scfg.sysop_dir && i!=scfg.upload_dir ! 4137: && !chk_ar(&scfg,scfg.dir[i]->ar,&user)) ! 4138: continue; ! 4139: if(!stricmp(scfg.dir[i]->code_suffix,p)) ! 4140: break; ! 4141: } ! 4142: if(i<scfg.total_dirs) ! 4143: dir=i; ! 4144: p=tp+1; ! 4145: } ! 4146: if(dir<0) { ! 4147: sprintf(str,"%s.rep",scfg.sys_id); ! 4148: if(!(startup->options&FTP_OPT_ALLOW_QWK) ! 4149: || stricmp(p,str)) { ! 4150: lprintf(LOG_WARNING,"%04d !%s attempted to upload to invalid directory" ! 4151: ,sock,user.alias); ! 4152: sockprintf(sock,"553 Invalid directory."); ! 4153: continue; ! 4154: } ! 4155: sprintf(fname,"%sfile/%04d.rep",scfg.data_dir,user.number); ! 4156: lprintf(LOG_INFO,"%04d %s uploading: %s in %s mode" ! 4157: ,sock,user.alias,fname ! 4158: ,mode); ! 4159: } else { ! 4160: ! 4161: append=(strnicmp(cmd,"APPE",4)==0); ! 4162: ! 4163: if(!chk_ar(&scfg,scfg.dir[dir]->ul_ar,&user)) { ! 4164: lprintf(LOG_WARNING,"%04d !%s has insufficient access to upload to /%s/%s" ! 4165: ,sock,user.alias ! 4166: ,scfg.lib[scfg.dir[dir]->lib]->sname ! 4167: ,scfg.dir[dir]->code_suffix); ! 4168: sockprintf(sock,"553 Insufficient access."); ! 4169: continue; ! 4170: } ! 4171: if(*p=='-' ! 4172: || strcspn(p,ILLEGAL_FILENAME_CHARS)!=strlen(p) ! 4173: || trashcan(&scfg,p,"file")) { ! 4174: lprintf(LOG_WARNING,"%04d !ILLEGAL FILENAME ATTEMPT by %s: %s" ! 4175: ,sock,user.alias,p); ! 4176: sockprintf(sock,"553 Illegal filename attempt"); ! 4177: hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr); ! 4178: #ifdef _WIN32 ! 4179: if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 4180: PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); ! 4181: #endif ! 4182: continue; ! 4183: } ! 4184: SAFEPRINTF2(fname,"%s%s",scfg.dir[dir]->path,p); ! 4185: if((!append && filepos==0 && fexist(fname)) ! 4186: || (startup->options&FTP_OPT_INDEX_FILE ! 4187: && !stricmp(p,startup->index_file_name)) ! 4188: || (startup->options&FTP_OPT_HTML_INDEX_FILE ! 4189: && !stricmp(p,startup->html_index_file)) ! 4190: ) { ! 4191: lprintf(LOG_WARNING,"%04d !%s attempted to overwrite existing file: %s" ! 4192: ,sock,user.alias,fname); ! 4193: sockprintf(sock,"553 File already exists."); ! 4194: continue; ! 4195: } ! 4196: if(append || filepos) { /* RESUME */ ! 4197: #ifdef _WIN32 ! 4198: GetShortPathName(fname, str, sizeof(str)); ! 4199: #else ! 4200: SAFECOPY(str,fname); ! 4201: #endif ! 4202: padfname(getfname(str),f.name); ! 4203: f.dir=dir; ! 4204: f.cdt=0; ! 4205: f.size=-1; ! 4206: if(!getfileixb(&scfg,&f) || !getfiledat(&scfg,&f)) { ! 4207: if(filepos) { ! 4208: lprintf(LOG_WARNING,"%04d !%s file (%s) not in database for %.4s command" ! 4209: ,sock,user.alias,fname,cmd); ! 4210: sockprintf(sock,"550 File not found: %s",p); ! 4211: continue; ! 4212: } ! 4213: append=FALSE; ! 4214: } ! 4215: /* Verify user is original uploader */ ! 4216: if((append || filepos) && stricmp(f.uler,user.alias)) { ! 4217: lprintf(LOG_WARNING,"%04d !%s cannot resume upload of %s, uploaded by %s" ! 4218: ,sock,user.alias,fname,f.uler); ! 4219: sockprintf(sock,"553 Insufficient access (can't resume upload from different user)."); ! 4220: continue; ! 4221: } ! 4222: } ! 4223: lprintf(LOG_INFO,"%04d %s uploading: %s to %s (%s) in %s mode" ! 4224: ,sock,user.alias ! 4225: ,p /* filename */ ! 4226: ,vpath(lib,dir,str) /* virtual path */ ! 4227: ,scfg.dir[dir]->path /* actual path */ ! 4228: ,mode); ! 4229: } ! 4230: sockprintf(sock,"150 Opening BINARY mode data connection for file transfer."); ! 4231: filexfer(&data_addr,sock,pasv_sock,&data_sock,fname,filepos ! 4232: ,&transfer_inprogress,&transfer_aborted,FALSE,FALSE ! 4233: ,&lastactive ! 4234: ,&user ! 4235: ,dir ! 4236: ,TRUE /* uploading */ ! 4237: ,TRUE /* credits */ ! 4238: ,append ! 4239: ,desc ! 4240: ); ! 4241: filepos=0; ! 4242: continue; ! 4243: } ! 4244: ! 4245: if(!stricmp(cmd,"CDUP") || !stricmp(cmd,"XCUP")) { ! 4246: if(curdir<0) ! 4247: curlib=-1; ! 4248: else ! 4249: curdir=-1; ! 4250: sockprintf(sock,"200 CDUP command successful."); ! 4251: continue; ! 4252: } ! 4253: ! 4254: if(!strnicmp(cmd, "CWD ", 4) || !strnicmp(cmd,"XCWD ",5)) { ! 4255: p=cmd+4; ! 4256: while(*p && *p<=' ') p++; ! 4257: ! 4258: if(!strnicmp(p,BBS_FSYS_DIR,strlen(BBS_FSYS_DIR))) ! 4259: p+=strlen(BBS_FSYS_DIR); /* already mounted */ ! 4260: ! 4261: if(*p=='/') { ! 4262: curlib=-1; ! 4263: curdir=-1; ! 4264: p++; ! 4265: } ! 4266: /* Local File System? */ ! 4267: if(sysop && !(startup->options&FTP_OPT_NO_LOCAL_FSYS) ! 4268: && !strnicmp(p,LOCAL_FSYS_DIR,strlen(LOCAL_FSYS_DIR))) { ! 4269: p+=strlen(LOCAL_FSYS_DIR); ! 4270: if(!direxist(p)) { ! 4271: sockprintf(sock,"550 Directory does not exist."); ! 4272: lprintf(LOG_WARNING,"%04d !%s attempted to mount invalid directory: %s" ! 4273: ,sock, user.alias, p); ! 4274: continue; ! 4275: } ! 4276: SAFECOPY(local_dir,p); ! 4277: local_fsys=TRUE; ! 4278: sockprintf(sock,"250 CWD command successful (local file system mounted)."); ! 4279: lprintf(LOG_INFO,"%04d %s mounted local file system", sock, user.alias); ! 4280: continue; ! 4281: } ! 4282: success=FALSE; ! 4283: ! 4284: /* Directory Alias? */ ! 4285: if(curlib<0 && ftpalias(p,NULL,&user,&curdir)==TRUE) { ! 4286: if(curdir>=0) ! 4287: curlib=scfg.dir[curdir]->lib; ! 4288: success=TRUE; ! 4289: } ! 4290: ! 4291: orglib=curlib; ! 4292: orgdir=curdir; ! 4293: tp=0; ! 4294: if(!strncmp(p,"...",3)) { ! 4295: curlib=-1; ! 4296: curdir=-1; ! 4297: p+=3; ! 4298: } ! 4299: if(!strncmp(p,"./",2)) ! 4300: p+=2; ! 4301: else if(!strncmp(p,"..",2)) { ! 4302: if(curdir<0) ! 4303: curlib=-1; ! 4304: else ! 4305: curdir=-1; ! 4306: p+=2; ! 4307: } ! 4308: if(*p==0) ! 4309: success=TRUE; ! 4310: else if(!strcmp(p,".")) ! 4311: success=TRUE; ! 4312: if(!success && (curlib<0 || *p=='/')) { /* Root dir */ ! 4313: if(*p=='/') p++; ! 4314: tp=strchr(p,'/'); ! 4315: if(tp) *tp=0; ! 4316: for(i=0;i<scfg.total_libs;i++) { ! 4317: if(!chk_ar(&scfg,scfg.lib[i]->ar,&user)) ! 4318: continue; ! 4319: if(!stricmp(scfg.lib[i]->sname,p)) ! 4320: break; ! 4321: } ! 4322: if(i<scfg.total_libs) { ! 4323: curlib=i; ! 4324: success=TRUE; ! 4325: } ! 4326: } ! 4327: if((!success && curdir<0) || (success && tp && *(tp+1))) { ! 4328: if(tp) ! 4329: p=tp+1; ! 4330: tp=lastchar(p); ! 4331: if(tp && *tp=='/') *tp=0; ! 4332: for(i=0;i<scfg.total_dirs;i++) { ! 4333: if(scfg.dir[i]->lib!=curlib) ! 4334: continue; ! 4335: if(i!=scfg.sysop_dir && i!=scfg.upload_dir ! 4336: && !chk_ar(&scfg,scfg.dir[i]->ar,&user)) ! 4337: continue; ! 4338: if(!stricmp(scfg.dir[i]->code_suffix,p)) ! 4339: break; ! 4340: } ! 4341: if(i<scfg.total_dirs) { ! 4342: curdir=i; ! 4343: success=TRUE; ! 4344: } else ! 4345: success=FALSE; ! 4346: } ! 4347: ! 4348: if(success) ! 4349: sockprintf(sock,"250 CWD command successful."); ! 4350: else { ! 4351: sockprintf(sock,"550 %s: No such file or directory.",p); ! 4352: curlib=orglib; ! 4353: curdir=orgdir; ! 4354: } ! 4355: continue; ! 4356: } ! 4357: ! 4358: if(!stricmp(cmd, "PWD") || !stricmp(cmd,"XPWD")) { ! 4359: if(curlib<0) ! 4360: sockprintf(sock,"257 \"/\" is current directory."); ! 4361: else if(curdir<0) ! 4362: sockprintf(sock,"257 \"/%s\" is current directory." ! 4363: ,scfg.lib[curlib]->sname); ! 4364: else ! 4365: sockprintf(sock,"257 \"/%s/%s\" is current directory." ! 4366: ,scfg.lib[curlib]->sname ! 4367: ,scfg.dir[curdir]->code_suffix); ! 4368: continue; ! 4369: } ! 4370: ! 4371: if(!strnicmp(cmd, "MKD", 3) || ! 4372: !strnicmp(cmd,"XMKD",4) || ! 4373: !strnicmp(cmd,"SITE EXEC",9)) { ! 4374: lprintf(LOG_WARNING,"%04d !SUSPECTED HACK ATTEMPT by %s: '%s'" ! 4375: ,sock,user.alias,cmd); ! 4376: hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr); ! 4377: #ifdef _WIN32 ! 4378: if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 4379: PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); ! 4380: #endif ! 4381: } ! 4382: sockprintf(sock,"500 Syntax error: '%s'",cmd); ! 4383: lprintf(LOG_WARNING,"%04d !UNSUPPORTED COMMAND from %s: '%s'" ! 4384: ,sock,user.alias,cmd); ! 4385: } /* while(1) */ ! 4386: ! 4387: #if defined(SOCKET_DEBUG_TERMINATE) ! 4388: socket_debug[sock]|=SOCKET_DEBUG_TERMINATE; ! 4389: #endif ! 4390: ! 4391: if(transfer_inprogress==TRUE) { ! 4392: lprintf(LOG_DEBUG,"%04d Waiting for transfer to complete...",sock); ! 4393: count=0; ! 4394: while(transfer_inprogress==TRUE) { ! 4395: if(server_socket==INVALID_SOCKET || terminate_server) { ! 4396: mswait(2000); /* allow xfer threads to terminate */ ! 4397: break; ! 4398: } ! 4399: if(!transfer_aborted) { ! 4400: if(gettimeleft(&scfg,&user,logintime)<1) { ! 4401: lprintf(LOG_WARNING,"%04d Out of time, disconnecting",sock); ! 4402: sockprintf(sock,"421 Sorry, you've run out of time."); ! 4403: ftp_close_socket(&data_sock,__LINE__); ! 4404: transfer_aborted=TRUE; ! 4405: } ! 4406: if((time(NULL)-lastactive)>startup->max_inactivity) { ! 4407: lprintf(LOG_WARNING,"%04d Disconnecting due to to inactivity",sock); ! 4408: sockprintf(sock,"421 Disconnecting due to inactivity (%u seconds)." ! 4409: ,startup->max_inactivity); ! 4410: ftp_close_socket(&data_sock,__LINE__); ! 4411: transfer_aborted=TRUE; ! 4412: } ! 4413: } ! 4414: if(count && (count%60)==0) ! 4415: lprintf(LOG_WARNING,"%04d Still waiting for transfer to complete " ! 4416: "(count=%lu, aborted=%d, lastactive=%lX) ..." ! 4417: ,sock,count,transfer_aborted,lastactive); ! 4418: count++; ! 4419: mswait(1000); ! 4420: } ! 4421: lprintf(LOG_DEBUG,"%04d Done waiting for transfer to complete",sock); ! 4422: } ! 4423: ! 4424: if(user.number) { ! 4425: /* Update User Statistics */ ! 4426: logoutuserdat(&scfg, &user, time(NULL), logintime); ! 4427: /* Remove QWK-pack semaphore file (if left behind) */ ! 4428: sprintf(str,"%spack%04u.now",scfg.data_dir,user.number); ! 4429: remove(str); ! 4430: lprintf(LOG_INFO,"%04d %s logged off",sock,user.alias); ! 4431: } ! 4432: ! 4433: #ifdef _WIN32 ! 4434: if(startup->hangup_sound[0] && !(startup->options&FTP_OPT_MUTE)) ! 4435: PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME); ! 4436: #endif ! 4437: ! 4438: #ifdef JAVASCRIPT ! 4439: if(js_cx!=NULL) { ! 4440: lprintf(LOG_DEBUG,"%04d JavaScript: Destroying context",sock); ! 4441: JS_DestroyContext(js_cx); /* Free Context */ ! 4442: } ! 4443: ! 4444: if(js_runtime!=NULL) { ! 4445: lprintf(LOG_DEBUG,"%04d JavaScript: Destroying runtime",sock); ! 4446: JS_DestroyRuntime(js_runtime); ! 4447: } ! 4448: ! 4449: #endif ! 4450: ! 4451: /* status(STATUS_WFC); server thread should control status display */ ! 4452: ! 4453: if(pasv_sock!=INVALID_SOCKET) ! 4454: ftp_close_socket(&pasv_sock,__LINE__); ! 4455: if(data_sock!=INVALID_SOCKET) ! 4456: ftp_close_socket(&data_sock,__LINE__); ! 4457: ! 4458: client_off(sock); ! 4459: ! 4460: #ifdef SOCKET_DEBUG_CTRL ! 4461: socket_debug[sock]&=~SOCKET_DEBUG_CTRL; ! 4462: #endif ! 4463: ! 4464: #if defined(SOCKET_DEBUG_TERMINATE) ! 4465: socket_debug[sock]&=~SOCKET_DEBUG_TERMINATE; ! 4466: #endif ! 4467: ! 4468: tmp_sock=sock; ! 4469: ftp_close_socket(&tmp_sock,__LINE__); ! 4470: ! 4471: if(active_clients) ! 4472: active_clients--, update_clients(); ! 4473: ! 4474: thread_down(); ! 4475: lprintf(LOG_DEBUG,"%04d CTRL thread terminated (%d clients, %u threads remain, %lu served)" ! 4476: ,sock, active_clients, thread_count, served); ! 4477: } ! 4478: ! 4479: static void cleanup(int code, int line) ! 4480: { ! 4481: #ifdef _DEBUG ! 4482: lprintf(LOG_INFO,"0000 cleanup called from line %d",line); ! 4483: #endif ! 4484: free_cfg(&scfg); ! 4485: free_text(text); ! 4486: ! 4487: semfile_list_free(&recycle_semfiles); ! 4488: semfile_list_free(&shutdown_semfiles); ! 4489: ! 4490: if(server_socket!=INVALID_SOCKET) ! 4491: ftp_close_socket(&server_socket,__LINE__); ! 4492: ! 4493: update_clients(); ! 4494: ! 4495: #ifdef _WINSOCKAPI_ ! 4496: if(WSAInitialized && WSACleanup()!=0) ! 4497: lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE); ! 4498: #endif ! 4499: ! 4500: thread_down(); ! 4501: status("Down"); ! 4502: if(terminate_server || code) ! 4503: lprintf(LOG_INFO,"#### FTP Server thread terminated (%u threads remain, %lu clients served)" ! 4504: ,thread_count, served); ! 4505: if(startup!=NULL && startup->terminated!=NULL) ! 4506: startup->terminated(startup->cbdata,code); ! 4507: } ! 4508: ! 4509: const char* DLLCALL ftp_ver(void) ! 4510: { ! 4511: static char ver[256]; ! 4512: char compiler[32]; ! 4513: ! 4514: DESCRIBE_COMPILER(compiler); ! 4515: ! 4516: sscanf("$Revision: 1.313 $", "%*s %s", revision); ! 4517: ! 4518: sprintf(ver,"%s %s%s " ! 4519: "Compiled %s %s with %s" ! 4520: ,FTP_SERVER ! 4521: ,revision ! 4522: #ifdef _DEBUG ! 4523: ," Debug" ! 4524: #else ! 4525: ,"" ! 4526: #endif ! 4527: ,__DATE__, __TIME__, compiler); ! 4528: ! 4529: return(ver); ! 4530: } ! 4531: ! 4532: void DLLCALL ftp_server(void* arg) ! 4533: { ! 4534: char* p; ! 4535: char path[MAX_PATH+1]; ! 4536: char error[256]; ! 4537: char compiler[32]; ! 4538: char str[256]; ! 4539: SOCKADDR_IN server_addr; ! 4540: SOCKADDR_IN client_addr; ! 4541: socklen_t client_addr_len; ! 4542: SOCKET client_socket; ! 4543: int i; ! 4544: int result; ! 4545: time_t t; ! 4546: time_t start; ! 4547: time_t initialized=0; ! 4548: fd_set socket_set; ! 4549: ftp_t* ftp; ! 4550: struct timeval tv; ! 4551: ! 4552: ftp_ver(); ! 4553: ! 4554: startup=(ftp_startup_t*)arg; ! 4555: ! 4556: #ifdef _THREAD_SUID_BROKEN ! 4557: if(thread_suid_broken) ! 4558: startup->seteuid(TRUE); ! 4559: #endif ! 4560: ! 4561: if(startup==NULL) { ! 4562: sbbs_beep(100,500); ! 4563: fprintf(stderr, "No startup structure passed!\n"); ! 4564: return; ! 4565: } ! 4566: ! 4567: if(startup->size!=sizeof(ftp_startup_t)) { /* verify size */ ! 4568: sbbs_beep(100,500); ! 4569: sbbs_beep(300,500); ! 4570: sbbs_beep(100,500); ! 4571: fprintf(stderr, "Invalid startup structure!\n"); ! 4572: return; ! 4573: } ! 4574: ! 4575: /* Setup intelligent defaults */ ! 4576: if(startup->port==0) startup->port=IPPORT_FTP; ! 4577: if(startup->qwk_timeout==0) startup->qwk_timeout=600; /* seconds */ ! 4578: if(startup->max_inactivity==0) startup->max_inactivity=300; /* seconds */ ! 4579: if(startup->sem_chk_freq==0) startup->sem_chk_freq=2; /* seconds */ ! 4580: if(startup->index_file_name[0]==0) SAFECOPY(startup->index_file_name,"00index"); ! 4581: if(startup->html_index_file[0]==0) SAFECOPY(startup->html_index_file,"00index.html"); ! 4582: if(startup->html_index_script[0]==0) { SAFECOPY(startup->html_index_script,"ftp-html.js"); ! 4583: startup->options|=FTP_OPT_HTML_INDEX_FILE; ! 4584: } ! 4585: if(startup->options&FTP_OPT_HTML_INDEX_FILE) ! 4586: startup->options&=~FTP_OPT_NO_JAVASCRIPT; ! 4587: else ! 4588: startup->options|=FTP_OPT_NO_JAVASCRIPT; ! 4589: #ifdef JAVASCRIPT ! 4590: if(startup->js.max_bytes==0) startup->js.max_bytes=JAVASCRIPT_MAX_BYTES; ! 4591: if(startup->js.cx_stack==0) startup->js.cx_stack=JAVASCRIPT_CONTEXT_STACK; ! 4592: ! 4593: ZERO_VAR(js_server_props); ! 4594: SAFEPRINTF2(js_server_props.version,"%s %s",FTP_SERVER,revision); ! 4595: js_server_props.version_detail=ftp_ver(); ! 4596: js_server_props.clients=&active_clients; ! 4597: js_server_props.options=&startup->options; ! 4598: js_server_props.interface_addr=&startup->interface_addr; ! 4599: #endif ! 4600: ! 4601: ! 4602: uptime=0; ! 4603: served=0; ! 4604: startup->recycle_now=FALSE; ! 4605: startup->shutdown_now=FALSE; ! 4606: terminate_server=FALSE; ! 4607: ! 4608: do { ! 4609: ! 4610: thread_up(FALSE /* setuid */); ! 4611: ! 4612: status("Initializing"); ! 4613: ! 4614: memset(&scfg, 0, sizeof(scfg)); ! 4615: ! 4616: lprintf(LOG_INFO,"Synchronet FTP Server Revision %s%s" ! 4617: ,revision ! 4618: #ifdef _DEBUG ! 4619: ," Debug" ! 4620: #else ! 4621: ,"" ! 4622: #endif ! 4623: ); ! 4624: ! 4625: DESCRIBE_COMPILER(compiler); ! 4626: ! 4627: lprintf(LOG_INFO,"Compiled %s %s with %s", __DATE__, __TIME__, compiler); ! 4628: ! 4629: sbbs_srand(); /* Seed random number generator */ ! 4630: ! 4631: if(!winsock_startup()) { ! 4632: cleanup(1,__LINE__); ! 4633: return; ! 4634: } ! 4635: ! 4636: t=time(NULL); ! 4637: lprintf(LOG_INFO,"Initializing on %.24s with options: %lx" ! 4638: ,CTIME_R(&t,str),startup->options); ! 4639: ! 4640: /* Initial configuration and load from CNF files */ ! 4641: SAFECOPY(scfg.ctrl_dir, startup->ctrl_dir); ! 4642: lprintf(LOG_INFO,"Loading configuration files from %s", scfg.ctrl_dir); ! 4643: scfg.size=sizeof(scfg); ! 4644: SAFECOPY(error,UNKNOWN_LOAD_ERROR); ! 4645: if(!load_cfg(&scfg, text, TRUE, error)) { ! 4646: lprintf(LOG_ERR,"!ERROR %s",error); ! 4647: lprintf(LOG_ERR,"!Failed to load configuration files"); ! 4648: cleanup(1,__LINE__); ! 4649: return; ! 4650: } ! 4651: ! 4652: if(startup->host_name[0]==0) ! 4653: SAFECOPY(startup->host_name,scfg.sys_inetaddr); ! 4654: ! 4655: if(!(scfg.sys_misc&SM_LOCAL_TZ) && !(startup->options&FTP_OPT_LOCAL_TIMEZONE)) { ! 4656: if(putenv("TZ=UTC0")) ! 4657: lprintf(LOG_ERR,"!putenv() FAILED"); ! 4658: tzset(); ! 4659: ! 4660: if((t=checktime())!=0) { /* Check binary time */ ! 4661: lprintf(LOG_ERR,"!TIME PROBLEM (%ld)",t); ! 4662: cleanup(1,__LINE__); ! 4663: return; ! 4664: } ! 4665: } ! 4666: ! 4667: if(uptime==0) ! 4668: uptime=time(NULL); /* this must be done *after* setting the timezone */ ! 4669: ! 4670: if(startup->temp_dir[0]) ! 4671: SAFECOPY(scfg.temp_dir,startup->temp_dir); ! 4672: else ! 4673: SAFECOPY(scfg.temp_dir,"../temp"); ! 4674: prep_dir(scfg.ctrl_dir, scfg.temp_dir, sizeof(scfg.temp_dir)); ! 4675: MKDIR(scfg.temp_dir); ! 4676: lprintf(LOG_DEBUG,"Temporary file directory: %s", scfg.temp_dir); ! 4677: if(!isdir(scfg.temp_dir)) { ! 4678: lprintf(LOG_ERR,"!Invalid temp directory: %s", scfg.temp_dir); ! 4679: cleanup(1,__LINE__); ! 4680: return; ! 4681: } ! 4682: ! 4683: if(!startup->max_clients) { ! 4684: startup->max_clients=scfg.sys_nodes; ! 4685: if(startup->max_clients<10) ! 4686: startup->max_clients=10; ! 4687: } ! 4688: lprintf(LOG_DEBUG,"Maximum clients: %d",startup->max_clients); ! 4689: ! 4690: /* Sanity-check the passive port range */ ! 4691: if(startup->pasv_port_low || startup->pasv_port_high) { ! 4692: if(startup->pasv_port_low > startup->pasv_port_high ! 4693: || startup->pasv_port_high-startup->pasv_port_low < (startup->max_clients-1)) { ! 4694: lprintf(LOG_WARNING,"!Correcting Passive Port Range (Low: %u, High: %u)" ! 4695: ,startup->pasv_port_low,startup->pasv_port_high); ! 4696: if(startup->pasv_port_low) ! 4697: startup->pasv_port_high = startup->pasv_port_low+(startup->max_clients-1); ! 4698: else ! 4699: startup->pasv_port_low = startup->pasv_port_high-(startup->max_clients-1); ! 4700: } ! 4701: lprintf(LOG_DEBUG,"Passive Port Low: %u",startup->pasv_port_low); ! 4702: lprintf(LOG_DEBUG,"Passive Port High: %u",startup->pasv_port_high); ! 4703: } ! 4704: ! 4705: lprintf(LOG_DEBUG,"Maximum inactivity: %d seconds",startup->max_inactivity); ! 4706: ! 4707: active_clients=0, update_clients(); ! 4708: ! 4709: strlwr(scfg.sys_id); /* Use lower-case unix-looking System ID for group name */ ! 4710: ! 4711: for(i=0;i<scfg.total_libs;i++) { ! 4712: strlwr(scfg.lib[i]->sname); ! 4713: dotname(scfg.lib[i]->sname,scfg.lib[i]->sname); ! 4714: } ! 4715: #if 0 /* this is now handled by load_cfg()->prep_cfg() */ ! 4716: for(i=0;i<scfg.total_dirs;i++) ! 4717: strlwr(scfg.dir[i]->code_suffix); ! 4718: #endif ! 4719: /* open a socket and wait for a client */ ! 4720: ! 4721: if((server_socket=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) { ! 4722: lprintf(LOG_ERR,"!ERROR %d opening socket", ERROR_VALUE); ! 4723: cleanup(1,__LINE__); ! 4724: return; ! 4725: } ! 4726: ! 4727: lprintf(LOG_DEBUG,"%04d FTP Server socket opened",server_socket); ! 4728: ! 4729: /*****************************/ ! 4730: /* Listen for incoming calls */ ! 4731: /*****************************/ ! 4732: memset(&server_addr, 0, sizeof(server_addr)); ! 4733: ! 4734: server_addr.sin_addr.s_addr = htonl(startup->interface_addr); ! 4735: server_addr.sin_family = AF_INET; ! 4736: server_addr.sin_port = htons(startup->port); ! 4737: ! 4738: if(startup->seteuid!=NULL) ! 4739: startup->seteuid(FALSE); ! 4740: result=retry_bind(server_socket, (struct sockaddr *) &server_addr,sizeof(server_addr) ! 4741: ,startup->bind_retry_count,startup->bind_retry_delay,"FTP Server",lprintf); ! 4742: if(startup->seteuid!=NULL) ! 4743: startup->seteuid(TRUE); ! 4744: if(result!=0) { ! 4745: lprintf(LOG_ERR,"%04d %s", server_socket, BIND_FAILURE_HELP); ! 4746: cleanup(1,__LINE__); ! 4747: return; ! 4748: } ! 4749: ! 4750: if((result=listen(server_socket, 1))!= 0) { ! 4751: lprintf(LOG_ERR,"%04d !ERROR %d (%d) listening on socket" ! 4752: ,server_socket, result, ERROR_VALUE); ! 4753: cleanup(1,__LINE__); ! 4754: return; ! 4755: } ! 4756: ! 4757: lprintf(LOG_NOTICE,"%04d FTP Server thread started on port %d",server_socket,startup->port); ! 4758: status(STATUS_WFC); ! 4759: ! 4760: /* Setup recycle/shutdown semaphore file lists */ ! 4761: shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","ftp"); ! 4762: recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","ftp"); ! 4763: SAFEPRINTF(path,"%sftpsrvr.rec",scfg.ctrl_dir); /* legacy */ ! 4764: semfile_list_add(&recycle_semfiles,path); ! 4765: if(!initialized) { ! 4766: initialized=time(NULL); ! 4767: semfile_list_check(&initialized,recycle_semfiles); ! 4768: semfile_list_check(&initialized,shutdown_semfiles); ! 4769: } ! 4770: ! 4771: ! 4772: /* signal caller that we've started up successfully */ ! 4773: if(startup->started!=NULL) ! 4774: startup->started(startup->cbdata); ! 4775: ! 4776: while(server_socket!=INVALID_SOCKET && !terminate_server) { ! 4777: ! 4778: if(active_clients==0) { ! 4779: if(!(startup->options&FTP_OPT_NO_RECYCLE)) { ! 4780: if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) { ! 4781: lprintf(LOG_INFO,"0000 Recycle semaphore file (%s) detected",p); ! 4782: break; ! 4783: } ! 4784: #if 0 /* unused */ ! 4785: if(startup->recycle_sem!=NULL && sem_trywait(&startup->recycle_sem)==0) ! 4786: startup->recycle_now=TRUE; ! 4787: #endif ! 4788: if(startup->recycle_now==TRUE) { ! 4789: lprintf(LOG_NOTICE,"0000 Recycle semaphore signaled"); ! 4790: startup->recycle_now=FALSE; ! 4791: break; ! 4792: } ! 4793: } ! 4794: if(((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL ! 4795: && lprintf(LOG_INFO,"0000 Shutdown semaphore file (%s) detected",p)) ! 4796: || (startup->shutdown_now==TRUE ! 4797: && lprintf(LOG_INFO,"0000 Shutdown semaphore signaled"))) { ! 4798: startup->shutdown_now=FALSE; ! 4799: terminate_server=TRUE; ! 4800: break; ! 4801: } ! 4802: } ! 4803: /* now wait for connection */ ! 4804: ! 4805: tv.tv_sec=startup->sem_chk_freq; ! 4806: tv.tv_usec=0; ! 4807: ! 4808: FD_ZERO(&socket_set); ! 4809: FD_SET(server_socket,&socket_set); ! 4810: ! 4811: if((i=select(server_socket+1,&socket_set,NULL,NULL,&tv))<1) { ! 4812: if(i==0) ! 4813: continue; ! 4814: if(ERROR_VALUE==EINTR) ! 4815: lprintf(LOG_DEBUG,"%04d FTP Server listening interrupted", server_socket); ! 4816: else if(ERROR_VALUE == ENOTSOCK) ! 4817: lprintf(LOG_NOTICE,"%04d FTP Server socket closed", server_socket); ! 4818: else ! 4819: lprintf(LOG_WARNING,"%04d !ERROR %d selecting socket",server_socket, ERROR_VALUE); ! 4820: continue; ! 4821: } ! 4822: ! 4823: if(server_socket==INVALID_SOCKET || terminate_server) /* terminated */ ! 4824: break; ! 4825: ! 4826: client_addr_len = sizeof(client_addr); ! 4827: client_socket = accept(server_socket, (struct sockaddr *)&client_addr ! 4828: ,&client_addr_len); ! 4829: ! 4830: if(client_socket == INVALID_SOCKET) ! 4831: { ! 4832: #if 0 /* is this necessary still? */ ! 4833: if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR || ERROR_VALUE == EINVAL) { ! 4834: lprintf(LOG_NOTICE,"0000 FTP socket closed while listening"); ! 4835: break; ! 4836: } ! 4837: #endif ! 4838: lprintf(LOG_WARNING,"%04d !ERROR %d accepting connection" ! 4839: ,server_socket, ERROR_VALUE); ! 4840: #ifdef _WIN32 ! 4841: if(WSAGetLastError()==WSAENOBUFS) /* recycle (re-init WinSock) on this error */ ! 4842: break; ! 4843: #endif ! 4844: continue; ! 4845: } ! 4846: if(startup->socket_open!=NULL) ! 4847: startup->socket_open(startup->cbdata,TRUE); ! 4848: sockets++; ! 4849: ! 4850: if(trashcan(&scfg,inet_ntoa(client_addr.sin_addr),"ip-silent")) { ! 4851: ftp_close_socket(&client_socket,__LINE__); ! 4852: continue; ! 4853: } ! 4854: ! 4855: if(active_clients>=startup->max_clients) { ! 4856: lprintf(LOG_WARNING,"%04d !MAXIMUM CLIENTS (%d) reached, access denied" ! 4857: ,client_socket, startup->max_clients); ! 4858: sockprintf(client_socket,"421 Maximum active clients reached, please try again later."); ! 4859: mswait(3000); ! 4860: ftp_close_socket(&client_socket,__LINE__); ! 4861: continue; ! 4862: } ! 4863: ! 4864: if((ftp=malloc(sizeof(ftp_t)))==NULL) { ! 4865: lprintf(LOG_CRIT,"%04d !ERROR allocating %d bytes of memory for ftp_t" ! 4866: ,client_socket,sizeof(ftp_t)); ! 4867: sockprintf(client_socket,"421 System error, please try again later."); ! 4868: mswait(3000); ! 4869: ftp_close_socket(&client_socket,__LINE__); ! 4870: continue; ! 4871: } ! 4872: ! 4873: ftp->socket=client_socket; ! 4874: ftp->client_addr=client_addr; ! 4875: ! 4876: _beginthread (ctrl_thread, 0, ftp); ! 4877: served++; ! 4878: } ! 4879: ! 4880: #ifdef _DEBUG ! 4881: lprintf(LOG_DEBUG,"0000 server_socket: %d",server_socket); ! 4882: lprintf(LOG_DEBUG,"0000 terminate_server: %d",terminate_server); ! 4883: #endif ! 4884: if(active_clients) { ! 4885: lprintf(LOG_DEBUG,"%04d Waiting for %d active clients to disconnect..." ! 4886: ,server_socket, active_clients); ! 4887: start=time(NULL); ! 4888: while(active_clients) { ! 4889: if(time(NULL)-start>startup->max_inactivity) { ! 4890: lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d active clients" ! 4891: ,server_socket, active_clients); ! 4892: break; ! 4893: } ! 4894: mswait(100); ! 4895: } ! 4896: } ! 4897: ! 4898: if(thread_count>1) { ! 4899: lprintf(LOG_DEBUG,"%04d Waiting for %d threads to terminate..." ! 4900: ,server_socket, thread_count-1); ! 4901: start=time(NULL); ! 4902: while(thread_count>1) { ! 4903: if(time(NULL)-start>TIMEOUT_THREAD_WAIT) { ! 4904: lprintf(LOG_WARNING,"%04d !TIMEOUT waiting for %d threads" ! 4905: ,server_socket, thread_count-1); ! 4906: break; ! 4907: } ! 4908: mswait(100); ! 4909: } ! 4910: } ! 4911: ! 4912: cleanup(0,__LINE__); ! 4913: ! 4914: if(!terminate_server) { ! 4915: lprintf(LOG_INFO,"Recycling server..."); ! 4916: mswait(2000); ! 4917: if(startup->recycle!=NULL) ! 4918: startup->recycle(startup->cbdata); ! 4919: } ! 4920: ! 4921: } while(!terminate_server); ! 4922: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.