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