masqmail

view src/smtp_in.c @ 281:ea5f86e0a81c

modes are now enforced exclusive Other MTAs (exim, postfix) are more relaxing, but as combinations of exclusive modes are senseless we behave more obvious if we fail early. This makes understanding the behavior easier too.
author markus schnalke <meillo@marmaro.de>
date Tue, 07 Dec 2010 14:04:56 -0300
parents 5745edd5b769
children 794071925a22
line source
1 /* MasqMail
2 Copyright (C) 1999-2001 Oliver Kurth
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
20 #include "masqmail.h"
21 #include "readsock.h"
23 /*
24 I always forget these rfc numbers:
25 RFC 821 (SMTP)
26 RFC 1869 (ESMTP)
27 RFC 1870 (ESMTP SIZE)
28 RFC 2197 (ESMTP PIPELINE)
29 RFC 2554 (ESMTP AUTH)
30 */
33 smtp_cmd smtp_cmds[] = {
34 {SMTP_HELO, "HELO",},
35 {SMTP_EHLO, "EHLO",},
36 {SMTP_MAIL_FROM, "MAIL FROM:",},
37 {SMTP_RCPT_TO, "RCPT TO:",},
38 {SMTP_DATA, "DATA",},
39 {SMTP_QUIT, "QUIT",},
40 {SMTP_RSET, "RSET",},
41 {SMTP_NOOP, "NOOP",},
42 {SMTP_HELP, "HELP"},
43 };
45 static smtp_cmd_id
46 get_id(const gchar * line)
47 {
48 gint i;
49 for (i = 0; i < SMTP_NUM_IDS; i++) {
50 if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) {
51 return (smtp_cmd_id) i;
52 }
53 }
54 return SMTP_ERROR;
55 }
57 static gboolean
58 get_size(gchar *line, unsigned long *msize) {
59 gchar *s = NULL;
61 /* hope we need not to handle cases like SiZe= ...*/
62 s = strstr(line, "SIZE=");
63 if (!s) {
64 /* try it in lowercase too */
65 if (!(s = strstr(line, "size="))) {
66 return FALSE;
67 }
68 }
69 s += 5;
70 *msize = atol(s);
71 DEBUG(5) debugf("get_size(): line=%s, msize=%ld\n", line, *msize);
73 return TRUE;
74 }
77 /* this is a quick hack: we expect the address to be syntactically correct
78 and containing the mailbox only, though we first check for size in
79 smtp_in().
80 Return false if address is too long.
81 */
82 static gboolean
83 get_address(gchar * line, gchar * addr)
84 {
85 gchar *p = line;
86 gchar *q = addr;
88 /* skip MAIL FROM: and RCPT TO: */
89 while (*p && (*p != ':')) {
90 p++;
91 }
92 p++;
94 /* skip spaces: */
95 while (*p && isspace(*p)) {
96 p++;
97 }
99 /* get address: */
100 while (*p && !isspace(*p)) {
101 if (q >= addr + MAX_ADDRESS-1) {
102 *q = '\0';
103 return FALSE;
104 }
105 *(q++) = *(p++);
106 }
107 *q = '\0';
109 return TRUE;
110 }
112 static smtp_connection*
113 create_base(gchar * remote_host)
114 {
115 smtp_connection *base = g_malloc(sizeof(smtp_connection));
116 if (!base) {
117 return NULL;
118 }
120 base->remote_host = g_strdup(remote_host);
122 base->prot = PROT_SMTP;
123 base->next_id = 0;
124 base->helo_seen = 0;
125 base->from_seen = 0;
126 base->rcpt_seen = 0;
127 base->msg = NULL;
129 return base;
130 }
132 static void
133 smtp_printf(FILE * out, gchar * fmt, ...)
134 {
135 va_list args;
136 va_start(args, fmt);
138 DEBUG(4) {
139 gchar buf[256];
140 va_list args_copy;
142 va_copy(args_copy, args);
143 vsnprintf(buf, 255, fmt, args_copy);
144 va_end(args_copy);
146 debugf(">>>%s\n", buf);
147 }
149 vfprintf(out, fmt, args);
150 fflush(out);
152 va_end(args);
153 }
155 void
156 smtp_in(FILE * in, FILE * out, gchar * remote_host, gchar * ident)
157 {
158 gchar *buffer;
159 smtp_cmd_id cmd_id;
160 message *msg = NULL;
161 smtp_connection *psc;
162 int len;
163 unsigned long size, msize;
165 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
167 psc = create_base(remote_host);
168 psc->msg = msg;
170 buffer = (gchar *) g_malloc(BUF_LEN);
171 if (!buffer) {
172 /* this check is actually unneccessary as g_malloc()
173 aborts on failure */
174 return;
175 }
177 /* send greeting string, containing ESMTP: */
178 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION);
180 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) {
181 cmd_id = get_id(buffer);
183 if (conf.defer_all) {
184 /* I need this to debug delivery failures */
185 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name);
186 destroy_message(msg);
187 msg = NULL;
188 return;
189 }
191 switch (cmd_id) {
192 case SMTP_HELO:
193 psc->prot = PROT_SMTP;
194 psc->helo_seen = TRUE;
195 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
196 break;
198 case SMTP_EHLO:
199 psc->prot = PROT_ESMTP;
200 psc->helo_seen = TRUE;
201 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
202 smtp_printf(out, "250-SIZE %d\r\n", conf.max_msg_size);
203 smtp_printf(out, "250-PIPELINING\r\n");
204 smtp_printf(out, "250 HELP\r\n");
205 break;
207 case SMTP_MAIL_FROM:
208 {
209 gchar buf[MAX_ADDRESS];
210 address *addr;
212 if (!psc->helo_seen) {
213 smtp_printf(out, "503 need HELO or EHLO\r\n");
214 break;
215 }
216 if (psc->from_seen) {
217 smtp_printf(out, "503 MAIL FROM: already given.\r\n");
218 break;
219 }
220 if (get_size(buffer, &msize)) {
221 DEBUG(5) debugf("smtp_in(): get_size: msize=%ld, conf.mms=%d\n",
222 msize, conf.max_msg_size);
223 if (conf.max_msg_size && (msize > conf.max_msg_size)) {
224 smtp_printf(out, "552 Message size exceeds fixed limit.\r\n");
225 break;
226 }
227 }
228 if (!get_address(buffer, buf)) {
229 smtp_printf(out, "553 Address too long.\r\n");
230 break;
231 }
233 msg = create_message();
234 msg->received_host = remote_host ? g_strdup(remote_host) : NULL;
235 msg->received_prot = psc->prot;
236 msg->ident = ident ? g_strdup(ident) : NULL;
237 /* get transfer id and increment for next one */
238 msg->transfer_id = (psc->next_id)++;
240 if (remote_host) {
241 addr = create_address(buf, TRUE);
242 } else {
243 addr = create_address_qualified(buf, TRUE, conf.host_name);
244 }
245 if (!addr) {
246 smtp_printf(out, "501 %s: syntax error.\r\n", buf);
247 } else if (!addr->domain) {
248 smtp_printf(out, "501 return path must be qualified.\r\n", buf);
249 } else {
250 psc->from_seen = TRUE;
251 msg->return_path = addr;
252 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address);
253 }
254 }
255 break;
257 case SMTP_RCPT_TO:
258 {
259 char buf[MAX_ADDRESS];
260 address *addr;
262 if (!psc->helo_seen) {
263 smtp_printf(out, "503 need HELO or EHLO.\r\n");
264 break;
265 }
266 if (!psc->from_seen) {
267 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n");
268 break;
269 }
270 if (!get_address(buffer, buf)) {
271 smtp_printf(out, "553 Address too long.\r\n");
272 break;
273 }
275 if (remote_host) {
276 addr = create_address(buf, TRUE);
277 } else {
278 addr = create_address_qualified(buf, TRUE, conf.host_name);
279 }
280 if (!addr) {
281 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf);
282 break;
283 }
284 if (addr->local_part[0] == '|') {
285 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf);
286 break;
287 }
288 if (!addr->domain) {
289 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf);
290 break;
291 }
292 gboolean do_relay = conf.do_relay;
293 if (!do_relay) {
294 do_relay = addr_is_local(msg->return_path);
295 if (!do_relay) {
296 do_relay = addr_is_local(addr);
297 }
298 }
299 if (!do_relay) {
300 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr));
301 break;
302 }
303 psc->rcpt_seen = TRUE;
304 msg->rcpt_list = g_list_append(msg->rcpt_list, addr);
305 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address);
306 }
307 break;
309 case SMTP_DATA:
310 if (!psc->helo_seen) {
311 smtp_printf(out, "503 need HELO or EHLO.\r\n");
312 break;
313 }
314 if (!psc->rcpt_seen) {
315 smtp_printf(out, "503 need RCPT TO: before DATA\r\n");
316 break;
317 }
318 accept_error err;
320 smtp_printf(out, "354 okay, and do not forget the dot\r\n");
322 err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0);
323 if (err != AERR_OK) {
324 switch (err) {
325 case AERR_TIMEOUT:
326 case AERR_EOF:
327 return;
328 case AERR_SIZE:
329 smtp_printf(out, "552 Error: message too large.\r\n");
330 return;
331 default:
332 /* should never happen: */
333 smtp_printf(out, "451 Unknown error\r\n");
334 return;
335 }
336 }
339 if (!spool_write(msg, TRUE)) {
340 smtp_printf(out, "451 Could not write spool file\r\n");
341 return;
342 }
343 pid_t pid;
344 smtp_printf(out, "250 OK id=%s\r\n", msg->uid);
346 if (remote_host != NULL) {
347 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid,
348 msg->return_path->local_part, msg->return_path->domain,
349 remote_host, prot_names[psc->prot]);
350 } else {
351 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid,
352 msg->return_path->local_part, msg->return_path->domain,
353 prot_names[psc->prot]);
354 }
356 if (conf.do_queue) {
357 DEBUG(1) debugf("queuing forced by configuration or option.\n");
358 } else {
359 pid = fork();
360 if (pid == 0) {
361 _exit(deliver(msg));
362 } else if (pid < 0) {
363 logwrite(LOG_ALERT, "could not fork for delivery, id = %s\n", msg->uid);
364 }
365 }
366 psc->rcpt_seen = psc->from_seen = FALSE;
367 destroy_message(msg);
368 msg = NULL;
369 break;
371 case SMTP_QUIT:
372 smtp_printf(out, "221 goodbye\r\n");
373 destroy_message(msg);
374 msg = NULL;
375 return;
377 case SMTP_RSET:
378 psc->from_seen = psc->rcpt_seen = FALSE;
379 destroy_message(msg);
380 msg = NULL;
381 smtp_printf(out, "250 OK\r\n");
382 break;
384 case SMTP_NOOP:
385 smtp_printf(out, "250 OK\r\n");
386 break;
388 case SMTP_HELP:
389 {
390 int i;
392 smtp_printf(out, "214-supported commands:\r\n");
393 for (i = 0; i < SMTP_NUM_IDS - 1; i++) {
394 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd);
395 }
396 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd);
397 }
398 break;
400 default:
401 smtp_printf(out, "501 command not recognized\r\n");
402 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer);
403 break;
404 }
405 }
406 switch (len) {
407 case -3:
408 logwrite(LOG_NOTICE, "connection timed out\n");
409 break;
410 case -2:
411 logwrite(LOG_NOTICE, "line overflow\n");
412 break;
413 case -1:
414 logwrite(LOG_NOTICE, "received EOF\n");
415 break;
416 default:
417 break;
418 }
419 }