-/* $Id: mmftpd.h,v 1.2 2002/12/12 20:54:21 mmondor Exp $ */
+/* $Id: mmftpd.h,v 1.21 2003/10/23 01:01:22 mmondor Exp $ */
/*
- * Copyright (C) 2000-2002, Matthew Mondor
+ * Copyright (C) 2000-2003, Matthew Mondor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <mmfd.h>
#include <mmpath.h>
#include <mmserver.h>
+#include <mmlist.h>
+#include <mmpool.h>
+#include <mmhash.h>
#include <mmfifo.h>
#include <mmstat.h>
#include <mmserver.h>
/* DEFINITIONS */
#define DAEMON_NAME "mmftpd"
-#define DAEMON_VERSION "0.0.15/mmondor"
+#define DAEMON_VERSION "0.0.18/mmondor"
/* Transfer buffer size */
#define T_BUFSIZE 16384
#define FDB_BUFSIZE 8192
/* Configuration file columns */
-#define CONF_USER 0
-#define CONF_GROUP 1
-#define CONF_PASS 2
-#define CONF_STATS 3
-#define CONF_CHKOWN 4
-#define CONF_UPLOAD 5
-#define CONF_MODIFY 6
-#define CONF_MUMASK 7
-#define CONF_UMASK 8
-#define CONF_MAXLOGINS 9
-#define CONF_MAXHOMESIZE 10
-#define CONF_MINFILESIZE 11
-#define CONF_BW_IN 12
-#define CONF_BW_OUT 13
-#define CONF_HOME 14
+enum columns {
+ CONF_USER = 0,
+ CONF_GROUP,
+ CONF_PASS,
+ CONF_STATS,
+ CONF_CHKOWN,
+ CONF_UPLOAD,
+ CONF_MODIFY,
+ CONF_MUMASK,
+ CONF_UMASK,
+ CONF_MAXLOGINS,
+ CONF_MAXHOMESIZE,
+ CONF_MINFILESIZE,
+ CONF_BW_IN,
+ CONF_BW_OUT,
+ CONF_HOME,
+ CONF_COLUMNS
+};
/* Negative states are used by the state swapper, others are real states */
#define STATE_ERROR -3
#define TR_LOST -4
/* Our true asynchroneous functions */
-#define ASYNC_HASHPW 1
+#define ASYNC_CHECKPW 1
#define ASYNC_TREESIZE 2
+#define ASYNC_GETUSERLINE 3
/* Error registration macro */
-#define REGISTER_ERROR(x) do { \
- (x)->errors++; \
+#define REGISTER_ERROR() do { \
+ clenv->errors++; \
if (CONF.DELAY_ON_ERROR) \
- pth_sleep((x)->errors); \
-} while(0)
+ pth_sleep(clenv->errors); \
+} while (FALSE)
+
+#define REGISTER_PERMISSION() do { \
+ if (CONF.STATFAIL_PERMISSION) \
+ mmstat(&clenv->pstat, STAT_UPDATE, 1, \
+ "mmftpd|failed|permission|%s|%s", \
+ clenv->user, clenv->c_ipaddr); \
+} while (FALSE)
+#define REGISTER_PORT() do { \
+ if (CONF.STATFAIL_PORT) \
+ mmstat(&clenv->pstat, STAT_UPDATE, 1, \
+ "mmftpd|failed|port|%s|%s", \
+ clenv->user, clenv->c_ipaddr); \
+} while (FALSE)
long ALLOC_BUFFERS, LOG_LEVEL, LISTEN_PORT, MAX_ERRORS, MAX_IPS,
MAX_PER_IP, CONNECTION_RATE, CONNECTION_PERIOD, CONTROL_TIMEOUT,
DATA_TIMEOUT, BANDWIDTH_IN, BANDWIDTH_OUT, GBANDWIDTH_IN,
- GBANDWIDTH_OUT, REMEMBER_CWDS, ASYNC_PROCESSES;
- bool RESOLVE_HOSTS, DELAY_ON_ERROR;
+ GBANDWIDTH_OUT, REMEMBER_CWDS, ASYNC_PROCESSES, PASV_RANGE_MIN,
+ PASV_RANGE_MAX;
+ bool RESOLVE_HOSTS, DELAY_ON_ERROR, PASV_RANGE, STATFAIL_LOGIN,
+ STATFAIL_PASSWORD, STATFAIL_PERMISSION, STATFAIL_PORT;
} CONFIG;
/* We communicate with our transfer thread using this message structure */
* functions of all states
*/
typedef struct clientenv {
- node nod;
+ pnode_t node;
unsigned long id; /* Our unique connection ID */
int timeout; /* Control connection timeout in ms */
int gid; /* Group set to new files */
bool stats; /* If download counters are wanted */
bool checkowner; /* If we should check for file ownership */
unsigned char type; /* Current transfer TYPE */
- fifo64 *visited; /* FIFO buffer of visited dirs hashes */
+ fifo64_t visited; /* FIFO buffer of visited dirs hashes */
u_int32_t uipaddr; /* Used for bind() on passive ports */
+ struct fifonode *fifobuf; /* Internal buffer for visited */
struct iface *iface; /* To obtain our server hostname */
struct async_clenv *aclenv; /* Thread context for async_call() support */
- MMSTAT vstat, pstat; /* Handles for mmstat */
+ mmstat_t vstat, pstat; /* Handles for mmstat */
} clientenv;
/* This structure is shared by simultanious logins of a same user. It thus
* to share a common current home directory size value.
*/
typedef struct lusernode {
- node nod;
- u_int64_t hash; /* User name hash */
- pth_mutex_t lock; /* For treesize_edit() */
- long logins; /* Simultanious current logins for user */
- off_t homesize; /* Current home directory size for user */
+ hashnode_t node;
+ char user[32]; /* User name (key) */
+ pth_mutex_t lock; /* For treesize_edit() */
+ long logins; /* Simultanious current logins for user */
+ off_t homesize; /* Current home directory size for user */
} lusernode;
+/* This structure is used for a longer term cache of user home directory
+ * sizes so that we can revert to recursive traversal only when strictly
+ * necessary.
+ */
+typedef struct quotanode {
+ hashnode_t node;
+ char dir[256]; /* Directory name (key) */
+ off_t homesize; /* Size in bytes */
+ time_t updated; /* Last cache update */
+} quotanode;
+
+/* This serves for fast command lookup */
+struct commandnode {
+ hashnode_t node;
+ u_int32_t hash;
+ int index;
+ struct command *command;
+};
+
+/* Used for mmfd thread support delegation/abstraction */
+struct mutexnode {
+ pnode_t node;
+ pth_mutex_t mutex;
+};
+
+/* Used to efficiently allocate FIFO buffers for recently visited directories
+*/
+struct fifonode {
+ pnode_t node;
+ u_int64_t buf[1];
+ /* Will be expanded here */
+};
+
/* This defines a state */
typedef struct state {
int (**functions)(clientenv *); /* array of commands for state */
/* A command of a state */
typedef struct command {
- int32_t hash; /* Used for fast comparision lookup */
int loglevel; /* Log level required to log this command */
char *name; /* Command name string */
char *args; /* Used for HELP, arguments of command */
};
/* Used by our asynchoneous functions */
-struct async_hashpw_msg {
+struct async_checkpw_msg {
struct async_msg msg;
union {
struct {
- char hash[33];
+ bool matching;
} res;
struct {
+ char hash[48];
char passwd[256];
} args;
} un;
} un;
};
+struct async_getuserline_msg {
+ struct async_msg msg;
+ union {
+ struct {
+ int cols[CONF_COLUMNS + 1];
+ char line[256];
+ } res;
+ struct {
+ char username[32];
+ } args;
+ } un;
+};
+
int main(int, char **);
-static void packcommands(struct command *, size_t);
+static bool hash_commands(struct command *, size_t);
+static u_int32_t commandnode_keyhash(const void *, size_t);
+static int commandnode_keycmp(const void *, const void *, size_t);
static bool reply(fdbuf *, int, bool, char *, ...);
static int readconfline(char *, fdbuf *, int, int, char **);
static void stripoptions(char *);
static off_t recursive_treesize(char *, off_t);
static bool treesize_edit(clientenv *, off_t);
-static bool checkuser(char *, clientenv *);
+static bool checkuser(clientenv *, const char *);
static clientenv *alloc_clientenv(void);
static clientenv *free_clientenv(clientenv *);
static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
struct async_clenv *);
+static bool pasv_bind(clientenv *, struct sockaddr_in *, int *, int *);
static void transferthread(void *);
static void transferthread_main(clientenv *, fdbuf *);
-static void async_hashpw(struct async_msg *);
+static void *_pth_mutex_create(void);
+static void *_pth_mutex_destroy(void *);
+static void _pth_mutex_lock(void *);
+static void _pth_mutex_unlock(void *);
+static void _pth_thread_yield(void);
+static bool _pth_eintr(void);
+static bool eintr(void);
+
+static void async_checkpw(struct async_msg *);
static void async_treesize(struct async_msg *);
-static bool hashpw(clientenv *, char *, const char *);
+static void async_getuserline(struct async_msg *);
+static bool checkpw(clientenv *, const char *, const char *);
static off_t treesize(clientenv *, const char *, off_t);
+static bool getuserline(clientenv *, char **, char **, const char *);