Revision bump
[mmondor.git] / mmsoftware / mmftpd / src / mmftpd.h
CommitLineData
1099fea4 1/* $Id: mmftpd.h,v 1.33 2009/01/17 03:48:20 mmondor Exp $ */
47071c2b
MM
2
3/*
5e164ff5 4 * Copyright (C) 2001-2008, Matthew Mondor
47071c2b
MM
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software written by Matthew Mondor.
18 * 4. The name of Matthew Mondor may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
5e164ff5
MM
21 * 5. Redistribution of source code may not be released under the terms of
22 * any GNU Public License derivate.
47071c2b
MM
23 *
24 * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36
37
38
39#ifndef MMFTPD_H
40#define MMFTPD_H
41
42
43
44
45/* HEADERS */
46
47#include <sys/types.h>
b232bd02
MM
48#include <stdbool.h>
49#include <stdint.h>
3dd832e3 50#include <pthread.h>
47071c2b
MM
51
52#include <mmfd.h>
53#include <mmpath.h>
54#include <mmserver.h>
7a56f31f
MM
55#include <mmlist.h>
56#include <mmpool.h>
904cd663 57#include <mmhash.h>
47071c2b
MM
58#include <mmfifo.h>
59#include <mmstat.h>
60#include <mmserver.h>
3dd832e3
MM
61
62#include <mm_pthread_msg.h>
63#include <mm_pthread_pool.h>
64#include <mm_pthread_sleep.h>
47071c2b
MM
65
66
67
68
69/* DEFINITIONS */
70
71#define DAEMON_NAME "mmftpd"
1099fea4 72#define DAEMON_VERSION "0.3.1/mmondor"
47071c2b
MM
73
74/* Transfer buffer size */
75#define T_BUFSIZE 16384
76/* fdb buffering size */
77#define FDB_BUFSIZE 8192
78
79/* Configuration file columns */
f36e2a66
MM
80enum columns {
81 CONF_USER = 0,
82 CONF_GROUP,
83 CONF_PASS,
84 CONF_STATS,
85 CONF_CHKOWN,
86 CONF_UPLOAD,
87 CONF_MODIFY,
88 CONF_MUMASK,
89 CONF_UMASK,
90 CONF_MAXLOGINS,
91 CONF_MAXHOMESIZE,
92 CONF_MINFILESIZE,
93 CONF_BW_IN,
94 CONF_BW_OUT,
95 CONF_HOME,
96 CONF_COLUMNS
97};
47071c2b 98
aa348c3f
MM
99enum transferthread_states {
100 TTSTATE_DONE = 0,
101 TTSTATE_INITIAL,
102 TTSTATE_CONNECT,
103 TTSTATE_TRANSFER
104};
105
47071c2b
MM
106/* Negative states are used by the state swapper, others are real states */
107#define STATE_ERROR -3
108#define STATE_END -2
109#define STATE_CURRENT -1
110#define STATE_AUTH 0
111#define STATE_MAIN 1
112
113/* Transfer types */
114#define TYPE_ASCII 1
115#define TYPE_IMAGE 2
116#define TYPE_LOCAL 3
117
118/* Transfer requests */
119#define REQ_NONE 0
120#define REQ_STATUS 1
121#define REQ_NEWPORT 2
122#define REQ_TRANSFER 3
123#define REQ_ABORT 4
124#define REQ_QUIT 5
125
126/* Transfer end reason */
127#define TR_OK 0
128#define TR_ABORTED -1
129#define TR_TIMEOUT -2
130#define TR_QUOTA -3
131#define TR_LOST -4
132
133/* Our true asynchroneous functions */
49769af2 134#define ASYNC_CHECKPW 1
47071c2b 135#define ASYNC_TREESIZE 2
5eb34fba 136#define ASYNC_GETUSERLINE 3
47071c2b 137
e334174e 138/* Error registration macro */
207ef3e2
MM
139#define REGISTER_ERROR() do { \
140 clenv->errors++; \
e334174e 141 if (CONF.DELAY_ON_ERROR) \
3dd832e3 142 pthread_sleep(clenv->errors); \
5155a339 143} while (FALSE)
49769af2 144
6b7f35e7
MM
145#define REGISTER_PERMISSION() do { \
146 if (CONF.STATFAIL_PERMISSION) \
147 mmstat(&clenv->pstat, STAT_UPDATE, 1, \
207ef3e2 148 "mmftpd|failed|permission|%s|%s", \
6b7f35e7
MM
149 clenv->user, clenv->c_ipaddr); \
150} while (FALSE)
151
207ef3e2
MM
152#define REGISTER_PORT() do { \
153 if (CONF.STATFAIL_PORT) \
154 mmstat(&clenv->pstat, STAT_UPDATE, 1, \
155 "mmftpd|failed|port|%s|%s", \
156 clenv->user, clenv->c_ipaddr); \
157} while (FALSE)
47071c2b
MM
158
159
160
161/* STRUCTURES */
162
163/* We store config file read results in this structure */
164typedef struct config {
165 char CHROOT_DIR[256], PASSWD_FILE[256], PID_PATH[256], USER[32],
166 GROUPS[256], LOG_FACILITY[32], SERVER_NAMES[1024], LISTEN_IPS[1024],
aa348c3f 167 WELCOME_FILE[256], MOTD_FILE[256], DISPLAY_FILE[64], PASV_REMAP[1024];
47071c2b
MM
168 long ALLOC_BUFFERS, LOG_LEVEL, LISTEN_PORT, MAX_ERRORS, MAX_IPS,
169 MAX_PER_IP, CONNECTION_RATE, CONNECTION_PERIOD, CONTROL_TIMEOUT,
170 DATA_TIMEOUT, BANDWIDTH_IN, BANDWIDTH_OUT, GBANDWIDTH_IN,
50c5968e
MM
171 GBANDWIDTH_OUT, REMEMBER_CWDS, ASYNC_PROCESSES, PASV_RANGE_MIN,
172 PASV_RANGE_MAX;
173 bool RESOLVE_HOSTS, DELAY_ON_ERROR, PASV_RANGE, STATFAIL_LOGIN,
174 STATFAIL_PASSWORD, STATFAIL_PERMISSION, STATFAIL_PORT;
47071c2b
MM
175} CONFIG;
176
177/* We communicate with our transfer thread using this message structure */
178typedef struct transfermsg {
3dd832e3 179 pthread_msg_t msg; /* Internal message node */
47071c2b
MM
180 int request; /* Request to send to device */
181 bool result; /* Result status after device request */
b232bd02 182 uint16_t port; /* PORT or PASV port for next transfer */
47071c2b
MM
183 int file; /* File descriptor to read/write from/to */
184 int rrate, wrate; /* Transfer dl/ul rate */
47071c2b
MM
185 char *path; /* Path to be passed to ls() if list=TRUE */
186 bool passive; /* Either next xfer is PORT or PASV mode */
187 bool ongoing; /* TRUE when a transfer is in progress */
188 bool download; /* TRUE if transfer direction is to user */
189 char list; /* 0=File xfer, 1=LIST, 2=NLST, 3=empty */
190 int64_t rbytes, wbytes; /* Number of bytes transfered */
191 int64_t dlfiles, ulfiles; /* Number of files transfered */
192} transfermsg;
193
194/* This structure holds the current environment for a user, shared among all
195 * functions of all states
196 */
197typedef struct clientenv {
7a56f31f 198 pnode_t node;
47071c2b
MM
199 unsigned long id; /* Our unique connection ID */
200 int timeout; /* Control connection timeout in ms */
201 int gid; /* Group set to new files */
202 int bw_in, bw_out; /* Maximum dl/up bandwidth in KB/s */
203 fdbuf *fdb; /* Buffered handle to fd */
204 char *buffer; /* Our command line buffer */
205 char *c_hostname; /* Pointer to client's hostname */
206 char *c_ipaddr; /* Pointer to client's IP address string */
5e164ff5 207 char *advaddr_l, *advaddr_s; /* Ptrs to IP addr for LPASV/PSV replies */
47071c2b
MM
208 char *user; /* Username of logged user */
209 char *tuser; /* Temporary username used by state_auth() */
210 char *passwd; /* Temporary, used by auth code */
211 char *home; /* User's real home directory path */
212 char *group; /* Text representation of gid */
213 char *rnfr; /* Used for RNFR/RNTO */
214 struct lusernode *unode; /* User's lusernode, for quick lookup */
215 char cwd[MMPATH_MAX]; /* User's current directory (chrooted) */
216 struct transfermsg tmsg; /* Only need one shared msg with tthread */
3dd832e3
MM
217 pthread_port_t rport, sport; /* Message ports (tthread and ours) */
218 pthread_ring_t rring; /* Ring of events we wait for */
219 pthread_t tthread; /* Thread ID of our transfer thread */
47071c2b
MM
220 long errors; /* Total number of errors that occured */
221 long attempts; /* Auth state temporary counter */
222 long maxlogins; /* Allowed simultanious logins for user */
223 off_t maxhomesize; /* Maximum home directory size (or -1) */
224 off_t minfilesize; /* If limits used, minimum file size */
1cb1c4b8 225 off_t rest; /* Restore at byte offset */
47071c2b
MM
226 mode_t umask; /* Current umask */
227 bool anonymous; /* TRUE if anonymous login acount */
228 bool login; /* TRUE if user currently logged in */
229 bool upload; /* Right to upload */
230 bool modify; /* Right to modify */
231 bool mumask; /* Right to change umask */
232 bool stats; /* If download counters are wanted */
233 bool checkowner; /* If we should check for file ownership */
234 unsigned char type; /* Current transfer TYPE */
4f87c15b 235 fifo64_t visited; /* FIFO buffer of visited dirs hashes */
5e164ff5
MM
236 struct server_sockaddr uipaddr; /* Used for bind() on passive ports */
237 struct server_sockaddr *cipaddr; /* Client's IP address */
4f87c15b 238 struct fifonode *fifobuf; /* Internal buffer for visited */
47071c2b
MM
239 struct iface *iface; /* To obtain our server hostname */
240 struct async_clenv *aclenv; /* Thread context for async_call() support */
4fd4b499 241 mmstat_t vstat, pstat; /* Handles for mmstat */
47071c2b
MM
242} clientenv;
243
244/* This structure is shared by simultanious logins of a same user. It thus
245 * allows to control how many connections of the same user are allowed, and
246 * to share a common current home directory size value.
247 */
248typedef struct lusernode {
904cd663
MM
249 hashnode_t node;
250 char user[32]; /* User name (key) */
3dd832e3 251 pthread_mutex_t lock; /* For treesize_edit() */
904cd663
MM
252 long logins; /* Simultanious current logins for user */
253 off_t homesize; /* Current home directory size for user */
47071c2b
MM
254} lusernode;
255
2f902c52
MM
256/* This structure is used for a longer term cache of user home directory
257 * sizes so that we can revert to recursive traversal only when strictly
258 * necessary.
259 */
260typedef struct quotanode {
261 hashnode_t node;
262 char dir[256]; /* Directory name (key) */
263 off_t homesize; /* Size in bytes */
264 time_t updated; /* Last cache update */
265} quotanode;
266
aa27679a
MM
267/* This serves for fast command lookup */
268struct commandnode {
269 hashnode_t node;
b232bd02 270 uint32_t hash;
aa27679a
MM
271 int index;
272 struct command *command;
273};
274
5eb34fba
MM
275/* Used for mmfd thread support delegation/abstraction */
276struct mutexnode {
7a56f31f 277 pnode_t node;
3dd832e3 278 pthread_mutex_t mutex;
5eb34fba
MM
279};
280
da634739
MM
281/* Used to efficiently allocate FIFO buffers for recently visited directories
282*/
4f87c15b 283struct fifonode {
7a56f31f 284 pnode_t node;
b232bd02 285 uint64_t buf[1];
7a56f31f 286 /* Will be expanded here */
4f87c15b
MM
287};
288
47071c2b
MM
289/* This defines a state */
290typedef struct state {
291 int (**functions)(clientenv *); /* array of commands for state */
292 int errcode; /* Code to reply if a command is NULL */
293 char *errtext; /* Text to reply if a command is NULL */
294} state;
295
296/* A command of a state */
297typedef struct command {
47071c2b
MM
298 int loglevel; /* Log level required to log this command */
299 char *name; /* Command name string */
300 char *args; /* Used for HELP, arguments of command */
301 char *desc; /* Used for HELP, command description */
302} command;
303
304/* Used to hold index mapping TR_* reasons to information for reply() */
305struct tr_messages {
306 int code;
307 char *msg;
308};
309
310/* Used by our asynchoneous functions */
49769af2 311struct async_checkpw_msg {
47071c2b
MM
312 struct async_msg msg;
313 union {
314 struct {
49769af2 315 bool matching;
47071c2b
MM
316 } res;
317 struct {
49769af2 318 char hash[48];
47071c2b
MM
319 char passwd[256];
320 } args;
c8a3d485 321 } un;
47071c2b
MM
322};
323
324struct async_treesize_msg {
325 struct async_msg msg;
326 union {
327 struct {
328 off_t size;
329 } res;
330 struct {
331 char path[256];
332 off_t min;
333 } args;
334 } un;
335};
336
5eb34fba
MM
337struct async_getuserline_msg {
338 struct async_msg msg;
339 union {
340 struct {
341 int cols[CONF_COLUMNS + 1];
342 char line[256];
343 } res;
344 struct {
345 char username[32];
346 } args;
347 } un;
348};
349
aa348c3f
MM
350struct pasv_remap {
351 const char *pattern;
5e164ff5
MM
352 char *advertize_l, *advertize_s;
353 struct server_sockaddr bind;
aa348c3f 354};
47071c2b
MM
355
356
357
358/* PROTOTYPES */
359
360/* State functions */
361static int all_quit(clientenv *);
362static int all_help(clientenv *);
363static int all_noop(clientenv *);
364static int all_beer(clientenv *);
365static int all_user(clientenv *);
366static int all_pass(clientenv *);
367static int all_syst(clientenv *);
368static int auth_user(clientenv *);
369static int auth_pass(clientenv *);
370static int main_cwd(clientenv *);
371static int main_cdup(clientenv *);
372static int main_port(clientenv *);
373static int main_lprt(clientenv *);
374static int main_eprt(clientenv *);
375static int main_pasv(clientenv *);
376static int main_lpsv(clientenv *);
377static int main_epsv(clientenv *);
378static int main_type(clientenv *);
379static int main_stru(clientenv *);
380static int main_mode(clientenv *);
381static int main_retr(clientenv *);
382static int main_stor(clientenv *);
383static int main_stou(clientenv *);
384static int main_appe(clientenv *);
385static int main_allo(clientenv *);
1cb1c4b8 386static int main_rest(clientenv *);
47071c2b
MM
387static int main_rnfr(clientenv *);
388static int main_rnto(clientenv *);
389static int main_abor(clientenv *);
390static int main_dele(clientenv *);
391static int main_rmd(clientenv *);
392static int main_mkd(clientenv *);
393static int main_mdtm(clientenv *);
394static int main_pwd(clientenv *);
395static int main_list(clientenv *);
396static int main_nlst(clientenv *);
397static int main_site(clientenv *);
398static int main_size(clientenv *);
399static int main_stat(clientenv *);
400
401int main(int, char **);
402
aa27679a 403static bool hash_commands(struct command *, size_t);
b232bd02 404static uint32_t commandnode_keyhash(const void *, size_t);
aa27679a 405static int commandnode_keycmp(const void *, const void *, size_t);
47071c2b
MM
406static bool reply(fdbuf *, int, bool, char *, ...);
407static int readconfline(char *, fdbuf *, int, int, char **);
408static void stripoptions(char *);
409static off_t recursive_treesize(char *, off_t);
410static bool treesize_edit(clientenv *, off_t);
5eb34fba 411static bool checkuser(clientenv *, const char *);
47071c2b
MM
412
413static clientenv *alloc_clientenv(void);
414static clientenv *free_clientenv(clientenv *);
415static bool start_transfer_thread(clientenv *);
416static void stop_transfer_thread(clientenv *);
417static bool transfer_request(int, bool, clientenv *);
418static bool file_out(fdbuf *, char *);
419static bool directory_message(clientenv *, int);
aa348c3f 420static int best_match(const char *, const char *);
5e164ff5
MM
421static ssize_t foobar_address(char *, size_t, char **,
422 struct server_sockaddr *);
aa348c3f 423static bool pasv_remap_parse(void);
5e164ff5
MM
424static bool pasv_remap(struct server_sockaddr *, char **, char **,
425 const char *);
47071c2b
MM
426
427static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
df3412ed 428 struct async_clenv *, void *);
47071c2b 429
5e164ff5 430static bool pasv_bind(clientenv *, struct server_sockaddr *, int *, int *);
df3412ed 431static void transferthread(pthread_object_t *, void *, void *);
47071c2b
MM
432static void transferthread_main(clientenv *, fdbuf *);
433
3dd832e3
MM
434static void thread_init(void);
435static void *thread_mutex_create(void);
436static void *thread_mutex_destroy(void *);
437static void thread_mutex_lock(void *);
438static void thread_mutex_unlock(void *);
439static bool thread_eintr(void);
5eb34fba 440
49769af2 441static void async_checkpw(struct async_msg *);
47071c2b 442static void async_treesize(struct async_msg *);
5eb34fba 443static void async_getuserline(struct async_msg *);
49769af2 444static bool checkpw(clientenv *, const char *, const char *);
47071c2b 445static off_t treesize(clientenv *, const char *, off_t);
5eb34fba 446static bool getuserline(clientenv *, char **, char **, const char *);
47071c2b
MM
447
448
449
450
451#endif