15b5cadc1f47abb5d280d9bf9bb55e8542202764
[mmondor.git] / mmsoftware / mmftpd / src / mmftpd.h
1 /* $Id: mmftpd.h,v 1.32 2008/03/11 17:09:55 mmondor Exp $ */
2
3 /*
4 * Copyright (C) 2001-2008, Matthew Mondor
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.
21 * 5. Redistribution of source code may not be released under the terms of
22 * any GNU Public License derivate.
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>
48 #include <stdbool.h>
49 #include <stdint.h>
50 #include <pthread.h>
51
52 #include <mmfd.h>
53 #include <mmpath.h>
54 #include <mmserver.h>
55 #include <mmlist.h>
56 #include <mmpool.h>
57 #include <mmhash.h>
58 #include <mmfifo.h>
59 #include <mmstat.h>
60 #include <mmserver.h>
61
62 #include <mm_pthread_msg.h>
63 #include <mm_pthread_pool.h>
64 #include <mm_pthread_sleep.h>
65
66
67
68
69 /* DEFINITIONS */
70
71 #define DAEMON_NAME "mmftpd"
72 #define DAEMON_VERSION "0.3.0/mmondor"
73
74 /* Transfer buffer size */
75 #define T_BUFSIZE 16384
76 /* fdb buffering size */
77 #define FDB_BUFSIZE 8192
78
79 /* Configuration file columns */
80 enum 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 };
98
99 enum transferthread_states {
100 TTSTATE_DONE = 0,
101 TTSTATE_INITIAL,
102 TTSTATE_CONNECT,
103 TTSTATE_TRANSFER
104 };
105
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 */
134 #define ASYNC_CHECKPW 1
135 #define ASYNC_TREESIZE 2
136 #define ASYNC_GETUSERLINE 3
137
138 /* Error registration macro */
139 #define REGISTER_ERROR() do { \
140 clenv->errors++; \
141 if (CONF.DELAY_ON_ERROR) \
142 pthread_sleep(clenv->errors); \
143 } while (FALSE)
144
145 #define REGISTER_PERMISSION() do { \
146 if (CONF.STATFAIL_PERMISSION) \
147 mmstat(&clenv->pstat, STAT_UPDATE, 1, \
148 "mmftpd|failed|permission|%s|%s", \
149 clenv->user, clenv->c_ipaddr); \
150 } while (FALSE)
151
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)
158
159
160
161 /* STRUCTURES */
162
163 /* We store config file read results in this structure */
164 typedef 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],
167 WELCOME_FILE[256], MOTD_FILE[256], DISPLAY_FILE[64], PASV_REMAP[1024];
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,
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;
175 } CONFIG;
176
177 /* We communicate with our transfer thread using this message structure */
178 typedef struct transfermsg {
179 pthread_msg_t msg; /* Internal message node */
180 int request; /* Request to send to device */
181 bool result; /* Result status after device request */
182 uint16_t port; /* PORT or PASV port for next transfer */
183 int file; /* File descriptor to read/write from/to */
184 int rrate, wrate; /* Transfer dl/ul rate */
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 */
197 typedef struct clientenv {
198 pnode_t node;
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 */
207 char *advaddr_l, *advaddr_s; /* Ptrs to IP addr for LPASV/PSV replies */
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 */
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 */
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 */
225 off_t rest; /* Restore at byte offset */
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 */
235 fifo64_t visited; /* FIFO buffer of visited dirs hashes */
236 struct server_sockaddr uipaddr; /* Used for bind() on passive ports */
237 struct server_sockaddr *cipaddr; /* Client's IP address */
238 struct fifonode *fifobuf; /* Internal buffer for visited */
239 struct iface *iface; /* To obtain our server hostname */
240 struct async_clenv *aclenv; /* Thread context for async_call() support */
241 mmstat_t vstat, pstat; /* Handles for mmstat */
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 */
248 typedef struct lusernode {
249 hashnode_t node;
250 char user[32]; /* User name (key) */
251 pthread_mutex_t lock; /* For treesize_edit() */
252 long logins; /* Simultanious current logins for user */
253 off_t homesize; /* Current home directory size for user */
254 } lusernode;
255
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 */
260 typedef 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
267 /* This serves for fast command lookup */
268 struct commandnode {
269 hashnode_t node;
270 uint32_t hash;
271 int index;
272 struct command *command;
273 };
274
275 /* Used for mmfd thread support delegation/abstraction */
276 struct mutexnode {
277 pnode_t node;
278 pthread_mutex_t mutex;
279 };
280
281 /* Used to efficiently allocate FIFO buffers for recently visited directories
282 */
283 struct fifonode {
284 pnode_t node;
285 uint64_t buf[1];
286 /* Will be expanded here */
287 };
288
289 /* This defines a state */
290 typedef 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 */
297 typedef struct command {
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() */
305 struct tr_messages {
306 int code;
307 char *msg;
308 };
309
310 /* Used by our asynchoneous functions */
311 struct async_checkpw_msg {
312 struct async_msg msg;
313 union {
314 struct {
315 bool matching;
316 } res;
317 struct {
318 char hash[48];
319 char passwd[256];
320 } args;
321 } un;
322 };
323
324 struct 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
337 struct 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
350 struct pasv_remap {
351 const char *pattern;
352 char *advertize_l, *advertize_s;
353 struct server_sockaddr bind;
354 };
355
356
357
358 /* PROTOTYPES */
359
360 /* State functions */
361 static int all_quit(clientenv *);
362 static int all_help(clientenv *);
363 static int all_noop(clientenv *);
364 static int all_beer(clientenv *);
365 static int all_user(clientenv *);
366 static int all_pass(clientenv *);
367 static int all_syst(clientenv *);
368 static int auth_user(clientenv *);
369 static int auth_pass(clientenv *);
370 static int main_cwd(clientenv *);
371 static int main_cdup(clientenv *);
372 static int main_port(clientenv *);
373 static int main_lprt(clientenv *);
374 static int main_eprt(clientenv *);
375 static int main_pasv(clientenv *);
376 static int main_lpsv(clientenv *);
377 static int main_epsv(clientenv *);
378 static int main_type(clientenv *);
379 static int main_stru(clientenv *);
380 static int main_mode(clientenv *);
381 static int main_retr(clientenv *);
382 static int main_stor(clientenv *);
383 static int main_stou(clientenv *);
384 static int main_appe(clientenv *);
385 static int main_allo(clientenv *);
386 static int main_rest(clientenv *);
387 static int main_rnfr(clientenv *);
388 static int main_rnto(clientenv *);
389 static int main_abor(clientenv *);
390 static int main_dele(clientenv *);
391 static int main_rmd(clientenv *);
392 static int main_mkd(clientenv *);
393 static int main_mdtm(clientenv *);
394 static int main_pwd(clientenv *);
395 static int main_list(clientenv *);
396 static int main_nlst(clientenv *);
397 static int main_site(clientenv *);
398 static int main_size(clientenv *);
399 static int main_stat(clientenv *);
400
401 int main(int, char **);
402
403 static bool hash_commands(struct command *, size_t);
404 static uint32_t commandnode_keyhash(const void *, size_t);
405 static int commandnode_keycmp(const void *, const void *, size_t);
406 static bool reply(fdbuf *, int, bool, char *, ...);
407 static int readconfline(char *, fdbuf *, int, int, char **);
408 static void stripoptions(char *);
409 static off_t recursive_treesize(char *, off_t);
410 static bool treesize_edit(clientenv *, off_t);
411 static bool checkuser(clientenv *, const char *);
412
413 static clientenv *alloc_clientenv(void);
414 static clientenv *free_clientenv(clientenv *);
415 static bool start_transfer_thread(clientenv *);
416 static void stop_transfer_thread(clientenv *);
417 static bool transfer_request(int, bool, clientenv *);
418 static bool file_out(fdbuf *, char *);
419 static bool directory_message(clientenv *, int);
420 static int best_match(const char *, const char *);
421 static ssize_t foobar_address(char *, size_t, char **,
422 struct server_sockaddr *);
423 static bool pasv_remap_parse(void);
424 static bool pasv_remap(struct server_sockaddr *, char **, char **,
425 const char *);
426
427 static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
428 struct async_clenv *, void *);
429
430 static bool pasv_bind(clientenv *, struct server_sockaddr *, int *, int *);
431 static void transferthread(pthread_object_t *, void *, void *);
432 static void transferthread_main(clientenv *, fdbuf *);
433
434 static void thread_init(void);
435 static void *thread_mutex_create(void);
436 static void *thread_mutex_destroy(void *);
437 static void thread_mutex_lock(void *);
438 static void thread_mutex_unlock(void *);
439 static bool thread_eintr(void);
440
441 static void async_checkpw(struct async_msg *);
442 static void async_treesize(struct async_msg *);
443 static void async_getuserline(struct async_msg *);
444 static bool checkpw(clientenv *, const char *, const char *);
445 static off_t treesize(clientenv *, const char *, off_t);
446 static bool getuserline(clientenv *, char **, char **, const char *);
447
448
449
450
451 #endif