1 /* $Id: mmsmtpd.h,v 1.55 2011/02/08 00:57:00 mmondor Exp $ */
4 * Copyright (C) 2001-2008, Matthew Mondor
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
21 * 5. Redistribution of source code may not be released under the terms of
22 * any GNU Public License derivate.
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.
47 #include <sys/types.h>
53 #include <mm_pthread_sleep.h>
62 #include <mmlimitrate.h>
70 #define DAEMON_NAME "mmsmtpd"
71 #define DAEMON_VERSION "mmmail-0.3.4"
73 /* Negative states are used by the state swapper, others are real states */
74 #define STATE_ERROR -3
76 #define STATE_CURRENT -1
79 /* Invalid RCPT reason */
107 /* Resolving flags for valid_host() */
110 #define HOST_RES_MX 2
112 /* Custom fdbreadbuf() return result */
113 #define CFDBRB_HOPS -1
114 #define CFDBRB_HEADER -2
115 #define CFDBRB_NOHOP -3
117 /* Asynchroneous functions we attach */
118 #define ASYNC_RESQUERY 1
120 /* Error registration macro */
121 #define REGISTER_ERROR(x) do { \
123 if (CONF.DELAY_ON_ERROR) \
124 pthread_sleep((x)->errors); \
125 } while (/* CONSTCOND */0)
127 /* Evaluates if a character is valid for addresses and hostnames */
128 #define VALID_ADDR_CHAR(c) \
129 (valid_addr_char_table[(int)((unsigned char)(c))] != 0)
130 #define VALID_HOST_CHAR(c) \
131 (valid_addr_host_table[(int)((unsigned char)(c))] != 0)
137 /* We store config file read results in this structure */
138 typedef struct config
{
139 char LOCK_PATH
[256], CHROOT_DIR
[256], PID_PATH
[256], USER
[32], GROUPS
[256],
140 LOG_FACILITY
[32], SERVER_NAMES
[1024], LISTEN_IPS
[1024], DB_INFO
[1024],
141 MAIL_DIR
[256], MMRELAYD_SOCKET_PATH
[256];
142 long ALLOC_BUFFERS
, LOG_LEVEL
, LISTEN_PORT
, MAX_ERRORS
, MAX_IPS
,
143 MAX_PER_IP
, CONNECTION_RATE
, CONNECTION_PERIOD
, INPUT_TIMEOUT
,
144 BANDWIDTH_IN
, BANDWIDTH_OUT
, GBANDWIDTH_IN
, GBANDWIDTH_OUT
, MAX_RCPTS
,
145 MAX_DATA_LINES
, MAX_DATA_SIZE
, MAX_HOPS
, FLOOD_MESSAGES
,
146 FLOOD_EXPIRES
, FLOOD_CACHE
, ASYNC_PROCESSES
;
147 bool RESOLVE_HOSTS
, RESOLVE_HELO
, RESOLVE_MX_MAIL
, RESOLVE_MX_RCPT
,
148 REQUIRE_HELO
, REQUIRE_HOP
, FLOOD_PROTECTION
, STATFAIL_HELO
,
149 STATFAIL_NOHELO
, STATFAIL_NOFROM
, STATFAIL_ADDRESS
, STATFAIL_RELAY
,
150 STATFAIL_FLOOD
, STATFAIL_FULL
, STATFAIL_TIMEOUT
, STATFAIL_EOF
,
151 STATFAIL_FILTER
, DELAY_ON_ERROR
, RELAYING
;
155 /* This consists of the state-shared clientenv structure */
156 typedef struct clientenv
{
158 fdbuf
*fdb
; /* Buffered handler around our fd */
159 char *buffer
; /* Buffer that points to last command line */
160 char *helo
; /* Cached helo hostname */
161 char *from
; /* Cached mail sender address */
162 char *c_hostname
; /* Pointer to client's hostname */
163 char *c_ipaddr
; /* Pointer to client's IP address string */
164 long mesg_size
; /* Current cached message size in bytes */
165 long errors
; /* Total number of errors that occured */
166 int timeout
; /* Timeout in ms */
167 bool nofrom
; /* If empty MAIL FROM from allowed server */
168 unsigned long id
; /* Our connection ID */
169 unsigned long messages
; /* Messages user sent us */
170 unsigned long rcpts
; /* Number of RCPT accepted */
171 struct iface
*iface
; /* Current interface user connected through */
172 list_t rcpt
; /* Cached recepients to send mail to */
173 struct async_clenv
*aclenv
; /* Thread context for async_call() */
174 mmstat_t vstat
, pstat
; /* Persistent mmstat(3) handles */
175 PGconn
*pgconn
; /* Persistent pgsql connection */
178 /* Used for RCPT addresses */
179 typedef struct rcptnode
{
181 char address
[64], foraddress
[64];
183 bool relay
; /* Non-local */
186 /* This structure is used to keep a cache of recent hosts from which mail was
187 * received, along with information on it to determine if the rate of messages
190 typedef struct hostnode
{
192 char host
[128]; /* Hostname, key */
196 struct hosts_expire_thread_iterator_udata
{
197 time_t current
, soonest
;
200 /* Used for mmfd thread support delegation/abstraction */
203 pthread_mutex_t mutex
;
206 /* This defines a state */
207 typedef struct state
{
208 int (**functions
)(clientenv
*);
213 /* A command of a state */
214 typedef struct command
{
216 char *name
, *args
, *desc
;
219 /* Information for a mailbox */
221 long max_size
, size
, max_msgs
, msgs
;
222 bool filter
, filter_type
;
225 /* For fast command lookup */
229 struct command
*command
;
233 /* Used for fast index of result messages */
234 struct reply_messages
{
239 /* Our validate_msg_line() context */
240 struct validate_udata
244 /* Used to count number of Received: lines */
246 /* Headers we consider mandatory, which we'll add if necessary */
247 bool msgid
, date
, from
, to
, subject
, inreply
;
248 /* Still considering to read the header */
250 /* Internal linking */
252 char *h_from
, *h_to
, *h_subject
, *h_id
, *h_reply
;
255 /* Our union for async_resquery() */
256 struct async_resquery_msg
{
257 struct async_msg msg
;
275 int main(int, char **);
277 static int all_noop(clientenv
*);
278 static int all_rset(clientenv
*);
279 static int all_quit(clientenv
*);
280 static int all_help(clientenv
*);
281 static int all_helo(clientenv
*);
282 static int all_mail(clientenv
*);
283 static int all_rcpt(clientenv
*);
284 static int all_data(clientenv
*);
285 static int all_beer(clientenv
*);
287 static bool hash_commands(struct command
*, size_t);
288 static uint32_t commandnode_keyhash(const void *, size_t);
289 static int commandnode_keycmp(const void *, const void *, size_t);
290 static bool reply(clientenv
*, int, bool, const char *, ...);
292 static bool clientenv_constructor(pnode_t
*);
293 static void clientenv_destructor(pnode_t
*);
294 static void *utdata_constructor(void);
295 static void utdata_destructor(void *);
296 static clientenv
*alloc_clientenv(void);
297 static bool init_clientenv(clientenv
*, bool);
298 static clientenv
*free_clientenv(clientenv
*);
299 static void empty_rcpts(list_t
*);
300 static bool check_alias(clientenv
*, char *);
301 static bool check_nofrom(clientenv
*);
302 static int lock_check(const char *);
303 static int best_match(const char *, const char *);
304 static bool local_address(clientenv
*, struct box_info
*, const char *);
305 static bool box_filter_allow(clientenv
*, const char *, const char *, bool);
306 static void rfc_time(char *);
307 static bool valid_address(clientenv
*, char *, size_t, char *, int);
308 static bool valid_host(clientenv
*, char *, int, bool, bool);
309 static bool valid_ipaddress(clientenv
*, const char *);
311 static int validate_msg_line(char *, ssize_t
*, int *, void *);
312 static bool do_data(clientenv
*);
313 inline static size_t do_data_received(char *, size_t, clientenv
*, rcptnode
*,
315 static void do_data_stats(clientenv
*, rcptnode
*, size_t);
316 static bool address_relay_allow(clientenv
*, int *, const char *);
317 static void iso_time(char *);
318 static bool message_write(char *, const char *, size_t, struct fdbrb_buffer
*,
320 static bool do_data_file(clientenv
*, struct fdbrb_buffer
*,
321 struct validate_udata
*);
322 static bool do_data_queue_box(clientenv
*, const char *, size_t, struct
323 fdbrb_buffer
*, rcptnode
*, struct validate_udata
*);
324 static bool do_data_queue_relay(clientenv
*, const char *, size_t, struct
325 fdbrb_buffer
*, rcptnode
*);
326 static void do_data_queue_notify(clientenv
*);
327 static int do_data_queue_notify_connect(void);
329 static int handleclient(unsigned long, int, clientlistnode
*, struct iface
*,
330 struct async_clenv
*, void *);
332 static void thread_init(void);
333 static void *thread_mutex_create(void);
334 static void *thread_mutex_destroy(void *);
335 static void thread_mutex_lock(void *);
336 static void thread_mutex_unlock(void *);
337 static bool thread_eintr(void);
339 static void async_resquery(struct async_msg
*);
340 static int a_res_query(clientenv
*, const char *, int, int, char *, int);
342 static void *hosts_expire_thread(void *);
343 static bool hosts_expire_thread_iterator(hashnode_t
*, void *);
345 static void *db_gc_thread(void *);