1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
|
#ifndef SMTP_SERVER_PRIVATE_H
#define SMTP_SERVER_PRIVATE_H
#include "connection.h"
#include "smtp-server.h"
#define SMTP_SERVER_COMMAND_POOL_MAX (8 * 1024)
#define SMTP_SERVER_DEFAULT_MAX_COMMAND_LINE (4 * 1024)
#define SMTP_SERVER_DEFAULT_MAX_BAD_COMMANDS 10
#define SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT (1024*1024)
#define SMTP_SERVER_DEFAULT_CAPABILITIES \
(SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES | \
SMTP_CAPABILITY_8BITMIME | SMTP_CAPABILITY_CHUNKING)
struct smtp_server_cmd_hook;
struct smtp_server_reply;
struct smtp_server_command;
struct smtp_server_connection;
ARRAY_DEFINE_TYPE(smtp_server_reply, struct smtp_server_reply);
ARRAY_DEFINE_TYPE(smtp_server_cmd_hook, struct smtp_server_cmd_hook);
enum smtp_server_command_state {
/* New command; callback to command start handler executing. */
SMTP_SERVER_COMMAND_STATE_NEW = 0,
/* This command is being processed; command data is fully read, but no
reply is yet submitted */
SMTP_SERVER_COMMAND_STATE_PROCESSING,
/* A reply is submitted for this command. If not all command data was
read by the handler, it is first skipped on the input. If this is a
multi-reply command (LMTP->DATA), not all replies may be submitted
yet. */
SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY,
/* Request is ready for sending reply; a reply is submitted and the
command payload is fully read. If this is a multi-reply command
(LMTP->DATA), not all replies may be submitted yet. In that case the
command state goes back to PROCESSING once the all submitted replies
are sent. */
SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY,
/* The reply for the command is sent */
SMTP_SERVER_COMMAND_STATE_FINISHED,
/* Request is aborted; still lingering due to references */
SMTP_SERVER_COMMAND_STATE_ABORTED
};
struct smtp_server_command_hook {
enum smtp_server_command_hook_type type;
struct smtp_server_command_hook *prev, *next;
smtp_server_cmd_func_t *func;
void *context;
};
struct smtp_server_recipient_hook {
enum smtp_server_recipient_hook_type type;
struct smtp_server_recipient_hook *prev, *next;
smtp_server_rcpt_func_t *func;
void *context;
};
struct smtp_server_reply_content {
unsigned int status;
const char *enhanced_code;
const char *status_prefix;
string_t *text;
size_t last_line;
};
struct smtp_server_reply {
struct smtp_server_command *command;
unsigned int index;
struct event *event;
/* Replies may share content */
struct smtp_server_reply_content *content;
bool submitted:1;
bool sent:1;
bool forwarded:1;
};
struct smtp_server_command_reg {
const char *name;
enum smtp_server_command_flags flags;
smtp_server_cmd_start_func_t *func;
};
struct smtp_server_command {
struct smtp_server_cmd_ctx context;
const struct smtp_server_command_reg *reg;
int refcount;
enum smtp_server_command_state state;
struct smtp_server_command *prev, *next;
struct smtp_server_command_hook *hooks_head, *hooks_tail;
void *data;
ARRAY_TYPE(smtp_server_reply) replies;
unsigned int replies_expected;
unsigned int replies_submitted;
bool input_locked:1;
bool input_captured:1;
bool pipeline_blocked:1;
bool reply_early:1;
bool destroying:1;
};
struct smtp_server_recipient_private {
struct smtp_server_recipient rcpt;
int refcount;
struct smtp_server_recipient_hook *hooks_head, *hooks_tail;
bool destroying:1;
};
struct smtp_server_state_data {
enum smtp_server_state state;
char *args;
time_t timestamp;
unsigned int pending_mail_cmds;
unsigned int pending_rcpt_cmds, denied_rcpt_cmds;
unsigned int pending_data_cmds;
struct smtp_server_transaction *trans;
struct istream *data_input, *data_chain_input;
struct istream_chain *data_chain;
unsigned int data_chunks;
uoff_t data_size;
bool data_failed:1;
};
struct smtp_server_connection {
struct connection conn;
struct smtp_server *server;
pool_t pool;
int refcount;
struct event *event, *next_trans_event;
struct smtp_server_settings set;
ARRAY(struct smtp_capability_extra) extra_capabilities;
ARRAY_TYPE(const_string) mail_param_extensions; /* NULL-terminated */
ARRAY_TYPE(const_string) rcpt_param_extensions; /* NULL-terminated */
const struct smtp_server_callbacks *callbacks;
void *context;
enum smtp_proxy_protocol proxy_proto;
unsigned int proxy_ttl_plus_1;
unsigned int proxy_timeout_secs;
char *proxy_helo;
struct smtp_server_helo_data helo, *pending_helo;
char *helo_domain, *username;
char *session_id;
unsigned int transaction_seq;
struct timeout *to_idle;
struct istream *raw_input;
struct ostream *raw_output;
struct ssl_iostream_context *ssl_ctx;
struct ssl_iostream *ssl_iostream;
struct smtp_command_parser *smtp_parser;
struct smtp_server_command *command_queue_head, *command_queue_tail;
unsigned int command_queue_count;
unsigned int bad_counter;
struct smtp_server_state_data state;
struct smtp_server_stats stats;
bool started:1;
bool halted:1;
bool ssl_start:1;
bool ssl_secured:1;
bool authenticated:1;
bool created_from_streams:1;
bool corked:1;
bool disconnected:1;
bool closing:1;
bool closed:1;
bool input_broken:1;
bool input_locked:1;
bool handling_input:1;
bool rawlog_checked:1;
bool rawlog_enabled:1;
};
struct smtp_server {
pool_t pool;
struct smtp_server_settings set;
struct event *event;
struct ssl_iostream_context *ssl_ctx;
ARRAY(struct smtp_server_command_reg) commands_reg;
struct connection_list *conn_list;
bool commands_unsorted:1;
};
bool smtp_server_connection_pending_command_data(
struct smtp_server_connection *conn);
/*
* Reply
*/
void smtp_server_reply_free(struct smtp_server_command *cmd);
int smtp_server_reply_send(struct smtp_server_reply *resp);
const char *
smtp_server_reply_get_one_line(const struct smtp_server_reply *reply);
const char *
smtp_server_reply_get_message(const struct smtp_server_reply *reply);
void smtp_server_reply_add_to_event(const struct smtp_server_reply *reply,
struct event_passthrough *e);
/*
* Command
*/
void smtp_server_commands_init(struct smtp_server *server);
void smtp_server_command_debug(struct smtp_server_cmd_ctx *cmd,
const char *format, ...) ATTR_FORMAT(2, 3);
struct smtp_server_command *
smtp_server_command_new_invalid(struct smtp_server_connection *conn);
struct smtp_server_command *
smtp_server_command_new(struct smtp_server_connection *conn, const char *name);
void smtp_server_command_execute(struct smtp_server_command *cmd,
const char *params);
void smtp_server_command_ref(struct smtp_server_command *cmd);
bool smtp_server_command_unref(struct smtp_server_command **_cmd);
void smtp_server_command_abort(struct smtp_server_command **_cmd);
bool smtp_server_command_call_hooks(struct smtp_server_command **_cmd,
enum smtp_server_command_hook_type type,
bool remove);
void smtp_server_command_remove_hooks(struct smtp_server_command *cmd,
enum smtp_server_command_hook_type type);
void smtp_server_command_submit_reply(struct smtp_server_command *cmd);
int smtp_server_connection_flush(struct smtp_server_connection *conn);
void smtp_server_command_ready_to_reply(struct smtp_server_command *cmd);
bool smtp_server_command_send_replies(struct smtp_server_command *cmd);
void smtp_server_command_finished(struct smtp_server_command *cmd);
bool smtp_server_command_next_to_reply(struct smtp_server_command **_cmd);
bool smtp_server_command_completed(struct smtp_server_command **_cmd);
static inline bool
smtp_server_command_is_complete(struct smtp_server_command *cmd)
{
struct smtp_server_connection *conn = cmd->context.conn;
return (conn->input_broken || (cmd->next != NULL) || cmd->reply_early ||
!smtp_server_connection_pending_command_data(conn));
}
/*
* Connection
*/
typedef void smtp_server_input_callback_t(void *context);
void smtp_server_connection_debug(struct smtp_server_connection *conn,
const char *format, ...) ATTR_FORMAT(2, 3);
struct connection_list *smtp_server_connection_list_init(void);
struct event_reason *
smtp_server_connection_reason_begin(struct smtp_server_connection *conn,
const char *name);
void smtp_server_connection_switch_ioloop(struct smtp_server_connection *conn);
void smtp_server_connection_handle_output_error(
struct smtp_server_connection *conn);
void smtp_server_connection_trigger_output(struct smtp_server_connection *conn);
bool smtp_server_connection_pending_payload(struct smtp_server_connection *conn);
void smtp_server_connection_cork(struct smtp_server_connection *conn);
void smtp_server_connection_uncork(struct smtp_server_connection *conn);
void smtp_server_connection_input_halt(struct smtp_server_connection *conn);
void smtp_server_connection_input_resume(struct smtp_server_connection *conn);
void smtp_server_connection_input_capture(
struct smtp_server_connection *conn,
smtp_server_input_callback_t *callback, void *context);
#define smtp_server_connection_input_capture(conn, callback, context) \
smtp_server_connection_input_capture(conn - \
CALLBACK_TYPECHECK(callback, void (*)(typeof(context))), \
(smtp_server_input_callback_t *)callback, context)
void smtp_server_connection_timeout_stop(struct smtp_server_connection *conn);
void smtp_server_connection_timeout_start(struct smtp_server_connection *conn);
void smtp_server_connection_timeout_reset(struct smtp_server_connection *conn);
void smtp_server_connection_send_line(struct smtp_server_connection *conn,
const char *fmt, ...) ATTR_FORMAT(2, 3);
void smtp_server_connection_reply_lines(struct smtp_server_connection *conn,
unsigned int status,
const char *enh_code,
const char *const *text_lines);
void smtp_server_connection_reply_immediate(
struct smtp_server_connection *conn, unsigned int status,
const char *fmt, ...) ATTR_FORMAT(3, 4);
void smtp_server_connection_reset_state(struct smtp_server_connection *conn);
void smtp_server_connection_set_state(struct smtp_server_connection *conn,
enum smtp_server_state state,
const char *args) ATTR_NULL(3);
int smtp_server_connection_ssl_init(struct smtp_server_connection *conn);
void smtp_server_connection_clear(struct smtp_server_connection *conn);
struct smtp_server_transaction *
smtp_server_connection_get_transaction(struct smtp_server_connection *conn);
/*
* Recipient
*/
struct smtp_server_recipient *
smtp_server_recipient_create(struct smtp_server_cmd_ctx *cmd,
const struct smtp_address *rcpt_to,
const struct smtp_params_rcpt *params);
void smtp_server_recipient_ref(struct smtp_server_recipient *rcpt);
bool smtp_server_recipient_unref(struct smtp_server_recipient **_rcpt);
void smtp_server_recipient_destroy(struct smtp_server_recipient **_rcpt);
bool smtp_server_recipient_approved(struct smtp_server_recipient **_rcpt);
void smtp_server_recipient_denied(struct smtp_server_recipient *rcpt,
const struct smtp_server_reply *reply);
void smtp_server_recipient_data_command(struct smtp_server_recipient *rcpt,
struct smtp_server_cmd_ctx *cmd);
void smtp_server_recipient_data_replied(struct smtp_server_recipient *rcpt);
void smtp_server_recipient_reset(struct smtp_server_recipient *rcpt);
void smtp_server_recipient_finished(struct smtp_server_recipient *rcpt,
const struct smtp_server_reply *reply);
bool smtp_server_recipient_call_hooks(
struct smtp_server_recipient **_rcpt,
enum smtp_server_recipient_hook_type type);
/*
* Transaction
*/
struct smtp_server_transaction *
smtp_server_transaction_create(struct smtp_server_connection *conn,
const struct smtp_server_cmd_mail *mail_data);
void smtp_server_transaction_free(struct smtp_server_transaction **_trans);
void smtp_server_transaction_add_rcpt(struct smtp_server_transaction *trans,
struct smtp_server_recipient *rcpt);
bool smtp_server_transaction_has_rcpt(struct smtp_server_transaction *trans);
unsigned int
smtp_server_transaction_rcpt_count(struct smtp_server_transaction *trans);
void smtp_server_transaction_data_command(struct smtp_server_transaction *trans,
struct smtp_server_cmd_ctx *cmd);
void smtp_server_transaction_received(struct smtp_server_transaction *trans,
uoff_t data_size);
void smtp_server_transaction_reset(struct smtp_server_transaction *trans);
void smtp_server_transaction_finished(struct smtp_server_transaction *trans,
struct smtp_server_cmd_ctx *cmd);
/*
* Server
*/
void smtp_server_event_init(struct smtp_server *server, struct event *event);
int smtp_server_init_ssl_ctx(struct smtp_server *server, const char **error_r);
#endif
|