Mercurial > masqmail
annotate src/smtp_in.c @ 91:3e7136221104
correct masqmail path in rmail script; remove docs on uninstall
on install the correct path to the masqmail executable gets
inserted into the rmail script now.
now documentation, examples, and the templates are removed on
uninstall. Empty directories are the only thing that may remain
if one installs masqmail into an unusual path.
author | meillo@marmaro.de |
---|---|
date | Mon, 21 Jun 2010 09:40:16 +0200 |
parents | 71ce3a1568e9 |
children | 5ec5e6637049 |
rev | line source |
---|---|
0 | 1 /* MasqMail |
2 Copyright (C) 1999-2001 Oliver Kurth | |
80 | 3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de> |
0 | 4 |
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. | |
9 | |
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. | |
14 | |
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 */ | |
19 | |
20 #include "masqmail.h" | |
21 #include "readsock.h" | |
22 | |
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 */ | |
31 | |
32 #ifdef ENABLE_SMTP_SERVER | |
33 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
34 smtp_cmd smtp_cmds[] = { |
15 | 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"}, | |
0 | 44 }; |
45 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
46 static smtp_cmd_id |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
47 get_id(const gchar * line) |
0 | 48 { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
49 gint i; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
50 for (i = 0; i < SMTP_NUM_IDS; i++) { |
80 | 51 if (strncasecmp(smtp_cmds[i].cmd, line, strlen(smtp_cmds[i].cmd)) == 0) { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
52 return (smtp_cmd_id) i; |
80 | 53 } |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
54 } |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
55 return SMTP_ERROR; |
0 | 56 } |
57 | |
58 /* this is a quick hack: we expect the address to be syntactically correct | |
59 and containing the mailbox only: | |
60 */ | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
61 static gboolean |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
62 get_address(gchar * line, gchar * addr) |
0 | 63 { |
80 | 64 gchar *p = line; |
65 gchar *q = addr; | |
0 | 66 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
67 /* skip MAIL FROM: and RCPT TO: */ |
80 | 68 while (*p && (*p != ':')) { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
69 p++; |
80 | 70 } |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
71 p++; |
0 | 72 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
73 /* skip spaces: */ |
80 | 74 while (*p && isspace(*p)) { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
75 p++; |
80 | 76 } |
0 | 77 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
78 /* get address: */ |
80 | 79 while (*p && !isspace(*p) && (q < addr + MAX_ADDRESS - 1)) { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
80 *(q++) = *(p++); |
80 | 81 } |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
82 *q = 0; |
0 | 83 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
84 return TRUE; |
0 | 85 } |
86 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
87 static smtp_connection* |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
88 create_base(gchar * remote_host) |
0 | 89 { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
90 smtp_connection *base = g_malloc(sizeof(smtp_connection)); |
80 | 91 if (!base) { |
92 return NULL; | |
93 } | |
94 | |
95 base->remote_host = g_strdup(remote_host); | |
0 | 96 |
80 | 97 base->prot = PROT_SMTP; |
98 base->next_id = 0; | |
99 base->helo_seen = 0; | |
100 base->from_seen = 0; | |
101 base->rcpt_seen = 0; | |
102 base->msg = NULL; | |
0 | 103 |
80 | 104 return base; |
0 | 105 } |
106 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
107 static void |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
108 smtp_printf(FILE * out, gchar * fmt, ...) |
0 | 109 { |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
110 va_list args; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
111 va_start(args, fmt); |
0 | 112 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
113 DEBUG(4) { |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
114 gchar buf[256]; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
115 va_list args_copy; |
0 | 116 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
117 va_copy(args_copy, args); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
118 vsnprintf(buf, 255, fmt, args_copy); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
119 va_end(args_copy); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
120 |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
121 debugf(">>>%s", buf); |
0 | 122 } |
123 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
124 vfprintf(out, fmt, args); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
125 fflush(out); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
126 |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
127 va_end(args); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
128 } |
0 | 129 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
130 void |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
131 smtp_in(FILE * in, FILE * out, gchar * remote_host, gchar * ident) |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
132 { |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
133 gchar *buffer; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
134 smtp_cmd_id cmd_id; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
135 message *msg = NULL; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
136 smtp_connection *psc; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
137 int len; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
138 |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
139 DEBUG(5) debugf("smtp_in entered, remote_host = %s\n", remote_host); |
0 | 140 |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
141 psc = create_base(remote_host); |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
142 psc->msg = msg; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
143 |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
144 buffer = (gchar *) g_malloc(BUF_LEN); |
80 | 145 if (!buffer) { |
146 /* this check is actually unneccessary as g_malloc() | |
147 aborts on failure */ | |
148 return; | |
149 } | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
150 |
80 | 151 /* send greeting string, containing ESMTP: */ |
152 smtp_printf(out, "220 %s MasqMail %s ESMTP\r\n", conf.host_name, VERSION); | |
0 | 153 |
80 | 154 while ((len = read_sockline(in, buffer, BUF_LEN, 5 * 60, READSOCKL_CHUG)) >= 0) { |
155 cmd_id = get_id(buffer); | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
156 |
80 | 157 switch (cmd_id) { |
158 case SMTP_EHLO: | |
159 psc->prot = PROT_ESMTP; | |
160 /* fall through */ | |
161 case SMTP_HELO: | |
162 psc->helo_seen = TRUE; | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
163 |
80 | 164 if (conf.defer_all) { /* I need this to debug delivery failures */ |
165 smtp_printf(out, "421 %s service temporarily unavailable.\r\n", conf.host_name); | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
166 break; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
167 } |
80 | 168 |
169 if (psc->prot == PROT_ESMTP) { | |
170 smtp_printf(out, "250-%s Nice to meet you with ESMTP\r\n", conf.host_name); | |
171 /* not yet: fprintf(out, "250-SIZE\r\n"); */ | |
172 smtp_printf(out, "250-PIPELINING\r\n" "250 HELP\r\n"); | |
173 } else { | |
174 smtp_printf(out, "250 %s pretty old mailer, huh?\r\n", conf.host_name); | |
175 } | |
176 break; | |
177 | |
178 case SMTP_MAIL_FROM: | |
179 { | |
180 gchar buf[MAX_ADDRESS]; | |
181 address *addr; | |
182 | |
183 if (!psc->helo_seen) { | |
184 smtp_printf(out, "503 need HELO or EHLO\r\n"); | |
185 break; | |
186 } | |
187 if (psc->from_seen) { | |
188 smtp_printf(out, "503 MAIL FROM: already given.\r\n"); | |
189 break; | |
190 } | |
191 | |
192 msg = create_message(); | |
193 msg->received_host = remote_host ? g_strdup(remote_host) : NULL; | |
194 msg->received_prot = psc->prot; | |
195 msg->ident = ident ? g_strdup(ident) : NULL; | |
196 /* get transfer id and increment for next one */ | |
197 msg->transfer_id = (psc->next_id)++; | |
198 | |
199 get_address(buffer, buf); | |
200 if (remote_host) { | |
201 addr = create_address(buf, TRUE); | |
202 } else { | |
203 addr = create_address_qualified(buf, TRUE, conf.host_name); | |
204 } | |
205 if (!addr) { | |
206 smtp_printf(out, "501 %s: syntax error.\r\n", buf); | |
207 } else if (!addr->domain) { | |
208 smtp_printf(out, "501 return path must be qualified.\r\n", buf); | |
209 } else { | |
210 psc->from_seen = TRUE; | |
211 msg->return_path = addr; | |
212 smtp_printf(out, "250 OK %s is a nice guy.\r\n", addr->address); | |
213 } | |
214 } | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
215 break; |
80 | 216 |
217 case SMTP_RCPT_TO: | |
218 { | |
219 char buf[MAX_ADDRESS]; | |
220 address *addr; | |
221 | |
222 if (!psc->helo_seen) { | |
223 smtp_printf(out, "503 need HELO or EHLO.\r\n"); | |
224 break; | |
225 } | |
226 if (!psc->from_seen) { | |
227 smtp_printf(out, "503 need MAIL FROM: before RCPT TO:\r\n"); | |
228 break; | |
229 } | |
230 | |
231 get_address(buffer, buf); | |
232 if (remote_host) { | |
233 addr = create_address(buf, TRUE); | |
234 } else { | |
235 addr = create_address_qualified(buf, TRUE, conf.host_name); | |
236 } | |
237 if (!addr) { | |
238 smtp_printf(out, "501 %s: syntax error in address.\r\n", buf); | |
239 break; | |
240 } | |
241 if (addr->local_part[0] == '|') { | |
242 smtp_printf(out, "501 %s: no pipe allowed for SMTP connections\r\n", buf); | |
243 break; | |
244 } | |
245 if (!addr->domain) { | |
246 smtp_printf(out, "501 recipient address must be qualified.\r\n", buf); | |
247 break; | |
248 } | |
249 gboolean do_relay = conf.do_relay; | |
250 if (!do_relay) { | |
251 do_relay = addr_is_local(msg->return_path); | |
252 if (!do_relay) { | |
253 do_relay = addr_is_local(addr); | |
254 } | |
255 } | |
256 if (!do_relay) { | |
257 smtp_printf(out, "550 relaying to %s denied.\r\n", addr_string(addr)); | |
258 break; | |
259 } | |
260 psc->rcpt_seen = TRUE; | |
261 msg->rcpt_list = g_list_append(msg->rcpt_list, addr); | |
262 smtp_printf(out, "250 OK %s is our friend.\r\n", addr->address); | |
263 } | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
264 break; |
80 | 265 |
266 case SMTP_DATA: | |
267 if (!psc->helo_seen) { | |
268 smtp_printf(out, "503 need HELO or EHLO.\r\n"); | |
269 break; | |
270 } | |
271 if (!psc->rcpt_seen) { | |
272 smtp_printf(out, "503 need RCPT TO: before DATA\r\n"); | |
273 break; | |
274 } | |
275 accept_error err; | |
276 | |
277 smtp_printf(out, "354 okay, and do not forget the dot\r\n"); | |
278 | |
279 err = accept_message(in, msg, conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0); | |
280 if (err != AERR_OK) { | |
281 if (err == AERR_TIMEOUT || err == AERR_EOF) { | |
282 return; | |
283 } | |
284 /* should never happen: */ | |
285 smtp_printf(out, "451 Unknown error\r\n"); | |
286 return; | |
287 } | |
288 | |
289 | |
290 if (!spool_write(msg, TRUE)) { | |
291 smtp_printf(out, "451 Could not write spool file\r\n"); | |
292 return; | |
293 } | |
294 pid_t pid; | |
295 smtp_printf(out, "250 OK id=%s\r\n", msg->uid); | |
296 | |
297 if (remote_host != NULL) { | |
298 logwrite(LOG_NOTICE, "%s <= <%s@%s> host=%s with %s\n", msg->uid, | |
299 msg->return_path->local_part, msg->return_path->domain, | |
300 remote_host, prot_names[psc->prot]); | |
301 } else { | |
302 logwrite(LOG_NOTICE, "%s <= <%s@%s> with %s\n", msg->uid, | |
303 msg->return_path->local_part, msg->return_path->domain, | |
304 prot_names[psc->prot]); | |
305 } | |
306 | |
307 if (conf.do_queue) { | |
308 DEBUG(1) debugf("queuing forced by configuration or option.\n"); | |
309 } else { | |
310 pid = fork(); | |
311 if (pid == 0) { | |
312 _exit(deliver(msg)); | |
313 } else if (pid < 0) { | |
314 logwrite(LOG_ALERT, "could not fork for delivery, id = %s", msg->uid); | |
315 } | |
316 } | |
317 psc->rcpt_seen = psc->from_seen = FALSE; | |
318 destroy_message(msg); | |
319 msg = NULL; | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
320 break; |
80 | 321 |
322 case SMTP_QUIT: | |
323 smtp_printf(out, "221 goodbye\r\n"); | |
81
71ce3a1568e9
moved check for NULL into destroy_message()
meillo@marmaro.de
parents:
80
diff
changeset
|
324 destroy_message(msg); |
71ce3a1568e9
moved check for NULL into destroy_message()
meillo@marmaro.de
parents:
80
diff
changeset
|
325 msg = NULL; |
80 | 326 return; |
327 | |
328 case SMTP_RSET: | |
329 psc->from_seen = psc->rcpt_seen = FALSE; | |
81
71ce3a1568e9
moved check for NULL into destroy_message()
meillo@marmaro.de
parents:
80
diff
changeset
|
330 destroy_message(msg); |
71ce3a1568e9
moved check for NULL into destroy_message()
meillo@marmaro.de
parents:
80
diff
changeset
|
331 msg = NULL; |
80 | 332 smtp_printf(out, "250 OK\r\n"); |
333 break; | |
334 | |
335 case SMTP_NOOP: | |
336 smtp_printf(out, "250 OK\r\n"); | |
337 break; | |
338 | |
339 case SMTP_HELP: | |
340 { | |
341 int i; | |
342 | |
343 smtp_printf(out, "214-supported commands:\r\n"); | |
344 for (i = 0; i < SMTP_NUM_IDS - 1; i++) { | |
345 smtp_printf(out, "214-%s\r\n", smtp_cmds[i].cmd); | |
346 } | |
347 smtp_printf(out, "214 %s\r\n", smtp_cmds[i].cmd); | |
348 } | |
349 break; | |
350 | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
351 default: |
80 | 352 smtp_printf(out, "501 command not recognized\r\n"); |
353 DEBUG(1) debugf("command not recognized, was '%s'\n", buffer); | |
10
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
354 break; |
26e34ae9a3e3
changed indention and line wrapping to a more consistent style
meillo@marmaro.de
parents:
0
diff
changeset
|
355 } |
0 | 356 } |
80 | 357 switch (len) { |
358 case -3: | |
359 logwrite(LOG_NOTICE, "connection timed out\n"); | |
360 break; | |
361 case -2: | |
362 logwrite(LOG_NOTICE, "line overflow\n"); | |
363 break; | |
364 case -1: | |
365 logwrite(LOG_NOTICE, "received EOF\n"); | |
366 break; | |
367 default: | |
368 break; | |
369 } | |
0 | 370 } |
371 #endif |