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