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