masqmail

view src/smtp_in.c @ 378:5781ba87df95

Removed ident. This had been discussed on the mailing list in Oct 2011. Ident is hardly useful in typical setups for masqmail. Probably Oliver had used it in his setup; that would make sense. Now, I know of nobody who needs it.
author markus schnalke <meillo@marmaro.de>
date Sat, 14 Jan 2012 21:36:58 +0100
parents b27f66555ba8
children
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 1999-2001 Oliver Kurth
4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include "masqmail.h"
22 #include "readsock.h"
24 /*
25 ** I always forget these rfc numbers:
26 ** RFC 821 (SMTP)
27 ** RFC 1869 (ESMTP)
28 ** RFC 1870 (ESMTP SIZE)
29 ** RFC 2197 (ESMTP PIPELINE)
30 ** RFC 2554 (ESMTP AUTH)
31 */
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 /*
79 ** this is a quick hack: we expect the address to be syntactically correct
80 ** and containing the mailbox only, though we first check for size in
81 ** smtp_in().
82 ** Return false if address is too long.
83 */
84 static gboolean
85 get_address(gchar *line, gchar *addr)
86 {
87 gchar *p = line;
88 gchar *q = addr;
90 /* skip MAIL FROM: and RCPT TO: */
91 while (*p && (*p != ':')) {
92 p++;
93 }
94 p++;
96 /* skip spaces: */
97 while (*p && isspace(*p)) {
98 p++;
99 }
101 /* get address: */
102 while (*p && !isspace(*p)) {
103 if (q >= addr + MAX_ADDRESS-1) {
104 *q = '\0';
105 return FALSE;
106 }
107 *(q++) = *(p++);
108 }
109 *q = '\0';
111 return TRUE;
112 }
114 static smtp_connection*
115 create_base(gchar *remote_host)
116 {
117 smtp_connection *base = g_malloc(sizeof(smtp_connection));
118 if (!base) {
119 return NULL;
120 }
122 base->remote_host = g_strdup(remote_host);
124 base->prot = PROT_SMTP;
125 base->next_id = 0;
126 base->helo_seen = 0;
127 base->from_seen = 0;
128 base->rcpt_seen = 0;
129 base->msg = NULL;
131 return base;
132 }
134 static void
135 smtp_printf(FILE *out, gchar *fmt, ...)
136 {
137 va_list args;
138 va_start(args, fmt);
140 DEBUG(4) {
141 gchar buf[256];
142 va_list args_copy;
144 va_copy(args_copy, args);
145 vsnprintf(buf, 255, fmt, args_copy);
146 va_end(args_copy);
148 debugf(">>>%s\n", buf);
149 }
151 vfprintf(out, fmt, args);
152 fflush(out);
154 va_end(args);
155 }
157 void
158 smtp_in(FILE *in, FILE *out, gchar *remote_host, gchar *ident)
159 {
160 gchar *buffer;
161 smtp_cmd_id cmd_id;
162 message *msg = NULL;
163 smtp_connection *psc;
164 int len;
165 unsigned long msize;
167 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host);
169 psc = create_base(remote_host);
170 psc->msg = msg;
172 buffer = (gchar *) g_malloc(BUF_LEN);
173 if (!buffer) {
174 /* this check is actually unneccessary as g_malloc()
175 aborts on failure */
176 return;
177 }
179 /* send greeting string, containing ESMTP: */
180 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION);
182 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) {
183 cmd_id = get_id(buffer);
185 if (conf.defer_all) {
186 /* I need this to debug delivery failures */
187 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name);
188 destroy_message(msg);
189 msg = NULL;
190 return;
191 }
193 switch (cmd_id) {
194 case SMTP_HELO:
195 psc->prot = PROT_SMTP;
196 psc->helo_seen = TRUE;
197 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name);
198 break;
200 case SMTP_EHLO:
201 psc->prot = PROT_ESMTP;
202 psc->helo_seen = TRUE;
203 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name);
204 smtp_printf(out, "250-SIZE %d\r\n", conf.max_msg_size);
205 smtp_printf(out, "250-PIPELINING\r\n");
206 smtp_printf(out, "250 HELP\r\n");
207 break;
209 case SMTP_MAIL_FROM:
210 {
211 gchar buf[MAX_ADDRESS];
212 address *addr;
214 if (!psc->helo_seen) {
215 smtp_printf(out, "503 need HELO or EHLO\r\n");
216 break;
217 }
218 if (psc->from_seen) {
219 smtp_printf(out, "503 MAIL FROM: already given.\r\n");
220 break;
221 }
222 if (get_size(buffer, &msize)) {
223 DEBUG(5) debugf("smtp_in(): get_size: msize=%ld, conf.mms=%d\n",
224 msize, conf.max_msg_size);
225 if (conf.max_msg_size && (msize > conf.max_msg_size)) {
226 smtp_printf(out, "552 Message size exceeds fixed limit.\r\n");
227 break;
228 }
229 }
230 if (!get_address(buffer, buf)) {
231 smtp_printf(out, "553 Address too long.\r\n");
232 break;
233 }
235 msg = create_message();
236 msg->received_host = remote_host ? g_strdup(remote_host) : NULL;
237 msg->received_prot = psc->prot;
238 msg->ident = ident ? g_strdup(ident) : NULL;
239 /* get transfer id and increment for next one */
240 msg->transfer_id = (psc->next_id)++;
242 if (remote_host) {
243 addr = create_address(buf, TRUE);
244 } else {
245 addr = create_address_qualified(buf, TRUE, conf.host_name);
246 }
247 if (!addr) {
248 smtp_printf(out, "501 %s: syntax error.\r\n", buf);
249 } else if (!addr->domain) {
250 smtp_printf(out, "501 return path must be qualified.\r\n", buf);
251 } else {
252 psc->from_seen = TRUE;
253 msg->return_path = addr;
254 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address);
255 }
256 }
257 break;
259 case SMTP_RCPT_TO:
260 {
261 char buf[MAX_ADDRESS];
262 address *addr;
264 if (!psc->helo_seen) {
265 smtp_printf(out, "503 need HELO or EHLO.\r\n");
266 break;
267 }
268 if (!psc->from_seen) {
269 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n");
270 break;
271 }
272 if (!get_address(buffer, buf)) {
273 smtp_printf(out, "553 Address too long.\r\n");
274 break;
275 }
277 if (remote_host) {
278 addr = create_address(buf, TRUE);
279 } else {
280 addr = create_address_qualified(buf, TRUE, conf.host_name);
281 }
282 if (!addr) {
283 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf);
284 break;
285 }
286 if (addr->local_part[0] == '|') {
287 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf);
288 break;
289 }
290 if (!addr->domain) {
291 /* TODO: ``postmaster'' may be unqualified */
292 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf);
293 break;
294 }
295 if (!(conf.do_relay || addr_is_local(msg->return_path) || addr_is_local(addr))) {
296 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr));
297 break;
298 }
299 psc->rcpt_seen = TRUE;
300 msg->rcpt_list = g_list_append(msg->rcpt_list, addr);
301 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address);
302 }
303 break;
305 case SMTP_DATA:
306 if (!psc->helo_seen) {
307 smtp_printf(out, "503 need HELO or EHLO.\r\n");
308 break;
309 }
310 if (!psc->rcpt_seen) {
311 smtp_printf(out, "503 need RCPT TO: before DATA\r\n");
312 break;
313 }
314 accept_error err;
316 smtp_printf(out, "354 okay, and do not forget the dot\r\n");
318 err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0);
319 if (err != AERR_OK) {
320 switch (err) {
321 case AERR_TIMEOUT:
322 case AERR_EOF:
323 return;
324 case AERR_SIZE:
325 smtp_printf(out, "552 Error: message too large.\r\n");
326 return;
327 default:
328 /* should never happen: */
329 smtp_printf(out, "451 Unknown error\r\n");
330 return;
331 }
332 }
335 if (!spool_write(msg, TRUE)) {
336 smtp_printf(out, "451 Could not write spool file\r\n");
337 return;
338 }
339 pid_t pid;
340 smtp_printf(out, "250 OK id=%s\r\n", msg->uid);
342 if (remote_host != NULL) {
343 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid,
344 msg->return_path->local_part, msg->return_path->domain,
345 remote_host, prot_names[psc->prot]);
346 } else {
347 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid,
348 msg->return_path->local_part, msg->return_path->domain,
349 prot_names[psc->prot]);
350 }
352 if (conf.do_queue) {
353 DEBUG(1) debugf("queuing forced by configuration or option.\n");
354 } else {
355 pid = fork();
356 if (pid < 0) {
357 logwrite(LOG_ALERT, "could not fork for delivery, id = %s\n", msg->uid);
358 } else if (pid == 0) {
359 /* FIXME: most likely inverted exit code */
360 _exit(deliver(msg));
361 }
362 }
363 psc->rcpt_seen = psc->from_seen = FALSE;
364 destroy_message(msg);
365 msg = NULL;
366 break;
368 case SMTP_QUIT:
369 smtp_printf(out, "221 goodbye\r\n");
370 destroy_message(msg);
371 msg = NULL;
372 return;
374 case SMTP_RSET:
375 psc->from_seen = psc->rcpt_seen = FALSE;
376 destroy_message(msg);
377 msg = NULL;
378 smtp_printf(out, "250 OK\r\n");
379 break;
381 case SMTP_NOOP:
382 smtp_printf(out, "250 OK\r\n");
383 break;
385 case SMTP_HELP:
386 {
387 int i;
389 smtp_printf(out, "214-supported commands:\r\n");
390 for (i = 0; i < SMTP_NUM_IDS - 1; i++) {
391 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd);
392 }
393 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd);
394 }
395 break;
397 default:
398 smtp_printf(out, "501 command not recognized\r\n");
399 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer);
400 break;
401 }
402 }
403 switch (len) {
404 case -3:
405 logwrite(LOG_NOTICE, "connection timed out\n");
406 break;
407 case -2:
408 logwrite(LOG_NOTICE, "line overflow\n");
409 break;
410 case -1:
411 logwrite(LOG_NOTICE, "received EOF\n");
412 break;
413 default:
414 break;
415 }
416 }