Added support for IPv6; updated license and copyright
[mmondor.git] / mmsoftware / mmmail / src / mmsmtpd / mmsmtpd.h
1 /* $Id: mmsmtpd.h,v 1.46 2008/01/10 22:09:24 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 MMSMTPD_H
40 #define MMSMTPD_H
41
42
43
44
45 /* HEADERS */
46
47 #include <sys/types.h>
48 #include <stdbool.h>
49 #include <stdint.h>
50 #include <time.h>
51
52 #include <pthread.h>
53 #include <mm_pthread_sleep.h>
54
55 #include <mmtypes.h>
56 #include <mmlist.h>
57 #include <mmpool.h>
58 #include <mmhash.h>
59 #include <mmserver.h>
60 #include <mmfd.h>
61 #include <mmstat.h>
62 #include <mmlimitrate.h>
63
64 #include <libpq-fe.h>
65
66
67
68
69 /* DEFINITIONS */
70 #define DAEMON_NAME "mmsmtpd"
71 #define DAEMON_VERSION "mmmail-0.3.0/mmondor"
72
73 /* Negative states are used by the state swapper, others are real states */
74 #define STATE_ERROR -3
75 #define STATE_END -2
76 #define STATE_CURRENT -1
77 #define STATE_ALL 0
78
79 /* Invalid RCPT reason */
80 enum rcpt_reason {
81 RCPT_OK = 0,
82 RCPT_NOFROM,
83 RCPT_MANY,
84 RCPT_INVALID,
85 RCPT_UNKNOWN,
86 RCPT_RELAY,
87 RCPT_EXISTS,
88 RCPT_FULL,
89 RCPT_FLOOD,
90 RCPT_FILTER,
91 RCPT_ERROR,
92 RCPT_MAX
93 };
94
95 /* DATA errors */
96 enum data_reason {
97 DATA_SUBMIT = 0,
98 DATA_OK,
99 DATA_OVERFLOW,
100 DATA_HOPS,
101 DATA_INTERNAL,
102 DATA_MAX
103 };
104
105 /* Resolving flags for valid_host() */
106 #define HOST_NORES 0
107 #define HOST_RES 1
108 #define HOST_RES_MX 2
109
110 /* Custom fdbreadbuf() return result */
111 #define CFDBRB_HOPS -1
112
113 /* Asynchroneous functions we attach */
114 #define ASYNC_RESQUERY 1
115
116 /* Error registration macro */
117 #define REGISTER_ERROR(x) do { \
118 (x)->errors++; \
119 if (CONF.DELAY_ON_ERROR) \
120 pthread_sleep((x)->errors); \
121 } while (/* CONSTCOND */0)
122
123 /* Evaluates if a character is valid for addresses and hostnames */
124 #define VALID_ADDR_CHAR(c) \
125 (valid_addr_char_table[(int)((unsigned char)(c))] != 0)
126 #define VALID_HOST_CHAR(c) \
127 (valid_addr_host_table[(int)((unsigned char)(c))] != 0)
128
129
130
131 /* STRUCTURES */
132
133 /* We store config file read results in this structure */
134 typedef struct config {
135 char LOCK_PATH[256], CHROOT_DIR[256], PID_PATH[256], USER[32], GROUPS[256],
136 LOG_FACILITY[32], SERVER_NAMES[1024], LISTEN_IPS[1024], DB_INFO[1024],
137 MAIL_DIR[256], MMRELAYD_SOCKET_PATH[256];
138 long ALLOC_BUFFERS, LOG_LEVEL, LISTEN_PORT, MAX_ERRORS, MAX_IPS,
139 MAX_PER_IP, CONNECTION_RATE, CONNECTION_PERIOD, INPUT_TIMEOUT,
140 BANDWIDTH_IN, BANDWIDTH_OUT, GBANDWIDTH_IN, GBANDWIDTH_OUT, MAX_RCPTS,
141 MAX_DATA_LINES, MAX_DATA_SIZE, MAX_HOPS, FLOOD_MESSAGES,
142 FLOOD_EXPIRES, FLOOD_CACHE, ASYNC_PROCESSES;
143 bool RESOLVE_HOSTS, RESOLVE_HELO, RESOLVE_MX_MAIL, RESOLVE_MX_RCPT,
144 REQUIRE_HELO, FLOOD_PROTECTION, STATFAIL_HELO, STATFAIL_NOHELO,
145 STATFAIL_NOFROM, STATFAIL_ADDRESS, STATFAIL_RELAY, STATFAIL_FLOOD,
146 STATFAIL_FULL, STATFAIL_TIMEOUT, STATFAIL_EOF, STATFAIL_FILTER,
147 DELAY_ON_ERROR, RELAYING;
148 } CONFIG;
149
150
151 /* This consists of the state-shared clientenv structure */
152 typedef struct clientenv {
153 pnode_t node;
154 fdbuf *fdb; /* Buffered handler around our fd */
155 char *buffer; /* Buffer that points to last command line */
156 char *helo; /* Cached helo hostname */
157 char *from; /* Cached mail sender address */
158 char *c_hostname; /* Pointer to client's hostname */
159 char *c_ipaddr; /* Pointer to client's IP address string */
160 long mesg_size; /* Current cached message size in bytes */
161 long errors; /* Total number of errors that occured */
162 int timeout; /* Timeout in ms */
163 bool nofrom; /* If empty MAIL FROM from allowed server */
164 unsigned long id; /* Our connection ID */
165 unsigned long messages; /* Messages user sent us */
166 unsigned long rcpts; /* Number of RCPT accepted */
167 struct iface *iface; /* Current interface user connected through */
168 list_t rcpt; /* Cached recepients to send mail to */
169 struct async_clenv *aclenv; /* Thread context for async_call() */
170 mmstat_t vstat, pstat; /* Persistent mmstat(3) handles */
171 PGconn *pgconn; /* Persistent pgsql connection */
172 } clientenv;
173
174 /* Used for RCPT addresses */
175 typedef struct rcptnode {
176 pnode_t node;
177 char address[64], foraddress[64];
178 uint64_t hash;
179 bool relay; /* Non-local */
180 } rcptnode;
181
182 /* This structure is used to keep a cache of recent hosts from which mail was
183 * received, along with information on it to determine if the rate of messages
184 * is too high.
185 */
186 typedef struct hostnode {
187 hashnode_t node;
188 char host[128]; /* Hostname, key */
189 struct limitrate lr;
190 } hostnode;
191
192 struct hosts_expire_thread_iterator_udata {
193 time_t current, soonest;
194 };
195
196 /* Used for mmfd thread support delegation/abstraction */
197 struct mutexnode {
198 pnode_t node;
199 pthread_mutex_t mutex;
200 };
201
202 /* This defines a state */
203 typedef struct state {
204 int (**functions)(clientenv *);
205 int errcode;
206 char *errtext;
207 } state;
208
209 /* A command of a state */
210 typedef struct command {
211 int loglevel;
212 char *name, *args, *desc;
213 } command;
214
215 /* Information for a mailbox */
216 struct box_info {
217 long max_size, size, max_msgs, msgs;
218 bool filter, filter_type;
219 };
220
221 /* For fast command lookup */
222 struct commandnode {
223 hashnode_t node;
224 uint32_t hash;
225 struct command *command;
226 int index;
227 };
228
229 /* Used for fast index of result messages */
230 struct reply_messages {
231 int code;
232 char *msg;
233 };
234
235 /* Our validate_msg_line() context */
236 struct validate_udata
237 {
238 /* Used to count number of Received: lines */
239 long hops;
240 /* Headers we consider mandatory, which we'll add if necessary */
241 bool msgid, date, from, to, subject, inreply;
242 /* Still considering to read the header */
243 bool header;
244 /* Internal linking */
245 clientenv *clenv;
246 char *h_from, *h_to, *h_subject, *h_id, *h_reply;
247 };
248
249 /* Our union for async_resquery() */
250 struct async_resquery_msg {
251 struct async_msg msg;
252 union {
253 struct {
254 int res;
255 char answer[128];
256 } res;
257 struct {
258 int r_class, r_type;
259 char host[128];
260 } args;
261 } un;
262 };
263
264
265
266
267 /* PROTOTYPES */
268
269 int main(int, char **);
270
271 static int all_noop(clientenv *);
272 static int all_rset(clientenv *);
273 static int all_quit(clientenv *);
274 static int all_help(clientenv *);
275 static int all_helo(clientenv *);
276 static int all_mail(clientenv *);
277 static int all_rcpt(clientenv *);
278 static int all_data(clientenv *);
279 static int all_beer(clientenv *);
280
281 static bool hash_commands(struct command *, size_t);
282 static uint32_t commandnode_keyhash(const void *, size_t);
283 static int commandnode_keycmp(const void *, const void *, size_t);
284 static bool reply(fdbuf *, int, bool, const char *, ...);
285
286 static bool clientenv_constructor(pnode_t *);
287 static void clientenv_destructor(pnode_t *);
288 static void *utdata_constructor(void);
289 static void utdata_destructor(void *);
290 static clientenv *alloc_clientenv(void);
291 static bool init_clientenv(clientenv *, bool);
292 static clientenv *free_clientenv(clientenv *);
293 static void empty_rcpts(list_t *);
294 static bool check_alias(clientenv *, char *);
295 static bool check_nofrom(clientenv *);
296 static int lock_check(const char *);
297 static int best_match(const char *, const char *);
298 static bool local_address(clientenv *, struct box_info *, const char *);
299 static bool box_filter_allow(clientenv *, const char *, const char *, bool);
300 static void rfc_time(char *);
301 static bool valid_address(clientenv *, char *, size_t, char *, int);
302 static bool valid_host(clientenv *, char *, int, bool, bool);
303 static bool valid_ipaddress(clientenv *, const char *);
304
305 static int validate_msg_line(char *, ssize_t *, int *, void *);
306 static bool do_data(clientenv *);
307 inline static size_t do_data_received(char *, size_t, clientenv *, rcptnode *,
308 const char *);
309 static void do_data_stats(clientenv *, rcptnode *, size_t);
310 static bool address_relay_allow(clientenv *, int *, const char *);
311 static void iso_time(char *);
312 static bool message_write(char *, const char *, size_t, struct fdbrb_buffer *,
313 const char *);
314 static bool do_data_file(clientenv *, struct fdbrb_buffer *,
315 struct validate_udata *);
316 static bool do_data_queue_box(clientenv *, const char *, size_t, struct
317 fdbrb_buffer *, rcptnode *, struct validate_udata *);
318 static bool do_data_queue_relay(clientenv *, const char *, size_t, struct
319 fdbrb_buffer *, rcptnode *);
320 static void do_data_queue_notify(clientenv *);
321 static int do_data_queue_notify_connect(void);
322
323 static int handleclient(unsigned long, int, clientlistnode *, struct iface *,
324 struct async_clenv *, void *);
325
326 static void thread_init(void);
327 static void *thread_mutex_create(void);
328 static void *thread_mutex_destroy(void *);
329 static void thread_mutex_lock(void *);
330 static void thread_mutex_unlock(void *);
331 static bool thread_eintr(void);
332
333 static void async_resquery(struct async_msg *);
334 static int a_res_query(clientenv *, const char *, int, int, char *, int);
335
336 static void *hosts_expire_thread(void *);
337 static bool hosts_expire_thread_iterator(hashnode_t *, void *);
338
339 static void *db_gc_thread(void *);
340
341
342
343
344 #endif