Skip to content
Snippets Groups Projects
ftpsrvr.c 163 KiB
Newer Older
/* Synchronet FTP server */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

rswindell's avatar
rswindell committed
/* ANSI C Library headers */
#include <stdio.h>
#include <stdlib.h>			/* ltoa in GNU C lib */
#include <stdarg.h>			/* va_list, varargs */
#include <string.h>			/* strrchr */
#include <fcntl.h>			/* O_WRONLY, O_RDONLY, etc. */
#include <errno.h>			/* EACCES */
#include <ctype.h>			/* toupper */
#include <sys/types.h>
#include <sys/stat.h>

/* Synchronet-specific headers */
#undef SBBS	/* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
#include "text.h"			/* TOTAL_TEXT */
rswindell's avatar
rswindell committed
#include "ftpsrvr.h"
#include "telnet.h"
deuce's avatar
deuce committed
#include "multisock.h"
deuce's avatar
deuce committed
#include "ssl.h"
#include "cryptlib.h"
#include "xpprintf.h"		// vasprintf
#include "git_branch.h"
#include "git_hash.h"
#define FTP_SERVER				"Synchronet FTP Server"
static const char* server_abbrev = "ftp";
#define ANONYMOUS				"anonymous"

#define BBS_VIRTUAL_PATH		"bbs:/""/"	/* this is actually bbs:<slash><slash> */
#define LOCAL_FSYS_DIR			"local:"
#define BBS_FSYS_DIR			"bbs:"
#define TIMEOUT_THREAD_WAIT		60		/* Seconds */
#define TIMEOUT_SOCKET_LISTEN	30		/* Seconds */

#define XFER_REPORT_INTERVAL	60		/* Seconds */

#define INDEX_FNAME_LEN			15

#define	NAME_LEN				15		/* User name length for listings */

#define MLSX_TYPE	(1<<0)
#define MLSX_PERM	(1<<1)
#define MLSX_SIZE	(1<<2)
#define MLSX_MODIFY	(1<<3)
#define MLSX_OWNER	(1<<4)
#define MLSX_UNIQUE	(1<<5)
#define MLSX_CREATE	(1<<6)
static ftp_startup_t*	startup=NULL;
static scfg_t	scfg;
static struct mqtt mqtt;
deuce's avatar
deuce committed
static struct xpms_set *ftp_set = NULL;
static protected_uint32_t active_clients;
static protected_uint32_t thread_count;
static volatile uint32_t client_highwater=0;
static volatile time_t	uptime=0;
static volatile ulong	served=0;
static volatile BOOL	terminate_server=FALSE;
static char 	*text[TOTAL_TEXT];
static str_list_t recycle_semfiles;
static str_list_t shutdown_semfiles;
static link_list_t current_connections;
	static BYTE 	socket_debug[0x10000]={0};
	#define	SOCKET_DEBUG_CTRL		(1<<0)	/* 0x01 */
	#define SOCKET_DEBUG_SEND		(1<<1)	/* 0x02 */
	#define SOCKET_DEBUG_READLINE	(1<<2)	/* 0x04 */
	#define SOCKET_DEBUG_ACCEPT		(1<<3)	/* 0x08 */
	#define SOCKET_DEBUG_SENDTHREAD	(1<<4)	/* 0x10 */
	#define SOCKET_DEBUG_TERMINATE	(1<<5)	/* 0x20 */
	#define SOCKET_DEBUG_RECV_CHAR	(1<<6)	/* 0x40 */
	#define SOCKET_DEBUG_FILEXFER	(1<<7)	/* 0x80 */
char* genvpath(int lib, int dir, char* str);

typedef struct {
	SOCKET			socket;
deuce's avatar
deuce committed
	union xp_sockaddr	client_addr;
	socklen_t		client_addr_len;
static const char *ftp_mon[]={"Jan","Feb","Mar","Apr","May","Jun"
            ,"Jul","Aug","Sep","Oct","Nov","Dec"};

BOOL direxist(char *dir)
{
	if(access(dir,0)==0)
		return(TRUE);
	else
		return(FALSE);
}

rswindell's avatar
rswindell committed
BOOL dir_op(scfg_t* cfg, user_t* user, client_t* client, uint dirnum)
	return is_user_dirop(cfg, dirnum, user, client);
static int lputs(int level, const char* str)
{
	mqtt_lputs(&mqtt, TOPIC_SERVER, level, str);
	if(level <= LOG_ERR) {
		char errmsg[1024];
		SAFEPRINTF2(errmsg, "%-4s %s", server_abbrev, str);
		errorlog(&scfg, &mqtt, level, startup == NULL ? NULL : startup->host_name, errmsg);
		if(startup != NULL && startup->errormsg != NULL)
			startup->errormsg(startup->cbdata, level, errmsg);
	}

	if(startup == NULL || startup->lputs == NULL || str == NULL || level > startup->log_level)
    	return 0;

#if defined(_WIN32)
	if(IsBadCodePtr((FARPROC)startup->lputs))
		return 0;
#endif

    return startup->lputs(startup->cbdata,level,str);
}

#if defined(__GNUC__)	// Catch printf-format errors with lprintf
static int lprintf(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
#endif
static int lprintf(int level, const char *fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

    va_start(argptr,fmt);
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
    return lputs(level, sbuf);
}

#ifdef _WINSOCKAPI_

static WSADATA WSAData;
#define SOCKLIB_DESC WSAData.szDescription

static BOOL WSAInitialized=FALSE;

static BOOL winsock_startup(void)
{
	int		status;             /* Status Code */

    if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
		lprintf(LOG_DEBUG,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
    lprintf(LOG_CRIT,"!WinSock startup ERROR %d", status);
#define winsock_startup()	(TRUE)
Loading
Loading full blame...