17750baabc986a1dfcf4e2e1fa7ce342204e17fe
[mmondor.git] / mmsoftware / mmftpd / src / mmftpd.h
1 /* $Id: mmftpd.h,v 1.20 2003/10/11 09:46:01 mmondor Exp $ */
2
3 /*
4 * Copyright (C) 2000-2003, 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 *
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>
51 #include <mmlist.h>
52 #include <mmpool.h>
53 #include <mmhash.h>
54 #include <mmfifo.h>
55 #include <mmstat.h>
56 #include <mmserver.h>
57
58
59
60
61 /* DEFINITIONS */
62
63 #define DAEMON_NAME "mmftpd"
64 #define DAEMON_VERSION "0.0.18/mmondor"
65
66 /* Transfer buffer size */
67 #define T_BUFSIZE 16384
68 /* fdb buffering size */
69 #define FDB_BUFSIZE 8192
70
71 /* Configuration file columns */
72 enum 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 };
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 */
119 #define ASYNC_CHECKPW 1
120 #define ASYNC_TREESIZE 2
121 #define ASYNC_GETUSERLINE 3
122
123 /* Error registration macro */
124 #define REGISTER_ERROR() do { \
125 clenv->errors++; \
126 if (CONF.DELAY_ON_ERROR) \
127 pth_sleep(clenv->errors); \
128 } while (FALSE)
129
130 #define REGISTER_PERMISSION() do { \
131 if (CONF.STATFAIL_PERMISSION) \
132 mmstat(&clenv->pstat, STAT_UPDATE, 1, \
133 "mmftpd|failed|permission|%s|%s", \
134 clenv->user, clenv->c_ipaddr); \
135 } while (FALSE)
136
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)
143
144
145
146 /* STRUCTURES */
147
148 /* We store config file read results in this structure */
149 typedef 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,
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;
160 } CONFIG;
161
162 /* We communicate with our transfer thread using this message structure */
163 typedef 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 */
183 typedef struct clientenv {
184 pnode_t node;
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 */
221 fifo64_t visited; /* FIFO buffer of visited dirs hashes */
222 u_int32_t uipaddr; /* Used for bind() on passive ports */
223 struct fifonode *fifobuf; /* Internal buffer for visited */
224 struct iface *iface; /* To obtain our server hostname */
225 struct async_clenv *aclenv; /* Thread context for async_call() support */
226 mmstat_t vstat, pstat; /* Handles for mmstat */
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 */
233 typedef struct lusernode {
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 */
239 } lusernode;
240
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 */
245 typedef 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
252 /* This serves for fast command lookup */
253 struct commandnode {
254 hashnode_t node;
255 u_int32_t hash;
256 int index;
257 struct command *command;
258 };
259
260 /* Used for mmfd thread support delegation/abstraction */
261 struct mutexnode {
262 pnode_t node;
263 pth_mutex_t mutex;
264 };
265
266 /* Used to efficiently allocate FIFO buffers */
267 struct fifonode {
268 pnode_t node;
269 u_int64_t buf[1];
270 /* Will be expanded here */
271 };
272
273 /* This defines a state */
274 typedef struct state {
275 int (**functions)(clientenv *); /* array of commands for state */
276 int errcode; /* Code to reply if a command is NULL */
277 char *errtext; /* Text to reply if a command is NULL */
278 } state;
279
280 /* A command of a state */
281 typedef struct command {
282 int loglevel; /* Log level required to log this command */
283 char *name; /* Command name string */
284 char *args; /* Used for HELP, arguments of command */
285 char *desc; /* Used for HELP, command description */
286 } command;
287
288 /* Used to hold index mapping TR_* reasons to information for reply() */
289 struct tr_messages {
290 int code;
291 char *msg;
292 };
293
294 /* Used by our asynchoneous functions */
295 struct async_checkpw_msg {
296 struct async_msg msg;
297 union {
298 struct {
299 bool matching;
300 } res;
301 struct {
302 char hash[48];
303 char passwd[256];
304 } args;
305 } un;
306 };
307
308 struct async_treesize_msg {
309 struct async_msg msg;
310 union {
311 struct {
312 off_t size;
313 } res;
314 struct {
315 char path[256];
316 off_t min;
317 } args;
318 } un;
319 };
320
321 struct async_getuserline_msg {
322 struct async_msg msg;
323 union {
324 struct {
325 int cols[CONF_COLUMNS + 1];
326 char line[256];
327 } res;
328 struct {
329 char username[32];
330 } args;
331 } un;
332 };
333
334
335
336
337 /* PROTOTYPES */
338
339 /* State functions */
340 static int all_quit(clientenv *);
341 static int all_help(clientenv *);
342 static int all_noop(clientenv *);
343 static int all_beer(clientenv *);
344 static int all_user(clientenv *);
345 static int all_pass(clientenv *);
346 static int all_syst(clientenv *);
347 static int auth_user(clientenv *);
348 static int auth_pass(clientenv *);
349 static int main_cwd(clientenv *);
350 static int main_cdup(clientenv *);
351 static int main_port(clientenv *);
352 static int main_lprt(clientenv *);
353 static int main_eprt(clientenv *);
354 static int main_pasv(clientenv *);
355 static int main_lpsv(clientenv *);
356 static int main_epsv(clientenv *);
357 static int main_type(clientenv *);
358 static int main_stru(clientenv *);
359 static int main_mode(clientenv *);
360 static int main_retr(clientenv *);
361 static int main_stor(clientenv *);
362 static int main_stou(clientenv *);
363 static int main_appe(clientenv *);
364 static int main_allo(clientenv *);
365 static int main_rest(clientenv *);
366 static int main_rnfr(clientenv *);
367 static int main_rnto(clientenv *);
368 static int main_abor(clientenv *);
369 static int main_dele(clientenv *);
370 static int main_rmd(clientenv *);
371 static int main_mkd(clientenv *);
372 static int main_mdtm(clientenv *);
373 static int main_pwd(clientenv *);
374 static int main_list(clientenv *);
375 static int main_nlst(clientenv *);
376 static int main_site(clientenv *);
377 static int main_size(clientenv *);
378 static int main_stat(clientenv *);
379
380 int main(int, char **);
381
382 static bool hash_commands(struct command *, size_t);
383 static u_int32_t commandnode_keyhash(const void *, size_t);
384 static int commandnode_keycmp(const void *, const void *, size_t);
385 static bool reply(fdbuf *, int, bool, char *, ...);
386 static int readconfline(char *, fdbuf *, int, int, char **);
387 static void stripoptions(char *);
388 static off_t recursive_treesize(char *, off_t);
389 static bool treesize_edit(clientenv *, off_t);
390 static bool checkuser(clientenv *, const char *);
391
392 static clientenv *alloc_clientenv(void);
393 static clientenv *free_clientenv(clientenv *);
394 static bool start_transfer_thread(clientenv *);
395 static void stop_transfer_thread(clientenv *);
396 static bool transfer_request(int, bool, clientenv *);
397 static bool file_out(fdbuf *, char *);
398 static bool directory_message(clientenv *, int);
399
400 static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
401 struct async_clenv *);
402
403 static bool pasv_bind(clientenv *, struct sockaddr_in *, int *, int *);
404 static void transferthread(void *);
405 static void transferthread_main(clientenv *, fdbuf *);
406
407 static void *_pth_mutex_create(void);
408 static void *_pth_mutex_destroy(void *);
409 static void _pth_mutex_lock(void *);
410 static void _pth_mutex_unlock(void *);
411 static void _pth_thread_yield(void);
412 static bool _pth_eintr(void);
413 static bool eintr(void);
414
415 static void async_checkpw(struct async_msg *);
416 static void async_treesize(struct async_msg *);
417 static void async_getuserline(struct async_msg *);
418 static bool checkpw(clientenv *, const char *, const char *);
419 static off_t treesize(clientenv *, const char *, off_t);
420 static bool getuserline(clientenv *, char **, char **, const char *);
421
422
423
424
425 #endif