/* Copyright (C) 1999 Beau Kuiper

   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, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Includes */

#ifndef DEBUG		/* If we are not debuging, disable assertions! */
#define NDEBUG
#endif

#include "../config.h"	/* Insert the config header */
#include "../defaults.h"   /* insert default info */

#include <assert.h> 	/* enable assertions */

#include "myglob.h"		/* use our simple glob */
#include "util/strerror.h"
#include <sys/types.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#undef WNOHANG
#undef WUNTRACED
#endif
#include <sys/ipc.h>
#include <sys/shm.h>
#include <pwd.h>
#include <grp.h>
#include <stdarg.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include <dirent.h>
#include <malloc.h>
#include <syslog.h>
#include <setjmp.h>

#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif

#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif

#ifdef HAVE_GETSPNAM
#include <shadow.h>
#endif
 
#ifndef INT_MAX
#define INT_MAX 0x7FFFFFFF
#endif

#include "pnums.h"
#include "configfile.h"
#include "acl.h"
#include "tokset.h"
#include "ratio.h"
#include "string.h"

/* Inportant Constants */

#ifndef FALSE
#define		FALSE		0
#endif
#ifndef TRUE
#define		TRUE		!FALSE
#endif
#define 	SYSLOG		1
#define 	TERMINAL	2
#define 	MUDLOG		3

#define		MYLOG_DACCESS	1
#define		MYLOG_FTRANS	2
#define		MYLOG_COMMAND	4
#define		MYLOG_RESPONSE	8
#define		MYLOG_INFO	16
#define 	MYLOG_LOGIN	32
#define 	MYLOG_DEBUG	64

#define		TRANS_LIST	1
#define 	TRANS_UPLOAD	2
#define		TRANS_DOWNLOAD  3
#define		TRANS_SUPLOAD	4
#define		TRANS_RUNNING	5

/* used in authentication modules */
#define		AUTH_OK		0
#define		AUTH_USERNKNOW	1
#define 	AUTH_ERROR	2

/* used for config errors */

#define		CONFIG_OK	     0
#define		CONFIG_HANDLER_ERROR 1
#define 	CONFIG_FILE_UNSAFE   2
#define		CONFIG_FILE_ERROR    3

#define		CFC_INCLUDE_ERROR    10
#define		CFC_SECTION_NONE     11
#define		CFC_SECTION_EXISTS   12
#define		CFC_NO_SECTION	     13
#define		CFC_INCLUDE_LOOP     14

/* used to define maximum IP address size (for ipv6 support) */

#define		MAX_IPSIZE	16

#define		FTP_IPV4	1
#define		FTP_IPV6	2

/* DO NOT CHANGE THESE DEFINES. THEY ARE REQUIRED CONSTANTS */

#define CR			13
#define LF			10

/* Macros */

#define MAXIMUM(x, y)		((x) > (y) ? (x) : (y))
#define MINIMUM(x, y)		((x) > (y) ? (y) : (x))
#define ERRORMSG(x)		errormsg(x, __FILE__, __LINE__)
#define ERRORMSGFATAL(x)	errormsgfatal(x, __FILE__, __LINE__)

#ifndef FNM_PATHNAME
#define FNM_PATHNAME 1
#endif

/* this specifies that the operation cannot be stopped by a signal */

#define NOSIGNALINTR(x)		while(((x) == -1) && (errno == EINTR))

/* Typedefs */

typedef unsigned int ipaddr_mt[MAX_IPSIZE];

typedef struct
{
	int fd;
	STRING *buffer;
	int eof;
} NEWFILE;

typedef struct strcache
{
	int size;
	struct {
		int num;
		char *str;
	       } data[STRCACHESIZE];
} STRCACHE;

struct selector;

struct selectorobj
{
	int (* readsockopt)(struct selector *, int, void *);
	int (* writesockopt)(struct selector *, int,void *);
	void *readdata;
	void *writedata;
	int next;		/* linked list of file descriptors */
	int last;
};

typedef struct selector
{
	fd_set readset;
	fd_set writeset;
	struct selectorobj **fdtable;
	int firstfd;
	int maxfds;
	int smax;
} SELECTER;

typedef struct limiter
{
	int maxspeed;
	struct timeval current_time;
	int bytes_transfered;
} LIMITER;

typedef struct
{
	int pos;
	MYGLOBDATA *dirdata;
	int nlist;
	int recursive;
	int all;
	STRCACHE *uidcache;
	STRCACHE *gidcache;
	char *dir;
	char *rdir;
	int odirlen;
	int numsubdirs;
	char **subdirs;
	unsigned int year;		/* this is stored as 4 chars */
} LISTHANDLE;

typedef struct dataport
{
	int filefd;
	int socketfd;
	off_t pos;
	off_t startpos;
	off_t tsize;
	STRING *buffer;
	LISTHANDLE *lhandle;
	int trans_type;
	int binary;
	int passive;
	off_t transbytes;
	LIMITER *download_limiter;
	LIMITER *upload_limiter;
} DATAPORT;

typedef struct
{
	unsigned int ipaddr;
	unsigned int netmask; 
	char *fnstr;
	int type;
	int accept;
} IPACL;

typedef struct
{
	int count;
	IPACL *list;
} IPACLLIST;

typedef struct vserver
{
	IPACLLIST *ipaccess;
	int maxusers;
	int loglevel;
	int timeout;
	char *logfile;
	char *email;
	int logincount;
	int authwait; 
	int umask;
	int maxperip;
	char *sectionname;
	char **grouplist;
	char *vhostname;
	char *prelogindump;
	char *prelogindumpdata;
	char *greetline;
	char *toobusy;
	struct vserver *next;
} VSERVER;

typedef struct vserverconn
{
	int port;
	int ip;
	int fd;
	VSERVER *vptr;
	struct vserverconn *next;
} VSERVERCONN;

typedef struct configdata
{
	CONFIGFILECACHE *configfile;

	pid_t parentpid;      /* the pid to signal when an fatal error occurs */

	int rootmode;         /* are we in root mode or not */
	int logout;	      /* log context */

	uid_t uidt_asuid;	      /* change to this user after listening to port */
	gid_t gidt_asgid;

	int toobusycount;     /* number of connections being given too busy
				 messages by main thread */
	char *username;	      /* the username muddleftpd will run as */
	uid_t uidt_nobodyuid;      /* uid for user nobody */
	gid_t gidt_nobodygid;      /* gid for user nobody */

	int inetd;	      /* are we running as inetd */
	int hostvservers;     /* are we running with hostname only
	                         virtual servers */
	int dnstimeout;	      /* maximum time to wait for reversedns */
	int altlongreplies;   /* use alternate long replies, more compatible 
			 	 with crappy clients */
	int smartbind;	      /* specifies whether to search for effecient
				 fd usage, or correct binding */
	int zerobind;	      /* bind all ports using address 0.0.0.0, use
				 with smartbind on Freebsd to use
				 virtual servers */
	char *hostname;       /* Computer host name */
	VSERVER *defaults;    /* Default values for VSERVER */
	VSERVER *defaulthost; /* The default host for hostvservers */
	char **vserverlist;   /* list of virtual servers names */
	VSERVER *vservers;    /* virtual server list */
	VSERVERCONN *inports; /* input ports */
} CONFIGDATA;
	
typedef struct ftpstate
{
	int remotefd;		/* fd of the port to the remote system */
	unsigned int remoteip;		/* the systems IP number */
	int connport;		/* port connected to */
	char *username;		/* the username of the ftp user */
	char *pwd;		/* the current dir the ftp user is in */
	char *homedir;		/* the home directory of the ftp user */
	char *basedir;		/* the / directory for that user */
	int passiveport;	/* the fd of the listening passive port */
	char *renameoldname;	/* the source file to rename */
	int loggedin;		/* true if the user is logged in */
	off_t restartpos;	/* the position to start a download or upload */
	int remoteport;		/* the port number to connect to for data conns */
	int binary;		/* true if binary mode is set */
	int threadnum;		/* the number of the thread in ftpd terms (not pid) */
	int *cmddisableset;	/* a set of integers used to disable commands */
	int *sitedisableset;	/* a set of integers used to disable site commands */
	STRING *inbuffer;	/* the input buffer */

	char *logindump;	/* file to print after login */
	char *cwddump;		/* dump this file when you move to this dir */
	char *busydump;		/* dump this file if too many users are logged in */
	char *quitdump;		/* dump this file when the user quits */

	char *logindumpdata;	/* this is for login dump */
	char *cwddumpdata;	/* this is when we change dir */
	char *busydumpdata;	/* this is when we are too busy */
	char *quitdumpdata;	/* this is when we quit */

	ACLLIST *acldata;	/* The access lists for this user */
	int umask;		/* the umask of newly created files */
	gid_t gidt_asgid;	/* all file work is done as this gid (if possible) */
	uid_t uidt_asuid;	/* all file work is done as this uid (if possible) */
	int maxusers;		/* maximum instances of this user allowed to be logged in */
	int maxtimeout;		/* maximum time out for this user */
	int timeout;		/* timeout for this user */
	int chmodable;		/* can do chmod and change umask */
	SELECTER *sel;		/* select data stored here */
	DATAPORT *dport;	/* Data port information */
	int loginsleft;		/* number of login attempts left */
	int jailenabled;	/* is this user a jail */
	int chroot;		/* does a chroot occur */
	int droproot;		/* do we drop root when logging in */
	int nicevalue;		/* what niceness to run as */
	int realdir;		/* use real directory instead of built up
				   name */
	int fxpallow;		/* allow fxp(server-server) transfers */
	int usercount;		/* the number of users in the current group when the user logged on */
	char *hostname;		/* the hostname of the remote host */
	int accessdevices;	/* can the user access device files */ 
	char *groupname;
	int fakemode;
	char *fakename;
	char *fakegroup;
	VSERVER *vserver;	/* vserver the user is connected to */
	RATIOHANDLE *ratioinfo;	/* ratio info */
	gid_t *supgids;		/* user supplementary gids */
	unsigned int dataip;	/* ip to connect data port to */
	STRING *outbuffer;	/* output coalessing buffer */
	int maxtranspd;		/* Maximum transfer speed */
	int maxtranspd_down;	/* Maximum download speed, overrides maxtranspd */
	int maxtranspd_up;	/* Maximum upload speed, overrides maxtranspd */
	int epsv_forced;	/* EPSV ALL was called, deny everything else */
	
	/* Counters for stats */
	int downloadedfiles;
	int uploadedfiles;
	off_t downloadedfilebytes;
	off_t uploadedfilebytes;
	off_t listdownloadedbytes;
	int listconns;
} FTPSTATE;

typedef struct ftpcmd
{
	char *command;
	int (* ftpfunc)(FTPSTATE *peer, char *params);
	int paramnum;
	int needslogin;	
	int dataportok;
	char *helpdesc;
} FTPCMD;

typedef struct inputline
{
	FTPCMD *command;
	char *parameters;
} INPUTLINE;

/* GLOBAL VARIABLES */

CONFIGDATA *config;	  /* configuration data stored here for easy access */
int inetd;		  /* is process running as inetd */
int logerrors;		  /* do we log config errors to screen, syslog, or
			     screen */

/* these prototypes are mostly auto generated by scribe */

/* procnum.h */

void writescratch(int pos, int size, char *buff);
void writeshmem(int num, int pos, int len, void *buff);
void shinfo_addtogrouplist(VSERVER *vs);
void shinfo_setuparea(void);
void shinfo_init(char *scfilename);
void inetd_init(char *scfile);
void shinfo_reinit(void);
int shinfo_addstandalone(int newthid, char *vservername, unsigned int ip, int viplimit, int iplimit);
int shinfo_adduser_inetd(unsigned int ip, int slimit, int iplimit, int *error);
int shinfo_adduser(char *vserver, unsigned int ip, int vlimit, int slimit, int viplimit, int iplimit);
int shinfo_setvserver(int thid, char *vservername, unsigned int ip, int vlimit, int viplimit, int *error);
int shinfo_newuser_standalone(unsigned int ip, int iplimit, int *error);
void shinfo_changeop(char *operation);
void shinfo_changeuser(char *username);
void shinfo_sethost(char *hostname);
int shinfo_addusergroup(char *groupname, int limit);
void shinfo_setpid(int thrid, int pid);
void shinfo_delbypid(int pid);
void shinfo_delusergroup(char *groupname);
void shinfo_freebynum(int threadnum);
void shinfo_freethreads(int freecount, pid_t *freelist);
void pnums_signalchildren(int signalnum);
void shinfo_shutdown(void);

/* socket.h */

char *getipstr(unsigned int server);
void takentoolong(int sig);
char *getnetworkstr(unsigned int server);
int getnetworkint(char *server, unsigned int *out);
int conn_server(unsigned int ip, int port);
int conn_server_nonblocking(unsigned int ip, int port, int localport, int fd);
int listenport(int port, unsigned int ip, int maxconnect);
int get_conn(int socketin, unsigned int *addr);
int listenparrelelport(int fd, int *port, unsigned int *ip, int maxconnect);
void getsockinfo(int fd, unsigned int *ip, int *port);
unsigned int getremoteip(int fd);
void socket_flush_wait(int fd, int timeout);

/* select.h */

SELECTER *select_new(void);
void select_addfd(SELECTER *sel, int newport);
void select_delfd(SELECTER *sel, int deadport);
void select_addread(SELECTER *sel, int port, int (* proc)(SELECTER *, int, void *), void *dat);
void select_addwrite(SELECTER *sel, int port, int (* proc)(SELECTER *, int, void *), void *dat);
void select_takeread(SELECTER *sel, int port);
void select_takewrite(SELECTER *sel, int port);
int select_do(SELECTER *sel, int *signum, int timeout);
void select_shutdown(SELECTER *sel);

/* ftpsite.h */

int ftp_site(FTPSTATE *peer, char *cmd);
int ftpsite_dump(FTPSTATE *peer, char *cmd);
int ftpsite_umask(FTPSTATE *peer, char *cmd);
int ftpsite_help(FTPSTATE *peer, char *cmd);
int ftpsite_idle(FTPSTATE *peer, char *cmd);
int ftpsite_chmod(FTPSTATE *peer, char *cmd);
int ftpsite_access(FTPSTATE *peer, char *cmd);

/* proxy.h */

int controlportgotdata(SELECTER *sel, int fd, void *peerdata);
char *remove_rootcomponent(FTPSTATE *peer, char *filename, char *descript);
void dochroot(FTPSTATE *peer);
void rotatelogs(FTPSTATE *peer);
void ftpserverside_main(int remotefd, int remoteip, int threadnum, int portnum, VSERVER *vserver);
int inport_bind(int portid, unsigned int bindip, int dodie);
int inport_getconn(SELECTER *mainsel, int fd, void *vs);
int vserver_select(FTPSTATE *peer, VSERVER *vserver);

/* version.h */

void showversion(char *desc);

/* acl.h */

ACLLIST *acllist_create(void);
char *acllist_makepermstr(ACLLIST *acl, int cnt, char *ret);
void acllist_add(ACLLIST *acl, char *dir, char *attribs, int is_regexp);
void acllist_tokendo(ACLLIST *acl, TOKENSET *tset);
int acllist_check(ACLLIST *acl, char *dir, int attr);
int check_acl(FTPSTATE *peer, char *path, int perm);
void acllist_dest(ACLLIST *acl);

/* ftpout.h */

void control_timeout(int num);
int ftp_write(FTPSTATE *peer, int bare, int messnum, char *fmt, ...);

/* utils.h */

void *mallocwrapper(int size);
void reallocwrapper(int size, void **inarea);
char *strdupwrapper(char *s);
void freewrapper(void *tofree);
void freeifnotnull(void *);
char *offt_tostr(off_t size);
int strto_offt(char *str, off_t *ret);

#ifndef HAVE_MEMMOVE
void *memmove(void *, const void *, int);
#endif

void strtrimspace(char *string);
int strchrcount(char *string, char tok);
char *safe_vsnprintf(int size, char *format, va_list ap);
char *safe_snprintf(char *format, ...);
char *getcwd2(void);
void pathname_simplify(char *pathname);
void test_libc(int verbose);

#ifndef HAVE_USLEEP
int usleep(int usecs);
#endif

STRCACHE *strcache_new(void);
char *strcache_check(STRCACHE *cache, int num);
void strcache_add(STRCACHE *cache, int num, char *str);
void strcache_free(STRCACHE *cache);
TOKENSET *tokenset_new(void);
void tokenset_settoken(TOKENSET *tset, unsigned char tok, char *data);
void tokenset_deltoken(TOKENSET *tset, unsigned char tok);
char *tokenset_apply(TOKENSET *tok, char *inputstr, int);
void tokenset_finish(TOKENSET *tset);

void init_pwgrfiles(void);
char *get_passwdname(uid_t inuid, int usefile);
char *get_groupname(gid_t ingid, int usefile);
gid_t *getusergrouplist(char *username);
gid_t *newgidlist(void);
gid_t *addgidlist(gid_t *list, gid_t new);
void delgidlist(gid_t *list, gid_t old);
gid_t *parsegidlist(char *str);
char *makegidliststr(gid_t *list);
void kill_uidgidfiles(void);
int isfilesafe(int fd);
LIMITER *limiter_new(int maxspeed);
void limiter_add(LIMITER *l, int byte_count, int force);
int giveuproot(uid_t uid, gid_t gid);
void errormsg( char *errmessage, char *file, int line );
void errormsgfatal( char *errmessage, char *file, int line );
void blockallsignals( void );
void unblockallsignals( void );

/* init.h */

void ftpd_setnogroups(void);
void ftpd_preinit(void);
void ftpd_init(char *filename, int verbose);

/* ftp.h */

void reporterror(FTPSTATE *peer, char *filename, int errorno);
int readipstr(char *data, int *port, unsigned int *ip);
int ftp_dele(FTPSTATE *peer, char *filename);
int ftp_chmod(FTPSTATE *peer, char *filename, int mode);
int ftp_size(FTPSTATE *peer, char *filename);
int ftp_mdtm(FTPSTATE *peer, char *filename);
void setdumptokens(FTPSTATE *peer, TOKENSET *ts);
int ftp_dumper(FTPSTATE *peer, NEWFILE *infile, int number, char *fmessage, int dotokens, int endtokens);
int ftp_dumpstr(FTPSTATE *peer, char *dumpstr, int number, char *fmessage, int endtokens);
int ftp_rnto(FTPSTATE *peer, char *filename);
int ftp_mkd(FTPSTATE *peer, char *filename);
int ftp_rmd(FTPSTATE *peer, char *filename);
int ftp_cwddo(FTPSTATE *peer, char *newdir, int dump);
int ftp_cwd(FTPSTATE *peer, char *newdir);
int ftp_run(FTPSTATE *peer, INPUTLINE *cmd, char *token);
int ftp_quit(FTPSTATE *peer, char *param);
int ftp_user(FTPSTATE *peer, char *param);
int ftp_pass(FTPSTATE *peer, char *param);
int ftp_rest(FTPSTATE *peer, char *param);
int ftp_syst(FTPSTATE *peer, char *param);
int ftp_port(FTPSTATE *peer, char *param);
int ftp_pwd(FTPSTATE *peer, char *param);
int ftp_type(FTPSTATE *peer, char *param);
int ftp_abor(FTPSTATE *peer, char *param);
int ftp_pasv(FTPSTATE *peer, char *param);
int ftp_list(FTPSTATE *peer, char *param);
int ftp_nlst(FTPSTATE *peer, char *param);
int ftp_cdup(FTPSTATE *peer, char *param);
int ftp_rnfr(FTPSTATE *peer, char *param);
int ftp_noop(FTPSTATE *peer, char *param);
int ftp_rein(FTPSTATE *peer, char *param);
int ftp_none(FTPSTATE *peer, char *param);
int ftp_help(FTPSTATE *peer, char *param);
int ftp_dohelp(FTPSTATE *peer, FTPCMD *ftpcmds, char *command, int *disableset);
int ftp_allo(FTPSTATE *peer, char *param);
int ftp_acct(FTPSTATE *peer, char *param);
int ftp_stru(FTPSTATE *peer, char *param);

/* ftpstat.h */

int ftp_stat(FTPSTATE *peer, char *param);

/* cmd.h */

int *disableset_create(void);
void disableset_disablecmd(int *set, FTPCMD *ctable, char *cmd);
char *getkeyword(char **iline);
void cmd_split(FTPSTATE *peer, INPUTLINE *cmd, char* inpline, FTPCMD *ctable, int log, int *disableset);

/* logger.h */

int log_initcontext(char *logname);
void log_setcontext(int logfd, int logmask);
void log_addentry(int type, FTPSTATE *peer, char *desc);
void log_giveentry(int type, FTPSTATE *peer, char *desc);
void debuglog(char *format, ...);
void log_shutdown(void);

/* dir.h */

char *dir_getreal(FTPSTATE *peer);
char *dir_getvirtual(FTPSTATE *peer, char *);
void dir_combine(FTPSTATE *peer, char **pwd, char *newdir);

/* shmem.h */

void shmem_finish(int shmemnum);
void *shmem_get(char *ipcfile, int size, int *shmemnum, int *isnew, int *lockfd);

/* ftplist.h */

int ftplist_parseflags(char *params);
char *listmakeline(FTPSTATE *peer, char *longname, char *filename, struct stat *fileinfo, STRCACHE *uidcache, STRCACHE *gidcache, int year);
LISTHANDLE *getlisthandle(FTPSTATE *peer, char *dirpattern, int nlist, char *reldir, int params);
char *getlisthandleline(FTPSTATE *peer, LISTHANDLE *lh);
void freelisthandle(LISTHANDLE *lh);
int list_write(SELECTER *sel, int fd, void *peerv);
char *listmakepattern(FTPSTATE *peer, char *parm, char **rdir, int flags);
int ftp_lister(FTPSTATE *peer, char *parm, int nlist, int params);

/* checkip.h */

int checknamelist(CONFIGFILECACHE *cf, int section, char *username);
IPACLLIST *ipacllist_new(CONFIGFILECACHE *cf, int section, char *name);
void ipacllist_destroy(IPACLLIST *list);
int user_allowed(IPACLLIST *list, int ip, char *hostname);

/* ftpstate.h */

void ftpstate_init(FTPSTATE *ftp, int fd, int ip, int threadnum, int portnum, VSERVER *vs);
void ftpstate_dest(FTPSTATE *ftp);

/* bufread.h */

int popcmd(FTPSTATE *peer, char **outstr);
int readcmd(FTPSTATE *peer);

/* config.h */

int loadconfigfile(char *filename, int (* confighandler)(char *, char *, int, void *), 
		   void *configdata, int bescure, int *handlererror, int *linenum);
int cachemaker(char *cmd, char *data, int linenum, void *c);
CONFIGFILECACHE *loadconfigcache(char *filename, int *linenum, int *error);
char *config_errorstr(int result);
int getsectionid(CONFIGFILECACHE *cache, char *section);
char *getconfigdata_r(CONFIGFILECACHE *cache, int section, char *cmd, int *occur, int depth, int *error);
char *getconfigdata(CONFIGFILECACHE *cache, int section, char *cmd, int occur);
char **makeconfiglist(CONFIGFILECACHE *cache, char *section, char *label);
void loadintfromconfig(CONFIGFILECACHE *cache, int section, char *setting, 
			int *to, int def);
void loadstrfromconfig(CONFIGFILECACHE *cache, int section, char *setting, 
			char **to, char *def);
void freeconfigcache(CONFIGFILECACHE *cache);

/* ftptrans.h */

int sigio_handler(int signum);
int filter_toascii(char *data, int *len);
int filter_fromascii(char *data, int *len);
int download_write(SELECTER *sel, int fd, void *peerv);
int upload_read(SELECTER *sel, int fd, void *peerv);
int ftp_retr(FTPSTATE *peer, char *filename);
int ftp_stor(FTPSTATE *peer, char *filename);
int ftp_stou(FTPSTATE *peer, char *filename);
int ftp_appe(FTPSTATE *peer, char *filename);

/* newfile.h */

int readbuffer(NEWFILE *file);
NEWFILE *nfopen(char *filename);
NEWFILE *nfdopen(int fd);
char *nfgetcs(NEWFILE *file, char testchar);
void nfclose(NEWFILE *file);

/* main.h */

void logfullmessage(int error, unsigned int ip);
VSERVER *findvserver(unsigned int ip, int port);
void smartbind(SELECTER *selset, VSERVERCONN *list, int dodie);
void dumbbind(SELECTER *selset, VSERVERCONN *list, int dodie);
void sighandler(int signum);
int mainprog(char *fconfig, int runforeground, int verbose);
void mainprog_inetd(char *fconfig, unsigned int ip);
void diehandler(int signum);
int main(int argc, char **argv);

/* datasock.h */

int datasock_connect(SELECTER *sel, int fd, void *peerv);
int startdatasocket(FTPSTATE *peer, int filefd, int trans_type, off_t tsize);
void closedatasocket(FTPSTATE *peer);
void abortdatasocket(FTPSTATE *peer);

/* auth.h */

void converttorealstr(char *strbuf);
int chkpassword(char *encrypass, char *password);
int checkexploits(FTPSTATE *peer);
int authlogmsg(char *directive, char *groupname);
int checkabsdir(char *dir);
void clearauth(FTPSTATE *peer);
char *mkconfrealstr(int sectionid, char *item, char *defaul);
char *mktokconfstr(TOKENSET *tset, int sectionid, char *item, char *defaul);
int mktokconfint(TOKENSET *tset, int sectionid, char *item, char *format,
		 char *defaultstr, int defaultint);
void setupacls(FTPSTATE *peer, TOKENSET *tset, int section, char *funcname, int aclfunc);
int transferconfig(FTPSTATE *peer, TOKENSET *tset, int section);
int auth_getcursectionid(FTPSTATE *peer);
void *auth_getconfigcache(void);
char *setuseropts(FTPSTATE *peer, char *password);

/* file.h */

void file_becomeuser(FTPSTATE *peer);
void file_becomeroot(FTPSTATE *peer);
int checkdir(char *dir);
int checkfile(char *file);
int checkchdir(FTPSTATE *peer, char *dir);
void convertperms(char *permstr, int mode);
char *file_expand(FTPSTATE *peer, char *filename);
int file_isfdregularfile(int fd);
int file_isfdadir(int fd);
int file_ustoreopen(FTPSTATE *peer, char *, int *, char **rname);
int file_storeopen(FTPSTATE *peer, char *infile, char **rname);
int file_readopen(FTPSTATE *peer, char *infile, char **rname);
NEWFILE *file_nfopen(FTPSTATE *peer, char *filename);
MYGLOBDATA *file_glob(FTPSTATE *peer, char *dir, char *pattern, int allfiles);
int file_unlink(FTPSTATE *peer, char *infile);
char *file_rename(FTPSTATE *peer, char *infile, char *infile2);
int file_stat(FTPSTATE *peer, char *infile, struct stat *output);
int file_mkdir(FTPSTATE *peer, char *infile);
int file_rmdir(FTPSTATE *peer, char *infile);
int file_chmod(FTPSTATE *peer, char *infile, int mode);

/* cfloader.h */

char *gethostname2(void);
void configerror(char *str);
void vserver_kill(VSERVER *c);
VSERVER *vserver_load(CONFIGDATA *cf, char *sectionname, VSERVER *def, VSERVERCONN ***vp);
void ftpd_killconfig(CONFIGDATA *dc);
CONFIGDATA *ftpd_loadconfig(char *inidata, int as_inetd, int use_umask);
int ftpd_checkvserver(CONFIGDATA *cdat, VSERVER *vs);
int ftpd_checkconfig(CONFIGDATA *cdat);

/* ratio.h */

int lockarea(int fd, int pos, int len, int locktype, int do_wait);
void lock_n_read(RATIOHANDLE *rh);
void write_n_unlock(RATIOHANDLE *rh);
int openratiofile(char *filename);
int decoderatiostr(char *ratstr, int *pa, int *pb);
RATIOHANDLE *ratio_loaduser(char *username, int section);
void ratio_uploadbytes(RATIOHANDLE *rh, int bytes);
int ratio_downloadbytes(RATIOHANDLE *rh, int bytes);
void ratio_uploadfile(RATIOHANDLE *rh);
int ratio_downloadfile(RATIOHANDLE *rh);
void ratio_reread(RATIOHANDLE *rh);
void ratio_stat(FTPSTATE *peer, RATIOHANDLE *rh, char *replystr);
void ratio_settokens(RATIOHANDLE *rh, TOKENSET *ts);
void ratio_finish(RATIOHANDLE *rh);


