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