masqmail

annotate src/smtp_in.c @ 421:f37384470855

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