masqmail-0.2

view src/smtp_in.c @ 179:ec3fe72a3e99

Fixed an important bug with folded headers! g_strconcat() returns a *copy* of the string, but hdr->value still pointed to the old header (which probably was a memory leak, too). If the folded part had been quite small it was likely that the new string was at the same position as the old one, thus making everything go well. But if pretty long headers were folded several times it was likely that the new string was allocated somewhere else in memory, thus breaking things. In result mails to lots of recipients (folded header) were frequently only sent to the ones in the first line. Sorry for the inconvenience.
author meillo@marmaro.de
date Fri, 03 Jun 2011 09:52:17 +0200
parents b072426cc6bb
children
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 */
32 #ifdef ENABLE_SMTP_SERVER
34 smtp_cmd smtp_cmds[] = {
35 {SMTP_HELO, "HELO",},
36 {SMTP_EHLO, "EHLO",},
37 {SMTP_MAIL_FROM, "MAIL FROM:",},
38 {SMTP_RCPT_TO, "RCPT TO:",},
39 {SMTP_DATA, "DATA",},
40 {SMTP_QUIT, "QUIT",},
41 {SMTP_RSET, "RSET",},
42 {SMTP_NOOP, "NOOP",},
43 {SMTP_HELP, "HELP"},
44 };
46 static smtp_cmd_id
47 get_id(const gchar * line)
48 {
49 gint i;
50 for (i = 0; i < SMTP_NUM_IDS; i++) {
51 if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) {
52 return (smtp_cmd_id) i;
53 }
54 }
55 return SMTP_ERROR;
56 }
58 static gboolean
59 get_size(gchar *line, unsigned long *msize) {
60 gchar *s = NULL;
62 /* hope we need not to handle cases like SiZe= ...*/
63 s = strstr(line, "SIZE=");
64 if (!s) {
65 /* try it in lowercase too */
66 if (!(s = strstr(line, "size="))) {
67 return FALSE;
68 }
69 }
70 s += 5;
71 *msize = atol(s);
72 DEBUG(5) debugf("get_size(): line=%s, msize=%ld\n", line, *msize);
74 return TRUE;
75 }
78 /* this is a quick hack: we expect the address to be syntactically correct
79 and containing the mailbox only, though we first check for size in
80 smtp_in().
81 Return false if address is too long.
82 */
83 static gboolean
84 get_address(gchar * line, gchar * addr)
85 {
86 gchar *p = line;
87 gchar *q = addr;
89 /* skip MAIL FROM: and RCPT TO: */
90 while (*p && (*p != ':')) {
91 p++;
92 }
93 p++;
95 /* skip spaces: */
96 while (*p && isspace(*p)) {
97 p++;
98 }
100 /* get address: */
101 while (*p && !isspace(*p)) {
102 if (q >= addr + MAX_ADDRESS-1) {
103 *q = '\0';
104 return FALSE;
105 }
106 *(q++) = *(p++);
107 }
108 *q = '\0';
110 return TRUE;
111 }
113 static smtp_connection*
114 create_base(gchar * remote_host)
115 {
116 smtp_connection *base = g_malloc(sizeof(smtp_connection));
117 if (!base) {
118 return NULL;
119 }
121 base->remote_host = g_strdup(remote_host);
123 base->prot = PROT_SMTP;
124 base->next_id = 0;
125 base->helo_seen = 0;
126 base->from_seen = 0;
127 base->rcpt_seen = 0;
128 base->msg = NULL;
130 return base;
131 }
133 static void
134 smtp_printf(FILE * out, gchar * fmt, ...)
135 {
136 va_list args;
137 va_start(args, fmt);
139 DEBUG(4) {
140 gchar buf[256];
141 va_list args_copy;
143 va_copy(args_copy, args);
144 vsnprintf(buf, 255, fmt, args_copy);
145 va_end(args_copy);
147 debugf(">>>%s", buf);
148 }
150 vfprintf(out, fmt, args);
151 fflush(out);
153 va_end(args);
154 }
156 void
157 smtp_in(FILE * in, FILE * out, gchar * remote_host, gchar * ident)
158 {
159 gchar *buffer;
160 smtp_cmd_id cmd_id;
161 message *msg = NULL;
162 smtp_connection *psc;
163 int len;
164 unsigned long size, msize;
166 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
168 psc = create_base(remote_host);
169 psc->msg = msg;
171 buffer = (gchar *) g_malloc(BUF_LEN);
172 if (!buffer) {
173 /* this check is actually unneccessary as g_malloc()
174 aborts on failure */
175 return;
176 }
178 /* send greeting string, containing ESMTP: */
179 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION);
181 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) {
182 cmd_id = get_id(buffer);
184 if (conf.defer_all) {
185 /* I need this to debug delivery failures */
186 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name);
187 destroy_message(msg);
188 msg = NULL;
189 return;
190 }
192 switch (cmd_id) {
193 case SMTP_HELO:
194 psc->prot = PROT_SMTP;
195 psc->helo_seen = TRUE;
196 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
197 break;
199 case SMTP_EHLO:
200 psc->prot = PROT_ESMTP;
201 psc->helo_seen = TRUE;
202 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
203 smtp_printf(out, "250-SIZE %d\r\n", conf.max_msg_size);
204 smtp_printf(out, "250-PIPELINING\r\n");
205 smtp_printf(out, "250 HELP\r\n");
206 break;
208 case SMTP_MAIL_FROM:
209 {
210 gchar buf[MAX_ADDRESS];
211 address *addr;
213 if (!psc->helo_seen) {
214 smtp_printf(out, "503 need HELO or EHLO\r\n");
215 break;
216 }
217 if (psc->from_seen) {
218 smtp_printf(out, "503 MAIL FROM: already given.\r\n");
219 break;
220 }
221 if (get_size(buffer, &msize)) {
222 DEBUG(5) debugf("smtp_in(): get_size: msize=%ld, conf.mms=%d\n",
223 msize, conf.max_msg_size);
224 if (conf.max_msg_size && (msize > conf.max_msg_size)) {
225 smtp_printf(out, "552 Message size exceeds fixed limit.\r\n");
226 break;
227 }
228 }
229 if (!get_address(buffer, buf)) {
230 smtp_printf(out, "553 Address too long.\r\n");
231 break;
232 }
234 msg = create_message();
235 msg->received_host = remote_host ? g_strdup(remote_host) : NULL;
236 msg->received_prot = psc->prot;
237 msg->ident = ident ? g_strdup(ident) : NULL;
238 /* get transfer id and increment for next one */
239 msg->transfer_id = (psc->next_id)++;
241 if (remote_host) {
242 addr = create_address(buf, TRUE);
243 } else {
244 addr = create_address_qualified(buf, TRUE, conf.host_name);
245 }
246 if (!addr) {
247 smtp_printf(out, "501 %s: syntax error.\r\n", buf);
248 } else if (!addr->domain) {
249 smtp_printf(out, "501 return path must be qualified.\r\n", buf);
250 } else {
251 psc->from_seen = TRUE;
252 msg->return_path = addr;
253 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address);
254 }
255 }
256 break;
258 case SMTP_RCPT_TO:
259 {
260 char buf[MAX_ADDRESS];
261 address *addr;
263 if (!psc->helo_seen) {
264 smtp_printf(out, "503 need HELO or EHLO.\r\n");
265 break;
266 }
267 if (!psc->from_seen) {
268 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n");
269 break;
270 }
271 if (!get_address(buffer, buf)) {
272 smtp_printf(out, "553 Address too long.\r\n");
273 break;
274 }
276 if (remote_host) {
277 addr = create_address(buf, TRUE);
278 } else {
279 addr = create_address_qualified(buf, TRUE, conf.host_name);
280 }
281 if (!addr) {
282 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf);
283 break;
284 }
285 if (addr->local_part[0] == '|') {
286 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf);
287 break;
288 }
289 if (!addr->domain) {
290 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf);
291 break;
292 }
293 gboolean do_relay = conf.do_relay;
294 if (!do_relay) {
295 do_relay = addr_is_local(msg->return_path);
296 if (!do_relay) {
297 do_relay = addr_is_local(addr);
298 }
299 }
300 if (!do_relay) {
301 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr));
302 break;
303 }
304 psc->rcpt_seen = TRUE;
305 msg->rcpt_list = g_list_append(msg->rcpt_list, addr);
306 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address);
307 }
308 break;
310 case SMTP_DATA:
311 if (!psc->helo_seen) {
312 smtp_printf(out, "503 need HELO or EHLO.\r\n");
313 break;
314 }
315 if (!psc->rcpt_seen) {
316 smtp_printf(out, "503 need RCPT TO: before DATA\r\n");
317 break;
318 }
319 accept_error err;
321 smtp_printf(out, "354 okay, and do not forget the dot\r\n");
323 err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0);
324 if (err != AERR_OK) {
325 switch (err) {
326 case AERR_TIMEOUT:
327 case AERR_EOF:
328 return;
329 case AERR_SIZE:
330 smtp_printf(out, "552 Error: message too large.\r\n");
331 return;
332 default:
333 /* should never happen: */
334 smtp_printf(out, "451 Unknown error\r\n");
335 return;
336 }
337 }
340 if (!spool_write(msg, TRUE)) {
341 smtp_printf(out, "451 Could not write spool file\r\n");
342 return;
343 }
344 pid_t pid;
345 smtp_printf(out, "250 OK id=%s\r\n", msg->uid);
347 if (remote_host != NULL) {
348 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid,
349 msg->return_path->local_part, msg->return_path->domain,
350 remote_host, prot_names[psc->prot]);
351 } else {
352 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid,
353 msg->return_path->local_part, msg->return_path->domain,
354 prot_names[psc->prot]);
355 }
357 if (conf.do_queue) {
358 DEBUG(1) debugf("queuing forced by configuration or option.\n");
359 } else {
360 pid = fork();
361 if (pid == 0) {
362 _exit(deliver(msg));
363 } else if (pid < 0) {
364 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid);
365 }
366 }
367 psc->rcpt_seen = psc->from_seen = FALSE;
368 destroy_message(msg);
369 msg = NULL;
370 break;
372 case SMTP_QUIT:
373 smtp_printf(out, "221 goodbye\r\n");
374 destroy_message(msg);
375 msg = NULL;
376 return;
378 case SMTP_RSET:
379 psc->from_seen = psc->rcpt_seen = FALSE;
380 destroy_message(msg);
381 msg = NULL;
382 smtp_printf(out, "250 OK\r\n");
383 break;
385 case SMTP_NOOP:
386 smtp_printf(out, "250 OK\r\n");
387 break;
389 case SMTP_HELP:
390 {
391 int i;
393 smtp_printf(out, "214-supported commands:\r\n");
394 for (i = 0; i < SMTP_NUM_IDS - 1; i++) {
395 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd);
396 }
397 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd);
398 }
399 break;
401 default:
402 smtp_printf(out, "501 command not recognized\r\n");
403 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer);
404 break;
405 }
406 }
407 switch (len) {
408 case -3:
409 logwrite(LOG_NOTICE, "connection timed out\n");
410 break;
411 case -2:
412 logwrite(LOG_NOTICE, "line overflow\n");
413 break;
414 case -1:
415 logwrite(LOG_NOTICE, "received EOF\n");
416 break;
417 default:
418 break;
419 }
420 }
421 #endif