Skip to content
Snippets Groups Projects
ftpsrvr.c 118 KiB
Newer Older

		if(!strnicmp(cmd, "MKD", 3) || 
			!strnicmp(cmd,"XMKD",4) || 
			!strnicmp(cmd,"SITE EXEC",9)) {
			lprintf("%04d !SUSPECTED HACK ATTEMPT by %s: '%s'"
				,sock,user.alias,cmd);
			hacklog(&scfg, "FTP", user.alias, cmd, host_name, &ftp.client_addr);
			if(startup->hack_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
				PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME);
		sockprintf(sock,"500 Syntax error: '%s'",cmd);
		lprintf("%04d !UNSUPPORTED COMMAND from %s: '%s'"
			,sock,user.alias,cmd);

	if(transfer_inprogress==TRUE) {
		lprintf("%04d Waiting for transfer to complete...",sock);
		while(/* data_sock!=INVALID_SOCKET && removed SEP-16-2001 */
			transfer_inprogress==TRUE && server_socket!=INVALID_SOCKET) {
			mswait(500);
			if(!transfer_aborted) {
				if(gettimeleft(&scfg,&user,logintime)<1) {
					lprintf("%04d Out of time, disconnecting",sock);
					sockprintf(sock,"421 Sorry, you've run out of time.");
					ftp_close_socket(&data_sock,__LINE__);
					transfer_aborted=TRUE;
				}
				if((time(NULL)-lastactive)>startup->max_inactivity) {
					lprintf("%04d Disconnecting due to to inactivity.",sock);
					sockprintf(sock,"421 Disconnecting due to inactivity (%u seconds)."
						,startup->max_inactivity);
					ftp_close_socket(&data_sock,__LINE__);
					transfer_aborted=TRUE;
				}
			}
		}
		lprintf("%04d Done waiting for transfer to complete",sock);
	}

	/* Update User Statistics */
		logoutuserdat(&scfg, &user, time(NULL), logintime);

	if(user.number)
		lprintf("%04d %s logged off.",sock,user.alias);

rswindell's avatar
rswindell committed
#ifdef _WIN32
	if(startup->hangup_sound[0] && !(startup->options&FTP_OPT_MUTE)) 
		PlaySound(startup->hangup_sound, NULL, SND_ASYNC|SND_FILENAME);
rswindell's avatar
rswindell committed
#endif
#ifdef JAVASCRIPT
	if(js_cx!=NULL) {
		lprintf("%04d JavaScript: Destroying context",sock);
		JS_DestroyContext(js_cx);	/* Free Context */
	}
	status(STATUS_WFC);

	lprintf("%04d CTRL thread terminated", sock);
	active_clients--;
	update_clients();
	client_off(sock);

	socket_debug[sock]&=~SOCKET_DEBUG_CTRL;

	/* Free up resources here */
	if(pasv_sock!=INVALID_SOCKET)
	if(data_sock!=INVALID_SOCKET)

	thread_down();
}

static void cleanup(int code)
{
	free_cfg(&scfg);

	if(server_socket!=INVALID_SOCKET)
	server_socket=INVALID_SOCKET;

	update_clients();
	if(WSAInitialized && WSACleanup()!=0) 
		lprintf("0000 !WSACleanup ERROR %d",ERROR_VALUE);
#ifdef _WIN32
	if(socket_mutex!=NULL) {
		CloseHandle(socket_mutex);
		socket_mutex=NULL;
	}
#endif

#ifdef JAVASCRIPT
	if(js_runtime!=NULL) {
		lprintf("0000 JavaScript: Destroying runtime");
		JS_DestroyRuntime(js_runtime);
		js_runtime=NULL;
	}
#endif

    lprintf("#### FTP Server thread terminated");
	status("Down");
	if(startup!=NULL && startup->terminated!=NULL)
		startup->terminated(code);
	thread_down();
}

const char* DLLCALL ftp_ver(void)
{
	static char ver[256];
	char compiler[32];

	sprintf(ver,"%s v%s%s  "
		"Compiled %s %s with %s"
		,FTP_SERVER
		,FTP_VERSION
#ifdef _DEBUG
		," Debug"
#else
		,""
#endif
		,__DATE__, __TIME__, compiler);

	return(ver);
}

{
	char			compiler[32];
	SOCKADDR_IN		server_addr;
	SOCKADDR_IN		client_addr;
	int				client_addr_len;
	SOCKET			client_socket;
	int				i;
	int				result;
	time_t			t;
	time_t			start;
	LINGER			linger;

	startup=(ftp_startup_t*)arg;

    if(startup==NULL) {
    	fprintf(stderr, "No startup structure passed!\n");
    	return;
    }

	if(startup->size!=sizeof(ftp_startup_t)) {	/* verify size */
		sbbs_beep(100,500);
		sbbs_beep(300,500);
		sbbs_beep(100,500);
		fprintf(stderr, "Invalid startup structure!\n");
		return;
	}

	/* Setup intelligent defaults */
	if(startup->port==0)					startup->port=IPPORT_FTP;
	if(startup->qwk_timeout==0)				startup->qwk_timeout=600;		/* seconds */
	if(startup->max_inactivity==0)			startup->max_inactivity=300;	/* seconds */
	if(startup->index_file_name[0]==0)		strcpy(startup->index_file_name,"00index");
	if(startup->html_index_file[0]==0)		strcpy(startup->html_index_file,"00index.html");
	if(startup->html_index_script[0]==0) {	strcpy(startup->html_index_script,"ftp-html.js");
											startup->options|=FTP_OPT_HTML_INDEX_FILE;
	}
	if(startup->options&FTP_OPT_HTML_INDEX_FILE)
		startup->options&=~FTP_OPT_NO_JAVASCRIPT;
	else
		startup->options|=FTP_OPT_NO_JAVASCRIPT;
	thread_up();

	status("Initializing");

    memset(&scfg, 0, sizeof(scfg));

#ifdef __unix__		/* Ignore "Broken Pipe" signal */
	signal(SIGPIPE,SIG_IGN);
#endif

	lprintf("Synchronet FTP Server Version %s%s"
		,FTP_VERSION
#ifdef _DEBUG
		," Debug"
#else
		,""
#endif
		);


	lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler);

	srand(time(NULL));

	if(!(startup->options&FTP_OPT_LOCAL_TIMEZONE)) { 
		if(PUTENV("TZ=UCT0"))
			lprintf("!putenv() FAILED");
		tzset();

		if((t=checktime())!=0) {   /* Check binary time */
			lprintf("!TIME PROBLEM (%ld)",t);
			cleanup(1);
			return;
		}
	}

	if(!winsock_startup()) {
		cleanup(1);
		return;
	}

	lprintf("Initializing on %.24s with options: %lx"
		,ctime(&t),startup->options);
    if((socket_mutex=CreateMutex(NULL,FALSE,NULL))==NULL) {
    	lprintf("!ERROR %d creating socket_mutex", GetLastError());
		cleanup(1);
        return;
    }

	/* Initial configuration and load from CNF files */
    sprintf(scfg.ctrl_dir, "%.*s",(int)sizeof(scfg.ctrl_dir)-1
    	,startup->ctrl_dir);
    lprintf("Loading configuration files from %s", scfg.ctrl_dir);
	scfg.size=sizeof(scfg);
	if(!load_cfg(&scfg, NULL, TRUE)) {
		lprintf("!Failed to load configuration files");
		cleanup(1);
		return;
	}

	/* Use DATA/TEMP for temp dir - should ch'd to be FTP/HOST specific */
	prep_dir(scfg.data_dir, scfg.temp_dir);

	if(!startup->max_clients) {
		startup->max_clients=scfg.sys_nodes;
		if(startup->max_clients<10)
			startup->max_clients=10;
	}
	lprintf("Maximum clients: %d",startup->max_clients);

	lprintf("Maximum inactivity: %d seconds",startup->max_inactivity);

	active_clients=0;
	update_clients();

	strlwr(scfg.sys_id); /* Use lower-case unix-looking System ID for group name */

	for(i=0;i<scfg.total_libs;i++) {
		strlwr(scfg.lib[i]->sname);
		dotname(scfg.lib[i]->sname,scfg.lib[i]->sname);
	}

	for(i=0;i<scfg.total_dirs;i++) 
		strlwr(scfg.dir[i]->code);

#ifdef JAVASCRIPT
	if(!(startup->options&FTP_OPT_NO_JAVASCRIPT)) {
		lprintf("JavaScript: Creating runtime: %lu bytes"
			,JAVASCRIPT_RUNTIME_MEMORY);
		if((js_runtime = JS_NewRuntime(JAVASCRIPT_RUNTIME_MEMORY))==NULL) {
			lprintf("!JS_NewRuntime failed");
			cleanup(1);
			return;
		}
		lprintf("JavaScript: Context stack: %lu bytes", JAVASCRIPT_CONTEXT_STACK);

    /* open a socket and wait for a client */

    if((server_socket=ftp_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
		lprintf("!ERROR %d opening socket", ERROR_VALUE);
		cleanup(1);
		return;
	}

    lprintf("%04d FTP socket opened",server_socket);

#if 1
	linger.l_onoff=TRUE;
    linger.l_linger=5;	/* seconds */

	if((result=setsockopt(server_socket, SOL_SOCKET, SO_LINGER
    	,(char *)&linger, sizeof(linger)))!=0) {
		lprintf ("%04d !ERROR %d (%d) setting socket options."
			,server_socket, result, ERROR_VALUE);
		cleanup(1);
		return;
	}
#endif

	/*****************************/
	/* Listen for incoming calls */
	/*****************************/
    memset(&server_addr, 0, sizeof(server_addr));

	server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port   = htons(startup->port);

    if((result=bind(server_socket, (struct sockaddr *) &server_addr
    	,sizeof(server_addr)))!=0) {
		lprintf("%04d !ERROR %d (%d) binding socket to port %u"
			,server_socket, result, ERROR_VALUE,startup->port);
		lprintf("!Another service may be using this port");
		cleanup(1);
		return;
	}

    if((result=listen(server_socket, 1))!= 0) {
		lprintf("%04d !ERROR %d (%d) listening on socket"
			,server_socket, result, ERROR_VALUE);
		cleanup(1);
		return;
	}

	/* signal caller that we've started up successfully */
    if(startup->started!=NULL)
    	startup->started();

	lprintf("%04d FTP Server thread started on port %d",server_socket,startup->port);
	status(STATUS_WFC);

	while(server_socket!=INVALID_SOCKET) {

		/* now wait for connection */

		tv.tv_sec=2;
		tv.tv_usec=0;

		FD_ZERO(&socket_set);
		FD_SET(server_socket,&socket_set);

		if((i=select(server_socket+1,&socket_set,NULL,NULL,&tv))<1) {
			if(i==0) {
				mswait(1);
				continue;
			}
			if(ERROR_VALUE==EINTR)
				lprintf("0000 FTP Server listening interrupted");
			else if(ERROR_VALUE == ENOTSOCK)
            	lprintf("0000 FTP Server sockets closed");
			else
				lprintf("0000 !ERROR %d selecting sockets",ERROR_VALUE);
			break;
		}

		client_addr_len = sizeof(client_addr);
		client_socket = accept(server_socket, (struct sockaddr *)&client_addr
        	,&client_addr_len);

		if(client_socket == INVALID_SOCKET)
		{
rswindell's avatar
rswindell committed
			if(ERROR_VALUE == ENOTSOCK || ERROR_VALUE == EINTR)
            	lprintf("0000 FTP socket closed while listening");
				lprintf("0000 !accept failed (ERROR %d)", ERROR_VALUE);
			continue;	/* Jun-08-2001 was break; */
		}
		if(startup->socket_open!=NULL)
			startup->socket_open(TRUE);
		sockets++;

		if(active_clients>=startup->max_clients) {
			lprintf("%04d !MAXMIMUM CLIENTS (%d) reached, access denied"
				,client_socket, startup->max_clients);
			sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");
			mswait(3000);
			continue;
		}

		if((ftp=malloc(sizeof(ftp_t)))==NULL) {
			lprintf("%04d !ERROR allocating %d bytes of memory for ftp_t"
				,client_socket,sizeof(ftp_t));
			sockprintf(client_socket,"421 System error, please try again later.");
			mswait(3000);
			continue;
		}

		ftp->socket=client_socket;
		ftp->client_addr=client_addr;

		_beginthread (ctrl_thread, 0, ftp);
	}

	if(active_clients) {
		lprintf("0000 Waiting for %d active clients to disconnect...", active_clients);
		start=time(NULL);
		while(active_clients) {
			if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
				lprintf("0000 !TIMEOUT waiting for %d active clients ",active_clients);
			mswait(100);